commit 34bf440a8c83d16cc76d05aeebcbf54444067258 Author: lx Date: Mon Jul 6 13:39:13 2026 -0400 add diff --git a/2016/AppSettings.xml b/2016/AppSettings.xml new file mode 100644 index 0000000..faae68e --- /dev/null +++ b/2016/AppSettings.xml @@ -0,0 +1,5 @@ + + + content + http://www.vortexi.cc + diff --git a/2016/ClientSettings/ClientAppSettings.json b/2016/ClientSettings/ClientAppSettings.json new file mode 100644 index 0000000..668b5d6 --- /dev/null +++ b/2016/ClientSettings/ClientAppSettings.json @@ -0,0 +1 @@ +{ "FFlagCoreScriptShowVisibleAgeV2": "True", "FFlagCoreScriptShowVisibleAge": "True", "DFFlagFindFirstChildOfClassEnabled": "True", "FFlagStudioCSGAssets": "True", "FFlagCSGLoadBlocking": "False", "FFlagCSGPhysicsLevelOfDetailEnabled": "True", "FFlagFormFactorDeprecated": "False", "FFlagFontSmoothScalling": "True", "FFlagAlternateFontKerning": "True", "FFlagFontSourceSans": "True", "FFlagRenderNewFonts": "True", "FFlagDMFeatherweightEnabled": "True", "FFlagRenderFeatherweightEnabled": "True", "FFlagRenderFeatherweightUseGeometryGenerator": "True", "FFlagScaleExplosionLifetime": "True", "FFlagEnableNonleathalExplosions": "True", "DFFlagHttpCurlHandle301": "True", "FFlagSearchToolboxByDataModelSearchString": "True", "FFlagClientABTestingEnabled": "False", "FFlagStudioSmoothTerrainForNewPlaces": "True", "FFlagUsePGSSolver": "True", "FFlagSimplifyKeyboardInputPath": "False", "FFlagNewInGameDevConsole": "True", "FFlagTextFieldUTF8": "True", "FFlagTypesettersReleaseResources": "True", "FFlagLuaBasedBubbleChat": "True", "FFlagUseCanManageApiToDetermineConsoleAccess": "False", "FFlagConsoleCodeExecutionEnabled": "True", "DFFlagCustomEmitterInstanceEnabled": "True", "FFlagCustomEmitterRenderEnabled": "True", "FFlagCustomEmitterLuaTypesEnabled": "True", "FFlagStudioInSyncWebKitAuthentication": "False", "FFlagGlowEnabled": "True", "FFlagUseNewAppBridgeInputWindows": "False", "DFFlagUseNewFullscreenLogic": "True", "FFlagRenderMaterialsOnMobile": "True", "FFlagMaterialPropertiesEnabled": "True", "FFlagSurfaceLightEnabled": "True", "FFlagStudioPropertyErrorOutput": "True", "DFFlagUseR15Character": "True", "DFFlagEnableHipHeight": "True", "DFFlagUseStarterPlayerCharacter": "True", "DFFlagFilteringEnabledDialogFix": "True", "FFlagCSGMeshColorToolsEnabled": "True", "FFlagStudioEnableGameAnimationsTab": "True", "DFFlagScriptExecutionContextApi": "True", "FFlagStudioVariableIntellesense": "True", "FFlagLuaDebugger": "True", "FFlagUseUserListMenu": "True", "FFlagEnableSetCoreTopbarEnabled": "True", "FFlagPlayerDropDownEnabled": "True", "FFlagSetCoreMoveChat": "True", "FFlagSetCoreDisableChatBar": "True", "FFlagGraphicsGL3": "True", "DFFlagUserUseLuaVehicleController": "True", "FFlagTextBoxUnicodeAware": "True", "FFlagLetLegacyScriptsWork": "True", "FFlagDep": "True", "DFFlagDisableBackendInsertConnection": "True", "FFlagPhysicsAnalyzerEnabled": "True", "DFFlagGetGroupsAsyncEnabled": "True", "DFFlagGetFocusedTextBoxEnabled": "True", "DFFlagTextBoxIsFocusedEnabled": "True", "DFFlagGetCharacterAppearanceEnabled": "True", "FFlagNewLayoutAndConstraintsEnabled": "True", "GoogleAnalyticsAccountPropertyID": "UA-43420590-3", "GoogleAnalyticsAccountPropertyIDPlayer": "UA-43420590-14", "AllowVideoPreRoll": "True", "FLogAsserts": "0", "FLogCloseDataModel": "3", "CaptureQTStudioCountersEnabled": "True", "CaptureMFCStudioCountersEnabled": "True", "CaptureCountersIntervalInMinutes": "5", "FLogServiceVectorResize": "4", "FLogServiceCreation": "4", "AxisAdornmentGrabSize": "12", "FFlagProcessAllPacketsPerStep": "True", "FFlagUS14116": "True", "FFlagBlockBlockNarrowPhaseRefactor": "True", "FFlagEnableRubberBandSelection": "True", "FFlagQtStudioScreenshotEnabled": "True", "FFlagFixNoPhysicsGlitchWithGyro": "True", "FLogFullRenderObjects": "0", "PublishedProjectsPageHeight": "535", "PublishedProjectsPageUrl": "/ide/publish", "StartPageUrl": "/ide/welcome", "FFlagOpenNewWindowsInDefaultBrowser": "True", "FFlagOnScreenProfiler": "True", "FFlagInitializeNewPlace": "True", "PrizeAssetIDs": "", "PrizeAwarderURL": "/ostara/boon", "MinNumberScriptExecutionsToGetPrize": "500", "FFlagDebugCrashEnabled": "True", "FLogHangDetection": "3", "FFlagCharAnimationStats": "False", "FFlagRenderOpenGLForcePOTTextures": "True", "FFlagUseNewCameraZoomPath": "True", "FFlagQTStudioPublishFailure": "True", "ExcludeContactWithInteriorTerrainMinusYFace": "True", "FFlagFixUphillClimb": "True", "FFlagUseAveragedFloorHeight": "True", "PublishedProjectsPageWidth": "950", "FFlagRenderFastClusterEverywhere": "True", "FLogPlayerShutdownLuaTimeoutSeconds": "1", "FFlagQtFixToolDragging": "True", "FFlagSelectPartOnUndoRedo": "True", "FFlagStatusBarProgress": "True", "FFlagStudioCheckForUpgrade": "True", "FFlagStudioInsertModelCounterEnabled": "True", "FFlagStudioAuthenticationFailureCounterEnabled": "True", "FFlagRenderCheckTextureContentProvider": "True", "FFlagRenderLightGridEnabled": "True", "FFlagStudioLightGridAPIVisible": "True", "FFlagBetterSleepingJobErrorComputation": "True", "FLogDXVideoMemory": "4", "FFlagRenderNoLegacy": "True", "FFlagStudioLightGridOnForNewPlaces": "True", "FFlagPhysicsSkipRedundantJoinAll": "True", "FFlagTerrainOptimizedLoad": "True", "FFlagTerrainOptimizedStorage": "True", "FFlagTerrainOptimizedCHS": "True", "FFlagRenderGLES2": "True", "FFlagStudioMacAddressValidationEnabled": "True", "FFlagDoNotPassSunkEventsToPlayerMouse": "True", "FFlagQtAutoSave": "True", "FFlagRenderLoopExplicit": "True", "FFlagStudioUseBinaryFormatForPlay": "True", "FFlagPhysicsRemoveWorldAssemble_US16512": "True", "FFlagNativeSafeChatRendering": "True", "FFlagRenderNewMegaCluster": "True", "FFlagAutoJumpForTouchDevices": "True", "FLogOutlineBrightnessMin": "50", "FLogOutlineBrightnessMax": "160", "FLogOutlineThickness": "40", "FFlagDE5511FixEnabled": "True", "FFlagDE4423Fixed": "True", "FFlagSymmetricContact": "True", "FFlagLocalMD5": "True", "FFlagStudioCookieParsingDisabled": "False", "FFlagLastWakeTimeSleepingJobError": "True", "FFlagPhysicsAllowAutoJointsWithSmallParts_DE6056": "True", "FFlagPhysicsLockGroupDraggerHitPointOntoSurface_DE6174": "True", "FFlagOutlineControlEnabled": "True", "FFlagAllowCommentedScriptSigs": "True", "FFlagDataModelUseBinaryFormatForSave": "True", "FFlagStudioUseBinaryFormatForSave": "True", "FFlagDebugAdornableCrash": "True", "FFlagOverlayDataModelEnabled": "True", "DFFlagFixInstanceParentDesyncBug": "True", "FFlagPromoteAssemblyModifications": "False", "DFFlagCreateHumanoidRootNode": "True", "FFlagStudioCookieDesegregation": "True", "FFlagResponsiveJump": "True", "FFlagGoogleAnalyticsTrackingEnabled": "True", "FFlagNoCollideLadderFilter": "True", "FFlagFlexibleTipping": "True", "FFlagUseStrongerBalancer": "True", "FFlagClampControllerVelocityMag": "True", "DFFlagUseSaferChatMetadataLoading": "True", "FFlagSinkActiveGuiObjectMouseEvents": "False", "FLogLuaBridge": "2", "DFFlagPromoteAssemblyModifications": "True", "FFlagDeferredContacts": "True", "FFlagFRMUse60FPSLockstepTable": "True", "FFlagFRMAdjustForMultiCore": "True", "FFlagPhysics60HZ": "True", "FFlagQtRightClickContextMenu": "True", "FFlagUseTopmostSettingToBringWindowToFront": "True", "FFlagNewLightAPI": "True", "FFlagRenderLightGridShadows": "True", "FFlagRenderLightGridShadowsSmooth": "True", "DFFlagSanitizeKeyframeUrl": "True", "DFFlagDisableGetKeyframeSequence": "False", "FFlagCreateServerScriptServiceInStudio": "True", "FFlagCreateServerStorageInStudio": "True", "FFlagCreateReplicatedStorageInStudio": "True", "FFlagFilterEmoteChat": "True", "DFFlagUseCharacterRootforCameraTarget": "True", "FFlagImageRectEnabled": "True", "FFlagNewWaterMaterialEnable": "True", "DFFlagUserHttpAPIEnabled": "True", "DFIntUserHttpAccessUserId0": "0", "FFlagUserHttpAPIVisible": "True", "FFlagCameraChangeHistory": "True", "FFlagDE4640Fixed": "True", "FFlagShowStreamingEnabledProp": "True", "FFlagOptimizedDragger": "True", "FFlagRenderNewMaterials": "True", "FFlagRenderAnisotropy": "True", "FFlagStudioInitializeViewOnPaint": "True", "DFFlagPartsStreamingEnabled": "True", "FFlagStudioLuaDebugger": "True", "FFlagStudioLocalSpaceDragger": "True", "FFlagGuiRotationEnabled": "True", "FFlagDataStoreEnabled": "True", "DFFlagDisableTeleportConfirmation": "True", "DFFlagAllowTeleportFromServer": "True", "DFFlagNonBlockingTeleport": "True", "FFlagD3D9CrashOnError": "False", "FFlagRibbonBarEnabled": "True", "SFFlagInfiniteTerrain": "True", "FFlagStudioScriptBlockAutocomplete": "True", "FFlagRenderFixAnchoredLag": "True", "DFFlagAllowAllUsersToUseHttpService": "True", "GoogleAnalyticsAccountPropertyIDClient": "", "FFlagSurfaceGuiVisible": "True", "FFlagStudioIntellesenseEnabled": "True", "FFlagAsyncPostMachineInfo": "True", "FFlagModuleScriptsVisible": "True", "FFlagModelPluginsEnabled": "True", "FFlagGetUserIdFromPluginEnabled": "True", "FFlagStudioPluginUIActionEnabled": "True", "DFFlagRemoveAdornFromBucketInDtor": "True", "FFlagRapidJSONEnabled": "True", "DFFlagDE6959Fixed": "True", "DFFlagScopedMutexOnJSONParser": "True", "FFlagSupressNavOnTextBoxFocus": "True", "DFFlagExplicitPostContentType": "True", "DFFlagAddPlaceIdToAnimationRequests": "True", "FFlagCreatePlaceEnabled": "True", "DFFlagClientAdditionalPOSTHeaders": "True", "FFlagEnableAnimationExport": "True", "DFFlagAnimationAllowProdUrls": "True", "FFlagGetUserIDFromPluginEnabled": "True", "FFlagStudioContextualHelpEnabled": "True", "FFlagLogServiceEnabled": "True", "FFlagQtPlaySoloOptimization": "True", "FFlagStudioBuildGui": "True", "DFFlagListenForZVectorChanges": "True", "DFFlagUserInputServiceProcessOnRender": "True", "FFlagDE7421Fixed": "True", "FFlagStudioExplorerActionsEnabledInScriptView": "True", "FFlagHumanoidNetworkOptEnabled": "False", "DFFlagEnableNPCServerAnimation": "True", "DFFlagDataStoreUseUForGlobalDataStore": "True", "DFFlagDataStoreAllowedForEveryone": "True", "DFFlagBadTypeOnConnectErrorEnabled": "True", "FFlagStudioRemoveUpdateUIThread": "True", "FFlagPhysicsSkipUnnecessaryContactCreation": "False", "FFlagUseNewHumanoidCache": "True", "FFlagSecureReceiptsBackendEnabled": "True", "FFlagOrderedDataStoreEnabled": "True", "FFlagStudioLuaDebuggerGA": "True", "FFlagNPSSetScriptDocsReadOnly": "True", "FFlagRDBGHashStringComparison": "True", "FFlagStudioDebuggerVisitDescendants": "True", "FFlagDeprecateScriptInfoService": "True", "FFlagIntellisenseScriptContextDatamodelSearchingEnabled": "True", "FFlagSecureReceiptsFrontendEnabled": "True", "DFFlagCreatePlaceEnabledForEveryone": "True", "FFlagCreatePlaceInPlayerInventoryEnabled": "True", "DFFlagAddRequestIdToDeveloperProductPurchases": "True", "DFFlagUseYPCallInsteadOfPCallEnabled": "True", "FFlagStudioMouseOffsetFixEnabled": "True", "DFFlagPlaceValidation": "True", "FFlagReconstructAssetUrl": "True", "FFlagUseNewSoundEngine": "True", "FIntMinMillisecondLengthForLongSoundChannel": "5000", "FFlagStudioHideInsertedServices": "True", "FFlagStudioAlwaysSetActionEnabledState": "True", "FFlagRenderNew": "True", "FIntRenderNewPercentWin": "100", "FIntRenderNewPercentMac": "100", "FLogGraphics": "6", "DFFlagDisallowHopperServerScriptReplication": "True", "FFlagInterpolationFix": "False", "FFlagHeartbeatAt60Hz": "False", "DFFlagFixProcessReceiptValueTypes": "True", "DFFlagPhysicsSkipUnnecessaryContactCreation": "True", "FFlagStudioLiveCoding": "True", "FFlagPlayerHumanoidStep60Hz": "True", "DFFlagCrispFilteringEnabled": "False", "SFFlagProtocolSynchronization": "True", "FFlagUserInputServicePipelineStudio": "True", "FFlagUserInputServicePipelineWindowsClient": "True", "FFlagUserInputServicePipelineMacClient": "True", "FFlagStudioKeyboardMouseConfig": "True", "DFFlagLogServiceEnabled": "True", "DFFlagLoadAnimationsThroughInsertService": "True", "FFlagFRMFogEnabled": "True", "FLogBrowserActivity": "3", "DFFlagPhysicsPacketAlwaysUseCurrentTime": "True", "FFlagFixedStudioRotateTool": "True", "FFlagRibbonBarEnabledGA": "True", "FFlagRenderSafeChat": "False", "DFFlagPhysicsAllowSimRadiusToDecreaseToOne": "True", "DFFlagPhysicsAggressiveSimRadiusReduction": "True", "DFFlagLuaYieldErrorNoResumeEnabled": "True", "DFFlagEnableJointCache": "False", "DFFlagOnCloseTimeoutEnabled": "True", "FFlagStudioQuickInsertEnabled": "True", "FFlagStudioPropertiesRespectCollisionToggle": "True", "FFlagTweenServiceUsesRenderStep": "True", "FFlagUseNewSoundEngine3dFix": "True", "FFlagDebugUseDefaultGlobalSettings": "True", "FFlagStudioMiddleMouseTrackCamera": "False", "FFlagTurnOffiOSNativeControls": "True", "DFFlagUseNewHumanoidHealthGui": "True", "DFFlagLoggingConsoleEnabled": "True", "DFFlagAllowModuleLoadingFromAssetId": "True", "FFlagStudioZoomExtentsExplorerFixEnabled": "True", "FFlagLuaDebuggerBreakOnError": "True", "FFlagRetentionTrackingEnabled": "True", "FFlagShowAlmostAllItemsInExplorer": "True", "FFlagStudioFindInAllScriptsEnabled": "True", "FFlagImprovedNameOcclusion": "True", "FFlagHumanoidMoveToDefaultValueEnabled": "True", "FFlagEnableDisplayDistances": "True", "FFlagUseMinMaxZoomDistance": "True", "SFFlagAllowPhysicsPacketCompression": "False", "FFlagStudioOneClickColorPickerEnabled": "True", "DFFlagHumanoidMoveToDefaultValueEnabled": "True", "VideoPreRollWaitTimeSeconds": "45", "FFlagBalancingRateLimit": "True", "FFlagLadderCheckRate": "True", "FFlagStateSpecificAutoJump": "True", "SFFlagOneWaySimRadiusReplication": "True", "DFFlagApiDictionaryCompression": "True", "SFFlagPathBasedPartMovement": "True", "FFlagEnsureInputIsCorrectState": "False", "DFFlagLuaLoadStringStrictSecurity": "True", "DFFlagCrossPacketCompression": "True", "FFlagWorkspaceLoadStringEnabledHidden": "True", "FFlagStudioPasteAsSiblingEnabled": "True", "FFlagStudioDuplicateActionEnabled": "True", "FFlagPreventInterpolationOnCFrameChange": "True", "FLogNetworkPacketsReceive": "5", "FFlagPlayPauseFix": "True", "DFFlagCrashOnNetworkPacketError": "False", "FFlagHumanoidStateInterfaces": "True", "FFlagRenderDownloadAssets": "True", "FFlagBreakOnErrorConfirmationDialog": "True", "FFlagStudioAnalyticsEnabled": "True", "FFlagAutoRotateFlag": "True", "DFFlagUseImprovedLadderClimb": "True", "FFlagUseCameraOffset": "True", "FFlagRenderBlobShadows": "True", "DFFlagWebParserDisableInstances": "False", "FFlagStudioNewWiki": "True", "DFFlagLogPacketErrorDetails": "False", "FFlagLimitHorizontalDragForce": "True", "DFFlagCreateSeatWeldOnServer": "True", "FFlagGraphicsUseRetina": "True", "FFlagDynamicEnvmapEnabled": "True", "DFFlagDeferredTouchReplication": "True", "DFFlagCreatePlayerGuiEarlier": "True", "DFFlagProjectileOwnershipOptimization": "True", "DFFlagLoadSourceForCoreScriptsBeforeInserting": "False", "GoogleAnalyticsLoadStudio": "1", "DFFlagTaskSchedulerFindJobOpt": "True", "SFFlagPreventInterpolationOnCFrameChange": "True", "DFIntNumPhysicsPacketsPerStep": "2", "DFFlagDataStoreUrlEncodingEnabled": "True", "FFlagShowWebPlaceNameOnTabWhenOpeningFromWeb": "True", "DFFlagTrackTimesScriptLoadedFromLinkedSource": "True", "FFlagToggleDevConsoleThroughChatCommandEnabled": "True", "FFlagEnableFullMonitorsResolution": "True", "DFFlagAlwaysUseHumanoidMass": "True", "DFFlagUseStrongerGroundControl": "True", "DFFlagCorrectlyReportSpeedOnRunStart": "True", "FFlagLuaDebuggerImprovedToolTip": "True", "FFlagLuaDebuggerPopulateFuncName": "True", "FFlagLuaDebuggerNewCodeFlow": "True", "DFFlagValidateCharacterAppearanceUrl": "false", "FFlagStudioQuickAccessCustomization": "True", "DFFlagTaskSchedulerUpdateJobPriorityOnWake": "True", "DFFlagTaskSchedulerNotUpdateErrorOnPreStep": "True", "FFlagWikiSelectionSearch": "True", "DFIntTaskSchedularBatchErrorCalcFPS": "1200", "FFlagSuppressNavOnTextBoxFocus": "False", "FFlagEnabledMouseIconStack": "True", "DFFlagFastClone": "True", "DFFlagLuaNoTailCalls": "True", "DFFlagFilterStreamingProps": "True", "DFFlagNetworkOwnerOptEnabled": "True", "DFFlagPathfindingEnabled": "True", "FFlagEnableiOSSettingsLeave": "True", "FFlagUseFollowCamera": "True", "FFlagDefaultToFollowCameraOnTouch": "True", "DFFlagAllowMoveToInMouseLookMove": "True", "DFFlagAllowHumanoidDecalTransparency": "True", "DFFlagSupportCsrfHeaders": "True", "DFFlagConfigureInsertServiceFromSettings": "True", "FFlagPathfindingClientComputeEnabled": "True", "DFFlagLuaResumeSupportsCeeCalls": "True", "DFFlagPhysicsSenderErrorCalcOpt": "True", "DFFlagClearPlayerReceivingServerLogsOnLeave": "True", "DFFlagConsoleCodeExecutionEnabled": "True", "DFFlagCSGDictionaryReplication": "True", "FFlagCSGToolsEnabled": "True", "FFlagCSGDictionaryServiceEnabled": "True", "FFlagCSGMeshRenderEnable": "True", "FFlagCSGChangeHistory": "True", "FFlagCSGMeshColorEnable": "True", "FFlagCSGScaleEnabled": "True", "FFlagCylinderUsesConstantTessellation": "True", "FFlagStudioDraggersScaleFixes": "True", "FFlagCSGDecalsEnabled": "True", "FFlagCSGMigrateChildData": "True", "SFFlagBinaryStringReplicationFix": "True", "FFlagHummanoidScaleEnable": "True", "FFlagStudioDataModelIsStudioFix": "True", "DFFlagWebParserEnforceASCIIEnabled": "True", "DFFlagScriptDefaultSourceIsEmpty": "True", "FFlagFixCaptureFocusInput": "True", "FFlagFireUserInputServiceEventsAfterDMEvents": "True", "FFlagVectorErrorOnNilArithmetic": "True", "DFFlagUseImageColor": "True", "FFlagStopNoPhysicsStrafe": "True", "DFFlagDebugLogNetworkErrorToDB": "False", "FFlagLowQMaterialsEnable": "True", "FFLagEnableFullMonitorsResolution": "True", "FFlagStudioChildProcessCleanEnabled": "True", "DFFlagAllowFullModelsWhenLoadingModules": "True", "DFFlagRealWinInetHttpCacheBypassingEnabled": "True", "FFlagNewUniverseInfoEndpointEnabled": "True", "FFlagGameExplorerEnabled": "True", "FFlagStudioUseBinaryFormatForModelPublish": "True", "FFlagGraphicsFeatureLvlStatsEnable": "True", "FFlagStudioEnableWebKitPlugins": "True", "DFFlagSendHumanoidTouchedSignal": "True", "DFFlagReduceHumanoidBounce": "True", "DFFlagUseNewSounds": "True", "FFlagFixHumanoidRootPartCollision": "True", "FFlagEnableAndroidMenuLeave": "True", "FFlagOnlyProcessGestureEventsWhenSunk": "True", "FFlagAdServiceReportImpressions": "True", "FFlagStudioUseExtendedHTTPTimeout": "True", "FFlagStudioSeparateActionByActivationMethod": "False", "DFFlagPhysicsSenderThrottleBasedOnBufferHealth": "True", "DFFlagGetGroupInfoEnabled": "True", "DFFlagGetGroupRelationsEnabled": "True", "SFFlagTopRepContSync": "True", "FFlagStudioUseBinaryFormatForModelSave": "True", "EnableFullMonitorsResolution": "True", "DFFlagRenderSteppedServerExceptionEnabled": "True", "FFlagUseWindowSizeFromGameSettings": "True", "DFFlagCheckStudioApiAccess": "True", "FFlagGameExplorerPublishEnabled": "True", "DFFlagKeepXmlIdsBetweenLoads": "True", "DFFlagReadXmlCDataEnabled": "True", "FFlagStudioRemoveToolSounds": "True", "FFlagStudioOneStudGridDefault": "True", "FFlagStudioPartSymmetricByDefault": "True", "FFlagStudioIncreasedBaseplateSize": "True", "FFlagSkipSilentAudioOps": "True", "SFFlagGuid64Bit": "False", "FIntValidateLauncherPercent": "100", "FFlagCSGDataLossFixEnabled": "True", "DFStringRobloxAnalyticsURL": "http://analytics.vertube.ml/", "DFFlagRobloxAnalyticsTrackingEnabled": "True", "FFlagStudioOpenLastSaved": "False", "FFlagStudioShowTutorialsByDefault": "True", "FFlagStudioForceToolboxSize": "True", "FFlagStudioExplorerDisabledByDefault": "True", "FFlagStudioDefaultWidgetSizeChangesEnabled": "True", "FFlagStudioUseScriptAnalyzer": "True", "FFlagNoClimbPeople": "True", "DFFlagAnimationFormatAssetId": "True", "FFlagGetCorrectScreenResolutionFaster": "True", "DFFlagFixTouchEndedReporting": "False", "FFlagStudioTeleportPlaySolo": "True", "FFlagStudioDE7928FixEnabled": "True", "FFlagDE8768FixEnabled": "True", "FFlagStudioDE9108FixEnabled": "True", "FFlagStudioPlaySoloMapDebuggerData": "True", "FFlagLuaDebuggerCloneDebugger": "True", "FFlagRenderLightgridInPerformEnable": "True", "SFFlagStateBasedAnimationReplication": "True", "FFlagVolumeControlInGameEnabled": "True", "FFlagGameConfigurerUseStatsService": "True", "FFlagStudioUseHttpAuthentication": "True", "FFlagDetectTemplatesWhenSettingUpGameExplorerEnabled": "True", "FFlagEntityNameEditingEnabled": "True", "FFlagNewCreatePlaceFlowEnabled": "True", "FFlagFakePlayableDevices": "False", "FFlagMutePreRollSoundService": "True", "DFFlagBodyMoverParentingFix": "True", "DFFlagBroadcastServerOnAllInterfaces": "True", "HttpUseCurlPercentageWinClient": "100", "HttpUseCurlPercentageMacClient": "100", "HttpUseCurlPercentageWinStudio": "100", "HttpUseCurlPercentageMacStudio": "100", "SFFlagReplicatedFirstEnabled": "True", "DFFlagCSGShrinkForMargin": "True", "FFlagPhysicsBulletConnectorPointRecalc": "True", "DFIntBulletContactBreakThresholdPercent": "200", "DFIntBulletContactBreakOrthogonalThresholdPercent": "200", "FFlagPhysicsBulletConnectorMatching": "True", "FFlagPhysicsBulletUseProximityMatching": "False", "FFlagPhysicsCSGUsesBullet": "True", "DFFlagCSGPhysicsDeserializeRefactor": "True", "FFlagWedgeEnableDecalOnTop": "True", "FFlagFrustumTestGUI": "True", "FFlagFeatureLvlsDX11BeforeDeviceCreate": "True", "FFlagStudioPasteSyncEnabled": "True", "FFlagResetMouseCursorOnToolUnequip": "True", "DFFlagUpdateCameraTarget": "True", "DFFlagFixGhostClimb": "True", "DFFlagUseStarterPlayer": "True", "FFlagStudioFindCrashFixEnabled": "True", "FFlagFixPartOffset": "True", "DFFlagLuaCloseUpvalues": "True", "FFlagRenderTextureCompositorUseBudgetForSize": "True", "FFlagAllowOutOfBoxAssets": "False", "FFlagRemoveTintingWhenActiveIsFalseOnImageButton": "True", "FFlagStudioModuleScriptDefaultContents": "True", "FFlagStudioHomeKeyChangeEnabled": "True", "FFlagStudioOpenStartPageForLogin": "True", "FFlagStudioNativeKeepSavedChanges": "True", "FFlagSerializeCurrentlyOpenPlaceWhenPublishingGame": "True", "FFlagGameNameLabelEnabled": "True", "FFlagStudioValidateBootstrapper": "True", "FFlagRakNetReadFast": "True", "DFFlagPhysicsSenderSleepingUpdate": "True", "FFlagUseShortShingles": "True", "FFlagKKTChecks": "False", "DFFlagUseApiProxyThrottling": "True", "DFFlagValidateSetCharacter": "True", "DFFlagUpdateHumanoidSimBodyInComputeForce": "True", "DFFlagNetworkPendingItemsPreserveTimestamp": "True", "FFlagStudioCSGRotationalFix": "True", "FFlagNewLoadingScreen": "True", "FFlagScrollingFrameOverridesButtonsOnTouch": "True", "DFFlagStreamLargeAudioFiles": "True", "DFFlagNewLuaChatScript": "True", "DFFlagLoopedDefaultHumanoidAnimation": "True", "FFlagSoundsRespectDelayedStop": "False", "DFFlagCSGPhysicsErrorCatchingEnabled": "True", "DFFlagFireStoppedAnimSignal": "True", "FFlagStudioFixToolboxReload": "True", "FFlagCSGDecalsV2": "True", "FFlagLocalOptimizer": "True", "DFFlagClearFailedUrlsWhenClearingCacheEnabled": "True", "DFFlagSupportNamedAssetsShortcutUrl": "True", "DFFlagUseW3CURIParser": "True", "DFFlagContentProviderHttpCaching": "True", "FFlagNoWallClimb": "False", "FFlagSmoothMouseLock": "False", "DFFlagCSGPhysicsNanPrevention": "True", "FFlagStudioDE9818FixEnabled": "True", "FFlagGameExplorerImagesEnabled": "True", "FFlagStudioInsertOrientationFix": "True", "FFlagStudioTabOrderingEnabled": "True", "FFlagFramerateDeviationDroppedReport": "True", "FFlagModuleScriptsPerVmEnabled": "False", "FFlagGameExplorerImagesInsertEnabled": "True", "FFlagTexturePropertyWidgetEnabled": "True", "FFlagReloadAllImagesOnDataReload": "True", "FFlagModuleScriptsPerVmEnabledFix2": "True", "DFFlagFixBufferZoneContainsCheck": "False", "FFlagStudioPlaceAssetFromToolbox": "True", "FFlagChannelMasterMuting": "True", "FFlagStudioUseDelayedSyntaxCheck": "True", "FFlagStudioCommandLineSaveEditText": "True", "FFlagStudioAddHelpInContextMenu": "True", "DFIntHttpCacheCleanMinFilesRequired": "10000", "DFIntHttpCacheCleanMaxFilesToKeep": "7500", "FFlagCSGVoxelizer": "True", "DFFlagCheckApiAccessInTransactionProcessing": "True", "FFlagBindPurchaseValidateCallbackInMarketplaceService": "True", "FFlagSetDataModelUniverseIdAfterPublishing": "True", "FFlagOpenScriptWorksOnModulesEnabled": "True", "FFlagStudioRibbonBarNewLayout": "True", "FFlagStudioRibbonBarLayoutFixes": "True", "FFlagStudioPlaceOnlineIndicator": "True", "FFlagRenderWangTiles": "True", "FFlagDisableBadUrl": "True", "FFlagPrimalSolverLogBarrierIP": "True", "FFlagDualSolverSimplex": "True", "FFlagPrimalSolverSimplex": "True", "FIntNumSmoothingPasses": "3", "FFlagVerifyConnection": "True", "FIntRegLambda": "1400", "FFlagScriptAnalyzerPlaceholder": "True", "FFlagCSGStripPublishedData": "True", "DFFlagRaycastReturnSurfaceNormal": "True", "FFlagMoveGameExplorerActionsIntoContextMenu": "True", "FFlagStudioAdvanceCookieExpirationBugFixEnabled": "True", "FFlagNewBackpackScript": "True", "FFlagNewPlayerListScript": "True", "FFlagGameNameAtTopOfExplorer": "False", "FFlagStudioActActionsAsTools": "True", "FFlagStudioInsertAtMouseClick": "True", "FFlagStopLoadingStockSounds": "True", "DFFlagFixTimePositionReplication": "True", "DFFlagHttpReportStatistics": "True", "DFFlagEnableChatTestingInStudio": "True", "DFIntHttpSendStatsEveryXSeconds": "300", "FLogStepAnimatedJoints": "5", "DFFlagLuaDisconnectFailingSlots": "False", "DFFlagEnsureSoundPosIsUpdated": "True", "DFFlagLoadStarterGearEarlier": "False", "DFFlagBlockUsersInLuaChat": "True", "FFlagRibbonPartInsertNotAllowedInModel": "True", "DFFlagUsePlayerScripts": "True", "DFFlagUserAccessUserSettings": "True", "DFFlagUseLuaCameraAndControl": "True", "DFFlagUseLuaPCInput": "True", "DFFlagFixLuaMoveDirection": "True", "DFFlagUseDecalLocalTransparencyModifier": "True", "DFFlagUseFolder": "True", "DFFlagUsePreferredSpawnInPlaySoloTeleport": "True", "DFFlagFilterAddSelectionToSameDataModel": "False", "FFlagGameExplorerAutofillImageNameFromFileName": "True", "FFlagGameExplorerBulkImageUpload": "True", "FFlagStudioAllowAudioSettings": "True", "DFFlagUsePlayerInGroupLuaChat": "True", "FFlagStudioDecalPasteFix": "True", "FFlagStudioCtrlTabDocSwitchEnabled": "True", "DFIntDraggerMaxMovePercent": "60", "FFlagUseUniverseGetInfoCallToDetermineUniverseAccess": "True", "FFlagMaxFriendsCount": "True", "DFIntPercentApiRequestsRecordGoogleAnalytics": "0", "FFlagSelectSpinlock": "True", "FFlagFastZlibPath": "True", "DFFlagWriteXmlCDataEnabled": "True", "DFFlagUseSpawnPointOrientation": "True", "DFFlagUsePlayerSpawnPoint": "True", "DFFlagCSGPhysicsRecalculateBadContactsInConnectors": "True", "FFlagStudioPartAlignmentChangeEnabled": "True", "FFlagStudioToolBoxModelDragFix": "True", "DFFlagOrder66": "False", "FFlagCloudIconFixEnabled": "True", "DFFlagFixHealthReplication": "True", "DFFlagReplicateAnimationSpeed": "True", "FFlagLuaFollowers": "True", "FFlagNewNotificationsScript": "True", "FFlagStudioSendMouseIdleToPluginMouse": "True", "DFFlagPhysicsOptimizeAssemblyHistory": "True", "DFFlagPhysicsOptimizeBallBallContact": "True", "DFFlagUseNewBubbleSkin": "True", "DFFlagUse9FrameBackgroundTransparency": "True", "DFFlagCheckForHeadHit": "False", "DFFlagUseHttpsForAllCalls": "True", "DFFlagLoadCoreModules": "True", "FFlagStudioRecentSavesEnabled": "True", "FFlagStudioToolBoxInsertUseRayTrace": "True", "FFlagInterpolationUseWightedDelay": "True", "FFlagUseInGameTopBar": "True", "FFlagNewPurchaseScript": "True", "FFlagStudioEnableGamepadSupport": "True", "FFlagStudioRemoveDuplicateParts": "True", "FFlagStudioLaunchDecalToolAfterDrag": "True", "DFFlagHumanoidFloorPVUpdateSignal": "True", "DFFlagHumanoidFloorDetectTeleport": "True", "DFFlagHumanoidFloorForceBufferZone": "False", "DFFlagHumanoidFloorManualDeltaUpdateManagment": "True", "DFFlagHumanoidFloorManualFrictionLimitation": "True", "DFFlagUpdateHumanoidNameAndHealth": "True", "DFFlagEnableHumanoidDisplayDistances": "True", "FFlagFixTouchInputEventStates": "False", "DFFlagInterpolationTimingFix": "True", "FIntRenderGBufferMinQLvl": "16", "FFlagResizeGuiOnStep": "True", "FFlagDontFireFakeMouseEventsOnUIS": "True", "FFlagCameraUseOwnViewport": "True", "FFlagGameExplorerMoveImagesUnderAssetsGroup": "True", "DFFlagNetworkFilterAllowToolWelds": "True", "DFIntHttpInfluxHundredthsPercentage": "5", "DFStringHttpInfluxURL": "http://influx.vertube.ml", "DFStringHttpInfluxDatabase": "main", "DFStringHttpInfluxUser": "user", "DFStringHttpInfluxPassword": "password", "FFlagStudioSpawnLocationsDefaultValues": "True", "FFlagStudioDE11536FixEnabled": "True", "FFlagStudioRibbonGroupResizeFixEnabled": "True", "FFlagGradientStep": "True", "FFlagUseNewContentProvider": "False", "SFFlagEquipToolOnClient": "True", "FFlagStartWindowMaximizedDefault": "True", "FFlagUseNewKeyboardHandling": "True", "FFlagCameraZoomNoModifier": "True", "DFFlagRemoteValidateSubscribersError": "True", "FFlagNewMenuSettingsScript": "True", "DFFlagHttpCurlSanitizeUrl": "True", "DFFlagRemoveDataModelDependenceInWaitForChild": "True", "FFlagFilterAddSelectionToSameDataModel": "True", "DFFlagUseCanManageApiToDetermineConsoleAccess": "True", "DFIntMoveInGameChatToTopPlaceId": "1", "FFlagStudioProgressIndicatorForInsertEnabled": "True", "FFlagTerrainLazyGrid": "True", "FFlagHintsRenderInUserGuiRect": "True", "FFlagCallSetFocusFromCorrectThread": "True", "FFlagFastRevert": "True", "FFlagSleepBeforeSpinlock": "True", "FFlagSparseCheckFastFail": "True", "FFlagStudioSmoothTerrainPlugin": "True", "FFlagStudioLoadPluginsLate": "True", "FFlagStudioInsertIntoStarterPack": "True", "FFlagStudioIgnoreSSLErrors": "True", "DFFlagFixJointReparentingDE11763": "True", "DFFlagPhysicsInvalidateContactCache": "True", "FFlagLuaMathNoise": "True", "FFlagArcHandlesBidirectional": "True", "FFlagChangeHistoryFixPendingChanges": "True", "DFFlagWorkspaceSkipTerrainRaycastForSurfaceGui": "True", "FFlagStudioBatchItemMapAddChild": "True", "FFlagRenderCameraFocusFix": "True", "DFFlagReplicatorWorkspaceProperties": "True", "FFlagDirectX11Enable": "True", "FFlagCheckDegenerateCases": "True", "DFFlagUseServerCoreScripts": "True", "DFFlagCorrectFloorNormal": "True", "FFlagNewBadgeServiceUrlEnabled": "True", "FFlagBubbleChatbarDocksAtTop": "True", "FFlagSmoothTerrainClient": "True", "FFlagLuaUseBuiltinEqForEnum": "True", "FFlagPlaceLauncherThreadCheckDmClosed": "True", "DFFlagAppendTrackerIdToTeleportUrl": "True", "FFlagPlayerMouseRespectGuiOffset": "True", "DFFlagReportElevatedPhysicsFPSToGA": "True", "DFFlagPreventReturnOfElevatedPhysicsFPS": "True", "FFlagStudioIgnoreMouseMoveOnIdle": "True", "FFlagStudioDraggerFixes": "True", "FLogUseLuaMemoryPool": "0", "FFlagCSGNewTriangulate": "True", "DFFlagLuaFixResumeWaiting": "True", "FFlagFRMInStudio": "True", "DFFlagFixLadderClimbSpeed": "True", "DFFlagNoWalkAnimWeld": "False", "DFFlagImprovedKick": "True", "FFlagRenderFixLightGridDirty": "True", "FFlagLoadLinkedScriptsOnDataModelLoad": "True", "FFlagFixMeshOffset": "True", "FIntLaunchInfluxHundredthsPercentage": "0", "DFIntJoinInfluxHundredthsPercentage": "100", "FFlagSmoothTerrain": "True", "FFlagNewVehicleHud": "True", "DFFlagHumanoidStandOnSeatDestroyed": "True", "DFFlagGuiBase3dReplicateColor3WithBrickColor": "True", "FFlagTaskSchedulerCyclicExecutiveStudio": "True", "DFIntElevatedPhysicsFPSReportThresholdTenths": "585", "DFIntExpireMarketPlaceServiceCacheSeconds": "60", "DFFlagEnableMarketPlaceServiceCaching": "True", "DFFlagUseNewAnalyticsApi": "True", "DFFlagSmoothTerrainDebounceUpdates": "True", "FFlagStudioAuthenticationCleanup": "True", "FFlagRenderFixGBufferLOD": "True", "FFlagStudioDraggerCrashFixEnabled": "True", "FFlagDraggerCrashFixEnabled": "True", "DFFlagEnableRapidJSONParser": "True", "DFFlagPushLuaWorldRayOriginToNearClipPlane": "True", "FFlagLoadTimeModificationTestFlag": "True", "DFFlagPhysicsFastSmoothTerrainUpdate": "True", "DFFlagSmoothTerrainPhysicsExpandPrimitiveOptimal": "True", "DFFlagFixBytesOnJoinReporting": "True", "FFlagRenderGBufferEverywhere": "False", "DFFlagSmoothTerrainPhysicsRayAabbExact": "True", "DFIntSmoothTerrainPhysicsRayAabbSlop": "1", "DFIntMaxClusterKBPerSecond": "300", "FLogLuaAssert": "0", "FFlagSmoothTerrainCountCellVolume": "True", "DFFlagSmoothTerrainWorldToCellUseDiagonals": "True", "DFFlagFireSelectionChangeOncePerChange": "True", "FIntLuaAssertCrash": "0", "FFlagRenderFixCameraFocus": "False", "DFFlagCSGPhysicsSphereRotationIdentity": "True", "DFFlagCSGPhysicsRefreshContactsManually": "True", "FFlagStudioUndoEnabledForEdit": "True", "DFIntLuaChatFloodCheckMessages": "7", "DFIntLuaChatFloodCheckInterval": "15", "FFlagLuaChatFiltering": "True", "FFlagMobileToggleChatVisibleIcon": "True", "FFlagStudioDE9132FixEnabled": "True", "DFFlagGetUserIdEnabled": "True", "DFFlagGetUserNameEnabled": "True", "DFFlagEnableAnimationInformationAccess": "True", "DFFlagEnableAnimationTrackExtendedAPI": "True", "FFlagRequestServerStatsV2Enabled": "True", "FFlagPhysicsPreventGroupDraggerPlacementToMinus400_DE6267": "True", "FFlagSpecificUserdataTypeErrors": "True", "DFFlagScrollingFrameDraggingFix": "True", "FFlagAutodetectCPU": "True", "DFFlagSetRenderedFrameOnClumpChanged": "True", "DFFlagDisableTimeoutDuringJoin": "True", "DFFlagDesiredAltitudeDefaultInf": "True", "DFFlagRCCDE13316CrashFix": "True", "DFFlagUseStarterPlayerGA": "True", "FFlagScrollingFrameMouseUpFix": "True", "DFFlagDebrisServiceUseDestroy": "True", "DFFlagAccessUserFeatureSetting": "True", "DFFlagAllowBindActivate": "True", "FFlagEnableControllerGuiSelection": "True", "FFlagUseNewSoftwareMouseRender": "True", "DFFlagDoNotHoldTagItemsForInitialData": "True", "FFlagAltSpinlock": "True", "FFlagSpinlock": "True", "FFlagGraphicsGLReduceLatency": "True", "DFFlagMovingHumananoidWakesFloor": "True", "DFFlagSetNetworkOwnerAPIEnabled": "True", "DFFlagSetNetworkOwnerAPIEnabledV2": "True", "DFFlagGetFriendsEnabled": "True", "DFFlagGetFriendsOnlineEnabled": "True", "DFFlagUseNewTextBoxLogic": "True", "FFlagOnScreenProfilerGPU": "True", "FFlagConfigurableLineThickness": "True", "DFFlagSpawnPointEnableProperty": "True", "DFFlagConfigurableFallenPartDestroyHeight": "True", "DFFlagMiddleMouseButtonEvent": "True", "DFFlagEnablePreloadAsync": "True", "DFFlagFoldersInGUIs": "True", "DFIntAndroidInfluxHundredthsPercentage": "0", "DFFlagNoOwnershipLogicOnKernelJoint": "True", "DFFlagEnableGetPlayingAnimationTracks": "True", "FFlagCyclicExecutivePriorityJobs": "True", "DFIntMaxMissedWorldStepsRemembered": "16", "DFIntMacInfluxHundredthsPercentage": "0", "DFIntiOSInfluxHundredthsPercentage": "100", "FFlagStudioLockServiceParents": "True", "DFFlagFirePlayerAddedAndPlayerRemovingOnClient": "True", "DFFlagRecursiveWakeForBodyMovers": "True", "DFFlagEnableHumanoidSetStateEnabled": "True", "DFFlagSoundEndedEnabled": "True", "DFFlagUseIntersectingOthersForSpawnEnabled": "True", "DFFlagMoveToDontAlignToGrid": "True", "DFFlagIsBestFriendsWithReturnFriendsWith": "True", "DFFlagPlayerOwnsAssetFalseForInvalidUsers": "True", "DFFlagIsUrlCheckAssetStringLength": "True", "DFFlagEnableGoodbyeDialog": "True", "DFFlagEnableReverseAnimations": "True", "DFFlagEnableAnimationSetTimePosition": "True", "DFFlagEnableMobileAutoJumpFlag": "True", "DFFlagHttpDelaySendInfluxStats": "True", "DFFlagDisableRequestMarker": "True", "DFFlagDisableCharacterRequest": "True", "FFlagStudioCollapsibleTutorials": "True", "FStringStudioTutorialsUrl": "http://wiki.roblox.com/index.php?title=Studio_Tutorials_Test&studiomode=true", "FStringStudioTutorialsTOCUrl": "http://wiki.roblox.com/index.php?title=Studio_Tutorials_Landing&studiomode=true", "FFlagSandboxHash": "True", "FFlagDE14316CrashFix": "True", "FFlagDE14317CrashFix": "True", "DFFlagSetNetworkOwnerCanSetCheck": "True", "DFFlagLiveColorUpdatesCanceling": "True", "DFFlagLuaGcPerVm": "True", "FFlagStudioDeviceEmulationTouchInputFix": "True", "FFlagTaskSchedulerCyclicExecutive": "True", "DFFlagMakeWebPendingFriendRequests": "True", "DFFlagGetLastestAssetVersionEnabled": "True", "FFlagHideDeprecatedEnums": "True", "FFlagSubmitEditedColor3WhenFocusLost": "True", "DFFlagFixScriptableCameraRoll": "True", "DFFlagSeparateBulletNarrowPhaseAndMidStepUpdates": "True", "DFFlagUsePGSSolverSpringConstantScale": "True", "DFFlagToolRequiresHandleProperty": "True", "FFlagPlayerScriptsNotArchivable": "True", "DFFlagClearAllChildrenUseDestroy": "True", "DFFlagMaxPlayersEnabled": "True", "DFFlagPreferredPlayersEnabled": "True", "DFFlagLocalHumanoidSoundsEnabled": "True", "DFFlagIncreaseSoundPositionClampLimit": "True", "DFFlagNameOcculsionIgnoreTransparent": "True", "DFFlagReconstructAssetUrlNew": "True", "DFFlagAdjustFloorForce": "True", "DFFlagFixAnimationPhaseInitialization": "True", "FFlagLuaChatPhoneFontSize": "True", "DFFlagUseAssetTypeHeader": "True", "FFlagCSGUnionCatchUnknownExceptions": "False", "FIntGamePerfMonitorPercentage": "10", "FFlagSoundTypeCheck": "True", "DFFlagIncreaseScrollWheelMultiplyTime": "True", "FFlagMacRemoveUserInputJob": "True", "FFlagStudioNewFonts": "True", "DFFlagApiCapitalizationChanges": "True", "FFlagParticleCullFix": "True", "DFFlagVideoCaptureTeleportFix": "False", "DFFlagCoreGuiCustomizationApi": "True", "DFFlagCustomTeleportLoadingScreen": "True", "DFFlagCharacterAppearanceLoadedEnabled": "True", "DFFlagVIPServerOwnerIdEnabled": "True", "DFFlagEnableParticleVelocityInheritance": "True", "DFFlagEnableParticleEmissionDirection": "True", "DFFlagFixParticleDistribution": "True", "DFFlagEnableParticleNewBoundingBox": "True", "DFFlagEnableParticlePartLock": "True", "DFFlagEnableParticleBurst": "True", "DFFlagNoRunSteepSlope": "True", "DFFlagHumanoidJumpPower": "True", "FFlagControllerMenu": "True", "FFlagFlyCamOnRenderStep": "True", "DFFlagFullscreenEnabledWhileRecording": "True", "DFFlagPreProcessTextBoxEvents": "True", "DFFlagAllowHideHudShortcut": "False", "DFFlagFixBallInsideBlockCollision": "True", "FFlagPGSSolverBodyCacheLeakFix": "True", "FFlagFixCrashAtShutdown": "True", "DFFlagEquipClonedToolFix": "True", "FFlagGamepadCursorChanges": "True", "DFFlagCreatePlayerGuiLocal": "False", "DFFlagDontUseInsertServiceOnAnimLoad": "True", "DFFlagCyclicExecutiveFixNonCyclicJobRun": "True", "DFFlagPhysicsFPSTimerFix": "True", "FFlagCyclicExecutiveRenderJobRunsFirst": "True", "FFlagPhysicsCylinders": "True", "DFFlagPhysicsUseNewBulletContact": "True", "FFlagReadCoordinateFrameFast": "False", "DFFlagRayHitMaterial": "True", "DFFlagPromptPurchaseOnGuestHandledInCoreScript": "True", "DFFlagNonEmptyPcallError": "True", "DFFlagDisplayTextBoxTextWhileTypingMobile": "False", "DFFlagOverrideScollingDisabledWhenRecalulateNeeded": "True", "DFFlagFixScrollingOffSurfaceGUIs": "True", "DFFlagTextScaleDontWrapInWords": "True", "DFFlagListenPositionEnabled": "True", "DFFlagBackTabInputInStudio": "True", "DFFlagTrackLastDownGUI": "True", "DFFlagBulletFixCacheReuse": "True", "DFFlagFastFilterHumanoidParts": "False", "DFFlagProcessAcceleratorsBeforeGUINaviagtion": "True", "DFFlagImageFailedToLoadContext": "True", "DFFlagDontReorderScreenGuisWhenDescendantRemoving": "True", "DFFlagSoundFailedToLoadContext": "True", "DFFlagAnimationFailedToLoadContext": "True", "DFFlagElasticEasingUseTwoPi": "True", "SFFlagNetworkUseServerScope": "True", "DFFlagHttpZeroLatencyCaching": "True", "DFFlagPasteWithCapsLockOn": "True", "DFFlagHttpCurlDomainTrimmingWithBaseURL": "False", "DFFlagLoadFileUseRegularHttp": "True", "DFFlagReplicatorCheckBadRebinding": "True", "FFlagFastClusterThrottleUpdateWaiting": "True", "DFFlagDeserializePacketThreadEnabled": "True", "FFlagFontSizeUseLargest": "True", "DFFlagRejectHashesInLinkedSource": "True", "FFlagUpdatePrimitiveStateForceSleep": "True", "FFlagPhysicsUseKDTreeForCSG": "True", "DFFlagCSGLeftoverDataFix": "True", "FFlagStudioTutorialSeeAll": "True", "DFFlagLimitScrollWheelMaxToHalfWindowSize": "True", "FFlagGameExplorerCopyPath": "True", "DFFlagFixRotatedHorizontalScrollBar": "True", "DFFlagFixAnchoredSeatingPosition": "True", "FFlagFixSlice9Scale": "True", "DFFlagFullscreenRefocusingFix": "True", "DFFlagEnableClimbingDirection": "True", "FFlagPGSGlueJoint": "True", "FFlagTweenCallbacksDuringRenderStep": "True", "FFlagFRMFixCullFlicker": "True", "DFFlagDisableProcessPacketsJobReschedule": "True", "FFlagCSGVoxelizerPrecompute": "False", "FFlagLazyRenderingCoordinateFrame": "True", "FFlagPGSSteppingMotorFix": "True", "DFFlagLockViolationScriptCrash": "False", "DFFlagLockViolationInstanceCrash": "False", "FFlagSpheresAllowedCustom": "True", "DFFlagHumanoidCookieRecursive": "True", "FFlagRwxFailReport": "True", "FIntStudioInsertDeletionCheckTimeMS": "30000", "DFFlagClampRocketThrustOnPGS": "True", "DFFlagPGSWakePrimitivesWithBodyMoverPropertyChanges": "True", "FFlagPGSUsesConstraintBasedBodyMovers": "True", "FFlagUseNewSubdomainsInCoreScripts": "True", "DFFlagEnableShowStatsLua": "True", "FFlagSmoothTerrainPacked": "True", "DFFlagUrlReconstructToAssetGame": "False", "FFlagPGSApplyImpulsesAtMidpoints": "True", "FFlagModifyDefaultMaterialProperties": "True", "FIntPhysicalPropFriction_SMOOTH_PLASTIC_MATERIAL": "200", "FIntPhysicalPropFriction_PLASTIC_MATERIAL": "300", "FIntPhysicalPropFriction_NEON_MATERIAL": "300", "FIntPhysicalPropFriction_SNOW_MATERIAL": "300", "FIntPhysicalPropFriction_ALUMINUM_MATERIAL": "400", "FIntPhysicalPropFriction_BRICK_MATERIAL": "800", "FIntPhysicalPropFriction_CONCRETE_MATERIAL": "700", "FIntPhysicalPropFriction_DIAMONDPLATE_MATERIAL": "350", "FIntPhysicalPropFriction_SANDSTONE_MATERIAL": "500", "FIntPhysicalPropFriction_SAND_MATERIAL": "500", "FIntPhysicalPropFWeight_ICE_MATERIAL": "3000", "FIntPhysicalPropFWeight_BRICK_MATERIAL": "300", "FIntPhysicalPropFWeight_CONCRETE_MATERIAL": "300", "FIntPhysicalPropFWeight_SANDSTONE_MATERIAL": "5000", "FIntPhysicalPropFWeight_BASALT_MATERIAL": "300", "FIntPhysicalPropFWeight_SAND_MATERIAL": "5000", "FIntPhysicalPropElasticity_SAND_MATERIAL": "50", "FIntPhysicalPropElasticity_SNOW_MATERIAL": "30", "FIntPhysicalPropElasticity_MUD_MATERIAL": "70", "FIntPhysicalPropElasticity_GROUND_MATERIAL": "100", "FIntPhysicalPropElasticity_MARBLE_MATERIAL": "170", "FIntPhysicalPropElasticity_BRICK_MATERIAL": "150", "FIntPhysicalPropElasticity_PEBBLE_MATERIAL": "170", "FIntPhysicalPropElasticity_COBBLESTONE_MATERIAL": "170", "FIntPhysicalPropElasticity_ROCK_MATERIAL": "170", "FIntPhysicalPropElasticity_SANDSTONE_MATERIAL": "150", "FIntPhysicalPropElasticity_BASALT_MATERIAL": "150", "FIntPhysicalPropElasticity_CRACKED_LAVA_MATERIAL": "150", "FIntPhysicalPropElasticity_FABRIC_MATERIAL": "50", "FIntPhysicalPropElasticity_WOOD_MATERIAL": "200", "FIntPhysicalPropElasticity_WOODPLANKS_MATERIAL": "200", "FIntPhysicalPropElasticity_ICE_MATERIAL": "150", "FIntPhysicalPropElasticity_GLACIER_MATERIAL": "150", "FIntPhysicalPropElasticity_RUST_MATERIAL": "200", "FIntPhysicalPropElasticity_DIAMONDPLATE_MATERIAL": "250", "FIntPhysicalPropElasticity_ALUMINUM_MATERIAL": "250", "FIntPhysicalPropElasticity_METAL_MATERIAL": "250", "FIntPhysicalPropElasticity_GRASS_MATERIAL": "100", "DFFlagFixSeatingWhileSitting": "True", "FFlagPGSSolverDefaultOnNewPlaces": "True", "FFlagPGSVariablePenetrationMargin": "False", "FIntPGSPentrationMarginMax": "50000", "FFlagStudioHideMouseCoursorOnCommand": "True", "SFFlagNewPhysicalPropertiesForcedOnAll": "True", "SFFlagMaterialPropertiesNewIsDefault": "True", "DFFlagMaterialPropertiesEnabled": "True", "FFlagWaterParams": "True", "FFlagSpatialHashMoreRoots": "True", "FFlagSkipAdornIfWorldIsNull": "True", "DFStringWorkspaceMessageLink": "http://devforum.roblox.com/t/improving-the-safety-of-our-community/33201", "DFStringWorkspaceMessageText": "Click here to read an important message about improving the safety of our community", "DFIntStudioWorkspaceNotificationLevel": "0", "DFFlagNetworkOwnershipRuleReplicates": "True", "DFFlagSmoothTerrainWriteVoxelsOccupancyFix": "True", "DFFlagCloudEditByPassCheckForServer": "True", "DFFlagDraggerUsesNewPartOnDuplicate": "True", "DFFlagRestoreTransparencyOnToolChange": "False", "FFlagEnableLuaFollowers": "False", "DFFlagUserServerFollowers": "True", "FFlagNetworkReplicateTerrainProperties": "True", "FFlagAllowInsertFreeModels": "False", "FFlagInsertUnderFolder": "True", "DFFlagPGSWakeOtherAssemblyForJoints": "True", "FFlagStudioPropertySliderEnabled": "True", "DFFlagSetNetworkOwnerFixAnchoring": "True", "FFlagFixBulletGJKOptimization": "True", "FFlagOSXUseSDL": "False", "DFFlagPhysicalPropMassCalcOnJoin": "False", "DFFlagBrickColorParseNonDeprecatedMatchEnabled": "True", "FFlagWindowsUseSDL": "False", "FFlagPhysicsOptimizeSendClumpChanged": "True", "DFFlagHumanoidFeetIsPlastic": "True", "DFFlagUseTerrainCustomPhysicalProperties": "True", "DFFlagFormFactorDeprecated": "True", "FFlagPGSVariablePenetrationMarginFix": "True", "DFIntDataStoreMaxValueSize": "262144", "DFFlagFixShapeChangeBug": "True", "FFlagScriptAnalyzerFixLocalScope": "True", "FFlagRenderVRBBGUI": "True", "FFlagRenderVR": "True", "DFFlagNetworkFixJoinDataItemOrder": "True", "FFlagStudioImproveModelDragFidelity": "True", "FFlagStudioOrthonormalizeSafeRotate": "True", "FFlagMacInferredCrashReporting": "True", "FFlagWindowsInferredCrashReporting": "True", "FFlagCloudEditDoNotLoadCoreScripts": "True", "FFlagStudioEmbeddedFindDialogEnabled": "True", "FFlagUserAllCamerasInLua": "False", "DFFlagMacInferredCrashReporting": "True", "DFFlagWindowsInferredCrashReporting": "True", "FFlagUseNewPromptEndHandling": "True", "FFlagPhysPropConstructFromMaterial": "True", "FFlagStudioToolboxModelDragToCastPoint": "True", "FFlagStudioPushTreeWidgetUpdatesToMainThread": "True", "DFFlagFixYieldThrottling": "True", "FFlagCheckSleepOptimization": "True", "DFFlagContactManagerOptimizedQueryExtents": "True", "FFlagUseBuildGenericGameUrl": "True", "DFFlagFixFallenPartsNotDeleted": "True", "DFFlagTrackPhysicalPropertiesGA": "True", "DFFlagSetNetworkOwnerFixAnchoring2": "True", "FFlagUseSimpleRapidJson": "True", "DFFlagTurnOffFakeEventsForCAS": "True", "DFFlagTurnOffFakeEventsForInputEvents": "True", "FFlagCancelPendingTextureLoads": "False", "DFFlagCachedPoseInitialized": "True", "DFFlagFixJumpGracePeriod": "True", "FFlagFilterSinglePass": "True", "DFFlagOrthonormalizeJointCoords": "True", "DFFlagPhysicsSenderUseOwnerTimestamp": "False", "DFFlagNamesOccludedAsDefault": "True", "FFlagUserUseNewControlScript": "True", "FFlagUseDynamicTypesetterUTF8": "True", "DFFlagUseNewPersistenceSubdomain": "True", "DFFlagUseNewDataStoreLogging": "True", "FFlagPlaceLauncherUsePOST": "False", "FFlagStudioUpdateSAResultsInUIThread": "True", "FFlagBillboardGuiVR": "True", "FFlagHumanoidRenderBillboard": "True", "FLogVR": "6", "FFlagStudioRemoveDebuggerResumeLock": "True", "FFlagAnalyzerGroupUIEnabled": "True", "DFFlagVariableHeartbeat": "True", "DFFlagScreenShotDuplicationFix": "True", "FFlagCSGDelayParentingOperationToEnd": "True", "FFlagStudioTreeWidgetCheckDeletingFlagWhenDoingUpdates": "True", "DFFlagUseComSiftUpdatedWebChatFilterParamsAndHeader": "False", "DFFlagConstructModerationFilterTextParamsAndHeadersUseLegacyFilterParams": "False", "FFlagMinMaxDistanceEnabled": "True", "FFlagRollOffModeEnabled": "True", "DFFlagGetLocalTeleportData": "True", "FFlagUseNewXboxLoginFlow": "True", "DFFlagFixSlowLadderClimb": "True", "DFFlagHumanoidCheckForNegatives": "True", "DFFlagFixMatrixToAxisAngle": "True", "DFFlagMaskWeightCleared": "True", "DFFlagUseStarterPlayerCharacterScripts": "True", "DFFlagUseStarterPlayerHumanoid": "True", "DFFlagAccessoriesAndAttachments": "True", "FFlagTeamCreateOptimizeRemoteSelection": "True", "FFlagReportInGameAssetSales": "True", "FFlagFilterDoublePass": "False", "DFFlagRaiseSendPriority": "False", "FFlagUsePreferredSoundDevice": "True", "FFlagRenderLowLatencyLoop": "False", "DFFlagLocalScriptSpawnPartAlwaysSetOwner": "True", "DFFlagCloudEditSupportImmediatePublish": "True", "FFlagFixSurfaceGuiGamepadNav": "True", "DFFlagEnableAdColony": "False", "FFlagEnableAdServiceVideoAds": "False", "DFFlagInfluxDb09Enabled": "True", "DFFlagTeleportSignalConnectOnServiceProvider": "True", "DFFlagScriptContextGuardAgainstCStackOverflow": "True", "FFlagFixPhysicalPropertiesComponentSet": "True", "DFFlagMaterialPropertiesDivideByZeroWeights": "True", "FFlagRemoveUnusedPhysicsSenders": "True", "FFlagRemoveInterpolationReciever": "True", "DFFlagActivatePGSMechanicalJoints": "True", "FIntPhysicalPropDensity_ALUMINUM_MATERIAL": "2700", "FFlagTreatCloudEditAsEditGameMode": "True", "FFlagSendFilteredExceptionOnInferredStep": "True", "DFFlagUrlReconstructToAssetGameSecure": "False", "DFFlagUseModerationFilterTextV2": "True", "FFlagGraphicsD3D10": "True", "FFlagRenderFixFog": "True", "FFlagUseNewAppBridgeWindows": "True", "DFFlagNullCheckJointStepWithNullPrim": "True", "FFlagJNIEnvScopeOptimization": "True", "DFFlagSanitizeLoadingGUICorrected": "True", "FFlagSendLegacyMachineConfigInfo": "False", "FFlagUseNewBadgesCreatePage": "True", "FFlagRetryWhenCloudEditEnabledEndpointFails": "True", "DFFlagTeamCreateDoNotReplicateShowDevGuiProp": "True", "FFlagStudioAddBackoffToNotificationsReconnects": "True", "DFFlagInsertServiceForceLocalInTeamCreate": "True", "FFlagGraphicsMacFix": "True", "FFlagUseNewAppBridgeOSX": "True", "FFlagNewColor3Functions": "True", "DFFlagSmootherVehicleSeatControlSystem": "True", "FFlagGameExplorerUseV2AliasEndpoint": "True", "FFlagDisableAbortRender": "True", "DFFlagInstancePredeleteNuke": "True", "DFFlagSimpleHermiteSplineInterpolate": "False", "DFFlagCleanUpInterpolationTimestamps": "True", "SFFlagPhysicsPacketSendWorldStepTimestamp": "True", "DFFlagUpdateTimeOnDelayedSamples": "False", "DFFlagDisableMovementHistory": "True", "DFFlagLookForDuplicateCoordinateFrameInBuffer": "True", "DFFlagDoNotForwardClientTimestamp": "True", "DFFlagZeroVelocityOnDelayedSamples": "True", "DFFlagUpdateHermiteLastFrameWhenUpdatePrevFrame": "True", "DFFlagCatchThrottledVelocityComponents": "True", "DFIntThrottledVelocityThresholdTenths": "15", "DFFlagShowFormFactorDeprecatedWarning": "False", "FFlagStudioTeamCreateWebChatBackendEnabled": "True", "DFFlagAnimationEasingStylesEnabled": "True", "FFlagUseVRKeyboardInLua": "True", "DFFlagCheckDataModelOnTeleportRetry": "True", "DFStringHttpInfluxWriterPassword": "faster1Play", "DFFlagOptimizeAnimator": "True", "FFlagOptimizeAnimatorCalcJoints": "True", "DFFlagStopUsingMaskWeight": "True", "FFlagRenderNoDepthLast": "True", "DFFlagFixTimeStampsForRunningNoThrottle": "True", "DFIntInterpolationDelayFactorTenths": "10", "DFFlagUseHermiteSplineInterpolation": "True", "DFFlagChatServiceFilterStringForPlayerFromAndToStudioBypass": "True", "FFlagCameraInterpolateMethodEnhancement": "False", "DFFlagBlendPosesWithIsOver": "True", "FFlagRestrictSales": "True", "FFlagBadTypeOnPcallEnabled": "True", "FFlagFixMouseFireOnEmulatingTouch": "True", "FFlagUseUpdatedSyntaxHighlighting": "True", "FFlagFixStickyDragBelowOrigin": "True", "FFlagFixBadMemoryOnStreamingGarbageCollection": "True", "DFFlagFixAllCharacterStreaming": "True", "FFlagDisableChangedServiceInTestMode": "True", "FFlagAllowFullColorSequences": "True", "FFlagStudioAllowFullColorSequences": "True", "DFFlagDynamicGravity": "True", "FFlagUseNewAppBridgeAndroid": "True", "FFlagFixSurfaceGuiGazeSelect": "True", "FFlagFixAlwaysOnTopSurfaceGuiInput": "True", "DFFlagCSGPreventCrashesWhenPartOperationsNotInDataModel": "True", "DFFlagUsePointsNewBatchingImpl": "True", "FFlagUseUpdatedKeyboardSettings": "False", "DFFlagFixAnimationControllerAnimator": "True", "DFFlagNoAnimationTrackState": "True", "DFFlagFixNestedAnimators": "True", "DFFlagWaitForToolHandleToEquip": "True", "DFFlagUseNewFetchFriendsFunction": "True", "FFlagWindowsNoDmpRetry": "False", "FFlagDeleteLogsOnMac": "True", "FFlagDeleteLogsByDate": "True", "FFlagTestMenuEnabledOnAllWindows": "True", "FFlagSoundServiceGameConfigurerConfigureRunServiceRun": "True", "DFFlagDoUpdateStepDetachedChannels": "True", "FFlagSoundChannelMaxDistanceStopFMODChannel": "True", "FFlagRenderSoftParticles": "True", "FFlagScriptContextSinglePendingThreadsQueue": "False", "DFIntTeleportExceptionInfluxHundredthsPercentage": "9000", "FIntStartupInfluxHundredthsPercentage": "100", "FFlagCSGAllowUnorderedProperties": "False", "DFFlagGamepadProcessMouseEvents": "False", "DFFlagCrashTouchTransmitterIfRefDtor": "False", "FFlagRenderUserGuiIn3DSpace": "True", "FFlagScreenGuisClipDescendants": "True", "FFlagUseNewNotificationPathLua": "True", "FFlagVideoDocumentationPluginEnabled": "True", "FFlagStudioBreakOnInfiniteLoops": "True", "FFlagMessageOnLoadScriptValidationFail": "True", "FFlagStudioMockPurchasesEnabled": "True", "FFlagStudioUseMarketplaceApiClient": "True", "DFFlagUseGameAvatarTypeEnum": "False", "FFlagStudioUsePlaySoloConfigurer": "True", "DFFlagUseAvatarFetchAPI": "False", "DFFlagSetHumanoidRegardlessOfNetworkOwnership": "True", "FFlagFixStudioCursorJitter": "True", "FFlagVoxelCompressedStorage": "True", "FFlagSmoothTerrainLODEnabled": "True", "FFlagBetterTabManagement": "True", "DFFlagBlockCustomHttpHeaders": "False", "FFlagStudioInsertAtTopCenterOfSelection": "True", "DFFlagCloudEditRemoveEditorOnPlayerRemove": "True", "FFlagWaitForChildTimeOut": "True", "FFlagDeviceEmulationStatistics": "True", "FFlagFixBoxSelectWithCtrl": "True", "FFlagStudioTrimPropertyWhitespace": "True", "FFlagDebugCSGExportFailure": "False", "FFlagFixCrashOnEmptyTextOnAutoComplete": "True", "FFlagCancelInputOnGuiNavigation": "True", "FFlagRemoveOldAnalyticsImplementation": "True", "FFlagRemoveOldCountersImplementation": "True", "FFlagUseNewAppBridgeStudio": "True", "FFlagStudioAnalyticsRefactoring": "True", "DFFlagRCCUseMarketplaceApiClient": "False", "FFlagStudioIntellesenseOnAllMembersEnabled": "True", "DFFlagDataStoreDisableReFetchingRecentKeys": "True", "FFlagNewDefaultScriptSource": "True", "FFlagStudioEnableDebuggerPerfImprovements": "True", "FFlagRecordForceStereo": "True", "FFlagStudioVideoRecordFix": "True", "FFlagStudioUseHttpsForUserInfo": "True", "FFlagUseHttpsForGameserverAshx": "True", "FFlagDisableScriptContextScriptsDisabled": "True", "DFFlagDuplicateInstanceReferenceFix": "True", "FFlagRakNetSupportIpV6": "False", "FFlagUseToStringN": "True", "FFlagStudioRenderRemotePlayerSelection": "True", "FFlagStackTraceLinks": "True", "FFlagStudioUpdateRestoreBehavior": "True", "FFlagTouchTransmitterWeakPtr": "True", "FFlagAdvancedRCCLoadFMODRetry": "True", "FFlagAdvancedRCCLoadFMODReportDeviceInfo": "True", "FFlagAdvancedRCCLoadFMODAttemptReportDeviceInfoOnFailure": "True", "FFlagClientLoadFMODReportDeviceInfo": "True", "DFIntReportDeviceInfoRate": "100", "DFFlagSoundV2LogOnSetSoundId": "True", "FFlagMouseUseUserInputServiceMouse": "True", "SFFlagSoundChannelUseV2Implementation": "True", "SFFlagUseNewSetFMOD3D": "True", "FFlagCSGReportSuccessFailure": "True", "FFlagUseAvatarFetchThumbnailLogic": "True", "FFlagDoIncrementalLoadingForR6AvatarFetch": "True", "FFlagUseAvatarFetchAPI": "True", "FFlagUseGameAvatarTypeEnum": "True", "FFlagSmoothTerrainLODFalseCoarseNeighbor": "True", "FFlagStudioPublishToRobloxActionUXAlwaysAvailable": "True", "FFlagFixArraysNotUnmarkedFromCyclicTableDetection": "True", "FFlagSoundIgnoreReplicatorJoinDataItemCache": "True", "FFlagStudioReportCachedRecentActions": "True", "FFlagStudioCacheRecentAction": "True", "FFlagRenderMeshReturnsCorrectly": "False", "FFlagEnableRenderCSGTrianglesDebug": "False", "FFlagStudioBreakOnInfiniteLoopsThreadingFixEnabled": "True", "SFFlagNetworkStreamRotationAsFloat": "False", "DFFlagStarterGuiMethodsWarnServer": "True", "DFFlagStarterGuiPropertiesReplicate": "True", "DFFlagClickDetectorReplicate": "True", "FFlagTeleportDetailedInfluxHttpStatusError": "True", "DFFlagHttpStatusCodeErrorIncludeBody": "True", "FFlagEnableVoiceASR": "False", "DFFlagFMODSetAccurateTime": "True", "FFlagRenderFixGuiOrder": "True", "FFlagExplosionsVisiblePropertyEnabled": "True", "FFlagEnableVoiceRecording": "False", "FFlagStudioReopenClosedTabsShortcut": "True", "FFlagStudioShowNotSavingScriptEditsOnce": "True", "FFlagHttpCurlCacheHandles": "True", "DFFlagAvatarFetchCanLoadCharacterAppearanceFix": "True", "FFlagGraphicsTextureCommitChanges": "False", "DFFlagLoadInstancesAsyncUseDataModelTasks": "False", "DFFlagInfluxOverUDP": "True", "FFlagUseLegacyEnumItemLookup": "True", "DFFlagInfluxOverTCP": "False", "DFFlagCFrameRightAndUpVectors": "True", "DFFlagLegacyBodyColorsOnCharacterLoadFailure": "True", "DFFlagUseMeshPartR15": "True", "FFlagStudioFixLockingScriptDisablesMenuOptions": "True", "FFlagUseCorrectDoppler": "True", "DFFlagFixJumpRequestOnLand": "True", "DFFlagNullStarterCharacterPrimaryPartFix": "True", "SFFlagR15CompositingEnabled": "True", "FFlagStudioFixPropertiesWindowScrollBarNotShowing": "True", "FFlagFixCollisionFidelityTeamCreate": "True", "DFFlagSendHttpBodyOnFailure": "True", "DFFlagCSGPreventNoContextCSGCrashes": "False", "FFlagConstraintPropertyReplicationRaceConditionFixEnabled": "True", "FFlagFixLogCulling": "True", "FFlagSmoothTerrainLODFixSeams": "True", "DFFlagDontCacheHumanoids": "True", "FFlagStudioPlaySoloConfigurerLegacyPlayerName": "True", "DFFlagPartForRegion3NoMaxLimit": "True", "FFlagRCCSupportTeamTest": "True", "FFlagStudioSupportBytecodeDeserialize": "True", "DFFlagStackTraceHasNewLines": "True", "DFFlagCleanCacheMoveMutex": "True", "FFlagFastFontMeasure": "False", "FFlagRenderMoreFonts": "True", "FFlagCleanFilteringEnabledLocalSpawnParts": "True", "FFlagFetchJoinScriptWithHttp": "False", "FFlagCheckPlayerProcessMutexCreation": "True", "FFlagCheckRegisterSoundChannelUniqueness": "True", "FFlagUseCommonModules": "True", "DFFlagRemoteFixDisconnectedPlayer": "True", "FFlagWarnForLegacyTerrain": "True", "FFlagFastClusterDisableReuse": "True", "FFlagStudioRespectMeshOffset": "False", "DFFlagRevisedClientJoinMetrics": "True", "FFlagRestoreScriptSourceWhenRedoingScriptCreation": "True", "DFFlagStudioFixPastingDecalsIntoMultiple": "True", "FFlagMeshPartMaterialTextureSupport": "True", "FFlagStudioPlaySoloCharacterAutoLoadsNullTool": "True", "DFFlagPGSWakeOtherIfOneAssemblyIsAwake": "False", "DFFlagFixR15BodyPhysics": "True", "FFlagLoadCharacterSoundFromCorescriptsRepo": "True", "DFFlagSoundV2LoadUseParamContext": "True", "DFFlagSoundV2LoadedRunCallbacks": "True", "FFlagFixPlayerProcessMutexDeadlock": "True", "FFlagImprovedJoinScriptFlow": "True", "FFlagRCCLoadFMOD": "True", "FFlagStudioDeadCodeOnMouseDown": "True", "DFFlagFireCharacterAddedAfterSpawn": "False", "FFlagChatVisiblePropertyEnabled": "True", "FFlagChatLayoutChange": "False", "FFlagCorescriptNewLoadChat": "True", "DFLogLuaTypeErrors": "4", "DFFlagLuaInstanceBridgeNewCamelCaseFixerEnabled": "True", "FFlagConstraintUIEnabled": "True", "FFlagStudioSetObjectsFromPropertiesWindow": "True", "FFlagStudioPromptWhenInsertingConstraints": "True", "DFFlagFixExperimentalSolverSetter": "True", "DFFlagShowRedForAutoJointsForPartsWithConstraint": "True", "FFlagTrackOriginalClientID": "True", "FFlagStudioHiddenPropertyCrashFixEnabled": "True", "FFlagStudioPropertyChangedSignalHandlerFix": "True", "FFlagStudioScriptAnalysisGetOrCreateRefactoring": "True", "DFFlagAllowHttpServiceInTeamCreate": "True", "DFFlagAllowRequireByAssetIdInTeamCreate": "True", "DFFlagLuaSignalCamelCaseAPI": "True", "FFlagFixLogManagerWritingToTempDir": "True", "FFlagTrackModuleScripts": "True", "FFlagUserJumpButtonPositionChange": "True", "FFlagLoadCommonModules": "True", "FFlagMouseCommandChangedSignalEnabled": "True", "DFIntInfluxTattletalePerUserHundredthsPercent": "1", "DFIntInfluxTattletalePerEventHundredthsPercent": "2000", "DFIntInfluxTattletaleCooldownSeconds": "300", "DFFlagSendHttpInfluxDatabaseField": "True", "FFlagGraphicsD3D11HandleDeviceRemoved": "True", "FFlagFixPlayerProcessMutexDeadlockForReal": "True", "FFlagNetworkKeepItemPools": "True", "FLogNetworkItemQueueDtor": "1", "FFlagFixLoadingScreenAngle": "False", "FFlagFixStudioInGamePaste": "True", "FFlagStudioSetViewportSizeOfClone": "True", "FFlagStudioTreeWidgetPotentialMemoryLeak": "True", "FFlagStudioEnableLayersForNSView": "True", "FFlagEnableViewportScaling": "True", "FFlagStudioDisableScrollingOnEarlyMac": "True", "FFlagPerformanceStatsCollectionEnabled": "True", "FFlagStudioStopSoundPlaybackAfterRemoval": "True", "FFlagStudioAllowSoundDraggingFromToolbox": "True", "FFlagStudioRelocateSoundJob": "True", "FFlagLuaDebugProfileEnabled": "True", "FFlagRemoveSoundServiceSoundDisabledProperty": "True", "FFlagRecordInGameDeaths": "False", "FFlagStudio3DGridUseAALines": "False", "FFlagFixIsCurrentlyVisibleSurfaceGuis": "True", "FFlagSurfaceGuiObjectEnabledCheck": "True", "FStringPlaceFilter_InterpolationAwareTargetTime": "True;249779150;333368740;444708274;64542766;248207867;171391948;360589910;388599755;163865146;127243303;162537373;6597705;332248116;348681325;196235086;13822889;189707", "DFFlagUseR15Character3": "True", "DFFlagAllowCustomR15Character": "True", "DFFlagFixDoubleJointR15Character": "True", "DFFlagFixR15SphereHead": "False", "DFFlagUseR15SwimFreestyle": "True", "DFFlagFixBodyColorsR15": "True", "DFFlagPlayerDescendantsDeleteOnDisconnectOff": "True", "DFFlagSpringConstraintInGameAdornFixEnabled": "True", "DFFlagDontPrintMalformedUrls": "True", "DFFlagUseMultiFormatCharacterAppearanceLoading": "True", "FFlagStudioFlycamAppBridgeFix": "True", "FFlagAllowCopyUnArchivableObjects": "True", "FFlagStudioReduceTeamCreateStuttering": "True", "DFFlagPGSSolverUsesIslandizableCode": "True", "DFFlagResetScreenGuiEnabled": "True", "FFlagGraphicsD3DPointOne": "True", "FFlagGraphicsNoMainDepth": "True", "FFlagCollectClientIDUpdateStatistics": "True", "FFlagStudioFixTestApis": "True", "FFlagAllowInsertConstrainedValuesAnywhere": "True", "FFlagStudioResizeMeshPartOnImport": "True", "FFlagStudioReportVitalParameters": "True", "FFlagSoundGroupsAndEffectsEnabled": "True", "FFlagSoundscapeReplicateChildren": "True", "FFlagLoadCorescriptsPlatformDefMode": "True", "FFlagEnableGetHitWhitelist": "True", "FFlagStudioUpdatePropertiesWithoutJob": "True", "FFlagOverrideTypeFunction": "True", "DFFlagEnableBindToClose": "True", "FFlagStudioFixUndeletingSoundCausesPlayback": "True", "FFlagServerSenderDontSendInterpolatedPhysics": "False", "FFlagGraphicsD3D9ComputeIndexRange": "True", "FFlagCrashOnScriptCloseFixEnabled": "True", "FFlagShowCoreGUIInExplorer": "True", "FFlagStudioUseServerConfigurer": "True", "FFlagUDim2LerpEnabled": "True", "FFlagDisableLayersForNSViewOnEarlyMac": "True", "FFlagStudioCorrectForRetinaScreensOnEarlyMac": "True", "FFlagStudioConsistentGuiInitalisation": "True", "FFlagStudioSanitizeInstancesOnLoad": "True", "FFlagStudioOnlyUpdateTeamTestActionsIfChanged": "True", "FFlagChatServiceReplicates": "True", "DFFlagICMPPingHundrethsPercentage": "100", "DFFlagUsePasiveOnlyForBind": "False", "DFFlagFavorIPV4Connections": "False", "DFFlagUsegetFamilyandMapAddress": "False", "FFlagBetterPlaceLauncherStatusHandling": "True", "FStringPlaceFilter_NewLayoutAndConstraintsEnabled": "True;534842009;20213796;379132413;485971234;515782100;248207867;360699282;498699944;540764930;534808604;520456996;552894983;551169796;560164377;599021441;609763195;609918169;599392478;614429353;337448601;615210477;606827239;19481228;19827397;26953764;561540866;20397851;626302497;402593749;589006000;461274216;129419469;478459751;460710135;464914388;481987774;610775332;567211827;636396993", "FFlagInformClientInsertFiltering": "True", "FStringClientInsertFilterMoreInfoUrl": "http://devforum.roblox.com/t/coming-changes-to-insert-service/30327", "FFlagSoundChannelOnAncestorChangedUseGameLaunchIntent": "True", "DFFlagAllowResetButtonCustomization": "True", "FFlagTattletaleFixTextValue": "True", "DFIntInfluxTattletaleInstancePathMaxLength": "200", "DFFlagFixRetriesExhaustedHandling": "True", "DFFlagBetterGetPlayerPlaceInstanceError": "True", "DFFlagCharacterScriptsLoadingRefactor": "True", "FFlagStudioPropertyWidgetRemoveUpdateEvents": "True", "FFlagStudioUserNotificationIgnoreSequenceNumber": "True", "FFlagStudioOnlyOneToolboxPreviewAtATime": "True", "FFlagStudioFixPauseDuringLoad": "True", "DFFlagStudioUseNewActiveToolEffect": "True", "FFlagGraphicsD3D11PickAdapter": "True", "FFlagChatFilterWorksLocally": "True", "FFlagFilterMessageWithCallbackNoTryCatch": "True", "FStringPlaceFilter_SetPhysicsToLastRealStateWhenBecomingOwner": "True;13822889;189707", "FFlagMetaliOS": "True", "FFlagUseNewAppBridgeIOS": "True", "FFlagTextBoundRespectTextScaled": "True", "FFlagRenderFastResolve": "True", "DFFlagLoadingGuiTeleportCrashFix": "True", "FFlagPluginSaveSelection": "True", "FFlagHandleSoundPreviewWidgetWithNoSelectedSound": "True", "FFlagDontSwallowInputForStudioShortcuts": "True", "FFlagStudioFireStickyMouseCommandChangedOnly": "True", "FFlagStudioDisableEditingCurrentEditor": "True", "FFlagFixCorruptionInLogFiles": "True", "FFlagStudioLockScriptsWithoutBlocking": "True", "FFlagSetPhysicsToLastRealStateWhenBecomingOwner": "True", "FFlagInterpolationAwareTargetTime": "True", "DFFlagServerSenderDontSendInterpolatedPhysics": "True", "FFlagSyncRenderingAndPhysicsInterpolation": "True", "DFIntTargetTimeDelayFacctorTenths": "20", "FFlagNewIncomingPhysicsManagement": "True", "DFFlagGetAssetIdsFromPackageAPI": "True", "DFFlagGoodbyeChoiceActiveProperty": "True", "FFlagAllowResizeRenderBufferiOS": "True", "FIntEnableAvatarEditoriOS": "100", "FIntEnableAvatarEditorAndroid": "1", "FIntAvatarEditorAndroidRollout": "1", "DFFlagFixScaledR15Physics": "True", "DFFlagScaleR15Character": "True", "FFlagCorescriptSetCoreChatActiveEnabled": "True", "FFlagOnlyShowHealthWhenDamaged": "True", "FFlagUserChatPrivacySetting": "True", "FFlagCorescriptNewChatSetCoresEnabled": "True"} diff --git a/2016/Microsoft.VC90.CRT/Microsoft.VC90.CRT.manifest b/2016/Microsoft.VC90.CRT/Microsoft.VC90.CRT.manifest new file mode 100644 index 0000000..41623b1 --- /dev/null +++ b/2016/Microsoft.VC90.CRT/Microsoft.VC90.CRT.manifest @@ -0,0 +1,13 @@ + + + + + + + diff --git a/2016/Microsoft.VC90.CRT/msvcm90.dll b/2016/Microsoft.VC90.CRT/msvcm90.dll new file mode 100644 index 0000000..b9cb123 Binary files /dev/null and b/2016/Microsoft.VC90.CRT/msvcm90.dll differ diff --git a/2016/Microsoft.VC90.CRT/msvcp90.dll b/2016/Microsoft.VC90.CRT/msvcp90.dll new file mode 100644 index 0000000..6b07c75 Binary files /dev/null and b/2016/Microsoft.VC90.CRT/msvcp90.dll differ diff --git a/2016/Microsoft.VC90.CRT/msvcr90.dll b/2016/Microsoft.VC90.CRT/msvcr90.dll new file mode 100644 index 0000000..a68249a Binary files /dev/null and b/2016/Microsoft.VC90.CRT/msvcr90.dll differ diff --git a/2016/Microsoft.VC90.MFC/Microsoft.VC90.MFC.manifest b/2016/Microsoft.VC90.MFC/Microsoft.VC90.MFC.manifest new file mode 100644 index 0000000..0184745 --- /dev/null +++ b/2016/Microsoft.VC90.MFC/Microsoft.VC90.MFC.manifest @@ -0,0 +1,13 @@ + + + + + + + diff --git a/2016/Microsoft.VC90.MFC/mfc90.dll b/2016/Microsoft.VC90.MFC/mfc90.dll new file mode 100644 index 0000000..31fb2b3 Binary files /dev/null and b/2016/Microsoft.VC90.MFC/mfc90.dll differ diff --git a/2016/Microsoft.VC90.MFC/mfcm90.dll b/2016/Microsoft.VC90.MFC/mfcm90.dll new file mode 100644 index 0000000..55b19e3 Binary files /dev/null and b/2016/Microsoft.VC90.MFC/mfcm90.dll differ diff --git a/2016/Microsoft.VC90.OPENMP/Microsoft.VC90.OpenMP.manifest b/2016/Microsoft.VC90.OPENMP/Microsoft.VC90.OpenMP.manifest new file mode 100644 index 0000000..213b1d7 --- /dev/null +++ b/2016/Microsoft.VC90.OPENMP/Microsoft.VC90.OpenMP.manifest @@ -0,0 +1,13 @@ + + + + + + + diff --git a/2016/Microsoft.VC90.OPENMP/vcomp90.dll b/2016/Microsoft.VC90.OPENMP/vcomp90.dll new file mode 100644 index 0000000..cf7c805 Binary files /dev/null and b/2016/Microsoft.VC90.OPENMP/vcomp90.dll differ diff --git a/2016/NPRobloxProxy.dll b/2016/NPRobloxProxy.dll new file mode 100644 index 0000000..07c98f6 Binary files /dev/null and b/2016/NPRobloxProxy.dll differ diff --git a/2016/NPRobloxProxy64.dll b/2016/NPRobloxProxy64.dll new file mode 100644 index 0000000..2a91d72 Binary files /dev/null and b/2016/NPRobloxProxy64.dll differ diff --git a/2016/PlatformContent/pc/terrain/diffuse.dds b/2016/PlatformContent/pc/terrain/diffuse.dds new file mode 100644 index 0000000..fcb9c55 Binary files /dev/null and b/2016/PlatformContent/pc/terrain/diffuse.dds differ diff --git a/2016/PlatformContent/pc/terrain/materials.json b/2016/PlatformContent/pc/terrain/materials.json new file mode 100644 index 0000000..65c2080 --- /dev/null +++ b/2016/PlatformContent/pc/terrain/materials.json @@ -0,0 +1,83 @@ +{ + "platform": "pc", + "atlas": + { + "pc": { + "width": 4096, + "height": 2048, + "tileSize": 512, + "tileCount": 6, + + "borderSize": 85 + }, + "ios": { + "width": 2048, + "height": 2048, + "tileSize": 384, + "tileCount": 4, + + "borderSize": 85 + }, + "android": { + "width": 2048, + "height": 2048, + "tileSize": 384, + "tileCount": 4, + + "borderSize": 85 + } + }, + "materials": + [ + { + "name": "Air" + }, + { + "name": "Water", + "water": 1.0 + }, + { + "name": "Grass", + "texture_top": { "tiling": 0.25, "detiling": 0.25 }, + "texture_side": { "tiling": 0.2, "detiling": 0.2 }, + "texture_bottom": { "tiling": 0.45, "detiling": 0.45 } + }, + { + "name": "Slate", + "shift": 0.1, + "texture": { "tiling": 0.55, "detiling": 0.55 } + }, + { + "name": "Concrete", + "quantize": 0.5, + "hard": true, + "texture_top": { "tiling": 0.5, "detiling": 0.8 }, + "texture_side": { "tiling": 0.5 } + }, + { + "name": "Brick", + "cubify": 1, + "hard": true, + "mapping": "cube", + "texture": { "tiling": 0.80, "detiling": 0.20 } + }, + { + "name": "Sand", + "texture_top": { "tiling": 0.25, "detiling": 0.25 }, + "texture_side": { "tiling": 0.25, "detiling": 0.25 } + }, + { + "name": "WoodPlanks", + "cubify": 1.0, + "hard": true, + "mapping": "cube", + "texture": { "tiling": 0.8, "detiling": 0.5 } + }, + { + "name": "Rock", + "shift": 0.3, + "hard": true, + "texture": { "tiling": 0.55, "detiling": 0.55 } + } + ] +} diff --git a/2016/PlatformContent/pc/terrain/normal.dds b/2016/PlatformContent/pc/terrain/normal.dds new file mode 100644 index 0000000..325db1e Binary files /dev/null and b/2016/PlatformContent/pc/terrain/normal.dds differ diff --git a/2016/PlatformContent/pc/terrain/specular.dds b/2016/PlatformContent/pc/terrain/specular.dds new file mode 100644 index 0000000..1a17980 Binary files /dev/null and b/2016/PlatformContent/pc/terrain/specular.dds differ diff --git a/2016/PlatformContent/pc/textures/aluminum/diffuse.dds b/2016/PlatformContent/pc/textures/aluminum/diffuse.dds new file mode 100644 index 0000000..fee64f0 Binary files /dev/null and b/2016/PlatformContent/pc/textures/aluminum/diffuse.dds differ diff --git a/2016/PlatformContent/pc/textures/aluminum/normal.dds b/2016/PlatformContent/pc/textures/aluminum/normal.dds new file mode 100644 index 0000000..466fcb4 Binary files /dev/null and b/2016/PlatformContent/pc/textures/aluminum/normal.dds differ diff --git a/2016/PlatformContent/pc/textures/aluminum/normaldetail.dds b/2016/PlatformContent/pc/textures/aluminum/normaldetail.dds new file mode 100644 index 0000000..818b2a8 Binary files /dev/null and b/2016/PlatformContent/pc/textures/aluminum/normaldetail.dds differ diff --git a/2016/PlatformContent/pc/textures/aluminum/specular.dds b/2016/PlatformContent/pc/textures/aluminum/specular.dds new file mode 100644 index 0000000..1cd4a27 Binary files /dev/null and b/2016/PlatformContent/pc/textures/aluminum/specular.dds differ diff --git a/2016/PlatformContent/pc/textures/brick/diffuse.dds b/2016/PlatformContent/pc/textures/brick/diffuse.dds new file mode 100644 index 0000000..a9f10fa Binary files /dev/null and b/2016/PlatformContent/pc/textures/brick/diffuse.dds differ diff --git a/2016/PlatformContent/pc/textures/brick/normal.dds b/2016/PlatformContent/pc/textures/brick/normal.dds new file mode 100644 index 0000000..1131f06 Binary files /dev/null and b/2016/PlatformContent/pc/textures/brick/normal.dds differ diff --git a/2016/PlatformContent/pc/textures/brick/normaldetail.dds b/2016/PlatformContent/pc/textures/brick/normaldetail.dds new file mode 100644 index 0000000..818b2a8 Binary files /dev/null and b/2016/PlatformContent/pc/textures/brick/normaldetail.dds differ diff --git a/2016/PlatformContent/pc/textures/brick/specular.dds b/2016/PlatformContent/pc/textures/brick/specular.dds new file mode 100644 index 0000000..58faad2 Binary files /dev/null and b/2016/PlatformContent/pc/textures/brick/specular.dds differ diff --git a/2016/PlatformContent/pc/textures/cobblestone/diffuse.dds b/2016/PlatformContent/pc/textures/cobblestone/diffuse.dds new file mode 100644 index 0000000..1ff6add Binary files /dev/null and b/2016/PlatformContent/pc/textures/cobblestone/diffuse.dds differ diff --git a/2016/PlatformContent/pc/textures/cobblestone/normal.dds b/2016/PlatformContent/pc/textures/cobblestone/normal.dds new file mode 100644 index 0000000..87e3a3f Binary files /dev/null and b/2016/PlatformContent/pc/textures/cobblestone/normal.dds differ diff --git a/2016/PlatformContent/pc/textures/cobblestone/normaldetail.dds b/2016/PlatformContent/pc/textures/cobblestone/normaldetail.dds new file mode 100644 index 0000000..818b2a8 Binary files /dev/null and b/2016/PlatformContent/pc/textures/cobblestone/normaldetail.dds differ diff --git a/2016/PlatformContent/pc/textures/cobblestone/specular.dds b/2016/PlatformContent/pc/textures/cobblestone/specular.dds new file mode 100644 index 0000000..423e0b4 Binary files /dev/null and b/2016/PlatformContent/pc/textures/cobblestone/specular.dds differ diff --git a/2016/PlatformContent/pc/textures/concrete/diffuse.dds b/2016/PlatformContent/pc/textures/concrete/diffuse.dds new file mode 100644 index 0000000..2174765 Binary files /dev/null and b/2016/PlatformContent/pc/textures/concrete/diffuse.dds differ diff --git a/2016/PlatformContent/pc/textures/concrete/normal.dds b/2016/PlatformContent/pc/textures/concrete/normal.dds new file mode 100644 index 0000000..dfd9bb8 Binary files /dev/null and b/2016/PlatformContent/pc/textures/concrete/normal.dds differ diff --git a/2016/PlatformContent/pc/textures/concrete/normaldetail.dds b/2016/PlatformContent/pc/textures/concrete/normaldetail.dds new file mode 100644 index 0000000..5c11a43 Binary files /dev/null and b/2016/PlatformContent/pc/textures/concrete/normaldetail.dds differ diff --git a/2016/PlatformContent/pc/textures/concrete/specular.dds b/2016/PlatformContent/pc/textures/concrete/specular.dds new file mode 100644 index 0000000..bfeb384 Binary files /dev/null and b/2016/PlatformContent/pc/textures/concrete/specular.dds differ diff --git a/2016/PlatformContent/pc/textures/diamondplate/diffuse.dds b/2016/PlatformContent/pc/textures/diamondplate/diffuse.dds new file mode 100644 index 0000000..e4f5f3a Binary files /dev/null and b/2016/PlatformContent/pc/textures/diamondplate/diffuse.dds differ diff --git a/2016/PlatformContent/pc/textures/diamondplate/normal.dds b/2016/PlatformContent/pc/textures/diamondplate/normal.dds new file mode 100644 index 0000000..88ece5f Binary files /dev/null and b/2016/PlatformContent/pc/textures/diamondplate/normal.dds differ diff --git a/2016/PlatformContent/pc/textures/diamondplate/normaldetail.dds b/2016/PlatformContent/pc/textures/diamondplate/normaldetail.dds new file mode 100644 index 0000000..818b2a8 Binary files /dev/null and b/2016/PlatformContent/pc/textures/diamondplate/normaldetail.dds differ diff --git a/2016/PlatformContent/pc/textures/diamondplate/specular.dds b/2016/PlatformContent/pc/textures/diamondplate/specular.dds new file mode 100644 index 0000000..9154362 Binary files /dev/null and b/2016/PlatformContent/pc/textures/diamondplate/specular.dds differ diff --git a/2016/PlatformContent/pc/textures/fabric/diffuse.dds b/2016/PlatformContent/pc/textures/fabric/diffuse.dds new file mode 100644 index 0000000..a0efd50 Binary files /dev/null and b/2016/PlatformContent/pc/textures/fabric/diffuse.dds differ diff --git a/2016/PlatformContent/pc/textures/fabric/normal.dds b/2016/PlatformContent/pc/textures/fabric/normal.dds new file mode 100644 index 0000000..ab1b6fd Binary files /dev/null and b/2016/PlatformContent/pc/textures/fabric/normal.dds differ diff --git a/2016/PlatformContent/pc/textures/fabric/normaldetail.dds b/2016/PlatformContent/pc/textures/fabric/normaldetail.dds new file mode 100644 index 0000000..818b2a8 Binary files /dev/null and b/2016/PlatformContent/pc/textures/fabric/normaldetail.dds differ diff --git a/2016/PlatformContent/pc/textures/fabric/specular.dds b/2016/PlatformContent/pc/textures/fabric/specular.dds new file mode 100644 index 0000000..e3c973d Binary files /dev/null and b/2016/PlatformContent/pc/textures/fabric/specular.dds differ diff --git a/2016/PlatformContent/pc/textures/granite/diffuse.dds b/2016/PlatformContent/pc/textures/granite/diffuse.dds new file mode 100644 index 0000000..bd67946 Binary files /dev/null and b/2016/PlatformContent/pc/textures/granite/diffuse.dds differ diff --git a/2016/PlatformContent/pc/textures/granite/normal.dds b/2016/PlatformContent/pc/textures/granite/normal.dds new file mode 100644 index 0000000..1a168d9 Binary files /dev/null and b/2016/PlatformContent/pc/textures/granite/normal.dds differ diff --git a/2016/PlatformContent/pc/textures/granite/normaldetail.dds b/2016/PlatformContent/pc/textures/granite/normaldetail.dds new file mode 100644 index 0000000..818b2a8 Binary files /dev/null and b/2016/PlatformContent/pc/textures/granite/normaldetail.dds differ diff --git a/2016/PlatformContent/pc/textures/granite/specular.dds b/2016/PlatformContent/pc/textures/granite/specular.dds new file mode 100644 index 0000000..aba04d5 Binary files /dev/null and b/2016/PlatformContent/pc/textures/granite/specular.dds differ diff --git a/2016/PlatformContent/pc/textures/grass/diffuse.dds b/2016/PlatformContent/pc/textures/grass/diffuse.dds new file mode 100644 index 0000000..c648fe4 Binary files /dev/null and b/2016/PlatformContent/pc/textures/grass/diffuse.dds differ diff --git a/2016/PlatformContent/pc/textures/grass/normal.dds b/2016/PlatformContent/pc/textures/grass/normal.dds new file mode 100644 index 0000000..829c341 Binary files /dev/null and b/2016/PlatformContent/pc/textures/grass/normal.dds differ diff --git a/2016/PlatformContent/pc/textures/grass/normaldetail.dds b/2016/PlatformContent/pc/textures/grass/normaldetail.dds new file mode 100644 index 0000000..818b2a8 Binary files /dev/null and b/2016/PlatformContent/pc/textures/grass/normaldetail.dds differ diff --git a/2016/PlatformContent/pc/textures/grass/specular.dds b/2016/PlatformContent/pc/textures/grass/specular.dds new file mode 100644 index 0000000..e47ed61 Binary files /dev/null and b/2016/PlatformContent/pc/textures/grass/specular.dds differ diff --git a/2016/PlatformContent/pc/textures/ice/diffuse.dds b/2016/PlatformContent/pc/textures/ice/diffuse.dds new file mode 100644 index 0000000..fee64f0 Binary files /dev/null and b/2016/PlatformContent/pc/textures/ice/diffuse.dds differ diff --git a/2016/PlatformContent/pc/textures/ice/normal.dds b/2016/PlatformContent/pc/textures/ice/normal.dds new file mode 100644 index 0000000..8752407 Binary files /dev/null and b/2016/PlatformContent/pc/textures/ice/normal.dds differ diff --git a/2016/PlatformContent/pc/textures/ice/normaldetail.dds b/2016/PlatformContent/pc/textures/ice/normaldetail.dds new file mode 100644 index 0000000..818b2a8 Binary files /dev/null and b/2016/PlatformContent/pc/textures/ice/normaldetail.dds differ diff --git a/2016/PlatformContent/pc/textures/ice/specular.dds b/2016/PlatformContent/pc/textures/ice/specular.dds new file mode 100644 index 0000000..4689e14 Binary files /dev/null and b/2016/PlatformContent/pc/textures/ice/specular.dds differ diff --git a/2016/PlatformContent/pc/textures/marble/diffuse.dds b/2016/PlatformContent/pc/textures/marble/diffuse.dds new file mode 100644 index 0000000..028e920 Binary files /dev/null and b/2016/PlatformContent/pc/textures/marble/diffuse.dds differ diff --git a/2016/PlatformContent/pc/textures/marble/normal.dds b/2016/PlatformContent/pc/textures/marble/normal.dds new file mode 100644 index 0000000..ba3641b Binary files /dev/null and b/2016/PlatformContent/pc/textures/marble/normal.dds differ diff --git a/2016/PlatformContent/pc/textures/marble/normaldetail.dds b/2016/PlatformContent/pc/textures/marble/normaldetail.dds new file mode 100644 index 0000000..818b2a8 Binary files /dev/null and b/2016/PlatformContent/pc/textures/marble/normaldetail.dds differ diff --git a/2016/PlatformContent/pc/textures/marble/specular.dds b/2016/PlatformContent/pc/textures/marble/specular.dds new file mode 100644 index 0000000..d2a1c7e Binary files /dev/null and b/2016/PlatformContent/pc/textures/marble/specular.dds differ diff --git a/2016/PlatformContent/pc/textures/metal/diffuse.dds b/2016/PlatformContent/pc/textures/metal/diffuse.dds new file mode 100644 index 0000000..a1f7fd2 Binary files /dev/null and b/2016/PlatformContent/pc/textures/metal/diffuse.dds differ diff --git a/2016/PlatformContent/pc/textures/metal/normal.dds b/2016/PlatformContent/pc/textures/metal/normal.dds new file mode 100644 index 0000000..c4e5757 Binary files /dev/null and b/2016/PlatformContent/pc/textures/metal/normal.dds differ diff --git a/2016/PlatformContent/pc/textures/metal/normaldetail.dds b/2016/PlatformContent/pc/textures/metal/normaldetail.dds new file mode 100644 index 0000000..818b2a8 Binary files /dev/null and b/2016/PlatformContent/pc/textures/metal/normaldetail.dds differ diff --git a/2016/PlatformContent/pc/textures/metal/specular.dds b/2016/PlatformContent/pc/textures/metal/specular.dds new file mode 100644 index 0000000..98a9f60 Binary files /dev/null and b/2016/PlatformContent/pc/textures/metal/specular.dds differ diff --git a/2016/PlatformContent/pc/textures/pebble/diffuse.dds b/2016/PlatformContent/pc/textures/pebble/diffuse.dds new file mode 100644 index 0000000..48b56cc Binary files /dev/null and b/2016/PlatformContent/pc/textures/pebble/diffuse.dds differ diff --git a/2016/PlatformContent/pc/textures/pebble/normal.dds b/2016/PlatformContent/pc/textures/pebble/normal.dds new file mode 100644 index 0000000..818b2a8 Binary files /dev/null and b/2016/PlatformContent/pc/textures/pebble/normal.dds differ diff --git a/2016/PlatformContent/pc/textures/pebble/normaldetail.dds b/2016/PlatformContent/pc/textures/pebble/normaldetail.dds new file mode 100644 index 0000000..5c11a43 Binary files /dev/null and b/2016/PlatformContent/pc/textures/pebble/normaldetail.dds differ diff --git a/2016/PlatformContent/pc/textures/pebble/specular.dds b/2016/PlatformContent/pc/textures/pebble/specular.dds new file mode 100644 index 0000000..bfeb384 Binary files /dev/null and b/2016/PlatformContent/pc/textures/pebble/specular.dds differ diff --git a/2016/PlatformContent/pc/textures/plastic/diffuse.dds b/2016/PlatformContent/pc/textures/plastic/diffuse.dds new file mode 100644 index 0000000..b6f626e Binary files /dev/null and b/2016/PlatformContent/pc/textures/plastic/diffuse.dds differ diff --git a/2016/PlatformContent/pc/textures/plastic/normal.dds b/2016/PlatformContent/pc/textures/plastic/normal.dds new file mode 100644 index 0000000..41210c9 Binary files /dev/null and b/2016/PlatformContent/pc/textures/plastic/normal.dds differ diff --git a/2016/PlatformContent/pc/textures/plastic/normaldetail.dds b/2016/PlatformContent/pc/textures/plastic/normaldetail.dds new file mode 100644 index 0000000..b29ac42 Binary files /dev/null and b/2016/PlatformContent/pc/textures/plastic/normaldetail.dds differ diff --git a/2016/PlatformContent/pc/textures/rust/diffuse.dds b/2016/PlatformContent/pc/textures/rust/diffuse.dds new file mode 100644 index 0000000..abd195a Binary files /dev/null and b/2016/PlatformContent/pc/textures/rust/diffuse.dds differ diff --git a/2016/PlatformContent/pc/textures/rust/normal.dds b/2016/PlatformContent/pc/textures/rust/normal.dds new file mode 100644 index 0000000..f65fb72 Binary files /dev/null and b/2016/PlatformContent/pc/textures/rust/normal.dds differ diff --git a/2016/PlatformContent/pc/textures/rust/normaldetail.dds b/2016/PlatformContent/pc/textures/rust/normaldetail.dds new file mode 100644 index 0000000..818b2a8 Binary files /dev/null and b/2016/PlatformContent/pc/textures/rust/normaldetail.dds differ diff --git a/2016/PlatformContent/pc/textures/rust/specular.dds b/2016/PlatformContent/pc/textures/rust/specular.dds new file mode 100644 index 0000000..9c3133e Binary files /dev/null and b/2016/PlatformContent/pc/textures/rust/specular.dds differ diff --git a/2016/PlatformContent/pc/textures/sand/diffuse.dds b/2016/PlatformContent/pc/textures/sand/diffuse.dds new file mode 100644 index 0000000..5b91413 Binary files /dev/null and b/2016/PlatformContent/pc/textures/sand/diffuse.dds differ diff --git a/2016/PlatformContent/pc/textures/sand/normal.dds b/2016/PlatformContent/pc/textures/sand/normal.dds new file mode 100644 index 0000000..4e8c7fa Binary files /dev/null and b/2016/PlatformContent/pc/textures/sand/normal.dds differ diff --git a/2016/PlatformContent/pc/textures/sand/normaldetail.dds b/2016/PlatformContent/pc/textures/sand/normaldetail.dds new file mode 100644 index 0000000..818b2a8 Binary files /dev/null and b/2016/PlatformContent/pc/textures/sand/normaldetail.dds differ diff --git a/2016/PlatformContent/pc/textures/sand/specular.dds b/2016/PlatformContent/pc/textures/sand/specular.dds new file mode 100644 index 0000000..6efec1b Binary files /dev/null and b/2016/PlatformContent/pc/textures/sand/specular.dds differ diff --git a/2016/PlatformContent/pc/textures/sky/sky512_bk.tex b/2016/PlatformContent/pc/textures/sky/sky512_bk.tex new file mode 100644 index 0000000..fcdd232 Binary files /dev/null and b/2016/PlatformContent/pc/textures/sky/sky512_bk.tex differ diff --git a/2016/PlatformContent/pc/textures/sky/sky512_dn.tex b/2016/PlatformContent/pc/textures/sky/sky512_dn.tex new file mode 100644 index 0000000..d63e52d Binary files /dev/null and b/2016/PlatformContent/pc/textures/sky/sky512_dn.tex differ diff --git a/2016/PlatformContent/pc/textures/sky/sky512_ft.tex b/2016/PlatformContent/pc/textures/sky/sky512_ft.tex new file mode 100644 index 0000000..215b51b Binary files /dev/null and b/2016/PlatformContent/pc/textures/sky/sky512_ft.tex differ diff --git a/2016/PlatformContent/pc/textures/sky/sky512_lf.tex b/2016/PlatformContent/pc/textures/sky/sky512_lf.tex new file mode 100644 index 0000000..a096acf Binary files /dev/null and b/2016/PlatformContent/pc/textures/sky/sky512_lf.tex differ diff --git a/2016/PlatformContent/pc/textures/sky/sky512_rt.tex b/2016/PlatformContent/pc/textures/sky/sky512_rt.tex new file mode 100644 index 0000000..6c0aaf1 Binary files /dev/null and b/2016/PlatformContent/pc/textures/sky/sky512_rt.tex differ diff --git a/2016/PlatformContent/pc/textures/sky/sky512_up.tex b/2016/PlatformContent/pc/textures/sky/sky512_up.tex new file mode 100644 index 0000000..a973654 Binary files /dev/null and b/2016/PlatformContent/pc/textures/sky/sky512_up.tex differ diff --git a/2016/PlatformContent/pc/textures/slate/diffuse.dds b/2016/PlatformContent/pc/textures/slate/diffuse.dds new file mode 100644 index 0000000..ff7ca6d Binary files /dev/null and b/2016/PlatformContent/pc/textures/slate/diffuse.dds differ diff --git a/2016/PlatformContent/pc/textures/slate/normal.dds b/2016/PlatformContent/pc/textures/slate/normal.dds new file mode 100644 index 0000000..6f38346 Binary files /dev/null and b/2016/PlatformContent/pc/textures/slate/normal.dds differ diff --git a/2016/PlatformContent/pc/textures/slate/normaldetail.dds b/2016/PlatformContent/pc/textures/slate/normaldetail.dds new file mode 100644 index 0000000..7e6b0ca Binary files /dev/null and b/2016/PlatformContent/pc/textures/slate/normaldetail.dds differ diff --git a/2016/PlatformContent/pc/textures/slate/specular.dds b/2016/PlatformContent/pc/textures/slate/specular.dds new file mode 100644 index 0000000..271b6c1 Binary files /dev/null and b/2016/PlatformContent/pc/textures/slate/specular.dds differ diff --git a/2016/PlatformContent/pc/textures/studs.dds b/2016/PlatformContent/pc/textures/studs.dds new file mode 100644 index 0000000..04f458c Binary files /dev/null and b/2016/PlatformContent/pc/textures/studs.dds differ diff --git a/2016/PlatformContent/pc/textures/terrain/diffuse.dds b/2016/PlatformContent/pc/textures/terrain/diffuse.dds new file mode 100644 index 0000000..26b370d Binary files /dev/null and b/2016/PlatformContent/pc/textures/terrain/diffuse.dds differ diff --git a/2016/PlatformContent/pc/textures/terrain/diffusefar.dds b/2016/PlatformContent/pc/textures/terrain/diffusefar.dds new file mode 100644 index 0000000..657e10b Binary files /dev/null and b/2016/PlatformContent/pc/textures/terrain/diffusefar.dds differ diff --git a/2016/PlatformContent/pc/textures/terrain/normal.dds b/2016/PlatformContent/pc/textures/terrain/normal.dds new file mode 100644 index 0000000..a64ba4a Binary files /dev/null and b/2016/PlatformContent/pc/textures/terrain/normal.dds differ diff --git a/2016/PlatformContent/pc/textures/terrain/specular.dds b/2016/PlatformContent/pc/textures/terrain/specular.dds new file mode 100644 index 0000000..82bc31f Binary files /dev/null and b/2016/PlatformContent/pc/textures/terrain/specular.dds differ diff --git a/2016/PlatformContent/pc/textures/wangIndex.dds b/2016/PlatformContent/pc/textures/wangIndex.dds new file mode 100644 index 0000000..e613ff1 Binary files /dev/null and b/2016/PlatformContent/pc/textures/wangIndex.dds differ diff --git a/2016/PlatformContent/pc/textures/water/normal_01.dds b/2016/PlatformContent/pc/textures/water/normal_01.dds new file mode 100644 index 0000000..d3ba9cc Binary files /dev/null and b/2016/PlatformContent/pc/textures/water/normal_01.dds differ diff --git a/2016/PlatformContent/pc/textures/water/normal_02.dds b/2016/PlatformContent/pc/textures/water/normal_02.dds new file mode 100644 index 0000000..012bf30 Binary files /dev/null and b/2016/PlatformContent/pc/textures/water/normal_02.dds differ diff --git a/2016/PlatformContent/pc/textures/water/normal_03.dds b/2016/PlatformContent/pc/textures/water/normal_03.dds new file mode 100644 index 0000000..343de72 Binary files /dev/null and b/2016/PlatformContent/pc/textures/water/normal_03.dds differ diff --git a/2016/PlatformContent/pc/textures/water/normal_04.dds b/2016/PlatformContent/pc/textures/water/normal_04.dds new file mode 100644 index 0000000..19a6276 Binary files /dev/null and b/2016/PlatformContent/pc/textures/water/normal_04.dds differ diff --git a/2016/PlatformContent/pc/textures/water/normal_05.dds b/2016/PlatformContent/pc/textures/water/normal_05.dds new file mode 100644 index 0000000..721320d Binary files /dev/null and b/2016/PlatformContent/pc/textures/water/normal_05.dds differ diff --git a/2016/PlatformContent/pc/textures/water/normal_06.dds b/2016/PlatformContent/pc/textures/water/normal_06.dds new file mode 100644 index 0000000..1e13691 Binary files /dev/null and b/2016/PlatformContent/pc/textures/water/normal_06.dds differ diff --git a/2016/PlatformContent/pc/textures/water/normal_07.dds b/2016/PlatformContent/pc/textures/water/normal_07.dds new file mode 100644 index 0000000..5edd661 Binary files /dev/null and b/2016/PlatformContent/pc/textures/water/normal_07.dds differ diff --git a/2016/PlatformContent/pc/textures/water/normal_08.dds b/2016/PlatformContent/pc/textures/water/normal_08.dds new file mode 100644 index 0000000..14693e8 Binary files /dev/null and b/2016/PlatformContent/pc/textures/water/normal_08.dds differ diff --git a/2016/PlatformContent/pc/textures/water/normal_09.dds b/2016/PlatformContent/pc/textures/water/normal_09.dds new file mode 100644 index 0000000..5b161c7 Binary files /dev/null and b/2016/PlatformContent/pc/textures/water/normal_09.dds differ diff --git a/2016/PlatformContent/pc/textures/water/normal_10.dds b/2016/PlatformContent/pc/textures/water/normal_10.dds new file mode 100644 index 0000000..353590e Binary files /dev/null and b/2016/PlatformContent/pc/textures/water/normal_10.dds differ diff --git a/2016/PlatformContent/pc/textures/water/normal_11.dds b/2016/PlatformContent/pc/textures/water/normal_11.dds new file mode 100644 index 0000000..8e2c7a0 Binary files /dev/null and b/2016/PlatformContent/pc/textures/water/normal_11.dds differ diff --git a/2016/PlatformContent/pc/textures/water/normal_12.dds b/2016/PlatformContent/pc/textures/water/normal_12.dds new file mode 100644 index 0000000..5babefd Binary files /dev/null and b/2016/PlatformContent/pc/textures/water/normal_12.dds differ diff --git a/2016/PlatformContent/pc/textures/water/normal_13.dds b/2016/PlatformContent/pc/textures/water/normal_13.dds new file mode 100644 index 0000000..fdc82da Binary files /dev/null and b/2016/PlatformContent/pc/textures/water/normal_13.dds differ diff --git a/2016/PlatformContent/pc/textures/water/normal_14.dds b/2016/PlatformContent/pc/textures/water/normal_14.dds new file mode 100644 index 0000000..7ca5c06 Binary files /dev/null and b/2016/PlatformContent/pc/textures/water/normal_14.dds differ diff --git a/2016/PlatformContent/pc/textures/water/normal_15.dds b/2016/PlatformContent/pc/textures/water/normal_15.dds new file mode 100644 index 0000000..601ebdc Binary files /dev/null and b/2016/PlatformContent/pc/textures/water/normal_15.dds differ diff --git a/2016/PlatformContent/pc/textures/water/normal_16.dds b/2016/PlatformContent/pc/textures/water/normal_16.dds new file mode 100644 index 0000000..ae10be5 Binary files /dev/null and b/2016/PlatformContent/pc/textures/water/normal_16.dds differ diff --git a/2016/PlatformContent/pc/textures/water/normal_17.dds b/2016/PlatformContent/pc/textures/water/normal_17.dds new file mode 100644 index 0000000..86667b2 Binary files /dev/null and b/2016/PlatformContent/pc/textures/water/normal_17.dds differ diff --git a/2016/PlatformContent/pc/textures/water/normal_18.dds b/2016/PlatformContent/pc/textures/water/normal_18.dds new file mode 100644 index 0000000..3cd7cfb Binary files /dev/null and b/2016/PlatformContent/pc/textures/water/normal_18.dds differ diff --git a/2016/PlatformContent/pc/textures/water/normal_19.dds b/2016/PlatformContent/pc/textures/water/normal_19.dds new file mode 100644 index 0000000..01db6d4 Binary files /dev/null and b/2016/PlatformContent/pc/textures/water/normal_19.dds differ diff --git a/2016/PlatformContent/pc/textures/water/normal_20.dds b/2016/PlatformContent/pc/textures/water/normal_20.dds new file mode 100644 index 0000000..0fcdfa8 Binary files /dev/null and b/2016/PlatformContent/pc/textures/water/normal_20.dds differ diff --git a/2016/PlatformContent/pc/textures/water/normal_21.dds b/2016/PlatformContent/pc/textures/water/normal_21.dds new file mode 100644 index 0000000..2aa6e82 Binary files /dev/null and b/2016/PlatformContent/pc/textures/water/normal_21.dds differ diff --git a/2016/PlatformContent/pc/textures/water/normal_22.dds b/2016/PlatformContent/pc/textures/water/normal_22.dds new file mode 100644 index 0000000..3e91016 Binary files /dev/null and b/2016/PlatformContent/pc/textures/water/normal_22.dds differ diff --git a/2016/PlatformContent/pc/textures/water/normal_23.dds b/2016/PlatformContent/pc/textures/water/normal_23.dds new file mode 100644 index 0000000..91e13c6 Binary files /dev/null and b/2016/PlatformContent/pc/textures/water/normal_23.dds differ diff --git a/2016/PlatformContent/pc/textures/water/normal_24.dds b/2016/PlatformContent/pc/textures/water/normal_24.dds new file mode 100644 index 0000000..87bbbdf Binary files /dev/null and b/2016/PlatformContent/pc/textures/water/normal_24.dds differ diff --git a/2016/PlatformContent/pc/textures/water/normal_25.dds b/2016/PlatformContent/pc/textures/water/normal_25.dds new file mode 100644 index 0000000..a0a4b49 Binary files /dev/null and b/2016/PlatformContent/pc/textures/water/normal_25.dds differ diff --git a/2016/PlatformContent/pc/textures/wood/diffuse.dds b/2016/PlatformContent/pc/textures/wood/diffuse.dds new file mode 100644 index 0000000..941b70f Binary files /dev/null and b/2016/PlatformContent/pc/textures/wood/diffuse.dds differ diff --git a/2016/PlatformContent/pc/textures/wood/normal.dds b/2016/PlatformContent/pc/textures/wood/normal.dds new file mode 100644 index 0000000..aa3190c Binary files /dev/null and b/2016/PlatformContent/pc/textures/wood/normal.dds differ diff --git a/2016/PlatformContent/pc/textures/wood/normaldetail.dds b/2016/PlatformContent/pc/textures/wood/normaldetail.dds new file mode 100644 index 0000000..5630e27 Binary files /dev/null and b/2016/PlatformContent/pc/textures/wood/normaldetail.dds differ diff --git a/2016/PlatformContent/pc/textures/wood/specular.dds b/2016/PlatformContent/pc/textures/wood/specular.dds new file mode 100644 index 0000000..f5a8470 Binary files /dev/null and b/2016/PlatformContent/pc/textures/wood/specular.dds differ diff --git a/2016/PlatformContent/pc/textures/woodplanks/diffuse.dds b/2016/PlatformContent/pc/textures/woodplanks/diffuse.dds new file mode 100644 index 0000000..df819fd Binary files /dev/null and b/2016/PlatformContent/pc/textures/woodplanks/diffuse.dds differ diff --git a/2016/PlatformContent/pc/textures/woodplanks/normal.dds b/2016/PlatformContent/pc/textures/woodplanks/normal.dds new file mode 100644 index 0000000..5f4dcf9 Binary files /dev/null and b/2016/PlatformContent/pc/textures/woodplanks/normal.dds differ diff --git a/2016/PlatformContent/pc/textures/woodplanks/normaldetail.dds b/2016/PlatformContent/pc/textures/woodplanks/normaldetail.dds new file mode 100644 index 0000000..818b2a8 Binary files /dev/null and b/2016/PlatformContent/pc/textures/woodplanks/normaldetail.dds differ diff --git a/2016/PlatformContent/pc/textures/woodplanks/specular.dds b/2016/PlatformContent/pc/textures/woodplanks/specular.dds new file mode 100644 index 0000000..6a1371d Binary files /dev/null and b/2016/PlatformContent/pc/textures/woodplanks/specular.dds differ diff --git a/2016/ReflectionMetadata.xml b/2016/ReflectionMetadata.xml new file mode 100644 index 0000000..5032f05 --- /dev/null +++ b/2016/ReflectionMetadata.xml @@ -0,0 +1,3965 @@ + + + + + + BindableFunction + Allow functions defined in one script to be called by another script + 4 + 66 + + + + + + Invoke + Causes the function assigned to OnInvoke to be called. Arguments passed to this function get passed to OnInvoke function. + + + + + + + OnInvoke + Should be defined as a function. This function is called when Invoke() is called. Number of arguments is variable. + + + + + + + BindableEvent + Allow events defined in one script to be subscribed to by another script + + 5 + 67 + + + + + Fire + Used to make the custom event fire (see Event for more info). Arguments can be variable length. + + + + + + + Event + This event fires when the Fire() method is used. Receives the variable length arguments from Fire(). + + + + + + + TouchTransmitter + Used by networking and replication code to transmit touch events - no other purpose + + false + 3 + 37 + + + + + ForceField + Prevents joint breakage from explosions, and stops Humanoids from taking damage + 3 + 37 + + + + + PluginManager + + + + + + TeleportService + Allows players to seamlessly leave a game and join another + + + + + StudioTool + + + + + + Plugin + + + + + + PluginMouse + + + + + + Glue + + + + + CollectionService + + + + + JointsService + + + + + BadgeService + + + + + LogService + + + + + AssetService + A service used to set and get information about assets stored on the Roblox website. + + + + + RevertAsset + Reverts a given place id to the version number provided. Returns true if successful on reverting, false otherwise. + + + + + SetPlacePermissions + Sets the permissions for a placeID to the place accessType. An optional table (inviteList) can be included that will set the accessType for only the player names provided. The table should be set up as an array of usernames (strings). + + + + + GetPlacePermissions + Given a placeID, this function will return a table with the permissions of the place. Useful for determining what kind of permissions a particular user may have for a place. + + + + + GetAssetVersions + Given a placeID, this function will return a table with the version info of the place. An optional arg of page number can be used to page through all revisions (a single page may hold about 50 revisions). + + + + + GetCreatorAssetID + Given a creationID, this function will return the asset that created the creationID. If no other asset created the given creationID, 0 is returned. + + + + + + + HttpService + 101 + + + + + + HttpEnabled + true + Enabling http requests from scripts + + + + + + + InsertService + A service used to insert objects stored on the website into the game. + + + + + GetCollection + Returns a table for the assets stored in the category. A category is an setId from www.roblox.com that links to a set. <a href="http://wiki.roblox.com/index.php/GetCollection_(Method)" target="_blank">More info on table format</a>. <a href="http://wiki.roblox.com/index.php/Sets" target="_blank">More info on sets</a> + + + + + Insert + Inserts the Instance into the workspace. It is recommended to use Instance.Parent = game.Workspace instead, as this can cause issues currently. + + + + + ApproveAssetId + true + Deprecated + + + + + ApproveAssetVersionId + true + Deprecated + + + + + + + + GetBaseSets + Returns a table containing a list of the various setIds that are ROBLOX approved. <a href="http://wiki.roblox.com/index.php/Sets" target="_blank">More info on sets</a> + + + + + GetUserSets + Returns a table containing a list of the various setIds that correspond to argument 'userId'. <a href="http://wiki.roblox.com/index.php/Sets" target="_blank">More info on sets</a> + + + + + GetBaseCategories + true + Deprecated. Use GetBaseSets() instead. + + + + + GetUserCategories + true + Deprecated. Use GetUserSets() instead. + + + + + LoadAsset + Returns a Model containing the Instance that resides at AssetId on the web. This call will also yield the script until the model is returned. Script execution can still continue, however, if you use a <a href="http://wiki.roblox.com/index.php/Function_Dump/Coroutine_Manipulationcoroutine" target="_blank">coroutine</a>. + + + + + LoadAssetVersion + Similar to LoadAsset, but instead an AssetVersionId is passed in, which refers to a particular version of the asset which is not neccessarily the latest version. + + + + + + + Hat + 3 + 45 + + + + + LocalBackpack + + + + + LocalBackpackItem + + + + + MotorFeature + + + + + Mouse + Used to receive input from the user. Actually tracks mouse events and keyboard events. + + + + + Hit + The CoordinateFrame of where the Mouse ray is currently hitting a 3D object in the Workspace. If the mouse is not over any 3D objects in the Workspace, this property is nil. + + + + + Icon + The current Texture of the Mouse Icon. Stored as a string, for more information on how to format the string <a href="http://wiki.roblox.com/index.php/Content" target="_blank">go here</a> + + + + + Origin + The CoordinateFrame of where the Mouse is when the mouse is not clicking. + + + + + Origin + The CoordinateFrame of where the Mouse is when the mouse is not clicking. This CoordinateFrame will be very close to the Camera.CoordinateFrame. + + + + + Target + The Part the mouse is currently over. If the mouse is not currently over any object (on the skybox, for example) this property is nil. + + + + + TargetFilter + A Part or Model that the Mouse will ignore when trying to find the Target, TargetSurface and Hit. + + + + + TargetSurface + The NormalId (Top, Left, Down, etc.) of the face of the part the Mouse is currently over. + + + + + UnitRay + The Unit Ray from where the mouse is (Origin) to the current Mouse.Target. + + + + + ViewSizeX + The viewport's (game window) width in pixels. + + + + + ViewSizeY + The viewport's (game window) height in pixels. + + + + + X + The absolute pixel position of the Mouse along the x-axis of the viewport (game window). Values start at 0 on the left hand side of the screen and increase to the right. + + + + + Y + The absolute pixel position of the Mouse along the y-axis of the viewport (game window). Values start at 0 on the stop of the screen and increase to the bottom. + + + + + + + Button1Down + Fired when the first button (usually the left, but could be another) on the mouse is depressed. + + + + + Button1Up + Fired when the first button (usually the left, but could be another) on the mouse is release. + + + + + Button2Down + This event is currently non-operational. + + + + + Button2Up + This event is currently non-operational. + + + + + Idle + Fired constantly when the mouse is not firing any other event (i.e. the mouse isn't moving, nor any buttons being pressed or depressed). + + + + + KeyDown + Fired when a user presses a key on the keyboard. Argument is a string representation of the key. If the key has no string representation (such as space), the string passed in is the keycode for that character. Keycodes are currently in ASCII. + + + + + KeyUp + Fired when a user releases a key on the keyboard. Argument is a string representation of the key. If the key has no string representation (such as space), the string passed in is the keycode for that character. Keycodes are currently in ASCII. + + + + + Move + Fired when the mouse X or Y member changes. + + + + + WheelBackward + This event is currently non-operational. + + + + + WheelForward + This event is currently non-operational. + + + + + + + ProfilingItem + + + + + ChangeHistoryService + + + + + RotateP + + + + + RotateV + + + + + ScriptContext + + + + + Selection + + + + + VelocityMotor + + + + + Weld + 20 + 34 + + + + + TaskScheduler + + + + + SetThreadShare + true + Deprecated + + + + + + + StatsItem + + + + + Snap + + + + + FileMesh + + + + + + ClickDetector + Raises mouse events for parent object + 3 + 41 + + + + + MaxActivationDistance + The maximum distance a Player's character can be from the ClickDetector's parent Part that will allow the Player's mouse to fire events on this object. + + + + + + + MouseClick + Fired when a player clicks on the parent Part of ClickDetector. The argument provided is always of type Player. + + + + + MouseHoverEnter + Fired when a player's mouse enters on the parent Part of ClickDetector. The argument provided is always of type Player. + + + + + MouseHoverLeave + Fired when a player's mouse leaves the parent Part of ClickDetector. The argument provided is always of type Player. + + + + + + + + Clothing + 0 + + + + + + Smoke + Makes the parent part or model object emit smoke + 3 + 59 + + + + + + ParticleEmitter + A generic particle system. + 3 + 80 + + + + + + Sparkles + Makes the parent part or model object fantastic + 3 + 42 + + + + + Explosion + 3 + 36 + Creates an Explosion! This can be used as a purely graphical effect, or can be made to damage objects. + + + + + BlastPressure + How much force this Explosion exerts on objects within it's BlastRadius. Setting this to 0 creates a purely graphical effect. A larger number will cause Parts to fly away at higher velocities. + + + + + BlastRadius + How big the Explosion is. This is a circle starting from the center of the Explosion's Position, the larger this property the larger the circle of destruction. + + + + + Position + Where the Explosion occurs in absolute world coordinates. + + + + + ExplosionType + Defines the behavior of the Explosion. <a href="http://wiki.roblox.com/index.php/ExplosionType_(Enum)" target="_blank">More info</a> + + + + + + + Fire + Makes the parent part or model object emit fire + 3 + 61 + + + + + Color + The color of the base of the fire. See SecondaryColor for more. + + + + + Heat + How hot the fire appears to be. The flame moves quicker the higher this value is set. + + + + + SecondaryColor + The color the fire interpolates to from Color. The longer a particle exists in the fire, the close to this color it becomes. + + + + + Size + How large the fire appears to be. + + + + + + + Seat + 3 + 35 + + + + + Platform + + Equivalent to a seat, except that the character stands up rather than sits down. + 3 + 35 + + + + + SkateboardPlatform + + 3 + 35 + + + + + VehicleSeat + Automatically finds and powers hinge joints in an assembly. Ignores motors. + 3 + 35 + + + + + Tool + 3 + 17 + + + + + Flag + 3 + 38 + + + + + CanBeDropped + If someone is carrying this flag, this bool determines whether or not they can drop it and run. + + + + + TeamColor + The Team this flag is for. Corresponds with the TeamColors in the Teams service. + + + + + + + FlagStand + 3 + 39 + + + + + BackpackItem + 0 + + + + + Decal + 4 + 7 + Descibes a texture that is placed on one of the sides of the Part it is parented to. + + + + + Face + Describes the face of the Part the decal will be applied to. <a href="http://wiki.roblox.com/index.php/NormalId_(Enum)" target="_blank">More info</a> + + + + + Shiny + How much light will appear to reflect off of the decal. + + + + + Specular + How light will react to the surface of the decal. + + + + + Transparency + How visible the decal is. 1 is completely invisible, while 0 is completely opaque + + + + + + + JointInstance + 20 + 34 + + + + + Message + 11 + 33 + StarterGui + + + + + Hint + true + 11 + 33 + + + + + IntValue + 3 + 4 + Stores a int value in it's Value member. Useful to share int information across multiple scripts. + + + + + RayValue + 3 + 4 + Stores a Ray value in it's Value member. Useful to share Ray information across multiple scripts. + + + + + IntConstrainedValue + 3 + 4 + Stores an int value in it's Value member. Value is clamped to be in range of Min and MaxValue. Useful to share int information across multiple scripts. + + + + MaxValue + The maximum we allow this Value to be set. If Value is set higher than this, it automatically gets adjusted to MaxValue + + + + + MinValue + The minimum we allow this Value to be set. If Value is set lower than this, it automatically gets adjusted to MinValue + + + + + + DoubleConstrainedValue + 3 + 4 + Stores a double value in it's Value member. Value is clamped to be in range of Min and MaxValue. Useful to share double information across multiple scripts. + + + + + MaxValue + The maximum we allow this Value to be set. If Value is set higher than this, it automatically gets adjusted to MaxValue + + + + + MinValue + The minimum we allow this Value to be set. If Value is set lower than this, it automatically gets adjusted to MinValue + + + + + + + BoolValue + 3 + 4 + Stores a boolean value in it's Value member. Useful to share boolean information across multiple scripts. + + + + + CustomEvent + 3 + 4 + + + + + CustomEventReceiver + 3 + 4 + + + + + TextureTrail + 3 + 4 + + + + + FloorWire + 3 + 4 + Renders a thin cylinder than can be adorned with textures that 'flow' from one object to the next. Has basic pathing abilities and attempts to to not intersect anything. <a href="http://wiki.roblox.com/index.php/FloorWire_Guide" target="_blank">More info</a> + + + + + CycleOffset + Controls how the decals are positioned along the wire. <a href="http://wiki.roblox.com/index.php/CycleOffset_(Property)" target="_blank">More info</a> + + + + + From + The object the FloorWire 'emits' from + + + + + StudsBetweenTextures + The space between two textures on the wire. Note: studs are relative depending on how far the camera is from the FloorWire. + + + + + Texture + The image we use to render the textures that flow from beginning to end of the FloorWire. + + + + + TextureSize + The size in studs of the Texture we use to flow from one object to the next. + + + + + To + The object the FloorWire 'emits' to + + + + + Velocity + The rate of travel that the textures flow along the wire. + + + + + WireRadius + How thick the wire is. + + + + + + + NumberValue + 3 + 4 + + + + + StringValue + 3 + 4 + + + + + Vector3Value + 3 + 4 + + + + + CFrameValue + 3 + 4 + Stores a CFrame value in it's Value member. Useful to share CFrame information across multiple scripts. + + + + + Color3Value + 3 + 4 + Stores a Color3 value in it's Value member. Useful to share Color3 information across multiple scripts. + + + + + BrickColorValue + 3 + 4 + Stores a BrickColor value in it's Value member. Useful to share BrickColor information across multiple scripts. + + + + + ObjectValue + 3 + 4 + + + + + SpecialMesh + 3 + 8 + + + + + BlockMesh + 3 + 8 + + + + + + CylinderMesh + 3 + 8 + + + + + + BevelMesh + false + true + + + + + DataModelMesh + false + + + + + + Texture + 4 + 10 + + + + + Sound + 1 + 11 + + + + + play + true + Deprecated. Use Play() instead + + + + + + + PlayOnRemove + The sound will play when it is removed from the Workspace. Looped sounds don't play + + + + + + + StockSound + false + -1 + + + + + SoundService + 50 + 31 + + + + + + AmbientReverb + + The ambient sound environment. May not work when using hardware sound + + + + + DopplerScale + + The doppler scale is a general scaling factor for how much the pitch varies due to doppler shifting in 3D sound. Doppler is the pitch bending effect when a sound comes towards the listener or moves away from it, much like the effect you hear when a train goes past you with its horn sounding. With dopplerscale you can exaggerate or diminish the effect. + + + + + DistanceFactor + + the relative distance factor, compared to 1.0 meters. + + + + + RolloffScale + + Setting this value makes the sound drop off faster or slower. The higher the value, the faster volume will attenuate, and conversely the lower the value, the slower it will attenuate. For example a rolloff factor of 1 will simulate the real world, where as a value of 2 will make sounds attenuate 2 times quicker. + + + + + + + Backpack + 3 + 20 + + + + + StarterPack + 3 + 20 + + + + + StarterPlayer + 3 + 79 + + + + + StarterGear + 3 + 20 + + + + + + StarterGui + 3 + 46 + + + + + + SetCoreGuiEnabled + Will stop/begin certain core gui elements being rendered. See CoreGuiType for core guis that can be modified. + + + + + GetCoreGuiEnabled + Returns a boolean describing whether a CoreGuiType is currently being rendered. + + + + + + + + CoreGui + false + 46 + + + + + + ContextActionService + A service used to bind input to various lua functions. + + + + + + BindActionToInputTypes + Binds 'functionToBind' to fire when any 'inputTypes' happen. InputTypes can be variable in number and type. Types can be Enum.KeyCode, single strings corresponding to keys, or Enum.UserInputType. 'actionName' is a key used by many other ContextActionService functions to query state. 'createTouchButton' if true will create a button on screen on touch devices. This button will fire 'functionToBind'. + + + + + SetTitle + If 'actionName' key contains a bound action, then 'title' is set as the title of the touch button. Does nothing if a touch button was not created. No guarantees are made whether title will be set when button is manipulated. + + + + + SetDescription + If 'actionName' key contains a bound action, then 'description' is set as the description of the bound action. This description will appear for users in a listing of current actions availables. + + + + + SetImage + If 'actionName' key contains a bound action, then 'image' is set as the image of the touch button. Does nothing if a touch button was not created. No guarantees are made whether image will be set when button is manipulated. + + + + + SetPosition + If 'actionName' key contains a bound action, then 'position' is set as the position of the touch button. Does nothing if a touch button was not created. No guarantees are made whether position will be set when button is manipulated. + + + + + UnbindAction + If 'actionName' key contains a bound action, removes function from being called by all input that it was bound by (if function was also bound by a different action name as well, those bound input are still active). Will also remove any touch button created (if button was manipulated manually there is no guarantee it will be cleaned up). + + + + + UnbindAllActions + Removes all functions bound. No actionNames will remain. All touch buttons will be removed. If button was manipulated manually there is no guarantee it will be cleaned up. + + + + + GetBoundActionInfo + Returns a table with info regarding the function bound with 'actionName'. Table has the keys 'title' (current title that was set with SetTitle) 'image' (image set with SetImage) 'description' (description set with SetDescription) 'inputTypes' (tuple containing all input bound for this 'actionName') 'createTouchButton' (whether or not we created a touch button for this 'actionName'). + + + + + GetAllBoundActionInfo + Returns a table with all bound action info. Each entry is a key with 'actionName' and value being the same table you would get from ContextActionService:GetBoundActionInfo('actionName'). + + + + + + + + GetButton + If 'actionName' key contains a bound action, then this will return the touch button (if was created). Returns nil if a touch button was not created. No guarantees are made whether button will be retrievable when button is manipulated. + + + + + + + + PointsService + A service used to query and award points for Roblox users using the universal point system. + + + + + + PointsAwarded + Fired when points are successfully awarded 'userId'. Also returns the updated balance of points for usedId in universe via 'userBalanceInUniverse', total points via 'userTotalBalance', and the amount points that were awarded via 'pointsAwarded'. This event fires on the server and also all clients in the game that awarded the points. + + + + + + + + AwardPoints + Will attempt to award the 'amount' points to 'userId', returns 'userId' awarded to, the number of points awarded, the new point total the user has in the game, and the total number of points the user now has. Will also fire PointsService.PointsAwarded. Works with server scripts ONLY. + + + + + GetPointBalance + Returns the overall balance of points that player with userId has (the sum of all points across all games). Works with server scripts ONLY. + + + + + GetGamePointBalance + Returns the balance of points that player with userId has in the current game (all placeID points combined within the game). Works with server scripts ONLY. + + + + + GetAwardablePoints + Returns the number of points the current universe can award to players. Works with server scripts ONLY. + + + + + + + + Chat + + + + + FilterStringForPlayerAsync + Will return an appropriately filtered string for the player passed in. + + + + + + + + MarketplaceService + 46 + + + + + + PromptPurchase + Will prompt 'player' to purchase the item associated with 'assetId'. 'equipIfPurchased' is an optional argument that will give the item to the player immediately if they buy it (only applies to gear). 'currencyType' is also optional and will attempt to prompt the user with a specified currency if the product can be purchased with this currency, otherwise we use the default currency of the product. + + + + + + + + GetProductInfo + Takes one argument "assetId" which should be a number of an asset on www.roblox.com. Returns a table containing the product information (if this process fails, returns an empty table). + + + + + PlayerOwnsAsset + Checks to see if 'Player' owns the product associated with 'assetId'. Returns true if the player owns it, false otherwise. This call will produce a warning if called on a guest player. + + + + + + + ProcessReceipt + Callback that is executed for pending Developer Product receipts. + + If this function does not return Enum.ProductPurchaseDecision.PurchaseGranted, then you will not be granted the money for the purchase! + + The callback will be invoked with a table, containing the following informational fields: + PlayerId - the id of the player making the purchase. + PlaceIdWherePurchased - the specific place where the purchase was made. + PurchaseId - a unique identifier for the purchase, should be used to prevent granting an item multiple times for one purchase. + ProductId - the id of the purchased product. + CurrencyType - the type of currency used (Tix, Robux). + CurrencySpent - the amount of currency spent on the product for this purchase. + + + + + + + + PromptPurchaseFinished + Fired when a 'player' dismisses a purchase dialog for 'assetId'. If the player purchased the item 'isPurchased' will be true, otherwise it will be false. This call will produce a warning if called on a guest player. + + + + + + + + UserInputService + + + + + TouchEnabled + Returns true if the local device accepts touch input, false otherwise. + + + + + KeyboardEnabled + Returns true if the local device accepts keyboard input, false otherwise. + + + + + MouseEnabled + Returns true if the local device accepts mouse input, false otherwise. + + + + + AccelerometerEnabled + Returns true if the local device has an accelerometer, false otherwise. + + + + + GyroscopeEnabled + Returns true if the local device has an gyroscope, false otherwise. + + + + + + + + TouchTap + Fired when a user taps their finger on a TouchEnabled device. 'touchPositions' is a Lua array of Vector2, each indicating the position of all the fingers involved in the tap gesture. This event only fires locally. This event will always fire regardless of game state. + + + + + TouchPinch + Fired when a user pinches their fingers on a TouchEnabled device. 'touchPositions' is a Lua array of Vector2, each indicating the position of all the fingers involved in the pinch gesture. 'scale' is a float that indicates the difference from the beginning of the pinch gesture. 'velocity' is a float indicating how quickly the pinch gesture is happening. 'state' indicates the Enum.UserInputState of the gesture. This event only fires locally. This event will always fire regardless of game state. + + + + + TouchSwipe + Fired when a user swipes their fingers on a TouchEnabled device. 'swipeDirection' is an Enum.SwipeDirection, indicating the direction the user swiped. 'numberOfTouches' is an int that indicates how many touches were involved with the gesture. This event only fires locally. This event will always fire regardless of game state. + + + + + TouchLongPress + Fired when a user holds at least one finger for a short amount of time on the same screen position on a TouchEnabled device. 'touchPositions' is a Lua array of Vector2, each indicating the position of all the fingers involved in the gesture. 'state' indicates the Enum.UserInputState of the gesture. This event only fires locally. This event will always fire regardless of game state. + + + + + TouchRotate + Fired when a user rotates two fingers on a TouchEnabled device. 'touchPositions' is a Lua array of Vector2, each indicating the position of all the fingers involved in the gesture. 'rotation' is a float indicating how much the rotation has gone from the start of the gesture. 'velocity' is a float that indicates how quickly the gesture is being performed. 'state' indicates the Enum.UserInputState of the gesture. This event only fires locally. This event will always fire regardless of game state. + + + + + TouchPan + Fired when a user drags at least one finger on a TouchEnabled device. 'touchPositions' is a Lua array of Vector2, each indicating the position of all the fingers involved in the gesture. 'totalTranslation' is a Vector2, indicating how far the pan gesture has gone from its starting point. 'velocity' is a Vector2 that indicates how quickly the gesture is being performed in each dimension. 'state' indicates the Enum.UserInputState of the gesture. This event only fires locally. This event will always fire regardless of game state. + + + + + + TouchStarted + Fired when a user places their finger on a TouchEnabled device. 'touch' is an InputObject, which contains useful data for querying user input. This event only fires locally. This event will always fire regardless of game state. + + + + + TouchMoved + Fired when a user moves their finger on a TouchEnabled device. 'touch' is an InputObject, which contains useful data for querying user input. This event only fires locally. This event will always fire regardless of game state. + + + + + TouchEnded + Fired when a user moves their finger on a TouchEnabled device. 'touch' is an InputObject, which contains useful data for querying user input. This event only fires locally. This event will always fire regardless of game state. + + + + + + InputBegan + Fired when a user begins interacting via a Human-Computer Interface device (Mouse button down, touch begin, keyboard button down, etc.). 'inputObject' is an InputObject, which contains useful data for querying user input. This event only fires locally. This event will always fire regardless of game state. + + + + + InputChanged + Fired when a user changes interacting via a Human-Computer Interface device (Mouse move, touch move, mouse wheel, etc.). 'inputObject' is an InputObject, which contains useful data for querying user input. This event only fires locally. This event will always fire regardless of game state. + + + + + InputEnded + Fired when a user stops interacting via a Human-Computer Interface device (Mouse button up, touch end, keyboard button up, etc.). 'inputObject' is an InputObject, which contains useful data for querying user input. This event only fires locally. This event will always fire regardless of game state. + + + + + + TextBoxFocused + Fired when a user clicks/taps on a textbox to begin text entry. Argument is the textbox that was put in focus. This also fires if a textbox forces focus on the user. This event only fires locally. + + + + + TextBoxFocusReleased + Fired when a user stops text entry into a textbox (usually by pressing return or clicking/tapping somewhere else on the screen). Argument is the textbox that was taken out of focus. This event only fires locally. + + + + + DeviceAccelerationChanged + Fired when a user moves a device that has an accelerometer. This is fired with an InputObject, which has type Enum.InputType.Accelerometer, and position that shows the g force in each local device axis. This event only fires locally. + + + + + DeviceGravityChanged + Fired when the force of gravity changes on a device that has an accelerometer. This is fired with an InputObject, which has type Enum.InputType.Accelerometer, and position that shows the g force in each local device axis. This event only fires locally. + + + + + DeviceRotationChanged + Fired when a user rotates a device that has an gyroscope. This is fired with an InputObject, which has type Enum.InputType.Gyroscope, and position that shows total rotation in each local device axis. The delta property describes the amount of rotation that last happened. A second argument of Vector4 is the device's current quaternion rotation in reference to it's default reference frame. This event only fires locally. + + + + + + + + GetDeviceAcceleration + Returns an InputObject that describes the device's current acceleration. This is fired with an InputObject, which has type Enum.InputType.Accelerometer, and position that shows the g force in each local device axis. The delta property describes the amount of rotation that last happened. This event only fires locally. + + + + + GetDeviceGravity + Returns an InputObject that describes the device's current gravity vector. This is fired with an InputObject, which has type Enum.InputType.Accelerometer, and position that shows the g force in each local device axis. The delta property describes the amount of rotation that last happened. This event only fires locally. + + + + + GetDeviceRotation + Returns an InputObject and a Vector4 that describes the device's current rotation vector. This is fired with an InputObject, which has type Enum.InputType.Gyroscope, and position that shows total rotation in each local device axis. The delta property describes the amount of rotation that last happened. The Vector4 is the device's current quaternion rotation in reference to it's default reference frame. This event only fires locally. + + + + + + + + Sky + 0 + 28 + + + + + Motor + + 0 + + + + + Humanoid + 3 + 9 + + + + + + MoveTo + Attempts to move the Humanoid and it's associated character to 'part'. 'location' is used as an offset from part's origin. + + + + + Jump + + + + + Sit + + + + + TakeDamage + Decreases health by the amount. Use this instead of changing health directly to make sure weapons are filtered for things such as ForceField(s). + + + + + UnequipTools + + Takes any active gear/tools that the Humanoid is using and puts them into the backpack. This function only works on Humanoids with a corresponding Player. + + + + + EquipTool + + Takes a specified tool and equips it to the Humanoid's Character. Tool argument should be of type 'Tool'. + + + + + + + NameOcclusion + + Sets how to display other humanoid names to this humanoid's player. <a href="http://wiki.roblox.com/index.php/NameOcclusion_(Enum)" target="_blank">More info</a> + + + Health + How many hit points the Humanoid has. When this number reaches 0 or goes below 0, the Humanoid's character falls apart and will respawn. + + + MaxHealth + The maximum number of hit points a Humanoid's health can reach. If the Humanoid's health is set over this amount, the health gets set to this value. + + + TargetPoint + The location that the Humanoid is trying to walk to. + + + + + + + BodyColors + + 0 + + + + + Shirt + 0 + 43 + + + + + Pants + 0 + 44 + + + + + ShirtGraphic + 0 + 40 + + + + + Skin + + 0 + + + + + DebugSettings + false + 0 + + + + + FaceInstance + false + + + + + GameSettings + false + 0 + + + + + GlobalSettings + false + 0 + + + + + Item + false + 0 + + + + + NetworkPeer + false + + + + + NetworkSettings + false + 0 + + + + + PVInstance + false + + + + + CoordinateFrame + true + Deprecated. Use CFrame instead + + + + + + + RenderSettings + false + 0 + + + + + RootInstance + false + + + + + ServiceProvider + false + + + + + service + true + Use GetService() instead + + + + + + + ProfilingItem + false + + + + + NetworkMarker + false + + + + + + Hopper + true + Use StarterPack instead + 0 + + + + + + Instance + false + + + + + + Archivable + Determines whether or not an Instance can be saved when the game closes/attempts to save the game. Note: this only applies to games that use Data Persistence, or Personal Build Servers. + + + + + ClassName + The string name of this Instance's most derived class. + + + + + Parent + The Instance that is directly above this Instance in the tree. + + + + + + + + + GetDebugId + false + This function is for internal testing. Don't use in production code + + + + + Clone + Returns a copy of this Object and all its children. The copy's Parent is nil + + + + + clone + true + Use Clone() instead + + + + + isA + true + Use IsA() instead + + + + + IsA + Returns a boolean if this Instance is of type 'className' or a is a subclass of type 'className'. If 'className' is not a valid class type in ROBLOX, this function will always return false. <a href="http://wiki.roblox.com/index.php/IsA" target="_blank">More info</a> + + + + + FindFirstChild + Returns the first child of this Instance that matches the first argument 'name'. The second argument 'recursive' is an optional boolean (defaults to false) that will force the call to traverse down thru all of this Instance's descendants until it finds an object with a name that matches the 'name' argument. The function will return nil if no Instance is found. + + + + + GetFullName + Returns a string that shows the path from the root node (DataModel) to this Instance. This string does not include the root node (DataModel). + + + + + children + true + Use GetChildren() instead + + + + + getChildren + true + Use GetChildren() instead + + + + + GetChildren + Returns a read-only table of this Object's children + + + + + Remove + Deprecated. Use ClearAllChildren() to get rid of all child objects, or Destroy() to invalidate this object and its descendants + true + + + + + remove + true + Use Remove() instead + + + + + ClearAllChildren + Removes all children (but not this object) from the workspace. + + + + + Destroy + Removes object and all of its children from the workspace. Disconnects object and all children from open connections. Object and children may not be usable after calling Destroy. + + + + + findFirstChild + true + Use FindFirstChild() instead + + + + + + + + AncestryChanged + Fired when any of this object's ancestors change. First argument 'child' is the object whose parent changed. Second argument 'parent' is the first argument's new parent. + + + + + DescendantAdded + Fired after an Instance is parented to this object, or any of this object's descendants. The 'descendant' argument is the Instance that is being added. + + + + + DescendantRemoving + Fired after an Instance is unparented from this object, or any of this object's descendants. The 'descendant' argument is the Instance that is being added. + + + + + Changed + Fired after a property changes value. The property argument is the name of the property + + + + + + + + BodyGyro + Attempts to maintain a fixed orientation of its parent Part + 14 + 14 + + + + + + maxTorque + The maximum torque that will be exerted on the Part + + + + + D + The dampening factor applied to this force + + + + + P + The power continually applied to this force + + + + + cframe + the cframe that this force is trying to orient its parent Part to. Note: this force only uses the rotation of the cframe, not the position. + + + + + + + BodyPosition + 14 + 14 + + + + + + maxForce + The maximum force that will be exerted on the Part + + + + + D + The dampening factor applied to this force + + + + + P + The power factor continually applied to this force + + + + + position + The Vector3 that this force is trying to position its parent Part to. + + + + + + + RocketPropulsion + + 14 + 14 + A propulsion system that mimics a rocket + + + + + BodyVelocity + 14 + 14 + + + + + maxForce + The maximum force that will be exerted on the Part in each axis + + + + + P + The amount of power we add to the system. The higher the power, the quicker the force will achieve its goal. + + + + + velocity + The velocity this system tries to achieve. How quickly the system reaches this velocity (if ever) is defined by P. + + + + + + + BodyAngularVelocity + 14 + 14 + + + + maxTorque + The maximum torque that will be exerted on the Part in each axis + + + P + The amount of power we add to the system. The higher the power, the quicker the force will achieve its goal. + + + angularVelocity + The rotational velocity this system tries to achieve. How quickly the system reaches this velocity is defined by P. + + + + + + BodyForce + 14 + 14 + When parented to a physical part, BodyForce will continually exert a force upon its parent object. + + + + force + The continual force exerted on an object, defined in each axis. + + + + + + BodyThrust + 14 + 14 + + + + + + force + The power continually applied to this force + + + + + location + The Vector3 location of where to apply the force to. + + + + + + + Hole + + 0 + + + + + Feature + 0 + + + + + + Teams + This Service-level object is the container for all Team objects in a level. A map that supports team games must have a Teams service. <a href="http://wiki.roblox.com/index.php/Team" target="_blank">More info</a> + 14 + 23 + + + + + + Team + The Team class is used to represent a faction in a team game. The only valid location for a Team object is under the Teams service. <a href="http://wiki.roblox.com/index.php/Team" target="_blank">More info</a> + 1 + 24 + + + + + SpawnLocation + 3 + 25 + + + + + NetworkClient + 3 + 16 + + + + + NetworkServer + 3 + 15 + + + + + + Script + 3 + 6 + + + + + + LinkedScript + + This property is under development. Do not use + + + + + + + + LocalScript + 4 + 18 + A script that runs on clients, NOT servers. LocalScripts can only run when parented under the PlayerGui currently. + + + + + + NetworkReplicator + 3 + 29 + + + + + + Model + 10 + 2 + A construct used to group Parts and other objects together, also allows manipulation of multiple objects. + + + + + BreakJoints + Breaks all surface joints contained within + + + + + GetModelCFrame + Returns a CFrame that has position of the centroid of all Parts in the Model. The rotation matrix is either the rotation matrix of the user-defined PrimaryPart, or if not specified then a part in the Model chosen by the engine. + + + + + GetModelSize + Returns a Vector3 that is union of the extents of all Parts in the model. + + + + + MakeJoints + Creates the appropriate SurfaceJoints between all touching Parts contrained within the model. Technically, this function calls MakeJoints() on all Parts inside the model. + + + + + MoveTo + Moves the centroid of the Model to the specified location, respecting all relative distances between parts in the model. + + + + + ResetOrientationToIdentity + Rotates all parts in the model to the orientation that was set using SetIdentityOrientation(). If this function has never been called, rotation is reset to GetModelCFrame()'s rotation. + + + + + SetIdentityOrientation + Takes the current rotation matrix of the model and stores it as the model's identity matrix. The rotation is applied when ResetOrientationToIdentity() is called. + + + + + TranslateBy + Similar to MoveTo(), except instead of moving to an explicit location, we use the model's current CFrame location and offset it. + + + + + GetPrimaryPartCFrame + Returns the cframe of the Model.PrimaryPart. If PrimaryPart is nil, then this function will throw an error. + + + + + SetPrimaryPartCFrame + Sets the cframe of the Model.PrimaryPart. If PrimaryPart is nil, then this function will throw an error. This also sets the cframe of all descendant Parts relative to the cframe change to PrimaryPart. + + + + + makeJoints + Use MakeJoints() instead + true + + + + + move + true + Use MoveTo() instead + + + + + + + PrimaryPart + A Part that serves as a reference for the Model's CFrame. Used in conjunction with GetModelPrimaryPartCFrame and SetModelPrimaryPartCFrame. Use this to rotate/translate all Parts relative to the PrimaryPart. + + + + + + + + Status + 10 + 2 + + + + + move + true + Use MoveTo() instead + + + + + + + + DataModel + + + + + + + + Workspace + + + + + workspace + true + Deprecated. Use Workspace + + + + + ShowMouse + true + Deprecated. Use Workspace.IsMouseCursorVisible + + + + + IsLoaded + Returns true if the game has finished loading, false otherwise. Check this before listening to the Loaded signal to ensure a script knows when a game finishes loading. + + + + + + + + Loaded + Fires when the game finishes loading. Use this to know when to remove your custom loading gui. It is best to check IsLoaded() before connecting to this event, as the game may load before the event is connected to. + + + + + + + + get + true + Use GetObjects() instead + + + + + SetPlaceID + true + Use SetPlaceId() instead + + + + + SetCreatorID + true + Use SetCreatorId() instead + + + + + + + + HopperBin + 24 + 22 + + + + + + Camera + 5 + 5 + + + + + CameraSubject + Where the Camera's focus is. Any rotation of the camera will be about this subject. + + + + + CameraType + Defines how the camera will behave. <a href="http://wiki.roblox.com/index.php/CameraType_(Enum)" target="_blank">More info</a> + + + + + CoordinateFrame + The current position and rotation of the Camera. For most CameraTypes, the rotation is set such that the CoordinateFrame lookVector is pointing at the Focus. + + + + + FieldOfView + The current angle, or width, of what the camera can see. Current acceptable values are from 20 degrees to 80. + + + + + Focus + The current CoordinateFrame that the camera is looking at. Note: it is not always guaranteed that the camera is always looking here. + + + + + ViewportSize + Holds the x,y screen resolution of the viewport the camera is presenting (note: this can differ from the AbsoluteSize property of a full screen gui). + + + + + + + GetRoll + Returns the camera's current roll. Roll is defined in radians, and is stored as the delta from the camera's y axis default normal vector. + + + + + WorldToScreenPoint + Takes a 3D position in the world and projects it onto x,y coordinates of screen space. Returns two values, first is a Vector3 that has x,y position and z position which is distance from camera (negative if behind camera, positive if in front). Second return value is a boolean indicating if the first argument is an on-screen coordinate. + + + + + ScreenPointToRay + Takes a 2D screen position and produces a Ray object to be used for 3D raycasting. Input is x,y screen coordinates, and a (optional, defaults to 0) z position which sets how far in the camera look vector to start the ray origin. + + + + + ViewportPointToRay + Same as ScreenPointToRay, except no GUI offsets are taken into account. Useful for things like casting a ray from the middle of the Camera.ViewportSize + + + + + WorldToViewportPoint + Same as WorldToScreenPoint, except no GUI offsets are taken into account. + + + + + SetRoll + Sets the camera's current roll. Roll is defined in radians, and is stored as the delta from the camera's y axis default normal vector. + + + + + + + + Players + 2 + 21 + + + + + CharacterAutoLoads + true + Set to true, when a player joins a game, they get a character automatically, as well as when they die. When set to false, characters do not auto load and will only load in using Player:LoadCharacter(). + + + + + + + players + true + Use GetPlayers() instead + + + + + + + + ReplicatedStorage + 3 + 70 + A container whose contents are replicated to all clients and the server. + + + + + + RobloxReplicatedStorage + false + + + + + + ReplicatedFirst + 3 + 70 + A container whose contents are replicated to all clients (but not back to the server) first before anything else. Useful for creating loading guis, tutorials, etc. + + + + + RemoveRobloxLoadingScreen + Removes the default Roblox loading screen from view. Call this when you are ready to either show your own loading gui, or when the game is ready to play. + + + + + + + + ServerStorage + 3 + 69 + A container whose contents are only on the server. + + + + + + ServerScriptService + 3 + 71 + A container whose contents should be scripts. Scripts that are added to the container are run on the server. + + + + + + Lighting + 3 + 13 + Responsible for all lighting aspects of the world (affects how things are rendered). + + + + + GetMinutesAfterMidnight + The number of minutes that the current time is past midnight. If currently at midnight, returns 0. Will return decimal values if not at an exact minute. + + + + + GetMoonDirection + Returns the lookVector (Vector3) of the moon. If this lookVector was used in a CFrame, the Part would face the moon. + + + + + GetMoonPhase + Currently always returns 0.75. MoonPhase cannot be edited. + + + + + GetSunDirection + Returns the lookVector (Vector3) of the sun. If this lookVector was used in a CFrame, the Part would face the moon. + + + + + SetMinutesAfterMidnight + Sets the time to be a certain number of minutes after midnight. This works with integer and decimal values. + + + + + + + Ambient + The hue of the global lighting. Changing this changes the color tint of all objects in the Workspace. + + + + + Brightness + How much global light each Part in the Workspace receives. Standard range is 0 to 1 (0 being little light), but can be increased all the way to 5 (colors start to be appear very different at this value). + + + + + ColorShift_Bottom + The hue of global lighting on the bottom surfaces of an object. + + + + + ColorShift_Top + The hue of global lighting on the top surfaces of an object. + + + + + FogColor + A Color3 value that changes the hue of distance fog. + + + + + FogEnd + The distance at which fog completely blocks your vision. This distance is relative to the camera position. Units are in studs + + + + + FogStart + The distance at which the fog gradient begins. This distance is relative to the camera position. Units are in studs. + + + + + GeographicLatitude + The latitude position the level is placed at. This affects sun position. <a href="http://wiki.roblox.com/index.php/GeographicLatitude_(Property)" target="_blank">More info</a> + + + + + GlobalShadows + Flag enabling shadows from sun and moon in the place + + + + + OutdoorAmbient + Effective ambient value for outdoors, effectively shadow color outdoors (requires GlobalShadows enabled) + + + + + Outlines + Flag enabling or disabling outlines on parts and terrain + + + + + ShadowColor + Color the shadows appear as. Shadows are drawn mostly for characters, but depending on the lighting will also show for Parts in the Workspace. Rendering settings can also affect if shadows are drawn. + + + + + TimeOfDay + A string that represent the current time of day. Time is in 24-hour clock format "XX::YY:ZZ", where X is hour, Y is minute, and Z is seconds. + + + + + + + LightingChanged + Fired whenever a property of Lighting is changed, or a skybox is added or removed. Skyboxes are of type 'Sky' and should be parented directly to lighting. + + + + + + + + TestService + 100 + 68 + + + + + + DebuggerManager + + + + + + + + ScriptDebugger + + + + + + + + DebuggerBreakpoint + + + + + + + + DebuggerWatch + + + + + + + + Debris + -1 + 30 + A service that provides utility in cleaning up objects + + + + + addItem + true + Use AddItem() instead + + + + + AddItem + Adds an Instance into the debris service that will later be destroyed. Second argument 'lifetime' is optional and specifies how long (in seconds) to wait before destroying the item. If no time is specified then the item added will automatically be destroyed in 10 seconds. + + + + + + + MaxItems + true + Deprecated. No replacement + + + + + + + + Accoutrement + 0 + 32 + + + + + + Player + 1 + 12 + + + + + + CharacterAppearance + false + + + + + CameraMode + An enum that describes how a Player's camera is allowed to behave. <a href="http://wiki.roblox.com/index.php/CameraMode_(Enum)" target="_blank">More info</a>. + + + + + DataReady + Read-only. If true, this Player's persistent data can be loaded, false otherwise. <a href="http://wiki.roblox.com/index.php/ROBLOX_Scripting_How_To:_Data_Persistence" target="_blank">Info on Data Persistence</a>. + + + + + + + + LoadCharacter + true + Loads in a new character for this player. This will replace the player's current character, if they have one. This should be used in conjunction with Players.CharacterAutoLoads to control spawning of characters. This function only works from a server-side script (NOT a LocalScript). + + + + + playerFromCharacter + true + Use GetPlayerFromCharacter() instead + + + + + SetUnder13 + true + + + + + + + + WaitForDataReady + true + Yields until the persistent data for this Player is ready to be loaded. <a href="http://wiki.roblox.com/index.php/ROBLOX_Scripting_How_To:_Data_Persistence" target="_blank">Info on Data Persistence</a>. + + + + + GetWebPersonalServerRank + true + + + + + + + + + Idled + Fired periodically after the user has been AFK for a while. Currently this event is only fired for the *local* Player. "time" is the time in seconds that the user has been idle. + + + + + + + + Workspace + 1 + 19 + + + + + FindPartsInRegion3 + Returns parts in the area defined by the Region3, up to specified maxCount or 100, whichever is less + + + + + FindPartsInRegion3WithIgnoreList + Returns parts in the area defined by the Region3, up to specified maxCount or 100, whichever is less + + + + + FindPartOnRay + Return type is (BasePart, Vector3) if the ray hits. If it misses it will return (nil, PointAtEndOfRay) + + + + + FindPartOnRayWithIgnoreList + Return type is (BasePart, Vector3) if the ray hits. If it misses it will return (nil, PointAtEndOfRay) + + + + + + + + BasePart + A structural class, not creatable + -1 + false + + + + + + Color + true + Deprecated. Use BrickColor instead + + + + + CFrame + Contains information regarding the Part's position and a matrix that defines the Part's rotation. Can read/write. <a href="http://wiki.roblox.com/index.php/Cframe" target="_blank">More info</a> + + + + + CanCollide + Determines whether physical interactions with other Parts are respected. If true, will collide and react with physics to other Parts. If false, other parts will pass thru instead of colliding + + + + + Anchored + Determines whether or not physics acts upon the Part. If true, part stays 'Anchored' in space, not moving regardless of any collision/forces acting upon it. If false, physics works normally on the part. + + + + + Elasticity + A float value ranging from 0.0f to 1.0f. Sets how much the Part will rebound against another. a value of 1 is like a superball, and 0 is like a lead block. + + + + + Friction + A float value ranging from 0.0f to 1.0f. Sets how much the Part will be able to slide. a value of 1 is no sliding, and 0 is no friction, so infinite sliding. + + + + + Locked + Determines whether building tools (in-game and studio) can manipulate this Part. If true, no editing allowed. If false, editing is allowed. + + + + + Material + Specifies the look and feel the Part should have. Note: this does not define the color the Part is, see BrickColor for that. <a href="http://wiki.roblox.com/index.php/Material_(Enum)" target="_blank">More info</a> + + + + + Reflectance + Specifies how shiny the Part is. A value of 1 is completely reflective (chrome), while a value of 0 is no reflectance (concrete wall) + + + + + ResizeIncrement + Sets the value for the smallest change in size allowable by the Resize(NormalId, int) function. + + + + + ResizeableFaces + Sets the value for the faces allowed to be resized by the Resize(NormalId, int) function. + + + + + Transparency + Sets how visible an object is. A value of 1 makes the object invisible, while a value of 0 makes the object opaque. + + + + + Velocity + How fast the Part is traveling in studs/second. This property is NOT recommended to be modified directly, unless there is good reason. Otherwise, try using a BodyForce to move a Part. + + + + + + + + makeJoints + Use MakeJoints() instead + true + + + + + MakeJoints + Creates the appropriate SurfaceJoints with all parts that are touching this Instance (including internal joints in the Instance, as in a Model). This uses the SurfaceTypes defined on the surfaces of parts to create the appropriate welds. <a href="http://wiki.roblox.com/index.php/MakeJoints_(Method)" target="_blank">More info</a> + + + + + BreakJoints + Destroys SurfaceJoints with all parts that are touching this Instance (including internal joints in the Instance, as in a Model). + + + + + GetMass + Returns a number that is the mass of this Instance. Mass of a Part is immutable, and is changed only by the size of the Part. + + + + + Resize + Resizes a Part in the direction of the face defined by 'NormalId', by the amount specified by 'deltaAmount'. If the operation will expand the part to intersect another Instance, the part will not resize at all. Return true if the call is successful, false otherwise. + + + + + getMass + Use GetMass() instead + true + + + + + + + OutfitChanged + true + + + + + LocalSimulationTouched + true + Deprecated. Use Touched instead + + + + + StoppedTouching + + Deprecated. Use TouchEnded instead + + + + + TouchEnded + Fired when the part stops touching another part + + + + + + + Part + A plastic building block - the fundamental component of ROBLOX + 11 + 1 + + + + + TrussPart + An extendable building truss + 12 + 1 + + + + + WedgePart + A Wedge Part + 12 + 1 + + + + + PrismPart + A Prism Part + false + 12 + 1 + + + + + PyramidPart + A Pyramid Part + false + 12 + 1 + + + + + ParallelRampPart + A ParallelRamp Part + false + 12 + 1 + + + + + RightAngleRampPart + A RightAngleRamp Part + false + 12 + 1 + + + + + CornerWedgePart + A CornerWedge Part + 12 + 1 + + + + + PlayerGui + A container instance that syncs data between a single player and the server. ScreenGui objects that are placed in this container will be shown to the Player parent only + 13 + 46 + + + + + PlayerScripts + A container instance that contains LocalScripts. LocalScript objects that are placed in this container will be exectue only when a Player is the parent. + 13 + 78 + + + + + GuiMain + Deprecated, please use ScreenGui + true + 14 + 47 + + + + + + ScreenGui + The core GUI object on which tools are built. Add Frames/Labels/Buttons to this object to have them rendered as a 2D overlay + 14 + 47 + StarterGui + + + + + FunctionalTest + Deprecated. Use TestService instead + true + 1 + + + + + BillboardGui + A GUI that adorns an object in the 3D world. Add Frames/Labels/Buttons to this object to have them rendered while attached to a 3D object + 14 + 64 + StarterGui + + + + + + Adornee + The Object the billboard gui uses as its base to render from. Currently, the only way to set this property is thru a script, and must exist in the workspace. This will only render if the object assigned derives from BasePart. + + + + + AbsolutePosition + A read-only Vector2 value that is the GuiObject's current position (x,y) in pixel space, from the top left corner of the GuiObject. + + + + + AbsoluteSize + A read-only Vector2 value that is the GuiObject's current size (width, height) in pixel space. + + + + + Active + If true, this GuiObject can fire mouse events and will pass them to any GuiObjects layered underneath, while false will do neither. + + + + + AlwaysOnTop + If true, billboard gui does not get occluded by 3D objects, but always renders on the screen. + + + + + Enabled + If true, billboard gui will render, otherwise rendering will be skipped. + + + + + ExtentsOffset + A Vector3 (x,y,z) defined in studs that will offset the gui from the extents of the 3d object it is rendering from. + + + + + PlayerToHideFrom + Specifies a Player that the BillboardGui will not render to. + + + + + StudsOffset + A Vector3 (x,y,z) defined in studs that will offset the gui from the centroid of the 3d object it is rendering from + + + + + SizeOffset + A Vector2 (x,y) defined in studs that will offset the gui size from it's current size. + + + + + Size + A UDim2 value describing the size of the BillboardGui. More information on UDim2 is available <a href="http://wiki.roblox.com/index.php/UDim2" target="_blank">here</a>. Relative values are defined as one-to-one with studs. + + + + + + + + SurfaceGui + tbd + 14 + 64 + StarterGui + + + + + + Adornee + The Object the billboard gui uses as its base to render from. Currently, the only way to set this property is thru a script, and must exist in the workspace. This will only render if the object assigned derives from BasePart. + + + + + Active + If true, this GuiObject can fire mouse events and will pass them to any GuiObjects layered underneath, while false will do neither. + + + + + Enabled + If true, billboard gui will render, otherwise rendering will be skipped. + + + + + + + + + + GuiBase2d + false + + + + + + AbsolutePosition + A read-only Vector2 value that is the GuiObject's current position (x,y) in pixel space, from the top left corner of the GuiObject. + + + + + AbsoluteSize + A read-only Vector2 value that is the GuiObject's current size (width, height) in pixel space. + + + + + + + + InputObject + An object that describes a particular user input, such as mouse movement, touches, keyboard, and more. + + + + + UserInputType + An enum that describes what kind of input this object is describing (mousebutton, touch, etc.). See Enum.UserInputType for more info. + + + + + UserInputState + An enum that describes what state of a particular input (touch began, touch moved, touch ended, etc.). See Enum.UserInputState for more info. + + + + + Position + A Vector3 value that describes a positional value of this input. For mouse and touch input, this is the screen position of the mouse/touch, described in the x and y components. For mouse wheel input, the z component describes whether the wheel was moved forward or backward. + + + + + KeyCode + An enum that describes what kind of input is being pressed. For types of input like Keyboard, this describes what key was pressed. For input like mousebutton, this provides no additional information. + + + + + + + + GuiObject + false + + + + + + TweenPosition + Smoothly moves a GuiObject from its current position to 'endPosition'. The only required argument is 'endPosition'. <a href="http://wiki.roblox.com/index.php/TweenPosition_(Method)" target="_blank">More info</a> + + + + + TweenSize + Smoothly translates a GuiObject's current size to 'endSize'. The only required argument is 'endSize'. <a href="http://wiki.roblox.com/index.php/TweenSize_(Method)" target="_blank">More info</a> + + + + + TweenSizeAndPosition + Smoothly translates a GuiObject's current size to 'endSize', and also smoothly translates the GuiObject's current position to 'endPosition'. The only required arguments are 'endSize' and 'endPosition'. <a href="http://wiki.roblox.com/index.php/TweenSizeAndPosition_(Method)" target="_blank">More info</a> + + + + + + + + Active + If true, this GuiObject can fire mouse events and will pass them to any GuiObjects layered underneath, while false will do neither. + + + + + BackgroundColor3 + A Color3 value that specifies the background color for the GuiObject. This value is ignored if the Style property (not found on all GuiObjects) is set to something besides custom. + + + + + BackgroundTransparency + A number value that specifies how transparent the background of the GuiObject is. This value is ignored if the Style property (not found on all GuiObjects) is set to something besides custom. + + + + + BorderColor3 + A Color3 value that specifies the color of the outline of the GuiObject. This value is ignored if the Style property (not found on all GuiObjects) is set to something besides custom. + + + + + BorderSizePixel + A number value that specifies the thickness (in pixels) of the outline of the GuiObject. Currently this value can only be set to either 0 or 1, any other number has no effect. This value is ignored if the Style property (not found on all GuiObjects) is set to something besides custom. + + + + + ClipsDescendants + If set to true, any descendants of this GuiObject will only render if contained within it's borders. If set to false, all descendants will render regardless of position. + + + + + Draggable + If true, allows a GuiObject to be dragged by the user's mouse. The events 'DragBegin' and 'DragStopped' are fired when the appropriate action happens, and only will fire on Draggable=true GuiObjects. + + + + + Size + A UDim2 value describing the size of the GuiObject on screen in both absolute and relative coordinates. More information on UDim2 is available <a href="http://wiki.roblox.com/index.php/UDim2" target="_blank">here</a>. + + + + + Position + A UDim2 value describing the position of the top-left corner of the GuiObject on screen. More information on UDim2 is available <a href="http://wiki.roblox.com/index.php/UDim2" target="_blank">here</a>. + + + + + SizeConstraint + The direction(s) that an object can be resized in. <a href="http://wiki.roblox.com/index.php/SizeConstraint_(Enum)" target="_blank">More info</a>. + + + + + ZIndex + Describes the ordering in which overlapping GuiObjects will be drawn. A value of 1 is drawn first, while higher values are drawn in ascending order (each value draws over the last). + + + + + BackgroundColor + true + Deprecated. Use BackgroundColor3 instead + + + + + BorderColor + true + Deprecated. Use BorderColor3 instead + + + + + + + + DragBegin + Fired when a GuiObject with Draggable set to true starts to be dragged. 'InitialPosition' is a UDim2 value of the position of the GuiObject before any drag operation began. + + + + + DragStopped + Always fired after a DragBegin event, DragStopped is fired when the user releases the mouse button causing a drag operation on the GuiObject. Arguments 'x', and 'y' specify the top-left absolute position of the GuiObject when the event is fired. + + + + + MouseEnter + Fired when the mouse enters a GuiObject, as long as the GuiObject is active (see active property for more detail). Arguments 'x', and 'y' specify the absolute pixel position of the mouse. + + + + + MouseLeave + Fired when the mouse leaves a GuiObject, as long as the GuiObject is active (see active property for more detail). Arguments 'x', and 'y' specify the absolute pixel position of the mouse. + + + + + MouseMoved + Fired when the mouse is inside a GuiObject and moves, as long as the GuiObject is active (see active property for more detail). Arguments 'x', and 'y' specify the absolute pixel position of the mouse. + + + + + + TouchTap + Fired when a user taps their finger on a TouchEnabled device. 'touchPositions' is a Lua array of Vector2, each indicating the position of all the fingers involved in the tap gesture. This event only fires locally. This event will always fire regardless of game state. + + + + + TouchPinch + Fired when a user pinches their fingers on a TouchEnabled device. 'touchPositions' is a Lua array of Vector2, each indicating the position of all the fingers involved in the pinch gesture. 'scale' is a float that indicates the difference from the beginning of the pinch gesture. 'velocity' is a float indicating how quickly the pinch gesture is happening. 'state' indicates the Enum.UserInputState of the gesture. This event only fires locally. + + + + + TouchSwipe + Fired when a user swipes their fingers on a TouchEnabled device. 'swipeDirection' is an Enum.SwipeDirection, indicating the direction the user swiped. 'numberOfTouches' is an int that indicates how many touches were involved with the gesture. This event only fires locally. + + + + + TouchLongPress + Fired when a user holds at least one finger for a short amount of time on the same screen position on a TouchEnabled device. 'touchPositions' is a Lua array of Vector2, each indicating the position of all the fingers involved in the gesture. 'state' indicates the Enum.UserInputState of the gesture. This event only fires locally. + + + + + TouchRotate + Fired when a user rotates two fingers on a TouchEnabled device. 'touchPositions' is a Lua array of Vector2, each indicating the position of all the fingers involved in the gesture. 'rotation' is a float indicating how much the rotation has gone from the start of the gesture. 'velocity' is a float that indicates how quickly the gesture is being performed. 'state' indicates the Enum.UserInputState of the gesture. This event only fires locally. + + + + + TouchPan + Fired when a user drags at least one finger on a TouchEnabled device. 'touchPositions' is a Lua array of Vector2, each indicating the position of all the fingers involved in the gesture. 'totalTranslation' is a Vector2, indicating how far the pan gesture has gone from its starting point. 'velocity' is a Vector2 that indicates how quickly the gesture is being performed in each dimension. 'state' indicates the Enum.UserInputState of the gesture. + + + + + + InputBegan + Fired when a user begins interacting via a Human-Computer Interface device (Mouse button down, touch begin, keyboard button down, etc.). 'inputObject' is an InputObject, which contains useful data for querying user input. This event only fires locally. + + + + + InputChanged + Fired when a user changes interacting via a Human-Computer Interface device (Mouse move, touch move, mouse wheel, etc.). 'inputObject' is an InputObject, which contains useful data for querying user input. This event only fires locally. + + + + + InputEnded + Fired when a user stops interacting via a Human-Computer Interface device (Mouse button up, touch end, keyboard button up, etc.). 'inputObject' is an InputObject, which contains useful data for querying user input. This event only fires locally. + + + + + + + + + Frame + A container object used to layout other GUI objects + 15 + 48 + StarterGui + + + + + Style + Determines how a frame will look. Uses Enum.FrameStyle. <a href="http://wiki.roblox.com/index.php/Framestyle" target="_blank">More info</a> + + + + + + + ScrollingFrame + A container object used to layout other GUI objects, and allows for scrolling. + 15 + 48 + StarterGui + + + + + ScrollingEnabled + Determines whether or not scrolling is allowed on this frame. If turned off, no scroll bars will be rendered. + + + + + CanvasSize + Determines the size of the area that is scrollable. The UDim2 is calculated using the parent gui's size, similar to the regular Size property on gui objects. + + + + + CanvasPosition + The absolute position the scroll frame is in respect to the canvas size. The minimum this can be set to is (0,0), while the max is the absolute canvas size - AbsoluteWindowSize. + + + + + AbsoluteWindowSize + The size in pixels of the frame, without the scrollbars. + + + + + ScrollBarThickness + How thick the scroll bar appears. This applies to both the horizontal and vertical scroll bars. Can be set to 0 for no bars render. + + + + + TopImage + The "Up" image on the vertical scrollbar. Size of this is always ScrollBarThickness by ScrollBarThickness. This is also used as the "left" image on the horizontal scroll bar. + + + + + MidImage + The "Middle" image on the vertical scrollbar. Size of this can vary in the y direction, but is always set at ScrollBarThickness in x direction. This is also used as the "mid" image on the horizontal scroll bar. + + + + + BottomImage + The "Down" image on the vertical scrollbar. Size of this is always ScrollBarThickness by ScrollBarThickness. This is also used as the "right" image on the horizontal scroll bar. + + + + + + + ImageLabel + A GUI object containing an Image + 18 + 49 + StarterGui + + + + + Image + Specifies the id of the texture to display. <a href="http://wiki.roblox.com/index.php/Image" target="_blank">More info</a> + + + + + + + TextLabel + A GUI object containing text + 19 + 50 + StarterGui + + + + + TextColor + true + Deprecated. Use TextColor3 instead + + + + + + + TextButton + A GUI button containing text + 17 + 51 + StarterGui + + + + + TextColor + true + Deprecated. Use TextColor3 instead + + + + + + + TextBox + A text entry box + 17 + 51 + StarterGui + + + + + TextColor + true + Deprecated. Use TextColor3 instead + + + + + + + GuiButton + A GUI button containing an Image + false + 16 + 52 + + + + + AutoButtonColor + Determines whether a button changes color automatically when reacting to mouse events. + + + + + Modal + Allows the mouse to be free in first person mode. If a button with this property set to true is visible, the mouse is 'free' in first person mode. + + + + + Style + Determines how a button will look, including mouse event states. Uses Enum.ButtonStyle. <a href="http://wiki.roblox.com/index.php/ButtonStyle_(Enum)" target="_blank">More info</a> + + + + + + + MouseButton1Click + Fired when the mouse is over the button, and the mouse down and up events fire without the mouse leaving the button. + + + + + MouseButton1Down + Fired when the mouse button is pushed down on a button. + + + + + MouseButton1Up + Fired when the mouse button is released on a button. + + + + + MouseButton2Click + This function currently does not work :( + + + + + MouseButton2Down + This function currently does not work :( + + + + + MouseButton2Up + This function currently does not work :( + + + + + + + + ImageButton + A GUI button containing an Image + 16 + 52 + StarterGui + + + + + Image + Specifies the asset id of the texture to display. <a href="http://wiki.roblox.com/index.php/Image" target="_blank">More info</a> + + + + + + + Handles + A 3D GUI object to represent draggable handles + + 19 + 53 + + + + + ArcHandles + A 3D GUI object to represent draggable arc handles + + 20 + 56 + + + + + SelectionBox + A 3D GUI object to represent the visible selection around an object + 21 + 54 + + + + + SelectionSphere + A 3D GUI object to represent the visible selection around an object + 21 + 54 + + + + + SurfaceSelection + A 3D GUI object to represent the visible selection around a face of an object + 21 + 55 + + + + + Configuration + An object that can be placed under parts to hold Value objects that represent that part's configuration + 22 + 58 + + + + + Folder + An object that can be created to hold and organize objects + 22 + 77 + + + + + SelectionPartLasso + A visual line drawn representation between two part objects + 22 + 57 + + + + + SelectionPointLasso + A visual line drawn representation between two positions + 22 + 57 + + + + + PartPairLasso + A visual line drawn representation between two parts. + 22 + 57 + + + + + Pose + The pose of a joint relative to it's parent part in a keyframe + 22 + 60 + + + + + Keyframe + One keyframe of an animation + 22 + 60 + + + + + Animation + Represents a linked animation object, containing keyframes and poses. + 22 + 60 + + + + + AnimationTrack + Returned by a call to LoadAnimation. Controls the playback of an animation on a Humanoid. + 22 + 60 + + + + + Stopped + true + This event is never raised + + + + + + + AnimationController + Allows animations to be played on joints of the parent object. + 22 + 60 + + + + + CharacterMesh + Modifies the appearance of a body part. + 22 + 60 + + + + + Dialog + An object used to make dialog trees to converse with players + 22 + 62 + + + + + DialogChoice + An object used to make dialog trees to converse with players + 22 + 63 + + + + + UnionOperation + A UnionOperation is a union of multiple parts + true + false + 0 + 73 + + + + + UsePartColor + Override the colors of the mesh with the part color. + + + + + + + NegateOperation + A NegateOperation can be used to create holes in other parts + true + false + 0 + 72 + + + + + UsePartColor + Override the colors of the mesh with the part color. + + + + + + + Terrain + Object representing a high performance bounded grid of static 4x4 parts + true + 0 + 65 + + + + + GetCell + Returns CellMaterial, CellBlock, CellOrientation + + + + + GetWaterCell + + Returns hasAnyWater, WaterForce, WaterDirection + + + + + SetWaterCell + + + + + + + + PointLight + Makes the parent part emit light in a spherical shape + 3 + 13 + + + + + SpotLight + Makes the parent part emit light in a conical shape + 3 + 13 + + + + + SurfaceLight + Makes the parent part emit light in a frustum shape from rectangle defined by part + 3 + 13 + + + + + RemoteFunction + Allow functions defined in one script to be called by another script across client/server boundary + 4 + 74 + + + + + RemoteEvent + Allow events defined in one script to be subscribed to by another script across client/server boundary + 5 + 75 + + + + + TerrainRegion + Object representing a snapshot of the region of terrain + true + 0 + 65 + + + + + ModuleScript + A script fragment. Only runs when another script uses require() on it. + 5 + 76 + + + + + + + + Material + + + + Air + false + + + + + Water + false + + + + + Rock + false + + + + + diff --git a/2016/RobloxProxy.dll b/2016/RobloxProxy.dll new file mode 100644 index 0000000..f67cbca Binary files /dev/null and b/2016/RobloxProxy.dll differ diff --git a/2016/RobloxProxy64.dll b/2016/RobloxProxy64.dll new file mode 100644 index 0000000..a505a8f Binary files /dev/null and b/2016/RobloxProxy64.dll differ diff --git a/2016/SDL2.dll b/2016/SDL2.dll new file mode 100644 index 0000000..8f053af Binary files /dev/null and b/2016/SDL2.dll differ diff --git a/2016/VMProtectSDK32.dll b/2016/VMProtectSDK32.dll new file mode 100644 index 0000000..ac30c03 Binary files /dev/null and b/2016/VMProtectSDK32.dll differ diff --git a/2016/VortexiPlayerBeta.exe b/2016/VortexiPlayerBeta.exe new file mode 100644 index 0000000..2f87ea8 Binary files /dev/null and b/2016/VortexiPlayerBeta.exe differ diff --git a/2016/content/Modules/BackpackScript3D.lua b/2016/content/Modules/BackpackScript3D.lua new file mode 100644 index 0000000..5f67f6c --- /dev/null +++ b/2016/content/Modules/BackpackScript3D.lua @@ -0,0 +1,502 @@ +--BackpackScript3D: VR port of backpack interface using a 3D panel +--written by 0xBAADF00D +local ICON_SIZE = 48 +local ICON_SPACING = 52 +local PIXELS_PER_STUD = 64 + +local SLOT_BORDER_SIZE = 0 +local SLOT_BORDER_SELECTED_SIZE = 4 +local SLOT_BORDER_COLOR = Color3.new(90/255, 142/255, 233/255) +local SLOT_BACKGROUND_COLOR = Color3.new(0.2, 0.2, 0.2) +local SLOT_HOVER_BACKGROUND_COLOR = Color3.new(90/255, 90/255, 90/255) + +local HOPPERBIN_ANGLE = math.rad(-45) +local HOPPERBIN_ROTATION = CFrame.Angles(HOPPERBIN_ANGLE, 0, 0) +local HOPPERBIN_OFFSET = Vector3.new(0, 0, -5) + +local HEALTHBAR_SPACE = 12 +local HEALTHBAR_WIDTH = 82 +local HEALTHBAR_HEIGHT = 5 + +local NAME_SPACE = 14 + +local Tools = {} +local ToolsList = {} +local slotIcons = {} + +local BackpackScript = {} +local topbarEnabled = false + +local player = game.Players.LocalPlayer +local currentHumanoid = nil +local CoreGui = game:GetService('CoreGui') +local RobloxGui = CoreGui:WaitForChild("RobloxGui") +local Panel3D = require(RobloxGui.Modules.VR.Panel3D) +local Util = require(RobloxGui.Modules.Settings.Utility) + +local ContextActionService = game:GetService("ContextActionService") + +local BackpackPanel = Panel3D.Get("Backpack") +BackpackPanel:ResizeStuds(5, 2) +BackpackPanel:SetType(Panel3D.Type.Fixed, { CFrame = CFrame.new(0, 0, -5) }) +BackpackPanel:SetVisible(true) + +local toolsFrame = Instance.new("TextButton", BackpackPanel:GetGUI()) --prevent clicks falling through in case you have a rocket launcher and blow yourself up +toolsFrame.Text = "" +toolsFrame.Size = UDim2.new(1, 0, 0, ICON_SIZE) +toolsFrame.BackgroundTransparency = 1 +toolsFrame.Selectable = false +local insetAdjustY = toolsFrame.AbsolutePosition.Y +toolsFrame.Position = UDim2.new(0, 0, 0, HEALTHBAR_SPACE + NAME_SPACE) + +--Healthbar color function stolen from Topbar.lua +local HEALTH_BACKGROUND_COLOR = Color3.new(228/255, 236/255, 246/255) +local HEALTH_RED_COLOR = Color3.new(255/255, 28/255, 0/255) +local HEALTH_YELLOW_COLOR = Color3.new(250/255, 235/255, 0) +local HEALTH_GREEN_COLOR = Color3.new(27/255, 252/255, 107/255) + +local healthbarBack = Instance.new("ImageLabel", BackpackPanel:GetGUI()) +healthbarBack.ImageColor3 = HEALTH_BACKGROUND_COLOR +healthbarBack.BackgroundTransparency = 1 +healthbarBack.ScaleType = Enum.ScaleType.Slice +healthbarBack.SliceCenter = Rect.new(10, 10, 10, 10) +healthbarBack.Name = "HealthbarContainer" +healthbarBack.Image = "rbxasset://textures/ui/Menu/rectBackgroundWhite.png" +local healthbarFront = Instance.new("ImageLabel", healthbarBack) +healthbarFront.ImageColor3 = HEALTH_GREEN_COLOR +healthbarFront.BackgroundTransparency = 1 +healthbarFront.ScaleType = Enum.ScaleType.Slice +healthbarFront.SliceCenter = Rect.new(10, 10, 10, 10) +healthbarFront.Size = UDim2.new(1, 0, 1, 0) +healthbarFront.Position = UDim2.new(0, 0, 0, 0) +healthbarFront.Name = "HealthbarFill" +healthbarFront.Image = "rbxasset://textures/ui/Menu/rectBackgroundWhite.png" + +local playerName = Instance.new("TextLabel", BackpackPanel:GetGUI()) +playerName.Name = "PlayerName" +playerName.BackgroundTransparency = 1 +playerName.TextColor3 = Color3.new(1, 1, 1) +playerName.Text = player.Name +playerName.Font = Enum.Font.SourceSansBold +playerName.FontSize = Enum.FontSize.Size12 +playerName.TextXAlignment = Enum.TextXAlignment.Left +playerName.Size = UDim2.new(1, 0, 0, NAME_SPACE) + + +local healthColorToPosition = { + [Vector3.new(HEALTH_RED_COLOR.r, HEALTH_RED_COLOR.g, HEALTH_RED_COLOR.b)] = 0.1; + [Vector3.new(HEALTH_YELLOW_COLOR.r, HEALTH_YELLOW_COLOR.g, HEALTH_YELLOW_COLOR.b)] = 0.5; + [Vector3.new(HEALTH_GREEN_COLOR.r, HEALTH_GREEN_COLOR.g, HEALTH_GREEN_COLOR.b)] = 0.8; +} +local min = 0.1 +local minColor = HEALTH_RED_COLOR +local max = 0.8 +local maxColor = HEALTH_GREEN_COLOR + +local function HealthbarColorTransferFunction(healthPercent) + if healthPercent < min then + return minColor + elseif healthPercent > max then + return maxColor + end + + -- Shepard's Interpolation + local numeratorSum = Vector3.new(0,0,0) + local denominatorSum = 0 + for colorSampleValue, samplePoint in pairs(healthColorToPosition) do + local distance = healthPercent - samplePoint + if distance == 0 then + -- If we are exactly on an existing sample value then we don't need to interpolate + return Color3.new(colorSampleValue.x, colorSampleValue.y, colorSampleValue.z) + else + local wi = 1 / (distance*distance) + numeratorSum = numeratorSum + wi * colorSampleValue + denominatorSum = denominatorSum + wi + end + end + local result = numeratorSum / denominatorSum + return Color3.new(result.x, result.y, result.z) +end +--- + +local backpackEnabled = true +local healthbarEnabled = true + +local function UpdateLayout() + local width, height = 100, 100 + local borderSize = (ICON_SPACING - ICON_SIZE) / 2 + + local x = borderSize + local y = 0 + for _, tool in ipairs(ToolsList) do + local slot = Tools[tool] + if slot then + slot.icon.Position = UDim2.new(0, x, 0, y) + x = x + ICON_SPACING + end + end + + if #ToolsList == 0 then + width = HEALTHBAR_WIDTH + height = HEALTHBAR_SPACE + NAME_SPACE + BackpackPanel.showCursor = false + else + width = #ToolsList * ICON_SPACING + height = ICON_SIZE + HEALTHBAR_SPACE + NAME_SPACE + BackpackPanel.showCursor = true + end + + BackpackPanel:ResizePixels(width, height) + + playerName.Position = UDim2.new(0, borderSize, 0, 0) + + healthbarBack.Position = UDim2.new(0, borderSize, 0, NAME_SPACE + (HEALTHBAR_SPACE - HEALTHBAR_HEIGHT) / 2) + healthbarBack.Size = UDim2.new(0, HEALTHBAR_WIDTH, 0, HEALTHBAR_HEIGHT) +end + +local function UpdateHealth(humanoid) + local percentHealth = humanoid.Health / humanoid.MaxHealth + if percentHealth ~= percentHealth then + percentHealth = 1 + end + healthbarFront.BackgroundColor3 = HealthbarColorTransferFunction(percentHealth) + healthbarFront.Size = UDim2.new(percentHealth, 0, 1, 0) +end + +local function SetTransparency(transparency) + for i, v in pairs(Tools) do + v.bg.ImageTransparency = transparency + v.image.ImageTransparency = transparency + v.text.TextTransparency = transparency + end + + healthbarBack.ImageTransparency = transparency + healthbarFront.ImageTransparency = transparency +end + +local function OnHotbarEquipPrimary(actionName, state, obj) + if state ~= Enum.UserInputState.Begin then + return + end + for tool, slot in pairs(Tools) do + if slot.hovered then + slot.OnClick() + return + end + end +end + +local function EnableHotbarInput(enable) + if not backpackEnabled then + enable = false + end + if not currentHumanoid then + return + end + if enable then + ContextActionService:BindCoreAction("HotbarEquipPrimary", OnHotbarEquipPrimary, false, Enum.KeyCode.ButtonA, Enum.KeyCode.ButtonR2, Enum.UserInputType.MouseButton1) + else + ContextActionService:UnbindCoreAction("HotbarEquipPrimary") + end +end + +local function AddTool(tool) + if Tools[tool] then + return + end + + local slot = {} + Tools[tool] = slot + table.insert(ToolsList, tool) + + slot.hovered = false + slot.tool = tool + + slot.icon = Instance.new("TextButton", toolsFrame) + slot.icon.Text = "" + slot.icon.Size = UDim2.new(0, ICON_SIZE, 0, ICON_SIZE) + slot.icon.BackgroundColor3 = Color3.new(0, 0, 0) + slot.icon.Selectable = true + slot.icon.BackgroundTransparency = 1 + slotIcons[tool] = slot.icon + + slot.bg = Instance.new("ImageLabel", slot.icon) + slot.bg.Position = UDim2.new(0, -1, 0, -1) + slot.bg.Size = UDim2.new(1, 2, 1, 2) + slot.bg.Image = "rbxasset://textures/ui/Menu/rectBackground.png" + slot.bg.ScaleType = Enum.ScaleType.Slice + slot.bg.SliceCenter = Rect.new(10, 10, 10, 10) + slot.bg.BackgroundTransparency = 1 + + slot.image = Instance.new("ImageLabel", slot.icon) + slot.image.Position = UDim2.new(0, 1, 0, 1) + slot.image.Size = UDim2.new(1, -2, 1, -2) + slot.image.BackgroundTransparency = 1 + slot.image.Selectable = false + + slot.text = Instance.new("TextLabel", slot.icon) + slot.text.Position = UDim2.new(0, 1, 0, 1) + slot.text.Size = UDim2.new(1, -2, 1, -2) + slot.text.BackgroundTransparency = 1 + slot.text.TextColor3 = Color3.new(1, 1, 1) + slot.text.Font = Enum.Font.SourceSans + slot.text.FontSize = Enum.FontSize.Size12 + slot.text.ClipsDescendants = true + slot.text.Selectable = false + + local selectionObject = Util:Create'ImageLabel' + { + Name = 'SelectionObject'; + Size = UDim2.new(1,0,1,0); + BackgroundTransparency = 1; + Image = "rbxasset://textures/ui/Keyboard/key_selection_9slice.png"; + ImageTransparency = 0; + ScaleType = Enum.ScaleType.Slice; + SliceCenter = Rect.new(12,12,52,52); + BorderSizePixel = 0; + } + slot.icon.SelectionImageObject = selectionObject + + local function updateToolData() + slot.image.Image = tool.TextureId + slot.text.Text = tool.TextureId == "" and tool.Name or "" + end + updateToolData() + + slot.OnClick = function() + if not player.Character then return end + local humanoid = player.Character:FindFirstChild("Humanoid") + if not humanoid then return end + + local in_backpack = tool.Parent == player.Backpack + humanoid:UnequipTools() + if in_backpack then + humanoid:EquipTool(tool) + end + end + + slot.icon.MouseButton1Click:connect(slot.OnClick) + slot.OnEnter = function() + slot.hovered = true + end + slot.OnLeave = function() + slot.hovered = false + end +-- slot.icon.MouseEnter:connect(slot.OnEnter) +-- slot.icon.MouseLeave:connect(slot.OnLeave) + + tool.Changed:connect(function(prop) + if prop == "Parent" then + if tool.Parent == player:FindFirstChild("Backpack") then + slot.bg.Size = UDim2.new(0, ICON_SIZE, 0, ICON_SIZE) --temporary hold-over until new backpack design comes along (can't use border with this antialiased frame stand-in) + slot.bg.Position = UDim2.new(0, 0, 0, 0) + elseif tool.Parent == player.Character then + slot.bg.Size = UDim2.new(0, ICON_SIZE + 8, 0, ICON_SIZE + 8) + slot.bg.Position = UDim2.new(0, -4, 0, -4) + end + elseif prop == "TextureId" or prop == "Name" then + updateToolData() + end + end) + + UpdateLayout() +end + +local humanoidChangedEvent = nil +local humanoidAncestryChangedEvent = nil +local function RegisterHumanoid(humanoid) + currentHumanoid = humanoid + if humanoidChangedEvent then + humanoidChangedEvent:disconnect() + humanoidChangedEvent = nil + end + if humanoidAncestryChangedEvent then + humanoidAncestryChangedEvent:disconnect() + humanoidAncestryChangedEvent = nil + end + if humanoid then + humanoidChangedEvent = humanoid.HealthChanged:connect(function() UpdateHealth(humanoid) end) + humanoidAncestryChangedEvent = humanoid.AncestryChanged:connect(function(child, parent) + if child == humanoid and parent ~= player.Character then + RegisterHumanoid(nil) + end + end) + UpdateHealth(humanoid) + end +end + +local function OnChildAdded(child) + if child:IsA("Tool") or child:IsA("HopperBin") then + AddTool(child) + end + if child:IsA("Humanoid") and child.Parent == player.Character then + RegisterHumanoid(child) + end +end + +local function RemoveTool(tool) + if not Tools[tool] then + return + end + Tools[tool].icon:Destroy() + for i, v in ipairs(ToolsList) do + if v == tool then + table.remove(ToolsList, i) + break + end + end + Tools[tool] = nil + slotIcons[tool] = nil + UpdateLayout() +end + +local function OnChildRemoved(child) + if child:IsA("Tool") or child:IsA("HopperBin") then + if Tools[child] then + if child.Parent ~= player:FindFirstChild("Backpack") and child.Parent ~= player.Character then + RemoveTool(child) + end + end + end +end + +local function OnCharacterAdded(character) + local backpack = player:WaitForChild("Backpack") + + for i, v in ipairs(character:GetChildren()) do + if v:IsA("Humanoid") then + RegisterHumanoid(v) + break + end + end + + for tool, v in pairs(Tools) do + RemoveTool(tool) + end + Tools = {} + ToolsList = {} + + character.ChildAdded:connect(OnChildAdded) + character.ChildRemoved:connect(OnChildRemoved) + + for i, v in ipairs(backpack:GetChildren()) do + OnChildAdded(v) + end + + backpack.ChildAdded:connect(OnChildAdded) + backpack.ChildRemoved:connect(OnChildRemoved) +end + +player.CharacterAdded:connect(OnCharacterAdded) +if player.Character then + spawn(function() OnCharacterAdded(player.Character) end) +end + +local function OnHotbarEquip(actionName, state, obj) + if not backpackEnabled then + return + end + local character = player.Character + if not character then + return + end + if not currentHumanoid then + return + end + if state ~= Enum.UserInputState.Begin then + return + end + if #ToolsList == 0 then + return + end + local current = 0 + for i, v in pairs(ToolsList) do + if v.Parent == character then + current = i + end + end + currentHumanoid:UnequipTools() + if obj.KeyCode == Enum.KeyCode.ButtonR1 then + current = current + 1 + if current > #ToolsList then + current = 1 + end + else + current = current - 1 + if current < 1 then + current = #ToolsList + end + end + currentHumanoid:EquipTool(ToolsList[current]) +end + +local function OnCoreGuiChanged(coreGuiType, enabled) + -- Check for enabling/disabling the whole thing + if coreGuiType == Enum.CoreGuiType.Backpack or coreGuiType == Enum.CoreGuiType.All then + backpackEnabled = enabled + UpdateLayout() + if enabled then + ContextActionService:BindCoreAction("HotbarEquip2", OnHotbarEquip, false, Enum.KeyCode.ButtonL1, Enum.KeyCode.ButtonR1) + toolsFrame.Parent = BackpackPanel:GetGUI() + else + ContextActionService:UnbindCoreAction("HotbarEquip2") + toolsFrame.Parent = nil + end + end + + if coreGuiType == Enum.CoreGuiType.Health or coreGuiType == Enum.CoreGuiType.All then + healthbarEnabled = enabled + UpdateLayout() + if enabled then + healthbarBack.Parent = BackpackPanel:GetGUI() + else + healthbarBack.Parent = nil + end + end +end + +local StarterGui = game:GetService("StarterGui") +StarterGui.CoreGuiChangedSignal:connect(OnCoreGuiChanged) +OnCoreGuiChanged(Enum.CoreGuiType.Backpack, StarterGui:GetCoreGuiEnabled(Enum.CoreGuiType.Backpack)) +OnCoreGuiChanged(Enum.CoreGuiType.Backpack, StarterGui:GetCoreGuiEnabled(Enum.CoreGuiType.All)) + +OnCoreGuiChanged(Enum.CoreGuiType.Health, StarterGui:GetCoreGuiEnabled(Enum.CoreGuiType.Health)) +OnCoreGuiChanged(Enum.CoreGuiType.Health, StarterGui:GetCoreGuiEnabled(Enum.CoreGuiType.All)) + +local panelLocalCF = CFrame.new(0, -3.5, 5) * CFrame.Angles(math.rad(20), 0, 0) + +function BackpackPanel:PreUpdate(cameraCF, cameraRenderCF, userHeadCF, lookRay) + --the backpack panel needs to go in front of the user when they look at it. + --if they aren't looking, we should be updating self.localCF + if self.transparency == 1 then + local headForwardCF = Panel3D.GetHeadLookXZ() + local panelOriginCF = CFrame.new(userHeadCF.p) * headForwardCF + self.localCF = panelOriginCF * panelLocalCF + end +end + +function BackpackPanel:OnUpdate() + SetTransparency(self.transparency) + + local hovered, tool = BackpackPanel:FindHoveredGuiElement(slotIcons) + if hovered and tool then + local slot = Tools[tool] + if not slot.hovered then + slot.OnEnter() + end + for i, v in pairs(Tools) do + if v.hovered and v ~= slot then + v.OnLeave() + end + end + end +end + +function BackpackPanel:OnMouseEnter(x, y) + EnableHotbarInput(true) +end +function BackpackPanel:OnMouseLeave(x, y) + EnableHotbarInput(false) +end + +return BackpackScript \ No newline at end of file diff --git a/2016/content/Modules/Chat.lua b/2016/content/Modules/Chat.lua new file mode 100644 index 0000000..f715a4f --- /dev/null +++ b/2016/content/Modules/Chat.lua @@ -0,0 +1,2726 @@ +--[[ + // FileName: Chat.lua + // Written by: SolarCrane + // Description: Code for lua side chat on ROBLOX. +]] + +--[[ CONSTANTS ]] + +-- NOTE: IF YOU WANT TO USE THIS CHAT SCRIPT IN YOUR OWN GAME: +-- 1) COPY THE CONTENTS OF THIS FILE INTO A MODULE +-- 2) CREATE A LOCALSCRIPT AND PARENT IT TO StarterGui +-- 3) IN THE LOCALSCRIPT require() THE CHAT MODULE YOU MADE IN STEP 1 +-- 4) CONFIGURE YOUR PLACE ON THE WEBSITE TO USE BUBBLE-CHAT +-- 5) SET THE FOLLOWING TWO VARIABLES TO TRUE +local FORCE_CHAT_GUI = false +local NON_CORESCRIPT_MODE = false +-- 6) (OPTIONAL) PUT THE FOLLOWING LINE IN A SERVER SCRIPT TO MAKE CHAT PERSIST THROUGH RESPAWNING +-- game:GetService('StarterGui').ResetPlayerGuiOnSpawn = false +--------------------------------- + +local MESSAGES_FADE_OUT_TIME = 30 +local MAX_UDIM_SIZE = 2^15 - 1 + +local PHONE_SCREEN_WIDTH = 640 +local TABLET_SCREEN_WIDTH = 1024 + +local FLOOD_CHECK_MESSAGE_COUNT = 7 +local FLOOD_CHECK_MESSAGE_INTERVAL = 15 -- This is in seconds + +local VR_CHAT_CLICK_DEBOUNCE = 0.25 + +local SCROLLBAR_THICKNESS = 7 +local CHAT_COLORS = +{ + Color3.new(253/255, 41/255, 67/255), -- BrickColor.new("Bright red").Color, + Color3.new(1/255, 162/255, 255/255), -- BrickColor.new("Bright blue").Color, + Color3.new(2/255, 184/255, 87/255), -- BrickColor.new("Earth green").Color, + BrickColor.new("Bright violet").Color, + BrickColor.new("Bright orange").Color, + BrickColor.new("Bright yellow").Color, + BrickColor.new("Light reddish violet").Color, + BrickColor.new("Brick yellow").Color, +} + +local emptySelectionImage = Instance.new("ImageLabel") +emptySelectionImage.ImageTransparency = 1 +emptySelectionImage.BackgroundTransparency = 1 + +--[[ END OF CONSTANTS ]] + +--[[ SERVICES ]] +local RunService = game:GetService('RunService') +local CoreGuiService = game:GetService('CoreGui') +local PlayersService = game:GetService('Players') +local DebrisService = game:GetService('Debris') +local GuiService = game:GetService('GuiService') +local InputService = game:GetService('UserInputService') +local StarterGui = game:GetService('StarterGui') +local ContextActionService = game:GetService('ContextActionService') +--[[ END OF SERVICES ]] + +--[[ Fast Flags ]]-- +local playerDropDownEnabledSuccess, playerDropDownEnabledFlagValue = pcall(function() return settings():GetFFlag("PlayerDropDownEnabled") end) +local IsPlayerDropDownEnabled = playerDropDownEnabledSuccess and playerDropDownEnabledFlagValue + +local getMoveChatSuccess, moveChatActiveValue = pcall(function() return settings():GetFFlag("SetCoreMoveChat") end) +local allowMoveChat = getMoveChatSuccess and moveChatActiveValue + +local getDisableChatBarSuccess, disableChatBarValue = pcall(function() return settings():GetFFlag("SetCoreDisableChatBar") end) +local allowDisableChatBar = getDisableChatBarSuccess and disableChatBarValue + +--[[ SCRIPT VARIABLES ]] + +-- I am not fond of waiting at the top of the script here... +while PlayersService.LocalPlayer == nil do PlayersService.ChildAdded:wait() end +local Player = PlayersService.LocalPlayer +-- GuiRoot will act as the top-node for parenting GUIs +local GuiRoot = Instance.new('Frame') +GuiRoot.Name = 'GuiRoot'; +GuiRoot.Size = UDim2.new(1,0,1,0); +GuiRoot.BackgroundTransparency = 1; + + + +local chatRepositioned = false +local chatBarDisabled = false + +local lastSelectedPlayer = nil +local lastSelectedButton = nil + +local playerDropDownModule = nil +local playerDropDown = nil +local blockingUtility = nil + +local topbarEnabled = true + + + +if not NON_CORESCRIPT_MODE and not InputService.VREnabled then + playerDropDownModule = require(CoreGuiService:WaitForChild('RobloxGui').Modules:WaitForChild("PlayerDropDown")) + playerDropDown = playerDropDownModule:CreatePlayerDropDown() + blockingUtility = playerDropDownModule:CreateBlockingUtility() +end + +--[[ END OF SCRIPT VARIABLES ]] + +local function GetLuaChatFilteringFlag() + local flagSuccess, flagValue = pcall(function() return settings():GetFFlag("LuaChatFiltering") end) + return flagSuccess and flagValue == true +end + +local Util = {} +do + -- Check if we are running on a touch device + function Util.IsTouchDevice() + local touchEnabled = false + pcall(function() touchEnabled = InputService.TouchEnabled end) + return touchEnabled + end + + function Util.IsSmallScreenSize() + return GuiRoot.AbsoluteSize.X <= PHONE_SCREEN_WIDTH + end + + function Util.Create(instanceType) + return function(data) + local obj = Instance.new(instanceType) + for k, v in pairs(data) do + if type(k) == 'number' then + v.Parent = obj + else + obj[k] = v + end + end + return obj + end + end + + function Util.Clamp(low, high, input) + return math.max(low, math.min(high, input)) + end + + function Util.Linear(t, b, c, d) + if t >= d then return b + c end + + return c*t/d + b + end + + function Util.EaseOutQuad(t, b, c, d) + if t >= d then return b + c end + + t = t/d; + return -c * t*(t-2) + b + end + + function Util.EaseInOutQuad(t, b, c, d) + if t >= d then return b + c end + + t = t / (d/2); + if (t < 1) then return c/2*t*t + b end; + t = t - 1; + return -c/2 * (t*(t-2) - 1) + b; + end + + function Util.PropertyTweener(instance, prop, start, final, duration, easingFunc, cbFunc) + local this = {} + this.StartTime = tick() + this.EndTime = this.StartTime + duration + this.Cancelled = false + + local finished = false + local percentComplete = 0 + spawn(function() + local now = tick() + while now < this.EndTime and instance do + if this.Cancelled then + return + end + instance[prop] = easingFunc(now - this.StartTime, start, final - start, duration) + percentComplete = Util.Clamp(0, 1, (now - this.StartTime) / duration) + RunService.RenderStepped:wait() + now = tick() + end + if this.Cancelled == false and instance then + instance[prop] = final + finished = true + percentComplete = 1 + if cbFunc then + cbFunc() + end + end + end) + + function this:GetPercentComplete() + return percentComplete + end + + function this:IsFinished() + return finished + end + + function this:Cancel() + this.Cancelled = true + end + + return this + end + + function Util.Signal() + local sig = {} + + local mSignaler = Instance.new('BindableEvent') + + local mArgData = nil + local mArgDataCount = nil + + function sig:fire(...) + mArgData = {...} + mArgDataCount = select('#', ...) + mSignaler:Fire() + end + + function sig:connect(f) + if not f then error("connect(nil)", 2) end + return mSignaler.Event:connect(function() + f(unpack(mArgData, 1, mArgDataCount)) + end) + end + + function sig:wait() + mSignaler.Event:wait() + assert(mArgData, "Missing arg data, likely due to :TweenSize/Position corrupting threadrefs.") + return unpack(mArgData, 1, mArgDataCount) + end + + return sig + end + + function Util.DisconnectEvent(conn) + if conn then + conn:disconnect() + end + return nil + end + + function Util.SetGUIInsetBounds(x, y) + local success, _ = pcall(function() GuiService:SetGlobalGuiInset(0, x, 0, y) end) + if not success then + pcall(function() GuiService:SetGlobalSizeOffsetPixel(-x, -y) end) -- Legacy GUI-offset function + end + end + + local baseUrl = game:GetService("ContentProvider").BaseUrl:lower() + baseUrl = string.gsub(baseUrl,"/m.","/www.") --mobile site does not work for this stuff! + function Util.GetSecureApiBaseUrl() + local secureApiUrl = baseUrl + secureApiUrl = string.gsub(secureApiUrl,"http://","https://") + secureApiUrl = string.gsub(secureApiUrl,"www","api") + return secureApiUrl + end + + function Util.GetPlayerByName(playerName) + -- O(n), may be faster if I store a reverse hash from the players list; can't trust FindFirstChild in PlayersService because anything can be parented to there. + local lowerName = string.lower(playerName) + for _, player in pairs(PlayersService:GetPlayers()) do + if string.lower(player.Name) == lowerName then + return player + end + end + return nil -- Found no player + end + + local adminCache = {} + function Util.IsPlayerAdminAsync(player) + local userId = player and player.userId + if userId then + if adminCache[userId] == nil then + local isAdmin = false + -- Many things can error is the IsInGroup check + pcall(function() + isAdmin = [1] + end) + adminCache[userId] = isAdmin + end + return adminCache[userId] + end + return false + end + + local function GetNameValue(pName) + local value = 0 + for index = 1, #pName do + local cValue = string.byte(string.sub(pName, index, index)) + local reverseIndex = #pName - index + 1 + if #pName%2 == 1 then + reverseIndex = reverseIndex - 1 + end + if reverseIndex%4 >= 2 then + cValue = -cValue + end + value = value + cValue + end + return value + end + + function Util.ComputeChatColor(pName) + return CHAT_COLORS[(GetNameValue(pName) % #CHAT_COLORS) + 1] + end + + -- This is a memo-izing function + local testLabel = Instance.new('TextLabel') + testLabel.TextWrapped = true; + testLabel.Position = UDim2.new(1,0,1,0) + testLabel.Parent = GuiRoot -- Note: We have to parent it to check TextBounds + -- The TextSizeCache table looks like this Text->Font->sizeBounds->FontSize + local TextSizeCache = {} + function Util.GetStringTextBounds(text, font, fontSize, sizeBounds) + -- If no sizeBounds are specified use some huge number + sizeBounds = sizeBounds or false + if not TextSizeCache[text] then + TextSizeCache[text] = {} + end + if not TextSizeCache[text][font] then + TextSizeCache[text][font] = {} + end + if not TextSizeCache[text][font][sizeBounds] then + TextSizeCache[text][font][sizeBounds] = {} + end + if not TextSizeCache[text][font][sizeBounds][fontSize] then + testLabel.Text = text + testLabel.Font = font + testLabel.FontSize = fontSize + if sizeBounds then + testLabel.TextWrapped = true; + testLabel.Size = sizeBounds + else + testLabel.TextWrapped = false; + end + TextSizeCache[text][font][sizeBounds][fontSize] = testLabel.TextBounds + end + return TextSizeCache[text][font][sizeBounds][fontSize] + end + + local PRINTABLE_CHARS = '[^' .. string.char(32) .. '-' .. string.char(126) .. ']' + local WHITESPACE_CHARS = '(' .. string.rep('%s', 7) .. ')%s+' + function Util.FilterUnprintableCharacters(str) + if not GetLuaChatFilteringFlag() then + return str + end + + local result = str:gsub(PRINTABLE_CHARS, ''); + result = str:gsub(WHITESPACE_CHARS, '%1'); + return result + end +end + +local SelectChatModeEvent = Util.Signal() +local SelectPlayerEvent = Util.Signal() + +local function CreateChatMessage() + local this = {} + this.FadeRoutines = {} + + function this:GetMessageFontSize(settings) + return Util.IsSmallScreenSize() and settings.SmallScreenFontSize or settings.FontSize + end + + function this:OnResize() + -- Nothing! + end + + function this:FadeIn() + local gui = this:GetGui() + if gui then + gui.Visible = true + end + end + + function this:FadeOut() + local gui = this:GetGui() + if gui then + gui.Visible = false + end + end + + function this:GetGui() + return this.Container + end + + function this:Destroy() + if this.Container ~= nil then + this.Container:Destroy() + this.Container = nil + end + if this.FadeRoutines then + for _, routine in pairs(this.FadeRoutines) do + routine:Cancel() + end + this.FadeRoutines = {} + end + end + + return this +end + +local function CreateSystemChatMessage(settings, chattedMessage) + local this = CreateChatMessage() + + this.Settings = settings + this.rawChatString = chattedMessage + + function this:OnResize(containerSize) + if this.Container and this.ChatMessage then + + if InputService.VREnabled then + this.ChatMessage.Position = UDim2.new(0, 4, 0, 0) + this.ChatMessage.Size = UDim2.new(1, 0, 1, 0) + end + + this.Container.Size = UDim2.new(1,0,0,1000) + local textHeight = this.ChatMessage.TextBounds.Y + + local newContainerHeight = textHeight + 5 + this.Container.Size = UDim2.new(1,0,0,newContainerHeight) + return newContainerHeight + end + end + + function this:FadeIn() + local gui = this:GetGui() + if gui then + gui.Visible = true + for _, routine in pairs(this.FadeRoutines) do + routine:Cancel() + end + this.FadeRoutines = {} + local tweenableObjects = { + this.ChatMessage; + } + for _, object in pairs(tweenableObjects) do + object.TextTransparency = 0; + object.TextStrokeTransparency = this.Settings.TextStrokeTransparency; + end + + if this.MessageBackgroundImage then + this.MessageBackgroundImage.Visible = InputService.VREnabled + end + end + end + + function this:FadeOut(instant) + local gui = this:GetGui() + if gui then + if instant then + gui.Visible = false + else + local tweenableObjects = { + this.ChatMessage; + } + for _, object in pairs(tweenableObjects) do + table.insert(this.FadeRoutines, Util.PropertyTweener(object, 'TextTransparency', object.TextTransparency, 1, 1, Util.Linear)) + table.insert(this.FadeRoutines, Util.PropertyTweener(object, 'TextStrokeTransparency', object.TextStrokeTransparency, 1, 0.85, Util.Linear)) + end + end + if this.MessageBackgroundImage then + this.MessageBackgroundImage.Visible = false + end + end + end + + local function CreateMessageGuiElement() + local fontSize = this:GetMessageFontSize(this.Settings) + + local systemMessageDisplayText = this.rawChatString or "" + local systemMessageSize = Util.GetStringTextBounds(systemMessageDisplayText, this.Settings.Font, fontSize, UDim2.new(0, 400, 0, 1000)) + + local container = Util.Create'Frame' + { + Name = 'MessageContainer'; + Position = UDim2.new(0, 0, 0, 0); + ZIndex = 1; + BackgroundColor3 = Color3.new(0, 0, 0); + BackgroundTransparency = 1; + }; + this.MessageBackgroundImage = Util.Create'ImageLabel' + { + Name = 'TextEntryBackground'; + Size = UDim2.new(1,0,1,-2); + Position = UDim2.new(0,0,0,1); + Image = 'rbxasset://textures/ui/Chat/VRChatBackground.png'; + ScaleType = Enum.ScaleType.Slice; + SliceCenter = Rect.new(8,8,56,56); + BackgroundTransparency = 1; + ImageTransparency = 0.3; + BorderSizePixel = 0; + ZIndex = 1; + Visible = InputService.VREnabled; + Parent = container; + } + + local chatMessage = Util.Create'TextLabel' + { + Name = 'SystemChatMessage'; + Position = UDim2.new(0, 0, 0, 0); + Size = UDim2.new(1, 0, 1, 0); + Text = systemMessageDisplayText; + ZIndex = 1; + BackgroundColor3 = Color3.new(0, 0, 0); + BackgroundTransparency = 1; + TextXAlignment = Enum.TextXAlignment.Left; + TextYAlignment = Enum.TextYAlignment.Top; + TextWrapped = true; + TextColor3 = this.Settings.DefaultMessageTextColor; + FontSize = fontSize; + Font = this.Settings.Font; + TextStrokeColor3 = this.Settings.TextStrokeColor; + TextStrokeTransparency = this.Settings.TextStrokeTransparency; + Parent = container; + }; + if InputService.VREnabled then + chatMessage.Position = UDim2.new(0, 4, 0, 0) + chatMessage.Size = UDim2.new(1, 0, 1, 0) + end + + container.Size = UDim2.new(1, 0, 0, systemMessageSize.Y + 1); + this.Container = container + this.ChatMessage = chatMessage + end + + CreateMessageGuiElement() + + return this +end + +--[[ Popup Handling ]]-- +function createPopupFrame(selectedPlayer, selectedButton) + if selectedPlayer and selectedPlayer.Parent == PlayersService then + if lastSelectedButton ~= selectedButton then + if lastSelectedButton ~= nil then + lastSelectedButton.BackgroundTransparency = 1 + lastSelectedButton = nil + end + lastSelectedButton = selectedButton + lastSelectedPlayer = selectedPlayer + selectedButton.BackgroundTransparency = 0.5 + + if IsPlayerDropDownEnabled then + playerDropDown.HidePopupImmediately = true + local PopupFrame = playerDropDown:CreatePopup(selectedPlayer) + PopupFrame.Position = UDim2.new(0, selectedButton.AbsolutePosition.X + selectedButton.AbsoluteSize.X + 2, 0, selectedButton.AbsolutePosition.Y) + PopupFrame.Size = UDim2.new(0, 150, PopupFrame.Size.Y.Scale, PopupFrame.Size.Y.Offset) + PopupFrame.ZIndex = 5 + PopupFrame.Parent = GuiRoot + end + + for _, button in pairs(PopupFrame:GetChildren()) do + button.BackgroundTransparency = 0 + button.ZIndex = 6 + end + else + if IsPlayerDropDownEnabled then + playerDropDown:Hide() + end + lastSelectedPlayer = nil + end + end +end + +function popupHidden() + if lastSelectedButton then + lastSelectedPlayer = nil + lastSelectedButton.BackgroundTransparency = 1 + lastSelectedButton = nil + end +end + +if IsPlayerDropDownEnabled and playerDropDown then + playerDropDown.HiddenSignal:connect(popupHidden) +end + +InputService.InputBegan:connect(function(inputObject, isProcessed) + if isProcessed then return end + local inputType = inputObject.UserInputType + if (inputType == Enum.UserInputType.Touch and inputObject.UserInputState == Enum.UserInputState.Begin) or + inputType == Enum.UserInputType.MouseButton1 then + if lastSelectedButton and IsPlayerDropDownEnabled then + playerDropDown:Hide() + end + end +end) + +--[[ End of popup handling ]]-- + +local function CreatePlayerChatMessage(settings, playerChatType, sendingPlayer, chattedMessage, receivingPlayer) + local this = CreateChatMessage() + + this.Settings = settings + this.PlayerChatType = playerChatType + this.SendingPlayer = sendingPlayer + this.RawMessageContent = chattedMessage + this.ReceivingPlayer = receivingPlayer + this.ReceivedTime = tick() + + this.Neutral = this.SendingPlayer and this.SendingPlayer.Neutral or true + this.TeamColor = this.SendingPlayer and this.SendingPlayer.TeamColor or BrickColor.new("White") + + function this:OnResize(containerSize) + if this.Container and this.ChatMessage then + this.Container.Size = UDim2.new(1,0,0,1000) + local textHeight = this.ChatMessage.TextBounds.Y + local newContainerHeight = textHeight + 5 + this.Container.Size = UDim2.new(1,0,0,newContainerHeight) + return newContainerHeight + end + end + + function this:FormatMessage() + local result = "" + if this.RawMessageContent then + local message = this.RawMessageContent + result = message + end + return result + end + + function this:FormatChatType() + if this.PlayerChatType then + if this.PlayerChatType == Enum.PlayerChatType.All then + --return "[All]" + elseif this.PlayerChatType == Enum.PlayerChatType.Team then + return "[Team]" + elseif this.PlayerChatType == Enum.PlayerChatType.Whisper then + -- nothing! + end + end + end + + function this:FormatPlayerNameText() + local playerName = "" + -- If we are sending a whisper to someone, then we should show their name + if this.PlayerChatType == Enum.PlayerChatType.Whisper and this.SendingPlayer and this.SendingPlayer == Player then + playerName = (this.ReceivingPlayer and this.ReceivingPlayer.Name or "") + else + playerName = (this.SendingPlayer and this.SendingPlayer.Name or "") + end + return "[" .. playerName .. "]:" + end + + function this:FadeIn() + local gui = this:GetGui() + if gui then + gui.Visible = true + for _, routine in pairs(this.FadeRoutines) do + routine:Cancel() + end + this.FadeRoutines = {} + local tweenableObjects = { + this.WhisperToText; + this.WhisperFromText; + this.ChatModeButton; + this.UserNameButton; + this.ChatMessage; + } + for _, object in pairs(tweenableObjects) do + object.TextTransparency = 0; + object.TextStrokeTransparency = this.Settings.TextStrokeTransparency; + object.Active = true + end + if this.UserNameDot then + this.UserNameDot.ImageTransparency = 0 + end + + if this.MessageBackgroundImage then + this.MessageBackgroundImage.Visible = InputService.VREnabled + end + end + end + + function this:FadeOut(instant) + local gui = this:GetGui() + if gui then + if instant then + gui.Visible = false + else + local tweenableObjects = { + this.WhisperToText; + this.WhisperFromText; + this.ChatModeButton; + this.UserNameButton; + this.ChatMessage; + } + for _, object in pairs(tweenableObjects) do + table.insert(this.FadeRoutines, Util.PropertyTweener(object, 'TextTransparency', object.TextTransparency, 1, 1, Util.Linear)) + table.insert(this.FadeRoutines, Util.PropertyTweener(object, 'TextStrokeTransparency', object.TextStrokeTransparency, 1, 0.85, Util.Linear)) + object.Active = false + end + if this.UserNameDot then + table.insert(this.FadeRoutines, Util.PropertyTweener(this.UserNameDot, 'ImageTransparency', this.UserNameDot.ImageTransparency, 1, 1, Util.Linear)) + end + end + if this.MessageBackgroundImage then + this.MessageBackgroundImage.Visible = false + end + end + end + + function this:Destroy() + if this.Container ~= nil then + this.Container:Destroy() + this.Container = nil + end + this.ClickedOnModeConn = Util.DisconnectEvent(this.ClickedOnModeConn) + this.ClickedOnPlayerConn = Util.DisconnectEvent(this.ClickedOnPlayerConn) + this.RightClickedOnPlayerConn = Util.DisconnectEvent(this.RightClickedOnPlayerConn) + end + + local function CreateMessageGuiElement() + local fontSize = this:GetMessageFontSize(this.Settings) + + local toMesasgeDisplayText = "To " + local toMessageSize = Util.GetStringTextBounds(toMesasgeDisplayText, this.Settings.Font, fontSize) + local fromMesasgeDisplayText = "From " + local fromMessageSize = Util.GetStringTextBounds(fromMesasgeDisplayText, this.Settings.Font, fontSize) + local chatTypeDisplayText = this:FormatChatType() + local chatTypeSize = chatTypeDisplayText and Util.GetStringTextBounds(chatTypeDisplayText, this.Settings.Font, fontSize) or Vector2.new(0,0) + local playerNameDisplayText = this:FormatPlayerNameText() + local playerNameSize = Util.GetStringTextBounds(playerNameDisplayText, this.Settings.Font, fontSize) + + local singleSpaceSize = Util.GetStringTextBounds(" ", this.Settings.Font, fontSize) + local numNeededSpaces = math.ceil(playerNameSize.X / singleSpaceSize.X) + 1 + local chatMessageDisplayText = string.rep(" ", numNeededSpaces) .. this:FormatMessage() + local chatMessageSize = Util.GetStringTextBounds(chatMessageDisplayText, this.Settings.Font, fontSize, UDim2.new(0, 400 - 5 - playerNameSize.X, 0, 1000)) + + + local playerColor = this.Settings.DefaultMessageTextColor + if this.SendingPlayer then + if this.PlayerChatType == Enum.PlayerChatType.Whisper then + if this.SendingPlayer == Player and this.ReceivingPlayer then + playerColor = Util.ComputeChatColor(this.ReceivingPlayer.Name) + else + playerColor = Util.ComputeChatColor(this.SendingPlayer.Name) + end + else + if this.SendingPlayer.Neutral then + playerColor = Util.ComputeChatColor(this.SendingPlayer.Name) + else + playerColor = this.SendingPlayer.TeamColor.Color + end + end + end + + local container = Util.Create'Frame' + { + Name = 'MessageContainer'; + Position = UDim2.new(0, 0, 0, 0); + ZIndex = 1; + BackgroundColor3 = Color3.new(0, 0, 0); + BackgroundTransparency = 1; + }; + this.MessageBackgroundImage = Util.Create'ImageLabel' + { + Name = 'TextEntryBackground'; + Size = UDim2.new(1,0,1,-2); + Position = UDim2.new(0,0,0,1); + Image = 'rbxasset://textures/ui/Chat/VRChatBackground.png'; + ScaleType = Enum.ScaleType.Slice; + SliceCenter = Rect.new(8,8,56,56); + BackgroundTransparency = 1; + ImageTransparency = 0.3; + BorderSizePixel = 0; + ZIndex = 1; + Visible = InputService.VREnabled; + Parent = container; + } + + local xOffset = InputService.VREnabled and 4 or 0 + + if this.SendingPlayer and this.SendingPlayer == Player and this.PlayerChatType == Enum.PlayerChatType.Whisper then + local whisperToText = Util.Create'TextLabel' + { + Name = 'WhisperTo'; + Position = UDim2.new(0, 0, 0, 0); + Size = UDim2.new(0, toMessageSize.X, 0, toMessageSize.Y); + Text = toMesasgeDisplayText; + ZIndex = 1; + BackgroundColor3 = Color3.new(0, 0, 0); + BackgroundTransparency = 1; + TextXAlignment = Enum.TextXAlignment.Left; + TextYAlignment = Enum.TextYAlignment.Top; + TextWrapped = true; + TextColor3 = this.Settings.DefaultMessageTextColor; + FontSize = fontSize; + Font = this.Settings.Font; + TextStrokeColor3 = this.Settings.TextStrokeColor; + TextStrokeTransparency = this.Settings.TextStrokeTransparency; + Parent = container; + }; + xOffset = xOffset + toMessageSize.X + this.WhisperToText = whisperToText + elseif this.SendingPlayer and this.SendingPlayer ~= Player and this.PlayerChatType == Enum.PlayerChatType.Whisper then + local whisperFromText = Util.Create'TextLabel' + { + Name = 'WhisperFromText'; + Position = UDim2.new(0, 0, 0, 0); + Size = UDim2.new(0, fromMessageSize.X, 0, fromMessageSize.Y); + Text = fromMesasgeDisplayText; + ZIndex = 1; + BackgroundColor3 = Color3.new(0, 0, 0); + BackgroundTransparency = 1; + TextXAlignment = Enum.TextXAlignment.Left; + TextYAlignment = Enum.TextYAlignment.Top; + TextWrapped = true; + TextColor3 = this.Settings.DefaultMessageTextColor; + FontSize = fontSize; + Font = this.Settings.Font; + TextStrokeColor3 = this.Settings.TextStrokeColor; + TextStrokeTransparency = this.Settings.TextStrokeTransparency; + Parent = container; + }; + xOffset = xOffset + fromMessageSize.X + this.WhisperFromText = whisperFromText + end + if chatTypeDisplayText then + local chatModeButton = Util.Create(Util.IsTouchDevice() and 'TextLabel' or 'TextButton') + { + Name = 'ChatMode'; + BackgroundTransparency = 1; + ZIndex = 2; + Text = chatTypeDisplayText; + TextColor3 = this.Settings.DefaultMessageTextColor; + Position = UDim2.new(0, xOffset, 0, 0); + TextXAlignment = Enum.TextXAlignment.Left; + TextYAlignment = Enum.TextYAlignment.Top; + FontSize = fontSize; + Font = this.Settings.Font; + Size = UDim2.new(0, chatTypeSize.X, 0, chatTypeSize.Y); + TextStrokeColor3 = this.Settings.TextStrokeColor; + TextStrokeTransparency = this.Settings.TextStrokeTransparency; + Parent = container + } + if chatModeButton:IsA('TextButton') then + this.ClickedOnModeConn = chatModeButton.MouseButton1Click:connect(function() + SelectChatModeEvent:fire(this.PlayerChatType) + end) + end + if this.PlayerChatType == Enum.PlayerChatType.Team then + chatModeButton.TextColor3 = playerColor + end + xOffset = xOffset + chatTypeSize.X + 1 + this.ChatModeButton = chatModeButton + end + local userNameButton = Util.Create(Util.IsTouchDevice() and 'TextLabel' or 'TextButton') + { + Name = 'PlayerName'; + BackgroundTransparency = 1; + BackgroundColor3 = Color3.new(0, 1, 1); + BorderSizePixel = 0; + ZIndex = 2; + Text = playerNameDisplayText; + TextColor3 = playerColor; + Position = UDim2.new(0, xOffset, 0, 0); + TextXAlignment = Enum.TextXAlignment.Left; + TextYAlignment = Enum.TextYAlignment.Top; + FontSize = fontSize; + Font = this.Settings.Font; + Size = UDim2.new(0, playerNameSize.X, 0, playerNameSize.Y); + TextStrokeColor3 = this.Settings.TextStrokeColor; + TextStrokeTransparency = this.Settings.TextStrokeTransparency; + Parent = container + } + if userNameButton:IsA('TextButton') then + this.ClickedOnPlayerConn = userNameButton.MouseButton1Click:connect(function() + local gui = this:GetGui() + if gui and gui.Visible then + if this.PlayerChatType == Enum.PlayerChatType.Whisper and this.SendingPlayer == Player and this.ReceivingPlayer then + SelectPlayerEvent:fire(this.ReceivingPlayer) + else + SelectPlayerEvent:fire(this.SendingPlayer) + end + end + end) + this.RightClickedOnPlayerConn = userNameButton.MouseButton2Click:connect(function() + local gui = this:GetGui() + if gui and gui.Visible then + if IsPlayerDropDownEnabled and playerDropDown then + if this.SendingPlayer and this.SendingPlayer ~= Player then + createPopupFrame(this.SendingPlayer, userNameButton) + end + end + end + end) + end + + local chatMessage = Util.Create'TextLabel' + { + Name = 'ChatMessage'; + Position = UDim2.new(0, xOffset, 0, 0); + Size = UDim2.new(1, -xOffset, 1, 0); + Text = chatMessageDisplayText; + ZIndex = 1; + BackgroundColor3 = Color3.new(0, 0, 0); + BackgroundTransparency = 1; + TextXAlignment = Enum.TextXAlignment.Left; + TextYAlignment = Enum.TextYAlignment.Top; + TextWrapped = true; + TextColor3 = this.Settings.DefaultMessageTextColor; + FontSize = fontSize; + Font = this.Settings.Font; + TextStrokeColor3 = this.Settings.TextStrokeColor; + TextStrokeTransparency = this.Settings.TextStrokeTransparency; + Parent = container; + }; + if InputService.VREnabled then + chatMessage.Size = chatMessage.Size - UDim2.new(0,4,0,0) + end + -- Check if they got moderated and put up a real message instead of Label + if chatMessage.Text == 'Label' and chatMessageDisplayText ~= 'Label' then + chatMessage.Text = string.rep(" ", numNeededSpaces) .. '[Content Deleted]' + end + if this.SendingPlayer and Util.IsPlayerAdminAsync(this.SendingPlayer) then + chatMessage.TextColor3 = this.Settings.AdminTextColor + end + chatMessage.Size = chatMessage.Size + UDim2.new(0, 0, 0, chatMessage.TextBounds.Y); + + container.Size = UDim2.new(1, 0, 0, math.max(chatMessageSize.Y + 1, userNameButton.Size.Y.Offset + 1)); + this.Container = container + this.ChatMessage = chatMessage + this.UserNameButton = userNameButton + end + + CreateMessageGuiElement() + + return this +end + +local function CreateChatBarWidget(settings) + local this = {} + + -- MessageModes: {All, Team, Whisper} + this.MessageMode = 'All' + this.TargetWhisperPlayer = nil + this.Settings = settings + + this.WidgetVisible = false + this.FadedIn = true + + this.ChatBarGainedFocusEvent = Util.Signal() + this.ChatBarLostFocusEvent = Util.Signal() + this.ChatCommandEvent = Util.Signal() -- Signal Signatue: success, actionType, [captures] + this.ChatErrorEvent = Util.Signal() -- Signal Signatue: success, actionType, [captures] + this.ChatBarFloodEvent = Util.Signal() + + this.unfocusedAt = 0 + + local chatCoreGuiEnabled = true + + -- This function while lets string.find work case-insensitively without clobbering the case of the captures + local function nocase(s) + s = string.gsub(s, "%a", function (c) + return string.format("[%s%s]", string.lower(c), + string.upper(c)) + end) + return s + end + + this.ChatMatchingRegex = + { + [function(chatBarText) return string.find(chatBarText, nocase("^/w ") .. "(%w+_?%w+)") end] = "Whisper"; + [function(chatBarText) return string.find(chatBarText, nocase("^/whisper ") .. "(%w+_?%w+)") end] = "Whisper"; + + [function(chatBarText) return string.find(chatBarText, "^%%") end] = "Team"; + [function(chatBarText) return string.find(chatBarText, "^%(TEAM%)") end] = "Team"; + [function(chatBarText) return string.find(chatBarText, nocase("^/t")) end] = "Team"; + [function(chatBarText) return string.find(chatBarText, nocase("^/team")) end] = "Team"; + + [function(chatBarText) return string.find(chatBarText, nocase("^/a")) end] = "All"; + [function(chatBarText) return string.find(chatBarText, nocase("^/all")) end] = "All"; + [function(chatBarText) return string.find(chatBarText, nocase("^/s")) end] = "All"; + [function(chatBarText) return string.find(chatBarText, nocase("^/say")) end] = "All"; + + [function(chatBarText) return string.find(chatBarText, nocase("^/e")) end] = "Emote"; + [function(chatBarText) return string.find(chatBarText, nocase("^/emote")) end] = "Emote"; + + [function(chatBarText) return string.find(chatBarText, "^/%?") end] = "Help"; + [function(chatBarText) return string.find(chatBarText, nocase("^/help")) end] = "Help"; + + [function(chatBarText) return string.find(chatBarText, nocase("^/block ") .. "(%w+_?%w+)") end] = "Block"; + + [function(chatBarText) return string.find(chatBarText, nocase("^/unblock ") .. "(%w+_?%w+)") end] = "Unblock"; + + [function(chatBarText) return string.find(chatBarText, nocase("^/mute ") .. "(%w+_?%w+)") end] = "Mute"; + + [function(chatBarText) return string.find(chatBarText, nocase("^/unmute ") .. "(%w+_?%w+)") end] = "Unmute"; + } + + local ChatModesDict = + { + ['Whisper'] = 'Whisper'; + ['Team'] = 'Team'; + ['All'] = 'All'; + [Enum.PlayerChatType.Whisper] = 'Whisper'; + [Enum.PlayerChatType.Team] = 'Team'; + [Enum.PlayerChatType.All] = 'All'; + } + + local function TearDownEvents() + this.ClickToChatButtonConn = Util.DisconnectEvent(this.ClickToChatButtonConn) + this.ChatBarFocusLostConn = Util.DisconnectEvent(this.ChatBarFocusLostConn) + this.ChatBarLostFocusConn = Util.DisconnectEvent(this.ChatBarLostFocusConn) + this.SelectChatModeConn = Util.DisconnectEvent(this.SelectChatModeConn) + this.SelectPlayerConn = Util.DisconnectEvent(this.SelectPlayerConn) + this.FocusChatBarInputBeganConn = Util.DisconnectEvent(this.FocusChatBarInputBeganConn) + this.InputBeganConn = Util.DisconnectEvent(this.InputBeganConn) + this.ChatBarChangedConn = Util.DisconnectEvent(this.ChatBarChangedConn) + end + + local function HookUpEvents() + TearDownEvents() -- Cleanup old events + + if this.ClickToChatButton then this.ClickToChatButtonConn = this.ClickToChatButton.MouseButton1Click:connect(function() this:FocusChatBar() end) end + + if this.ChatBar then + -- Use a count to check for double backspace out of a chatmode + local count = 0 + if not Util.IsTouchDevice() then + this.FocusChatBarInputBeganConn = Util.DisconnectEvent(this.FocusChatBarInputBeganConn) + this.FocusChatBarInputBeganConn = InputService.InputBegan:connect(function(inputObj) + if inputObj.KeyCode == Enum.KeyCode.Backspace and this:GetChatBarText() == "" then + if count == 0 then + count = count + 1 + else + this:SetMessageMode('All') + end + else + count = 0 + end + end) + end + + this.ChatBarFocusLostConn = this.ChatBar.FocusLost:connect(function(...) + count = 0 + this.unfocusedAt = tick() + this.ChatBarLostFocusEvent:fire(...) + end) + this.ChatBarChangedConn = this.ChatBar.Changed:connect(function(prop) + if prop == "Text" then + this:OnChatBarTextChanged() + elseif prop == 'TextFits' or prop == 'TextBounds' or prop == 'Visible' then + this:OnChatBarBoundsChanged() + end + end) + end + + if this.ChatBarLostFocusEvent then this.ChatBarLostFocusConn = this.ChatBarLostFocusEvent:connect(function(...) this:OnChatBarFocusLost(...) end) end + + this.SelectChatModeConn = SelectChatModeEvent:connect(function(chatType) + this:SetMessageMode(chatType) + this:FocusChatBar() + end) + + this.SelectPlayerConn = SelectPlayerEvent:connect(function(chatPlayer) + this.TargetWhisperPlayer = chatPlayer + this:SetMessageMode("Whisper") + this:FocusChatBar() + end) + + this.InputBeganConn = InputService.InputBegan:connect(function(inputObject) + if inputObject.KeyCode == Enum.KeyCode.Escape then + -- Clear text when they press escape + this:SetChatBarText("") + end + end) + end + + function this:CalculateVisibility() + if this.ChatBarContainer then + local enabled = self.WidgetVisible and chatCoreGuiEnabled and not NON_CORESCRIPT_MODE + if enabled then + HookUpEvents() + else + TearDownEvents() + end + this.ChatBarContainer.Visible = enabled and self.FadedIn and (not chatBarDisabled) + end + end + + function this:ToggleVisibility(visible) + if visible ~= self.WidgetVisible then + self.WidgetVisible = visible + self:CalculateVisibility() + end + if NON_CORESCRIPT_MODE or chatBarDisabled then + this.ChatBarContainer.Visible = false + end + end + + function this:FadeIn() + self.FadedIn = true + self:CalculateVisibility() + end + + function this:FadeOut() + self.FadedIn = false + self:CalculateVisibility() + end + + function this:CoreGuiChanged(coreGuiType, enabled) + if coreGuiType == Enum.CoreGuiType.Chat or coreGuiType == Enum.CoreGuiType.All then + chatCoreGuiEnabled = enabled + self:CalculateVisibility() + end + end + + function this:IsAChatMode(mode) + return ChatModesDict[mode] ~= nil + end + + function this:ProcessChatBarModes(requireWhitespaceAfterChatMode) + local matchedAChatCommand = false + if this.ChatBar then + local chatBarText = this:SanitizeInput(this:GetChatBarText()) + for regexFunc, actionType in pairs(this.ChatMatchingRegex) do + local start, finish, capture = regexFunc(chatBarText) + if start and finish then + -- The following line is for whether or not to try setting the chatmode as-you-type + -- versus when you press enter. + local whitespaceAfterSlashCommand = string.find(string.sub(chatBarText, finish+1, finish+1), "%s") + if (not requireWhitespaceAfterChatMode and finish == #chatBarText) or whitespaceAfterSlashCommand then + if this:IsAChatMode(actionType) then + if actionType == "Whisper" then + local targetPlayer = capture and Util.GetPlayerByName(capture) + if targetPlayer then --and targetPlayer ~= Player then + this.TargetWhisperPlayer = targetPlayer + -- start from two over to eat the space or tab character after the slash command + this:SetChatBarText(string.sub(chatBarText, finish + 2)) + this:SetMessageMode(actionType) + this.ChatCommandEvent:fire(true, actionType, capture) + else + -- This is an indirect way of detecting if they used enter to close submit this chat + if not requireWhitespaceAfterChatMode then + this:SetChatBarText("") + this.ChatCommandEvent:fire(false, actionType, capture) + end + end + else + -- start from two over to eat the space or tab character after the slash command + this:SetChatBarText(string.sub(chatBarText, finish + 2)) + this:SetMessageMode(actionType) + this.ChatCommandEvent:fire(true, actionType, capture) + end + elseif actionType == "Emote" then + -- You can only emote to everyone. + this:SetMessageMode('All') + elseif not requireWhitespaceAfterChatMode then -- Some non-chat related command + if actionType == "Help" then + this:SetChatBarText("") -- Clear the chat so we don't send /? to everyone + end + this.ChatCommandEvent:fire(true, actionType, capture) + end + -- should we break here since we already matched a slash command or keep going? + matchedAChatCommand = true + end + end + end + end + return matchedAChatCommand + end + + local previousText = "" + function this:OnChatBarTextChanged() + if not Util.IsTouchDevice() then + this:ProcessChatBarModes(true) + local originalText = this:GetChatBarText() + local newText = Util.FilterUnprintableCharacters(originalText) + if newText ~= originalText then + previousText = newText + end + + local fixedText = newText + if #newText > this.Settings.MaxCharactersInMessage or originalText ~= newText then + -- This is a hack to deal with the bug that holding down a key for repeated input doesn't trigger the textChanged event + if #newText == #previousText + 1 then + fixedText = string.sub(previousText, 1, this.Settings.MaxCharactersInMessage) + else + fixedText = string.sub(newText, 1, this.Settings.MaxCharactersInMessage) + end + end + this:SetChatBarText(fixedText) + previousText = fixedText + end + end + + function this:OnChatBarBoundsChanged() + if this.ChatBarContainer and this.ChatBar then + local currSize = this.ChatBarContainer.Size + if this.ChatBar.Visible and not this.ChatBar.TextFits then + local textBounds = Util.GetStringTextBounds(this.ChatBar.Text, this.ChatBar.Font, this.ChatBar.FontSize, UDim2.new(0, this.ChatBar.AbsoluteSize.X, 0, 1000)) + if textBounds.Y <= 36 then + this.ChatBarContainer.Size = UDim2.new(currSize.X.Scale, currSize.X.Offset, currSize.Y.Scale, 58) + else --if currSize.Y.Offset <= 54 then + this.ChatBarContainer.Size = UDim2.new(currSize.X.Scale, currSize.X.Offset, currSize.Y.Scale, 76) + end + elseif this.ChatBar.Visible == false or this.ChatBar.TextBounds.Y <= 18 then + if currSize.Y.Offset ~= 40 then + this.ChatBarContainer.Size = UDim2.new(currSize.X.Scale, currSize.X.Offset, currSize.Y.Scale, 40) + end + elseif this.ChatBar.TextBounds.Y <= 36 then + this.ChatBarContainer.Size = UDim2.new(currSize.X.Scale, currSize.X.Offset, currSize.Y.Scale, 58) + end + end + end + + function this:GetChatBarText() + return this.ChatBar and this.ChatBar.Text or "" + end + + function this:SetChatBarText(newText) + if this.ChatBar and newText ~= this.ChatBar.Text then + this.ChatBar.Text = newText + end + end + + function this:GetMessageMode() + return this.MessageMode + end + + function this:SetMessageMode(newMessageMode) + newMessageMode = ChatModesDict[newMessageMode] + + local chatRecipientText = "[" .. (this.TargetWhisperPlayer and this.TargetWhisperPlayer.Name or "") .. "]" + if this.MessageMode ~= newMessageMode or (newMessageMode == 'Whisper' and this.ChatModeText and chatRecipientText ~= this.ChatModeText.Text) then + if this.ChatModeText then + this.MessageMode = newMessageMode + if newMessageMode == 'Whisper' then + local chatRecipientTextBounds = Util.GetStringTextBounds(chatRecipientText, this.ChatModeText.Font, this.ChatModeText.FontSize) + + this.ChatModeText.TextColor3 = this.Settings.WhisperTextColor + this.ChatModeText.Text = chatRecipientText + this.ChatModeText.Size = UDim2.new(0, chatRecipientTextBounds.X, 1, 0) + elseif newMessageMode == 'Team' then + local chatTeamText = '[Team]' + local chatTeamTextBounds = Util.GetStringTextBounds(chatTeamText, this.ChatModeText.Font, this.ChatModeText.FontSize) + + this.ChatModeText.TextColor3 = this.Settings.TeamTextColor + this.ChatModeText.Text = "[Team]" + this.ChatModeText.Size = UDim2.new(0, chatTeamTextBounds.X, 1, 0) + else + this.ChatModeText.Text = "" + this.ChatModeText.Size = UDim2.new(0, 0, 1, 0) + end + if this.ChatBar then + local offset = this.ChatModeText.Size.X.Offset + this.ChatModeText.Position.X.Offset + this.ChatBar.Size = UDim2.new(1, -14 - offset, 1, 0) + this.ChatBar.Position = UDim2.new(0, 7 + offset, 0, 0) + end + end + end + end + + function this:FocusChatBar() + if this.ChatBar and not chatBarDisabled then + this.ChatBar.Visible = true + this.ChatBar:CaptureFocus() + if self.ClickToChatButton then + self.ClickToChatButton.Visible = false + end + if this.ChatModeText then + this.ChatModeText.Visible = true + end + if Util.IsTouchDevice() or InputService.VREnabled then + this:SetMessageMode('All') -- Don't remember message mode on mobile devices or VR + end + -- Update chatbar properties when chatbar is focused + this:OnChatBarBoundsChanged() + if this.ChatBarContainer then + if self.ChatBarInnerBackground then + self.ChatBarInnerBackground.BackgroundTransparency = 0 + end + end + this.ChatBarGainedFocusEvent:fire() + end + end + + function this:RemoveFocus() + if self:IsFocused() then + self.ChatBar:ReleaseFocus() + end + end + + function this:IsFocused() + return self.ChatBar and self.ChatBar == InputService:GetFocusedTextBox() + end + + function this:WasFocused() + return (tick() - this.unfocusedAt) < VR_CHAT_CLICK_DEBOUNCE + end + + function this:SanitizeInput(input) + local sanitizedInput = input + -- Chomp the whitespace at the front and end of the string + -- TODO: maybe only chop off the front space if there are more than a few? + local _, _, capture = string.find(sanitizedInput, "^%s*(.*)%s*$") + sanitizedInput = capture or "" + + return sanitizedInput + end + + + local sentMessageTimeQueue = {} + function this:FloodCheck() + if not GetLuaChatFilteringFlag() then + return false + end + + while sentMessageTimeQueue[1] and tick() - sentMessageTimeQueue[1] > FLOOD_CHECK_MESSAGE_INTERVAL do + table.remove(sentMessageTimeQueue, 1) + end + if #sentMessageTimeQueue > FLOOD_CHECK_MESSAGE_COUNT then + return true + end + return false + end + + function this:OnChatBarFocusLost(enterPressed) + if self.ChatBar then + self.ChatBar.Visible = false + -- TODO: remove this when API for VR to set enterPressed is released + if enterPressed or InputService.VREnabled then + local didMatchSlashCommand = self:ProcessChatBarModes(false) + local cText = self:SanitizeInput(self:GetChatBarText()) + if cText ~= "" then + if self:FloodCheck() then -- and not didMatchSlashCommand then + self.ChatBarFloodEvent:fire() + else + -- For now we will let any slash command go through, NOTE: these will show up in bubble-chat + --if not didMatchSlashCommand and string.sub(cText,1,1) == "/" then + -- self.ChatCommandEvent:fire(false, "Unknown", cText) + --else + local currentMessageMode = self:GetMessageMode() + -- {All, Team, Whisper} + if currentMessageMode == 'Team' then + if Player and Player.Neutral == true then + self.ChatErrorEvent:fire("You're not on a team.") + else + pcall(function() PlayersService:TeamChat(cText) end) + end + elseif currentMessageMode == 'Whisper' then + if self.TargetWhisperPlayer then + if self.TargetWhisperPlayer == Player then + self.ChatErrorEvent:fire("You cannot send a whisper to yourself.") + else + pcall(function() PlayersService:WhisperChat(cText, self.TargetWhisperPlayer) end) + end + else + self.ChatErrorEvent:fire("Invalid whisper target.") + end + elseif currentMessageMode == 'All' then + pcall(function() PlayersService:Chat(cText) end) + else + spawn(function() error("ChatScript: Unknown Message Mode of " .. tostring(currentMessageMode)) end) + end + table.insert(sentMessageTimeQueue, tick()) + --end + self:SetChatBarText("") + end + end + end + end + if self.ClickToChatButton then + self.ClickToChatButton.Visible = true + -- Fade-back in the text so it doesn't abruptly appear + -- Normally I would like to cancel the old tween but it is so short that it doesn't matter + self.ClickToChatButton.TextTransparency = 1 + Util.PropertyTweener(self.ClickToChatButton, 'TextTransparency', 1, 0, 0.25, Util.Linear) + end + if self.ChatModeText then + self.ChatModeText.Visible = false + end + if this.ChatBarContainer then + local currSize = this.ChatBarContainer.Size + this.ChatBarContainer.Size = UDim2.new(currSize.X.Scale, currSize.X.Offset, currSize.Y.Scale, 32) + if self.ChatBarInnerBackground then + self.ChatBarInnerBackground.BackgroundTransparency = 0.5 + end + end + this.ChatBarChangedConn = Util.DisconnectEvent(this.ChatBarChangedConn) + this.FocusChatBarInputBeganConn = Util.DisconnectEvent(this.FocusChatBarInputBeganConn) + end + + local function CreateChatBar() + local chatBarContainer = Util.Create'Frame' + { + Name = 'ChatBarContainer'; + Position = UDim2.new(0, 0, 1, 0); + Size = UDim2.new(1, 0, 0, 20); + ZIndex = 1; + BackgroundColor3 = Color3.new(0, 0, 0); + BackgroundTransparency = 0.25; + BorderSizePixel = 0; + }; + chatBarContainer.BackgroundColor3 = Color3.new(31/255, 31/255, 31/255); + chatBarContainer.BackgroundTransparency = 0.5; + local chatBarInnerBackground = Util.Create'Frame' + { + Name = 'InnerBackground'; + Position = UDim2.new(0, 7, 0, 5); + Size = UDim2.new(1, -14, 1, -10); + ZIndex = 1; + BackgroundColor3 = Color3.new(209/255, 216/255, 221/255); + BackgroundTransparency = 0.5; + BorderSizePixel = 0; + }; + local clickToChatButton = Util.Create'TextButton' + { + Name = 'ClickToChat'; + Position = UDim2.new(0,9,0,0); + Size = UDim2.new(1, -9, 1, 0); + BackgroundTransparency = 1; + AutoButtonColor = false; + ZIndex = 3; + Text = 'To chat click here or press "/" key'; + TextColor3 = this.Settings.GlobalTextColor; + TextXAlignment = Enum.TextXAlignment.Left; + TextYAlignment = Enum.TextYAlignment.Top; + Font = Enum.Font.SourceSansBold; + FontSize = Enum.FontSize.Size18; + Parent = chatBarContainer; + } + clickToChatButton.TextWrapped = true; + clickToChatButton.Position = UDim2.new(0, 7, 0, 0); + clickToChatButton.Size = UDim2.new(1, -14, 1, 0); + clickToChatButton.TextYAlignment = Enum.TextYAlignment.Center; + if Util.IsTouchDevice() then + clickToChatButton.Text = "Tap here to chat" + end + + local chatBar = Util.Create'TextBox' + { + Name = 'ChatBar'; + Position = UDim2.new(0, 9, 0, 0); + Size = UDim2.new(1, -9, 1, 0); + Text = ""; + ZIndex = 1; + BackgroundColor3 = Color3.new(0, 0, 0); + Active = false; + BackgroundTransparency = 1; + TextXAlignment = Enum.TextXAlignment.Left; + TextYAlignment = Enum.TextYAlignment.Top; + TextColor3 = this.Settings.GlobalTextColor; + Font = Enum.Font.SourceSansBold; + FontSize = Enum.FontSize.Size18; + ClearTextOnFocus = false; + Visible = not Util.IsTouchDevice(); + Parent = chatBarContainer; + SelectionImageObject = emptySelectionImage; + } + chatBar.TextWrapped = true; + chatBar.Position = UDim2.new(0, 7, 0, 0); + chatBar.Size = UDim2.new(1, -14, 1, 0); + chatBar.TextYAlignment = Enum.TextYAlignment.Center; + chatBar.Visible = false; + + local chatModeText = Util.Create'TextButton' + { + Name = 'ChatModeText'; + Position = UDim2.new(0, 9, 0, 0); + Size = UDim2.new(1, -9, 1, 0); + AutoButtonColor = false; + BackgroundTransparency = 1; + ZIndex = 2; + Text = ''; + TextColor3 = this.Settings.WhisperTextColor; + TextXAlignment = Enum.TextXAlignment.Left; + TextYAlignment = Enum.TextYAlignment.Top; + Font = Enum.Font.SourceSansBold; + FontSize = Enum.FontSize.Size18; + Parent = chatBarContainer; + } + chatModeText.Position = UDim2.new(0, 7, 0, 0); + chatModeText.Size = UDim2.new(1, -14, 1, 0); + chatModeText.TextYAlignment = Enum.TextYAlignment.Center; + -- Create grey background for text + chatBarInnerBackground.Parent = chatBarContainer; + clickToChatButton.Parent = chatBarInnerBackground; + chatBar.Parent = chatBarInnerBackground; + chatModeText.Parent = chatBarInnerBackground; + + this.ChatBarContainer = chatBarContainer + this.ChatBarInnerBackground = chatBarInnerBackground + this.ClickToChatButton = clickToChatButton + this.ChatBar = chatBar + this.ChatModeText = chatModeText + this.ChatBarContainer.Parent = GuiRoot + + local function RobloxClientScreenSizeChanged(newSize) + if chatBarContainer then + local chatbarVisible = this.ChatBar and this.ChatBar.Visible + local bubbleChatIsOn = not PlayersService.ClassicChat and PlayersService.BubbleChat + -- Phone + if newSize.X <= PHONE_SCREEN_WIDTH then + chatBarContainer.Size = UDim2.new(0.5, 0,0, chatbarVisible and 40 or 32) + if bubbleChatIsOn then + chatBarContainer.Position = UDim2.new(0, 0, 0, 2) + else + chatBarContainer.Position = UDim2.new(0, 0, 0.5, 2) + end + -- Tablet + elseif newSize.X <= TABLET_SCREEN_WIDTH then + chatBarContainer.Size = UDim2.new(0.4, 0,0, chatbarVisible and 40 or 32) + if bubbleChatIsOn then + chatBarContainer.Position = UDim2.new(0, 0, 0, 2) + else + chatBarContainer.Position = UDim2.new(0, 0, 0.3, 2) + end + -- Desktop + else + chatBarContainer.Size = UDim2.new(0.3, 0,0, chatbarVisible and 40 or 32) + if bubbleChatIsOn then + chatBarContainer.Position = UDim2.new(0, 0, 0, 2) + else + chatBarContainer.Position = UDim2.new(0,0,0.25, 2) + end + end + + if Util.IsTouchDevice() or InputService.VREnabled then + -- Hide the chatbar on mobile and in VR so they can't see it. + chatBarContainer.Position = UDim2.new(0,0,1,20); + end + end + end + + GuiRoot.Changed:connect(function(prop) if prop == "AbsoluteSize" and not chatRepositioned then RobloxClientScreenSizeChanged(GuiRoot.AbsoluteSize) end end) + RobloxClientScreenSizeChanged(GuiRoot.AbsoluteSize) + end + + + CreateChatBar() + return this +end + +local function CreateChatWindowWidget(settings) + local this = {} + this.Settings = settings + this.Chats = {} + this.BackgroundVisible = false + this.ChatsVisible = false + this.WidgetVisible = false + this.NewUnreadMessage = false + this.MessageCount = 0 + + this.MessageCountChanged = Util.Signal() + this.FadeInSignal = Util.Signal() + this.FadeOutSignal = Util.Signal() + + this.ChatWindowPagingConn = nil + + local lastMoveTime = tick() + local lastEnterTime = tick() + local lastLeaveTime = tick() + + local lastFadeOutTime = 0 + local lastFadeInTime = 0 + local lastChatActivity = 0 + + local FadeLock = false + + local chatCoreGuiEnabled = true + + local function PointInChatWindow(pt) + local point0 = this.ChatContainer.AbsolutePosition + local point1 = point0 + this.ChatContainer.AbsoluteSize + -- HACK, this is so the "ChatWindow" includes the chatbar box, TODO: refactor the fadeing code to include the chatbar + point1 = point1 + Vector2.new(0, 34) + return point0.X <= pt.X and point1.X >= pt.X and + point0.Y <= pt.Y and point1.Y >= pt.Y + end + + function this:IsHovering() + if this.ChatContainer and this.LastMousePosition and self:CalculateVisibility() then + return PointInChatWindow(this.LastMousePosition) + end + return false + end + + function this:SetFadeLock(lock) + FadeLock = lock + end + + function this:GetFadeLock() + return FadeLock + end + + function this:SetCanvasPosition(newCanvasPosition) + if this.ScrollingFrame then + local maxSize = Vector2.new(math.max(0, this.ScrollingFrame.CanvasSize.X.Offset - this.ScrollingFrame.AbsoluteWindowSize.X), + math.max(0, this.ScrollingFrame.CanvasSize.Y.Offset - this.ScrollingFrame.AbsoluteWindowSize.Y)) + this.ScrollingFrame.CanvasPosition = Vector2.new(Util.Clamp(0, maxSize.X, newCanvasPosition.X), + Util.Clamp(0, maxSize.Y, newCanvasPosition.Y)) + end + end + + function this:ScrollToBottom() + if this.ScrollingFrame then + this:SetCanvasPosition(Vector2.new(this.ScrollingFrame.CanvasPosition.X, this.ScrollingFrame.CanvasSize.Y.Offset)) + end + end + + function this:FadeIn(duration, lockFade) + if not FadeLock then + duration = duration or 0.75 + local backgroundTransparency = InputService.VREnabled and 1 or 0.5 + -- fade in + if this.BackgroundTweener then + this.BackgroundTweener:Cancel() + end + lastFadeInTime = tick() + lastChatActivity = tick() + this.ScrollingFrame.ScrollingEnabled = true + this.ScrollingFrame.ScrollBarThickness = SCROLLBAR_THICKNESS + this.BackgroundTweener = Util.PropertyTweener(this.ChatContainer, 'BackgroundTransparency', this.ChatContainer.BackgroundTransparency, backgroundTransparency, duration, Util.Linear) + this.BackgroundVisible = true + this:FadeInChats() + + this.ChatWindowPagingConn = Util.DisconnectEvent(this.ChatWindowPagingConn) + this.ChatWindowPagingConn = InputService.InputBegan:connect(function(inputObject) + local key = inputObject.KeyCode + if key == Enum.KeyCode.PageUp then + this:SetCanvasPosition(this.ScrollingFrame.CanvasPosition - Vector2.new(0, this.ScrollingFrame.AbsoluteWindowSize.Y)) + elseif key == Enum.KeyCode.PageDown then + this:SetCanvasPosition(this.ScrollingFrame.CanvasPosition + Vector2.new(0, this.ScrollingFrame.AbsoluteWindowSize.Y)) + elseif key == Enum.KeyCode.Home then + this:SetCanvasPosition(Vector2.new(0, 0)) + elseif key == Enum.KeyCode.End then + this:ScrollToBottom() + end + end) + if this.FadeInSignal then + this.FadeInSignal:fire() + end + end + end + + function this:FadeOut(duration, unlockFade) + if not FadeLock then + duration = duration or 0.75 + -- fade out + if this.BackgroundTweener then + this.BackgroundTweener:Cancel() + end + lastFadeOutTime = tick() + lastChatActivity = tick() + this.ScrollingFrame.ScrollingEnabled = false + this.ScrollingFrame.ScrollBarThickness = 0 + this.BackgroundTweener = Util.PropertyTweener(this.ChatContainer, 'BackgroundTransparency', this.ChatContainer.BackgroundTransparency, 1, duration, Util.Linear) + this.BackgroundVisible = false + + this.ChatWindowPagingConn = Util.DisconnectEvent(this.ChatWindowPagingConn) + if this.FadeOutSignal then + this.FadeOutSignal:fire() + end + end + end + + function this:FadeInChats() + if this.ChatsVisible == true then return end + this.ChatsVisible = true + for index, message in pairs(this.Chats) do + message:FadeIn() + end + end + + function this:FadeOutChats() + if InputService.VREnabled then return end + if this.ChatsVisible == false then return end + this.ChatsVisible = false + if IsPlayerDropDownEnabled and playerDropDown then + playerDropDown:Hide() + end + for index, message in pairs(this.Chats) do + local messageGui = message:GetGui() + local instant = false + if messageGui and this.ScrollingFrame then + -- If the chat is not in the visible frame then don't waste cpu cycles fading it out + if messageGui.AbsolutePosition.Y > (this.ScrollingFrame.AbsolutePosition + this.ScrollingFrame.AbsoluteWindowSize).Y or + messageGui.AbsolutePosition.Y + messageGui.AbsoluteSize.Y < this.ScrollingFrame.AbsolutePosition.Y then + instant = true + end + end + message:FadeOut(instant) + end + end + + local ResizeCount = 0 + function this:OnResize() + ResizeCount = ResizeCount + 1 + local currentResizeCount = ResizeCount + local isScrolledDown = this:IsScrolledDown() + -- Unfortunately there is a race condition so we need this wait here. + wait() + if this.ScrollingFrame then + if currentResizeCount ~= ResizeCount then return end + local scrollingFrameAbsoluteSize = this.ScrollingFrame.AbsoluteWindowSize + if scrollingFrameAbsoluteSize ~= nil and scrollingFrameAbsoluteSize.X > 0 and scrollingFrameAbsoluteSize.Y > 0 then + local ySize = 0 + + if this.ScrollingFrame then + for _, message in pairs(this.Chats) do + local newHeight = message:OnResize(scrollingFrameAbsoluteSize) + if newHeight then + local chatMessageElement = message:GetGui() + if chatMessageElement then + local chatMessageElementYSize = chatMessageElement.Size.Y.Offset + chatMessageElement.Position = UDim2.new(0, 0, 0, ySize) + ySize = ySize + chatMessageElementYSize + end + end + end + end + if this.MessageContainer and this.ScrollingFrame then + this.MessageContainer.Size = UDim2.new( + this.MessageContainer.Size.X.Scale, + this.MessageContainer.Size.X.Offset, + 0, + ySize) + this.MessageContainer.Position = UDim2.new(0, 0, 1, -this.MessageContainer.Size.Y.Offset) + this.ScrollingFrame.CanvasSize = UDim2.new(this.ScrollingFrame.CanvasSize.X.Scale, this.ScrollingFrame.CanvasSize.X.Offset, this.ScrollingFrame.CanvasSize.Y.Scale, ySize) + end + end + this:ScrollToBottom() + end + end + + function this:FilterMessage(playerChatType, sendingPlayer, chattedMessage, receivingPlayer) + if chattedMessage and string.sub(chattedMessage, 1, 1) ~= '/' then + return true + end + return false + end + + function this:PushMessageIntoQueue(chatMessage, silently) + table.insert(this.Chats, chatMessage) + + local isScrolledDown = this:IsScrolledDown() + + local chatMessageElement = chatMessage:GetGui() + + chatMessageElement.Parent = this.MessageContainer + local chatMessageHeight = chatMessage:OnResize() or 10 + local ySize = this.MessageContainer.Size.Y.Offset + local chatMessageElementYSize = UDim2.new(0, 0, 0, chatMessageHeight) + + if not silently then + this.MessageCount = this.MessageCount + 1 + end + + chatMessageElement.Position = chatMessageElement.Position + UDim2.new(0, 0, 0, ySize) + this.MessageContainer.Size = this.MessageContainer.Size + chatMessageElementYSize + this.ScrollingFrame.CanvasSize = this.ScrollingFrame.CanvasSize + chatMessageElementYSize + + if this.Settings.MaxWindowChatMessages < #this.Chats then + this:RemoveOldestMessage() + end + if isScrolledDown then + this:ScrollToBottom() + elseif not silently then + -- Raise unread message alert! + this.NewUnreadMessage = true + end + + if silently then + if this.ChatsVisible == false then + chatMessage:FadeOut(true) + end + else + this:FadeInChats() + lastChatActivity = tick() + this.MessageCountChanged:fire(this.MessageCount) + end + + -- NOTE: Sort of hacky, but if we are approaching the max 16 bit size + -- we need to rebase y back to 0 which can be done with the resize function + if ySize > (MAX_UDIM_SIZE / 2) then + self:OnResize() + end + end + + function this:AddSystemChatMessage(chattedMessage, silently) + local chatMessage = CreateSystemChatMessage(this.Settings, chattedMessage) + this:PushMessageIntoQueue(chatMessage, silently) + end + + local function checkEnum(enumItems, value) + for _, enum in pairs(enumItems) do + if enum.Value == value then + return enum + end + end + return nil + end + + -- We only need to copy the top level for the settings table + local function shallowCopy(tableToCopy) + local newTable = {} + for key, value in pairs(tableToCopy) do + newTable[key] = value + end + return newTable + end + + function this:AddDeveloperSystemChatMessage(informationTable) + local settings = shallowCopy(this.Settings) + + if informationTable["Text"] and type(informationTable["Text"]) == "string" then + if informationTable["Color"] and pcall(function() Color3.new(informationTable["Color"].r, informationTable["Color"].g, informationTable["Color"].b) end) then + settings.DefaultMessageTextColor = informationTable["Color"] + end + if informationTable["Font"] then + local success, value = pcall(function() return checkEnum(Enum.Font:GetEnumItems(), informationTable["Font"].Value) end) + if success and value ~= nil then + settings.Font = value + end + end + if informationTable["FontSize"] then + local success, value = pcall(function() return checkEnum(Enum.FontSize:GetEnumItems(), informationTable["FontSize"].Value) end) + if success and value ~= nil then + settings.FontSize = value + end + end + local chatMessage = CreateSystemChatMessage(settings, informationTable["Text"]) + this:PushMessageIntoQueue(chatMessage, false) + end + end + + function this:AddChatMessage(playerChatType, sendingPlayer, chattedMessage, receivingPlayer, silently) + local fixedChattedMessage = Util.FilterUnprintableCharacters(chattedMessage) + if this:FilterMessage(playerChatType, sendingPlayer, fixedChattedMessage, receivingPlayer) then + local chatMessage = CreatePlayerChatMessage(this.Settings, playerChatType, sendingPlayer, fixedChattedMessage, receivingPlayer) + this:PushMessageIntoQueue(chatMessage, silently) + end + end + + function this:RemoveOldestMessage() + local oldestChat = this.Chats[1] + if oldestChat then + return this:RemoveChatMessage(oldestChat) + end + end + + function this:RemoveChatMessage(chatMessage) + if chatMessage then + for index, message in pairs(this.Chats) do + if chatMessage == message then + local guiObj = chatMessage:GetGui() + if guiObj then + local ySize = guiObj.Size.Y.Offset + this.ScrollingFrame.CanvasSize = this.ScrollingFrame.CanvasSize - UDim2.new(0,0,0,ySize) + -- Clamp the canvasposition + this:SetCanvasPosition(this.ScrollingFrame.CanvasPosition) + guiObj.Parent = nil + end + message:Destroy() + return table.remove(this.Chats, index) + end + end + end + end + + function this:IsScrolledDown() + if this.ScrollingFrame then + local yCanvasSize = this.ScrollingFrame.CanvasSize.Y.Offset + local yContainerSize = this.ScrollingFrame.AbsoluteWindowSize.Y + local yScrolledPosition = this.ScrollingFrame.CanvasPosition.Y + -- Check if the messages are at the bottom + return yCanvasSize < yContainerSize or + yCanvasSize - yScrolledPosition <= yContainerSize + 5 -- a little wiggle room + end + return false + end + + function this:GetMessageCount() + return this.MessageCount + end + + function this:CalculateVisibility() + return this.WidgetVisible and ((chatCoreGuiEnabled and PlayersService.ClassicChat) or NON_CORESCRIPT_MODE) + end + + function this:ToggleVisibility(visible) + if visible ~= self.WidgetVisible then + self.WidgetVisible = visible + if this.ChatContainer then + this.ChatContainer.Visible = self:CalculateVisibility() + end + end + if NON_CORESCRIPT_MODE then + this.ChatContainer.Visible = true + end + end + + function this:CoreGuiChanged(coreGuiType, enabled) + if coreGuiType == Enum.CoreGuiType.Chat or coreGuiType == Enum.CoreGuiType.All then + chatCoreGuiEnabled = enabled + if this.ChatContainer then + this.ChatContainer.Visible = self:CalculateVisibility() + end + end + end + + local function CreateChatWindow() + local container = Util.Create'TextButton' + { + Name = 'ChatWindowContainer'; + Size = UDim2.new(0.3, 0, 0.25, 0); + Position = UDim2.new(0, 8, 0, 37); + ZIndex = 1; + BackgroundColor3 = Color3.new(0, 0, 0); + BackgroundTransparency = 1; + BorderSizePixel = 0; + Text = ""; + SelectionImageObject = emptySelectionImage; + }; + container.Position = UDim2.new(0,0,0,37); + container.BackgroundColor3 = Color3.new(31/255, 31/255, 31/255); + local scrollingFrame = Util.Create'ScrollingFrame' + { + Name = 'ChatWindow'; + Size = UDim2.new(1, -4 - 10, 1, -20); + CanvasSize = UDim2.new(1, -4 - 10, 0, 0); + Position = UDim2.new(0, 10, 0, 10); + ZIndex = 1; + BackgroundColor3 = Color3.new(0, 0, 0); + BackgroundTransparency = 1; + BottomImage = "rbxasset://textures/ui/scroll-bottom.png"; + MidImage = "rbxasset://textures/ui/scroll-middle.png"; + TopImage = "rbxasset://textures/ui/scroll-top.png"; + ScrollBarThickness = 0; + BorderSizePixel = 0; + ScrollingEnabled = false; + Parent = container; + }; + local messageContainer = Util.Create'Frame' + { + Name = 'MessageContainer'; + Size = UDim2.new(1, -SCROLLBAR_THICKNESS - 1, 0, 0); + Position = UDim2.new(0, 0, 1, 0); + ZIndex = 1; + BackgroundColor3 = Color3.new(0, 0, 0); + BackgroundTransparency = 1; + Parent = scrollingFrame + }; + + -- This is some trickery we are doing to make the first chat messages appear at the bottom and go towards the top. + local function OnChatWindowResize(prop) + if prop == 'AbsoluteSize' then + messageContainer.Position = UDim2.new(0, 0, 1, -messageContainer.Size.Y.Offset) + end + if prop == 'CanvasPosition' then + if this.ScrollingFrame then + if this:IsScrolledDown() then + this.NewUnreadMessage = false + end + end + end + end + container.Changed:connect(function(prop) if prop == 'AbsoluteSize' then this:OnResize() end end) + + local function RobloxClientScreenSizeChanged(newSize) + if container then + container.Position = UDim2.new(0,0,0,2); + if InputService.VREnabled then + container.Size = UDim2.new(1,0,1,0) + -- Phone + elseif newSize.X <= 640 then + container.Size = UDim2.new(0.5,0,0.5,0) - container.Position + -- Tablet + elseif newSize.X <= 1024 then + container.Size = UDim2.new(0.4,0,0.3,0) - container.Position + -- Desktop + else + container.Size = UDim2.new(0.3,0,0.25,0) - container.Position + end + end + end + + GuiRoot.Changed:connect(function(prop) if prop == "AbsoluteSize" and not chatRepositioned then RobloxClientScreenSizeChanged(GuiRoot.AbsoluteSize) end end) + RobloxClientScreenSizeChanged(GuiRoot.AbsoluteSize) + + messageContainer.Changed:connect(OnChatWindowResize) + scrollingFrame.Changed:connect(OnChatWindowResize) + + this.ChatContainer = container + this.ScrollingFrame = scrollingFrame + this.MessageContainer = messageContainer + this.ChatContainer.Parent = GuiRoot + + + -- It is important to set this to true in NON_CORESCRIPT_MODE because normally the topbar sets + -- the chat window to visible + if NON_CORESCRIPT_MODE then + this:ToggleVisibility(true) + end + + --- BACKGROUND FADING CODE --- + -- This is so we don't accidentally fade out when we are scrolling and mess with the scrollbar. + local dontFadeOutOnMouseLeave = false + + if Util:IsTouchDevice() then + local touchCount = 0 + this.InputBeganConn = InputService.InputBegan:connect(function(inputObject) + if inputObject.UserInputType == Enum.UserInputType.Touch and inputObject.UserInputState == Enum.UserInputState.Begin then + if PointInChatWindow(Vector2.new(inputObject.Position.X, inputObject.Position.Y)) then + touchCount = touchCount + 1 + dontFadeOutOnMouseLeave = true + end + end + end) + + this.InputEndedConn = InputService.InputEnded:connect(function(inputObject) + if inputObject.UserInputType == Enum.UserInputType.Touch and inputObject.UserInputState == Enum.UserInputState.End then + local endedCount = touchCount + wait(2) + if touchCount == endedCount then + dontFadeOutOnMouseLeave = false + end + end + end) + + spawn(function() + local now = tick() + while true do + wait() + now = tick() + if this.BackgroundVisible then + if not dontFadeOutOnMouseLeave then + this:FadeOut(0.25) + end + -- If background is not visible/in-focus + elseif this.ChatsVisible and now > lastChatActivity + MESSAGES_FADE_OUT_TIME then + this:FadeOutChats() + end + end + end) + else + this.LastMousePosition = Vector2.new() + + this.MouseEnterFrameConn = this.ChatContainer.MouseEnter:connect(function() + lastEnterTime = tick() + if this.BackgroundTweener and not this.BackgroundTweener:IsFinished() and not this.BackgroundVisible then + this:FadeIn() + end + end) + + this.MouseMoveConn = InputService.InputChanged:connect(function(inputObject) + if inputObject.UserInputType == Enum.UserInputType.MouseMovement then + lastMoveTime = tick() + this.LastMousePosition = Vector2.new(inputObject.Position.X, inputObject.Position.Y) + if this.BackgroundTweener and this.BackgroundTweener:GetPercentComplete() < 0.5 and this.BackgroundVisible then + if not dontFadeOutOnMouseLeave then + this:FadeOut() + end + end + end + end) + + local clickCount = 0 + this.InputBeganConn = InputService.InputBegan:connect(function(inputObject) + if inputObject.UserInputType == Enum.UserInputType.MouseButton1 and inputObject.UserInputState == Enum.UserInputState.Begin then + if PointInChatWindow(Vector2.new(inputObject.Position.X, inputObject.Position.Y)) then + clickCount = clickCount + 1 + dontFadeOutOnMouseLeave = true + end + end + end) + + this.InputEndedConn = InputService.InputEnded:connect(function(inputObject) + if inputObject.UserInputType == Enum.UserInputType.MouseButton1 and inputObject.UserInputState == Enum.UserInputState.End then + local nowCount = clickCount + wait(1.3) + if nowCount == clickCount then + dontFadeOutOnMouseLeave = false + end + end + end) + + this.MouseLeaveFrameConn = this.ChatContainer.MouseLeave:connect(function() + lastLeaveTime = tick() + if this.BackgroundTweener and not this.BackgroundTweener:IsFinished() and this.BackgroundVisible then + if not dontFadeOutOnMouseLeave then + this:FadeOut() + end + end + end) + + spawn(function() + while true do + wait() + local now = tick() + if this:IsHovering() then + if now - lastMoveTime > 1.3 and not this.BackgroundVisible then + this:FadeIn() + end + else -- not this:IsHovering() + if this.BackgroundVisible then + if not dontFadeOutOnMouseLeave then + this:FadeOut(0.25) + end + -- If background is not visible/in-focus + elseif this.ChatsVisible and now > lastChatActivity + MESSAGES_FADE_OUT_TIME then + this:FadeOutChats() + end + end + end + end) + end + --- END OF BACKGROUND FADING CODE --- + end + + CreateChatWindow() + + return this +end + + +local function CreateChat() + local this = {} + + this.Settings = + { + GlobalTextColor = Color3.new(112/255, 110/255, 106/255); + WhisperTextColor = Color3.new(77/255, 139/255, 255/255); + TeamTextColor = Color3.new(230/255, 207/255, 0); + DefaultMessageTextColor = Color3.new(255/255, 255/255, 243/255); + AdminTextColor = Color3.new(1, 215/255, 0); + TextStrokeTransparency = 0.75; + TextStrokeColor = Color3.new(34/255,34/255,34/255); + Font = Enum.Font.SourceSansBold; + SmallScreenFontSize = Enum.FontSize.Size14; + FontSize = Enum.FontSize.Size18; + MaxWindowChatMessages = 50; + MaxCharactersInMessage = 140; + } + + this.CurrentWindowMessageCountChanged = nil + this.VisibilityStateChanged = Util.Signal() + this.ChatBarFocusChanged = Util.Signal() + this.Visible = false + + function this:CoreGuiChanged(coreGuiType, enabled) + enabled = enabled and (topbarEnabled or InputService.VREnabled) + if coreGuiType == Enum.CoreGuiType.Chat or coreGuiType == Enum.CoreGuiType.All then + if enabled then + pcall(function() + self.SpecialKeyPressedConn = Util.DisconnectEvent(self.SpecialKeyPressedConn) + GuiService:AddSpecialKey(Enum.SpecialKey.ChatHotkey) + self.SpecialKeyPressedConn = GuiService.SpecialKeyPressed:connect(function(key) + if key == Enum.SpecialKey.ChatHotkey then + if self.Visible == false then + self:ToggleVisibility() + end + if self.ChatBarWidget then + self.ChatBarWidget:FocusChatBar() + end + end + end) + end) + else + pcall(function() GuiService:RemoveSpecialKey(Enum.SpecialKey.ChatHotkey) end) + self.SpecialKeyPressedConn = Util.DisconnectEvent(self.SpecialKeyPressedConn) + end + if this.MobileChatButton then + if enabled == true then + this.MobileChatButton.Parent = GuiRoot + -- we need to set it to be visible in-case we missed a lost focus event while chat was turned off. + this.MobileChatButton.Visible = true + else + this.MobileChatButton.Parent = nil + end + end + end + if this.ChatWindowWidget then + this.ChatWindowWidget:CoreGuiChanged(coreGuiType, enabled) + end + if this.ChatBarWidget then + this.ChatBarWidget:CoreGuiChanged(coreGuiType, enabled) + end + end + + -- This event has 4 callback arguments + -- Enum.PlayerChatType.{All|Team|Whisper}, chatPlayer, message, targetPlayer + function this:OnPlayerChatted(playerChatType, sendingPlayer, chattedMessage, receivingPlayer) + if this.ChatWindowWidget then + -- Don't add messages from blocked players, don't show message if is a debug command + local isDebugCommand = false + pcall(function() + if sendingPlayer == PlayersService.LocalPlayer then + isDebugCommand = game:GetService("GuiService"):ShowStatsBasedOnInputString(chattedMessage) + end + end) + if not (this:IsPlayerBlocked(sendingPlayer) or this:IsPlayerMuted(sendingPlayer) or isDebugCommand) then + this.ChatWindowWidget:AddChatMessage(playerChatType, sendingPlayer, chattedMessage, receivingPlayer) + end + end + end + + function this:OnPlayerAdded(newPlayer) + if newPlayer then + spawn(function() Util.IsPlayerAdminAsync(newPlayer) end) + end + if NON_CORESCRIPT_MODE then + newPlayer.Chatted:connect(function(msg, recipient) + this:OnPlayerChatted(Enum.PlayerChatType.All, newPlayer, msg, recipient) + end) + else + this.PlayerChattedConn = Util.DisconnectEvent(this.PlayerChattedConn) + this.PlayerChattedConn = PlayersService.PlayerChatted:connect(function(...) + this:OnPlayerChatted(...) + end) + end + end + + function this:IsPlayerBlocked(player) + if blockingUtility then + return player and blockingUtility:IsPlayerBlockedByUserId(player.userId) + else + return false + end + end + + function this:BlockPlayerAsync(playerToBlock) + if playerToBlock and Player ~= playerToBlock then + local blockUserId = playerToBlock.userId + local playerToBlockName = playerToBlock.Name + if blockUserId > 0 then + if not this:IsPlayerBlocked(playerToBlock) then + if blockingUtility then + blockingUtility:BlockPlayerAsync(playerToBlock) + this.ChatWindowWidget:AddSystemChatMessage(playerToBlockName .. " is now blocked.") + end + else + this.ChatWindowWidget:AddSystemChatMessage(playerToBlockName .. " is already blocked.") + end + else + this.ChatWindowWidget:AddSystemChatMessage("You cannot block guests.") + end + else + this.ChatWindowWidget:AddSystemChatMessage("You cannot block yourself.") + end + end + + function this:UnblockPlayerAsync(playerToUnblock) + if playerToUnblock then + local unblockUserId = playerToUnblock.userId + local playerToUnblockName = playerToUnblock.Name + + if this:IsPlayerBlocked(playerToUnblock) then + if blockingUtility then + this.ChatWindowWidget:AddSystemChatMessage(playerToUnblockName .. " is no longer blocked.") + blockingUtility:UnblockPlayerAsync(playerToUnblock) + end + else + this.ChatWindowWidget:AddSystemChatMessage(playerToUnblockName .. " is not blocked.") + end + end + end + + function this:IsPlayerMuted(player) + if blockingUtility then + return player and blockingUtility:IsPlayerMutedByUserId(player.userId) + else + return false + end + end + + function this:MutePlayer(playerToMute) + if playerToMute and playerToMute ~= Player then + if playerToMute.UserId > 0 then + if not this:IsPlayerMuted(playerToMute) then + if blockingUtility then + blockingUtility:MutePlayer(playerToMute) + this.ChatWindowWidget:AddSystemChatMessage(playerToMute.Name .. " is now muted.") + end + else + this.ChatWindowWidget:AddSystemChatMessage(playerToMute.Name .. " is already muted.") + end + else + this.ChatWindowWidget:AddSystemChatMessage("You cannot mute guests.") + end + else + this.ChatWindowWidget:AddSystemChatMessage("You cannot mute yourself.") + end + end + + function this:UnmutePlayer(playerToUnmute) + if playerToUnmute then + if this:IsPlayerMuted(playerToUnmute) then + if blockingUtility then + blockingUtility:UnmutePlayer(playerToUnmute) + this.ChatWindowWidget:AddSystemChatMessage(playerToUnmute.Name .. " is no longer muted.") + end + else + this.ChatWindowWidget:AddSystemChatMessage(playerToUnmute.Name .. " is not muted.") + end + end + end + + function this:CreateTouchDeviceChatButton() + return Util.Create'ImageButton' + { + Name = 'TouchDeviceChatButton'; + Size = UDim2.new(0, 128, 0, 32); + Position = UDim2.new(0, 88, 0, 0); + BackgroundTransparency = 1.0; + Image = 'http://www.roblox.com/asset/?id=97078724'; + }; + end + + function this:PrintWelcome() + if this.ChatWindowWidget then + if Util.IsTouchDevice() then + this.ChatWindowWidget:AddSystemChatMessage("Please press the '...' icon to chat", true) + end + this.ChatWindowWidget:AddSystemChatMessage("Please chat '/?' for a list of commands", true) + end + end + + local doOnceVRWelcome = false + function this:PrintVRWelcome() + if this.ChatWindowWidget and not doOnceVRWelcome then + if InputService.VREnabled then + this.ChatWindowWidget:AddSystemChatMessage("Press here to chat", true) + doOnceVRWelcome = true + end + end + end + + function this:PrintHelp() + if this.ChatWindowWidget then + this.ChatWindowWidget:AddSystemChatMessage("Help Menu") + this.ChatWindowWidget:AddSystemChatMessage("Chat Commands:") + this.ChatWindowWidget:AddSystemChatMessage("/w [PlayerName] or /whisper [PlayerName] - Whisper Chat") + this.ChatWindowWidget:AddSystemChatMessage("/t or /team - Team Chat") + this.ChatWindowWidget:AddSystemChatMessage("/a or /all - All Chat") + + this.ChatWindowWidget:AddSystemChatMessage("/block [PlayerName] - Block communications from Target Player") + this.ChatWindowWidget:AddSystemChatMessage("/unblock [PlayerName] - Restore communications with Target Player") + this.ChatWindowWidget:AddSystemChatMessage("/mute [PlayerName] - Mute in-game communications from Target Player") + this.ChatWindowWidget:AddSystemChatMessage("/unmute [PlayerName] - Restore in-game communications with Target Player") + end + end + + local focusCount = 0 + function this:CreateGUI() + if FORCE_CHAT_GUI or Player.ChatMode == Enum.ChatMode.TextAndMenu and + game:GetService("UserInputService"):GetPlatform() ~= Enum.Platform.XBoxOne + then + if NON_CORESCRIPT_MODE then + local chatGui = Instance.new("ScreenGui") + chatGui.Name = "RobloxGui" + chatGui.Parent = Player:WaitForChild('PlayerGui') + GuiRoot.Parent = chatGui + end + + -- NOTE: eventually we will make multiple chat window frames + this.ChatWindowWidget = CreateChatWindowWidget(this.Settings) + this.ChatBarWidget = CreateChatBarWidget(this.Settings) + this.CurrentWindowMessageCountChanged = this.ChatWindowWidget.MessageCountChanged + + this.ChatWindowWidget.FadeInSignal:connect(function() + this.ChatBarWidget:FadeIn() + end) + this.ChatWindowWidget.FadeOutSignal:connect(function() + this.ChatBarWidget:FadeOut() + end) + + this.ChatWindowWidget:FadeOut(0) + this.ChatBarWidget.ChatBarGainedFocusEvent:connect(function() + focusCount = focusCount + 1 + this.ChatWindowWidget:FadeIn(0.25) + this.ChatWindowWidget:SetFadeLock(true) + this.ChatBarFocusChanged:fire(true) + end) + this.ChatBarWidget.ChatBarLostFocusEvent:connect(function() + local focusNow = focusCount + if Util:IsTouchDevice() then + delay(2, function() + if focusNow == focusCount then + this.ChatWindowWidget:SetFadeLock(false) + end + end) + else + this.ChatWindowWidget:SetFadeLock(false) + end + this.ChatBarFocusChanged:fire(false) + end) + this.ChatBarWidget.ChatBarFloodEvent:connect(function() + if this.ChatWindowWidget then + this.ChatWindowWidget:AddSystemChatMessage("Wait before sending another message.") + end + end) + + this.ChatBarWidget.ChatErrorEvent:connect(function(msg) + if msg then + this.ChatWindowWidget:AddSystemChatMessage(msg) + end + end) + + this.ChatBarWidget.ChatCommandEvent:connect(function(success, actionType, capture) + if actionType == "Help" then + this:PrintHelp() + elseif actionType == "Block" then + local blockPlayerName = capture and tostring(capture) or "" + local playerToBlock = Util.GetPlayerByName(blockPlayerName) + if playerToBlock then + spawn(function() this:BlockPlayerAsync(playerToBlock) end) + else + this.ChatWindowWidget:AddSystemChatMessage("Cannot block " .. blockPlayerName .. " because they are not in the game.") + end + elseif actionType == "Unblock" then + local unblockPlayerName = capture and tostring(capture) or "" + local playerToBlock = Util.GetPlayerByName(unblockPlayerName) + if playerToBlock then + spawn(function() this:UnblockPlayerAsync(playerToBlock) end) + else + this.ChatWindowWidget:AddSystemChatMessage("Cannot unblock " .. unblockPlayerName .. " because they are not in the game.") + end + elseif actionType == "Mute" then + local mutePlayerName = capture and tostring(capture) or "" + local playerToMute = Util.GetPlayerByName(mutePlayerName) + if playerToMute then + this:MutePlayer(playerToMute) + else + this.ChatWindowWidget:AddSystemChatMessage("Cannot mute " .. mutePlayerName .. " because they are not in the game.") + end + elseif actionType == "Unmute" then + local unmutePlayerName = capture and tostring(capture) or "" + local playerToUnmute = Util.GetPlayerByName(unmutePlayerName) + if playerToUnmute then + this:UnmutePlayer(playerToUnmute) + else + this.ChatWindowWidget:AddSystemChatMessage("Cannot unmute " .. unmutePlayerName .. " because they are not in the game.") + end + elseif actionType == "Whisper" then + if success == false then + local playerName = capture and tostring(capture) or "Unknown" + this.ChatWindowWidget:AddSystemChatMessage("Unable to Send a Whisper to Player: " .. playerName) + end + elseif actionType == "Unknown" then + if success == false then + local commandText = capture and tostring(capture) or "Unknown" + this.ChatWindowWidget:AddSystemChatMessage("Invalid Slash Command: " .. commandText) + end + end + end) + + if not NON_CORESCRIPT_MODE then + local function onVREnabled() + if InputService.VREnabled then + self.Settings.TextStrokeTransparency = 1 + self:PrintVRWelcome() + local Panel3D = require(CoreGuiService:WaitForChild('RobloxGui').Modules.VR.Panel3D) + local panel = Panel3D.Get("Chat") + panel:LinkTo("Keyboard") + panel:SetType(Panel3D.Type.Fixed) + panel:ResizePixels(300, 125) + GuiRoot.Parent = panel:GetGUI() + + if this.ChatWindowWidget and this.ChatWindowWidget.ChatContainer then + this.ChatWindowWidget.ChatContainer.MouseButton1Click:connect(function() + if this.ChatBarWidget then + if this.ChatBarWidget:WasFocused() then + this.ChatBarWidget:RemoveFocus() + else + self:FocusChatBar() + end + end + end) + end + + function panel:CalculateTransparency() + return 0 + end + else + self.Settings.TextStrokeTransparency = 0.75 + GuiRoot.Parent = CoreGuiService:WaitForChild('RobloxGui') + end + end + onVREnabled() + InputService.Changed:connect(function(prop) + if prop == 'VREnabled' then + onVREnabled() + end + end) + end + end + end + + local toggleCount = 0 + local function SetVisbility(newVisibility) + this.Visible = newVisibility + if this.ChatWindowWidget then + this.ChatWindowWidget:ToggleVisibility(this.Visible) + if this.Visible then + toggleCount = toggleCount + 1 + local thisToggle = toggleCount + local thisFocusCount = focusCount + this.ChatWindowWidget:FadeIn() + this.ChatWindowWidget:SetFadeLock(true) + delay(5, function() + if thisToggle == toggleCount and thisFocusCount == focusCount then + this.ChatWindowWidget:SetFadeLock(false) + end + end) + end + end + if this.ChatBarWidget then + this.ChatBarWidget:ToggleVisibility(this.Visible) + if this.Visible then + this.ChatBarWidget:FadeIn() + end + if InputService.VREnabled and not this.Visible then + this.ChatBarWidget:RemoveFocus() + end + end + if IsPlayerDropDownEnabled and playerDropDown then + if not this.Visible then + playerDropDown:Hide() + end + end + if InputService.VREnabled then + local Panel3D = require(CoreGuiService:WaitForChild('RobloxGui').Modules.VR.Panel3D) + local panel = Panel3D.Get("Chat") + if this.Visible then + local headLook = Panel3D.GetHeadLookXZ(true) + panel.localCF = headLook * CFrame.Angles(math.rad(5), 0, 0) * CFrame.new(0, 0, 6.5) + panel:ForceShowUntilLookedAt() + else + panel:SetVisible(this.Visible) + end + end + this.VisibilityStateChanged:fire(this.Visible) + end + + function this:ToggleVisibility() + SetVisbility(not self.Visible) + end + + function this:SetVisible(visible) + SetVisbility(visible) + end + + function this:FocusChatBar() + if self.ChatBarWidget and this.Visible then + self.ChatBarWidget:FocusChatBar() + end + end + + function this:IsFocused(useWasFocused) + if not self.ChatBarWidget then return false end + return self.ChatBarWidget:IsFocused() or (useWasFocused and self.ChatBarWidget:WasFocused()) + end + + function this:GetCurrentWindowMessageCount() + if this.ChatWindowWidget then + return this.ChatWindowWidget:GetMessageCount() + end + return 0 + end + + function this:TopbarEnabledChanged(enabled) + topbarEnabled = enabled + -- Update coregui to reflect new topbar status + self:CoreGuiChanged(Enum.CoreGuiType.Chat, StarterGui:GetCoreGuiEnabled(Enum.CoreGuiType.Chat)) + end + + function this:Initialize() + --[[ Developer Customization API ]]-- + if not NON_CORESCRIPT_MODE then + game:WaitForChild("StarterGui"):RegisterSetCore("ChatMakeSystemMessage", function(informationTable) + if this.ChatWindowWidget then + this.ChatWindowWidget:AddDeveloperSystemChatMessage(informationTable) + end + end) + local function isUDim2Value(value) + local success, value = pcall(function() return UDim2.new(value.X.Scale, value.X.Offset, value.Y.Scale, value.Y.Offset) end) + return success and value or nil + end + + local function isBubbleChatOn() + return not PlayersService.ClassicChat and PlayersService.BubbleChat + end + + if allowMoveChat then + game.StarterGui:RegisterSetCore("ChatWindowPosition", function(value) + if this.ChatWindowWidget and this.ChatBarWidget then + value = isUDim2Value(value) + if value ~= nil and not isBubbleChatOn() then + chatRepositioned = true -- Prevent chat from moving back to the original position on screen resolution change + this.ChatWindowWidget.ChatContainer.Position = value + this.ChatBarWidget.ChatBarContainer.Position = value + UDim2.new(0, 0, this.ChatWindowWidget.ChatContainer.Size.Y.Scale, this.ChatWindowWidget.ChatContainer.Size.Y.Offset + 2) + end + end + end) + + game.StarterGui:RegisterSetCore("ChatWindowSize", function(value) + if this.ChatWindowWidget and this.ChatBarWidget then + value = isUDim2Value(value) + if value ~= nil and not isBubbleChatOn() then + chatRepositioned = true + this.ChatWindowWidget.ChatContainer.Size = value + this.ChatBarWidget.ChatBarContainer.Size = UDim2.new(this.ChatWindowWidget.ChatContainer.Size.X.Scale, this.ChatWindowWidget.ChatContainer.Size.X.Offset, this.ChatBarWidget.ChatBarContainer.Size.Y.Scale, this.ChatBarWidget.ChatBarContainer.Size.Y.Offset) + this.ChatBarWidget.ChatBarContainer.Position = this.ChatWindowWidget.ChatContainer.Position + UDim2.new(0, 0, this.ChatWindowWidget.ChatContainer.Size.Y.Scale, this.ChatWindowWidget.ChatContainer.Size.Y.Offset + 2) + end + end + end) + + else + game.StarterGui:RegisterSetCore("ChatWindowPosition", function() end) + game.StarterGui:RegisterSetCore("ChatWindowSize", function() end) + end + + game.StarterGui:RegisterGetCore("ChatWindowPosition", function() + if this.ChatWindowWidget then + return this.ChatWindowWidget.ChatContainer.Position + else + return nil + end + end) + + game.StarterGui:RegisterGetCore("ChatWindowSize", function() + if this.ChatWindowWidget then + return this.ChatWindowWidget.ChatContainer.Size + else + return nil + end + end) + + if allowDisableChatBar then + game.StarterGui:RegisterSetCore("ChatBarDisabled", function(value) + if this.ChatBarWidget then + if type(value) == "boolean" then + chatBarDisabled = value + if value == true then + this.ChatBarWidget:ToggleVisibility(false) + end + end + end + end) + else + game.StarterGui:RegisterSetCore("ChatBarDisabled", function() end) + end + + game.StarterGui:RegisterGetCore("ChatBarDisabled", function() return chatBarDisabled end) + end + + this:OnPlayerAdded(Player) + -- Upsettingly, it seems everytime a player is added, you have to redo the connection + -- NOTE: PlayerAdded only fires on the server, hence ChildAdded is used here + PlayersService.ChildAdded:connect(function(child) + if child:IsA('Player') then + this:OnPlayerAdded(child) + end + end) + this:CreateGUI() + + + this:CoreGuiChanged(Enum.CoreGuiType.Chat, StarterGui:GetCoreGuiEnabled(Enum.CoreGuiType.Chat)) + this.CoreGuiChangedConn = Util.DisconnectEvent(this.CoreGuiChangedConn) + pcall(function() + this.CoreGuiChangedConn = StarterGui.CoreGuiChangedSignal:connect( + function(coreGuiType,enabled) + this:CoreGuiChanged(coreGuiType, enabled) + end) + end) + + if not NON_CORESCRIPT_MODE then + this:PrintWelcome() + end + + --SetVisbility(true) + end + + return this +end + +local moduleApiTable = {} +-- Main Entry Point +do + local ChatInstance = CreateChat() + ChatInstance:Initialize() + + function moduleApiTable:ToggleVisibility() + ChatInstance:ToggleVisibility() + end + + function moduleApiTable:SetVisible(visible) + ChatInstance:SetVisible(visible) + end + + function moduleApiTable:FocusChatBar() + ChatInstance:FocusChatBar() + end + + function moduleApiTable:GetVisibility() + return ChatInstance.Visible + end + + function moduleApiTable:GetMessageCount() + return ChatInstance:GetCurrentWindowMessageCount() + end + + function moduleApiTable:TopbarEnabledChanged(...) + return ChatInstance:TopbarEnabledChanged(...) + end + + function moduleApiTable:IsFocused(useWasFocused) + return ChatInstance:IsFocused(useWasFocused) + end + + moduleApiTable.ChatBarFocusChanged = ChatInstance.ChatBarFocusChanged + moduleApiTable.VisibilityStateChanged = ChatInstance.VisibilityStateChanged + moduleApiTable.MessagesChanged = ChatInstance.CurrentWindowMessageCountChanged + +end + +return moduleApiTable + diff --git a/2016/content/Modules/Panel3D.lua b/2016/content/Modules/Panel3D.lua new file mode 100644 index 0000000..a672056 --- /dev/null +++ b/2016/content/Modules/Panel3D.lua @@ -0,0 +1,491 @@ +--Panel3D: 3D GUI panels for VR +--written by 0xBAADF00D +local PIXELS_PER_STUD = 64 +local SETTINGS_DISTANCE = 3.5 + +local CURSOR_HIDE_TIME = 2 +local CURSOR_FADE_TIME = 0.125 + +local CoreGui = game:GetService('CoreGui') +local RobloxGui = CoreGui:WaitForChild("RobloxGui") + +local Panel3D = {} + +Panel3D.Panels = { + Lower = 1, + Hamburger = 2, + Settings = 3, + Keyboard = 4, + Chat = 5 +} + +Panel3D.Orientation = { + Horizontal = 1, + Fixed = 2 +} + +Panel3D.Visibility = { + BelowAngleThreshold = 1, + Modal = 2, + Normal = 3 +} + +local panelDefaultVectors = { + [Panel3D.Panels.Lower] = CFrame.Angles(math.rad(-45), 0, 0):vectorToWorldSpace(Vector3.new(0, 0, -5)), + [Panel3D.Panels.Hamburger] = CFrame.Angles(math.rad(-55), 0, 0):vectorToWorldSpace(Vector3.new(0, 0, -5)), + [Panel3D.Panels.Settings] = Vector3.new(0, 0, -SETTINGS_DISTANCE), + [Panel3D.Panels.Keyboard] = CFrame.Angles(math.rad(-22.5), 0, 0):vectorToWorldSpace(Vector3.new(0, 0, -5)), + [Panel3D.Panels.Chat] = CFrame.Angles(math.rad(5), 0, 0):vectorToWorldSpace(Vector3.new(0, 0, -5)) +} +local DEFAULT_PANEL_LOCK_THRESHOLD = math.rad(-25) +local panelTransparencyBias = { --tuned values; raise the opacity value to this power + [Panel3D.Panels.Lower] = 6.5, + [Panel3D.Panels.Hamburger] = 8, + [Panel3D.Panels.Settings] = 0, + [Panel3D.Panels.Keyboard] = 1.5, + [Panel3D.Panels.Chat] = 1.5 +} +local panels = {} + +local headScale = 1 + +local renderStepName = "Panel3D" + +local cursor = Instance.new("ImageLabel") +cursor.Image = "rbxasset://textures/Cursors/Gamepad/Pointer.png" +cursor.Size = UDim2.new(0, 8, 0, 8) +cursor.BackgroundTransparency = 1 +cursor.ZIndex = 10 + +local resetOrientationFlag = false +local currentModalPanel = nil + +local GuiService = game:GetService("GuiService") +local UserInputService = game:GetService("UserInputService") + +local cursorHidden = false +local hasTool = false +local lastMouseMove = tick() + +local function OnCharacterAdded(character) + hasTool = false + for i, v in ipairs(character:GetChildren()) do + if v:IsA("Tool") then + hasTool = true + end + end + character.ChildAdded:connect(function(child) + if child:IsA("Tool") then + hasTool = true + lastMouseMove = tick() --kick the mouse when a tool is equipped + end + end) + character.ChildRemoved:connect(function(child) + if child:IsA("Tool") then + hasTool = false + end + end) +end +spawn(function() + while not game.Players.LocalPlayer do wait() end + game.Players.LocalPlayer.CharacterAdded:connect(OnCharacterAdded) + if game.Players.LocalPlayer.Character then OnCharacterAdded(game.Players.LocalPlayer.Character) end +end) +local function autoHideCursor(hide) + if not UserInputService.VREnabled then + cursorHidden = false + return + end + if hide then + --don't hide if there's a tool in the character + local character = game.Players.LocalPlayer.Character + if character and hasTool then + return + end + cursorHidden = true + UserInputService.OverrideMouseIconBehavior = Enum.OverrideMouseIconBehavior.ForceHide + else + cursorHidden = false + UserInputService.OverrideMouseIconBehavior = Enum.OverrideMouseIconBehavior.None + end +end + +local function isCursorVisible() + --if ForceShow, the cursor is definitely visible at all times + if UserInputService.OverrideMouseIconBehavior == Enum.OverrideMouseIconBehavior.ForceShow then + return true + end + --if ForceHide, the cursor is definitely NOT visible + if UserInputService.OverrideMouseIconBehavior == Enum.OverrideMouseIconBehavior.ForceHide then + return false + end + --Otherwise, we need to check if the developer set MouseIconEnabled=false + if UserInputService.MouseIconEnabled and UserInputService.OverrideMouseIconBehavior == Enum.OverrideMouseIconBehavior.None then + return true + end + return false +end + +UserInputService.InputChanged:connect(function(inputObj, processed) + if inputObj.UserInputType == Enum.UserInputType.MouseMovement then + lastMouseMove = tick() + autoHideCursor(false) + end +end) +game:GetService("RunService").Heartbeat:connect(function() + if isCursorVisible() then + cursorHidden = false + end + if lastMouseMove + CURSOR_HIDE_TIME < tick() and not GuiService.MenuIsOpen and not cursorHidden then + autoHideCursor(true) + end +end) + +local function createPanel() + local panelPart = Instance.new("Part") + panelPart.Transparency = 1 + panelPart.CanCollide = false + panelPart.Anchored = true + panelPart.Archivable = false + panelPart.Size = Vector3.new(1.5, 1.5, 1) + panelPart.Parent = workspace.CurrentCamera + local panelGUI = Instance.new("SurfaceGui", CoreGui) + panelGUI.Name = "GUI" + panelGUI.Adornee = panelPart + panelGUI.ToolPunchThroughDistance = 1000 + panelGUI.Active = true + pcall(function() --todo: remove this when api is live + panelGUI.AlwaysOnTop = true + end) + return panelPart, panelGUI +end + +function Panel3D.Get(panelId) + local panel = panels[panelId] + if not panel then + local panelName + for name, value in pairs(Panel3D.Panels) do + if value == panelId then + panelName = name + break + end + end + if not panelName then + error("Tried to request an invalid 3D panel") + end + + local part, gui = createPanel() + + panel = {} + panel.part = part + panel.part.Name = "GUI"--("%sPanel3D"):format(panelName) + panel.gui = gui + panel.gui.Name = ("%sPanelGUI"):format(panelName) + + panel.vector = panelDefaultVectors[panelId] + panel.horizontalVector = Vector3.new(panel.vector.x, 0, panel.vector.z).unit + panel.pitchAngle = math.asin(panel.vector.unit.y) + panel.verticalRange = math.rad(5) + panel.horizontalRange = math.rad(5) + + panel.transparencyCallbacks = {} + + panel.OnMouseEnter = nil + panel.OnMouseLeave = nil + + panel.pixelScale = 1 + + panel.visible = true + panel.visibilityBehavior = Panel3D.Visibility.BelowAngleThreshold + + panel.orientationMode = Panel3D.Orientation.Horizontal + panel.orientation = nil + + panel.cursorEnabled = true + + panel.width = 1 + panel.height = 1 + + function panel:AddTransparencyCallback(callback) + table.insert(panel.transparencyCallbacks, callback) + end + + function panel:Resize(width, height, pixelsPerStud) + panel.width = width + panel.height = height + + pixelsPerStud = pixelsPerStud or PIXELS_PER_STUD + panel.pixelScale = pixelsPerStud / PIXELS_PER_STUD + panel.part.Size = Vector3.new(panel.width * headScale, panel.height * headScale, 1) + panel.gui.CanvasSize = Vector2.new(pixelsPerStud * panel.width, pixelsPerStud * panel.height) + + local distance = panel.vector.magnitude + panel.verticalRange = math.atan(panel.part.Size.Y / (2 * distance)) * 2 + panel.horizontalRange = math.atan(panel.part.Size.X / (2 * distance)) * 2 + end + + function panel:ResizePixels(width, height) + local widthStuds = width / PIXELS_PER_STUD + local heightStuds = height / PIXELS_PER_STUD + panel:Resize(widthStuds, heightStuds) + end + + function panel:SetModal() + panel.visible = false + panel.visibilityBehavior = Panel3D.Visibility.Modal + + if panel.visible then + currentModalPanel = panel + if panel.orientationMode == Panel3D.Orientation.Fixed then + local userHeadCFrame = UserInputService:GetUserCFrame(Enum.UserCFrame.Head) + panel.orientation = userHeadCFrame * CFrame.new(0, 0, -panel.vector.magnitude) * CFrame.Angles(0, math.pi, 0) + end + end + end + + function panel:SetVisible(visible) + panel.visible = visible + + if visible and panel.visibilityBehavior == Panel3D.Visibility.Modal then + currentModalPanel = panel + if panel.orientationMode == Panel3D.Orientation.Fixed then + local userHeadCFrame = UserInputService:GetUserCFrame(Enum.UserCFrame.Head) + panel.orientation = userHeadCFrame * CFrame.new(0, 0, -panel.vector.magnitude) * CFrame.Angles(0, math.pi, 0) + end + else + if currentModalPanel == panel then + currentModalPanel = nil + end + end + end + + panels[panelId] = panel + end + return panel +end + +function Panel3D.ResetOrientation() + resetOrientationFlag = true +end + +function Panel3D.GetGUI(panel) + local panelGUI = panelGUIs[panel] + if not panelGUI then + local part = Panel3D.GetPart(panel) + panelGUI = panelGUIs[panel] + end + return panelGUI +end + +local zeroVector = Vector3.new(0, 0, 0) +local headXZ = CFrame.new() +local headOffset = Vector3.new() +local currentHoverPanel = nil +local savedMouseBehavior = Enum.MouseBehavior.Default +function Panel3D.OnRenderStep() + if not UserInputService.VREnabled then + return + end + local cameraCFrame = workspace.CurrentCamera.CFrame + local cameraRenderCFrame = workspace.CurrentCamera:GetRenderCFrame() + local userHeadCFrame = UserInputService:GetUserCFrame(Enum.UserCFrame.Head) + + local userHeadLook = userHeadCFrame.lookVector + local userHeadHorizontalVector = Vector3.new(userHeadLook.X, 0, userHeadLook.Z).unit + local userHeadPitch = math.asin(userHeadLook.Y) + + local panelLockThreshold = DEFAULT_PANEL_LOCK_THRESHOLD + + for panelId, panel in pairs(panels) do + if panel.pitchLockThreshold and panel.visible then + panelLockThreshold = math.max(panelLockThreshold, panel.pitchLockThreshold) + end + end + + local isAboveThreshold = false + if userHeadPitch > panelLockThreshold or resetOrientationFlag then + isAboveThreshold = true + headXZ = CFrame.new(zeroVector, userHeadHorizontalVector) + headOffset = userHeadCFrame.p + resetOrientationFlag = false + end + + local panelsOrigin = cameraCFrame * CFrame.new(headOffset) * headXZ + for panelId, panel in pairs(panels) do + if panel.visibilityBehavior == Panel3D.Visibility.BelowAngleThreshold then + panel.visible = not (isAboveThreshold or currentModalPanel) + end + + if not panel.visible then + panel.part.Parent = nil + panel.gui.Adornee = nil + else + panel.part.Parent = workspace.CurrentCamera --TODO: move to new 3D gui space + panel.gui.Adornee = panel.part + + local panelCFrame; + if panel.orientationMode == Panel3D.Orientation.Fixed and panel.orientation then + local pos = panel.orientation.p * headScale + panel.part.CFrame = workspace.CurrentCamera.CFrame * ((panel.orientation - panel.orientation.p) + pos) + panelCFrame = panel.part.CFrame + else + local panelPosition = panelsOrigin:pointToWorldSpace(panel.vector * headScale) + panelCFrame = CFrame.new(panelPosition, panelsOrigin.p) + panel.part.CFrame = panelCFrame + end + + local toPanel = (panelCFrame.p - cameraRenderCFrame.p).unit + + local transparency = panel.visible and 1 - (math.max(0, cameraRenderCFrame.lookVector:Dot(toPanel)) ^ panelTransparencyBias[panelId]) or 1 + for _, callback in pairs(panel.transparencyCallbacks) do + callback(transparency) + end + end + end + + --Render a cursor overlaid onto the panels + local cframe = cameraRenderCFrame + local ray = Ray.new(cframe.p, cframe.lookVector * 999) + local ignoreList = { game.Players.LocalPlayer.Character } + local part, endpoint = workspace:FindPartOnRayWithIgnoreList(ray, ignoreList) + local hitPanel = nil + local hitPanelId = nil + for panelId, panel in pairs(panels) do + if part == panel.part then + hitPanel = panel + hitPanelId = panelId + end + end + if hitPanel then + if not currentHoverPanel then + savedMouseBehavior = UserInputService.MouseBehavior + UserInputService.MouseBehavior = Enum.MouseBehavior.LockCenter + else + if currentHoverPanel ~= hitPanel then + if currentHoverPanel.OnMouseLeave then + currentHoverPanel:OnMouseLeave() + end + end + end + if hitPanel.OnMouseEnter and currentHoverPanel ~= hitPanel then + hitPanel:OnMouseEnter() + end + + currentHoverPanel = hitPanel + + UserInputService.OverrideMouseIconBehavior = Enum.OverrideMouseIconBehavior.ForceHide + if hitPanel.cursorEnabled then + cursor.Parent = hitPanel.gui + else + cursor.Parent = nil + end + + local localEndpoint = part:GetRenderCFrame():pointToObjectSpace(endpoint) + local x = (localEndpoint.X / part.Size.X) + 0.5 + local y = (localEndpoint.Y / part.Size.Y) + 0.5 + x = 1 - x + y = 1 - y + cursor.Size = UDim2.new(0, 8 * hitPanel.pixelScale, 0, 8 * hitPanel.pixelScale) + cursor.Position = UDim2.new(x, -cursor.AbsoluteSize.x * 0.5, y, -cursor.AbsoluteSize.y * 0.5) + + if hitPanel.visible and not modalPanelIsOpen then + hitPanel.part.Parent = workspace.CurrentCamera + for _, callback in pairs(hitPanel.transparencyCallbacks) do + callback(0) + end + end + else + if currentHoverPanel then + UserInputService.MouseBehavior = savedMouseBehavior + + if currentHoverPanel.OnMouseLeave then + currentHoverPanel:OnMouseLeave() + end + end + currentHoverPanel = false + cursor.Parent = nil + end +end + + + +-- RayPlaneIntersection + +-- http://www.siggraph.org/education/materials/HyperGraph/raytrace/rayplane_intersection.htm +local function RayPlaneIntersection(ray, planeNormal, pointOnPlane) + planeNormal = planeNormal.unit + ray = ray.Unit + -- compute Pn (dot) Rd = Vd and check if Vd == 0 then we know ray is parallel to plane + local Vd = planeNormal:Dot(ray.Direction) + + -- could fuzzy equals this a little bit to account for imprecision or very close angles to zero + if Vd == 0 then -- parallel, no intersection + return nil + end + + local V0 = planeNormal:Dot(pointOnPlane - ray.Origin) + local t = V0 / Vd + + if t < 0 then --plane is behind ray origin, and thus there is no intersection + return nil + end + + return ray.Origin + ray.Direction * t +end + +function Panel3D.FindHoveredGuiElement(panel, elements) + local cameraRenderCFrame = workspace.CurrentCamera and workspace.CurrentCamera:GetRenderCFrame() + local panelPart = panel.part + if cameraRenderCFrame and panelPart then + local panelPartSize = panelPart.Size + local panelSurfaceCFrame = panelPart.CFrame + panelPart.CFrame.lookVector * (panelPartSize.Z * 0.5) + local intersectionPt = RayPlaneIntersection(Ray.new(cameraRenderCFrame.p, cameraRenderCFrame.lookVector), panelSurfaceCFrame.lookVector, panelSurfaceCFrame.p) + if intersectionPt then + local localPoint = panelSurfaceCFrame:pointToObjectSpace(intersectionPt) * Vector3.new(-1, 1, 1) + Vector3.new(panelPartSize.X/2, -panelPartSize.Y/2, 0) + local guiPoint = Vector2.new((localPoint.X / panelPartSize.X) * panel.gui.AbsoluteSize.X, (localPoint.Y / panelPartSize.Y) * -panel.gui.AbsoluteSize.Y) + + local x = guiPoint.x + local y = guiPoint.y + for _, item in pairs(elements) do + local minPt = item.AbsolutePosition + local maxPt = item.AbsolutePosition + item.AbsoluteSize + if minPt.X <= x and maxPt.X >= x and minPt.Y <= y and maxPt.Y >= y then + return item + end + end + end + end +end + + + + + +game:GetService("RunService"):BindToRenderStep(renderStepName, Enum.RenderPriority.Last.Value, Panel3D.OnRenderStep) + +local function OnCameraChanged(prop) + if prop == "HeadScale" then + pcall(function() + headScale = workspace.CurrentCamera.HeadScale + end) + for i, v in pairs(panels) do + v:Resize(v.width, v.height, v.pixelScale * PIXELS_PER_STUD) + end + end +end +local cameraChangedConn = nil +workspace.Changed:connect(function(prop) + if prop == "CurrentCamera" then + OnCameraChanged("HeadScale") + if cameraChangedConn then + cameraChangedConn:disconnect() + end + cameraChangedConn = workspace.CurrentCamera.Changed:connect(OnCameraChanged) + end +end) +if workspace.CurrentCamera then + OnCameraChanged("HeadScale") + cameraChangedConn = workspace.CurrentCamera.Changed:connect(OnCameraChanged) +end + +return Panel3D \ No newline at end of file diff --git a/2016/content/Modules/PlayerDropDown.lua b/2016/content/Modules/PlayerDropDown.lua new file mode 100644 index 0000000..017a54d --- /dev/null +++ b/2016/content/Modules/PlayerDropDown.lua @@ -0,0 +1,628 @@ +--[[ + // FileName: PlayerDropDown.lua + // Written by: TheGamer101 + // Description: Code for the player drop down in the PlayerList and Chat +]] +local moduleApiTable = {} + +--[[ Services ]]-- +local CoreGui = game:GetService('CoreGui') +local HttpService = game:GetService('HttpService') +local HttpRbxApiService = game:GetService('HttpRbxApiService') +local PlayersService = game:GetService('Players') + +--[[ Script Variables ]]-- +local LocalPlayer = PlayersService.LocalPlayer + +--[[ Constants ]]-- +local POPUP_ENTRY_SIZE_Y = 24 +local ENTRY_PAD = 2 +local BG_TRANSPARENCY = 0.5 +local BG_COLOR = Color3.new(31/255, 31/255, 31/255) +local TEXT_STROKE_TRANSPARENCY = 0.75 +local TEXT_COLOR = Color3.new(1, 1, 243/255) +local TEXT_STROKE_COLOR = Color3.new(34/255, 34/255, 34/255) +local MAX_FRIEND_COUNT = 200 +local FRIEND_IMAGE = 'http://www.roblox.com/thumbs/avatar.ashx?userId=' + +--[[ Fast Flags ]]-- +local followerSuccess, isFollowersEnabled = pcall(function() return settings():GetFFlag("EnableLuaFollowers") end) +local IsFollowersEnabled = followerSuccess and isFollowersEnabled + +local serverFollowersSuccess, serverFollowersEnabled = pcall(function() return settings():GetFFlag("UserServerFollowers") end) +local IsServerFollowers = serverFollowersSuccess and serverFollowersEnabled + +--[[ Modules ]]-- +local RobloxGui = CoreGui:WaitForChild('RobloxGui') +local reportAbuseMenu = require(RobloxGui.Modules.Settings.Pages.ReportAbuseMenu) + +--[[ Bindables ]]-- +local BinbableFunction_SendNotification = nil +spawn(function() + BinbableFunction_SendNotification = RobloxGui:WaitForChild("SendNotification") +end) + +--[[ Remotes ]]-- +local RemoteEvent_NewFollower = nil + +spawn(function() + local RobloxReplicatedStorage = game:GetService('RobloxReplicatedStorage') + RemoteEvent_NewFollower = RobloxReplicatedStorage:WaitForChild('NewFollower') +end) + +--[[ Utility Functions ]]-- +local function createSignal() + local sig = {} + + local mSignaler = Instance.new('BindableEvent') + + local mArgData = nil + local mArgDataCount = nil + + function sig:fire(...) + mArgData = {...} + mArgDataCount = select('#', ...) + mSignaler:Fire() + end + + function sig:connect(f) + if not f then error("connect(nil)", 2) end + return mSignaler.Event:connect(function() + f(unpack(mArgData, 1, mArgDataCount)) + end) + end + + function sig:wait() + mSignaler.Event:wait() + assert(mArgData, "Missing arg data, likely due to :TweenSize/Position corrupting threadrefs.") + return unpack(mArgData, 1, mArgDataCount) + end + + return sig +end + +--[[ Events ]]-- +local BlockStatusChanged = createSignal() + +--[[ Personal Server Stuff ]]-- +local IsPersonalServer = false +local PersonalServerService = nil +if game.Workspace:FindFirstChild('PSVariable') then + IsPersonalServer = true + PersonalServerService = game:GetService('PersonalServerService') +end +game.Workspace.ChildAdded:connect(function(child) + if child.Name == 'PSVariable' and child:IsA('BoolValue') then + IsPersonalServer = true + PersonalServerService = game:GetService('PersonalServerService') + end +end) + +local PRIVILEGE_LEVEL = { + OWNER = 255, + ADMIN = 240, + MEMBER = 128, + VISITOR = 10, + BANNED = 0, +} + +local function onPrivilegeLevelSelect(player, rank) + while player.PersonalServerRank < rank do + PersonalServerService:Promote(player) + end + while player.PersonalServerRank > rank do + PersonalServerService:Demote(player) + end +end + +--[[ Follower Notifications ]]-- +local function sendNotification(title, text, image, duration, callback) + if BinbableFunction_SendNotification then + BinbableFunction_SendNotification:Invoke(title, text, image, duration, callback) + end +end + +--[[ Friend Functions ]]-- +local function getFriendStatus(selectedPlayer) + if selectedPlayer == LocalPlayer then + return Enum.FriendStatus.NotFriend + else + local success, result = pcall(function() + -- NOTE: Core script only + return LocalPlayer:GetFriendStatus(selectedPlayer) + end) + if success then + return result + else + return Enum.FriendStatus.NotFriend + end + end +end + +-- if userId = nil, then it will get count for local player +local function getFriendCountAsync(userId) + local friendCount = nil + local wasSuccess, result = pcall(function() + local str = 'user/get-friendship-count' + if userId then + str = str..'?userId='..tostring(userId) + end + return HttpRbxApiService:GetAsync(str, true) + end) + if not wasSuccess then + print("getFriendCountAsync() failed because", result) + return nil + end + result = HttpService:JSONDecode(result) + + if result["success"] and result["count"] then + friendCount = result["count"] + end + + return friendCount +end + +-- checks if we can send a friend request. Right now the only way we +-- can't is if one of the players is at the max friend limit +local function canSendFriendRequestAsync(otherPlayer) + local theirFriendCount = getFriendCountAsync(otherPlayer.userId) + local myFriendCount = getFriendCountAsync() + + -- assume max friends if web call fails + if not myFriendCount or not theirFriendCount then + return false + end + if myFriendCount < MAX_FRIEND_COUNT and theirFriendCount < MAX_FRIEND_COUNT then + return true + elseif myFriendCount >= MAX_FRIEND_COUNT then + sendNotification("Cannot send friend request", "You are at the max friends limit.", "", 5, function() end) + return false + elseif theirFriendCount >= MAX_FRIEND_COUNT then + sendNotification("Cannot send friend request", otherPlayer.Name.." is at the max friends limit.", "", 5, function() end) + return false + end +end + +--[[ Follower Functions ]]-- + +-- Returns whether followerUserId is following userId +local function isFollowing(userId, followerUserId) + local apiPath = "user/following-exists?userId=" + local params = userId.."&followerUserId="..followerUserId + local success, result = pcall(function() + return HttpRbxApiService:GetAsync(apiPath..params, true) + end) + if not success then + print("isFollowing() failed because", result) + return false + end + + -- can now parse web response + result = HttpService:JSONDecode(result) + return result["success"] and result["isFollowing"] +end + +--[[ Functions for Blocking users ]]-- +local BlockedList = {} +local MutedList = {} + +local function GetBlockedPlayersAsync() + local userId = LocalPlayer.userId + local apiPath = "userblock/getblockedusers" .. "?" .. "userId=" .. tostring(userId) .. "&" .. "page=" .. "1" + if userId > 0 then + local blockList = nil + local success, msg = pcall(function() + local request = HttpRbxApiService:GetAsync(apiPath) + blockList = request and game:GetService('HttpService'):JSONDecode(request) + end) + if blockList and blockList['success'] == true and blockList['userList'] then + return blockList['userList'] + end + end + return {} +end + +spawn(function() + BlockedList = GetBlockedPlayersAsync() +end) + +local function isBlocked(userId) + if (BlockedList[userId] ~= nil and BlockedList[userId] == true) then + return true + end + return false +end + +local function isMuted(userId) + if (MutedList[userId] ~= nil and MutedList[userId] == true) then + return true + end + return false +end + +local function BlockPlayerAsync(playerToBlock) + if playerToBlock and LocalPlayer ~= playerToBlock then + local blockUserId = playerToBlock.UserId + if blockUserId > 0 then + if not isBlocked(blockUserId) then + BlockedList[blockUserId] = true + BlockStatusChanged:fire(blockUserId, true) + pcall(function() + local success = PlayersService:BlockUser(LocalPlayer.userId, blockUserId) + end) + end + end + end +end + +local function UnblockPlayerAsync(playerToUnblock) + if playerToUnblock then + local unblockUserId = playerToUnblock.userId + + if isBlocked(unblockUserId) then + BlockedList[unblockUserId] = nil + BlockStatusChanged:fire(unblockUserId, false) + pcall(function() + local success = PlayersService:UnblockUser(LocalPlayer.userId, unblockUserId) + end) + end + end +end + +local function MutePlayer(playerToMute) + if playerToMute and LocalPlayer ~= playerToMute then + local muteUserId = playerToMute.UserId + if muteUserId > 0 then + if not isMuted(muteUserId) then + MutedList[muteUserId] = true + end + end + end +end + +local function UnmutePlayer(playerToUnmute) + if playerToUnmute then + local unmuteUserId = playerToUnmute.UserId + MutedList[unmuteUserId] = nil + end +end + +--[[ Function to create DropDown class ]]-- +function createPlayerDropDown() + local playerDropDown = {} + playerDropDown.Player = nil + playerDropDown.PopupFrame = nil + playerDropDown.HidePopupImmediately = false + playerDropDown.PopupFrameOffScreenPosition = nil -- if this is set the popup frame tweens to a different offscreen position than the default + + playerDropDown.HiddenSignal = createSignal() + + --[[ Functions for when options in the dropdown are pressed ]]-- + local function onFriendButtonPressed() + if playerDropDown.Player then + local status = getFriendStatus(playerDropDown.Player) + if status == Enum.FriendStatus.Friend then + LocalPlayer:RevokeFriendship(playerDropDown.Player) + elseif status == Enum.FriendStatus.Unknown or status == Enum.FriendStatus.NotFriend then + -- cache and spawn + local cachedLastSelectedPlayer = playerDropDown.Player + spawn(function() + -- check for max friends before letting them send the request + if canSendFriendRequestAsync(cachedLastSelectedPlayer) then -- Yields + if cachedLastSelectedPlayer and cachedLastSelectedPlayer.Parent == PlayersService then + LocalPlayer:RequestFriendship(cachedLastSelectedPlayer) + end + end + end) + elseif status == Enum.FriendStatus.FriendRequestSent then + LocalPlayer:RevokeFriendship(playerDropDown.Player) + elseif status == Enum.FriendStatus.FriendRequestReceived then + LocalPlayer:RequestFriendship(playerDropDown.Player) + end + + playerDropDown:Hide() + end + end + + local function onDeclineFriendButonPressed() + if playerDropDown.Player then + LocalPlayer:RevokeFriendship(playerDropDown.Player) + playerDropDown:Hide() + end + end + + -- Client unfollows followedUserId + local function onUnfollowButtonPressed() + if not playerDropDown.Player then return end + -- + local apiPath = "user/unfollow" + local params = "followedUserId="..tostring(playerDropDown.Player.userId) + local success, result = pcall(function() + return HttpRbxApiService:PostAsync(apiPath, params, true, Enum.ThrottlingPriority.Default, Enum.HttpContentType.ApplicationUrlEncoded) + end) + if not success then + print("unfollowPlayer() failed because", result) + playerDropDown:Hide() + return + end + + result = HttpService:JSONDecode(result) + if result["success"] then + if RemoteEvent_NewFollower then + RemoteEvent_NewFollower:FireServer(playerDropDown.Player, false) + end + moduleApiTable.FollowerStatusChanged:fire() + end + + playerDropDown:Hide() + -- no need to send notification when someone unfollows + end + + local function onBlockButtonPressed() + if playerDropDown.Player then + local cachedPlayer = playerDropDown.Player + spawn(function() + BlockPlayerAsync(cachedPlayer) + end) + playerDropDown:Hide() + end + end + + local function onUnblockButtonPressed() + if playerDropDown.Player then + local cachedPlayer = playerDropDown.Player + spawn(function() + UnblockPlayerAsync(cachedPlayer) + end) + playerDropDown:Hide() + end + end + + local function onReportButtonPressed() + if playerDropDown.Player then + reportAbuseMenu:ReportPlayer(playerDropDown.Player) + playerDropDown:Hide() + end + end + + -- Client follows followedUserId + local function onFollowButtonPressed() + if not playerDropDown.Player then return end + -- + local followedUserId = tostring(playerDropDown.Player.userId) + local apiPath = "user/follow" + local params = "followedUserId="..followedUserId + local success, result = pcall(function() + return HttpRbxApiService:PostAsync(apiPath, params, true, Enum.ThrottlingPriority.Default, Enum.HttpContentType.ApplicationUrlEncoded) + end) + if not success then + print("followPlayer() failed because", result) + playerDropDown:Hide() + return + end + + result = HttpService:JSONDecode(result) + if result["success"] then + sendNotification("You are", "now following "..playerDropDown.Player.Name, FRIEND_IMAGE..followedUserId.."&x=48&y=48", 5, function() end) + if RemoteEvent_NewFollower then + RemoteEvent_NewFollower:FireServer(playerDropDown.Player, true) + end + moduleApiTable.FollowerStatusChanged:fire() + end + + playerDropDown:Hide() + end + + --[[ GUI Creation Functions ]]-- + local function createPersonalServerDialog(buttons, selectedPlayer) + local showPersonalServerRanks = IsPersonalServer and LocalPlayer.PersonalServerRank >= PRIVILEGE_LEVEL.ADMIN and LocalPlayer.PersonalServerRank > selectedPlayer.PersonalServerRank + if showPersonalServerRanks then + table.insert(buttons, { + Name = "BanButton", + Text = "Ban", + OnPress = function() + playerDropDown:Hide() + onPrivilegeLevelSelect(selectedPlayer, PRIVILEGE_LEVEL.BANNED) + end, + }) + table.insert(buttons, { + Name = "VistorButton", + Text = "Visitor", + OnPress = function() + onPrivilegeLevelSelect(selectedPlayer, PRIVILEGE_LEVEL.VISITOR) + end, + }) + table.insert(buttons, { + Name = "MemberButton", + Text = "Member", + OnPress = function() + onPrivilegeLevelSelect(selectedPlayer, PRIVILEGE_LEVEL.MEMBER) + end, + }) + table.insert(buttons, { + Name = "AdminButton", + Text = "Admin", + OnPress = function() + onPrivilegeLevelSelect(selectedPlayer, PRIVILEGE_LEVEL.ADMIN) + end, + }) + end + end + + local function createPopupFrame(buttons) + local frame = Instance.new('Frame') + frame.Name = "PopupFrame" + frame.Size = UDim2.new(1, 0, 0, (POPUP_ENTRY_SIZE_Y * #buttons) + (#buttons - ENTRY_PAD)) + frame.Position = UDim2.new(1, 1, 0, 0) + frame.BackgroundTransparency = 1 + + for i,button in ipairs(buttons) do + local btn = Instance.new('TextButton') + btn.Name = button.Name + btn.Size = UDim2.new(1, 0, 0, POPUP_ENTRY_SIZE_Y) + btn.Position = UDim2.new(0, 0, 0, POPUP_ENTRY_SIZE_Y * (i - 1) + ((i - 1) * ENTRY_PAD)) + btn.BackgroundTransparency = BG_TRANSPARENCY + btn.BackgroundColor3 = BG_COLOR + btn.BorderSizePixel = 0 + btn.Text = button.Text + btn.Font = Enum.Font.SourceSans + btn.FontSize = Enum.FontSize.Size14 + btn.TextColor3 = TEXT_COLOR + btn.TextStrokeTransparency = TEXT_STROKE_TRANSPARENCY + btn.TextStrokeColor3 = TEXT_STROKE_COLOR + btn.AutoButtonColor = true + btn.Parent = frame + + btn.MouseButton1Click:connect(button.OnPress) + end + + return frame + end + + --[[ PlayerDropDown Functions ]]-- + function playerDropDown:Hide() + if playerDropDown.PopupFrame then + local offscreenPosition = (playerDropDown.PopupFrameOffScreenPosition ~= nil and playerDropDown.PopupFrameOffScreenPosition or UDim2.new(1, 1, 0, playerDropDown.PopupFrame.Position.Y.Offset)) + if not playerDropDown.HidePopupImmediately then + playerDropDown.PopupFrame:TweenPosition(offscreenPosition, Enum.EasingDirection.InOut, + Enum.EasingStyle.Quad, TWEEN_TIME, true, function() + if playerDropDown.PopupFrame then + playerDropDown.PopupFrame:Destroy() + playerDropDown.PopupFrame = nil + end + end) + else + playerDropDown.PopupFrame:Destroy() + playerDropDown.PopupFrame = nil + end + end + if playerDropDown.Player then + playerDropDown.Player = nil + end + playerDropDown.HiddenSignal:fire() + end + + function playerDropDown:CreatePopup(Player) + playerDropDown.Player = Player + + local buttons = {} + + local status = getFriendStatus(playerDropDown.Player) + local friendText = "" + local canDeclineFriend = false + if status == Enum.FriendStatus.Friend then + friendText = "Unfriend Player" + elseif status == Enum.FriendStatus.Unknown or status == Enum.FriendStatus.NotFriend then + friendText = "Send Friend Request" + elseif status == Enum.FriendStatus.FriendRequestSent then + friendText = "Revoke Friend Request" + elseif status == Enum.FriendStatus.FriendRequestReceived then + friendText = "Accept Friend Request" + canDeclineFriend = true + end + + local blocked = isBlocked(playerDropDown.Player.userId) + + if not blocked then + table.insert(buttons, { + Name = "FriendButton", + Text = friendText, + OnPress = onFriendButtonPressed, + }) + end + + if canDeclineFriend and not blocked then + table.insert(buttons, { + Name = "DeclineFriend", + Text = "Decline Friend Request", + OnPress = onDeclineFriendButonPressed, + }) + end + -- following status + if IsServerFollowers or IsFollowersEnabled then + local following = isFollowing(playerDropDown.Player.userId, LocalPlayer.userId) + local followerText = following and "Unfollow Player" or "Follow Player" + + if not blocked then + table.insert(buttons, { + Name = "FollowerButton", + Text = followerText, + OnPress = following and onUnfollowButtonPressed or onFollowButtonPressed, + }) + end + end + + local blockedText = blocked and "Unblock Player" or "Block Player" + table.insert(buttons, { + Name = "BlockButton", + Text = blockedText, + OnPress = blocked and onUnblockButtonPressed or onBlockButtonPressed, + }) + table.insert(buttons, { + Name = "ReportButton", + Text = "Report Abuse", + OnPress = onReportButtonPressed, + }) + + createPersonalServerDialog(buttons, playerDropDown.Player) + if playerDropDown.PopupFrame then + playerDropDown.PopupFrame:Destroy() + end + playerDropDown.PopupFrame = createPopupFrame(buttons) + return playerDropDown.PopupFrame + end + + --[[ PlayerRemoving Connection ]]-- + PlayersService.PlayerRemoving:connect(function(leavingPlayer) + if playerDropDown.Player == leavingPlayer then + playerDropDown:Hide() + end + end) + + return playerDropDown +end + + +do + moduleApiTable.FollowerStatusChanged = createSignal() + + function moduleApiTable:CreatePlayerDropDown() + return createPlayerDropDown() + end + + function moduleApiTable:CreateBlockingUtility() + local blockingUtility = {} + + function blockingUtility:BlockPlayerAsync(player) + return BlockPlayerAsync(player) + end + + function blockingUtility:UnblockPlayerAsync(player) + return UnblockPlayerAsync(player) + end + + function blockingUtility:MutePlayer(player) + return MutePlayer(player) + end + + function blockingUtility:UnmutePlayer(player) + return UnmutePlayer(player) + end + + function blockingUtility:IsPlayerBlockedByUserId(userId) + return isBlocked(userId) + end + + function blockingUtility:GetBlockedStatusChangedEvent() + return BlockStatusChanged + end + + function blockingUtility:IsPlayerMutedByUserId(userId) + return isMuted(userId) + end + + return blockingUtility + end +end + +return moduleApiTable diff --git a/2016/content/Modules/PlayerlistModule.lua b/2016/content/Modules/PlayerlistModule.lua new file mode 100644 index 0000000..bec5c5f --- /dev/null +++ b/2016/content/Modules/PlayerlistModule.lua @@ -0,0 +1,1752 @@ +--[[ + // FileName: PlayerlistModule.lua + // Version 1.3 + // Written by: jmargh + // Description: Implementation of in game player list and leaderboard +]] + +local CoreGui = game:GetService('CoreGui') +local GuiService = game:GetService('GuiService') -- NOTE: Can only use in core scripts +local UserInputService = game:GetService('UserInputService') +local HttpService = game:GetService('HttpService') +local HttpRbxApiService = game:GetService('HttpRbxApiService') +local Players = game:GetService('Players') +local TeamsService = game:FindService('Teams') +local ContextActionService = game:GetService('ContextActionService') +local StarterGui = game:GetService('StarterGui') + +local RbxGuiLibrary = nil +if LoadLibrary then + RbxGuiLibrary = LoadLibrary("RbxGui") +end + +while not Players.LocalPlayer do + wait() +end +local Player = Players.LocalPlayer +local RobloxGui = CoreGui:WaitForChild('RobloxGui') + +local TenFootInterface = require(RobloxGui.Modules.TenFootInterface) +local isTenFootInterface = TenFootInterface:IsEnabled() + +local playerDropDownModule = require(RobloxGui.Modules.PlayerDropDown) +local blockingUtility = playerDropDownModule:CreateBlockingUtility() +local playerDropDown = playerDropDownModule:CreatePlayerDropDown() + +--[[ Fast Flags ]]-- +local followerSuccess, isFollowersEnabled = pcall(function() return settings():GetFFlag("EnableLuaFollowers") end) +local IsFollowersEnabled = followerSuccess and isFollowersEnabled + +local serverFollowersSuccess, serverFollowersEnabled = pcall(function() return settings():GetFFlag("UserServerFollowers") end) +local IsServerFollowers = serverFollowersSuccess and serverFollowersEnabled + +--[[ Remotes ]]-- +local RemoveEvent_OnFollowRelationshipChanged = nil +local RemoteFunc_GetFollowRelationships = nil + +--[[ Start Module ]]-- +local Playerlist = {} + +--[[ Public Event API ]]-- +-- Parameters: Sorted Array - see GameStats below +Playerlist.OnLeaderstatsChanged = Instance.new('BindableEvent') +-- Parameters: nameOfStat(string), formatedStringOfStat(string) +Playerlist.OnStatChanged = Instance.new('BindableEvent') + +--[[ Client Stat Table ]]-- +-- Sorted Array of tables +local GameStats = {} +-- Fields + -- Name: String the developer has given the stat + -- Text: Formated string of the stat value + -- AddId: Child add order id + -- IsPrimary: Is this the primary stat + -- Priority: Sorting priority +-- NOTE: IsPrimary and Priority are unofficially supported. They are left over legacy from the old player list. +-- They can be un-supported at anytime. You should prefer using child add order to order your stats in the leader board. + +--[[ Script Variables ]]-- +local topbarEnabled = true +local playerlistCoreGuiEnabled = true +local MyPlayerEntryTopFrame = nil +local PlayerEntries = {} +local StatAddId = 0 +local TeamEntries = {} +local TeamAddId = 0 +local NeutralTeam = nil +local IsShowingNeutralFrame = false +local LastSelectedFrame = nil +local LastSelectedPlayer = nil +local MinContainerSize = UDim2.new(0, 165, 0.5, 0) +if isTenFootInterface then + MinContainerSize = UDim2.new(0, 1000, 0, 720) +end +local TempHideKeys = {} + +local PlayerEntrySizeY = 24 +if isTenFootInterface then + PlayerEntrySizeY = 80 +end + +local TeamEntrySizeY = 18 + +if isTenFootInterface then + TeamEntrySizeY = 32 +end + +local NameEntrySizeX = 170 +if isTenFootInterface then + NameEntrySizeX = 350 +end + +local StatEntrySizeX = 75 +if isTenFootInterface then + StatEntrySizeX = 250 +end + +local IsSmallScreenDevice = UserInputService.TouchEnabled and GuiService:GetScreenResolution().Y <= 500 + +local BaseUrl = game:GetService('ContentProvider').BaseUrl:lower() +BaseUrl = string.gsub(BaseUrl, "/m.", "/www.") +AssetGameUrl = string.gsub(BaseUrl, 'www', 'assetgame') + +--[[ Constants ]]-- +local ENTRY_PAD = 2 +local BG_TRANSPARENCY = 0.5 +local BG_COLOR = Color3.new(31/255, 31/255, 31/255) +local BG_COLOR_TOP = Color3.new(106/255, 106/255, 106/255) +local TEXT_STROKE_TRANSPARENCY = 0.75 +local TEXT_COLOR = Color3.new(1, 1, 243/255) +local TEXT_STROKE_COLOR = Color3.new(34/255, 34/255, 34/255) +local TWEEN_TIME = 0.15 +local MAX_LEADERSTATS = 4 +local MAX_STR_LEN = 12 +local TILE_SPACING = 2 +if isTenFootInterface then + BG_COLOR_TOP = Color3.new(25/255, 25/255, 25/255) + BG_COLOR = Color3.new(60/255, 60/255, 60/255) + BG_TRANSPARENCY = 0.25 + TEXT_STROKE_TRANSPARENCY = 1 + TILE_SPACING = 5 +end +local SHADOW_IMAGE = 'rbxasset://textures/ui/PlayerList/TileShadowMissingTop.png'--'http://www.roblox.com/asset?id=286965900' +local SHADOW_SLICE_SIZE = 5 +local SHADOW_SLICE_RECT = Rect.new(SHADOW_SLICE_SIZE+1, SHADOW_SLICE_SIZE+1, SHADOW_SLICE_SIZE*2-1, SHADOW_SLICE_SIZE*2-1) + +local ADMINS = { -- Admins with special icons + ['123'] = 'ADMIN_ICON', -- Jeditkacheff + ['13268404'] = 'http://www.roblox.com/asset/?id=12081960875', -- Sorcus + ['1456'] = 'http://www.roblox.com/asset/?id=105897927', -- shedlestky + ['20396593'] = 'http://www.roblox.com/asset/?id=12081960875', -- Robloxsai +} + +local ABUSES = { + "Swearing", + "Bullying", + "Scamming", + "Dating", + "Cheating/Exploiting", + "Personal Questions", + "Offsite Links", + "Bad Username", +} + +local FOLLOWER_STATUS = { + FOLLOWER = 0, + FOLLOWING = 1, + MUTUAL = 2, +} + +--[[ Images ]]-- +local CHAT_ICON = 'rbxasset://textures/ui/chat_teamButton.png' +local ADMIN_ICON = 'rbxasset://textures/ui/icon_admin-16.png' +local PLACE_OWNER_ICON = 'rbxasset://textures/ui/icon_placeowner.png' +local BC_ICON = 'rbxasset://textures/ui/icon_BC-16.png' +local TBC_ICON = 'rbxasset://textures/ui/icon_TBC-16.png' +local OBC_ICON = 'rbxasset://textures/ui/icon_OBC-16.png' +local BLOCKED_ICON = 'rbxasset://textures/ui/PlayerList/BlockedIcon.png' +local FRIEND_ICON = 'rbxasset://textures/ui/icon_friends_16.png' +local FRIEND_REQUEST_ICON = 'rbxasset://textures/ui/icon_friendrequestsent_16.png' +local FRIEND_RECEIVED_ICON = 'rbxasset://textures/ui/icon_friendrequestrecieved-16.png' + +local FOLLOWER_ICON = 'rbxasset://textures/ui/icon_follower-16.png' +local FOLLOWING_ICON = 'rbxasset://textures/ui/icon_following-16.png' +local MUTUAL_FOLLOWING_ICON = 'rbxasset://textures/ui/icon_mutualfollowing-16.png' + +local CHARACTER_BACKGROUND_IMAGE = 'rbxasset://textures/ui/PlayerList/CharacterBackgroundImage.png' + +--[[ Helper Functions ]]-- +local function clamp(value, min, max) + if value < min then + value = min + elseif value > max then + value = max + end + + return value +end + +-- Returns whether followerUserId is following userId +local function isFollowing(userId, followerUserId) + local apiPath = "user/following-exists?userId=" + local params = userId.."&followerUserId="..followerUserId + local success, result = pcall(function() + return HttpRbxApiService:GetAsync(apiPath..params, true) + end) + if not success then + print("isFollowing() failed because", result) + return false + end + + -- can now parse web response + result = HttpService:JSONDecode(result) + return result["success"] and result["isFollowing"] +end + +-- TODO: Once server followers is good to go, remove this function and all code paths +local function getFollowerStatus(selectedPlayer) + -- we're going to check this flag first in case of a condition were the two flags are not set in sync + -- in that case, followers will be disabled + if not IsFollowersEnabled then + return nil + end + + if selectedPlayer == Player then + return nil + end + + -- ignore guest + if selectedPlayer.userId <= 0 or Player.userId <= 0 then + return + end + + local myUserId = tostring(Player.userId) + local theirUserId = tostring(selectedPlayer.userId) + + local isFollowingMe = isFollowing(myUserId, theirUserId) + local isFollowingThem = isFollowing(theirUserId, myUserId) + + if isFollowingMe and isFollowingThem then -- mutual + return FOLLOWER_STATUS.MUTUAL + elseif isFollowingMe then + return FOLLOWER_STATUS.FOLLOWER + elseif isFollowingThem then + return FOLLOWER_STATUS.FOLLOWING + else + return nil + end +end + +local function getFriendStatusIcon(friendStatus) + if friendStatus == Enum.FriendStatus.Unknown or friendStatus == Enum.FriendStatus.NotFriend then + return nil + elseif friendStatus == Enum.FriendStatus.Friend then + return FRIEND_ICON + elseif friendStatus == Enum.FriendStatus.FriendRequestSent then + return FRIEND_REQUEST_ICON + elseif friendStatus == Enum.FriendStatus.FriendRequestReceived then + return FRIEND_RECEIVED_ICON + else + error("PlayerList: Unknown value for friendStatus: "..tostring(friendStatus)) + end +end + +local function getFollowerStatusIcon(followerStatus) + if followerStatus == FOLLOWER_STATUS.MUTUAL then + return MUTUAL_FOLLOWING_ICON + elseif followerStatus == FOLLOWER_STATUS.FOLLOWING then + return FOLLOWING_ICON + elseif followerStatus == FOLLOWER_STATUS.FOLLOWER then + return FOLLOWER_ICON + else + return nil + end +end + +local function getAdminIcon(player) + local userIdStr = tostring(player.userId) + if ADMINS[userIdStr] then return nil end + -- + local success, result = pcall(function() + return player:IsInGroup(1200769) -- yields + end) + if not success then + print("PlayerListScript2: getAdminIcon() failed because", result) + return nil + end + -- + if result then + return ADMIN_ICON + end +end + +local function setAvatarIconAsync(player, iconImage) + -- this function is pretty much for xbox right now and makes use of modules that are part + -- of the xbox app. Please see Kip or Jason if you have any questions + local useSubdomainsFlagExists, useSubdomainsFlagValue = pcall(function() return settings():GetFFlag("UseNewSubdomainsInCoreScripts") end) + local thumbsUrl = BaseUrl + if(useSubdomainsFlagExists and useSubdomainsFlagValue and AssetGameUrl~=nil) then + thumbsUrl = AssetGameUrl + end + + local thumbnailLoader = nil + pcall(function() + thumbnailLoader = require(RobloxGui.Modules.ThumbnailLoader) + end) + + local isFinalSuccess = false + if thumbnailLoader then + local loader = thumbnailLoader:Create(iconImage, player.userId, + thumbnailLoader.Sizes.Small, thumbnailLoader.AssetType.Avatar, true) + isFinalSuccess = loader:LoadAsync(false, true, nil) + end + + if not isFinalSuccess then + iconImage.Image = 'rbxasset://textures/ui/Shell/Icons/DefaultProfileIcon.png' + end +end + +local function getMembershipIcon(player) + if isTenFootInterface then + -- return nothing, we need to spawn off setAvatarIconAsync() as a later time to not block + return "" + else + if blockingUtility:IsPlayerBlockedByUserId(player.userId) then + return BLOCKED_ICON + else + local userIdStr = tostring(player.userId) + local membershipType = player.MembershipType + if ADMINS[userIdStr] then + return ADMINS[userIdStr] + elseif player.userId == game.CreatorId and game.CreatorType == Enum.CreatorType.User then + return PLACE_OWNER_ICON + elseif membershipType == Enum.MembershipType.None then + return "" + elseif membershipType == Enum.MembershipType.BuildersClub then + return BC_ICON + elseif membershipType == Enum.MembershipType.TurboBuildersClub then + return TBC_ICON + elseif membershipType == Enum.MembershipType.OutrageousBuildersClub then + return OBC_ICON + else + return "" + end + end + end + + return "" +end + +local function isValidStat(obj) + return obj:IsA('StringValue') or obj:IsA('IntValue') or obj:IsA('BoolValue') or obj:IsA('NumberValue') or + obj:IsA('DoubleConstrainedValue') or obj:IsA('IntConstrainedValue') +end + +local function sortPlayerEntries(a, b) + if a.PrimaryStat == b.PrimaryStat then + return a.Player.Name:upper() < b.Player.Name:upper() + end + if not a.PrimaryStat then return false end + if not b.PrimaryStat then return true end + return a.PrimaryStat > b.PrimaryStat +end + +local function sortLeaderStats(a, b) + if a.IsPrimary ~= b.IsPrimary then + return a.IsPrimary + end + if a.Priority == b.Priority then + return a.AddId < b.AddId + end + return a.Priority < b.Priority +end + +local function sortTeams(a, b) + if a.TeamScore == b.TeamScore then + return a.Id < b.Id + end + if not a.TeamScore then return false end + if not b.TeamScore then return true end + return a.TeamScore < b.TeamScore +end + +-- Start of Gui Creation +local Container = Instance.new('Frame') +Container.Name = "PlayerListContainer" +if isTenFootInterface then + Container.Position = UDim2.new(0.5, -MinContainerSize.X.Offset/2, 0.25, 0) + Container.Size = MinContainerSize +else + Container.Position = UDim2.new(1, -167, 0, 2) + Container.Size = MinContainerSize +end + +Container.BackgroundTransparency = 1 +Container.Visible = false +Container.Parent = RobloxGui + +-- Scrolling Frame +local noSelectionObject = Instance.new("Frame") +noSelectionObject.BackgroundTransparency = 1 +noSelectionObject.BorderSizePixel = 0 + +local ScrollList = Instance.new('ScrollingFrame') +ScrollList.Name = "ScrollList" +ScrollList.Size = UDim2.new(1, -1, 0, 0) +if isTenFootInterface then + ScrollList.Position = UDim2.new(0, 0, 0, PlayerEntrySizeY + TILE_SPACING) + ScrollList.Size = UDim2.new(1, 19, 0, 0) +end +ScrollList.BackgroundTransparency = 1 +ScrollList.BackgroundColor3 = Color3.new() +ScrollList.BorderSizePixel = 0 +ScrollList.CanvasSize = UDim2.new(0, 0, 0, 0) -- NOTE: Look into if x needs to be set to anything +ScrollList.ScrollBarThickness = 6 +ScrollList.BottomImage = 'rbxasset://textures/ui/scroll-bottom.png' +ScrollList.MidImage = 'rbxasset://textures/ui/scroll-middle.png' +ScrollList.TopImage = 'rbxasset://textures/ui/scroll-top.png' +ScrollList.SelectionImageObject = noSelectionObject +ScrollList.Parent = Container + +-- PlayerDropDown clipping frame +local PopupClipFrame = Instance.new('Frame') +PopupClipFrame.Name = "PopupClipFrame" +PopupClipFrame.Size = UDim2.new(0, 150, 1.5, 0) +PopupClipFrame.Position = UDim2.new(0, -150 - ENTRY_PAD, 0, 0) +PopupClipFrame.BackgroundTransparency = 1 +PopupClipFrame.ClipsDescendants = true +PopupClipFrame.Parent = Container + + +--[[ Creation Helper Functions ]]-- +local function createEntryFrame(name, sizeYOffset, isTopStat) + local containerFrame = Instance.new('Frame') + containerFrame.Name = name + containerFrame.Position = UDim2.new(0, 0, 0, 0) + containerFrame.Size = UDim2.new(1, 0, 0, sizeYOffset) + if isTenFootInterface then + containerFrame.Position = UDim2.new(0, 10, 0, 0) + containerFrame.Size = containerFrame.Size + UDim2.new(0, -20, 0, 0) + end + containerFrame.BackgroundTransparency = 1 + containerFrame.ZIndex = isTenFootInterface and 2 or 1 + + local nameFrame = Instance.new('TextButton') + nameFrame.Name = "BGFrame" + nameFrame.Position = UDim2.new(0, 0, 0, 0) + nameFrame.Size = UDim2.new(0, NameEntrySizeX, 0, sizeYOffset) + nameFrame.BackgroundTransparency = isTopStat and 0 or BG_TRANSPARENCY + nameFrame.BackgroundColor3 = isTopStat and BG_COLOR_TOP or BG_COLOR + nameFrame.BorderSizePixel = 0 + nameFrame.AutoButtonColor = false + nameFrame.Text = "" + nameFrame.Parent = containerFrame + nameFrame.ZIndex = isTenFootInterface and 2 or 1 + + return containerFrame, nameFrame +end + +local function createEntryNameText(name, text, sizeXOffset, posXOffset) + local nameLabel = Instance.new('TextLabel') + nameLabel.Name = name + nameLabel.Size = UDim2.new(-0.01, sizeXOffset, 1, 0) + nameLabel.Position = UDim2.new(0.01, posXOffset, 0, 0) + nameLabel.BackgroundTransparency = 1 + nameLabel.Font = Enum.Font.SourceSans + if isTenFootInterface then + nameLabel.FontSize = Enum.FontSize.Size32 + else + nameLabel.FontSize = Enum.FontSize.Size14 + end + nameLabel.TextColor3 = TEXT_COLOR + nameLabel.TextStrokeTransparency = TEXT_STROKE_TRANSPARENCY + nameLabel.TextStrokeColor3 = TEXT_STROKE_COLOR + nameLabel.TextXAlignment = Enum.TextXAlignment.Left + nameLabel.ClipsDescendants = true + nameLabel.Text = text + nameLabel.ZIndex = isTenFootInterface and 2 or 1 + + return nameLabel +end + +local function createStatFrame(offset, parent, name, isTopStat) + local statFrame = Instance.new('Frame') + statFrame.Name = name + statFrame.Size = UDim2.new(0, StatEntrySizeX, 1, 0) + statFrame.Position = UDim2.new(0, offset + TILE_SPACING, 0, 0) + statFrame.BackgroundTransparency = isTopStat and 0 or BG_TRANSPARENCY + statFrame.BackgroundColor3 = isTopStat and BG_COLOR_TOP or BG_COLOR + statFrame.BorderSizePixel = 0 + statFrame.Parent = parent + + if isTenFootInterface then + statFrame.ZIndex = 2 + + local shadow = Instance.new("ImageLabel") + shadow.BackgroundTransparency = 1 + shadow.Name = 'Shadow' + shadow.Image = SHADOW_IMAGE + shadow.Position = UDim2.new(0, -SHADOW_SLICE_SIZE, 0, 0) + shadow.Size = UDim2.new(1, SHADOW_SLICE_SIZE*2, 1, SHADOW_SLICE_SIZE) + shadow.ScaleType = 'Slice' + shadow.SliceCenter = SHADOW_SLICE_RECT + shadow.Parent = statFrame + end + + return statFrame +end + +local function createStatText(parent, text, isTopStat, isTeamStat) + local statText = Instance.new('TextLabel') + statText.Name = "StatText" + statText.Size = isTopStat and UDim2.new(1, 0, 0.5, 0) or UDim2.new(1, 0, 1, 0) + statText.Position = isTopStat and UDim2.new(0, 0, 0.5, 0) or UDim2.new(0, 0, 0, 0) + statText.BackgroundTransparency = 1 + statText.Font = isTopStat and Enum.Font.SourceSansBold or Enum.Font.SourceSans + if isTenFootInterface then + statText.FontSize = Enum.FontSize.Size32 + else + statText.FontSize = Enum.FontSize.Size14 + end + statText.TextColor3 = TEXT_COLOR + statText.TextStrokeColor3 = TEXT_STROKE_COLOR + statText.TextStrokeTransparency = TEXT_STROKE_TRANSPARENCY + statText.Text = text + statText.Active = true + statText.Parent = parent + if isTenFootInterface then + statText.ZIndex = 2 + end + + if isTopStat then + local statName = statText:Clone() + statName.Name = "StatName" + statName.Text = tostring(parent.Name) + statName.Position = UDim2.new(0,0,0,0) + statName.Font = Enum.Font.SourceSans + statName.ClipsDescendants = true + statName.Parent = parent + if isTenFootInterface then + statName.ZIndex = 2 + end + end + + if isTeamStat then + statText.Font = 'SourceSansBold' + end + + return statText +end + +local function createImageIcon(image, name, xOffset, parent) + local imageLabel = Instance.new('ImageLabel') + imageLabel.Name = name + if isTenFootInterface then + imageLabel.Size = UDim2.new(0, 64, 0, 64) + imageLabel.ZIndex = 2 + + local background = Instance.new("ImageLabel", imageLabel) + background.Name = 'Background' + background.BackgroundTransparency = 1 + background.Image = CHARACTER_BACKGROUND_IMAGE + background.Size = UDim2.new(0, 66, 0, 66) + background.Position = UDim2.new(0.5, -66/2, 0.5, -66/2) + background.ZIndex = 2 + else + imageLabel.Size = UDim2.new(0, 16, 0, 16) + end + imageLabel.Position = UDim2.new(0.01, xOffset, 0.5, -imageLabel.Size.Y.Offset/2) + imageLabel.BackgroundTransparency = 1 + imageLabel.Image = image + imageLabel.BorderSizePixel = 0 + imageLabel.Parent = parent + + return imageLabel +end + +local function getScoreValue(statObject) + if statObject:IsA('DoubleConstrainedValue') or statObject:IsA('IntConstrainedValue') then + return statObject.ConstrainedValue + elseif statObject:IsA('BoolValue') then + if statObject.Value then return 1 else return 0 end + else + return statObject.Value + end +end + +local THIN_CHARS = "[^%[iIl\%.,']" +local function strWidth(str) + return string.len(str) - math.floor(string.len(string.gsub(str, THIN_CHARS, "")) / 2) +end + +local function formatNumber(value) + local _,_,minusSign, int, fraction = tostring(value):find('([-]?)(%d+)([.]?%d*)') + int = int:reverse():gsub("%d%d%d", "%1,") + return minusSign..int:reverse():gsub("^,", "")..fraction +end + +local function formatStatString(text) + local numberValue = tonumber(text) + if numberValue then + text = formatNumber(numberValue) + end + + if strWidth(text) <= MAX_STR_LEN then + return text + else + return string.sub(text, 1, MAX_STR_LEN - 3).."..." + end +end + +--[[ Resize Functions ]]-- +local LastMaxScrollSize = 0 +local function setScrollListSize() + local teamSize = #TeamEntries * TeamEntrySizeY + local playerSize = #PlayerEntries * PlayerEntrySizeY + local spacing = #PlayerEntries * ENTRY_PAD + #TeamEntries * ENTRY_PAD + local canvasSize = teamSize + playerSize + spacing + if #TeamEntries > 0 and NeutralTeam and IsShowingNeutralFrame then + canvasSize = canvasSize + TeamEntrySizeY + ENTRY_PAD + end + ScrollList.CanvasSize = UDim2.new(0, 0, 0, canvasSize) + local newScrollListSize = math.min(canvasSize, Container.AbsoluteSize.y) + if ScrollList.Size.Y.Offset == LastMaxScrollSize then + if isTenFootInterface then + ScrollList.Size = UDim2.new(1, 20, 0, newScrollListSize) + else + ScrollList.Size = UDim2.new(1, 0, 0, newScrollListSize) + end + end + LastMaxScrollSize = newScrollListSize +end + +--[[ Re-position Functions ]]-- +local function setPlayerEntryPositions() + local position = 0 + for i = 1, #PlayerEntries do + if isTenFootInterface and PlayerEntries[i].Frame ~= MyPlayerEntryTopFrame then + PlayerEntries[i].Frame.Position = UDim2.new(0, 10, 0, position) + position = position + PlayerEntrySizeY + TILE_SPACING + elseif PlayerEntries[i].Frame ~= MyPlayerEntryTopFrame then + PlayerEntries[i].Frame.Position = UDim2.new(0, 0, 0, position) + position = position + PlayerEntrySizeY + TILE_SPACING + end + end +end + +local function setTeamEntryPositions() + local teams = {} + for _,teamEntry in ipairs(TeamEntries) do + local team = teamEntry.Team + teams[tostring(team.TeamColor)] = {} + end + if NeutralTeam then + teams.Neutral = {} + end + + for _,playerEntry in ipairs(PlayerEntries) do + if playerEntry.Frame ~= MyPlayerEntryTopFrame then + local player = playerEntry.Player + if player.Neutral then + table.insert(teams.Neutral, playerEntry) + elseif teams[tostring(player.TeamColor)] then + table.insert(teams[tostring(player.TeamColor)], playerEntry) + else + table.insert(teams.Neutral, playerEntry) + end + end + end + + local position = 0 + for _,teamEntry in ipairs(TeamEntries) do + local team = teamEntry.Team + teamEntry.Frame.Position = UDim2.new(0, isTenFootInterface and 10 or 0, 0, position) + position = position + TeamEntrySizeY + TILE_SPACING + local players = teams[tostring(team.TeamColor)] + for _,playerEntry in ipairs(players) do + playerEntry.Frame.Position = UDim2.new(0, isTenFootInterface and 10 or 0, 0, position) + position = position + PlayerEntrySizeY + TILE_SPACING + end + end + if NeutralTeam then + NeutralTeam.Frame.Position = UDim2.new(0, isTenFootInterface and 10 or 0, 0, position) + position = position + TeamEntrySizeY + TILE_SPACING + if #teams.Neutral > 0 then + IsShowingNeutralFrame = true + local players = teams.Neutral + for _,playerEntry in ipairs(players) do + playerEntry.Frame.Position = UDim2.new(0, isTenFootInterface and 10 or 0, 0, position) + position = position + PlayerEntrySizeY + TILE_SPACING + end + else + IsShowingNeutralFrame = false + end + end +end + +local function setEntryPositions() + table.sort(PlayerEntries, sortPlayerEntries) + if #TeamEntries > 0 then + setTeamEntryPositions() + else + setPlayerEntryPositions() + end +end + +local function updateSocialIcon(newIcon, bgFrame) + local socialIcon = bgFrame:FindFirstChild('SocialIcon') + local nameFrame = bgFrame:FindFirstChild('PlayerName') + local offset = 19 + if socialIcon then + if newIcon then + socialIcon.Image = newIcon + else + if nameFrame then + local newSize = nameFrame.Size.X.Offset + socialIcon.Size.X.Offset + 2 + nameFrame.Size = UDim2.new(-0.01, newSize, 0.5, 0) + nameFrame.Position = UDim2.new(0.01, offset, 0.245, 0) + end + socialIcon:Destroy() + end + elseif newIcon and bgFrame then + socialIcon = createImageIcon(newIcon, "SocialIcon", offset, bgFrame) + offset = offset + socialIcon.Size.X.Offset + 2 + if nameFrame then + local newSize = bgFrame.Size.X.Offset - offset + nameFrame.Size = UDim2.new(-0.01, newSize, 0.5, 0) + nameFrame.Position = UDim2.new(0.01, offset, 0.245, 0) + end + end +end + +local function getFriendStatus(selectedPlayer) + if selectedPlayer == Player then + return Enum.FriendStatus.NotFriend + else + local success, result = pcall(function() + -- NOTE: Core script only + return Player:GetFriendStatus(selectedPlayer) + end) + if success then + return result + else + return Enum.FriendStatus.NotFriend + end + end +end + +local function onFollowerStatusChanged() + -- TODO: Remove this event completely when server version is stable + if not IsFollowersEnabled and not LastSelectedFrame or not LastSelectedPlayer then + return + end + + -- don't update icon if already friends + local friendStatus = getFriendStatus(LastSelectedPlayer) + if friendStatus == Enum.FriendStatus.Friend then + return + end + + local bgFrame = LastSelectedFrame:FindFirstChild('BGFrame') + local followerStatus = getFollowerStatus(LastSelectedPlayer) + local newIcon = getFollowerStatusIcon(followerStatus) + if bgFrame then + updateSocialIcon(newIcon, bgFrame) + end +end +-- Don't listen/show rbx follower status on xbox +if not isTenFootInterface then + playerDropDownModule.FollowerStatusChanged:connect(onFollowerStatusChanged) +end + +function popupHidden() + if LastSelectedFrame then + for _,childFrame in pairs(LastSelectedFrame:GetChildren()) do + if childFrame:IsA('TextButton') or childFrame:IsA('Frame') then + childFrame.BackgroundColor3 = BG_COLOR + end + end + end + ScrollList.ScrollingEnabled = true + LastSelectedFrame = nil + LastSelectedPlayer = nil +end +playerDropDown.HiddenSignal:connect(popupHidden) + +local function onEntryFrameSelected(selectedFrame, selectedPlayer) + if selectedPlayer ~= Player and selectedPlayer.userId > 1 and Player.userId > 1 then + if LastSelectedFrame ~= selectedFrame then + if LastSelectedFrame then + for _,childFrame in pairs(LastSelectedFrame:GetChildren()) do + if childFrame:IsA('TextButton') or childFrame:IsA('Frame') then + childFrame.BackgroundColor3 = BG_COLOR + end + end + end + LastSelectedFrame = selectedFrame + LastSelectedPlayer = selectedPlayer + for _,childFrame in pairs(selectedFrame:GetChildren()) do + if childFrame:IsA('TextButton') or childFrame:IsA('Frame') then + childFrame.BackgroundColor3 = Color3.new(0, 1, 1) + end + end + -- NOTE: Core script only + ScrollList.ScrollingEnabled = false + + local PopupFrame = playerDropDown:CreatePopup(selectedPlayer) + PopupFrame.Position = UDim2.new(1, 1, 0, selectedFrame.Position.Y.Offset - ScrollList.CanvasPosition.y) + PopupFrame.Parent = PopupClipFrame + PopupFrame:TweenPosition(UDim2.new(0, 0, 0, selectedFrame.Position.Y.Offset - ScrollList.CanvasPosition.y), Enum.EasingDirection.InOut, Enum.EasingStyle.Quad, TWEEN_TIME, true) + else + playerDropDown:Hide() + LastSelectedFrame = nil + LastSelectedPlayer = nil + end + end +end + +local function onFriendshipChanged(otherPlayer, newFriendStatus) + local entryToUpdate = nil + for _,entry in ipairs(PlayerEntries) do + if entry.Player == otherPlayer then + entryToUpdate = entry + break + end + end + if not entryToUpdate then + return + end + local newIcon = getFriendStatusIcon(newFriendStatus) + local frame = entryToUpdate.Frame + local bgFrame = frame:FindFirstChild('BGFrame') + if bgFrame then + --no longer friends, but might still be following + if not IsServerFollowers and IsFollowersEnabled and not newIcon then + local followerStatus = getFollowerStatus(otherPlayer) + newIcon = getFollowerStatusIcon(followerStatus) + end + + updateSocialIcon(newIcon, bgFrame) + end +end + +-- NOTE: Core script only. This fires when a player joins the game. +-- Don't listen/show rbx friends status on xbox +if not isTenFootInterface then + Player.FriendStatusChanged:connect(onFriendshipChanged) +end + +--[[ Begin New Server Followers ]]-- +local function setFollowRelationshipsView(relationshipTable) + if not relationshipTable then + return + end + + for i = 1, #PlayerEntries do + local entry = PlayerEntries[i] + local player = entry.Player + local userId = tostring(player.userId) + + -- don't update icon if already friends + local friendStatus = getFriendStatus(player) + if friendStatus == Enum.FriendStatus.Friend then + return + end + + local icon = nil + if relationshipTable[userId] then + local relationship = relationshipTable[userId] + if relationship.IsMutual == true then + icon = MUTUAL_FOLLOWING_ICON + elseif relationship.IsFollowing == true then + icon = FOLLOWING_ICON + elseif relationship.IsFollower == true then + icon = FOLLOWER_ICON + end + end + + local frame = entry.Frame + local bgFrame = frame:FindFirstChild('BGFrame') + if bgFrame then + updateSocialIcon(icon, bgFrame) + end + end +end + +local function getFollowRelationships() + local result = nil + if RemoteFunc_GetFollowRelationships then + result = RemoteFunc_GetFollowRelationships:InvokeServer() + end + return result +end + +--[[ End New Server Followers ]]-- + +local function updateAllTeamScores() + local teamScores = {} + for _,playerEntry in ipairs(PlayerEntries) do + local player = playerEntry.Player + local leaderstats = player:FindFirstChild('leaderstats') + local team = player.Neutral and 'Neutral' or tostring(player.TeamColor) + local isInValidColor = true + if team ~= 'Neutral' then + for _,teamEntry in ipairs(TeamEntries) do + local color = teamEntry.Team.TeamColor + if team == tostring(color) then + isInValidColor = false + break + end + end + end + if isInValidColor then + team = 'Neutral' + end + if not teamScores[team] then + teamScores[team] = {} + end + if playerEntry.Frame ~= MyPlayerEntryTopFrame then + if leaderstats then + for _,stat in ipairs(GameStats) do + local statObject = leaderstats:FindFirstChild(stat.Name) + if statObject and not statObject:IsA('StringValue') then + if not teamScores[team][stat.Name] then + teamScores[team][stat.Name] = 0 + end + teamScores[team][stat.Name] = teamScores[team][stat.Name] + getScoreValue(statObject) + end + end + end + end + end + + for _,teamEntry in ipairs(TeamEntries) do + local team = teamEntry.Team + local frame = teamEntry.Frame + local color = tostring(team.TeamColor) + local stats = teamScores[color] + if stats then + for statName,statValue in pairs(stats) do + local statFrame = frame:FindFirstChild(statName) + if statFrame then + local statText = statFrame:FindFirstChild('StatText') + if statText then + statText.Text = formatStatString(tostring(statValue)) + end + end + end + else + for _,childFrame in pairs(frame:GetChildren()) do + local statText = childFrame:FindFirstChild('StatText') + if statText then + statText.Text = '' + end + end + end + end + if NeutralTeam then + local frame = NeutralTeam.Frame + local stats = teamScores['Neutral'] + if stats then + frame.Visible = true + for statName,statValue in pairs(stats) do + local statFrame = frame:FindFirstChild(statName) + if statFrame then + local statText = statFrame:FindFirstChild('StatText') + if statText then + statText.Text = formatStatString(tostring(statValue)) + end + end + end + else + frame.Visible = false + end + end +end + +local function updateTeamEntry(entry) + local frame = entry.Frame + local team = entry.Team + local color = team.TeamColor.Color + local offset = NameEntrySizeX + for _,stat in ipairs(GameStats) do + local statFrame = frame:FindFirstChild(stat.Name) + if not statFrame then + statFrame = createStatFrame(offset, frame, stat.Name) + statFrame.BackgroundColor3 = color + createStatText(statFrame, "", false, true) + end + statFrame.Position = UDim2.new(0, offset + TILE_SPACING, 0, 0) + offset = offset + statFrame.Size.X.Offset + TILE_SPACING + end +end + +local function updatePrimaryStats(statName) + for _,entry in ipairs(PlayerEntries) do + local player = entry.Player + local leaderstats = player:FindFirstChild('leaderstats') + entry.PrimaryStat = nil + if leaderstats then + local statObject = leaderstats:FindFirstChild(statName) + if statObject then + local scoreValue = getScoreValue(statObject) + entry.PrimaryStat = scoreValue + end + end + end +end + +local updateLeaderstatFrames = nil +-- TODO: fire event to top bar? +local function initializeStatText(stat, statObject, entry, statFrame, index, isTopStat) + local player = entry.Player + local statValue = getScoreValue(statObject) + if statObject.Name == GameStats[1].Name then + entry.PrimaryStat = statValue + end + local statText = createStatText(statFrame, formatStatString(tostring(statValue)), isTopStat) + -- Top Bar insertion + if player == Player then + stat.Text = statText.Text + end + + statObject.Changed:connect(function(newValue) + local scoreValue = getScoreValue(statObject) + statText.Text = formatStatString(tostring(scoreValue)) + if statObject.Name == GameStats[1].Name then + entry.PrimaryStat = scoreValue + end + -- Top bar changed event + if player == Player then + stat.Text = statText.Text + Playerlist.OnStatChanged:Fire(stat.Name, stat.Text) + end + updateAllTeamScores() + setEntryPositions() + end) + statObject.ChildAdded:connect(function(child) + if child.Name == "IsPrimary" then + GameStats[1].IsPrimary = false + stat.IsPrimary = true + updatePrimaryStats(stat.Name) + if updateLeaderstatFrames then updateLeaderstatFrames() end + Playerlist.OnLeaderstatsChanged:Fire(GameStats) + end + end) +end + +updateLeaderstatFrames = function() + table.sort(GameStats, sortLeaderStats) + if #TeamEntries > 0 then + for _,entry in ipairs(TeamEntries) do + updateTeamEntry(entry) + end + if NeutralTeam then + updateTeamEntry(NeutralTeam) + end + end + + for _,entry in ipairs(PlayerEntries) do + local player = entry.Player + local mainFrame = entry.Frame + local offset = NameEntrySizeX + local leaderstats = player:FindFirstChild('leaderstats') + local isTopStat = (entry.Frame == MyPlayerEntryTopFrame) + + if leaderstats then + for _,stat in ipairs(GameStats) do + local statObject = leaderstats:FindFirstChild(stat.Name) + local statFrame = mainFrame:FindFirstChild(stat.Name) + + if not statFrame then + statFrame = createStatFrame(offset, mainFrame, stat.Name, isTopStat) + if statObject then + initializeStatText(stat, statObject, entry, statFrame, _, isTopStat) + end + elseif statObject then + local statText = statFrame:FindFirstChild('StatText') + if not statText then + initializeStatText(stat, statObject, entry, statFrame, _, isTopStat) + end + end + statFrame.Position = UDim2.new(0, offset + TILE_SPACING, 0, 0) + offset = offset + statFrame.Size.X.Offset + TILE_SPACING + end + else + for _,stat in ipairs(GameStats) do + local statFrame = mainFrame:FindFirstChild(stat.Name) + if not statFrame then + statFrame = createStatFrame(offset, mainFrame, stat.Name, isTopStat) + end + offset = offset + statFrame.Size.X.Offset + TILE_SPACING + end + end + + if entry.Frame ~= MyPlayerEntryTopFrame then + if isTenFootInterface then + Container.Position = UDim2.new(0.5, -offset/2, 0, 110) + Container.Size = UDim2.new(0, offset, 0.8, 0) + else + Container.Position = UDim2.new(1, -offset, 0, 2) + Container.Size = UDim2.new(0, offset, 0.5, 0) + end + + local newMinContainerOffset = offset + MinContainerSize = UDim2.new(0, newMinContainerOffset, 0.5, 0) + end + end + updateAllTeamScores() + setEntryPositions() + Playerlist.OnLeaderstatsChanged:Fire(GameStats) +end + +local function addNewStats(leaderstats) + for i,stat in ipairs(leaderstats:GetChildren()) do + if isValidStat(stat) and #GameStats < MAX_LEADERSTATS then + local gameHasStat = false + for _,gStat in ipairs(GameStats) do + if stat.Name == gStat.Name then + gameHasStat = true + break + end + end + + if not gameHasStat then + local newStat = {} + newStat.Name = stat.Name + newStat.Text = "-" + newStat.Priority = 0 + local priority = stat:FindFirstChild('Priority') + if priority then newStat.Priority = priority end + newStat.IsPrimary = false + local isPrimary = stat:FindFirstChild('IsPrimary') + if isPrimary then + newStat.IsPrimary = true + end + newStat.AddId = StatAddId + StatAddId = StatAddId + 1 + table.insert(GameStats, newStat) + table.sort(GameStats, sortLeaderStats) + if #GameStats == 1 then + setScrollListSize() + setEntryPositions() + end + end + end + end +end + +local function removeStatFrameFromEntry(stat, frame) + local statFrame = frame:FindFirstChild(stat.Name) + if statFrame then + statFrame:Destroy() + end +end + +local function doesStatExists(stat) + local doesExists = false + for _,entry in ipairs(PlayerEntries) do + local player = entry.Player + if player then + local leaderstats = player:FindFirstChild('leaderstats') + if leaderstats and leaderstats:FindFirstChild(stat.Name) then + doesExists = true + break + end + end + end + + return doesExists +end + +local function onStatRemoved(oldStat, entry) + if isValidStat(oldStat) then + removeStatFrameFromEntry(oldStat, entry.Frame) + local statExists = doesStatExists(oldStat) + -- + local toRemove = nil + for i, stat in ipairs(GameStats) do + if stat.Name == oldStat.Name then + toRemove = i + break + end + end + -- removed from player but not from game; another player still has this stat + if statExists then + if toRemove and entry.Player == Player then + GameStats[toRemove].Text = "-" + Playerlist.OnStatChanged:Fire(GameStats[toRemove].Name, GameStats[toRemove].Text) + end + -- removed from game + else + for _,playerEntry in ipairs(PlayerEntries) do + removeStatFrameFromEntry(oldStat, playerEntry.Frame) + end + for _,teamEntry in ipairs(TeamEntries) do + removeStatFrameFromEntry(oldStat, teamEntry.Frame) + end + if toRemove then + table.remove(GameStats, toRemove) + table.sort(GameStats, sortLeaderStats) + end + end + if GameStats[1] then + updatePrimaryStats(GameStats[1].Name) + end + updateLeaderstatFrames() + end +end + +local function onStatAdded(leaderstats, entry) + leaderstats.ChildAdded:connect(function(newStat) + if isValidStat(newStat) then + addNewStats(newStat.Parent) + updateLeaderstatFrames() + end + end) + leaderstats.ChildRemoved:connect(function(child) + onStatRemoved(child, entry) + end) + addNewStats(leaderstats) + updateLeaderstatFrames() +end + +local function setLeaderStats(entry) + local player = entry.Player + local leaderstats = player:FindFirstChild('leaderstats') + + if leaderstats then + onStatAdded(leaderstats, entry) + end + + local function onPlayerChildChanged(property, child) + if property == 'Name' and child.Name == 'leaderstats' then + onStatAdded(child, entry) + end + end + + player.ChildAdded:connect(function(child) + if child.Name == 'leaderstats' then + onStatAdded(child, entry) + end + child.Changed:connect(function(property) onPlayerChildChanged(property, child) end) + end) + for _,child in pairs(player:GetChildren()) do + child.Changed:connect(function(property) onPlayerChildChanged(property, child) end) + end + + player.ChildRemoved:connect(function(child) + if child.Name == 'leaderstats' then + for i,stat in ipairs(child:GetChildren()) do + onStatRemoved(stat, entry) + end + updateLeaderstatFrames() + end + end) +end + +local offsetSize = 18 +if isTenFootInterface then offsetSize = 32 end + +local function createPlayerEntry(player, isTopStat) + local playerEntry = {} + local name = player.Name + + local containerFrame, entryFrame = createEntryFrame(name, PlayerEntrySizeY, isTopStat) + entryFrame.Active = true + + if not isTenFootInterface then + local function localEntrySelected() + onEntryFrameSelected(containerFrame, player) + end + entryFrame.MouseButton1Click:connect(localEntrySelected) + end + + local currentXOffset = 1 + + -- check membership + local membershipIconImage = getMembershipIcon(player) + local membershipIcon = nil + if membershipIconImage then + membershipIcon = createImageIcon(membershipIconImage, "MembershipIcon", currentXOffset, entryFrame) + currentXOffset = currentXOffset + membershipIcon.Size.X.Offset + 2 + else + currentXOffset = currentXOffset + offsetSize + end + + spawn(function() + if isTenFootInterface and membershipIcon then + setAvatarIconAsync(player, membershipIcon) + end + end) + + -- Some functions yield, so we need to spawn off in order to not cause a race condition with other events like Players.ChildRemoved + spawn(function() + local success, result = pcall(function() + return player:GetRankInGroup(game.CreatorId) == 255 + end) + if success then + if game.CreatorType == Enum.CreatorType.Group and result then + membershipIconImage = PLACE_OWNER_ICON + if not membershipIcon then + membershipIcon = createImageIcon(membershipIconImage, "MembershipIcon", 1, entryFrame) + else + membershipIcon.Image = membershipIconImage + end + end + else + print("PlayerList: GetRankInGroup failed because", result) + end + local adminIconImage = getAdminIcon(player) + if adminIconImage then + if not membershipIcon then + membershipIcon = createImageIcon(adminIconImage, "MembershipIcon", 1, entryFrame) + else + membershipIcon.Image = adminIconImage + end + end + -- Friendship and Follower status is checked by onFriendshipChanged, which is called by the FriendStatusChanged + -- event. This event is fired when any player joins the game. onFriendshipChanged will check Follower status in + -- the case that we are not friends with the new player who is joining. + end) + + local playerNameXSize = entryFrame.Size.X.Offset - currentXOffset + local playerName = createEntryNameText("PlayerName", name, playerNameXSize, currentXOffset) + playerName.Parent = entryFrame + playerEntry.Player = player + playerEntry.Frame = containerFrame + + if isTenFootInterface then + local shadow = Instance.new("ImageLabel") + shadow.BackgroundTransparency = 1 + shadow.Name = 'Shadow' + shadow.Image = SHADOW_IMAGE + shadow.Position = UDim2.new(0, -SHADOW_SLICE_SIZE, 0, 0) + shadow.Size = UDim2.new(1, SHADOW_SLICE_SIZE*2, 1, SHADOW_SLICE_SIZE) + shadow.ScaleType = 'Slice' + shadow.SliceCenter = SHADOW_SLICE_RECT + shadow.Parent = entryFrame + end + + if isTopStat then + playerName.Font = 'SourceSansBold' + end + + return playerEntry +end + +local function createTeamEntry(team) + local teamEntry = {} + teamEntry.Team = team + teamEntry.TeamScore = 0 + + local containerFrame, entryFrame = createEntryFrame(team.Name, TeamEntrySizeY) + entryFrame.BackgroundColor3 = team.TeamColor.Color + + local teamName = createEntryNameText("TeamName", team.Name, entryFrame.AbsoluteSize.x, 1) + teamName.Parent = entryFrame + + teamEntry.Frame = containerFrame + + if isTenFootInterface then + local shadow = Instance.new("ImageLabel") + shadow.BackgroundTransparency = 1 + shadow.Name = 'Shadow' + shadow.Image = SHADOW_IMAGE + shadow.Position = UDim2.new(0, -SHADOW_SLICE_SIZE, 0, 0) + shadow.Size = UDim2.new(1, SHADOW_SLICE_SIZE*2, 1, SHADOW_SLICE_SIZE) + shadow.ScaleType = 'Slice' + shadow.SliceCenter = SHADOW_SLICE_RECT + shadow.Parent = entryFrame + end + + -- connections + team.Changed:connect(function(property) + if property == 'Name' then + teamName.Text = team.Name + elseif property == 'TeamColor' then + for _,childFrame in pairs(containerFrame:GetChildren()) do + if childFrame:IsA('GuiObject') then + childFrame.BackgroundColor3 = team.TeamColor.Color + end + end + + setTeamEntryPositions() + updateAllTeamScores() + setEntryPositions() + setScrollListSize() + end + end) + + return teamEntry +end + +local function createNeutralTeam() + if not NeutralTeam then + local team = Instance.new('Team') + team.Name = 'Neutral' + team.TeamColor = BrickColor.new('White') + NeutralTeam = createTeamEntry(team) + NeutralTeam.Frame.Parent = ScrollList + end +end + +--[[ Insert/Remove Player Functions ]]-- +local function setupEntry(player, newEntry, isTopStat) + setLeaderStats(newEntry) + + if isTopStat then + newEntry.Frame.Parent = Container + table.insert(PlayerEntries, newEntry) + else + newEntry.Frame.Parent = ScrollList + table.insert(PlayerEntries, newEntry) + setScrollListSize() + end + + updateLeaderstatFrames() + + player.Changed:connect(function(property) + if #TeamEntries > 0 and (property == 'Neutral' or property == 'TeamColor') then + setTeamEntryPositions() + updateAllTeamScores() + setEntryPositions() + setScrollListSize() + end + end) +end + +local function insertPlayerEntry(player) + local entry = createPlayerEntry(player) + setupEntry(player, entry) + + -- create an entry on the top of the playerlist + if player == Player and isTenFootInterface then + local localEntry = createPlayerEntry(player, true) + MyPlayerEntryTopFrame = localEntry.Frame + MyPlayerEntryTopFrame.BackgroundTransparency = 1 + MyPlayerEntryTopFrame.BorderSizePixel = 0 + setupEntry(player, localEntry, true) + end +end + +local function removePlayerEntry(player) + for i = 1, #PlayerEntries do + if PlayerEntries[i].Player == player then + PlayerEntries[i].Frame:Destroy() + table.remove(PlayerEntries, i) + break + end + end + setEntryPositions() + setScrollListSize() +end + +--[[ Team Functions ]]-- +local function onTeamAdded(team) + for i = 1, #TeamEntries do + if TeamEntries[i].Team.TeamColor == team.TeamColor then + TeamEntries[i].Frame:Destroy() + table.remove(TeamEntries, i) + break + end + end + local entry = createTeamEntry(team) + entry.Id = TeamAddId + TeamAddId = TeamAddId + 1 + if not NeutralTeam then + createNeutralTeam() + end + table.insert(TeamEntries, entry) + table.sort(TeamEntries, sortTeams) + setTeamEntryPositions() + updateLeaderstatFrames() + setScrollListSize() + entry.Frame.Parent = ScrollList +end + +local function onTeamRemoved(removedTeam) + for i = 1, #TeamEntries do + local team = TeamEntries[i].Team + if team.Name == removedTeam.Name then + TeamEntries[i].Frame:Destroy() + table.remove(TeamEntries, i) + break + end + end + if #TeamEntries == 0 then + if NeutralTeam then + NeutralTeam.Frame:Destroy() + NeutralTeam.Team:Destroy() + NeutralTeam = nil + IsShowingNeutralFrame = false + end + end + setEntryPositions() + updateLeaderstatFrames() + setScrollListSize() +end + +--[[ Resize/Position Functions ]]-- +local function clampCanvasPosition() + local maxCanvasPosition = ScrollList.CanvasSize.Y.Offset - ScrollList.Size.Y.Offset + if maxCanvasPosition >= 0 and ScrollList.CanvasPosition.y > maxCanvasPosition then + ScrollList.CanvasPosition = Vector2.new(0, maxCanvasPosition) + end +end + +local function resizePlayerList() + setScrollListSize() + clampCanvasPosition() +end + +RobloxGui.Changed:connect(function(property) + if property == 'AbsoluteSize' then + spawn(function() -- must spawn because F11 delays when abs size is set + resizePlayerList() + end) + end +end) + +UserInputService.InputBegan:connect(function(inputObject, isProcessed) + if isProcessed then return end + local inputType = inputObject.UserInputType + if (inputType == Enum.UserInputType.Touch and inputObject.UserInputState == Enum.UserInputState.Begin) or + inputType == Enum.UserInputType.MouseButton1 then + if LastSelectedFrame then + playerDropDown:Hide() + end + end +end) + +-- NOTE: Core script only + +--[[ Player Add/Remove Connections ]]-- +Players.ChildAdded:connect(function(child) + if child:IsA('Player') then + insertPlayerEntry(child) + end +end) +for _,player in pairs(Players:GetPlayers()) do + insertPlayerEntry(player) +end + +--[[ Begin new Server Followers ]]-- +-- Don't listen/show rbx followers status on console +if IsServerFollowers and not isTenFootInterface then + -- spawn so we don't block script + spawn(function() + local RobloxReplicatedStorage = game:GetService('RobloxReplicatedStorage') + RemoveEvent_OnFollowRelationshipChanged = RobloxReplicatedStorage:WaitForChild('FollowRelationshipChanged') + RemoteFunc_GetFollowRelationships = RobloxReplicatedStorage:WaitForChild('GetFollowRelationships') + + RemoveEvent_OnFollowRelationshipChanged.OnClientEvent:connect(function(result) + setFollowRelationshipsView(result) + end) + + local result = getFollowRelationships() + setFollowRelationshipsView(result) + end) +end + +Players.ChildRemoved:connect(function(child) + if child:IsA('Player') then + if LastSelectedPlayer and child == LastSelectedPlayer then + playerDropDown:Hide() + end + removePlayerEntry(child) + end +end) + +--[[ Teams ]]-- +local function initializeTeams(teams) + for _,team in pairs(teams:GetTeams()) do + onTeamAdded(team) + end + + teams.ChildAdded:connect(function(team) + if team:IsA('Team') then + onTeamAdded(team) + end + end) + + teams.ChildRemoved:connect(function(team) + if team:IsA('Team') then + onTeamRemoved(team) + end + end) +end + +TeamsService = game:FindService('Teams') +if TeamsService then + initializeTeams(TeamsService) +end + +game.ChildAdded:connect(function(child) + if child:IsA('Teams') then + initializeTeams(child) + end +end) + +--[[ Public API ]]-- +Playerlist.GetStats = function() + return GameStats +end + +local noOpFunc = function ( ) +end + +local isOpen = not isTenFootInterface + +local closeListFunc = function(name, state, input) + if state ~= Enum.UserInputState.Begin then return end + + isOpen = false + Container.Visible = false + spawn(function() GuiService:SetMenuIsOpen(false) end) + ContextActionService:UnbindCoreAction("CloseList") + ContextActionService:UnbindCoreAction("StopAction") + GuiService.SelectedCoreObject = nil + UserInputService.OverrideMouseIconBehavior = Enum.OverrideMouseIconBehavior.None +end + +local setVisible = function(state, fromTemp) + Container.Visible = state + + if state then + local children = ScrollList:GetChildren() + if children and #children > 0 then + local frame = children[1] + local frameChildren = frame:GetChildren() + for i = 1, #frameChildren do + if frameChildren[i]:IsA("TextButton") then + local lastInputType = UserInputService:GetLastInputType() + local isUsingGamepad = (lastInputType == Enum.UserInputType.Gamepad1 or lastInputType == Enum.UserInputType.Gamepad2 or + lastInputType == Enum.UserInputType.Gamepad3 or lastInputType == Enum.UserInputType.Gamepad4) + if not isTenFootInterface then + if isUsingGamepad and not fromTemp then + GuiService.SelectedCoreObject = frameChildren[i] + end + elseif not fromTemp then + GuiService.SelectedCoreObject = ScrollList + end + + if isUsingGamepad and not fromTemp then + UserInputService.OverrideMouseIconBehavior = Enum.OverrideMouseIconBehavior.ForceHide + ContextActionService:BindCoreAction("StopAction", noOpFunc, false, Enum.UserInputType.Gamepad1) + ContextActionService:BindCoreAction("CloseList", closeListFunc, false, Enum.KeyCode.ButtonB, Enum.KeyCode.ButtonStart) + end + break + end + end + end + else + if isUsingGamepad then + UserInputService.OverrideMouseIconBehavior = Enum.OverrideMouseIconBehavior.None + end + + ContextActionService:UnbindCoreAction("CloseList") + ContextActionService:UnbindCoreAction("StopAction") + + if GuiService.SelectedCoreObject and GuiService.SelectedCoreObject:IsDescendantOf(Container) then + GuiService.SelectedCoreObject = nil + end + end +end + +Playerlist.ToggleVisibility = function(name, inputState, inputObject) + if inputState and inputState ~= Enum.UserInputState.Begin then return end + if IsSmallScreenDevice then return end + if not playerlistCoreGuiEnabled then return end + + isOpen = not isOpen + + if next(TempHideKeys) == nil then + setVisible(isOpen) + end +end + +Playerlist.IsOpen = function() + return isOpen +end + +Playerlist.HideTemp = function(self, key, hidden) + if not playerlistCoreGuiEnabled then return end + if IsSmallScreenDevice then return end + + TempHideKeys[key] = hidden and true or nil + + if next(TempHideKeys) == nil then + if isOpen then + setVisible(true, true) + end + else + if isOpen then + setVisible(false, true) + end + end +end +local topStat = nil +if isTenFootInterface then + topStat = TenFootInterface:SetupTopStat() +end + +--[[ Core Gui Changed events ]]-- +-- NOTE: Core script only +local function onCoreGuiChanged(coreGuiType, enabled) + if coreGuiType == Enum.CoreGuiType.All or coreGuiType == Enum.CoreGuiType.PlayerList then + playerlistCoreGuiEnabled = enabled and topbarEnabled + + -- not visible on small screen devices + if IsSmallScreenDevice then + Container.Visible = false + return + end + + setVisible(playerlistCoreGuiEnabled and isOpen and next(TempHideKeys) == nil, true) + + if isTenFootInterface and topStat then + topStat:SetTopStatEnabled(playerlistCoreGuiEnabled) + end + + if playerlistCoreGuiEnabled then + ContextActionService:BindCoreAction("RbxPlayerListToggle", Playerlist.ToggleVisibility, false, Enum.KeyCode.Tab) + else + ContextActionService:UnbindCoreAction("RbxPlayerListToggle") + end + end +end + +Playerlist.TopbarEnabledChanged = function(enabled) + topbarEnabled = enabled + -- Update coregui to reflect new topbar status + onCoreGuiChanged(Enum.CoreGuiType.PlayerList, StarterGui:GetCoreGuiEnabled(Enum.CoreGuiType.PlayerList)) +end + +onCoreGuiChanged(Enum.CoreGuiType.PlayerList, StarterGui:GetCoreGuiEnabled(Enum.CoreGuiType.PlayerList)) +StarterGui.CoreGuiChangedSignal:connect(onCoreGuiChanged) + +resizePlayerList() + +if GuiService then + if isTenFootInterface then + GuiService:AddSelectionTuple("PlayerListSelection", ScrollList) + else + GuiService:AddSelectionParent("PlayerListSelection", Container) + end +end + +local blockStatusChanged = function(userId, isBlocked) + if userId < 0 then return end + + for _,playerEntry in ipairs(PlayerEntries) do + if playerEntry.Player.UserId == userId then + playerEntry.Frame.BGFrame.MembershipIcon.Image = getMembershipIcon(playerEntry.Player) + return + end + end +end + +blockingUtility:GetBlockedStatusChangedEvent():connect(blockStatusChanged) + +return Playerlist diff --git a/2016/content/Modules/Settings/Pages/GameSettings.lua b/2016/content/Modules/Settings/Pages/GameSettings.lua new file mode 100644 index 0000000..89e5aa5 --- /dev/null +++ b/2016/content/Modules/Settings/Pages/GameSettings.lua @@ -0,0 +1,790 @@ +--[[ + Filename: GameSettings.lua + Written by: jeditkacheff + Version 1.1 + Description: Takes care of the Game Settings Tab in Settings Menu +--]] + +-------------- SERVICES -------------- +local CoreGui = game:GetService("CoreGui") +local RobloxGui = CoreGui:WaitForChild("RobloxGui") +local GuiService = game:GetService("GuiService") +local UserInputService = game:GetService("UserInputService") +local PlatformService = nil +pcall(function() PlatformService = game:GetService("PlatformService") end) +local ContextActionService = game:GetService("ContextActionService") +local StarterGui = game:GetService("StarterGui") +local Settings = UserSettings() +local GameSettings = Settings.GameSettings + +-------------- CONSTANTS -------------- +local GRAPHICS_QUALITY_LEVELS = 10 +local GRAPHICS_QUALITY_TO_INT = { + ["Enum.SavedQualitySetting.Automatic"] = 0, + ["Enum.SavedQualitySetting.QualityLevel1"] = 1, + ["Enum.SavedQualitySetting.QualityLevel2"] = 2, + ["Enum.SavedQualitySetting.QualityLevel3"] = 3, + ["Enum.SavedQualitySetting.QualityLevel4"] = 4, + ["Enum.SavedQualitySetting.QualityLevel5"] = 5, + ["Enum.SavedQualitySetting.QualityLevel6"] = 6, + ["Enum.SavedQualitySetting.QualityLevel7"] = 7, + ["Enum.SavedQualitySetting.QualityLevel8"] = 8, + ["Enum.SavedQualitySetting.QualityLevel9"] = 9, + ["Enum.SavedQualitySetting.QualityLevel10"] = 10, +} +local PC_CHANGED_PROPS = { + DevComputerMovementMode = true, + DevComputerCameraMode = true, + DevEnableMouseLock = true, +} +local TOUCH_CHANGED_PROPS = { + DevTouchMovementMode = true, + DevTouchCameraMode = true, +} +local CAMERA_MODE_DEFAULT_STRING = UserInputService.TouchEnabled and "Default (Follow)" or "Default (Classic)" + +local MOVEMENT_MODE_DEFAULT_STRING = UserInputService.TouchEnabled and "Default (Thumbstick)" or "Default (Keyboard)" +local MOVEMENT_MODE_KEYBOARDMOUSE_STRING = "Keyboard + Mouse" +local MOVEMENT_MODE_CLICKTOMOVE_STRING = UserInputService.TouchEnabled and "Tap to Move" or "Click to Move" + +----------- UTILITIES -------------- +local utility = require(RobloxGui.Modules.Settings.Utility) + +------------ Variables ------------------- +RobloxGui:WaitForChild("Modules"):WaitForChild("TenFootInterface") +RobloxGui:WaitForChild("Modules"):WaitForChild("Settings"):WaitForChild("SettingsHub") +local isTenFootInterface = require(RobloxGui.Modules.TenFootInterface):IsEnabled() +local HasVRAPI = false +pcall(function() HasVRAPI = UserInputService.GetUserCFrame ~= nil end) +local PageInstance = nil +local LocalPlayer = game.Players.LocalPlayer +local platform = UserInputService:GetPlatform() +local overscanScreen = nil + +----------- CLASS DECLARATION -------------- + +local function Initialize() + local settingsPageFactory = require(RobloxGui.Modules.Settings.SettingsPageFactory) + local this = settingsPageFactory:CreateNewPage() + + ----------- FUNCTIONS --------------- + local function createGraphicsOptions() + + ------------------ Fullscreen Selection GUI Setup ------------------ + local fullScreenInit = 1 + if not GameSettings:InFullScreen() then + fullScreenInit = 2 + end + + this.FullscreenFrame, + this.FullscreenLabel, + this.FullscreenEnabler = utility:AddNewRow(this, "Fullscreen", "Selector", {"On", "Off"}, fullScreenInit) + + local fullScreenSelectionFrame = this.FullscreenEnabler.SliderFrame and this.FullscreenEnabler.SliderFrame or this.FullscreenEnabler.SelectorFrame + + this.FullscreenEnabler.IndexChanged:connect(function(newIndex) + GuiService:ToggleFullscreen() + end) + + ------------------ Gfx Enabler Selection GUI Setup ------------------ + local graphicsEnablerStart = 1 + if GameSettings.SavedQualityLevel ~= Enum.SavedQualitySetting.Automatic then + graphicsEnablerStart = 2 + end + + this.GraphicsEnablerFrame, + this.GraphicsEnablerLabel, + this.GraphicsQualityEnabler = utility:AddNewRow(this, "Graphics Mode", "Selector", {"Automatic", "Manual"}, graphicsEnablerStart) + + ------------------ Gfx Slider GUI Setup ------------------ + this.GraphicsQualityFrame, + this.GraphicsQualityLabel, + this.GraphicsQualitySlider = utility:AddNewRow(this, "Graphics Quality", "Slider", GRAPHICS_QUALITY_LEVELS, 1) + this.GraphicsQualitySlider:SetMinStep(1) + + ------------------------- Connection Setup ---------------------------- + settings().Rendering.EnableFRM = true + + function SetGraphicsQuality(newValue, automaticSettingAllowed) + local percentage = newValue/GRAPHICS_QUALITY_LEVELS + local newQualityLevel = math.floor((settings().Rendering:GetMaxQualityLevel() - 1) * percentage) + if newQualityLevel == 20 then + newQualityLevel = 21 + elseif newValue == 1 then + newQualityLevel = 1 + elseif newValue < 1 and not automaticSettingAllowed then + newValue = 1 + newQualityLevel = 1 + elseif newQualityLevel > settings().Rendering:GetMaxQualityLevel() then + newQualityLevel = settings().Rendering:GetMaxQualityLevel() - 1 + end + + GameSettings.SavedQualityLevel = newValue + settings().Rendering.QualityLevel = newQualityLevel + end + + local function setGraphicsToAuto() + this.GraphicsQualitySlider:SetZIndex(1) + this.GraphicsQualityLabel.ZIndex = 1 + this.GraphicsQualitySlider:SetInteractable(false) + + SetGraphicsQuality(Enum.QualityLevel.Automatic.Value, true) + end + local function setGraphicsToManual(level) + this.GraphicsQualitySlider:SetZIndex(2) + this.GraphicsQualityLabel.ZIndex = 2 + this.GraphicsQualitySlider:SetInteractable(true) + + -- need to force the quality change if slider is already at this position + if this.GraphicsQualitySlider:GetValue() == level then + SetGraphicsQuality(level) + else + this.GraphicsQualitySlider:SetValue(level) + end + end + + game.GraphicsQualityChangeRequest:connect(function(isIncrease) + if settings().Rendering.QualityLevel == Enum.QualityLevel.Automatic then return end + -- + local currentGraphicsSliderValue = this.GraphicsQualitySlider:GetValue() + if isIncrease then + currentGraphicsSliderValue = currentGraphicsSliderValue + 1 + else + currentGraphicsSliderValue = currentGraphicsSliderValue - 1 + end + + this.GraphicsQualitySlider:SetValue(currentGraphicsSliderValue) + end) + + this.GraphicsQualitySlider.ValueChanged:connect(function(newValue) + SetGraphicsQuality(newValue) + end) + + this.GraphicsQualityEnabler.IndexChanged:connect(function(newIndex) + if newIndex == 1 then + setGraphicsToAuto() + elseif newIndex == 2 then + setGraphicsToManual( this.GraphicsQualitySlider:GetValue() ) + end + end) + + -- initialize the slider position + if GameSettings.SavedQualityLevel == Enum.SavedQualitySetting.Automatic then + this.GraphicsQualitySlider:SetValue(5) + setGraphicsToAuto() + else + local graphicsLevel = tostring(GameSettings.SavedQualityLevel) + if GRAPHICS_QUALITY_TO_INT[graphicsLevel] then + graphicsLevel = GRAPHICS_QUALITY_TO_INT[graphicsLevel] + else + graphicsLevel = GRAPHICS_QUALITY_LEVELS + end + + spawn(function() + this.GraphicsQualitySlider:SetValue(graphicsLevel) + end) + end + end + + local function createCameraModeOptions(movementModeEnabled) + ------------------------------------------------------ + ------------------ + ------------------ Shift Lock Switch ----------------- + if UserInputService.MouseEnabled then + this.ShiftLockFrame, + this.ShiftLockLabel, + this.ShiftLockMode, + this.ShiftLockOverrideText = nil + + if UserInputService.MouseEnabled and UserInputService.KeyboardEnabled then + local startIndex = 2 + if GameSettings.ControlMode == Enum.ControlMode.MouseLockSwitch then + startIndex = 1 + end + + this.ShiftLockFrame, + this.ShiftLockLabel, + this.ShiftLockMode = utility:AddNewRow(this, "Shift Lock Switch", "Selector", {"On", "Off"}, startIndex) + + this.ShiftLockOverrideText = utility:Create'TextLabel' + { + Name = "ShiftLockOverrideLabel", + Text = "Set by Developer", + TextColor3 = Color3.new(1,1,1), + Font = Enum.Font.SourceSans, + FontSize = Enum.FontSize.Size24, + BackgroundTransparency = 1, + Size = UDim2.new(0,200,1,0), + Position = UDim2.new(1,-350,0,0), + Visible = false, + ZIndex = 2, + Parent = this.ShiftLockFrame + }; + + this.ShiftLockMode.IndexChanged:connect(function(newIndex) + if newIndex == 1 then + GameSettings.ControlMode = Enum.ControlMode.MouseLockSwitch + else + GameSettings.ControlMode = Enum.ControlMode.Classic + end + end) + end + end + + + ------------------------------------------------------ + ------------------ + ------------------ Camera Mode ----------------------- + do + local enumItems = nil + local startingCameraEnumItem = 1 + if UserInputService.TouchEnabled then + enumItems = Enum.TouchCameraMovementMode:GetEnumItems() + else + enumItems = Enum.ComputerCameraMovementMode:GetEnumItems() + end + + local cameraEnumNames = {} + local cameraEnumNameToItem = {} + for i = 1, #enumItems do + local displayName = enumItems[i].Name + if displayName == 'Default' then + displayName = CAMERA_MODE_DEFAULT_STRING + end + + if UserInputService.TouchEnabled then + if GameSettings.TouchCameraMovementMode == enumItems[i] then + startingCameraEnumItem = i + end + else + if GameSettings.ComputerCameraMovementMode == enumItems[i] then + startingCameraEnumItem = i + end + end + + cameraEnumNames[i] = displayName + cameraEnumNameToItem[displayName] = enumItems[i].Value + end + + this.CameraModeFrame, + this.CameraModeLabel, + this.CameraMode = utility:AddNewRow(this, "Camera Mode", "Selector", cameraEnumNames, startingCameraEnumItem) + + this.CameraModeOverrideText = utility:Create'TextLabel' + { + Name = "CameraDevOverrideLabel", + Text = "Set by Developer", + TextColor3 = Color3.new(1,1,1), + Font = Enum.Font.SourceSans, + FontSize = Enum.FontSize.Size24, + BackgroundTransparency = 1, + Size = UDim2.new(0,200,1,0), + Position = UDim2.new(1,-350,0,0), + Visible = false, + ZIndex = 2, + Parent = this.CameraModeFrame + }; + + this.CameraMode.IndexChanged:connect(function(newIndex) + local newEnumSetting = cameraEnumNameToItem[cameraEnumNames[newIndex]] + + if UserInputService.TouchEnabled then + GameSettings.TouchCameraMovementMode = newEnumSetting + else + GameSettings.ComputerCameraMovementMode = newEnumSetting + end + end) + end + + + ------------------------------------------------------ + ------------------ + ------------------ VR Camera Mode ----------------------- + + if HasVRAPI and UserInputService.VREnabled then + local VR_ROTATION_INTENSITY_OPTIONS = {"Low", "High", "Smooth"} + + if utility:IsSmallTouchScreen() then + this.VRRotationFrame, + this.VRRotationLabel, + this.VRRotationMode = utility:AddNewRow(this, "VR Camera Rotation", "Selector", VR_ROTATION_INTENSITY_OPTIONS, GameSettings.VRRotationIntensity) + else + this.VRRotationFrame, + this.VRRotationLabel, + this.VRRotationMode = utility:AddNewRow(this, "VR Camera Rotation", "Selector", VR_ROTATION_INTENSITY_OPTIONS, GameSettings.VRRotationIntensity, 3) + end + + StarterGui:RegisterGetCore("VRRotationIntensity", + function() + return VR_ROTATION_INTENSITY_OPTIONS[GameSettings.VRRotationIntensity] or VR_ROTATION_INTENSITY_OPTIONS[1] + end) + this.VRRotationMode.IndexChanged:connect(function(newIndex) + GameSettings.VRRotationIntensity = newIndex + end) + end + + ------------------------------------------------------ + ------------------ + ------------------ Movement Mode --------------------- + if movementModeEnabled then + local movementEnumItems = nil + local startingMovementEnumItem = 1 + if UserInputService.TouchEnabled then + movementEnumItems = Enum.TouchMovementMode:GetEnumItems() + else + movementEnumItems = Enum.ComputerMovementMode:GetEnumItems() + end + + local movementEnumNames = {} + local movementEnumNameToItem = {} + for i = 1, #movementEnumItems do + local displayName = movementEnumItems[i].Name + if displayName == "Default" then + displayName = MOVEMENT_MODE_DEFAULT_STRING + elseif displayName == "KeyboardMouse" then + displayName = MOVEMENT_MODE_KEYBOARDMOUSE_STRING + elseif displayName == "ClickToMove" then + displayName = MOVEMENT_MODE_CLICKTOMOVE_STRING + end + + if UserInputService.TouchEnabled then + if GameSettings.TouchMovementMode == movementEnumItems[i] then + startingMovementEnumItem = i + end + else + if GameSettings.ComputerMovementMode == movementEnumItems[i] then + startingMovementEnumItem = i + end + end + + movementEnumNames[i] = displayName + movementEnumNameToItem[displayName] = movementEnumItems[i] + end + + this.MovementModeFrame, + this.MovementModeLabel, + this.MovementMode = utility:AddNewRow(this, "Movement Mode", "Selector", movementEnumNames, startingMovementEnumItem) + + this.MovementModeOverrideText = utility:Create'TextLabel' + { + Name = "MovementDevOverrideLabel", + Text = "Set by Developer", + TextColor3 = Color3.new(1,1,1), + Font = Enum.Font.SourceSans, + FontSize = Enum.FontSize.Size24, + BackgroundTransparency = 1, + Size = UDim2.new(0,200,1,0), + Position = UDim2.new(1,-350,0,0), + Visible = false, + ZIndex = 2, + Parent = this.MovementModeFrame + }; + + this.MovementMode.IndexChanged:connect(function(newIndex) + local newEnumSetting = movementEnumNameToItem[movementEnumNames[newIndex]] + + if UserInputService.TouchEnabled then + GameSettings.TouchMovementMode = newEnumSetting + else + GameSettings.ComputerMovementMode = newEnumSetting + end + end) + end + + + ------------------------------------------------------ + ------------------ + ------------------------- Connection Setup ----------- + function setCameraModeVisible(visible) + if this.CameraMode then + this.CameraMode.SelectorFrame.Visible = visible + this.CameraMode:SetInteractable(visible) + end + end + + function setMovementModeVisible(visible) + if this.MovementMode then + this.MovementMode.SelectorFrame.Visible = visible + this.MovementMode:SetInteractable(visible) + end + end + + function setShiftLockVisible(visible) + if this.ShiftLockMode then + this.ShiftLockMode.SelectorFrame.Visible = visible + this.ShiftLockMode:SetInteractable(visible) + end + end + + do -- initial set of dev vs user choice for guis + local isUserChoiceCamera = false + if UserInputService.TouchEnabled then + isUserChoiceCamera = LocalPlayer.DevTouchCameraMode == Enum.DevTouchCameraMovementMode.UserChoice + else + isUserChoiceCamera = LocalPlayer.DevComputerCameraMode == Enum.DevComputerCameraMovementMode.UserChoice + end + + if not isUserChoiceCamera then + this.CameraModeOverrideText.Visible = true + setCameraModeVisible(false) + else + this.CameraModeOverrideText.Visible = false + setCameraModeVisible(true) + end + + + local isUserChoiceMovement = false + if UserInputService.TouchEnabled then + isUserChoiceMovement = LocalPlayer.DevTouchMovementMode == Enum.DevTouchMovementMode.UserChoice + else + isUserChoiceMovement = LocalPlayer.DevComputerMovementMode == Enum.DevComputerMovementMode.UserChoice + end + + if this.MovementModeOverrideText then + if not isUserChoiceMovement then + this.MovementModeOverrideText.Visible = true + setMovementModeVisible(false) + else + this.MovementModeOverrideText.Visible = false + setMovementModeVisible(true) + end + end + + if this.ShiftLockOverrideText then + this.ShiftLockOverrideText.Visible = not LocalPlayer.DevEnableMouseLock + setShiftLockVisible(LocalPlayer.DevEnableMouseLock) + end + end + + local function updateUserSettingsMenu(property) + if this.ShiftLockOverrideText and property == "DevEnableMouseLock" then + this.ShiftLockOverrideText.Visible = not LocalPlayer.DevEnableMouseLock + setShiftLockVisible(LocalPlayer.DevEnableMouseLock) + elseif property == "DevComputerCameraMode" then + local isUserChoice = LocalPlayer.DevComputerCameraMode == Enum.DevComputerCameraMovementMode.UserChoice + setCameraModeVisible(isUserChoice) + this.CameraModeOverrideText.Visible = not isUserChoice + elseif property == "DevComputerMovementMode" then + local isUserChoice = LocalPlayer.DevComputerMovementMode == Enum.DevComputerMovementMode.UserChoice + setMovementModeVisible(isUserChoice) + if this.MovementModeOverrideText then + this.MovementModeOverrideText.Visible = not isUserChoice + end + -- TOUCH + elseif property == "DevTouchMovementMode" then + local isUserChoice = LocalPlayer.DevTouchMovementMode == Enum.DevTouchMovementMode.UserChoice + setMovementModeVisible(isUserChoice) + if this.MovementModeOverrideText then + this.MovementModeOverrideText.Visible = not isUserChoice + end + elseif property == "DevTouchCameraMode" then + local isUserChoice = LocalPlayer.DevTouchCameraMode == Enum.DevTouchCameraMovementMode.UserChoice + setCameraModeVisible(isUserChoice) + this.CameraModeOverrideText.Visible = not isUserChoice + end + end + + LocalPlayer.Changed:connect(function(property) + if IsTouchClient then + if TOUCH_CHANGED_PROPS[property] then + updateUserSettingsMenu(property) + end + else + if PC_CHANGED_PROPS[property] then + updateUserSettingsMenu(property) + end + end + end) + end + + local function createVolumeOptions() + local startVolumeLevel = math.floor(GameSettings.MasterVolume * 10) + this.VolumeFrame, + this.VolumeLabel, + this.VolumeSlider = utility:AddNewRow(this, "Volume", "Slider", 10, startVolumeLevel) + + local volumeSound = Instance.new("Sound", game.CoreGui.RobloxGui.Sounds) + volumeSound.Name = "VolumeChangeSound" + volumeSound.SoundId = "rbxasset://sounds/metalstone2.mp3" + + this.VolumeSlider.ValueChanged:connect(function(newValue) + local soundPercent = newValue/10 + volumeSound.Volume = soundPercent + volumeSound:Play() + GameSettings.MasterVolume = soundPercent + end) + end + + local function createMouseOptions() + local MouseSteps = 10 + local MinMouseSensitivity = 0.2 + local AdvancedSuccess, AdvancedValue = pcall(function() return settings():GetFFlag("AdvancedMouseSensitivityEnabled") end) + local AdvancedEnabled = AdvancedSuccess and AdvancedValue + + -- equations below map a function to include points (0, 0.2) (5, 1) (10, 4) + -- where x is the slider position, y is the mouse sensitivity + local function translateEngineMouseSensitivityToGui(engineSensitivity) + return math.floor((2.0/3.0) * (math.sqrt(75.0 * engineSensitivity - 11.0) - 2)) + end + + local function translateGuiMouseSensitivityToEngine(guiSensitivity) + return 0.03 * math.pow(guiSensitivity,2) + (0.08 * guiSensitivity) + MinMouseSensitivity + end + + local startMouseLevel = translateEngineMouseSensitivityToGui(GameSettings.MouseSensitivity) + + ------------------ Mouse Selection GUI Setup ------------------ + -- switch between basic mode and advanced mode. + local MouseModeEnablerStart = 2 + if GameSettings.UseBasicMouseSensitivity or not AdvancedEnabled then + MouseModeEnablerStart = 1 + end + + -- auto-detect mouse invert + local MouseInvertStart = 1 + if GameSettings.MouseSensitivityFirstPerson.y < 0 then + MouseInvertStart = 2 + end + + if AdvancedEnabled then + this.MouseModeFrame, + this.MouseModeLabel, + this.MouseModeEnabler = utility:AddNewRow(this, "Mouse Sensitivity Mode", "Selector", {"Basic", "Advanced"}, MouseModeEnablerStart) + end + + ------------------ Basic Mouse Sensitivity Slider ------------------ + -- basic quantized sensitivity with a weird number of settings. + local SliderLabel = "Basic Mouse Sensitivity" + if not AdvancedEnabled then + SliderLabel = "Mouse Sensitivity" + end + this.MouseSensitivityFrame, + this.MouseSensitivityLabel, + this.MouseSensitivitySlider = utility:AddNewRow(this, SliderLabel, "Slider", MouseSteps, startMouseLevel) + this.MouseSensitivitySlider:SetMinStep(1) + + this.MouseSensitivitySlider.ValueChanged:connect(function(newValue) + GameSettings.MouseSensitivity = translateGuiMouseSensitivityToEngine(newValue) + end) + + ------------------ 3D Sensitivity ------------------ + -- affects both first and third person. + if AdvancedEnabled then + local MouseAdvancedStart = tostring(GameSettings.MouseSensitivityFirstPerson.y) + this.MouseAdvancedFrame, + this.MouseAdvancedLabel, + this.MouseAdvancedEntry = utility:AddNewRow(this, "Advanced Mouse Sensitivity", "TextEntry", 1.0, 1.0, MouseAdvancedStart) + + this.MouseAdvancedEntry.ValueChanged:connect(function(newValueText) + local currentFirstSensitivity = GameSettings.MouseSensitivityFirstPerson + local currentThirdSensitivity = GameSettings.MouseSensitivityThirdPerson + + local newValue = tonumber(newValueText) + if not newValue then + this.MouseAdvancedEntry:SetValue(string.format("%.3f",currentFirstSensitivity.x)) + return + end + + -- inverted mouse will be handled later + if newValue < 0.0 then + newValue = -newValue + end + + -- * assume a minimum that allows a 16000 dpi mouse a full 800mm travel for 360deg + -- ~0.0029: min of 0.001 seems ok. + -- * assume a max that allows a 400 dpi mouse a 360deg travel in 10mm + -- ~9.2: max of 10 seems ok, but users will want to have a bit of fun with crazy settings. + if newValue > 100.0 then + newValue = 100.0 + elseif newValue < 0.001 then + newValue = 0.001 + end + + -- try to keep ratios the same, even though they aren't exposed to the GUI + local firstPersonX = newValue + local firstPersonY = newValue * (currentFirstSensitivity.y / currentFirstSensitivity.x) + local thirdPersonX = newValue * (currentFirstSensitivity.x / currentThirdSensitivity.x) + local thirdPersonY = thirdPersonX * (currentThirdSensitivity.y / currentThirdSensitivity.x) + + -- handle invert + if currentFirstSensitivity.y < 0.0 then + firstPersonY = -firstPersonY + end + if currentThirdSensitivity.y < 0.0 then + thirdPersonY = -thirdPersonY + end + + GameSettings.MouseSensitivityFirstPerson = Vector2.new(firstPersonX, firstPersonY) + GameSettings.MouseSensitivityThirdPerson = Vector2.new(thirdPersonX, thirdPersonY) + this.MouseAdvancedEntry:SetValue(string.format("%.3f",firstPersonX)) + + end) + end + + ------------------ Mouse Invert ------------------ + -- This is a common setting in games, even if it is rare + if AdvancedEnabled then + this.MouseInvertFrame, + this.MouseInvertLabel, + this.MouseInvertEnabler = utility:AddNewRow(this, "Advanced Mouse Invert", "Selector", {"Normal", "Inverted"}, MouseInvertStart) + + this.MouseInvertEnabler.IndexChanged:connect(function(newIndex) + local currentFirstSensitivity = GameSettings.MouseSensitivityFirstPerson + local currentThirdSensitivity = GameSettings.MouseSensitivityThirdPerson + + if newIndex == 1 then + if currentFirstSensitivity.y < 0.0 then + currentFirstSensitivity = Vector2.new(currentFirstSensitivity.x, -currentFirstSensitivity.y) + currentThirdSensitivity = Vector2.new(currentThirdSensitivity.x, -currentThirdSensitivity.y) + end + elseif newIndex == 2 then + if currentFirstSensitivity.y > 0.0 then + currentFirstSensitivity = Vector2.new(currentFirstSensitivity.x, -currentFirstSensitivity.y) + currentThirdSensitivity = Vector2.new(currentThirdSensitivity.x, -currentThirdSensitivity.y) + end + end + GameSettings.MouseSensitivityFirstPerson = currentFirstSensitivity + GameSettings.MouseSensitivityThirdPerson = currentThirdSensitivity + end) + end + + ------------------ Init ------------------ + if AdvancedEnabled then + local function setMouseModeToBasic() + this.MouseSensitivitySlider:SetZIndex(2) + this.MouseSensitivityLabel.ZIndex = 2 + this.MouseSensitivitySlider:SetInteractable(true) + this.MouseSensitivitySlider:SetValue(translateEngineMouseSensitivityToGui(GameSettings.MouseSensitivity)) + + this.MouseAdvancedLabel.ZIndex = 1 + this.MouseAdvancedEntry:SetInteractable(false) + + this.MouseInvertLabel.ZIndex = 1 + this.MouseInvertEnabler:SetInteractable(false) + + end + local function setMouseModeToAdvanced() + this.MouseSensitivitySlider:SetZIndex(1) + this.MouseSensitivityLabel.ZIndex = 1 + this.MouseSensitivitySlider:SetInteractable(false) + + this.MouseAdvancedLabel.ZIndex = 2 + this.MouseAdvancedEntry:SetInteractable(true) + local MouseSensitivity3d = GameSettings.MouseSensitivityFirstPerson + this.MouseAdvancedEntry:SetValue(tostring(MouseSensitivity3d.x)); + + this.MouseInvertLabel.ZIndex = 2 + this.MouseInvertEnabler:SetInteractable(true) + + end + + this.MouseModeEnabler.IndexChanged:connect(function(newIndex) + if newIndex == 1 then + GameSettings.UseBasicMouseSensitivity = true + setMouseModeToBasic() + elseif newIndex == 2 then + GameSettings.UseBasicMouseSensitivity = false + setMouseModeToAdvanced() + end + end) + + if GameSettings.UseBasicMouseSensitivity then + setMouseModeToBasic() + this.MouseAdvancedEntry:SetValue(tostring(MouseAdvancedStart)) + else + setMouseModeToAdvanced() + end + end + + end + + local function createOverscanOption() + local showOverscanScreen = function() + + if not overscanScreen then + local createOverscanFunc = require(RobloxGui.Modules.OverscanScreen) + overscanScreen = createOverscanFunc(RobloxGui) + overscanScreen:SetStyleForInGame() + end + + local MenuModule = require(RobloxGui.Modules.Settings.SettingsHub) + MenuModule:SetVisibility(false, true) + + local closedCon = nil + closedCon = overscanScreen.Closed:connect(function() + closedCon:disconnect() + pcall(function() PlatformService.BlurIntensity = 0 end) + ContextActionService:UnbindCoreAction("RbxStopOverscanMovement") + MenuModule:SetVisibility(true, true) + end) + + pcall(function() PlatformService.BlurIntensity = 10 end) + + local noOpFunc = function() end + ContextActionService:BindCoreAction("RbxStopOverscanMovement", noOpFunc, false, + Enum.UserInputType.Gamepad1, Enum.UserInputType.Gamepad2, + Enum.UserInputType.Gamepad3, Enum.UserInputType.Gamepad4) + + local ScreenManager = require(RobloxGui.Modules.ScreenManager) + ScreenManager:OpenScreen(overscanScreen) + + end + + local adjustButton, adjustText, setButtonRowRef = utility:MakeStyledButton("AdjustButton", "Adjust", UDim2.new(0,300,1,-20), showOverscanScreen, this) + adjustText.Font = Enum.Font.SourceSans + adjustButton.Position = UDim2.new(1,-400,0,12) + + local row = utility:AddNewRowObject(this, "Safe Zone", adjustButton) + setButtonRowRef(row) + end + + createCameraModeOptions(not isTenFootInterface and + (UserInputService.TouchEnabled or UserInputService.MouseEnabled or UserInputService.KeyboardEnabled)) + + if UserInputService.MouseEnabled then + createMouseOptions() + end + + createVolumeOptions() + + if platform == Enum.Platform.Windows or platform == Enum.Platform.UWP or platform == Enum.Platform.OSX then + createGraphicsOptions() + end + + if isTenFootInterface then + createOverscanOption() + end + + ------ TAB CUSTOMIZATION ------- + this.TabHeader.Name = "GameSettingsTab" + + this.TabHeader.Icon.Image = "rbxasset://textures/ui/Settings/MenuBarIcons/GameSettingsTab.png" + if utility:IsSmallTouchScreen() then + this.TabHeader.Icon.Size = UDim2.new(0,34,0,34) + this.TabHeader.Icon.Position = UDim2.new(this.TabHeader.Icon.Position.X.Scale,this.TabHeader.Icon.Position.X.Offset,0.5,-17) + this.TabHeader.Size = UDim2.new(0,125,1,0) + elseif isTenFootInterface then + this.TabHeader.Icon.Image = "rbxasset://textures/ui/Settings/MenuBarIcons/GameSettingsTab@2x.png" + this.TabHeader.Icon.Size = UDim2.new(0,90,0,90) + this.TabHeader.Icon.Position = UDim2.new(0,0,0.5,-43) + this.TabHeader.Size = UDim2.new(0,280,1,0) + else + this.TabHeader.Icon.Size = UDim2.new(0,45,0,45) + this.TabHeader.Icon.Position = UDim2.new(0,15,0.5,-22) + end + + + this.TabHeader.Icon.Title.Text = "Settings" + + ------ PAGE CUSTOMIZATION ------- + this.Page.ZIndex = 5 + + return this +end + + +----------- Page Instantiation -------------- + +PageInstance = Initialize() + +return PageInstance diff --git a/2016/content/Modules/Settings/Pages/Help.lua b/2016/content/Modules/Settings/Pages/Help.lua new file mode 100644 index 0000000..7156dba --- /dev/null +++ b/2016/content/Modules/Settings/Pages/Help.lua @@ -0,0 +1,489 @@ +--[[ + Filename: Help.lua + Written by: jeditkacheff + Version 1.0 + Description: Takes care of the help page in Settings Menu +--]] +-------------- CONSTANTS -------------- +local KEYBOARD_MOUSE_TAG = "KeyboardMouse" +local TOUCH_TAG = "Touch" +local GAMEPAD_TAG = "Gamepad" +local PC_TABLE_SPACING = 4 + +-------------- SERVICES -------------- +local CoreGui = game:GetService("CoreGui") +local RobloxGui = CoreGui:WaitForChild("RobloxGui") +local UserInputService = game:GetService("UserInputService") +local GuiService = game:GetService("GuiService") + +----------- UTILITIES -------------- +local utility = require(RobloxGui.Modules.Settings.Utility) + +------------ Variables ------------------- +local PageInstance = nil +RobloxGui:WaitForChild("Modules"):WaitForChild("TenFootInterface") +local isTenFootInterface = require(RobloxGui.Modules.TenFootInterface):IsEnabled() + +----------- CLASS DECLARATION -------------- + +local function Initialize() + local settingsPageFactory = require(RobloxGui.Modules.Settings.SettingsPageFactory) + local this = settingsPageFactory:CreateNewPage() + this.HelpPages = {} + + -- TODO: Change dev console script to parent this to somewhere other than an engine created gui + local ControlFrame = RobloxGui:WaitForChild('ControlFrame') + local ToggleDevConsoleBindableFunc = ControlFrame:WaitForChild('ToggleDevConsole') + local lastInputType = nil + + function this:GetCurrentInputType() + if lastInputType == nil then -- we don't know what controls the user has, just use reasonable defaults + local platform = UserInputService:GetPlatform() + if platform == Enum.Platform.XBoxOne or platform == Enum.Platform.WiiU then + + return GAMEPAD_TAG + elseif platform == Enum.Platform.Windows or platform == Enum.Platform.OSX then + return KEYBOARD_MOUSE_TAG + else + return TOUCH_TAG + end + end + + if lastInputType == Enum.UserInputType.Keyboard or lastInputType == Enum.UserInputType.MouseMovement or + lastInputType == Enum.UserInputType.MouseButton1 or lastInputType == Enum.UserInputType.MouseButton2 or + lastInputType == Enum.UserInputType.MouseButton3 or lastInputType == Enum.UserInputType.MouseWheel then + return KEYBOARD_MOUSE_TAG + elseif lastInputType == Enum.UserInputType.Touch then + return TOUCH_TAG + elseif lastInputType == Enum.UserInputType.Gamepad1 or lastInputType == Enum.UserInputType.Gamepad2 or + inputType == Enum.UserInputType.Gamepad3 or lastInputType == Enum.UserInputType.Gamepad4 then + return GAMEPAD_TAG + end + + return KEYBOARD_MOUSE_TAG + end + + + local function createPCHelp(parentFrame) + local function createPCGroup(title, actionInputBindings) + local textIndent = 9 + + local pcGroupFrame = utility:Create'Frame' + { + Size = UDim2.new(1/3,-PC_TABLE_SPACING,1,0), + BackgroundTransparency = 1, + Name = "PCGroupFrame" .. tostring(title) + }; + local pcGroupTitle = utility:Create'TextLabel' + { + Position = UDim2.new(0,textIndent,0,0), + Size = UDim2.new(1,-textIndent,0,30), + BackgroundTransparency = 1, + Text = title, + Font = Enum.Font.SourceSansBold, + FontSize = Enum.FontSize.Size18, + TextColor3 = Color3.new(1,1,1), + TextXAlignment = Enum.TextXAlignment.Left, + Name = "PCGroupTitle" .. tostring(title), + ZIndex = 2, + Parent = pcGroupFrame + }; + + local count = 0 + local frameHeight = 42 + local spacing = 2 + local offset = pcGroupTitle.Size.Y.Offset + for i = 1, #actionInputBindings do + for actionName, inputName in pairs(actionInputBindings[i]) do + local actionInputFrame = utility:Create'Frame' + { + Size = UDim2.new(1,0,0,frameHeight), + Position = UDim2.new(0,0,0, offset + ((frameHeight + spacing) * count)), + BackgroundTransparency = 0.65, + BorderSizePixel = 0, + ZIndex = 2, + Name = "ActionInputBinding" .. tostring(actionName), + Parent = pcGroupFrame + }; + + local nameLabel = utility:Create'TextLabel' + { + Size = UDim2.new(0.4,-textIndent,0,frameHeight), + Position = UDim2.new(0,textIndent,0,0), + BackgroundTransparency = 1, + Text = actionName, + Font = Enum.Font.SourceSansBold, + FontSize = Enum.FontSize.Size18, + TextColor3 = Color3.new(1,1,1), + TextXAlignment = Enum.TextXAlignment.Left, + Name = actionName .. "Label", + ZIndex = 2, + Parent = actionInputFrame + }; + + local inputLabel = utility:Create'TextLabel' + { + Size = UDim2.new(0.6,0,0,frameHeight), + Position = UDim2.new(0.5,-4,0,0), + BackgroundTransparency = 1, + Text = inputName, + Font = Enum.Font.SourceSans, + FontSize = Enum.FontSize.Size18, + TextColor3 = Color3.new(1,1,1), + TextXAlignment = Enum.TextXAlignment.Left, + Name = inputName .. "Label", + ZIndex = 2, + Parent = actionInputFrame + }; + + count = count + 1 + end + end + + pcGroupFrame.Size = UDim2.new(pcGroupFrame.Size.X.Scale,pcGroupFrame.Size.X.Offset, + 0, offset + ((frameHeight + spacing) * count)) + + return pcGroupFrame + end + + local rowOffset = 50 + local isOSX = UserInputService:GetPlatform() == Enum.Platform.OSX + + local charMoveFrame = createPCGroup( "Character Movement", {[1] = {["Move Forward"] = "W/Up Arrow"}, + [2] = {["Move Backward"] = "S/Down Arrow"}, + [3] = {["Move Left"] = "A/Left Arrow"}, + [4] = {["Move Right"] = "D/Right Arrow"}, + [5] = {["Jump"] = "Space"}} ) + charMoveFrame.Parent = parentFrame + + local accessoriesFrame = createPCGroup("Accessories", { [1] = {["Equip Tools"] = "1,2,3..."}, + [2] = {["Unequip Tools"] = "1,2,3..."}, + [3] = {["Drop Tool"] = "Backspace"}, + [4] = {["Use Tool"] = "Left Mouse Button"}, + [5] = {["Drop Hats"] = "+"} }) + accessoriesFrame.Position = UDim2.new(1/3,PC_TABLE_SPACING,0,0) + accessoriesFrame.Parent = parentFrame + + local miscFrame = nil + local hideHudSuccess, hideHudFlagValue = pcall(function() return settings():GetFFlag("AllowHideHudShortcut") end) + if (hideHudSuccess and hideHudFlagValue) then + miscFrame = createPCGroup("Misc", { [1] = {["Screenshot"] = "Print Screen"}, + [2] = {["Record Video"] = isOSX and "F12/fn + F12" or "F12"}, + [3] = {["Hide HUD"] = isOSX and "F7/fn + F7" or "F7"}, + [4] = {["Dev Console"] = isOSX and "F9/fn + F9" or "F9"}, + [5] = {["Mouselock"] = "Shift"}, + [6] = {["Graphics Level"] = isOSX and "F10/fn + F10" or "F10"}, + [7] = {["Fullscreen"] = isOSX and "F11/fn + F11" or "F11"} }) + else + miscFrame = createPCGroup("Misc", { [1] = {["Screenshot"] = "Print Screen"}, + [2] = {["Record Video"] = isOSX and "F12/fn + F12" or "F12"}, + [3] = {["Dev Console"] = isOSX and "F9/fn + F9" or "F9"}, + [4] = {["Mouselock"] = "Shift"}, + [5] = {["Graphics Level"] = isOSX and "F10/fn + F10" or "F10"}, + [6] = {["Fullscreen"] = isOSX and "F11/fn + F11" or "F11"} }) + end + miscFrame.Position = UDim2.new(2/3,PC_TABLE_SPACING * 2,0,0) + miscFrame.Parent = parentFrame + + local camFrame = createPCGroup("Camera Movement", { [1] = {["Rotate"] = "Right Mouse Button"}, + [2] = {["Zoom In/Out"] = "Mouse Wheel"}, + [3] = {["Zoom In"] = "I"}, + [4] = {["Zoom Out"] = "O"} }) + camFrame.Position = UDim2.new(0,0,charMoveFrame.Size.Y.Scale,charMoveFrame.Size.Y.Offset + rowOffset) + camFrame.Parent = parentFrame + + local menuFrame = createPCGroup("Menu Items", { [1] = {["ROBLOX Menu"] = "ESC"}, + [2] = {["Backpack"] = "~"}, + [3] = {["Playerlist"] = "TAB"}, + [4] = {["Chat"] = "/"} }) + menuFrame.Position = UDim2.new(1/3,PC_TABLE_SPACING,charMoveFrame.Size.Y.Scale,charMoveFrame.Size.Y.Offset + rowOffset) + menuFrame.Parent = parentFrame + + parentFrame.Size = UDim2.new(parentFrame.Size.X.Scale, parentFrame.Size.X.Offset, 0, + menuFrame.Size.Y.Offset + menuFrame.Position.Y.Offset) + end + + local function createGamepadHelp(parentFrame) + local gamepadImage = "rbxasset://textures/ui/Settings/Help/GenericController.png" + local imageSize = UDim2.new(0,650,0,239) + local imagePosition = UDim2.new(0.5,-imageSize.X.Offset/2,0.5,-imageSize.Y.Offset/2) + if UserInputService:GetPlatform() == Enum.Platform.XBoxOne or UserInputService:GetPlatform() == Enum.Platform.XBox360 then + gamepadImage = "rbxasset://textures/ui/Settings/Help/XboxController.png" + imageSize = UDim2.new(0,1334,0,570) + imagePosition = UDim2.new(0.5, (-imageSize.X.Offset/2) - 50, 0.5, -imageSize.Y.Offset/2) + elseif UserInputService:GetPlatform() == Enum.Platform.PS4 or UserInputService:GetPlatform() == Enum.Platform.PS3 then + gamepadImage = "rbxasset://textures/ui/Settings/Help/PSController.png" + end + + local gamepadImageLabel = utility:Create'ImageLabel' + { + Name = "GamepadImage", + Size = imageSize, + Position = imagePosition, + Image = gamepadImage, + BackgroundTransparency = 1, + ZIndex = 2, + Parent = parentFrame + }; + parentFrame.Size = UDim2.new(parentFrame.Size.X.Scale, parentFrame.Size.X.Offset, 0, gamepadImageLabel.Size.Y.Offset + 100) + + local gamepadFontSize = isTenFootInterface and Enum.FontSize.Size36 or Enum.FontSize.Size24 + local function createGamepadLabel(text, position, size) + local nameLabel = utility:Create'TextLabel' + { + Position = position, + Size = size, + BackgroundTransparency = 1, + Text = text, + TextXAlignment = Enum.TextXAlignment.Left, + Font = Enum.Font.SourceSansBold, + FontSize = gamepadFontSize, + TextColor3 = Color3.new(1,1,1), + Name = text .. "Label", + ZIndex = 2, + Parent = gamepadImageLabel + }; + end + + local textVerticalSize = (gamepadFontSize == Enum.FontSize.Size36) and 36 or 24 + + if gamepadImage == "rbxasset://textures/ui/Settings/Help/XboxController.png" then + createGamepadLabel("Switch Tool", UDim2.new(0,50,0,-textVerticalSize/2), UDim2.new(0,100,0,textVerticalSize)) + createGamepadLabel("Game Menu Toggle", UDim2.new(0,-38,0.15,-textVerticalSize/2), UDim2.new(0,164,0,textVerticalSize)) + createGamepadLabel("Move", UDim2.new(0,-80,0.31,-textVerticalSize/2), UDim2.new(0,46,0,textVerticalSize)) + createGamepadLabel("Menu Navigation", UDim2.new(0,-50,0.46,-textVerticalSize/2), UDim2.new(0,164,0,textVerticalSize)) + createGamepadLabel("Use Tool", UDim2.new(0.96,0,0,-textVerticalSize/2), UDim2.new(0,73,0,textVerticalSize)) + createGamepadLabel("ROBLOX Menu", UDim2.new(0.96,0,0.15,-textVerticalSize/2), UDim2.new(0,122,0,textVerticalSize)) + createGamepadLabel("Back", UDim2.new(0.96,0,0.31,-textVerticalSize/2), UDim2.new(0,43,0,textVerticalSize)) + createGamepadLabel("Jump", UDim2.new(0.96,0,0.46,-textVerticalSize/2), UDim2.new(0,49,0,textVerticalSize)) + createGamepadLabel("Rotate Camera", UDim2.new(1,0,0.62,-textVerticalSize/2), UDim2.new(0,132,0,textVerticalSize)) + createGamepadLabel("Camera Zoom", UDim2.new(1,0,0.77,-textVerticalSize/2), UDim2.new(0,122,0,textVerticalSize)) + else + createGamepadLabel("Switch Tool", UDim2.new(-0.01,0,0,-textVerticalSize/2), UDim2.new(0,100,0,textVerticalSize)) + createGamepadLabel("Game Menu Toggle", UDim2.new(-0.11,0,0.15,-textVerticalSize/2), UDim2.new(0,164,0,textVerticalSize)) + createGamepadLabel("Move", UDim2.new(-0.08,0,0.31,-textVerticalSize/2), UDim2.new(0,46,0,textVerticalSize)) + createGamepadLabel("Menu Navigation", UDim2.new(-0.125,0,0.46,-textVerticalSize/2), UDim2.new(0,164,0,textVerticalSize)) + createGamepadLabel("Use Tool", UDim2.new(0.96,0,0,-textVerticalSize/2), UDim2.new(0,73,0,textVerticalSize)) + createGamepadLabel("ROBLOX Menu", UDim2.new(0.9,0,0.15,-textVerticalSize/2), UDim2.new(0,122,0,textVerticalSize)) + createGamepadLabel("Back", UDim2.new(1.01,0,0.31,-textVerticalSize/2), UDim2.new(0,43,0,textVerticalSize)) + createGamepadLabel("Jump", UDim2.new(0.91,0,0.46,-textVerticalSize/2), UDim2.new(0,49,0,textVerticalSize)) + createGamepadLabel("Rotate Camera", UDim2.new(0.91,0,0.62,-textVerticalSize/2), UDim2.new(0,132,0,textVerticalSize)) + createGamepadLabel("Camera Zoom", UDim2.new(0.91,0,0.77,-textVerticalSize/2), UDim2.new(0,122,0,textVerticalSize)) + end + + + -- todo: turn on dev console button when dev console is ready + --[[local openDevConsoleFunc = function() + this.HubRef:SetVisibility(false) + ToggleDevConsoleBindableFunc:Invoke() + end + local devConsoleButton = utility:MakeStyledButton("ConsoleButton", " Toggle Dev Console", UDim2.new(0,300,0,44), openDevConsoleFunc) + devConsoleButton.Size = UDim2.new(devConsoleButton.Size.X.Scale, devConsoleButton.Size.X.Offset, 0, 60) + devConsoleButton.Position = UDim2.new(1,-300,1,30) + if UserInputService.GamepadEnabled and not UserInputService.TouchEnabled and not UserInputService.MouseEnabled and not UserInputService.KeyboardEnabled then + devConsoleButton.ImageTransparency = 1 + end + devConsoleButton.Parent = gamepadImageLabel + local aButtonImage = utility:Create'ImageLabel' + { + Name = "AButtonImage", + Size = UDim2.new(0,55,0,55), + Position = UDim2.new(0,5,0.5,-28), + Image = "rbxasset://textures/ui/Settings/Help/AButtonDark.png", + BackgroundTransparency = 1, + ZIndex = 2, + Parent = devConsoleButton + }; + + this:AddRow(nil, nil, devConsoleButton, 340)]] + end + + local function createTouchHelp(parentFrame) + local smallScreen = utility:IsSmallTouchScreen() + local ySize = GuiService:GetScreenResolution().y - 350 + if smallScreen then + ySize = GuiService:GetScreenResolution().y - 100 + end + parentFrame.Size = UDim2.new(1,0,0,ySize) + + local function createTouchLabel(text, position, size, parent) + local nameLabel = utility:Create'TextLabel' + { + Position = position, + Size = size, + BackgroundTransparency = 1, + Text = text, + Font = Enum.Font.SourceSansBold, + FontSize = Enum.FontSize.Size14, + TextColor3 = Color3.new(1,1,1), + Name = text .. "Label", + ZIndex = 2, + Parent = parent + }; + if not smallScreen then + nameLabel.FontSize = Enum.FontSize.Size18 + nameLabel.Size = UDim2.new(nameLabel.Size.X.Scale, nameLabel.Size.X.Offset, nameLabel.Size.Y.Scale, nameLabel.Size.Y.Offset + 4) + end + local nameBackgroundImage = utility:Create'ImageLabel' + { + Name = text .. "BackgroundImage", + Size = UDim2.new(1,0,1,0), + Position = UDim2.new(0,0,0,2), + BackgroundTransparency = 1, + Image = "rbxasset://textures/ui/Settings/Radial/RadialLabel.png", + ScaleType = Enum.ScaleType.Slice, + SliceCenter = Rect.new(12,2,65,21), + ZIndex = 2, + Parent = nameLabel + }; + + return nameLabel + end + + local function createTouchGestureImage(name, image, position, size, parent) + local gestureImage = utility:Create'ImageLabel' + { + Name = name, + Size = size, + Position = position, + BackgroundTransparency = 1, + Image = image, + ZIndex = 2, + Parent = parent + }; + + return gestureImage + end + + local xSizeOffset = 30 + local ySize = 25 + if smallScreen then xSizeOffset = 0 end + + local moveLabel = createTouchLabel("Move", UDim2.new(0.06,0,0.58,0), UDim2.new(0,77 + xSizeOffset,0,ySize), parentFrame) + if not smallScreen then moveLabel.Position = UDim2.new(-0.03,0,0.7,0) end + local jumpLabel = createTouchLabel("Jump", UDim2.new(0.8,0,0.58,0), UDim2.new(0,77 + xSizeOffset,0,ySize), parentFrame) + if not smallScreen then jumpLabel.Position = UDim2.new(0.85,0,0.7,0) end + local equipLabel = createTouchLabel("Equip/Unequip Tools", UDim2.new(0.5,-60,0.64,0), UDim2.new(0,120 + xSizeOffset,0,ySize), parentFrame) + if not smallScreen then equipLabel.Position = UDim2.new(0.5,-60,0.95,0) end + + local zoomLabel = createTouchLabel("Zoom In/Out", UDim2.new(0.15,-60,0.02,0), UDim2.new(0,120,0,ySize), parentFrame) + createTouchGestureImage("ZoomImage", "rbxasset://textures/ui/Settings/Help/ZoomGesture.png", UDim2.new(0.5,-26,1,3), UDim2.new(0,53,0,59), zoomLabel) + local rotateLabel = createTouchLabel("Rotate Camera", UDim2.new(0.5,-60,0.02,0), UDim2.new(0,120,0,ySize), parentFrame) + createTouchGestureImage("RotateImage", "rbxasset://textures/ui/Settings/Help/RotateCameraGesture.png", UDim2.new(0.5,-32,1,3), UDim2.new(0,65,0,48), rotateLabel) + local useToolLabel = createTouchLabel("Use Tool", UDim2.new(0.85,-60,0.02,0), UDim2.new(0,120,0,ySize), parentFrame) + createTouchGestureImage("ToolImage", "rbxasset://textures/ui/Settings/Help/UseToolGesture.png", UDim2.new(0.5,-19,1,3), UDim2.new(0,38,0,52), useToolLabel) + + end + + local function createHelpDisplay(typeOfHelp) + local helpFrame = utility:Create'Frame' + { + Size = UDim2.new(1,0,1,0), + BackgroundTransparency = 1, + Name = "HelpFrame" .. tostring(typeOfHelp) + }; + + if typeOfHelp == KEYBOARD_MOUSE_TAG then + createPCHelp(helpFrame) + elseif typeOfHelp == GAMEPAD_TAG then + createGamepadHelp(helpFrame) + elseif typeOfHelp == TOUCH_TAG then + createTouchHelp(helpFrame) + end + + return helpFrame + end + + local function displayHelp(currentPage) + for i, helpPage in pairs(this.HelpPages) do + if helpPage == currentPage then + helpPage.Parent = this.Page + this.Page.Size = helpPage.Size + else + helpPage.Parent = nil + end + end + if UserInputService:GetPlatform() == Enum.Platform.XBoxOne then + this.HubRef.PageViewClipper.ClipsDescendants = false + this.HubRef.PageView.ClipsDescendants = false + end + end + + local function switchToHelp(typeOfHelp) + local helpPage = this.HelpPages[typeOfHelp] + if helpPage then + displayHelp(helpPage) + else + this.HelpPages[typeOfHelp] = createHelpDisplay(typeOfHelp) + switchToHelp(typeOfHelp) + end + end + + local function showTypeOfHelp() + switchToHelp(this:GetCurrentInputType()) + end + + ------ TAB CUSTOMIZATION ------- + this.TabHeader.Name = "HelpTab" + + this.TabHeader.Icon.Image = "rbxasset://textures/ui/Settings/MenuBarIcons/HelpTab.png" + + if utility:IsSmallTouchScreen() then + this.TabHeader.Icon.Size = UDim2.new(0,33,0,33) + this.TabHeader.Icon.Position = UDim2.new(this.TabHeader.Icon.Position.X.Scale,this.TabHeader.Icon.Position.X.Offset,0.5,-16) + this.TabHeader.Size = UDim2.new(0,100,1,0) + elseif isTenFootInterface then + this.TabHeader.Icon.Image = "rbxasset://textures/ui/Settings/MenuBarIcons/HelpTab@2x.png" + this.TabHeader.Icon.Size = UDim2.new(0,90,0,90) + this.TabHeader.Icon.Position = UDim2.new(0,0,0.5,-43) + this.TabHeader.Size = UDim2.new(0,210,1,0) + else + this.TabHeader.Icon.Size = UDim2.new(0,44,0,44) + this.TabHeader.Icon.Position = UDim2.new(this.TabHeader.Icon.Position.X.Scale,this.TabHeader.Icon.Position.X.Offset,0.5,-22) + this.TabHeader.Size = UDim2.new(0,130,1,0) + end + + this.TabHeader.Icon.Title.Text = "Help" + + + ------ PAGE CUSTOMIZATION ------- + this.Page.Name = "Help" + + UserInputService.InputBegan:connect(function(inputObject) + local inputType = inputObject.UserInputType + if inputType ~= Enum.UserInputType.Focus and inputType ~= Enum.UserInputType.None then + lastInputType = inputObject.UserInputType + showTypeOfHelp() + end + end) + + return this +end + + +----------- Public Facing API Additions -------------- +do + PageInstance = Initialize() + + PageInstance.Displayed.Event:connect(function() + if PageInstance:GetCurrentInputType() == TOUCH_TAG then + if PageInstance.HubRef.BottomButtonFrame and not utility:IsSmallTouchScreen() then + PageInstance.HubRef.BottomButtonFrame.Visible = false + end + end + end) + + PageInstance.Hidden.Event:connect(function() + PageInstance.HubRef.PageViewClipper.ClipsDescendants = true + PageInstance.HubRef.PageView.ClipsDescendants = true + + PageInstance.HubRef:ShowShield() + + if PageInstance:GetCurrentInputType() == TOUCH_TAG then + PageInstance.HubRef.BottomButtonFrame.Visible = true + end + end) +end + + +return PageInstance \ No newline at end of file diff --git a/2016/content/Modules/Settings/Pages/LeaveGame.lua b/2016/content/Modules/Settings/Pages/LeaveGame.lua new file mode 100644 index 0000000..e79086a --- /dev/null +++ b/2016/content/Modules/Settings/Pages/LeaveGame.lua @@ -0,0 +1,124 @@ +--[[ + Filename: LeaveGame.lua + Written by: jeditkacheff + Version 1.0 + Description: Takes care of the leave game in Settings Menu +--]] + + +-------------- CONSTANTS ------------- +local LEAVE_GAME_ACTION = "LeaveGameCancelAction" + +-------------- SERVICES -------------- +local CoreGui = game:GetService("CoreGui") +local ContextActionService = game:GetService("ContextActionService") +local RobloxGui = CoreGui:WaitForChild("RobloxGui") +local GuiService = game:GetService("GuiService") + +----------- UTILITIES -------------- +local utility = require(RobloxGui.Modules.Settings.Utility) + +------------ Variables ------------------- +local PageInstance = nil +RobloxGui:WaitForChild("Modules"):WaitForChild("TenFootInterface") +local isTenFootInterface = require(RobloxGui.Modules.TenFootInterface):IsEnabled() + + +----------- CLASS DECLARATION -------------- + +local function Initialize() + local settingsPageFactory = require(RobloxGui.Modules.Settings.SettingsPageFactory) + local this = settingsPageFactory:CreateNewPage() + + this.DontLeaveFunc = function(isUsingGamepad) + if this.HubRef then + this.HubRef:PopMenu(isUsingGamepad, true) + end + end + this.DontLeaveFromHotkey = function(name, state, input) + if state == Enum.UserInputState.Begin then + local isUsingGamepad = input.UserInputType == Enum.UserInputType.Gamepad1 or input.UserInputType == Enum.UserInputType.Gamepad2 + or input.UserInputType == Enum.UserInputType.Gamepad3 or input.UserInputType == Enum.UserInputType.Gamepad4 + + this.DontLeaveFunc(isUsingGamepad) + end + end + this.DontLeaveFromButton = function(isUsingGamepad) + this.DontLeaveFunc(isUsingGamepad) + end + + ------ TAB CUSTOMIZATION ------- + this.TabHeader = nil -- no tab for this page + + ------ PAGE CUSTOMIZATION ------- + this.Page.Name = "LeaveGamePage" + + local leaveGameText = utility:Create'TextLabel' + { + Name = "LeaveGameText", + Text = "Are you sure you want to leave the game?", + Font = Enum.Font.SourceSansBold, + FontSize = Enum.FontSize.Size36, + TextColor3 = Color3.new(1,1,1), + BackgroundTransparency = 1, + Size = UDim2.new(1,0,0,200), + TextWrapped = true, + ZIndex = 2, + Parent = this.Page + }; + if utility:IsSmallTouchScreen() then + leaveGameText.FontSize = Enum.FontSize.Size24 + leaveGameText.Size = UDim2.new(1,0,0,100) + elseif isTenFootInterface then + leaveGameText.FontSize = Enum.FontSize.Size48 + end + + local buttonSpacing = 20 + local buttonSize = UDim2.new(0, 200, 0, 50) + if isTenFootInterface then + leaveGameText.Position = UDim2.new(0,0,0,100) + buttonSize = UDim2.new(0, 300, 0, 80) + end + + this.LeaveGameButton = utility:MakeStyledButton("LeaveGame", "Leave", buttonSize) + this.LeaveGameButton.NextSelectionRight = nil + this.LeaveGameButton:SetVerb("Exit") + if utility:IsSmallTouchScreen() then + this.LeaveGameButton.Position = UDim2.new(0.5, -buttonSize.X.Offset - buttonSpacing, 1, 0) + else + this.LeaveGameButton.Position = UDim2.new(0.5, -buttonSize.X.Offset - buttonSpacing, 1, -30) + end + this.LeaveGameButton.Parent = leaveGameText + + + ------------- Init ---------------------------------- + + local dontleaveGameButton = utility:MakeStyledButton("DontLeaveGame", "Don't Leave", buttonSize, this.DontLeaveFromButton) + dontleaveGameButton.NextSelectionLeft = nil + if utility:IsSmallTouchScreen() then + dontleaveGameButton.Position = UDim2.new(0.5, buttonSpacing, 1, 0) + else + dontleaveGameButton.Position = UDim2.new(0.5, buttonSpacing, 1, -30) + end + dontleaveGameButton.Parent = leaveGameText + + this.Page.Size = UDim2.new(1,0,0,dontleaveGameButton.AbsolutePosition.Y + dontleaveGameButton.AbsoluteSize.Y) + + return this +end + + +----------- Public Facing API Additions -------------- +PageInstance = Initialize() + +PageInstance.Displayed.Event:connect(function() + GuiService.SelectedCoreObject = PageInstance.LeaveGameButton + ContextActionService:BindCoreAction(LEAVE_GAME_ACTION, PageInstance.DontLeaveFromHotkey, false, Enum.KeyCode.ButtonB) +end) + +PageInstance.Hidden.Event:connect(function() + ContextActionService:UnbindCoreAction(LEAVE_GAME_ACTION) +end) + + +return PageInstance \ No newline at end of file diff --git a/2016/content/Modules/Settings/Pages/Record.lua b/2016/content/Modules/Settings/Pages/Record.lua new file mode 100644 index 0000000..7f69056 --- /dev/null +++ b/2016/content/Modules/Settings/Pages/Record.lua @@ -0,0 +1,170 @@ +--[[r + Filename: Record.lua + Written by: jeditkacheff + Version 1.0 + Description: Takes care of the Record Tab in Settings Menu +--]] +-------------- SERVICES -------------- +local CoreGui = game:GetService("CoreGui") +local RobloxGui = CoreGui:WaitForChild("RobloxGui") +local GuiService = game:GetService("GuiService") +local Settings = UserSettings() +local GameSettings = Settings.GameSettings + +----------- UTILITIES -------------- +RobloxGui:WaitForChild("Modules"):WaitForChild("TenFootInterface") +local utility = require(RobloxGui.Modules.Settings.Utility) +local isTenFootInterface = require(RobloxGui.Modules.TenFootInterface):IsEnabled() + +------------ Variables ------------------- +local PageInstance = nil + +----------- CLASS DECLARATION -------------- + +local function Initialize() + local settingsPageFactory = require(RobloxGui.Modules.Settings.SettingsPageFactory) + local this = settingsPageFactory:CreateNewPage() + local isRecordingVideo = false + + local recordingEvent = Instance.new("BindableEvent") + recordingEvent.Name = "RecordingEvent" + this.RecordingChanged = recordingEvent.Event + function this:IsRecording() + return isRecordingVideo + end + + ------ TAB CUSTOMIZATION ------- + this.TabHeader.Name = "RecordTab" + + this.TabHeader.Icon.Image = "rbxasset://textures/ui/Settings/MenuBarIcons/RecordTab.png" + this.TabHeader.Icon.Size = UDim2.new(0,41,0,40) + this.TabHeader.Icon.Position = UDim2.new(0,5,0.5,-20) + + this.TabHeader.Icon.Title.Text = "Record" + + this.TabHeader.Size = UDim2.new(0,130,1,0) + + + ------ PAGE CUSTOMIZATION ------- + this.Page.Name = "Record" + + local function makeTextLabel(name, text, bold, size, pos, parent) + local textLabel = utility:Create'TextLabel' + { + Name = name, + BackgroundTransparency = 1, + Text = text, + TextWrapped = true, + Font = Enum.Font.SourceSans, + FontSize = Enum.FontSize.Size24, + TextColor3 = Color3.new(1,1,1), + Size = size, + Position = pos, + TextXAlignment = Enum.TextXAlignment.Left, + TextYAlignment = Enum.TextYAlignment.Top, + ZIndex = 2, + Parent = parent + }; + if bold then textLabel.Font = Enum.Font.SourceSansBold end + + return textLabel + end + + -- need to override this function from SettingsPageFactory + -- DropDown menus require hub to to be set when they are initialized + function this:SetHub(newHubRef) + this.HubRef = newHubRef + + local recordEnumNames = {} + recordEnumNames[1] = "Save To Disk" + recordEnumNames[2] = "Upload to YouTube" + + local startSetting = 2 + if GameSettings.VideoUploadPromptBehavior == Enum.UploadSetting["Never"] then + startSetting = 1 + end + + ---------------------------------- SCREENSHOT ------------------------------------- + local screenshotTitle = makeTextLabel("ScreenshotTitle", + "Screenshot", + true, UDim2.new(1,0,0,36), UDim2.new(0,10,0.05,0), this.Page) + screenshotTitle.FontSize = Enum.FontSize.Size36 + + local screenshotBody = makeTextLabel("ScreenshotBody", + "By clicking the 'Take Screenshot' button, the menu will close and take a screenshot and save it to your computer.", + false, UDim2.new(1,-10,0,70), UDim2.new(0,0,1,0), screenshotTitle) + + local closeSettingsFunc = function() + this.HubRef:SetVisibility(false, true) + end + this.ScreenshotButton = utility:MakeStyledButton("ScreenshotButton", "Take Screenshot", UDim2.new(0,300,0,44), closeSettingsFunc, this) + + this.ScreenshotButton.Position = UDim2.new(0,400,1,0) + this.ScreenshotButton.Parent = screenshotBody + + + ---------------------------------- VIDEO ------------------------------------- + local videoTitle = makeTextLabel("VideoTitle", + "Video", + true, UDim2.new(1,0,0,36), UDim2.new(0,10,0.5,0), this.Page) + videoTitle.FontSize = Enum.FontSize.Size36 + + local videoBody = makeTextLabel("VideoBody", + "By clicking the 'Record Video' button, the menu will close and start recording your screen.", + false, UDim2.new(1,-10,0,70), UDim2.new(0,0,1,0), videoTitle) + + this.VideoSettingsFrame, + this.VideoSettingsLabel, + this.VideoSettingsMode = utility:AddNewRow(this, "Video Settings", "Selector", recordEnumNames, startSetting, 270) + + this.VideoSettingsMode.IndexChanged:connect(function(newIndex) + if newIndex == 1 then + GameSettings.VideoUploadPromptBehavior = Enum.UploadSetting.Never + elseif newIndex == 2 then + GameSettings.VideoUploadPromptBehavior = Enum.UploadSetting.Always + end + end) + + + local recordButton = utility:MakeStyledButton("RecordButton", "Record Video", UDim2.new(0,300,0,44), closeSettingsFunc, this) + + recordButton.Position = UDim2.new(0,410,1,10) + recordButton.Parent = this.VideoSettingsMode.SelectorFrame.Parent + recordButton.MouseButton1Click:connect(function() + recordingEvent:Fire(not isRecordingVideo) + end) + + local gameOptions = settings():FindFirstChild("Game Options") + if gameOptions then + gameOptions.VideoRecordingChangeRequest:connect(function(recording) + isRecordingVideo = recording + if recording then + recordButton.RecordButtonTextLabel.Text = "Stop Recording" + else + recordButton.RecordButtonTextLabel.Text = "Record Video" + end + end) + end + + + recordButton:SetVerb("RecordToggle") + this.ScreenshotButton:SetVerb("Screenshot") + + this.Page.Size = UDim2.new(1,0,0,400) + end + + return this +end + + +----------- Public Facing API Additions -------------- +PageInstance = Initialize() + +PageInstance.Displayed.Event:connect(function(switchedFromGamepadInput) + if switchedFromGamepadInput then + GuiService.SelectedCoreObject = PageInstance.ScreenshotButton + end +end) + + +return PageInstance \ No newline at end of file diff --git a/2016/content/Modules/Settings/Pages/ReportAbuseMenu.lua b/2016/content/Modules/Settings/Pages/ReportAbuseMenu.lua new file mode 100644 index 0000000..d8c2b43 --- /dev/null +++ b/2016/content/Modules/Settings/Pages/ReportAbuseMenu.lua @@ -0,0 +1,311 @@ +--[[ + Filename: ReportAbuseMenu.lua + Written by: jeditkacheff + Version 1.0 + Description: Takes care of the report abuse page in Settings Menu +--]] + +-------------- SERVICES -------------- +local CoreGui = game:GetService("CoreGui") +local RobloxGui = CoreGui:WaitForChild("RobloxGui") +local GuiService = game:GetService("GuiService") +local PlayersService = game:GetService("Players") + +----------- UTILITIES -------------- +local utility = require(RobloxGui.Modules.Settings.Utility) + +------------ CONSTANTS ------------------- +local ABUSE_TYPES_PLAYER = { + "Swearing", + "Inappropriate Username", + "Bullying", + "Scamming", + "Dating", + "Cheating/Exploiting", + "Personal Question", + "Offsite Links", +} + +local ABUSE_TYPES_GAME = { + "Inappropriate Content", + "Bad Model or Script", + "Offsite Link", +} +local DEFAULT_ABUSE_DESC_TEXT = " Short Description (Optional)" +if utility:IsSmallTouchScreen() then + DEFAULT_ABUSE_DESC_TEXT = " (Optional)" +end + +------------ VARIABLES ------------------- +local PageInstance = nil + +----------- CLASS DECLARATION -------------- +local function Initialize() + local settingsPageFactory = require(RobloxGui.Modules.Settings.SettingsPageFactory) + local this = settingsPageFactory:CreateNewPage() + + local playerNames = {} + local nameToRbxPlayer = {} + + function this:GetPlayerFromIndex(index) + local playerName = playerNames[index] + if playerName then + return nameToRbxPlayer[nameToRbxPlayer] + end + + return nil + end + + function this:UpdatePlayerDropDown() + playerNames = {} + nameToRbxPlayer = {} + + local players = PlayersService:GetPlayers() + local index = 1 + for i = 1, #players do + local player = players[i] + if player ~= PlayersService.LocalPlayer and player.UserId > 0 then + playerNames[index] = player.Name + nameToRbxPlayer[player.Name] = player + index = index + 1 + end + end + + this.WhichPlayerMode:UpdateDropDownList(playerNames) + + if index == 1 then + this.GameOrPlayerMode:SetSelectionIndex(1) + this.TypeOfAbuseMode:UpdateDropDownList(ABUSE_TYPES_GAME) + end + + this.WhichPlayerMode:SetInteractable(index > 1 and this.GameOrPlayerMode.CurrentIndex ~= 1) + this.GameOrPlayerMode:SetInteractable(index > 1) + end + + ------ TAB CUSTOMIZATION ------- + this.TabHeader.Name = "ReportAbuseTab" + + this.TabHeader.Icon.Image = "rbxasset://textures/ui/Settings/MenuBarIcons/ReportAbuseTab.png" + if utility:IsSmallTouchScreen() then + this.TabHeader.Icon.Size = UDim2.new(0,27,0,32) + this.TabHeader.Size = UDim2.new(0,120,1,0) + else + this.TabHeader.Size = UDim2.new(0,150,1,0) + this.TabHeader.Icon.Size = UDim2.new(0,36,0,43) + end + this.TabHeader.Icon.Position = UDim2.new(this.TabHeader.Icon.Position.X.Scale, this.TabHeader.Icon.Position.X.Offset + 10, 0.5,-this.TabHeader.Icon.Size.Y.Offset/2) + + this.TabHeader.Icon.Title.Text = "Report" + + ------ PAGE CUSTOMIZATION ------- + this.Page.Name = "ReportAbusePage" + + -- need to override this function from SettingsPageFactory + -- DropDown menus require hub to to be set when they are initialized + function this:SetHub(newHubRef) + this.HubRef = newHubRef + + if utility:IsSmallTouchScreen() then + this.GameOrPlayerFrame, + this.GameOrPlayerLabel, + this.GameOrPlayerMode = utility:AddNewRow(this, "Game or Player?", "Selector", {"Game", "Player"}, 1) + else + this.GameOrPlayerFrame, + this.GameOrPlayerLabel, + this.GameOrPlayerMode = utility:AddNewRow(this, "Game or Player?", "Selector", {"Game", "Player"}, 1, 3) + end + + this.WhichPlayerFrame, + this.WhichPlayerLabel, + this.WhichPlayerMode = utility:AddNewRow(this, "Which Player?", "DropDown", {"update me"}) + this.WhichPlayerMode:SetInteractable(false) + this.WhichPlayerLabel.ZIndex = 1 + + this.TypeOfAbuseFrame, + this.TypeOfAbuseLabel, + this.TypeOfAbuseMode = utility:AddNewRow(this, "Type Of Abuse", "DropDown", ABUSE_TYPES_GAME) + + if utility:IsSmallTouchScreen() then + this.AbuseDescriptionFrame, + this.AbuseDescriptionLabel, + this.AbuseDescription = utility:AddNewRow(this, DEFAULT_ABUSE_DESC_TEXT, "TextBox", nil, nil) + else + this.AbuseDescriptionFrame, + this.AbuseDescriptionLabel, + this.AbuseDescription = utility:AddNewRow(this, DEFAULT_ABUSE_DESC_TEXT, "TextBox", nil, nil, 5) + end + + if utility:IsSmallTouchScreen() then + this.AbuseDescription.Selection.Size = UDim2.new(0, 290, 0, 30) + this.AbuseDescription.Selection.Position = UDim2.new(1,-345,this.AbuseDescription.Selection.Position.Y.Scale, this.AbuseDescription.Selection.Position.Y.Offset) + + this.AbuseDescriptionLabel = this.TypeOfAbuseLabel:clone() + this.AbuseDescriptionLabel.Text = "Abuse Description" + this.AbuseDescriptionLabel.Position = UDim2.new(this.AbuseDescriptionLabel.Position.X.Scale, this.AbuseDescriptionLabel.Position.X.Offset, + 0,50) + this.AbuseDescriptionLabel.Parent = this.Page + end + + local SelectionOverrideObject = utility:Create'ImageLabel' + { + Image = "", + BackgroundTransparency = 1 + }; + + local submitButton, submitText = nil, nil + + local function makeSubmitButtonActive() + submitButton.ZIndex = 2 + submitButton.Selectable = true + submitText.ZIndex = 2 + end + + local function makeSubmitButtonInactive() + submitButton.ZIndex = 1 + submitButton.Selectable = false + submitText.ZIndex = 1 + end + + local function updateAbuseDropDown() + this.WhichPlayerMode:ResetSelectionIndex() + this.TypeOfAbuseMode:ResetSelectionIndex() + + if this.GameOrPlayerMode.CurrentIndex == 1 then + this.TypeOfAbuseMode:UpdateDropDownList(ABUSE_TYPES_GAME) + this.WhichPlayerMode:SetInteractable(false) + this.WhichPlayerLabel.ZIndex = 1 + this.GameOrPlayerMode.SelectorFrame.NextSelectionDown = this.TypeOfAbuseMode.DropDownFrame + else + this.TypeOfAbuseMode:UpdateDropDownList(ABUSE_TYPES_PLAYER) + this.WhichPlayerMode:SetInteractable(true) + this.WhichPlayerLabel.ZIndex = 2 + this.GameOrPlayerMode.SelectorFrame.NextSelectionDown = this.WhichPlayerMode.DropDownFrame + end + makeSubmitButtonInactive() + end + + local function cleanupReportAbuseMenu() + updateAbuseDropDown() + this.AbuseDescription.Selection.Text = DEFAULT_ABUSE_DESC_TEXT + this.HubRef:SetVisibility(false, true) + end + + local function onReportSubmitted() + local abuseReason = nil + if this.GameOrPlayerMode.CurrentIndex == 2 then + abuseReason = ABUSE_TYPES_PLAYER[this.TypeOfAbuseMode.CurrentIndex] + + local currentAbusingPlayer = this:GetPlayerFromIndex(this.WhichPlayerMode.CurrentIndex) + if currentAbusingPlayer and abuseReason then + spawn(function() + game.Players:ReportAbuse(currentAbusingPlayer, abuseReason, this.AbuseDescription.Selection.Text) + end) + end + else + abuseReason = ABUSE_TYPES_GAME[this.TypeOfAbuseMode.CurrentIndex] + if abuseReason then + spawn(function() + game.Players:ReportAbuse(nil, abuseReason, this.AbuseDescription.Selection.Text) + end) + end + end + + if abuseReason then + local alertText = "Thanks for your report! Our moderators will review the chat logs and evaluate what happened." + + if abuseReason == 'Cheating/Exploiting' then + alertText = "Thanks for your report! We've recorded your report for evaluation." + elseif abuseReason == 'Inappropriate Username' then + alertText = "Thanks for your report! Our moderators will evaluate the username." + elseif abuseReason == "Bad Model or Script" or abuseReason == "Inappropriate Content" or abuseReason == "Offsite Link" or abuseReason == "Offsite Links" then + alertText = "Thanks for your report! Our moderators will review the place and make a determination." + end + + utility:ShowAlert(alertText, "Ok", this.HubRef, cleanupReportAbuseMenu) + + this.LastSelectedObject = nil + end + end + + submitButton, submitText = utility:MakeStyledButton("SubmitButton", "Submit", UDim2.new(0,198,0,50), onReportSubmitted, this) + if utility:IsSmallTouchScreen() then + submitButton.Position = UDim2.new(1,-220,1,5) + else + submitButton.Position = UDim2.new(1,-194,1,5) + end + submitButton.Selectable = false + submitButton.ZIndex = 1 + submitText.ZIndex = 1 + submitButton.Parent = this.AbuseDescription.Selection + + local function playerSelectionChanged(newIndex) + if newIndex ~= nil and this.TypeOfAbuseMode:GetSelectedIndex() ~= nil then + makeSubmitButtonActive() + else + makeSubmitButtonInactive() + end + end + this.WhichPlayerMode.IndexChanged:connect(playerSelectionChanged) + + local function typeOfAbuseChanged(newIndex) + if newIndex ~= nil then + if this.GameOrPlayerMode.CurrentIndex == 1 or this.WhichPlayerMode:GetSelectedIndex() ~= nil then + makeSubmitButtonActive() + else + makeSubmitButtonInactive() + end + else + makeSubmitButtonInactive() + end + end + this.TypeOfAbuseMode.IndexChanged:connect(typeOfAbuseChanged) + + this.GameOrPlayerMode.IndexChanged:connect(updateAbuseDropDown) + + this:AddRow(nil, nil, this.AbuseDescription) + + this.Page.Size = UDim2.new(1,0,0,submitButton.AbsolutePosition.Y + submitButton.AbsoluteSize.Y) + end + + return this +end + + +----------- Public Facing API Additions -------------- +do + PageInstance = Initialize() + + PageInstance.Displayed.Event:connect(function() + PageInstance:UpdatePlayerDropDown() + end) + + function PageInstance:ReportPlayer(player) + if player then + local setReportPlayerConnection = nil + setReportPlayerConnection = PageInstance.Displayed.Event:connect(function() + -- When we change the SelectionIndex of GameOrPlayerMode it waits until the tween is done + -- before it fires the IndexChanged signal. The WhichPlayerMode dropdown listens to this signal + -- and resets when it is fired. Therefore we need to listen to this signal and set the player we want + -- to report the frame after the dropdown is reset + local indexChangedConnection = nil + indexChangedConnection = PageInstance.GameOrPlayerMode.IndexChanged:connect(function() + if indexChangedConnection then + indexChangedConnection:disconnect() + indexChangedConnection = nil + end + PageInstance.WhichPlayerMode:SetSelectionByValue(player.Name) + end) + PageInstance.GameOrPlayerMode:SetSelectionIndex(2) + + if setReportPlayerConnection then + setReportPlayerConnection:disconnect() + setReportPlayerConnection = nil + end + end) + PageInstance.HubRef:SetVisibility(true, false, PageInstance) + end + end +end + + +return PageInstance diff --git a/2016/content/Modules/Settings/SettingsHub.lua b/2016/content/Modules/Settings/SettingsHub.lua new file mode 100644 index 0000000..5e3b108 --- /dev/null +++ b/2016/content/Modules/Settings/SettingsHub.lua @@ -0,0 +1,1122 @@ +--[[ + Filename: SettingsHub.lua + Written by: jeditkacheff + Version 1.0 + Description: Controls the settings menu navigation and contains the settings pages +--]] + +--[[ CONSTANTS ]] +local SETTINGS_SHIELD_COLOR = Color3.new(41/255,41/255,41/255) +local SETTINGS_SHIELD_TRANSPARENCY = 0.2 +local SETTINGS_SHIELD_VR_TRANSPARENCY = 1 +local SETTINGS_SHIELD_SIZE = UDim2.new(1, 0, 1, 0) +local SETTINGS_SHIELD_INACTIVE_POSITION = UDim2.new(0,0,-1,-36) +local SETTINGS_SHIELD_ACTIVE_POSITION = UDim2.new(0, 0, 0, 0) +local SETTINGS_BASE_ZINDEX = 2 +local DEV_CONSOLE_ACTION_NAME = "Open Dev Console" + +--[[ SERVICES ]] +local CoreGui = game:GetService("CoreGui") +local RobloxGui = CoreGui:WaitForChild("RobloxGui") +local ContextActionService = game:GetService("ContextActionService") +local GuiService = game:GetService("GuiService") +local UserInputService = game:GetService("UserInputService") +local RunService = game:GetService("RunService") + +--[[ UTILITIES ]] +local utility = require(RobloxGui.Modules.Settings.Utility) + +--[[ VARIABLES ]] +local isTouchDevice = UserInputService.TouchEnabled +local isSmallTouchScreen = utility:IsSmallTouchScreen() +RobloxGui:WaitForChild("Modules"):WaitForChild("TenFootInterface") +local isTenFootInterface = require(RobloxGui.Modules.TenFootInterface):IsEnabled() +local platform = UserInputService:GetPlatform() +-- TODO: Change dev console script to parent this to somewhere other than an engine created gui +local ControlFrame = RobloxGui:WaitForChild('ControlFrame') +local ToggleDevConsoleBindableFunc = ControlFrame:WaitForChild('ToggleDevConsole') +local lastInputChangedCon = nil +local chatWasVisible = false +local userlistSuccess, userlistFlagValue = pcall(function() return settings():GetFFlag("UseUserListMenu") end) +local useUserList = (userlistSuccess and userlistFlagValue == true) + +local VREnabled = false + +local function IsPlayMyPlaceEnabled() + if UserInputService:GetPlatform() == Enum.Platform.XBoxOne then + local playMyPlaceSuccess, playMyPlaceFlagValue = pcall(function() return settings():GetFFlag("XboxPlayMyPlace") end) + return (playMyPlaceSuccess and playMyPlaceFlagValue == true) + end + return false +end + + +--[[ CORE MODULES ]] +local chat = require(RobloxGui.Modules.Chat) + +if isSmallTouchScreen or isTenFootInterface then + SETTINGS_SHIELD_ACTIVE_POSITION = UDim2.new(0,0,0,0) + SETTINGS_SHIELD_SIZE = UDim2.new(1,0,1,0) +end + +local function CreateSettingsHub() + local this = {} + this.Visible = false + this.Active = false + this.Pages = {CurrentPage = nil, PageTable = {}} + this.MenuStack = {} + this.TabHeaders = {} + this.BottomBarButtons = {} + this.TabConnection = nil + this.LeaveGamePage = require(RobloxGui.Modules.Settings.Pages.LeaveGame) + this.ResetCharacterPage = require(RobloxGui.Modules.Settings.Pages.ResetCharacter) + this.SettingsShowSignal = utility:CreateSignal() + this.OpenStateChangedCount = 0 + + local pageChangeCon = nil + + local PoppedMenuEvent = Instance.new("BindableEvent") + PoppedMenuEvent.Name = "PoppedMenu" + this.PoppedMenu = PoppedMenuEvent.Event + + local function setBottomBarBindings() + for i = 1, #this.BottomBarButtons do + local buttonTable = this.BottomBarButtons[i] + local buttonName = buttonTable[1] + local hotKeyTable = buttonTable[2] + ContextActionService:BindCoreAction(buttonName, hotKeyTable[1], false, unpack(hotKeyTable[2])) + end + + if this.BottomButtonFrame then + this.BottomButtonFrame.Visible = true + end + end + + local function removeBottomBarBindings(delayBeforeRemoving) + for _, hotKeyTable in pairs(this.BottomBarButtons) do + ContextActionService:UnbindCoreAction(hotKeyTable[1]) + end + + local myOpenStateChangedCount = this.OpenStateChangedCount + local remove = function() + if this.OpenStateChangedCount == myOpenStateChangedCount and this.BottomButtonFrame then + this.BottomButtonFrame.Visible = false + end + end + + if delayBeforeRemoving then + delay(delayBeforeRemoving, remove) + else + remove() + end + end + + local function addBottomBarButton(name, text, gamepadImage, keyboardImage, position, clickFunc, hotkeys) + local buttonName = name .. "Button" + local textName = name .. "Text" + + local size = UDim2.new(0,260,0,70) + if isTenFootInterface then + size = UDim2.new(0,320,0,120) + end + + this[buttonName], this[textName] = utility:MakeStyledButton(name .. "Button", text, size, clickFunc, nil, this) + this[buttonName].Position = position + this[buttonName].Parent = this.BottomButtonFrame + if isTenFootInterface then + this[buttonName].ImageTransparency = 1 + end + + this[textName].FontSize = Enum.FontSize.Size24 + local hintLabel = nil + + if not isTouchDevice then + this[textName].Size = UDim2.new(1,0,1,0) + if isTenFootInterface then + this[textName].Position = UDim2.new(0,60,0,-4) + else + this[textName].Position = UDim2.new(0,10,0,-4) + end + + local hintNameText = name .. "HintText" + local hintName = name .. "Hint" + local image = "" + if UserInputService:GetGamepadConnected(Enum.UserInputType.Gamepad1) or platform == Enum.Platform.XBoxOne then + image = gamepadImage + else + image = keyboardImage + end + + hintLabel = utility:Create'ImageLabel' + { + Name = hintName, + Size = UDim2.new(0,60,0,60), + Position = UDim2.new(0,10,0,5), + ZIndex = this.Shield.ZIndex + 2, + BackgroundTransparency = 1, + Image = image, + Parent = this[buttonName] + }; + if isTenFootInterface then + hintLabel.Size = UDim2.new(0,90,0,90) + hintLabel.Position = UDim2.new(0,10,0.5,-45) + elseif UserInputService.MouseEnabled then + hintLabel.Image = keyboardImage + hintLabel.Size = UDim2.new(0,48,0,48) + hintLabel.Position = UDim2.new(0,10,0,8) + end + end + + if isTenFootInterface then + this[textName].FontSize = Enum.FontSize.Size36 + end + + UserInputService.InputBegan:connect(function(inputObject) + if inputObject.UserInputType == Enum.UserInputType.Gamepad1 or inputObject.UserInputType == Enum.UserInputType.Gamepad2 or + inputObject.UserInputType == Enum.UserInputType.Gamepad3 or inputObject.UserInputType == Enum.UserInputType.Gamepad4 then + if hintLabel then + hintLabel.Image = gamepadImage + if isTenFootInterface then + hintLabel.Size = UDim2.new(0,90,0,90) + hintLabel.Position = UDim2.new(0,10,0.5,-45) + else + hintLabel.Size = UDim2.new(0,60,0,60) + hintLabel.Position = UDim2.new(0,10,0,5) + end + end + elseif inputObject.UserInputType == Enum.UserInputType.Keyboard then + if hintLabel then + hintLabel.Image = keyboardImage + hintLabel.Size = UDim2.new(0,48,0,48) + hintLabel.Position = UDim2.new(0,10,0,8) + end + end + end) + + local hotKeyFunc = function(contextName, inputState, inputObject) + if inputState == Enum.UserInputState.Begin then + clickFunc() + end + end + + local hotKeyTable = {hotKeyFunc, hotkeys} + this.BottomBarButtons[#this.BottomBarButtons + 1] = {buttonName, hotKeyTable} + end + + local function createGui() + local PageViewSizeReducer = 0 + if isSmallTouchScreen then + PageViewSizeReducer = 5 + end + + this.ClippingShield = utility:Create'Frame' + { + Name = "SettingsShield", + Size = SETTINGS_SHIELD_SIZE, + Position = SETTINGS_SHIELD_ACTIVE_POSITION, + BorderSizePixel = 0, + ClipsDescendants = true, + BackgroundTransparency = 1, + Visible = true, + ZIndex = SETTINGS_BASE_ZINDEX, + Parent = RobloxGui + }; + + this.Shield = utility:Create'Frame' + { + Name = "SettingsShield", + Size = UDim2.new(1,0,1,0), + Position = SETTINGS_SHIELD_INACTIVE_POSITION, + BackgroundTransparency = SETTINGS_SHIELD_TRANSPARENCY, + BackgroundColor3 = SETTINGS_SHIELD_COLOR, + BorderSizePixel = 0, + Visible = false, + Active = true, + ZIndex = SETTINGS_BASE_ZINDEX, + Parent = this.ClippingShield + }; + + this.Modal = utility:Create'TextButton' -- Force unlocks the mouse, really need a way to do this via UIS + { + Name = 'Modal', + BackgroundTransparency = 1, + Position = UDim2.new(0, 0, 1, -1), + Size = UDim2.new(1, 0, 1, 0), + Modal = true, + Text = '', + Parent = this.Shield, + Selectable = false + } + + this.HubBar = utility:Create'ImageLabel' + { + Name = "HubBar", + ZIndex = this.Shield.ZIndex + 1, + BorderSizePixel = 0, + BackgroundColor3 = Color3.new(78/255, 84/255, 96/255), + BackgroundTransparency = 1, + Image = "rbxasset://textures/ui/Settings/MenuBarAssets/MenuBackground.png", + ScaleType = Enum.ScaleType.Slice, + SliceCenter = Rect.new(4,4,6,6), + Parent = this.Shield + }; + + local barHeight = 60 + if isSmallTouchScreen then + barHeight = 40 + this.HubBar.Size = UDim2.new(1,-10,0,40) + this.HubBar.Position = UDim2.new(0,5,0,6) + elseif isTenFootInterface then + barHeight = 100 + this.HubBar.Size = UDim2.new(0,1200,0,100) + this.HubBar.Position = UDim2.new(0.5,-600,0.1,0) + else + this.HubBar.Size = UDim2.new(0,800,0,60) + this.HubBar.Position = UDim2.new(0.5,-400,0.1,0) + end + + this.PageViewClipper = utility:Create'Frame' + { + Name = 'PageViewClipper', + BackgroundTransparency = 1, + Size = UDim2.new(this.HubBar.Size.X.Scale,this.HubBar.Size.X.Offset, + 1, -this.HubBar.Size.Y.Offset - this.HubBar.Position.Y.Offset - PageViewSizeReducer), + Position = UDim2.new(this.HubBar.Position.X.Scale, this.HubBar.Position.X.Offset, + this.HubBar.Position.Y.Scale, this.HubBar.Position.Y.Offset + this.HubBar.Size.Y.Offset + 1), + ClipsDescendants = true, + Parent = this.Shield, + + utility:Create'ImageButton'{ + Name = 'InputCapture', + BackgroundTransparency = 1, + Size = UDim2.new(1, 0, 1, 0), + Image = '' + } + } + + this.PageView = utility:Create'ScrollingFrame' + { + Name = "PageView", + Size = UDim2.new(1, 0, 1, 0), + ZIndex = this.Shield.ZIndex, + BackgroundTransparency = 1, + BorderSizePixel = 0, + Selectable = false, + Parent = this.PageViewClipper, + }; + if UserInputService.MouseEnabled then + this.PageViewClipper.Size = UDim2.new(this.HubBar.Size.X.Scale,this.HubBar.Size.X.Offset, + 0.5, -(this.HubBar.Position.Y.Offset - this.HubBar.Size.Y.Offset)) + end + + if isSmallTouchScreen then + this.PageView.CanvasSize = this.PageViewClipper.Size + else + local bottomOffset = 0 + if isTouchDevice and not UserInputService.MouseEnabled then + bottomOffset = 80 + end + this.BottomButtonFrame = utility:Create'Frame' + { + Name = "BottomButtonFrame", + Size = this.HubBar.Size, + Position = UDim2.new(0.5, -this.HubBar.Size.X.Offset/2, 1-this.HubBar.Position.Y.Scale-this.HubBar.Size.Y.Scale, -this.HubBar.Position.Y.Offset-this.HubBar.Size.Y.Offset), + ZIndex = this.Shield.ZIndex + 1, + BackgroundTransparency = 1, + Parent = this.Shield + }; + + local leaveGameFunc = function() + this:AddToMenuStack(this.Pages.CurrentPage) + this.HubBar.Visible = false + removeBottomBarBindings() + this:SwitchToPage(this.LeaveGamePage, nil, 1, true) + end + + local resetCharFunc = function() + this:AddToMenuStack(this.Pages.CurrentPage) + this.HubBar.Visible = false + removeBottomBarBindings() + this:SwitchToPage(this.ResetCharacterPage, nil, 1, true) + end + + -- Xbox Only + local inviteToGameFunc = function() + local platformService = game:GetService('PlatformService') + if platformService then + platformService:PopupGameInviteUI() + end + end + + local resumeFunc = function() + setVisibilityInternal(false) + end + + local buttonImageAppend = "" + + if isTenFootInterface then + buttonImageAppend = "@2x" + end + + if UserInputService:GetPlatform() == Enum.Platform.XBoxOne then + local function createInviteButton() + addBottomBarButton("InviteToGame", "Send Game Invites", "rbxasset://textures/ui/Settings/Help/XButtonLight" .. buttonImageAppend .. ".png", + "", UDim2.new(0.5,isTenFootInterface and -160 or -130,0.5,-25), + inviteToGameFunc, {Enum.KeyCode.ButtonX}) + end + + if IsPlayMyPlaceEnabled() then + spawn(function() + local PlatformService = nil + pcall(function() PlatformService = game:GetService('PlatformService') end) + local pmpCreatorId = PlatformService and PlatformService:BeginGetPMPCreatorId() + if pmpCreatorId == 0 then + createInviteButton() + end + end) + else + createInviteButton() + end + else + addBottomBarButton("LeaveGame", "Leave Game", "rbxasset://textures/ui/Settings/Help/XButtonLight" .. buttonImageAppend .. ".png", + "rbxasset://textures/ui/Settings/Help/LeaveIcon.png", UDim2.new(0.5,isTenFootInterface and -160 or -130,0.5,-25), + leaveGameFunc, {Enum.KeyCode.L, Enum.KeyCode.ButtonX}) + end + + addBottomBarButton("ResetCharacter", " Reset Character", "rbxasset://textures/ui/Settings/Help/YButtonLight" .. buttonImageAppend .. ".png", + "rbxasset://textures/ui/Settings/Help/ResetIcon.png", UDim2.new(0.5,isTenFootInterface and -550 or -400,0.5,-25), + resetCharFunc, {Enum.KeyCode.R, Enum.KeyCode.ButtonY}) + addBottomBarButton("Resume", "Resume Game", "rbxasset://textures/ui/Settings/Help/BButtonLight" .. buttonImageAppend .. ".png", + "rbxasset://textures/ui/Settings/Help/EscapeIcon.png", UDim2.new(0.5,isTenFootInterface and 200 or 140,0.5,-25), + resumeFunc, {Enum.KeyCode.ButtonB, Enum.KeyCode.ButtonStart}) + end + + local function onScreenSizeChanged() + local largestPageSize = 600 + local fullScreenSize = RobloxGui.AbsoluteSize.y + local bufferSize = (1-0.95) * fullScreenSize + if isTenFootInterface then + largestPageSize = 800 + bufferSize = 0.07 * fullScreenSize + elseif isSmallTouchScreen then + bufferSize = (1-0.99) * fullScreenSize + end + local barSize = this.HubBar.Size.Y.Offset + local extraSpace = bufferSize*2+barSize*2 + + + local usableScreenHeight = fullScreenSize - extraSpace + local minimumPageSize = 150 + local usePageSize = nil + + if largestPageSize < usableScreenHeight then + usePageSize = largestPageSize + this.HubBar.Position = UDim2.new( + this.HubBar.Position.X.Scale, + this.HubBar.Position.X.Offset, + 0.5, + -largestPageSize/2 - this.HubBar.Size.Y.Offset + ) + if this.BottomButtonFrame then + this.BottomButtonFrame.Position = UDim2.new( + this.BottomButtonFrame.Position.X.Scale, + this.BottomButtonFrame.Position.X.Offset, + 0.5, + largestPageSize/2 + ) + end + elseif usableScreenHeight < minimumPageSize then + usePageSize = minimumPageSize + this.HubBar.Position = UDim2.new( + this.HubBar.Position.X.Scale, + this.HubBar.Position.X.Offset, + 0.5, + -minimumPageSize/2 - this.HubBar.Size.Y.Offset + ) + if this.BottomButtonFrame then + this.BottomButtonFrame.Position = UDim2.new( + this.BottomButtonFrame.Position.X.Scale, + this.BottomButtonFrame.Position.X.Offset, + 0.5, + minimumPageSize/2 + ) + end + else + usePageSize = usableScreenHeight + this.HubBar.Position = UDim2.new( + this.HubBar.Position.X.Scale, + this.HubBar.Position.X.Offset, + 0, + bufferSize + ) + if this.BottomButtonFrame then + this.BottomButtonFrame.Position = UDim2.new( + this.BottomButtonFrame.Position.X.Scale, + this.BottomButtonFrame.Position.X.Offset, + 1, + -(bufferSize + barSize) + ) + end + end + + if useUserList and not isTenFootInterface then + if isSmallTouchScreen then + this.PageViewClipper.Size = UDim2.new( + this.PageViewClipper.Size.X.Scale, + this.PageViewClipper.Size.X.Offset, + 0, + usePageSize + 44 + ) + else + this.PageViewClipper.Size = UDim2.new( + this.PageViewClipper.Size.X.Scale, + this.PageViewClipper.Size.X.Offset, + 0, + usePageSize + ) + end + else + this.PageViewClipper.Size = UDim2.new( + this.PageViewClipper.Size.X.Scale, + this.PageViewClipper.Size.X.Offset, + 0, + usePageSize + ) + end + this.PageViewClipper.Position = UDim2.new( + this.PageViewClipper.Position.X.Scale, + this.PageViewClipper.Position.X.Offset, + 0.5, + -usePageSize/2 + ) + end + -- TODO: disconnect this event? + RobloxGui.Changed:connect(function(prop) + if prop == "AbsoluteSize" then + onScreenSizeChanged() + end + end) + onScreenSizeChanged() + end + + local function toggleDevConsole(actionName, inputState, inputObject) + if actionName == DEV_CONSOLE_ACTION_NAME then -- ContextActionService->F9 + if inputState and inputState == Enum.UserInputState.Begin and ToggleDevConsoleBindableFunc then + ToggleDevConsoleBindableFunc:Invoke() + end + end + end + + local lastInputUsedToSelectGui = isTenFootInterface + UserInputService.InputBegan:connect(function(input) + if input.UserInputType == Enum.UserInputType.Gamepad1 or input.UserInputType == Enum.UserInputType.Gamepad2 or input.UserInputType == Enum.UserInputType.Gamepad3 or input.UserInputType == Enum.UserInputType.Gamepad4 + or input.KeyCode == Enum.KeyCode.Left or input.KeyCode == Enum.KeyCode.Right or input.KeyCode == Enum.KeyCode.Up or input.KeyCode == Enum.KeyCode.Down or input.KeyCode == Enum.KeyCode.Tab then + lastInputUsedToSelectGui = true + elseif input.UserInputType == Enum.UserInputType.Touch or input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.MouseButton2 then + lastInputUsedToSelectGui = false + end + end) + UserInputService.InputChanged:connect(function(input) + if input.KeyCode == Enum.KeyCode.Thumbstick1 or input.KeyCode == Enum.KeyCode.Thumbstick2 then + if input.Position.magnitude >= 0.25 then + lastInputUsedToSelectGui = true + end + elseif input.UserInputType == Enum.UserInputType.Touch or input.UserInputType == Enum.UserInputType.MouseMovement then + lastInputUsedToSelectGui = false + end + end) + + + local switchTab = function(direction, cycle) + local currentTabPosition = GetHeaderPosition(this.Pages.CurrentPage) + if currentTabPosition < 0 then return end + + local newTabPosition = currentTabPosition + direction + if cycle then + if newTabPosition > #this.TabHeaders then + newTabPosition = 1 + elseif newTabPosition < 1 then + newTabPosition = #this.TabHeaders + end + end + local newHeader = this.TabHeaders[newTabPosition] + + if newHeader then + for pager,v in pairs(this.Pages.PageTable) do + if pager:GetTabHeader() == newHeader then + this:SwitchToPage(pager, true, direction) + break + end + end + end + end + + local switchTabFromBumpers = function(actionName, inputState, inputObject) + if inputState ~= Enum.UserInputState.Begin then return end + + local direction = 0 + if inputObject.KeyCode == Enum.KeyCode.ButtonR1 then + direction = 1 + elseif inputObject.KeyCode == Enum.KeyCode.ButtonL1 then + direction = -1 + end + + switchTab(direction, true, true) + end + + local switchTabFromKeyboard = function(input) + if input.KeyCode == Enum.KeyCode.Tab then + local direction = 0 + if UserInputService:IsKeyDown(Enum.KeyCode.LeftShift) or UserInputService:IsKeyDown(Enum.KeyCode.RightShift) then + direction = -1 + else + direction = 1 + end + + switchTab(direction, true, true) + end + end + + local scrollHotkeyFunc = function(actionName, inputState, inputObject) + if inputState ~= Enum.UserInputState.Begin then return end + + local direction = 0 + if inputObject.KeyCode == Enum.KeyCode.PageUp then + direction = -100 + elseif inputObject.KeyCode == Enum.KeyCode.PageDown then + direction = 100 + end + + this:ScrollPixels(direction) + end + + -- need some stuff for functions below so init here + createGui() + + function GetHeaderPosition(page) + local header = page:GetTabHeader() + if not header then return -1 end + + for i,v in pairs(this.TabHeaders) do + if v == header then + return i + end + end + + return -1 + end + + local setZIndex = nil + setZIndex = function(newZIndex, object) + if object:IsA("GuiObject") then + object.ZIndex = newZIndex + local children = object:GetChildren() + for i = 1, #children do + setZIndex(newZIndex, children[i]) + end + end + end + + local function AddHeader(newHeader, headerPage) + if not newHeader then return end + + this.TabHeaders[#this.TabHeaders + 1] = newHeader + headerPage.TabPosition = #this.TabHeaders + + local sizeOfTab = 1/#this.TabHeaders + for i = 1, #this.TabHeaders do + local tabMaxPos = (sizeOfTab * i) + local tabMinPos = (sizeOfTab * (i - 1)) + local pos = ((tabMaxPos - tabMinPos)/2) + tabMinPos + + local tab = this.TabHeaders[i] + tab.Position = UDim2.new(pos,-tab.Size.X.Offset/2,0,0) + end + + setZIndex(SETTINGS_BASE_ZINDEX + 1, newHeader) + newHeader.Parent = this.HubBar + end + + local function RemoveHeader(oldHeader) + local removedPos = nil + + for i = 1, #this.TabHeaders do + if this.TabHeaders[i] == oldHeader then + removedPos = i + table.remove(this.TabHeaders, i) + break + end + end + + if removedPos then + for i = removedPos, #this.TabHeaders do + local currentTab = this.TabHeaders[i] + currentTab.Position = UDim2.new(currentTab.Position.X.Scale, currentTab.Position.X.Offset - oldHeader.AbsoluteSize.X, + currentTab.Position.Y.Scale, currentTab.Position.Y.Offset) + end + end + + oldHeader.Parent = nil + end + + -- Page APIs + function this:AddPage(pageToAdd) + this.Pages.PageTable[pageToAdd] = true + AddHeader(pageToAdd:GetTabHeader(), pageToAdd) + pageToAdd.Page.Position = UDim2.new(pageToAdd.TabPosition - 1,0,0,0) + end + + function this:RemovePage(pageToRemove) + this.Pages.PageTable[pageToRemove] = nil + RemoveHeader(pageToRemove:GetTabHeader()) + end + + function this:HideBar() + this.HubBar.Visible = false + this.PageViewClipper.Visible = false + if this.BottomButtonFrame then + removeBottomBarBindings() + end + end + + function this:ShowBar() + this.HubBar.Visible = true + this.PageViewClipper.Visible = true + if this.BottomButtonFrame then + setBottomBarBindings() + end + end + + function this:ScrollPixels(pixels) + -- Only Y + local oldY = this.PageView.CanvasPosition.Y + local maxY = this.PageView.CanvasSize.Y.Offset - this.PageViewClipper.AbsoluteSize.y + local newY = math.max(0, math.min(oldY+pixels, maxY)) -- i.e. clamp + this.PageView.CanvasPosition = Vector2.new(0, newY) + end + + function this:ScrollToFrame(frame, forced) + if lastInputUsedToSelectGui or forced then + local ay = frame.AbsolutePosition.y - this.Pages.CurrentPage.Page.AbsolutePosition.y + local by = ay + frame.AbsoluteSize.y + + if ay < this.PageView.CanvasPosition.y then -- Scroll up to fit top + this.PageView.CanvasPosition = Vector2.new(0, ay) + elseif by - this.PageView.CanvasPosition.y > this.PageViewClipper.Size.Y.Offset then -- Scroll down to fit bottom + this.PageView.CanvasPosition = Vector2.new(0, by - this.PageViewClipper.Size.Y.Offset) + end + end + end + + function this:SwitchToPage(pageToSwitchTo, ignoreStack, direction, skipAnimation) + if this.Pages.PageTable[pageToSwitchTo] == nil then return end + + -- detect direction + if direction == nil then + if this.Pages.CurrentPage and this.Pages.CurrentPage.TabHeader and pageToSwitchTo and pageToSwitchTo.TabHeader then + direction = this.Pages.CurrentPage.TabHeader.AbsolutePosition.x < pageToSwitchTo.TabHeader.AbsolutePosition.x and 1 or -1 + end + end + if direction == nil then + direction = 1 + end + + -- if we have a page we need to let it know to go away + if this.Pages.CurrentPage then + pageChangeCon:disconnect() + this.Pages.CurrentPage.Active = false + end + + -- make sure all pages are in right position + local newPagePos = pageToSwitchTo.TabPosition + for page, _ in pairs(this.Pages.PageTable) do + if page ~= pageToSwitchTo then + page:Hide(-direction, newPagePos, skipAnimation) + end + end + + if this.BottomButtonFrame then + this.BottomButtonFrame.Visible = (pageToSwitchTo ~= this.ResetCharacterPage and pageToSwitchTo ~= this.LeaveGamePage) + this.HubBar.Visible = this.BottomButtonFrame.Visible + end + + -- make sure page is visible + this.Pages.CurrentPage = pageToSwitchTo + this.Pages.CurrentPage:Display(this.PageView, skipAnimation) + this.Pages.CurrentPage.Active = true + + local pageSize = this.Pages.CurrentPage:GetSize() + this.PageView.CanvasSize = UDim2.new(0,pageSize.X,0,pageSize.Y) + + pageChangeCon = this.Pages.CurrentPage.Page.Changed:connect(function(prop) + if prop == "AbsoluteSize" then + local pageSize = this.Pages.CurrentPage:GetSize() + this.PageView.CanvasSize = UDim2.new(0,pageSize.X,0,pageSize.Y) + end + end) + + if this.MenuStack[#this.MenuStack] ~= this.Pages.CurrentPage and not ignoreStack then + this.MenuStack[#this.MenuStack + 1] = this.Pages.CurrentPage + end + end + + function this:SetActive(active) + this.Active = active + + if this.Pages.CurrentPage then + this.Pages.CurrentPage.Active = active + end + end + + function clearMenuStack() + while this.MenuStack and #this.MenuStack > 0 do + this:PopMenu() + end + end + + function setOverrideMouseIconBehavior() + pcall(function() + if UserInputService:GetLastInputType() == Enum.UserInputType.Gamepad1 then + UserInputService.OverrideMouseIconBehavior = Enum.OverrideMouseIconBehavior.ForceHide + else + UserInputService.OverrideMouseIconBehavior = Enum.OverrideMouseIconBehavior.ForceShow + end + end) + end + + function setVisibilityInternal(visible, noAnimation, customStartPage) + this.OpenStateChangedCount = this.OpenStateChangedCount + 1 + local switchedFromGamepadInput = switchedFromGamepadInput or isTenFootInterface + this.Visible = visible + + + this.Modal.Visible = this.Visible + + if this.TabConnection then + this.TabConnection:disconnect() + this.TabConnection = nil + end + + local playerList = require(RobloxGui.Modules.PlayerlistModule) + + if this.Visible then + this.SettingsShowSignal:fire(this.Visible) + + pcall(function() GuiService:SetMenuIsOpen(true) end) + this.Shield.Visible = this.Visible + if noAnimation or not this.Shield:IsDescendantOf(game) then + this.Shield.Position = SETTINGS_SHIELD_ACTIVE_POSITION + else + this.Shield:TweenPosition(SETTINGS_SHIELD_ACTIVE_POSITION, Enum.EasingDirection.InOut, Enum.EasingStyle.Quart, 0.5, true) + end + + local noOpFunc = function() end + ContextActionService:BindCoreAction("RbxSettingsHubStopCharacter", noOpFunc, false, + Enum.PlayerActions.CharacterForward, + Enum.PlayerActions.CharacterBackward, + Enum.PlayerActions.CharacterLeft, + Enum.PlayerActions.CharacterRight, + Enum.PlayerActions.CharacterJump, + Enum.KeyCode.LeftShift, + Enum.KeyCode.RightShift, + Enum.KeyCode.Tab, + Enum.UserInputType.Gamepad1, Enum.UserInputType.Gamepad2, Enum.UserInputType.Gamepad3, Enum.UserInputType.Gamepad4) + + ContextActionService:BindCoreAction("RbxSettingsHubSwitchTab", switchTabFromBumpers, false, Enum.KeyCode.ButtonR1, Enum.KeyCode.ButtonL1) + ContextActionService:BindCoreAction("RbxSettingsScrollHotkey", scrollHotkeyFunc, false, Enum.KeyCode.PageUp, Enum.KeyCode.PageDown) + setBottomBarBindings() + + this.TabConnection = UserInputService.InputBegan:connect(switchTabFromKeyboard) + + + setOverrideMouseIconBehavior() + pcall(function() lastInputChangedCon = UserInputService.LastInputTypeChanged:connect(setOverrideMouseIconBehavior) end) + if UserInputService.MouseEnabled then + pcall(function() + UserInputService.OverrideMouseIconBehavior = Enum.OverrideMouseIconBehavior.ForceShow + end) + end + + if customStartPage then + removeBottomBarBindings() + this:SwitchToPage(customStartPage, nil, 1, true) + else + if useUserList and not isTenFootInterface then + this:SwitchToPage(this.PlayersPage, nil, 1, true) + else + if this.HomePage then + this:SwitchToPage(this.HomePage, nil, 1, true) + else + this:SwitchToPage(this.GameSettingsPage, nil, 1, true) + end + end + end + + playerList:HideTemp('SettingsMenu', true) + + if chat:GetVisibility() then + chatWasVisible = true + chat:ToggleVisibility() + end + + local backpack = require(RobloxGui.Modules.BackpackScript) + if backpack.IsOpen then + backpack:OpenClose() + end + else + if noAnimation then + this.Shield.Position = SETTINGS_SHIELD_INACTIVE_POSITION + this.Shield.Visible = this.Visible + this.SettingsShowSignal:fire(this.Visible) + pcall(function() GuiService:SetMenuIsOpen(false) end) + else + this.Shield:TweenPosition(SETTINGS_SHIELD_INACTIVE_POSITION, Enum.EasingDirection.In, Enum.EasingStyle.Quad, 0.4, true, function() + this.Shield.Visible = this.Visible + this.SettingsShowSignal:fire(this.Visible) + if not this.Visible then pcall(function() GuiService:SetMenuIsOpen(false) end) end + end) + end + + if lastInputChangedCon then + lastInputChangedCon:disconnect() + end + + playerList:HideTemp('SettingsMenu', false) + + if chatWasVisible then + chat:ToggleVisibility() + chatWasVisible = false + end + + pcall(function() UserInputService.OverrideMouseIconBehavior = Enum.OverrideMouseIconBehavior.None end) + + clearMenuStack() + ContextActionService:UnbindCoreAction("RbxSettingsHubSwitchTab") + ContextActionService:UnbindCoreAction("RbxSettingsHubStopCharacter") + ContextActionService:UnbindCoreAction("RbxSettingsScrollHotkey") + removeBottomBarBindings(0.4) + + GuiService.SelectedCoreObject = nil + end + end + + function this:SetVisibility(visible, noAnimation, customStartPage, switchedFromGamepadInput) + if this.Visible == visible then return end + + setVisibilityInternal(visible, noAnimation, customStartPage, switchedFromGamepadInput) + end + + function this:ToggleVisibility(switchedFromGamepadInput) + setVisibilityInternal(not this.Visible, nil, nil, switchedFromGamepadInput) + end + + function this:AddToMenuStack(newItem) + if this.MenuStack[#this.MenuStack] ~= newItem then + this.MenuStack[#this.MenuStack + 1] = newItem + end + end + + + function this:PopMenu(switchedFromGamepadInput, skipAnimation) + if this.MenuStack and #this.MenuStack > 0 then + local lastStackItem = this.MenuStack[#this.MenuStack] + + if type(lastStackItem) ~= "table" then + PoppedMenuEvent:Fire(lastStackItem) + end + + if lastStackItem == this.LeaveGamePage or lastStackItem == this.ResetCharacterPage then + setBottomBarBindings() + end + + table.remove(this.MenuStack, #this.MenuStack) + this:SwitchToPage(this.MenuStack[#this.MenuStack], true, 1, skipAnimation) + if #this.MenuStack == 0 then + this:SetVisibility(false) + this.Pages.CurrentPage:Hide(0, 0) + end + else + this.MenuStack = {} + PoppedMenuEvent:Fire() + this:ToggleVisibility() + end + end + + function this:ShowShield() + this.Shield.BackgroundTransparency = VREnabled and SETTINGS_SHIELD_VR_TRANSPARENCY or SETTINGS_SHIELD_TRANSPARENCY + end + function this:HideShield() + this.Shield.BackgroundTransparency = 1 + end + + local function enableVR() + local Panel3D = require(RobloxGui.Modules.VR.Panel3D) + local panel = Panel3D.Get("SettingsMenu") + panel:ResizeStuds(3, 3, 256) + panel:SetType(Panel3D.Type.Fixed) + panel:SetVisible(false) + panel:SetCanFade(false) + + this.ClippingShield.Parent = panel:GetGUI() + this.Shield.Parent.ClipsDescendants = false + this:HideShield() + + GuiService.MenuOpened:connect(function() + local headLook = Panel3D.GetHeadLookXZ(true) + panel.localCF = headLook * CFrame.Angles(math.rad(5), 0, 0) * CFrame.new(0, 0, 5) + panel:SetVisible(true, true) + end) + GuiService.MenuClosed:connect(function() + panel:SetVisible(false, false) + end) + end + + local UISChanged; + local function OnVREnabled(prop) + if prop == "VREnabled" and UserInputService.VREnabled then + VREnabled = true + enableVR() + if UISChanged then + UISChanged:disconnect() + UISChanged = nil + end + end + end + UISChanged = UserInputService.Changed:connect(OnVREnabled) + OnVREnabled("VREnabled") + + + local closeMenuFunc = function(name, inputState, input) + if inputState ~= Enum.UserInputState.Begin then return end + this:PopMenu(false, true) + end + ContextActionService:BindCoreAction("RBXEscapeMainMenu", closeMenuFunc, false, Enum.KeyCode.Escape) + + this.ResetCharacterPage:SetHub(this) + this.LeaveGamePage:SetHub(this) + + -- full page initialization + if not useUserList then + if utility:IsSmallTouchScreen() then + this.HomePage = require(RobloxGui.Modules.Settings.Pages.Home) + this.HomePage:SetHub(this) + end + end + + this.GameSettingsPage = require(RobloxGui.Modules.Settings.Pages.GameSettings) + this.GameSettingsPage:SetHub(this) + + if platform ~= Enum.Platform.XBoxOne and platform ~= Enum.Platform.PS4 then + this.ReportAbusePage = require(RobloxGui.Modules.Settings.Pages.ReportAbuseMenu) + this.ReportAbusePage:SetHub(this) + end + + this.HelpPage = require(RobloxGui.Modules.Settings.Pages.Help) + this.HelpPage:SetHub(this) + + if platform == Enum.Platform.Windows then + this.RecordPage = require(RobloxGui.Modules.Settings.Pages.Record) + this.RecordPage:SetHub(this) + end + + if useUserList and not isTenFootInterface then + this.PlayersPage = require(RobloxGui.Modules.Settings.Pages.Players) + this.PlayersPage:SetHub(this) + end + + -- page registration + if useUserList and not isTenFootInterface then + this:AddPage(this.PlayersPage) + end + this:AddPage(this.ResetCharacterPage) + this:AddPage(this.LeaveGamePage) + if not useUserList then + if this.HomePage then + this:AddPage(this.HomePage) + end + end + this:AddPage(this.GameSettingsPage) + if this.ReportAbusePage then + this:AddPage(this.ReportAbusePage) + end + this:AddPage(this.HelpPage) + if this.RecordPage then + this:AddPage(this.RecordPage) + end + + if useUserList and not isTenFootInterface then + this:SwitchToPage(this.PlayerPage, true, 1) + else + if this.HomePage then + this:SwitchToPage(this.HomePage, true, 1) + else + this:SwitchToPage(this.GameSettingsPage, true, 1) + end + end + -- hook up to necessary signals + + -- connect back button on android + GuiService.ShowLeaveConfirmation:connect(function() + if #this.MenuStack == 0 then + this:SetVisibility(true) + this:SwitchToPage(this.LeaveGamePage, nil, 1) + else + this:PopMenu(false, true) + end + end) + + -- Dev Console Connections + ContextActionService:BindCoreAction(DEV_CONSOLE_ACTION_NAME, toggleDevConsole, false, Enum.KeyCode.F9) + + -- Keyboard control + UserInputService.InputBegan:connect(function(input) + if input.KeyCode == Enum.KeyCode.Left or input.KeyCode == Enum.KeyCode.Right or input.KeyCode == Enum.KeyCode.Up or input.KeyCode == Enum.KeyCode.Down then + if this.Visible and this.Active then + if this.Pages.CurrentPage then + if GuiService.SelectedCoreObject == nil then + this.Pages.CurrentPage:SelectARow() + end + end + end + end + end) + + return this +end + + +-- Main Entry Point + +local moduleApiTable = {} + + local SettingsHubInstance = CreateSettingsHub() + + function moduleApiTable:SetVisibility(visible, noAnimation, customStartPage, switchedFromGamepadInput) + SettingsHubInstance:SetVisibility(visible, noAnimation, customStartPage, switchedFromGamepadInput) + end + + function moduleApiTable:ToggleVisibility(switchedFromGamepadInput) + SettingsHubInstance:ToggleVisibility(switchedFromGamepadInput) + end + + function moduleApiTable:SwitchToPage(pageToSwitchTo, ignoreStack) + SettingsHubInstance:SwitchToPage(pageToSwitchTo, ignoreStack, 1) + end + + function moduleApiTable:GetVisibility() + return SettingsHubInstance.Visible + end + + function moduleApiTable:ShowShield() + SettingsHubInstance:ShowShield() + end + + function moduleApiTable:HideShield() + SettingsHubInstance:HideShield() + end + + moduleApiTable.SettingsShowSignal = SettingsHubInstance.SettingsShowSignal + + moduleApiTable.Instance = SettingsHubInstance + +return moduleApiTable \ No newline at end of file diff --git a/2016/content/Modules/Settings/Utility.lua b/2016/content/Modules/Settings/Utility.lua new file mode 100644 index 0000000..4c6bebf --- /dev/null +++ b/2016/content/Modules/Settings/Utility.lua @@ -0,0 +1,2155 @@ +--[[ + Filename: SettingsPage.lua + Written by: jeditkacheff + Version 1.0 + Description: Base Page Functionality for all Settings Pages +--]] + +------------------ CONSTANTS -------------------- +local SELECTED_COLOR = Color3.new(0,162/255,1) +local NON_SELECTED_COLOR = Color3.new(78/255,84/255,96/255) + +local SELECTED_LEFT_IMAGE = "rbxasset://textures/ui/Settings/Slider/SelectedBarLeft.png" +local NON_SELECTED_LEFT_IMAGE = "rbxasset://textures/ui/Settings/Slider/BarLeft.png" +local SELECTED_RIGHT_IMAGE = "rbxasset://textures/ui/Settings/Slider/SelectedBarRight.png" +local NON_SELECTED_RIGHT_IMAGE= "rbxasset://textures/ui/Settings/Slider/BarRight.png" + +local CONTROLLER_SCROLL_DELTA = 0.2 +local CONTROLLER_THUMBSTICK_DEADZONE = 0.8 + +------------- SERVICES ---------------- +local HttpService = game:GetService("HttpService") +local UserInputService = game:GetService("UserInputService") +local GuiService = game:GetService("GuiService") +local RunService = game:GetService("RunService") +local CoreGui = game:GetService("CoreGui") +local RobloxGui = CoreGui:FindFirstChild("RobloxGui") +local ContextActionService = game:GetService("ContextActionService") + +------------------ VARIABLES -------------------- +local tenFootInterfaceEnabled = false +do + RobloxGui:WaitForChild("Modules"):WaitForChild("TenFootInterface") + tenFootInterfaceEnabled = require(RobloxGui.Modules.TenFootInterface):IsEnabled() +end + + + +----------- UTILITIES -------------- +local Util = {} +do + function Util.Create(instanceType) + return function(data) + local obj = Instance.new(instanceType) + for k, v in pairs(data) do + if type(k) == 'number' then + v.Parent = obj + else + obj[k] = v + end + end + return obj + end + end +end + + +-- used by several guis to show no selection adorn +local noSelectionObject = Util.Create'ImageLabel' +{ + Image = "", + BackgroundTransparency = 1 +}; + + +-- MATH -- +function clamp(low, high, input) + return math.max(low, math.min(high, input)) +end + +function ClampVector2(low, high, input) + return Vector2.new(clamp(low.x, high.x, input.x), clamp(low.y, high.y, input.y)) +end + +---- TWEENZ ---- +local Linear = function(t, b, c, d) + if t >= d then return b + c end + + return c*t/d + b +end + +local EaseOutQuad = function(t, b, c, d) + if t >= d then return b + c end + + t = t/d; + return -c * t*(t-2) + b +end + +local EaseInOutQuad = function(t, b, c, d) + if t >= d then return b + c end + + t = t / (d/2); + if (t < 1) then return c/2*t*t + b end; + t = t - 1; + return -c/2 * (t*(t-2) - 1) + b; +end + +function PropertyTweener(instance, prop, start, final, duration, easingFunc, cbFunc) + local this = {} + this.StartTime = tick() + this.EndTime = this.StartTime + duration + this.Cancelled = false + + local finished = false + local percentComplete = 0 + + local function finalize() + if instance then + instance[prop] = easingFunc(1, start, final - start, 1) + end + finished = true + percentComplete = 1 + if cbFunc then + cbFunc() + end + end + + -- Initial set + instance[prop] = easingFunc(0, start, final - start, duration) + spawn(function() + local now = tick() + while now < this.EndTime and instance do + if this.Cancelled then + return + end + instance[prop] = easingFunc(now - this.StartTime, start, final - start, duration) + percentComplete = clamp(0, 1, (now - this.StartTime) / duration) + RunService.RenderStepped:wait() + now = tick() + end + if this.Cancelled == false and instance then + finalize() + end + end) + + function this:GetFinal() + return final + end + + function this:GetPercentComplete() + return percentComplete + end + + function this:IsFinished() + return finished + end + + function this:Finish() + if not finished then + self:Cancel() + finalize() + end + end + + function this:Cancel() + this.Cancelled = true + end + + return this +end + +----------- CLASS DECLARATION -------------- + +local function CreateSignal() + local sig = {} + + local mSignaler = Instance.new('BindableEvent') + + local mArgData = nil + local mArgDataCount = nil + + function sig:fire(...) + mArgData = {...} + mArgDataCount = select('#', ...) + mSignaler:Fire() + end + + function sig:connect(f) + if not f then error("connect(nil)", 2) end + return mSignaler.Event:connect(function() + f(unpack(mArgData, 1, mArgDataCount)) + end) + end + + function sig:wait() + mSignaler.Event:wait() + assert(mArgData, "Missing arg data, likely due to :TweenSize/Position corrupting threadrefs.") + return unpack(mArgData, 1, mArgDataCount) + end + + return sig +end + +local function getViewportSize() + while not game.Workspace.CurrentCamera do + game.Workspace.Changed:wait() + end + + while game.Workspace.CurrentCamera.ViewportSize == Vector2.new(0,0) do + game.Workspace.CurrentCamera.Changed:wait() + end + + return game.Workspace.CurrentCamera.ViewportSize +end + +local function isSmallTouchScreen() + return UserInputService.TouchEnabled and getViewportSize().Y <= 500 +end + +local function isTenFootInterface() + return tenFootInterfaceEnabled +end + +local function usesSelectedObject() + if UserInputService.TouchEnabled and not UserInputService.GamepadEnabled then return false end + + return true +end + +local function isPosOverGui(pos, gui, debug) -- does not account for rotation + local ax, ay = gui.AbsolutePosition.x, gui.AbsolutePosition.y + local sx, sy = gui.AbsoluteSize.x, gui.AbsoluteSize.y + local bx, by = ax+sx, ay+sy + + if pos.x > ax and pos.x < bx and pos.y > ay and pos.y < by then + return true + else + return false + end +end + +local function isPosOverGuiWithClipping(pos, gui) -- isPosOverGui, accounts for clipping and visibility, does not account for rotation + if not isPosOverGui(pos, gui) then + return false + end + + local clipping = false + local check = gui + while true do + if check == nil or (not check:IsA'GuiObject' and not check:IsA'LayerCollector') then + clipping = true + if check and check:IsA'CoreGui' then + clipping = false + end + break + end + + if check:IsA'GuiObject' and not check.Visible then + clipping = true + break + end + if check:IsA'LayerCollector' or check.ClipsDescendants then + if not isPosOverGui(pos, check) then + clipping = true + break + end + end + + check = check.Parent + end + + if clipping then + return false + else + return true + end +end + +local function areGuisIntersecting(a, b) -- does not account for rotation + local aax, aay = a.AbsolutePosition.x, a.AbsolutePosition.y + local asx, asy = a.AbsoluteSize.x, a.AbsoluteSize.y + local abx, aby = aax+asx, aay+asy + local bax, bay = b.AbsolutePosition.x, b.AbsolutePosition.y + local bsx, bsy = b.AbsoluteSize.x, b.AbsoluteSize.y + local bbx, bby = bax+bsx, bay+bsy + + local intersectingX = aax < bbx and abx > bax + local intersectingY = aay < bby and aby > bay + local intersecting = intersectingX and intersectingY + + return intersecting +end + +local function isGuiVisible(gui, debug) -- true if any part of the gui is visible on the screen, considers clipping, does not account for rotation + local clipping = false + local check = gui + while true do + if check == nil or not check:IsA'GuiObject' and not check:IsA'LayerCollector' then + clipping = true + if check and check:IsA'CoreGui' then + clipping = false + end + break + end + + if check:IsA'GuiObject' and not check.Visible then + clipping = true + break + end + if check:IsA'LayerCollector' or check.ClipsDescendants then + if not areGuisIntersecting(check, gui) then + clipping = true + break + end + end + + check = check.Parent + end + + if clipping then + return false + else + return true + end +end + +local function MakeButton(name, text, size, clickFunc, pageRef, hubRef) + local SelectionOverrideObject = Util.Create'ImageLabel' + { + Image = "", + BackgroundTransparency = 1, + }; + + local button = Util.Create'ImageButton' + { + Name = name .. "Button", + Image = "rbxasset://textures/ui/Settings/MenuBarAssets/MenuButton.png", + ScaleType = Enum.ScaleType.Slice, + SliceCenter = Rect.new(8,6,46,44), + AutoButtonColor = false, + BackgroundTransparency = 1, + Size = size, + ZIndex = 2, + SelectionImageObject = SelectionOverrideObject + }; + button.NextSelectionLeft = button + button.NextSelectionRight = button + + local enabled = Util.Create'BoolValue' + { + Name = 'Enabled', + Parent = button, + Value = true + } + + if clickFunc then + button.MouseButton1Click:connect(function() + local lastInputType = nil + pcall(function() lastInputType = UserInputService:GetLastInputType() end) + if lastInputType then + clickFunc(lastInputTypee == Enum.UserInputType.Gamepad1 or lastInputType == Enum.UserInputType.Gamepad2 or + lastInputType == Enum.UserInputType.Gamepad3 or lastInputType == Enum.UserInputType.Gamepad4) + else + clickFunc(false) + end + end) + end + + local function isPointerInput(inputObject) + return (inputObject.UserInputType == Enum.UserInputType.MouseMovement or inputObject.UserInputType == Enum.UserInputType.Touch) + end + + local function selectButton() + local hub = hubRef + if hub == nil then + if pageRef then + hub = pageRef.HubRef + end + end + + if (hub and hub.Active or hub == nil) then + button.Image = "rbxasset://textures/ui/Settings/MenuBarAssets/MenuButtonSelected.png" + + local scrollTo = button + if rowRef then + scrollTo = rowRef + end + if hub then + hub:ScrollToFrame(scrollTo) + end + end + end + + local function deselectButton() + button.Image = "rbxasset://textures/ui/Settings/MenuBarAssets/MenuButton.png" + end + + button.InputBegan:connect(function(inputObject) + if button.Selectable and isPointerInput(inputObject) then + selectButton() + end + end) + button.InputEnded:connect(function(inputObject) + if button.Selectable and GuiService.SelectedCoreObject ~= button and isPointerInput(inputObject) then + deselectButton() + end + end) + + local rowRef = nil + local function setRowRef(ref) + rowRef = ref + end + button.SelectionGained:connect(function() + selectButton() + end) + button.SelectionLost:connect(function() + deselectButton() + end) + + local textLabel = Util.Create'TextLabel' + { + Name = name .. "TextLabel", + BackgroundTransparency = 1, + BorderSizePixel = 0, + Size = UDim2.new(1, 0, 1, -8), + Position = UDim2.new(0,0,0,0), + TextColor3 = Color3.new(1,1,1), + TextYAlignment = Enum.TextYAlignment.Center, + Font = Enum.Font.SourceSansBold, + FontSize = Enum.FontSize.Size24, + Text = text, + TextWrapped = true, + ZIndex = 2, + Parent = button + }; + + if isSmallTouchScreen() then + textLabel.FontSize = Enum.FontSize.Size18 + elseif isTenFootInterface() then + textLabel.FontSize = Enum.FontSize.Size36 + end + + local guiServiceCon = GuiService.Changed:connect(function(prop) + if prop ~= "SelectedCoreObject" then return end + if not usesSelectedObject() then return end + + if GuiService.SelectedCoreObject == nil or GuiService.SelectedCoreObject ~= button then + deselectButton() + return + end + + if button.Selectable then + selectButton() + end + end) + + return button, textLabel, setRowRef +end + +local function CreateDropDown(dropDownStringTable, startPosition, settingsHub) + -------------------- CONSTANTS ------------------------ + local DEFAULT_DROPDOWN_TEXT = "Choose One" + local SCROLLING_FRAME_PIXEL_OFFSET = 25 + local SELECTION_TEXT_COLOR_NORMAL = Color3.new(0.7,0.7,0.7) + local SELECTION_TEXT_COLOR_HIGHLIGHTED = Color3.new(1,1,1) + + -------------------- VARIABLES ------------------------ + local lastSelectedCoreObject= nil + + -------------------- SETUP ------------------------ + local this = {} + this.CurrentIndex = nil + + local indexChangedEvent = Instance.new("BindableEvent") + indexChangedEvent.Name = "IndexChanged" + + if type(dropDownStringTable) ~= "table" then + error("CreateDropDown dropDownStringTable (first arg) is not a table") + return this + end + + local indexChangedEvent = Instance.new("BindableEvent") + indexChangedEvent.Name = "IndexChanged" + + local interactable = true + local guid = HttpService:GenerateGUID(false) + local dropDownButtonEnabled + + this.CurrentIndex = 0 + + ----------------- GUI SETUP ------------------------ + local DropDownFullscreenFrame = Util.Create'ImageButton' + { + Name = "DropDownFullscreenFrame", + BackgroundTransparency = 0.2, + BorderSizePixel = 0, + Size = UDim2.new(1, 0, 1, 0), + BackgroundColor3 = Color3.new(0,0,0), + ZIndex = 10, + Active = true, + Visible = false, + Selectable = false, + AutoButtonColor = false, + Parent = CoreGui.RobloxGui + }; + + local DropDownSelectionFrame = Util.Create'ImageLabel' + { + Name = "DropDownSelectionFrame", + Image = "rbxasset://textures/ui/Settings/MenuBarAssets/MenuButton.png", + ScaleType = Enum.ScaleType.Slice, + SliceCenter = Rect.new(8,6,46,44), + BackgroundTransparency = 1, + Size = UDim2.new(0, 400, 0.9, 0), + Position = UDim2.new(0.5, -200, 0.05, 0), + ZIndex = 10, + Parent = DropDownFullscreenFrame + }; + + local DropDownScrollingFrame = Util.Create'ScrollingFrame' + { + Name = "DropDownScrollingFrame", + BackgroundTransparency = 1, + BorderSizePixel = 0, + Size = UDim2.new(1, -20, 1, -SCROLLING_FRAME_PIXEL_OFFSET), + Position = UDim2.new(0, 10, 0, 10), + ZIndex = 10, + Parent = DropDownSelectionFrame + }; + + local guiServiceChangeCon = nil + local active = false + local hideDropDownSelection = function(name, inputState) + if name ~= nil and inputState ~= Enum.UserInputState.Begin then return end + this.DropDownFrame.Selectable = interactable + + if DropDownFullscreenFrame.Visible and usesSelectedObject() then + GuiService.SelectedCoreObject = lastSelectedCoreObject + end + DropDownFullscreenFrame.Visible = false + if guiServiceChangeCon then guiServiceChangeCon:disconnect() end + ContextActionService:UnbindCoreAction(guid .. "Action") + ContextActionService:UnbindCoreAction(guid .. "FreezeAction") + + settingsHub:SetActive(true) + + dropDownButtonEnabled.Value = interactable + active = false + end + local noOpFunc = function() end + + local DropDownFrameClicked = function() + if not interactable then return end + + this.DropDownFrame.Selectable = false + active = true + + DropDownFullscreenFrame.Visible = true + if not this.CurrentIndex then this.CurrentIndex = 1 end + if this.CurrentIndex <= 0 then this.CurrentIndex = 1 end + + lastSelectedCoreObject = this.DropDownFrame + GuiService.SelectedCoreObject = this.Selections[this.CurrentIndex] + + guiServiceChangeCon = GuiService.Changed:connect(function(prop) + if not prop == "SelectedCoreObject" then return end + for i = 1, #this.Selections do + if GuiService.SelectedCoreObject == this.Selections[i] then + this.Selections[i].TextColor3 = SELECTION_TEXT_COLOR_HIGHLIGHTED + else + this.Selections[i].TextColor3 = SELECTION_TEXT_COLOR_NORMAL + end + end + end) + + ContextActionService:BindCoreAction(guid .. "FreezeAction", noOpFunc, false, Enum.UserInputType.Keyboard, Enum.UserInputType.Gamepad1) + ContextActionService:BindCoreAction(guid .. "Action", hideDropDownSelection, false, Enum.KeyCode.ButtonB, Enum.KeyCode.Escape) + + settingsHub:SetActive(false) + + dropDownButtonEnabled.Value = false + end + + local dropDownFrameSize = UDim2.new(0,400,0,44) + if isSmallTouchScreen() then + dropDownFrameSize = UDim2.new(0,300,0,44) + end + this.DropDownFrame = MakeButton("DropDownFrame", DEFAULT_DROPDOWN_TEXT, dropDownFrameSize, DropDownFrameClicked) + dropDownButtonEnabled = this.DropDownFrame.Enabled + local selectedTextLabel = this.DropDownFrame.DropDownFrameTextLabel + local dropDownImage = Util.Create'ImageLabel' + { + Name = "DropDownImage", + Image = "rbxasset://textures/ui/Settings/DropDown/DropDown.png", + BackgroundTransparency = 1, + Size = UDim2.new(0,15,0,10), + Position = UDim2.new(1, -45,0.5,-7), + ZIndex = 2, + Parent = this.DropDownFrame + }; + + + ---------------------- FUNCTIONS ----------------------------------- + local function setSelection(index) + local shouldFireChanged = false + for i, selectionLabel in pairs(this.Selections) do + if i == index then + selectedTextLabel.Text = selectionLabel.Text + this.CurrentIndex = i + + shouldFireChanged = true + end + end + + if shouldFireChanged then + indexChangedEvent:Fire(index) + end + end + + local function setSelectionByValue(value) + local shouldFireChanged = false + for i, selectionLabel in pairs(this.Selections) do + if selectionLabel.Text == value then + selectedTextLabel.Text = selectionLabel.Text + this.CurrentIndex = i + + shouldFireChanged = true + end + end + + if shouldFireChanged then + indexChangedEvent:Fire(this.CurrentIndex) + end + return shouldFireChanged + end + + local enterIsDown = false + local function processInput(input) + if input.UserInputState == Enum.UserInputState.Begin then + if input.KeyCode == Enum.KeyCode.Return then + if GuiService.SelectedCoreObject == this.DropDownFrame or this.SelectionInfo and this.SelectionInfo[GuiService.SelectedCoreObject] then + enterIsDown = true + end + end + elseif input.UserInputState == Enum.UserInputState.End then + if input.KeyCode == Enum.KeyCode.Return and enterIsDown then + enterIsDown = false + if GuiService.SelectedCoreObject == this.DropDownFrame then + DropDownFrameClicked() + elseif this.SelectionInfo and this.SelectionInfo[GuiService.SelectedCoreObject] then + local info = this.SelectionInfo[GuiService.SelectedCoreObject] + info.Clicked() + end + end + end + end + + + --------------------- PUBLIC FACING FUNCTIONS ----------------------- + this.IndexChanged = indexChangedEvent.Event + + function this:SetSelectionIndex(newIndex) + setSelection(newIndex) + end + + function this:SetSelectionByValue(value) + return setSelectionByValue(value) + end + + function this:ResetSelectionIndex() + this.CurrentIndex = nil + selectedTextLabel.Text = DEFAULT_DROPDOWN_TEXT + hideDropDownSelection() + end + + function this:GetSelectedIndex() + return this.CurrentIndex + end + + function this:SetZIndex(newZIndex) + this.DropDownFrame.ZIndex = newZIndex + dropDownImage.ZIndex = newZIndex + selectedTextLabel.ZIndex = newZIndex + end + + function this:SetInteractable(value) + interactable = value + this.DropDownFrame.Selectable = interactable + + if not interactable then + hideDropDownSelection() + this:SetZIndex(1) + else + this:SetZIndex(2) + end + + dropDownButtonEnabled.Value = value and not active + end + + + function this:UpdateDropDownList(dropDownStringTable) + if this.Selections then + for i = 1, #this.Selections do + this.Selections[i]:Destroy() + end + end + + this.Selections = {} + this.SelectionInfo = {} + + for i,v in pairs(dropDownStringTable) do + local SelectionOverrideObject = Util.Create'Frame' + { + BackgroundTransparency = 0.7, + BorderSizePixel = 0, + Size = UDim2.new(1, 0, 1, 0) + }; + + local nextSelection = Util.Create'TextButton' + { + Name = "Selection" .. tostring(i), + BackgroundTransparency = 1, + BorderSizePixel = 0, + AutoButtonColor = false, + Size = UDim2.new(1, -28, 0, 50), + Position = UDim2.new(0,14,0, (i - 1) * 51), + TextColor3 = SELECTION_TEXT_COLOR_NORMAL, + Font = Enum.Font.SourceSans, + FontSize = Enum.FontSize.Size24, + Text = v, + ZIndex = 10, + SelectionImageObject = SelectionOverrideObject, + Parent = DropDownScrollingFrame + }; + + if i == startPosition then + this.CurrentIndex = i + selectedTextLabel.Text = v + nextSelection.TextColor3 = SELECTION_TEXT_COLOR_HIGHLIGHTED + elseif not startPosition and i == 1 then + nextSelection.TextColor3 = SELECTION_TEXT_COLOR_HIGHLIGHTED + end + + local clicked = function() + selectedTextLabel.Text = nextSelection.Text + hideDropDownSelection() + this.CurrentIndex = i + indexChangedEvent:Fire(i) + end + + nextSelection.MouseButton1Click:connect(clicked) + + nextSelection.MouseEnter:connect(function() + if usesSelectedObject() then + GuiService.SelectedCoreObject = nextSelection + end + end) + + this.Selections[i] = nextSelection + this.SelectionInfo[nextSelection] = {Clicked = clicked} + end + + GuiService:RemoveSelectionGroup(guid) + GuiService:AddSelectionTuple(guid, unpack(this.Selections)) + + DropDownScrollingFrame.CanvasSize = UDim2.new(1,-20,0,#dropDownStringTable * 51) + + local function updateDropDownSize() + if DropDownScrollingFrame.CanvasSize.Y.Offset < (DropDownFullscreenFrame.AbsoluteSize.Y - 10) then + DropDownSelectionFrame.Size = UDim2.new(DropDownSelectionFrame.Size.X.Scale, DropDownSelectionFrame.Size.X.Offset, + 0,DropDownScrollingFrame.CanvasSize.Y.Offset + SCROLLING_FRAME_PIXEL_OFFSET) + DropDownSelectionFrame.Position = UDim2.new(DropDownSelectionFrame.Position.X.Scale, DropDownSelectionFrame.Position.X.Offset, + 0.5, -DropDownSelectionFrame.Size.Y.Offset/2) + else + DropDownSelectionFrame.Size = UDim2.new(0, 400, 0.9, 0) + DropDownSelectionFrame.Position = UDim2.new(0.5, -200, 0.05, 0) + end + end + + DropDownFullscreenFrame.Changed:connect(function(prop) + if prop ~= "AbsoluteSize" then return end + updateDropDownSize() + end) + + updateDropDownSize() + end + + ----------------------- CONNECTIONS/SETUP -------------------------------- + this:UpdateDropDownList(dropDownStringTable) + + DropDownFullscreenFrame.MouseButton1Click:connect(hideDropDownSelection) + + settingsHub.PoppedMenu:connect(function(poppedMenu) + if poppedMenu == DropDownFullscreenFrame then + hideDropDownSelection() + end + end) + + UserInputService.InputBegan:connect(processInput) + UserInputService.InputEnded:connect(processInput) + + return this +end + + +local function CreateSelector(selectionStringTable, startPosition) + + -------------------- VARIABLES ------------------------ + local lastInputDirection = 0 + local TweenTime = 0.15 + + -------------------- SETUP ------------------------ + local this = {} + this.HubRef = nil + + if type(selectionStringTable) ~= "table" then + error("CreateSelector selectionStringTable (first arg) is not a table") + return this + end + + local indexChangedEvent = Instance.new("BindableEvent") + indexChangedEvent.Name = "IndexChanged" + + local interactable = true + + this.CurrentIndex = 0 + + ----------------- GUI SETUP ------------------------ + this.SelectorFrame = Util.Create'ImageButton' + { + Name = "Selector", + Image = "", + AutoButtonColor = false, + NextSelectionLeft = this.SelectorFrame, + NextSelectionRight = this.SelectorFrame, + BackgroundTransparency = 1, + Size = UDim2.new(0,502,0,50), + ZIndex = 2, + SelectionImageObject = noSelectionObject + }; + if isSmallTouchScreen() then + this.SelectorFrame.Size = UDim2.new(0,400,0,50) + end + + local leftButton = Util.Create'ImageButton' + { + Name = "LeftButton", + BackgroundTransparency = 1, + Position = UDim2.new(0,-10,0.5,-25), + Size = UDim2.new(0,60,0,50), + Image = "", + ZIndex = 3, + Selectable = false, + Active = true, + Parent = this.SelectorFrame + }; + local rightButton = Util.Create'ImageButton' + { + Name = "RightButton", + BackgroundTransparency = 1, + Position = UDim2.new(1,-50,0.5,-25), + Size = UDim2.new(0,50,0,50), + Image = "", + ZIndex = 3, + Selectable = false, + Parent = this.SelectorFrame + }; + + local leftButtonImage = Util.Create'ImageLabel' + { + Name = "LeftButton", + BackgroundTransparency = 1, + Position = UDim2.new(1,-24,0.5,-15), + Size = UDim2.new(0,18,0,30), + Image = "rbxasset://textures/ui/Settings/Slider/Left.png", + ZIndex = 2, + Active = true, + Parent = leftButton + }; + local rightButtonImage = Util.Create'ImageLabel' + { + Name = "RightButton", + BackgroundTransparency = 1, + Position = UDim2.new(0,6,0.5,-15), + Size = UDim2.new(0,18,0,30), + Image = "rbxasset://textures/ui/Settings/Slider/Right.png", + ZIndex = 2, + Parent = rightButton + }; + + + this.Selections = {} + local isSelectionLabelVisible = {} + local isAutoSelectButton = {} + + for i,v in pairs(selectionStringTable) do + local nextSelection = Util.Create'TextLabel' + { + Name = "Selection" .. tostring(i), + BackgroundTransparency = 1, + BorderSizePixel = 0, + Size = UDim2.new(1,leftButton.Size.X.Offset * -2, 1, 0), + Position = UDim2.new(1,0,0,0), + TextColor3 = Color3.new(1,1,1), + TextYAlignment = Enum.TextYAlignment.Center, + TextTransparency = 0.5, + Font = Enum.Font.SourceSans, + FontSize = Enum.FontSize.Size24, + Text = v, + ZIndex = 2, + Visible = false, + Parent = this.SelectorFrame + }; + if isTenFootInterface() then + nextSelection.FontSize = Enum.FontSize.Size36 + end + + if i == startPosition then + this.CurrentIndex = i + nextSelection.Position = UDim2.new(0,leftButton.Size.X.Offset,0,0) + nextSelection.Visible = true + + isSelectionLabelVisible[nextSelection] = true + else + isSelectionLabelVisible[nextSelection] = false + end + + local autoSelectButton = Util.Create'ImageButton'{ + Name = 'AutoSelectButton', + BackgroundTransparency = 1, + Image = '', + Size = UDim2.new(1, 0, 1, 0), + Parent = nextSelection, + ZIndex = 2 + } + autoSelectButton.MouseButton1Click:connect(function() + local newIndex = this.CurrentIndex + 1 + if newIndex > #this.Selections then + newIndex = 1 + end + this:SetSelectionIndex(newIndex) + if usesSelectedObject() then + GuiService.SelectedCoreObject = this.SelectorFrame + end + end) + isAutoSelectButton[autoSelectButton] = true + + this.Selections[i] = nextSelection + end + + + ---------------------- FUNCTIONS ----------------------------------- + local function setSelection(index, direction) + for i, selectionLabel in pairs(this.Selections) do + local isSelected = (i == index) + + if not selectionLabel:IsDescendantOf(game) then + this.CurrentIndex = i + indexChangedEvent:Fire(index) + return + end + + local tweenPos = UDim2.new(0,leftButton.Size.X.Offset * direction * 3,0,0) + if isSelectionLabelVisible[selectionLabel] then + tweenPos = UDim2.new(0,leftButton.Size.X.Offset * -direction * 3,0,0) + end + + if tweenPos.X.Offset < 0 then + tweenPos = UDim2.new(0,tweenPos.X.Offset + (selectionLabel.AbsoluteSize.X/4),0,0) + end + + if isSelected then + isSelectionLabelVisible[selectionLabel] = true + selectionLabel.Position = tweenPos + selectionLabel.Visible = true + PropertyTweener(selectionLabel, "TextTransparency", 1, 0, TweenTime * 1.1, EaseOutQuad) + selectionLabel:TweenPosition(UDim2.new(0,leftButton.Size.X.Offset,0,0), Enum.EasingDirection.In, Enum.EasingStyle.Quad, TweenTime, true) + this.CurrentIndex = i + indexChangedEvent:Fire(index) + elseif isSelectionLabelVisible[selectionLabel] then + isSelectionLabelVisible[selectionLabel] = false + PropertyTweener(selectionLabel, "TextTransparency", 0, 1, TweenTime * 1.1, EaseOutQuad) + selectionLabel:TweenPosition(tweenPos, Enum.EasingDirection.Out, Enum.EasingStyle.Quad, TweenTime * 0.9, true) + end + end + end + + local function stepFunc(inputObject, step) + if not interactable then return end + + if inputObject ~= nil and inputObject.UserInputType ~= Enum.UserInputType.MouseButton1 and + inputObject.UserInputType ~= Enum.UserInputType.Gamepad1 and inputObject.UserInputType ~= Enum.UserInputType.Gamepad2 and + inputObject.UserInputType ~= Enum.UserInputType.Gamepad3 and inputObject.UserInputType ~= Enum.UserInputType.Gamepad4 and + inputObject.UserInputType ~= Enum.UserInputType.Keyboard then return end + + if usesSelectedObject() then + GuiService.SelectedCoreObject = this.SelectorFrame + end + + local newIndex = step + this.CurrentIndex + + local direction = 0 + if newIndex > this.CurrentIndex then + direction = 1 + else + direction = -1 + end + + if newIndex > #this.Selections then + newIndex = 1 + elseif newIndex < 1 then + newIndex = #this.Selections + end + + setSelection(newIndex, direction) + end + + local guiServiceCon = nil + local function connectToGuiService() + guiServiceCon = GuiService.Changed:connect(function(prop) + if prop == "SelectedCoreObject" then + if GuiService.SelectedCoreObject == this.SelectorFrame then + this.Selections[this.CurrentIndex].TextTransparency = 0 + else + if GuiService.SelectedCoreObject ~= nil and isAutoSelectButton[GuiService.SelectedCoreObject] then + GuiService.SelectedCoreObject = this.SelectorFrame + else + this.Selections[this.CurrentIndex].TextTransparency = 0.5 + end + end + end + end) + end + + --------------------- PUBLIC FACING FUNCTIONS ----------------------- + this.IndexChanged = indexChangedEvent.Event + + function this:SetSelectionIndex(newIndex) + setSelection(newIndex, 1) + end + + function this:GetSelectedIndex() + return this.CurrentIndex + end + + function this:SetZIndex(newZIndex) + leftButton.ZIndex = newZIndex + rightButton.ZIndex = newZIndex + leftButtonImage.ZIndex = newZIndex + rightButtonImage.ZIndex = newZIndex + + for i = 1, #this.Selections do + this.Selections[i].ZIndex = newZIndex + end + end + + function this:SetInteractable(value) + interactable = value + this.SelectorFrame.Selectable = interactable + if not interactable then + for i, selectionLabel in pairs(this.Selections) do + selectionLabel.TextColor3 = Color3.new(49/255, 49/255, 49/255) + end + else + for i, selectionLabel in pairs(this.Selections) do + selectionLabel.TextColor3 = Color3.new(1, 1, 1) + end + end + end + + --------------------- SETUP ----------------------- + leftButton.InputBegan:connect(function(inputObject) + if inputObject.UserInputType == Enum.UserInputType.Touch then + stepFunc(nil, -1) + end + end) + leftButton.MouseButton1Click:connect(function() + if not UserInputService.TouchEnabled then + stepFunc(nil, -1) + end + end) + rightButton.InputBegan:connect(function(inputObject) + if inputObject.UserInputType == Enum.UserInputType.Touch then + stepFunc(nil, 1) + end + end) + rightButton.MouseButton1Click:connect(function() + if not UserInputService.TouchEnabled then + stepFunc(nil, 1) + end + end) + + local isInTree = true + + UserInputService.InputBegan:connect(function(inputObject) + if not interactable then return end + if not isInTree then return end + + if inputObject.UserInputType ~= Enum.UserInputType.Gamepad1 and inputObject.UserInputType ~= Enum.UserInputType.Keyboard then return end + if GuiService.SelectedCoreObject ~= this.SelectorFrame then return end + + if inputObject.KeyCode == Enum.KeyCode.DPadLeft or inputObject.KeyCode == Enum.KeyCode.Left or inputObject.KeyCode == Enum.KeyCode.A then + stepFunc(inputObject, -1) + elseif inputObject.KeyCode == Enum.KeyCode.DPadRight or inputObject.KeyCode == Enum.KeyCode.Right or inputObject.KeyCode == Enum.KeyCode.D then + stepFunc(inputObject, 1) + end + end) + + UserInputService.InputChanged:connect(function(inputObject) + if not interactable then return end + if not isInTree then lastInputDirection = 0 return end + + if inputObject.UserInputType ~= Enum.UserInputType.Gamepad1 then return end + if GuiService.SelectedCoreObject ~= this.SelectorFrame then return end + if inputObject.KeyCode ~= Enum.KeyCode.Thumbstick1 then return end + + + if inputObject.Position.X > CONTROLLER_THUMBSTICK_DEADZONE and inputObject.Delta.X > 0 and lastInputDirection ~= 1 then + lastInputDirection = 1 + stepFunc(inputObject, lastInputDirection) + elseif inputObject.Position.X < -CONTROLLER_THUMBSTICK_DEADZONE and inputObject.Delta.X < 0 and lastInputDirection ~= -1 then + lastInputDirection = -1 + stepFunc(inputObject, lastInputDirection) + elseif math.abs(inputObject.Position.X) < CONTROLLER_THUMBSTICK_DEADZONE then + lastInputDirection = 0 + end + end) + + this.SelectorFrame.AncestryChanged:connect(function(child, parent) + isInTree = parent + if not isInTree then + if guiServiceCon then guiServiceCon:disconnect() end + else + connectToGuiService() + end + end) + + connectToGuiService() + + return this +end + +local function ShowAlert(alertMessage, okButtonText, settingsHub, okPressedFunc, hasBackground) + if CoreGui.RobloxGui:FindFirstChild("AlertViewFullScreen") then return end + + local NON_SELECTED_TEXT_COLOR = Color3.new(59/255, 166/255, 241/255) + local SELECTED_TEXT_COLOR = Color3.new(1,1,1) + + local AlertViewBacking = Util.Create'ImageLabel' + { + Name = "AlertViewBacking", + Image = "rbxasset://textures/ui/Settings/MenuBarAssets/MenuButton.png", + ScaleType = Enum.ScaleType.Slice, + SliceCenter = Rect.new(8,6,46,44), + BackgroundTransparency = 1, + ImageTransparency = 1, + Size = UDim2.new(0, 400, 0, 350), + Position = UDim2.new(0.5, -200, 0.5, -175), + ZIndex = 9, + Parent = CoreGui.RobloxGui + }; + if hasBackground then + AlertViewBacking.ImageTransparency = 0 + else + AlertViewBacking.Size = UDim2.new(0.8, 0, 0, 350) + AlertViewBacking.Position = UDim2.new(0.1, 0, 0.1, 0) + end + + if CoreGui.RobloxGui.AbsoluteSize.Y <= AlertViewBacking.Size.Y.Offset then + AlertViewBacking.Size = UDim2.new(AlertViewBacking.Size.X.Scale, AlertViewBacking.Size.X.Offset, + AlertViewBacking.Size.Y.Scale, CoreGui.RobloxGui.AbsoluteSize.Y) + AlertViewBacking.Position = UDim2.new(0.5, -AlertViewBacking.Size.X.Offset/2, 0.5, -AlertViewBacking.Size.Y.Offset/2) + end + + local AlertViewText = Util.Create'TextLabel' + { + Name = "AlertViewText", + BackgroundTransparency = 1, + Size = UDim2.new(0.95, 0, 0.6, 0), + Position = UDim2.new(0.025, 0, 0.05, 0), + Font = Enum.Font.SourceSansBold, + FontSize = Enum.FontSize.Size36, + Text = alertMessage, + TextWrapped = true, + TextColor3 = Color3.new(1,1,1), + TextXAlignment = Enum.TextXAlignment.Center, + TextYAlignment = Enum.TextYAlignment.Center, + ZIndex = 10, + Parent = AlertViewBacking + }; + + local SelectionOverrideObject = Util.Create'ImageLabel' + { + Image = "", + BackgroundTransparency = 1 + }; + + local removeId = HttpService:GenerateGUID(false) + + local destroyAlert = function() + AlertViewBacking:Destroy() + if okPressedFunc then + okPressedFunc() + end + ContextActionService:UnbindCoreAction(removeId) + Game.GuiService.SelectedCoreObject = nil + if settingsHub then + settingsHub:ShowBar() + end + end + + local AlertViewButtonSize = UDim2.new(1, -20, 0, 60) + local AlertViewButtonPosition = UDim2.new(0, 10, 0.65, 0) + if not hasBackground then + AlertViewButtonSize = UDim2.new(0, 200, 0, 50) + AlertViewButtonPosition = UDim2.new(0.5, -100, 0.65, 0) + end + + local AlertViewButton, AlertViewText = MakeButton("AlertViewButton", okButtonText, AlertViewButtonSize, destroyAlert) + AlertViewButton.Position = AlertViewButtonPosition + AlertViewButton.NextSelectionLeft = AlertViewButton + AlertViewButton.NextSelectionRight = AlertViewButton + AlertViewButton.NextSelectionUp = AlertViewButton + AlertViewButton.NextSelectionDown = AlertViewButton + AlertViewButton.ZIndex = 10 + AlertViewText.ZIndex = AlertViewButton.ZIndex + AlertViewButton.Parent = AlertViewBacking + + if usesSelectedObject() then + Game.GuiService.SelectedCoreObject = AlertViewButton + end + + GuiService.SelectedCoreObject = AlertViewButton + + ContextActionService:BindCoreAction(removeId, destroyAlert, false, Enum.KeyCode.Escape, Enum.KeyCode.ButtonB, Enum.KeyCode.ButtonA) + + if settingsHub then + settingsHub:HideBar() + settingsHub.Pages.CurrentPage:Hide(1, 1) + end +end + +local function CreateNewSlider(numOfSteps, startStep, minStep) + -------------------- SETUP ------------------------ + local this = {} + + local spacing = 4 + local initialSpacing = 8 + local steps = tonumber(numOfSteps) + local currentStep = startStep + + local lastInputDirection = 0 + local timeAtLastInput = nil + + local interactable = true + + local renderStepBindName = HttpService:GenerateGUID(false) + + -- this is done to prevent using these values below (trying to keep the variables consistent) + numOfSteps = "" + startStep = "" + + if steps <= 0 then + error("CreateNewSlider failed because numOfSteps (first arg) is 0 or negative, please supply a positive integer") + return + end + + local valueChangedEvent = Instance.new("BindableEvent") + valueChangedEvent.Name = "ValueChanged" + + ----------------- GUI SETUP ------------------------ + this.SliderFrame = Util.Create'ImageButton' + { + Name = "Slider", + Image = "", + AutoButtonColor = false, + NextSelectionLeft = this.SliderFrame, + NextSelectionRight = this.SliderFrame, + BackgroundTransparency = 1, + Size = UDim2.new(0,502,0,50), + SelectionImageObject = noSelectionObject, + ZIndex = 2 + }; + if isSmallTouchScreen() then + this.SliderFrame.Size = UDim2.new(0,400,0,30) + end + + local leftButton = Util.Create'ImageButton' + { + Name = "LeftButton", + BackgroundTransparency = 1, + Position = UDim2.new(0,0,0.5,-25), + Size = UDim2.new(0,50,0,50), + Image = "", + ZIndex = 2, + Selectable = false, + Active = true, + Parent = this.SliderFrame + }; + local rightButton = Util.Create'ImageButton' + { + Name = "RightButton", + BackgroundTransparency = 1, + Position = UDim2.new(1,-50,0.5,-25), + Size = UDim2.new(0,50,0,50), + Image = "", + ZIndex = 2, + Selectable = false, + Active = true, + Parent = this.SliderFrame + }; + + local leftButtonImage = Util.Create'ImageLabel' + { + Name = "LeftButton", + BackgroundTransparency = 1, + Position = UDim2.new(1,-24,0.5,-15), + Size = UDim2.new(0,18,0,30), + Image = "rbxasset://textures/ui/Settings/Slider/Left.png", + ZIndex = 2, + Parent = leftButton + }; + local rightButtonImage = Util.Create'ImageLabel' + { + Name = "RightButton", + BackgroundTransparency = 1, + Position = UDim2.new(0,6,0.5,-15), + Size = UDim2.new(0,18,0,30), + Image = "rbxasset://textures/ui/Settings/Slider/Right.png", + ZIndex = 2, + Parent = rightButton + }; + + + this.Steps = {} + local stepXSize = 35 + if isSmallTouchScreen() then + stepXSize = 25 + end + + for i = 1, steps do + local nextStep = Util.Create'ImageButton' + { + Name = "Step" .. tostring(i), + BackgroundColor3 = SELECTED_COLOR, + BackgroundTransparency = 0.36, + BorderSizePixel = 0, + AutoButtonColor = false, + Active = false, + Position = UDim2.new(0,initialSpacing + leftButton.Size.X.Offset + ((stepXSize + spacing) * (i - 1)),0.5,-12), + Size = UDim2.new(0,stepXSize,0, 24), + Image = "", + ZIndex = 2, + Selectable = false, + ImageTransparency = 0.36, + Parent = this.SliderFrame + }; + + if i > currentStep then + nextStep.BackgroundColor3 = NON_SELECTED_COLOR + end + + if i == 1 or i == steps then + nextStep.BackgroundTransparency = 1 + nextStep.ScaleType = Enum.ScaleType.Slice + nextStep.SliceCenter = Rect.new(3,3,32,21) + + if i <= currentStep then + if i == 1 then + nextStep.Image = SELECTED_LEFT_IMAGE + else + nextStep.Image = SELECTED_RIGHT_IMAGE + end + else + if i == 1 then + nextStep.Image = NON_SELECTED_LEFT_IMAGE + else + nextStep.Image = NON_SELECTED_RIGHT_IMAGE + end + end + end + + this.Steps[#this.Steps + 1] = nextStep + end + + local xSize = initialSpacing + (leftButton.Size.X.Offset) + this.Steps[#this.Steps].Size.X.Offset + + this.Steps[#this.Steps].Position.X.Offset + this.SliderFrame.Size = UDim2.new(0, xSize, 0, this.SliderFrame.Size.Y.Offset) + + + ------------------- FUNCTIONS --------------------- + local function hideSelection() + for i = 1, steps do + this.Steps[i].BackgroundColor3 = NON_SELECTED_COLOR + if i == 1 then + this.Steps[i].Image = NON_SELECTED_LEFT_IMAGE + elseif i == steps then + this.Steps[i].Image = NON_SELECTED_RIGHT_IMAGE + end + end + end + local function showSelection() + for i = 1, steps do + if i > currentStep then break end + this.Steps[i].BackgroundColor3 = SELECTED_COLOR + if i == 1 then + this.Steps[i].Image = SELECTED_LEFT_IMAGE + elseif i == steps then + this.Steps[i].Image = SELECTED_RIGHT_IMAGE + end + end + end + local function modifySelection(alpha) + for i = 1, steps do + if i == 1 or i == steps then + this.Steps[i].ImageTransparency = alpha + else + this.Steps[i].BackgroundTransparency = alpha + end + end + end + + local function setCurrentStep(newStepPosition) + if not minStep then minStep = 0 end + + leftButton.Visible = true + rightButton.Visible = true + + if newStepPosition <= minStep then + newStepPosition = minStep + leftButton.Visible = false + end + if newStepPosition >= steps then + newStepPosition = steps + rightButton.Visible = false + end + + if currentStep == newStepPosition then return end + + currentStep = newStepPosition + + hideSelection() + showSelection() + + timeAtLastInput = tick() + valueChangedEvent:Fire(currentStep) + end + + local function mouseDownFunc(inputObject, newStepPos, repeatAction) + if not interactable then return end + + if inputObject == nil then return end + if inputObject.UserInputType ~= Enum.UserInputType.MouseButton1 and inputObject.UserInputType ~= Enum.UserInputType.Touch then return end + + if usesSelectedObject() then + GuiService.SelectedCoreObject = this.SliderFrame + end + + if repeatAction then + lastInputDirection = newStepPos - currentStep + else + lastInputDirection = 0 + + local mouseInputMovedCon = nil + local mouseInputEndedCon = nil + mouseInputMovedCon = UserInputService.InputChanged:connect(function( inputObject ) + if inputObject.UserInputType ~= Enum.UserInputType.MouseMovement and inputObject.UserInputType ~= Enum.UserInputType.Touch then return end + + local mousePos = inputObject.Position.X + for i = 1, steps do + local stepPosition = this.Steps[i].AbsolutePosition.X + local stepSize = this.Steps[i].AbsoluteSize.X + if mousePos >= stepPosition and mousePos <= stepPosition + stepSize then + setCurrentStep(i) + break + elseif i == 1 and mousePos < stepPosition then + setCurrentStep(0) + break + elseif i == steps and mousePos >= stepPosition then + setCurrentStep(i) + break + end + end + end) + mouseInputEndedCon = UserInputService.InputEnded:connect(function( inputObject ) + if inputObject.UserInputType ~= Enum.UserInputType.MouseButton1 and inputObject.UserInputType ~= Enum.UserInputType.Touch then return end + + lastInputDirection = 0 + mouseInputEndedCon:disconnect() + mouseInputMovedCon:disconnect() + end) + end + + setCurrentStep(newStepPos) + end + + local function mouseUpFunc(inputObject) + if not interactable then return end + if inputObject.UserInputType ~= Enum.UserInputType.MouseButton1 then return end + + lastInputDirection = 0 + end + + local function touchClickFunc(inputObject, newStepPos, repeatAction) + mouseDownFunc(inputObject, newStepPos, repeatAction) + end + + --------------------- PUBLIC FACING FUNCTIONS ----------------------- + this.ValueChanged = valueChangedEvent.Event + + function this:SetValue(newValue) + setCurrentStep(newValue) + end + + function this:GetValue() + return currentStep + end + + function this:SetInteractable(value) + lastInputDirection = 0 + interactable = value + this.SliderFrame.Selectable = value + if not interactable then + hideSelection() + else + showSelection() + end + end + + function this:SetZIndex(newZIndex) + leftButton.ZIndex = newZIndex + rightButton.ZIndex = newZIndex + leftButtonImage.ZIndex = newZIndex + rightButtonImage.ZIndex = newZIndex + + for i = 1, #this.Steps do + this.Steps[i].ZIndex = newZIndex + end + end + + function this:SetMinStep(newMinStep) + if newMinStep >= 0 and newMinStep <= steps then + minStep = newMinStep + end + + if currentStep <= minStep then + currentStep = minStep + leftButton.Visible = false + end + if currentStep >= steps then + currentStep = steps + rightButton.Visible = false + end + end + + --------------------- SETUP ----------------------- + + leftButton.InputBegan:connect(function(inputObject) mouseDownFunc(inputObject, currentStep - 1, true) end) + leftButton.InputEnded:connect(function(inputObject) mouseUpFunc(inputObject) end) + leftButton.MouseButton1Click:connect(function() + if UserInputService.TouchEnabled and not UserInputService.GamepadEnabled then + touchClickFunc(inputObject, currentStep - 1, true) + end + end) + rightButton.InputBegan:connect(function(inputObject) mouseDownFunc(inputObject, currentStep + 1, true) end) + rightButton.InputEnded:connect(function(inputObject) mouseUpFunc(inputObject) end) + rightButton.MouseButton1Click:connect(function() + if UserInputService.TouchEnabled and not UserInputService.GamepadEnabled then + touchClickFunc(inputObject, currentStep + 1, true) + end + end) + + for i = 1, steps do + this.Steps[i].InputBegan:connect(function(inputObject) mouseDownFunc(inputObject, i) end) + this.Steps[i].InputEnded:connect(function(inputObject) mouseUpFunc(inputObject) end) + end + + this.SliderFrame.InputBegan:connect(function(inputObject) mouseDownFunc(inputObject, currentStep) end) + this.SliderFrame.InputEnded:connect(function(inputObject) mouseUpFunc(inputObject) end) + + + local stepSliderFunc = function() + if timeAtLastInput == nil then return end + + local currentTime = tick() + local timeSinceLastInput = currentTime - timeAtLastInput + + if timeSinceLastInput >= CONTROLLER_SCROLL_DELTA then + setCurrentStep(currentStep + lastInputDirection) + end + end + + local isInTree = true + UserInputService.InputBegan:connect(function(inputObject) + if not interactable then return end + if not isInTree then return end + + if inputObject.UserInputType ~= Enum.UserInputType.Gamepad1 and inputObject.UserInputType ~= Enum.UserInputType.Keyboard then return end + if GuiService.SelectedCoreObject ~= this.SliderFrame then return end + + if inputObject.KeyCode == Enum.KeyCode.DPadLeft or inputObject.KeyCode == Enum.KeyCode.Left or inputObject.KeyCode == Enum.KeyCode.A then + lastInputDirection = -1 + setCurrentStep(currentStep - 1) + elseif inputObject.KeyCode == Enum.KeyCode.DPadRight or inputObject.KeyCode == Enum.KeyCode.Right or inputObject.KeyCode == Enum.KeyCode.D then + lastInputDirection = 1 + setCurrentStep(currentStep + 1) + end + end) + + UserInputService.InputEnded:connect(function(inputObject) + if not interactable then return end + + if inputObject.UserInputType ~= Enum.UserInputType.Gamepad1 and inputObject.UserInputType ~= Enum.UserInputType.Keyboard then return end + if GuiService.SelectedCoreObject ~= this.SliderFrame then return end + + if inputObject.KeyCode == Enum.KeyCode.Thumbstick1 or inputObject.KeyCode == Enum.KeyCode.DPadLeft + or inputObject.KeyCode == Enum.KeyCode.DPadRight or inputObject.KeyCode == Enum.KeyCode.Left + or inputObject.KeyCode == Enum.KeyCode.A or inputObject.KeyCode == Enum.KeyCode.Right or inputObject.KeyCode == Enum.KeyCode.D then + lastInputDirection = 0 + end + end) + + UserInputService.InputChanged:connect(function(inputObject) + if not interactable then + lastInputDirection = 0 + return + end + if not isInTree then + lastInputDirection = 0 + return + end + + if inputObject.UserInputType ~= Enum.UserInputType.Gamepad1 then return end + if GuiService.SelectedCoreObject ~= this.SliderFrame then return end + if inputObject.KeyCode ~= Enum.KeyCode.Thumbstick1 then return end + + if inputObject.Position.X > CONTROLLER_THUMBSTICK_DEADZONE and inputObject.Delta.X > 0 and lastInputDirection ~= 1 then + lastInputDirection = 1 + setCurrentStep(currentStep + 1) + elseif inputObject.Position.X < -CONTROLLER_THUMBSTICK_DEADZONE and inputObject.Delta.X < 0 and lastInputDirection ~= -1 then + lastInputDirection = -1 + setCurrentStep(currentStep - 1) + elseif math.abs(inputObject.Position.X) < CONTROLLER_THUMBSTICK_DEADZONE then + lastInputDirection = 0 + end + end) + + GuiService.Changed:connect(function(prop) + if prop ~= "SelectedCoreObject" then return end + + if GuiService.SelectedCoreObject == this.SliderFrame then + modifySelection(0) + RunService:BindToRenderStep(renderStepBindName, Enum.RenderPriority.Input.Value + 1, stepSliderFunc) + else + modifySelection(0.36) + RunService:UnbindFromRenderStep(renderStepBindName) + end + end) + + this.SliderFrame.AncestryChanged:connect(function(child, parent) + isInTree = parent + end) + + setCurrentStep(currentStep) + + return this +end + +local ROW_HEIGHT = 50 +if isTenFootInterface() then ROW_HEIGHT = 90 end + +local nextPosTable = {} +local function AddNewRow(pageToAddTo, rowDisplayName, selectionType, rowValues, rowDefault, extraSpacing) + local nextRowPositionY = 0 + local isARealRow = selectionType ~= 'TextBox' -- Textboxes are constructed in this function - they don't have an associated class. + + if nextPosTable[pageToAddTo] then + nextRowPositionY = nextPosTable[pageToAddTo] + end + + local RowFrame = nil + RowFrame = Util.Create'ImageButton' + { + Name = rowDisplayName .. "Frame", + BackgroundTransparency = 1, + BorderSizePixel = 0, + Image = "", + Active = false, + AutoButtonColor = false, + Size = UDim2.new(1,0,0,ROW_HEIGHT), + Position = UDim2.new(0,0,0,nextRowPositionY), + ZIndex = 2, + Selectable = false, + Parent = pageToAddTo.Page + }; + + if RowFrame and extraSpacing then + RowFrame.Position = UDim2.new(RowFrame.Position.X.Scale,RowFrame.Position.X.Offset, + RowFrame.Position.Y.Scale,RowFrame.Position.Y.Offset + extraSpacing) + end + + local RowLabel = nil + RowLabel = Util.Create'TextLabel' + { + Name = rowDisplayName .. "Label", + Text = rowDisplayName, + Font = Enum.Font.SourceSansBold, + FontSize = Enum.FontSize.Size24, + TextColor3 = Color3.new(1,1,1), + TextXAlignment = Enum.TextXAlignment.Left, + BackgroundTransparency = 1, + Size = UDim2.new(0,200,1,0), + Position = UDim2.new(0,10,0,0), + ZIndex = 2, + Parent = RowFrame + }; + if isTenFootInterface() then + RowLabel.FontSize = Enum.FontSize.Size36 + end + if not isARealRow then + RowLabel.Text = '' + end + + local ValueChangerSelection = nil + local ValueChangerInstance = nil + if selectionType == "Slider" then + ValueChangerInstance = CreateNewSlider(rowValues, rowDefault) + ValueChangerInstance.SliderFrame.Position = UDim2.new(1,-ValueChangerInstance.SliderFrame.Size.X.Offset, + 0.5,-ValueChangerInstance.SliderFrame.Size.Y.Offset/2) + ValueChangerInstance.SliderFrame.Parent = RowFrame + ValueChangerSelection = ValueChangerInstance.SliderFrame + elseif selectionType == "Selector" then + ValueChangerInstance = CreateSelector(rowValues, rowDefault) + ValueChangerInstance.SelectorFrame.Position = UDim2.new(1,-ValueChangerInstance.SelectorFrame.Size.X.Offset, + 0.5,-ValueChangerInstance.SelectorFrame.Size.Y.Offset/2) + ValueChangerInstance.SelectorFrame.Parent = RowFrame + ValueChangerSelection = ValueChangerInstance.SelectorFrame + elseif selectionType == "DropDown" then + ValueChangerInstance = CreateDropDown(rowValues, rowDefault, pageToAddTo.HubRef) + ValueChangerInstance.DropDownFrame.Position = UDim2.new(1,-ValueChangerInstance.DropDownFrame.Size.X.Offset - 50, + 0.5,-ValueChangerInstance.DropDownFrame.Size.Y.Offset/2) + ValueChangerInstance.DropDownFrame.Parent = RowFrame + ValueChangerSelection = ValueChangerInstance.DropDownFrame + elseif selectionType == "TextBox" then + local isMouseOverRow = false + local forceReturnSelectionOnFocusLost = false + local SelectionOverrideObject = Util.Create'ImageLabel' + { + Image = "", + BackgroundTransparency = 1, + }; + + ValueChangerInstance = {} + ValueChangerInstance.HubRef = nil + + local box = Util.Create'TextBox' + { + Size = UDim2.new(1,-10,0,100), + Position = UDim2.new(0,5,0,nextRowPositionY), + Text = rowDisplayName, + TextColor3 = Color3.new(49/255, 49/255, 49/255), + BackgroundTransparency = 0.5, + BorderSizePixel = 0, + TextYAlignment = Enum.TextYAlignment.Top, + TextXAlignment = Enum.TextXAlignment.Left, + TextWrapped = true, + Font = Enum.Font.SourceSans, + FontSize = Enum.FontSize.Size24, + ZIndex = 2, + SelectionImageObject = SelectionOverrideObject, + ClearTextOnFocus = false, + Parent = pageToAddTo.Page + }; + ValueChangerSelection = box + + box.Focused:connect(function() + if usesSelectedObject() then + GuiService.SelectedCoreObject = box + end + + if box.Text == rowDisplayName then + box.Text = "" + end + end) + box.FocusLost:connect(function(enterPressed, inputObject) + if GuiService.SelectedCoreObject == box and (not isMouseOverRow or forceReturnSelectionOnFocusLost) then + GuiService.SelectedCoreObject = nil + end + forceReturnSelectionOnFocusLost = false + end) + if extraSpacing then + box.Position = UDim2.new(box.Position.X.Scale,box.Position.X.Offset, + box.Position.Y.Scale,box.Position.Y.Offset + extraSpacing) + end + + ValueChangerSelection.SelectionGained:connect(function() + if usesSelectedObject() then + box.BackgroundTransparency = 0.1 + + if ValueChangerInstance.HubRef then + ValueChangerInstance.HubRef:ScrollToFrame(ValueChangerSelection) + end + end + end) + ValueChangerSelection.SelectionLost:connect(function() + if usesSelectedObject() then + box.BackgroundTransparency = 0.5 + end + end) + + local setRowSelection = function() + local fullscreenDropDown = CoreGui.RobloxGui:FindFirstChild("DropDownFullscreenFrame") + if fullscreenDropDown and fullscreenDropDown.Visible then return end + + local valueFrame = ValueChangerSelection + + if valueFrame and valueFrame.Visible and valueFrame.ZIndex > 1 and usesSelectedObject() and pageToAddTo.Active then + GuiService.SelectedCoreObject = valueFrame + isMouseOverRow = true + end + end + local function processInput(input) + if input.UserInputState == Enum.UserInputState.Begin then + if input.KeyCode == Enum.KeyCode.Return then + if GuiService.SelectedCoreObject == ValueChangerSelection then + forceReturnSelectionOnFocusLost = true + box:CaptureFocus() + end + end + end + end + RowFrame.MouseEnter:connect(setRowSelection) + RowFrame.Size = UDim2.new(1, 0, 0, 100) + + UserInputService.InputBegan:connect(processInput) + + elseif selectionType == "TextEntry" then + local isMouseOverRow = false + local forceReturnSelectionOnFocusLost = false + local SelectionOverrideObject = Util.Create'ImageLabel' + { + Image = "", + BackgroundTransparency = 1, + }; + + ValueChangerInstance = {} + ValueChangerInstance.HubRef = nil + + local box = Util.Create'TextBox' + { + Size = UDim2.new(0.4,-10,0,40), + Position = UDim2.new(0.5,5,0,nextRowPositionY+5), + Text = rowDisplayName, + TextColor3 = Color3.new(0.7, 0.7, 0.7), + BackgroundTransparency = 1.0, + BorderSizePixel = 0, + TextYAlignment = Enum.TextYAlignment.Center, + TextXAlignment = Enum.TextXAlignment.Center, + TextWrapped = false, + Font = Enum.Font.SourceSans, + FontSize = Enum.FontSize.Size24, + ZIndex = 2, + SelectionImageObject = SelectionOverrideObject, + ClearTextOnFocus = false, + Parent = pageToAddTo.Page + }; + ValueChangerSelection = box + + box.Focused:connect(function() + if usesSelectedObject() then + GuiService.SelectedCoreObject = box + end + + if box.Text == rowDisplayName then + box.Text = "" + end + end) + box.FocusLost:connect(function(enterPressed, inputObject) + if GuiService.SelectedCoreObject == box and (not isMouseOverRow or forceReturnSelectionOnFocusLost) then + GuiService.SelectedCoreObject = nil + end + forceReturnSelectionOnFocusLost = false + end) + if extraSpacing then + box.Position = UDim2.new(box.Position.X.Scale,box.Position.X.Offset, + box.Position.Y.Scale,box.Position.Y.Offset + extraSpacing) + end + + ValueChangerSelection.SelectionGained:connect(function() + if usesSelectedObject() then + box.BackgroundTransparency = 0.8 + + if ValueChangerInstance.HubRef then + ValueChangerInstance.HubRef:ScrollToFrame(ValueChangerSelection) + end + end + end) + ValueChangerSelection.SelectionLost:connect(function() + if usesSelectedObject() then + box.BackgroundTransparency = 1.0 + end + end) + + local setRowSelection = function() + local fullscreenDropDown = CoreGui.RobloxGui:FindFirstChild("DropDownFullscreenFrame") + if fullscreenDropDown and fullscreenDropDown.Visible then return end + + local valueFrame = ValueChangerSelection + + if valueFrame and valueFrame.Visible and valueFrame.ZIndex > 1 and usesSelectedObject() and pageToAddTo.Active then + GuiService.SelectedCoreObject = valueFrame + isMouseOverRow = true + end + end + local function processInput(input) + if input.UserInputState == Enum.UserInputState.Begin then + if input.KeyCode == Enum.KeyCode.Return then + if GuiService.SelectedCoreObject == ValueChangerSelection then + forceReturnSelectionOnFocusLost = true + box:CaptureFocus() + end + end + end + end + RowFrame.MouseEnter:connect(setRowSelection) + + function ValueChangerInstance:SetZIndex(newZIndex) + box.ZIndex = newZIndex + end + + function ValueChangerInstance:SetInteractable(value) + interactable = value + box.Selectable = interactable + if not interactable then + box.TextColor3 = Color3.new(49/255, 49/255, 49/255) + box.ZIndex = 1 + else + box.TextColor3 = Color3.new(0.7, 0.7, 0.7) + box.ZIndex = 2 + end + end + + function ValueChangerInstance:SetValue(value) -- should this do more? + box.Text = value + end + + local valueChangedEvent = Instance.new("BindableEvent") + valueChangedEvent.Name = "ValueChanged" + + box.FocusLost:connect(function() + valueChangedEvent:Fire(box.Text) + end) + + ValueChangerInstance.ValueChanged = valueChangedEvent.Event + + UserInputService.InputBegan:connect(processInput) + end + + ValueChangerInstance.Name = rowDisplayName .. "ValueChanger" + + nextRowPositionY = nextRowPositionY + ROW_HEIGHT + if extraSpacing then + nextRowPositionY = nextRowPositionY + extraSpacing + end + + nextPosTable[pageToAddTo] = nextRowPositionY + + if isARealRow then + local setRowSelection = function() + local fullscreenDropDown = CoreGui.RobloxGui:FindFirstChild("DropDownFullscreenFrame") + if fullscreenDropDown and fullscreenDropDown.Visible then return end + + local valueFrame = ValueChangerInstance.SliderFrame + if not valueFrame then + valueFrame = ValueChangerInstance.SliderFrame + end + if not valueFrame then + valueFrame = ValueChangerInstance.DropDownFrame + end + if not valueFrame then + valueFrame = ValueChangerInstance.SelectorFrame + end + + if valueFrame and valueFrame.Visible and valueFrame.ZIndex > 1 and usesSelectedObject() and pageToAddTo.Active then + GuiService.SelectedCoreObject = valueFrame + end + end + RowFrame.MouseEnter:connect(setRowSelection) + + ValueChangerSelection.SelectionGained:connect(function() + if usesSelectedObject() then + RowFrame.BackgroundTransparency = 0.5 + + if ValueChangerInstance.HubRef then + ValueChangerInstance.HubRef:ScrollToFrame(RowFrame) + end + end + end) + ValueChangerSelection.SelectionLost:connect(function() + if usesSelectedObject() then + RowFrame.BackgroundTransparency = 1 + end + end) + end + + pageToAddTo:AddRow(RowFrame, RowLabel, ValueChangerInstance, extraSpacing, false) + + ValueChangerInstance.Selection = ValueChangerSelection + + return RowFrame, RowLabel, ValueChangerInstance +end + +local function AddNewRowObject(pageToAddTo, rowDisplayName, rowObject, extraSpacing) + local nextRowPositionY = 0 + + if nextPosTable[pageToAddTo] then + nextRowPositionY = nextPosTable[pageToAddTo] + end + + local RowFrame = Util.Create'ImageButton' + { + Name = rowDisplayName .. "Frame", + BackgroundTransparency = 1, + BorderSizePixel = 0, + Image = "", + Active = false, + AutoButtonColor = false, + Size = UDim2.new(1,0,0,ROW_HEIGHT), + Position = UDim2.new(0,0,0,nextRowPositionY), + ZIndex = 2, + Selectable = false, + SelectionImageObject = noSelectionObject, + Parent = pageToAddTo.Page + }; + RowFrame.SelectionGained:connect(function() + RowFrame.BackgroundTransparency = 0.5 + end) + RowFrame.SelectionLost:connect(function() + RowFrame.BackgroundTransparency = 1 + end) + + local RowLabel = Util.Create'TextLabel' + { + Name = rowDisplayName .. "Label", + Text = rowDisplayName, + Font = Enum.Font.SourceSansBold, + FontSize = Enum.FontSize.Size24, + TextColor3 = Color3.new(1,1,1), + TextXAlignment = Enum.TextXAlignment.Left, + BackgroundTransparency = 1, + Size = UDim2.new(0,200,1,0), + Position = UDim2.new(0,10,0,0), + ZIndex = 2, + Parent = RowFrame + }; + if isTenFootInterface() then + RowLabel.FontSize = Enum.FontSize.Size36 + end + + if extraSpacing then + RowFrame.Position = UDim2.new(RowFrame.Position.X.Scale,RowFrame.Position.X.Offset, + RowFrame.Position.Y.Scale,RowFrame.Position.Y.Offset + extraSpacing) + end + + nextRowPositionY = nextRowPositionY + ROW_HEIGHT + if extraSpacing then + nextRowPositionY = nextRowPositionY + extraSpacing + end + + nextPosTable[pageToAddTo] = nextRowPositionY + + local setRowSelection = function() + if RowFrame.Visible then + GuiService.SelectedCoreObject = RowFrame + end + end + RowFrame.MouseEnter:connect(setRowSelection) + + rowObject.SelectionImageObject = noSelectionObject + + rowObject.SelectionGained:connect(function() + RowFrame.BackgroundTransparency = 0.5 + end) + rowObject.SelectionLost:connect(function() + RowFrame.BackgroundTransparency = 1 + end) + + rowObject.Parent = RowFrame + + pageToAddTo:AddRow(RowFrame, RowLabel, rowObject, extraSpacing, true) + return RowFrame +end + +-------- public facing API ---------------- +local moduleApiTable = {} + +function moduleApiTable:Create(instanceType) + return function(data) + local obj = Instance.new(instanceType) + for k, v in pairs(data) do + if type(k) == 'number' then + v.Parent = obj + else + obj[k] = v + end + end + return obj + end +end + +function moduleApiTable:GetEaseLinear() + return Linear +end +function moduleApiTable:GetEaseOutQuad() + return EaseOutQuad +end +function moduleApiTable:GetEaseInOutQuad() + return EaseInOutQuad +end + +function moduleApiTable:CreateNewSlider(numOfSteps, startStep, minStep) + return CreateNewSlider(numOfSteps, startStep, minStep) +end + +function moduleApiTable:CreateNewSelector(selectionStringTable, startPosition) + return CreateSelector(selectionStringTable, startPosition) +end + +function moduleApiTable:CreateNewDropDown(dropDownStringTable, startPosition) + return CreateDropDown(dropDownStringTable, startPosition, nil) +end + +function moduleApiTable:AddNewRow(pageToAddTo, rowDisplayName, selectionType, rowValues, rowDefault, extraSpacing) + return AddNewRow(pageToAddTo, rowDisplayName, selectionType, rowValues, rowDefault, extraSpacing) +end + +function moduleApiTable:AddNewRowObject(pageToAddTo, rowDisplayName, rowObject, extraSpacing) + return AddNewRowObject(pageToAddTo, rowDisplayName, rowObject, extraSpacing) +end + +function moduleApiTable:ShowAlert(alertMessage, okButtonText, settingsHub, okPressedFunc, hasBackground) + ShowAlert(alertMessage, okButtonText, settingsHub, okPressedFunc, hasBackground) +end + +function moduleApiTable:IsSmallTouchScreen() + return isSmallTouchScreen() +end + +function moduleApiTable:MakeStyledButton(name, text, size, clickFunc, pageRef, hubRef) + return MakeButton(name, text, size, clickFunc, pageRef, hubRef) +end + +function moduleApiTable:CreateSignal() + return CreateSignal() +end + +function moduleApiTable:UsesSelectedObject() + return usesSelectedObject(); +end + +function moduleApiTable:TweenProperty(instance, prop, start, final, duration, easingFunc, cbFunc) + return PropertyTweener(instance, prop, start, final, duration, easingFunc, cbFunc) +end + +return moduleApiTable + diff --git a/2016/content/Modules/TenFootInterface.lua b/2016/content/Modules/TenFootInterface.lua new file mode 100644 index 0000000..0e92d97 --- /dev/null +++ b/2016/content/Modules/TenFootInterface.lua @@ -0,0 +1,345 @@ +--[[ + Filename: TenFootInterface.lua + Written by: jeditkacheff + Version 1.0 + Description: Setups up some special UI for ROBLOX TV gaming +--]] +-------------- CONSTANTS -------------- +local HEALTH_GREEN_COLOR = Color3.new(27/255, 252/255, 107/255) +local DISPLAY_POS_INIT_INSET = 0 +local DISPLAY_ITEM_OFFSET = 4 +local FORCE_TEN_FOOT_INTERFACE = false + +-------------- SERVICES -------------- +local CoreGui = game:GetService("CoreGui") +local RobloxGui = CoreGui:WaitForChild("RobloxGui") +local UserInputService = game:GetService("UserInputService") +local GuiService = game:GetService("GuiService") + +------------------ VARIABLES -------------------- +local tenFootInterfaceEnabled = false +do + local platform = UserInputService:GetPlatform() + + tenFootInterfaceEnabled = (platform == Enum.Platform.XBoxOne or platform == Enum.Platform.WiiU or platform == Enum.Platform.PS4 or + platform == Enum.Platform.AndroidTV or platform == Enum.Platform.XBox360 or platform == Enum.Platform.PS3 or + platform == Enum.Platform.Ouya or platform == Enum.Platform.SteamOS) +end + +if FORCE_TEN_FOOT_INTERFACE then + tenFootInterfaceEnabled = true +end + +local Util = {} +do + function Util.Create(instanceType) + return function(data) + local obj = Instance.new(instanceType) + for k, v in pairs(data) do + if type(k) == 'number' then + v.Parent = obj + else + obj[k] = v + end + end + return obj + end + end +end + +local function CreateModule() + local this = {} + local nextObjectDisplayYPos = DISPLAY_POS_INIT_INSET + local displayStack = {} + + -- setup base gui + local function createContainer() + if not this.Container then + this.Container = Util.Create'ImageButton' + { + Name = "TopRightContainer"; + Size = UDim2.new(0, 350, 0, 100); + Position = UDim2.new(1,-360,0,10); + AutoButtonColor = false; + Image = ""; + Active = false; + BackgroundTransparency = 1; + Parent = RobloxGui; + }; + end + end + + function removeFromDisplayStack(displayObject) + local moveUpFromHere = nil + + for i = 1, #displayStack do + if displayStack[i] == displayObject then + moveUpFromHere = i + 1 + break + end + end + + local prevObject = displayObject + for i = moveUpFromHere, #displayStack do + local objectToMoveUp = displayStack[i] + objectToMoveUp.Position = UDim2.new(objectToMoveUp.Position.X.Scale, objectToMoveUp.Position.X.Offset, + objectToMoveUp.Position.Y.Scale, prevObject.AbsolutePosition.Y) + prevObject = objectToMoveUp + end + end + + function addBackToDisplayStack(displayObject) + for i = 1, #displayStack do + if displayStack[i] == displayObject then + moveDownFromHere = i + 1 + break + end + end + + local prevObject = displayObject + for i = moveDownFromHere, #displayStack do + local objectToMoveDown = displayStack[i] + local nextDisplayPos = prevObject.AbsolutePosition.Y + prevObject.AbsoluteSize.Y + DISPLAY_ITEM_OFFSET + objectToMoveDown.Position = UDim2.new(objectToMoveDown.Position.X.Scale, objectToMoveDown.Position.X.Offset, + objectToMoveDown.Position.Y.Scale, nextDisplayPos) + prevObject = objectToMoveDown + end + end + + function addToDisplayStack(displayObject) + local lastDisplayed = nil + if #displayStack > 0 then + lastDisplayed = displayStack[#displayStack] + end + displayStack[#displayStack + 1] = displayObject + + local nextDisplayPos = DISPLAY_POS_INIT_INSET + if lastDisplayed then + nextDisplayPos = lastDisplayed.AbsolutePosition.Y + lastDisplayed.AbsoluteSize.Y + DISPLAY_ITEM_OFFSET + end + + displayObject.Position = UDim2.new(displayObject.Position.X.Scale, displayObject.Position.X.Offset, + displayObject.Position.Y.Scale, nextDisplayPos) + + createContainer() + displayObject.Parent = this.Container + + displayObject.Changed:connect(function(prop) + if prop == "Visible" then + if not displayObject.Visible then + removeFromDisplayStack(displayObject) + else + addBackToDisplayStack(displayObject) + end + end + end) + end + + function this:CreateHealthBar() + this.HealthContainer = Util.Create'Frame'{ + Name = "HealthContainer"; + Size = UDim2.new(1, -86, 0, 50); + Position = UDim2.new(0, 92, 0, 0); + BorderSizePixel = 0; + BackgroundColor3 = Color3.new(0,0,0); + BackgroundTransparency = 0.5; + }; + + local healthFillHolder = Util.Create'Frame'{ + Name = "HealthFillHolder"; + Size = UDim2.new(1, -10, 1, -10); + Position = UDim2.new(0, 5, 0, 5); + BorderSizePixel = 0; + BackgroundColor3 = Color3.new(1,1,1); + BackgroundTransparency = 1.0; + Parent = this.HealthContainer; + }; + + local healthFill = Util.Create'Frame'{ + Name = "HealthFill"; + Size = UDim2.new(1, 0, 1, 0); + Position = UDim2.new(0, 0, 0, 0); + BorderSizePixel = 0; + BackgroundTransparency = 0.0; + BackgroundColor3 = HEALTH_GREEN_COLOR; + Parent = healthFillHolder; + }; + + local healthText = Util.Create'TextLabel'{ + Name = "HealthText"; + Size = UDim2.new(0, 98, 0, 50); + Position = UDim2.new(0, -100, 0, 0); + BackgroundTransparency = 0.5; + BackgroundColor3 = Color3.new(0,0,0); + Font = Enum.Font.SourceSans; + FontSize = Enum.FontSize.Size36; + Text = "Health"; + TextColor3 = Color3.new(1,1,1); + BorderSizePixel = 0; + Parent = this.HealthContainer; + }; + + local username = Util.Create'TextLabel'{ + Visible = false + } + + addToDisplayStack(this.HealthContainer) + createContainer() + + return this.Container, username, this.HealthContainer, healthFill + end + + function this:SetupTopStat() + local topStatEnabled = true + local displayedStat = nil + local displayedStatChangedCon = nil + local displayedStatParentedCon = nil + local leaderstatsChildAddedCon = nil + local tenFootInterfaceStat = nil + + local function makeTenFootInterfaceStat() + if tenFootInterfaceStat then return end + + tenFootInterfaceStat = Util.Create'Frame'{ + Name = "OneStatFrame"; + Size = UDim2.new(1, 0, 0, 36); + Position = UDim2.new(0, 0, 0, 0); + BorderSizePixel = 0; + BackgroundTransparency = 1; + }; + local statName = Util.Create'TextLabel'{ + Name = "StatName"; + Size = UDim2.new(0.5,0,0,36); + BackgroundTransparency = 1; + Font = Enum.Font.SourceSans; + FontSize = Enum.FontSize.Size36; + TextStrokeColor3 = Color3.new(104/255, 104/255, 104/255); + TextStrokeTransparency = 0; + Text = " StatName:"; + TextColor3 = Color3.new(1,1,1); + TextXAlignment = Enum.TextXAlignment.Left; + BorderSizePixel = 0; + ClipsDescendants = true; + Parent = tenFootInterfaceStat; + }; + local statValue = statName:clone() + statValue.Position = UDim2.new(0.5,0,0,0) + statValue.Name = "StatValue" + statValue.Text = "123,643,231" + statValue.TextXAlignment = Enum.TextXAlignment.Right + statValue.Parent = tenFootInterfaceStat + + addToDisplayStack(tenFootInterfaceStat) + end + + local function setDisplayedStat(newStat) + if displayedStatChangedCon then displayedStatChangedCon:disconnect() displayedStatChangedCon = nil end + if displayedStatParentedCon then displayedStatParentedCon:disconnect() displayedStatParentedCon = nil end + + displayedStat = newStat + + if displayedStat then + makeTenFootInterfaceStat() + updateTenFootStat(displayedStat) + displayedStatParentedCon = displayedStat.AncestryChanged:connect(function() updateTenFootStat(displayedStat, "Parent") end) + displayedStatChangedCon = displayedStat.Changed:connect(function(prop) updateTenFootStat(displayedStat, prop) end) + end + end + + function updateTenFootStat(statObj, property) + if property and property == "Parent" then + tenFootInterfaceStat.StatName.Text = "" + tenFootInterfaceStat.StatValue.Text = "" + setDisplayedStat(nil) + + tenFootInterfaceChanged() + else + if topStatEnabled then + tenFootInterfaceStat.StatName.Text = " " .. tostring(statObj.Name) .. ":" + tenFootInterfaceStat.StatValue.Text = tostring(statObj.Value) + else + tenFootInterfaceStat.StatName.Text = "" + tenFootInterfaceStat.StatValue.Text = "" + end + end + end + + local function isValidStat(obj) + return obj:IsA('StringValue') or obj:IsA('IntValue') or obj:IsA('BoolValue') or obj:IsA('NumberValue') or + obj:IsA('DoubleConstrainedValue') or obj:IsA('IntConstrainedValue') + end + + local function tenFootInterfaceNewStat( newStat ) + if not displayedStat and isValidStat(newStat) then + setDisplayedStat(newStat) + end + end + + function tenFootInterfaceChanged() + game:WaitForChild("Players") + while not game.Players.LocalPlayer do + wait() + end + + local leaderstats = game.Players.LocalPlayer:FindFirstChild('leaderstats') + if leaderstats then + local statChildren = leaderstats:GetChildren() + for i = 1, #statChildren do + tenFootInterfaceNewStat(statChildren[i]) + end + if leaderstatsChildAddedCon then leaderstatsChildAddedCon:disconnect() end + leaderstatsChildAddedCon = leaderstats.ChildAdded:connect(function(newStat) + tenFootInterfaceNewStat(newStat) + end) + end + end + + game:WaitForChild("Players") + while not game.Players.LocalPlayer do + wait() + end + + local leaderstats = game.Players.LocalPlayer:FindFirstChild('leaderstats') + if leaderstats then + tenFootInterfaceChanged() + else + game.Players.LocalPlayer.ChildAdded:connect(tenFootInterfaceChanged) + end + + --Top Stat Public API + + local topStatApiTable = {} + + function topStatApiTable:SetTopStatEnabled(value) + topStatEnabled = value + if displayedStat then + updateTenFootStat(displayedStat, "") + end + end + + return topStatApiTable + end + + return this +end + + +-- Public API + +local moduleApiTable = {} + + local TenFootInterfaceModule = CreateModule() + + function moduleApiTable:IsEnabled() + return tenFootInterfaceEnabled + end + + function moduleApiTable:CreateHealthBar() + return TenFootInterfaceModule:CreateHealthBar() + end + + function moduleApiTable:SetupTopStat() + return TenFootInterfaceModule:SetupTopStat() + end + +return moduleApiTable \ No newline at end of file diff --git a/2016/content/Modules/VR/Panel3D.lua b/2016/content/Modules/VR/Panel3D.lua new file mode 100644 index 0000000..d928754 --- /dev/null +++ b/2016/content/Modules/VR/Panel3D.lua @@ -0,0 +1,808 @@ +--Panel3D: 3D GUI panels for VR +--written by 0xBAADF00D +--revised/refactored 5/11/16 + +local UserInputService = game:GetService("UserInputService") +local RunService = game:GetService("RunService") +local GuiService = game:GetService("GuiService") +local CoreGui = game:GetService("CoreGui") +local RobloxGui = CoreGui:WaitForChild("RobloxGui") +local PlayersService = game.Players + + +--Util +local Util = {} +do + function Util.Create(instanceType) + return function(data) + local obj = Instance.new(instanceType) + for k, v in pairs(data) do + if type(k) == 'number' then + v.Parent = obj + else + obj[k] = v + end + end + return obj + end + end + + -- RayPlaneIntersection (shortened) + -- http://www.siggraph.org/education/materials/HyperGraph/raytrace/rayplane_intersection.htm + function Util.RayPlaneIntersection(ray, planeNormal, pointOnPlane) + planeNormal = planeNormal.unit + ray = ray.Unit + + local Vd = planeNormal:Dot(ray.Direction) + if Vd == 0 then -- parallel, no intersection + return nil + end + + local V0 = planeNormal:Dot(pointOnPlane - ray.Origin) + local t = V0 / Vd + if t < 0 then --plane is behind ray origin, and thus there is no intersection + return nil + end + + return ray.Origin + ray.Direction * t + end +end +--End of Util + + +--Panel3D State variables +local renderStepName = "Panel3DRenderStep-" .. game:GetService("HttpService"):GenerateGUID() +local defaultPixelsPerStud = 64 +local pointUpCF = CFrame.Angles(math.rad(-90), math.rad(180), 0) +local zeroVector = Vector3.new(0, 0, 0) +local zeroVector2 = Vector2.new(0, 0) +local turnAroundCF = CFrame.Angles(0, math.rad(180), 0) +local fullyOpaqueAtPixelsFromEdge = 10 +local fullyTransparentAtPixelsFromEdge = 80 +local partThickness = 0.2 + +local cursorHidden = false +local cursorHideTime = 2.5 + +local currentModal = nil +local lastModal = nil +local currentMaxDist = math.huge +local currentClosest = nil +local lastClosest = nil +local currentHeadScale = 1 +local panels = {} +local floorRotation = CFrame.new() +local cursor = Util.Create "ImageLabel" { + Image = "rbxasset://textures/Cursors/Gamepad/Pointer.png", + Size = UDim2.new(0, 8, 0, 8), + BackgroundTransparency = 1, + ZIndex = 10 +} +--End of Panel3D State variables + + +--Panel3D Declaration and enumerations +local Panel3D = {} +Panel3D.Type = { + None = 0, + Floor = 1, + Fixed = 2, + HorizontalFollow = 3, + FixedToHead = 4 +} + +Panel3D.OnPanelClosed = Util.Create 'BindableEvent' { + Name = 'OnPanelClosed' +} + +function Panel3D.GetHeadLookXZ(withTranslation) + local userHeadCF = UserInputService:GetUserCFrame(Enum.UserCFrame.Head) + local headLook = userHeadCF.lookVector + local headYaw = math.atan2(-headLook.Z, headLook.X) + math.rad(90) + local cf = CFrame.Angles(0, headYaw, 0) + + if withTranslation then + cf = cf + userHeadCF.p + end + return cf +end + +function Panel3D.FindContainerOf(element) + for i, v in pairs(panels) do + if v.gui and v.gui:IsAncestorOf(element) then + return v + end + end + return nil +end + +function Panel3D.SetModalPanel(panel) + if currentModal == panel then + return + end + if currentModal then + currentModal:OnModalChanged(false) + end + if panel then + panel:OnModalChanged(true) + end + lastModal = currentModal + currentModal = panel +end +--End of Panel3D Declaration and enumerations + + +--Cursor autohiding methods +local cursorHidden = false +local hasTool = false +local lastMouseActivity = tick() +local lastMouseBehavior = Enum.MouseBehavior.Default + +local function OnCharacterAdded(character) + hasTool = false + for i, v in ipairs(character:GetChildren()) do + if v:IsA("Tool") then + hasTool = true + end + end + character.ChildAdded:connect(function(child) + if child:IsA("Tool") then + hasTool = true + lastMouseActivity = tick() --kick the mouse when a tool is equipped + end + end) + character.ChildRemoved:connect(function(child) + if child:IsA("Tool") then + hasTool = false + end + end) +end +spawn(function() + while not PlayersService.LocalPlayer do wait() end + PlayersService.LocalPlayer.CharacterAdded:connect(OnCharacterAdded) + if PlayersService.LocalPlayer.Character then OnCharacterAdded(PlayersService.LocalPlayer.Character) end +end) +local function autoHideCursor(hide) + if not UserInputService.VREnabled then + cursorHidden = false + return + end + if hide then + --don't hide if there's a tool in the character + local character = PlayersService.LocalPlayer.Character + if character and hasTool then + return + end + cursorHidden = true + UserInputService.OverrideMouseIconBehavior = Enum.OverrideMouseIconBehavior.ForceHide + else + cursorHidden = false + UserInputService.OverrideMouseIconBehavior = Enum.OverrideMouseIconBehavior.None + end +end + +local function isCursorVisible() + --if ForceShow, the cursor is definitely visible at all times + if UserInputService.OverrideMouseIconBehavior == Enum.OverrideMouseIconBehavior.ForceShow then + return true + end + --if ForceHide, the cursor is definitely NOT visible + if UserInputService.OverrideMouseIconBehavior == Enum.OverrideMouseIconBehavior.ForceHide then + return false + end + --Otherwise, we need to check if the developer set MouseIconEnabled=false + if UserInputService.MouseIconEnabled and UserInputService.OverrideMouseIconBehavior == Enum.OverrideMouseIconBehavior.None then + return true + end + return false +end + +--End of cursor autohiding methods + + +--Panel class implementation +local Panel = {} +Panel.mt = { __index = Panel } +function Panel.new(name) + local instance = { + name = name, + + part = nil, + gui = nil, + + width = 1, + height = 1, + + isVisible = false, + isEnabled = false, + panelType = Panel3D.Type.None, + pixelScale = 1, + showCursor = true, + canFade = true, + shouldFindLookAtGuiElement = false, + ignoreModal = false, + + linkedTo = nil, + subpanels = {}, + + transparency = 1, + forceShowUntilLookedAt = false, + isLookedAt = false, + isOffscreen = true, + lookAtPixel = Vector2.new(-1, -1), + lookAtDistance = math.huge, + lookAtGuiElement = nil, + isClosest = true + } + + if panels[name] then + error("A panel by the name of " .. name .. " already exists.") + end + panels[name] = instance + + return setmetatable(instance, Panel.mt) +end + +--Panel accessor methods +function Panel:GetPart() + if not self.part then + self.part = Util.Create "Part" { + Name = self.name, + Parent = nil, + + Transparency = 1, + + CanCollide = false, + Anchored = true, + Archivable = false, + + Size = Vector3.new(1, 1, partThickness) + } + end + return self.part +end + +function Panel:GetGUI() + if not self.gui then + local part = self:GetPart() + self.gui = Util.Create "SurfaceGui" { + Parent = CoreGui, + Adornee = part, + Active = true, + ToolPunchThroughDistance = 1000, + CanvasSize = Vector2.new(0, 0), + Enabled = self.isEnabled, + AlwaysOnTop = true + } + end + return self.gui +end + +function Panel:FindHoveredGuiElement(elements) + local x, y = self.lookAtPixel.X, self.lookAtPixel.Y + for i, v in pairs(elements) do + local minPt = v.AbsolutePosition + local maxPt = v.AbsolutePosition + v.AbsoluteSize + if minPt.X <= x and maxPt.X >= x and + minPt.Y <= y and maxPt.Y >= y then + return v, i + end + end +end +--End of panel accessor methods + + +--Panel update methods +function Panel:SetPartCFrame(cframe) + self:GetPart().CFrame = cframe * CFrame.new(0, 0, -0.5 * partThickness) +end + +function Panel:SetEnabled(enabled) + if self.isEnabled == enabled then + return + end + + self.isEnabled = enabled + if enabled then + self:GetPart().Parent = workspace.CurrentCamera --todo: Perhaps this can change soon. + self:GetGUI().Enabled = true + for i, v in pairs(self.subpanels) do + v:GetPart().Parent = workspace.CurrentCamera + v:GetGUI().Enabled = true + end + else + self:GetPart().Parent = nil + self:GetGUI().Enabled = false + for i, v in pairs(self.subpanels) do + v:GetPart().Parent = nil + v:GetGUI().Enabled = false + end + end + + self:OnEnabled(enabled) +end + +function Panel:EvaluatePositioning(cameraCF, cameraRenderCF, userHeadCF) + if self.panelType == Panel3D.Type.Floor then + --Floor panels simply... go on the floor. + --Panel will be in camera's local space (which is assumed to be horizontal), + --and floorRotation is derived from the user's head rotation (yaw only) + local floorCF = cameraCF * CFrame.new(0, -headHeightFromFloor * currentHeadScale, 0) * floorRotation + self:SetPartCFrame(floorCF * pointUpCF) + elseif self.panelType == Panel3D.Type.Fixed then + --Places the panel in the camera's local space, but doesn't follow the user's head. + --Useful if you know what you're doing. localCF can be updated in PreUpdate for animation. + local cf = self.localCF - self.localCF.p + cf = cf + (self.localCF.p * currentHeadScale) + self:SetPartCFrame(cameraCF * cf) + elseif self.panelType == Panel3D.Type.HorizontalFollow then + local headLook = userHeadCF.lookVector + local headYaw = math.atan2(-headLook.Z, headLook.X) + math.rad(90) + local headForwardCF = CFrame.Angles(0, headYaw, 0) + userHeadCF.p + local localCF = (headForwardCF * self.angleFromForward) * --Rotate about Y (left-right) + self.angleFromHorizon * --Rotate about X (up-down) + (currentHeadScale * self.distance) * --Move into scene + turnAroundCF --Turn around to face character + self:SetPartCFrame(cameraCF * localCF) + elseif self.panelType == Panel3D.Type.FixedToHead then + --Places the panel in the user's head local space. localCF can be updated in PreUpdate for animation. + local cf = self.localCF - self.localCF.p + cf = cf + (self.localCF.p * currentHeadScale) + self:SetPartCFrame(cameraRenderCF * cf) + end +end + +function Panel:EvaluateGaze(cameraCF, cameraRenderCF, userHeadCF, lookRay) + --reset distance data + self.isClosest = false + self.lookAtPixel = zeroVector2 + self.lookAtDistance = math.huge + + --Evaluate the lookRay versus this panel + local planeCF = self:GetPart().CFrame + local planeNormal = planeCF.lookVector + local pointOnPlane = planeCF.p + (planeNormal * partThickness * 0.5) --Move the point out by half the thickness of the part + + local worldIntersectPoint = Util.RayPlaneIntersection(lookRay, planeNormal, pointOnPlane) + if worldIntersectPoint then + self.isOffscreen = false + + --transform worldIntersectPoint to gui space + local gui = self:GetGUI() + local guiWidth, guiHeight = gui.AbsoluteSize.X, gui.AbsoluteSize.Y + local localIntersectPoint = (planeCF:pointToObjectSpace(worldIntersectPoint) / currentHeadScale) * Vector3.new(-1, 1, 1) + Vector3.new(self.width / 2, -self.height / 2, 0) + self.lookAtPixel = Vector2.new((localIntersectPoint.X / self.width) * gui.AbsoluteSize.X, (localIntersectPoint.Y / self.height) * -gui.AbsoluteSize.Y) + + --fire mouse enter/leave events if necessary + local guiX, guiY = self.lookAtPixel.X, self.lookAtPixel.Y + if guiX >= 0 and guiX <= guiWidth and + guiY >= 0 and guiY <= guiHeight then + if not self.isLookedAt then + self.isLookedAt = true + self:OnMouseEnter(guiX, guiY) + if self.forceShowUntilLookedAt then + self.forceShowUntilLookedAt = false + end + end + else + if self.isLookedAt then + self.isLookedAt = false + self:OnMouseLeave(guiX, guiY) + end + end + + --evaluate distance + self.lookAtDistance = (worldIntersectPoint - cameraRenderCF.p).magnitude + if self.isLookedAt and self.lookAtDistance < currentMaxDist and self.showCursor then + currentMaxDist = self.lookAtDistance + currentClosest = self + end + else + self.isOffscreen = true + + --Not looking at the plane at all, so fire off mouseleave if necessary. + if self.isLookedAt then + self.isLookedAt = false + self:OnMouseLeave(self.lookAtPixel.X, self.lookAtPixel.Y) + end + end +end + +function Panel:EvaluateTransparency() + --Early exit if force shown + if self.forceShowUntilLookedAt then + self.transparency = 0 + return + end + --Early exit if we're looking at the panel (no transparency!) + if self.isLookedAt then + self.transparency = 0 + return + end + --Similarly, exit if we can't possibly see the panel. + if self.isOffscreen then + self.transparency = 1 + return + end + --Otherwise, we'll want to calculate the transparency. + self.transparency = self:CalculateTransparency() +end + +function Panel:Update(cameraCF, cameraRenderCF, userHeadCF, lookRay) + if self.forceShowUntilLookedAt and not self.part then + self:GetPart() + self:GetGUI() + end + if not self.part then + return + end + + local isModal = (currentModal == self) + if not isModal and self.linkedTo and self.linkedTo == currentModal then + isModal = true + end + if currentModal and not isModal then + self:SetEnabled(false) + return + end + + self:PreUpdate(cameraCF, cameraRenderCF, userHeadCF, lookRay) + if self.isVisible then + self:EvaluatePositioning(cameraCF, cameraRenderCF, userHeadCF) + self:EvaluateGaze(cameraCF, cameraRenderCF, userHeadCF, lookRay) + + self:EvaluateTransparency(cameraCF, cameraRenderCF) + end +end +--End of Panel update methods + +--Panel virtual methods +function Panel:PreUpdate() --virtual: handle positioning here +end + +function Panel:OnUpdate() --virtual: handle transparency here +end + +function Panel:OnMouseEnter(x, y) --virtual +end + +function Panel:OnMouseLeave(x, y) --virtual +end + +function Panel:OnEnabled(enabled) --virtual +end + +function Panel:OnModalChanged(isModal) --virtual +end + +function Panel:OnVisibilityChanged(visible) --virtual +end + +function Panel:CalculateTransparency() --virtual + if not self.canFade then + return 0 + end + + local guiWidth, guiHeight = self.gui.AbsoluteSize.X, self.gui.AbsoluteSize.Y + local lookX, lookY = self.lookAtPixel.X, self.lookAtPixel.Y + + --Determine the distance from the edge; + --if x is negative it's on the left side, meaning the distance is just absolute value + --if x is positive it's on the right side, meaning the distance is x minus the width + local xEdgeDist = lookX < 0 and -lookX or (lookX - guiWidth) + local yEdgeDist = lookY < 0 and -lookY or (lookY - guiHeight) + if lookX > 0 and lookX < guiWidth then + xEdgeDist = 0 + end + if lookY > 0 and lookY < guiHeight then + yEdgeDist = 0 + end + local edgeDist = math.sqrt(xEdgeDist ^ 2 + yEdgeDist ^ 2) + + --since transparency is 0-1, we know how many pixels will give us 0 and how many will give us 1. + local offset = fullyOpaqueAtPixelsFromEdge + local interval = fullyTransparentAtPixelsFromEdge + --then we just clamp between 0 and 1. + return math.max(0, math.min(1, (edgeDist - offset) / interval)) +end +--End of Panel virtual methods + + +--Panel configuration methods +function Panel:ResizeStuds(width, height, pixelsPerStud) + pixelsPerStud = pixelsPerStud or defaultPixelsPerStud + + self.width = width + self.height = height + + self.pixelScale = pixelsPerStud / defaultPixelsPerStud + + local part = self:GetPart() + part.Size = Vector3.new(self.width * currentHeadScale, self.height * currentHeadScale, partThickness) + + local gui = self:GetGUI() + gui.CanvasSize = Vector2.new(pixelsPerStud * self.width, pixelsPerStud * self.height) +end + +function Panel:ResizePixels(width, height, pixelsPerStud) + pixelsPerStud = pixelsPerStud or defaultPixelsPerStud + + local widthInStuds = width / pixelsPerStud + local heightInStuds = height / pixelsPerStud + self:ResizeStuds(widthInStuds, heightInStuds, pixelsPerStud) +end + +function Panel:OnHeadScaleChanged(newHeadScale) + local pixelsPerStud = self.pixelScale * defaultPixelsPerStud + self:ResizeStuds(self.width, self.height, pixelsPerStud) +end + +function Panel:SetType(panelType, config) + self.panelType = panelType + + --clear out old type-specific members + self.floorPos = nil + + self.localCF = nil + + self.angleFromHorizon = nil + self.angleFromForward = nil + self.distance = nil + + if not config then + config = {} + end + + if panelType == Panel3D.Type.None then + --nothing to do + return + elseif panelType == Panel3D.Type.Floor then + self.floorPos = config.FloorPosition or Vector3.new(0, 0, 0) + elseif panelType == Panel3D.Type.Fixed then + self.localCF = config.CFrame or CFrame.new() + elseif panelType == Panel3D.Type.HorizontalFollow then + self.angleFromHorizon = CFrame.Angles(config.angleFromHorizon or 0, 0, 0) + self.angleFromForward = CFrame.Angles(0, config.angleFromForward or 0, 0) + self.distance = CFrame.new(0, 0, config.distance or 5) + elseif panelType == Panel3D.Type.FixedToHead then + self.localCF = config.CFrame or CFrame.new() + else + error("Invalid Panel type") + end +end + +function Panel:SetVisible(visible, modal) + if visible ~= self.isVisible then + self:OnVisibilityChanged(visible) + if not visible then + Panel3D.OnPanelClosed:Fire(self.name) + end + end + + self.isVisible = visible + self:SetEnabled(visible) + if visible and modal then + Panel3D.SetModalPanel(self) + end + if not visible and currentModal == self then + if modal and not doNotRestore then + --restore last modal panel + Panel3D.SetModalPanel(lastModal) + else + Panel3D.SetModalPanel(nil) + + --if the coder explicitly wanted to hide this modal panel, + --it follows that they don't want it to be restored when the next + --modal panel is hidden. + if lastModal == self then + lastModal = nil + end + end + end + + if not visible and self.forceShowUntilLookedAt then + self.forceShowUntilLookedAt = false + end +end + +function Panel:LinkTo(panelName) + if type(panelName) == "string" then + self.linkedTo = Panel3D.Get(panelName) + else + self.linkedTo = panelName + end +end + +function Panel:ForceShowUntilLookedAt(makeModal) + --ensure the part exists + self:GetPart() + self:GetGUI() + + self:SetVisible(true, makeModal) + self.forceShowUntilLookedAt = true +end + +function Panel:SetCanFade(canFade) + self.canFade = canFade +end + +--Child class, Subpanel +local Subpanel = {} +local Subpanel_mt = {} +function Subpanel.new(guiElement) + local instance = { + guiElement = guiElement + } + return setmetatable(instance, Subpanel_mt) +end + +function Subpanel:GetPart() + warn("Subpanel:GetPart() not yet implemented") + return nil +end + +function Subpanel:GetGUI() + warn("Subpanel:GetGUI() not yet implemented") + return nil +end + +function Panel:AddSubpanel(guiElement) + local subpanel = Subpanel.new(guiElement) + self.subpanels[guiElement] = subpanel +end + +function Panel:RemoveSubpanel(guiElement) + self.subpanels[guiElement] = nil +end +--End of Panel configuration methods +--End of Panel class implementation + + +--Panel3D API +function Panel3D.Get(name) + local panel = panels[name] + if not panels[name] then + panels[name] = Panel.new(name) + panel = panels[name] + end + return panel +end +--End of Panel3D API + + +--Panel3D Setup +local function onRenderStep() + if not UserInputService.VREnabled then + return + end + + + --reset distance info + currentClosest = nil + currentMaxDist = math.huge + + --figure out some useful stuff + local camera = workspace.CurrentCamera + local cameraCF = camera.CFrame + local cameraRenderCF = camera:GetRenderCFrame() + local userHeadCF = UserInputService:GetUserCFrame(Enum.UserCFrame.Head) + local lookRay = Ray.new(cameraRenderCF.p, cameraRenderCF.lookVector) + + --allow all panels to run their own update code + for i, v in pairs(panels) do + v:Update(cameraCF, cameraRenderCF, userHeadCF, lookRay) + end + + --evaluate linked panels + local processed = {} + for i, v in pairs(panels) do + if not processed[v] and v.linkedTo and v.isVisible and v.linkedTo.isVisible then + processed[v] = true + processed[v.linkedTo] = true + + local minTransparency = math.min(v.transparency, v.linkedTo.transparency) + v.transparency = minTransparency + v.linkedTo.transparency = minTransparency + end + end + + --run post update because the distance information hasn't been + --finalized until now. + for i, v in pairs(panels) do + --If the part is fully transparent, we don't want to keep it around in the workspace. + if v.part and v.gui then + --check if this panel is the current modal panel + local isModal = (currentModal == v) + --but also check if this panel is linked to the current modal panel + if not isModal and v.linkedTo and v.linkedTo == currentModal then + isModal = true + end + + local show = v.isVisible + if not isModal and currentModal then + show = false + end + if v.transparency >= 1 then + show = false + end + + if v.forceShowUntilLookedAt then + show = true + end + if not v.canFade and v.isVisible then + show = true + end + + v:SetEnabled(show) + end + + v:OnUpdate() + end + + --place the cursor on the closest panel (for now) + if not currentClosest and lastClosest then + UserInputService.MouseBehavior = lastMouseBehavior + elseif currentClosest and not lastClosest then + lastMouseBehavior = UserInputService.MouseBehavior + end + + if currentClosest then + UserInputService.MouseBehavior = Enum.MouseBehavior.LockCenter + UserInputService.OverrideMouseIconBehavior = Enum.OverrideMouseIconBehavior.ForceHide + cursor.Parent = currentClosest:GetGUI() + + local x, y = currentClosest.lookAtPixel.X, currentClosest.lookAtPixel.Y + cursor.Size = UDim2.new(0, 8 * currentClosest.pixelScale, 0, 8 * currentClosest.pixelScale) + cursor.Position = UDim2.new(0, x - cursor.AbsoluteSize.x * 0.5, 0, y - cursor.AbsoluteSize.y * 0.5) + else + cursor.Parent = nil + end + lastClosest = currentClosest +end +RunService:BindToRenderStep(renderStepName, Enum.RenderPriority.Last.Value, onRenderStep) + +--Implement cursor autohide functionality +UserInputService.InputChanged:connect(function(inputObj, processed) + if inputObj.UserInputType == Enum.UserInputType.MouseMovement then + lastMouseActivity = tick() + autoHideCursor(false) + end +end) +local function onHeartbeat() + if isCursorVisible() then + cursorHidden = false + end + if lastMouseActivity + cursorHideTime < tick() and not GuiService.MenuIsOpen and not cursorHidden then + autoHideCursor(true) + end +end +RunService.Heartbeat:connect(onHeartbeat) + +--Handle camera changes +local cameraChangedConnection = nil +local function onCameraChanged(prop) + if prop == "HeadScale" then + pcall(function() + currentHeadScale = workspace.CurrentCamera.HeadScale + end) + for i, v in pairs(panels) do + v:OnHeadScaleChanged(currentHeadScale) + end + end +end + +local function onWorkspaceChanged(prop) + if prop == "CurrentCamera" then + onCameraChanged("HeadScale") + if cameraChangedConnection then + cameraChangedConnection:disconnect() + end + cameraChangedConnection = workspace.CurrentCamera.Changed:connect(onCameraChanged) + end +end +if workspace.CurrentCamera then + onWorkspaceChanged("CurrentCamera") +end +workspace.Changed:connect(onWorkspaceChanged) + +return Panel3D \ No newline at end of file diff --git a/2016/content/Modules/VR/VirtualKeyboard.lua b/2016/content/Modules/VR/VirtualKeyboard.lua new file mode 100644 index 0000000..b632a77 --- /dev/null +++ b/2016/content/Modules/VR/VirtualKeyboard.lua @@ -0,0 +1,1151 @@ +-- VirtualKeyboard.lua -- +-- Written by Kip Turner, copyright ROBLOX 2016 -- + + +local CoreGui = game:GetService('CoreGui') +local RunService = game:GetService('RunService') +local UserInputService = game:GetService('UserInputService') +local GuiService = game:GetService('GuiService') +local HttpService = game:GetService('HttpService') +local ContextActionService = game:GetService('ContextActionService') +local PlayersService = game:GetService('Players') +local TextService = game:GetService('TextService') + +local RobloxGui = CoreGui:WaitForChild("RobloxGui") +local Util = require(RobloxGui.Modules.Settings.Utility) + +local vrKeyboardSuccess, vrKeyboardFlagValue = pcall(function() return settings():GetFFlag("UseVRKeyboardInLua") end) +local useVRKeyboard = (vrKeyboardSuccess and vrKeyboardFlagValue == true) + +local BACKGROUND_OPACITY = 0.3 +local NORMAL_KEY_COLOR = Color3.new(49/255,49/255,49/255) +local HOVER_KEY_COLOR = Color3.new(49/255,49/255,49/255) +local PRESSED_KEY_COLOR = Color3.new(0,162/255,1) +local SET_KEY_COLOR = Color3.new(0,162/255,1) + +local KEY_TEXT_COLOR = Color3.new(1,1,1) +---------------------------------------- KEYBOARD LAYOUT -------------------------------------- +local MINIMAL_KEYBOARD_LAYOUT = HttpService:JSONDecode([==[ +[ + [ + { + "a": 7, + "w": 0.8 + }, + "*", + "Q", + "W", + "E", + "R", + "T", + "Y", + "U", + "I", + "O", + "P", + { + "w": 1.8 + }, + "Delete" + ], + [ + { + "w": 1.6 + }, + "Caps", + "A", + "S", + "D", + "F", + "G", + "H", + "J", + "K", + "L", + "?", + { + "h": 2, + "w2": 2.4, + "h2": 1, + "x2": -1.4, + "y2": 1 + }, + "Enter" + ], + [ + { + "w": 2.2 + }, + "Shift", + "Z", + "X", + "C", + "V", + "B", + "N", + "M", + "." + ], + [ + { + "w": 2.2 + }, + "123/sym", + { + "w": 8 + }, + "", + { + "w": 2.4 + }, + "" + ] +] +]==]) + +local MINIMAL_KEYBOARD_LAYOUT_SYMBOLS = HttpService:JSONDecode([==[ +[ + [ + { + "a": 7, + "w": 0.8 + }, + "*", + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9", + "0", + { + "w": 1.8 + }, + "Delete" + ], + [ + { + "w": 1.6 + }, + "!", + "@", + "#", + "$", + "%", + "^", + "&", + "(", + ")", + "=", + "?", + { + "h": 2, + "w2": 2.4, + "h2": 1, + "x2": -1.4, + "y2": 1 + }, + "Enter" + ], + [ + { + "w": 1.2 + }, + "/", + "-", + "+", + "_", + ":", + ";", + "'", + "\"", + ",", + "." + ], + [ + { + "w": 2.2 + }, + "abc", + { + "w": 8 + }, + "", + { + "w": 2.4 + }, + "" + ] +] +]==]) + + +---------------------------------------- END KEYBOARD LAYOUT -------------------------------------- + + +local function tokenizeString(str, tokenChar) + local words = {} + for word in string.gmatch(str, '([^' .. tokenChar .. ']+)') do + table.insert(words, word) + end + return words +end + +local function ConvertFontSizeEnumToInt(fontSizeEnum) + local result = string.match(fontSizeEnum.Name, '%d+') + return (result and tostring(result)) or 12 +end + + +-- RayPlaneIntersection + +-- http://www.siggraph.org/education/materials/HyperGraph/raytrace/rayplane_intersection.htm +local function RayPlaneIntersection(ray, planeNormal, pointOnPlane) + planeNormal = planeNormal.unit + ray = ray.Unit + -- compute Pn (dot) Rd = Vd and check if Vd == 0 then we know ray is parallel to plane + local Vd = planeNormal:Dot(ray.Direction) + + -- could fuzzy equals this a little bit to account for imprecision or very close angles to zero + if Vd == 0 then -- parallel, no intersection + return nil + end + + local V0 = planeNormal:Dot(pointOnPlane - ray.Origin) + local t = V0 / Vd + + if t < 0 then --plane is behind ray origin, and thus there is no intersection + return nil + end + + return ray.Origin + ray.Direction * t +end + +function Clamp(low, high, input) + return math.max(low, math.min(high, input)) +end + +-- No rotation as of yet +local function PointInGuiObject(object, x, y) + local minPt = object.AbsolutePosition + local maxPt = object.AbsolutePosition + object.AbsoluteSize + if minPt.X <= x and maxPt.X >= x and minPt.Y <= y and maxPt.Y >= y then + return true + end + return false +end + + +local function ExtendedInstance(instance) + local this = {} + do + local mt = + { + __index = function (t, k) + return instance[k] + end; + + __newindex = function (t, k, v) + instance[k] = v + end; + } + setmetatable(this, mt) + end + return this +end + +local function IsVoiceToTextEnabled() + return false +end + +local function CreateVRButton(instance) + local newButton = ExtendedInstance(instance) + + rawset(newButton, "OnEnter", function(self) + end) + rawset(newButton, "OnLeave", function(self) + end) + rawset(newButton, "OnDown", function(self) + end) + rawset(newButton, "OnUp", function(self) + end) + rawset(newButton, "ContainsPoint", function(self, x, y) + return PointInGuiObject(instance, x, y) + end) + rawset(newButton, "Update", function(self) + end) + + return newButton +end + +local selectionRing = Util:Create'ImageLabel' +{ + Name = 'SelectionRing'; + Size = UDim2.new(1, -6, 1, -6); + Position = UDim2.new(0, 4, 0, 3); + Image = 'rbxasset://textures/ui/menu/buttonHover.png'; + ScaleType = Enum.ScaleType.Slice; + SliceCenter = Rect.new(94/2, 94/2, 94/2, 94/2); + BackgroundTransparency = 1; +} + +local KEY_ICONS = +{ + [""] = {Asset = "rbxasset://textures/ui/Keyboard/mic_icon.png", AspectRatio = 0.615}; +} + +local function CreateKeyboardKey(keyboard, layoutData, keyData) + local isSpecialShapeKey = layoutData['width2'] and layoutData['height2'] and layoutData['x2'] and layoutData['y2'] + + local newKeyElement = Util:Create'ImageButton' + { + Name = keyData[1]; + Position = UDim2.new(layoutData['x'], 0, layoutData['y'], 0); + Size = UDim2.new(layoutData['width'], 0, layoutData['height'], 0); + BorderSizePixel = 0; + Image = ""; + BackgroundTransparency = 1; + ZIndex = 1; + } + local keyText = Util:Create'TextLabel' + { + Name = "KeyText"; + Text = keyData[#keyData]; + Position = UDim2.new(0, -10, 0, -10); + Size = UDim2.new(1, 0, 1, 0); + Font = Enum.Font.SourceSansBold; + FontSize = Enum.FontSize.Size96; + TextColor3 = KEY_TEXT_COLOR; + BackgroundTransparency = 1; + Selectable = true; + ZIndex = 2; + Parent = newKeyElement; + } + local backgroundImage = Util:Create'Frame' + { + Name = 'KeyBackground'; + Size = UDim2.new(1,-10,1,-10); + Position = UDim2.new(0,-5,0,-5); + BackgroundColor3 = NORMAL_KEY_COLOR; + BackgroundTransparency = BACKGROUND_OPACITY; + BorderSizePixel = 0; + Parent = newKeyElement; + } + + local selectionObject = Util:Create'ImageLabel' + { + Name = 'SelectionObject'; + Size = UDim2.new(1,0,1,0); + BackgroundTransparency = 1; + Image = "rbxasset://textures/ui/Keyboard/key_selection_9slice.png"; + ImageTransparency = 0; + ScaleType = Enum.ScaleType.Slice; + SliceCenter = Rect.new(12,12,52,52); + BorderSizePixel = 0; + } + + newKeyElement.SelectionImageObject = Util:Create'ImageLabel' + { + Visible = false; + } + + -- Special silly enter key nonsense + local secondBackgroundImage = nil + local specialSelectionObject, specialSelectionObject2, specialSelectionObject3 = nil, nil, nil + if isSpecialShapeKey then + secondBackgroundImage = Util:Create'ImageButton' + { + Name = 'KeyBackground'; + Position = UDim2.new(layoutData['x2'] / layoutData['width'], -5, layoutData['y2'] / layoutData['height'], -5); + Size = UDim2.new(layoutData['width2'] / layoutData['width'], 0, layoutData['height2'] / layoutData['height'], -10); + BackgroundColor3 = NORMAL_KEY_COLOR; + BackgroundTransparency = BACKGROUND_OPACITY; + BorderSizePixel = 0; + AutoButtonColor = false; + Parent = newKeyElement; + } + if layoutData['x2'] <= 0 then + keyText.Size = secondBackgroundImage.Size - UDim2.new(0,10,0,0) + keyText.Position = secondBackgroundImage.Position + secondBackgroundImage.Size = secondBackgroundImage.Size - UDim2.new(1,0,0,0) + end + + do + specialSelectionObject = Util:Create'Frame' + { + Name = 'SpecialSelectionObject'; + Size = UDim2.new(1,0,0.5,0); + Position = UDim2.new(0,0,0.5,0); + BackgroundTransparency = 1; + ClipsDescendants = true; + Util:Create'ImageLabel' + { + Name = 'Borders'; + Position = UDim2.new(-1,0,-1,0); + Size = UDim2.new(2,0,2,0); + BackgroundTransparency = 1; + Image = "rbxasset://textures/ui/Keyboard/key_selection_9slice.png"; + ImageTransparency = 0; + ScaleType = Enum.ScaleType.Slice; + SliceCenter = Rect.new(12,12,52,52); + }; + } + specialSelectionObject2 = specialSelectionObject:Clone() + specialSelectionObject2.Size = UDim2.new(1,0,0.5,5) + specialSelectionObject2.Position = UDim2.new(0,0,0,0) + specialSelectionObject2.Borders.Size = UDim2.new(1,0,1,30) + specialSelectionObject2.Borders.Position = UDim2.new(0,0,0,0) + + specialSelectionObject3 = specialSelectionObject:Clone() + specialSelectionObject3.Size = UDim2.new(1,5,1,0) + specialSelectionObject3.Position = UDim2.new(0,0,0,0) + specialSelectionObject3.Borders.Size = UDim2.new(1,30,1,0) + specialSelectionObject3.Borders.Position = UDim2.new(0,0,0,0) + end + -- End of nonsense + end + + local newKey = CreateVRButton(newKeyElement) + + local hovering = false + local pressed = false + local isAlpha = #keyData == 1 and type(keyData[1]) == 'string' and #keyData[1] == 1 and + string.byte(keyData[1]) >= string.byte("A") and string.byte(keyData[1]) <= string.byte("z") + + local icon = nil + if keyData[1] and KEY_ICONS[keyData[1]] then + keyText.Visible = false + icon = Util:Create'ImageLabel' + { + Name = 'KeyIcon'; + Size = UDim2.new(KEY_ICONS[keyData[1]].AspectRatio, -20, 1, -20); + SizeConstraint = Enum.SizeConstraint.RelativeYY; + BackgroundTransparency = 1; + Image = KEY_ICONS[keyData[1]].Asset; + Parent = backgroundImage; + } + + local function onChanged(prop) + if prop == 'AbsoluteSize' then + icon.Position = UDim2.new(0.5,-icon.AbsoluteSize.X/2,0.5,-icon.AbsoluteSize.Y/2); + end + end + icon.Changed:connect(onChanged) + onChanged('AbsoluteSize') + end + + local function isEnabled() + if newKey:GetCurrentKeyValue() == "" then + return IsVoiceToTextEnabled() + end + return true + end + + local function onClicked() + local keyValue = nil + local currentKeySetting = newKey:GetCurrentKeyValue() + + if currentKeySetting == 'Shift' then + keyboard:SetShift(not keyboard:GetShift()) + elseif currentKeySetting == 'Caps' then + keyboard:SetCaps(not keyboard:GetCaps()) + elseif currentKeySetting == 'Enter' then + keyboard:SubmitText(true, true) + elseif currentKeySetting == 'Delete' then + keyboard:BackspaceAtCursor() + elseif currentKeySetting == "123/sym" then + keyboard:SetCurrentKeyset(2) + elseif currentKeySetting == "abc" then + keyboard:SetCurrentKeyset(1) + elseif currentKeySetting == "" then + keyboard:SetVoiceMode(true) + elseif currentKeySetting == 'Tab' then + keyValue = '\t' + else + keyValue = currentKeySetting + end + + if keyValue ~= nil then + keyboard:SubmitCharacter(keyValue, isAlpha) + end + end + + local function setKeyColor(newColor, hovering) + backgroundImage.BackgroundColor3 = newColor + if secondBackgroundImage then + secondBackgroundImage.BackgroundColor3 = newColor + end + if isSpecialShapeKey then + specialSelectionObject.Parent = hovering and backgroundImage or nil + specialSelectionObject2.Parent = hovering and backgroundImage or nil + specialSelectionObject3.Parent = hovering and secondBackgroundImage or nil + else + selectionObject.Parent = hovering and backgroundImage or nil + end + end + + local function update() + local currentKey = newKey:GetCurrentKeyValue() + + if pressed then + setKeyColor(PRESSED_KEY_COLOR, false) + elseif hovering then + setKeyColor(HOVER_KEY_COLOR, true) + elseif currentKey == 'Caps' and keyboard:GetCaps() then + setKeyColor(SET_KEY_COLOR, false) + elseif currentKey == 'Shift' and keyboard:GetShift() then + setKeyColor(SET_KEY_COLOR, false) + elseif currentKey == 'abc' then + setKeyColor(SET_KEY_COLOR, false) + else + setKeyColor(NORMAL_KEY_COLOR, false) + end + + if icon then + icon.ImageTransparency = isEnabled() and 0 or 0.5 + end + + keyText.Text = newKey:GetCurrentKeyValue() + end + + local hoveringGuiElements = {} + + rawset(newKey, "OnEnter", function(self) + hovering = true + update() + end) + rawset(newKey, "OnLeave", function(self) + if not next(hoveringGuiElements) then + hovering = false + pressed = false + update() + end + end) + rawset(newKey, "OnDown", function(self) + pressed = true + update() + end) + rawset(newKey, "OnUp", function(self) + pressed = false + update() + end) + rawset(newKey, "GetCurrentKeyValue", function(self) + local shiftEnabled = keyboard:GetShift() + local capsEnabled = keyboard:GetCaps() + + if isAlpha then + if capsEnabled and shiftEnabled then + return string.lower(keyData[#keyData]) + elseif capsEnabled or shiftEnabled then + return keyData[1] + else + return string.lower(keyData[#keyData]) + end + end + + if shiftEnabled then + return keyData[1] + end + + return keyData[#keyData] + end) + rawset(newKey, "ContainsPoint", function(self, x, y) + return PointInGuiObject(backgroundImage, x, y) or + (secondBackgroundImage and PointInGuiObject(secondBackgroundImage, x, y)) + end) + rawset(newKey, "Update", function(self) + update() + end) + rawset(newKey, "GetInstance", function(self) + return newKeyElement + end) + + newKeyElement.MouseButton1Down:connect(function() newKey:OnDown() end) + newKeyElement.MouseButton1Up:connect(function() newKey:OnUp() end) + newKeyElement.SelectionGained:connect(function() hoveringGuiElements[newKeyElement] = true newKey:OnEnter() end) + newKeyElement.SelectionLost:connect(function() hoveringGuiElements[newKeyElement] = nil newKey:OnLeave() end) + newKeyElement.MouseButton1Click:connect(function() onClicked() end) + if secondBackgroundImage then + secondBackgroundImage.MouseButton1Click:connect(onClicked) + secondBackgroundImage.MouseButton1Down:connect(function() newKey:OnDown() end) + secondBackgroundImage.MouseButton1Up:connect(function() newKey:OnUp() end) + secondBackgroundImage.SelectionGained:connect(function() + hoveringGuiElements[secondBackgroundImage] = true + newKey:OnEnter() + end) + secondBackgroundImage.SelectionLost:connect(function() + hoveringGuiElements[secondBackgroundImage] = nil + newKey:OnLeave() + end) + end + + update() + + return newKey +end + + + +local function ConstructKeyboardUI(keyboardLayoutDefinitions) + local Panel3D = require(RobloxGui.Modules.VR.Panel3D) + local panel = Panel3D.Get("Keyboard") + panel:SetVisible(false) + + -- DEBUG setting + -- panel:GetGUI().Parent = workspace + + + local buttons = {} + + local keyboardContainer = Util:Create'Frame' + { + Name = 'VirtualKeyboard'; + Size = UDim2.new(1, 0, 1, 0); + Position = UDim2.new(0, 0, 0, 0); + BackgroundTransparency = 1; + Active = true; + Visible = false; + }; + + local textEntryBackground = Util:Create'ImageLabel' + { + Name = 'TextEntryBackground'; + Size = UDim2.new(0.5,0,0.125,0); + Position = UDim2.new(0.25,0,0,0); + Image = ""; + BackgroundTransparency = 0.5; + BackgroundColor3 = Color3.new(31/255,31/255,31/255); + BorderSizePixel = 0; + ClipsDescendants = true; + Parent = keyboardContainer; + } + local textfieldBackground = Util:Create'Frame' + { + Name = 'TextfieldBackground'; + Position = UDim2.new(0,2,0,2); + Size = UDim2.new(1, -4, 1, -4); + BackgroundTransparency = 0; + BackgroundColor3 = Color3.new(209/255,216/255,221/255); + BorderSizePixel = 0; + Visible = true; + Parent = textEntryBackground; + }; + local textEntryField = Util:Create'TextButton' + { + Name = "TextEntryField"; + Text = ""; + Position = UDim2.new(0,4,0,4); + Size = UDim2.new(1, -8, 1, -8); + Font = Enum.Font.SourceSans; + FontSize = Enum.FontSize.Size60; + TextXAlignment = Enum.TextXAlignment.Left; + BackgroundTransparency = 1; + BorderSizePixel = 0; + Parent = textfieldBackground; + } + local textfieldCursor = Util:Create'Frame' + { + Name = 'TextfieldCursor'; + Size = UDim2.new(0, 5, 0.9, 0); + Position = UDim2.new(0, 0, 0.05, 0); + BackgroundTransparency = 0; + BackgroundColor3 = SET_KEY_COLOR; + BorderSizePixel = 0; + Visible = true; + ZIndex = 2; + Parent = textEntryField; + }; + + local closeButtonElement = Util:Create'ImageButton' + { + Name = 'CloseButton'; + Size = UDim2.new(0.075,-10,0.198,-10); + Position = UDim2.new(0,-5,0,-35); + Image = "rbxasset://textures/ui/Keyboard/close_button_background.png"; + BackgroundTransparency = 1; + AutoButtonColor = false; + Parent = keyboardContainer; + } + do + closeButtonElement.SelectionImageObject = Util:Create'ImageLabel' + { + Name = 'Selection'; + Size = UDim2.new(0.9,0,0.9,0); + Position = UDim2.new(0.05,0,0.05,0); + Image = "rbxasset://textures/ui/Keyboard/close_button_selection.png"; + BackgroundTransparency = 1; + } + Util:Create'ImageLabel' + { + Name = 'Icon'; + Size = UDim2.new(0.5,0,0.5,0); + Position = UDim2.new(0.25,0,0.25,0); + Image = "rbxasset://textures/ui/Keyboard/close_button_icon.png"; + BackgroundTransparency = 1; + Parent = closeButtonElement; + } + end + local closeButton = CreateVRButton(closeButtonElement) + table.insert(buttons, closeButton) + + local voiceRecognitionContainer = Util:Create'Frame' + { + Name = 'VoiceRecognitionContainer'; + Size = UDim2.new(1, 0, 0.85, 0); + Position = UDim2.new(0, 0, 0.15, 0); + BackgroundTransparency = 1; + Active = true; + Visible = false; + Parent = keyboardContainer; + }; + do + local voiceRecognitionBackground1 = Util:Create'Frame' + { + Name = 'voiceRecognitionBackground1'; + Size = UDim2.new(1, 0, 0.75, 0); + Position = UDim2.new(0, 0, 0, 0); + BackgroundColor3 = Color3.new(0,0,0); + BackgroundTransparency = 0.5; + BorderSizePixel = 0; + Active = true; + Parent = voiceRecognitionContainer; + }; + local voiceRecognitionBackground2 = voiceRecognitionBackground1:Clone() + voiceRecognitionBackground2.Size = UDim2.new(0.75, 0, 0.25, 0) + voiceRecognitionBackground2.Position = UDim2.new(0, 0, 0.75, 0) + voiceRecognitionBackground2.Parent = voiceRecognitionContainer + end + + local voiceDoneButton = CreateVRButton(Util:Create'ImageButton' + { + Name = 'DoneButton'; + Size = UDim2.new(0.25,-5,0.25,-5); + Position = UDim2.new(0.75,5,0.75,5); + Image = ""; + BackgroundTransparency = 0; + AutoButtonColor = false; + BorderSizePixel = 0; + Parent = voiceRecognitionContainer; + }) + table.insert(buttons, voiceDoneButton) + + local newKeyboard = ExtendedInstance(keyboardContainer) + + local keyboardOptions = nil + local keysets = {} + + local capsLockEnabled = false + local shiftEnabled = false + + local textfieldCursorPosition = 0 + + local closedEvent = Instance.new('BindableEvent') + local opened = false + + local function SetTextFieldCursorPosition(newPosition) + textfieldCursorPosition = Clamp(0, #textEntryField.Text, newPosition) + if not textEntryField.TextFits then + textfieldCursorPosition = #textEntryField.Text + end + + local textSize = TextService:GetTextSize( + string.sub(textEntryField.Text, 1, textfieldCursorPosition), + ConvertFontSizeEnumToInt(textEntryField.FontSize), + textEntryField.Font, + textEntryField.AbsoluteSize) + textfieldCursor.Position = UDim2.new(0, textSize.x, textfieldCursor.Position.Y.Scale, textfieldCursor.Position.Y.Offset) + end + + local function UpdateTextEntryFieldText(newText) + textEntryField.Text = newText + SetTextFieldCursorPosition(textfieldCursorPosition) + end + + local buffer = "" + local function getBufferText() + if keyboardOptions and keyboardOptions.TextBox then + return keyboardOptions.TextBox.Text + end + return buffer + end + local function setBufferText(newBufferText) + if keyboardOptions and keyboardOptions.TextBox then + keyboardOptions.TextBox.Text = newBufferText + elseif buffer ~= newBufferText then + buffer = newBufferText + UpdateTextEntryFieldText(buffer) + end + end + + local function calculateTextCursorPosition(x, y) + x = x - textEntryField.AbsolutePosition.x + y = y - textEntryField.AbsolutePosition.y + + for i = 1, #textEntryField.Text do + local textSize = TextService:GetTextSize( + string.sub(textEntryField.Text, 1, i), + ConvertFontSizeEnumToInt(textEntryField.FontSize), + textEntryField.Font, + textEntryField.AbsoluteSize) + if textSize.x > x then + return i - 1 + end + end + + return #textEntryField.Text + end + + local currentKeyset = nil + + rawset(newKeyboard, "ClosedEvent", closedEvent.Event) + + rawset(newKeyboard, "GetCurrentKeyset", function(self) + return keysets[currentKeyset] + end) + + rawset(newKeyboard, "SetCurrentKeyset", function(self, newKeyset) + if newKeyset ~= currentKeyset and keysets[newKeyset] ~= nil then + if keysets[currentKeyset] and keysets[currentKeyset].container then + keysets[currentKeyset].container.Visible = false + end + + currentKeyset = newKeyset + + if keysets[currentKeyset] and keysets[currentKeyset].container then + keysets[currentKeyset].container.Visible = true + end + end + end) + + rawset(newKeyboard, "SetVoiceMode", function(self, inVoiceMode) + inVoiceMode = inVoiceMode and IsVoiceToTextEnabled() + + local currentKeysetObject = self:GetCurrentKeyset() + if currentKeysetObject and currentKeysetObject.container then + currentKeysetObject.container.Visible = not inVoiceMode + end + + voiceRecognitionContainer.Visible = inVoiceMode + end) + + rawset(newKeyboard, "GetCaps", function(self) + return capsLockEnabled + end) + + rawset(newKeyboard, "SetCaps", function(self, newCaps) + capsLockEnabled = newCaps + for _, key in pairs(self:GetCurrentKeyset().keys) do + key:Update() + end + end) + + rawset(newKeyboard, "GetShift", function(self) + return shiftEnabled + end) + + rawset(newKeyboard, "SetShift", function(self, newShift) + shiftEnabled = newShift + for _, key in pairs(self:GetCurrentKeyset().keys) do + key:Update() + end + end) + + local textChangedConn = nil + local panelClosedConn = nil + rawset(newKeyboard, "Open", function(self, options) + if opened then return end + opened = true + + keyboardOptions = options + + self:SetCurrentKeyset(1) + self:SetVoiceMode(false) + keyboardContainer.Visible = true + + panel:ResizeStuds(5.9, 2.25, 320) + + local localCF = CFrame.new() + + if textChangedConn then textChangedConn:disconnect() end + textChangedConn = nil + if options.TextBox then + textChangedConn = options.TextBox.Changed:connect(function(prop) + if prop == 'Text' then + UpdateTextEntryFieldText(options.TextBox.Text) + end + end) + options.TextBox.FocusLost:connect(function(submitted) + self:Close(submitted) + end) + if options.TextBox.ClearTextOnFocus then + setBufferText("") + else + UpdateTextEntryFieldText(options.TextBox.Text) + end + + local textboxPanel = Panel3D.FindContainerOf(options.TextBox) + if textboxPanel then + panelClosedConn = Panel3D.OnPanelClosed.Event:connect(function(closedPanelName) + if closedPanelName == textboxPanel.name then + self:Close(false) + end + end) + + --Attach to it if it's in the same space + if textboxPanel.panelType == Panel3D.Type.Fixed then + local panelCF = textboxPanel.localCF + localCF = panelCF * CFrame.new(0, (-textboxPanel.height / 2) - 0.5, 0) * + CFrame.Angles(math.rad(30), 0, 0) * + CFrame.new(0, (-panel.height / 2) - 0.5, 0) + else + --Otherwise, best-guess where it should go based on the user's head. + local headForwardCF = Panel3D.GetHeadLookXZ(true) + localCF = headForwardCF * CFrame.Angles(math.rad(22.5), 0, 0) * CFrame.new(0, -1, 5) + end + end + else + setBufferText("") + end + + ContextActionService:BindCoreAction("VirtualKeyboardControllerInput", + function(actionName, inputState, inputObject) + if inputState == Enum.UserInputState.End then + if inputObject.KeyCode == Enum.KeyCode.ButtonL1 then + SetTextFieldCursorPosition(textfieldCursorPosition - 1) + elseif inputObject.KeyCode == Enum.KeyCode.ButtonR1 then + SetTextFieldCursorPosition(textfieldCursorPosition + 1) + elseif inputObject.KeyCode == Enum.KeyCode.ButtonX then + self:BackspaceAtCursor() + elseif inputObject.KeyCode == Enum.KeyCode.ButtonY then + self:SubmitCharacter(" ", false) + elseif inputObject.KeyCode == Enum.KeyCode.ButtonL2 then + if currentKeyset then + -- Go to the next keyset + self:SetCurrentKeyset((currentKeyset % #keysets) + 1) + end + elseif inputObject.KeyCode == Enum.KeyCode.ButtonL3 then + self:SetCaps(not self:GetCaps()) + end + end + end, + false, + Enum.KeyCode.ButtonL1, Enum.KeyCode.ButtonR1, Enum.KeyCode.ButtonL2, Enum.KeyCode.ButtonL3, Enum.KeyCode.ButtonX, Enum.KeyCode.ButtonY) + + self.Parent = panel:GetGUI() + + panel:SetType(Panel3D.Type.Fixed, { CFrame = localCF }) + panel:SetCanFade(false) + panel:SetVisible(true, true) + panel:ForceShowUntilLookedAt() + + function panel:OnUpdate() + end + end) + + rawset(newKeyboard, "Close", function(self, submit) + submit = (submit == true) + + if not opened then return end + opened = false + + + if textChangedConn then textChangedConn:disconnect() end + textChangedConn = nil + if panelClosedConn then panelClosedConn:disconnect() end + panelClosedConn = nil + + ContextActionService:UnbindCoreAction("VirtualKeyboardControllerInput") + -- Clean-up + panel:OnMouseLeave() + panel:SetVisible(false, true) + keyboardContainer.Visible = false + + self:SubmitText(submit, false) + end) + + rawset(newKeyboard, "SubmitText", function(self, submit, keepKeyboardOpen) + local keyboardTextbox = keyboardOptions and keyboardOptions.TextBox + if keyboardTextbox then + if submit then + keyboardTextbox.Text = getBufferText() + end + keyboardTextbox:ReleaseFocus(submit) + if keepKeyboardOpen then + keyboardTextbox:CaptureFocus() + end + end + end) + + rawset(newKeyboard, "GetCurrentOptions", function(self) + return keyboardOptions + end) + + rawset(newKeyboard, "BackspaceAtCursor", function(self) + if textfieldCursorPosition >= 1 then + local bufferText = getBufferText() + local newBufferText = string.sub(bufferText, 1, textfieldCursorPosition - 1) .. string.sub(bufferText, textfieldCursorPosition + 1, #bufferText) + local newCursorPosition = textfieldCursorPosition - 1 + setBufferText(newBufferText) + SetTextFieldCursorPosition(newCursorPosition) + end + end) + + rawset(newKeyboard, "SubmitCharacter", function(self, character, isAnAlphaKey) + local bufferText = getBufferText() + local newBufferText = string.sub(bufferText, 1, textfieldCursorPosition) .. character .. string.sub(bufferText, textfieldCursorPosition + 1, #bufferText) + setBufferText(newBufferText) + SetTextFieldCursorPosition(textfieldCursorPosition + #character) + + if isAnAlphaKey and self:GetShift() then + self:SetShift(false) + end + end) + + do -- Parse input definition + for _, keyboardKeyset in pairs(keyboardLayoutDefinitions) do + local keys = {} + local keyboardSizeConstrainer = Util:Create'Frame' + { + Name = 'KeyboardSizeConstrainer'; + Size = UDim2.new(1, 0, 1, -20); + Position = UDim2.new(0, 0, 0, 20); + BackgroundTransparency = 1; + Parent = keyboardContainer; + }; + + local maxWidth = 0 + local maxHeight = 0 + local y = 0 + for rowNum, rowData in pairs(keyboardKeyset) do + local x = 0 + local width = 1 + local height = 1 + local width2, height2, x2, y2; + for columnNum, columnData in pairs(rowData) do + if type(columnData) == 'table' then + if columnData['w'] then width = columnData['w'] end + if columnData['h'] then height = columnData['h'] end + if columnData['x'] then x = x + columnData['x'] end + if columnData['y'] then y = y + columnData['y'] end + if columnData['x2'] then x2 = columnData['x2'] end + if columnData['y2'] then y2 = columnData['y2'] end + if columnData['w2'] then width2 = columnData['w2'] end + if columnData['h2'] then height2 = columnData['h2'] end + elseif type(columnData) == 'string' then + if columnData == "" then + columnData = " " + end + -- put key + local key = CreateKeyboardKey( + newKeyboard, + {x = x, y = y, width = width, height = height, x2 = x2, y2 = y2, width2 = width2, height2 = height2}, + tokenizeString(columnData, '\n')) + table.insert(keys, key) + + x = x + width + maxWidth = math.max(maxWidth, x) + maxHeight = math.max(maxHeight, y + height) + -- reset for the next key + width = 1 + height = 1 + width2, height2, x2, y2 = nil, nil, nil, nil + end + end + y = y + 1 + end + + -- Fix the positions and sizes to fit in our KeyboardContainer + for _, element in pairs(keys) do + element.Position = UDim2.new(element.Position.X.Scale / maxWidth, 0, element.Position.Y.Scale / maxHeight, 0) + element.Size = UDim2.new(element.Size.X.Scale / maxWidth, 0, element.Size.Y.Scale / maxHeight, 0) + element.Parent = keyboardSizeConstrainer + end + + keyboardSizeConstrainer.SizeConstraint = Enum.SizeConstraint.RelativeXX + keyboardSizeConstrainer.Size = UDim2.new(1, 0, -maxHeight / maxWidth, 0) + keyboardSizeConstrainer.Position = UDim2.new(0, 0, 1, 0) + keyboardSizeConstrainer.Visible = false + + table.insert(keysets, {keys = keys, container = keyboardSizeConstrainer}) + end + newKeyboard:SetCurrentKeyset(1) + end + + textEntryField.MouseButton1Click:connect(function() + SetTextFieldCursorPosition(calculateTextCursorPosition(panel.lookAtPixel.X, panel.lookAtPixel.Y)) + end) + + closeButton.MouseButton1Click:connect(function() + newKeyboard:Close(false) + closedEvent:Fire() + end) + + voiceDoneButton.MouseButton1Click:connect(function() + newKeyboard:SetVoiceMode(false) + end) + + return newKeyboard +end + + +local Keyboard = nil; +local function GetKeyboard() + if Keyboard == nil then + Keyboard = ConstructKeyboardUI({MINIMAL_KEYBOARD_LAYOUT, MINIMAL_KEYBOARD_LAYOUT_SYMBOLS}) + end + return Keyboard +end + + + +local VirtualKeyboardClass = {} + + +function VirtualKeyboardClass:CreateVirtualKeyboardOptions(textbox) + local keyboardOptions = {} + + keyboardOptions.TextBox = textbox + + return keyboardOptions +end + +local VirtualKeyboardPlatform = false +do + -- iOS, Android and Xbox already have platform specific keyboards + local platform = UserInputService:GetPlatform() + VirtualKeyboardPlatform = platform == Enum.Platform.Windows or + platform == Enum.Platform.OSX +end + + +function VirtualKeyboardClass:ShowVirtualKeyboard(virtualKeyboardOptions) + if VirtualKeyboardPlatform and UserInputService.VREnabled then + GetKeyboard():Open(virtualKeyboardOptions) + end +end + +function VirtualKeyboardClass:CloseVirtualKeyboard() + if VirtualKeyboardPlatform and UserInputService.VREnabled then + local currentKeyboard = GetKeyboard() + currentKeyboard:Close(false) + end +end + +VirtualKeyboardClass.ClosedEvent = GetKeyboard().ClosedEvent + + +if VirtualKeyboardPlatform and useVRKeyboard then + UserInputService.TextBoxFocused:connect(function(textbox) + VirtualKeyboardClass:ShowVirtualKeyboard(VirtualKeyboardClass:CreateVirtualKeyboardOptions(textbox)) + end) + + UserInputService.TextBoxFocusReleased:connect(function(textbox) + VirtualKeyboardClass:CloseVirtualKeyboard() + end) +end + + +return VirtualKeyboardClass diff --git a/2016/content/fonts/AccanthisADFStd-Regular.otf b/2016/content/fonts/AccanthisADFStd-Regular.otf new file mode 100644 index 0000000..b3d6f03 Binary files /dev/null and b/2016/content/fonts/AccanthisADFStd-Regular.otf differ diff --git a/2016/content/fonts/Arial.font b/2016/content/fonts/Arial.font new file mode 100644 index 0000000..e223b3d Binary files /dev/null and b/2016/content/fonts/Arial.font differ diff --git a/2016/content/fonts/ArialBold.font b/2016/content/fonts/ArialBold.font new file mode 100644 index 0000000..eda0976 Binary files /dev/null and b/2016/content/fonts/ArialBold.font differ diff --git a/2016/content/fonts/Balthazar-Regular.ttf b/2016/content/fonts/Balthazar-Regular.ttf new file mode 100644 index 0000000..fff2ff7 Binary files /dev/null and b/2016/content/fonts/Balthazar-Regular.ttf differ diff --git a/2016/content/fonts/ComicNeue-Angular-Bold.ttf b/2016/content/fonts/ComicNeue-Angular-Bold.ttf new file mode 100644 index 0000000..d70a258 Binary files /dev/null and b/2016/content/fonts/ComicNeue-Angular-Bold.ttf differ diff --git a/2016/content/fonts/CompositExtraSlot0.mesh b/2016/content/fonts/CompositExtraSlot0.mesh new file mode 100644 index 0000000..87b9d85 Binary files /dev/null and b/2016/content/fonts/CompositExtraSlot0.mesh differ diff --git a/2016/content/fonts/CompositExtraSlot1.mesh b/2016/content/fonts/CompositExtraSlot1.mesh new file mode 100644 index 0000000..6874c5e Binary files /dev/null and b/2016/content/fonts/CompositExtraSlot1.mesh differ diff --git a/2016/content/fonts/CompositExtraSlot2.mesh b/2016/content/fonts/CompositExtraSlot2.mesh new file mode 100644 index 0000000..423f198 Binary files /dev/null and b/2016/content/fonts/CompositExtraSlot2.mesh differ diff --git a/2016/content/fonts/CompositExtraSlot3.mesh b/2016/content/fonts/CompositExtraSlot3.mesh new file mode 100644 index 0000000..de05ced Binary files /dev/null and b/2016/content/fonts/CompositExtraSlot3.mesh differ diff --git a/2016/content/fonts/CompositExtraSlot4.mesh b/2016/content/fonts/CompositExtraSlot4.mesh new file mode 100644 index 0000000..ff9cb62 Binary files /dev/null and b/2016/content/fonts/CompositExtraSlot4.mesh differ diff --git a/2016/content/fonts/CompositFullAtlasBaseTexture.mesh b/2016/content/fonts/CompositFullAtlasBaseTexture.mesh new file mode 100644 index 0000000..b7e6595 Binary files /dev/null and b/2016/content/fonts/CompositFullAtlasBaseTexture.mesh differ diff --git a/2016/content/fonts/CompositFullAtlasOverlayTexture.mesh b/2016/content/fonts/CompositFullAtlasOverlayTexture.mesh new file mode 100644 index 0000000..eda1938 Binary files /dev/null and b/2016/content/fonts/CompositFullAtlasOverlayTexture.mesh differ diff --git a/2016/content/fonts/CompositLeftArmBase.mesh b/2016/content/fonts/CompositLeftArmBase.mesh new file mode 100644 index 0000000..5bcc4ae Binary files /dev/null and b/2016/content/fonts/CompositLeftArmBase.mesh differ diff --git a/2016/content/fonts/CompositLeftLegBase.mesh b/2016/content/fonts/CompositLeftLegBase.mesh new file mode 100644 index 0000000..f4712ce Binary files /dev/null and b/2016/content/fonts/CompositLeftLegBase.mesh differ diff --git a/2016/content/fonts/CompositPantsTemplate.mesh b/2016/content/fonts/CompositPantsTemplate.mesh new file mode 100644 index 0000000..756ee03 Binary files /dev/null and b/2016/content/fonts/CompositPantsTemplate.mesh differ diff --git a/2016/content/fonts/CompositQuad.mesh b/2016/content/fonts/CompositQuad.mesh new file mode 100644 index 0000000..192abf2 Binary files /dev/null and b/2016/content/fonts/CompositQuad.mesh differ diff --git a/2016/content/fonts/CompositRightArmBase.mesh b/2016/content/fonts/CompositRightArmBase.mesh new file mode 100644 index 0000000..02f2721 Binary files /dev/null and b/2016/content/fonts/CompositRightArmBase.mesh differ diff --git a/2016/content/fonts/CompositRightLegBase.mesh b/2016/content/fonts/CompositRightLegBase.mesh new file mode 100644 index 0000000..b287939 Binary files /dev/null and b/2016/content/fonts/CompositRightLegBase.mesh differ diff --git a/2016/content/fonts/CompositShirtTemplate.mesh b/2016/content/fonts/CompositShirtTemplate.mesh new file mode 100644 index 0000000..75487e1 Binary files /dev/null and b/2016/content/fonts/CompositShirtTemplate.mesh differ diff --git a/2016/content/fonts/CompositTShirt.mesh b/2016/content/fonts/CompositTShirt.mesh new file mode 100644 index 0000000..b39b8ac Binary files /dev/null and b/2016/content/fonts/CompositTShirt.mesh differ diff --git a/2016/content/fonts/CompositTorsoBase.mesh b/2016/content/fonts/CompositTorsoBase.mesh new file mode 100644 index 0000000..0388bde Binary files /dev/null and b/2016/content/fonts/CompositTorsoBase.mesh differ diff --git a/2016/content/fonts/Guru-Regular.otf b/2016/content/fonts/Guru-Regular.otf new file mode 100644 index 0000000..20d7398 Binary files /dev/null and b/2016/content/fonts/Guru-Regular.otf differ diff --git a/2016/content/fonts/HWYGOTH.ttf b/2016/content/fonts/HWYGOTH.ttf new file mode 100644 index 0000000..20ac3e2 Binary files /dev/null and b/2016/content/fonts/HWYGOTH.ttf differ diff --git a/2016/content/fonts/Inconsolata-Regular.ttf b/2016/content/fonts/Inconsolata-Regular.ttf new file mode 100644 index 0000000..bbc9647 Binary files /dev/null and b/2016/content/fonts/Inconsolata-Regular.ttf differ diff --git a/2016/content/fonts/LoadingScript.lua b/2016/content/fonts/LoadingScript.lua new file mode 100644 index 0000000..efe5151 --- /dev/null +++ b/2016/content/fonts/LoadingScript.lua @@ -0,0 +1,815 @@ +--rbxsig%hm7SbDaf0GHizpUYxb6qQAHuUU7LfsWX8bgPnc64hv1MnSJFX+Komih+acv/5vqLxpzxHNtvBCnuAwN6l63fYukZ0Yat7mDBHBx0w0CPTaWSCs2P5WDx/W7P+L8AkqpaowXKgCKST9VBErgwqTlUySsi0r9+HfExO+cl3h2lXig=% +--rbxassetid%158948138% +-- Creates the generic "ROBLOX" loading screen on startup +-- Written by ArceusInator & Ben Tkacheff, 2014 +-- + +-- Constants +local PLACEID = Game.PlaceId + +local MPS = Game:GetService 'MarketplaceService' +local CP = Game:GetService 'ContentProvider' + +local COLORS = { + BLACK = Color3.new(0, 0, 0), + DARK = Color3.new(35/255, 35/255, 38/255), + DARKMED = Color3.new(61/255, 61/255, 67/255), + DARKMED2 = Color3.new(75/255, 76/255, 85/255), + MED = Color3.new(118/255, 118/255, 129/255), + LIGHTMED = Color3.new(190/255, 192/255, 212/255), + LIGHT = Color3.new(217/255, 218/255, 231/255), + ERROR = Color3.new(253/255,68/255,72/255) +} + +local IMAGES = { + BACKGROUND_THUMBNAIL_VIGNETTE = 'rbxasset://textures/loading/loadingvignette.png', + ROBLOX_LOGO_256 = 'rbxasset://textures/loading/robloxlogo.png', + GAME_THUMBNAIL = 'http://www.roblox.com/Thumbs/Asset.ashx?format=png&width=420&height=230&assetId=', + GAME_BACKGROUND = 'rbxasset://textures/loading/loadingTexture.png' +} + +local VALID_TEXT_SIZES = { + 12, + 14, + 18, + 24, + 36, + 48 +} + +-- +-- Variables +local GameAssetInfo -- loaded by InfoProvider:LoadAssets() +local currScreenGui = nil +local renderSteppedConnection = nil + +-- +-- Utility functions +local create = function(className, defaultParent) + return function(propertyList) + local object = Instance.new(className) + + for index, value in next, propertyList do + if type(index) == 'string' then + object[index] = value + else + if type(value) == 'function' then + value(object) + elseif type(value) == 'userdata' then + value.Parent = object + end + end + end + + if object.Parent == nil then + object.Parent = defaultParent + end + + return object + end +end + +-- +-- Create objects +local MainGui = {} +local InfoProvider = {} + + +function InfoProvider:GetGameName() + if GameAssetInfo ~= nil then + return GameAssetInfo.Name + else + return '' + end +end + +function InfoProvider:GetCreatorName() + if GameAssetInfo ~= nil then + return GameAssetInfo.Creator.Name + else + return '' + end +end + +function InfoProvider:LoadAssets() + Spawn(function() + if PLACEID <= 0 then + while Game.PlaceId <= 0 do + wait() + end + PLACEID = Game.PlaceId + end + + IMAGES.GAME_THUMBNAIL = IMAGES.GAME_THUMBNAIL .. tostring(PLACEID) + + -- load game asset info + coroutine.resume(coroutine.create(function() GameAssetInfo = MPS:GetProductInfo(PLACEID) end)) + + while not currScreenGui do + wait() + end + currScreenGui.ThumbnailContainer.Thumbnail.Image = IMAGES.GAME_THUMBNAIL + + -- load images + for imageName, imageContent in next, IMAGES do + CP:Preload(imageContent) + end + + end) +end + +-- +-- Declare member functions +function MainGui:GenerateMain() + local screenGui = create 'ScreenGui' { + Name = 'RobloxLoadingGui' + } + + -- + -- create descendant frames + + local mainBackgroundContainer = create 'Frame' { + Name = 'MainBackgroundContainer', + BackgroundColor3 = COLORS.DARK, + Size = UDim2.new(1, 0, 1, 0), + Active = true, + + create 'Frame' { + Name = 'TopBar', + BackgroundColor3 = COLORS.DARKMED, + BorderColor3 = COLORS.MED, + BorderSizePixel = 3, + Position = UDim2.new(0, -220, 0, -205), + Rotation = -10, + Size = UDim2.new(0, 1000, 0, 220), + ZIndex = 5, + + create 'ImageLabel' { + Name = 'RobloxLogo', + BackgroundTransparency = 1, + Image = IMAGES.ROBLOX_LOGO_256, + Position = UDim2.new(0, 214, 1, -80), + Rotation = 2, + Size = UDim2.new(0, 128, 0, 128), + ZIndex = 6, + + create 'TextLabel' { + Name = 'PoweredBy', + BackgroundTransparency = 1, + Position = UDim2.new(0.5, -60, 0, 30), + Size = UDim2.new(0, 80, 0, 18), + Font = Enum.Font.SourceSans, + FontSize = Enum.FontSize.Size18, + TextColor3 = Color3.new(1,1,1), + Text = "Powered By", + ZIndex = 6 + } + } + }, + + create 'ImageButton' { + Name = 'CloseButton', + Image = 'rbxasset://textures/ui/CloseButton.png', + BackgroundTransparency = 1, + Position = UDim2.new(1, -27, 0, 5), + Size = UDim2.new(0, 22, 0, 22), + Active = true, + ZIndex = 10 + }, + + create 'Frame' { + Name = 'ErrorFrame', + BackgroundColor3 = COLORS.ERROR, + BorderSizePixel = 0, + Position = UDim2.new(0.25,0,0,0), + Size = UDim2.new(0.5, 0, 0, 80), + ZIndex = 5, + Visible = false, + + create 'TextLabel' { + Name = "ErrorText", + BackgroundTransparency = 1, + ZIndex = 6, + Position = UDim2.new(0,5,0,5), + Size = UDim2.new(1,-10,1,-10), + Font = Enum.Font.SourceSans, + FontSize = Enum.FontSize.Size18, + Text = "", + TextColor3 = Color3.new(1,1,1), + TextXAlignment = Enum.TextXAlignment.Center, + TextYAlignment = Enum.TextYAlignment.Center, + TextWrap = true + } + }, + + create 'Frame' { + Name = 'BottomBar', + BorderSizePixel = 0, + BackgroundTransparency = 1, + Position = UDim2.new(0, 0, 1, -150), + Size = UDim2.new(1, 0, 0, 300), + ZIndex = 5, + + create 'Frame' { + Name = 'BottomBarActual', + BackgroundColor3 = COLORS.DARKMED, + BorderColor3 = COLORS.MED, + BorderSizePixel = 3, + Position = UDim2.new(0, 0, 0, 0), + Size = UDim2.new(1, 0, 1, 0), + ZIndex = 5, + + create 'Frame' { + Name = 'TextContainer', + BackgroundTransparency = 1, + Position = UDim2.new(0, -5, 0, 5), + Size = UDim2.new(1, 0, 1, 0), + ZIndex = 8, + + create 'TextLabel' { + Name = 'CreatorName', + BackgroundTransparency = 1, + Position = UDim2.new(0, 0, 0, 70), + Size = UDim2.new(1, 0, 1, 0), + ZIndex = 9, + Font = Enum.Font.SourceSansBold, + FontSize = Enum.FontSize.Size48, + Text = InfoProvider:GetCreatorName(), + TextColor3 = COLORS.LIGHT, + TextStrokeColor3 = COLORS.DARKMED2, + TextStrokeTransparency = 0, + TextXAlignment = Enum.TextXAlignment.Right, + TextYAlignment = Enum.TextYAlignment.Top + }, + + create 'TextLabel' { + Name = 'GameName', + BackgroundTransparency = 1, + Position = UDim2.new(0, 0, 0, 30), + Size = UDim2.new(1, 0, 1, 0), + ZIndex = 9, + Font = Enum.Font.SourceSansBold, + FontSize = Enum.FontSize.Size48, + Text = InfoProvider:GetGameName(), + TextColor3 = COLORS.LIGHT, + TextStrokeColor3 = COLORS.DARKMED2, + TextStrokeTransparency = 0, + TextXAlignment = Enum.TextXAlignment.Right, + TextYAlignment = Enum.TextYAlignment.Top + }, + + create 'TextLabel' { + Name = 'CreatorNamePrefix', + BackgroundTransparency = 1, + Size = UDim2.new(1, 0, 1, 0), + ZIndex = 9, + Font = Enum.Font.SourceSans, + FontSize = Enum.FontSize.Size48, + Text = 'By', + TextColor3 = COLORS.LIGHTMED, + TextStrokeColor3 = COLORS.DARKMED2, + TextStrokeTransparency = 0, + TextXAlignment = Enum.TextXAlignment.Right, + TextYAlignment = Enum.TextYAlignment.Top + }, + + create 'TextLabel' { + Name = 'OnYourWay', + BackgroundTransparency = 1, + Size = UDim2.new(1, 0, 1, 0), + ZIndex = 9, + Font = Enum.Font.SourceSans, + FontSize = Enum.FontSize.Size36, + Text = 'You\'re on your way to', + TextColor3 = COLORS.LIGHTMED, + TextStrokeColor3 = COLORS.DARKMED2, + TextStrokeTransparency = 0, + TextXAlignment = Enum.TextXAlignment.Right, + TextYAlignment = Enum.TextYAlignment.Top + } + } + } + }, + + create 'ImageLabel' { + Name = 'BackgroundThumbnailVignette', + BackgroundTransparency = 1, + Image = IMAGES.BACKGROUND_THUMBNAIL_VIGNETTE, + Size = UDim2.new(1, 0, 1, 0), + ZIndex = 3 + }, + + create 'ImageLabel' { + Name = 'BackgroundThumbnail', + BackgroundTransparency = 1, + Image = IMAGES.GAME_BACKGROUND, + Size = UDim2.new(1.5, 0, 1.5, 0), + Position = UDim2.new(-0.5,0,0,0), + ZIndex = 2 + }, + + Parent = screenGui + } + + local thumbnailContainer = create 'Frame' { + Name = 'ThumbnailContainer', + BackgroundColor3 = COLORS.BLACK, + BorderColor3 = COLORS.MED, + BorderSizePixel = 4, + Position = UDim2.new(0.5, -210, 0.5, -115), + Size = UDim2.new(0, 420, 0, 230), + ZIndex = 8, + + create 'ImageLabel' { + Name = 'Thumbnail', + BorderColor3 = COLORS.DARKMED2, + BorderSizePixel = 3, + Image = "", + Size = UDim2.new(1, 0, 1, 0), + ZIndex = 8 + }, + + create 'Frame' { + Name = 'LoadingInfoContainer', + BorderColor3 = COLORS.MED, + BackgroundColor3 = COLORS.DARKMED, + BorderSizePixel = 2, + Position = UDim2.new(0,20,1,0), + Size = UDim2.new(1,-40,0,40), + ZIndex = 7, + + create 'TextLabel' { + Name = 'InstancesLabel', + BackgroundTransparency = 1, + Position = UDim2.new(0,0,0,5), + Size = UDim2.new(0.25, 0, 1, -10), + ZIndex = 9, + Font = Enum.Font.SourceSansBold, + FontSize = Enum.FontSize.Size14, + Text = 'Instances', + TextColor3 = COLORS.LIGHTMED, + TextStrokeColor3 = COLORS.DARKMED2, + TextStrokeTransparency = 0, + TextXAlignment = Enum.TextXAlignment.Center, + TextYAlignment = Enum.TextYAlignment.Top + }, + create 'TextLabel' { + Name = 'InstancesValue', + BackgroundTransparency = 1, + Position = UDim2.new(0,0,0,5), + Size = UDim2.new(0.25, 0, 1, -10), + ZIndex = 9, + Font = Enum.Font.SourceSansBold, + FontSize = Enum.FontSize.Size14, + Text = '0', + TextColor3 = COLORS.LIGHTMED, + TextStrokeColor3 = COLORS.DARKMED2, + TextStrokeTransparency = 0, + TextXAlignment = Enum.TextXAlignment.Center, + TextYAlignment = Enum.TextYAlignment.Bottom + }, + + + + + create 'TextLabel' { + Name = 'VoxelsLabel', + BackgroundTransparency = 1, + Position = UDim2.new(0.75,0,0,5), + Size = UDim2.new(0.25, 0, 1, -10), + ZIndex = 9, + Font = Enum.Font.SourceSansBold, + FontSize = Enum.FontSize.Size14, + Text = 'Voxels', + TextColor3 = COLORS.LIGHTMED, + TextStrokeColor3 = COLORS.DARKMED2, + TextStrokeTransparency = 0, + TextXAlignment = Enum.TextXAlignment.Center, + TextYAlignment = Enum.TextYAlignment.Top + }, + create 'TextLabel' { + Name = 'VoxelsValue', + BackgroundTransparency = 1, + Position = UDim2.new(0.75,0,0,5), + Size = UDim2.new(0.25, 0, 1, -10), + ZIndex = 9, + Font = Enum.Font.SourceSansBold, + FontSize = Enum.FontSize.Size14, + Text = '0', + TextColor3 = COLORS.LIGHTMED, + TextStrokeColor3 = COLORS.DARKMED2, + TextStrokeTransparency = 0, + TextXAlignment = Enum.TextXAlignment.Center, + TextYAlignment = Enum.TextYAlignment.Bottom + }, + + + + create 'TextLabel' { + Name = 'ConnectorsLabel', + BackgroundTransparency = 1, + Position = UDim2.new(0.5,0,0,5), + Size = UDim2.new(0.25, 0, 1, -10), + ZIndex = 9, + Font = Enum.Font.SourceSansBold, + FontSize = Enum.FontSize.Size14, + Text = 'Connectors', + TextColor3 = COLORS.LIGHTMED, + TextStrokeColor3 = COLORS.DARKMED2, + TextStrokeTransparency = 0, + TextXAlignment = Enum.TextXAlignment.Center, + TextYAlignment = Enum.TextYAlignment.Top + }, + create 'TextLabel' { + Name = 'ConnectorsValue', + BackgroundTransparency = 1, + Position = UDim2.new(0.5,0,0,5), + Size = UDim2.new(0.25, 0, 1, -10), + ZIndex = 9, + Font = Enum.Font.SourceSansBold, + FontSize = Enum.FontSize.Size14, + Text = '0', + TextColor3 = COLORS.LIGHTMED, + TextStrokeColor3 = COLORS.DARKMED2, + TextStrokeTransparency = 0, + TextXAlignment = Enum.TextXAlignment.Center, + TextYAlignment = Enum.TextYAlignment.Bottom + }, + + + + create 'TextLabel' { + Name = 'BricksLabel', + BackgroundTransparency = 1, + Position = UDim2.new(0.25,0,0,5), + Size = UDim2.new(0.25, 0, 1, -10), + ZIndex = 9, + Font = Enum.Font.SourceSansBold, + FontSize = Enum.FontSize.Size14, + Text = 'Bricks', + TextColor3 = COLORS.LIGHTMED, + TextStrokeColor3 = COLORS.DARKMED2, + TextStrokeTransparency = 0, + TextXAlignment = Enum.TextXAlignment.Center, + TextYAlignment = Enum.TextYAlignment.Top + }, + create 'TextLabel' { + Name = 'BricksValue', + BackgroundTransparency = 1, + Position = UDim2.new(0.25,0,0,5), + Size = UDim2.new(0.25, 0, 1, -10), + ZIndex = 9, + Font = Enum.Font.SourceSansBold, + FontSize = Enum.FontSize.Size14, + Text = '0', + TextColor3 = COLORS.LIGHTMED, + TextStrokeColor3 = COLORS.DARKMED2, + TextStrokeTransparency = 0, + TextXAlignment = Enum.TextXAlignment.Center, + TextYAlignment = Enum.TextYAlignment.Bottom + }, + }, + + Parent = screenGui + } + + -- + -- recalculate everything + while not Game:GetService("CoreGui") do + wait() + end + screenGui.Parent = Game.CoreGui + + MainGui:RecalculateSizes(screenGui) + + -- + -- return generated gui + return screenGui +end + +function MainGui:RecalculateTextSize(screenGui) + local screenSize = screenGui.AbsoluteSize + + local textSizeScale = math.min(screenSize.y/800, 1) + local closestValidSizePrevIndex = math.floor(textSizeScale*#VALID_TEXT_SIZES)-1 + local closestValidSizePrevIndex2 = closestValidSizePrevIndex-1 + local closestValidTextSize + local closestValidTextSizePrev + -- next can't take a 0 because it's a total wuss + if closestValidSizePrevIndex > 0 then + _, closestValidTextSize = next(VALID_TEXT_SIZES, closestValidSizePrevIndex) + if closestValidSizePrevIndex2 > 0 then + _, closestValidTextSizePrev = next(VALID_TEXT_SIZES, closestValidSizePrevIndex2) + else + _, closestValidTextSizePrev = next(VALID_TEXT_SIZES) -- not doing t[1] because this looks cleaner + end + else + _, closestValidTextSize = next(VALID_TEXT_SIZES) + _, closestValidTextSizePrev = next(VALID_TEXT_SIZES) + end + local textSizeEnum = Enum.FontSize['Size'..closestValidTextSize] + local textSizePrevEnum = Enum.FontSize['Size'..closestValidTextSizePrev] + + if not screenGui:FindFirstChild("MainBackgroundContainer") then return end + + local TextContainer = screenGui.MainBackgroundContainer.BottomBar.BottomBarActual.TextContainer + local currentYBumpDistance = 0 + TextContainer.OnYourWay.FontSize = textSizePrevEnum + currentYBumpDistance = currentYBumpDistance + closestValidTextSizePrev*(40/48) + TextContainer.GameName.Position = UDim2.new(0, 0, 0, currentYBumpDistance) + TextContainer.GameName.FontSize = textSizeEnum + currentYBumpDistance = currentYBumpDistance + closestValidTextSize*(40/48) + TextContainer.CreatorName.Position = UDim2.new(0, 0, 0, currentYBumpDistance) + TextContainer.CreatorName.FontSize = textSizeEnum + local currentXBumpDistance = -(TextContainer.CreatorName.TextBounds.X+5) + TextContainer.CreatorNamePrefix.Position = UDim2.new(0, currentXBumpDistance, 0, currentYBumpDistance) + TextContainer.CreatorNamePrefix.FontSize = textSizeEnum + + -- recalculate bottom bar size + local sizeScale = closestValidTextSize/48 + screenGui.MainBackgroundContainer.BottomBar.Size = UDim2.new(1, 0, 0, 300 * sizeScale) + screenGui.MainBackgroundContainer.BottomBar.Position = UDim2.new(0, 0, 1, -150 * sizeScale) + screenGui.MainBackgroundContainer.BottomBar.BottomBarActual.Position = UDim2.new(0, -130 * sizeScale,0,0) +end + +function MainGui:RecalculateSizes(screenGui) + local screenSize = screenGui.AbsoluteSize + + -- recalculate thumbnail size + local thumbnailSizeScale = math.min(math.max(screenSize.y/630, 50/230), 1) + local thumbnailSize = UDim2.new(0, thumbnailSizeScale*420, 0, thumbnailSizeScale*230) + local thumbnailPosition = UDim2.new(0.5, -thumbnailSizeScale*420/2, 0.5, -20 - thumbnailSizeScale*230/2 ) + screenGui.ThumbnailContainer.Size = thumbnailSize + screenGui.ThumbnailContainer.Position = thumbnailPosition + + screenGui.ThumbnailContainer.LoadingInfoContainer.Visible = (screenSize.Y > 500) + + -- update names + + -- if we don't have a name yet, keep trying! + if InfoProvider:GetCreatorName() == '' or InfoProvider:GetGameName() == '' then + Spawn(function() + + while InfoProvider and InfoProvider:GetCreatorName() == '' or InfoProvider:GetGameName() == '' do + wait() + end + + if screenGui and screenGui:FindFirstChild("MainBackgroundContainer") then + screenGui.MainBackgroundContainer.BottomBar.BottomBarActual.TextContainer.CreatorName.Text = InfoProvider:GetCreatorName() + screenGui.MainBackgroundContainer.BottomBar.BottomBarActual.TextContainer.GameName.Text = InfoProvider:GetGameName() + end + + MainGui:RecalculateTextSize(screenGui) + end) + else + screenGui.MainBackgroundContainer.BottomBar.BottomBarActual.TextContainer.CreatorName.Text = InfoProvider:GetCreatorName() + screenGui.MainBackgroundContainer.BottomBar.BottomBarActual.TextContainer.GameName.Text = InfoProvider:GetGameName() + end + + MainGui:RecalculateTextSize(screenGui) +end + +function MainGui:Show() + currScreenGui = MainGui:GenerateMain() + currScreenGui.MainBackgroundContainer.Visible = true + currScreenGui.ThumbnailContainer.Visible = true + + currScreenGui.Changed:connect(function(prop) + if prop == "AbsoluteSize" then + MainGui:RecalculateSizes(currScreenGui) + end + end) +end + + + +--------------------------------------------------------- +-- Main Script (show something now + setup connections) + +-- start loading assets asap +InfoProvider:LoadAssets() + +MainGui:Show() + +local guiService = Game:GetService("GuiService") +local instanceCount = 0 +local voxelCount = 0 +local brickCount = 0 +local connectorCount = 0 +local setVerb = true + +renderSteppedConnection = Game:GetService("RunService").RenderStepped:connect(function() + + instanceCount = guiService:GetInstanceCount() + voxelCount = guiService:GetVoxelCount() + brickCount = guiService:GetBrickCount() + connectorCount = guiService:GetConnectorCount() + + if not currScreenGui then return end + + if setVerb then + currScreenGui.MainBackgroundContainer.CloseButton:SetVerb("Exit") + setVerb = false + end + + currScreenGui.ThumbnailContainer.LoadingInfoContainer.InstancesValue.Text = tostring(instanceCount) + currScreenGui.ThumbnailContainer.LoadingInfoContainer.BricksValue.Text = tostring(brickCount) + currScreenGui.ThumbnailContainer.LoadingInfoContainer.ConnectorsValue.Text = tostring(connectorCount) + + if voxelCount <= 0 then + currScreenGui.ThumbnailContainer.LoadingInfoContainer.VoxelsValue.Text = "0" + else + currScreenGui.ThumbnailContainer.LoadingInfoContainer.VoxelsValue.Text = tostring(voxelCount) .." million" + end +end) + +guiService.ErrorMessageChanged:connect(function() + if guiService:GetErrorMessage() ~= '' then + currScreenGui.MainBackgroundContainer.ErrorFrame.ErrorText.Text = guiService:GetErrorMessage() + currScreenGui.MainBackgroundContainer.ErrorFrame.Visible = true + else + currScreenGui.MainBackgroundContainer.ErrorFrame.Visible = false + end +end) + +if guiService:GetErrorMessage() ~= '' then + currScreenGui.MainBackgroundContainer.ErrorFrame.ErrorText.Text = guiService:GetErrorMessage() + currScreenGui.MainBackgroundContainer.ErrorFrame.Visible = true +end + + +local forceRemovalTime = 5 +local destroyed = false + +function removeLoadingScreen() + if renderSteppedConnection then + renderSteppedConnection:disconnect() + end + + if currScreenGui then + currScreenGui:Destroy() + currScreenGui = nil + end + + if script then script:Destroy() end + destroyed = true +end + + +function startForceLoadingDoneTimer() + wait(forceRemovalTime) + removeLoadingScreen() +end + +function gameIsLoaded() + if Game.ReplicatedFirst:IsDefaultLoadingGuiRemoved() then + removeLoadingScreen() + else + startForceLoadingDoneTimer() + end +end + +Game.ReplicatedFirst.RemoveDefaultLoadingGuiSignal:connect(function() + removeLoadingScreen() +end) + +if Game.ReplicatedFirst:IsDefaultLoadingGuiRemoved() then + removeLoadingScreen() + return +end + +Game.Loaded:connect(function() + gameIsLoaded() +end) + +if Game:IsLoaded() then + gameIsLoaded() +end + +-------------------------------------------------------------------------- +-- +-- Animation (make the stuff we are showing look cool) + +local blockSize = 10 +local blockColor = Color3.new(33/255,66/255,209/255) + +local yPosScale = 0 +local yPosOffset = -blockSize * 3.5 + +local tweenStyle = Enum.EasingStyle.Sine +local tweenVelocity = 1500 +local tweenTime = (currScreenGui.AbsoluteSize.X/2)/tweenVelocity + +function createBlock() + local initBlock = Instance.new("Frame") + initBlock.ZIndex = 5 + initBlock.Size = UDim2.new(0,blockSize,0,blockSize) + initBlock.BackgroundColor3 = COLORS.DARK + initBlock.BorderSizePixel = 0 + initBlock.Position = UDim2.new(0,-blockSize,yPosScale,yPosOffset) + initBlock.Parent = currScreenGui.MainBackgroundContainer.BottomBar + + return initBlock +end + + +local blocks = {} +for i = 1,6 do + blocks[i] = createBlock() +end + +function getYOffset(newSize) + return yPosOffset - (newSize/3) +end + +function rightScreenExit() + wait(tweenTime * 3) + if not currScreenGui then return end + + local regSize = blocks[6].Size + local regPos = blocks[6].Position + + blocks[6].Size = blocks[1].Size + blocks[6].Position = blocks[1].Position + + blocks[1].Size = regSize + blocks[1].Position = regPos + + wait() + + for i = 1,6 do + local delayTime = tweenTime * (i - 1) * 0.5 + Delay(delayTime, function() + if not currScreenGui then return end + + local blockIndex = i + local blockSizeMultiplier = 4 - (i * 0.5) + + blocks[blockIndex]:TweenPosition(UDim2.new(1,0,yPosScale,yPosOffset), + Enum.EasingDirection.Out,tweenStyle, + tweenTime,true) + if i == 6 then + blocks[6]:TweenSizeAndPosition(UDim2.new(0,blockSize,0,blockSize), + UDim2.new(1,0,yPosScale,yPosOffset), + Enum.EasingDirection.InOut,tweenStyle, + tweenTime,true) + + wait(tweenTime * 1.1) + leftScreenEntrance() + else + local newSize = blockSize * blockSizeMultiplier + blocks[6]:TweenSizeAndPosition(UDim2.new(0,newSize,0,newSize), + UDim2.new(0.5,-newSize/2,yPosScale,getYOffset(newSize)), + Enum.EasingDirection.InOut,tweenStyle, + tweenTime * 0.75,true) + end + end) + end +end + +function leftScreenEntrance() + if not currScreenGui then return end + + for i = 1,6 do + blocks[i].Size = UDim2.new(0,blockSize,0,blockSize) + blocks[i].Position = UDim2.new(0,-blockSize,yPosScale,yPosOffset) + end + + blocks[1]:TweenPosition(UDim2.new(0.5,-blockSize/2,yPosScale,yPosOffset),Enum.EasingDirection.Out,tweenStyle,tweenTime,true,function() + for i = 1, 6 do + local delayTime = tweenTime * (i - 1) * 0.5 + + Delay(delayTime, function() + if not currScreenGui then return end + + local blockIndex = i + local blockSizeMultiplier = 1 + (i * 0.5) + + blocks[blockIndex]:TweenPosition(UDim2.new(0.5,-blockSize/2,yPosScale,yPosOffset), + Enum.EasingDirection.Out,tweenStyle, + tweenTime,true) + + local newSize = blockSize * blockSizeMultiplier + blocks[1]:TweenSizeAndPosition(UDim2.new(0,newSize,0,newSize), + UDim2.new(0.5,-newSize/2,yPosScale,getYOffset(newSize)), + Enum.EasingDirection.InOut,tweenStyle, + tweenTime * 0.75,true) + + + if i == 4 then + rightScreenExit() + end + end) + end + end) +end + +function startLoadingAnimation() + currScreenGui.MainBackgroundContainer.BackgroundThumbnail:TweenPosition(UDim2.new(0,0,0,0),Enum.EasingDirection.InOut,Enum.EasingStyle.Linear,20,true) + leftScreenEntrance() +end + + +---------------------------------- +-- Animation Begin +startLoadingAnimation() \ No newline at end of file diff --git a/2016/content/fonts/PressStart2P-Regular.ttf b/2016/content/fonts/PressStart2P-Regular.ttf new file mode 100644 index 0000000..e659e95 Binary files /dev/null and b/2016/content/fonts/PressStart2P-Regular.ttf differ diff --git a/2016/content/fonts/R15CompositLeftArmBase.mesh b/2016/content/fonts/R15CompositLeftArmBase.mesh new file mode 100644 index 0000000..c262d08 Binary files /dev/null and b/2016/content/fonts/R15CompositLeftArmBase.mesh differ diff --git a/2016/content/fonts/R15CompositRightArmBase.mesh b/2016/content/fonts/R15CompositRightArmBase.mesh new file mode 100644 index 0000000..c745b94 Binary files /dev/null and b/2016/content/fonts/R15CompositRightArmBase.mesh differ diff --git a/2016/content/fonts/R15CompositTorsoBase.mesh b/2016/content/fonts/R15CompositTorsoBase.mesh new file mode 100644 index 0000000..ddd2faa Binary files /dev/null and b/2016/content/fonts/R15CompositTorsoBase.mesh differ diff --git a/2016/content/fonts/Rocket.rbxm b/2016/content/fonts/Rocket.rbxm new file mode 100644 index 0000000..72beea5 --- /dev/null +++ b/2016/content/fonts/Rocket.rbxm @@ -0,0 +1,102 @@ + + null + nil + + + false + -0.5 + 0.5 + 3 + 0 + -0.5 + 0.5 + 3 + 0 + 23 + + -0.5 + 0.5 + 0 + -1.1920929e-007 + 1.00000012 + 0 + 1.00000012 + -1.1920929e-007 + 0 + 0 + 0 + -1.00000024 + + true + true + 0 + true + true + 0.5 + 0 + 0.300000012 + -0.5 + 0.5 + 3 + 0 + -0.5 + 0.5 + 3 + 0 + false + Rocket + 0 + -0.5 + 0.5 + 3 + 0 + + 0 + 0 + 0 + + -0.5 + 0.5 + 3 + 0 + 0 + + 0 + 0 + 0 + + 1 + + 1 + 1 + 4 + + + + + true + Swoosh + 0 + false + rbxasset://sounds\Rocket whoosh 01.wav + 0.699999988 + + + + + false + Explosion + 0 + true + rbxasset://sounds\collide.wav + 1 + + + + + Script + r = game:service("RunService") shaft = script.Parent position = Vector3.new(0,0,0) function fly() direction = shaft.CFrame.lookVector position = position + direction error = position - shaft.Position shaft.Velocity = 7*error end function blow() swoosh:Stop() explosion = Instance.new("Explosion") explosion.Position = shaft.Position explosion.Parent = game.Workspace connection:disconnect() shaft:remove() end t, s = r.Stepped:wait() swoosh = script.Parent.Swoosh swoosh:Play() position = shaft.Position d = t + 10.0 - s connection = shaft.Touched:connect(blow) while t < d do fly() t = r.Stepped:wait() end script.Parent.Explosion.PlayOnRemove = false swoosh:Stop() shaft:remove() + + + + \ No newline at end of file diff --git a/2016/content/fonts/RomanAntique.otf b/2016/content/fonts/RomanAntique.otf new file mode 100644 index 0000000..dac6f3d Binary files /dev/null and b/2016/content/fonts/RomanAntique.otf differ diff --git a/2016/content/fonts/SlingshotPellet.rbxm b/2016/content/fonts/SlingshotPellet.rbxm new file mode 100644 index 0000000..d753b0a --- /dev/null +++ b/2016/content/fonts/SlingshotPellet.rbxm @@ -0,0 +1,82 @@ + + null + nil + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 4 + 0 + 194 + + 0 + 6.4000001 + -8 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + true + true + 0 + true + true + 0.5 + 0 + 0.300000012 + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + false + Pellet + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + -0.5 + 0.5 + 3 + 0 + 0 + + 0 + 0 + 0 + + 0 + + 2 + 2 + 2 + + + + + Script + pellet = script.Parent damage = 8 function onTouched(hit) humanoid = hit.Parent:findFirstChild("Humanoid") if humanoid~=nil then humanoid.Health = humanoid.Health - damage connection:disconnect() else damage = damage / 2 if damage < 0.1 then connection:disconnect() end end end connection = pellet.Touched:connect(onTouched) r = game:service("RunService") t, s = r.Stepped:wait() d = t + 1.0 - s while t < d do t = r.Stepped:wait() end pellet.Parent = nil + + + + \ No newline at end of file diff --git a/2016/content/fonts/SourceSans.font b/2016/content/fonts/SourceSans.font new file mode 100644 index 0000000..6b7a4f3 Binary files /dev/null and b/2016/content/fonts/SourceSans.font differ diff --git a/2016/content/fonts/SourceSansBold.font b/2016/content/fonts/SourceSansBold.font new file mode 100644 index 0000000..f3520e0 Binary files /dev/null and b/2016/content/fonts/SourceSansBold.font differ diff --git a/2016/content/fonts/SourceSansItalic.font b/2016/content/fonts/SourceSansItalic.font new file mode 100644 index 0000000..6c49189 Binary files /dev/null and b/2016/content/fonts/SourceSansItalic.font differ diff --git a/2016/content/fonts/SourceSansLight.font b/2016/content/fonts/SourceSansLight.font new file mode 100644 index 0000000..5bb3ac8 Binary files /dev/null and b/2016/content/fonts/SourceSansLight.font differ diff --git a/2016/content/fonts/SourceSansPro-Bold.ttf b/2016/content/fonts/SourceSansPro-Bold.ttf new file mode 100644 index 0000000..be46652 Binary files /dev/null and b/2016/content/fonts/SourceSansPro-Bold.ttf differ diff --git a/2016/content/fonts/SourceSansPro-It.ttf b/2016/content/fonts/SourceSansPro-It.ttf new file mode 100644 index 0000000..c689cd2 Binary files /dev/null and b/2016/content/fonts/SourceSansPro-It.ttf differ diff --git a/2016/content/fonts/SourceSansPro-Light.ttf b/2016/content/fonts/SourceSansPro-Light.ttf new file mode 100644 index 0000000..dcff4e9 Binary files /dev/null and b/2016/content/fonts/SourceSansPro-Light.ttf differ diff --git a/2016/content/fonts/SourceSansPro-Regular.ttf b/2016/content/fonts/SourceSansPro-Regular.ttf new file mode 100644 index 0000000..a011dff Binary files /dev/null and b/2016/content/fonts/SourceSansPro-Regular.ttf differ diff --git a/2016/content/fonts/arial.ttf b/2016/content/fonts/arial.ttf new file mode 100644 index 0000000..4ba94d1 Binary files /dev/null and b/2016/content/fonts/arial.ttf differ diff --git a/2016/content/fonts/arialbd.ttf b/2016/content/fonts/arialbd.ttf new file mode 100644 index 0000000..2ca4b28 Binary files /dev/null and b/2016/content/fonts/arialbd.ttf differ diff --git a/2016/content/fonts/backup.rbxm b/2016/content/fonts/backup.rbxm new file mode 100644 index 0000000..161e840 --- /dev/null +++ b/2016/content/fonts/backup.rbxm @@ -0,0 +1,850 @@ + + null + nil + + + + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + erik.cassel + RBX1 + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 4 + 0 + 194 + + 0 + 19.5 + 22.5 + -1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + -1 + + true + + false + + 0.5 + 0.300000012 + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + true + 256 + Head + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + -0.5 + 0.5 + 0 + 0 + 0 + + 0 + 0 + 0 + + 0 + 1 + + 2 + 1 + 1 + + + + + 2 + 2 + + 0 + Mesh + + 0 + 0 + 0 + + + 1.25 + 1.25 + 1.25 + + + + 1 + 1 + 1 + + + + + + 5 + face + rbxasset://textures/face.png + 0 + + + + + + 0 + 0.600000024 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + HairAttachment + + + + + + 0 + 0.600000024 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + HatAttachment + + + + + + 0 + 0 + -0.600000024 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + FaceFrontAttachment + + + + + + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + FaceCenterAttachment + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 4 + 0 + 194 + + 0 + 18 + 22.5 + -1 + 0 + -0 + -0 + 1 + -0 + -0 + 0 + -1 + + true + + false + + 0.5 + 0.300000012 + -0.5 + 0.5 + 0 + 0 + 0 + 0 + 2 + 0 + true + 256 + Torso + 0 + 0 + 0 + 2 + 0 + + 0 + 0 + 0 + + -0.5 + 0.5 + 3 + 0 + 0 + + 0 + 0 + 0 + + 0 + 1 + + 2 + 2 + 1 + + + + + 5 + roblox + + 0 + + + + + + 0 + 1 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + NeckAttachment + + + + + + 0 + 0 + -0.5 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + BodyFrontAttachment + + + + + + 0 + 0 + 0.5 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + BodyBackAttachment + + + + + + -1 + 1 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + LeftCollarAttachment + + + + + + 1 + 1 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + RightCollarAttachment + + + + + + 0 + -1 + -0.5 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + WaistFrontAttachment + + + + + + 0 + -1 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + WaistCenterAttachment + + + + + + 0 + -1 + 0.5 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + WaistBackAttachment + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 4 + 0 + 194 + + 1.5 + 18 + 22.5 + -1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + -1 + + false + + false + + 0.5 + 0.300000012 + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + true + 256 + Left Arm + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + -0.5 + 0.5 + 3 + 0 + 0 + + 0 + 0 + 0 + + 0 + 1 + + 1 + 2 + 1 + + + + + + 0 + 1.0 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + LeftShoulderAttachment + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 4 + 0 + 194 + + -1.5 + 18 + 22.5 + -1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + -1 + + false + + false + + 0.5 + 0.300000012 + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + true + 256 + Right Arm + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + -0.5 + 0.5 + 3 + 0 + 0 + + 0 + 0 + 0 + + 0 + 1 + + 1 + 2 + 1 + + + + + + 0 + 1.0 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + RightShoulderAttachment + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + 194 + + 0.5 + 16 + 22.5 + -1 + 0 + -0 + -0 + 1 + -0 + -0 + 0 + -1 + + false + + false + + 0.5 + 0.300000012 + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + true + 256 + Left Leg + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + -0.5 + 0.5 + 3 + 0 + 0 + + 0 + 0 + 0 + + 0 + 1 + + 1 + 2 + 1 + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + 194 + + -0.5 + 16 + 22.5 + -1 + 0 + -0 + -0 + 1 + -0 + -0 + 0 + -1 + + false + + false + + 0.5 + 0.300000012 + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + true + 256 + Right Leg + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + -0.5 + 0.5 + 3 + 0 + 0 + + 0 + 0 + 0 + + 0 + 1 + + 1 + 2 + 1 + + + + + + 0 + 100 + 100 + 0 + 50 + 100 + 89 + Humanoid + 100 + 2 + 16 + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + 194 + + 0 + 18 + 22.5 + -1 + 0 + -0 + -0 + 1 + -0 + -0 + 0 + -1 + + false + + false + + 0.5 + 0.300000012 + -0.5 + 0.5 + 0 + 0 + 0 + 0 + 0 + 0 + true + 256 + HumanoidRootPart + 0 + 0 + 0 + 0 + 0 + + 0 + 0 + 0 + + -0.5 + 0.5 + 0 + 0 + 1 + + 0 + 0 + 0 + + 0 + 1 + + 2 + 2 + 1 + + + + + \ No newline at end of file diff --git a/2016/content/fonts/character.rbxm b/2016/content/fonts/character.rbxm new file mode 100644 index 0000000..7bf4b8a --- /dev/null +++ b/2016/content/fonts/character.rbxm @@ -0,0 +1,527 @@ + + null + nil + + + 7 + true + + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + erik.cassel + RBX1 + true + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 4 + 0 + 24 + + 0 + 4.5 + 25.5 + -1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + -1 + + true + 0 + true + false + 0.5 + 0 + 0.300000012 + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + true + Head + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + -0.5 + 0.5 + 0 + 0 + 0 + + 0 + 0 + 0 + + true + 1 + + 2 + 1 + 1 + + + + + + 0 + Mesh + + 1.25 + 1.25 + 1.25 + + + + 1 + 1 + 1 + + true + + + + + 5 + face + 20 + 0 + rbxasset://textures/face.png + true + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 4 + 0 + 23 + + 0 + 3 + 25.5 + -1 + 0 + -0 + -0 + 1 + -0 + -0 + 0 + -1 + + true + 0 + true + false + 0.5 + 0 + 0.300000012 + -0.5 + 0.5 + 0 + 0 + 0 + 0 + 2 + 0 + true + Torso + 0 + 0 + 0 + 2 + 0 + + 0 + 0 + 0 + + -0.5 + 0.5 + 3 + 0 + 0 + + 0 + 0 + 0 + + true + 1 + + 2 + 2 + 1 + + + + + 5 + roblox + 20 + 0 + + + + true + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 4 + 0 + 24 + + 1.5 + 3 + 25.5 + -1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + -1 + + false + 0 + true + false + 0.5 + 0 + 0.300000012 + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + true + Left Arm + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + -0.5 + 0.5 + 3 + 0 + 0 + + 0 + 0 + 0 + + true + 1 + + 1 + 2 + 1 + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 4 + 0 + 24 + + -1.5 + 3 + 25.5 + -1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + -1 + + false + 0 + true + false + 0.5 + 0 + 0.300000012 + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + true + Right Arm + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + -0.5 + 0.5 + 3 + 0 + 0 + + 0 + 0 + 0 + + true + 1 + + 1 + 2 + 1 + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + 119 + + 0.5 + 1 + 25.5 + -1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + -1 + + false + 0 + true + false + 0.5 + 0 + 0.300000012 + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + true + Left Leg + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + -0.5 + 0.5 + 3 + 0 + 0 + + 0 + 0 + 0 + + true + 1 + + 1 + 2 + 1 + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + 119 + + -0.5 + 1 + 25.5 + -1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + -1 + + false + 0 + true + false + 0.5 + 0 + 0.300000012 + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + true + Right Leg + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + -0.5 + 0.5 + 3 + 0 + 0 + + 0 + 0 + 0 + + true + 1 + + 1 + 2 + 1 + + + + + + 100 + false + 100 + Humanoid + false + + 0 + 0 + 0 + + + 0 + 0 + 0 + + 0 + null + + 0 + 0 + 0 + + true + + + + \ No newline at end of file diff --git a/2016/content/fonts/character3.rbxm b/2016/content/fonts/character3.rbxm new file mode 100644 index 0000000..5d54cb2 Binary files /dev/null and b/2016/content/fonts/character3.rbxm differ diff --git a/2016/content/fonts/characterCameraScript.rbxmx b/2016/content/fonts/characterCameraScript.rbxmx new file mode 100644 index 0000000..809f08a --- /dev/null +++ b/2016/content/fonts/characterCameraScript.rbxmx @@ -0,0 +1,4667 @@ + + null + nil + + + false + + CameraScript + + + + + + ClickToMove + y then + return x + else + return y + end + end + end + Utility.ViewSizeX = ViewSizeX + + local function ViewSizeY() + local camera = workspace.CurrentCamera + local x = camera and camera.ViewportSize.X or 0 + local y = camera and camera.ViewportSize.Y or 0 + if y == 0 then + return 768 + else + if x > y then + return y + else + return x + end + end + end + Utility.ViewSizeY = ViewSizeY + + local function AspectRatio() + return ViewSizeX() / ViewSizeY() + end + Utility.AspectRatio = AspectRatio + + local function FindChacterAncestor(part) + if part then + local humanoid = part:FindFirstChild("Humanoid") + if humanoid then + return part, humanoid + else + return FindChacterAncestor(part.Parent) + end + end + end + Utility.FindChacterAncestor = FindChacterAncestor + + + local function GetUnitRay(x, y, viewWidth, viewHeight, camera) + return camera:ScreenPointToRay(x, y) + end + Utility.GetUnitRay = GetUnitRay + + local RayCastIgnoreList = workspace.FindPartOnRayWithIgnoreList + local function Raycast(ray, ignoreNonCollidable, ignoreList) + local ignoreList = ignoreList or {} + local hitPart, hitPos = RayCastIgnoreList(workspace, ray, ignoreList) + if hitPart then + if ignoreNonCollidable and hitPart.CanCollide == false then + table.insert(ignoreList, hitPart) + return Raycast(ray, ignoreNonCollidable, ignoreList) + end + return hitPart, hitPos + end + return nil, nil + end + Utility.Raycast = Raycast + + + Utility.Round = function(num, roundToNearest) + roundToNearest = roundToNearest or 1 + return math.floor((num + roundToNearest/2) / roundToNearest) * roundToNearest + end + + local function AveragePoints(positions) + local avgPos = Vector2.new(0,0) + if #positions > 0 then + for i = 1, #positions do + avgPos = avgPos + positions[i] + end + avgPos = avgPos / #positions + end + return avgPos + end + Utility.AveragePoints = AveragePoints + + local function FuzzyEquals(numa, numb) + return numa + 0.1 > numb and numa - 0.1 < numb + end + Utility.FuzzyEquals = FuzzyEquals + + local LastInput = 0 + UIS.InputBegan:connect(function(inputObject, wasSunk) + if not wasSunk then + if inputObject.UserInputType == Enum.UserInputType.Touch or + inputObject.UserInputType == Enum.UserInputType.MouseButton1 or + inputObject.UserInputType == Enum.UserInputType.MouseButton2 then + LastInput = tick() + end + end + end) + Utility.GetLastInput = function() + return LastInput + end +end + +local humanoidCache = {} +local function findPlayerHumanoid(player) + local character = player and player.Character + if character then + local resultHumanoid = humanoidCache[player] + if resultHumanoid and resultHumanoid.Parent == character then + return resultHumanoid + else + humanoidCache[player] = nil -- Bust Old Cache + for _, child in pairs(character:GetChildren()) do + if child:IsA('Humanoid') then + humanoidCache[player] = child + return child + end + end + end + end +end + +local function CFrameInterpolator(c0, c1) -- (CFrame from, CFrame to) -> (float theta, (float fraction -> CFrame between)) + local fromAxisAngle = CFrame.fromAxisAngle + local components = CFrame.new().components + local inverse = CFrame.new().inverse + local v3 = Vector3.new + local acos = math.acos + local sqrt = math.sqrt + local invroot2 = 1 / math.sqrt(2) + -- The expanded matrix + local _, _, _, xx, yx, zx, + xy, yy, zy, + xz, yz, zz = components(inverse(c0)*c1) + -- The cos-theta of the axisAngles from + local cosTheta = (xx + yy + zz - 1)/2 + -- Rotation axis + local rotationAxis = v3(yz-zy, zx-xz, xy-yx) + -- The position to tween through + local positionDelta = (c1.p - c0.p) + -- Theta + local theta; + -- Catch degenerate cases + if cosTheta >= 0.999 then + -- Case same rotation, just return an interpolator over the positions + return 0, function(t) + return c0 + positionDelta*t + end + elseif cosTheta <= -0.999 then + -- Case exactly opposite rotations, disambiguate + theta = math.pi + xx = (xx + 1) / 2 + yy = (yy + 1) / 2 + zz = (zz + 1) / 2 + if xx > yy and xx > zz then + if xx < 0.001 then + rotationAxis = v3(0, invroot2, invroot2) + else + local x = sqrt(xx) + xy = (xy + yx) / 4 + xz = (xz + zx) / 4 + rotationAxis = v3(x, xy/x, xz/x) + end + elseif yy > zz then + if yy < 0.001 then + rotationAxis = v3(invroot2, 0, invroot2) + else + local y = sqrt(yy) + xy = (xy + yx) / 4 + yz = (yz + zy) / 4 + rotationAxis = v3(xy/y, y, yz/y) + end + else + if zz < 0.001 then + rotationAxis = v3(invroot2, invroot2, 0) + else + local z = sqrt(zz) + xz = (xz + zx) / 4 + yz = (yz + zy) / 4 + rotationAxis = v3(xz/z, yz/z, z) + end + end + else + -- Normal case, get theta from cosTheta + theta = acos(cosTheta) + end + -- Return the interpolator + return theta, function(t) + return c0*fromAxisAngle(rotationAxis, theta*t) + positionDelta*t + end +end +--------------------------------------------------------- + +local Signal = Utility.Signal +local Create = Utility.Create + +--------------------------CHARACTER CONTROL------------------------------- +local function CreateController() + local this = {} + + this.TorsoLookPoint = nil + + function this:SetTorsoLookPoint(point) + local humanoid = findPlayerHumanoid(Player) + if humanoid then + humanoid.AutoRotate = false + end + this.TorsoLookPoint = point + self:UpdateTorso() + delay(2, + function() + -- this isnt technically correct for detecting if this is the last issue to the setTorso function + if this.TorsoLookPoint == point then + this.TorsoLookPoint = nil + if humanoid then + humanoid.AutoRotate = true + end + end + end) + end + + function this:UpdateTorso(point) + if this.TorsoLookPoint then + point = this.TorsoLookPoint + else + return + end + + local humanoid = findPlayerHumanoid(Player) + local torso = humanoid and humanoid.Torso + if torso then + local lookVec = (point - torso.CFrame.p).unit + local squashedLookVec = Vector3.new(lookVec.X, 0, lookVec.Z).unit + torso.CFrame = CFrame.new(torso.CFrame.p, torso.CFrame.p + squashedLookVec) + end + end + + return this +end + +local CharacterControl = CreateController() +----------------------------------------------------------------------- + +--------------------------PC AUTO JUMPER------------------------------- + +local function GetCharacter() + return Player and Player.Character +end + +local function GetTorso() + local humanoid = findPlayerHumanoid(Player) + return humanoid and humanoid.Torso +end + +local function IsPartAHumanoid(part) + return part and part.Parent and (part.Parent:FindFirstChild('Humanoid') ~= nil) +end + +local function doAutoJump() + local character = GetCharacter() + if (character == nil) then + return; + end + + local humanoid = findPlayerHumanoid(Player) + if (humanoid == nil) then + return; + end + + local rayLength = 1.5; + -- This is how high a ROBLOXian jumps from the mid point of his torso + local jumpHeight = 7.0; + + local torso = GetTorso() + if (torso == nil) then + return; + end + + local torsoCFrame = torso.CFrame; + local torsoLookVector = torsoCFrame.lookVector; + local torsoPos = torsoCFrame.p; + + local torsoRay = Ray.new(torsoPos + Vector3.new(0, -torso.Size.Y/2, 0), torsoLookVector * rayLength); + local jumpRay = Ray.new(torsoPos + Vector3.new(0, jumpHeight - torso.Size.Y, 0), torsoLookVector * rayLength); + + local hitPart, _ = RayCastIgnoreList(workspace, torsoRay, {character}, false) + local jumpHitPart, _ = RayCastIgnoreList(workspace, jumpRay, {character}, false) + + if (hitPart and jumpHitPart == nil and hitPart.CanCollide == true) then + -- NOTE: this follow line is not in the C++ impl, but an improvement in Click to Move + if not IsPartAHumanoid(hitPart) then + humanoid.Jump = true; + end + end +end + +local NO_JUMP_STATES = +{ + [Enum.HumanoidStateType.FallingDown] = false; + [Enum.HumanoidStateType.Flying] = false; + [Enum.HumanoidStateType.Freefall] = false; + [Enum.HumanoidStateType.GettingUp] = false; + [Enum.HumanoidStateType.Ragdoll] = false; + [Enum.HumanoidStateType.Running] = false; + [Enum.HumanoidStateType.Seated] = false; + [Enum.HumanoidStateType.Swimming] = false; + + -- Special case to detect if we are on a ladder + [Enum.HumanoidStateType.Climbing] = false; +} + +local function enableAutoJump() + local humanoid = findPlayerHumanoid(Player) + local currentState = humanoid and humanoid:GetState() + if currentState then + return NO_JUMP_STATES[currentState] == nil + end + return false +end + +local function getAutoJump() + return true +end + +local function vec3IsZero(vec3) + return vec3.magnitude < 0.05 +end + +-- NOTE: This function is radically different from the engine's implementation +local function calcDesiredWalkVelocity() + -- TEMP + return Vector3.new(1,1,1) +end + +local function preStepSimulatorSide(dt) + if getAutoJump() and enableAutoJump() then + local desiredWalkVelocity = calcDesiredWalkVelocity(); + if (not vec3IsZero(desiredWalkVelocity)) then + doAutoJump(); + end + end +end + +local function AutoJumper() + local this = {} + local running = false + local runRoutine = nil + + function this:Run() + running = true + local thisRoutine = nil + thisRoutine = coroutine.create(function() + while running and thisRoutine == runRoutine do + this:Step() + wait() + end + end) + runRoutine = thisRoutine + coroutine.resume(thisRoutine) + end + + function this:Stop() + running = false + end + + function this:Step() + preStepSimulatorSide() + end + + return this +end + +----------------------------------------------------------------------------- + +-----------------------------------PATHER-------------------------------------- + +local function CreateDestinationIndicator(pos) + local destinationGlobe = Create'Part' + { + Name = 'PathGlobe'; + TopSurface = 'Smooth'; + BottomSurface = 'Smooth'; + Shape = 'Ball'; + CanCollide = false; + Size = Vector3.new(2,2,2); + BrickColor = BrickColor.new('Institutional white'); + Transparency = 0; + Anchored = true; + CFrame = CFrame.new(pos); + } + return destinationGlobe +end + +local function Pather(character, point) + local this = {} + + this.Cancelled = false + this.Started = false + + this.Finished = Signal.Create() + this.PathFailed = Signal.Create() + this.PathStarted = Signal.Create() + + this.PathComputed = false + + function this:YieldUntilPointReached(character, point, timeout) + timeout = timeout or 10000000 + + local humanoid = findPlayerHumanoid(Player) + local torso = humanoid and humanoid.Torso + local start = tick() + local lastMoveTo = start + while torso and tick() - start < timeout and this.Cancelled == false do + local diffVector = (point - torso.CFrame.p) + local xzMagnitude = (diffVector * Vector3.new(1,0,1)).magnitude + if xzMagnitude < 6 then + -- Jump if the path is telling is to go upwards + if diffVector.Y >= 2.2 then + humanoid.Jump = true + end + end + -- The hard-coded number 2 here is from the engine's MoveTo implementation + if xzMagnitude < 2 then + return true + end + -- Keep on issuing the move command because it will automatically quit every so often. + if tick() - lastMoveTo > 1.5 then + humanoid:MoveTo(point) + lastMoveTo = tick() + end + CharacterControl:UpdateTorso(point) + wait() + end + return false + end + + function this:Cancel() + this.Cancelled = true + local humanoid = findPlayerHumanoid(Player) + local torso = humanoid and humanoid.Torso + if humanoid and torso then + humanoid:MoveTo(torso.CFrame.p) + end + end + + function this:CheckOcclusion(point1, point2, character, torsoRadius) + local humanoid = findPlayerHumanoid(Player) + local torso = humanoid and humanoid.Torso + if torsoRadius == nil then + torsoRadius = torso and Vector3.new(torso.Size.X/2,0,torso.Size.Z/2) or Vector3.new(1,0,1) + end + + local diffVector = point2 - point1 + local directionVector = diffVector.unit + + local rightVector = Vector3.new(0,1,0):Cross(directionVector) * torsoRadius + + local rightPart, _ = Utility.Raycast(Ray.new(point1 + rightVector, diffVector + rightVector), true, {character}) + local hitPart, _ = Utility.Raycast(Ray.new(point1, diffVector), true, {character}) + local leftPart, _ = Utility.Raycast(Ray.new(point1 - rightVector, diffVector - rightVector), true, {character}) + + if rightPart or hitPart or leftPart then + return false + end + + -- Make sure we have somewhere to stand on + local midPt = (point2 + point1) / 2 + local studsBetweenSamples = 2 + for i = 1, math.floor(diffVector.magnitude/studsBetweenSamples) do + local downPart, _ = Utility.Raycast(Ray.new(point1 + directionVector * i * studsBetweenSamples, Vector3.new(0,-7,0)), true, {character}) + if not downPart then + return false + end + end + + return true + end + + function this:SmoothPoints(pathToSmooth) + local result = {} + + local humanoid = findPlayerHumanoid(Player) + local torso = humanoid and humanoid.Torso + for i = 1, #pathToSmooth do + table.insert(result, pathToSmooth[i]) + end + + -- Backwards for safe-deletion + for i = #result - 1, 1, -1 do + if i + 1 <= #result then + + local nextPoint = result[i+1] + local thisPoint = result[i] + + local lastPoint = result[i-1] + if lastPoint == nil then + lastPoint = torso and Vector3.new(torso.CFrame.p.X, thisPoint.Y, torso.CFrame.p.Z) + end + + if lastPoint and Utility.FuzzyEquals(thisPoint.Y, lastPoint.Y) and Utility.FuzzyEquals(thisPoint.Y, nextPoint.Y) then + if this:CheckOcclusion(lastPoint, nextPoint, character) then + table.remove(result, i) + -- Move i back one to recursively-smooth + i = i + 1 + end + end + end + end + + return result + end + + function this:CheckNeighboringCells(character) + local pathablePoints = {} + local humanoid = findPlayerHumanoid(Player) + local torso = character and humanoid and humanoid.Torso + if torso then + local torsoCFrame = torso.CFrame + local torsoPos = torsoCFrame.p + -- Minus and plus 2 is so we can get it into the cell-corner space and then translate it back into cell-center space + local roundedPos = Vector3.new(Utility.Round(torsoPos.X-2,4)+2, Utility.Round(torsoPos.Y-2,4)+2, Utility.Round(torsoPos.Z-2,4)+2) + local neighboringCells = {} + for x = -4, 4, 8 do + for z = -4, 4, 8 do + table.insert(neighboringCells, roundedPos + Vector3.new(x,0,z)) + end + end + for _, testPoint in pairs(neighboringCells) do + local pathable = this:CheckOcclusion(roundedPos, testPoint, character, Vector3.new(0,0,0)) + if pathable then + table.insert(pathablePoints, testPoint) + end + end + end + return pathablePoints + end + + function this:ComputeDirectPath() + local humanoid = findPlayerHumanoid(Player) + local torso = humanoid and humanoid.Torso + if torso then + local startPt = torso.CFrame.p + local finishPt = point + if (finishPt - startPt).magnitude < 150 then + -- move back the destination by 2 studs or otherwise the pather will collide with the object we are trying to reach + finishPt = finishPt - (finishPt - startPt).unit * 2 + if this:CheckOcclusion(startPt, finishPt, character, Vector3.new(0,0,0)) then + local pathResult = {} + pathResult.Status = Enum.PathStatus.Success + function pathResult:GetPointCoordinates() + return {finishPt} + end + return pathResult + end + end + end + end + + local function AllAxisInThreshhold(targetPt, otherPt, threshold) + return math.abs(targetPt.X - otherPt.X) <= threshold and + math.abs(targetPt.Y - otherPt.Y) <= threshold and + math.abs(targetPt.Z - otherPt.Z) <= threshold + end + + function this:ComputePath() + local smoothed = false + local humanoid = findPlayerHumanoid(Player) + local torso = humanoid and humanoid.Torso + if torso then + if this.PathComputed then return end + this.PathComputed = true + -- Will yield the script since it is an Async script (start, finish, maxDistance) + -- Try to use the smooth function, but it may not exist yet :( + local success = pcall(function() + -- 3 is height from torso cframe to ground + this.pathResult = PathfindingService:ComputeSmoothPathAsync(torso.CFrame.p - Vector3.new(0,3,0), point, 400) + smoothed = true + end) + if not success then + -- 3 is height from torso cframe to ground + this.pathResult = PathfindingService:ComputeRawPathAsync(torso.CFrame.p - Vector3.new(0,3,0), point, 400) + smoothed = false + end + this.pointList = this.pathResult and this.pathResult:GetPointCoordinates() + local pathFound = false + if this.pathResult.Status == Enum.PathStatus.FailFinishNotEmpty then + -- Lets try again with a slightly set back start point; it is ok to do this again so the FailFinishNotEmpty uses little computation + local diffVector = point - workspace.CurrentCamera.CoordinateFrame.p + if diffVector.magnitude > 2 then + local setBackPoint = point - (diffVector).unit * 2.1 + local success = pcall(function() + this.pathResult = PathfindingService:ComputeSmoothPathAsync(torso.CFrame.p, setBackPoint, 400) + smoothed = true + end) + if not success then + this.pathResult = PathfindingService:ComputeRawPathAsync(torso.CFrame.p, setBackPoint, 400) + smoothed = false + end + this.pointList = this.pathResult and this.pathResult:GetPointCoordinates() + pathFound = true + end + end + if this.pathResult.Status == Enum.PathStatus.ClosestNoPath and #this.pointList >= 1 and pathFound == false then + local otherPt = this.pointList[#this.pointList] + if AllAxisInThreshhold(point, otherPt, 4) and (torso.CFrame.p - point).magnitude > (otherPt - point).magnitude then + local pathResult = {} + pathResult.Status = Enum.PathStatus.Success + function pathResult:GetPointCoordinates() + return {this.pointList} + end + this.pathResult = pathResult + pathFound = true + end + end + if (this.pathResult.Status == Enum.PathStatus.FailStartNotEmpty or this.pathResult.Status == Enum.PathStatus.ClosestNoPath) and pathFound == false then + local pathablePoints = this:CheckNeighboringCells(character) + for _, otherStart in pairs(pathablePoints) do + local pathResult; + local success = pcall(function() + pathResult = PathfindingService:ComputeSmoothPathAsync(otherStart, point, 400) + smoothed = true + end) + if not success then + pathResult = PathfindingService:ComputeRawPathAsync(otherStart, point, 400) + smoothed = false + end + if pathResult and pathResult.Status == Enum.PathStatus.Success then + this.pathResult = pathResult + if this.pathResult then + this.pointList = this.pathResult:GetPointCoordinates() + table.insert(this.pointList, 1, otherStart) + end + break + end + end + end + if DirectPathEnabled then + if this.pathResult.Status ~= Enum.PathStatus.Success then + local directPathResult = this:ComputeDirectPath() + if directPathResult and directPathResult.Status == Enum.PathStatus.Success then + this.pathResult = directPathResult + this.pointList = directPathResult:GetPointCoordinates() + end + end + end + end + return smoothed + end + + function this:IsValidPath() + this:ComputePath() + local pathStatus = this.pathResult.Status + return pathStatus == Enum.PathStatus.Success + end + + function this:GetPathStatus() + this:ComputePath() + return this.pathResult.Status + end + + function this:Start() + if CurrentSeatPart then + return + end + spawn(function() + local humanoid = findPlayerHumanoid(Player) + --humanoid.AutoRotate = false + local torso = humanoid and humanoid.Torso + if torso then + if this.Started then return end + this.Started = true + -- Will yield the script since it is an Async function script (start, finish, maxDistance) + local smoothed = this:ComputePath() + if this:IsValidPath() then + this.PathStarted:fire() + -- smooth out zig-zaggy paths + local smoothPath = smoothed and this.pointList or this:SmoothPoints(this.pointList) + for i, point in pairs(smoothPath) do + if humanoid then + if this.Cancelled then + return + end + + local wayPoint = nil + if SHOW_PATH then + wayPoint = CreateDestinationIndicator(point) + wayPoint.BrickColor = BrickColor.new("New Yeller") + wayPoint.Parent = workspace + print(wayPoint.CFrame.p) + end + + humanoid:MoveTo(point) + + local distance = ((torso.CFrame.p - point) * Vector3.new(1,0,1)).magnitude + local approxTime = 10 + if math.abs(humanoid.WalkSpeed) > 0 then + approxTime = distance / math.abs(humanoid.WalkSpeed) + end + + local yielding = true + + if i == 1 then + --local rotatedCFrame = CameraModule:LookAtPreserveHeight(point) + if CameraModule then + local rotatedCFrame = CameraModule:LookAtPreserveHeight(smoothPath[#smoothPath]) + local finishedSignal, duration = CameraModule:TweenCameraLook(rotatedCFrame) + end + --CharacterControl:SetTorsoLookPoint(point) + end + ---[[ + if (humanoid.Torso.CFrame.p - point).magnitude > 9 then + spawn(function() + while yielding and this.Cancelled == false do + if CameraModule then + local look = CameraModule:GetCameraLook() + local squashedLook = (look * Vector3.new(1,0,1)).unit + local direction = ((point - CameraModule.cframe.p) * Vector3.new(1,0,1)).unit + + local theta = math.deg(math.acos(squashedLook:Dot(direction))) + + if tick() - Utility.GetLastInput() > 2 and theta > (workspace.CurrentCamera.FieldOfView / 2) then + local rotatedCFrame = CameraModule:LookAtPreserveHeight(point) + local finishedSignal, duration = CameraModule:TweenCameraLook(rotatedCFrame) + --return + end + end + wait(0.1) + end + end) + end + --]] + local didReach = this:YieldUntilPointReached(character, point, approxTime * 3 + 1) + + yielding = false + + if SHOW_PATH then + wayPoint:Destroy() + end + + if not didReach then + this.PathFailed:fire() + return + end + end + end + + this.Finished:fire() + return + end + end + this.PathFailed:fire() + end) + end + + return this +end + +------------------------------------------------------------------------- + +local function FlashRed(object) + local origColor = object.BrickColor + local redColor = BrickColor.new("Really red") + local start = tick() + local duration = 4 + spawn(function() + while object and tick() - start < duration do + object.BrickColor = origColor + wait(0.13) + if object then + object.BrickColor = redColor + end + wait(0.13) + end + end) +end + +--local joystickWidth = 250 +--local joystickHeight = 250 +local function IsInBottomLeft(pt) + local joystickHeight = math.min(Utility.ViewSizeY() * 0.33, 250) + local joystickWidth = joystickHeight + return pt.X <= joystickWidth and pt.Y > Utility.ViewSizeY() - joystickHeight +end + +local function IsInBottomRight(pt) + local joystickHeight = math.min(Utility.ViewSizeY() * 0.33, 250) + local joystickWidth = joystickHeight + return pt.X >= Utility.ViewSizeX() - joystickWidth and pt.Y > Utility.ViewSizeY() - joystickHeight +end + +local function CheckAlive(character) + local humanoid = findPlayerHumanoid(Player) + return humanoid ~= nil and humanoid.Health > 0 +end + +local function GetEquippedTool(character) + if character ~= nil then + for _, child in pairs(character:GetChildren()) do + if child:IsA('Tool') then + return child + end + end + end +end + +local function ExploreWithRayCast(currentPoint, originDirection) + local TestDistance = 40 + local TestVectors = {} + do + local forwardVector = originDirection; + for i = 0, 15 do + table.insert(TestVectors, CFrame.Angles(0, math.pi / 8 * i, 0) * forwardVector) + end + end + + local testResults = {} + -- Heuristic should be something along the lines of distance and closeness to the traveling direction + local function ExploreHeuristic() + for _, testData in pairs(testResults) do + local walkDirection = -1 * originDirection + local directionCoeff = (walkDirection:Dot(testData['Vector']) + 1) / 2 + local distanceCoeff = testData['Distance'] / TestDistance + testData["Value"] = directionCoeff * distanceCoeff + end + end + + for i, vec in pairs(TestVectors) do + local hitPart, hitPos = Utility.Raycast(Ray.new(currentPoint, vec * TestDistance), true, {Player.Character}) + if hitPos then + table.insert(testResults, {Vector = vec; Distance = (hitPos - currentPoint).magnitude}) + else + table.insert(testResults, {Vector = vec; Distance = TestDistance}) + end + end + + ExploreHeuristic() + + table.sort(testResults, function(a,b) return a["Value"] > b["Value"] end) + + return testResults +end + +local TapId = 1 +local ExistingPather = nil +local ExistingIndicator = nil +local PathCompleteListener = nil +local PathFailedListener = nil + +local function CleanupPath() + DrivingTo = nil + if ExistingPather then + ExistingPather:Cancel() + end + if PathCompleteListener then + PathCompleteListener:disconnect() + PathCompleteListener = nil + end + if PathFailedListener then + PathFailedListener:disconnect() + PathFailedListener = nil + end + if ExistingIndicator then + DebrisService:AddItem(ExistingIndicator, 0) + ExistingIndicator = nil + end +end + +local function getExtentsSize(Parts) + local maxX = Parts[1].Position.X + local maxY = Parts[1].Position.Y + local maxZ = Parts[1].Position.Z + local minX = Parts[1].Position.X + local minY = Parts[1].Position.Y + local minZ = Parts[1].Position.Z + for i = 2, #Parts do + maxX = math.max(maxX, Parts[i].Position.X) + maxY = math.max(maxY, Parts[i].Position.Y) + maxZ = math.max(maxZ, Parts[i].Position.Z) + minX = math.min(minX, Parts[i].Position.X) + minY = math.min(minY, Parts[i].Position.Y) + minZ = math.min(minZ, Parts[i].Position.Z) + end + return Region3.new(Vector3.new(minX, minY, minZ), Vector3.new(maxX, maxY, maxZ)) +end + +local function inExtents(Extents, Position) + if Position.X < (Extents.CFrame.p.X - Extents.Size.X/2) or Position.X > (Extents.CFrame.p.X + Extents.Size.X/2) then + return false + end + if Position.Z < (Extents.CFrame.p.Z - Extents.Size.Z/2) or Position.Z > (Extents.CFrame.p.Z + Extents.Size.Z/2) then + return false + end + --ignoring Y for now + return true +end + +local AutoJumperInstance = nil +local ShootCount = 0 +local FailCount = 0 +local function OnTap(tapPositions, goToPoint) + -- Good to remember if this is the latest tap event + TapId = TapId + 1 + local thisTapId = TapId + + + local camera = workspace.CurrentCamera + local character = Player.Character + + + if not CheckAlive(character) then return end + + -- This is a path tap position + if #tapPositions == 1 or goToPoint then + if camera then + local unitRay = Utility.GetUnitRay(tapPositions[1].x, tapPositions[1].y, MyMouse.ViewSizeX, MyMouse.ViewSizeY, camera) + local ray = Ray.new(unitRay.Origin, unitRay.Direction*400) + local hitPart, hitPt = Utility.Raycast(ray, true, {character}) + + local hitChar, hitHumanoid = Utility.FindChacterAncestor(hitPart) + local torso = character and character:FindFirstChild("Humanoid") and character:FindFirstChild("Humanoid").Torso + local startPos = torso.CFrame.p + if goToPoint then + hitPt = goToPoint + hitChar = nil + end + if hitChar and hitHumanoid and hitHumanoid.Torso and (hitHumanoid.Torso.CFrame.p - torso.CFrame.p).magnitude < 7 then + CleanupPath() + + local myHumanoid = findPlayerHumanoid(Player) + if myHumanoid then + myHumanoid:MoveTo(hitPt) + end + + ShootCount = ShootCount + 1 + local thisShoot = ShootCount + -- Do shooot + local currentWeapon = GetEquippedTool(character) + if currentWeapon then + currentWeapon:Activate() + LastFired = tick() + end + elseif hitPt and character and not CurrentSeatPart then + local thisPather = Pather(character, hitPt) + if thisPather:IsValidPath() then + FailCount = 0 + -- TODO: Remove when bug in engine is fixed + Player:Move(Vector3.new(1, 0, 0)) + Player:Move(Vector3.new(0, 0, 0)) + thisPather:Start() + if BindableEvent_OnFailStateChanged then + BindableEvent_OnFailStateChanged:Fire(false) + end + CleanupPath() + + local destinationGlobe = CreateDestinationIndicator(hitPt) + destinationGlobe.Parent = camera + + ExistingPather = thisPather + ExistingIndicator = destinationGlobe + + if AutoJumperInstance then + AutoJumperInstance:Run() + end + + PathCompleteListener = thisPather.Finished:connect(function() + if AutoJumperInstance then + AutoJumperInstance:Stop() + end + if destinationGlobe then + if ExistingIndicator == destinationGlobe then + ExistingIndicator = nil + end + DebrisService:AddItem(destinationGlobe, 0) + destinationGlobe = nil + end + if hitChar then + local humanoid = findPlayerHumanoid(Player) + ShootCount = ShootCount + 1 + local thisShoot = ShootCount + -- Do shoot + local currentWeapon = GetEquippedTool(character) + if currentWeapon then + currentWeapon:Activate() + LastFired = tick() + end + if humanoid then + humanoid:MoveTo(hitPt) + end + end + local finishPos = torso and torso.CFrame.p --hitPt + if finishPos and startPos and tick() - Utility.GetLastInput() > 2 then + local exploreResults = ExploreWithRayCast(finishPos, ((startPos - finishPos) * Vector3.new(1,0,1)).unit) + -- Check for Nans etc.. + if exploreResults[1] and exploreResults[1]["Vector"] and exploreResults[1]["Vector"].magnitude >= 0.5 and exploreResults[1]["Distance"] > 3 then + if CameraModule then + local rotatedCFrame = CameraModule:LookAtPreserveHeight(finishPos + exploreResults[1]["Vector"] * exploreResults[1]["Distance"]) + local finishedSignal, duration = CameraModule:TweenCameraLook(rotatedCFrame) + end + end + end + end) + PathFailedListener = thisPather.PathFailed:connect(function() + if AutoJumperInstance then + AutoJumperInstance:Stop() + end + if destinationGlobe then + FlashRed(destinationGlobe) + DebrisService:AddItem(destinationGlobe, 3) + end + end) + else + if hitPt then + -- Feedback here for when we don't have a good path + local failedGlobe = CreateDestinationIndicator(hitPt) + FlashRed(failedGlobe) + DebrisService:AddItem(failedGlobe, 1) + failedGlobe.Parent = camera + if ExistingIndicator == nil then + FailCount = FailCount + 1 + if FailCount >= 3 then + if BindableEvent_OnFailStateChanged then + BindableEvent_OnFailStateChanged:Fire(true) + end + CleanupPath() + end + end + end + end + elseif hitPt and character and CurrentSeatPart then + local destinationGlobe = CreateDestinationIndicator(hitPt) + destinationGlobe.Parent = camera + ExistingIndicator = destinationGlobe + DrivingTo = hitPt + local ConnectedParts = CurrentSeatPart:GetConnectedParts(true) + + while wait() do + if CurrentSeatPart and ExistingIndicator == destinationGlobe then + local ExtentsSize = getExtentsSize(ConnectedParts) + if inExtents(ExtentsSize, destinationGlobe.Position) then + DebrisService:AddItem(destinationGlobe, 0) + destinationGlobe = nil + DrivingTo = nil + break + end + else + DebrisService:AddItem(destinationGlobe, 0) + if CurrentSeatPart == nil and destinationGlobe == ExistingIndicator then + DrivingTo = nil + OnTap(tapPositions, hitPt) + end + destinationGlobe = nil + break + end + end + + else + -- no hit pt + end + end + elseif #tapPositions >= 2 then + if camera then + ShootCount = ShootCount + 1 + local thisShoot = ShootCount + -- Do shoot + local avgPoint = Utility.AveragePoints(tapPositions) + local unitRay = Utility.GetUnitRay(avgPoint.x, avgPoint.y, MyMouse.ViewSizeX, MyMouse.ViewSizeY, camera) + local currentWeapon = GetEquippedTool(character) + if currentWeapon then + currentWeapon:Activate() + LastFired = tick() + end + end + end +end + + +local function CreateClickToMoveModule() + local this = {} + + local LastStateChange = 0 + local LastState = Enum.HumanoidStateType.Running + local FingerTouches = {} + local NumUnsunkTouches = 0 + -- PC simulation + local mouse1Down = tick() + local mouse1DownPos = Vector2.new() + local mouse2Down = tick() + local mouse2DownPos = Vector2.new() + local mouse2Up = tick() + + local movementKeys = { + [Enum.KeyCode.W] = true; + [Enum.KeyCode.A] = true; + [Enum.KeyCode.S] = true; + [Enum.KeyCode.D] = true; + [Enum.KeyCode.Up] = true; + [Enum.KeyCode.Down] = true; + } + + local TapConn = nil + local InputBeganConn = nil + local InputChangedConn = nil + local InputEndedConn = nil + local HumanoidDiedConn = nil + local CharacterChildAddedConn = nil + local OnCharacterAddedConn = nil + local CharacterChildRemovedConn = nil + local RenderSteppedConn = nil + local HumanoidSeatedConn = nil + + local function disconnectEvent(event) + if event then + event:disconnect() + end + end + + local function DisconnectEvents() + disconnectEvent(TapConn) + disconnectEvent(InputBeganConn) + disconnectEvent(InputChangedConn) + disconnectEvent(InputEndedConn) + disconnectEvent(HumanoidDiedConn) + disconnectEvent(CharacterChildAddedConn) + disconnectEvent(OnCharacterAddedConn) + disconnectEvent(RenderSteppedConn) + disconnectEvent(CharacterChildRemovedConn) + pcall(function() RunService:UnbindFromRenderStep("ClickToMoveRenderUpdate") end) + disconnectEvent(HumanoidSeatedConn) + end + + + + local function IsFinite(num) + return num == num and num ~= 1/0 and num ~= -1/0 + end + + local function findAngleBetweenXZVectors(vec2, vec1) + return math.atan2(vec1.X*vec2.Z-vec1.Z*vec2.X, vec1.X*vec2.X + vec1.Z*vec2.Z) + end + + -- Setup the camera + CameraModule = ClassicCameraModule() + + do + -- Extend The Camera Module Class + function CameraModule:LookAtPreserveHeight(newLookAtPt) + local camera = workspace.CurrentCamera + + local focus = camera.Focus.p + + local cameraCFrame = CameraModule.cframe + local mag = Vector3.new(cameraCFrame.lookVector.x, 0, cameraCFrame.lookVector.z).magnitude + local newLook = (Vector3.new(newLookAtPt.x, focus.y, newLookAtPt.z) - focus).unit * mag + local flippedLook = newLook + Vector3.new(0, cameraCFrame.lookVector.y, 0) + + local distance = (focus - cameraCFrame.p).magnitude + + local newCamPos = focus - flippedLook.unit * distance + return CFrame.new(newCamPos, newCamPos + flippedLook) + end + + function CameraModule:TweenCameraLook(desiredCFrame, speed) + local e = 2.718281828459 + local function SCurve(t) + return 1/(1 + e^(-t*1.5)) + end + local function easeOutSine(t, b, c, d) + if t >= d then return b + c end + return c * math.sin(t/d * (math.pi/2)) + b; + end + + local theta, interper = CFrameInterpolator(CFrame.new(Vector3.new(), self:GetCameraLook()), desiredCFrame - desiredCFrame.p) + theta = Utility.Clamp(0, math.pi, theta) + local duration = 0.65 * SCurve(theta - math.pi/4) + 0.15 + if speed then + duration = theta / speed + end + local start = tick() + local finish = start + duration + + self.UpdateTweenFunction = function() + local currTime = tick() - start + local alpha = Utility.Clamp(0, 1, easeOutSine(currTime, 0, 1, duration)) + local newCFrame = interper(alpha) + local y = findAngleBetweenXZVectors(newCFrame.lookVector, self:GetCameraLook()) + if IsFinite(y) and math.abs(y) > 0.0001 then + self.RotateInput = self.RotateInput + Vector2.new(y, 0) + end + return (currTime >= finish or alpha >= 1) + end + end + end + --- Done Extending + + + local function OnTouchBegan(input, processed) + if FingerTouches[input] == nil and not processed then + NumUnsunkTouches = NumUnsunkTouches + 1 + end + FingerTouches[input] = processed + end + + local function OnTouchChanged(input, processed) + if FingerTouches[input] == nil then + FingerTouches[input] = processed + if not processed then + NumUnsunkTouches = NumUnsunkTouches + 1 + end + end + end + + local function OnTouchEnded(input, processed) + --print("Touch tap fake:" , processed) + --if not processed then + -- OnTap({input.Position}) + --end + if FingerTouches[input] ~= nil and FingerTouches[input] == false then + NumUnsunkTouches = NumUnsunkTouches - 1 + end + FingerTouches[input] = nil + end + + + local function OnCharacterAdded(character) + DisconnectEvents() + + InputBeganConn = UIS.InputBegan:connect(function(input, processed) + if input.UserInputType == Enum.UserInputType.Touch then + OnTouchBegan(input, processed) + + + -- Give back controls when they tap both sticks + local wasInBottomLeft = IsInBottomLeft(input.Position) + local wasInBottomRight = IsInBottomRight(input.Position) + if wasInBottomRight or wasInBottomLeft then + for otherInput, _ in pairs(FingerTouches) do + if otherInput ~= input then + local otherInputInLeft = IsInBottomLeft(otherInput.Position) + local otherInputInRight = IsInBottomRight(otherInput.Position) + if otherInput.UserInputState ~= Enum.UserInputState.End and ((wasInBottomLeft and otherInputInRight) or (wasInBottomRight and otherInputInLeft)) then + if BindableEvent_OnFailStateChanged then + BindableEvent_OnFailStateChanged:Fire(true) + end + return + end + end + end + end + end + + -- Cancel path when you use the keyboard controls. + if processed == false and input.UserInputType == Enum.UserInputType.Keyboard and movementKeys[input.KeyCode] then + CleanupPath() + end + if input.UserInputType == Enum.UserInputType.MouseButton1 then + mouse1Down = tick() + mouse1DownPos = input.Position + end + if input.UserInputType == Enum.UserInputType.MouseButton2 then + mouse2Down = tick() + mouse2DownPos = input.Position + end + end) + + InputChangedConn = UIS.InputChanged:connect(function(input, processed) + if input.UserInputType == Enum.UserInputType.Touch then + OnTouchChanged(input, processed) + end + end) + + InputEndedConn = UIS.InputEnded:connect(function(input, processed) + if input.UserInputType == Enum.UserInputType.Touch then + OnTouchEnded(input, processed) + end + + if input.UserInputType == Enum.UserInputType.MouseButton2 then + mouse2Up = tick() + local currPos = input.Position + if mouse2Up - mouse2Down < 0.25 and (currPos - mouse2DownPos).magnitude < 5 then + local positions = {currPos} + OnTap(positions) + end + end + end) + + TapConn = UIS.TouchTap:connect(function(touchPositions, processed) + if not processed then + OnTap(touchPositions) + end + end) + + if not UIS.TouchEnabled then -- PC + if AutoJumperInstance then + AutoJumperInstance:Stop() + AutoJumperInstance = nil + end + AutoJumperInstance = AutoJumper() + end + + local function getThrottleAndSteer(object, point) + local lookVector = (point - object.Position) + lookVector = Vector3.new(lookVector.X, 0, lookVector.Z).unit + local objectVector = Vector3.new(object.CFrame.lookVector.X, 0, object.CFrame.lookVector.Z).unit + local dirVector = lookVector - objectVector + local mag = dirVector.magnitude + local degrees = math.deg(math.acos(lookVector:Dot(objectVector))) + local side = (object.CFrame:pointToObjectSpace(point).X > 0) + local throttle = 0 + if mag < 0.25 then + throttle = 1 + end + if mag > 1.8 then + throttle = -1 + end + local distance = CurrentSeatPart.Position - DrivingTo + local velocity = CurrentSeatPart.Velocity + if velocity.magnitude*1.5 > distance.magnitude then + if velocity.magnitude*0.5 > distance.magnitude then + throttle = -throttle + else + throttle = 0 + end + end + local steer = 0 + if degrees > 5 and degrees < 175 then + if side then + steer = 1 + else + steer = -1 + end + end + local rotatingAt = math.deg(CurrentSeatPart.RotVelocity.magnitude) + local degreesAway = math.max(math.min(degrees, 180 - degrees), 10) + if (CurrentSeatPart.RotVelocity.X < 0)== (steer < 0) then + if rotatingAt*1.5 > degreesAway then + if rotatingAt*0.5 > degreesAway then + steer = -steer + else + steer = 0 + end + end + end + return throttle, steer + end + + local function Update() + if CameraModule then + if CameraModule.UserPanningTheCamera then + CameraModule.UpdateTweenFunction = nil + else + if CameraModule.UpdateTweenFunction then + local done = CameraModule.UpdateTweenFunction() + if done then + CameraModule.UpdateTweenFunction = nil + end + end + end + CameraModule:Update() + end + if CurrentSeatPart then + if DrivingTo then + local throttle, steer = getThrottleAndSteer(CurrentSeatPart, DrivingTo) + CurrentSeatPart.Throttle = throttle + CurrentSeatPart.Steer = steer + end + end + end + + local success = pcall(function() RunService:BindToRenderStep("ClickToMoveRenderUpdate",Enum.RenderPriority.Camera.Value - 1,Update) end) + if not success then + if RenderSteppedConn then + RenderSteppedConn:disconnect() + end + RenderSteppedConn = RunService.RenderStepped:connect(Update) + end + + local WasAutoJumper = false + local WasAutoJumpMobile = false + local function onSeated(child, active, currentSeatPart) + if active then + if BindableEvent_EnableTouchJump then + BindableEvent_EnableTouchJump:Fire(true) + end + if currentSeatPart.ClassName == "VehicleSeat" then + CurrentSeatPart = currentSeatPart + if AutoJumperInstance then + AutoJumperInstance:Stop() + AutoJumperInstance = nil + WasAutoJumper = true + else + WasAutoJumper = false + end + if child.AutoJumpEnabled then + WasAutoJumpMobile = true + child.AutoJumpEnabled = false + end + end + else + CurrentSeatPart = nil + if BindableEvent_EnableTouchJump then + BindableEvent_EnableTouchJump:Fire(false) + end + if WasAutoJumper then + AutoJumperInstance = AutoJumper() + WasAutoJumper = false + end + if WasAutoJumpMobile then + child.AutoJumpEnabled = true + WasAutoJumpMobile = false + end + end + end + + local function OnCharacterChildAdded(child) + if UIS.TouchEnabled then + if child:IsA('Tool') then + child.ManualActivationOnly = true + end + end + if child:IsA('Humanoid') then + disconnectEvent(HumanoidDiedConn) + HumanoidDiedConn = child.Died:connect(function() + DebrisService:AddItem(ExistingIndicator, 1) + if AutoJumperInstance then + AutoJumperInstance:Stop() + AutoJumperInstance = nil + end + end) + local WasAutoJumper = false + local WasAutoJumpMobile = false + HumanoidSeatedConn = child.Seated:connect(function(active, seat) onSeated(child, active, seat) end) + if child.SeatPart then + onSeated(child, true, child.SeatPart) + end + end + end + + CharacterChildAddedConn = character.ChildAdded:connect(function(child) + OnCharacterChildAdded(child) + end) + CharacterChildRemovedConn = character.ChildRemoved:connect(function(child) + if UIS.TouchEnabled then + if child:IsA('Tool') then + child.ManualActivationOnly = false + end + end + end) + for _, child in pairs(character:GetChildren()) do + OnCharacterChildAdded(child) + end + end + + local Running = false + + function this:Stop() + if Running then + DisconnectEvents() + CleanupPath() + if AutoJumperInstance then + AutoJumperInstance:Stop() + AutoJumperInstance = nil + end + if CameraModule then + CameraModule.UpdateTweenFunction = nil + CameraModule:SetEnabled(false) + end + -- Restore tool activation on shutdown + if UIS.TouchEnabled then + local character = Player.Character + if character then + for _, child in pairs(character:GetChildren()) do + if child:IsA('Tool') then + child.ManualActivationOnly = false + end + end + end + end + DrivingTo = nil + Running = false + end + end + + function this:Start() + if not Running then + if Player.Character then -- retro-listen + OnCharacterAdded(Player.Character) + end + OnCharacterAddedConn = Player.CharacterAdded:connect(OnCharacterAdded) + if CameraModule then + CameraModule:SetEnabled(true) + end + Running = true + end + end + + return this +end + +return CreateClickToMoveModule +]]> + + + + + Invisicam + originalFade then + hit.LocalTransparencyModifier = math.max(originalFade, currentFade - FADE_RATE) + else + SavedHits[hit] = nil + end + end + end +end + +function Invisicam:SetMode(newMode) + AssertTypes(newMode, 'number') + for modeName, modeNum in pairs(MODE) do + if modeNum == newMode then + Mode = newMode + return + end + end + error("Invalid mode number") +end + +function Invisicam:SetCustomBehavior(func) + AssertTypes(func, 'function') + Behaviors[MODE.CUSTOM] = func +end + +-- Want to turn off Invisicam? Be sure to call this after. +function Invisicam:Cleanup() + for hit, originalFade in pairs(SavedHits) do + hit.LocalTransparencyModifier = originalFade + end +end + +--------------------- +--| Running Logic |-- +--------------------- + +-- Connect to the current and all future cameras +workspace.Changed:connect(OnWorkspaceChanged) +OnWorkspaceChanged('CurrentCamera') + +Player.CharacterAdded:connect(OnCharacterAdded) +if Player.Character then + OnCharacterAdded(Player.Character) +end + +Invisicam:SetMode(STARTING_MODE) + +Behaviors[MODE.CUSTOM] = function() end -- (Does nothing until SetCustomBehavior) +Behaviors[MODE.LIMBS] = LimbBehavior +Behaviors[MODE.MOVEMENT] = MoveBehavior +Behaviors[MODE.CORNERS] = CornerBehavior +Behaviors[MODE.CIRCLE1] = CircleBehavior +Behaviors[MODE.CIRCLE2] = CircleBehavior +Behaviors[MODE.LIMBMOVE] = LimbMoveBehavior + +return Invisicam +]]> + + + + + + PopperCam + 0.95 or hitPart.CanCollide == false) then + table.insert(ignoreList, hitPart) + else + return hitPart, hitPoint + end + until false +end + +local function ScreenToWorld(screenPoint, screenSize, pushDepth) + local cameraFOV, cameraCFrame = Camera.FieldOfView, Camera.CoordinateFrame + local imagePlaneDepth = screenSize.y / (2 * math.tan(math.rad(cameraFOV) / 2)) + local direction = Vector3.new(screenPoint.x - (screenSize.x / 2), (screenSize.y / 2) - screenPoint.y, -imagePlaneDepth) + local worldDirection = (cameraCFrame:vectorToWorldSpace(direction)).Unit + local theta = math.acos(math.min(1, worldDirection:Dot(cameraCFrame.lookVector))) + local fixedPushDepth = pushDepth / math.sin((math.pi / 2) - theta) + return cameraCFrame.p + worldDirection * fixedPushDepth +end + +local function OnCameraChanged(property) + if property == 'CameraSubject' then + VehicleParts = {} + + local newSubject = Camera.CameraSubject + if newSubject then + -- Determine if we should be popping at all + PopperEnabled = false + for _, subjectType in pairs(VALID_SUBJECTS) do + if newSubject:IsA(subjectType) then + PopperEnabled = true + break + end + end + + -- Get all parts of the vehicle the player is controlling + if newSubject:IsA('VehicleSeat') then + VehicleParts = newSubject:GetConnectedParts(true) + end + end + end +end + +local function OnCharacterAdded(player, character) + PlayerCharacters[player] = character +end + +local function OnPlayersChildAdded(child) + if child:IsA('Player') then + child.CharacterAdded:connect(function(character) + OnCharacterAdded(child, character) + end) + if child.Character then + OnCharacterAdded(child, child.Character) + end + end +end + +local function OnPlayersChildRemoved(child) + if child:IsA('Player') then + PlayerCharacters[child] = nil + end +end + +local function OnWorkspaceChanged(property) + if property == 'CurrentCamera' then + local newCamera = workspace.CurrentCamera + if newCamera then + Camera = newCamera + + if CameraChangeConn then + CameraChangeConn:disconnect() + end + CameraChangeConn = Camera.Changed:connect(OnCameraChanged) + OnCameraChanged('CameraSubject') + end + end +end + +------------------------- +--| Exposed Functions |-- +------------------------- + +function PopperCam:Update() + if PopperEnabled then + -- First, prep some intermediate vars + local focusPoint = Camera.Focus.p + local cameraCFrame = Camera.CoordinateFrame + local cameraFrontPoint = cameraCFrame.p + (cameraCFrame.lookVector * NEAR_CLIP_PLANE_OFFSET) + local screenSize = Camera.ViewportSize + local ignoreList = {} + for _, character in pairs(PlayerCharacters) do + table.insert(ignoreList, character) + end + for _, basePart in pairs(VehicleParts) do + table.insert(ignoreList, basePart) + end + + -- Cast rays at the near clip plane, from corresponding points near the focus point, + -- and find the direct line that is the most cut off + local largest = 0 + for _, screenScale in pairs(CAST_SCREEN_SCALES) do + local clipWorldPoint = ScreenToWorld(screenSize * screenScale, screenSize, NEAR_CLIP_PLANE_OFFSET) + local rayStartPoint = focusPoint + (clipWorldPoint - cameraFrontPoint) + local _, hitPoint = PiercingCast(rayStartPoint, clipWorldPoint, ignoreList) + local cutoffAmount = (hitPoint - clipWorldPoint).Magnitude + if cutoffAmount > largest then + largest = cutoffAmount + end + end + + -- Then check if the player zoomed since the last frame, + -- and if so, reset our pop history so we stop tweening + local zoomLevel = (cameraCFrame.p - focusPoint).Magnitude + if math.abs(zoomLevel - LastZoomLevel) > 0.001 then + LastPopAmount = 0 + end + + -- Finally, zoom the camera in (pop) by that most-cut-off amount, or the last pop amount if that's more + local popAmount = math.max(largest, LastPopAmount) + if popAmount > 0 then + Camera.CoordinateFrame = cameraCFrame + (cameraCFrame.lookVector * popAmount) + LastPopAmount = math.max(0, popAmount - POP_RESTORE_RATE) -- Shrink it for the next frame + end + + LastZoomLevel = zoomLevel + end +end + +-------------------- +--| Script Logic |-- +-------------------- + +-- Connect to the current and all future cameras +workspace.Changed:connect(OnWorkspaceChanged) +OnWorkspaceChanged('CurrentCamera') + +-- Connect to all Players so we can ignore their Characters +PlayersService.ChildRemoved:connect(OnPlayersChildRemoved) +PlayersService.ChildAdded:connect(OnPlayersChildAdded) +for _, player in pairs(PlayersService:GetPlayers()) do + OnPlayersChildAdded(player) +end + +return PopperCam +]]> + + + + + + RootCamera + = self:GetRepeatDelayValue(vrRotationIntensity) + + if math.abs(vrGamepadRotation.x) >= self:GetActivateValue() then + if (delayExpired or not vrRotateKeyCooldown[Enum.KeyCode.Thumbstick2]) then + local sign = 1 + if vrGamepadRotation.x < 0 then + sign = -1 + end + vrRotateSum = vrRotateSum + self:GetRotateAmountValue(vrRotationIntensity) * sign + vrRotateKeyCooldown[Enum.KeyCode.Thumbstick2] = true + end + elseif math.abs(vrGamepadRotation.x) < self:GetActivateValue() - 0.1 then + vrRotateKeyCooldown[Enum.KeyCode.Thumbstick2] = nil + end + if self.TurningLeft then + if delayExpired or not vrRotateKeyCooldown[Enum.KeyCode.Left] then + vrRotateSum = vrRotateSum - self:GetRotateAmountValue(vrRotationIntensity) + vrRotateKeyCooldown[Enum.KeyCode.Left] = true + end + else + vrRotateKeyCooldown[Enum.KeyCode.Left] = nil + end + if self.TurningRight then + if (delayExpired or not vrRotateKeyCooldown[Enum.KeyCode.Right]) then + vrRotateSum = vrRotateSum + self:GetRotateAmountValue(vrRotationIntensity) + vrRotateKeyCooldown[Enum.KeyCode.Right] = true + end + else + vrRotateKeyCooldown[Enum.KeyCode.Right] = nil + end + + if vrRotateSum ~= ZERO_VECTOR2 then + lastVRRotation = tick() + end + + return vrRotateSum + end + + local cameraTranslationConstraints = Vector3.new(1,1,1) + local humanoidJumpOrigin = nil + local trackingHumanoid = nil + local cameraFrozen = false + local subjectStateChangedConn = nil + local cameraChangedConn = nil + local workspaceChangedConn = nil + local humanoidChildAddedConn = nil + local humanoidChildRemovedConn = nil + + local function cancelCameraFreeze(keepConstraints) + if not keepConstraints then + cameraTranslationConstraints = Vector3.new(cameraTranslationConstraints.x, 1, cameraTranslationConstraints.z) + end + if cameraFrozen then + trackingHumanoid = nil + cameraFrozen = false + end + end + + local function startCameraFreeze(subjectPosition, humanoidToTrack) + if not cameraFrozen then + humanoidJumpOrigin = subjectPosition + trackingHumanoid = humanoidToTrack + cameraTranslationConstraints = Vector3.new(cameraTranslationConstraints.x, 0, cameraTranslationConstraints.z) + cameraFrozen = true + end + end + + local function rescaleCameraOffset(newScaleFactor) + R15HeadHeight = R15_HEAD_OFFSET*newScaleFactor + end + + local function onHumanoidSubjectChildAdded(child) + if child.Name == "BodyHeightScale" and child:IsA("NumberValue") then + if heightScaleChangedConn then + heightScaleChangedConn:disconnect() + end + heightScaleChangedConn = child.Changed:connect(rescaleCameraOffset) + rescaleCameraOffset(child.Value) + end + end + + local function onHumanoidSubjectChildRemoved(child) + if child.Name == "BodyHeightScale" then + rescaleCameraOffset(1) + if heightScaleChangedConn then + heightScaleChangedConn:disconnect() + heightScaleChangedConn = nil + end + end + end + + local function onNewCameraSubject() + if subjectStateChangedConn then + subjectStateChangedConn:disconnect() + subjectStateChangedConn = nil + end + if humanoidChildAddedConn then + humanoidChildAddedConn:disconnect() + humanoidChildAddedConn = nil + end + if humanoidChildRemovedConn then + humanoidChildRemovedConn:disconnect() + humanoidChildRemovedConn = nil + end + if heightScaleChangedConn then + heightScaleChangedConn:disconnect() + heightScaleChangedConn = nil + end + + local humanoid = workspace.CurrentCamera and workspace.CurrentCamera.CameraSubject + if trackingHumanoid ~= humanoid then + cancelCameraFreeze() + end + if humanoid and humanoid:IsA('Humanoid') then + humanoidChildAddedConn = humanoid.ChildAdded:connect(onHumanoidSubjectChildAdded) + humanoidChildRemovedConn = humanoid.ChildRemoved:connect(onHumanoidSubjectChildRemoved) + for _, child in pairs(humanoid:GetChildren()) do + onHumanoidSubjectChildAdded(child) + end + + subjectStateChangedConn = humanoid.StateChanged:connect(function(oldState, newState) + if newState == Enum.HumanoidStateType.Jumping and not this:IsInFirstPerson() and VRService.VREnabled then + startCameraFreeze(this:GetSubjectPosition(), humanoid) + elseif newState ~= Enum.HumanoidStateType.Jumping and newState ~= Enum.HumanoidStateType.Freefall then + cancelCameraFreeze(true) + end + end) + end + end + + local function onCameraChanged(prop) + if prop == 'CameraSubject' then + onNewCameraSubject() + end + end + + local function onCurrentCameraChanged() + if cameraChangedConn then + cameraChangedConn:disconnect() + cameraChangedConn = nil + end + local camera = workspace.CurrentCamera + if camera then + camera.Changed:connect(onCameraChanged) + onCameraChanged('CameraSubject') + end + end + + function this:GetVRFocus(subjectPosition, timeDelta) + local newFocus = nil + + local camera = workspace.CurrentCamera + local lastFocus = self.LastCameraFocus or subjectPosition + if not cameraFrozen then + cameraTranslationConstraints = Vector3.new(cameraTranslationConstraints.x, math.min(1, cameraTranslationConstraints.y + 0.42 * timeDelta), cameraTranslationConstraints.z) + end + if cameraFrozen and humanoidJumpOrigin and humanoidJumpOrigin.y > lastFocus.y then + newFocus = CFrame.new(Vector3.new(subjectPosition.x, math.min(humanoidJumpOrigin.y, lastFocus.y + 5 * timeDelta), subjectPosition.z)) + else + newFocus = CFrame.new(Vector3.new(subjectPosition.x, lastFocus.y, subjectPosition.z):lerp(subjectPosition, cameraTranslationConstraints.y)) + end + + if cameraFrozen then + -- No longer in 3rd person + if self:IsInFirstPerson() then -- not VRService.VREnabled + cancelCameraFreeze() + end + -- This case you jumped off a cliff and want to keep your character in view + -- 0.5 is to fix floating point error when not jumping off cliffs + if humanoidJumpOrigin and subjectPosition.y < (humanoidJumpOrigin.y - 0.5) then + cancelCameraFreeze() + end + end + + return newFocus + end + + ------------------------ + + ---- Input Events ---- + local startPos = nil + local lastPos = nil + local panBeginLook = nil + + local fingerTouches = {} + local NumUnsunkTouches = 0 + + local StartingDiff = nil + local pinchBeginZoom = nil + + this.ZoomEnabled = true + this.PanEnabled = true + this.KeyPanEnabled = true + + local function OnTouchBegan(input, processed) + fingerTouches[input] = processed + if not processed then + NumUnsunkTouches = NumUnsunkTouches + 1 + end + end + + local function OnTouchChanged(input, processed) + if fingerTouches[input] == nil then + fingerTouches[input] = processed + if not processed then + NumUnsunkTouches = NumUnsunkTouches + 1 + end + end + + if NumUnsunkTouches == 1 then + if fingerTouches[input] == false then + panBeginLook = panBeginLook or this:GetCameraLook() + startPos = startPos or input.Position + lastPos = lastPos or startPos + this.UserPanningTheCamera = true + + local delta = input.Position - lastPos + if this.PanEnabled then + local desiredXYVector = this:ScreenTranslationToAngle(delta) * TOUCH_SENSITIVTY + this.RotateInput = this.RotateInput + desiredXYVector + end + + lastPos = input.Position + end + else + panBeginLook = nil + startPos = nil + lastPos = nil + this.UserPanningTheCamera = false + end + if NumUnsunkTouches == 2 then + local unsunkTouches = {} + for touch, wasSunk in pairs(fingerTouches) do + if not wasSunk then + table.insert(unsunkTouches, touch) + end + end + if #unsunkTouches == 2 then + local difference = (unsunkTouches[1].Position - unsunkTouches[2].Position).magnitude + if StartingDiff and pinchBeginZoom then + local scale = difference / math.max(0.01, StartingDiff) + local clampedScale = clamp(0.1, 10, scale) + if this.ZoomEnabled then + this:ZoomCamera(pinchBeginZoom / clampedScale) + end + else + StartingDiff = difference + pinchBeginZoom = this:GetCameraActualZoom() + end + end + else + StartingDiff = nil + pinchBeginZoom = nil + end + end + + local function OnTouchEnded(input, processed) + if fingerTouches[input] == false then + if NumUnsunkTouches == 1 then + panBeginLook = nil + startPos = nil + lastPos = nil + this.UserPanningTheCamera = false + elseif NumUnsunkTouches == 2 then + StartingDiff = nil + pinchBeginZoom = nil + end + end + + if fingerTouches[input] ~= nil and fingerTouches[input] == false then + NumUnsunkTouches = NumUnsunkTouches - 1 + end + fingerTouches[input] = nil + end + + local function OnMousePanButtonPressed(input, processed) + if processed then return end + this:UpdateMouseBehavior() + panBeginLook = panBeginLook or this:GetCameraLook() + startPos = startPos or input.Position + lastPos = lastPos or startPos + this.UserPanningTheCamera = true + end + + local function OnMousePanButtonReleased(input, processed) + this:UpdateMouseBehavior() + if not (isRightMouseDown or isMiddleMouseDown) then + panBeginLook = nil + startPos = nil + lastPos = nil + this.UserPanningTheCamera = false + end + end + + local function OnMouse2Down(input, processed) + if processed then return end + + isRightMouseDown = true + OnMousePanButtonPressed(input, processed) + end + + local function OnMouse2Up(input, processed) + isRightMouseDown = false + OnMousePanButtonReleased(input, processed) + end + + local function OnMouse3Down(input, processed) + if processed then return end + + isMiddleMouseDown = true + OnMousePanButtonPressed(input, processed) + end + + local function OnMouse3Up(input, processed) + isMiddleMouseDown = false + OnMousePanButtonReleased(input, processed) + end + + local function OnMouseMoved(input, processed) + if not hasGameLoaded and VRService.VREnabled then + return + end + if startPos and lastPos and panBeginLook then + local currPos = lastPos + input.Delta + local totalTrans = currPos - startPos + if this.PanEnabled then + local desiredXYVector = this:MouseTranslationToAngle(input.Delta) * MOUSE_SENSITIVITY + this.RotateInput = this.RotateInput + desiredXYVector + end + lastPos = currPos + elseif this:IsInFirstPerson() or this:GetShiftLock() then + if this.PanEnabled then + local desiredXYVector = this:MouseTranslationToAngle(input.Delta) * MOUSE_SENSITIVITY + this.RotateInput = this.RotateInput + desiredXYVector + end + end + end + + local function OnMouseWheel(input, processed) + if not hasGameLoaded and VRService.VREnabled then + return + end + if not processed then + if this.ZoomEnabled then + if UserSettings():IsUserFeatureEnabled("UserBetterInertialScrolling") then + this:ZoomCameraBy(-input.Position.Z/15) + else + this:ZoomCameraBy(clamp(-1, 1, -input.Position.Z) * 1.4) + end + end + end + end + + local function round(num) + return math.floor(num + 0.5) + end + + local eight2Pi = math.pi / 4 + + local function rotateVectorByAngleAndRound(camLook, rotateAngle, roundAmount) + if camLook ~= Vector3.new(0,0,0) then + camLook = camLook.unit + local currAngle = math.atan2(camLook.z, camLook.x) + local newAngle = round((math.atan2(camLook.z, camLook.x) + rotateAngle) / roundAmount) * roundAmount + return newAngle - currAngle + end + return 0 + end + + local function OnKeyDown(input, processed) + if not hasGameLoaded and VRService.VREnabled then + return + end + if processed then return end + if this.ZoomEnabled then + if input.KeyCode == Enum.KeyCode.I then + this:ZoomCameraBy(-5) + elseif input.KeyCode == Enum.KeyCode.O then + this:ZoomCameraBy(5) + end + end + if panBeginLook == nil and this.KeyPanEnabled then + if input.KeyCode == Enum.KeyCode.Left then + this.TurningLeft = true + elseif input.KeyCode == Enum.KeyCode.Right then + this.TurningRight = true + elseif input.KeyCode == Enum.KeyCode.Comma then + local angle = rotateVectorByAngleAndRound(this:GetCameraLook() * Vector3.new(1,0,1), -eight2Pi * (3/4), eight2Pi) + if angle ~= 0 then + this.RotateInput = this.RotateInput + Vector2.new(angle, 0) + this.LastUserPanCamera = tick() + this.LastCameraTransform = nil + end + elseif input.KeyCode == Enum.KeyCode.Period then + local angle = rotateVectorByAngleAndRound(this:GetCameraLook() * Vector3.new(1,0,1), eight2Pi * (3/4), eight2Pi) + if angle ~= 0 then + this.RotateInput = this.RotateInput + Vector2.new(angle, 0) + this.LastUserPanCamera = tick() + this.LastCameraTransform = nil + end + elseif input.KeyCode == Enum.KeyCode.PageUp then + --elseif input.KeyCode == Enum.KeyCode.Home then + this.RotateInput = this.RotateInput + Vector2.new(0,math.rad(15)) + this.LastCameraTransform = nil + elseif input.KeyCode == Enum.KeyCode.PageDown then + --elseif input.KeyCode == Enum.KeyCode.End then + this.RotateInput = this.RotateInput + Vector2.new(0,math.rad(-15)) + this.LastCameraTransform = nil + end + end + end + + local function OnKeyUp(input, processed) + if input.KeyCode == Enum.KeyCode.Left then + this.TurningLeft = false + elseif input.KeyCode == Enum.KeyCode.Right then + this.TurningRight = false + end + end + + local lastThumbstickRotate = nil + local numOfSeconds = 0.7 + local currentSpeed = 0 + local maxSpeed = 6 + local vrMaxSpeed = 4 + local thumbstickSensitivity = 1.0 + local lastThumbstickPos = Vector2.new(0,0) + local ySensitivity = 0.65 + local lastVelocity = nil + + -- K is a tunable parameter that changes the shape of the S-curve + -- the larger K is the more straight/linear the curve gets + local k = 0.35 + local lowerK = 0.8 + local function SCurveTranform(t) + t = clamp(-1,1,t) + if t >= 0 then + return (k*t) / (k - t + 1) + end + return -((lowerK*-t) / (lowerK + t + 1)) + end + + -- DEADZONE + local DEADZONE = 0.1 + local function toSCurveSpace(t) + return (1 + DEADZONE) * (2*math.abs(t) - 1) - DEADZONE + end + + local function fromSCurveSpace(t) + return t/2 + 0.5 + end + + local function gamepadLinearToCurve(thumbstickPosition) + local function onAxis(axisValue) + local sign = 1 + if axisValue < 0 then + sign = -1 + end + local point = fromSCurveSpace(SCurveTranform(toSCurveSpace(math.abs(axisValue)))) + point = point * sign + return clamp(-1,1,point) + end + return Vector2.new(onAxis(thumbstickPosition.x), onAxis(thumbstickPosition.y)) + end + + function this:UpdateGamepad() + local gamepadPan = this.GamepadPanningCamera + if gamepadPan and (hasGameLoaded or not VRService.VREnabled) then + gamepadPan = gamepadLinearToCurve(gamepadPan) + local currentTime = tick() + if gamepadPan.X ~= 0 or gamepadPan.Y ~= 0 then + this.userPanningTheCamera = true + elseif gamepadPan == Vector2.new(0,0) then + lastThumbstickRotate = nil + if lastThumbstickPos == Vector2.new(0,0) then + currentSpeed = 0 + end + end + + local finalConstant = 0 + + if lastThumbstickRotate then + if VRService.VREnabled then + currentSpeed = vrMaxSpeed + else + local elapsedTime = (currentTime - lastThumbstickRotate) * 10 + currentSpeed = currentSpeed + (maxSpeed * ((elapsedTime*elapsedTime)/numOfSeconds)) + + if currentSpeed > maxSpeed then currentSpeed = maxSpeed end + + if lastVelocity then + local velocity = (gamepadPan - lastThumbstickPos)/(currentTime - lastThumbstickRotate) + local velocityDeltaMag = (velocity - lastVelocity).magnitude + + if velocityDeltaMag > 12 then + currentSpeed = currentSpeed * (20/velocityDeltaMag) + if currentSpeed > maxSpeed then currentSpeed = maxSpeed end + end + end + end + + finalConstant = thumbstickSensitivity * currentSpeed + lastVelocity = (gamepadPan - lastThumbstickPos)/(currentTime - lastThumbstickRotate) + end + + lastThumbstickPos = gamepadPan + lastThumbstickRotate = currentTime + + return Vector2.new( gamepadPan.X * finalConstant, gamepadPan.Y * finalConstant * ySensitivity) + end + + return Vector2.new(0,0) + end + + local InputBeganConn, InputChangedConn, InputEndedConn, MenuOpenedConn, ShiftLockToggleConn, GamepadConnectedConn, GamepadDisconnectedConn = nil, nil, nil, nil, nil, nil, nil + + function this:DisconnectInputEvents() + if InputBeganConn then + InputBeganConn:disconnect() + InputBeganConn = nil + end + if InputChangedConn then + InputChangedConn:disconnect() + InputChangedConn = nil + end + if InputEndedConn then + InputEndedConn:disconnect() + InputEndedConn = nil + end + if MenuOpenedConn then + MenuOpenedConn:disconnect() + MenuOpenedConn = nil + end + if ShiftLockToggleConn then + ShiftLockToggleConn:disconnect() + ShiftLockToggleConn = nil + end + if GamepadConnectedConn then + GamepadConnectedConn:disconnect() + GamepadConnectedConn = nil + end + if GamepadDisconnectedConn then + GamepadDisconnectedConn:disconnect() + GamepadDisconnectedConn = nil + end + if subjectStateChangedConn then + subjectStateChangedConn:disconnect() + subjectStateChangedConn = nil + end + if cameraChangedConn then + cameraChangedConn:disconnect() + cameraChangedConn = nil + end + if workspaceChangedConn then + workspaceChangedConn:disconnect() + workspaceChangedConn = nil + end + + this.TurningLeft = false + this.TurningRight = false + this.LastCameraTransform = nil + self.LastSubjectCFrame = nil + this.UserPanningTheCamera = false + this.RotateInput = Vector2.new() + this.GamepadPanningCamera = Vector2.new(0,0) + + -- Reset input states + startPos = nil + lastPos = nil + panBeginLook = nil + isRightMouseDown = false + isMiddleMouseDown = false + + fingerTouches = {} + NumUnsunkTouches = 0 + + StartingDiff = nil + pinchBeginZoom = nil + + -- Unlock mouse for example if right mouse button was being held down + if UserInputService.MouseBehavior ~= Enum.MouseBehavior.LockCenter then + UserInputService.MouseBehavior = Enum.MouseBehavior.Default + end + end + + function this:ResetInputStates() + isRightMouseDown = false + isMiddleMouseDown = false + OnMousePanButtonReleased() -- this function doesn't seem to actually need parameters + + if UserInputService.TouchEnabled then + --[[menu opening was causing serious touch issues + this should disable all active touch events if + they're active when menu opens.]] + for inputObject, value in pairs(fingerTouches) do + fingerTouches[inputObject] = nil + end + panBeginLook = nil + startPos = nil + lastPos = nil + this.UserPanningTheCamera = false + StartingDiff = nil + pinchBeginZoom = nil + NumUnsunkTouches = 0 + end + end + + function this:ConnectInputEvents() + InputBeganConn = UserInputService.InputBegan:connect(function(input, processed) + if input.UserInputType == Enum.UserInputType.Touch then + OnTouchBegan(input, processed) + elseif input.UserInputType == Enum.UserInputType.MouseButton2 then + OnMouse2Down(input, processed) + elseif input.UserInputType == Enum.UserInputType.MouseButton3 then + OnMouse3Down(input, processed) + end + -- Keyboard + if input.UserInputType == Enum.UserInputType.Keyboard then + OnKeyDown(input, processed) + end + end) + + InputChangedConn = UserInputService.InputChanged:connect(function(input, processed) + if input.UserInputType == Enum.UserInputType.Touch then + OnTouchChanged(input, processed) + elseif input.UserInputType == Enum.UserInputType.MouseMovement then + OnMouseMoved(input, processed) + elseif input.UserInputType == Enum.UserInputType.MouseWheel then + OnMouseWheel(input, processed) + end + end) + + InputEndedConn = UserInputService.InputEnded:connect(function(input, processed) + if input.UserInputType == Enum.UserInputType.Touch then + OnTouchEnded(input, processed) + elseif input.UserInputType == Enum.UserInputType.MouseButton2 then + OnMouse2Up(input, processed) + elseif input.UserInputType == Enum.UserInputType.MouseButton3 then + OnMouse3Up(input, processed) + end + -- Keyboard + if input.UserInputType == Enum.UserInputType.Keyboard then + OnKeyUp(input, processed) + end + end) + + MenuOpenedConn = GuiService.MenuOpened:connect(function() + this:ResetInputStates() + end) + + workspaceChangedConn = workspace.Changed:connect(function(prop) + if prop == "CurrentCamera" then + onCurrentCameraChanged() + end + end) + onCurrentCameraChanged() + + ShiftLockToggleConn = ShiftLockController.OnShiftLockToggled.Event:connect(function() + this:UpdateMouseBehavior() + end) + + this.RotateInput = Vector2.new() + + local activateGamepad = nil + local function assignActivateGamepad() + local connectedGamepads = UserInputService:GetConnectedGamepads() + if #connectedGamepads > 0 then + for i = 1, #connectedGamepads do + if activateGamepad == nil then + activateGamepad = connectedGamepads[i] + elseif connectedGamepads[i].Value < activateGamepad.Value then + activateGamepad = connectedGamepads[i] + end + end + end + + if activateGamepad == nil then -- nothing is connected, at least set up for gamepad1 + activateGamepad = Enum.UserInputType.Gamepad1 + end + end + + GamepadConnectedConn = UserInputService.GamepadDisconnected:connect(function(gamepadEnum) + if activateGamepad ~= gamepadEnum then return end + activateGamepad = nil + assignActivateGamepad() + end) + + GamepadDisconnectedConn = UserInputService.GamepadConnected:connect(function(gamepadEnum) + if activateGamepad == nil then + assignActivateGamepad() + end + end) + + local getGamepadPan = function(name, state, input) + if input.UserInputType == activateGamepad and input.KeyCode == Enum.KeyCode.Thumbstick2 then + + if state == Enum.UserInputState.Cancel then + this.GamepadPanningCamera = Vector2.new(0,0) + return + end + + local inputVector = Vector2.new(input.Position.X, -input.Position.Y) + if inputVector.magnitude > THUMBSTICK_DEADZONE then + this.GamepadPanningCamera = Vector2.new(input.Position.X, -input.Position.Y) + else + this.GamepadPanningCamera = Vector2.new(0,0) + end + end + end + + local doGamepadZoom = function(name, state, input) + if input.UserInputType == activateGamepad and input.KeyCode == Enum.KeyCode.ButtonR3 and state == Enum.UserInputState.Begin then + if this.ZoomEnabled then + if this.currentZoom > 0.5 then + this:ZoomCamera(0) + else + this:ZoomCamera(10) + end + end + end + end + + game.ContextActionService:BindAction("RootCamGamepadPan", getGamepadPan, false, Enum.KeyCode.Thumbstick2) + game.ContextActionService:BindAction("RootCamGamepadZoom", doGamepadZoom, false, Enum.KeyCode.ButtonR3) + + assignActivateGamepad() + + -- set mouse behavior + self:UpdateMouseBehavior() + end + + function this:SetEnabled(newState) + if newState ~= self.Enabled then + self.Enabled = newState + if self.Enabled then + self:ConnectInputEvents() + self.cframe = workspace.CurrentCamera.CoordinateFrame + else + self:DisconnectInputEvents() + end + end + end + + local function OnPlayerAdded(player) + player.Changed:connect(function(prop) + if this.Enabled then + if prop == "CameraMode" or prop == "CameraMaxZoomDistance" or prop == "CameraMinZoomDistance" then + this:ZoomCameraFixedBy(0) + end + end + end) + + local function OnCharacterAdded(newCharacter) + this:ZoomCamera(12.5) + local humanoid = findPlayerHumanoid(player) + local start = tick() + while tick() - start < 0.3 and (humanoid == nil or humanoid.Torso == nil) do + wait() + humanoid = findPlayerHumanoid(player) + end + local function setLookBehindCharacter() + if humanoid and humanoid.Torso and player.Character == newCharacter then + local newDesiredLook = (humanoid.Torso.CFrame.lookVector - Vector3.new(0,0.23,0)).unit + local horizontalShift = findAngleBetweenXZVectors(newDesiredLook, this:GetCameraLook()) + local vertShift = math.asin(this:GetCameraLook().y) - math.asin(newDesiredLook.y) + if not IsFinite(horizontalShift) then + horizontalShift = 0 + end + if not IsFinite(vertShift) then + vertShift = 0 + end + this.RotateInput = Vector2.new(horizontalShift, vertShift) + + -- reset old camera info so follow cam doesn't rotate us + this.LastCameraTransform = nil + end + end + wait() + setLookBehindCharacter() + end + + player.CharacterAdded:connect(function(character) + if this.Enabled or SetCameraOnSpawn then + OnCharacterAdded(character) + SetCameraOnSpawn = false + end + end) + if player.Character then + spawn(function() OnCharacterAdded(player.Character) end) + end + end + if PlayersService.LocalPlayer then + OnPlayerAdded(PlayersService.LocalPlayer) + end + PlayersService.ChildAdded:connect(function(child) + if child and PlayersService.LocalPlayer == child then + OnPlayerAdded(PlayersService.LocalPlayer) + end + end) + + local function OnGameLoaded() + hasGameLoaded = true + end + + spawn(function() + if game:IsLoaded() then + OnGameLoaded() + else + game.Loaded:wait() + OnGameLoaded() + end + end) + + + return this +end + +return CreateCamera +]]> + + + + + AttachCamera + 1 then + module:ResetCameraLook() + self.LastCameraTransform = nil + end + + local subjectPosition = self:GetSubjectPosition() + if subjectPosition and player and camera then + local zoom = self:GetCameraZoom() + if zoom <= 0 then + zoom = 0.1 + end + + + local humanoid = self:GetHumanoid() + if lastUpdate and humanoid and humanoid.Torso then + + -- Cap out the delta to 0.1 so we don't get some crazy things when we re-resume from + local delta = math.min(0.1, now - lastUpdate) + local gamepadRotation = self:UpdateGamepad() + self.RotateInput = self.RotateInput + (gamepadRotation * delta) + + local forwardVector = humanoid.Torso.CFrame.lookVector + + local y = findAngleBetweenXZVectors(forwardVector, self:GetCameraLook()) + if IsFinite(y) then + -- Preserve vertical rotation from user input + self.RotateInput = Vector2.new(y, self.RotateInput.Y) + end + end + + local newLookVector = self:RotateCamera(self:GetCameraLook(), self.RotateInput) + self.RotateInput = Vector2.new() + + + camera.Focus = CFrame.new(subjectPosition) + camera.CoordinateFrame = CFrame.new(camera.Focus.p - (zoom * newLookVector), camera.Focus.p) + self.LastCameraTransform = camera.CoordinateFrame + end + lastUpdate = now + end + + return module +end + +return CreateAttachCamera +]]> + + + + + + ClassicCamera + + 1 then + module:ResetCameraLook() + self.LastCameraTransform = nil + end + + if lastUpdate then + local gamepadRotation = self:UpdateGamepad() + + if self:ShouldUseVRRotation() then + self.RotateInput = self.RotateInput + self:GetVRRotationInput() + else + -- Cap out the delta to 0.1 so we don't get some crazy things when we re-resume from + local delta = math.min(0.1, now - lastUpdate) + + if gamepadRotation ~= ZERO_VECTOR2 then + userPanningTheCamera = true + self.RotateInput = self.RotateInput + (gamepadRotation * delta) + end + + local angle = 0 + if not (isInVehicle or isOnASkateboard) then + angle = angle + (self.TurningLeft and -120 or 0) + angle = angle + (self.TurningRight and 120 or 0) + end + + if angle ~= 0 then + self.RotateInput = self.RotateInput + Vector2.new(math.rad(angle * delta), 0) + userPanningTheCamera = true + end + end + end + + -- Reset tween speed if user is panning + if userPanningTheCamera then + tweenSpeed = 0 + module.LastUserPanCamera = tick() + end + + local userRecentlyPannedCamera = now - module.LastUserPanCamera < timeBeforeAutoRotate + local subjectPosition = self:GetSubjectPosition() + + if subjectPosition and player and camera then + local zoom = self:GetCameraZoom() + if zoom < 0.5 then + zoom = 0.5 + end + + if self:GetShiftLock() and not self:IsInFirstPerson() then + -- We need to use the right vector of the camera after rotation, not before + local newLookVector = self:RotateCamera(self:GetCameraLook(), self.RotateInput) + local offset = ((newLookVector * XZ_VECTOR):Cross(UP_VECTOR).unit * 1.75) + + if IsFiniteVector3(offset) then + subjectPosition = subjectPosition + offset + end + else + if self.LastCameraTransform and not userPanningTheCamera then + local isInFirstPerson = self:IsInFirstPerson() + if (isInVehicle or isOnASkateboard) and lastUpdate and humanoid and humanoid.Torso then + if isInFirstPerson then + if self.LastSubjectCFrame and (isInVehicle or isOnASkateboard) and cameraSubject:IsA('BasePart') then + local y = -findAngleBetweenXZVectors(self.LastSubjectCFrame.lookVector, cameraSubject.CFrame.lookVector) + if IsFinite(y) then + self.RotateInput = self.RotateInput + Vector2.new(y, 0) + end + tweenSpeed = 0 + end + elseif not userRecentlyPannedCamera then + local forwardVector = humanoid.Torso.CFrame.lookVector + if isOnASkateboard then + forwardVector = cameraSubject.CFrame.lookVector + end + + tweenSpeed = clamp(0, tweenMaxSpeed, tweenSpeed + tweenAcceleration * timeDelta) + + local percent = clamp(0, 1, tweenSpeed * timeDelta) + if self:IsInFirstPerson() then + percent = 1 + end + + local y = findAngleBetweenXZVectors(forwardVector, self:GetCameraLook()) + if IsFinite(y) and math.abs(y) > 0.0001 then + self.RotateInput = self.RotateInput + Vector2.new(y * percent, 0) + end + end + end + end + end + + camera.Focus = VRService.VREnabled and self:GetVRFocus(subjectPosition, timeDelta) or CFrame.new(subjectPosition) + + local cameraHeight = self:GetCameraHeight() + local cameraFocusP = camera.Focus.p + + if VRService.VREnabled and not self:IsInFirstPerson() then + local vecToSubject = (subjectPosition - camera.CFrame.p) + local distToSubject = vecToSubject.magnitude + + --Only move the camera if it exceeded a maximum distance to the subject in VR + if distToSubject > zoom or self.RotateInput.x ~= 0 then + local desiredDist = math.min(distToSubject, zoom) + vecToSubject = self:RotateCamera(vecToSubject.unit * Vector3.new(1, 0, 1), Vector2.new(self.RotateInput.x, 0)) * desiredDist + local newPos = cameraFocusP - vecToSubject + local desiredLookDir = camera.CFrame.lookVector + if self.RotateInput.x ~= 0 then + desiredLookDir = vecToSubject + end + local lookAt = Vector3.new(newPos.x + desiredLookDir.x, newPos.y, newPos.z + desiredLookDir.z) + self.RotateInput = ZERO_VECTOR2 + + camera.CFrame = CFrame.new(newPos, lookAt) + Vector3.new(0, cameraHeight, 0) + end + else + local newLookVector = self:RotateCamera(self:GetCameraLook(), self.RotateInput) + self.RotateInput = ZERO_VECTOR2 + camera.CFrame = CFrame.new(cameraFocusP - (zoom * newLookVector), cameraFocusP) + Vector3.new(0, cameraHeight, 0) + end + + self.LastCameraTransform = camera.CFrame + self.LastCameraFocus = camera.Focus + if isInVehicle or isOnASkateboard and cameraSubject:IsA('BasePart') then + self.LastSubjectCFrame = cameraSubject.CFrame + else + self.LastSubjectCFrame = nil + end + end + + lastUpdate = now + end + + return module +end + +return CreateClassicCamera +]]> + + + + + + FixedCamera + 1 then + module:ResetCameraLook() + self.LastCameraTransform = nil + end + + if lastUpdate then + -- Cap out the delta to 0.1 so we don't get some crazy things when we re-resume from + local delta = math.min(0.1, now - lastUpdate) + local gamepadRotation = self:UpdateGamepad() + self.RotateInput = self.RotateInput + (gamepadRotation * delta) + end + + local subjectPosition = self:GetSubjectPosition() + if subjectPosition and player and camera then + local zoom = self:GetCameraZoom() + if zoom <= 0 then + zoom = 0.1 + end + local newLookVector = self:RotateCamera(self:GetCameraLook(), self.RotateInput) + self.RotateInput = Vector2.new() + + camera.CoordinateFrame = CFrame.new(camera.Focus.p - (zoom * newLookVector), camera.Focus.p) + self.LastCameraTransform = camera.CoordinateFrame + end + lastUpdate = now + end + + return module +end + +return CreateFixedCamera +]]> + + + + + + FollowCamera + 1 then + module:ResetCameraLook() + self.LastCameraTransform = nil + end + + if lastUpdate then + + if self:ShouldUseVRRotation() then + self.RotateInput = self.RotateInput + self:GetVRRotationInput() + else + -- Cap out the delta to 0.1 so we don't get some crazy things when we re-resume from + local delta = math.min(0.1, now - lastUpdate) + local angle = 0 + -- NOTE: Traditional follow camera does not rotate with arrow keys + if not (isInVehicle or isOnASkateboard) then + angle = angle + (self.TurningLeft and -120 or 0) + angle = angle + (self.TurningRight and 120 or 0) + end + + local gamepadRotation = self:UpdateGamepad() + if gamepadRotation ~= Vector2.new(0,0) then + userPanningTheCamera = true + self.RotateInput = self.RotateInput + (gamepadRotation * delta) + end + + if angle ~= 0 then + userPanningTheCamera = true + self.RotateInput = self.RotateInput + Vector2.new(math.rad(angle * delta), 0) + end + end + end + + -- Reset tween speed if user is panning + if userPanningTheCamera then + tweenSpeed = 0 + module.LastUserPanCamera = tick() + end + + local userRecentlyPannedCamera = now - module.LastUserPanCamera < timeBeforeAutoRotate + + local subjectPosition = self:GetSubjectPosition() + if subjectPosition and player and camera then + local zoom = self:GetCameraZoom() + if zoom < 0.5 then + zoom = 0.5 + end + + if self:GetShiftLock() and not self:IsInFirstPerson() then + local newLookVector = self:RotateCamera(self:GetCameraLook(), self.RotateInput) + local offset = ((newLookVector * XZ_VECTOR):Cross(UP_VECTOR).unit * 1.75) + if IsFiniteVector3(offset) then + subjectPosition = subjectPosition + offset + end + else + if self.LastCameraTransform and not userPanningTheCamera then + local isInFirstPerson = self:IsInFirstPerson() + if (isClimbing or isInVehicle or isOnASkateboard) and lastUpdate and humanoid and humanoid.Torso then + if isInFirstPerson then + if self.LastSubjectCFrame and (isInVehicle or isOnASkateboard) and cameraSubject:IsA('BasePart') then + local y = -findAngleBetweenXZVectors(self.LastSubjectCFrame.lookVector, cameraSubject.CFrame.lookVector) + if IsFinite(y) then + self.RotateInput = self.RotateInput + Vector2.new(y, 0) + end + tweenSpeed = 0 + end + elseif not userRecentlyPannedCamera then + local forwardVector = humanoid.Torso.CFrame.lookVector + if isOnASkateboard then + forwardVector = cameraSubject.CFrame.lookVector + end + + tweenSpeed = clamp(0, tweenMaxSpeed, tweenSpeed + tweenAcceleration * timeDelta) + + local percent = clamp(0, 1, tweenSpeed * timeDelta) + if not isClimbing and self:IsInFirstPerson() then + percent = 1 + end + local y = findAngleBetweenXZVectors(forwardVector, self:GetCameraLook()) + -- Check for NaN + if IsFinite(y) and math.abs(y) > 0.0001 then + self.RotateInput = self.RotateInput + Vector2.new(y * percent, 0) + end + end + elseif not (isInFirstPerson or userRecentlyPannedCamera) and not VRService.VREnabled then + local lastVec = -(self.LastCameraTransform.p - subjectPosition) + local y = findAngleBetweenXZVectors(lastVec, self:GetCameraLook()) + -- Check for NaNs + if IsFinite(y) and math.abs(y) > 0.0001 then + self.RotateInput = self.RotateInput + Vector2.new(y, 0) + end + end + end + end + local newLookVector = self:RotateCamera(self:GetCameraLook(), self.RotateInput) + self.RotateInput = Vector2.new() + + camera.Focus = VRService.VREnabled and self:GetVRFocus(subjectPosition, timeDelta) or CFrame.new(subjectPosition) + camera.CFrame = CFrame.new(camera.Focus.p - (zoom * newLookVector), camera.Focus.p) + Vector3.new(0, self:GetCameraHeight(), 0) + + self.LastCameraTransform = camera.CFrame + self.LastCameraFocus = camera.Focus + if isInVehicle or isOnASkateboard and cameraSubject:IsA('BasePart') then + self.LastSubjectCFrame = cameraSubject.CFrame + else + self.LastSubjectCFrame = nil + end + end + + lastUpdate = now + end + + return module +end + +return CreateFollowCamera +]]> + + + + + + ScriptableCamera + + + + + + + TrackCamera + 1 then + module:ResetCameraLook() + self.LastCameraTransform = nil + end + + if lastUpdate then + -- Cap out the delta to 0.1 so we don't get some crazy things when we re-resume from + local delta = math.min(0.1, now - lastUpdate) + local gamepadRotation = self:UpdateGamepad() + if gamepadRotation ~= Vector2.new(0,0) then + userPanningTheCamera = true + self.RotateInput = self.RotateInput + (gamepadRotation * delta) + end + end + + local subjectPosition = self:GetSubjectPosition() + if subjectPosition and player and camera then + local zoom = self:GetCameraZoom() + if zoom <= 0 then + zoom = 0.1 + end + local newLookVector = self:RotateCamera(self:GetCameraLook(), self.RotateInput) + self.RotateInput = Vector2.new() + + camera.Focus = CFrame.new(subjectPosition) + camera.CoordinateFrame = CFrame.new(camera.Focus.p - (zoom * newLookVector), camera.Focus.p) + self.LastCameraTransform = camera.CoordinateFrame + end + lastUpdate = now + end + + return module +end + +return CreateTrackCamera +]]> + + + + + + WatchCamera + 1 then + module:ResetCameraLook() + self.LastCameraTransform = nil + self.LastZoom = nil + end + + + local subjectPosition = self:GetSubjectPosition() + if subjectPosition and player and camera then + local cameraLook = nil + + if self.LastCameraTransform then + local humanoid = self:GetHumanoid() + if humanoid and humanoid.Torso then + -- TODO: let the paging buttons move the camera but not the mouse/touch + -- currently neither do + local diffVector = subjectPosition - self.LastCameraTransform.p + cameraLook = diffVector.unit + + if self.LastZoom and self.LastZoom == self:GetCameraZoom() then + -- Don't clobber the zoom if they zoomed the camera + local zoom = diffVector.magnitude + self:ZoomCamera(zoom) + end + end + end + + local zoom = self:GetCameraZoom() + if zoom <= 0 then + zoom = 0.1 + end + + local newLookVector = self:RotateVector(cameraLook or self:GetCameraLook(), self.RotateInput) + self.RotateInput = Vector2.new() + local newFocus = CFrame.new(subjectPosition) + local newCamCFrame = CFrame.new(newFocus.p - (zoom * newLookVector), newFocus.p) + + camera.Focus = newFocus + camera.CoordinateFrame = newCamCFrame + self.LastCameraTransform = newCamCFrame + self.LastZoom = zoom + end + lastUpdate = now + end + + return module +end + +return CreateWatchCamera +]]> + + + + + + + ShiftLockController + + + + + + + TransparencyController + + + + + \ No newline at end of file diff --git a/2016/content/fonts/characterControlScript.rbxmx b/2016/content/fonts/characterControlScript.rbxmx new file mode 100644 index 0000000..6a7178d --- /dev/null +++ b/2016/content/fonts/characterControlScript.rbxmx @@ -0,0 +1,1888 @@ + + null + nil + + + false + + ControlScript + PlayerScripts. + + // Required Modules: + ClickToMove + DPad + KeyboardMovement + Thumbpad + Thumbstick + TouchJump + MasterControl + VehicleController +--]] + +--[[ Services ]]-- +local ContextActionService = game:GetService('ContextActionService') +local Players = game:GetService('Players') +local UserInputService = game:GetService('UserInputService') +-- Settings and GameSettings are read only +local Settings = UserSettings() +local GameSettings = Settings.GameSettings + +-- Issue with play solo? (F6) +while not UserInputService.KeyboardEnabled and not UserInputService.TouchEnabled and not UserInputService.GamepadEnabled do + wait() +end + +--[[ Script Variables ]]-- +while not Players.LocalPlayer do + wait() +end + +local lastInputType = nil +local LocalPlayer = Players.LocalPlayer +local PlayerGui = LocalPlayer:WaitForChild('PlayerGui') +local IsTouchDevice = UserInputService.TouchEnabled +local UserMovementMode = IsTouchDevice and GameSettings.TouchMovementMode or GameSettings.ComputerMovementMode +local DevMovementMode = IsTouchDevice and LocalPlayer.DevTouchMovementMode or LocalPlayer.DevComputerMovementMode +local IsUserChoice = (IsTouchDevice and DevMovementMode == Enum.DevTouchMovementMode.UserChoice) or (DevMovementMode == Enum.DevComputerMovementMode.UserChoice) +local TouchGui = nil +local TouchControlFrame = nil +local IsModalEnabled = UserInputService.ModalEnabled +local BindableEvent_OnFailStateChanged = nil +local isJumpEnabled = false + +local ControlState = {} +ControlState.Current = nil +function ControlState:SwitchTo(newControl) + if ControlState.Current == newControl then return end + + if ControlState.Current then + ControlState.Current:Disable() + end + + ControlState.Current = newControl + + if ControlState.Current then + ControlState.Current:Enable() + end +end + +--[[ Modules ]]-- +local ClickToMoveTouchControls = nil +local ControlModules = {} + +local MasterControl = require(script:WaitForChild('MasterControl')) + +local ThumbstickModule = require(script.MasterControl:WaitForChild('Thumbstick')) +local ThumbpadModule = require(script.MasterControl:WaitForChild('Thumbpad')) +local DPadModule = require(script.MasterControl:WaitForChild('DPad')) +local DefaultModule = ControlModules.Thumbstick +local TouchJumpModule = require(script.MasterControl:WaitForChild('TouchJump')) + +local keyboardModule = require(script.MasterControl:WaitForChild('KeyboardMovement')) +ControlModules.Gamepad = require(script.MasterControl:WaitForChild('Gamepad')) + +function getTouchModule() + local module = nil + if not IsUserChoice then + if DevMovementMode == Enum.DevTouchMovementMode.Thumbstick then + module = ThumbstickModule + isJumpEnabled = true + elseif DevMovementMode == Enum.DevTouchMovementMode.Thumbpad then + module = ThumbpadModule + isJumpEnabled = true + elseif DevMovementMode == Enum.DevTouchMovementMode.DPad then + module = DPadModule + isJumpEnabled = false + elseif DevMovementMode == Enum.DevTouchMovementMode.ClickToMove then + -- Managed by CameraScript + module = nil + elseif DevMovementMode == Enum.DevTouchMovementMode.Scriptable then + module = nil + end + else + if UserMovementMode == Enum.TouchMovementMode.Default or UserMovementMode == Enum.TouchMovementMode.Thumbstick then + module = ThumbstickModule + isJumpEnabled = true + elseif UserMovementMode == Enum.TouchMovementMode.Thumbpad then + module = ThumbpadModule + isJumpEnabled = true + elseif UserMovementMode == Enum.TouchMovementMode.DPad then + module = DPadModule + isJumpEnabled = false + elseif UserMovementMode == Enum.TouchMovementMode.ClickToMove then + -- Managed by CameraScript + module = nil + end + end + + return module +end + +function setJumpModule(isEnabled) + if not isEnabled then + TouchJumpModule:Disable() + elseif ControlState.Current == ControlModules.Touch then + TouchJumpModule:Enable() + end +end + +function setClickToMove() + if DevMovementMode == Enum.DevTouchMovementMode.ClickToMove or DevMovementMode == Enum.DevComputerMovementMode.ClickToMove or + UserMovementMode == Enum.ComputerMovementMode.ClickToMove or UserMovementMode == Enum.TouchMovementMode.ClickToMove then + -- + if lastInputType == Enum.UserInputType.Touch then + ClickToMoveTouchControls = ControlState.Current + end + elseif ClickToMoveTouchControls then + ClickToMoveTouchControls:Disable() + ClickToMoveTouchControls = nil + end +end + +ControlModules.Touch = {} +ControlModules.Touch.Current = nil +ControlModules.Touch.LocalPlayerChangedCon = nil +ControlModules.Touch.GameSettingsChangedCon = nil + +function ControlModules.Touch:RefreshControlStyle() + if ControlModules.Touch.Current then + ControlModules.Touch.Current:Disable() + end + setJumpModule(false) + TouchJumpModule:Disable() + ControlModules.Touch:Enable() +end +function ControlModules.Touch:DisconnectEvents() + if ControlModules.Touch.LocalPlayerChangedCon then + ControlModules.Touch.LocalPlayerChangedCon:disconnect() + ControlModules.Touch.LocalPlayerChangedCon = nil + end + if ControlModules.Touch.GameSettingsChangedCon then + ControlModules.Touch.GameSettingsChangedCon:disconnect() + ControlModules.Touch.GameSettingsChangedCon = nil + end +end +function ControlModules.Touch:Enable() + DevMovementMode = LocalPlayer.DevTouchMovementMode + IsUserChoice = DevMovementMode == Enum.DevTouchMovementMode.UserChoice + if IsUserChoice then + UserMovementMode = GameSettings.TouchMovementMode + end + + local newModuleToEnable = getTouchModule() + if newModuleToEnable then + setClickToMove() + setJumpModule(isJumpEnabled) + + newModuleToEnable:Enable() + ControlModules.Touch.Current = newModuleToEnable + + if isJumpEnabled then TouchJumpModule:Enable() end + end + + -- This being within the above if statement was causing issues with ClickToMove, which isn't a module within this script. + ControlModules.Touch:DisconnectEvents() + ControlModules.Touch.LocalPlayerChangedCon = LocalPlayer.Changed:connect(function(property) + if property == 'DevTouchMovementMode' then + ControlModules.Touch:RefreshControlStyle() + end + end) + + ControlModules.Touch.GameSettingsChangedCon = GameSettings.Changed:connect(function(property) + if property == 'TouchMovementMode' then + ControlModules.Touch:RefreshControlStyle() + end + end) +end +function ControlModules.Touch:Disable() + ControlModules.Touch:DisconnectEvents() + + local newModuleToDisable = getTouchModule() + + if newModuleToDisable == ThumbstickModule or + newModuleToDisable == DPadModule or + newModuleToDisable == ThumbpadModule then + newModuleToDisable:Disable() + setJumpModule(false) + TouchJumpModule:Disable() + end +end + +local function getKeyboardModule() + -- NOTE: Click to move still uses keyboard. Leaving cases in case this ever changes. + local whichModule = nil + if not IsUserChoice then + if DevMovementMode == Enum.DevComputerMovementMode.KeyboardMouse then + whichModule = keyboardModule + elseif DevMovementMode == Enum.DevComputerMovementMode.ClickToMove then + -- Managed by CameraScript + whichModule = keyboardModule + end + else + if UserMovementMode == Enum.ComputerMovementMode.KeyboardMouse or UserMovementMode == Enum.ComputerMovementMode.Default then + whichModule = keyboardModule + elseif UserMovementMode == Enum.ComputerMovementMode.ClickToMove then + -- Managed by CameraScript + whichModule = keyboardModule + end + end + + return whichModule +end + +ControlModules.Keyboard = {} +function ControlModules.Keyboard:RefreshControlStyle() + ControlModules.Keyboard:Disable() + ControlModules.Keyboard:Enable() +end +function ControlModules.Keyboard:Enable() + DevMovementMode = LocalPlayer.DevComputerMovementMode + IsUserChoice = DevMovementMode == Enum.DevComputerMovementMode.UserChoice + if IsUserChoice then + UserMovementMode = GameSettings.ComputerMovementMode + end + + local newModuleToEnable = getKeyboardModule() + if newModuleToEnable then + newModuleToEnable:Enable() + end + + ControlModules.Keyboard:DisconnectEvents() + ControlModules.Keyboard.LocalPlayerChangedCon = LocalPlayer.Changed:connect(function(property) + if property == 'DevComputerMovementMode' then + ControlModules.Keyboard:RefreshControlStyle() + end + end) + + ControlModules.Keyboard.GameSettingsChangedCon = GameSettings.Changed:connect(function(property) + if property == 'ComputerMovementMode' then + ControlModules.Keyboard:RefreshControlStyle() + end + end) +end +function ControlModules.Keyboard:DisconnectEvents() + if ControlModules.Keyboard.LocalPlayerChangedCon then + ControlModules.Keyboard.LocalPlayerChangedCon:disconnect() + ControlModules.Keyboard.LocalPlayerChangedCon = nil + end + if ControlModules.Keyboard.GameSettingsChangedCon then + ControlModules.Keyboard.GameSettingsChangedCon:disconnect() + ControlModules.Keyboard.GameSettingsChangedCon = nil + end +end +function ControlModules.Keyboard:Disable() + ControlModules.Keyboard:DisconnectEvents() + local newModuleToDisable = getKeyboardModule() + if newModuleToDisable then + newModuleToDisable:Disable() + end +end + +if IsTouchDevice then + BindableEvent_OnFailStateChanged = script.Parent:WaitForChild('OnClickToMoveFailStateChange') +end + +-- not used, but needs to be required +local VehicleController = require(script.MasterControl:WaitForChild('VehicleController')) + + +--[[ Initialization/Setup ]]-- +local function createTouchGuiContainer() + if TouchGui then TouchGui:Destroy() end + + -- Container for all touch device guis + TouchGui = Instance.new('ScreenGui') + TouchGui.Name = "TouchGui" + TouchGui.Parent = PlayerGui + + TouchControlFrame = Instance.new('Frame') + TouchControlFrame.Name = "TouchControlFrame" + TouchControlFrame.Size = UDim2.new(1, 0, 1, 0) + TouchControlFrame.BackgroundTransparency = 1 + TouchControlFrame.Parent = TouchGui + + ThumbstickModule:Create(TouchControlFrame) + DPadModule:Create(TouchControlFrame) + ThumbpadModule:Create(TouchControlFrame) + TouchJumpModule:Create(TouchControlFrame) +end + +--[[ Settings Changed Connections ]]-- +LocalPlayer.Changed:connect(function(property) + if lastInputType == Enum.UserInputType.Touch and property == 'DevTouchMovementMode' then + ControlState:SwitchTo(ControlModules.Touch) + elseif UserInputService.KeyboardEnabled and property == 'DevComputerMovementMode' then + ControlState:SwitchTo(ControlModules.Keyboard) + end +end) + +GameSettings.Changed:connect(function(property) + if not IsUserChoice then return end + if property == 'TouchMovementMode' or property == 'ComputerMovementMode' then + UserMovementMode = GameSettings[property] + if property == 'TouchMovementMode' then + ControlState:SwitchTo(ControlModules.Touch) + elseif property == 'ComputerMovementMode' then + ControlState:SwitchTo(ControlModules.Keyboard) + end + end +end) + +--[[ Touch Events ]]-- +-- On touch devices we need to recreate the guis on character load. +local lastControlState = nil +LocalPlayer.CharacterAdded:connect(function(character) + if ControlState.Current then -- only do this if it wasn't done through CharacterRemoving + lastControlState = ControlState.Current + ControlState:SwitchTo(nil) + end + + if UserInputService.TouchEnabled then + createTouchGuiContainer() + end + + if ControlState.Current == nil then + ControlState:SwitchTo(lastControlState) + end +end) + +LocalPlayer.CharacterRemoving:connect(function() + lastControlState = ControlState.Current + ControlState:SwitchTo(nil) +end) + +UserInputService.Changed:connect(function(property) + if property == 'ModalEnabled' then + IsModalEnabled = UserInputService.ModalEnabled + + if lastInputType == Enum.UserInputType.Touch then + if ControlState.Current == ControlModules.Touch and IsModalEnabled then + ControlState:SwitchTo(nil) + elseif ControlState.Current == nil and not IsModalEnabled then + ControlState:SwitchTo(ControlModules.Touch) + end + end + end +end) + +if BindableEvent_OnFailStateChanged then + BindableEvent_OnFailStateChanged.Event:connect(function(isOn) + if lastInputType == Enum.UserInputType.Touch and ClickToMoveTouchControls then + if isOn then + ControlState:SwitchTo(ClickToMoveTouchControls) + else + ControlState:SwitchTo(nil) + end + end + end) +end + +local switchToInputType = function(newLastInputType) + lastInputType = newLastInputType + + if lastInputType == Enum.UserInputType.Touch then + ControlState:SwitchTo(ControlModules.Touch) + elseif lastInputType == Enum.UserInputType.Keyboard or + lastInputType == Enum.UserInputType.MouseButton1 or + lastInputType == Enum.UserInputType.MouseButton2 or + lastInputType == Enum.UserInputType.MouseButton3 or + lastInputType == Enum.UserInputType.MouseWheel or + lastInputType == Enum.UserInputType.MouseMovement then + ControlState:SwitchTo(ControlModules.Keyboard) + elseif lastInputType == Enum.UserInputType.Gamepad1 or + lastInputType == Enum.UserInputType.Gamepad2 or + lastInputType == Enum.UserInputType.Gamepad3 or + lastInputType == Enum.UserInputType.Gamepad4 then + ControlState:SwitchTo(ControlModules.Gamepad) + end +end + +if IsTouchDevice then + createTouchGuiContainer() +end + +MasterControl:Init() + +UserInputService.GamepadDisconnected:connect(function(gamepadEnum) + local connectedGamepads = UserInputService:GetConnectedGamepads() + if #connectedGamepads > 0 then return end + + if UserInputService.KeyboardEnabled then + ControlState:SwitchTo(ControlModules.Keyboard) + elseif IsTouchDevice then + ControlState:SwitchTo(ControlModules.Touch) + end +end) + +UserInputService.GamepadConnected:connect(function(gamepadEnum) + ControlState:SwitchTo(ControlModules.Gamepad) +end) + +switchToInputType(UserInputService:GetLastInputType()) +UserInputService.LastInputTypeChanged:connect(switchToInputType)]]> + + + + + MasterControl + + + + + DPad + jumpRadius then + local angle = ATAN2(direction.y, direction.x) + local octant = (FLOOR(8 * angle / (2 * PI) + 8.5)%8) + 1 + movementVector = COMPASS_DIR[octant] + end + + if not flBtn.Visible and movementVector == COMPASS_DIR[7] then + flBtn.Visible = true + frBtn.Visible = true + end + end + + DPadFrame.InputBegan:connect(function(inputObject) + if TouchObject or inputObject.UserInputType ~= Enum.UserInputType.Touch then + return + end + + MasterControl:AddToPlayerMovement(-movementVector) + + TouchObject = inputObject + normalizeDirection(TouchObject.Position) + + MasterControl:AddToPlayerMovement(movementVector) + end) + + DPadFrame.InputChanged:connect(function(inputObject) + if inputObject == TouchObject then + MasterControl:AddToPlayerMovement(-movementVector) + normalizeDirection(TouchObject.Position) + MasterControl:AddToPlayerMovement(movementVector) + MasterControl:SetIsJumping(false) + end + end) + + OnInputEnded = function() + TouchObject = nil + flBtn.Visible = false + frBtn.Visible = false + + MasterControl:AddToPlayerMovement(-movementVector) + movementVector = Vector3.new(0, 0, 0) + end + + DPadFrame.InputEnded:connect(function(inputObject) + if inputObject == TouchObject then + OnInputEnded() + end + end) + + GuiService.MenuOpened:connect(function() + if TouchObject then + OnInputEnded() + end + end) + + DPadFrame.Parent = parentFrame +end + +return DPad +]]> + + + + + + Gamepad + 0 then + for i = 1, #connectedGamepads do + if activateGamepad == nil then + activateGamepad = connectedGamepads[i] + elseif connectedGamepads[i].Value < activateGamepad.Value then + activateGamepad = connectedGamepads[i] + end + end + end + + if activateGamepad == nil then -- nothing is connected, at least set up for gamepad1 + activateGamepad = Enum.UserInputType.Gamepad1 + end +end + +--[[ Public API ]]-- +function Gamepad:Enable() + local forwardValue = 0 + local backwardValue = 0 + local leftValue = 0 + local rightValue = 0 + + local moveFunc = LocalPlayer.Move + local gamepadSupports = UserInputService.GamepadSupports + + local controlCharacterGamepad = function(actionName, inputState, inputObject) + if activateGamepad ~= inputObject.UserInputType then return end + if inputObject.KeyCode ~= Enum.KeyCode.Thumbstick1 then return end + + if inputState == Enum.UserInputState.Cancel then + MasterControl:AddToPlayerMovement(-currentMoveVector) + currentMoveVector = Vector3.new(0,0,0) + return + end + + if inputObject.Position.magnitude > thumbstickDeadzone then + MasterControl:AddToPlayerMovement(-currentMoveVector) + currentMoveVector = Vector3.new(inputObject.Position.X, 0, -inputObject.Position.Y) + MasterControl:AddToPlayerMovement(currentMoveVector) + else + MasterControl:AddToPlayerMovement(-currentMoveVector) + currentMoveVector = Vector3.new(0,0,0) + end + end + + local jumpCharacterGamepad = function(actionName, inputState, inputObject) + if activateGamepad ~= inputObject.UserInputType then return end + if inputObject.KeyCode ~= Enum.KeyCode.ButtonA then return end + + if inputState == Enum.UserInputState.Cancel then + MasterControl:SetIsJumping(false) + return + end + + MasterControl:SetIsJumping(inputObject.UserInputState == Enum.UserInputState.Begin) + end + + local doDpadMoveUpdate = function(userInputType) + if not gamepadSupports(UserInputService, userInputType, Enum.KeyCode.Thumbstick1) then + if LocalPlayer and LocalPlayer.Character then + MasterControl:AddToPlayerMovement(-currentMoveVector) + currentMoveVector = Vector3.new(leftValue + rightValue,0,forwardValue + backwardValue) + MasterControl:AddToPlayerMovement(currentMoveVector) + end + end + end + + local moveForwardFunc = function(actionName, inputState, inputObject) + if inputState == Enum.UserInputState.End then + forwardValue = -1 + elseif inputState == Enum.UserInputState.Begin or inputState == Enum.UserInputState.Cancel then + forwardValue = 0 + end + + doDpadMoveUpdate(inputObject.UserInputType) + end + + local moveBackwardFunc = function(actionName, inputState, inputObject) + if inputState == Enum.UserInputState.End then + backwardValue = 1 + elseif inputState == Enum.UserInputState.Begin or inputState == Enum.UserInputState.Cancel then + backwardValue = 0 + end + + doDpadMoveUpdate(inputObject.UserInputType) + end + + local moveLeftFunc = function(actionName, inputState, inputObject) + if inputState == Enum.UserInputState.End then + leftValue = -1 + elseif inputState == Enum.UserInputState.Begin or inputState == Enum.UserInputState.Cancel then + leftValue = 0 + end + + doDpadMoveUpdate(inputObject.UserInputType) + end + + local moveRightFunc = function(actionName, inputState, inputObject) + if inputState == Enum.UserInputState.End then + rightValue = 1 + elseif inputState == Enum.UserInputState.Begin or inputState == Enum.UserInputState.Cancel then + rightValue = 0 + end + + doDpadMoveUpdate(inputObject.UserInputType) + end + + local function setActivateGamepad() + if activateGamepad then + ContextActionService:UnbindActivate(activateGamepad, Enum.KeyCode.ButtonR2) + end + assignActivateGamepad() + if activateGamepad then + ContextActionService:BindActivate(activateGamepad, Enum.KeyCode.ButtonR2) + end + end + + ContextActionService:BindAction("JumpButton",jumpCharacterGamepad, false, Enum.KeyCode.ButtonA) + ContextActionService:BindAction("MoveThumbstick",controlCharacterGamepad, false, Enum.KeyCode.Thumbstick1) + + ContextActionService:BindAction("forwardDpad", moveForwardFunc, false, Enum.KeyCode.DPadUp) + ContextActionService:BindAction("backwardDpad", moveBackwardFunc, false, Enum.KeyCode.DPadDown) + ContextActionService:BindAction("leftDpad", moveLeftFunc, false, Enum.KeyCode.DPadLeft) + ContextActionService:BindAction("rightDpad", moveRightFunc, false, Enum.KeyCode.DPadRight) + + setActivateGamepad() + + gamepadConnectedCon = UserInputService.GamepadDisconnected:connect(function(gamepadEnum) + if activateGamepad ~= gamepadEnum then return end + + MasterControl:AddToPlayerMovement(-currentMoveVector) + currentMoveVector = Vector3.new(0,0,0) + + activateGamepad = nil + setActivateGamepad() + end) + + gamepadDisconnectedCon = UserInputService.GamepadConnected:connect(function(gamepadEnum) + if activateGamepad == nil then + setActivateGamepad() + end + end) +end + +function Gamepad:Disable() + + ContextActionService:UnbindAction("forwardDpad") + ContextActionService:UnbindAction("backwardDpad") + ContextActionService:UnbindAction("leftDpad") + ContextActionService:UnbindAction("rightDpad") + + ContextActionService:UnbindAction("MoveThumbstick") + ContextActionService:UnbindAction("JumpButton") + ContextActionService:UnbindActivate(activateGamepad, Enum.KeyCode.ButtonR2) + + if gamepadConnectedCon then gamepadConnectedCon:disconnect() end + if gamepadDisconnectedCon then gamepadDisconnectedCon:disconnect() end + + activateGamepad = nil + MasterControl:AddToPlayerMovement(-currentMoveVector) + currentMoveVector = Vector3.new(0,0,0) + MasterControl:SetIsJumping(false) +end + +return Gamepad +]]> + + + + + + KeyboardMovement + + + + + + Thumbpad + 0.5 then -- UP + if not isUp then + isUp, isDown = true, false + doTween(uArrow, lgArrowSize, UDim2.new(0.5, -smArrowSize.X.Offset, 0, smImgOffset - smArrowSize.Y.Offset * 1.5)) + doTween(dArrow, smArrowSize, UDim2.new(0.5, -smArrowSize.X.Offset/2, 1, lgImgOffset)) + end + elseif forwardDot < -0.5 then -- DOWN + if not isDown then + isDown, isUp = true, false + doTween(dArrow, lgArrowSize, UDim2.new(0.5, -smArrowSize.X.Offset, 1, lgImgOffset + smArrowSize.Y.Offset/2)) + doTween(uArrow, smArrowSize, UDim2.new(0.5, -smArrowSize.X.Offset/2, 0, smImgOffset)) + end + else + isUp, isDown = false, false + doTween(dArrow, smArrowSize, UDim2.new(0.5, -smArrowSize.X.Offset/2, 1, lgImgOffset)) + doTween(uArrow, smArrowSize, UDim2.new(0.5, -smArrowSize.X.Offset/2, 0, smImgOffset)) + end + + if rightDot > 0.5 then + if not isRight then + isRight, isLeft = true, false + doTween(rArrow, lgArrowSize, UDim2.new(1, lgImgOffset + smArrowSize.X.Offset/2, 0.5, -smArrowSize.Y.Offset)) + doTween(lArrow, smArrowSize, UDim2.new(0, smImgOffset, 0.5, -smArrowSize.Y.Offset/2)) + end + elseif rightDot < -0.5 then + if not isLeft then + isLeft, isRight = true, false + doTween(lArrow, lgArrowSize, UDim2.new(0, smImgOffset - smArrowSize.X.Offset * 1.5, 0.5, -smArrowSize.Y.Offset)) + doTween(rArrow, smArrowSize, UDim2.new(1, lgImgOffset, 0.5, -smArrowSize.Y.Offset/2)) + end + else + isRight, isLeft = false, false + doTween(lArrow, smArrowSize, UDim2.new(0, smImgOffset, 0.5, -smArrowSize.Y.Offset/2)) + doTween(rArrow, smArrowSize, UDim2.new(1, lgImgOffset, 0.5, -smArrowSize.Y.Offset/2)) + end + end + + --input connections + ThumbpadFrame.InputBegan:connect(function(inputObject) + if TouchObject or inputObject.UserInputType ~= Enum.UserInputType.Touch then + return + end + + ThumbpadFrame.Position = UDim2.new(0, inputObject.Position.x - ThumbpadFrame.AbsoluteSize.x/2, 0, inputObject.Position.y - ThumbpadFrame.Size.Y.Offset/2) + padOrigin = Vector2.new(ThumbpadFrame.AbsolutePosition.x + ThumbpadFrame.AbsoluteSize.x/2, + ThumbpadFrame.AbsolutePosition.y + ThumbpadFrame.AbsoluteSize.y/2) + doMove(inputObject.Position) + TouchObject = inputObject + end) + + OnTouchChangedCn = UserInputService.TouchMoved:connect(function(inputObject, isProcessed) + if inputObject == TouchObject then + doMove(TouchObject.Position) + end + end) + + OnInputEnded = function() + MasterControl:AddToPlayerMovement(-currentMoveVector) + currentMoveVector = Vector3.new(0,0,0) + MasterControl:SetIsJumping(false) + + ThumbpadFrame.Position = position + TouchObject = nil + isUp, isDown, isLeft, isRight = false, false, false, false + doTween(dArrow, smArrowSize, UDim2.new(0.5, -smArrowSize.X.Offset/2, 1, lgImgOffset)) + doTween(uArrow, smArrowSize, UDim2.new(0.5, -smArrowSize.X.Offset/2, 0, smImgOffset)) + doTween(lArrow, smArrowSize, UDim2.new(0, smImgOffset, 0.5, -smArrowSize.Y.Offset/2)) + doTween(rArrow, smArrowSize, UDim2.new(1, lgImgOffset, 0.5, -smArrowSize.Y.Offset/2)) + end + + OnTouchEndedCn = UserInputService.TouchEnded:connect(function(inputObject) + if inputObject == TouchObject then + OnInputEnded() + end + end) + + GuiService.MenuOpened:connect(function() + if TouchObject then + OnInputEnded() + end + end) + + ThumbpadFrame.Parent = parentFrame +end + +return Thumbpad +]]> + + + + + + Thumbstick + maxLength then + local offset = relativePosition.unit * maxLength + ThumbstickFrame.Position = UDim2.new( + 0, pos.x - ThumbstickFrame.AbsoluteSize.x/2 - offset.x, + 0, pos.y - ThumbstickFrame.AbsoluteSize.y/2 - offset.y) + else + length = math.min(length, maxLength) + relativePosition = relativePosition.unit * length + end + StickImage.Position = UDim2.new(0, relativePosition.x + StickImage.AbsoluteSize.x/2, 0, relativePosition.y + StickImage.AbsoluteSize.y/2) + end + + -- input connections + ThumbstickFrame.InputBegan:connect(function(inputObject) + if MoveTouchObject or inputObject.UserInputType ~= Enum.UserInputType.Touch then + return + end + + MoveTouchObject = inputObject + ThumbstickFrame.Position = UDim2.new(0, inputObject.Position.x - ThumbstickFrame.Size.X.Offset/2, 0, inputObject.Position.y - ThumbstickFrame.Size.Y.Offset/2) + centerPosition = Vector2.new(ThumbstickFrame.AbsolutePosition.x + ThumbstickFrame.AbsoluteSize.x/2, + ThumbstickFrame.AbsolutePosition.y + ThumbstickFrame.AbsoluteSize.y/2) + local direction = Vector2.new(inputObject.Position.x - centerPosition.x, inputObject.Position.y - centerPosition.y) + end) + + OnTouchMovedCn = UserInputService.TouchMoved:connect(function(inputObject, isProcessed) + if inputObject == MoveTouchObject then + centerPosition = Vector2.new(ThumbstickFrame.AbsolutePosition.x + ThumbstickFrame.AbsoluteSize.x/2, + ThumbstickFrame.AbsolutePosition.y + ThumbstickFrame.AbsoluteSize.y/2) + local direction = Vector2.new(inputObject.Position.x - centerPosition.x, inputObject.Position.y - centerPosition.y) + doMove(direction) + moveStick(inputObject.Position) + end + end) + + OnTouchEnded = function() + ThumbstickFrame.Position = position + StickImage.Position = UDim2.new(0, ThumbstickFrame.Size.X.Offset/2 - thumbstickSize/4, 0, ThumbstickFrame.Size.Y.Offset/2 - thumbstickSize/4) + MoveTouchObject = nil + + MasterControl:AddToPlayerMovement(-currentMoveVector) + currentMoveVector = Vector3.new(0,0,0) + MasterControl:SetIsJumping(false) + end + + OnTouchEndedCn = UserInputService.TouchEnded:connect(function(inputObject, isProcessed) + if inputObject == MoveTouchObject then + OnTouchEnded() + end + end) + + GuiService.MenuOpened:connect(function() + if MoveTouchObject then + OnTouchEnded() + end + end) + + ThumbstickFrame.Parent = parentFrame +end + +return Thumbstick +]]> + + + + + + TouchJump + + 0 and JumpStateEnabled then + TouchJump:Enable() + else + TouchJump:Disable() + end +end + +local function humanoidChanged(prop) + if prop == "JumpPower" then + JumpPower = Humanoid.JumpPower + updateEnabled() + elseif prop == "Parent" then + if not Humanoid.Parent then + HumChangeConnection:disconnect() + end + end +end + +local function humandoidStateEnabledChanged(state, isEnabled) + if state == Enum.HumanoidStateType.Jumping then + JumpStateEnabled = isEnabled + updateEnabled() + end +end + +local function disableButton() + JumpButton.Visible = false + OnInputEnded() +end + +local function enableButton() + if Humanoid and ExternallyEnabled then + if Humanoid.JumpPower > 0 then + JumpButton.Visible = true + end + end +end + +local function characterAdded(newCharacter) + if HumChangeConnection then + HumChangeConnection:disconnect() + end + -- rebind event to new Humanoid + Humanoid = nil + repeat + Humanoid = MasterControl:GetHumanoid() + wait() + until Humanoid and Humanoid.Parent == newCharacter + HumChangeConnection = Humanoid.Changed:connect(humanoidChanged) + HumStateConnection = Humanoid.StateEnabledChanged:connect(humandoidStateEnabledChanged) + JumpPower = Humanoid.JumpPower + JumpStateEnabled = Humanoid:GetStateEnabled(Enum.HumanoidStateType.Jumping) + updateEnabled() +end + +local function setupCharacterAddedFunction() + CharacterAddedConnection = LocalPlayer.CharacterAdded:connect(characterAdded) + if LocalPlayer.Character then + characterAdded(LocalPlayer.Character) + end +end + +--[[ Public API ]]-- +function TouchJump:Enable() + ExternallyEnabled = true + enableButton() +end + +function TouchJump:Disable() + ExternallyEnabled = false + disableButton() +end + +function TouchJump:Create(parentFrame) + if JumpButton then + JumpButton:Destroy() + JumpButton = nil + end + + local isSmallScreen = parentFrame.AbsoluteSize.y <= 500 + local jumpButtonSize = isSmallScreen and 70 or 120 + + JumpButton = Instance.new('ImageButton') + JumpButton.Name = "JumpButton" + JumpButton.Visible = false + JumpButton.BackgroundTransparency = 1 + JumpButton.Image = TOUCH_CONTROL_SHEET + JumpButton.ImageRectOffset = Vector2.new(176, 222) + JumpButton.ImageRectSize = Vector2.new(174, 174) + JumpButton.Size = UDim2.new(0, jumpButtonSize, 0, jumpButtonSize) + + if not repositionJumpButton then + JumpButton.Position = isSmallScreen and UDim2.new(1, jumpButtonSize * -2.25, 1, -jumpButtonSize - 20) or + UDim2.new(1, jumpButtonSize * -2.75, 1, -jumpButtonSize - 120) + else + JumpButton.Position = isSmallScreen and UDim2.new(1, -(jumpButtonSize*1.5-10), 1, -jumpButtonSize - 20) or + UDim2.new(1, -(jumpButtonSize*1.5-10), 1, -jumpButtonSize * 1.75) + end + + local touchObject = nil + JumpButton.InputBegan:connect(function(inputObject) + if touchObject or inputObject.UserInputType ~= Enum.UserInputType.Touch then + return + end + + touchObject = inputObject + JumpButton.ImageRectOffset = Vector2.new(0, 222) + MasterControl:SetIsJumping(true) + end) + + OnInputEnded = function() + touchObject = nil + MasterControl:SetIsJumping(false) + JumpButton.ImageRectOffset = Vector2.new(176, 222) + end + + JumpButton.InputEnded:connect(function(inputObject) + if inputObject == touchObject then + OnInputEnded() + end + end) + + GuiService.MenuOpened:connect(function() + if touchObject then + OnInputEnded() + end + end) + + if not CharacterAddedConnection then + setupCharacterAddedFunction() + end + + JumpButton.Parent = parentFrame +end + +return TouchJump +]]> + + + + + + VehicleController + 0.5 then + return 1 + elseif value < -0.5 then + return -1 + end + return 0 +end + +local function onRenderStepped() + if CurrentVehicleSeat then + local moveValue = MasterControl:GetMoveVector() + if game:GetService("UserInputService"):GetGamepadConnected(Enum.UserInputType.Gamepad1) and onlyTriggersForThrottle and useTriggersForThrottle then + CurrentVehicleSeat.Throttle = -CurrentThrottle + else + CurrentVehicleSeat.Throttle = getClosestFittingValue(-moveValue.z) + end + CurrentVehicleSeat.Steer = getClosestFittingValue(moveValue.x) + end +end + +local function onSeated(active, currentSeatPart) + if active then + if currentSeatPart and currentSeatPart:IsA('VehicleSeat') then + CurrentVehicleSeat = currentSeatPart + if useTriggersForThrottle then + ContextActionService:BindAction("throttleAccel", onThrottleAccel, false, Enum.KeyCode.ButtonR2) + ContextActionService:BindAction("throttleDeccel", onThrottleDeccel, false, Enum.KeyCode.ButtonL2) + end + ContextActionService:BindAction("arrowSteerRight", onSteerRight, false, Enum.KeyCode.Right) + ContextActionService:BindAction("arrowSteerLeft", onSteerLeft, false, Enum.KeyCode.Left) + local success = pcall(function() RunService:BindToRenderStep("VehicleControlStep", Enum.RenderPriority.Input.Value, onRenderStepped) end) + + if not success then + if RenderSteppedCn then return end + RenderSteppedCn = RunService.RenderStepped:connect(onRenderStepped) + end + end + else + CurrentVehicleSeat = nil + if useTriggersForThrottle then + ContextActionService:UnbindAction("throttleAccel") + ContextActionService:UnbindAction("throttleDeccel") + end + ContextActionService:UnbindAction("arrowSteerRight") + ContextActionService:UnbindAction("arrowSteerLeft") + MasterControl:AddToPlayerMovement(Vector3.new(-CurrentSteer, 0, -CurrentThrottle)) + CurrentThrottle = 0 + CurrentSteer = 0 + local success = pcall(function() RunService:UnbindFromRenderStep("VehicleControlStep") end) + if not success and RenderSteppedCn then + RenderSteppedCn:disconnect() + RenderSteppedCn = nil + end + end +end + +local function CharacterAdded(character) + local humanoid = getHumanoid() + while not humanoid do + wait() + humanoid = getHumanoid() + end + -- + if HumanoidSeatedCn then + HumanoidSeatedCn:disconnect() + HumanoidSeatedCn = nil + end + HumanoidSeatedCn = humanoid.Seated:connect(onSeated) +end + +if LocalPlayer.Character then + CharacterAdded(LocalPlayer.Character) +end +LocalPlayer.CharacterAdded:connect(CharacterAdded) + +return VehicleController +]]> + + + + + \ No newline at end of file diff --git a/2016/content/fonts/characterR15.rbxm b/2016/content/fonts/characterR15.rbxm new file mode 100644 index 0000000..5449e9e --- /dev/null +++ b/2016/content/fonts/characterR15.rbxm @@ -0,0 +1,2453 @@ + + null + nil + + + + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + PlayerR15 + RBXCBB23D04551C4C1CA7A615BB0E363445 + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + 194 + + -7.32807493 + 4.93474579 + 23.0964928 + -0.550465405 + 1.69023281e-021 + 0.834857941 + 5.09723496e-022 + 1 + -1.68849151e-021 + -0.834857941 + -5.03909301e-022 + -0.550465405 + + true + + false + + 0.5 + 0.300000012 + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + false + 256 + Head + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + -0.5 + 0.5 + 0 + 0 + 0 + + 0 + 0 + 0 + + 3 + 1 + + 1 + 1 + 1 + + + + + 5 + Decal + rbxasset://textures/face.png + 0 + + + + + 2 + 2 + http://www.roblox.com/asset?id=419776358 + 5 + Mesh + + 0 + 0 + 0 + + + 1 + 1 + 1 + + + + 1 + 1 + 1 + + + + + + + 0 + -0.634747982 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + NeckRigAttachment + + + + + + 2.7e-005 + 0.529992998 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + HairAttachment + + + + + + 2.7e-005 + 0.529992998 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + HatAttachment + + + + + + 2.7e-005 + -0.0690819994 + -0.597245991 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + FaceFrontAttachment + + + + + + 2.7e-005 + -0.0687479973 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + FaceCenterAttachment + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + 194 + + -7.32807493 + 2.62639618 + 23.0964928 + -0.550465405 + 1.69023281e-021 + 0.834857941 + 5.09723496e-022 + 1 + -1.68849151e-021 + -0.834857941 + -5.03909301e-022 + -0.550465405 + + false + + false + + 0.5 + 0.300000012 + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + false + 256 + HumanoidRootPart + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + -0.5 + 0.5 + 0 + 0 + 1 + + 0 + 0 + 0 + + 3 + 1 + + 2 + 2 + 1 + + + + + + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + RootRigAttachment + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + 194 + + -6.50264025 + 2.92789984 + 24.3483791 + -0.550465286 + 0 + 0.834857941 + 0 + 0.999999762 + -1.68849151e-021 + -0.834857762 + 0 + -0.550465405 + + false + + false + + 0.5 + 0.300000012 + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + false + 256 + LeftLowerArm + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + -0.5 + 0.5 + 0 + 0 + 0 + + 0 + 0 + 0 + + 3 + 1 + + 1 + 0.805206001 + 1 + + + + + 2 + 2 + http://www.roblox.com/asset?id=419770884 + 5 + Mesh + + 0 + 0 + 0 + + + 1 + 1 + 1 + + + + 1 + 1 + 1 + + + + + + + 0 + 0.402603 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + LeftElbowRigAttachment + + + + + + 0 + -0.402603 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + LeftWristRigAttachment + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + 194 + + -6.57134676 + 3.69043899 + 24.2441769 + -0.52008301 + -0.180348992 + 0.834857941 + -0.327630013 + 0.94480598 + -1.68849151e-021 + -0.788778782 + -0.273524523 + -0.550465405 + + false + + false + + 0.5 + 0.300000012 + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + false + 256 + LeftUpperArm + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + -0.5 + 0.5 + 0 + 0 + 0 + + 0 + 0 + 0 + + 3 + 1 + + 1 + 0.761925995 + 1 + + + + + 2 + 2 + http://www.roblox.com/asset?id=419769794 + 5 + Mesh + + 0 + 0 + 0 + + + 1 + 1 + 1 + + + + 1 + 1 + 1 + + + + + + + 0 + 0.380962998 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + LeftShoulderRigAttachment + + + + + + 0 + -0.380962998 + 0 + 0.944806099 + -0.327630043 + 0 + 0.327630043 + 0.944806099 + -0 + 0 + 0 + 1 + + LeftElbowRigAttachment + + + + + + -0.328602999 + 0.534847021 + 0 + 0.944806099 + -0.327630043 + 0 + 0.327630043 + 0.944806099 + -0 + 0 + 0 + 1 + + LeftShoulderAttachment + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + 194 + + -7.05028296 + 0.250696182 + 23.5179825 + -0.550465405 + 0 + 0.834857941 + 5.09723496e-022 + 1 + 0 + -0.834857941 + 0 + -0.550465405 + + false + + false + + 0.5 + 0.300000012 + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + false + 256 + LeftFoot + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + -0.5 + 0.5 + 0 + 0 + 0 + + 0 + 0 + 0 + + 3 + 1 + + 1 + 0.5 + 1 + + + + + 2 + 2 + http://www.roblox.com/asset?id=419771742 + 5 + Mesh + + 0 + 0 + 0 + + + 1 + 1 + 1 + + + + 1 + 1 + 1 + + + + + + + 0 + 0.25 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + LeftAnkleRigAttachment + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + 194 + + -6.50264025 + 2.32399487 + 24.3483791 + -0.550465286 + 0 + 0.834857941 + 0 + 0.999999762 + -1.68849151e-021 + -0.834857762 + 0 + -0.550465405 + + false + + false + + 0.5 + 0.300000012 + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + false + 256 + LeftHand + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + -0.5 + 0.5 + 0 + 0 + 0 + + 0 + 0 + 0 + + 3 + 1 + + 1 + 0.402603 + 1 + + + + + 2 + 2 + http://www.roblox.com/asset?id=419771232 + 5 + Mesh + + 0 + 0 + 0 + + + 1 + 1 + 1 + + + + 1 + 1 + 1 + + + + + + + 0 + 0.201302007 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + LeftWristRigAttachment + + + + + + -0.0104189999 + -0.0252640005 + 0 + 1 + 0 + -0 + 0 + 0 + 1 + 0 + -1 + 0 + + LeftGripAttachment + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + 194 + + -7.05028296 + 1.00069618 + 23.5179825 + -0.550465405 + 0 + 0.834857941 + 5.09723496e-022 + 1 + 0 + -0.834857941 + 0 + -0.550465405 + + false + + false + + 0.5 + 0.300000012 + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + false + 256 + LeftLowerLeg + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + -0.5 + 0.5 + 0 + 0 + 0 + + 0 + 0 + 0 + + 3 + 1 + + 1 + 1 + 1 + + + + + 2 + 2 + http://www.roblox.com/asset?id=419771410 + 5 + Mesh + + 0 + 0 + 0 + + + 1 + 1 + 1 + + + + 1 + 1 + 1 + + + + + + + 0 + 0.5 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + LeftKneeRigAttachment + + + + + + 0 + -0.5 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + LeftAnkleRigAttachment + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + 194 + + -7.05024147 + 1.87549615 + 23.5179558 + -0.550465405 + 0.000111036104 + 0.834857941 + 5.09723496e-022 + 1 + -0.000132999994 + -0.834857941 + -7.32118933e-005 + -0.550465405 + + false + + false + + 0.5 + 0.300000012 + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + false + 256 + LeftUpperLeg + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + -0.5 + 0.5 + 0 + 0 + 0 + + 0 + 0 + 0 + + 3 + 1 + + 1 + 0.749599993 + 1 + + + + + 2 + 2 + http://www.roblox.com/asset?id=419771598 + 5 + Mesh + + 0 + 0 + 0 + + + 1 + 1 + 1 + + + + 1 + 1 + 1 + + + + + + + 0 + 0.374799997 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + LeftHipRigAttachment + + + + + + 0 + -0.374799997 + 0 + 1 + 0 + -0 + 0 + 1 + 0.000132999994 + 0 + -0.000132999994 + 1 + + LeftKneeRigAttachment + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + 194 + + -8.15377235 + 2.92800188 + 21.8442059 + -0.550465047 + -1.49011612e-008 + 0.834857941 + 0 + 0.999999344 + -1.68849151e-021 + -0.834857345 + 0 + -0.550465405 + + false + + false + + 0.5 + 0.300000012 + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + false + 256 + RightLowerArm + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + -0.5 + 0.5 + 0 + 0 + 0 + + 0 + 0 + 0 + + 3 + 1 + + 1 + 0.805000007 + 1 + + + + + 2 + 2 + http://www.roblox.com/asset?id=419772046 + 5 + Mesh + + 0 + 0 + 0 + + + 1 + 1 + 1 + + + + 1 + 1 + 1 + + + + + + + 0 + 0.402500004 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + RightElbowRigAttachment + + + + + + 0 + -0.402500004 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + RightWristRigAttachment + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + 194 + + -8.08495903 + 3.69051075 + 21.9485722 + -0.520007074 + 0.180567518 + 0.834857941 + 0.32802701 + 0.944667995 + -1.68849151e-021 + -0.788663566 + 0.273855954 + -0.550465405 + + false + + false + + 0.5 + 0.300000012 + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + false + 256 + RightUpperArm + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + -0.5 + 0.5 + 0 + 0 + 0 + + 0 + 0 + 0 + + 3 + 1 + + 1 + 0.762190998 + 1 + + + + + 2 + 2 + http://www.roblox.com/asset?id=419771918 + 5 + Mesh + + 0 + 0 + 0 + + + 1 + 1 + 1 + + + + 1 + 1 + 1 + + + + + + + 0 + 0.381096005 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + RightShoulderRigAttachment + + + + + + 0 + -0.381096005 + 0 + 0.944668353 + 0.328027129 + -0 + -0.328027129 + 0.944668353 + 0 + 0 + 0 + 1.00000012 + + RightElbowRigAttachment + + + + + + 0.328592002 + 0.534713984 + 0 + 0.944668353 + 0.328027129 + -0 + -0.328027129 + 0.944668353 + 0 + 0 + 0 + 1.00000012 + + RightShoulderAttachment + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + 194 + + -7.60585737 + 0.250096202 + 22.6749954 + -0.550465405 + -0.000114375536 + 0.834857941 + 5.09723496e-022 + 1 + 0.000136999995 + -0.834857941 + 7.54137582e-005 + -0.550465405 + + false + + false + + 0.5 + 0.300000012 + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + false + 256 + RightFoot + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + -0.5 + 0.5 + 0 + 0 + 0 + + 0 + 0 + 0 + + 3 + 1 + + 1 + 0.5 + 1 + + + + + 2 + 2 + http://www.roblox.com/asset?id=419775789 + 5 + Mesh + + 0 + 0 + 0 + + + 1 + 1 + 1 + + + + 1 + 1 + 1 + + + + + + + 0 + 0.25 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + RightAnkleRigAttachment + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + 194 + + -8.15377235 + 2.32425237 + 21.8442059 + -0.550465047 + -1.49011612e-008 + 0.834857941 + 0 + 0.999999344 + -1.68849151e-021 + -0.834857345 + 0 + -0.550465405 + + false + + false + + 0.5 + 0.300000012 + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + false + 256 + RightHand + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + -0.5 + 0.5 + 0 + 0 + 0 + + 0 + 0 + 0 + + 3 + 1 + + 1 + 0.402500004 + 1 + + + + + 2 + 2 + http://www.roblox.com/asset?id=419774811 + 5 + Mesh + + 0 + 0 + 0 + + + 1 + 1 + 1 + + + + 1 + 1 + 1 + + + + + + + 0 + 0.201250002 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + RightWristRigAttachment + + + + + + 0.00999999978 + -0.0255210008 + 0 + 1 + 0 + -0 + 0 + 0 + 1 + 0 + -1 + 0 + + RightGripAttachment + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + 194 + + -7.6059432 + 1.0000962 + 22.6750526 + -0.550465405 + -0.000114375536 + 0.834857941 + 5.09723496e-022 + 1 + 0.000136999995 + -0.834857941 + 7.54137582e-005 + -0.550465405 + + false + + false + + 0.5 + 0.300000012 + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + false + 256 + RightLowerLeg + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + -0.5 + 0.5 + 0 + 0 + 0 + + 0 + 0 + 0 + + 3 + 1 + + 1 + 1 + 1 + + + + + 2 + 2 + http://www.roblox.com/asset?id=419775579 + 5 + Mesh + + 0 + 0 + 0 + + + 1 + 1 + 1 + + + + 1 + 1 + 1 + + + + + + + 0 + 0.5 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + RightKneeRigAttachment + + + + + + 0 + -0.5 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + RightAnkleRigAttachment + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + 194 + + -7.60597515 + 1.8750962 + 22.6750736 + -0.550465405 + 6.67886343e-005 + 0.834857941 + 5.09723496e-022 + 1 + -7.9999998e-005 + -0.834857941 + -4.40372314e-005 + -0.550465405 + + false + + false + + 0.5 + 0.300000012 + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + false + 256 + RightUpperLeg + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + -0.5 + 0.5 + 0 + 0 + 0 + + 0 + 0 + 0 + + 3 + 1 + + 1 + 0.75 + 1 + + + + + 2 + 2 + http://www.roblox.com/asset?id=419775117 + 5 + Mesh + + 0 + 0 + 0 + + + 1 + 1 + 1 + + + + 1 + 1 + 1 + + + + + + + 0 + 0.375 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + RightHipRigAttachment + + + + + + 0 + -0.375 + 0 + 1 + 0 + -0 + 0 + 1 + 0.000216999993 + 0 + -0.000216999993 + 1 + + RightKneeRigAttachment + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + 194 + + -7.32807493 + 3.03050208 + 23.0964928 + -0.550465405 + 1.69023281e-021 + 0.834857941 + 5.09723496e-022 + 1 + -1.68849151e-021 + -0.834857941 + -5.03909301e-022 + -0.550465405 + + true + + false + + 0.5 + 0.300000012 + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + false + 256 + UpperTorso + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + -0.5 + 0.5 + 0 + 0 + 0 + + 0 + 0 + 0 + + 3 + 1 + + 1 + 1 + 1 + + + + + 2 + 2 + http://www.roblox.com/asset?id=419776040 + 5 + Mesh + + 0 + 0 + 0 + + + 1 + 1 + 1 + + + + 1 + 1 + 1 + + + + + + + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + WaistRigAttachment + + + + + + 0 + 1.26949596 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + NeckRigAttachment + + + + + + -1.24989104 + 1.01987302 + 0 + 0.944806099 + 0.327630043 + -0 + -0.327630043 + 0.944806099 + 0 + 0 + 0 + 1 + + LeftShoulderRigAttachment + + + + + + 1.24997997 + 1.02001798 + 0 + 0.944668353 + -0.328027129 + 0 + 0.328027129 + 0.944668353 + -0 + 0 + 0 + 1.00000012 + + RightShoulderRigAttachment + + + + + + 0 + 1.25758302 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + NeckAttachment + + + + + + 0 + 0.239388004 + 0.538740993 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + BodyBackAttachment + + + + + + 0 + 0.239388004 + -0.483112991 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + BodyFrontAttachment + + + + + + 1 + 1.26776195 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + RightCollarAttachment + + + + + + -1 + 1.26776195 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + LeftCollarAttachment + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + 194 + + -7.32807493 + 2.62639618 + 23.0964928 + -0.550465405 + 1.69023281e-021 + 0.834857941 + 5.09723496e-022 + 1 + -1.68849151e-021 + -0.834857941 + -5.03909301e-022 + -0.550465405 + + true + + false + + 0.5 + 0.300000012 + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + false + 256 + LowerTorso + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + -0.5 + 0.5 + 0 + 0 + 0 + + 0 + 0 + 0 + + 3 + 1 + + 1 + 1 + 1 + + + + + 2 + 2 + http://www.roblox.com/asset?id=419776201 + 5 + Mesh + + 0 + 0 + 0 + + + 1 + 1 + 1 + + + + 1 + 1 + 1 + + + + + + + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + RootRigAttachment + + + + + + 0 + 0.404105991 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + WaistRigAttachment + + + + + + -0.504800022 + -0.376100004 + 0 + 1 + 0 + 0 + 0 + 1 + -0.000132999994 + 0 + 0.000132999994 + 1 + + LeftHipRigAttachment + + + + + + 0.504800022 + -0.376300007 + 0 + 1 + 0 + 0 + 0 + 1 + -7.9999998e-005 + 0 + 7.9999998e-005 + 1 + + RightHipRigAttachment + + + + + + 0 + -0.199870005 + -0.486988008 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + WaistFrontAttachment + + + + + + 0 + -0.199870005 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + WaistCenterAttachment + + + + + + 0 + -0.199870005 + 0.505133986 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + WaistBackAttachment + + + + + + 0 + 100 + 100 + 1.35000002 + 50 + 100 + 89 + Humanoid + 100 + 2 + 16 + + + + Animator + + + + + \ No newline at end of file diff --git a/2016/content/fonts/characterR15_3.rbxm b/2016/content/fonts/characterR15_3.rbxm new file mode 100644 index 0000000..db49255 --- /dev/null +++ b/2016/content/fonts/characterR15_3.rbxm @@ -0,0 +1,2248 @@ + + null + nil + + + + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + Player + RBX9909D4D409004F18956C91B88A6A32A3 + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 4 + 0 + 311 + + -8.03512478 + 2.3499999 + -12.6754742 + 0.790692151 + 1.11743961e-035 + 0.612213969 + -5.6419155e-036 + 1 + -1.0965738e-035 + -0.612213969 + 5.21646317e-036 + 0.790692151 + + true + + false + + 0.5 + 0.300000012 + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + false + 256 + HumanoidRootPart + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + -0.5 + 0.5 + 3 + 0 + 1 + + -1.40129846e-045 + 0 + -1.40129846e-045 + + 1 + 1 + + 2 + 2 + 1 + + + + + + -0 + -0 + -0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + RootRigAttachment + false + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + 311 + + -9.2211628 + 2.14999962 + -11.7571526 + 0.790692151 + 1.11743961e-035 + 0.612213969 + -5.6419155e-036 + 1 + -1.0965738e-035 + -0.612213969 + 5.21646317e-036 + 0.790692151 + + false + 2 + + false + + 0.5 + 0.300000012 + -0.5 + 0.5 + 0 + 0 + + 0.999999762 + 0.299999982 + 0.999999881 + + -0.5 + 0.5 + 0 + 0 + false + 256 + http://www.roblox.com/asset/?id=532219986 + LeftHand + + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + + -0.5 + 0.5 + 0 + 0 + 0 + + -1.40129846e-045 + 0 + -1.40129846e-045 + + + 0.999999762 + 0.299999982 + 0.999999881 + + + + + + 0.000478863716 + 0.149999991 + 5.96046448e-008 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + LeftWristRigAttachment + false + + + + + + -1.1920929e-007 + -0.149999633 + -1.46306121e-007 + 1 + 0 + -0 + 0 + 6.12323426e-017 + 1 + 0 + -1 + 6.12323426e-017 + + LeftGripAttachment + false + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + 311 + + -9.2211628 + 2.84999967 + -11.7571526 + 0.790692151 + 1.11743961e-035 + 0.612213969 + -5.6419155e-036 + 1 + -1.0965738e-035 + -0.612213969 + 5.21646317e-036 + 0.790692151 + + false + 2 + + false + + 0.5 + 0.300000012 + -0.5 + 0.5 + 0 + 0 + + 0.999999762 + 1.20000029 + 1 + + -0.5 + 0.5 + 0 + 0 + false + 256 + http://www.roblox.com/asset/?id=532219991 + LeftLowerArm + + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + + -0.5 + 0.5 + 0 + 0 + 0 + + -1.40129846e-045 + 0 + -1.40129846e-045 + + + 0.999999762 + 1.20000029 + 1 + + + + + + 0.000478506088 + 0.25000003 + 7.64462551e-020 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + LeftElbowRigAttachment + false + + + + + + 0.000478506088 + -0.549999952 + 7.64462551e-020 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + LeftWristRigAttachment + false + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + 311 + + -9.22116375 + 3.29999995 + -11.7571526 + 0.790692151 + 1.11743961e-035 + 0.612213969 + -5.6419155e-036 + 1 + -1.0965738e-035 + -0.612213969 + 5.21646317e-036 + 0.790692151 + + false + 2 + + false + + 0.5 + 0.300000012 + -0.5 + 0.5 + 0 + 0 + + 0.999999762 + 1.40000033 + 0.99999994 + + -0.5 + 0.5 + 0 + 0 + false + 256 + http://www.roblox.com/asset/?id=532219996 + LeftUpperArm + + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + + -0.5 + 0.5 + 0 + 0 + 0 + + -1.40129846e-045 + 0 + -1.40129846e-045 + + + 0.999999762 + 1.40000033 + 0.99999994 + + + + + + 0.250109196 + 0.449999809 + 8.94069672e-008 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + LeftShoulderRigAttachment + false + + + + + + 0.000479102135 + -0.200000167 + 8.94069672e-008 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + LeftElbowRigAttachment + false + + + + + + 2.38418579e-007 + 0.700000286 + -2.70968314e-008 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + LeftShoulderAttachment + false + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + 311 + + -6.84908628 + 2.14999962 + -13.5937948 + 0.790692151 + 1.11743961e-035 + 0.612213969 + -5.6419155e-036 + 1 + -1.0965738e-035 + -0.612213969 + 5.21646317e-036 + 0.790692151 + + false + 2 + + false + + 0.5 + 0.300000012 + -0.5 + 0.5 + 0 + 0 + + 0.999999881 + 0.299999982 + 0.999999881 + + -0.5 + 0.5 + 0 + 0 + false + 256 + http://www.roblox.com/asset/?id=532219997 + RightHand + + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + + -0.5 + 0.5 + 0 + 0 + 0 + + -1.40129846e-045 + 0 + -1.40129846e-045 + + + 0.999999881 + 0.299999982 + 0.999999881 + + + + + + 3.57627869e-007 + 0.149999991 + 5.96046448e-008 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + RightWristRigAttachment + false + + + + + + 0 + -0.149999633 + -1.46306121e-007 + 1 + 0 + -0 + 0 + 6.12323426e-017 + 1 + 0 + -1 + 6.12323426e-017 + + RightGripAttachment + false + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + 311 + + -6.84908628 + 2.84999967 + -13.5937948 + 0.790692151 + 1.11743961e-035 + 0.612213969 + -5.6419155e-036 + 1 + -1.0965738e-035 + -0.612213969 + 5.21646317e-036 + 0.790692151 + + false + 2 + + false + + 0.5 + 0.300000012 + -0.5 + 0.5 + 0 + 0 + + 0.999999762 + 1.20000029 + 1 + + -0.5 + 0.5 + 0 + 0 + false + 256 + http://www.roblox.com/asset/?id=532219999 + RightLowerArm + + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + + -0.5 + 0.5 + 0 + 0 + 0 + + -1.40129846e-045 + 0 + -1.40129846e-045 + + + 0.999999762 + 1.20000029 + 1 + + + + + + 1.1920929e-007 + 0.25000003 + 7.64462551e-020 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + RightElbowRigAttachment + false + + + + + + 1.1920929e-007 + -0.549999952 + -6.86244753e-018 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + RightWristRigAttachment + false + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + 311 + + -6.84908581 + 3.29999995 + -13.5937958 + 0.790692151 + 1.11743961e-035 + 0.612213969 + -5.6419155e-036 + 1 + -1.0965738e-035 + -0.612213969 + 5.21646317e-036 + 0.790692151 + + false + 2 + + false + + 0.5 + 0.300000012 + -0.5 + 0.5 + 0 + 0 + + 0.999999642 + 1.40000033 + 0.99999994 + + -0.5 + 0.5 + 0 + 0 + false + 256 + http://www.roblox.com/asset/?id=532220004 + RightUpperArm + + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + + -0.5 + 0.5 + 0 + 0 + 0 + + -1.40129846e-045 + 0 + -1.40129846e-045 + + + 0.999999642 + 1.40000033 + 0.99999994 + + + + + + -0.250020266 + 0.449999809 + 8.94069672e-008 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + RightShoulderRigAttachment + false + + + + + + -5.96046448e-007 + -0.200000167 + 8.94069672e-008 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + RightElbowRigAttachment + false + + + + + + -9.53674316e-007 + 0.700000286 + -2.70968314e-008 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + RightShoulderAttachment + false + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + 311 + + -8.03512478 + 3.19999981 + -12.6754742 + 0.790692151 + 1.11743961e-035 + 0.612213969 + -5.6419155e-036 + 1 + -1.0965738e-035 + -0.612213969 + 5.21646317e-036 + 0.790692151 + + true + 2 + + false + + 0.5 + 0.300000012 + -0.5 + 0.5 + 0 + 0 + + 2 + 1.60000014 + 1.00000036 + + -0.5 + 0.5 + 0 + 0 + false + 256 + http://www.roblox.com/asset/?id=532220007 + UpperTorso + + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + + -0.5 + 0.5 + 0 + 0 + 0 + + -1.40129846e-045 + 0 + -1.40129846e-045 + + + 2 + 1.60000014 + 1.00000036 + + + + + + -5.96046448e-008 + -0.450000018 + 1.1920929e-007 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + WaistRigAttachment + false + + + + + + -5.96046448e-008 + 0.799999952 + 1.1920929e-007 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + NeckRigAttachment + false + + + + + + -1.24989128 + 0.549999952 + 1.1920929e-007 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + LeftShoulderRigAttachment + false + + + + + + 1.24998045 + 0.549999952 + 1.1920929e-007 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + RightShoulderRigAttachment + false + + + + + + -5.96046448e-008 + -0.200000048 + -0.499999881 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + BodyFrontAttachment + false + + + + + + -5.96046448e-008 + -0.200000048 + 0.5 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + BodyBackAttachment + false + + + + + + -0.999999881 + 0.800000191 + -7.27397378e-008 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + LeftCollarAttachment + false + + + + + + 0.99999994 + 0.799999952 + 4.61295997e-008 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + RightCollarAttachment + false + + + + + + 0.0 + 0.8 + 0.0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + NeckAttachment + false + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + 311 + + -8.43047047 + 0.150000095 + -12.3693666 + 0.790692151 + 1.11743961e-035 + 0.612213969 + -5.6419155e-036 + 1 + -1.0965738e-035 + -0.612213969 + 5.21646317e-036 + 0.790692151 + + false + 2 + + false + + 0.5 + 0.300000012 + -0.5 + 0.5 + 0 + 0 + + 1 + 0.300000191 + 1 + + -0.5 + 0.5 + 0 + 0 + false + 256 + http://www.roblox.com/asset/?id=532220012 + LeftFoot + + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + + -0.5 + 0.5 + 0 + 0 + 0 + + -1.40129846e-045 + 0 + -1.40129846e-045 + + + 1 + 0.300000191 + 1 + + + + + + -2.38418579e-007 + 0.0500025749 + 8.08154482e-007 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + LeftAnkleRigAttachment + false + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + 311 + + -8.43047047 + 0.950000286 + -12.3693666 + 0.790692151 + 1.11743961e-035 + 0.612213969 + -5.6419155e-036 + 1 + -1.0965738e-035 + -0.612213969 + 5.21646317e-036 + 0.790692151 + + false + 2 + + false + + 0.5 + 0.300000012 + -0.5 + 0.5 + 0 + 0 + + 0.99999994 + 1.50000036 + 1.00000012 + + -0.5 + 0.5 + 0 + 0 + false + 256 + http://www.roblox.com/asset/?id=532220017 + LeftLowerLeg + + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + + -0.5 + 0.5 + 0 + 0 + 0 + + -1.40129846e-045 + 0 + -1.40129846e-045 + + + 0.99999994 + 1.50000036 + 1.00000012 + + + + + + -0 + 0.249999642 + -1.78813934e-007 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + LeftKneeRigAttachment + false + + + + + + -1.78813934e-007 + -0.749997616 + 6.29340548e-007 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + LeftAnkleRigAttachment + false + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + 311 + + -8.43047047 + 1.49999988 + -12.3693666 + 0.790692151 + 1.11743961e-035 + 0.612213969 + -5.6419155e-036 + 1 + -1.0965738e-035 + -0.612213969 + 5.21646317e-036 + 0.790692151 + + false + 2 + + false + + 0.5 + 0.300000012 + -0.5 + 0.5 + 0 + 0 + + 1.00000036 + 1.49999976 + 0.999999881 + + -0.5 + 0.5 + 0 + 0 + false + 256 + http://www.roblox.com/asset/?id=532220018 + LeftUpperLeg + + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + + -0.5 + 0.5 + 0 + 0 + 0 + + -1.40129846e-045 + 0 + -1.40129846e-045 + + + 1.00000036 + 1.49999976 + 0.999999881 + + + + + + 5.96046448e-008 + 0.5 + -1.63912773e-007 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + LeftHipRigAttachment + false + + + + + + 5.96046448e-008 + -0.299999952 + -1.63912773e-007 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + LeftKneeRigAttachment + false + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + 311 + + -7.63977861 + 0.150000095 + -12.9815807 + 0.790692151 + 1.11743961e-035 + 0.612213969 + -5.6419155e-036 + 1 + -1.0965738e-035 + -0.612213969 + 5.21646317e-036 + 0.790692151 + + false + 2 + + false + + 0.5 + 0.300000012 + -0.5 + 0.5 + 0 + 0 + + 0.99999994 + 0.300000191 + 1 + + -0.5 + 0.5 + 0 + 0 + false + 256 + http://www.roblox.com/asset/?id=532220020 + RightFoot + + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + + -0.5 + 0.5 + 0 + 0 + 0 + + -1.40129846e-045 + 0 + -1.40129846e-045 + + + 0.99999994 + 0.300000191 + 1 + + + + + + -0 + 0.0499997139 + 9.84534345e-005 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + RightAnkleRigAttachment + false + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + 311 + + -7.63977861 + 0.950000286 + -12.9815807 + 0.790692151 + 1.11743961e-035 + 0.612213969 + -5.6419155e-036 + 1 + -1.0965738e-035 + -0.612213969 + 5.21646317e-036 + 0.790692151 + + false + 2 + + false + + 0.5 + 0.300000012 + -0.5 + 0.5 + 0 + 0 + + 0.99999994 + 1.50000036 + 1.00000012 + + -0.5 + 0.5 + 0 + 0 + false + 256 + http://www.roblox.com/asset/?id=532220027 + RightLowerLeg + + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + + -0.5 + 0.5 + 0 + 0 + 0 + + -1.40129846e-045 + 0 + -1.40129846e-045 + + + 0.99999994 + 1.50000036 + 1.00000012 + + + + + + -0 + 0.249999642 + 4.35260044e-005 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + RightKneeRigAttachment + false + + + + + + -0 + -0.750000477 + 9.82746205e-005 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + RightAnkleRigAttachment + false + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + 311 + + -7.63977861 + 1.49999988 + -12.9815807 + 0.790692151 + 1.11743961e-035 + 0.612213969 + -5.6419155e-036 + 1 + -1.0965738e-035 + -0.612213969 + 5.21646317e-036 + 0.790692151 + + false + 2 + + false + + 0.5 + 0.300000012 + -0.5 + 0.5 + 0 + 0 + + 1.00000048 + 1.49999976 + 0.999999881 + + -0.5 + 0.5 + 0 + 0 + false + 256 + http://www.roblox.com/asset/?id=532220031 + RightUpperLeg + + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + + -0.5 + 0.5 + 0 + 0 + 0 + + -1.40129846e-045 + 0 + -1.40129846e-045 + + + 1.00000048 + 1.49999976 + 0.999999881 + + + + + + -0 + 0.5 + -1.04308128e-007 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + RightHipRigAttachment + false + + + + + + -0 + -0.299999952 + 4.36005103e-005 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + RightKneeRigAttachment + false + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + 311 + + -8.03512478 + 2.19999981 + -12.6754742 + 0.790692151 + 1.11743961e-035 + 0.612213969 + -5.6419155e-036 + 1 + -1.0965738e-035 + -0.612213969 + 5.21646317e-036 + 0.790692151 + + true + 2 + + false + + 0.5 + 0.300000012 + -0.5 + 0.5 + 0 + 0 + + 1.99999976 + 0.399999976 + 1.00000012 + + -0.5 + 0.5 + 0 + 0 + false + 256 + http://www.roblox.com/asset/?id=532220036 + LowerTorso + + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + + -0.5 + 0.5 + 0 + 0 + 0 + + -1.40129846e-045 + 0 + -1.40129846e-045 + + + 1.99999976 + 0.399999976 + 1.00000012 + + + + + + -1.1920929e-007 + 0.150000036 + -0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + RootRigAttachment + false + + + + + + -1.1920929e-007 + 0.550000072 + 7.64462551e-020 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + WaistRigAttachment + false + + + + + + -0.500000119 + -0.199999958 + -0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + LeftHipRigAttachment + false + + + + + + 0.499999881 + -0.199999958 + -0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + RightHipRigAttachment + false + + + + + + 0.0 + -0.2 + 0.0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + WaistCenterAttachment + false + + + + + + 0.0 + -0.2 + -0.5 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + WaistFrontAttachment + false + + + + + + 0.0 + -0.2 + 0.5 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + WaistBackAttachment + false + + + + + + 0 + 100 + 100 + 1.35000002 + 50 + 100 + 89 + Humanoid + 100 + 2 + 1 + 16 + + + + Animator + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + 311 + + -8.03495789 + 4.5 + -12.6752586 + 0.790692151 + 1.11743961e-035 + 0.612213969 + -5.6419155e-036 + 1 + -1.0965738e-035 + -0.612213969 + 5.21646317e-036 + 0.790692151 + + true + + false + + 0.5 + 0.300000012 + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + false + 256 + Head + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + -0.5 + 0.5 + 0 + 0 + 0 + + -1.40129846e-045 + 0 + -1.40129846e-045 + + 1 + 1 + + 2 + 1 + 1 + + + + + 2 + 2 + + 0 + Mesh + + 0 + 0 + 0 + + + 1.25 + 1.25 + 1.25 + + + + 1 + 1 + 1 + + + + + + + 3.93568822e-009 + 0 + -0.000272244215 + 1 + 7.87137555e-009 + 3.02998127e-015 + -7.87137555e-009 + 1 + -4.1444258e-016 + -3.02998127e-015 + 4.14442554e-016 + 1 + + FaceCenterAttachment + false + + + + + + 3.93568866e-009 + 0 + -0.600272298 + 1 + 7.87137555e-009 + 3.02998127e-015 + -7.87137555e-009 + 1 + -4.1444258e-016 + -3.02998127e-015 + 4.14442554e-016 + 1 + + FaceFrontAttachment + false + + + + + + 8.65851391e-009 + 0.599999905 + -0.000272244215 + 1 + 7.87137555e-009 + 3.02998127e-015 + -7.87137555e-009 + 1 + -4.1444258e-016 + -3.02998127e-015 + 4.14442554e-016 + 1 + + HairAttachment + false + + + + + + 8.65851391e-009 + 0.599999905 + -0.000272244215 + 1 + 7.87137555e-009 + 3.02998127e-015 + -7.87137555e-009 + 1 + -4.1444258e-016 + -3.02998127e-015 + 4.14442554e-016 + 1 + + HatAttachment + false + + + + + + -0 + -0.500000119 + -0.000272244215 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + NeckRigAttachment + false + + + + + 5 + face + rbxasset://textures/face.png + 0 + + + + + \ No newline at end of file diff --git a/2016/content/fonts/characterSound.rbxmx b/2016/content/fonts/characterSound.rbxmx new file mode 100644 index 0000000..792a4cf --- /dev/null +++ b/2016/content/fonts/characterSound.rbxmx @@ -0,0 +1,366 @@ + + null + nil + + + false + + Sound + + + + + + false + + LocalSound + + 0.5 then + Util.Resume(sound) + setSoundInPlayingLoopedSounds(sound) + else + stopPlayingLoopedSoundsExcept() + end + end; + + [Enum.HumanoidStateType.Swimming] = function() + if activeState ~= Enum.HumanoidStateType.Swimming and Util.VerticalSpeed(Head) > 0.1 then + local splashSound = Sounds[SFX.Splash] + splashSound.Volume = Util.Clamp( + Util.YForLineGivenXAndTwoPts( + Util.VerticalSpeed(Head), + 100, 0.28, + 350, 1), + 0,1) + Util.Play(splashSound) + end + + do + local sound = Sounds[SFX.Swimming] + stopPlayingLoopedSoundsExcept(sound) + Util.Resume(sound) + setSoundInPlayingLoopedSounds(sound) + end + end; + + [Enum.HumanoidStateType.Climbing] = function() + local sound = Sounds[SFX.Climbing] + if Util.VerticalSpeed(Head) > 0.1 then + Util.Resume(sound) + stopPlayingLoopedSoundsExcept(sound) + else + stopPlayingLoopedSoundsExcept() + end + setSoundInPlayingLoopedSounds(sound) + end; + + [Enum.HumanoidStateType.Jumping] = function() + if activeState == Enum.HumanoidStateType.Jumping then + return + end + stopPlayingLoopedSoundsExcept() + local sound = Sounds[SFX.Jumping] + Util.Play(sound) + end; + + [Enum.HumanoidStateType.GettingUp] = function() + stopPlayingLoopedSoundsExcept() + local sound = Sounds[SFX.GettingUp] + Util.Play(sound) + end; + + [Enum.HumanoidStateType.Freefall] = function() + if activeState == Enum.HumanoidStateType.Freefall then + return + end + local sound = Sounds[SFX.FreeFalling] + sound.Volume = 0 + stopPlayingLoopedSoundsExcept() + end; + + [Enum.HumanoidStateType.FallingDown] = function() + stopPlayingLoopedSoundsExcept() + end; + + [Enum.HumanoidStateType.Landed] = function() + stopPlayingLoopedSoundsExcept() + if Util.VerticalSpeed(Head) > 75 then + local landingSound = Sounds[SFX.Landing] + landingSound.Volume = Util.Clamp( + Util.YForLineGivenXAndTwoPts( + Util.VerticalSpeed(Head), + 50, 0, + 100, 1), + 0,1) + Util.Play(landingSound) + end + end; + + [Enum.HumanoidStateType.Seated] = function() + stopPlayingLoopedSoundsExcept() + end; + } + + -- Handle state event fired or OnChange fired + function stateUpdated(state) + if stateUpdateHandler[state] ~= nil then + stateUpdateHandler[state]() + end + activeState = state + end + + Humanoid.Died:connect( function() stateUpdated(Enum.HumanoidStateType.Dead) end) + Humanoid.Running:connect( function() stateUpdated(Enum.HumanoidStateType.Running) end) + Humanoid.Swimming:connect( function() stateUpdated(Enum.HumanoidStateType.Swimming) end) + Humanoid.Climbing:connect( function() stateUpdated(Enum.HumanoidStateType.Climbing) end) + Humanoid.Jumping:connect( function() stateUpdated(Enum.HumanoidStateType.Jumping) end) + Humanoid.GettingUp:connect( function() stateUpdated(Enum.HumanoidStateType.GettingUp) end) + Humanoid.FreeFalling:connect( function() stateUpdated(Enum.HumanoidStateType.Freefall) end) + Humanoid.FallingDown:connect( function() stateUpdated(Enum.HumanoidStateType.FallingDown) end) + + -- required for proper handling of Landed event + Humanoid.StateChanged:connect(function(old, new) + stateUpdated(new) + end) + + + function onUpdate(stepDeltaSeconds, tickSpeedSeconds) + local stepScale = stepDeltaSeconds / tickSpeedSeconds + do + local sound = Sounds[SFX.FreeFalling] + if activeState == Enum.HumanoidStateType.Freefall then + if Head.Velocity.Y < 0 and Util.VerticalSpeed(Head) > 75 then + Util.Resume(sound) + + --Volume takes 1.1 seconds to go from volume 0 to 1 + local ANIMATION_LENGTH_SECONDS = 1.1 + + local normalizedIncrement = tickSpeedSeconds / ANIMATION_LENGTH_SECONDS + sound.Volume = Util.Clamp(sound.Volume + normalizedIncrement * stepScale, 0, 1) + else + sound.Volume = 0 + end + else + Util.Pause(sound) + end + end + + do + local sound = Sounds[SFX.Running] + if activeState == Enum.HumanoidStateType.Running then + if Util.HorizontalSpeed(Head) < 0.5 then + Util.Pause(sound) + end + end + end + end + + local lastTick = tick() + local TICK_SPEED_SECONDS = 0.25 + while true do + onUpdate(tick() - lastTick,TICK_SPEED_SECONDS) + lastTick = tick() + wait(TICK_SPEED_SECONDS) + end +end +]]> + + + + \ No newline at end of file diff --git a/2016/content/fonts/comics.fnt b/2016/content/fonts/comics.fnt new file mode 100644 index 0000000..6b71c7e Binary files /dev/null and b/2016/content/fonts/comics.fnt differ diff --git a/2016/content/fonts/diogenes.fnt b/2016/content/fonts/diogenes.fnt new file mode 100644 index 0000000..c43fded --- /dev/null +++ b/2016/content/fonts/diogenes.fnt @@ -0,0 +1,356 @@ +a 6> +4=:90 +4;499, +4; & +4&=:90 +4&=:90& +4&&=:90 +4&&=:90& +4&&><&&0' +704&!<49 +7 !!3 6>0' +7 !!=4<' +7 !!&0- +7 !!&06& +7 !!&0>& +6=<;> +6<'690?0'> +69 +6:6>{ +6:6>& +6:6>& 6> +6:6>& 6>01 +6:6>& 6>0' +6:6>& 6><;2 +6:6>& 6>& +6:> +6:;1:8 +6:;1:8& +6::!0' +6 8 +6 880' +6 88<;2 +6 8& +6 8&=:! +6 8&=:! +6 ;<9<;2 & +6 ;<99<;2 & +6 ;;<9<;2 & +6 ;! +6 ;!9<6> +6 ;!9<6>0' +6 ;!9<6><;2 +6 ;!& +6,70'3 6 +6,70'3 6> +6,70'3 6>01 +6,70'3 6>0' +6,70'3 6>0'& +6,70'3 6><;2 +1<6> +1<6>& +1<>0 +1<91: +1<91: +1<91:& +1<91:& +1<%&=0 +0?46 94!0 +0?46 94!01 +0?46 94!0& +0?46 94!<;2 +0?46 94!<;2& +0?46 94!<:; +30' +3<;2 +342 +3420! +3422 +34220! +3422<;2 +3422 +36><;2 +3094!<: +3094!<: +30994!<: +3<;20'74;2 +3<;20'3 6> +3<;20'3 6>01 +3<;20'3 6>0' +3<;20'3 6>0'& +3<;20'3 6><;2 +3<;20'3 6>& +3<&!3 6> +3<&!3 6>01 +3<&!3 6>0' +3<&!3 6>0'& +3<&!3 6><;2 +3<&!3 6><;2& +3<&!3 6>& +3:6><;2 +3 6> +3 6>t +3 6>0 +3 6>01 +3 6>0; +3 6>0' +3 6>0'& +3 6><; +3 6><;2 +3 6><;2& +3 6>>>>>>>>>>>>>>>>> +3 6>80 +3 6>& +3 6>!4'1 +3 6>,: +3 > +3 >0' +3 ><; +3 ><;2 +3 >> +3 >& +3 '7 '20' +24;274;2 +24;274;201 +24;274;2& +24, +24,&0- +24/:;24& +24/:;20'& +2:;41& +2::> +=4'16:'0&0- +=4'1:; +=:8: +=::>0' +=:';<0&! +=:';, +=:!&0- += 8% +?46>4&& +?46><;2:33 +?46>:33 +?46>x:33 +?4% +?0'>x:33 +?0" +?<&8 +?<>0 +>>> +>:6> +>:;1 8 +>:;1 8& +> 8 +> 880' +> 88<;2 +> 8& +> ;<9<;2 & +90&7<4; +90&7: +9 &!<;2 +80'10 +8:90&! +8:!=43 6> +8:!=43 6> +8:!=43 6>4 +8:!=43 6>4 +8:!=43 6>4& +8:!=43 6>4& +8:!=43 6>4/ +8:!=43 6>4/ +8:!=43 6>01 +8:!=43 6>01 +8:!=43 6>0' +8:!=43 6>0' +8:!=43 6>0'& +8:!=43 6>0'& +8:!=43 6><; +8:!=43 6><; +8:!=43 6><;2 +8:!=43 6><;2 +8:!=43 6><;2& +8:!=43 6><;2& +8:!=43 6>& +8:!=43 6>& +8:!=0'3 6> +8:!=0'3 6> +8:!=0'3 6>01 +8:!=0'3 6>0' +8:!=0'3 6>0' +8:!=0'3 6>0'& +8:!=0'3 6>0'& +8:!=0'3 6><; +8:!=0'3 6><; +8:!=0'3 6><;2 +8:!=0'3 6><;2 +8:!=0'3 6><;2& +8:!=0'3 6><;2& +8:!=0'3 6>& +8:!=0'3 6>& +;4/< +;<20' +;<224 +;<224& +;<220' +;<220' +;<220'& +;<220'& +:'24&<8 +:'24&<8& +:'24&8 +:'24&8& +%06>0' +%0;<& +%=:;0&0- +%= >01 +%= ><;2 +%= >>01 +%= >><;2 +%= > +%= >& +%= $ +%<8% +%<&&:33 +%:'; +%:';: +%:';:2'4%=, +%:';:& +%'<6> +%'<6>& +%':&! +& 6> +!'48% +!"4! +#42<;4 +#<7'4!:' +"4;2 +"4;> +"4;>0' +"0!746> +"=:'0 +":% + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/2016/content/fonts/fonts.dds b/2016/content/fonts/fonts.dds new file mode 100644 index 0000000..30e4474 Binary files /dev/null and b/2016/content/fonts/fonts.dds differ diff --git a/2016/content/fonts/gamecontrollerdb.txt b/2016/content/fonts/gamecontrollerdb.txt new file mode 100644 index 0000000..dd49836 --- /dev/null +++ b/2016/content/fonts/gamecontrollerdb.txt @@ -0,0 +1,89 @@ +# Windows - DINPUT +8f0e1200000000000000504944564944,Acme,platform:Windows,x:b2,a:b0,b:b1,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2, +341a3608000000000000504944564944,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +ffff0000000000000000504944564944,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +6d0416c2000000000000504944564944,Generic DirectInput Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +6d0419c2000000000000504944564944,Logitech F710 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +88880803000000000000504944564944,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b9,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b0,y:b3,platform:Windows, +4c056802000000000000504944564944,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Windows, +25090500000000000000504944564944,PS3 DualShock,a:b2,b:b1,back:b9,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b0,y:b3,platform:Windows, +4c05c405000000000000504944564944,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +6d0418c2000000000000504944564944,Logitech RumblePad 2 USB,platform:Windows,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3, +36280100000000000000504944564944,OUYA Controller,platform:Windows,a:b0,b:b3,y:b2,x:b1,start:b14,guide:b15,leftstick:b6,rightstick:b7,leftshoulder:b4,rightshoulder:b5,dpup:b8,dpleft:b10,dpdown:b9,dpright:b11,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b12,righttrigger:b13, +4f0400b3000000000000504944564944,Thrustmaster Firestorm Dual Power,a:b0,b:b2,y:b3,x:b1,start:b10,guide:b8,back:b9,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Windows, +00f00300000000000000504944564944,RetroUSB.com RetroPad,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Windows, +00f0f100000000000000504944564944,RetroUSB.com Super RetroPort,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Windows, +28040140000000000000504944564944,GamePad Pro USB,platform:Windows,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,lefttrigger:b6,righttrigger:b7, +ff113133000000000000504944564944,SVEN X-PAD,platform:Windows,a:b2,b:b3,y:b1,x:b0,start:b5,back:b4,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b8,righttrigger:b9, +8f0e0300000000000000504944564944,Piranha xtreme,platform:Windows,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2, +8f0e0d31000000000000504944564944,Multilaser JS071 USB,platform:Windows,a:b1,b:b2,y:b3,x:b0,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7, +10080300000000000000504944564944,PS2 USB,platform:Windows,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a4,righty:a2,lefttrigger:b4,righttrigger:b5, +79000600000000000000504944564944,G-Shark GS-GP702,a:b2,b:b1,x:b3,y:b0,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b6,righttrigger:b7,platform:Windows, +4b12014d000000000000504944564944,NYKO AIRFLO,a:b0,b:b1,x:b2,y:b3,back:b8,guide:b10,start:b9,leftstick:a0,rightstick:a2,leftshoulder:a3,rightshoulder:b5,dpup:h0.1,dpdown:h0.0,dpleft:h0.8,dpright:h0.2,leftx:h0.6,lefty:h0.12,rightx:h0.9,righty:h0.4,lefttrigger:b6,righttrigger:b7,platform:Windows, +d6206dca000000000000504944564944,PowerA Pro Ex,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.0,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows, +a3060cff000000000000504944564944,Saitek P2500,a:b2,b:b3,y:b1,x:b0,start:b4,guide:b10,back:b5,leftstick:b8,rightstick:b9,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,platform:Windows, +8f0e0300000000000000504944564944,Trust GTX 28,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows, +4f0415b3000000000000504944564944,Thrustmaster Dual Analog 3.2,platform:Windows,x:b1,a:b0,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3, + +# OS X +0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X, +6d0400000000000016c2000000000000,Logitech F310 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +6d0400000000000018c2000000000000,Logitech F510 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +6d040000000000001fc2000000000000,Logitech F710 Gamepad (XInput),a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +6d0400000000000019c2000000000000,Logitech Wireless Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +4c050000000000006802000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Mac OS X, +4c05000000000000c405000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,Platform:Mac OS X, +5e040000000000008e02000000000000,X360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +891600000000000000fd000000000000,Razer Onza Tournament,a:b0,b:b1,y:b3,x:b2,start:b8,guide:b10,back:b9,leftstick:b6,rightstick:b7,leftshoulder:b4,rightshoulder:b5,dpup:b11,dpleft:b13,dpdown:b12,dpright:b14,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Mac OS X, +4f0400000000000000b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,y:b3,x:b1,start:b10,guide:b8,back:b9,leftstick:b11,rightstick:,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Mac OS X, +8f0e0000000000000300000000000000,Piranha xtreme,platform:Mac OS X,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2, +0d0f0000000000004d00000000000000,HORI Gem Pad 3,platform:Mac OS X,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7, +79000000000000000600000000000000,G-Shark GP-702,a:b2,b:b1,x:b3,y:b0,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b6,righttrigger:b7,platform:Mac OS X, +4f0400000000000015b3000000000000,Thrustmaster Dual Analog 3.2,platform:Mac OS X,x:b1,a:b0,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3, + +# Linux +0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +03000000ba2200002010000001010000,Jess Technology USB Game Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux, +030000006d04000019c2000010010000,Logitech Cordless RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000006d0400001dc2000014400000,Logitech F310 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006d0400001ec2000020200000,Logitech F510 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006d04000019c2000011010000,Logitech F710 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000006d0400001fc2000005030000,Logitech F710 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000004c0500006802000011010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux, +030000004c050000c405000011010000,Sony DualShock 4,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:b7,platform:Linux, +03000000de280000ff11000001000000,Valve Streaming Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e0400008e02000014010000,X360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e0400008e02000010010000,X360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e0400001907000000010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000100800000100000010010000,Twin USB PS2 Adapter,a:b2,b:b1,y:b0,x:b3,start:b9,guide:,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5,platform:Linux, +03000000a306000023f6000011010000,Saitek Cyborg V.1 Game Pad,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b6,righttrigger:b7,platform:Linux, +030000004f04000020b3000010010000,Thrustmaster 2 in 1 DT,a:b0,b:b2,y:b3,x:b1,start:b9,guide:,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Linux, +030000004f04000023b3000000010000,Thrustmaster Dual Trigger 3-in-1,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a5, +030000008f0e00000300000010010000,GreenAsia Inc. USB Joystick ,platform:Linux,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2, +030000008f0e00001200000010010000,GreenAsia Inc. USB Joystick ,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2, +030000005e0400009102000007010000,X360 Wireless Controller,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:b13,dpleft:b11,dpdown:b14,dpright:b12,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux, +030000006d04000016c2000010010000,Logitech Logitech Dual Action,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3, +03000000260900008888000000010000,GameCube {WiseGroup USB box},a:b0,b:b2,y:b3,x:b1,start:b7,leftshoulder:,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,rightstick:,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Linux, +030000006d04000011c2000010010000,Logitech WingMan Cordless RumblePad,a:b0,b:b1,y:b4,x:b3,start:b8,guide:b5,back:b2,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b9,righttrigger:b10,platform:Linux, +030000006d04000018c2000010010000,Logitech Logitech RumblePad 2 USB,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3, +05000000d6200000ad0d000001000000,Moga Pro,platform:Linux,a:b0,b:b1,y:b3,x:b2,start:b6,leftstick:b7,rightstick:b8,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a5,righttrigger:a4, +030000004f04000009d0000000010000,Thrustmaster Run N Drive Wireless PS3,platform:Linux,a:b1,b:b2,x:b0,y:b3,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7, +030000004f04000008d0000000010000,Thrustmaster Run N Drive Wireless,platform:Linux,a:b1,b:b2,x:b0,y:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:b7, +0300000000f000000300000000010000,RetroUSB.com RetroPad,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Linux, +0300000000f00000f100000000010000,RetroUSB.com Super RetroPort,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Linux, +030000006f0e00001f01000000010000,Generic X-Box pad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4, +03000000280400000140000000010000,Gravis GamePad Pro USB ,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftx:a0,lefty:a1, +030000005e0400008902000021010000,Microsoft X-Box pad v2 (US),platform:Linux,x:b3,a:b0,b:b1,y:b4,back:b6,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b5,lefttrigger:a2,rightshoulder:b2,righttrigger:a5,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a3,righty:a4, +030000006f0e00001e01000011010000,Rock Candy Gamepad for PS3,platform:Linux,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,guide:b12,leftshoulder:b4,rightshoulder:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2, +03000000250900000500000000010000,Sony PS2 pad with SmartJoy adapter,platform:Linux,a:b2,b:b1,y:b0,x:b3,start:b8,back:b9,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b4,righttrigger:b5, +030000008916000000fd000024010000,Razer Onza Tournament,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:b13,dpleft:b11,dpdown:b14,dpright:b12,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux, +030000004f04000000b3000010010000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,y:b3,x:b1,start:b10,guide:b8,back:b9,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Linux, +03000000ad1b000001f5000033050000,Hori Pad EX Turbo 2,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux, +050000004c050000c405000000010000,PS4 Controller (Bluetooth),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +060000004c0500006802000000010000,PS3 Controller (Bluetooth),a:b14,b:b13,y:b12,x:b15,start:b3,guide:b16,back:b0,leftstick:b1,rightstick:b2,leftshoulder:b10,rightshoulder:b11,dpup:b4,dpleft:b7,dpdown:b6,dpright:b5,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b8,righttrigger:b9,platform:Linux, +03000000790000000600000010010000,DragonRise Inc. Generic USB Joystick ,platform:Linux,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a4, +03000000666600000488000000010000,Super Joy Box 5 Pro,platform:Linux,a:b2,b:b1,x:b3,y:b0,back:b9,start:b8,leftshoulder:b6,rightshoulder:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b4,righttrigger:b5,dpup:b12,dpleft:b15,dpdown:b14,dpright:b13, +05000000362800000100000002010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,platform:Linux,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2, +05000000362800000100000003010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,platform:Linux,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2, +030000008916000001fd000024010000,Razer Onza Classic Edition,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:b11,dpdown:b14,dpright:b12,dpup:b13,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4, +030000005e040000d102000001010000,Microsoft X-Box One pad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4, \ No newline at end of file diff --git a/2016/content/fonts/head.mesh b/2016/content/fonts/head.mesh new file mode 100644 index 0000000..26db950 Binary files /dev/null and b/2016/content/fonts/head.mesh differ diff --git a/2016/content/fonts/headA.mesh b/2016/content/fonts/headA.mesh new file mode 100644 index 0000000..76b2e72 Binary files /dev/null and b/2016/content/fonts/headA.mesh differ diff --git a/2016/content/fonts/headB.mesh b/2016/content/fonts/headB.mesh new file mode 100644 index 0000000..7705a05 Binary files /dev/null and b/2016/content/fonts/headB.mesh differ diff --git a/2016/content/fonts/headC.mesh b/2016/content/fonts/headC.mesh new file mode 100644 index 0000000..4672c59 Binary files /dev/null and b/2016/content/fonts/headC.mesh differ diff --git a/2016/content/fonts/headD.mesh b/2016/content/fonts/headD.mesh new file mode 100644 index 0000000..ff6cd6c Binary files /dev/null and b/2016/content/fonts/headD.mesh differ diff --git a/2016/content/fonts/headE.mesh b/2016/content/fonts/headE.mesh new file mode 100644 index 0000000..d722d29 Binary files /dev/null and b/2016/content/fonts/headE.mesh differ diff --git a/2016/content/fonts/headF.mesh b/2016/content/fonts/headF.mesh new file mode 100644 index 0000000..7c0b311 Binary files /dev/null and b/2016/content/fonts/headF.mesh differ diff --git a/2016/content/fonts/headG.mesh b/2016/content/fonts/headG.mesh new file mode 100644 index 0000000..38db235 Binary files /dev/null and b/2016/content/fonts/headG.mesh differ diff --git a/2016/content/fonts/headH.mesh b/2016/content/fonts/headH.mesh new file mode 100644 index 0000000..fe7365b Binary files /dev/null and b/2016/content/fonts/headH.mesh differ diff --git a/2016/content/fonts/headI.mesh b/2016/content/fonts/headI.mesh new file mode 100644 index 0000000..8ff7ba1 Binary files /dev/null and b/2016/content/fonts/headI.mesh differ diff --git a/2016/content/fonts/headJ.mesh b/2016/content/fonts/headJ.mesh new file mode 100644 index 0000000..ff76d44 Binary files /dev/null and b/2016/content/fonts/headJ.mesh differ diff --git a/2016/content/fonts/headK.mesh b/2016/content/fonts/headK.mesh new file mode 100644 index 0000000..b08bffc Binary files /dev/null and b/2016/content/fonts/headK.mesh differ diff --git a/2016/content/fonts/headL.mesh b/2016/content/fonts/headL.mesh new file mode 100644 index 0000000..645531b Binary files /dev/null and b/2016/content/fonts/headL.mesh differ diff --git a/2016/content/fonts/headM.mesh b/2016/content/fonts/headM.mesh new file mode 100644 index 0000000..ba144e8 Binary files /dev/null and b/2016/content/fonts/headM.mesh differ diff --git a/2016/content/fonts/headN.mesh b/2016/content/fonts/headN.mesh new file mode 100644 index 0000000..6fc4620 Binary files /dev/null and b/2016/content/fonts/headN.mesh differ diff --git a/2016/content/fonts/headO.mesh b/2016/content/fonts/headO.mesh new file mode 100644 index 0000000..a41f85f Binary files /dev/null and b/2016/content/fonts/headO.mesh differ diff --git a/2016/content/fonts/headP.mesh b/2016/content/fonts/headP.mesh new file mode 100644 index 0000000..cdb1647 Binary files /dev/null and b/2016/content/fonts/headP.mesh differ diff --git a/2016/content/fonts/humanoidAnimate.rbxm b/2016/content/fonts/humanoidAnimate.rbxm new file mode 100644 index 0000000..7a59cb9 --- /dev/null +++ b/2016/content/fonts/humanoidAnimate.rbxm @@ -0,0 +1,296 @@ + + null + nil + + + false + + Animate + -- Now with exciting TeamColors HACK! + +function waitForChild(parent, childName) + local child = parent:findFirstChild(childName) + if child then return child end + while true do + child = parent.ChildAdded:wait() + if child.Name==childName then return child end + end +end + +-- TEAM COLORS + + +function onTeamChanged(player) + + wait(1) + + local char = player.Character + if char == nil then return end + + if player.Neutral then + -- Replacing the current BodyColor object will force a reset + local old = char:findFirstChild("Body Colors") + if not old then return end + old:clone().Parent = char + old.Parent = nil + else + local head = char:findFirstChild("Head") + local torso = char:findFirstChild("Torso") + local left_arm = char:findFirstChild("Left Arm") + local right_arm = char:findFirstChild("Right Arm") + local left_leg = char:findFirstChild("Left Leg") + local right_leg = char:findFirstChild("Right Leg") + + if head then head.BrickColor = BrickColor.new(24) end + if torso then torso.BrickColor = player.TeamColor end + if left_arm then left_arm.BrickColor = BrickColor.new(26) end + if right_arm then right_arm.BrickColor = BrickColor.new(26) end + if left_leg then left_leg.BrickColor = BrickColor.new(26) end + if right_leg then right_leg.BrickColor = BrickColor.new(26) end + end +end + +function onPlayerPropChanged(property, player) + if property == "Character" then + onTeamChanged(player) + end + if property== "TeamColor" or property == "Neutral" then + onTeamChanged(player) + end +end + + +local cPlayer = game.Players:GetPlayerFromCharacter(script.Parent) +cPlayer.Changed:connect(function(property) onPlayerPropChanged(property, cPlayer) end ) +onTeamChanged(cPlayer) + + +-- ANIMATION + +-- declarations + +local Figure = script.Parent +local Torso = waitForChild(Figure, "Torso") +local RightShoulder = waitForChild(Torso, "Right Shoulder") +local LeftShoulder = waitForChild(Torso, "Left Shoulder") +local RightHip = waitForChild(Torso, "Right Hip") +local LeftHip = waitForChild(Torso, "Left Hip") +local Neck = waitForChild(Torso, "Neck") +local Humanoid = waitForChild(Figure, "Humanoid") +local pose = "Standing" + +local toolAnim = "None" +local toolAnimTime = 0 + +-- functions + +function onRunning(speed) + if speed>0 then + pose = "Running" + else + pose = "Standing" + end +end + +function onDied() + pose = "Dead" +end + +function onJumping() + pose = "Jumping" +end + +function onClimbing() + pose = "Climbing" +end + +function onGettingUp() + pose = "GettingUp" +end + +function onFreeFall() + pose = "FreeFall" +end + +function onFallingDown() + pose = "FallingDown" +end + +function onSeated() + pose = "Seated" +end + +function onPlatformStanding() + pose = "PlatformStanding" +end + +function moveJump() + RightShoulder.MaxVelocity = 0.5 + LeftShoulder.MaxVelocity = 0.5 + RightShoulder:SetDesiredAngle(3.14) + LeftShoulder:SetDesiredAngle(-3.14) + RightHip:SetDesiredAngle(0) + LeftHip:SetDesiredAngle(0) +end + + +-- same as jump for now + +function moveFreeFall() + RightShoulder.MaxVelocity = 0.5 + LeftShoulder.MaxVelocity = 0.5 + RightShoulder:SetDesiredAngle(3.14) + LeftShoulder:SetDesiredAngle(-3.14) + RightHip:SetDesiredAngle(0) + LeftHip:SetDesiredAngle(0) +end + +function moveSit() + RightShoulder.MaxVelocity = 0.15 + LeftShoulder.MaxVelocity = 0.15 + RightShoulder:SetDesiredAngle(3.14 /2) + LeftShoulder:SetDesiredAngle(-3.14 /2) + RightHip:SetDesiredAngle(3.14 /2) + LeftHip:SetDesiredAngle(-3.14 /2) +end + +function getTool() + for _, kid in ipairs(Figure:GetChildren()) do + if kid.className == "Tool" then return kid end + end + return nil +end + +function getToolAnim(tool) + for _, c in ipairs(tool:GetChildren()) do + if c.Name == "toolanim" and c.className == "StringValue" then + return c + end + end + return nil +end + +function animateTool() + + if (toolAnim == "None") then + RightShoulder:SetDesiredAngle(1.57) + return + end + + if (toolAnim == "Slash") then + RightShoulder.MaxVelocity = 0.5 + RightShoulder:SetDesiredAngle(0) + return + end + + if (toolAnim == "Lunge") then + RightShoulder.MaxVelocity = 0.5 + LeftShoulder.MaxVelocity = 0.5 + RightHip.MaxVelocity = 0.5 + LeftHip.MaxVelocity = 0.5 + RightShoulder:SetDesiredAngle(1.57) + LeftShoulder:SetDesiredAngle(1.0) + RightHip:SetDesiredAngle(1.57) + LeftHip:SetDesiredAngle(1.0) + return + end +end + +function move(time) + local amplitude + local frequency + + if (pose == "Jumping") then + moveJump() + return + end + + if (pose == "FreeFall") then + moveFreeFall() + return + end + + if (pose == "Seated") then + moveSit() + return + end + + local climbFudge = 0 + + if (pose == "Running") then + RightShoulder.MaxVelocity = 0.15 + LeftShoulder.MaxVelocity = 0.15 + amplitude = 1 + frequency = 9 + elseif (pose == "Climbing") then + RightShoulder.MaxVelocity = 0.5 + LeftShoulder.MaxVelocity = 0.5 + amplitude = 1 + frequency = 9 + climbFudge = 3.14 + else + amplitude = 0.1 + frequency = 1 + end + + desiredAngle = amplitude * math.sin(time*frequency) + + RightShoulder:SetDesiredAngle(desiredAngle + climbFudge) + LeftShoulder:SetDesiredAngle(desiredAngle - climbFudge) + RightHip:SetDesiredAngle(-desiredAngle) + LeftHip:SetDesiredAngle(-desiredAngle) + + + local tool = getTool() + + if tool then + + animStringValueObject = getToolAnim(tool) + + if animStringValueObject then + toolAnim = animStringValueObject.Value + -- message recieved, delete StringValue + animStringValueObject.Parent = nil + toolAnimTime = time + .3 + end + + if time > toolAnimTime then + toolAnimTime = 0 + toolAnim = "None" + end + + animateTool() + + + else + toolAnim = "None" + toolAnimTime = 0 + end +end + + +-- connect events + +Humanoid.Died:connect(onDied) +Humanoid.Running:connect(onRunning) +Humanoid.Jumping:connect(onJumping) +Humanoid.Climbing:connect(onClimbing) +Humanoid.GettingUp:connect(onGettingUp) +Humanoid.FreeFalling:connect(onFreeFall) +Humanoid.FallingDown:connect(onFallingDown) +Humanoid.Seated:connect(onSeated) +Humanoid.PlatformStanding:connect(onPlatformStanding) + +-- main program + +local runService = game:service("RunService"); + +while Figure.Parent~=nil do + local _, time = wait(0.1) + move(time) +end + + true + + + \ No newline at end of file diff --git a/2016/content/fonts/humanoidAnimateLocal.rbxm b/2016/content/fonts/humanoidAnimateLocal.rbxm new file mode 100644 index 0000000..5c18211 --- /dev/null +++ b/2016/content/fonts/humanoidAnimateLocal.rbxm @@ -0,0 +1,336 @@ + + null + nil + + + false + + Animate + + + function waitForChild(parent, childName) + local child = parent:findFirstChild(childName) + if child then return child end + while true do + child = parent.ChildAdded:wait() + if child.Name==childName then return child end + end +end + +-- ANIMATION + +-- declarations + +local Figure = script.Parent +local Torso = waitForChild(Figure, "Torso") +local RightShoulder = waitForChild(Torso, "Right Shoulder") +local LeftShoulder = waitForChild(Torso, "Left Shoulder") +local RightHip = waitForChild(Torso, "Right Hip") +local LeftHip = waitForChild(Torso, "Left Hip") +local Neck = waitForChild(Torso, "Neck") +local Humanoid = waitForChild(Figure, "Humanoid") +local pose = "Standing" + +local toolAnim = "None" +local toolAnimTime = 0 + +local jumpMaxLimbVelocity = 0.75 + +-- functions + +function onRunning(speed) + if speed>0 then + pose = "Running" + else + pose = "Standing" + end +end + +function onDied() + pose = "Dead" +end + +function onJumping() + pose = "Jumping" +end + +function onClimbing() + pose = "Climbing" +end + +function onGettingUp() + pose = "GettingUp" +end + +function onFreeFall() + pose = "FreeFall" +end + +function onFallingDown() + pose = "FallingDown" +end + +function onSeated() + pose = "Seated" +end + +function onPlatformStanding() + pose = "PlatformStanding" +end + +function onSwimming(speed) + if speed>0 then + pose = "Running" + else + pose = "Standing" + end +end + +function moveJump() + RightShoulder.MaxVelocity = jumpMaxLimbVelocity + LeftShoulder.MaxVelocity = jumpMaxLimbVelocity + RightShoulder:SetDesiredAngle(3.14) + LeftShoulder:SetDesiredAngle(-3.14) + RightHip:SetDesiredAngle(0) + LeftHip:SetDesiredAngle(0) +end + + +-- same as jump for now + +function moveFreeFall() + RightShoulder.MaxVelocity = jumpMaxLimbVelocity + LeftShoulder.MaxVelocity = jumpMaxLimbVelocity + RightShoulder:SetDesiredAngle(3.14) + LeftShoulder:SetDesiredAngle(-3.14) + RightHip:SetDesiredAngle(0) + LeftHip:SetDesiredAngle(0) +end + +function moveSit() + RightShoulder.MaxVelocity = 0.15 + LeftShoulder.MaxVelocity = 0.15 + RightShoulder:SetDesiredAngle(3.14 /2) + LeftShoulder:SetDesiredAngle(-3.14 /2) + RightHip:SetDesiredAngle(3.14 /2) + LeftHip:SetDesiredAngle(-3.14 /2) +end + +function getTool() + for _, kid in ipairs(Figure:GetChildren()) do + if kid.className == "Tool" then return kid end + end + return nil +end + +function getToolAnim(tool) + for _, c in ipairs(tool:GetChildren()) do + if c.Name == "toolanim" and c.className == "StringValue" then + return c + end + end + return nil +end + +function animateTool() + + if (toolAnim == "None") then + RightShoulder:SetDesiredAngle(1.57) + return + end + + if (toolAnim == "Slash") then + RightShoulder.MaxVelocity = 0.5 + RightShoulder:SetDesiredAngle(0) + return + end + + if (toolAnim == "Lunge") then + RightShoulder.MaxVelocity = 0.5 + LeftShoulder.MaxVelocity = 0.5 + RightHip.MaxVelocity = 0.5 + LeftHip.MaxVelocity = 0.5 + RightShoulder:SetDesiredAngle(1.57) + LeftShoulder:SetDesiredAngle(1.0) + RightHip:SetDesiredAngle(1.57) + LeftHip:SetDesiredAngle(1.0) + return + end +end + +function move(time) + local amplitude + local frequency + + if (pose == "Jumping") then + moveJump() + return + end + + if (pose == "FreeFall") then + moveFreeFall() + return + end + + if (pose == "Seated") then + moveSit() + return + end + + local climbFudge = 0 + + if (pose == "Running") then + if (RightShoulder.CurrentAngle > 1.5 or RightShoulder.CurrentAngle < -1.5) then + RightShoulder.MaxVelocity = jumpMaxLimbVelocity + else + RightShoulder.MaxVelocity = 0.15 + end + if (LeftShoulder.CurrentAngle > 1.5 or LeftShoulder.CurrentAngle < -1.5) then + LeftShoulder.MaxVelocity = jumpMaxLimbVelocity + else + LeftShoulder.MaxVelocity = 0.15 + end + amplitude = 1 + frequency = 9 + elseif (pose == "Climbing") then + RightShoulder.MaxVelocity = 0.5 + LeftShoulder.MaxVelocity = 0.5 + amplitude = 1 + frequency = 9 + climbFudge = 3.14 + else + amplitude = 0.1 + frequency = 1 + end + + desiredAngle = amplitude * math.sin(time*frequency) + + RightShoulder:SetDesiredAngle(desiredAngle + climbFudge) + LeftShoulder:SetDesiredAngle(desiredAngle - climbFudge) + RightHip:SetDesiredAngle(-desiredAngle) + LeftHip:SetDesiredAngle(-desiredAngle) + + + local tool = getTool() + + if tool then + + animStringValueObject = getToolAnim(tool) + + if animStringValueObject then + toolAnim = animStringValueObject.Value + -- message recieved, delete StringValue + animStringValueObject.Parent = nil + toolAnimTime = time + .3 + end + + if time > toolAnimTime then + toolAnimTime = 0 + toolAnim = "None" + end + + animateTool() + + + else + toolAnim = "None" + toolAnimTime = 0 + end +end + + +-- connect events + +Humanoid.Died:connect(onDied) +Humanoid.Running:connect(onRunning) +Humanoid.Jumping:connect(onJumping) +Humanoid.Climbing:connect(onClimbing) +Humanoid.GettingUp:connect(onGettingUp) +Humanoid.FreeFalling:connect(onFreeFall) +Humanoid.FallingDown:connect(onFallingDown) +Humanoid.Seated:connect(onSeated) +Humanoid.PlatformStanding:connect(onPlatformStanding) +Humanoid.Swimming:connect(onSwimming) +-- main program + +local runService = game:service("RunService"); + +while Figure.Parent~=nil do + local _, time = wait(0.1) + move(time) +end + + true + + + + + false + + + + RobloxTeam + + -- Now with exciting TeamColors HACK! + + function waitForChild(parent, childName) + local child = parent:findFirstChild(childName) + if child then return child end + while true do + child = parent.ChildAdded:wait() + if child.Name==childName then return child end + end + end + + -- TEAM COLORS + + + function onTeamChanged(player) + + wait(1) + + local char = player.Character + if char == nil then return end + + if player.Neutral then + -- Replacing the current BodyColor object will force a reset + local old = char:findFirstChild("Body Colors") + if not old then return end + old:clone().Parent = char + old.Parent = nil + else + local head = char:findFirstChild("Head") + local torso = char:findFirstChild("Torso") + local left_arm = char:findFirstChild("Left Arm") + local right_arm = char:findFirstChild("Right Arm") + local left_leg = char:findFirstChild("Left Leg") + local right_leg = char:findFirstChild("Right Leg") + + if head then head.BrickColor = BrickColor.new(24) end + if torso then torso.BrickColor = player.TeamColor end + if left_arm then left_arm.BrickColor = BrickColor.new(26) end + if right_arm then right_arm.BrickColor = BrickColor.new(26) end + if left_leg then left_leg.BrickColor = BrickColor.new(26) end + if right_leg then right_leg.BrickColor = BrickColor.new(26) end + end + end + + function onPlayerPropChanged(property, player) + if property == "Character" then + onTeamChanged(player) + end + if property== "TeamColor" or property == "Neutral" then + onTeamChanged(player) + end + end + + + local cPlayer = game.Players:GetPlayerFromCharacter(script.Parent) + cPlayer.Changed:connect(function(property) onPlayerPropChanged(property, cPlayer) end ) + onTeamChanged(cPlayer) + + + true + + + \ No newline at end of file diff --git a/2016/content/fonts/humanoidAnimateLocalKeyframe.rbxm b/2016/content/fonts/humanoidAnimateLocalKeyframe.rbxm new file mode 100644 index 0000000..fc12d22 --- /dev/null +++ b/2016/content/fonts/humanoidAnimateLocalKeyframe.rbxm @@ -0,0 +1,649 @@ + + null + nil + + + false + + Animate + function waitForChild(parent, childName) + local child = parent:findFirstChild(childName) + if child then return child end + while true do + child = parent.ChildAdded:wait() + if child.Name==childName then return child end + end +end + +local Figure = script.Parent +local Torso = waitForChild(Figure, "Torso") +local RightShoulder = waitForChild(Torso, "Right Shoulder") +local LeftShoulder = waitForChild(Torso, "Left Shoulder") +local RightHip = waitForChild(Torso, "Right Hip") +local LeftHip = waitForChild(Torso, "Left Hip") +local Neck = waitForChild(Torso, "Neck") +local Humanoid = waitForChild(Figure, "Humanoid") +local pose = "Standing" + +local currentAnim = "" +local currentAnimTrack = nil +local currentAnimKeyframeHandler = nil +local currentAnimSpeed = 1.0 +local animTable = {} +local animNames = { + idle = { + { id = "http://www.roblox.com/asset/?id=125750544", weight = 9 }, + { id = "http://www.roblox.com/asset/?id=125750618", weight = 1 } + }, + walk = { + { id = "http://www.roblox.com/asset/?id=125749145", weight = 10 } + }, + run = { + { id = "run.xml", weight = 10 } + }, + jump = { + { id = "http://www.roblox.com/asset/?id=125750702", weight = 10 } + }, + fall = { + { id = "http://www.roblox.com/asset/?id=125750759", weight = 10 } + }, + climb = { + { id = "http://www.roblox.com/asset/?id=125750800", weight = 10 } + }, + sit = { + { id = "http://www.roblox.com/asset/?id=178130996", weight = 10 } + }, + toolnone = { + { id = "http://www.roblox.com/asset/?id=125750867", weight = 10 } + }, + toolslash = { + { id = "http://www.roblox.com/asset/?id=129967390", weight = 10 } +-- { id = "slash.xml", weight = 10 } + }, + toollunge = { + { id = "http://www.roblox.com/asset/?id=129967478", weight = 10 } + }, + wave = { + { id = "http://www.roblox.com/asset/?id=128777973", weight = 10 } + }, + point = { + { id = "http://www.roblox.com/asset/?id=128853357", weight = 10 } + }, + dance = { + { id = "http://www.roblox.com/asset/?id=130018893", weight = 10 }, + { id = "http://www.roblox.com/asset/?id=132546839", weight = 10 }, + { id = "http://www.roblox.com/asset/?id=132546884", weight = 10 } + }, + dance2 = { + { id = "http://www.roblox.com/asset/?id=160934142", weight = 10 }, + { id = "http://www.roblox.com/asset/?id=160934298", weight = 10 }, + { id = "http://www.roblox.com/asset/?id=160934376", weight = 10 } + }, + dance3 = { + { id = "http://www.roblox.com/asset/?id=160934458", weight = 10 }, + { id = "http://www.roblox.com/asset/?id=160934530", weight = 10 }, + { id = "http://www.roblox.com/asset/?id=160934593", weight = 10 } + }, + laugh = { + { id = "http://www.roblox.com/asset/?id=129423131", weight = 10 } + }, + cheer = { + { id = "http://www.roblox.com/asset/?id=129423030", weight = 10 } + }, +} + +-- Existance in this list signifies that it is an emote, the value indicates if it is a looping emote +local emoteNames = { wave = false, point = false, dance = true, dance2 = true, dance3 = true, laugh = false, cheer = false} + +math.randomseed(tick()) + +function configureAnimationSet(name, fileList) + if (animTable[name] ~= nil) then + for _, connection in pairs(animTable[name].connections) do + connection:disconnect() + end + end + animTable[name] = {} + animTable[name].count = 0 + animTable[name].totalWeight = 0 + animTable[name].connections = {} + + -- check for config values + local config = script:FindFirstChild(name) + if (config ~= nil) then +-- print("Loading anims " .. name) + table.insert(animTable[name].connections, config.ChildAdded:connect(function(child) configureAnimationSet(name, fileList) end)) + table.insert(animTable[name].connections, config.ChildRemoved:connect(function(child) configureAnimationSet(name, fileList) end)) + local idx = 1 + for _, childPart in pairs(config:GetChildren()) do + if (childPart:IsA("Animation")) then + table.insert(animTable[name].connections, childPart.Changed:connect(function(property) configureAnimationSet(name, fileList) end)) + animTable[name][idx] = {} + animTable[name][idx].anim = childPart + local weightObject = childPart:FindFirstChild("Weight") + if (weightObject == nil) then + animTable[name][idx].weight = 1 + else + animTable[name][idx].weight = weightObject.Value + end + animTable[name].count = animTable[name].count + 1 + animTable[name].totalWeight = animTable[name].totalWeight + animTable[name][idx].weight + -- print(name .. " [" .. idx .. "] " .. animTable[name][idx].anim.AnimationId .. " (" .. animTable[name][idx].weight .. ")") + idx = idx + 1 + end + end + end + + -- fallback to defaults + if (animTable[name].count <= 0) then + for idx, anim in pairs(fileList) do + animTable[name][idx] = {} + animTable[name][idx].anim = Instance.new("Animation") + animTable[name][idx].anim.Name = name + animTable[name][idx].anim.AnimationId = anim.id + animTable[name][idx].weight = anim.weight + animTable[name].count = animTable[name].count + 1 + animTable[name].totalWeight = animTable[name].totalWeight + anim.weight +-- print(name .. " [" .. idx .. "] " .. anim.id .. " (" .. anim.weight .. ")") + end + end +end + +-- Setup animation objects +function scriptChildModified(child) + local fileList = animNames[child.Name] + if (fileList ~= nil) then + configureAnimationSet(child.Name, fileList) + end +end + +script.ChildAdded:connect(scriptChildModified) +script.ChildRemoved:connect(scriptChildModified) + + +for name, fileList in pairs(animNames) do + configureAnimationSet(name, fileList) +end + +-- ANIMATION + +-- declarations +local toolAnim = "None" +local toolAnimTime = 0 + +local jumpAnimTime = 0 +local jumpAnimDuration = 0.3 + +local toolTransitionTime = 0.1 +local fallTransitionTime = 0.3 +local jumpMaxLimbVelocity = 0.75 + +-- functions + +function stopAllAnimations() + local oldAnim = currentAnim + + -- return to idle if finishing an emote + if (emoteNames[oldAnim] ~= nil and emoteNames[oldAnim] == false) then + oldAnim = "idle" + end + + currentAnim = "" + if (currentAnimKeyframeHandler ~= nil) then + currentAnimKeyframeHandler:disconnect() + end + + if (currentAnimTrack ~= nil) then + currentAnimTrack:Stop() + currentAnimTrack:Destroy() + currentAnimTrack = nil + end + return oldAnim +end + +function setAnimationSpeed(speed) + if speed ~= currentAnimSpeed then + currentAnimSpeed = speed + currentAnimTrack:AdjustSpeed(currentAnimSpeed) + end +end + +function keyFrameReachedFunc(frameName) + if (frameName == "End") then +-- print("Keyframe : ".. frameName) + local repeatAnim = stopAllAnimations() + local animSpeed = currentAnimSpeed + playAnimation(repeatAnim, 0.0, Humanoid) + setAnimationSpeed(animSpeed) + end +end + +-- Preload animations +function playAnimation(animName, transitionTime, humanoid) + local idleFromEmote = (animName == "idle" and emoteNames[currentAnim] ~= nil) + if (animName ~= currentAnim and not idleFromEmote) then + + if (currentAnimTrack ~= nil) then + currentAnimTrack:Stop(transitionTime) + currentAnimTrack:Destroy() + end + + currentAnimSpeed = 1.0 + local roll = math.random(1, animTable[animName].totalWeight) + local origRoll = roll + local idx = 1 + while (roll > animTable[animName][idx].weight) do + roll = roll - animTable[animName][idx].weight + idx = idx + 1 + end +-- print(animName .. " " .. idx .. " [" .. origRoll .. "]") + local anim = animTable[animName][idx].anim + + -- load it to the humanoid; get AnimationTrack + currentAnimTrack = humanoid:LoadAnimation(anim) + + -- play the animation + currentAnimTrack:Play(transitionTime) + currentAnim = animName + + -- set up keyframe name triggers + if (currentAnimKeyframeHandler ~= nil) then + currentAnimKeyframeHandler:disconnect() + end + currentAnimKeyframeHandler = currentAnimTrack.KeyframeReached:connect(keyFrameReachedFunc) + end +end + +------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------- + +local toolAnimName = "" +local toolAnimTrack = nil +local currentToolAnimKeyframeHandler = nil + +function toolKeyFrameReachedFunc(frameName) + if (frameName == "End") then +-- print("Keyframe : ".. frameName) + local repeatAnim = stopToolAnimations() + playToolAnimation(repeatAnim, 0.0, Humanoid) + end +end + + +function playToolAnimation(animName, transitionTime, humanoid) + if (animName ~= toolAnimName) then + + if (toolAnimTrack ~= nil) then + toolAnimTrack:Stop() + toolAnimTrack:Destroy() + transitionTime = 0 + end + + local roll = math.random(1, animTable[animName].totalWeight) + local origRoll = roll + local idx = 1 + while (roll > animTable[animName][idx].weight) do + roll = roll - animTable[animName][idx].weight + idx = idx + 1 + end +-- print(animName .. " * " .. idx .. " [" .. origRoll .. "]") + local anim = animTable[animName][idx].anim + + -- load it to the humanoid; get AnimationTrack + toolAnimTrack = humanoid:LoadAnimation(anim) + + -- play the animation + toolAnimTrack:Play(transitionTime) + toolAnimName = animName + + currentToolAnimKeyframeHandler = toolAnimTrack.KeyframeReached:connect(toolKeyFrameReachedFunc) + end +end + +function stopToolAnimations() + local oldAnim = toolAnimName + + if (currentToolAnimKeyframeHandler ~= nil) then + currentToolAnimKeyframeHandler:disconnect() + end + + toolAnimName = "" + if (toolAnimTrack ~= nil) then + toolAnimTrack:Stop() + toolAnimTrack:Destroy() + toolAnimTrack = nil + end + + + return oldAnim +end + +------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------- + + +function onRunning(speed) + if speed>0.5 then + playAnimation("walk", 0.1, Humanoid) + pose = "Running" + else + playAnimation("idle", 0.1, Humanoid) + pose = "Standing" + end +end + +function onDied() + pose = "Dead" +end + +function onJumping() + playAnimation("jump", 0.1, Humanoid) + jumpAnimTime = jumpAnimDuration + pose = "Jumping" +end + +function onClimbing(speed) + playAnimation("climb", 0.1, Humanoid) + setAnimationSpeed(speed / 12.0) + pose = "Climbing" +end + +function onGettingUp() + pose = "GettingUp" +end + +function onFreeFall() + if (jumpAnimTime <= 0) then + playAnimation("fall", fallTransitionTime, Humanoid) + end + pose = "FreeFall" +end + +function onFallingDown() + pose = "FallingDown" +end + +function onSeated() + pose = "Seated" +end + +function onPlatformStanding() + pose = "PlatformStanding" +end + +function onSwimming(speed) + if speed>0 then + pose = "Running" + else + pose = "Standing" + end +end + +function getTool() + for _, kid in ipairs(Figure:GetChildren()) do + if kid.className == "Tool" then return kid end + end + return nil +end + +function getToolAnim(tool) + for _, c in ipairs(tool:GetChildren()) do + if c.Name == "toolanim" and c.className == "StringValue" then + return c + end + end + return nil +end + +function animateTool() + + if (toolAnim == "None") then + playToolAnimation("toolnone", toolTransitionTime, Humanoid) + return + end + + if (toolAnim == "Slash") then + playToolAnimation("toolslash", 0, Humanoid) + return + end + + if (toolAnim == "Lunge") then + playToolAnimation("toollunge", 0, Humanoid) + return + end +end + +function moveSit() + RightShoulder.MaxVelocity = 0.15 + LeftShoulder.MaxVelocity = 0.15 + RightShoulder:SetDesiredAngle(3.14 /2) + LeftShoulder:SetDesiredAngle(-3.14 /2) + RightHip:SetDesiredAngle(3.14 /2) + LeftHip:SetDesiredAngle(-3.14 /2) +end + +local lastTick = 0 + +function move(time) + local amplitude = 1 + local frequency = 1 + local deltaTime = time - lastTick + lastTick = time + + local climbFudge = 0 + local setAngles = false + + if (jumpAnimTime > 0) then + jumpAnimTime = jumpAnimTime - deltaTime + end + + if (pose == "FreeFall" and jumpAnimTime <= 0) then + playAnimation("fall", fallTransitionTime, Humanoid) + elseif (pose == "Seated") then + playAnimation("sit", 0.5, Humanoid) + return + elseif (pose == "Running") then + playAnimation("walk", 0.1, Humanoid) + elseif (pose == "Dead" or pose == "GettingUp" or pose == "FallingDown" or pose == "Seated" or pose == "PlatformStanding") then +-- print("Wha " .. pose) + stopAllAnimations() + amplitude = 0.1 + frequency = 1 + setAngles = true + end + + if (setAngles) then + desiredAngle = amplitude * math.sin(time * frequency) + + RightShoulder:SetDesiredAngle(desiredAngle + climbFudge) + LeftShoulder:SetDesiredAngle(desiredAngle - climbFudge) + RightHip:SetDesiredAngle(-desiredAngle) + LeftHip:SetDesiredAngle(-desiredAngle) + end + + -- Tool Animation handling + local tool = getTool() + if tool then + + animStringValueObject = getToolAnim(tool) + + if animStringValueObject then + toolAnim = animStringValueObject.Value + -- message recieved, delete StringValue + animStringValueObject.Parent = nil + toolAnimTime = time + .3 + end + + if time > toolAnimTime then + toolAnimTime = 0 + toolAnim = "None" + end + + animateTool() + else + stopToolAnimations() + toolAnim = "None" + toolAnimTime = 0 + end +end + +-- connect events +Humanoid.Died:connect(onDied) +Humanoid.Running:connect(onRunning) +Humanoid.Jumping:connect(onJumping) +Humanoid.Climbing:connect(onClimbing) +Humanoid.GettingUp:connect(onGettingUp) +Humanoid.FreeFalling:connect(onFreeFall) +Humanoid.FallingDown:connect(onFallingDown) +Humanoid.Seated:connect(onSeated) +Humanoid.PlatformStanding:connect(onPlatformStanding) +Humanoid.Swimming:connect(onSwimming) + +-- setup emote chat hook +Game.Players.LocalPlayer.Chatted:connect(function(msg) + local emote = "" + if (string.sub(msg, 1, 3) == "/e ") then + emote = string.sub(msg, 4) + elseif (string.sub(msg, 1, 7) == "/emote ") then + emote = string.sub(msg, 8) + end + + if (pose == "Standing" and emoteNames[emote] ~= nil) then + playAnimation(emote, 0.1, Humanoid) + end +-- print("===> " .. string.sub(msg, 1, 3) .. "(" .. emote .. ")") +end) + + +-- main program + +local runService = game:service("RunService"); + +-- initialize to idle +playAnimation("idle", 0.1, Humanoid) +pose = "Standing" + +while Figure.Parent~=nil do + local _, time = wait(0.1) + move(time) +end + + + + + + + idle + + + + + http://www.roblox.com/asset/?id=125750544 + Animation1 + + + + Weight + 9 + + + + + + http://www.roblox.com/asset/?id=125750618 + Animation2 + + + + Weight + 1 + + + + + + + walk + + + + + http://www.roblox.com/asset/?id=125749145 + WalkAnim + + + + + + run + + + + + http://www.roblox.com/asset/?id=125749145 + RunAnim + + + + + + jump + + + + + http://www.roblox.com/asset/?id=125750702 + JumpAnim + + + + + + climb + + + + + http://www.roblox.com/asset/?id=125750800 + ClimbAnim + + + + + + toolnone + + + + + http://www.roblox.com/asset/?id=125750867 + ToolNoneAnim + + + + + + fall + + + + + http://www.roblox.com/asset/?id=125750759 + FallAnim + + + + + + sit + + + + + http://www.roblox.com/asset/?id=178130996 + SitAnim + + + + + \ No newline at end of file diff --git a/2016/content/fonts/humanoidAnimateLocalKeyframe2.rbxm b/2016/content/fonts/humanoidAnimateLocalKeyframe2.rbxm new file mode 100644 index 0000000..137ab16 --- /dev/null +++ b/2016/content/fonts/humanoidAnimateLocalKeyframe2.rbxm @@ -0,0 +1,673 @@ + + null + nil + + + false + + Animate + animTable[animName][idx].weight) do + roll = roll - animTable[animName][idx].weight + idx = idx + 1 + end +-- print(animName .. " " .. idx .. " [" .. origRoll .. "]") + local anim = animTable[animName][idx].anim + + -- switch animation + if (anim ~= currentAnimInstance) then + + if (currentAnimTrack ~= nil) then + currentAnimTrack:Stop(transitionTime) + currentAnimTrack:Destroy() + end + + currentAnimSpeed = 1.0 + + -- load it to the humanoid; get AnimationTrack + currentAnimTrack = humanoid:LoadAnimation(anim) + + -- play the animation + currentAnimTrack:Play(transitionTime) + currentAnim = animName + currentAnimInstance = anim + + -- set up keyframe name triggers + if (currentAnimKeyframeHandler ~= nil) then + currentAnimKeyframeHandler:disconnect() + end + currentAnimKeyframeHandler = currentAnimTrack.KeyframeReached:connect(keyFrameReachedFunc) + + end + +end + +------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------- + +local toolAnimName = "" +local toolAnimTrack = nil +local toolAnimInstance = nil +local currentToolAnimKeyframeHandler = nil + +function toolKeyFrameReachedFunc(frameName) + if (frameName == "End") then +-- print("Keyframe : ".. frameName) + playToolAnimation(toolAnimName, 0.0, Humanoid) + end +end + + +function playToolAnimation(animName, transitionTime, humanoid) + + local roll = math.random(1, animTable[animName].totalWeight) + local origRoll = roll + local idx = 1 + while (roll > animTable[animName][idx].weight) do + roll = roll - animTable[animName][idx].weight + idx = idx + 1 + end +-- print(animName .. " * " .. idx .. " [" .. origRoll .. "]") + local anim = animTable[animName][idx].anim + + if (toolAnimInstance ~= anim) then + + if (toolAnimTrack ~= nil) then + toolAnimTrack:Stop() + toolAnimTrack:Destroy() + transitionTime = 0 + end + + -- load it to the humanoid; get AnimationTrack + toolAnimTrack = humanoid:LoadAnimation(anim) + + -- play the animation + toolAnimTrack:Play(transitionTime) + toolAnimName = animName + toolAnimInstance = anim + + currentToolAnimKeyframeHandler = toolAnimTrack.KeyframeReached:connect(toolKeyFrameReachedFunc) + end +end + +function stopToolAnimations() + local oldAnim = toolAnimName + + if (currentToolAnimKeyframeHandler ~= nil) then + currentToolAnimKeyframeHandler:disconnect() + end + + toolAnimName = "" + toolAnimInstance = nil + if (toolAnimTrack ~= nil) then + toolAnimTrack:Stop() + toolAnimTrack:Destroy() + toolAnimTrack = nil + end + + + return oldAnim +end + +------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------- + + +function onRunning(speed) + if speed>0.01 then + playAnimation("walk", 0.1, Humanoid) + if currentAnimInstance and currentAnimInstance.AnimationId == "http://www.roblox.com/asset/?id=180426354" then + setAnimationSpeed(speed / 14.5) + end + pose = "Running" + else + playAnimation("idle", 0.1, Humanoid) + pose = "Standing" + end +end + +function onDied() + pose = "Dead" +end + +function onJumping() + playAnimation("jump", 0.1, Humanoid) + jumpAnimTime = jumpAnimDuration + pose = "Jumping" +end + +function onClimbing(speed) + playAnimation("climb", 0.1, Humanoid) + setAnimationSpeed(speed / 12.0) + pose = "Climbing" +end + +function onGettingUp() + pose = "GettingUp" +end + +function onFreeFall() + if (jumpAnimTime <= 0) then + playAnimation("fall", fallTransitionTime, Humanoid) + end + pose = "FreeFall" +end + +function onFallingDown() + pose = "FallingDown" +end + +function onSeated() + pose = "Seated" +end + +function onPlatformStanding() + pose = "PlatformStanding" +end + +function onSwimming(speed) + if speed>0 then + pose = "Running" + else + pose = "Standing" + end +end + +function getTool() + for _, kid in ipairs(Figure:GetChildren()) do + if kid.className == "Tool" then return kid end + end + return nil +end + +function getToolAnim(tool) + for _, c in ipairs(tool:GetChildren()) do + if c.Name == "toolanim" and c.className == "StringValue" then + return c + end + end + return nil +end + +function animateTool() + + if (toolAnim == "None") then + playToolAnimation("toolnone", toolTransitionTime, Humanoid) + return + end + + if (toolAnim == "Slash") then + playToolAnimation("toolslash", 0, Humanoid) + return + end + + if (toolAnim == "Lunge") then + playToolAnimation("toollunge", 0, Humanoid) + return + end +end + +function moveSit() + RightShoulder.MaxVelocity = 0.15 + LeftShoulder.MaxVelocity = 0.15 + RightShoulder:SetDesiredAngle(3.14 /2) + LeftShoulder:SetDesiredAngle(-3.14 /2) + RightHip:SetDesiredAngle(3.14 /2) + LeftHip:SetDesiredAngle(-3.14 /2) +end + +local lastTick = 0 + +function move(time) + local amplitude = 1 + local frequency = 1 + local deltaTime = time - lastTick + lastTick = time + + local climbFudge = 0 + local setAngles = false + + if (jumpAnimTime > 0) then + jumpAnimTime = jumpAnimTime - deltaTime + end + + if (pose == "FreeFall" and jumpAnimTime <= 0) then + playAnimation("fall", fallTransitionTime, Humanoid) + elseif (pose == "Seated") then + playAnimation("sit", 0.5, Humanoid) + return + elseif (pose == "Running") then + playAnimation("walk", 0.1, Humanoid) + elseif (pose == "Dead" or pose == "GettingUp" or pose == "FallingDown" or pose == "Seated" or pose == "PlatformStanding") then +-- print("Wha " .. pose) + stopAllAnimations() + amplitude = 0.1 + frequency = 1 + setAngles = true + end + + if (setAngles) then + desiredAngle = amplitude * math.sin(time * frequency) + + RightShoulder:SetDesiredAngle(desiredAngle + climbFudge) + LeftShoulder:SetDesiredAngle(desiredAngle - climbFudge) + RightHip:SetDesiredAngle(-desiredAngle) + LeftHip:SetDesiredAngle(-desiredAngle) + end + + -- Tool Animation handling + local tool = getTool() + if tool and tool:FindFirstChild("Handle") then + + animStringValueObject = getToolAnim(tool) + + if animStringValueObject then + toolAnim = animStringValueObject.Value + -- message recieved, delete StringValue + animStringValueObject.Parent = nil + toolAnimTime = time + .3 + end + + if time > toolAnimTime then + toolAnimTime = 0 + toolAnim = "None" + end + + animateTool() + else + stopToolAnimations() + toolAnim = "None" + toolAnimInstance = nil + toolAnimTime = 0 + end +end + +-- connect events +Humanoid.Died:connect(onDied) +Humanoid.Running:connect(onRunning) +Humanoid.Jumping:connect(onJumping) +Humanoid.Climbing:connect(onClimbing) +Humanoid.GettingUp:connect(onGettingUp) +Humanoid.FreeFalling:connect(onFreeFall) +Humanoid.FallingDown:connect(onFallingDown) +Humanoid.Seated:connect(onSeated) +Humanoid.PlatformStanding:connect(onPlatformStanding) +Humanoid.Swimming:connect(onSwimming) + +-- setup emote chat hook +game.Players.LocalPlayer.Chatted:connect(function(msg) + local emote = "" + if msg == "/e dance" then + emote = dances[math.random(1, #dances)] + elseif (string.sub(msg, 1, 3) == "/e ") then + emote = string.sub(msg, 4) + elseif (string.sub(msg, 1, 7) == "/emote ") then + emote = string.sub(msg, 8) + end + + if (pose == "Standing" and emoteNames[emote] ~= nil) then + playAnimation(emote, 0.1, Humanoid) + end + +end) + + +-- main program + +local runService = game:service("RunService"); + +-- initialize to idle +playAnimation("idle", 0.1, Humanoid) +pose = "Standing" + +while Figure.Parent~=nil do + local _, time = wait(0.1) + move(time) +end + + +]]> + + + + idle + + + + + http://www.roblox.com/asset/?id=180435571 + Animation1 + + + + Weight + 9 + + + + + + http://www.roblox.com/asset/?id=180435792 + Animation2 + + + + Weight + 1 + + + + + + + walk + + + + + http://www.roblox.com/asset/?id=180426354 + WalkAnim + + + + + + run + + + + + http://www.roblox.com/asset/?id=180426354 + RunAnim + + + + + + jump + + + + + http://www.roblox.com/asset/?id=125750702 + JumpAnim + + + + + + climb + + + + + http://www.roblox.com/asset/?id=180436334 + ClimbAnim + + + + + + toolnone + + + + + http://www.roblox.com/asset/?id=182393478 + ToolNoneAnim + + + + + + fall + + + + + http://www.roblox.com/asset/?id=180436148 + FallAnim + + + + + + sit + + + + + http://www.roblox.com/asset/?id=178130996 + SitAnim + + + + + \ No newline at end of file diff --git a/2016/content/fonts/humanoidAnimateR15.rbxm b/2016/content/fonts/humanoidAnimateR15.rbxm new file mode 100644 index 0000000..a4e6a12 --- /dev/null +++ b/2016/content/fonts/humanoidAnimateR15.rbxm @@ -0,0 +1,669 @@ + + null + nil + + + false + + Animate + animTable[animName][idx].weight) do + roll = roll - animTable[animName][idx].weight + idx = idx + 1 + end + +-- print(animName .. " " .. idx .. " [" .. origRoll .. "]") + + local anim = animTable[animName][idx].anim + + -- switch animation + if (anim ~= currentAnimInstance) then + + if (currentAnimTrack ~= nil) then + currentAnimTrack:Stop(transitionTime) + currentAnimTrack:Destroy() + end + + currentAnimSpeed = 1.0 + + -- load it to the humanoid; get AnimationTrack + currentAnimTrack = humanoid:LoadAnimation(anim) + + -- play the animation + currentAnimTrack:Play(transitionTime) + currentAnim = animName + currentAnimInstance = anim + + -- set up keyframe name triggers + if (currentAnimKeyframeHandler ~= nil) then + currentAnimKeyframeHandler:disconnect() + end + currentAnimKeyframeHandler = currentAnimTrack.KeyframeReached:connect(keyFrameReachedFunc) + + end + +end + +------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------- + +local toolAnimName = "" +local toolAnimTrack = nil +local toolAnimInstance = nil +local currentToolAnimKeyframeHandler = nil + +function toolKeyFrameReachedFunc(frameName) + if (frameName == "End") then +-- print("Keyframe : ".. frameName) + playToolAnimation(toolAnimName, 0.0, Humanoid) + end +end + + +function playToolAnimation(animName, transitionTime, humanoid) + + local roll = math.random(1, animTable[animName].totalWeight) + local origRoll = roll + local idx = 1 + while (roll > animTable[animName][idx].weight) do + roll = roll - animTable[animName][idx].weight + idx = idx + 1 + end +-- print(animName .. " * " .. idx .. " [" .. origRoll .. "]") + local anim = animTable[animName][idx].anim + + if (toolAnimInstance ~= anim) then + + if (toolAnimTrack ~= nil) then + toolAnimTrack:Stop() + toolAnimTrack:Destroy() + transitionTime = 0 + end + + -- load it to the humanoid; get AnimationTrack + toolAnimTrack = humanoid:LoadAnimation(anim) + + -- play the animation + toolAnimTrack:Play(transitionTime) + toolAnimName = animName + toolAnimInstance = anim + + currentToolAnimKeyframeHandler = toolAnimTrack.KeyframeReached:connect(toolKeyFrameReachedFunc) + end +end + +function stopToolAnimations() + local oldAnim = toolAnimName + + if (currentToolAnimKeyframeHandler ~= nil) then + currentToolAnimKeyframeHandler:disconnect() + end + + toolAnimName = "" + toolAnimInstance = nil + if (toolAnimTrack ~= nil) then + toolAnimTrack:Stop() + toolAnimTrack:Destroy() + toolAnimTrack = nil + end + + + return oldAnim +end + +------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------- + + +function onRunning(speed) + if speed>0.01 then + local scale = 15.0 + playAnimation("walk", 0.1, Humanoid) + setAnimationSpeed(speed / scale) + pose = "Running" + else + playAnimation("idle", 0.1, Humanoid) + pose = "Standing" + end +end + +function onDied() + pose = "Dead" +end + +function onJumping() + playAnimation("jump", 0.1, Humanoid) + jumpAnimTime = jumpAnimDuration + pose = "Jumping" +end + +function onClimbing(speed) + local scale = 2.0 + playAnimation("climb", 0.1, Humanoid) + setAnimationSpeed(speed / scale) + pose = "Climbing" +end + +function onGettingUp() + pose = "GettingUp" +end + +function onFreeFall() + if (jumpAnimTime <= 0) then + playAnimation("fall", fallTransitionTime, Humanoid) + end + pose = "FreeFall" +end + +function onFallingDown() + pose = "FallingDown" +end + +function onSeated() + pose = "Seated" +end + +function onPlatformStanding() + pose = "PlatformStanding" +end + +function onSwimming(speed) + if speed>0 then + pose = "Running" + else + pose = "Standing" + end +end + +function getTool() + for _, kid in ipairs(Figure:GetChildren()) do + if kid.className == "Tool" then return kid end + end + return nil +end + +function getToolAnim(tool) + for _, c in ipairs(tool:GetChildren()) do + if c.Name == "toolanim" and c.className == "StringValue" then + return c + end + end + return nil +end + +function animateTool() + + if (toolAnim == "None") then + playToolAnimation("toolnone", toolTransitionTime, Humanoid) + return + end + + if (toolAnim == "Slash") then + playToolAnimation("toolslash", 0, Humanoid) + return + end + + if (toolAnim == "Lunge") then + playToolAnimation("toollunge", 0, Humanoid) + return + end +end + +function moveSit() + RightShoulder.MaxVelocity = 0.15 + LeftShoulder.MaxVelocity = 0.15 + RightShoulder:SetDesiredAngle(3.14 /2) + LeftShoulder:SetDesiredAngle(-3.14 /2) + RightHip:SetDesiredAngle(3.14 /2) + LeftHip:SetDesiredAngle(-3.14 /2) +end + +local lastTick = 0 + +function move(time) + local amplitude = 1 + local frequency = 1 + local deltaTime = time - lastTick + lastTick = time + + local climbFudge = 0 + local setAngles = false + + if (jumpAnimTime > 0) then + jumpAnimTime = jumpAnimTime - deltaTime + end + + if (pose == "FreeFall" and jumpAnimTime <= 0) then + playAnimation("fall", fallTransitionTime, Humanoid) + elseif (pose == "Seated") then + playAnimation("sit", 0.5, Humanoid) + return + elseif (pose == "Running") then + playAnimation("walk", 0.1, Humanoid) + elseif (pose == "Dead" or pose == "GettingUp" or pose == "FallingDown" or pose == "Seated" or pose == "PlatformStanding") then + stopAllAnimations() + amplitude = 0.1 + frequency = 1 + setAngles = true + end + + -- Tool Animation handling + local tool = getTool() + if tool then + + animStringValueObject = getToolAnim(tool) + + if animStringValueObject then + toolAnim = animStringValueObject.Value + -- message recieved, delete StringValue + animStringValueObject.Parent = nil + toolAnimTime = time + .3 + end + + if time > toolAnimTime then + toolAnimTime = 0 + toolAnim = "None" + end + + animateTool() + else + stopToolAnimations() + toolAnim = "None" + toolAnimInstance = nil + toolAnimTime = 0 + end +end + +-- connect events +Humanoid.Died:connect(onDied) +Humanoid.Running:connect(onRunning) +Humanoid.Jumping:connect(onJumping) +Humanoid.Climbing:connect(onClimbing) +Humanoid.GettingUp:connect(onGettingUp) +Humanoid.FreeFalling:connect(onFreeFall) +Humanoid.FallingDown:connect(onFallingDown) +Humanoid.Seated:connect(onSeated) +Humanoid.PlatformStanding:connect(onPlatformStanding) +Humanoid.Swimming:connect(onSwimming) + +-- setup emote chat hook +Game.Players.LocalPlayer.Chatted:connect(function(msg) + local emote = "" + if (string.sub(msg, 1, 3) == "/e ") then + emote = string.sub(msg, 4) + elseif (string.sub(msg, 1, 7) == "/emote ") then + emote = string.sub(msg, 8) + end + + if (pose == "Standing" and emoteNames[emote] ~= nil) then + playAnimation(emote, 0.1, Humanoid) + end +-- print("===> " .. string.sub(msg, 1, 3) .. "(" .. emote .. ")") +end) + + +-- main program + +local runService = game:service("RunService"); + +-- print("bottom") + +-- initialize to idle +playAnimation("idle", 0.1, Humanoid) +pose = "Standing" + +while Figure.Parent~=nil do + local _, time = wait(0.1) + move(time) +end + + +]]> + + + + climb + + + + + http://www.roblox.com/asset/?id=434415851 + ClimbAnim + + + + + + fall + + + + + http://www.roblox.com/asset/?id=434418643 + FallAnim + + + + + + idle + + + + + http://www.roblox.com/asset/?id=434416649 + Animation1 + + + + Weight + 9 + + + + + + http://www.roblox.com/asset/?id=434417169 + Animation2 + + + + Weight + 1 + + + + + + http://www.roblox.com/asset/?id=434417655 + Animation3 + + + + Weight + 1 + + + + + + + jump + + + + + http://www.roblox.com/asset/?id=434415339 + JumpAnim + + + + + + run + + + + + http://www.roblox.com/asset/?id=434418038 + RunAnim + + + + + + sit + + + + + http://www.roblox.com/asset/?id=434419018 + SitAnim + + + + + + toolnone + + + + + http://www.roblox.com/asset/?id=434419638 + ToolNoneAnim + + + + + + walk + + + + + http://www.roblox.com/asset/?id=387947975 + WalkAnim + + + + + \ No newline at end of file diff --git a/2016/content/fonts/humanoidAnimateR15_3.rbxm b/2016/content/fonts/humanoidAnimateR15_3.rbxm new file mode 100644 index 0000000..2d33fa6 --- /dev/null +++ b/2016/content/fonts/humanoidAnimateR15_3.rbxm @@ -0,0 +1,694 @@ + + null + nil + + + false + + Animate + + animTable[animName][idx].weight) do + roll = roll - animTable[animName][idx].weight + idx = idx + 1 + end + +-- print(animName .. " " .. idx .. " [" .. origRoll .. "]") + + local anim = animTable[animName][idx].anim + + -- switch animation + if (anim ~= currentAnimInstance) then + + if (currentAnimTrack ~= nil) then + currentAnimTrack:Stop(transitionTime) + currentAnimTrack:Destroy() + end + + currentAnimSpeed = 1.0 + + -- load it to the humanoid; get AnimationTrack + currentAnimTrack = humanoid:LoadAnimation(anim) + + -- play the animation + currentAnimTrack:Play(transitionTime) + currentAnim = animName + currentAnimInstance = anim + + -- set up keyframe name triggers + if (currentAnimKeyframeHandler ~= nil) then + currentAnimKeyframeHandler:disconnect() + end + currentAnimKeyframeHandler = currentAnimTrack.KeyframeReached:connect(keyFrameReachedFunc) + + end + +end + +------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------- + +local toolAnimName = "" +local toolAnimTrack = nil +local toolAnimInstance = nil +local currentToolAnimKeyframeHandler = nil + +function toolKeyFrameReachedFunc(frameName) + if (frameName == "End") then +-- print("Keyframe : ".. frameName) + playToolAnimation(toolAnimName, 0.0, Humanoid) + end +end + + +function playToolAnimation(animName, transitionTime, humanoid) + + local roll = math.random(1, animTable[animName].totalWeight) + local origRoll = roll + local idx = 1 + while (roll > animTable[animName][idx].weight) do + roll = roll - animTable[animName][idx].weight + idx = idx + 1 + end +-- print(animName .. " * " .. idx .. " [" .. origRoll .. "]") + local anim = animTable[animName][idx].anim + + if (toolAnimInstance ~= anim) then + + if (toolAnimTrack ~= nil) then + toolAnimTrack:Stop() + toolAnimTrack:Destroy() + transitionTime = 0 + end + + -- load it to the humanoid; get AnimationTrack + toolAnimTrack = humanoid:LoadAnimation(anim) + + -- play the animation + toolAnimTrack:Play(transitionTime) + toolAnimName = animName + toolAnimInstance = anim + + currentToolAnimKeyframeHandler = toolAnimTrack.KeyframeReached:connect(toolKeyFrameReachedFunc) + end +end + +function stopToolAnimations() + local oldAnim = toolAnimName + + if (currentToolAnimKeyframeHandler ~= nil) then + currentToolAnimKeyframeHandler:disconnect() + end + + toolAnimName = "" + toolAnimInstance = nil + if (toolAnimTrack ~= nil) then + toolAnimTrack:Stop() + toolAnimTrack:Destroy() + toolAnimTrack = nil + end + + + return oldAnim +end + +------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------- + + +function onRunning(speed) + if speed > 0.01 then + local scale = 15.0 + playAnimation("walk", 0.1, Humanoid) + setAnimationSpeed(speed / scale) + pose = "Running" + else + if emoteNames[currentAnim] == nil then + playAnimation("idle", 0.1, Humanoid) + pose = "Standing" + end + end +end + +function onDied() + pose = "Dead" +end + +function onJumping() + playAnimation("jump", 0.1, Humanoid) + jumpAnimTime = jumpAnimDuration + pose = "Jumping" +end + +function onClimbing(speed) + local scale = 5.0 + playAnimation("climb", 0.1, Humanoid) + setAnimationSpeed(speed / scale) + pose = "Climbing" +end + +function onGettingUp() + pose = "GettingUp" +end + +function onFreeFall() + if (jumpAnimTime <= 0) then + playAnimation("fall", fallTransitionTime, Humanoid) + end + pose = "FreeFall" +end + +function onFallingDown() + pose = "FallingDown" +end + +function onSeated() + pose = "Seated" +end + +function onPlatformStanding() + pose = "PlatformStanding" +end + +function onSwimming(speed) + if speed > 1.00 then + local scale = 10.0 + playAnimation("swim", 0.4, Humanoid) + setAnimationSpeed(speed / scale) + pose = "Swimming" + else + playAnimation("swimidle", 0.4, Humanoid) + pose = "Standing" + end +end + +function getTool() + for _, kid in ipairs(Figure:GetChildren()) do + if kid.className == "Tool" then return kid end + end + return nil +end + +function getToolAnim(tool) + for _, c in ipairs(tool:GetChildren()) do + if c.Name == "toolanim" and c.className == "StringValue" then + return c + end + end + return nil +end + +function animateTool() + + if (toolAnim == "None") then + playToolAnimation("toolnone", toolTransitionTime, Humanoid) + return + end + + if (toolAnim == "Slash") then + playToolAnimation("toolslash", 0, Humanoid) + return + end + + if (toolAnim == "Lunge") then + playToolAnimation("toollunge", 0, Humanoid) + return + end +end + +function moveSit() + RightShoulder.MaxVelocity = 0.15 + LeftShoulder.MaxVelocity = 0.15 + RightShoulder:SetDesiredAngle(3.14 /2) + LeftShoulder:SetDesiredAngle(-3.14 /2) + RightHip:SetDesiredAngle(3.14 /2) + LeftHip:SetDesiredAngle(-3.14 /2) +end + +local lastTick = 0 + +function move(time) + local amplitude = 1 + local frequency = 1 + local deltaTime = time - lastTick + lastTick = time + + local climbFudge = 0 + local setAngles = false + + if (jumpAnimTime > 0) then + jumpAnimTime = jumpAnimTime - deltaTime + end + + if (pose == "FreeFall" and jumpAnimTime <= 0) then + playAnimation("fall", fallTransitionTime, Humanoid) + elseif (pose == "Seated") then + playAnimation("sit", 0.5, Humanoid) + return + elseif (pose == "Running") then + playAnimation("walk", 0.1, Humanoid) + elseif (pose == "Dead" or pose == "GettingUp" or pose == "FallingDown" or pose == "Seated" or pose == "PlatformStanding") then + stopAllAnimations() + amplitude = 0.1 + frequency = 1 + setAngles = true + end + + -- Tool Animation handling + local tool = getTool() + if tool and (tool.RequiresHandle or tool:FindFirstChild("Handle")) then + + animStringValueObject = getToolAnim(tool) + + if animStringValueObject then + toolAnim = animStringValueObject.Value + -- message recieved, delete StringValue + animStringValueObject.Parent = nil + toolAnimTime = time + .3 + end + + if time > toolAnimTime then + toolAnimTime = 0 + toolAnim = "None" + end + + animateTool() + else + stopToolAnimations() + toolAnim = "None" + toolAnimInstance = nil + toolAnimTime = 0 + end +end + +-- connect events +Humanoid.Died:connect(onDied) +Humanoid.Running:connect(onRunning) +Humanoid.Jumping:connect(onJumping) +Humanoid.Climbing:connect(onClimbing) +Humanoid.GettingUp:connect(onGettingUp) +Humanoid.FreeFalling:connect(onFreeFall) +Humanoid.FallingDown:connect(onFallingDown) +Humanoid.Seated:connect(onSeated) +Humanoid.PlatformStanding:connect(onPlatformStanding) +Humanoid.Swimming:connect(onSwimming) + +-- setup emote chat hook +Game.Players.LocalPlayer.Chatted:connect(function(msg) + local emote = "" + if (string.sub(msg, 1, 3) == "/e ") then + emote = string.sub(msg, 4) + elseif (string.sub(msg, 1, 7) == "/emote ") then + emote = string.sub(msg, 8) + end + + if (pose == "Standing" and emoteNames[emote] ~= nil) then + playAnimation(emote, 0.1, Humanoid) + end +-- print("===> " .. string.sub(msg, 1, 3) .. "(" .. emote .. ")") +end) + + +-- main program + +local runService = game:service("RunService"); + +-- print("bottom") + +-- initialize to idle +playAnimation("idle", 0.1, Humanoid) +pose = "Standing" + +while Figure.Parent~=nil do + local _, time = wait(0.1) + move(time) +end + + +]]> + + + + climb + + + + + http://www.roblox.com/asset/?id=507765644 + ClimbAnim + + + + + + fall + + + + + http://www.roblox.com/asset/?id=507767968 + FallAnim + + + + + + idle + + + + + http://www.roblox.com/asset/?id=507766388 + Animation1 + + + + Weight + 9 + + + + + + http://www.roblox.com/asset/?id=507766666 + Animation2 + + + + Weight + 1 + + + + + + + jump + + + + + http://www.roblox.com/asset/?id=507765000 + JumpAnim + + + + + + run + + + + + http://www.roblox.com/asset/?id=5077677142 + RunAnim + + + + + + sit + + + + + http://www.roblox.com/asset/?id=507768133 + SitAnim + + + + + + toolnone + + + + + http://www.roblox.com/asset/?id=507768375 + ToolNoneAnim + + + + + + walk + + + + + http://www.roblox.com/asset/?id=507777826 + RunAnim + + + + + + swimidle + + + + + http://www.roblox.com/asset/?id=481825862 + SwimIdle + + + + + + swim + + + + + http://www.roblox.com/asset/?id=507784897 + Swim + + + + + \ No newline at end of file diff --git a/2016/content/fonts/humanoidAnimateR15_4.rbxm b/2016/content/fonts/humanoidAnimateR15_4.rbxm new file mode 100644 index 0000000..722952a --- /dev/null +++ b/2016/content/fonts/humanoidAnimateR15_4.rbxm @@ -0,0 +1,942 @@ + + null + nil + + + false + + Animate + + animTable[animName][idx].weight) do + roll = roll - animTable[animName][idx].weight + idx = idx + 1 + end + return idx +end + +function playAnimation(animName, transitionTime, humanoid) + + local idx = rollAnimation(animName) + +-- print(animName .. " " .. idx .. " [" .. origRoll .. "]") + + local anim = animTable[animName][idx].anim + + -- switch animation + if (anim ~= currentAnimInstance) then + + if (currentAnimTrack ~= nil) then + currentAnimTrack:Stop(transitionTime) + currentAnimTrack:Destroy() + end + + if (runAnimTrack ~= nil) then + runAnimTrack:Stop(transitionTime) + runAnimTrack:Destroy() + end + + currentAnimSpeed = 1.0 + + -- load it to the humanoid; get AnimationTrack + currentAnimTrack = humanoid:LoadAnimation(anim) + + -- play the animation + currentAnimTrack:Play(transitionTime) + currentAnim = animName + currentAnimInstance = anim + + -- set up keyframe name triggers + if (currentAnimKeyframeHandler ~= nil) then + currentAnimKeyframeHandler:disconnect() + end + currentAnimKeyframeHandler = currentAnimTrack.KeyframeReached:connect(keyFrameReachedFunc) + + -- check to see if we need to blend a walk/run animation + if animName == "walk" then + local runAnimName = "run" + local runIdx = rollAnimation(runAnimName) + + runAnimTrack = humanoid:LoadAnimation(animTable[runAnimName][runIdx].anim) + runAnimTrack:Play(transitionTime) + + if (runAnimKeyframeHandler ~= nil) then + runAnimKeyframeHandler:disconnect() + end + runAnimKeyframeHandler = runAnimTrack.KeyframeReached:connect(keyFrameReachedFunc) + end + end + +end + +------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------- + +local toolAnimName = "" +local toolAnimTrack = nil +local toolAnimInstance = nil +local currentToolAnimKeyframeHandler = nil + +function toolKeyFrameReachedFunc(frameName) + if (frameName == "End") then +-- print("Keyframe : ".. frameName) + playToolAnimation(toolAnimName, 0.0, Humanoid) + end +end + + +function playToolAnimation(animName, transitionTime, humanoid) + + local idx = rollAnimation(animName) +-- print(animName .. " * " .. idx .. " [" .. origRoll .. "]") + local anim = animTable[animName][idx].anim + + if (toolAnimInstance ~= anim) then + + if (toolAnimTrack ~= nil) then + toolAnimTrack:Stop() + toolAnimTrack:Destroy() + transitionTime = 0 + end + + -- load it to the humanoid; get AnimationTrack + toolAnimTrack = humanoid:LoadAnimation(anim) + + -- play the animation + toolAnimTrack:Play(transitionTime) + toolAnimName = animName + toolAnimInstance = anim + + currentToolAnimKeyframeHandler = toolAnimTrack.KeyframeReached:connect(toolKeyFrameReachedFunc) + end +end + +function stopToolAnimations() + local oldAnim = toolAnimName + + if (currentToolAnimKeyframeHandler ~= nil) then + currentToolAnimKeyframeHandler:disconnect() + end + + toolAnimName = "" + toolAnimInstance = nil + if (toolAnimTrack ~= nil) then + toolAnimTrack:Stop() + toolAnimTrack:Destroy() + toolAnimTrack = nil + end + + + return oldAnim +end + +------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------- + + +function onRunning(speed) + if speed > 0.01 then + local scale = 16.0 + playAnimation("walk", 0.1, Humanoid) + setAnimationSpeed(speed / scale) + pose = "Running" + else + if emoteNames[currentAnim] == nil then + playAnimation("idle", 0.1, Humanoid) + pose = "Standing" + end + end +end + +function onDied() + pose = "Dead" +end + +function onJumping() + playAnimation("jump", 0.1, Humanoid) + jumpAnimTime = jumpAnimDuration + pose = "Jumping" +end + +function onClimbing(speed) + local scale = 5.0 + playAnimation("climb", 0.1, Humanoid) + setAnimationSpeed(speed / scale) + pose = "Climbing" +end + +function onGettingUp() + pose = "GettingUp" +end + +function onFreeFall() + if (jumpAnimTime <= 0) then + playAnimation("fall", fallTransitionTime, Humanoid) + end + pose = "FreeFall" +end + +function onFallingDown() + pose = "FallingDown" +end + +function onSeated() + pose = "Seated" +end + +function onPlatformStanding() + pose = "PlatformStanding" +end + +function onSwimming(speed) + if speed > 1.00 then + local scale = 10.0 + playAnimation("swim", 0.4, Humanoid) + setAnimationSpeed(speed / scale) + pose = "Swimming" + else + playAnimation("swimidle", 0.4, Humanoid) + pose = "Standing" + end +end + +function getTool() + for _, kid in ipairs(Figure:GetChildren()) do + if kid.className == "Tool" then return kid end + end + return nil +end + + +function animateTool() + + if (toolAnim == "None") then + playToolAnimation("toolnone", toolTransitionTime, Humanoid) + return + end + + if (toolAnim == "Slash") then + playToolAnimation("toolslash", 0, Humanoid) + return + end + + if (toolAnim == "Lunge") then + playToolAnimation("toollunge", 0, Humanoid) + return + end +end + +function getToolAnim(tool) + for _, c in ipairs(tool:GetChildren()) do + if c.Name == "toolanim" and c.className == "StringValue" then + return c + end + end + return nil +end + +local lastTick = 0 + +function move(time) + local amplitude = 1 + local frequency = 1 + local deltaTime = time - lastTick + lastTick = time + + local climbFudge = 0 + local setAngles = false + + if (jumpAnimTime > 0) then + jumpAnimTime = jumpAnimTime - deltaTime + end + + if (pose == "FreeFall" and jumpAnimTime <= 0) then + playAnimation("fall", fallTransitionTime, Humanoid) + elseif (pose == "Seated") then + playAnimation("sit", 0.5, Humanoid) + return + elseif (pose == "Running") then + playAnimation("walk", 0.1, Humanoid) + elseif (pose == "Dead" or pose == "GettingUp" or pose == "FallingDown" or pose == "Seated" or pose == "PlatformStanding") then + stopAllAnimations() + amplitude = 0.1 + frequency = 1 + setAngles = true + end + + -- Tool Animation handling + local tool = getTool() + if tool then + + local animStringValueObject = getToolAnim(tool) + + if animStringValueObject then + toolAnim = animStringValueObject.Value + -- message recieved, delete StringValue + animStringValueObject.Parent = nil + toolAnimTime = time + .3 + end + + if time > toolAnimTime then + toolAnimTime = 0 + toolAnim = "None" + end + + animateTool() + else + stopToolAnimations() + toolAnim = "None" + toolAnimInstance = nil + toolAnimTime = 0 + end +end + +-- connect events +Humanoid.Died:connect(onDied) +Humanoid.Running:connect(onRunning) +Humanoid.Jumping:connect(onJumping) +Humanoid.Climbing:connect(onClimbing) +Humanoid.GettingUp:connect(onGettingUp) +Humanoid.FreeFalling:connect(onFreeFall) +Humanoid.FallingDown:connect(onFallingDown) +Humanoid.Seated:connect(onSeated) +Humanoid.PlatformStanding:connect(onPlatformStanding) +Humanoid.Swimming:connect(onSwimming) + +-- setup emote chat hook +Game.Players.LocalPlayer.Chatted:connect(function(msg) + local emote = "" + if (string.sub(msg, 1, 3) == "/e ") then + emote = string.sub(msg, 4) + elseif (string.sub(msg, 1, 7) == "/emote ") then + emote = string.sub(msg, 8) + end + + if (pose == "Standing" and emoteNames[emote] ~= nil) then + playAnimation(emote, 0.1, Humanoid) + end +-- print("===> " .. string.sub(msg, 1, 3) .. "(" .. emote .. ")") +end) + + + +-- initialize to idle +playAnimation("idle", 0.1, Humanoid) +pose = "Standing" + +-- loop to handle timed state transitions and tool animations +while Figure.Parent~=nil do + local _, time = wait(0.1) + move(time) +end + +]]> + + + + climb + + + + + http://www.roblox.com/asset/?id=507765644 + ClimbAnim + + + + + + fall + + + + + http://www.roblox.com/asset/?id=507767968 + FallAnim + + + + + + idle + + + + + http://www.roblox.com/asset/?id=507766388 + Animation1 + + + + Weight + 9 + + + + + + http://www.roblox.com/asset/?id=507766666 + Animation2 + + + + Weight + 1 + + + + + + + jump + + + + + http://www.roblox.com/asset/?id=507765000 + JumpAnim + + + + + + run + + + + + http://www.roblox.com/asset/?id=507767714 + RunAnim + + + + + + sit + + + + + http://www.roblox.com/asset/?id=507768133 + SitAnim + + + + + + toollunge + + + + + http://www.roblox.com/asset/?id=507768375 + ToolLungeAnim + + + + + + walk + + + + + http://www.roblox.com/asset/?id=540798782 + WalkAnim + + + + + + swimidle + + + + + http://www.roblox.com/asset/?id=481825862 + SwimIdle + + + + + + swim + + + + + http://www.roblox.com/asset/?id=507784897 + Swim + + + + + + toolslash + + + + + http://www.roblox.com/asset/?id=507768375 + ToolSlashAnim + + + + + + toolnone + + + + + http://www.roblox.com/asset/?id=507768375 + ToolNoneAnim + + + + + + wave + + + + + http://www.roblox.com/asset/?id=507770239 + WaveAnim + + + + + + laugh + + + + + http://www.roblox.com/asset/?id=507770818 + LaughAnim + + + + + + point + + + + + http://www.roblox.com/asset/?id=507770453 + PointAnim + + + + + + cheer + + + + + http://www.roblox.com/asset/?id=507770677 + CheerAnim + + + + + + dance + + + + + http://www.roblox.com/asset/?id=507771019 + Animation1 + + + + Weight + 10 + + + + + + http://www.roblox.com/asset/?id=507771955 + Animation2 + + + + Weight + 10 + + + + + + http://www.roblox.com/asset/?id=507772104 + Animation3 + + + + Weight + 10 + + + + + + + dance2 + + + + + http://www.roblox.com/asset/?id=507776043 + Animation1 + + + + Weight + 10 + + + + + + http://www.roblox.com/asset/?id=507776720 + Animation2 + + + + Weight + 10 + + + + + + http://www.roblox.com/asset/?id=507776879 + Animation3 + + + + Weight + 10 + + + + + + + dance3 + + + + + http://www.roblox.com/asset/?id=507777268 + Animation1 + + + + Weight + 10 + + + + + + http://www.roblox.com/asset/?id=507777451 + Animation2 + + + + Weight + 10 + + + + + + http://www.roblox.com/asset/?id=507777623 + Animation3 + + + + Weight + 10 + + + + + + \ No newline at end of file diff --git a/2016/content/fonts/humanoidExtra.rbxm b/2016/content/fonts/humanoidExtra.rbxm new file mode 100644 index 0000000..ea08e27 --- /dev/null +++ b/2016/content/fonts/humanoidExtra.rbxm @@ -0,0 +1,11 @@ + + null + nil + + + false + Script + while script.Parent.Head==nil do wait(0.05) end function newSound(id) local sound = Instance.new("Sound") sound.SoundId = id sound.Parent = script.Parent.Head return sound end sDied = newSound("rbxasset://sounds/uuhhh.wav") sFallingDown = newSound("rbxasset://sounds/splat.wav") sFreeFalling = newSound("rbxasset://sounds/swoosh.wav") sGettingUp = newSound("rbxasset://sounds/hit.wav") sJumping = newSound("rbxasset://sounds/button.wav") sRunning = newSound("rbxasset://sounds/bfsl-minifigfoots1.mp3") sRunning.Looped = true function onDied() sDied:play() end function onState(state, sound) if state then sound:play() else sound:pause() end end function onRunning(speed) if speed>0 then sRunning:play() else sRunning:pause() end end while script.Parent.Humanoid==nil do wait(0.05) end h = script.Parent.Humanoid h.Died:connect(onDied) h.Running:connect(onRunning) h.Jumping:connect(function(state) onState(state, sJumping) end) h.GettingUp:connect(function(state) onState(state, sGettingUp) end) h.FreeFalling:connect(function(state) onState(state, sFreeFalling) end) h.FallingDown:connect(function(state) onState(state, sFallingDown) end) -- regeneration while true do local s = wait(1) local health=h.Health if health>0 and health<h.MaxHealth then health = health + 0.01*s*h.MaxHealth if health*1.05 < h.MaxHealth then h.Health = health else h.Health = h.MaxHealth end end end + + + \ No newline at end of file diff --git a/2016/content/fonts/humanoidSoundNewLocal.rbxmx b/2016/content/fonts/humanoidSoundNewLocal.rbxmx new file mode 100644 index 0000000..d0fb982 --- /dev/null +++ b/2016/content/fonts/humanoidSoundNewLocal.rbxmx @@ -0,0 +1,191 @@ + + null + nil + + + false + + Sound + + + + + false + + LocalSound + 0.1) then + local vol = math.min(1.0, math.max(0.0, (fallSpeed - 50) / 110)) + sLanding.Volume = vol + sLanding:Play() + fallSpeed = 0 + end + if speed>0.5 then + sRunning:Resume() + sRunning.Pitch = speed / 8.0 + else + sRunning:Pause() + end + prevState = "Run" +end + +function onSwimming(speed) + if (prevState ~= "Swim" and speed > 0.1) then + local volume = math.min(1.0, speed / 350) + sSplash.Volume = volume + sSplash:Play() + prevState = "Swim" + end + sClimbing:Stop() + sRunning:Stop() + sSwimming.Pitch = 1.6 + sSwimming:Resume() +end + +function onClimbing(speed) + sRunning:Stop() + sSwimming:Stop() + if speed>0.01 then + sClimbing:Resume() + sClimbing.Pitch = speed / 5.5 + else + sClimbing:Pause() + end + prevState = "Climb" +end +-- connect up + +function stopLoopedSounds() + sRunning:Stop() + sClimbing:Stop() + sSwimming:Stop() +end + +Humanoid.Died:connect(onDied) +Humanoid.Running:connect(onRunning) +Humanoid.Swimming:connect(onSwimming) +Humanoid.Climbing:connect(onClimbing) +Humanoid.Jumping:connect(function(state) onStateNoStop(state, sJumping) prevState = "Jump" end) +Humanoid.GettingUp:connect(function(state) stopLoopedSounds() onStateNoStop(state, sGettingUp) prevState = "GetUp" end) +Humanoid.FreeFalling:connect(function(state) stopLoopedSounds() onStateFall(state, sFreeFalling) prevState = "FreeFall" end) +Humanoid.FallingDown:connect(function(state) stopLoopedSounds() end) +Humanoid.StateChanged:connect(function(old, new) + if not (new.Name == "Dead" or + new.Name == "Running" or + new.Name == "RunningNoPhysics" or + new.Name == "Swimming" or + new.Name == "Jumping" or + new.Name == "GettingUp" or + new.Name == "Freefall" or + new.Name == "FallingDown") then + stopLoopedSounds() + end +end) + +]]> + + + + \ No newline at end of file diff --git a/2016/content/fonts/humanoidStatic.rbxm b/2016/content/fonts/humanoidStatic.rbxm new file mode 100644 index 0000000..1c9fcb7 --- /dev/null +++ b/2016/content/fonts/humanoidStatic.rbxm @@ -0,0 +1,12 @@ + + null + nil + + + false + Static + local Figure = script.Parent local Torso = Figure:findFirstChild("Torso") Torso:makeJoints() + true + + + \ No newline at end of file diff --git a/2016/content/fonts/leftarm.mesh b/2016/content/fonts/leftarm.mesh new file mode 100644 index 0000000..6e8bb63 Binary files /dev/null and b/2016/content/fonts/leftarm.mesh differ diff --git a/2016/content/fonts/leftleg.mesh b/2016/content/fonts/leftleg.mesh new file mode 100644 index 0000000..aba3a29 Binary files /dev/null and b/2016/content/fonts/leftleg.mesh differ diff --git a/2016/content/fonts/rightarm.mesh b/2016/content/fonts/rightarm.mesh new file mode 100644 index 0000000..14a52a4 Binary files /dev/null and b/2016/content/fonts/rightarm.mesh differ diff --git a/2016/content/fonts/rightleg.mesh b/2016/content/fonts/rightleg.mesh new file mode 100644 index 0000000..dab065d Binary files /dev/null and b/2016/content/fonts/rightleg.mesh differ diff --git a/2016/content/fonts/safechat.xml b/2016/content/fonts/safechat.xml new file mode 100644 index 0000000..199e3b2 --- /dev/null +++ b/2016/content/fonts/safechat.xml @@ -0,0 +1,737 @@ + + null + nil + Use the Chat menu to talk to me. + I can only see menu chats. + + Hello + + Hi + Hi there! + Hi everyone + + + Howdy + Howdy partner! + + + Greetings + Greetings everyone + Greetings Robloxians! + Seasons greetings! + + + Welcome + Welcome to my place + Welcome to our base + Welcome to my barbeque + + Hey there! + + What's up? + How are you doing? + How's it going? + What's new? + + + Good day + Good morning + Good afternoon + Good evening + Good night + + + Silly + Waaaaaaaz up?! + Hullo! + Behold greatness, mortals! + Pardon me, is this Sparta? + THIS IS SPARTAAAA! + + + Happy Holidays! + Happy New Year! + Happy Valentine's Day! + Beware the Ides of March! + Happy St. Patrick's Day! + Happy Easter! + Happy Earth Day! + Happy 4th of July! + Happy Thanksgiving! + Happy Halloween! + Happy Hanukkah! + Merry Christmas! + Happy Halloween! + Happy Earth Day! + Happy May Day! + Happy Towel Day! + Happy ROBLOX Day! + Happy LOL Day! + + + + Goodbye + + Good Night + Sweet dreams + Go to sleep! + Lights out! + Bedtime + Going to bed now + + + Later + See ya later + Later gator! + See you tomorrow + + + Bye + Hasta la bye bye! + + I'll be right back + I have to go + + Farewell + Take care + Have a nice day + Goodluck! + Ta-ta for now! + + + Peace + Peace out! + Peace dudes! + Rest in pieces! + + + Silly + To the batcave! + Over and out! + Happy trails! + I've got to book it! + Tootles! + Smell you later! + GG! + My house is on fire! gtg. + + + + Friend + Wanna be friends? + + Follow me + Come to my place! + Come to my base! + Follow me, team! + Follow me + + + Your place is cool + Your place is fun + Your place is awesome + Your place looks good + This place is awesome! + + + Thank you + Thanks for playing + Thanks for visiting + Thanks for everything + No, thank you + Thanx + + + No problem + Don't worry + That's ok + np + + + You are ... + You are great! + You are good! + You are cool! + You are funny! + You are silly! + You are awesome! + You are doing something I don't like, please stop + + + I like ... + I like your name + I like your shirt + I like your place + I like your style + I like you + I like items + I like money + + + Sorry + My bad! + I'm sorry + Whoops! + Please forgive me. + I forgive you. + I didn't mean to do that. + Sorry, I'll stop now. + + + + Questions + + Who? + Who wants to be my friend? + Who wants to be on my team? + Who made this brilliant game? + LOLWHO? + + + What? + What is your favorite animal? + What is your favorite game? + What is your favorite movie? + What is your favorite TV show? + What is your favorite music? + What are your hobbies? + LOLWUT? + + + When? + When are you online? + When is the new version coming out? + When can we play again? + When will your place be done? + + + Where? + Where do you want to go? + Where are you going? + Where am I?! + Where did you go? + + + How? + How are you today? + How did you make this cool place? + LOLHOW? + + + Can I... + Can I have a tour? + Can I be on your team? + Can I be your friend? + Can I try something? + Can I have that please? + Can I have that back please? + Can I have borrow your hat? + Can I have borrow your gear? + + + + Answers + + You need help? + Check out the news section + Check out the help section + Read the wiki! + All the answers are in the wiki! + I will help you with this. + + + Some people ... + Me + Not me + You + All of us + Everyone but you + Builderman! + Telamon! + My team + My group + Mom + Dad + Sister + Brother + Cousin + Grandparent + Friend + + + Time ... + In the morning + In the afternoon + At night + Tomorrow + This week + This month + Sometime + Sometimes + Whenever you want + Never + After this + In 10 minutes + In a couple hours + In a couple days + + + Animals + + Cats + Lion + Tiger + Leopard + Cheetah + + + Dogs + Wolves + Beagle + Collie + Dalmatian + Poodle + Spaniel + Shepherd + Terrier + Retriever + + + Horses + Ponies + Stallions + Pwnyz + + + Reptiles + Dinosaurs + Lizards + Snakes + Turtles! + + Hamster + Monkey + Bears + + Fish + Goldfish + Sharks + Sea Bass + Halibut + Tropical Fish + + + Birds + Eagles + Penguins + Parakeets + Owls + Hawks + Pidgeons + + Elephants + + Mythical Beasts + Dragons + Unicorns + Sea Serpents + Sphinx + Cyclops + Minotaurs + Goblins + Honest Politicians + Ghosts + Scylla and Charybdis + + + + Games + + Roblox + BrickBattle + Community Building + Roblox Minigames + Contest Place + + Action + Puzzle + Strategy + Racing + RPG + Obstacle Course + Tycoon + + Board games + Chess + Checkers + Settlers of Catan + Tigris and Euphrates + El Grande + Stratego + Carcassonne + + + + Sports + Hockey + Soccer + Football + Baseball + Basketball + Volleyball + Tennis + Sports team practice + + Watersports + Surfing + Swimming + Water Polo + + + Winter sports + Skiing + Snowboarding + Sledding + Skating + + + Adventure + Rock climbing + Hiking + Fishing + Horseback riding + + + Wacky + Foosball + Calvinball + Croquet + Cricket + Dodgeball + Squash + Trampoline + + + + Movies/TV + Science Fiction + + Animated + Anime + + Comedy + Romantic + Action + Fantasy + + + Music + Country + Jazz + Rap + Hip-hop + Techno + Classical + Pop + Rock + + + Hobbies + + Computers + Building computers + Videogames + Coding + Hacking + + + The Internet + lol. teh internets! + Watching vids + + Dance + Gymnastics + + Martial Arts + Karate + Judo + Taikwon Do + Wushu + Street fighting + + Listening to music + + Music lessons + Playing in my band + Playing piano + Playing guitar + Playing violin + Playing drums + Playing a weird instrument + + Arts and crafts + + + Location + + USA + + West + Alaska + Arizona + California + Colorado + Hawaii + Idaho + Montana + Nevada + New Mexico + Oregon + Utah + Washington + Wyoming + + + Midwest + Illinois + Indiana + Iowa + Kansas + Michigan + Minnesota + Missouri + Nebraska + North Dakota + Ohio + South Dakota + Wisconsin + + + Northeast + Connecticut + Delaware + Maine + Maryland + Massachusetts + New Hampshire + New Jersey + New York + Pennsylvania + Rhode Island + Vermont + + + South + Alabama + Arkansas + Florida + Georgia + Kentucky + Louisiana + Mississippi + North Carolina + Oklahoma + South Carolina + Tennessee + Texas + Virginia + West Virginia + + + + Canada + Alberta + British Columbia + Manitoba + New Brunswick + Newfoundland + Northwest Territories + Nova Scotia + Nunavut + Ontario + Prince Edward Island + Quebec + Saskatchewan + Yukon + + Mexico + Central America + + Europe + + Great Britain + England + Scotland + Wales + Northern Ireland + + France + Germany + Spain + Italy + Poland + Switzerland + Greece + Romania + Netherlands + + + Asia + China + India + Japan + Korea + Russia + Vietnam + + + South America + Argentina + Brazil + + + Africa + Eygpt + Swaziland + + Australia + Middle East + Antarctica + New Zealand + + + Age + Rugrat + Kid + Tween + Teen + Twenties + Old + Ancient + Mesozoic + I don't want to say my age. Don't ask. + + + Mood + Good + Great! + Not bad + Sad + Hyper + Chill + Happy + Kind of mad + + Boy + Girl + I don't want to say boy or girl. Don't ask. + + + Game + Let's build + Let's battle + Nice one! + So far so good! + Lucky shot! + Oh man! + I challenge you to a fight! + Help me with this + Let's go to your game + Can you show me how do to that? + Backflip! + Frontflip! + Dance! + I'm on your side! + + Game Commands + regen + reset + go + fix + respawn + + + + Silly + Muahahahaha! + all your base are belong to me! + GET OFF MAH LAWN + TEH EPIK DUCK IS COMING!!! + ROFL + + 1337 + i r teh pwnz0r! + w00t! + z0mg h4x! + ub3rR0xXorzage! + + + + Yes + Absolutely! + Rock on! + Totally! + Juice! + Yay! + Yesh + + + No + Ummm. No. + ... + Stop! + Go away! + Don't do that + Stop breaking the rules + I don't want to + + + Ok + Well... ok + Sure + + + Uncertain + Maybe + I don't know + idk + I can't decide + Hmm... + + + + :-) + :-( + :D + :-O + lol + =D + D= + XD + ;D + ;) + O_O + =) + @_@ + >_< + T_T + ^_^ + <(0_0<) <(0_0)> (>0_0)> KIRBY DANCE + )'; + :3 + + + Ratings + Rate it! + I give it a 1 out of 10 + I give it a 2 out of 10 + I give it a 3 out of 10 + I give it a 4 out of 10 + I give it a 5 out of 10 + I give it a 6 out of 10 + I give it a 7 out of 10 + I give it a 8 out of 10 + I give it a 9 out of 10 + I give it a 10 out of 10! + + diff --git a/2016/content/fonts/torso.mesh b/2016/content/fonts/torso.mesh new file mode 100644 index 0000000..43d58d1 Binary files /dev/null and b/2016/content/fonts/torso.mesh differ diff --git a/2016/content/fonts/zekton_rg.ttf b/2016/content/fonts/zekton_rg.ttf new file mode 100644 index 0000000..8ad2dd1 Binary files /dev/null and b/2016/content/fonts/zekton_rg.ttf differ diff --git a/2016/content/music/bass.wav b/2016/content/music/bass.wav new file mode 100644 index 0000000..5f4b791 Binary files /dev/null and b/2016/content/music/bass.wav differ diff --git a/2016/content/music/ufofly.wav b/2016/content/music/ufofly.wav new file mode 100644 index 0000000..359710b Binary files /dev/null and b/2016/content/music/ufofly.wav differ diff --git a/2016/content/particles/explosion.particle b/2016/content/particles/explosion.particle new file mode 100644 index 0000000..a7c5e1f --- /dev/null +++ b/2016/content/particles/explosion.particle @@ -0,0 +1,192 @@ +///////////////////////////////////////////////////////// +// The fast rising center plume of the explosion. +// Grows and rotates. +///////////////////////////////////////////////////////// +particle_system explosion/explosionPlume +{ + quota 40 + material explosion/explosionMatl + particle_width 6 + particle_height 6 + cull_each false + renderer billboard + billboard_type point + sorted false + local_space false + iteration_interval 0 + nonvisible_update_timeout 0 + billboard_type point + billboard_origin center + billboard_rotation_type vertex + common_up_vector 0 1 0 + point_rendering false + accurate_facing false + + emitter Ellipsoid + { + angle 16 + colour 1.0 0.4 0.2 1.0 + colour_range_start 1.0 0.4 0.2 1.0 + colour_range_end 0.7 0.2 0.1 0.6 + direction 0 1 0 + emission_rate 100 + position 0 6 0 + velocity 25 + velocity_min 25 + velocity_max 38 + time_to_live 1.5 + time_to_live_min 1.5 + time_to_live_max 1.5 + duration 0.2 + duration_min 0.2 + duration_max 0.2 + repeat_delay 10000 + repeat_delay_min 10000 + repeat_delay_max 10000 + width 3 + height 3 + depth 3 + } + + affector ColourFader + { + red -0.9 + green -0.5 + blue -0.3 + alpha -1.0 + } + affector Scaler + { + rate 13 + } + affector Rotator + { + rotation_speed_range_start 100 + rotation_speed_range_end 200 + rotation_range_start 100 + rotation_range_end 300 + } +} + + +///////////////////////////////////////////////////////// +//The slow moving base of the explosion. +///////////////////////////////////////////////////////// +particle_system explosion/explosionBase +{ + quota 40 + material explosion/explosionMatl + particle_width 20 + particle_height 20 + cull_each false + renderer billboard + billboard_type point + sorted false + local_space false + iteration_interval 0 + nonvisible_update_timeout 0 + billboard_type point + billboard_origin center + billboard_rotation_type vertex + common_up_vector 0 1 0 + point_rendering false + accurate_facing false + + emitter Ellipsoid + { + angle 100 + colour 1.0 0.4 0.2 1.0 + colour_range_start 1.0 0.4 0.2 1.0 + colour_range_end 0.7 0.2 0.1 0.6 + direction 0 1 0 + emission_rate 80 + position 0 0 0 + velocity 11 + velocity_min 11 + velocity_max 16 + time_to_live 1.5 + time_to_live_min 1.5 + time_to_live_max 1.5 + duration 0.2 + duration_min 0.2 + duration_max 0.2 + repeat_delay 10000 + repeat_delay_min 10000 + repeat_delay_max 10000 + width 15 + height 15 + depth 15 + } + + affector ColourFader + { + red -0.9 + green -0.5 + blue -0.3 + alpha -1.0 + } + affector Scaler + { + rate 5 + } +} + + +///////////////////////////////////////////////////////// +// The fast flying sparks of the explosion. +///////////////////////////////////////////////////////// +particle_system explosion/explosionSparks +{ + quota 120 + material explosion/explosparkMatl + particle_width 3 + particle_height 3 + cull_each false + renderer billboard + billboard_type point + sorted false + local_space false + iteration_interval 0 + nonvisible_update_timeout 0 + billboard_type point + billboard_origin center + billboard_rotation_type vertex + common_up_vector 0 1 0 + point_rendering false + accurate_facing false + + emitter Point + { + angle 120 + colour 1.0 0.6 0.4 1.0 + colour_range_start 1.0 0.6 0.4 1.0 + colour_range_end 1.0 0.6 0.4 1.0 + direction 0 1 0 + emission_rate 900 + position 0 0 0 + velocity 30 + velocity_min 30 + velocity_max 60 + time_to_live 1.2 + time_to_live_min 1.2 + time_to_live_max 1.2 + duration 0.2 + duration_min 0.1 + duration_max 0.1 + repeat_delay 10000 + repeat_delay_min 10000 + repeat_delay_max 10000 + } + + affector ColourFader + { + red -0.7 + green -0.6 + blue -0.4 + alpha -0.7 + } + affector Scaler + { + rate -3 + } +} diff --git a/2016/content/particles/fire.particle b/2016/content/particles/fire.particle new file mode 100644 index 0000000..442fe8e --- /dev/null +++ b/2016/content/particles/fire.particle @@ -0,0 +1,59 @@ +///////////////////////////////////////////////////////// +// Fire +///////////////////////////////////////////////////////// + +// height and width modified by RbxParticleFactory for user input size +particle_system FireTemplate +{ + material fireMat1 + particle_width 5 + particle_height 5 + cull_each false + quota 40 + renderer billboard + billboard_type point + point_rendering false + accurate_facing false + sorted false + local_space false + iteration_interval 0 + nonvisible_update_timeout 0 + + // emission rate is modified by RbxParticleManager for throttling + // of particle systems + emitter Point + { + colour_range_start 240 240 240 + colour_range_end 240 240 240 + angle 18 + emission_rate 35 + time_to_live_min 1 + time_to_live_max 1 + direction 0 1 0 + velocity_min 2.33 + velocity_max 7.0 + } + affector Rotator + { + rotation_range_start 0 + rotation_range_end 365 + rotation_speed_range_start 0 + rotation_speed_range_end 100 + } + // modified in RbxParticleFactory for user input size + affector Scaler + { + rate -5.0 + } + // modified in RbxParticleFactory for user input colors + affector ColourInterpolator + { + time0 0 + colour0 240 240 240 1 + + time1 1 + colour1 240 240 240 1 + + } + +} diff --git a/2016/content/particles/forceFieldBeam.particle b/2016/content/particles/forceFieldBeam.particle new file mode 100644 index 0000000..22914a9 --- /dev/null +++ b/2016/content/particles/forceFieldBeam.particle @@ -0,0 +1,55 @@ +///////////////////////////////////////////////////////// +// Beam +///////////////////////////////////////////////////////// +particle_system forceField/beam +{ + quota 40 + material PE/lensflare + particle_width 0.5 + particle_height 2 + cull_each false + billboard_type oriented_common + common_direction 0 1 0 + + emitter Ring + { + colour 1 1 1 0 + angle 0 + direction 0 1 0 + emission_rate 20 + position 0 -2 0 + velocity_min 2 + velocity_max 5 + time_to_live 2 + duration 0 + duration_min 0 + duration_max 0 + repeat_delay 0 + repeat_delay_min 0 + repeat_delay_max 0 + width 5 + height 5 + depth 1 + inner_width 0.8 + inner_height 0.8 + } + + //affector LinearForce +// { + // force_vector 0 -1 0 + // force_application add + //} + + affector ColourFader2 + { + red1 0 + green1 0 + blue1 0 + alpha1 1 + red2 0 + green2 0 + blue2 0 + alpha2 -1 + state_change 1 + } +} diff --git a/2016/content/particles/forceFieldRadial.particle b/2016/content/particles/forceFieldRadial.particle new file mode 100644 index 0000000..807f93d --- /dev/null +++ b/2016/content/particles/forceFieldRadial.particle @@ -0,0 +1,51 @@ +///////////////////////////////////////////////////////// +// Radial +///////////////////////////////////////////////////////// +particle_system forceField/radial +{ + material PE/lensflare + particle_width 5 + particle_height 5 + cull_each false + quota 6 + renderer billboard + billboard_type point + point_rendering false + accurate_facing false + sorted false + local_space false + iteration_interval 0 + nonvisible_update_timeout 0 + + // emission rate is modified by RbxParticleManager for throttling + // of particle systems + emitter Point + { + angle 18 + emission_rate 2 + time_to_live_min 2 + time_to_live_max 2 + direction 0 1 0 + velocity_min 0 + velocity_max 0.1 + } + affector Rotator + { + rotation_range_start 0 + rotation_range_end 365 + rotation_speed_range_start 4 + rotation_speed_range_end 100 + } + // modified in RbxParticleFactory for user input size + affector Scaler + { + rate 6.0 + } + affector ColourFader + { + red 0 + green 0 + blue 0 + alpha -0.5 + } +} diff --git a/2016/content/particles/smoke.particle b/2016/content/particles/smoke.particle new file mode 100644 index 0000000..79c6c16 --- /dev/null +++ b/2016/content/particles/smoke.particle @@ -0,0 +1,57 @@ +particle_system SmokeTemplate +{ + quota 70 + material PE/smoke + particle_width 1 + particle_height 1 + cull_each false + renderer billboard + billboard_type point + + emitter Box + { + angle 180 + colour 0.8 0.8 0.8 0.3 + colour_range_start 0.8 0.8 0.8 0.3 + colour_range_end 0.8 0.8 0.8 0.3 + direction 0 1 0 + emission_rate 6 + position 0 0 0 + velocity 0.1 + velocity_min 0 + velocity_max 0.1 + time_to_live 4 + time_to_live_min 4 + time_to_live_max 6 + duration 0 + duration_min 0 + duration_max 0 + repeat_delay 0 + repeat_delay_min 0 + repeat_delay_max 0 + width 1 + height 1 + depth 1 + } + + affector ColourFader + { + red -0.11 + green -0.11 + blue -0.11 + alpha -0.1 + } + + affector Scaler + { + rate 1.5 + } + + affector Rotator + { + rotation_speed_range_start 0 + rotation_speed_range_end 0 + rotation_range_start 0 + rotation_range_end 0 + } +} diff --git a/2016/content/particles/sparkles.particle b/2016/content/particles/sparkles.particle new file mode 100644 index 0000000..60102d0 --- /dev/null +++ b/2016/content/particles/sparkles.particle @@ -0,0 +1,49 @@ +///////////////////////////////////////////////////////// +// Sparkles +///////////////////////////////////////////////////////// +particle_system SparklesTemplate +{ + quota 40 + material sparkle/sparkleMatl + particle_width 0.8 + particle_height 1 + cull_each false + renderer billboard + sorted false + local_space false + iteration_interval 0 + nonvisible_update_timeout 0 + billboard_type point + billboard_origin center + billboard_rotation_type vertex + common_up_vector 0 1 0 + point_rendering false + accurate_facing false + + emitter Point + { + angle 180 + direction 0 -1 0 + emission_rate 35 + position 0 0 0 + velocity_min 4 + velocity_max 8 + duration 0.0 + time_to_live 1.1 + //repeat_delay 2.0 + } + affector Rotator + { + rotation_speed_range_end 360 + rotation_range_start 0 + rotation_range_end 360 + } + affector ColourFader + { + red 0 + green 0 + blue 0 + alpha -1 + } +} + diff --git a/2016/content/scripts/CoreScripts/BuildToolsScripts/BuildToolsScript.lua b/2016/content/scripts/CoreScripts/BuildToolsScripts/BuildToolsScript.lua new file mode 100644 index 0000000..a00b3ad --- /dev/null +++ b/2016/content/scripts/CoreScripts/BuildToolsScripts/BuildToolsScript.lua @@ -0,0 +1,214 @@ +-- This script is responsible for loading in all build tools for build mode + +-- Script Globals +local buildTools = {} +local currentTools = {} + +local BaseUrl = game:GetService("ContentProvider").BaseUrl:lower() + +if BaseUrl:find("www.roblox.com") or BaseUrl:find("gametest1") then + DeleteToolID = 73089190 + PartSelectionID = 73089166 + CloneToolID = 73089204 + RotateToolID = 73089214 + ConfigToolID = 73089239 + WiringToolID = 73089259 + classicToolID = 58921588 +elseif BaseUrl:find("gametest2") then + DeleteToolID = 70353317 + PartSelectionID = 70353315 + CloneToolID = 70353314 + RotateToolID = 70353318 + ConfigToolID = 70353319 + WiringToolID = 70353320 + classicToolID = 58921588 +end + +local player = nil +local backpack = nil + +-- Basic Functions +local function waitForProperty(instance, name) + while not instance[name] do + instance.Changed:wait() + end +end + +local function waitForChild(instance, name) + while not instance:FindFirstChild(name) do + instance.ChildAdded:wait() + end +end + +waitForProperty(game:GetService("Players"),"LocalPlayer") +waitForProperty(game:GetService("Players").LocalPlayer,"userId") + +-- we aren't in a true build mode session, don't give build tools and delete this script +if game:GetService("Players").LocalPlayer.userId < 1 then + script:Destroy() + return -- this is probably not necessesary, doing it just in case +end + +-- Functions +function getLatestPlayer() + waitForProperty(game:GetService("Players"),"LocalPlayer") + player = game:GetService("Players").LocalPlayer + waitForChild(player,"Backpack") + backpack = player.Backpack +end + +function waitForCharacterLoad() + + local startTick = tick() + + local playerLoaded = false + + local success = pcall(function() playerLoaded = player.AppearanceDidLoad end) --TODO: remove pcall once this in client on prod + if not success then return false end + + while not playerLoaded do + player.Changed:wait() + playerLoaded = player.AppearanceDidLoad + end + + return true +end + +function showBuildToolsTutorial() + local tutorialKey = "BuildToolsTutorial" + if UserSettings().GameSettings:GetTutorialState(tutorialKey) == true then return end --already have shown tutorial + + local RbxGui = LoadLibrary("RbxGui") + + local frame, showTutorial, dismissTutorial, gotoPage = RbxGui.CreateTutorial("Build", tutorialKey, false) + local firstPage = RbxGui.CreateImageTutorialPage(" ", "http://www.roblox.com/asset/?id=59162193", 359, 296, function() dismissTutorial() end, true) + + RbxGui.AddTutorialPage(frame, firstPage) + frame.Parent = game:GetService("CoreGui"):FindFirstChild("RobloxGui") + + game:GetService("GuiService"):AddCenterDialog(frame, Enum.CenterDialogType.UnsolicitedDialog, + --showFunction + function() + frame.Visible = true + showTutorial() + end, + --hideFunction + function() + frame.Visible = false + end + ) + + wait(1) + showTutorial() +end + +function clearLoadout() + currentTools = {} + + local backpackChildren = game:GetService("Players").LocalPlayer.Backpack:GetChildren() + for i = 1, #backpackChildren do + if backpackChildren[i]:IsA("Tool") or backpackChildren[i]:IsA("HopperBin") then + table.insert(currentTools,backpackChildren[i]) + end + end + + if game:GetService("Players").LocalPlayer["Character"] then + local characterChildren = game:GetService("Players").LocalPlayer.Character:GetChildren() + for i = 1, #characterChildren do + if characterChildren[i]:IsA("Tool") or characterChildren[i]:IsA("HopperBin") then + table.insert(currentTools,characterChildren[i]) + end + end + end + + for i = 1, #currentTools do + currentTools[i].Parent = nil + end +end + +function giveToolsBack() + for i = 1, #currentTools do + currentTools[i].Parent = game:GetService("Players").LocalPlayer.Backpack + end +end + +function backpackHasTool(tool) + local backpackChildren = backpack:GetChildren() + for i = 1, #backpackChildren do + if backpackChildren[i] == tool then + return true + end + end + return false +end + +function getToolAssetID(assetID) + local newTool = game:GetService("InsertService"):LoadAsset(assetID) + local toolChildren = newTool:GetChildren() + for i = 1, #toolChildren do + if toolChildren[i]:IsA("Tool") then + return toolChildren[i] + end + end + return nil +end + +-- remove legacy identifiers +-- todo: determine if we still need this +function removeBuildToolTag(tool) + if tool:FindFirstChild("RobloxBuildTool") then + tool.RobloxBuildTool:Destroy() + end +end + +function giveAssetId(assetID,toolName) + local theTool = getToolAssetID(assetID,toolName) + if theTool and not backpackHasTool(theTool) then + removeBuildToolTag(theTool) + theTool.Parent = backpack + table.insert(buildTools,theTool) + end +end + +function loadBuildTools() + giveAssetId(PartSelectionID) + giveAssetId(DeleteToolID) + giveAssetId(CloneToolID) + giveAssetId(RotateToolID) + giveAssetId(WiringToolID) + giveAssetId(ConfigToolID) + + -- deprecated tools + giveAssetId(classicToolID) +end + +function givePlayerBuildTools() + getLatestPlayer() + + clearLoadout() + + loadBuildTools() + + giveToolsBack() +end + +function takePlayerBuildTools() + for k,v in ipairs(buildTools) do + v.Parent = nil + end + buildTools = {} +end + + +-- Script start +getLatestPlayer() +waitForCharacterLoad() +givePlayerBuildTools() + +-- If player dies, we make sure to give them build tools again +player.CharacterAdded:connect(function() + takePlayerBuildTools() + givePlayerBuildTools() +end) + +showBuildToolsTutorial() diff --git a/2016/content/scripts/CoreScripts/BuildToolsScripts/PersonalServerScript.lua b/2016/content/scripts/CoreScripts/BuildToolsScripts/PersonalServerScript.lua new file mode 100644 index 0000000..12b710d --- /dev/null +++ b/2016/content/scripts/CoreScripts/BuildToolsScripts/PersonalServerScript.lua @@ -0,0 +1,206 @@ +-- Personal Server Script + +----------------- +--| Constants |-- +----------------- + +local CHANGES_PER_PLAYER = 100 -- Saving also occurs every time the number of edits reaches this number times the number of players +local SAVE_CHECK_INTERVAL = 1800 -- should be set in seconds, this is how long we wait to force a save, as long as at least one change has been made +local MIN_SAVE_TIME = 900 -- At least this many seconds will pass before saving again + +----------------- +--| Variables |-- +----------------- + +local ContentProviderService = game:GetService('ContentProvider') +local PlayersService = game:GetService('Players') +local RunService = game:GetService("RunService") + +local StartingPlayerRanks = {} +local RbxUtil = nil + +local LastSaveTime = 0 +local ChangeCount = 0 +local TryingToSave = false +local NumberOfChangesBeforeSaveAbsolute = CHANGES_PER_PLAYER +local GameRunning = true +local WaitingToSave = false + +local PlaceId = game.PlaceId +local Url = ContentProviderService.BaseUrl +local UrlBase = Url:match('^http://www\.(.-)/?$') -- Turns "http://www.gametest1.robloxlabs.com/" into "gametest1.robloxlabs.com" +local ApiProxyUrl = 'https://api.' .. UrlBase +local DataFarmProtocol = 'http' +local DataFarmUsesHttpsFlagExists, DataFarmUsesHttpsFlagValue = pcall(function () return settings():GetFFlag("DataFarmUsesHttps") end) +if DataFarmUsesHttpsFlagExists and DataFarmUsesHttpsFlagValue then + DataFarmProtocol = 'https' +end +local DataFarmUrl = DataFarmProtocol .. '://data.' .. UrlBase + +----------------- +--| Functions |-- +----------------- + +function GetRbxUtil() + if not RbxUtil then + RbxUtil = LoadLibrary("RbxUtility") + end + return RbxUtil +end + +-- Checks the full hierarchy of an instance for archivability +local function IsArchivable(instance) + if instance == workspace then + return true + elseif not instance.Archivable then + return false + else + return IsArchivable(instance.Parent) + end +end + +local function UpdateSaveOnChangeAmount() + local players = PlayersService:GetPlayers() + NumberOfChangesBeforeSaveAbsolute = #players * CHANGES_PER_PLAYER +end + +local function OnPlayerAdded(player) + if player:IsA('Player') then + + local getRankUrl = ApiProxyUrl .. '/RoleSets/GetRoleSetForUser?placeId=' .. tostring(PlaceId) .. '&userId=' .. tostring(player.userId) + local serverRankTable = nil + pcall(function() + serverRankTable = GetRbxUtil().DecodeJSON(game:HttpGetAsync(getRankUrl)) + end) + + local playerRank = 0 + if serverRankTable and type(serverRankTable) == 'table' then + for k, v in pairs(serverRankTable) do + if k == "data" then + if v["Rank"] then + playerRank = v["Rank"] + end + end + end + end + + player.PersonalServerRank = playerRank + StartingPlayerRanks[player] = playerRank + + UpdateSaveOnChangeAmount() + end +end + +local function OnPlayerRemoved(player) + if player:IsA('Player') then + UpdateSaveOnChangeAmount() + + if StartingPlayerRanks[player] then + local playerRank = player.PersonalServerRank + if StartingPlayerRanks[player] ~= playerRank then -- Don't need to make web call if rank is the same + local setRankUrl = ApiProxyUrl .. '/RoleSets/PrivilegedSetUserRoleSetRank?placeId=' .. tostring(PlaceId) .. '&userId=' .. tostring(player.userId) .. '&newRank=' .. tostring(playerRank) + ypcall(function() game:HttpPostAsync(setRankUrl, 'SetPersonalServerRank') end) + end + StartingPlayerRanks[player] = nil + end + end +end + +local function DoSave() + if GameRunning then + ChangeCount = 0 + LastSaveTime = tick() + game:ServerSave() + end +end + +local function TrySave() + if not TryingToSave then + TryingToSave = true + + local now = tick() + + if now - LastSaveTime >= MIN_SAVE_TIME then + DoSave() + elseif not WaitingToSave then -- Save after cooldown + WaitingToSave = true + delay(LastSaveTime + MIN_SAVE_TIME - now, function() + DoSave() + WaitingToSave = false + end) + end + + TryingToSave = false + end +end + +-- Save based on number of edits to workspace +local function OnEdit(descendant) + if IsArchivable(descendant) then + ChangeCount = ChangeCount + 1 + if ChangeCount >= NumberOfChangesBeforeSaveAbsolute then + TrySave() + end + end +end + +-- Make sure we save every interval regardless of number of edits, so long as there is one +local function CheckForSaveOnInterval() + while true do + wait(SAVE_CHECK_INTERVAL) + + if tick() - LastSaveTime >= SAVE_CHECK_INTERVAL and ChangeCount > 0 then + TrySave() + end + end +end + +-------------------- +--| Script Logic |-- +-------------------- + +game:WaitForChild('Workspace') + +pcall(function() + game.IsPersonalServer = true + + if not workspace:FindFirstChild("PSVariable") then + local psVar = Instance.new("BoolValue") + psVar.Name = "PSVariable" + psVar.Archivable = false + psVar.Parent = workspace + end +end) + +PlayersService.PlayerAdded:connect(OnPlayerAdded) +PlayersService.ChildRemoved:connect(OnPlayerRemoved) +for _, player in pairs(PlayersService:GetPlayers()) do + OnPlayerAdded(player) +end + +local useSubdomainsFlagExists, useSubdomainsFlagValue = pcall(function () return settings():GetFFlag("UseNewSubdomainsInCoreScripts") end) +local saveUrlBase = Url +if(useSubdomainsFlagExists and useSubdomainsFlagValue and DataFarmUrl~=nil) then + saveUrlBase = DataFarmUrl +end + +if saveUrlBase~=nil then + game:SetServerSaveUrl(saveUrlBase .. "/Data/AutoSave.ashx?assetId=" .. PlaceId) +end + +if pcall(function() + game.Close:connect( + function() + GameRunning = false + game:ServerSave() + end) + end) == false then + print("!Error in Game.Close:connect") +end + +RunService:Run() + +game:GetService("Workspace").DescendantAdded:connect(OnEdit) +game:GetService("Workspace").DescendantRemoving:connect(OnEdit) + +spawn(CheckForSaveOnInterval) diff --git a/2016/content/scripts/CoreScripts/ContextActionTouch.lua b/2016/content/scripts/CoreScripts/ContextActionTouch.lua new file mode 100644 index 0000000..823f3e6 --- /dev/null +++ b/2016/content/scripts/CoreScripts/ContextActionTouch.lua @@ -0,0 +1,268 @@ +-- ContextActionTouch.lua +-- Copyright ROBLOX 2014, created by Ben Tkacheff +-- this script controls ui and firing of lua functions that are bound in ContextActionService for touch inputs +-- Essentially a user can bind a lua function to a key code, input type (mousebutton1 etc.) and this + +-- Variables +local contextActionService = game:GetService("ContextActionService") +local userInputService = game:GetService("UserInputService") +local isTouchDevice = userInputService.TouchEnabled +local functionTable = {} +local buttonVector = {} +local buttonScreenGui = nil +local buttonFrame = nil + +local ContextDownImage = "http://www.roblox.com/asset/?id=97166756" +local ContextUpImage = "http://www.roblox.com/asset/?id=97166444" + +local oldTouches = {} + +local buttonPositionTable = { + [1] = UDim2.new(0,123,0,70), + [2] = UDim2.new(0,30,0,60), + [3] = UDim2.new(0,180,0,160), + [4] = UDim2.new(0,85,0,-25), + [5] = UDim2.new(0,185,0,-25), + [6] = UDim2.new(0,185,0,260), + [7] = UDim2.new(0,216,0,65) + } +local maxButtons = #buttonPositionTable + +-- Preload images +game:GetService("ContentProvider"):Preload(ContextDownImage) +game:GetService("ContentProvider"):Preload(ContextUpImage) + +repeat wait() until game:GetService("Players").LocalPlayer + +local localPlayer = game:GetService("Players").LocalPlayer + +function createContextActionGui() + if not buttonScreenGui and isTouchDevice then + buttonScreenGui = Instance.new("ScreenGui") + buttonScreenGui.Name = "ContextActionGui" + + buttonFrame = Instance.new("Frame") + buttonFrame.BackgroundTransparency = 1 + buttonFrame.Size = UDim2.new(0.3,0,0.5,0) + buttonFrame.Position = UDim2.new(0.7,0,0.5,0) + buttonFrame.Name = "ContextButtonFrame" + buttonFrame.Parent = buttonScreenGui + + buttonFrame.Visible = not userInputService.ModalEnabled + userInputService.Changed:connect(function(property) + if property == "ModalEnabled" then + buttonFrame.Visible = not userInputService.ModalEnabled + end + end) + end +end + +-- functions +function setButtonSizeAndPosition(object) + local buttonSize = 55 + local xOffset = 10 + local yOffset = 95 + + -- todo: better way to determine mobile sized screens + local onSmallScreen = (game:GetService("CoreGui").RobloxGui.AbsoluteSize.X < 600) + if not onSmallScreen then + buttonSize = 85 + xOffset = 40 + end + + object.Size = UDim2.new(0,buttonSize,0,buttonSize) +end + +function contextButtonDown(button, inputObject, actionName) + if inputObject.UserInputType == Enum.UserInputType.Touch then + button.Image = ContextDownImage + contextActionService:CallFunction(actionName, Enum.UserInputState.Begin, inputObject) + end +end + +function contextButtonMoved(button, inputObject, actionName) + if inputObject.UserInputType == Enum.UserInputType.Touch then + button.Image = ContextDownImage + contextActionService:CallFunction(actionName, Enum.UserInputState.Change, inputObject) + end +end + +function contextButtonUp(button, inputObject, actionName) + button.Image = ContextUpImage + if inputObject.UserInputType == Enum.UserInputType.Touch and inputObject.UserInputState == Enum.UserInputState.End then + contextActionService:CallFunction(actionName, Enum.UserInputState.End, inputObject) + end +end + +function isSmallScreenDevice() + return game:GetService("GuiService"):GetScreenResolution().y <= 320 +end + + +function createNewButton(actionName, functionInfoTable) + local contextButton = Instance.new("ImageButton") + contextButton.Name = "ContextActionButton" + contextButton.BackgroundTransparency = 1 + contextButton.Size = UDim2.new(0,90,0,90) + contextButton.Active = true + if isSmallScreenDevice() then + contextButton.Size = UDim2.new(0,70,0,70) + end + contextButton.Image = ContextUpImage + contextButton.Parent = buttonFrame + + local currentButtonTouch = nil + + userInputService.InputEnded:connect(function ( inputObject ) + oldTouches[inputObject] = nil + end) + contextButton.InputBegan:connect(function(inputObject) + if oldTouches[inputObject] then return end + + if inputObject.UserInputState == Enum.UserInputState.Begin and currentButtonTouch == nil then + currentButtonTouch = inputObject + contextButtonDown(contextButton, inputObject, actionName) + end + end) + contextButton.InputChanged:connect(function(inputObject) + if oldTouches[inputObject] then return end + if currentButtonTouch ~= inputObject then return end + + contextButtonMoved(contextButton, inputObject, actionName) + end) + contextButton.InputEnded:connect(function(inputObject) + if oldTouches[inputObject] then return end + if currentButtonTouch ~= inputObject then return end + + currentButtonTouch = nil + oldTouches[inputObject] = true + contextButtonUp(contextButton, inputObject, actionName) + end) + + local actionIcon = Instance.new("ImageLabel") + actionIcon.Name = "ActionIcon" + actionIcon.Position = UDim2.new(0.175, 0, 0.175, 0) + actionIcon.Size = UDim2.new(0.65, 0, 0.65, 0) + actionIcon.BackgroundTransparency = 1 + if functionInfoTable["image"] and type(functionInfoTable["image"]) == "string" then + actionIcon.Image = functionInfoTable["image"] + end + actionIcon.Parent = contextButton + + local actionTitle = Instance.new("TextLabel") + actionTitle.Name = "ActionTitle" + actionTitle.Size = UDim2.new(1,0,1,0) + actionTitle.BackgroundTransparency = 1 + actionTitle.Font = Enum.Font.SourceSansBold + actionTitle.TextColor3 = Color3.new(1,1,1) + actionTitle.TextStrokeTransparency = 0 + actionTitle.FontSize = Enum.FontSize.Size18 + actionTitle.TextWrapped = true + actionTitle.Text = "" + if functionInfoTable["title"] and type(functionInfoTable["title"]) == "string" then + actionTitle.Text = functionInfoTable["title"] + end + actionTitle.Parent = contextButton + + return contextButton +end + +function createButton( actionName, functionInfoTable ) + local button = createNewButton(actionName, functionInfoTable) + + local position = nil + for i = 1,#buttonVector do + if buttonVector[i] == "empty" then + position = i + break + end + end + + if not position then + position = #buttonVector + 1 + end + + if position > maxButtons then + return -- todo: let user know we have too many buttons already? + end + + buttonVector[position] = button + functionTable[actionName]["button"] = button + + button.Position = buttonPositionTable[position] + button.Parent = buttonFrame + + if buttonScreenGui and buttonScreenGui.Parent == nil then + buttonScreenGui.Parent = localPlayer.PlayerGui + end +end + +function removeAction(actionName) + if not functionTable[actionName] then return end + + local actionButton = functionTable[actionName]["button"] + + if actionButton then + actionButton.Parent = nil + + for i = 1,#buttonVector do + if buttonVector[i] == actionButton then + buttonVector[i] = "empty" + break + end + end + + actionButton:Destroy() + end + + functionTable[actionName] = nil +end + +function addAction(actionName,createTouchButton,functionInfoTable) + if functionTable[actionName] then + removeAction(actionName) + end + functionTable[actionName] = {functionInfoTable} + if createTouchButton and isTouchDevice then + createContextActionGui() + createButton(actionName, functionInfoTable) + end +end + +-- Connections +contextActionService.BoundActionChanged:connect( function(actionName, changeName, changeTable) + if functionTable[actionName] and changeTable then + local button = functionTable[actionName]["button"] + if button then + if changeName == "image" then + button.ActionIcon.Image = changeTable[changeName] + elseif changeName == "title" then + button.ActionTitle.Text = changeTable[changeName] + elseif changeName == "description" then + -- todo: add description to menu + elseif changeName == "position" then + button.Position = changeTable[changeName] + end + end + end +end) + +contextActionService.BoundActionAdded:connect( function(actionName, createTouchButton, functionInfoTable) + addAction(actionName, createTouchButton, functionInfoTable) +end) + +contextActionService.BoundActionRemoved:connect( function(actionName, functionInfoTable) + removeAction(actionName) +end) + +contextActionService.GetActionButtonEvent:connect( function(actionName) + if functionTable[actionName] then + contextActionService:FireActionButtonFoundSignal(actionName, functionTable[actionName]["button"]) + end +end) + +-- make sure any bound data before we setup connections is handled +local boundActions = contextActionService:GetAllBoundActionInfo() +for actionName, actionData in pairs(boundActions) do + addAction(actionName,actionData["createTouchButton"],actionData) +end diff --git a/2016/content/scripts/CoreScripts/GamepadMenu.lua b/2016/content/scripts/CoreScripts/GamepadMenu.lua new file mode 100644 index 0000000..39a96fe --- /dev/null +++ b/2016/content/scripts/CoreScripts/GamepadMenu.lua @@ -0,0 +1,693 @@ +--[[ + Filename: GamepadMenu.lua + Written by: jeditkacheff + Version 1.1 + Description: Controls the radial menu that appears when pressing menu button on gamepad +--]] + +--[[ SERVICES ]] +local GuiService = game:GetService('GuiService') +local CoreGuiService = game:GetService('CoreGui') +local InputService = game:GetService('UserInputService') +local ContextActionService = game:GetService('ContextActionService') +local HttpService = game:GetService('HttpService') +local StarterGui = game:GetService('StarterGui') +local GuiRoot = CoreGuiService:WaitForChild('RobloxGui') +--[[ END OF SERVICES ]] + +--[[ MODULES ]] +local tenFootInterface = require(GuiRoot.Modules.TenFootInterface) +local utility = require(GuiRoot.Modules.Settings.Utility) +local recordPage = require(GuiRoot.Modules.Settings.Pages.Record) + +--[[ VARIABLES ]] +local gamepadSettingsFrame = nil +local isVisible = false +local smallScreen = utility:IsSmallTouchScreen() +local isTenFootInterface = tenFootInterface:IsEnabled() +local radialButtons = {} +local lastInputChangedCon = nil + +local function getButtonForCoreGuiType(coreGuiType) + if coreGuiType == Enum.CoreGuiType.All then + return radialButtons + else + for button, table in pairs(radialButtons) do + if table["CoreGuiType"] == coreGuiType then + return button + end + end + end + + return nil +end + +local function getImagesForSlot(slot) + if slot == 1 then return "rbxasset://textures/ui/Settings/Radial/Top.png", "rbxasset://textures/ui/Settings/Radial/TopSelected.png", + "rbxasset://textures/ui/Settings/Radial/Menu.png", + UDim2.new(0.5,-26,0,18), UDim2.new(0,52,0,41), + UDim2.new(0,150,0,100), UDim2.new(0.5,-75,0,0) + elseif slot == 2 then return "rbxasset://textures/ui/Settings/Radial/TopRight.png", "rbxasset://textures/ui/Settings/Radial/TopRightSelected.png", + "rbxasset://textures/ui/Settings/Radial/PlayerList.png", + UDim2.new(1,-90,0,90), UDim2.new(0,52,0,52), + UDim2.new(0,108,0,150), UDim2.new(1,-110,0,50) + elseif slot == 3 then return "rbxasset://textures/ui/Settings/Radial/BottomRight.png", "rbxasset://textures/ui/Settings/Radial/BottomRightSelected.png", + "rbxasset://textures/ui/Settings/Radial/Alert.png", + UDim2.new(1,-85,1,-150), UDim2.new(0,42,0,58), + UDim2.new(0,120,0,150), UDim2.new(1,-120,1,-200) + elseif slot == 4 then return "rbxasset://textures/ui/Settings/Radial/Bottom.png", "rbxasset://textures/ui/Settings/Radial/BottomSelected.png", + "rbxasset://textures/ui/Settings/Radial/Leave.png", + UDim2.new(0.5,-20,1,-62), UDim2.new(0,55,0,46), + UDim2.new(0,150,0,100), UDim2.new(0.5,-75,1,-100) + elseif slot == 5 then return "rbxasset://textures/ui/Settings/Radial/BottomLeft.png", "rbxasset://textures/ui/Settings/Radial/BottomLeftSelected.png", + "rbxasset://textures/ui/Settings/Radial/Backpack.png", + UDim2.new(0,40,1,-150), UDim2.new(0,44,0,56), + UDim2.new(0,110,0,150), UDim2.new(0,0,0,205) + elseif slot == 6 then return "rbxasset://textures/ui/Settings/Radial/TopLeft.png", "rbxasset://textures/ui/Settings/Radial/TopLeftSelected.png", + "rbxasset://textures/ui/Settings/Radial/Chat.png", + UDim2.new(0,35,0,100), UDim2.new(0,56,0,53), + UDim2.new(0,110,0,150), UDim2.new(0,0,0,50) + end + + return "", "", UDim2.new(0,0,0,0), UDim2.new(0,0,0,0) +end + +local function setSelectedRadialButton(selectedObject) + for button, buttonTable in pairs(radialButtons) do + local isVisible = (button == selectedObject) + button:FindFirstChild("Selected").Visible = isVisible + button:FindFirstChild("RadialLabel").Visible = isVisible + end +end + +local function activateSelectedRadialButton() + for button, buttonTable in pairs(radialButtons) do + if button:FindFirstChild("Selected").Visible then + buttonTable["Function"]() + return true + end + end + + return false +end + +local function setButtonEnabled(button, enabled) + if radialButtons[button]["Disabled"] == not enabled then return end + + if button:FindFirstChild("Selected").Visible == true then + setSelectedRadialButton(nil) + end + + if enabled then + button.Image = string.gsub(button.Image, "rbxasset://textures/ui/Settings/Radial/Empty", "rbxasset://textures/ui/Settings/Radial/") + button.ImageTransparency = 0 + button.RadialIcon.ImageTransparency = 0 + else + button.Image = string.gsub(button.Image, "rbxasset://textures/ui/Settings/Radial/", "rbxasset://textures/ui/Settings/Radial/Empty") + button.ImageTransparency = 0 + button.RadialIcon.ImageTransparency = 1 + end + + radialButtons[button]["Disabled"] = not enabled +end + +local function setButtonVisible(button, visible) + button.Visible = visible + if not visible then + setButtonEnabled(button, false) + end +end + +local function enableVR() + local visibleButtons = { + Settings = true, LeaveGame = true, + PlayerList = false, Notifications = false, + Backpack = false, Chat = false + } + for button, _ in pairs(radialButtons) do + if visibleButtons[button.Name] ~= nil then + setButtonVisible(button, visibleButtons[button.Name]) + end + end +end + +local emptySelectedImageObject = utility:Create'ImageLabel' +{ + BackgroundTransparency = 1, + Size = UDim2.new(1,0,1,0), + Image = "" +}; + +local function createRadialButton(name, text, slot, disabled, coreGuiType, activateFunc) + local slotImage, selectedSlotImage, slotIcon, + slotIconPosition, slotIconSize, mouseFrameSize, mouseFramePos = getImagesForSlot(slot) + + local radialButton = utility:Create'ImageButton' + { + Name = name, + Position = UDim2.new(0,0,0,0), + Size = UDim2.new(1,0,1,0), + BackgroundTransparency = 1, + Image = slotImage, + ZIndex = 2, + SelectionImageObject = emptySelectedImageObject, + Parent = gamepadSettingsFrame + }; + if disabled then + radialButton.Image = string.gsub(radialButton.Image, "rbxasset://textures/ui/Settings/Radial/", "rbxasset://textures/ui/Settings/Radial/Empty") + end + + local selectedRadial = utility:Create'ImageLabel' + { + Name = "Selected", + Position = UDim2.new(0,0,0,0), + Size = UDim2.new(1,0,1,0), + BackgroundTransparency = 1, + Image = selectedSlotImage, + ZIndex = 2, + Visible = false, + Parent = radialButton + }; + + local radialIcon = utility:Create'ImageLabel' + { + Name = "RadialIcon", + Position = slotIconPosition, + Size = slotIconSize, + BackgroundTransparency = 1, + Image = slotIcon, + ZIndex = 3, + ImageTransparency = disabled and 1 or 0, + Parent = radialButton + }; + + local nameLabel = utility:Create'TextLabel' + { + + Size = UDim2.new(0,220,0,50), + Position = UDim2.new(0.5, -110, 0.5, -25), + BackgroundTransparency = 1, + Text = text, + Font = Enum.Font.SourceSansBold, + FontSize = Enum.FontSize.Size14, + TextColor3 = Color3.new(1,1,1), + Name = "RadialLabel", + Visible = false, + ZIndex = 2, + Parent = radialButton + }; + if not smallScreen then + nameLabel.FontSize = Enum.FontSize.Size36 + nameLabel.Size = UDim2.new(nameLabel.Size.X.Scale, nameLabel.Size.X.Offset, nameLabel.Size.Y.Scale, nameLabel.Size.Y.Offset + 4) + end + local nameBackgroundImage = utility:Create'ImageLabel' + { + Name = text .. "BackgroundImage", + Size = UDim2.new(1,0,1,0), + Position = UDim2.new(0,0,0,2), + BackgroundTransparency = 1, + Image = "rbxasset://textures/ui/Settings/Radial/RadialLabel@2x.png", + ScaleType = Enum.ScaleType.Slice, + SliceCenter = Rect.new(24,4,130,42), + ZIndex = 2, + Parent = nameLabel + }; + + local mouseFrame = utility:Create'ImageButton' + { + Name = "MouseFrame", + Position = mouseFramePos, + Size = mouseFrameSize, + ZIndex = 3, + BackgroundTransparency = 1, + SelectionImageObject = emptySelectedImageObject, + Parent = radialButton + }; + + mouseFrame.MouseEnter:connect(function() + if not radialButtons[radialButton]["Disabled"] then + setSelectedRadialButton(radialButton) + end + end) + mouseFrame.MouseLeave:connect(function() + setSelectedRadialButton(nil) + end) + + mouseFrame.MouseButton1Click:connect(function() + if selectedRadial.Visible then + activateFunc() + end + end) + + radialButtons[radialButton] = {["Function"] = activateFunc, ["Disabled"] = disabled, ["CoreGuiType"] = coreGuiType} + + return radialButton +end + +local function createGamepadMenuGui() + gamepadSettingsFrame = utility:Create'Frame' + { + Name = "GamepadSettingsFrame", + Position = UDim2.new(0.5,-51,0.5,-51), + BackgroundTransparency = 1, + BorderSizePixel = 0, + Size = UDim2.new(0,102,0,102), + Visible = false, + Parent = GuiRoot + }; + + --------------------------------- + -------- Settings Menu ---------- + local settingsFunc = function() + toggleCoreGuiRadial(true) + local MenuModule = require(GuiRoot.Modules.Settings.SettingsHub) + MenuModule:SetVisibility(true, nil, nil, true) + end + local settingsRadial = createRadialButton("Settings", "Settings", 1, false, nil, settingsFunc) + settingsRadial.Parent = gamepadSettingsFrame + + --------------------------------- + -------- Player List ------------ + local playerListFunc = function() + toggleCoreGuiRadial(true) + local PlayerListModule = require(GuiRoot.Modules.PlayerlistModule) + if not PlayerListModule:IsOpen() then + PlayerListModule:ToggleVisibility() + end + end + local playerListRadial = createRadialButton("PlayerList", "Player List", 2, not StarterGui:GetCoreGuiEnabled(Enum.CoreGuiType.PlayerList), Enum.CoreGuiType.PlayerList, playerListFunc) + playerListRadial.Parent = gamepadSettingsFrame + + --------------------------------- + -------- Notifications ---------- + local gamepadNotifications = Instance.new("BindableEvent") + gamepadNotifications.Name = "GamepadNotifications" + gamepadNotifications.Parent = script + local notificationsFunc = function() + toggleCoreGuiRadial() + gamepadNotifications:Fire(true) + end + local notificationsRadial = createRadialButton("Notifications", "Notifications", 3, false, nil, notificationsFunc) + if isTenFootInterface then + setButtonEnabled(notificationsRadial, false) + end + notificationsRadial.Parent = gamepadSettingsFrame + + --------------------------------- + ---------- Leave Game ----------- + local leaveGameFunc = function() + toggleCoreGuiRadial(true) + local MenuModule = require(GuiRoot.Modules.Settings.SettingsHub) + MenuModule:SetVisibility(true, false, require(GuiRoot.Modules.Settings.Pages.LeaveGame), true) + end + local leaveGameRadial = createRadialButton("LeaveGame", "Leave Game", 4, false, nil, leaveGameFunc) + leaveGameRadial.Parent = gamepadSettingsFrame + + --------------------------------- + ---------- Backpack ------------- + local backpackFunc = function() + toggleCoreGuiRadial(true) + local BackpackModule = require(GuiRoot.Modules.BackpackScript) + BackpackModule:OpenClose() + end + local backpackRadial = createRadialButton("Backpack", "Backpack", 5, not StarterGui:GetCoreGuiEnabled(Enum.CoreGuiType.Backpack), Enum.CoreGuiType.Backpack, backpackFunc) + backpackRadial.Parent = gamepadSettingsFrame + + --------------------------------- + ------------ Chat --------------- + local chatFunc = function() + toggleCoreGuiRadial() + local ChatModule = require(GuiRoot.Modules.Chat) + ChatModule:ToggleVisibility() + end + local chatRadial = createRadialButton("Chat", "Chat", 6, not StarterGui:GetCoreGuiEnabled(Enum.CoreGuiType.Chat), Enum.CoreGuiType.Chat, chatFunc) + if isTenFootInterface then + setButtonEnabled(chatRadial, false) + end + chatRadial.Parent = gamepadSettingsFrame + + + --------------------------------- + --------- Close Button ---------- + local closeHintImage = utility:Create'ImageLabel' + { + Name = "CloseHint", + Position = UDim2.new(1,10,1,10), + Size = UDim2.new(0,60,0,60), + BackgroundTransparency = 1, + Image = "rbxasset://textures/ui/Settings/Help/BButtonDark.png", + Parent = gamepadSettingsFrame + } + if isTenFootInterface then + closeHintImage.Image = "rbxasset://textures/ui/Settings/Help/BButtonDark@2x.png" + closeHintImage.Size = UDim2.new(0,90,0,90) + end + + local closeHintText = utility:Create'TextLabel' + { + Name = "closeHintText", + Position = UDim2.new(1,10,0.5,-12), + Size = UDim2.new(0,43,0,24), + Font = Enum.Font.SourceSansBold, + FontSize = Enum.FontSize.Size24, + BackgroundTransparency = 1, + Text = "Back", + TextColor3 = Color3.new(1,1,1), + TextXAlignment = Enum.TextXAlignment.Left, + Parent = closeHintImage + } + if isTenFootInterface then + closeHintText.FontSize = Enum.FontSize.Size36 + end + + ------------------------------------------ + --------- Stop Recording Button ---------- + --todo: enable this when recording is not a verb + --[[local stopRecordingImage = utility:Create'ImageLabel' + { + Name = "StopRecordingHint", + Position = UDim2.new(0,-100,1,10), + Size = UDim2.new(0,61,0,61), + BackgroundTransparency = 1, + Image = "rbxasset://textures/ui/Settings/Help/YButtonDark.png", + Visible = recordPage:IsRecording(), + Parent = gamepadSettingsFrame + } + local stopRecordingText = utility:Create'TextLabel' + { + Name = "stopRecordingHintText", + Position = UDim2.new(1,10,0.5,-12), + Size = UDim2.new(0,43,0,24), + Font = Enum.Font.SourceSansBold, + FontSize = Enum.FontSize.Size24, + BackgroundTransparency = 1, + Text = "Stop Recording", + TextColor3 = Color3.new(1,1,1), + TextXAlignment = Enum.TextXAlignment.Left, + Parent = stopRecordingImage + } + + recordPage.RecordingChanged:connect(function(isRecording) + stopRecordingImage.Visible = isRecording + end)]] + + GuiService:AddSelectionParent(HttpService:GenerateGUID(false), gamepadSettingsFrame) + + gamepadSettingsFrame.Changed:connect(function(prop) + if prop == "Visible" then + if not gamepadSettingsFrame.Visible then + unbindAllRadialActions() + end + end + end) + + if InputService.VREnabled then + enableVR() + end +end + +local function isCoreGuiDisabled() + for _, enumItem in pairs(Enum.CoreGuiType:GetEnumItems()) do + if StarterGui:GetCoreGuiEnabled(enumItem) then + return false + end + end + + return true +end + +local function setupGamepadControls() + local freezeControllerActionName = "doNothingAction" + local radialSelectActionName = "RadialSelectAction" + local thumbstick2RadialActionName = "Thumbstick2RadialAction" + local radialCancelActionName = "RadialSelectCancel" + local radialAcceptActionName = "RadialSelectAccept" + local toggleMenuActionName = "RBXToggleMenuAction" + + local noOpFunc = function() end + local doGamepadMenuButton = nil + + function unbindAllRadialActions() + local success = pcall(function() GuiService.CoreGuiNavigationEnabled = true end) + if not success then + GuiService.GuiNavigationEnabled = true + end + + ContextActionService:UnbindCoreAction(radialSelectActionName) + ContextActionService:UnbindCoreAction(radialCancelActionName) + ContextActionService:UnbindCoreAction(radialAcceptActionName) + ContextActionService:UnbindCoreAction(freezeControllerActionName) + ContextActionService:UnbindCoreAction(thumbstick2RadialActionName) + end + + local radialButtonLayout = { PlayerList = { + Range = { Begin = 36, + End = 96 + } + }, + Notifications = { + Range = { Begin = 96, + End = 156 + } + }, + LeaveGame = { + Range = { Begin = 156, + End = 216 + } + }, + Backpack = { + Range = { Begin = 216, + End = 276 + } + }, + Chat = { + Range = { Begin = 276, + End = 336 + } + }, + Settings = { + Range = { Begin = 336, + End = 36 + } + }, + } + + + local function getSelectedObjectFromAngle(angle, depth) + local closest = nil + local closestDistance = 30 -- threshold of 30 for selecting the closest radial button + for radialKey, buttonLayout in pairs(radialButtonLayout) do + if radialButtons[gamepadSettingsFrame[radialKey]]["Disabled"] == false then + --Check for exact match + if buttonLayout.Range.Begin < buttonLayout.Range.End then + if angle > buttonLayout.Range.Begin and angle <= buttonLayout.Range.End then + return gamepadSettingsFrame[radialKey] + end + else + if angle > buttonLayout.Range.Begin or angle <= buttonLayout.Range.End then + return gamepadSettingsFrame[radialKey] + end + end + --Check if this is the closest button so far + local distanceBegin = math.min(math.abs((buttonLayout.Range.Begin + 360) - angle), math.abs(buttonLayout.Range.Begin - angle)) + local distanceEnd = math.min(math.abs((buttonLayout.Range.End + 360) - angle), math.abs(buttonLayout.Range.End - angle)) + local distance = math.min(distanceBegin, distanceEnd) + if distance < closestDistance then + closestDistance = distance + closest = gamepadSettingsFrame[radialKey] + end + end + end + return closest + end + + local radialSelect = function(name, state, input) + local inputVector = Vector2.new(0,0) + + if input.KeyCode == Enum.KeyCode.Thumbstick1 then + inputVector = Vector2.new(input.Position.x, input.Position.y) + end + + local selectedObject = nil + + if inputVector.magnitude > 0.8 then + + local angle = math.atan2(inputVector.X, inputVector.Y) * 180 / math.pi + if angle < 0 then + angle = angle + 360 + end + + selectedObject = getSelectedObjectFromAngle(angle) + + setSelectedRadialButton(selectedObject) + end + end + + local radialSelectAccept = function(name, state, input) + if gamepadSettingsFrame.Visible and state == Enum.UserInputState.Begin then + activateSelectedRadialButton() + end + end + + local radialSelectCancel = function(name, state, input) + if gamepadSettingsFrame.Visible and state == Enum.UserInputState.Begin then + toggleCoreGuiRadial() + end + end + + function setVisibility() + local children = gamepadSettingsFrame:GetChildren() + for i = 1, #children do + if children[i]:FindFirstChild("RadialIcon") then + children[i].RadialIcon.Visible = isVisible + end + if children[i]:FindFirstChild("RadialLabel") and not isVisible then + children[i].RadialLabel.Visible = isVisible + end + end + end + + function setOverrideMouseIconBehavior() + pcall(function() + if InputService:GetLastInputType() == Enum.UserInputType.Gamepad1 then + InputService.OverrideMouseIconBehavior = Enum.OverrideMouseIconBehavior.ForceHide + else + InputService.OverrideMouseIconBehavior = Enum.OverrideMouseIconBehavior.ForceShow + end + end) + end + + function toggleCoreGuiRadial(goingToSettings) + isVisible = not gamepadSettingsFrame.Visible + + setVisibility() + + if isVisible then + setOverrideMouseIconBehavior() + pcall(function() lastInputChangedCon = InputService.LastInputTypeChanged:connect(setOverrideMouseIconBehavior) end) + + gamepadSettingsFrame.Visible = isVisible + + local settingsChildren = gamepadSettingsFrame:GetChildren() + for i = 1, #settingsChildren do + if settingsChildren[i]:IsA("GuiButton") then + utility:TweenProperty(settingsChildren[i], "ImageTransparency", 1, 0, 0.1, utility:GetEaseOutQuad(), nil) + end + end + gamepadSettingsFrame:TweenSizeAndPosition(UDim2.new(0,408,0,408), UDim2.new(0.5,-204,0.5,-204), + Enum.EasingDirection.Out, Enum.EasingStyle.Back, 0.18, true, + function() + setVisibility() + end) + else + if lastInputChangedCon ~= nil then + lastInputChangedCon:disconnect() + lastInputChangedCon = nil + end + pcall(function() InputService.OverrideMouseIconBehavior = Enum.OverrideMouseIconBehavior.None end) + + local settingsChildren = gamepadSettingsFrame:GetChildren() + for i = 1, #settingsChildren do + if settingsChildren[i]:IsA("GuiButton") then + utility:TweenProperty(settingsChildren[i], "ImageTransparency", 0, 1, 0.1, utility:GetEaseOutQuad(), nil) + end + end + gamepadSettingsFrame:TweenSizeAndPosition(UDim2.new(0,102,0,102), UDim2.new(0.5,-51,0.5,-51), + Enum.EasingDirection.Out, Enum.EasingStyle.Sine, 0.1, true, + function() + if not goingToSettings and not isVisible then GuiService:SetMenuIsOpen(false) end + gamepadSettingsFrame.Visible = isVisible + end) + end + + if isVisible then + setSelectedRadialButton(nil) + + local success = pcall(function() GuiService.CoreGuiNavigationEnabled = false end) + if not success then + GuiService.GuiNavigationEnabled = false + end + + GuiService:SetMenuIsOpen(true) + + ContextActionService:BindCoreAction(freezeControllerActionName, noOpFunc, false, Enum.UserInputType.Gamepad1) + ContextActionService:BindCoreAction(radialAcceptActionName, radialSelectAccept, false, Enum.KeyCode.ButtonA) + ContextActionService:BindCoreAction(radialCancelActionName, radialSelectCancel, false, Enum.KeyCode.ButtonB) + ContextActionService:BindCoreAction(radialSelectActionName, radialSelect, false, Enum.KeyCode.Thumbstick1) + ContextActionService:BindCoreAction(thumbstick2RadialActionName, noOpFunc, false, Enum.KeyCode.Thumbstick2) + ContextActionService:BindCoreAction(toggleMenuActionName, doGamepadMenuButton, false, Enum.KeyCode.ButtonStart) + else + unbindAllRadialActions() + end + + return gamepadSettingsFrame.Visible + end + + doGamepadMenuButton = function(name, state, input) + if state ~= Enum.UserInputState.Begin then return end + + if game.IsLoaded then + if not toggleCoreGuiRadial() then + unbindAllRadialActions() + end + end + end + + if InputService:GetGamepadConnected(Enum.UserInputType.Gamepad1) then + createGamepadMenuGui() + else + InputService.GamepadConnected:connect(function(gamepadEnum) + if gamepadEnum == Enum.UserInputType.Gamepad1 then + createGamepadMenuGui() + end + end) + end + + local function setRadialButtonEnabled(coreGuiType, enabled) + local returnValue = getButtonForCoreGuiType(coreGuiType) + if not returnValue then return end + + local buttonsToDisable = {} + if type(returnValue) == "table" then + for button, buttonTable in pairs(returnValue) do + if buttonTable["CoreGuiType"] then + if isTenFootInterface and buttonTable["CoreGuiType"] == Enum.CoreGuiType.Chat then + else + buttonsToDisable[#buttonsToDisable + 1] = button + end + end + end + else + if isTenFootInterface and returnValue.Name == "Chat" then + else + buttonsToDisable[1] = returnValue + end + end + + for i = 1, #buttonsToDisable do + local button = buttonsToDisable[i] + setButtonEnabled(button, enabled) + end + end + + local loadedConnection + local function enableRadialMenu() + ContextActionService:BindCoreAction(toggleMenuActionName, doGamepadMenuButton, false, Enum.KeyCode.ButtonStart) + loadedConnection:disconnect() + end + + loadedConnection = game.Players.PlayerAdded:connect(function(plr) + if game.Players.LocalPlayer and plr == game.Players.LocalPlayer then + enableRadialMenu() + end + end) + + if game.Players.LocalPlayer then + enableRadialMenu() + end + + StarterGui.CoreGuiChangedSignal:connect(setRadialButtonEnabled) +end + +-- hook up gamepad stuff +setupGamepadControls() diff --git a/2016/content/scripts/CoreScripts/HealthScript.lua b/2016/content/scripts/CoreScripts/HealthScript.lua new file mode 100644 index 0000000..398d54e --- /dev/null +++ b/2016/content/scripts/CoreScripts/HealthScript.lua @@ -0,0 +1,316 @@ +--[[ + This script controls the gui the player sees in regards to his or her health. + Can be turned with Game.StarterGui:SetCoreGuiEnabled(Enum.CoreGuiType.Health,false) + Copyright ROBLOX 2014. Written by Ben Tkacheff. +--]] + +--------------------------------------------------------------------- +-- Initialize/Variables +while not game do + wait(1/60) +end +while not game:GetService("Players") do + wait(1/60) +end + +local useCoreHealthBar = false +local success = pcall(function() useCoreHealthBar = game:GetService("Players"):GetUseCoreScriptHealthBar() end) +if not success or not useCoreHealthBar then + return +end + +local currentHumanoid = nil + +local HealthGui = nil +local lastHealth = 100 +local HealthPercentageForOverlay = 5 +local maxBarTweenTime = 0.3 +local greenColor = Color3.new(0.2, 1, 0.2) +local redColor = Color3.new(1, 0.2, 0.2) +local yellowColor = Color3.new(1, 1, 0.2) + +local guiEnabled = false +local healthChangedConnection = nil +local humanoidDiedConnection = nil +local characterAddedConnection = nil + +local greenBarImage = "rbxasset://textures/ui/Health-BKG-Center.png" +local greenBarImageLeft = "rbxasset://textures/ui/Health-BKG-Left-Cap.png" +local greenBarImageRight = "rbxasset://textures/ui/Health-BKG-Right-Cap.png" +local hurtOverlayImage = "http://www.roblox.com/asset/?id=34854607" + +game:GetService("ContentProvider"):Preload(greenBarImage) +game:GetService("ContentProvider"):Preload(hurtOverlayImage) + +while not game:GetService("Players").LocalPlayer do + wait(1/60) +end + +--------------------------------------------------------------------- +-- Functions + +local capHeight = 15 +local capWidth = 7 + +function CreateGui() + if HealthGui and #HealthGui:GetChildren() > 0 then + HealthGui.Parent = game:GetService("CoreGui").RobloxGui + return + end + + local hurtOverlay = Instance.new("ImageLabel") + hurtOverlay.Name = "HurtOverlay" + hurtOverlay.BackgroundTransparency = 1 + hurtOverlay.Image = hurtOverlayImage + hurtOverlay.Position = UDim2.new(-10,0,-10,0) + hurtOverlay.Size = UDim2.new(20,0,20,0) + hurtOverlay.Visible = false + hurtOverlay.Parent = HealthGui + + local healthFrame = Instance.new("Frame") + healthFrame.Name = "HealthFrame" + healthFrame.BackgroundTransparency = 1 + healthFrame.BackgroundColor3 = Color3.new(1,1,1) + healthFrame.BorderColor3 = Color3.new(0,0,0) + healthFrame.BorderSizePixel = 0 + healthFrame.Position = UDim2.new(0.5,-85,1,-20) + healthFrame.Size = UDim2.new(0,170,0,capHeight) + healthFrame.Parent = HealthGui + + + local healthBarBackCenter = Instance.new("ImageLabel") + healthBarBackCenter.Name = "healthBarBackCenter" + healthBarBackCenter.BackgroundTransparency = 1 + healthBarBackCenter.Image = greenBarImage + healthBarBackCenter.Size = UDim2.new(1,-capWidth*2,1,0) + healthBarBackCenter.Position = UDim2.new(0,capWidth,0,0) + healthBarBackCenter.Parent = healthFrame + healthBarBackCenter.ImageColor3 = Color3.new(1,1,1) + + local healthBarBackLeft = Instance.new("ImageLabel") + healthBarBackLeft.Name = "healthBarBackLeft" + healthBarBackLeft.BackgroundTransparency = 1 + healthBarBackLeft.Image = greenBarImageLeft + healthBarBackLeft.Size = UDim2.new(0,capWidth,1,0) + healthBarBackLeft.Position = UDim2.new(0,0,0,0) + healthBarBackLeft.Parent = healthFrame + healthBarBackLeft.ImageColor3 = Color3.new(1,1,1) + + local healthBarBackRight = Instance.new("ImageLabel") + healthBarBackRight.Name = "healthBarBackRight" + healthBarBackRight.BackgroundTransparency = 1 + healthBarBackRight.Image = greenBarImageRight + healthBarBackRight.Size = UDim2.new(0,capWidth,1,0) + healthBarBackRight.Position = UDim2.new(1,-capWidth,0,0) + healthBarBackRight.Parent = healthFrame + healthBarBackRight.ImageColor3 = Color3.new(1,1,1) + + + local healthBar = Instance.new("Frame") + healthBar.Name = "HealthBar" + healthBar.BackgroundTransparency = 1 + healthBar.BackgroundColor3 = Color3.new(1,1,1) + healthBar.BorderColor3 = Color3.new(0,0,0) + healthBar.BorderSizePixel = 0 + healthBar.ClipsDescendants = true + healthBar.Position = UDim2.new(0, 0, 0, 0) + healthBar.Size = UDim2.new(1,0,1,0) + healthBar.Parent = healthFrame + + + local healthBarCenter = Instance.new("ImageLabel") + healthBarCenter.Name = "healthBarCenter" + healthBarCenter.BackgroundTransparency = 1 + healthBarCenter.Image = greenBarImage + healthBarCenter.Size = UDim2.new(1,-capWidth*2,1,0) + healthBarCenter.Position = UDim2.new(0,capWidth,0,0) + healthBarCenter.Parent = healthBar + healthBarCenter.ImageColor3 = greenColor + + local healthBarLeft = Instance.new("ImageLabel") + healthBarLeft.Name = "healthBarLeft" + healthBarLeft.BackgroundTransparency = 1 + healthBarLeft.Image = greenBarImageLeft + healthBarLeft.Size = UDim2.new(0,capWidth,1,0) + healthBarLeft.Position = UDim2.new(0,0,0,0) + healthBarLeft.Parent = healthBar + healthBarLeft.ImageColor3 = greenColor + + local healthBarRight = Instance.new("ImageLabel") + healthBarRight.Name = "healthBarRight" + healthBarRight.BackgroundTransparency = 1 + healthBarRight.Image = greenBarImageRight + healthBarRight.Size = UDim2.new(0,capWidth,1,0) + healthBarRight.Position = UDim2.new(1,-capWidth,0,0) + healthBarRight.Parent = healthBar + healthBarRight.ImageColor3 = greenColor + + HealthGui.Parent = game:GetService("CoreGui").RobloxGui +end + +function UpdateGui(health) + if not HealthGui then return end + + local healthFrame = HealthGui:FindFirstChild("HealthFrame") + if not healthFrame then return end + + local healthBar = healthFrame:FindFirstChild("HealthBar") + if not healthBar then return end + + -- If more than 1/4 health, bar = green. Else, bar = red. + local percentHealth = (health/currentHumanoid.MaxHealth) + if percentHealth ~= percentHealth then + percentHealth = 1 + healthBar.healthBarCenter.ImageColor3 = yellowColor + healthBar.healthBarRight.ImageColor3 = yellowColor + healthBar.healthBarLeft.ImageColor3 = yellowColor + elseif percentHealth > 0.25 then + healthBar.healthBarCenter.ImageColor3 = greenColor + healthBar.healthBarRight.ImageColor3 = greenColor + healthBar.healthBarLeft.ImageColor3 = greenColor + else + healthBar.healthBarCenter.ImageColor3 = redColor + healthBar.healthBarRight.ImageColor3 = redColor + healthBar.healthBarLeft.ImageColor3 = redColor + end + + local width = (health / currentHumanoid.MaxHealth) + width = math.max(math.min(width,1),0) -- make sure width is between 0 and 1 + if width ~= width then width = 1 end + + local healthDelta = lastHealth - health + lastHealth = health + + local percentOfTotalHealth = math.abs(healthDelta/currentHumanoid.MaxHealth) + percentOfTotalHealth = math.max(math.min(percentOfTotalHealth,1),0) -- make sure percentOfTotalHealth is between 0 and 1 + if percentOfTotalHealth ~= percentOfTotalHealth then percentOfTotalHealth = 1 end + + local newHealthSize = UDim2.new(width,0,1,0) + + healthBar.Size = newHealthSize + + local sizeX = healthBar.AbsoluteSize.X + if sizeX < capWidth then + healthBar.healthBarCenter.Visible = false + healthBar.healthBarRight.Visible = false + elseif sizeX < (2*capWidth + 1) then + healthBar.healthBarCenter.Visible = true + healthBar.healthBarCenter.Size = UDim2.new(0,sizeX - capWidth,1,0) + healthBar.healthBarRight.Visible = false + else + healthBar.healthBarCenter.Visible = true + healthBar.healthBarCenter.Size = UDim2.new(1,-capWidth*2,1,0) + healthBar.healthBarRight.Visible = true + end + + local thresholdForHurtOverlay = currentHumanoid.MaxHealth * (HealthPercentageForOverlay/100) + + if healthDelta >= thresholdForHurtOverlay and guiEnabled then + AnimateHurtOverlay() + end + +end + +function AnimateHurtOverlay() + if not HealthGui then return end + + local overlay = HealthGui:FindFirstChild("HurtOverlay") + if not overlay then return end + + local newSize = UDim2.new(20, 0, 20, 0) + local newPos = UDim2.new(-10, 0, -10, 0) + + if overlay:IsDescendantOf(game) then + -- stop any tweens on overlay + overlay:TweenSizeAndPosition(newSize,newPos,Enum.EasingDirection.Out,Enum.EasingStyle.Linear,0,true,function() + + -- show the gui + overlay.Size = UDim2.new(1,0,1,0) + overlay.Position = UDim2.new(0,0,0,0) + overlay.Visible = true + + -- now tween the hide + if overlay:IsDescendantOf(game) then + overlay:TweenSizeAndPosition(newSize,newPos,Enum.EasingDirection.Out,Enum.EasingStyle.Quad,10,false,function() + overlay.Visible = false + end) + else + overlay.Size = newSize + overlay.Position = newPos + end + end) + else + overlay.Size = newSize + overlay.Position = newPos + end + +end + +function humanoidDied() + UpdateGui(0) +end + +function disconnectPlayerConnections() + if characterAddedConnection then characterAddedConnection:disconnect() end + if humanoidDiedConnection then humanoidDiedConnection:disconnect() end + if healthChangedConnection then healthChangedConnection:disconnect() end +end + +function newPlayerCharacter() + disconnectPlayerConnections() + startGui() +end + +function startGui() + characterAddedConnection = game:GetService("Players").LocalPlayer.CharacterAdded:connect(newPlayerCharacter) + + local character = game:GetService("Players").LocalPlayer.Character + if not character then + return + end + + currentHumanoid = character:WaitForChild("Humanoid") + if not currentHumanoid then + return + end + + if not game:GetService("StarterGui"):GetCoreGuiEnabled(Enum.CoreGuiType.Health) then + return + end + + healthChangedConnection = currentHumanoid.HealthChanged:connect(UpdateGui) + humanoidDiedConnection = currentHumanoid.Died:connect(humanoidDied) + UpdateGui(currentHumanoid.Health) + + CreateGui() +end + + + +--------------------------------------------------------------------- +-- Start Script + +HealthGui = Instance.new("Frame") +HealthGui.Name = "HealthGui" +HealthGui.BackgroundTransparency = 1 +HealthGui.Size = UDim2.new(1,0,1,0) + +game:GetService("StarterGui").CoreGuiChangedSignal:connect(function(coreGuiType,enabled) + if coreGuiType == Enum.CoreGuiType.Health or coreGuiType == Enum.CoreGuiType.All then + if guiEnabled and not enabled then + if HealthGui then + HealthGui.Parent = nil + end + disconnectPlayerConnections() + elseif not guiEnabled and enabled then + startGui() + end + + guiEnabled = enabled + end +end) + +if game:GetService("StarterGui"):GetCoreGuiEnabled(Enum.CoreGuiType.Health) then + guiEnabled = true + startGui() +end diff --git a/2016/content/scripts/CoreScripts/MainBotChatScript2.lua b/2016/content/scripts/CoreScripts/MainBotChatScript2.lua new file mode 100644 index 0000000..0b02eec --- /dev/null +++ b/2016/content/scripts/CoreScripts/MainBotChatScript2.lua @@ -0,0 +1,729 @@ +local PURPOSE_DATA = { + [Enum.DialogPurpose.Quest] = {"rbxasset://textures/DialogQuest.png", Vector2.new(10, 34)}, + [Enum.DialogPurpose.Help] = {"rbxasset://textures/DialogHelp.png", Vector2.new(20, 35)}, + [Enum.DialogPurpose.Shop] = {"rbxasset://textures/ui/DialogShop.png", Vector2.new(22, 43)}, +} +local TEXT_HEIGHT = 24 -- Pixel height of one row +local FONT_SIZE = Enum.FontSize.Size24 +local BAR_THICKNESS = 6 +local STYLE_PADDING = 17 +local CHOICE_PADDING = 6 * 2 -- (Added to vertical height) +local PROMPT_SIZE = Vector2.new(80, 90) +local FRAME_WIDTH = 350 + +local WIDTH_BONUS = (STYLE_PADDING * 2) - BAR_THICKNESS +local XPOS_OFFSET = -(STYLE_PADDING - BAR_THICKNESS) + +local contextActionService = game:GetService("ContextActionService") +local guiService = game:GetService("GuiService") +local YPOS_OFFSET = -math.floor(STYLE_PADDING / 2) +local usingGamepad = false + +function setUsingGamepad(input, processed) + if input.UserInputType == Enum.UserInputType.Gamepad1 or input.UserInputType == Enum.UserInputType.Gamepad2 or + input.UserInputType == Enum.UserInputType.Gamepad3 or input.UserInputType == Enum.UserInputType.Gamepad4 then + usingGamepad = true + else + usingGamepad = false + end +end + +game:GetService("UserInputService").InputBegan:connect(setUsingGamepad) +game:GetService("UserInputService").InputChanged:connect(setUsingGamepad) + +function waitForProperty(instance, name) + while not instance[name] do + instance.Changed:wait() + end +end + +function waitForChild(instance, name) + while not instance:FindFirstChild(name) do + instance.ChildAdded:wait() + end +end + +local filteringEnabledFixFlagSuccess, filteringEnabledFixFlagValue = pcall(function() return settings():GetFFlag("FilteringEnabledDialogFix") end) +local filterEnabledFixActive = (filteringEnabledFixFlagSuccess and filteringEnabledFixFlagValue) + +local goodbyeChoiceActiveFlagSuccess, goodbyeChoiceActiveFlagValue = pcall(function() return settings():GetFFlag("GoodbyeChoiceActiveProperty") end) +local goodbyeChoiceActiveFlag = (goodbyeChoiceActiveFlagSuccess and goodbyeChoiceActiveFlagValue) + +local mainFrame +local choices = {} +local lastChoice +local choiceMap = {} +local currentConversationDialog +local currentConversationPartner +local currentAbortDialogScript + +local coroutineMap = {} +local currentDialogTimeoutCoroutine = nil + +local tooFarAwayMessage = "You are too far away to chat!" +local tooFarAwaySize = 300 +local characterWanderedOffMessage = "Chat ended because you walked away" +local characterWanderedOffSize = 350 +local conversationTimedOut = "Chat ended because you didn't reply" +local conversationTimedOutSize = 350 + +local RobloxReplicatedStorage = game:GetService('RobloxReplicatedStorage') +local setDialogInUseEvent = RobloxReplicatedStorage:WaitForChild("SetDialogInUse") + +local player +local screenGui +local chatNotificationGui +local messageDialog +local timeoutScript +local reenableDialogScript +local dialogMap = {} +local dialogConnections = {} +local touchControlGui = nil + +local gui = nil +waitForChild(game,"CoreGui") +waitForChild(game:GetService("CoreGui"),"RobloxGui") + +game:GetService("CoreGui").RobloxGui:WaitForChild("Modules"):WaitForChild("TenFootInterface") +local isTenFootInterface = require(game:GetService("CoreGui").RobloxGui.Modules.TenFootInterface):IsEnabled() +local utility = require(game:GetService("CoreGui").RobloxGui.Modules.Settings.Utility) +local isSmallTouchScreen = utility:IsSmallTouchScreen() + +if isTenFootInterface then + FONT_SIZE = Enum.FontSize.Size36 + TEXT_HEIGHT = 36 + FRAME_WIDTH = 500 +elseif isSmallTouchScreen then + FONT_SIZE = Enum.FontSize.Size14 + TEXT_HEIGHT = 14 + FRAME_WIDTH = 250 +end + +if game:GetService("CoreGui").RobloxGui:FindFirstChild("ControlFrame") then + gui = game:GetService("CoreGui").RobloxGui.ControlFrame +else + gui = game:GetService("CoreGui").RobloxGui +end +local touchEnabled = game:GetService("UserInputService").TouchEnabled + +function currentTone() + if currentConversationDialog then + return currentConversationDialog.Tone + else + return Enum.DialogTone.Neutral + end +end + + +function createChatNotificationGui() + chatNotificationGui = Instance.new("BillboardGui") + chatNotificationGui.Name = "ChatNotificationGui" + + chatNotificationGui.ExtentsOffset = Vector3.new(0,1,0) + chatNotificationGui.Size = UDim2.new(PROMPT_SIZE.X / 31.5, 0, PROMPT_SIZE.Y / 31.5, 0) + chatNotificationGui.SizeOffset = Vector2.new(0,0) + chatNotificationGui.StudsOffset = Vector3.new(0, 3.7, 0) + chatNotificationGui.Enabled = true + chatNotificationGui.RobloxLocked = true + chatNotificationGui.Active = true + + local button = Instance.new("ImageButton") + button.Name = "Background" + button.Active = false + button.BackgroundTransparency = 1 + button.Position = UDim2.new(0, 0, 0, 0) + button.Size = UDim2.new(1, 0, 1, 0) + button.Image = "" + button.RobloxLocked = true + button.Parent = chatNotificationGui + + local icon = Instance.new("ImageLabel") + icon.Name = "Icon" + icon.Position = UDim2.new(0, 0, 0, 0) + icon.Size = UDim2.new(1, 0, 1, 0) + icon.Image = "" + icon.BackgroundTransparency = 1 + icon.RobloxLocked = true + icon.Parent = button + + local activationButton = Instance.new("ImageLabel") + activationButton.Name = "ActivationButton" + activationButton.Position = UDim2.new(-0.3, 0, -0.4, 0) + activationButton.Size = UDim2.new(.8, 0, .8*(PROMPT_SIZE.X/PROMPT_SIZE.Y), 0) + activationButton.Image = "rbxasset://textures/ui/Settings/Help/XButtonDark.png" + activationButton.BackgroundTransparency = 1 + activationButton.Visible = false + activationButton.RobloxLocked = true + activationButton.Parent = button +end + +function getChatColor(tone) + if tone == Enum.DialogTone.Neutral then + return Enum.ChatColor.Blue + elseif tone == Enum.DialogTone.Friendly then + return Enum.ChatColor.Green + elseif tone == Enum.DialogTone.Enemy then + return Enum.ChatColor.Red + end +end + +function styleChoices() + for _, obj in pairs(choices) do + obj.BackgroundTransparency = 1 + end + lastChoice.BackgroundTransparency = 1 +end + +function styleMainFrame(tone) + if tone == Enum.DialogTone.Neutral then + mainFrame.Style = Enum.FrameStyle.ChatBlue + elseif tone == Enum.DialogTone.Friendly then + mainFrame.Style = Enum.FrameStyle.ChatGreen + elseif tone == Enum.DialogTone.Enemy then + mainFrame.Style = Enum.FrameStyle.ChatRed + end + + styleChoices() +end +function setChatNotificationTone(gui, purpose, tone) + if tone == Enum.DialogTone.Neutral then + gui.Background.Image = "rbxasset://textures/ui/chatBubble_blue_notify_bkg.png" + elseif tone == Enum.DialogTone.Friendly then + gui.Background.Image = "rbxasset://textures/ui/chatBubble_green_notify_bkg.png" + elseif tone == Enum.DialogTone.Enemy then + gui.Background.Image = "rbxasset://textures/ui/chatBubble_red_notify_bkg.png" + end + + local newIcon, size = unpack(PURPOSE_DATA[purpose]) + local relativeSize = size / PROMPT_SIZE + gui.Background.Icon.Size = UDim2.new(relativeSize.X, 0, relativeSize.Y, 0) + gui.Background.Icon.Position = UDim2.new(0.5 - (relativeSize.X / 2), 0, 0.4 - (relativeSize.Y / 2), 0) + gui.Background.Icon.Image = newIcon +end + +function createMessageDialog() + messageDialog = Instance.new("Frame"); + messageDialog.Name = "DialogScriptMessage" + messageDialog.Style = Enum.FrameStyle.Custom + messageDialog.BackgroundTransparency = 0.5 + messageDialog.BackgroundColor3 = Color3.new(31/255, 31/255, 31/255) + messageDialog.Visible = false + + local text = Instance.new("TextLabel") + text.Name = "Text" + text.Position = UDim2.new(0,0,0,-1) + text.Size = UDim2.new(1,0,1,0) + text.FontSize = Enum.FontSize.Size14 + text.BackgroundTransparency = 1 + text.TextColor3 = Color3.new(1,1,1) + text.RobloxLocked = true + text.Parent = messageDialog +end + +function showMessage(msg, size) + messageDialog.Text.Text = msg + messageDialog.Size = UDim2.new(0,size,0,40) + messageDialog.Position = UDim2.new(0.5, -size/2, 0.5, -40) + messageDialog.Visible = true + wait(2) + messageDialog.Visible = false +end + +function variableDelay(str) + local length = math.min(string.len(str), 100) + wait(0.75 + ((length/75) * 1.5)) +end + +function resetColor(frame) + frame.BackgroundTransparency = 1 +end + +function wanderDialog() + mainFrame.Visible = false + endDialog() + showMessage(characterWanderedOffMessage, characterWanderedOffSize) +end + +function timeoutDialog() + mainFrame.Visible = false + endDialog() + showMessage(conversationTimedOut, conversationTimedOutSize) +end + +function normalEndDialog() + endDialog() +end + +function endDialog() + if filterEnabledFixActive then + if currentDialogTimeoutCoroutine then + coroutineMap[currentDialogTimeoutCoroutine] = false + currentDialogTimeoutCoroutine = nil + end + else + if currentAbortDialogScript then + currentAbortDialogScript:Destroy() + currentAbortDialogScript = nil + end + end + + local dialog = currentConversationDialog + currentConversationDialog = nil + if dialog and dialog.InUse then + if filterEnabledFixActive then + spawn(function() + wait(5) + setDialogInUseEvent:FireServer(dialog, false) + end) + else + local reenableScript = reenableDialogScript:Clone() + reenableScript.Archivable = false + reenableScript.Disabled = false + reenableScript.Parent = dialog + end + end + + for dialog, gui in pairs(dialogMap) do + if dialog and gui then + gui.Enabled = not dialog.InUse + end + end + + contextActionService:UnbindCoreAction("Nothing") + currentConversationPartner = nil + + if touchControlGui then + touchControlGui.Visible = true + end +end + +function sanitizeMessage(msg) + if string.len(msg) == 0 then + return "..." + else + return msg + end +end + +function selectChoice(choice) + renewKillswitch(currentConversationDialog) + + --First hide the Gui + mainFrame.Visible = false + if choice == lastChoice then + game:GetService("Chat"):Chat(game:GetService("Players").LocalPlayer.Character, lastChoice.UserPrompt.Text, getChatColor(currentTone())) + + normalEndDialog() + else + local dialogChoice = choiceMap[choice] + + game:GetService("Chat"):Chat(game:GetService("Players").LocalPlayer.Character, sanitizeMessage(dialogChoice.UserDialog), getChatColor(currentTone())) + wait(1) + currentConversationDialog:SignalDialogChoiceSelected(player, dialogChoice) + game:GetService("Chat"):Chat(currentConversationPartner, sanitizeMessage(dialogChoice.ResponseDialog), getChatColor(currentTone())) + + variableDelay(dialogChoice.ResponseDialog) + presentDialogChoices(currentConversationPartner, dialogChoice:GetChildren(), dialogChoice) + end +end + +function newChoice() + local dummyFrame = Instance.new("Frame") + dummyFrame.Visible = false + + local frame = Instance.new("TextButton") + frame.BackgroundColor3 = Color3.new(227/255, 227/255, 227/255) + frame.BackgroundTransparency = 1 + frame.AutoButtonColor = false + frame.BorderSizePixel = 0 + frame.Text = "" + frame.MouseEnter:connect(function() frame.BackgroundTransparency = 0 end) + frame.MouseLeave:connect(function() frame.BackgroundTransparency = 1 end) + frame.SelectionImageObject = dummyFrame + frame.MouseButton1Click:connect(function() selectChoice(frame) end) + frame.RobloxLocked = true + + local prompt = Instance.new("TextLabel") + prompt.Name = "UserPrompt" + prompt.BackgroundTransparency = 1 + prompt.Font = Enum.Font.SourceSans + prompt.FontSize = FONT_SIZE + prompt.Position = UDim2.new(0, 40, 0, 0) + prompt.Size = UDim2.new(1, -32-40, 1, 0) + prompt.TextXAlignment = Enum.TextXAlignment.Left + prompt.TextYAlignment = Enum.TextYAlignment.Center + prompt.TextWrap = true + prompt.RobloxLocked = true + prompt.Parent = frame + + local selectionButton = Instance.new("ImageLabel") + selectionButton.Name = "RBXchatDialogSelectionButton" + selectionButton.Position = UDim2.new(0, 0, 0.5, -33/2) + selectionButton.Size = UDim2.new(0, 33, 0, 33) + selectionButton.Image = "rbxasset://textures/ui/Settings/Help/AButtonLightSmall.png" + selectionButton.BackgroundTransparency = 1 + selectionButton.Visible = false + selectionButton.RobloxLocked = true + selectionButton.Parent = frame + + return frame +end +function initialize(parent) + choices[1] = newChoice() + choices[2] = newChoice() + choices[3] = newChoice() + choices[4] = newChoice() + + lastChoice = newChoice() + lastChoice.UserPrompt.Text = "Goodbye!" + lastChoice.Size = UDim2.new(1, WIDTH_BONUS, 0, TEXT_HEIGHT + CHOICE_PADDING) + + mainFrame = Instance.new("Frame") + mainFrame.Name = "UserDialogArea" + mainFrame.Size = UDim2.new(0, FRAME_WIDTH, 0, 200) + mainFrame.Style = Enum.FrameStyle.ChatBlue + mainFrame.Visible = false + + for n, obj in pairs(choices) do + obj.RobloxLocked = true + obj.Parent = mainFrame + end + + lastChoice.RobloxLocked = true + lastChoice.Parent = mainFrame + + mainFrame.RobloxLocked = true + mainFrame.Parent = parent +end + +function presentDialogChoices(talkingPart, dialogChoices, parentDialog) + if not currentConversationDialog then + return + end + + currentConversationPartner = talkingPart + sortedDialogChoices = {} + for n, obj in pairs(dialogChoices) do + if obj:IsA("DialogChoice") then + table.insert(sortedDialogChoices, obj) + end + end + table.sort(sortedDialogChoices, function(a,b) return a.Name < b.Name end) + + if #sortedDialogChoices == 0 then + normalEndDialog() + return + end + + local pos = 1 + local yPosition = 0 + choiceMap = {} + for n, obj in pairs(choices) do + obj.Visible = false + end + + for n, obj in pairs(sortedDialogChoices) do + if pos <= #choices then + --3 lines is the maximum, set it to that temporarily + choices[pos].Size = UDim2.new(1, WIDTH_BONUS, 0, TEXT_HEIGHT * 3) + choices[pos].UserPrompt.Text = obj.UserDialog + local height = (math.ceil(choices[pos].UserPrompt.TextBounds.Y / TEXT_HEIGHT) * TEXT_HEIGHT) + CHOICE_PADDING + + choices[pos].Position = UDim2.new(0, XPOS_OFFSET, 0, YPOS_OFFSET + yPosition) + choices[pos].Size = UDim2.new(1, WIDTH_BONUS, 0, height) + choices[pos].Visible = true + + choiceMap[choices[pos]] = obj + + yPosition = yPosition + height + 1 -- The +1 makes highlights not overlap + pos = pos + 1 + end + end + + lastChoice.Size = UDim2.new(1, WIDTH_BONUS, 0, TEXT_HEIGHT * 3) + lastChoice.UserPrompt.Text = parentDialog.GoodbyeDialog == "" and "Goodbye!" or parentDialog.GoodbyeDialog + local height = (math.ceil(lastChoice.UserPrompt.TextBounds.Y / TEXT_HEIGHT) * TEXT_HEIGHT) + CHOICE_PADDING + lastChoice.Size = UDim2.new(1, WIDTH_BONUS, 0, height) + lastChoice.Position = UDim2.new(0, XPOS_OFFSET, 0, YPOS_OFFSET + yPosition) + lastChoice.Visible = true + + if goodbyeChoiceActiveFlag and not parentDialog.GoodbyeChoiceActive then + lastChoice.Visible = false + mainFrame.Size = UDim2.new(0, FRAME_WIDTH, 0, yPosition + (STYLE_PADDING * 2) + (YPOS_OFFSET * 2)) + else + mainFrame.Size = UDim2.new(0, FRAME_WIDTH, 0, yPosition + lastChoice.AbsoluteSize.Y + (STYLE_PADDING * 2) + (YPOS_OFFSET * 2)) + end + + mainFrame.Position = UDim2.new(0,20,1.0, -mainFrame.Size.Y.Offset-20) + if isSmallTouchScreen then + local touchScreenGui = game.Players.LocalPlayer.PlayerGui:FindFirstChild("TouchGui") + if touchScreenGui then + touchControlGui = touchScreenGui:FindFirstChild("TouchControlFrame") + if touchControlGui then + touchControlGui.Visible = false + end + end + mainFrame.Position = UDim2.new(0,10,1.0, -mainFrame.Size.Y.Offset) + end + styleMainFrame(currentTone()) + mainFrame.Visible = true + + if usingGamepad then + Game:GetService("GuiService").SelectedCoreObject = choices[1] + end +end + +function doDialog(dialog) + if dialog.InUse then + return + else + dialog.InUse = true + if filterEnabledFixActive then + setDialogInUseEvent:FireServer(dialog, true) + end + end + + currentConversationDialog = dialog + game:GetService("Chat"):Chat(dialog.Parent, dialog.InitialPrompt, getChatColor(dialog.Tone)) + variableDelay(dialog.InitialPrompt) + + presentDialogChoices(dialog.Parent, dialog:GetChildren(), dialog) +end + +function renewKillswitch(dialog) + if filterEnabledFixActive then + if currentDialogTimeoutCoroutine then + coroutineMap[currentDialogTimeoutCoroutine] = false + currentDialogTimeoutCoroutine = nil + end + else + if currentAbortDialogScript then + currentAbortDialogScript:Destroy() + currentAbortDialogScript = nil + end + end + + if filterEnabledFixActive then + currentDialogTimeoutCoroutine = coroutine.create(function(thisCoroutine) + wait(15) + if thisCoroutine ~= nil then + if coroutineMap[thisCoroutine] == nil then + setDialogInUseEvent:FireServer(dialog, false) + end + coroutineMap[thisCoroutine] = nil + end + end) + coroutine.resume(currentDialogTimeoutCoroutine, currentDialogTimeoutCoroutine) + else + currentAbortDialogScript = timeoutScript:Clone() + currentAbortDialogScript.Archivable = false + currentAbortDialogScript.Disabled = false + currentAbortDialogScript.Parent = dialog + end +end + +function checkForLeaveArea() + while currentConversationDialog do + if currentConversationDialog.Parent and (player:DistanceFromCharacter(currentConversationDialog.Parent.Position) >= currentConversationDialog.ConversationDistance) then + wanderDialog() + end + wait(1) + end +end + +function startDialog(dialog) + if dialog.Parent and dialog.Parent:IsA("BasePart") then + if player:DistanceFromCharacter(dialog.Parent.Position) >= dialog.ConversationDistance then + showMessage(tooFarAwayMessage, tooFarAwaySize) + return + end + + for dialog, gui in pairs(dialogMap) do + if dialog and gui then + gui.Enabled = false + end + end + + contextActionService:BindCoreAction("Nothing", function() end, false, Enum.UserInputType.Gamepad1, Enum.UserInputType.Gamepad2, Enum.UserInputType.Gamepad3, Enum.UserInputType.Gamepad4) + + renewKillswitch(dialog) + + delay(1, checkForLeaveArea) + doDialog(dialog) + end +end + +function removeDialog(dialog) + if dialogMap[dialog] then + dialogMap[dialog]:Destroy() + dialogMap[dialog] = nil + end + if dialogConnections[dialog] then + dialogConnections[dialog]:disconnect() + dialogConnections[dialog] = nil + end +end + +function addDialog(dialog) + if dialog.Parent then + if dialog.Parent:IsA("BasePart") then + local chatGui = chatNotificationGui:clone() + chatGui.Enabled = not dialog.InUse + chatGui.Adornee = dialog.Parent + chatGui.RobloxLocked = true + + chatGui.Parent = game:GetService("CoreGui") + + chatGui.Background.MouseButton1Click:connect(function() startDialog(dialog) end) + setChatNotificationTone(chatGui, dialog.Purpose, dialog.Tone) + + dialogMap[dialog] = chatGui + + dialogConnections[dialog] = dialog.Changed:connect(function(prop) + if prop == "Parent" and dialog.Parent then + --This handles the reparenting case, seperate from removal case + removeDialog(dialog) + addDialog(dialog) + elseif prop == "InUse" then + chatGui.Enabled = not currentConversationDialog and not dialog.InUse + if dialog == currentConversationDialog then + timeoutDialog() + end + elseif prop == "Tone" or prop == "Purpose" then + setChatNotificationTone(chatGui, dialog.Purpose, dialog.Tone) + end + end) + else -- still need to listen to parent changes even if current parent is not a BasePart + dialogConnections[dialog] = dialog.Changed:connect(function(prop) + if prop == "Parent" and dialog.Parent then + --This handles the reparenting case, seperate from removal case + removeDialog(dialog) + addDialog(dialog) + end + end) + end + end +end + +function fetchScripts() + local model = game:GetService("InsertService"):LoadAsset(39226062) + if type(model) == "string" then -- load failed, lets try again + wait(0.1) + model = game:GetService("InsertService"):LoadAsset(39226062) + end + if type(model) == "string" then -- not going to work, lets bail + return + end + + waitForChild(model,"TimeoutScript") + timeoutScript = model.TimeoutScript + waitForChild(model,"ReenableDialogScript") + reenableDialogScript = model.ReenableDialogScript +end + +function onLoad() + waitForProperty(game:GetService("Players"), "LocalPlayer") + player = game:GetService("Players").LocalPlayer + waitForProperty(player, "Character") + + --print("Creating Guis") + createChatNotificationGui() + + --print("Creating MessageDialog") + createMessageDialog() + messageDialog.RobloxLocked = true + messageDialog.Parent = gui + + if not filterEnabledFixActive then + fetchScripts() + end + + --print("Waiting for BottomLeftControl") + waitForChild(gui, "BottomLeftControl") + + --print("Initializing Frame") + local frame = Instance.new("Frame") + frame.Name = "DialogFrame" + frame.Position = UDim2.new(0,0,0,0) + frame.Size = UDim2.new(0,0,0,0) + frame.BackgroundTransparency = 1 + frame.RobloxLocked = true + game:GetService("GuiService"):AddSelectionParent("RBXDialogGroup", frame) + + if (touchEnabled and not isSmallTouchScreen) then + frame.Position = UDim2.new(0,20,0.5,0) + frame.Size = UDim2.new(0.25,0,0.1,0) + frame.Parent = gui + elseif isSmallTouchScreen then + frame.Position = UDim2.new(0,0,.9,-10) + frame.Size = UDim2.new(0.25,0,0.1,0) + frame.Parent = gui + else + frame.Parent = gui.BottomLeftControl + end + initialize(frame) + + --print("Adding Dialogs") + game:GetService("CollectionService").ItemAdded:connect(function(obj) if obj:IsA("Dialog") then addDialog(obj) end end) + game:GetService("CollectionService").ItemRemoved:connect(function(obj) if obj:IsA("Dialog") then removeDialog(obj) end end) + for i, obj in pairs(game:GetService("CollectionService"):GetCollection("Dialog")) do + if obj:IsA("Dialog") then + addDialog(obj) + end + end +end + +local lastClosestDialog = nil +local getClosestDialogToPosition = guiService.GetClosestDialogToPosition + +game:GetService("RunService").Heartbeat:connect(function() + local closestDistance = math.huge + local closestDialog = nil + if usingGamepad == true then + if game.Players.LocalPlayer and game.Players.LocalPlayer.Character and game.Players.LocalPlayer.Character:FindFirstChild("HumanoidRootPart") then + local characterPosition = game.Players.LocalPlayer.Character:FindFirstChild("HumanoidRootPart").Position + closestDialog = getClosestDialogToPosition(guiService, characterPosition) + end + end + + if closestDialog ~= lastClosestDialog then + if dialogMap[lastClosestDialog] then + dialogMap[lastClosestDialog].Background.ActivationButton.Visible = false + end + lastClosestDialog = closestDialog + contextActionService:UnbindCoreAction("StartDialogAction") + if closestDialog ~= nil then + contextActionService:BindCoreAction("StartDialogAction", + function(actionName, userInputState, inputObject) + if userInputState == Enum.UserInputState.Begin then + if closestDialog and closestDialog.Parent then + startDialog(closestDialog) + end + end + end, + false, + Enum.KeyCode.ButtonX) + if dialogMap[closestDialog] then + dialogMap[closestDialog].Background.ActivationButton.Visible = true + end + end + end +end) + +local lastSelectedChoice = nil + +guiService.Changed:connect(function(property) + if property == "SelectedCoreObject" then + if lastSelectedChoice and lastSelectedChoice:FindFirstChild("RBXchatDialogSelectionButton") then + lastSelectedChoice:FindFirstChild("RBXchatDialogSelectionButton").Visible = false + lastSelectedChoice.BackgroundTransparency = 1 + end + lastSelectedChoice = guiService.SelectedCoreObject + if lastSelectedChoice and lastSelectedChoice:FindFirstChild("RBXchatDialogSelectionButton") then + lastSelectedChoice:FindFirstChild("RBXchatDialogSelectionButton").Visible = true + lastSelectedChoice.BackgroundTransparency = 0 + end + end +end) + +onLoad() \ No newline at end of file diff --git a/2016/content/scripts/CoreScripts/Topbar.lua b/2016/content/scripts/CoreScripts/Topbar.lua new file mode 100644 index 0000000..82d2fe6 --- /dev/null +++ b/2016/content/scripts/CoreScripts/Topbar.lua @@ -0,0 +1,1659 @@ +--[[ + // FileName: Topbar.lua + // Written by: SolarCrane + // Description: Code for lua side Top Menu items in ROBLOX. +]] + + +--[[ CONSTANTS ]] + +local TOPBAR_THICKNESS = 36 +local USERNAME_CONTAINER_WIDTH = 170 +local COLUMN_WIDTH = 75 +local NAME_LEADERBOARD_SEP_WIDTH = 2 + +local ITEM_SPACING = 0 +local VR_ITEM_SPACING = 3 + +local FONT_COLOR = Color3.new(1,1,1) +local TOPBAR_BACKGROUND_COLOR = Color3.new(31/255,31/255,31/255) +local TOPBAR_OPAQUE_TRANSPARENCY = 0 +local TOPBAR_TRANSLUCENT_TRANSPARENCY = 0.5 + +local HEALTH_BACKGROUND_COLOR = Color3.new(228/255, 236/255, 246/255) +local HEALTH_RED_COLOR = Color3.new(255/255, 28/255, 0/255) +local HEALTH_YELLOW_COLOR = Color3.new(250/255, 235/255, 0) +local HEALTH_GREEN_COLOR = Color3.new(27/255, 252/255, 107/255) + +local HEALTH_PERCANTAGE_FOR_OVERLAY = 5 / 100 + +local HURT_OVERLAY_IMAGE = "http://www.roblox.com/asset/?id=34854607" + +local DEBOUNCE_TIME = 0.25 + +--[[ END OF CONSTANTS ]] + +--[[ FFLAG VALUES ]] + +local defeatableTopbarSuccess, defeatableTopbarFlagValue = pcall(function() return settings():GetFFlag("EnableSetCoreTopbarEnabled") end) +local defeatableTopbar = (defeatableTopbarSuccess and defeatableTopbarFlagValue == true) + +local vr3dGuisSuccess, vr3dGuisFlagValue = pcall(function() return settings():GetFFlag("RenderUserGuiIn3DSpace") end) +local vr3dGuis = (vr3dGuisSuccess and vr3dGuisFlagValue == true) + +--[[ END OF FFLAG VALUES ]] + + +--[[ SERVICES ]] + +local CoreGuiService = game:GetService('CoreGui') +local PlayersService = game:GetService('Players') +local GuiService = game:GetService('GuiService') +local InputService = game:GetService('UserInputService') +local StarterGui = game:GetService('StarterGui') +local ContextActionService = game:GetService("ContextActionService") +local RunService = game:GetService('RunService') +local TextService = game:GetService('TextService') + +--[[ END OF SERVICES ]] + + +local topbarEnabled = true +local topbarEnabledChangedEvent = Instance.new('BindableEvent') + +local settingsActive = false + +local GameSettings = UserSettings().GameSettings +local Player = PlayersService.LocalPlayer +while Player == nil do + wait() + Player = PlayersService.LocalPlayer +end + +local GuiRoot = CoreGuiService:WaitForChild('RobloxGui') +local TenFootInterface = require(GuiRoot.Modules.TenFootInterface) +local isTenFootInterface = TenFootInterface:IsEnabled() + +local Panel3D = require(GuiRoot.Modules.VR.Panel3D) +local Topbar3DPanel = Panel3D.Get("Topbar3D") + +local Util = {} +do + -- Check if we are running on a touch device + function Util.IsTouchDevice() + return InputService.TouchEnabled + end + + function Util.Create(instanceType) + return function(data) + local obj = Instance.new(instanceType) + for k, v in pairs(data) do + if type(k) == 'number' then + v.Parent = obj + else + obj[k] = v + end + end + return obj + end + end + + function Util.Clamp(low, high, input) + return math.max(low, math.min(high, input)) + end + + function Util.DisconnectEvent(conn) + if conn then + conn:disconnect() + end + return nil + end + + function Util.SetGUIInsetBounds(x1, y1, x2, y2) + GuiService:SetGlobalGuiInset(x1, y1, x2, y2) + if GuiRoot:FindFirstChild("GuiInsetChanged") then + GuiRoot.GuiInsetChanged:Fire(x1, y1, x2, y2) + end + end + + local humanoidCache = {} + function Util.FindPlayerHumanoid(player) + local character = player and player.Character + if character then + local resultHumanoid = humanoidCache[player] + if resultHumanoid and resultHumanoid.Parent == character then + return resultHumanoid + else + humanoidCache[player] = nil -- Bust Old Cache + for _, child in pairs(character:GetChildren()) do + if child:IsA('Humanoid') then + humanoidCache[player] = child + return child + end + end + end + end + end +end + +local selectionRing = Util.Create "ImageLabel" { + Name = "SelectionRing", + Position = UDim2.new(0.5, -23, 0.5, -23), + Size = UDim2.new(0, 46, 0, 46), + BackgroundTransparency = 1, + Image = "rbxasset://textures/ui/menu/buttonHover.png" +} + +local function CreateTopBar() + local this = {} + + local playerGuiChangedConn = nil + + local topbarContainer = Util.Create'Frame'{ + Name = "TopBarContainer"; + Size = UDim2.new(1, 0, 0, TOPBAR_THICKNESS); + Position = UDim2.new(0, 0, 0, -TOPBAR_THICKNESS); + BackgroundTransparency = TOPBAR_OPAQUE_TRANSPARENCY; + BackgroundColor3 = TOPBAR_BACKGROUND_COLOR; + BorderSizePixel = 0; + Active = true; + Parent = GuiRoot; + }; + + local topbarShadow = Util.Create'ImageLabel'{ + Name = "TopBarShadow"; + Size = UDim2.new(1, 0, 0, 3); + Position = UDim2.new(0, 0, 1, 0); + Image = "rbxasset://textures/ui/TopBar/dropshadow.png"; + BackgroundTransparency = 1; + Active = false; + Visible = false; + Parent = topbarContainer; + }; + + local function ComputeTransparency() + if not topbarEnabled then + return 1 + end + + local playerGui = Player:FindFirstChild('PlayerGui') + if playerGui then + return playerGui:GetTopbarTransparency() + end + + return TOPBAR_TRANSLUCENT_TRANSPARENCY + end + + function this:UpdateBackgroundTransparency() + if settingsActive and not VREnabled then + topbarContainer.BackgroundTransparency = TOPBAR_OPAQUE_TRANSPARENCY + topbarShadow.Visible = false + else + topbarContainer.BackgroundTransparency = ComputeTransparency() + topbarShadow.Visible = (topbarContainer.BackgroundTransparency == 0) + end + end + + function this:GetInstance() + return topbarContainer + end + + spawn(function() + local playerGui = Player:WaitForChild('PlayerGui') + playerGuiChangedConn = Util.DisconnectEvent(playerGuiChangedConn) + pcall(function() + playerGuiChangedConn = playerGui.TopbarTransparencyChangedSignal:connect(this.UpdateBackgroundTransparency) + end) + this:UpdateBackgroundTransparency() + end) + + return this +end + + +local BarAlignmentEnum = +{ + Right = 0; + Left = 1; + Middle = 2; +} + +local function CreateMenuBar(barAlignment) + local this = {} + local thickness = TOPBAR_THICKNESS + local alignment = barAlignment or BarAlignmentEnum.Right + local items = {} + local propertyChangedConnections = {} + local dock = nil + + function this:ArrangeItems() + local totalWidth = 0 + + local spacing = ITEM_SPACING + if InputService.VREnabled then + spacing = VR_ITEM_SPACING + end + + for i, item in ipairs(items) do + local width = item:GetWidth() + + if alignment == BarAlignmentEnum.Left then + item.Position = UDim2.new(0, totalWidth, 0, 0) + elseif alignment == BarAlignmentEnum.Right then + item.Position = UDim2.new(1, -totalWidth - width, 0, 0) + end + + if i ~= #items then + width = width + spacing + end + + totalWidth = totalWidth + width + end + + if alignment == BarAlignmentEnum.Middle then + local currentX = -totalWidth / 2 + for _, item in ipairs(items) do + item.Position = UDim2.new(0, currentX, 0, 0) + + currentX = currentX + item:GetWidth() + spacing + end + end + + return totalWidth + end + + function this:GetThickness() + return thickness + end + + function this:GetNumberOfItems() + return #items + end + + function this:SetDock(newDock) + dock = newDock + for _, item in pairs(items) do + item.Parent = dock + end + end + + function this:IndexOfItem(searchItem) + for index, item in pairs(items) do + if item == searchItem then + return index + end + end + return nil + end + + function this:ItemAtIndex(index) + return items[index] + end + + function this:GetItems() + return items + end + + function this:AddItem(item, index) + local numItems = self:GetNumberOfItems() + index = Util.Clamp(1, numItems + 1, (index or numItems + 1)) + + local alreadyFoundIndex = self:IndexOfItem(item) + if alreadyFoundIndex then + return item, index + end + + table.insert(items, index, item) + Util.DisconnectEvent(propertyChangedConnections[item]) + propertyChangedConnections[item] = item.Changed:connect(function(property) + if property == 'AbsoluteSize' then + self:ArrangeItems() + end + end) + self:ArrangeItems() + + if dock then + item.Parent = dock + end + + return item, index + end + + function this:RemoveItem(item) + local index = self:IndexOfItem(item) + if index then + local removedItem = table.remove(items, index) + + removedItem.Parent = nil + Util.DisconnectEvent(propertyChangedConnections[removedItem]) + + self:ArrangeItems() + return removedItem, index + end + end + + + return this +end + +local function Create3DMenuBar(barAlignment, threeDPanel) + local this = CreateMenuBar(barAlignment) + + local superArrangeItems = this.ArrangeItems + function this:ArrangeItems() + local totalWidth = superArrangeItems(self) + if threeDPanel then + threeDPanel:ResizePixels(totalWidth, 120) + end + for _, v in pairs(this:GetItems()) do + v:UpdateHoverText() + end + return totalWidth + end + + function this:CloseAllExcept(item) + for _, v in pairs(this:GetItems()) do + if v ~= item then + v:SetActive(false) + end + end + end + + return this +end + + +local function CreateMenuItem(origInstance) + local this = {} + local instance = origInstance + + function this:SetInstance(newInstance) + if not instance then + instance = newInstance + else + print("Trying to set an Instance of a Menu Item that already has an instance; doing nothing.") + end + end + + function this:GetWidth() + return self.Size.X.Offset + end + + -- We are extending a regular instance. + do + local mt = + { + __index = function (t, k) + return instance[k] + end; + + __newindex = function (t, k, v) + --if instance[k] ~= nil then + instance[k] = v + --else + -- rawset(t, k, v) + --end + end; + } + setmetatable(this, mt) + end + + return this +end + +local function Create3DMenuItem() + local menuItem = {} + + local backgroundButton = Util.Create 'ImageButton' { + Name = "ButtonBackground", + Size = UDim2.new(0, 52, 0, 52), + + BackgroundTransparency = 1, + SelectionImageObject = selectionRing:Clone(), + + ClipsDescendants = false + } + + local isActive = false + + function menuItem:SetActive(active) + isActive = active + if active then + backgroundButton.Image = "rbxasset://textures/ui/menu/buttonActive.png" + else + backgroundButton.Image = "rbxasset://textures/ui/menu/buttonBackground.png" + end + backgroundButton.SelectionImageObject.Visible = not active + end + + function menuItem:GetWidth() + return backgroundButton.AbsoluteSize.X + end + + function menuItem:GetInstance() + return backgroundButton + end + + local function setTransparency(parent, transparency) + if parent:IsA("ImageLabel") or parent:IsA("ImageButton") then + parent.ImageTransparency = transparency + elseif parent:IsA("TextLabel") or parent:IsA("TextButton") then + parent.TextTransparency = transparency + end + for _, v in pairs(parent:GetChildren()) do + if v:IsA("GuiObject") then + setTransparency(v, transparency) + end + end + end + function menuItem:SetTransparency(transparency) + setTransparency(backgroundButton, transparency) + end + + menuItem:SetActive(false) + + local hoverTextFrame = Util.Create 'Frame' { + Name = "ButtonHoverText", + BackgroundTransparency = 1, + BorderSizePixel = 0, + + Position = UDim2.new(0.5, -45, 0, 55), + Size = UDim2.new(0, 90, 0, 60), + + Visible = false, + Parent = backgroundButton + } + local hoverMid = Util.Create 'ImageLabel' { + Name = "HoverMid", + BackgroundTransparency = 1, + + Image = "rbxasset://textures/ui/Menu/hoverPopupMid.png", + + Position = UDim2.new(0.5, -12, 0, 0), + Size = UDim2.new(0, 24, 1, 0), + Parent = hoverTextFrame + } + local hoverLeft = Util.Create 'ImageLabel' { + Name = "HoverLeft", + BackgroundTransparency = 1, + + Image = "rbxasset://textures/ui/Menu/hoverPopupLeft.png", + + Position = UDim2.new(0, 0, 0, 0), + Size = UDim2.new(0.5, -12, 1, 0), + ScaleType = Enum.ScaleType.Slice, + SliceCenter = Rect.new(1, 1, 33, 59), + Parent = hoverTextFrame + } + local hoverRight = Util.Create 'ImageLabel' { + Name = "HoverRight", + BackgroundTransparency = 1, + + Image = "rbxasset://textures/ui/Menu/hoverPopupRight.png", + + Position = UDim2.new(0.5, 12, 0, 0), + Size = UDim2.new(0.5, -12, 1, 0), + ScaleType = Enum.ScaleType.Slice, + SliceCenter = Rect.new(0, 1, 32, 59), + Parent = hoverTextFrame + } + + local hoverTextLabel = Util.Create 'TextLabel' { + Name = "ButtonHoverTextLabel", + BackgroundTransparency = 1, + + Font = Enum.Font.SourceSansBold, + FontSize = Enum.FontSize.Size24, + Text = "", + TextColor3 = Color3.new(1, 1, 1), + + Position = UDim2.new(0, 0, 0, 8), + Size = UDim2.new(1, 0, 1, -5), + + Parent = hoverTextFrame + } + + function menuItem:SetHoverText(text) + hoverTextLabel.Text = text + local textSize = TextService:GetTextSize( + hoverTextLabel.Text, + 24, + hoverTextLabel.Font, + Vector2.new(1000, 10000)) + local frameWidth = textSize.x + 20 + hoverTextFrame.Position = UDim2.new(0.5, -frameWidth / 2, 0, 55) + hoverTextFrame.Size = UDim2.new(0, frameWidth, 0, 60) + end + + backgroundButton.SelectionGained:connect(function() + hoverTextFrame.Visible = true + end) + backgroundButton.SelectionLost:connect(function() + hoverTextFrame.Visible = false + end) + + function menuItem:UpdateHoverText() + self:SetHoverText(hoverTextLabel.Text) + end + + setmetatable(menuItem, { + __index = function(t, k) + return backgroundButton[k] + end, + __newindex = function(t, k, v) + backgroundButton[k] = v + end + }) + + return menuItem +end + +local function createNormalHealthBar() + local container = Util.Create'ImageButton' + { + Name = "NameHealthContainer"; + Size = UDim2.new(0, USERNAME_CONTAINER_WIDTH, 1, 0); + AutoButtonColor = false; + Image = ""; + BackgroundTransparency = 1; + } + + local username = Util.Create'TextLabel'{ + Name = "Username"; + Text = Player.Name; + Size = UDim2.new(1, -14, 0, 22); + Position = UDim2.new(0, 7, 0, 0); + Font = Enum.Font.SourceSansBold; + FontSize = Enum.FontSize.Size14; + BackgroundTransparency = 1; + TextColor3 = FONT_COLOR; + TextYAlignment = Enum.TextYAlignment.Bottom; + TextXAlignment = Enum.TextXAlignment.Left; + Parent = container; + }; + + local healthContainer = Util.Create'Frame'{ + Name = "HealthContainer"; + Size = UDim2.new(1, -14, 0, 3); + Position = UDim2.new(0, 7, 1, -9); + BorderSizePixel = 0; + BackgroundColor3 = HEALTH_BACKGROUND_COLOR; + Parent = container; + }; + + local healthFill = Util.Create'Frame'{ + Name = "HealthFill"; + Size = UDim2.new(1, 0, 1, 0); + BorderSizePixel = 0; + BackgroundColor3 = HEALTH_GREEN_COLOR; + Parent = healthContainer; + }; + + return container, username, healthContainer, healthFill +end + +----- HEALTH ----- +local function CreateUsernameHealthMenuItem() + + local container, username, healthContainer, healthFill = nil + + if isTenFootInterface then + container, username, healthContainer, healthFill = TenFootInterface:CreateHealthBar() + else + container, username, healthContainer, healthFill = createNormalHealthBar() + end + + local hurtOverlay = Util.Create'ImageLabel' + { + Name = "HurtOverlay"; + BackgroundTransparency = 1; + Image = HURT_OVERLAY_IMAGE; + Position = UDim2.new(-10,0,-10,0); + Size = UDim2.new(20,0,20,0); + Visible = false; + Parent = GuiRoot; + }; + + local this = CreateMenuItem(container) + + --- EVENTS --- + local humanoidChangedConn, childAddedConn, childRemovedConn = nil + -------------- + + local function AnimateHurtOverlay() + if hurtOverlay and not VREnabled then + local newSize = UDim2.new(20, 0, 20, 0) + local newPos = UDim2.new(-10, 0, -10, 0) + + if hurtOverlay:IsDescendantOf(game) then + -- stop any tweens on overlay + hurtOverlay:TweenSizeAndPosition(newSize, newPos, Enum.EasingDirection.Out, Enum.EasingStyle.Linear, 0, true, function() + -- show the gui + hurtOverlay.Size = UDim2.new(1,0,1,0) + hurtOverlay.Position = UDim2.new(0,0,0,0) + hurtOverlay.Visible = true + -- now tween the hide + if hurtOverlay:IsDescendantOf(game) then + hurtOverlay:TweenSizeAndPosition(newSize, newPos, Enum.EasingDirection.Out, Enum.EasingStyle.Quad, 10, false, function() + hurtOverlay.Visible = false + end) + else + hurtOverlay.Size = newSize + hurtOverlay.Position = newPos + end + end) + end + end + end + + local healthColorToPosition = { + [Vector3.new(HEALTH_RED_COLOR.r, HEALTH_RED_COLOR.g, HEALTH_RED_COLOR.b)] = 0.1; + [Vector3.new(HEALTH_YELLOW_COLOR.r, HEALTH_YELLOW_COLOR.g, HEALTH_YELLOW_COLOR.b)] = 0.5; + [Vector3.new(HEALTH_GREEN_COLOR.r, HEALTH_GREEN_COLOR.g, HEALTH_GREEN_COLOR.b)] = 0.8; + } + local min = 0.1 + local minColor = HEALTH_RED_COLOR + local max = 0.8 + local maxColor = HEALTH_GREEN_COLOR + + local function HealthbarColorTransferFunction(healthPercent) + if healthPercent < min then + return minColor + elseif healthPercent > max then + return maxColor + end + + -- Shepard's Interpolation + local numeratorSum = Vector3.new(0,0,0) + local denominatorSum = 0 + for colorSampleValue, samplePoint in pairs(healthColorToPosition) do + local distance = healthPercent - samplePoint + if distance == 0 then + -- If we are exactly on an existing sample value then we don't need to interpolate + return Color3.new(colorSampleValue.x, colorSampleValue.y, colorSampleValue.z) + else + local wi = 1 / (distance*distance) + numeratorSum = numeratorSum + wi * colorSampleValue + denominatorSum = denominatorSum + wi + end + end + local result = numeratorSum / denominatorSum + return Color3.new(result.x, result.y, result.z) + end + + local function OnHumanoidAdded(humanoid) + local lastHealth = humanoid.Health + local function OnHumanoidHealthChanged(health) + if humanoid then + local healthDelta = lastHealth - health + local healthPercent = health / humanoid.MaxHealth + if humanoid.MaxHealth <= 0 then + healthPercent = 0 + end + healthPercent = Util.Clamp(0, 1, healthPercent) + local healthColor = HealthbarColorTransferFunction(healthPercent) + local thresholdForHurtOverlay = humanoid.MaxHealth * HEALTH_PERCANTAGE_FOR_OVERLAY + + if healthDelta >= thresholdForHurtOverlay and health ~= humanoid.MaxHealth and game.StarterGui:GetCoreGuiEnabled("Health") == true then + AnimateHurtOverlay() + end + + healthFill.Size = UDim2.new(healthPercent, 0, 1, 0) + healthFill.BackgroundColor3 = healthColor + + lastHealth = health + end + end + Util.DisconnectEvent(humanoidChangedConn) + humanoidChangedConn = humanoid.HealthChanged:connect(OnHumanoidHealthChanged) + OnHumanoidHealthChanged(lastHealth) + end + + local function OnCharacterAdded(character) + local humanoid = Util.FindPlayerHumanoid(Player) + if humanoid then + OnHumanoidAdded(humanoid) + end + + local function onChildAddedOrRemoved() + local tempHumanoid = Util.FindPlayerHumanoid(Player) + if tempHumanoid and tempHumanoid ~= humanoid then + humanoid = tempHumanoid + OnHumanoidAdded(humanoid) + end + end + Util.DisconnectEvent(childAddedConn) + Util.DisconnectEvent(childRemovedConn) + childAddedConn = character.ChildAdded:connect(onChildAddedOrRemoved) + childRemovedConn = character.ChildRemoved:connect(onChildAddedOrRemoved) + end + + rawset(this, "SetHealthbarEnabled", + function(self, enabled) + healthContainer.Visible = enabled + if enabled then + username.Size = UDim2.new(1, -14, 0, 22); + username.TextYAlignment = Enum.TextYAlignment.Bottom; + else + username.Size = UDim2.new(1, -14, 1, 0); + username.TextYAlignment = Enum.TextYAlignment.Center; + end + end) + + rawset(this, "SetNameVisible", + function(self, visible) + username.Visible = visible + end) + + -- Don't need to disconnect this one because we never reconnect it. + Player.CharacterAdded:connect(OnCharacterAdded) + if Player.Character then + OnCharacterAdded(Player.Character) + end + + local PlayerlistModule = require(GuiRoot.Modules.PlayerlistModule) + container.MouseButton1Click:connect(function() + if topbarEnabled then + PlayerlistModule.ToggleVisibility() + end + end) + + return this +end +----- END OF HEALTH ----- + +----- LEADERSTATS ----- +local function CreateLeaderstatsMenuItem() + local PlayerlistModule = require(GuiRoot.Modules.PlayerlistModule) + + local leaderstatsContainer = Util.Create'ImageButton' + { + Name = "LeaderstatsContainer"; + Size = UDim2.new(0, 0, 1, 0); + AutoButtonColor = false; + Image = ""; + BackgroundTransparency = 1; + }; + + local this = CreateMenuItem(leaderstatsContainer) + local columns = {} + + rawset(this, "SetColumns", + function(self, columnsList) + -- Should we handle is the screen dimensions change and it is no longer a small touch device after we set columns? + local isSmallTouchDevice = Util.IsTouchDevice() and GuiService:GetScreenResolution().Y < 500 + local numColumns = #columnsList + + -- Destroy old columns + for _, oldColumn in pairs(columns) do + oldColumn:Destroy() + end + columns = {} + -- End destroy old columns + local count = 0 + for index, columnData in pairs(columnsList) do -- i = 1, numColumns do + if not isSmallTouchDevice or index <= 1 then + local columnName = columnData.Name + local columnValue = columnData.Text + + local columnframe = Util.Create'Frame' + { + Name = "Column" .. tostring(index); + Size = UDim2.new(0, COLUMN_WIDTH + (index == numColumns and 0 or NAME_LEADERBOARD_SEP_WIDTH), 1, 0); + Position = UDim2.new(0, NAME_LEADERBOARD_SEP_WIDTH + (COLUMN_WIDTH + NAME_LEADERBOARD_SEP_WIDTH) * (index-1), 0, 0); + BackgroundTransparency = 1; + Parent = leaderstatsContainer; + + Util.Create'TextLabel' + { + Name = "ColumnName"; + Text = columnName; + Size = UDim2.new(1, 0, 0, 10); + Position = UDim2.new(0, 0, 0, 4); + Font = Enum.Font.SourceSans; + FontSize = Enum.FontSize.Size14; + BorderSizePixel = 0; + BackgroundTransparency = 1; + TextColor3 = FONT_COLOR; + TextYAlignment = Enum.TextYAlignment.Center; + TextXAlignment = Enum.TextXAlignment.Center; + }; + + Util.Create'TextLabel' + { + Name = "ColumnValue"; + Text = columnValue; + Size = UDim2.new(1, 0, 0, 10); + Position = UDim2.new(0, 0, 0, 19); + Font = Enum.Font.SourceSansBold; + FontSize = Enum.FontSize.Size14; + BorderSizePixel = 0; + BackgroundTransparency = 1; + TextColor3 = FONT_COLOR; + TextYAlignment = Enum.TextYAlignment.Center; + TextXAlignment = Enum.TextXAlignment.Center; + }; + }; + columns[columnName] = columnframe + count = count + 1 + end + end + leaderstatsContainer.Size = UDim2.new(0, COLUMN_WIDTH * count + NAME_LEADERBOARD_SEP_WIDTH * count, 1, 0) + end) + + rawset(this, "UpdateColumnValue", + function(self, columnName, value) + local column = columns[columnName] + local columnValue = column and column:FindFirstChild('ColumnValue') + if columnValue then + columnValue.Text = tostring(value) + end + end) + + topbarEnabledChangedEvent.Event:connect(function() + PlayerlistModule.TopbarEnabledChanged(topbarEnabled) + end) + + this:SetColumns(PlayerlistModule.GetStats()) + PlayerlistModule.OnLeaderstatsChanged.Event:connect(function(newStatColumns) + this:SetColumns(newStatColumns) + end) + + PlayerlistModule.OnStatChanged.Event:connect(function(statName, statValueAsString) + this:UpdateColumnValue(statName, statValueAsString) + end) + + leaderstatsContainer.MouseButton1Click:connect(function() + if topbarEnabled then + PlayerlistModule.ToggleVisibility() + end + end) + + return this +end +----- END OF LEADERSTATS ----- + +--- SETTINGS --- +local function CreateSettingsIcon(topBarInstance) + local MenuModule = require(game.CoreGui.RobloxGui.Modules.Settings.SettingsHub) + + local settingsIconButton = Util.Create'ImageButton' + { + Name = "Settings"; + Size = UDim2.new(0, 50, 0, TOPBAR_THICKNESS); + Image = ""; + AutoButtonColor = false; + BackgroundTransparency = 1; + } + + local settingsIconImage = Util.Create'ImageLabel' + { + Name = "SettingsIcon"; + Size = UDim2.new(0, 32, 0, 25); + Position = UDim2.new(0.5, -16, 0.5, -12); + BackgroundTransparency = 1; + Image = "rbxasset://textures/ui/Menu/Hamburger.png"; + Parent = settingsIconButton; + }; + + local function UpdateHamburgerIcon() + if settingsActive then + settingsIconImage.Image = "rbxasset://textures/ui/Menu/HamburgerDown.png"; + else + settingsIconImage.Image = "rbxasset://textures/ui/Menu/Hamburger.png"; + end + end + + local function toggleSettings() + if settingsActive == false then + settingsActive = true + else + settingsActive = false + end + + MenuModule:ToggleVisibility() + UpdateHamburgerIcon() + + return settingsActive + end + + settingsIconButton.MouseButton1Click:connect(function() toggleSettings() end) + + MenuModule.SettingsShowSignal:connect(function(active) + settingsActive = active + topBarInstance:UpdateBackgroundTransparency() + UpdateHamburgerIcon() + end) + + local menuItem = CreateMenuItem(settingsIconButton) + + rawset(menuItem, "SetTransparency", function(self, transparency) + settingsIconImage.ImageTransparency = transparency + end) + rawset(menuItem, "SetImage", function(self, image) + settingsIconImage.Image = image + end) + rawset(menuItem, "SetSettingsActive", function(self, active) + settingsActive = active + MenuModule:ToggleVisibility(settingsActive) + UpdateHamburgerIcon() + + return settingsActive + end) + + return menuItem +end + +local function Create3DSettingsIcon(topBarInstance, panel, menubar) + local MenuModule = require(game.CoreGui.RobloxGui.Modules.Settings.SettingsHub) + local menuItem = Create3DMenuItem() + menuItem:SetHoverText("Settings") + + local icon = Util.Create "ImageLabel" { + Parent = menuItem:GetInstance(), + + Position = UDim2.new(0.5, -15, 0.5, -11), + Size = UDim2.new(0, 30, 0, 22), + + BackgroundTransparency = 1, + + Image = "rbxasset://textures/ui/Menu/hamburger3D.png" + } + + menuItem.MouseButton1Click:connect(function() + MenuModule:SetVisibility(true) + menubar:CloseAllExcept(menuItem) + end) + + local settingsPanel = Panel3D.Get("SettingsMenu") + function settingsPanel:OnVisibilityChanged(visible) + menuItem:SetActive(visible) + end + + return menuItem +end + +------------ + +--- CHAT --- +local function CreateUnreadMessagesNotifier(ChatModule) + local chatActive = false + local lastMessageCount = 0 + + local chatCounter = Util.Create'ImageLabel' + { + Name = "ChatCounter"; + Size = UDim2.new(0, 18, 0, 18); + Position = UDim2.new(1, -12, 0, -4); + BackgroundTransparency = 1; + Image = "rbxasset://textures/ui/Chat/MessageCounter.png"; + Visible = false; + }; + + local chatCountText = Util.Create'TextLabel' + { + Name = "ChatCounterText"; + Text = ''; + Size = UDim2.new(0, 13, 0, 9); + Position = UDim2.new(0.5, -7, 0.5, -7); + Font = Enum.Font.SourceSansBold; + FontSize = Enum.FontSize.Size14; + BorderSizePixel = 0; + BackgroundTransparency = 1; + TextColor3 = FONT_COLOR; + TextYAlignment = Enum.TextYAlignment.Center; + TextXAlignment = Enum.TextXAlignment.Center; + Parent = chatCounter; + }; + + local function OnUnreadMessagesChanged(count) + if chatActive then + lastMessageCount = count + end + local unreadCount = count - lastMessageCount + + if unreadCount <= 0 then + chatCountText.Text = "" + chatCounter.Visible = false + else + if unreadCount < 100 then + chatCountText.Text = tostring(unreadCount) + else + chatCountText.Text = "!" + end + chatCounter.Visible = true + end + end + + local function onChatStateChanged(visible) + chatActive = visible + if ChatModule then + OnUnreadMessagesChanged(ChatModule:GetMessageCount()) + end + end + + + if ChatModule then + if ChatModule.VisibilityStateChanged then + ChatModule.VisibilityStateChanged:connect(onChatStateChanged) + end + if ChatModule.MessagesChanged then + ChatModule.MessagesChanged:connect(OnUnreadMessagesChanged) + end + + onChatStateChanged(ChatModule:GetVisibility()) + OnUnreadMessagesChanged(ChatModule:GetMessageCount()) + end + + return chatCounter +end + +local function CreateChatIcon() + local chatEnabled = game:GetService("UserInputService"):GetPlatform() ~= Enum.Platform.XBoxOne + if not chatEnabled then return end + + local ChatModule = require(GuiRoot.Modules.Chat) + + local bubbleChatIsOn = not PlayersService.ClassicChat and PlayersService.BubbleChat + local debounce = 0 + + local chatIconButton = Util.Create'ImageButton' + { + Name = "Chat"; + Size = UDim2.new(0, 50, 0, TOPBAR_THICKNESS); + Image = ""; + AutoButtonColor = false; + BackgroundTransparency = 1; + }; + + local chatIconImage = Util.Create'ImageLabel' + { + Name = "ChatIcon"; + Size = UDim2.new(0, 28, 0, 27); + Position = UDim2.new(0.5, -14, 0.5, -13); + BackgroundTransparency = 1; + Image = "rbxasset://textures/ui/Chat/Chat.png"; + Parent = chatIconButton; + }; + if not Util.IsTouchDevice() then + local chatCounter = CreateUnreadMessagesNotifier(ChatModule) + chatCounter.Parent = chatIconImage; + end + + local function updateIcon(down) + if down then + chatIconImage.Image = "rbxasset://textures/ui/Chat/ChatDown.png"; + else + chatIconImage.Image = "rbxasset://textures/ui/Chat/Chat.png"; + end + end + + local function onChatStateChanged(visible) + if not Util.IsTouchDevice() then + updateIcon(visible) + end + end + + local function toggleChat() + if InputService.VREnabled then + ChatModule:ToggleVisibility() + elseif Util.IsTouchDevice() or bubbleChatIsOn then + if debounce + DEBOUNCE_TIME < tick() then + if Util.IsTouchDevice() then + ChatModule:SetVisible(true) + end + ChatModule:FocusChatBar() + end + else + ChatModule:ToggleVisibility() + end + end + + topbarEnabledChangedEvent.Event:connect(function() + ChatModule:TopbarEnabledChanged(topbarEnabled) + end) + + chatIconButton.MouseButton1Click:connect(function() + toggleChat() + end) + + if Util.IsTouchDevice() or bubbleChatIsOn then + if ChatModule.ChatBarFocusChanged then + ChatModule.ChatBarFocusChanged:connect(function(isFocused) + updateIcon(isFocused) + debounce = tick() + end) + end + updateIcon(false) + end + + if ChatModule.VisibilityStateChanged then + ChatModule.VisibilityStateChanged:connect(onChatStateChanged) + end + onChatStateChanged(ChatModule:GetVisibility()) + + if not (Util.IsTouchDevice() or InputService.VREnabled) then + ChatModule:SetVisible(true) + end + + local menuItem = CreateMenuItem(chatIconButton) + + rawset(menuItem, "ToggleChat", function(self) + toggleChat() + end) + rawset(menuItem, "SetTransparency", function(self, transparency) + chatIconImage.ImageTransparency = transparency + end) + rawset(menuItem, "SetImage", function(self, newImage) + chatIconImage.Image = newImage + end) + + return menuItem +end + +local function CreateMobileHideChatIcon() + local ChatModule = require(GuiRoot.Modules.Chat) + + local chatHideIconButton = Util.Create'ImageButton' + { + Name = "ChatVisible"; + Size = UDim2.new(0, 50, 0, TOPBAR_THICKNESS); + Image = ""; + AutoButtonColor = false; + BackgroundTransparency = 1; + }; + + local chatIconImage = Util.Create'ImageLabel' + { + Name = "ChatVisibleIcon"; + Size = UDim2.new(0, 28, 0, 27); + Position = UDim2.new(0.5, -14, 0.5, -13); + BackgroundTransparency = 1; + Image = "rbxasset://textures/ui/Chat/ToggleChat.png"; + Parent = chatHideIconButton; + }; + + local unreadMessageNotifier = CreateUnreadMessagesNotifier(ChatModule) + unreadMessageNotifier.Parent = chatIconImage + + local function updateIcon(down) + if down then + chatIconImage.Image = "rbxasset://textures/ui/Chat/ToggleChatDown.png"; + else + chatIconImage.Image = "rbxasset://textures/ui/Chat/ToggleChat.png"; + end + end + + local function toggleChat() + ChatModule:ToggleVisibility() + end + + local function onChatStateChanged(visible) + updateIcon(visible) + end + + chatHideIconButton.MouseButton1Click:connect(function() + toggleChat() + end) + + if ChatModule.VisibilityStateChanged then + ChatModule.VisibilityStateChanged:connect(onChatStateChanged) + end + onChatStateChanged(ChatModule:GetVisibility()) + + return CreateMenuItem(chatHideIconButton) +end + + +local function Create3DChatIcon(topBarInstance, panel, menubar) + local chatEnabled = game:GetService("UserInputService"):GetPlatform() ~= Enum.Platform.XBoxOne + if not chatEnabled then return end + + local ChatModule = require(GuiRoot.Modules.Chat) + + local menuItem = Create3DMenuItem() + menuItem:SetHoverText("Chat") + + local icon = Util.Create "ImageLabel" { + Parent = menuItem:GetInstance(), + + Position = UDim2.new(0.5, -14, 0.5, -12), + Size = UDim2.new(0, 28, 0, 28), + + BackgroundTransparency = 1, + + Image = "rbxasset://textures/ui/Chat/Chat.png" + } + + menuItem.MouseButton1Click:connect(function() + ChatModule:SetVisible(not ChatModule:GetVisibility()) + if ChatModule:GetVisibility() then + ChatModule:FocusChatBar() + end + menubar:CloseAllExcept(menuItem) + end) + + local closedEventConn = nil + local function OnVREnabled(prop) + if prop == 'VREnabled' then + if closedEventConn then + closedEventConn:disconnect() + closedEventConn = nil + end + if InputService.VREnabled then + local VirtualKeyboardModule = require(GuiRoot.Modules.VR.VirtualKeyboard) + closedEventConn = VirtualKeyboardModule.ClosedEvent:connect(function() + if ChatModule:IsFocused(true) then + ChatModule:SetVisible(false) + end + end) + end + end + end + InputService.Changed:connect(OnVREnabled) + spawn(function() OnVREnabled("VREnabled") end) + + + local chatPanel = Panel3D.Get("Chat") + function chatPanel:OnVisibilityChanged(visible) + menuItem:SetActive(visible) + end + + return menuItem +end + +local function Create3DUserGuiToggleIcon(topBarInstance, panel, menubar) + local menuItem = Create3DMenuItem() + menuItem:SetHoverText("2D UI") + + local icon = Util.Create "ImageLabel" { + Parent = menuItem:GetInstance(), + + Position = UDim2.new(0.5, -14, 0.5, -14), + Size = UDim2.new(0, 28, 0, 28), + + BackgroundTransparency = 1, + + Image = "rbxasset://textures/ui/VR/toggle2D.png" + } + + local userGuiPanel = Panel3D.Get("UserGui") + userGuiPanel:SetType(Panel3D.Type.Fixed) + userGuiPanel:ResizePixels(300, 125) + userGuiPanel:SetVisible(false, false) + + menuItem.MouseButton1Click:connect(function() + if InputService.VREnabled then + userGuiPanel:SetVisible(not userGuiPanel.isVisible, false) + end + end) + + function userGuiPanel:OnVisibilityChanged(visible) + if visible then + local headLook = Panel3D.GetHeadLookXZ(true) + userGuiPanel.localCF = headLook * CFrame.Angles(math.rad(5), 0, 0) * CFrame.new(0, 0, 5) + end + menuItem:SetActive(visible) + local success, msg = pcall(function() + CoreGuiService:SetUserGuiRendering(true, visible and userGuiPanel:GetPart() or nil, Enum.NormalId.Front) + end) + end + + local function OnVREnabled(prop) + if prop == 'VREnabled' then + local guiPart = nil + if InputService.VREnabled then + if userGuiPanel.isVisible then + guiPart = userGuiPanel:GetPart() + end + else + userGuiPanel:SetVisible(false, false) + end + local success, msg = pcall(function() + CoreGuiService:SetUserGuiRendering(InputService.VREnabled, guiPart, Enum.NormalId.Front) + end) + end + end + InputService.Changed:connect(OnVREnabled) + spawn(function() OnVREnabled("VREnabled") end) + + return menuItem +end + +----------- + +--- Backpack --- +local function CreateBackpackIcon() + local BackpackModule = require(GuiRoot.Modules.BackpackScript) + + local backpackIconButton = Util.Create'ImageButton' + { + Name = "Backpack"; + Size = UDim2.new(0, 50, 0, TOPBAR_THICKNESS); + Image = ""; + AutoButtonColor = false; + BackgroundTransparency = 1; + }; + + local backpackIconImage = Util.Create'ImageLabel' + { + Name = "BackpackIcon"; + Size = UDim2.new(0, 22, 0, 28); + Position = UDim2.new(0.5, -11, 0.5, -14); + BackgroundTransparency = 1; + Image = "rbxasset://textures/ui/Backpack/Backpack.png"; + Parent = backpackIconButton; + }; + + local function onBackpackStateChanged(open) + if open then + backpackIconImage.Image = "rbxasset://textures/ui/Backpack/Backpack_Down.png"; + else + backpackIconImage.Image = "rbxasset://textures/ui/Backpack/Backpack.png"; + end + end + + BackpackModule.StateChanged.Event:connect(onBackpackStateChanged) + + local function toggleBackpack() + BackpackModule:OpenClose() + end + + topbarEnabledChangedEvent.Event:connect(function() + BackpackModule:TopbarEnabledChanged(topbarEnabled) + end) + + backpackIconButton.MouseButton1Click:connect(function() + BackpackModule:OpenClose() + end) + + return CreateMenuItem(backpackIconButton) +end +-------------- + +----- Stop Recording -- +local function CreateStopRecordIcon() + local stopRecordIconButton = Util.Create'ImageButton' + { + Name = "StopRecording"; + Size = UDim2.new(0, 50, 0, TOPBAR_THICKNESS); + Image = ""; + Visible = true; + BackgroundTransparency = 1; + }; + stopRecordIconButton:SetVerb("RecordToggle") + + local stopRecordIconLabel = Util.Create'ImageLabel' + { + Name = "StopRecordingIcon"; + Size = UDim2.new(0, 28, 0, 28); + Position = UDim2.new(0.5, -14, 0.5, -14); + BackgroundTransparency = 1; + Image = "rbxasset://textures/ui/RecordDown.png"; + Parent = stopRecordIconButton; + }; + + return CreateMenuItem(stopRecordIconButton) +end +----------------------- + +local TopBar = CreateTopBar() +local LeftMenubar = CreateMenuBar(BarAlignmentEnum.Left) +local RightMenubar = CreateMenuBar(BarAlignmentEnum.Right) +local ThreeDMenubar = Create3DMenuBar(BarAlignmentEnum.Left, Topbar3DPanel) + +local settingsIcon = CreateSettingsIcon(TopBar) +local mobileShowChatIcon = Util.IsTouchDevice() and CreateMobileHideChatIcon() or nil +local chatIcon = CreateChatIcon() +local backpackIcon = CreateBackpackIcon() +local stopRecordingIcon = CreateStopRecordIcon() + +local leaderstatsMenuItem = CreateLeaderstatsMenuItem() +local nameAndHealthMenuItem = CreateUsernameHealthMenuItem() + +local settingsIcon3D = Create3DSettingsIcon(TopBar, Topbar3DPanel, ThreeDMenubar) +local chatIcon3D = Create3DChatIcon(TopBar, Topbar3DPanel, ThreeDMenubar) +local userGuiIcon3D = Create3DUserGuiToggleIcon(TopBar, Topbar3DPanel, ThreeDMenubar) + +local LEFT_ITEM_ORDER = {} +local RIGHT_ITEM_ORDER = {} +local THREE_D_ITEM_ORDER = {} + + +-- Set Item Orders +if settingsIcon then + LEFT_ITEM_ORDER[settingsIcon] = 1 +end +if mobileShowChatIcon then + LEFT_ITEM_ORDER[mobileShowChatIcon] = 2 +end +if chatIcon then + LEFT_ITEM_ORDER[chatIcon] = 3 +end +if backpackIcon then + LEFT_ITEM_ORDER[backpackIcon] = 4 +end +if stopRecordingIcon then + LEFT_ITEM_ORDER[stopRecordingIcon] = 5 +end + +if leaderstatsMenuItem then + RIGHT_ITEM_ORDER[leaderstatsMenuItem] = 1 +end +if nameAndHealthMenuItem and not isTenFootInterface then + RIGHT_ITEM_ORDER[nameAndHealthMenuItem] = 2 +end + +if settingsIcon3D then + THREE_D_ITEM_ORDER[settingsIcon3D] = 1 +end +if chatIcon3D then + THREE_D_ITEM_ORDER[chatIcon3D] = 2 +end +if userGuiIcon3D then + THREE_D_ITEM_ORDER[userGuiIcon3D] = 3 +end + +------------------------- + + +local function AddItemInOrder(Bar, Item, ItemOrder) + local index = 1 + while ItemOrder[Bar:ItemAtIndex(index)] and ItemOrder[Bar:ItemAtIndex(index)] < ItemOrder[Item] do + index = index + 1 + end + Bar:AddItem(Item, index) +end + +local function OnCoreGuiChanged(coreGuiType, coreGuiEnabled) + local enabled = coreGuiEnabled and topbarEnabled + if coreGuiType == Enum.CoreGuiType.PlayerList or coreGuiType == Enum.CoreGuiType.All then + if leaderstatsMenuItem then + if enabled then + AddItemInOrder(RightMenubar, leaderstatsMenuItem, RIGHT_ITEM_ORDER) + else + RightMenubar:RemoveItem(leaderstatsMenuItem) + end + end + end + if coreGuiType == Enum.CoreGuiType.Health or coreGuiType == Enum.CoreGuiType.All then + if nameAndHealthMenuItem then + nameAndHealthMenuItem:SetHealthbarEnabled(enabled) + end + end + if coreGuiType == Enum.CoreGuiType.Backpack or coreGuiType == Enum.CoreGuiType.All then + if backpackIcon then + if enabled then + AddItemInOrder(LeftMenubar, backpackIcon, LEFT_ITEM_ORDER) + else + LeftMenubar:RemoveItem(backpackIcon) + end + end + end + if coreGuiType == Enum.CoreGuiType.Chat or coreGuiType == Enum.CoreGuiType.All then + local showTopbarChatIcon = enabled and Player.ChatMode == Enum.ChatMode.TextAndMenu + local showThree3DChatIcon = coreGuiEnabled and InputService.VREnabled and Player.ChatMode == Enum.ChatMode.TextAndMenu + + if showThree3DChatIcon then + if chatIcon3D then + AddItemInOrder(ThreeDMenubar, chatIcon3D, THREE_D_ITEM_ORDER) + end + else + if chatIcon3D then + ThreeDMenubar:RemoveItem(chatIcon3D) + end + end + if showTopbarChatIcon then + if chatIcon then + AddItemInOrder(LeftMenubar, chatIcon, LEFT_ITEM_ORDER) + end + if mobileShowChatIcon and PlayersService.ClassicChat then + AddItemInOrder(LeftMenubar, mobileShowChatIcon, LEFT_ITEM_ORDER) + end + else + if chatIcon then + LeftMenubar:RemoveItem(chatIcon) + end + if mobileShowChatIcon then + LeftMenubar:RemoveItem(mobileShowChatIcon) + end + end + end + + if nameAndHealthMenuItem then + local playerListOn = StarterGui:GetCoreGuiEnabled(Enum.CoreGuiType.PlayerList) + local healthbarOn = StarterGui:GetCoreGuiEnabled(Enum.CoreGuiType.Health) + -- Left-align the player's name if either playerlist or healthbar is shown + nameAndHealthMenuItem:SetNameVisible((playerListOn or healthbarOn) and topbarEnabled) + end +end + + +TopBar:UpdateBackgroundTransparency() + +LeftMenubar:SetDock(TopBar:GetInstance()) +RightMenubar:SetDock(TopBar:GetInstance()) +ThreeDMenubar:SetDock(Topbar3DPanel:GetGUI()) + + +if not isTenFootInterface then + Util.SetGUIInsetBounds(0, TOPBAR_THICKNESS, 0, 0) +end + +if settingsIcon then + AddItemInOrder(LeftMenubar, settingsIcon, LEFT_ITEM_ORDER) +end +if nameAndHealthMenuItem and topbarEnabled and not isTenFootInterface then + AddItemInOrder(RightMenubar, nameAndHealthMenuItem, RIGHT_ITEM_ORDER) +end + +if userGuiIcon3D and vr3dGuis then + local function FindScreenGuiChild(object) + for _, child in pairs(object:GetChildren()) do + if child:IsA('ScreenGui') then + return child + end + end + end + + local function onPlayerGuiAdded(playerGui) + playerGui.ChildAdded:connect(function(child) + if FindScreenGuiChild(playerGui) then + AddItemInOrder(ThreeDMenubar, userGuiIcon3D, THREE_D_ITEM_ORDER) + end + end) + playerGui.ChildRemoved:connect(function(child) + if child:IsA('ScreenGui') and not FindScreenGuiChild(playerGui) then + ThreeDMenubar:RemoveItem(userGuiIcon3D) + end + end) + if FindScreenGuiChild(playerGui) then + AddItemInOrder(ThreeDMenubar, userGuiIcon3D, THREE_D_ITEM_ORDER) + end + end + Player.ChildAdded:connect(function(child) + if child:IsA('PlayerGui') then + onPlayerGuiAdded(child) + end + end) + if Player:FindFirstChild('PlayerGui') then + onPlayerGuiAdded(Player:FindFirstChild('PlayerGui')) + end +end + + +local function MoveHamburgerTo3D() + Topbar3DPanel:SetType(Panel3D.Type.Fixed) + Topbar3DPanel:LinkTo("Backpack") + Topbar3DPanel:SetVisible(true) + + local backpackPanel = Panel3D.Get("Backpack") + local panelLocalCF = CFrame.Angles(math.rad(5), 0, 0) * CFrame.new(0, -1.625, 0) * CFrame.Angles(math.rad(5), 0, 0) + function Topbar3DPanel:PreUpdate(cameraCF, cameraRenderCF, userHeadCF, lookRay) + local panelOriginCF = backpackPanel.localCF or CFrame.new() + self.localCF = panelOriginCF * panelLocalCF + end + + function Topbar3DPanel:OnUpdate() + for _, item in pairs(ThreeDMenubar:GetItems()) do + item:SetTransparency(self.transparency) + end + end + + LeftMenubar:RemoveItem(settingsIcon) + AddItemInOrder(ThreeDMenubar, settingsIcon3D, THREE_D_ITEM_ORDER) +end + +local gameOptions = settings():FindFirstChild("Game Options") +if gameOptions and not isTenFootInterface then + local success, result = pcall(function() + gameOptions.VideoRecordingChangeRequest:connect(function(recording) + if recording and topbarEnabled then + AddItemInOrder(LeftMenubar, stopRecordingIcon, LEFT_ITEM_ORDER) + else + LeftMenubar:RemoveItem(stopRecordingIcon) + end + end) + end) +end + +local function topBarEnabledChanged() + topbarEnabledChangedEvent:Fire(topbarEnabled) + TopBar:UpdateBackgroundTransparency() + for _, enumItem in pairs(Enum.CoreGuiType:GetEnumItems()) do + -- The All enum will be false if any of the coreguis are false + -- therefore by force updating it we are clobbering the previous sets + if enumItem ~= Enum.CoreGuiType.All then + OnCoreGuiChanged(enumItem, StarterGui:GetCoreGuiEnabled(enumItem)) + end + end +end + +local UISChanged; +local function OnVREnabled(prop) + if prop == "VREnabled" and InputService.VREnabled then + VREnabled = true + topbarEnabled = false + MoveHamburgerTo3D() + topBarEnabledChanged() + if UISChanged then + UISChanged:disconnect() + UISChanged = nil + end + end +end +UISChanged = InputService.Changed:connect(OnVREnabled) +OnVREnabled("VREnabled") + +if defeatableTopbar then + StarterGui:RegisterSetCore("TopbarEnabled", function(enabled) + if type(enabled) == "boolean" then + topbarEnabled = enabled + topBarEnabledChanged() + end + end) +end + +-- Hook-up coregui changing +StarterGui.CoreGuiChangedSignal:connect(OnCoreGuiChanged) +topBarEnabledChanged() diff --git a/2016/content/scripts/CoreScripts/VehicleHud.lua b/2016/content/scripts/CoreScripts/VehicleHud.lua new file mode 100644 index 0000000..92b749b --- /dev/null +++ b/2016/content/scripts/CoreScripts/VehicleHud.lua @@ -0,0 +1,160 @@ +--[[ + // Filename: VehicleHud.lua + // Version 1.0 + // Written by: jmargh + // Description: Implementation of the VehicleSeat HUD + + // TODO: + Once this is live and stable, move to PlayerScripts as module +]] +local RunService = game:GetService('RunService') +local Players = game:GetService('Players') +while not Players.LocalPlayer do + wait() +end +local LocalPlayer = Players.LocalPlayer +local RobloxGui = script.Parent +local CurrentVehicleSeat = nil +local VehicleSeatRenderCn = nil +local VehicleSeatHUDChangedCn = nil + +local RobloxGui = game:GetService("CoreGui"):WaitForChild("RobloxGui") +RobloxGui:WaitForChild("Modules"):WaitForChild("TenFootInterface") +local isTenFootInterface = require(RobloxGui.Modules.TenFootInterface):IsEnabled() + + +--[[ Images ]]-- +local VEHICLE_HUD_BG = 'rbxasset://textures/ui/Vehicle/SpeedBarBKG.png' +local SPEED_BAR_EMPTY = 'rbxasset://textures/ui/Vehicle/SpeedBarEmpty.png' +local SPEED_BAR = 'rbxasset://textures/ui/Vehicle/SpeedBar.png' + +--[[ Constants ]]-- +local BOTTOM_OFFSET = (isTenFootInterface and 100 or 70) + +--[[ Gui Creation ]]-- +local function createImageLabel(name, size, position, image, parent) + local imageLabel = Instance.new('ImageLabel') + imageLabel.Name = name + imageLabel.Size = size + imageLabel.Position = position + imageLabel.BackgroundTransparency = 1 + imageLabel.Image = image + imageLabel.Parent = parent + + return imageLabel +end + +local function createTextLabel(name, alignment, text, parent) + local textLabel = Instance.new('TextLabel') + textLabel.Name = name + textLabel.Size = UDim2.new(1, -4, 0, (isTenFootInterface and 50 or 20)) + textLabel.Position = UDim2.new(0, 2, 0, (isTenFootInterface and -50 or -20)) + textLabel.BackgroundTransparency = 1 + textLabel.TextXAlignment = alignment + textLabel.Font = Enum.Font.SourceSans + textLabel.FontSize = (isTenFootInterface and Enum.FontSize.Size48 or Enum.FontSize.Size18) + textLabel.TextColor3 = Color3.new(1, 1, 1) + textLabel.TextStrokeTransparency = 0.5 + textLabel.TextStrokeColor3 = Color3.new(49/255, 49/255, 49/255) + textLabel.Text = text + textLabel.Parent = parent + + return textLabel +end + +local VehicleHudFrame = Instance.new('Frame') +VehicleHudFrame.Name = "VehicleHudFrame" +VehicleHudFrame.Size = UDim2.new(0, (isTenFootInterface and 316 or 158), 0, (isTenFootInterface and 50 or 14)) +VehicleHudFrame.Position = UDim2.new(0.5, -(VehicleHudFrame.Size.X.Offset/2), 1, -BOTTOM_OFFSET - VehicleHudFrame.Size.Y.Offset) +VehicleHudFrame.BackgroundTransparency = 1 +VehicleHudFrame.Visible = false +VehicleHudFrame.Parent = RobloxGui + +local speedBarClippingFrame = Instance.new("Frame") +speedBarClippingFrame.Name = "SpeedBarClippingFrame" +speedBarClippingFrame.Size = UDim2.new(0, 0, 0, (isTenFootInterface and 24 or 4)) +speedBarClippingFrame.Position = UDim2.new(0.5, (isTenFootInterface and -142 or -71), 0.5, (isTenFootInterface and -13 or -2)) +speedBarClippingFrame.BackgroundTransparency = 1 +speedBarClippingFrame.ClipsDescendants = true +speedBarClippingFrame.Parent = VehicleHudFrame + +local HudBG = createImageLabel("HudBG", UDim2.new(1, 0, 1, 0), UDim2.new(0, 0, 0, 1), VEHICLE_HUD_BG, VehicleHudFrame) +local SpeedBG = createImageLabel("SpeedBG", UDim2.new(0, (isTenFootInterface and 284 or 142), 0, (isTenFootInterface and 24 or 4)), UDim2.new(0.5, (isTenFootInterface and -142 or -71), 0.5, (isTenFootInterface and -13 or -2)), SPEED_BAR_EMPTY, VehicleHudFrame) +local SpeedBarImage = createImageLabel("SpeedBarImage", UDim2.new(0, (isTenFootInterface and 284 or 142), 1, 0), UDim2.new(0, 0, 0, 0), SPEED_BAR, speedBarClippingFrame) +SpeedBarImage.ZIndex = 2 + +local SpeedLabel = createTextLabel("SpeedLabel", Enum.TextXAlignment.Left, "Speed", VehicleHudFrame) +local SpeedText = createTextLabel("SpeedText", Enum.TextXAlignment.Right, "0", VehicleHudFrame) + +--[[ Local Functions ]]-- +local function getHumanoid() + local character = LocalPlayer and LocalPlayer.Character + if character then + for _,child in pairs(character:GetChildren()) do + if child:IsA('Humanoid') then + return child + end + end + end +end + +local function onRenderStepped() + if CurrentVehicleSeat then + local speed = CurrentVehicleSeat.Velocity.magnitude + SpeedText.Text = tostring(math.min(math.floor(speed), 9999)) + local drawSize = math.floor((speed / CurrentVehicleSeat.MaxSpeed) * SpeedBG.Size.X.Offset) + drawSize = math.min(drawSize, SpeedBG.Size.X.Offset) + speedBarClippingFrame.Size = UDim2.new(0, drawSize, 0, (isTenFootInterface and 24 or 4)) + end +end + +local function onVehicleSeatChanged(property) + if property == "HeadsUpDisplay" then + VehicleHudFrame.Visible = not VehicleHudFrame.Visible + end +end + +local function onSeated(active, currentSeatPart) + if active then + -- TODO: Clean up when new API is live for a while + if currentSeatPart and currentSeatPart:IsA('VehicleSeat') then + CurrentVehicleSeat = currentSeatPart + else + local camSubject = workspace.CurrentCamera.CameraSubject + if camSubject and camSubject:IsA('VehicleSeat') then + CurrentVehicleSeat = camSubject + end + end + if CurrentVehicleSeat then + VehicleHudFrame.Visible = CurrentVehicleSeat.HeadsUpDisplay + VehicleSeatRenderCn = RunService.RenderStepped:connect(onRenderStepped) + VehicleSeatHUDChangedCn = CurrentVehicleSeat.Changed:connect(onVehicleSeatChanged) + end + else + if CurrentVehicleSeat then + VehicleHudFrame.Visible = false + CurrentVehicleSeat = nil + if VehicleSeatRenderCn then + VehicleSeatRenderCn:disconnect() + VehicleSeatRenderCn = nil + end + if VehicleSeatHUDChangedCn then + VehicleSeatHUDChangedCn:disconnect() + VehicleSeatHUDChangedCn = nil + end + end + end +end + +local function connectSeated() + local humanoid = getHumanoid() + while not humanoid do + wait() + humanoid = getHumanoid() + end + humanoid.Seated:connect(onSeated) +end +connectSeated() +LocalPlayer.CharacterAdded:connect(function(character) + connectSeated() +end) diff --git a/2016/content/scripts/Libraries/RbxStamper.lua b/2016/content/scripts/Libraries/RbxStamper.lua new file mode 100644 index 0000000..b88212c --- /dev/null +++ b/2016/content/scripts/Libraries/RbxStamper.lua @@ -0,0 +1,2206 @@ +local t = {} + +function waitForChild(instance, name) + while not instance:FindFirstChild(name) do + instance.ChildAdded:wait() + end +end + +-- Do a line/plane intersection. The line starts at the camera. The plane is at y == 0, normal(0, 1, 0) +-- +-- vectorPos - End point of the line. +-- +-- Return: +-- cellPos - The terrain cell intersection point if there is one, vectorPos if there isn't. +-- hit - Whether there was a plane intersection. Value is true if there was, false if not. +function PlaneIntersection(vectorPos) + local hit = false + local currCamera = game:GetService("Workspace").CurrentCamera + local startPos = Vector3.new(currCamera.CoordinateFrame.p.X, currCamera.CoordinateFrame.p.Y, currCamera.CoordinateFrame.p.Z) + local endPos = Vector3.new(vectorPos.X, vectorPos.Y, vectorPos.Z) + local normal = Vector3.new(0, 1, 0) + local p3 = Vector3.new(0, 0, 0) + local startEndDot = normal:Dot(endPos - startPos) + local cellPos = vectorPos + if startEndDot ~= 0 then + local t = normal:Dot(p3 - startPos) / startEndDot + if(t >=0 and t <=1) then + local intersection = ((endPos - startPos) * t) + startPos + cellPos = game:GetService("Workspace").Terrain:WorldToCell(intersection) + hit = true + end + end + + return cellPos, hit +end + + +-- Purpose: +-- Checks for terrain touched by the mouse hit. +-- Will do a plane intersection if no terrain is touched. +-- +-- mouse - Mouse to check the .hit for. +-- +-- Return: +-- cellPos - Cell position hit. Nil if none. +function GetTerrainForMouse(mouse) + -- There was no target, so all it could be is a plane intersection. + -- Check for a plane intersection. If there isn't one then nothing will get hit. + local cell = game:GetService("Workspace").Terrain:WorldToCellPreferSolid(Vector3.new(mouse.hit.x, mouse.hit.y, mouse.hit.z)) + local planeLoc = nil + -- If nothing was hit, do the plane intersection. + if 0 == game:GetService("Workspace").Terrain:GetCell(cell.X, cell.Y, cell.Z).Value then + cell = nil + planeLoc, hit = PlaneIntersection(Vector3.new(mouse.hit.x, mouse.hit.y, mouse.hit.z)) + if hit then + cell = planeLoc + end + end + return cell +end + +-- setup helper functions +local insertBoundingBoxOverlapVector = Vector3.new(.3, .3, .3) -- we can still stamp if our character extrudes into the target stamping space by .3 or fewer units + +-- rotates a model by yAngle radians about the global y-axis +local function rotatePartAndChildren(part, rotCF, offsetFromOrigin) + -- rotate this thing, if it's a part + if part:IsA("BasePart") then + part.CFrame = (rotCF * (part.CFrame - offsetFromOrigin)) + offsetFromOrigin + end + + -- recursively do the same to all children + local partChildren = part:GetChildren() + for c = 1, #partChildren do rotatePartAndChildren(partChildren[c], rotCF, offsetFromOrigin) end +end + +local function modelRotate(model, yAngle) + local rotCF = CFrame.Angles(0, yAngle, 0) + local offsetFromOrigin = model:GetModelCFrame().p + + rotatePartAndChildren(model, rotCF, offsetFromOrigin) +end + + +local function collectParts(object, baseParts, scripts, decals) + if object:IsA("BasePart") then + baseParts[#baseParts+1] = object + elseif object:IsA("Script") then + scripts[#scripts+1] = object + elseif object:IsA("Decal") then + decals[#decals+1] = object + end + + for index,child in pairs(object:GetChildren()) do + collectParts(child, baseParts, scripts, decals) + end +end + +local function clusterPartsInRegion(startVector, endVector) + local cluster = game:GetService("Workspace"):FindFirstChild("Terrain") + + local startCell = cluster:WorldToCell(startVector) + local endCell = cluster:WorldToCell(endVector) + + local startX = startCell.X + local startY = startCell.Y + local startZ = startCell.Z + + local endX = endCell.X + local endY = endCell.Y + local endZ = endCell.Z + + if startX < cluster.MaxExtents.Min.X then startX = cluster.MaxExtents.Min.X end + if startY < cluster.MaxExtents.Min.Y then startY = cluster.MaxExtents.Min.Y end + if startZ < cluster.MaxExtents.Min.Z then startZ = cluster.MaxExtents.Min.Z end + + if endX > cluster.MaxExtents.Max.X then endX = cluster.MaxExtents.Max.X end + if endY > cluster.MaxExtents.Max.Y then endY = cluster.MaxExtents.Max.Y end + if endZ > cluster.MaxExtents.Max.Z then endZ = cluster.MaxExtents.Max.Z end + + for x = startX, endX do + for y = startY, endY do + for z = startZ, endZ do + if (cluster:GetCell(x, y, z).Value) > 0 then return true end + end + end + end + + return false +end + +local function findSeatsInModel(parent, seatTable) + if not parent then return end + + if parent.className == "Seat" or parent.className == "VehicleSeat" then + table.insert(seatTable, parent) + end + local myChildren = parent:GetChildren() + for j = 1, #myChildren do + findSeatsInModel(myChildren[j], seatTable) + end +end + +local function setSeatEnabledStatus(model, isEnabled) + local seatList = {} + findSeatsInModel(model, seatList) + + if isEnabled then + -- remove any welds called "SeatWeld" in seats + for i = 1, #seatList do + local nextSeat = seatList[i]:FindFirstChild("SeatWeld") + while nextSeat do nextSeat:Remove() nextSeat = seatList[i]:FindFirstChild("SeatWeld") end + end + else + -- put a weld called "SeatWeld" in every seat + -- this tricks it into thinking there's already someone sitting there, and it won't make you sit XD + for i = 1, #seatList do + local fakeWeld = Instance.new("Weld") + fakeWeld.Name = "SeatWeld" + fakeWeld.Parent = seatList[i] + end + end +end + +local function autoAlignToFace(parts) + local aatf = parts:FindFirstChild("AutoAlignToFace") + if aatf then return aatf.Value else return false end +end + +local function getClosestAlignedWorldDirection(aVector3InWorld) + local xDir = Vector3.new(1,0,0) + local yDir = Vector3.new(0,1,0) + local zDir = Vector3.new(0,0,1) + local xDot = aVector3InWorld.x * xDir.x + aVector3InWorld.y * xDir.y + aVector3InWorld.z * xDir.z + local yDot = aVector3InWorld.x * yDir.x + aVector3InWorld.y * yDir.y + aVector3InWorld.z * yDir.z + local zDot = aVector3InWorld.x * zDir.x + aVector3InWorld.y * zDir.y + aVector3InWorld.z * zDir.z + + if math.abs(xDot) > math.abs(yDot) and math.abs(xDot) > math.abs(zDot) then + if xDot > 0 then + return 0 + else + return 3 + end + elseif math.abs(yDot) > math.abs(xDot) and math.abs(yDot) > math.abs(zDot) then + if yDot > 0 then + return 1 + else + return 4 + end + else + if zDot > 0 then + return 2 + else + return 5 + end + end +end + +local function positionPartsAtCFrame3(aCFrame, currentParts) + local insertCFrame = nil + if not currentParts then return currentParts end + if currentParts and (currentParts:IsA("Model") or currentParts:IsA("Tool")) then + insertCFrame = currentParts:GetModelCFrame() + currentParts:TranslateBy(aCFrame.p - insertCFrame.p) + else + currentParts.CFrame = aCFrame + end + return currentParts +end + +local function calcRayHitTime(rayStart, raySlope, intersectionPlane) + if math.abs(raySlope) < .01 then return 0 end -- 0 slope --> we just say intersection time is 0, and sidestep this dimension + return (intersectionPlane - rayStart) / raySlope +end + +local function modelTargetSurface(partOrModel, rayStart, rayEnd) + if not partOrModel then + return 0 + end + + local modelCFrame = nil + local modelSize = nil + if partOrModel:IsA("Model") then + modelCFrame = partOrModel:GetModelCFrame() + modelSize = partOrModel:GetModelSize() + else + modelCFrame = partOrModel.CFrame + modelSize = partOrModel.Size + end + + local mouseRayStart = modelCFrame:pointToObjectSpace(rayStart) + local mouseRayEnd = modelCFrame:pointToObjectSpace(rayEnd) + local mouseSlope = mouseRayEnd - mouseRayStart + + local xPositive = 1 + local yPositive = 1 + local zPositive = 1 + if mouseSlope.X > 0 then xPositive = -1 end + if mouseSlope.Y > 0 then yPositive = -1 end + if mouseSlope.Z > 0 then zPositive = -1 end + + -- find which surface the transformed mouse ray hits (using modelSize): + local xHitTime = calcRayHitTime(mouseRayStart.X, mouseSlope.X, modelSize.X/2 * xPositive) + local yHitTime = calcRayHitTime(mouseRayStart.Y, mouseSlope.Y, modelSize.Y/2 * yPositive) + local zHitTime = calcRayHitTime(mouseRayStart.Z, mouseSlope.Z, modelSize.Z/2 * zPositive) + + local hitFace = 0 + + --if xHitTime >= 0 and yHitTime >= 0 and zHitTime >= 0 then + if xHitTime > yHitTime then + if xHitTime > zHitTime then + -- xFace is hit + hitFace = 1*xPositive + else + -- zFace is hit + hitFace = 3*zPositive + end + else + if yHitTime > zHitTime then + -- yFace is hit + hitFace = 2*yPositive + else + -- zFace is hit + hitFace = 3*zPositive + end + end + + return hitFace +end + +local function getBoundingBox2(partOrModel) + + -- for models, the bounding box is defined as the minimum and maximum individual part bounding boxes + -- relative to the first part's coordinate frame. + local minVec = Vector3.new(math.huge, math.huge, math.huge) + local maxVec = Vector3.new(-math.huge, -math.huge, -math.huge) + + if partOrModel:IsA("Terrain") then + minVec = Vector3.new(-2, -2, -2) + maxVec = Vector3.new(2, 2, 2) + elseif partOrModel:IsA("BasePart") then + minVec = -0.5 * partOrModel.Size + maxVec = -minVec + else + maxVec = partOrModel:GetModelSize()*0.5 + minVec = -maxVec + end + + -- Adjust bounding box to reflect what the model or part author wants in terms of justification + local justifyValue = partOrModel:FindFirstChild("Justification") + if justifyValue ~= nil then + -- find the multiple of 4 that contains the model + justify = justifyValue.Value + two = Vector3.new(2, 2, 2) + actualBox = maxVec - minVec - Vector3.new(0.01, 0.01, 0.01) + containingGridBox = Vector3.new(4 * math.ceil(actualBox.x/4), 4 * math.ceil(actualBox.y/4), 4 * math.ceil(actualBox.z/4)) + adjustment = containingGridBox - actualBox + minVec = minVec - 0.5 * adjustment * justify + maxVec = maxVec + 0.5 * adjustment * (two - justify) + end + + return minVec, maxVec +end + +local function getBoundingBoxInWorldCoordinates(partOrModel) + local minVec = Vector3.new(math.huge, math.huge, math.huge) + local maxVec = Vector3.new(-math.huge, -math.huge, -math.huge) + + if partOrModel:IsA("BasePart") and not partOrModel:IsA("Terrain") then + vec1 = partOrModel.CFrame:pointToWorldSpace(-0.5 * partOrModel.Size) + vec2 = partOrModel.CFrame:pointToWorldSpace(0.5 * partOrModel.Size) + minVec = Vector3.new(math.min(vec1.X, vec2.X), math.min(vec1.Y, vec2.Y), math.min(vec1.Z, vec2.Z)) + maxVec = Vector3.new(math.max(vec1.X, vec2.X), math.max(vec1.Y, vec2.Y), math.max(vec1.Z, vec2.Z)) + elseif partOrModel:IsA("Terrain") then + -- we shouldn't have to deal with this case + --minVec = Vector3.new(-2, -2, -2) + --maxVec = Vector3.new(2, 2, 2) + else + vec1 = partOrModel:GetModelCFrame():pointToWorldSpace(-0.5 * partOrModel:GetModelSize()) + vec2 = partOrModel:GetModelCFrame():pointToWorldSpace(0.5 * partOrModel:GetModelSize()) + minVec = Vector3.new(math.min(vec1.X, vec2.X), math.min(vec1.Y, vec2.Y), math.min(vec1.Z, vec2.Z)) + maxVec = Vector3.new(math.max(vec1.X, vec2.X), math.max(vec1.Y, vec2.Y), math.max(vec1.Z, vec2.Z)) + end + + return minVec, maxVec +end + +local function getTargetPartBoundingBox(targetPart) + if targetPart.Parent:FindFirstChild("RobloxModel") ~= nil then + return getBoundingBox2(targetPart.Parent) + else + return getBoundingBox2(targetPart) + end +end + +local function getMouseTargetCFrame(targetPart) + if targetPart.Parent:FindFirstChild("RobloxModel") ~= nil then + if targetPart.Parent:IsA("Tool") then return targetPart.Parent.Handle.CFrame + else return targetPart.Parent:GetModelCFrame() end + else + return targetPart.CFrame + end +end + +local function isBlocker(part) -- returns whether or not we want to cancel the stamp because we're blocked by this part + if not part then return false end + if not part.Parent then return false end + if part:FindFirstChild("Humanoid") then return false end + if part:FindFirstChild("RobloxStamper") or part:FindFirstChild("RobloxModel") then return true end + if part:IsA("Part") and not part.CanCollide then return false end + if part == game:GetService("Lighting") then return false end + return isBlocker(part.Parent) +end + +-- helper function to determine if a character can be pushed upwards by a certain amount +-- character is 5 studs tall, we'll check a 1.5 x 1.5 x 4.5 box around char, with center .5 studs below torsocenter +local function spaceAboveCharacter(charTorso, newTorsoY, stampData) + local partsAboveChar = game:GetService("Workspace"):FindPartsInRegion3( + Region3.new(Vector3.new(charTorso.Position.X, newTorsoY, charTorso.Position.Z) - Vector3.new(.75, 2.75, .75), + Vector3.new(charTorso.Position.X, newTorsoY, charTorso.Position.Z) + Vector3.new(.75, 1.75, .75)), + charTorso.Parent, + 100) + + for j = 1, #partsAboveChar do + if partsAboveChar[j].CanCollide and not partsAboveChar[j]:IsDescendantOf(stampData.CurrentParts) then return false end + end + + if clusterPartsInRegion(Vector3.new(charTorso.Position.X, newTorsoY, charTorso.Position.Z) - Vector3.new(.75, 2.75, .75), + Vector3.new(charTorso.Position.X, newTorsoY, charTorso.Position.Z) + Vector3.new(.75, 1.75, .75)) then + return false + end + + return true +end + + +local function findConfigAtMouseTarget(Mouse, stampData) + -- *Critical Assumption* : + -- This function assumes the target CF axes are orthogonal with the target bounding box faces + -- And, it assumes the insert CF axes are orthongonal with the insert bounding box faces + -- Therefore, insertion will not work with angled faces on wedges or other "non-block" parts, nor + -- will it work for parts in a model that are not orthogonally aligned with the model's CF. + + if not Mouse then return nil end -- This can happen sometimes, return if so + if not stampData then error("findConfigAtMouseTarget: stampData is nil") return nil end + if not stampData["CurrentParts"] then return nil end + + local grid = 4.0 + local admissibleConfig = false + local targetConfig = CFrame.new(0,0,0) + + local minBB, maxBB = getBoundingBox2(stampData.CurrentParts) + local diagBB = maxBB - minBB + + local insertCFrame + if stampData.CurrentParts:IsA("Model") or stampData.CurrentParts:IsA("Tool") then + insertCFrame = stampData.CurrentParts:GetModelCFrame() + else + insertCFrame = stampData.CurrentParts.CFrame + end + + if Mouse then + if stampData.CurrentParts:IsA("Tool") then + Mouse.TargetFilter = stampData.CurrentParts.Handle + else + Mouse.TargetFilter = stampData.CurrentParts + end + end + + local hitPlane = false + local targetPart = nil + local success = pcall(function() targetPart = Mouse.Target end) + + if not success then-- or targetPart == nil then + return admissibleConfig, targetConfig + end + + local mouseHitInWorld = Vector3.new(0, 0, 0) + if Mouse then + mouseHitInWorld = Vector3.new(Mouse.Hit.x, Mouse.Hit.y, Mouse.Hit.z) + end + + local cellPos = nil + + -- Nothing was hit, so check for the default plane. + if nil == targetPart then + cellPos = GetTerrainForMouse(Mouse) + if nil == cellPos then + hitPlane = false + return admissibleConfig, targetConfig + else + targetPart = game:GetService("Workspace").Terrain + hitPlane = true + -- Take into account error that will occur. + cellPos = Vector3.new(cellPos.X - 1, cellPos.Y, cellPos.Z) + mouseHitInWorld = game:GetService("Workspace").Terrain:CellCenterToWorld(cellPos.x, cellPos.y, cellPos.z) + end + end + + -- test mouse hit location + local minBBTarget, maxBBTarget = getTargetPartBoundingBox(targetPart) + local diagBBTarget = maxBBTarget - minBBTarget + local targetCFrame = getMouseTargetCFrame(targetPart) + + if targetPart:IsA("Terrain") then + if not cluster then cluster = game:GetService("Workspace"):FindFirstChild("Terrain") end + local cellID = cluster:WorldToCellPreferSolid(mouseHitInWorld) + if hitPlane then + cellID = cellPos + end + + targetCFrame = CFrame.new(game:GetService("Workspace").Terrain:CellCenterToWorld(cellID.x, cellID.y, cellID.z)) + end + + local mouseHitInTarget = targetCFrame:pointToObjectSpace(mouseHitInWorld) + local targetVectorInWorld = Vector3.new(0,0,0) + if Mouse then + -- DON'T WANT THIS IN TERMS OF THE MODEL CFRAME! (.TargetSurface is in terms of the part CFrame, so this would break, right? [HotThoth]) + -- (ideally, we would want to make the Mouse.TargetSurface a model-targetsurface instead, but for testing will be using the converse) + --targetVectorInWorld = targetCFrame:vectorToWorldSpace(Vector3.FromNormalId(Mouse.TargetSurface)) + targetVectorInWorld = targetPart.CFrame:vectorToWorldSpace(Vector3.FromNormalId(Mouse.TargetSurface)) -- better, but model cframe would be best + --[[if targetPart.Parent:IsA("Model") then + local hitFace = modelTargetSurface(targetPart.Parent, Mouse.Hit.p, game.Workspace.CurrentCamera.CoordinateFrame.p) -- best, if you get it right + local WORLD_AXES = {Vector3.new(1, 0, 0), Vector3.new(0, 1, 0), Vector3.new(0, 0, 1)} + if hitFace > 0 then + targetVectorInWorld = targetCFrame:vectorToWorldSpace(WORLD_AXES[hitFace]) + elseif hitFace < 0 then + targetVectorInWorld = targetCFrame:vectorToWorldSpace(-WORLD_AXES[-hitFace]) + end + end]] + end + + local targetRefPointInTarget + local clampToSurface + + if getClosestAlignedWorldDirection(targetVectorInWorld) == 0 then + targetRefPointInTarget = targetCFrame:vectorToObjectSpace(Vector3.new(1, -1, 1)) + insertRefPointInInsert = insertCFrame:vectorToObjectSpace(Vector3.new(-1, -1, 1)) + clampToSurface = Vector3.new(0,1,1) + elseif getClosestAlignedWorldDirection(targetVectorInWorld) == 3 then + targetRefPointInTarget = targetCFrame:vectorToObjectSpace(Vector3.new(-1, -1, -1)) + insertRefPointInInsert = insertCFrame:vectorToObjectSpace(Vector3.new(1, -1, -1)) + clampToSurface = Vector3.new(0,1,1) + elseif getClosestAlignedWorldDirection(targetVectorInWorld) == 1 then + targetRefPointInTarget = targetCFrame:vectorToObjectSpace(Vector3.new(-1, 1, 1)) + insertRefPointInInsert = insertCFrame:vectorToObjectSpace(Vector3.new(-1, -1, 1)) + clampToSurface = Vector3.new(1,0,1) + elseif getClosestAlignedWorldDirection(targetVectorInWorld) == 4 then + targetRefPointInTarget = targetCFrame:vectorToObjectSpace(Vector3.new(-1, -1, 1)) + insertRefPointInInsert = insertCFrame:vectorToObjectSpace(Vector3.new(-1, 1, 1)) + clampToSurface = Vector3.new(1,0,1) + elseif getClosestAlignedWorldDirection(targetVectorInWorld) == 2 then + targetRefPointInTarget = targetCFrame:vectorToObjectSpace(Vector3.new(-1, -1, 1)) + insertRefPointInInsert = insertCFrame:vectorToObjectSpace(Vector3.new(-1, -1, -1)) + clampToSurface = Vector3.new(1,1,0) + else + targetRefPointInTarget = targetCFrame:vectorToObjectSpace(Vector3.new(1, -1, -1)) + insertRefPointInInsert = insertCFrame:vectorToObjectSpace(Vector3.new(1, -1, 1)) + clampToSurface = Vector3.new(1,1,0) + end + + targetRefPointInTarget = targetRefPointInTarget * (0.5 * diagBBTarget) + 0.5 * (maxBBTarget + minBBTarget) + insertRefPointInInsert = insertRefPointInInsert * (0.5 * diagBB) + 0.5 * (maxBB + minBB) + + -- To Do: For cases that are not aligned to the world grid, account for the minimal rotation + -- needed to bring the Insert part(s) into alignment with the Target Part + -- Apply the rotation here + + local delta = mouseHitInTarget - targetRefPointInTarget + local deltaClamped = Vector3.new(grid * math.modf(delta.x/grid), grid * math.modf(delta.y/grid), grid * math.modf(delta.z/grid)) + deltaClamped = deltaClamped * clampToSurface + local targetTouchInTarget = deltaClamped + targetRefPointInTarget + + local TargetTouchRelToWorld = targetCFrame:pointToWorldSpace(targetTouchInTarget) + local InsertTouchInWorld = insertCFrame:vectorToWorldSpace(insertRefPointInInsert) + local posInsertOriginInWorld = TargetTouchRelToWorld - InsertTouchInWorld + + local x, y, z, R00, R01, R02, R10, R11, R12, R20, R21, R22 = insertCFrame:components() + targetConfig = CFrame.new(posInsertOriginInWorld.x, posInsertOriginInWorld.y, posInsertOriginInWorld.z, R00, R01, R02, R10, R11, R12, R20, R21, R22) + admissibleConfig = true + + return admissibleConfig, targetConfig, getClosestAlignedWorldDirection(targetVectorInWorld) +end + +local function truncateToCircleEighth(bigValue, littleValue) + local big = math.abs(bigValue) + local little = math.abs(littleValue) + local hypotenuse = math.sqrt(big*big + little*little) + local frac = little / hypotenuse + + local bigSign = 1 + local littleSign = 1 + if bigValue < 0 then bigSign = -1 end + if littleValue < 0 then littleSign = -1 end + + if frac > .382683432 then + -- between 22.5 and 45 degrees, so truncate to 45-degree tilt + return .707106781 * hypotenuse * bigSign, .707106781 * hypotenuse * littleSign + else + -- between 0 and 22.5 degrees, so truncate to 0-degree tilt + return hypotenuse * bigSign, 0 + end +end + + +local function saveTheWelds(object, manualWeldTable, manualWeldParentTable) + if object:IsA("ManualWeld") or object:IsA("Rotate") then + table.insert(manualWeldTable, object) + table.insert(manualWeldParentTable, object.Parent) + else + local children = object:GetChildren() + for i = 1, #children do + saveTheWelds(children[i], manualWeldTable, manualWeldParentTable) + end + end +end + +local function restoreTheWelds(manualWeldTable, manualWeldParentTable) + for i = 1, #manualWeldTable do + manualWeldTable[i].Parent = manualWeldParentTable[i] + end +end + +t.CanEditRegion = function(partOrModel, EditRegion) -- todo: use model and stamper metadata + if not EditRegion then return true, false end + + local minBB, maxBB = getBoundingBoxInWorldCoordinates(partOrModel) + + if minBB.X < EditRegion.CFrame.p.X - EditRegion.Size.X/2 or + minBB.Y < EditRegion.CFrame.p.Y - EditRegion.Size.Y/2 or + minBB.Z < EditRegion.CFrame.p.Z - EditRegion.Size.Z/2 then + return false, false + end + + if maxBB.X > EditRegion.CFrame.p.X + EditRegion.Size.X/2 or + maxBB.Y > EditRegion.CFrame.p.Y + EditRegion.Size.Y/2 or + maxBB.Z > EditRegion.CFrame.p.Z + EditRegion.Size.Z/2 then + return false, false + end + + return true, false +end + +t.GetStampModel = function(assetId, terrainShape, useAssetVersionId) + if assetId == 0 then + return nil, "No Asset" + end + if assetId < 0 then + return nil, "Negative Asset" + end + + local function UnlockInstances(object) + if object:IsA("BasePart") then + object.Locked = false + end + for index,child in pairs(object:GetChildren()) do + UnlockInstances(child) + end + end + + local function getClosestColorToTerrainMaterial(terrainValue) + if terrainValue == 1 then + return BrickColor.new("Bright green") + elseif terrainValue == 2 then + return BrickColor.new("Bright yellow") + elseif terrainValue == 3 then + return BrickColor.new("Bright red") + elseif terrainValue == 4 then + return BrickColor.new("Sand red") + elseif terrainValue == 5 then + return BrickColor.new("Black") + elseif terrainValue == 6 then + return BrickColor.new("Dark stone grey") + elseif terrainValue == 7 then + return BrickColor.new("Sand blue") + elseif terrainValue == 8 then + return BrickColor.new("Deep orange") + elseif terrainValue == 9 then + return BrickColor.new("Dark orange") + elseif terrainValue == 10 then + return BrickColor.new("Reddish brown") + elseif terrainValue == 11 then + return BrickColor.new("Light orange") + elseif terrainValue == 12 then + return BrickColor.new("Light stone grey") + elseif terrainValue == 13 then + return BrickColor.new("Sand green") + elseif terrainValue == 14 then + return BrickColor.new("Medium stone grey") + elseif terrainValue == 15 then + return BrickColor.new("Really red") + elseif terrainValue == 16 then + return BrickColor.new("Really blue") + elseif terrainValue == 17 then + return BrickColor.new("Bright blue") + else + return BrickColor.new("Bright green") + end + end + + local function setupFakeTerrainPart(cellMat, cellType, cellOrient) + local newTerrainPiece = nil + if (cellType == 1 or cellType == 4) then newTerrainPiece = Instance.new("WedgePart") + elseif (cellType == 2) then newTerrainPiece = Instance.new("CornerWedgePart") + else newTerrainPiece = Instance.new("Part") end + newTerrainPiece.Name = "MegaClusterCube" + newTerrainPiece.Size = Vector3.new(4, 4, 4) + newTerrainPiece.BottomSurface = "Smooth" + newTerrainPiece.TopSurface = "Smooth" + + -- can add decals or textures here if feeling particularly adventurous... for now, can make a table of look-up colors + newTerrainPiece.BrickColor = getClosestColorToTerrainMaterial(cellMat) + + local sideways = 0 + local flipped = math.pi + if cellType == 4 then sideways = -math.pi/2 end + if cellType == 2 or cellType == 3 then flipped = 0 end + newTerrainPiece.CFrame = CFrame.Angles(0, math.pi/2*cellOrient + flipped, sideways) + + if cellType == 3 then + local inverseCornerWedgeMesh = Instance.new("SpecialMesh") + inverseCornerWedgeMesh.MeshType = "FileMesh" + inverseCornerWedgeMesh.MeshId = "http://www.roblox.com/asset/?id=66832495" + inverseCornerWedgeMesh.Scale = Vector3.new(2, 2, 2) + inverseCornerWedgeMesh.Parent = newTerrainPiece + end + + local materialTag = Instance.new("Vector3Value") + materialTag.Value = Vector3.new(cellMat, cellType, cellOrient) + materialTag.Name = "ClusterMaterial" + materialTag.Parent = newTerrainPiece + + return newTerrainPiece + end + + -- This call will cause a "wait" until the data comes back + -- below we wait a max of 8 seconds before deciding to bail out on loading + local root + local loader + loading = true + if useAssetVersionId then + loader = coroutine.create(function() + root = game:GetService("InsertService"):LoadAssetVersion(assetId) + loading = false + end) + coroutine.resume(loader) + else + loader = coroutine.create(function() + root = game:GetService("InsertService"):LoadAsset(assetId) + loading = false + end) + coroutine.resume(loader) + end + + local lastGameTime = 0 + local totalTime = 0 + local maxWait = 8 + while loading and totalTime < maxWait do + lastGameTime = tick() + wait(1) + totalTime = totalTime + tick() - lastGameTime + end + loading = false + + if totalTime >= maxWait then + return nil, "Load Time Fail" + end + + + if root == nil then + return nil, "Load Asset Fail" + end + + if not root:IsA("Model") then + return nil, "Load Type Fail" + end + + local instances = root:GetChildren() + if #instances == 0 then + return nil, "Empty Model Fail" + end + + --Unlock all parts that are inserted, to make sure they are editable + UnlockInstances(root) + + --Continue the insert process + root = root:GetChildren()[1] + + --Examine the contents and decide what it looks like + for pos, instance in pairs(instances) do + if instance:IsA("Team") then + instance.Parent = game:GetService("Teams") + elseif instance:IsA("Sky") then + local lightingService = game:GetService("Lighting") + for index,child in pairs(lightingService:GetChildren()) do + if child:IsA("Sky") then + child:Remove(); + end + end + instance.Parent = lightingService + return + end + end + + -- ...and tag all inserted models for subsequent origin identification + -- if no RobloxModel tag already exists, then add it. + if root:FindFirstChild("RobloxModel") == nil then + local stringTag = Instance.new("BoolValue", root) + stringTag.Name = "RobloxModel" + + if root:FindFirstChild("RobloxStamper") == nil then + local stringTag2 = Instance.new("BoolValue", root) + stringTag2.Name = "RobloxStamper" + end + end + + if terrainShape then + if root.Name == "MegaClusterCube" then + if (terrainShape == 6) then -- insert an autowedging tag + local autowedgeTag = Instance.new("BoolValue") + autowedgeTag.Name = "AutoWedge" + autowedgeTag.Parent = root + else + local clusterTag = root:FindFirstChild("ClusterMaterial") + if clusterTag then + if clusterTag:IsA("Vector3Value") then + root = setupFakeTerrainPart(clusterTag.Value.X, terrainShape, clusterTag.Value.Z) + else + root = setupFakeTerrainPart(clusterTag.Value, terrainShape, 0) + end + else + root = setupFakeTerrainPart(1, terrainShape, 0) + end + end + end + end + + return root +end + + + +t.SetupStamperDragger = function(modelToStamp, Mouse, StampInModel, AllowedStampRegion, StampFailedFunc) + if not modelToStamp then + error("SetupStamperDragger: modelToStamp (first arg) is nil! Should be a stamper model") + return nil + end + if not modelToStamp:IsA("Model") and not modelToStamp:IsA("BasePart") then + error("SetupStamperDragger: modelToStamp (first arg) is neither a Model or Part!") + return nil + end + if not Mouse then + error("SetupStamperDragger: Mouse (second arg) is nil! Should be a mouse object") + return nil + end + if not Mouse:IsA("Mouse") then + error("SetupStamperDragger: Mouse (second arg) is not of type Mouse!") + return nil + end + + local stampInModel = nil + local allowedStampRegion = nil + local stampFailedFunc = nil + if StampInModel then + if not StampInModel:IsA("Model") then + error("SetupStamperDragger: StampInModel (optional third arg) is not of type 'Model'") + return nil + end + if not AllowedStampRegion then + error("SetupStamperDragger: AllowedStampRegion (optional fourth arg) is nil when StampInModel (optional third arg) is defined") + return nil + end + stampFailedFunc = StampFailedFunc + stampInModel = StampInModel + allowedStampRegion = AllowedStampRegion + end + + -- Init all state variables + local gInitial90DegreeRotations = 0 + local stampData = nil + local mouseTarget = nil + + local errorBox = Instance.new("SelectionBox") + errorBox.Color = BrickColor.new("Bright red") + errorBox.Transparency = 0 + errorBox.Archivable = false + + -- for megacluster MEGA STAMPING + local adornPart = Instance.new("Part") + adornPart.Parent = nil + adornPart.Size = Vector3.new(4, 4, 4) + adornPart.CFrame = CFrame.new() + adornPart.Archivable = false + + local adorn = Instance.new("SelectionBox") + adorn.Color = BrickColor.new("Toothpaste") + adorn.Adornee = adornPart + adorn.Visible = true + adorn.Transparency = 0 + adorn.Name = "HighScalabilityStamperLine" + adorn.Archivable = false + + local HighScalabilityLine = {} + HighScalabilityLine.Start = nil + HighScalabilityLine.End = nil + HighScalabilityLine.Adorn = adorn + HighScalabilityLine.AdornPart = adornPart + HighScalabilityLine.InternalLine = nil + HighScalabilityLine.NewHint = true + + HighScalabilityLine.MorePoints = {nil, nil} + HighScalabilityLine.MoreLines = {nil, nil} + HighScalabilityLine.Dimensions = 1 + + local control = {} + local movingLock = false + local stampUpLock = false + local unstampableSurface = false + local mouseCons = {} + local keyCon = nil + + local stamped = Instance.new("BoolValue") + stamped.Archivable = false + stamped.Value = false + + local lastTarget = {} + lastTarget.TerrainOrientation = 0 + lastTarget.CFrame = 0 + + local cellInfo = {} + cellInfo.Material = 1 + cellInfo.clusterType = 0 + cellInfo.clusterOrientation = 0 + + local function isMegaClusterPart() + if not stampData then return false end + if not stampData.CurrentParts then return false end + + return ( stampData.CurrentParts:FindFirstChild("ClusterMaterial",true) or (stampData.CurrentParts.Name == "MegaClusterCube") ) + end + + local function DoHighScalabilityRegionSelect() + local megaCube = stampData.CurrentParts:FindFirstChild("MegaClusterCube") + if not megaCube then + if not stampData.CurrentParts.Name == "MegaClusterCube" then + return + else + megaCube = stampData.CurrentParts + end + end + + HighScalabilityLine.End = megaCube.CFrame.p + local line = nil + local line2 = Vector3.new(0, 0, 0) + local line3 = Vector3.new(0, 0, 0) + + if HighScalabilityLine.Dimensions == 1 then + -- extract the line from these positions and limit to a 2D plane made from 2 of the world axes + -- then use dominating axis to limit line to be at 45-degree intervals + -- will use this internal representation of the line for the actual stamping + line = (HighScalabilityLine.End - HighScalabilityLine.Start) + + if math.abs(line.X) < math.abs(line.Y) then + if math.abs(line.X) < math.abs(line.Z) then + -- limit to Y/Z plane, domination unknown + local newY, newZ + if (math.abs(line.Y) > math.abs(line.Z)) then + newY, newZ = truncateToCircleEighth(line.Y, line.Z) + else + newZ, newY = truncateToCircleEighth(line.Z, line.Y) + end + line = Vector3.new(0, newY, newZ) + else + -- limit to X/Y plane, with Y dominating + local newY, newX = truncateToCircleEighth(line.Y, line.X) + line = Vector3.new(newX, newY, 0) + end + else + if math.abs(line.Y) < math.abs(line.Z) then + -- limit to X/Z plane, domination unknown + local newX, newZ + if math.abs(line.X) > math.abs(line.Z) then + newX, newZ = truncateToCircleEighth(line.X, line.Z) + else + newZ, newX = truncateToCircleEighth(line.Z, line.X) + end + line = Vector3.new(newX, 0, newZ) + else + -- limit to X/Y plane, with X dominating + local newX, newY = truncateToCircleEighth(line.X, line.Y) + line = Vector3.new(newX, newY, 0) + end + end + HighScalabilityLine.InternalLine = line + + elseif HighScalabilityLine.Dimensions == 2 then + line = HighScalabilityLine.MoreLines[1] + line2 = HighScalabilityLine.End - HighScalabilityLine.MorePoints[1] + + -- take out any component of line2 along line1, so you get perpendicular to line1 component + line2 = line2 - line.unit*line.unit:Dot(line2) + + tempCFrame = CFrame.new(HighScalabilityLine.Start, HighScalabilityLine.Start + line) + + -- then zero out whichever is the smaller component + local yAxis = tempCFrame:vectorToWorldSpace(Vector3.new(0, 1, 0)) + local xAxis = tempCFrame:vectorToWorldSpace(Vector3.new(1, 0, 0)) + + local xComp = xAxis:Dot(line2) + local yComp = yAxis:Dot(line2) + + if math.abs(yComp) > math.abs(xComp) then + line2 = line2 - xAxis * xComp + else + line2 = line2 - yAxis * yComp + end + + HighScalabilityLine.InternalLine = line2 + + elseif HighScalabilityLine.Dimensions == 3 then + line = HighScalabilityLine.MoreLines[1] + line2 = HighScalabilityLine.MoreLines[2] + line3 = HighScalabilityLine.End - HighScalabilityLine.MorePoints[2] + + -- zero out all components of previous lines + line3 = line3 - line.unit * line.unit:Dot(line3) + line3 = line3 - line2.unit * line2.unit:Dot(line3) + + HighScalabilityLine.InternalLine = line3 + end + + -- resize the "line" graphic to be the correct size and orientation + tempCFrame = CFrame.new(HighScalabilityLine.Start, HighScalabilityLine.Start + line) + + if HighScalabilityLine.Dimensions == 1 then -- faster calculation for line + HighScalabilityLine.AdornPart.Size = Vector3.new(4, 4, line.magnitude + 4) + HighScalabilityLine.AdornPart.CFrame = tempCFrame + tempCFrame:vectorToWorldSpace(Vector3.new(2, 2, 2) - HighScalabilityLine.AdornPart.Size/2) + else + local boxSize = tempCFrame:vectorToObjectSpace(line + line2 + line3) + HighScalabilityLine.AdornPart.Size = Vector3.new(4, 4, 4) + Vector3.new(math.abs(boxSize.X), math.abs(boxSize.Y), math.abs(boxSize.Z)) + HighScalabilityLine.AdornPart.CFrame = tempCFrame + tempCFrame:vectorToWorldSpace(boxSize/2) + end + + -- make player able to see this ish + + local gui = nil + if game:GetService("Players")["LocalPlayer"] then + gui = game:GetService("Players").LocalPlayer:FindFirstChild("PlayerGui") + if gui and gui:IsA("PlayerGui") then + if HighScalabilityLine.Dimensions == 1 and line.magnitude > 3 then -- don't show if mouse hasn't moved enough + HighScalabilityLine.Adorn.Parent = gui + elseif HighScalabilityLine.Dimensions > 1 then + HighScalabilityLine.Adorn.Parent = gui + end + end + end + + if gui == nil then -- we are in studio + gui = game:GetService("CoreGui") + if HighScalabilityLine.Dimensions == 1 and line.magnitude > 3 then -- don't show if mouse hasn't moved enough + HighScalabilityLine.Adorn.Parent = gui + elseif HighScalabilityLine.Dimensions > 1 then + HighScalabilityLine.Adorn.Parent = gui + end + end + end + + + local function DoStamperMouseMove(Mouse) + if not Mouse then + error("Error: RbxStamper.DoStamperMouseMove: Mouse is nil") + return + end + if not Mouse:IsA("Mouse") then + error("Error: RbxStamper.DoStamperMouseMove: Mouse is of type", Mouse.className,"should be of type Mouse") + return + end + + -- There wasn't a target (no part or terrain), so check for plane intersection. + if not Mouse.Target then + local cellPos = GetTerrainForMouse(Mouse) + if nil == cellPos then + return + end + end + + if not stampData then + return + end + + -- don't move with dragger - will move in one step on mouse down + -- draw ghost at acceptable positions + configFound, targetCFrame, targetSurface = findConfigAtMouseTarget(Mouse, stampData) + if not configFound then + error("RbxStamper.DoStamperMouseMove No configFound, returning") + return + end + + local numRotations = 0 -- update this according to how many rotations you need to get it to target surface + if autoAlignToFace(stampData.CurrentParts) and targetSurface ~= 1 and targetSurface ~= 4 then -- pre-rotate the flag or portrait so it's aligned correctly + if targetSurface == 3 then numRotations = 0 - gInitial90DegreeRotations + autoAlignToFace(stampData.CurrentParts) + elseif targetSurface == 0 then numRotations = 2 - gInitial90DegreeRotations + autoAlignToFace(stampData.CurrentParts) + elseif targetSurface == 5 then numRotations = 3 - gInitial90DegreeRotations + autoAlignToFace(stampData.CurrentParts) + elseif targetSurface == 2 then numRotations = 1 - gInitial90DegreeRotations + autoAlignToFace(stampData.CurrentParts) + end + end + + local ry = math.pi/2 + gInitial90DegreeRotations = gInitial90DegreeRotations + numRotations + if stampData.CurrentParts:IsA("Model") or stampData.CurrentParts:IsA("Tool") then + --stampData.CurrentParts:Rotate(0, ry*numRotations, 0) + modelRotate(stampData.CurrentParts, ry*numRotations) + else + stampData.CurrentParts.CFrame = CFrame.fromEulerAnglesXYZ(0, ry*numRotations, 0) * stampData.CurrentParts.CFrame + end + + -- CODE TO CHECK FOR DRAGGING GHOST PART INTO A COLLIDING STATE + local minBB, maxBB = getBoundingBoxInWorldCoordinates(stampData.CurrentParts) + + -- need to offset by distance to be dragged + local currModelCFrame = nil + if stampData.CurrentParts:IsA("Model") then + currModelCFrame = stampData.CurrentParts:GetModelCFrame() + else + currModelCFrame = stampData.CurrentParts.CFrame + end + + minBB = minBB + targetCFrame.p - currModelCFrame.p + maxBB = maxBB + targetCFrame.p - currModelCFrame.p + + -- don't drag into terrain + if clusterPartsInRegion(minBB + insertBoundingBoxOverlapVector, maxBB - insertBoundingBoxOverlapVector) then + if lastTarget.CFrame then + if (stampData.CurrentParts:FindFirstChild("ClusterMaterial", true)) then + local theClusterMaterial = stampData.CurrentParts:FindFirstChild("ClusterMaterial", true) + if theClusterMaterial:IsA("Vector3Value") then + local stampClusterMaterial = stampData.CurrentParts:FindFirstChild("ClusterMaterial", true) + if stampClusterMaterial then + stampClusterMaterial = clusterMat + end + end + end + end + return + end + + -- if we are stamping a terrain part, make sure it goes on the grid! Otherwise preview block could be placed off grid, but stamped on grid + if isMegaClusterPart() then + local cellToStamp = game:GetService("Workspace").Terrain:WorldToCell(targetCFrame.p) + local newCFramePosition = game:GetService("Workspace").Terrain:CellCenterToWorld(cellToStamp.X, cellToStamp.Y, cellToStamp.Z) + local x, y, z, R00, R01, R02, R10, R11, R12, R20, R21, R22 = targetCFrame:components() + targetCFrame = CFrame.new(newCFramePosition.X,newCFramePosition.Y,newCFramePosition.Z,R00, R01, R02, R10, R11, R12, R20, R21, R22) + end + + positionPartsAtCFrame3(targetCFrame, stampData.CurrentParts) + lastTarget.CFrame = targetCFrame -- successful positioning, so update 'dat cframe + if stampData.CurrentParts:FindFirstChild("ClusterMaterial", true) then + local clusterMat = stampData.CurrentParts:FindFirstChild("ClusterMaterial", true) + if clusterMat:IsA("Vector3Value") then + lastTarget.TerrainOrientation = clusterMat.Value.Z + end + end + + + -- auto break joints code + if Mouse and Mouse.Target and Mouse.Target.Parent then + local modelInfo = Mouse.Target:FindFirstChild("RobloxModel") + if not modelInfo then modelInfo = Mouse.Target.Parent:FindFirstChild("RobloxModel") end + + local myModelInfo = stampData.CurrentParts:FindFirstChild("UnstampableFaces") + + --if (modelInfo and modelInfo.Parent:FindFirstChild("UnstampableFaces")) or (modelInfo and myModelInfo) then -- need better targetSurface calcs + if (true) then + local breakingFaces = "" + local myBreakingFaces = "" + if modelInfo and modelInfo.Parent:FindFirstChild("UnstampableFaces") then breakingFaces = modelInfo.Parent.UnstampableFaces.Value end + if myModelInfo then myBreakingFaces = myModelInfo.Value end + local hitFace = 0 + + if modelInfo then hitFace = modelTargetSurface(modelInfo.Parent, game:GetService("Workspace").CurrentCamera.CoordinateFrame.p, Mouse.Hit.p) end + + -- are we stamping TO an unstampable surface? + for bf in string.gmatch(breakingFaces, "[^,]+") do + if hitFace == tonumber(bf) then + -- return before we hit the JointsService code below! + unstampableSurface = true + game.JointsService:ClearJoinAfterMoveJoints() -- clear the JointsService cache + return + end + end + + -- now we have to cast the ray back in the other direction to find the surface we're stamping FROM + hitFace = modelTargetSurface(stampData.CurrentParts, Mouse.Hit.p, game:GetService("Workspace").CurrentCamera.CoordinateFrame.p) + + -- are we stamping WITH an unstampable surface? + for bf in string.gmatch(myBreakingFaces, "[^,]+") do + if hitFace == tonumber(bf) then + unstampableSurface = true + game.JointsService:ClearJoinAfterMoveJoints() -- clear the JointsService cache + return + end + end + + -- just need to match breakingFace against targetSurface using rotation supplied by modelCFrame + -- targetSurface: 1 is top, 4 is bottom, + end + end + + -- to show joints during the mouse move + unstampableSurface = false + game.JointsService:SetJoinAfterMoveInstance(stampData.CurrentParts) + + -- most common mouse inactive error occurs here, so check mouse active one more time in a pcall + if not pcall(function() + if Mouse and Mouse.Target and Mouse.Target.Parent:FindFirstChild("RobloxModel") == nil then + return + else + return + end + end) + then + error("Error: RbxStamper.DoStamperMouseMove Mouse is nil on second check") + game.JointsService:ClearJoinAfterMoveJoints() + Mouse = nil + return + end + + if Mouse and Mouse.Target and Mouse.Target.Parent:FindFirstChild("RobloxModel") == nil then + game.JointsService:SetJoinAfterMoveTarget(Mouse.Target) + else + game.JointsService:SetJoinAfterMoveTarget(nil) + end + game.JointsService:ShowPermissibleJoints() + + -- here we allow for a line of high-scalability parts + if isMegaClusterPart() and HighScalabilityLine and HighScalabilityLine.Start then + DoHighScalabilityRegionSelect() + end + end + + local function setupKeyListener(key, Mouse) + if control and control["Paused"] then return end -- don't do this if we have no stamp + + key = string.lower(key) + if key == 'r' and not autoAlignToFace(stampData.CurrentParts) then -- rotate the model + gInitial90DegreeRotations = gInitial90DegreeRotations + 1 + + -- Update orientation value if this is a fake terrain part + local clusterValues = stampData.CurrentParts:FindFirstChild("ClusterMaterial", true) + if clusterValues and clusterValues:IsA("Vector3Value") then + clusterValues.Value = Vector3.new(clusterValues.Value.X, clusterValues.Value.Y, (clusterValues.Value.Z + 1) % 4) + end + + -- Rotate the parts or all the parts in the model + local ry = math.pi/2 + if stampData.CurrentParts:IsA("Model") or stampData.CurrentParts:IsA("Tool") then + --stampData.CurrentParts:Rotate(0, ry, 0) + modelRotate(stampData.CurrentParts, ry) + else + stampData.CurrentParts.CFrame = CFrame.fromEulerAnglesXYZ(0, ry, 0) * stampData.CurrentParts.CFrame + end + + -- After rotating, update the position + configFound, targetCFrame = findConfigAtMouseTarget(Mouse, stampData) + if configFound then + positionPartsAtCFrame3(targetCFrame, stampData.CurrentParts) + + -- update everything else in MouseMove + DoStamperMouseMove(Mouse) + end + elseif key == 'c' then -- try to expand our high scalability dragger dimension + if HighScalabilityLine.InternalLine and HighScalabilityLine.InternalLine.magnitude > 0 and HighScalabilityLine.Dimensions < 3 then + HighScalabilityLine.MorePoints[HighScalabilityLine.Dimensions] = HighScalabilityLine.End + HighScalabilityLine.MoreLines[HighScalabilityLine.Dimensions] = HighScalabilityLine.InternalLine + HighScalabilityLine.Dimensions = HighScalabilityLine.Dimensions + 1 + HighScalabilityLine.NewHint = true + end + end + end + + keyCon = Mouse.KeyDown:connect(function(key) -- init key connection (keeping code close to func) + setupKeyListener(key, Mouse) + end) + + local function resetHighScalabilityLine() + if HighScalabilityLine then + HighScalabilityLine.Start = nil + HighScalabilityLine.End = nil + HighScalabilityLine.InternalLine = nil + HighScalabilityLine.NewHint = true + end + end + + local function flashRedBox() + local gui = game:GetService("CoreGui") + if game:GetService("Players") then + if game:GetService("Players")["LocalPlayer"] then + if game:GetService("Players").LocalPlayer:FindFirstChild("PlayerGui") then + gui = game:GetService("Players").LocalPlayer.PlayerGui + end + end + end + if not stampData["ErrorBox"] then return end + + stampData.ErrorBox.Parent = gui + if stampData.CurrentParts:IsA("Tool") then + stampData.ErrorBox.Adornee = stampData.CurrentParts.Handle + else + stampData.ErrorBox.Adornee = stampData.CurrentParts + end + + delay(0,function() + for i = 1, 3 do + if stampData["ErrorBox"] then stampData.ErrorBox.Visible = true end + wait(0.13) + if stampData["ErrorBox"] then stampData.ErrorBox.Visible = false end + wait(0.13) + end + if stampData["ErrorBox"] then + stampData.ErrorBox.Adornee = nil + stampData.ErrorBox.Parent = Tool + end + end) + end + + local function DoStamperMouseDown(Mouse) + if not Mouse then + error("Error: RbxStamper.DoStamperMouseDown: Mouse is nil") + return + end + if not Mouse:IsA("Mouse") then + error("Error: RbxStamper.DoStamperMouseDown: Mouse is of type", Mouse.className,"should be of type Mouse") + return + end + if not stampData then + return + end + + if isMegaClusterPart() then + if Mouse and HighScalabilityLine then + local megaCube = stampData.CurrentParts:FindFirstChild("MegaClusterCube", true) + local terrain = game:GetService("Workspace").Terrain + if megaCube then + HighScalabilityLine.Dimensions = 1 + local tempCell = terrain:WorldToCell(megaCube.CFrame.p) + HighScalabilityLine.Start = terrain:CellCenterToWorld(tempCell.X, tempCell.Y, tempCell.Z) + return + else + HighScalabilityLine.Dimensions = 1 + local tempCell = terrain:WorldToCell(stampData.CurrentParts.CFrame.p) + HighScalabilityLine.Start = terrain:CellCenterToWorld(tempCell.X, tempCell.Y, tempCell.Z) + return + end + end + end + end + + local function loadSurfaceTypes(part, surfaces) + part.TopSurface = surfaces[1] + part.BottomSurface = surfaces[2] + part.LeftSurface = surfaces[3] + part.RightSurface = surfaces[4] + part.FrontSurface = surfaces[5] + part.BackSurface = surfaces[6] + end + + local function saveSurfaceTypes(part, myTable) + local tempTable = {} + tempTable[1] = part.TopSurface + tempTable[2] = part.BottomSurface + tempTable[3] = part.LeftSurface + tempTable[4] = part.RightSurface + tempTable[5] = part.FrontSurface + tempTable[6] = part.BackSurface + + myTable[part] = tempTable + end + + local function makeSurfaceUnjoinable(part, surface) + -- TODO: FILL OUT! + end + + local function prepareModel(model) + if not model then return nil end + + local gDesiredTrans = 0.7 + local gStaticTrans = 1 + + local clone = model:Clone() + local scripts = {} + local parts = {} + local decals = {} + + stampData = {} + stampData.DisabledScripts = {} + stampData.TransparencyTable = {} + stampData.MaterialTable = {} + stampData.CanCollideTable = {} + stampData.AnchoredTable = {} + stampData.ArchivableTable = {} + stampData.DecalTransparencyTable = {} + stampData.SurfaceTypeTable = {} + + collectParts(clone, parts, scripts, decals) + + if #parts <= 0 then return nil, "no parts found in modelToStamp" end + + for index,script in pairs(scripts) do + if not(script.Disabled) then + script.Disabled = true + stampData.DisabledScripts[#stampData.DisabledScripts + 1] = script + end + end + for index, part in pairs(parts) do + stampData.TransparencyTable[part] = part.Transparency + part.Transparency = gStaticTrans + (1 - gStaticTrans) * part.Transparency + stampData.MaterialTable[part] = part.Material + part.Material = Enum.Material.Plastic + stampData.CanCollideTable[part] = part.CanCollide + part.CanCollide = false + stampData.AnchoredTable[part] = part.Anchored + part.Anchored = true + stampData.ArchivableTable[part] = part.Archivable + part.Archivable = false + + saveSurfaceTypes(part, stampData.SurfaceTypeTable) + + local fadeInDelayTime = 0.5 + local transFadeInTime = 0.5 + delay(0,function() + wait(fadeInDelayTime) -- give it some time to be completely transparent + + local begTime = tick() + local currTime = begTime + while (currTime - begTime) < transFadeInTime and part and part:IsA("BasePart") and part.Transparency > gDesiredTrans do + local newTrans = 1 - (((currTime - begTime)/transFadeInTime) * (gStaticTrans - gDesiredTrans)) + if stampData["TransparencyTable"] and stampData.TransparencyTable[part] then + part.Transparency = newTrans + (1 - newTrans) * stampData.TransparencyTable[part] + end + wait(0.03) + currTime = tick() + end + if part and part:IsA("BasePart") then + if stampData["TransparencyTable"] and stampData.TransparencyTable[part] then + part.Transparency = gDesiredTrans + (1 - gDesiredTrans) * stampData.TransparencyTable[part] + end + end + end) + end + + for index, decal in pairs(decals) do + stampData.DecalTransparencyTable[decal] = decal.Transparency + decal.Transparency = gDesiredTrans + (1 - gDesiredTrans) * decal.Transparency + end + + -- disable all seats + setSeatEnabledStatus(clone, true) + setSeatEnabledStatus(clone, false) + + stampData.CurrentParts = clone + + -- if auto-alignable, we enforce a pre-rotation to the canonical "0-frame" + if autoAlignToFace(clone) then + stampData.CurrentParts:ResetOrientationToIdentity() + gInitial90DegreeRotations = 0 + else -- pre-rotate if necessary + local ry = gInitial90DegreeRotations * math.pi/2 + if stampData.CurrentParts:IsA("Model") or stampData.CurrentParts:IsA("Tool") then + --stampData.CurrentParts:Rotate(0, ry, 0) + modelRotate(stampData.CurrentParts, ry) + else + stampData.CurrentParts.CFrame = CFrame.fromEulerAnglesXYZ(0, ry, 0) * stampData.CurrentParts.CFrame + end + end + + -- since we're cloning the old model instead of the new one, we will need to update the orientation based on the original value AND how many more + -- rotations we expect since then [either that or we need to store the just-stamped clusterMaterial.Value.Z somewhere]. This should fix the terrain rotation + -- issue (fingers crossed) [HotThoth] + + local clusterMaterial = stampData.CurrentParts:FindFirstChild("ClusterMaterial", true) + if clusterMaterial and clusterMaterial:IsA("Vector3Value") then + clusterMaterial.Value = Vector3.new(clusterMaterial.Value.X, clusterMaterial.Value.Y, (clusterMaterial.Value.Z + gInitial90DegreeRotations) % 4) + end + + -- After rotating, update the position + local configFound, targetCFrame = findConfigAtMouseTarget(Mouse, stampData) + if configFound then + stampData.CurrentParts = positionPartsAtCFrame3(targetCFrame, stampData.CurrentParts) + end + + -- to show joints during the mouse move + game.JointsService:SetJoinAfterMoveInstance(stampData.CurrentParts) + + return clone, parts + end + + local function checkTerrainBlockCollisions(cellPos, checkHighScalabilityStamp) + local cellCenterToWorld = game:GetService("Workspace").Terrain.CellCenterToWorld + local cellCenter = cellCenterToWorld(game:GetService("Workspace").Terrain, cellPos.X, cellPos.Y, cellPos.Z) + local cellBlockingParts = game:GetService("Workspace"):FindPartsInRegion3(Region3.new(cellCenter - Vector3.new(2, 2, 2) + insertBoundingBoxOverlapVector, cellCenter + Vector3.new(2, 2, 2) - insertBoundingBoxOverlapVector), stampData.CurrentParts, 100) + + local skipThisCell = false + + for b = 1, #cellBlockingParts do + if isBlocker(cellBlockingParts[b]) then skipThisCell = true break end + end + + if not skipThisCell then + -- pop players up above any set cells + local alreadyPushedUp = {} + -- if no blocking model below, then see if stamping on top of a character + for b = 1, #cellBlockingParts do + if cellBlockingParts[b].Parent and + not alreadyPushedUp[cellBlockingParts[b].Parent] and + cellBlockingParts[b].Parent:FindFirstChild("Humanoid") and + cellBlockingParts[b].Parent:FindFirstChild("Humanoid"):IsA("Humanoid") then + ----------------------------------------------------------------------------------- + local blockingPersonTorso = cellBlockingParts[b].Parent:FindFirstChild("Torso") + alreadyPushedUp[cellBlockingParts[b].Parent] = true + + if blockingPersonTorso then + -- if so, let's push the person upwards so they pop on top of the stamped model/part (but only if there's space above them) + local newY = cellCenter.Y + 5 + if spaceAboveCharacter(blockingPersonTorso, newY, stampData) then + blockingPersonTorso.CFrame = blockingPersonTorso.CFrame + Vector3.new(0, newY - blockingPersonTorso.CFrame.p.Y, 0) + else + -- if no space, we just skip this one + skipThisCell = true + break + end + end + ----------------------------------------------------------------------------------- + end + end + end + + if not skipThisCell then -- if we STILL aren't skipping... then we're good to go! + local canSetCell = true + + if checkHighScalabilityStamp then -- check to see if cell is in region, if not we'll skip set + if allowedStampRegion then + local cellPos = cellCenterToWorld(game:GetService("Workspace").Terrain, cellPos.X, cellPos.Y, cellPos.Z) + if cellPos.X + 2 > allowedStampRegion.CFrame.p.X + allowedStampRegion.Size.X/2 then + canSetCell = false + elseif cellPos.X - 2 < allowedStampRegion.CFrame.p.X - allowedStampRegion.Size.X/2 then + canSetCell = false + elseif cellPos.Y + 2 > allowedStampRegion.CFrame.p.Y + allowedStampRegion.Size.Y/2 then + canSetCell = false + elseif cellPos.Y - 2 < allowedStampRegion.CFrame.p.Y - allowedStampRegion.Size.Y/2 then + canSetCell = false + elseif cellPos.Z + 2 > allowedStampRegion.CFrame.p.Z + allowedStampRegion.Size.Z/2 then + canSetCell = false + elseif cellPos.Z - 2 < allowedStampRegion.CFrame.p.Z - allowedStampRegion.Size.Z/2 then + canSetCell = false + end + end + end + + return canSetCell + end + return false + end + + + local function ResolveMegaClusterStamp(checkHighScalabilityStamp) + local cellSet = false + + local cluser = game:GetService("Workspace").Terrain + + local line = HighScalabilityLine.InternalLine + local cMax = game:GetService("Workspace").Terrain.MaxExtents.Max + local cMin = game:GetService("Workspace").Terrain.MaxExtents.Min + + local clusterMaterial = 1 -- default is grass + local clusterType = 0 -- default is brick + local clusterOrientation = 0 -- default is 0 rotation + + local autoWedgeClusterParts = false + if stampData.CurrentParts:FindFirstChild("AutoWedge") then autoWedgeClusterParts = true end + + if stampData.CurrentParts:FindFirstChild("ClusterMaterial", true) then + clusterMaterial = stampData.CurrentParts:FindFirstChild("ClusterMaterial", true) + if clusterMaterial:IsA("Vector3Value") then + clusterType = clusterMaterial.Value.Y + clusterOrientation = clusterMaterial.Value.Z + clusterMaterial = clusterMaterial.Value.X + elseif clusterMaterial:IsA("IntValue") then + clusterMaterial = clusterMaterial.Value + end + end + + if HighScalabilityLine.Adorn.Parent and HighScalabilityLine.Start and ((HighScalabilityLine.Dimensions > 1) or (line and line.magnitude > 0)) then + local startCell = game:GetService("Workspace").Terrain:WorldToCell(HighScalabilityLine.Start) + local xInc = {0,0,0} + local yInc = {0,0,0} + local zInc = {0,0,0} + + local cluster = game:GetService("Workspace").Terrain + + local incrementVect = {nil, nil, nil} + local stepVect = {Vector3.new(0, 0, 0), Vector3.new(0, 0, 0), Vector3.new(0, 0, 0)} + + local worldAxes = {Vector3.new(1, 0, 0), Vector3.new(0, 1, 0), Vector3.new(0, 0, 1)} + + local lines = {} + if HighScalabilityLine.Dimensions > 1 then table.insert(lines, HighScalabilityLine.MoreLines[1]) end + if line and line.magnitude > 0 then table.insert(lines, line) end + if HighScalabilityLine.Dimensions > 2 then table.insert(lines, HighScalabilityLine.MoreLines[2]) end + + for i = 1, #lines do + lines[i] = Vector3.new(math.floor(lines[i].X+.5), math.floor(lines[i].Y+.5), math.floor(lines[i].Z+.5)) -- round to integers + + if lines[i].X > 0 then xInc[i] = 1 elseif lines[i].X < 0 then xInc[i] = -1 end + if lines[i].Y > 0 then yInc[i] = 1 elseif lines[i].Y < 0 then yInc[i] = -1 end + if lines[i].Z > 0 then zInc[i] = 1 elseif lines[i].Z < 0 then zInc[i] = -1 end + + incrementVect[i] = Vector3.new(xInc[i], yInc[i], zInc[i]) + if incrementVect[i].magnitude < .9 then incrementVect[i] = nil end + end + + + if not lines[2] then lines[2] = Vector3.new(0, 0, 0) end + if not lines[3] then lines[3] = Vector3.new(0, 0, 0) end + + local waterForceTag = stampData.CurrentParts:FindFirstChild("WaterForceTag", true) + local waterForceDirectionTag = stampData.CurrentParts:FindFirstChild("WaterForceDirectionTag", true) + + while (stepVect[3].magnitude*4 <= lines[3].magnitude) do + local outerStepVectIndex = 1 + while outerStepVectIndex < 4 do + stepVect[2] = Vector3.new(0, 0, 0) + while (stepVect[2].magnitude*4 <= lines[2].magnitude) do + local innerStepVectIndex = 1 + while innerStepVectIndex < 4 do + stepVect[1] = Vector3.new(0, 0, 0) + while (stepVect[1].magnitude*4 <= lines[1].magnitude) do + local stepVectSum = stepVect[1] + stepVect[2] + stepVect[3] + local cellPos = Vector3int16.new(startCell.X + stepVectSum.X, startCell.Y + stepVectSum.Y, startCell.Z + stepVectSum.Z) + if cellPos.X >= cMin.X and cellPos.Y >= cMin.Y and cellPos.Z >= cMin.Z and cellPos.X < cMax.X and cellPos.Y < cMax.Y and cellPos.Z < cMax.Z then + -- check if overlaps player or part + local okToStampTerrainBlock = checkTerrainBlockCollisions(cellPos, checkHighScalabilityStamp) + + if okToStampTerrainBlock then + if waterForceTag then + cluster:SetWaterCell(cellPos.X, cellPos.Y, cellPos.Z, Enum.WaterForce[waterForceTag.Value], Enum.WaterDirection[waterForceDirectionTag.Value]) + else + cluster:SetCell(cellPos.X, cellPos.Y, cellPos.Z, clusterMaterial, clusterType, clusterOrientation) + end + cellSet = true + + -- auto-wedge it? + if (autoWedgeClusterParts) then + game:GetService("Workspace").Terrain:AutowedgeCells(Region3int16.new(Vector3int16.new(cellPos.x - 1, cellPos.y - 1, cellPos.z - 1), + Vector3int16.new(cellPos.x + 1, cellPos.y + 1, cellPos.z + 1))) + end + end + end + stepVect[1] = stepVect[1] + incrementVect[1] + end + if incrementVect[2] then + while innerStepVectIndex < 4 and worldAxes[innerStepVectIndex]:Dot(incrementVect[2]) == 0 do + innerStepVectIndex = innerStepVectIndex + 1 + end + if innerStepVectIndex < 4 then + stepVect[2] = stepVect[2] + worldAxes[innerStepVectIndex] * worldAxes[innerStepVectIndex]:Dot(incrementVect[2]) + end + innerStepVectIndex = innerStepVectIndex + 1 + else + stepVect[2] = Vector3.new(1, 0, 0) + innerStepVectIndex = 4 -- skip all remaining loops + end + if (stepVect[2].magnitude*4 > lines[2].magnitude) then innerStepVectIndex = 4 end + end + end + if incrementVect[3] then + while outerStepVectIndex < 4 and worldAxes[outerStepVectIndex]:Dot(incrementVect[3]) == 0 do + outerStepVectIndex = outerStepVectIndex + 1 + end + if outerStepVectIndex < 4 then + stepVect[3] = stepVect[3] + worldAxes[outerStepVectIndex] * worldAxes[outerStepVectIndex]:Dot(incrementVect[3]) + end + outerStepVectIndex = outerStepVectIndex + 1 + else -- skip all remaining loops + stepVect[3] = Vector3.new(1, 0, 0) outerStepVectIndex = 4 + end + if (stepVect[3].magnitude*4 > lines[3].magnitude) then outerStepVectIndex = 4 end + end + end + end + + -- and also get rid of any HighScalabilityLine stuff if it's there + HighScalabilityLine.Start = nil + HighScalabilityLine.Adorn.Parent = nil + + -- Mark for undo. + if cellSet then + stampData.CurrentParts.Parent = nil + pcall(function() game:GetService("ChangeHistoryService"): SetWaypoint("StamperMulti") end) + end + + return cellSet + end + + local function DoStamperMouseUp(Mouse) + if not Mouse then + error("Error: RbxStamper.DoStamperMouseUp: Mouse is nil") + return false + end + if not Mouse:IsA("Mouse") then + error("Error: RbxStamper.DoStamperMouseUp: Mouse is of type", Mouse.className,"should be of type Mouse") + return false + end + + if not stampData.Dragger then + error("Error: RbxStamper.DoStamperMouseUp: stampData.Dragger is nil") + return false + end + + if not HighScalabilityLine then + return false + end + + local checkHighScalabilityStamp = nil + if stampInModel then + local canStamp = nil + local isHSLPart = isMegaClusterPart() + + if isHSLPart and + HighScalabilityLine and + HighScalabilityLine.Start and + HighScalabilityLine.InternalLine and + HighScalabilityLine.InternalLine.magnitude > 0 then -- we have an HSL line, test later + canStamp = true + checkHighScalabilityStamp = true + else + canStamp, checkHighScalabilityStamp = t.CanEditRegion(stampData.CurrentParts, allowedStampRegion) + end + + if not canStamp then + if stampFailedFunc then + stampFailedFunc() + end + return false + end + end + + -- if unstampable face, then don't let us stamp there! + if unstampableSurface then + flashRedBox() + return false + end + + -- recheck if we can stamp, as we just moved part + canStamp, checkHighScalabilityStamp = t.CanEditRegion(stampData.CurrentParts, allowedStampRegion) + if not canStamp then + if stampFailedFunc then + stampFailedFunc() + end + return false + end + + -- Prevent part from being stamped on top of a player + + local minBB, maxBB = getBoundingBoxInWorldCoordinates(stampData.CurrentParts) + + -- HotThoth's note: Now that above CurrentParts positioning has been commented out, to be truly correct, we would need to use the + -- value of configFound from the previous onStamperMouseMove call which moved the CurrentParts + -- Shouldn't this be true when lastTargetCFrame has been set and false otherwise? + configFound, targetCFrame = findConfigAtMouseTarget(Mouse, stampData) + + if configFound and not HighScalabilityLine.Adorn.Parent then + if clusterPartsInRegion(minBB + insertBoundingBoxOverlapVector, maxBB - insertBoundingBoxOverlapVector) then + flashRedBox() + return false + end + + local blockingParts = game:GetService("Workspace"):FindPartsInRegion3(Region3.new(minBB + insertBoundingBoxOverlapVector, + maxBB - insertBoundingBoxOverlapVector), + stampData.CurrentParts, + 100) + + + for b = 1, #blockingParts do + if isBlocker(blockingParts[b]) then + flashRedBox() + return false + end + end + + local alreadyPushedUp = {} + -- if no blocking model below, then see if stamping on top of a character + for b = 1, #blockingParts do + if blockingParts[b].Parent and + not alreadyPushedUp[blockingParts[b].Parent] and + blockingParts[b].Parent:FindFirstChild("Humanoid") and + blockingParts[b].Parent:FindFirstChild("Humanoid"):IsA("Humanoid") then + --------------------------------------------------------------------------- + local blockingPersonTorso = blockingParts[b].Parent:FindFirstChild("Torso") + alreadyPushedUp[blockingParts[b].Parent] = true + + if blockingPersonTorso then + -- if so, let's push the person upwards so they pop on top of the stamped model/part (but only if there's space above them) + local newY = maxBB.Y + 3 + if spaceAboveCharacter(blockingPersonTorso, newY, stampData) then + blockingPersonTorso.CFrame = blockingPersonTorso.CFrame + Vector3.new(0, newY - blockingPersonTorso.CFrame.p.Y, 0) + else + -- if no space, we just error + flashRedBox() + return false + end + end + --------------------------------------------------------------------------- + end + end + + elseif (not configFound) and not (HighScalabilityLine.Start and HighScalabilityLine.Adorn.Parent) then -- if no config then only stamp if it's a real HSL! + resetHighScalabilityLine() + return false + end + + -- something will be stamped! so set the "StampedSomething" toggle to true + if game:FindFirstChild("Players") then + if game:GetService("Players")["LocalPlayer"] then + if game:GetService("Players").LocalPlayer["Character"] then + local localChar = game:GetService("Players").LocalPlayer.Character + local stampTracker = localChar:FindFirstChild("StampTracker") + if stampTracker and not stampTracker.Value then + stampTracker.Value = true + end + end + end + end + + -- if we drew a line of mega parts, stamp them out + if HighScalabilityLine.Start and HighScalabilityLine.Adorn.Parent and isMegaClusterPart() then + if ResolveMegaClusterStamp(checkHighScalabilityStamp) or checkHighScalabilityStamp then + -- kill the ghost part + stampData.CurrentParts.Parent = nil + return true + end + end + + -- not High-Scalability-Line-Based, so behave normally [and get rid of any HSL stuff] + HighScalabilityLine.Start = nil + HighScalabilityLine.Adorn.Parent = nil + + local cluster = game:GetService("Workspace").Terrain + + -- if target point is in cluster, just use cluster:SetCell + if isMegaClusterPart() then + -- if targetCFrame is inside cluster, just set that cell to 1 and return + --local cellPos = cluster:WorldToCell(targetCFrame.p) + + local cellPos + if stampData.CurrentParts:IsA("Model") then cellPos = cluster:WorldToCell(stampData.CurrentParts:GetModelCFrame().p) + else cellPos = cluster:WorldToCell(stampData.CurrentParts.CFrame.p) end + + local cMax = game:GetService("Workspace").Terrain.MaxExtents.Max + local cMin = game:GetService("Workspace").Terrain.MaxExtents.Min + + if checkTerrainBlockCollisions(cellPos, false) then + + local clusterValues = stampData.CurrentParts:FindFirstChild("ClusterMaterial", true) + local waterForceTag = stampData.CurrentParts:FindFirstChild("WaterForceTag", true) + local waterForceDirectionTag = stampData.CurrentParts:FindFirstChild("WaterForceDirectionTag", true) + + if cellPos.X >= cMin.X and cellPos.Y >= cMin.Y and cellPos.Z >= cMin.Z and cellPos.X < cMax.X and cellPos.Y < cMax.Y and cellPos.Z < cMax.Z then + + if waterForceTag then + cluster:SetWaterCell(cellPos.X, cellPos.Y, cellPos.Z, Enum.WaterForce[waterForceTag.Value], Enum.WaterDirection[waterForceDirectionTag.Value]) + elseif not clusterValues then + cluster:SetCell(cellPos.X, cellPos.Y, cellPos.Z, cellInfo.Material, cellInfo.clusterType, gInitial90DegreeRotations % 4) + elseif clusterValues:IsA("Vector3Value") then + cluster:SetCell(cellPos.X, cellPos.Y, cellPos.Z, clusterValues.Value.X, clusterValues.Value.Y, clusterValues.Value.Z) + else + cluster:SetCell(cellPos.X, cellPos.Y, cellPos.Z, clusterValues.Value, 0, 0) + end + + local autoWedgeClusterParts = false + if stampData.CurrentParts:FindFirstChild("AutoWedge") then autoWedgeClusterParts = true end + + -- auto-wedge it + if (autoWedgeClusterParts) then + game:GetService("Workspace").Terrain:AutowedgeCells( + Region3int16.new( + Vector3int16.new(cellPos.x - 1, cellPos.y - 1, cellPos.z - 1), + Vector3int16.new(cellPos.x + 1, cellPos.y + 1, cellPos.z + 1) + ) + ) + end + + -- kill the ghost part + stampData.CurrentParts.Parent = nil + + -- Mark for undo. It has to happen here or the selection display will come back also. + pcall(function() game:GetService("ChangeHistoryService"):SetWaypoint("StamperSingle") end) + return true + end + else + -- you tried to stamp a HSL-single part where one does not belong! + flashRedBox() + return false + end + end + + local function getPlayer() + if game:FindFirstChild("Players") then + if game:GetService("Players")["LocalPlayer"] then + return game:GetService("Players").LocalPlayer + end + end + return nil + end + + + -- Post process: after positioning the part or model, restore transparency, material, anchored and collide states and create joints + if stampData.CurrentParts:IsA("Model") or stampData.CurrentParts:IsA("Tool") then + if stampData.CurrentParts:IsA("Model") then + -- Tyler's magical hack-code for allowing/preserving clones of both Surface and Manual Welds... just don't ask X< + local manualWeldTable = {} + local manualWeldParentTable = {} + saveTheWelds(stampData.CurrentParts, manualWeldTable, manualWeldParentTable) + stampData.CurrentParts:BreakJoints() + stampData.CurrentParts:MakeJoints() + restoreTheWelds(manualWeldTable, manualWeldParentTable) + end + + -- if it's a model, we also want to fill in the playerID and playerName tags, if it has those (e.g. for the friend-only door) + playerIdTag = stampData.CurrentParts:FindFirstChild("PlayerIdTag") + playerNameTag = stampData.CurrentParts:FindFirstChild("PlayerNameTag") + if playerIdTag ~= nil then + tempPlayerValue = getPlayer() + if tempPlayerValue ~= nil then playerIdTag.Value = tempPlayerValue.userId end + end + if playerNameTag ~= nil then + if game:FindFirstChild("Players") and game:GetService("Players")["LocalPlayer"] then + tempPlayerValue = game:GetService("Players").LocalPlayer + if tempPlayerValue ~= nil then playerNameTag.Value = tempPlayerValue.Name end + end + end + -- ...and tag all inserted models for subsequent origin identification + -- if no RobloxModel tag already exists, then add it. + if stampData.CurrentParts:FindFirstChild("RobloxModel") == nil then + local stringTag = Instance.new("BoolValue", stampData.CurrentParts) + stringTag.Name = "RobloxModel" + + if stampData.CurrentParts:FindFirstChild("RobloxStamper") == nil then + local stringTag2 = Instance.new("BoolValue", stampData.CurrentParts) + stringTag2.Name = "RobloxStamper" + end + end + + else + stampData.CurrentParts:BreakJoints() + if stampData.CurrentParts:FindFirstChild("RobloxStamper") == nil then + local stringTag2 = Instance.new("BoolValue", stampData.CurrentParts) + stringTag2.Name = "RobloxStamper" + end + end + + -- make sure all the joints are activated before restoring anchor states + if not createJoints then game.JointsService:CreateJoinAfterMoveJoints() end + + -- Restore the original properties for all parts being stamped + for part, transparency in pairs(stampData.TransparencyTable) do + part.Transparency = transparency + end + for part, archivable in pairs(stampData.ArchivableTable) do + part.Archivable = archivable + end + for part, material in pairs(stampData.MaterialTable) do + part.Material = material + end + for part, collide in pairs(stampData.CanCollideTable) do + part.CanCollide = collide + end + for part, anchored in pairs(stampData.AnchoredTable) do + part.Anchored = anchored + end + for decal, transparency in pairs(stampData.DecalTransparencyTable) do + decal.Transparency = transparency + end + + for part, surfaces in pairs(stampData.SurfaceTypeTable) do + loadSurfaceTypes(part, surfaces) + end + + if isMegaClusterPart() then + stampData.CurrentParts.Transparency = 0 + end + + -- re-enable all seats + setSeatEnabledStatus(stampData.CurrentParts, true) + + stampData.TransparencyTable = nil + stampData.ArchivableTable = nil + stampData.MaterialTable = nil + stampData.CanCollideTable = nil + stampData.AnchoredTable = nil + stampData.SurfaceTypeTable = nil + + -- ...and tag all inserted models for subsequent origin identification + -- if no RobloxModel tag already exists, then add it. + if stampData.CurrentParts:FindFirstChild("RobloxModel") == nil then + local stringTag = Instance.new("BoolValue", stampData.CurrentParts) + stringTag.Name = "RobloxModel" + end + + -- and make sure we don't delete it, now that it's not a ghost part + if ghostRemovalScript then ghostRemovalScript.Parent = nil end + + --Re-enable the scripts + for index,script in pairs(stampData.DisabledScripts) do + script.Disabled = false + end + + --Now that they are all marked enabled, reinsert them into the world so they start running + for index,script in pairs(stampData.DisabledScripts) do + local oldParent = script.Parent + script.Parent = nil + script:Clone().Parent = oldParent + end + + -- clear out more data + stampData.DisabledScripts = nil + stampData.Dragger = nil + stampData.CurrentParts = nil + + pcall(function() game:GetService("ChangeHistoryService"): SetWaypoint("StampedObject") end) + return true + end + + local function pauseStamper() + for i = 1, #mouseCons do -- stop the mouse from doing anything + mouseCons[i]:disconnect() + mouseCons[i] = nil + end + mouseCons = {} + + if stampData and stampData.CurrentParts then -- remove our ghost part + stampData.CurrentParts.Parent = nil + stampData.CurrentParts:Remove() + end + + resetHighScalabilityLine() + + game.JointsService:ClearJoinAfterMoveJoints() + end + + + local function prepareUnjoinableSurfaces(modelCFrame, parts, whichSurface) + local AXIS_VECTORS = {Vector3.new(1, 0, 0), Vector3.new(0, 1, 0), Vector3.new(0, 0, 1)} -- maybe last one is negative? TODO: check this! + local isPositive = 1 + if whichSurface < 0 then isPositive = isPositive * -1 whichSurface = whichSurface*-1 end + local surfaceNormal = isPositive * modelCFrame:vectorToWorldSpace(AXIS_VECTORS[whichSurface]) + + for i = 1, #parts do + local currPart = parts[i] + + -- now just need to find which surface of currPart most closely match surfaceNormal and then set that to Unjoinable + local surfaceNormalInLocalCoords = currPart.CFrame:vectorToObjectSpace(surfaceNormal) + if math.abs(surfaceNormalInLocalCoords.X) > math.abs(surfaceNormalInLocalCoords.Y) then + if math.abs(surfaceNormalInLocalCoords.X) > math.abs(surfaceNormalInLocalCoords.Z) then + if surfaceNormalInLocalCoords.X > 0 then currPart.RightSurface = "Unjoinable" else currPart.LeftSurface = "Unjoinable" end + else + if surfaceNormalInLocalCoords.Z > 0 then currPart.BackSurface = "Unjoinable" else currPart.FrontSurface = "Unjoinable" end + end + else + if math.abs(surfaceNormalInLocalCoords.Y) > math.abs(surfaceNormalInLocalCoords.Z) then + if surfaceNormalInLocalCoords.Y > 0 then currPart.TopSurface = "Unjoinable" else currPart.BottomSurface = "Unjoinable" end + else + if surfaceNormalInLocalCoords.Z > 0 then currPart.BackSurface = "Unjoinable" else currPart.FrontSurface = "Unjoinable" end + end + end + end + end + + local function resumeStamper() + clone, parts = prepareModel(modelToStamp) + + if not clone or not parts then + return + end + + -- if we have unjoinable faces, then we want to change those surfaces to be Unjoinable + local unjoinableTag = clone:FindFirstChild("UnjoinableFaces", true) + if unjoinableTag then + for unjoinableSurface in string.gmatch(unjoinableTag.Value, "[^,]*") do + if tonumber(unjoinableSurface) then + if clone:IsA("Model") then + prepareUnjoinableSurfaces(clone:GetModelCFrame(), parts, tonumber(unjoinableSurface)) + else + prepareUnjoinableSurfaces(clone.CFrame, parts, tonumber(unjoinableSurface)) + end + end + end + end + + stampData.ErrorBox = errorBox + if stampInModel then + clone.Parent = stampInModel + else + clone.Parent = game:GetService("Workspace") + end + + if clone:FindFirstChild("ClusterMaterial", true) then -- extract all info from vector + clusterMaterial = clone:FindFirstChild("ClusterMaterial", true) + if (clusterMaterial:IsA("Vector3Value")) then + cellInfo.Material = clusterMaterial.Value.X + cellInfo.clusterType = clusterMaterial.Value.Y + cellInfo.clusterOrientation = clusterMaterial.Value.Z + elseif clusterMaterial:IsA("IntValue") then + cellInfo.Material = clusterMaterial.Value + end + end + + pcall(function() mouseTarget = Mouse.Target end) + + if mouseTarget and mouseTarget.Parent:FindFirstChild("RobloxModel") == nil then + game.JointsService:SetJoinAfterMoveTarget(mouseTarget) + else + game.JointsService:SetJoinAfterMoveTarget(nil) + end + game.JointsService:ShowPermissibleJoints() + + for index, object in pairs(stampData.DisabledScripts) do + if object.Name == "GhostRemovalScript" then + object.Parent = stampData.CurrentParts + end + end + + stampData.Dragger = Instance.new("Dragger") + + --Begin a movement by faking a MouseDown signal + stampData.Dragger:MouseDown(parts[1], Vector3.new(0,0,0), parts) + stampData.Dragger:MouseUp() + + DoStamperMouseMove(Mouse) + + table.insert(mouseCons,Mouse.Move:connect(function() + if movingLock or stampUpLock then return end + movingLock = true + DoStamperMouseMove(Mouse) + movingLock = false + end)) + + table.insert(mouseCons,Mouse.Button1Down:connect(function() + DoStamperMouseDown(Mouse) + end)) + + table.insert(mouseCons,Mouse.Button1Up:connect(function() + stampUpLock = true + while movingLock do wait() end + stamped.Value = DoStamperMouseUp(Mouse) + resetHighScalabilityLine() + stampUpLock = false + end)) + + stamped.Value = false + end + + local function resetStamperState(newModelToStamp) + + -- if we have a new model, swap it out + if newModelToStamp then + if not newModelToStamp:IsA("Model") and not newModelToStamp:IsA("BasePart") then + error("resetStamperState: newModelToStamp (first arg) is not nil, but not a model or part!") + end + modelToStamp = newModelToStamp + end + + -- first clear our state + pauseStamper() + -- now lets load in the new model + resumeStamper() + + end + + -- load the model initially + resetStamperState() + + + -- setup the control table we pass back to the user + control.Stamped = stamped -- BoolValue that fires when user stamps + control.Paused = false + + control.LoadNewModel = function(newStampModel) -- allows us to specify a new stamper model to be used with this stamper + if newStampModel and not newStampModel:IsA("Model") and not newStampModel:IsA("BasePart") then + error("Control.LoadNewModel: newStampModel (first arg) is not a Model or Part!") + return nil + end + resetStamperState(newStampModel) + end + + control.ReloadModel = function() -- will automatically set stamper to get a new model of current model and start stamping with new model + resetStamperState() + end + + control.Pause = function() -- temporarily stops stamping, use resume to start up again + if not control.Paused then + pauseStamper() + control.Paused = true + else + print("RbxStamper Warning: Tried to call Control.Pause() when already paused") + end + end + + control.Resume = function() -- resumes stamping, if currently paused + if control.Paused then + resumeStamper() + control.Paused = false + else + print("RbxStamper Warning: Tried to call Control.Resume() without Pausing First") + end + end + + control.ResetRotation = function() -- resets the model rotation so new models are at default orientation + -- gInitial90DegreeRotations = 0 + -- Note: This function will not always work quite the way we want it to; we will have to build this out further so it works with + -- High-Scalability and with the new model orientation setting methods (model:ResetOrientationToIdentity()) [HotThoth] + end + + control.Destroy = function() -- Stops current Stamp operation and destroys control construct + for i = 1, #mouseCons do + mouseCons[i]:disconnect() + mouseCons[i] = nil + end + + if keyCon then + keyCon:disconnect() + end + + game.JointsService:ClearJoinAfterMoveJoints() + + if adorn then adorn:Destroy() end + if adornPart then adornPart:Destroy() end + if errorBox then errorBox:Destroy() end + if stampData then + if stampData["Dragger"] then + stampData.Dragger:Destroy() + end + if stampData.CurrentParts then + stampData.CurrentParts:Destroy() + end + end + if control and control["Stamped"] then + control.Stamped:Destroy() + end + control = nil + end + + return control +end + +t.Help = + function(funcNameOrFunc) + --input argument can be a string or a function. Should return a description (of arguments and expected side effects) + if funcNameOrFunc == "GetStampModel" or funcNameOrFunc == t.GetStampModel then + return "Function GetStampModel. Arguments: assetId, useAssetVersionId. assetId is the asset to load in, define useAssetVersionId as true if assetId is a version id instead of a relative assetId. Side effect: returns a model of the assetId, or a string with error message if something fails" + end + if funcNameOrFunc == "SetupStamperDragger" or funcNameOrFunc == t.SetupStamperDragger then + return "Function SetupStamperDragger. Side Effect: Creates 4x4 stamping mechanism for building out parts quickly. Arguments: ModelToStamp, Mouse, LegalStampCheckFunction. ModelToStamp should be a Model or Part, preferrably loaded from RbxStamper.GetStampModel and should have extents that are multiples of 4. Mouse should be a mouse object (obtained from things such as Tool.OnEquipped), used to drag parts around 'stamp' them out. LegalStampCheckFunction is optional, used as a callback with a table argument (table is full of instances about to be stamped). Function should return either true or false, false stopping the stamp action." + end + end + +return t diff --git a/2016/content/scripts/LoadingScript.lua b/2016/content/scripts/LoadingScript.lua new file mode 100644 index 0000000..60f5da4 --- /dev/null +++ b/2016/content/scripts/LoadingScript.lua @@ -0,0 +1,777 @@ +-- Creates the generic "ROBLOX" loading screen on startup +-- Written by ArceusInator & Ben Tkacheff, 2014 +-- + +-- Constants +local PLACEID = game.PlaceId + +local MPS = game:GetService('MarketplaceService') +local UIS = game:GetService('UserInputService') +local guiService = game:GetService("GuiService") +local ContextActionService = game:GetService('ContextActionService') +local RobloxGui = game:GetService("CoreGui"):WaitForChild("RobloxGui") + +local startTime = tick() + +local COLORS = { + BLACK = Color3.new(0, 0, 0), + BACKGROUND_COLOR = Color3.new(45/255, 45/255, 45/255), + WHITE = Color3.new(1, 1, 1), + ERROR = Color3.new(253/255,68/255,72/255) +} + +local function getViewportSize() + while not game.Workspace.CurrentCamera do + game.Workspace.Changed:wait() + end + + while game.Workspace.CurrentCamera.ViewportSize == Vector2.new(0,0) do + game.Workspace.CurrentCamera.Changed:wait() + end + + return game.Workspace.CurrentCamera.ViewportSize +end + +-- +-- Variables +local GameAssetInfo -- loaded by InfoProvider:LoadAssets() +local currScreenGui, renderSteppedConnection = nil, nil +local destroyingBackground, destroyedLoadingGui, hasReplicatedFirstElements = false, false, false +local backgroundImageTransparency = 0 +local isMobile = (UIS.TouchEnabled == true and UIS.MouseEnabled == false and getViewportSize().Y <= 500) +local isTenFootInterface = guiService:IsTenFootInterface() +local platform = UIS:GetPlatform() + +local function IsConvertMyPlaceNameInXboxAppEnabled() + if UIS:GetPlatform() == Enum.Platform.XBoxOne then + local success, flagValue = pcall(function() return settings():GetFFlag("ConvertMyPlaceNameInXboxApp") end) + return (success and flagValue == true) + end + return false +end + +-- +-- Utility functions +local create = function(className, defaultParent) + return function(propertyList) + local object = Instance.new(className) + + for index, value in next, propertyList do + if type(index) == 'string' then + object[index] = value + else + if type(value) == 'function' then + value(object) + elseif type(value) == 'userdata' then + value.Parent = object + end + end + end + + if object.Parent == nil then + object.Parent = defaultParent + end + + return object + end +end + +-- +-- Create objects + +local MainGui = {} +local InfoProvider = {} + + +function ExtractGeneratedUsername(gameName) + local tempUsername = string.match(gameName, "^([0-9a-fA-F]+)'s Place$") + if tempUsername and #tempUsername == 32 then + return tempUsername + end +end + +-- Fix places that have been made with incorrect temporary usernames +function GetFilteredGameName(gameName, creatorName) + if gameName and type(gameName) == 'string' then + local tempUsername = ExtractGeneratedUsername(gameName) + if tempUsername then + local newGameName = string.gsub(gameName, tempUsername, creatorName, 1) + if newGameName then + return newGameName + end + end + end + return gameName +end + + +function InfoProvider:GetGameName() + if GameAssetInfo ~= nil then + if IsConvertMyPlaceNameInXboxAppEnabled() then + return GetFilteredGameName(GameAssetInfo.Name, self:GetCreatorName()) + else + return GameAssetInfo.Name + end + else + return '' + end +end + +function InfoProvider:GetCreatorName() + if GameAssetInfo ~= nil then + return GameAssetInfo.Creator.Name + else + return '' + end +end + +function InfoProvider:LoadAssets() + spawn(function() + if PLACEID <= 0 then + while game.PlaceId <= 0 do + wait() + end + PLACEID = game.PlaceId + end + + -- load game asset info + coroutine.resume(coroutine.create(function() + local success, result = pcall(function() + GameAssetInfo = MPS:GetProductInfo(PLACEID) + end) + if not success then + print("LoadingScript->InfoProvider:LoadAssets:", result) + end + end)) + end) +end + +function MainGui:tileBackgroundTexture(frameToFill) + if not frameToFill then return end + frameToFill:ClearAllChildren() + if backgroundImageTransparency < 1 then + local backgroundTextureSize = Vector2.new(512, 512) + for i = 0, math.ceil(frameToFill.AbsoluteSize.X/backgroundTextureSize.X) do + for j = 0, math.ceil(frameToFill.AbsoluteSize.Y/backgroundTextureSize.Y) do + create 'ImageLabel' { + Name = 'BackgroundTextureImage', + BackgroundTransparency = 1, + ImageTransparency = backgroundImageTransparency, + Image = 'rbxasset://textures/loading/darkLoadingTexture.png', + Position = UDim2.new(0, i*backgroundTextureSize.X, 0, j*backgroundTextureSize.Y), + Size = UDim2.new(0, backgroundTextureSize.X, 0, backgroundTextureSize.Y), + ZIndex = 1, + Parent = frameToFill + } + end + end + end +end + +-- create a cancel binding for console to be able to cancel anytime while loading +local function createTenfootCancelGui() + local cancelLabel = create'ImageLabel' + { + Name = "CancelLabel"; + Size = UDim2.new(0, 83, 0, 83); + Position = UDim2.new(1, -32 - 83, 0, 32); + BackgroundTransparency = 1; + Image = 'rbxasset://textures/ui/Shell/ButtonIcons/BButton.png'; + } + local cancelText = create'TextLabel' + { + Name = "CancelText"; + Size = UDim2.new(0, 0, 0, 0); + Position = UDim2.new(1, -131, 0, 64); + BackgroundTransparency = 1; + FontSize = Enum.FontSize.Size36; + TextXAlignment = Enum.TextXAlignment.Right; + TextColor3 = COLORS.WHITE; + Text = "Cancel"; + } + + -- bind cancel action + local platformService = nil + pcall(function() + platformService = game:GetService('PlatformService') + end) + + if platformService then + if not game:GetService("ReplicatedFirst"):IsFinishedReplicating() then + local seenBButtonBegin = false + ContextActionService:BindCoreAction("CancelGameLoad", + function(actionName, inputState, inputObject) + if inputState == Enum.UserInputState.Begin then + seenBButtonBegin = true + elseif inputState == Enum.UserInputState.End and seenBButtonBegin then + cancelLabel:Destroy() + cancelText.Text = "Canceling..." + cancelText.Position = UDim2.new(1, -32, 0, 64) + ContextActionService:UnbindCoreAction('CancelGameLoad') + platformService:RequestGameShutdown() + end + end, + false, + Enum.KeyCode.ButtonB) + end + end + + while cancelLabel.Parent == nil do + if currScreenGui then + local blackFrame = currScreenGui:FindFirstChild('BlackFrame') + if blackFrame then + cancelLabel.Parent = blackFrame + cancelText.Parent = blackFrame + break + end + end + wait() + end +end + +-- +-- Declare member functions +function MainGui:GenerateMain() + local screenGui = create 'ScreenGui' { + Name = 'RobloxLoadingGui' + } + + -- + -- create descendant frames + local mainBackgroundContainer = create 'Frame' { + Name = 'BlackFrame', + BackgroundColor3 = COLORS.BACKGROUND_COLOR, + BackgroundTransparency = 0, + Size = UDim2.new(1, 0, 1, 0), + Position = UDim2.new(0, 0, 0, 0), + Active = true, + Parent = screenGui, + } + + local closeButton = create 'ImageButton' { + Name = 'CloseButton', + Image = 'rbxasset://textures/loading/cancelButton.png', + ImageTransparency = 1, + BackgroundTransparency = 1, + Position = UDim2.new(1, -37, 0, 5), + Size = UDim2.new(0, 32, 0, 32), + Active = false, + ZIndex = 10, + Parent = mainBackgroundContainer, + } + + local graphicsFrame = create 'Frame' { + Name = 'GraphicsFrame', + BorderSizePixel = 0, + BackgroundTransparency = 1, + Position = UDim2.new(1, (isMobile == true and -75 or (isTenFootInterface and -245 or -225)), 1, (isMobile == true and -75 or (isTenFootInterface and -185 or -165))), + Size = UDim2.new(0, (isMobile == true and 70 or (isTenFootInterface and 140 or 120)), 0, (isMobile == true and 70 or (isTenFootInterface and 140 or 120))), + ZIndex = 2, + Parent = mainBackgroundContainer, + } + + local loadingImage = create 'ImageLabel' { + Name = 'LoadingImage', + BackgroundTransparency = 1, + Image = 'rbxasset://textures/loading/loadingCircle.png', + Position = UDim2.new(0, 0, 0, 0), + Size = UDim2.new(1, 0, 1, 0), + ZIndex = 2, + Parent = graphicsFrame, + } + + local loadingText = create 'TextLabel' { + Name = 'LoadingText', + BackgroundTransparency = 1, + Size = UDim2.new(1, (isMobile == true and -14 or -56), 1, 0), + Position = UDim2.new(0, (isMobile == true and 12 or 28), 0, 0), + Font = Enum.Font.SourceSans, + FontSize = (isMobile == true and Enum.FontSize.Size12 or Enum.FontSize.Size18), + TextWrapped = true, + TextColor3 = COLORS.WHITE, + TextXAlignment = Enum.TextXAlignment.Left, + Visible = not isTenFootInterface, + Text = "Loading...", + ZIndex = 2, + Parent = graphicsFrame, + } + + local uiMessageFrame = create 'Frame' { + Name = 'UiMessageFrame', + BackgroundTransparency = 1, + Position = UDim2.new(0.25, 0, 1, -120), + Size = UDim2.new(0.5, 0, 0, 80), + ZIndex = 2, + Parent = mainBackgroundContainer, + } + + local uiMessage = create 'TextLabel' { + Name = 'UiMessage', + BackgroundTransparency = 1, + Size = UDim2.new(1, 0, 1, 0), + Font = Enum.Font.SourceSansBold, + FontSize = Enum.FontSize.Size18, + TextWrapped = true, + TextColor3 = COLORS.WHITE, + Text = "", + ZIndex = 2, + Parent = uiMessageFrame, + } + + local infoFrame = create 'Frame' { + Name = 'InfoFrame', + BackgroundTransparency = 1, + Position = UDim2.new(0, (isMobile == true and 20 or 100), 1, (isMobile == true and -120 or -150)), + Size = UDim2.new(0.4, 0, 0, 110), + ZIndex = 2, + Parent = mainBackgroundContainer, + } + + local placeLabel = create 'TextLabel' { + Name = 'PlaceLabel', + BackgroundTransparency = 1, + Size = UDim2.new(1, 0, 0, 80), + Position = UDim2.new(0, 0, 0, 0), + Font = Enum.Font.SourceSans, + FontSize = (isTenFootInterface and Enum.FontSize.Size48 or Enum.FontSize.Size24), + TextWrapped = true, + TextScaled = true, + TextColor3 = COLORS.WHITE, + TextStrokeTransparency = 0, + Text = "", + TextXAlignment = Enum.TextXAlignment.Left, + TextYAlignment = Enum.TextYAlignment.Bottom, + ZIndex = 2, + Parent = infoFrame, + } + + if isTenFootInterface then + local byLabel = create'TextLabel' { + Name = "ByLabel", + BackgroundTransparency = 1, + Size = UDim2.new(0, 36, 0, 30), + Position = UDim2.new(0, 0, 0, 80), + Font = Enum.Font.SourceSans, + FontSize = Enum.FontSize.Size36, + TextScaled = true, + TextColor3 = COLORS.WHITE, + TextStrokeTransparency = 0, + Text = "By", + TextXAlignment = Enum.TextXAlignment.Left, + TextYAlignment = Enum.TextYAlignment.Top, + ZIndex = 2, + Visible = false, + Parent = infoFrame, + } + local creatorIcon = create'ImageLabel' { + Name = "CreatorIcon", + BackgroundTransparency = 1, + Size = UDim2.new(0, 30, 0, 30), + Position = UDim2.new(0, 38, 0, 80), + ImageTransparency = 0, + Image = 'rbxasset://textures/ui/Shell/Icons/RobloxIcon32.png', + ZIndex = 2, + Visible = false, + Parent = infoFrame, + } + end + + local creatorLabel = create 'TextLabel' { + Name = 'CreatorLabel', + BackgroundTransparency = 1, + Size = UDim2.new(1, 0, 0, 30), + Position = UDim2.new(0, isTenFootInterface and 72 or 0, 0, 80), + Font = Enum.Font.SourceSans, + FontSize = (isTenFootInterface and Enum.FontSize.Size36 or Enum.FontSize.Size18), + TextWrapped = true, + TextScaled = true, + TextColor3 = COLORS.WHITE, + TextStrokeTransparency = 0, + Text = "", + TextXAlignment = Enum.TextXAlignment.Left, + TextYAlignment = Enum.TextYAlignment.Top, + ZIndex = 2, + Parent = infoFrame, + } + + local backgroundTextureFrame = create 'Frame' { + Name = 'BackgroundTextureFrame', + BorderSizePixel = 0, + Size = UDim2.new(1, 0, 1, 0), + Position = UDim2.new(0, 0, 0, 0), + ClipsDescendants = true, + ZIndex = 1, + BackgroundTransparency = 1, + Parent = mainBackgroundContainer, + } + + local errorFrame = create 'Frame' { + Name = 'ErrorFrame', + BackgroundColor3 = COLORS.ERROR, + BorderSizePixel = 0, + Position = UDim2.new(0.25,0,0,0), + Size = UDim2.new(0.5, 0, 0, 80), + ZIndex = 8, + Visible = false, + Parent = screenGui, + } + + local errorText = create 'TextLabel' { + Name = "ErrorText", + BackgroundTransparency = 1, + Size = UDim2.new(1, 0, 1, 0), + Font = Enum.Font.SourceSansBold, + FontSize = Enum.FontSize.Size14, + TextWrapped = true, + TextColor3 = COLORS.WHITE, + Text = "", + ZIndex = 8, + Parent = errorFrame, + } + + while not game:GetService("CoreGui") do + wait() + end + screenGui.Parent = game:GetService("CoreGui") + currScreenGui = screenGui +end + +function round(num, idp) + local mult = 10^(idp or 0) + return math.floor(num * mult + 0.5) / mult +end + +--------------------------------------------------------- +-- Main Script (show something now + setup connections) + +-- start loading assets asap +InfoProvider:LoadAssets() +MainGui:GenerateMain() +if isTenFootInterface then + createTenfootCancelGui() +end + +local setVerb = true +local lastRenderTime, lastDotUpdateTime, brickCountChange = nil, nil, nil +local fadeCycleTime = 1.7 +local turnCycleTime = 2 +local lastAbsoluteSize = Vector2.new(0, 0) +local loadingDots = "..." +local dotChangeTime = .2 +local lastBrickCount = 0 + +renderSteppedConnection = game:GetService("RunService").RenderStepped:connect(function() + if not currScreenGui then return end + if not currScreenGui:FindFirstChild("BlackFrame") then return end + + if setVerb then + currScreenGui.BlackFrame.CloseButton:SetVerb("Exit") + setVerb = false + end + + if currScreenGui.BlackFrame:FindFirstChild("BackgroundTextureFrame") and currScreenGui.BlackFrame.BackgroundTextureFrame.AbsoluteSize ~= lastAbsoluteSize then + lastAbsoluteSize = currScreenGui.BlackFrame.BackgroundTextureFrame.AbsoluteSize + MainGui:tileBackgroundTexture(currScreenGui.BlackFrame.BackgroundTextureFrame) + end + + local infoFrame = currScreenGui.BlackFrame:FindFirstChild('InfoFrame') + if infoFrame then + -- set place name + local placeLabel = infoFrame:FindFirstChild('PlaceLabel') + if placeLabel and placeLabel.Text == "" then + placeLabel.Text = InfoProvider:GetGameName() + end + + -- set creator name + local creatorLabel = infoFrame:FindFirstChild('CreatorLabel') + if creatorLabel and creatorLabel.Text == "" then + local creatorName = InfoProvider:GetCreatorName() + if creatorName ~= "" then + if isTenFootInterface then + local showDevName = true + if platform == Enum.Platform.XBoxOne then + local success, result = pcall(function() + return settings():GetFFlag("ShowDevNameInXboxApp") + end) + if success then + showDevName = result + end + end + creatorLabel.Text = showDevName and creatorName or "" + local creatorIcon = infoFrame:FindFirstChild('CreatorIcon') + local byLabel = infoFrame:FindFirstChild('ByLabel') + if creatorIcon then creatorIcon.Visible = showDevName end + if byLabel then byLabel.Visible = showDevName end + else + creatorLabel.Text = "By "..creatorName + end + end + end + end + + if not lastRenderTime then + lastRenderTime = tick() + lastDotUpdateTime = lastRenderTime + return + end + + local currentTime = tick() + local fadeAmount = (currentTime - lastRenderTime) * fadeCycleTime + local turnAmount = (currentTime - lastRenderTime) * (360/turnCycleTime) + lastRenderTime = currentTime + + currScreenGui.BlackFrame.GraphicsFrame.LoadingImage.Rotation = currScreenGui.BlackFrame.GraphicsFrame.LoadingImage.Rotation + turnAmount + + local updateLoadingDots = function() + loadingDots = loadingDots.. "." + if loadingDots == "...." then + loadingDots = "" + end + currScreenGui.BlackFrame.GraphicsFrame.LoadingText.Text = "Loading" ..loadingDots + end + + if currentTime - lastDotUpdateTime >= dotChangeTime and InfoProvider:GetCreatorName() == "" then + lastDotUpdateTime = currentTime + updateLoadingDots() + else + if guiService:GetBrickCount() > 0 then + if brickCountChange == nil then + brickCountChange = guiService:GetBrickCount() + end + if guiService:GetBrickCount() - lastBrickCount >= brickCountChange then + lastBrickCount = guiService:GetBrickCount() + updateLoadingDots() + end + end + end + + if not isTenFootInterface then + if currentTime - startTime > 5 and currScreenGui.BlackFrame.CloseButton.ImageTransparency > 0 then + currScreenGui.BlackFrame.CloseButton.ImageTransparency = currScreenGui.BlackFrame.CloseButton.ImageTransparency - fadeAmount + + if currScreenGui.BlackFrame.CloseButton.ImageTransparency <= 0 then + currScreenGui.BlackFrame.CloseButton.Active = true + end + end + end +end) + +spawn(function() + local RobloxGui = game:GetService("CoreGui"):WaitForChild("RobloxGui") + local guiInsetChangedEvent = Instance.new("BindableEvent") + guiInsetChangedEvent.Name = "GuiInsetChanged" + guiInsetChangedEvent.Parent = RobloxGui + guiInsetChangedEvent.Event:connect(function(x1, y1, x2, y2) + if currScreenGui and currScreenGui:FindFirstChild("BlackFrame") then + currScreenGui.BlackFrame.Position = UDim2.new(0, -x1, 0, -y1) + currScreenGui.BlackFrame.Size = UDim2.new(1, x1 + x2, 1, y1 + y2) + end + end) +end) + +local leaveGameButton, leaveGameTextLabel, errorImage = nil + +guiService.ErrorMessageChanged:connect(function() + if guiService:GetErrorMessage() ~= '' then + if isTenFootInterface then + currScreenGui.ErrorFrame.Size = UDim2.new(1, 0, 0, 144) + currScreenGui.ErrorFrame.Position = UDim2.new(0, 0, 0, 0) + currScreenGui.ErrorFrame.BackgroundColor3 = COLORS.BLACK + currScreenGui.ErrorFrame.BackgroundTransparency = 0.5 + currScreenGui.ErrorFrame.ErrorText.FontSize = Enum.FontSize.Size36 + currScreenGui.ErrorFrame.ErrorText.Position = UDim2.new(.3, 0, 0, 0) + currScreenGui.ErrorFrame.ErrorText.Size = UDim2.new(.4, 0, 0, 144) + if errorImage == nil then + errorImage = Instance.new("ImageLabel") + errorImage.Image = "rbxasset://textures/ui/ErrorIconSmall.png" + errorImage.Size = UDim2.new(0, 96, 0, 79) + errorImage.Position = UDim2.new(0.228125, 0, 0, 32) + errorImage.ZIndex = 9 + errorImage.BackgroundTransparency = 1 + errorImage.Parent = currScreenGui.ErrorFrame + end + -- we show a B button to kill game data model on console + if not isTenFootInterface then + if leaveGameButton == nil then + local RobloxGui = game:GetService("CoreGui"):WaitForChild("RobloxGui") + local utility = require(RobloxGui.Modules.Settings.Utility) + local textLabel = nil + leaveGameButton, leaveGameTextLabel = utility:MakeStyledButton("LeaveGame", "Leave", UDim2.new(0, 288, 0, 78)) + leaveGameButton:SetVerb("Exit") + leaveGameButton.NextSelectionDown = leaveGameButton + leaveGameButton.NextSelectionLeft = leaveGameButton + leaveGameButton.NextSelectionRight = leaveGameButton + leaveGameButton.NextSelectionUp = leaveGameButton + leaveGameButton.ZIndex = 9 + leaveGameButton.Position = UDim2.new(0.771875, 0, 0, 37) + leaveGameButton.Parent = currScreenGui.ErrorFrame + leaveGameTextLabel.FontSize = Enum.FontSize.Size36 + leaveGameTextLabel.ZIndex = 10 + game:GetService("GuiService").SelectedCoreObject = leaveGameButton + else + game:GetService("GuiService").SelectedCoreObject = leaveGameButton + end + end + end + currScreenGui.ErrorFrame.ErrorText.Text = guiService:GetErrorMessage() + currScreenGui.ErrorFrame.Visible = true + local blackFrame = currScreenGui:FindFirstChild('BlackFrame') + if blackFrame then + blackFrame.CloseButton.ImageTransparency = 0 + blackFrame.CloseButton.Active = true + end + else + currScreenGui.ErrorFrame.Visible = false + end +end) + +guiService.UiMessageChanged:connect(function(type, newMessage) + if type == Enum.UiMessageType.UiMessageInfo then + local blackFrame = currScreenGui and currScreenGui:FindFirstChild('BlackFrame') + if blackFrame then + blackFrame.UiMessageFrame.UiMessage.Text = newMessage + if newMessage ~= '' then + blackFrame.UiMessageFrame.Visible = true + else + blackFrame.UiMessageFrame.Visible = false + end + end + end +end) + +if guiService:GetErrorMessage() ~= '' then + currScreenGui.ErrorFrame.ErrorText.Text = guiService:GetErrorMessage() + currScreenGui.ErrorFrame.Visible = true +end + + +function stopListeningToRenderingStep() + if renderSteppedConnection then + renderSteppedConnection:disconnect() + renderSteppedConnection = nil + end +end + +function fadeAndDestroyBlackFrame(blackFrame) + if destroyingBackground then return end + destroyingBackground = true + spawn(function() + local infoFrame = blackFrame:FindFirstChild("InfoFrame") + local graphicsFrame = blackFrame:FindFirstChild("GraphicsFrame") + + local infoFrameChildren = infoFrame:GetChildren() + local transparency = 0 + local rateChange = 1.8 + local lastUpdateTime = nil + + while transparency < 1 do + if not lastUpdateTime then + lastUpdateTime = tick() + else + local newTime = tick() + transparency = transparency + rateChange * (newTime - lastUpdateTime) + for i = 1, #infoFrameChildren do + local child = infoFrameChildren[i] + if child:IsA('TextLabel') then + child.TextTransparency = transparency + child.TextStrokeTransparency = transparency + elseif child:IsA('ImageLabel') then + child.ImageTransparency = transparency + end + end + graphicsFrame.LoadingImage.ImageTransparency = transparency + blackFrame.BackgroundTransparency = transparency + + if backgroundImageTransparency < 1 then + backgroundImageTransparency = transparency + local backgroundImages = blackFrame.BackgroundTextureFrame:GetChildren() + for i = 1, #backgroundImages do + backgroundImages[i].ImageTransparency = backgroundImageTransparency + end + end + + lastUpdateTime = newTime + end + wait() + end + if blackFrame ~= nil then + stopListeningToRenderingStep() + blackFrame:Destroy() + end + end) +end + +function destroyLoadingElements(instant) + if not currScreenGui then return end + if destroyedLoadingGui then return end + destroyedLoadingGui = true + + local guiChildren = currScreenGui:GetChildren() + for i=1, #guiChildren do + -- need to keep this around in case we get a connection error later + if guiChildren[i].Name ~= "ErrorFrame" then + if guiChildren[i].Name == "BlackFrame" and not instant then + fadeAndDestroyBlackFrame(guiChildren[i]) + else + guiChildren[i]:Destroy() + end + end + end +end + +function handleFinishedReplicating() + hasReplicatedFirstElements = (#game:GetService("ReplicatedFirst"):GetChildren() > 0) + + if not hasReplicatedFirstElements then + if game:IsLoaded() then + handleRemoveDefaultLoadingGui() + else + local gameLoadedCon = nil + gameLoadedCon = game.Loaded:connect(function() + gameLoadedCon:disconnect() + gameLoadedCon = nil + handleRemoveDefaultLoadingGui() + end) + end + else + wait(5) -- make sure after 5 seconds we remove the default gui, even if the user doesn't + handleRemoveDefaultLoadingGui() + end +end + +function handleRemoveDefaultLoadingGui(instant) + if isTenFootInterface then + ContextActionService:UnbindCoreAction('CancelGameLoad') + end + destroyLoadingElements(instant) +end + +game:GetService("ReplicatedFirst").FinishedReplicating:connect(handleFinishedReplicating) +if game:GetService("ReplicatedFirst"):IsFinishedReplicating() then + handleFinishedReplicating() +end + +game:GetService("ReplicatedFirst").RemoveDefaultLoadingGuiSignal:connect(handleRemoveDefaultLoadingGui) +if game:GetService("ReplicatedFirst"):IsDefaultLoadingGuiRemoved() then + handleRemoveDefaultLoadingGui() +end + +local UserInputServiceChangedConn; +local function onUserInputServiceChanged(prop) + if prop == 'VREnabled' then + local UseVr = false + pcall(function() UseVr = UIS.VREnabled end) + + if UseVr then + if UserInputServiceChangedConn then + UserInputServiceChangedConn:disconnect() + UserInputServiceChangedConn = nil + end + handleRemoveDefaultLoadingGui(true) + require(RobloxGui.Modules.LoadingScreen3D) + end + end +end + +UserInputServiceChangedConn = UIS.Changed:connect(onUserInputServiceChanged) +onUserInputServiceChanged('VREnabled') diff --git a/2016/content/scripts/Modules/BackpackScript3D.lua b/2016/content/scripts/Modules/BackpackScript3D.lua new file mode 100644 index 0000000..5f67f6c --- /dev/null +++ b/2016/content/scripts/Modules/BackpackScript3D.lua @@ -0,0 +1,502 @@ +--BackpackScript3D: VR port of backpack interface using a 3D panel +--written by 0xBAADF00D +local ICON_SIZE = 48 +local ICON_SPACING = 52 +local PIXELS_PER_STUD = 64 + +local SLOT_BORDER_SIZE = 0 +local SLOT_BORDER_SELECTED_SIZE = 4 +local SLOT_BORDER_COLOR = Color3.new(90/255, 142/255, 233/255) +local SLOT_BACKGROUND_COLOR = Color3.new(0.2, 0.2, 0.2) +local SLOT_HOVER_BACKGROUND_COLOR = Color3.new(90/255, 90/255, 90/255) + +local HOPPERBIN_ANGLE = math.rad(-45) +local HOPPERBIN_ROTATION = CFrame.Angles(HOPPERBIN_ANGLE, 0, 0) +local HOPPERBIN_OFFSET = Vector3.new(0, 0, -5) + +local HEALTHBAR_SPACE = 12 +local HEALTHBAR_WIDTH = 82 +local HEALTHBAR_HEIGHT = 5 + +local NAME_SPACE = 14 + +local Tools = {} +local ToolsList = {} +local slotIcons = {} + +local BackpackScript = {} +local topbarEnabled = false + +local player = game.Players.LocalPlayer +local currentHumanoid = nil +local CoreGui = game:GetService('CoreGui') +local RobloxGui = CoreGui:WaitForChild("RobloxGui") +local Panel3D = require(RobloxGui.Modules.VR.Panel3D) +local Util = require(RobloxGui.Modules.Settings.Utility) + +local ContextActionService = game:GetService("ContextActionService") + +local BackpackPanel = Panel3D.Get("Backpack") +BackpackPanel:ResizeStuds(5, 2) +BackpackPanel:SetType(Panel3D.Type.Fixed, { CFrame = CFrame.new(0, 0, -5) }) +BackpackPanel:SetVisible(true) + +local toolsFrame = Instance.new("TextButton", BackpackPanel:GetGUI()) --prevent clicks falling through in case you have a rocket launcher and blow yourself up +toolsFrame.Text = "" +toolsFrame.Size = UDim2.new(1, 0, 0, ICON_SIZE) +toolsFrame.BackgroundTransparency = 1 +toolsFrame.Selectable = false +local insetAdjustY = toolsFrame.AbsolutePosition.Y +toolsFrame.Position = UDim2.new(0, 0, 0, HEALTHBAR_SPACE + NAME_SPACE) + +--Healthbar color function stolen from Topbar.lua +local HEALTH_BACKGROUND_COLOR = Color3.new(228/255, 236/255, 246/255) +local HEALTH_RED_COLOR = Color3.new(255/255, 28/255, 0/255) +local HEALTH_YELLOW_COLOR = Color3.new(250/255, 235/255, 0) +local HEALTH_GREEN_COLOR = Color3.new(27/255, 252/255, 107/255) + +local healthbarBack = Instance.new("ImageLabel", BackpackPanel:GetGUI()) +healthbarBack.ImageColor3 = HEALTH_BACKGROUND_COLOR +healthbarBack.BackgroundTransparency = 1 +healthbarBack.ScaleType = Enum.ScaleType.Slice +healthbarBack.SliceCenter = Rect.new(10, 10, 10, 10) +healthbarBack.Name = "HealthbarContainer" +healthbarBack.Image = "rbxasset://textures/ui/Menu/rectBackgroundWhite.png" +local healthbarFront = Instance.new("ImageLabel", healthbarBack) +healthbarFront.ImageColor3 = HEALTH_GREEN_COLOR +healthbarFront.BackgroundTransparency = 1 +healthbarFront.ScaleType = Enum.ScaleType.Slice +healthbarFront.SliceCenter = Rect.new(10, 10, 10, 10) +healthbarFront.Size = UDim2.new(1, 0, 1, 0) +healthbarFront.Position = UDim2.new(0, 0, 0, 0) +healthbarFront.Name = "HealthbarFill" +healthbarFront.Image = "rbxasset://textures/ui/Menu/rectBackgroundWhite.png" + +local playerName = Instance.new("TextLabel", BackpackPanel:GetGUI()) +playerName.Name = "PlayerName" +playerName.BackgroundTransparency = 1 +playerName.TextColor3 = Color3.new(1, 1, 1) +playerName.Text = player.Name +playerName.Font = Enum.Font.SourceSansBold +playerName.FontSize = Enum.FontSize.Size12 +playerName.TextXAlignment = Enum.TextXAlignment.Left +playerName.Size = UDim2.new(1, 0, 0, NAME_SPACE) + + +local healthColorToPosition = { + [Vector3.new(HEALTH_RED_COLOR.r, HEALTH_RED_COLOR.g, HEALTH_RED_COLOR.b)] = 0.1; + [Vector3.new(HEALTH_YELLOW_COLOR.r, HEALTH_YELLOW_COLOR.g, HEALTH_YELLOW_COLOR.b)] = 0.5; + [Vector3.new(HEALTH_GREEN_COLOR.r, HEALTH_GREEN_COLOR.g, HEALTH_GREEN_COLOR.b)] = 0.8; +} +local min = 0.1 +local minColor = HEALTH_RED_COLOR +local max = 0.8 +local maxColor = HEALTH_GREEN_COLOR + +local function HealthbarColorTransferFunction(healthPercent) + if healthPercent < min then + return minColor + elseif healthPercent > max then + return maxColor + end + + -- Shepard's Interpolation + local numeratorSum = Vector3.new(0,0,0) + local denominatorSum = 0 + for colorSampleValue, samplePoint in pairs(healthColorToPosition) do + local distance = healthPercent - samplePoint + if distance == 0 then + -- If we are exactly on an existing sample value then we don't need to interpolate + return Color3.new(colorSampleValue.x, colorSampleValue.y, colorSampleValue.z) + else + local wi = 1 / (distance*distance) + numeratorSum = numeratorSum + wi * colorSampleValue + denominatorSum = denominatorSum + wi + end + end + local result = numeratorSum / denominatorSum + return Color3.new(result.x, result.y, result.z) +end +--- + +local backpackEnabled = true +local healthbarEnabled = true + +local function UpdateLayout() + local width, height = 100, 100 + local borderSize = (ICON_SPACING - ICON_SIZE) / 2 + + local x = borderSize + local y = 0 + for _, tool in ipairs(ToolsList) do + local slot = Tools[tool] + if slot then + slot.icon.Position = UDim2.new(0, x, 0, y) + x = x + ICON_SPACING + end + end + + if #ToolsList == 0 then + width = HEALTHBAR_WIDTH + height = HEALTHBAR_SPACE + NAME_SPACE + BackpackPanel.showCursor = false + else + width = #ToolsList * ICON_SPACING + height = ICON_SIZE + HEALTHBAR_SPACE + NAME_SPACE + BackpackPanel.showCursor = true + end + + BackpackPanel:ResizePixels(width, height) + + playerName.Position = UDim2.new(0, borderSize, 0, 0) + + healthbarBack.Position = UDim2.new(0, borderSize, 0, NAME_SPACE + (HEALTHBAR_SPACE - HEALTHBAR_HEIGHT) / 2) + healthbarBack.Size = UDim2.new(0, HEALTHBAR_WIDTH, 0, HEALTHBAR_HEIGHT) +end + +local function UpdateHealth(humanoid) + local percentHealth = humanoid.Health / humanoid.MaxHealth + if percentHealth ~= percentHealth then + percentHealth = 1 + end + healthbarFront.BackgroundColor3 = HealthbarColorTransferFunction(percentHealth) + healthbarFront.Size = UDim2.new(percentHealth, 0, 1, 0) +end + +local function SetTransparency(transparency) + for i, v in pairs(Tools) do + v.bg.ImageTransparency = transparency + v.image.ImageTransparency = transparency + v.text.TextTransparency = transparency + end + + healthbarBack.ImageTransparency = transparency + healthbarFront.ImageTransparency = transparency +end + +local function OnHotbarEquipPrimary(actionName, state, obj) + if state ~= Enum.UserInputState.Begin then + return + end + for tool, slot in pairs(Tools) do + if slot.hovered then + slot.OnClick() + return + end + end +end + +local function EnableHotbarInput(enable) + if not backpackEnabled then + enable = false + end + if not currentHumanoid then + return + end + if enable then + ContextActionService:BindCoreAction("HotbarEquipPrimary", OnHotbarEquipPrimary, false, Enum.KeyCode.ButtonA, Enum.KeyCode.ButtonR2, Enum.UserInputType.MouseButton1) + else + ContextActionService:UnbindCoreAction("HotbarEquipPrimary") + end +end + +local function AddTool(tool) + if Tools[tool] then + return + end + + local slot = {} + Tools[tool] = slot + table.insert(ToolsList, tool) + + slot.hovered = false + slot.tool = tool + + slot.icon = Instance.new("TextButton", toolsFrame) + slot.icon.Text = "" + slot.icon.Size = UDim2.new(0, ICON_SIZE, 0, ICON_SIZE) + slot.icon.BackgroundColor3 = Color3.new(0, 0, 0) + slot.icon.Selectable = true + slot.icon.BackgroundTransparency = 1 + slotIcons[tool] = slot.icon + + slot.bg = Instance.new("ImageLabel", slot.icon) + slot.bg.Position = UDim2.new(0, -1, 0, -1) + slot.bg.Size = UDim2.new(1, 2, 1, 2) + slot.bg.Image = "rbxasset://textures/ui/Menu/rectBackground.png" + slot.bg.ScaleType = Enum.ScaleType.Slice + slot.bg.SliceCenter = Rect.new(10, 10, 10, 10) + slot.bg.BackgroundTransparency = 1 + + slot.image = Instance.new("ImageLabel", slot.icon) + slot.image.Position = UDim2.new(0, 1, 0, 1) + slot.image.Size = UDim2.new(1, -2, 1, -2) + slot.image.BackgroundTransparency = 1 + slot.image.Selectable = false + + slot.text = Instance.new("TextLabel", slot.icon) + slot.text.Position = UDim2.new(0, 1, 0, 1) + slot.text.Size = UDim2.new(1, -2, 1, -2) + slot.text.BackgroundTransparency = 1 + slot.text.TextColor3 = Color3.new(1, 1, 1) + slot.text.Font = Enum.Font.SourceSans + slot.text.FontSize = Enum.FontSize.Size12 + slot.text.ClipsDescendants = true + slot.text.Selectable = false + + local selectionObject = Util:Create'ImageLabel' + { + Name = 'SelectionObject'; + Size = UDim2.new(1,0,1,0); + BackgroundTransparency = 1; + Image = "rbxasset://textures/ui/Keyboard/key_selection_9slice.png"; + ImageTransparency = 0; + ScaleType = Enum.ScaleType.Slice; + SliceCenter = Rect.new(12,12,52,52); + BorderSizePixel = 0; + } + slot.icon.SelectionImageObject = selectionObject + + local function updateToolData() + slot.image.Image = tool.TextureId + slot.text.Text = tool.TextureId == "" and tool.Name or "" + end + updateToolData() + + slot.OnClick = function() + if not player.Character then return end + local humanoid = player.Character:FindFirstChild("Humanoid") + if not humanoid then return end + + local in_backpack = tool.Parent == player.Backpack + humanoid:UnequipTools() + if in_backpack then + humanoid:EquipTool(tool) + end + end + + slot.icon.MouseButton1Click:connect(slot.OnClick) + slot.OnEnter = function() + slot.hovered = true + end + slot.OnLeave = function() + slot.hovered = false + end +-- slot.icon.MouseEnter:connect(slot.OnEnter) +-- slot.icon.MouseLeave:connect(slot.OnLeave) + + tool.Changed:connect(function(prop) + if prop == "Parent" then + if tool.Parent == player:FindFirstChild("Backpack") then + slot.bg.Size = UDim2.new(0, ICON_SIZE, 0, ICON_SIZE) --temporary hold-over until new backpack design comes along (can't use border with this antialiased frame stand-in) + slot.bg.Position = UDim2.new(0, 0, 0, 0) + elseif tool.Parent == player.Character then + slot.bg.Size = UDim2.new(0, ICON_SIZE + 8, 0, ICON_SIZE + 8) + slot.bg.Position = UDim2.new(0, -4, 0, -4) + end + elseif prop == "TextureId" or prop == "Name" then + updateToolData() + end + end) + + UpdateLayout() +end + +local humanoidChangedEvent = nil +local humanoidAncestryChangedEvent = nil +local function RegisterHumanoid(humanoid) + currentHumanoid = humanoid + if humanoidChangedEvent then + humanoidChangedEvent:disconnect() + humanoidChangedEvent = nil + end + if humanoidAncestryChangedEvent then + humanoidAncestryChangedEvent:disconnect() + humanoidAncestryChangedEvent = nil + end + if humanoid then + humanoidChangedEvent = humanoid.HealthChanged:connect(function() UpdateHealth(humanoid) end) + humanoidAncestryChangedEvent = humanoid.AncestryChanged:connect(function(child, parent) + if child == humanoid and parent ~= player.Character then + RegisterHumanoid(nil) + end + end) + UpdateHealth(humanoid) + end +end + +local function OnChildAdded(child) + if child:IsA("Tool") or child:IsA("HopperBin") then + AddTool(child) + end + if child:IsA("Humanoid") and child.Parent == player.Character then + RegisterHumanoid(child) + end +end + +local function RemoveTool(tool) + if not Tools[tool] then + return + end + Tools[tool].icon:Destroy() + for i, v in ipairs(ToolsList) do + if v == tool then + table.remove(ToolsList, i) + break + end + end + Tools[tool] = nil + slotIcons[tool] = nil + UpdateLayout() +end + +local function OnChildRemoved(child) + if child:IsA("Tool") or child:IsA("HopperBin") then + if Tools[child] then + if child.Parent ~= player:FindFirstChild("Backpack") and child.Parent ~= player.Character then + RemoveTool(child) + end + end + end +end + +local function OnCharacterAdded(character) + local backpack = player:WaitForChild("Backpack") + + for i, v in ipairs(character:GetChildren()) do + if v:IsA("Humanoid") then + RegisterHumanoid(v) + break + end + end + + for tool, v in pairs(Tools) do + RemoveTool(tool) + end + Tools = {} + ToolsList = {} + + character.ChildAdded:connect(OnChildAdded) + character.ChildRemoved:connect(OnChildRemoved) + + for i, v in ipairs(backpack:GetChildren()) do + OnChildAdded(v) + end + + backpack.ChildAdded:connect(OnChildAdded) + backpack.ChildRemoved:connect(OnChildRemoved) +end + +player.CharacterAdded:connect(OnCharacterAdded) +if player.Character then + spawn(function() OnCharacterAdded(player.Character) end) +end + +local function OnHotbarEquip(actionName, state, obj) + if not backpackEnabled then + return + end + local character = player.Character + if not character then + return + end + if not currentHumanoid then + return + end + if state ~= Enum.UserInputState.Begin then + return + end + if #ToolsList == 0 then + return + end + local current = 0 + for i, v in pairs(ToolsList) do + if v.Parent == character then + current = i + end + end + currentHumanoid:UnequipTools() + if obj.KeyCode == Enum.KeyCode.ButtonR1 then + current = current + 1 + if current > #ToolsList then + current = 1 + end + else + current = current - 1 + if current < 1 then + current = #ToolsList + end + end + currentHumanoid:EquipTool(ToolsList[current]) +end + +local function OnCoreGuiChanged(coreGuiType, enabled) + -- Check for enabling/disabling the whole thing + if coreGuiType == Enum.CoreGuiType.Backpack or coreGuiType == Enum.CoreGuiType.All then + backpackEnabled = enabled + UpdateLayout() + if enabled then + ContextActionService:BindCoreAction("HotbarEquip2", OnHotbarEquip, false, Enum.KeyCode.ButtonL1, Enum.KeyCode.ButtonR1) + toolsFrame.Parent = BackpackPanel:GetGUI() + else + ContextActionService:UnbindCoreAction("HotbarEquip2") + toolsFrame.Parent = nil + end + end + + if coreGuiType == Enum.CoreGuiType.Health or coreGuiType == Enum.CoreGuiType.All then + healthbarEnabled = enabled + UpdateLayout() + if enabled then + healthbarBack.Parent = BackpackPanel:GetGUI() + else + healthbarBack.Parent = nil + end + end +end + +local StarterGui = game:GetService("StarterGui") +StarterGui.CoreGuiChangedSignal:connect(OnCoreGuiChanged) +OnCoreGuiChanged(Enum.CoreGuiType.Backpack, StarterGui:GetCoreGuiEnabled(Enum.CoreGuiType.Backpack)) +OnCoreGuiChanged(Enum.CoreGuiType.Backpack, StarterGui:GetCoreGuiEnabled(Enum.CoreGuiType.All)) + +OnCoreGuiChanged(Enum.CoreGuiType.Health, StarterGui:GetCoreGuiEnabled(Enum.CoreGuiType.Health)) +OnCoreGuiChanged(Enum.CoreGuiType.Health, StarterGui:GetCoreGuiEnabled(Enum.CoreGuiType.All)) + +local panelLocalCF = CFrame.new(0, -3.5, 5) * CFrame.Angles(math.rad(20), 0, 0) + +function BackpackPanel:PreUpdate(cameraCF, cameraRenderCF, userHeadCF, lookRay) + --the backpack panel needs to go in front of the user when they look at it. + --if they aren't looking, we should be updating self.localCF + if self.transparency == 1 then + local headForwardCF = Panel3D.GetHeadLookXZ() + local panelOriginCF = CFrame.new(userHeadCF.p) * headForwardCF + self.localCF = panelOriginCF * panelLocalCF + end +end + +function BackpackPanel:OnUpdate() + SetTransparency(self.transparency) + + local hovered, tool = BackpackPanel:FindHoveredGuiElement(slotIcons) + if hovered and tool then + local slot = Tools[tool] + if not slot.hovered then + slot.OnEnter() + end + for i, v in pairs(Tools) do + if v.hovered and v ~= slot then + v.OnLeave() + end + end + end +end + +function BackpackPanel:OnMouseEnter(x, y) + EnableHotbarInput(true) +end +function BackpackPanel:OnMouseLeave(x, y) + EnableHotbarInput(false) +end + +return BackpackScript \ No newline at end of file diff --git a/2016/content/scripts/Modules/Chat.lua b/2016/content/scripts/Modules/Chat.lua new file mode 100644 index 0000000..f715a4f --- /dev/null +++ b/2016/content/scripts/Modules/Chat.lua @@ -0,0 +1,2726 @@ +--[[ + // FileName: Chat.lua + // Written by: SolarCrane + // Description: Code for lua side chat on ROBLOX. +]] + +--[[ CONSTANTS ]] + +-- NOTE: IF YOU WANT TO USE THIS CHAT SCRIPT IN YOUR OWN GAME: +-- 1) COPY THE CONTENTS OF THIS FILE INTO A MODULE +-- 2) CREATE A LOCALSCRIPT AND PARENT IT TO StarterGui +-- 3) IN THE LOCALSCRIPT require() THE CHAT MODULE YOU MADE IN STEP 1 +-- 4) CONFIGURE YOUR PLACE ON THE WEBSITE TO USE BUBBLE-CHAT +-- 5) SET THE FOLLOWING TWO VARIABLES TO TRUE +local FORCE_CHAT_GUI = false +local NON_CORESCRIPT_MODE = false +-- 6) (OPTIONAL) PUT THE FOLLOWING LINE IN A SERVER SCRIPT TO MAKE CHAT PERSIST THROUGH RESPAWNING +-- game:GetService('StarterGui').ResetPlayerGuiOnSpawn = false +--------------------------------- + +local MESSAGES_FADE_OUT_TIME = 30 +local MAX_UDIM_SIZE = 2^15 - 1 + +local PHONE_SCREEN_WIDTH = 640 +local TABLET_SCREEN_WIDTH = 1024 + +local FLOOD_CHECK_MESSAGE_COUNT = 7 +local FLOOD_CHECK_MESSAGE_INTERVAL = 15 -- This is in seconds + +local VR_CHAT_CLICK_DEBOUNCE = 0.25 + +local SCROLLBAR_THICKNESS = 7 +local CHAT_COLORS = +{ + Color3.new(253/255, 41/255, 67/255), -- BrickColor.new("Bright red").Color, + Color3.new(1/255, 162/255, 255/255), -- BrickColor.new("Bright blue").Color, + Color3.new(2/255, 184/255, 87/255), -- BrickColor.new("Earth green").Color, + BrickColor.new("Bright violet").Color, + BrickColor.new("Bright orange").Color, + BrickColor.new("Bright yellow").Color, + BrickColor.new("Light reddish violet").Color, + BrickColor.new("Brick yellow").Color, +} + +local emptySelectionImage = Instance.new("ImageLabel") +emptySelectionImage.ImageTransparency = 1 +emptySelectionImage.BackgroundTransparency = 1 + +--[[ END OF CONSTANTS ]] + +--[[ SERVICES ]] +local RunService = game:GetService('RunService') +local CoreGuiService = game:GetService('CoreGui') +local PlayersService = game:GetService('Players') +local DebrisService = game:GetService('Debris') +local GuiService = game:GetService('GuiService') +local InputService = game:GetService('UserInputService') +local StarterGui = game:GetService('StarterGui') +local ContextActionService = game:GetService('ContextActionService') +--[[ END OF SERVICES ]] + +--[[ Fast Flags ]]-- +local playerDropDownEnabledSuccess, playerDropDownEnabledFlagValue = pcall(function() return settings():GetFFlag("PlayerDropDownEnabled") end) +local IsPlayerDropDownEnabled = playerDropDownEnabledSuccess and playerDropDownEnabledFlagValue + +local getMoveChatSuccess, moveChatActiveValue = pcall(function() return settings():GetFFlag("SetCoreMoveChat") end) +local allowMoveChat = getMoveChatSuccess and moveChatActiveValue + +local getDisableChatBarSuccess, disableChatBarValue = pcall(function() return settings():GetFFlag("SetCoreDisableChatBar") end) +local allowDisableChatBar = getDisableChatBarSuccess and disableChatBarValue + +--[[ SCRIPT VARIABLES ]] + +-- I am not fond of waiting at the top of the script here... +while PlayersService.LocalPlayer == nil do PlayersService.ChildAdded:wait() end +local Player = PlayersService.LocalPlayer +-- GuiRoot will act as the top-node for parenting GUIs +local GuiRoot = Instance.new('Frame') +GuiRoot.Name = 'GuiRoot'; +GuiRoot.Size = UDim2.new(1,0,1,0); +GuiRoot.BackgroundTransparency = 1; + + + +local chatRepositioned = false +local chatBarDisabled = false + +local lastSelectedPlayer = nil +local lastSelectedButton = nil + +local playerDropDownModule = nil +local playerDropDown = nil +local blockingUtility = nil + +local topbarEnabled = true + + + +if not NON_CORESCRIPT_MODE and not InputService.VREnabled then + playerDropDownModule = require(CoreGuiService:WaitForChild('RobloxGui').Modules:WaitForChild("PlayerDropDown")) + playerDropDown = playerDropDownModule:CreatePlayerDropDown() + blockingUtility = playerDropDownModule:CreateBlockingUtility() +end + +--[[ END OF SCRIPT VARIABLES ]] + +local function GetLuaChatFilteringFlag() + local flagSuccess, flagValue = pcall(function() return settings():GetFFlag("LuaChatFiltering") end) + return flagSuccess and flagValue == true +end + +local Util = {} +do + -- Check if we are running on a touch device + function Util.IsTouchDevice() + local touchEnabled = false + pcall(function() touchEnabled = InputService.TouchEnabled end) + return touchEnabled + end + + function Util.IsSmallScreenSize() + return GuiRoot.AbsoluteSize.X <= PHONE_SCREEN_WIDTH + end + + function Util.Create(instanceType) + return function(data) + local obj = Instance.new(instanceType) + for k, v in pairs(data) do + if type(k) == 'number' then + v.Parent = obj + else + obj[k] = v + end + end + return obj + end + end + + function Util.Clamp(low, high, input) + return math.max(low, math.min(high, input)) + end + + function Util.Linear(t, b, c, d) + if t >= d then return b + c end + + return c*t/d + b + end + + function Util.EaseOutQuad(t, b, c, d) + if t >= d then return b + c end + + t = t/d; + return -c * t*(t-2) + b + end + + function Util.EaseInOutQuad(t, b, c, d) + if t >= d then return b + c end + + t = t / (d/2); + if (t < 1) then return c/2*t*t + b end; + t = t - 1; + return -c/2 * (t*(t-2) - 1) + b; + end + + function Util.PropertyTweener(instance, prop, start, final, duration, easingFunc, cbFunc) + local this = {} + this.StartTime = tick() + this.EndTime = this.StartTime + duration + this.Cancelled = false + + local finished = false + local percentComplete = 0 + spawn(function() + local now = tick() + while now < this.EndTime and instance do + if this.Cancelled then + return + end + instance[prop] = easingFunc(now - this.StartTime, start, final - start, duration) + percentComplete = Util.Clamp(0, 1, (now - this.StartTime) / duration) + RunService.RenderStepped:wait() + now = tick() + end + if this.Cancelled == false and instance then + instance[prop] = final + finished = true + percentComplete = 1 + if cbFunc then + cbFunc() + end + end + end) + + function this:GetPercentComplete() + return percentComplete + end + + function this:IsFinished() + return finished + end + + function this:Cancel() + this.Cancelled = true + end + + return this + end + + function Util.Signal() + local sig = {} + + local mSignaler = Instance.new('BindableEvent') + + local mArgData = nil + local mArgDataCount = nil + + function sig:fire(...) + mArgData = {...} + mArgDataCount = select('#', ...) + mSignaler:Fire() + end + + function sig:connect(f) + if not f then error("connect(nil)", 2) end + return mSignaler.Event:connect(function() + f(unpack(mArgData, 1, mArgDataCount)) + end) + end + + function sig:wait() + mSignaler.Event:wait() + assert(mArgData, "Missing arg data, likely due to :TweenSize/Position corrupting threadrefs.") + return unpack(mArgData, 1, mArgDataCount) + end + + return sig + end + + function Util.DisconnectEvent(conn) + if conn then + conn:disconnect() + end + return nil + end + + function Util.SetGUIInsetBounds(x, y) + local success, _ = pcall(function() GuiService:SetGlobalGuiInset(0, x, 0, y) end) + if not success then + pcall(function() GuiService:SetGlobalSizeOffsetPixel(-x, -y) end) -- Legacy GUI-offset function + end + end + + local baseUrl = game:GetService("ContentProvider").BaseUrl:lower() + baseUrl = string.gsub(baseUrl,"/m.","/www.") --mobile site does not work for this stuff! + function Util.GetSecureApiBaseUrl() + local secureApiUrl = baseUrl + secureApiUrl = string.gsub(secureApiUrl,"http://","https://") + secureApiUrl = string.gsub(secureApiUrl,"www","api") + return secureApiUrl + end + + function Util.GetPlayerByName(playerName) + -- O(n), may be faster if I store a reverse hash from the players list; can't trust FindFirstChild in PlayersService because anything can be parented to there. + local lowerName = string.lower(playerName) + for _, player in pairs(PlayersService:GetPlayers()) do + if string.lower(player.Name) == lowerName then + return player + end + end + return nil -- Found no player + end + + local adminCache = {} + function Util.IsPlayerAdminAsync(player) + local userId = player and player.userId + if userId then + if adminCache[userId] == nil then + local isAdmin = false + -- Many things can error is the IsInGroup check + pcall(function() + isAdmin = [1] + end) + adminCache[userId] = isAdmin + end + return adminCache[userId] + end + return false + end + + local function GetNameValue(pName) + local value = 0 + for index = 1, #pName do + local cValue = string.byte(string.sub(pName, index, index)) + local reverseIndex = #pName - index + 1 + if #pName%2 == 1 then + reverseIndex = reverseIndex - 1 + end + if reverseIndex%4 >= 2 then + cValue = -cValue + end + value = value + cValue + end + return value + end + + function Util.ComputeChatColor(pName) + return CHAT_COLORS[(GetNameValue(pName) % #CHAT_COLORS) + 1] + end + + -- This is a memo-izing function + local testLabel = Instance.new('TextLabel') + testLabel.TextWrapped = true; + testLabel.Position = UDim2.new(1,0,1,0) + testLabel.Parent = GuiRoot -- Note: We have to parent it to check TextBounds + -- The TextSizeCache table looks like this Text->Font->sizeBounds->FontSize + local TextSizeCache = {} + function Util.GetStringTextBounds(text, font, fontSize, sizeBounds) + -- If no sizeBounds are specified use some huge number + sizeBounds = sizeBounds or false + if not TextSizeCache[text] then + TextSizeCache[text] = {} + end + if not TextSizeCache[text][font] then + TextSizeCache[text][font] = {} + end + if not TextSizeCache[text][font][sizeBounds] then + TextSizeCache[text][font][sizeBounds] = {} + end + if not TextSizeCache[text][font][sizeBounds][fontSize] then + testLabel.Text = text + testLabel.Font = font + testLabel.FontSize = fontSize + if sizeBounds then + testLabel.TextWrapped = true; + testLabel.Size = sizeBounds + else + testLabel.TextWrapped = false; + end + TextSizeCache[text][font][sizeBounds][fontSize] = testLabel.TextBounds + end + return TextSizeCache[text][font][sizeBounds][fontSize] + end + + local PRINTABLE_CHARS = '[^' .. string.char(32) .. '-' .. string.char(126) .. ']' + local WHITESPACE_CHARS = '(' .. string.rep('%s', 7) .. ')%s+' + function Util.FilterUnprintableCharacters(str) + if not GetLuaChatFilteringFlag() then + return str + end + + local result = str:gsub(PRINTABLE_CHARS, ''); + result = str:gsub(WHITESPACE_CHARS, '%1'); + return result + end +end + +local SelectChatModeEvent = Util.Signal() +local SelectPlayerEvent = Util.Signal() + +local function CreateChatMessage() + local this = {} + this.FadeRoutines = {} + + function this:GetMessageFontSize(settings) + return Util.IsSmallScreenSize() and settings.SmallScreenFontSize or settings.FontSize + end + + function this:OnResize() + -- Nothing! + end + + function this:FadeIn() + local gui = this:GetGui() + if gui then + gui.Visible = true + end + end + + function this:FadeOut() + local gui = this:GetGui() + if gui then + gui.Visible = false + end + end + + function this:GetGui() + return this.Container + end + + function this:Destroy() + if this.Container ~= nil then + this.Container:Destroy() + this.Container = nil + end + if this.FadeRoutines then + for _, routine in pairs(this.FadeRoutines) do + routine:Cancel() + end + this.FadeRoutines = {} + end + end + + return this +end + +local function CreateSystemChatMessage(settings, chattedMessage) + local this = CreateChatMessage() + + this.Settings = settings + this.rawChatString = chattedMessage + + function this:OnResize(containerSize) + if this.Container and this.ChatMessage then + + if InputService.VREnabled then + this.ChatMessage.Position = UDim2.new(0, 4, 0, 0) + this.ChatMessage.Size = UDim2.new(1, 0, 1, 0) + end + + this.Container.Size = UDim2.new(1,0,0,1000) + local textHeight = this.ChatMessage.TextBounds.Y + + local newContainerHeight = textHeight + 5 + this.Container.Size = UDim2.new(1,0,0,newContainerHeight) + return newContainerHeight + end + end + + function this:FadeIn() + local gui = this:GetGui() + if gui then + gui.Visible = true + for _, routine in pairs(this.FadeRoutines) do + routine:Cancel() + end + this.FadeRoutines = {} + local tweenableObjects = { + this.ChatMessage; + } + for _, object in pairs(tweenableObjects) do + object.TextTransparency = 0; + object.TextStrokeTransparency = this.Settings.TextStrokeTransparency; + end + + if this.MessageBackgroundImage then + this.MessageBackgroundImage.Visible = InputService.VREnabled + end + end + end + + function this:FadeOut(instant) + local gui = this:GetGui() + if gui then + if instant then + gui.Visible = false + else + local tweenableObjects = { + this.ChatMessage; + } + for _, object in pairs(tweenableObjects) do + table.insert(this.FadeRoutines, Util.PropertyTweener(object, 'TextTransparency', object.TextTransparency, 1, 1, Util.Linear)) + table.insert(this.FadeRoutines, Util.PropertyTweener(object, 'TextStrokeTransparency', object.TextStrokeTransparency, 1, 0.85, Util.Linear)) + end + end + if this.MessageBackgroundImage then + this.MessageBackgroundImage.Visible = false + end + end + end + + local function CreateMessageGuiElement() + local fontSize = this:GetMessageFontSize(this.Settings) + + local systemMessageDisplayText = this.rawChatString or "" + local systemMessageSize = Util.GetStringTextBounds(systemMessageDisplayText, this.Settings.Font, fontSize, UDim2.new(0, 400, 0, 1000)) + + local container = Util.Create'Frame' + { + Name = 'MessageContainer'; + Position = UDim2.new(0, 0, 0, 0); + ZIndex = 1; + BackgroundColor3 = Color3.new(0, 0, 0); + BackgroundTransparency = 1; + }; + this.MessageBackgroundImage = Util.Create'ImageLabel' + { + Name = 'TextEntryBackground'; + Size = UDim2.new(1,0,1,-2); + Position = UDim2.new(0,0,0,1); + Image = 'rbxasset://textures/ui/Chat/VRChatBackground.png'; + ScaleType = Enum.ScaleType.Slice; + SliceCenter = Rect.new(8,8,56,56); + BackgroundTransparency = 1; + ImageTransparency = 0.3; + BorderSizePixel = 0; + ZIndex = 1; + Visible = InputService.VREnabled; + Parent = container; + } + + local chatMessage = Util.Create'TextLabel' + { + Name = 'SystemChatMessage'; + Position = UDim2.new(0, 0, 0, 0); + Size = UDim2.new(1, 0, 1, 0); + Text = systemMessageDisplayText; + ZIndex = 1; + BackgroundColor3 = Color3.new(0, 0, 0); + BackgroundTransparency = 1; + TextXAlignment = Enum.TextXAlignment.Left; + TextYAlignment = Enum.TextYAlignment.Top; + TextWrapped = true; + TextColor3 = this.Settings.DefaultMessageTextColor; + FontSize = fontSize; + Font = this.Settings.Font; + TextStrokeColor3 = this.Settings.TextStrokeColor; + TextStrokeTransparency = this.Settings.TextStrokeTransparency; + Parent = container; + }; + if InputService.VREnabled then + chatMessage.Position = UDim2.new(0, 4, 0, 0) + chatMessage.Size = UDim2.new(1, 0, 1, 0) + end + + container.Size = UDim2.new(1, 0, 0, systemMessageSize.Y + 1); + this.Container = container + this.ChatMessage = chatMessage + end + + CreateMessageGuiElement() + + return this +end + +--[[ Popup Handling ]]-- +function createPopupFrame(selectedPlayer, selectedButton) + if selectedPlayer and selectedPlayer.Parent == PlayersService then + if lastSelectedButton ~= selectedButton then + if lastSelectedButton ~= nil then + lastSelectedButton.BackgroundTransparency = 1 + lastSelectedButton = nil + end + lastSelectedButton = selectedButton + lastSelectedPlayer = selectedPlayer + selectedButton.BackgroundTransparency = 0.5 + + if IsPlayerDropDownEnabled then + playerDropDown.HidePopupImmediately = true + local PopupFrame = playerDropDown:CreatePopup(selectedPlayer) + PopupFrame.Position = UDim2.new(0, selectedButton.AbsolutePosition.X + selectedButton.AbsoluteSize.X + 2, 0, selectedButton.AbsolutePosition.Y) + PopupFrame.Size = UDim2.new(0, 150, PopupFrame.Size.Y.Scale, PopupFrame.Size.Y.Offset) + PopupFrame.ZIndex = 5 + PopupFrame.Parent = GuiRoot + end + + for _, button in pairs(PopupFrame:GetChildren()) do + button.BackgroundTransparency = 0 + button.ZIndex = 6 + end + else + if IsPlayerDropDownEnabled then + playerDropDown:Hide() + end + lastSelectedPlayer = nil + end + end +end + +function popupHidden() + if lastSelectedButton then + lastSelectedPlayer = nil + lastSelectedButton.BackgroundTransparency = 1 + lastSelectedButton = nil + end +end + +if IsPlayerDropDownEnabled and playerDropDown then + playerDropDown.HiddenSignal:connect(popupHidden) +end + +InputService.InputBegan:connect(function(inputObject, isProcessed) + if isProcessed then return end + local inputType = inputObject.UserInputType + if (inputType == Enum.UserInputType.Touch and inputObject.UserInputState == Enum.UserInputState.Begin) or + inputType == Enum.UserInputType.MouseButton1 then + if lastSelectedButton and IsPlayerDropDownEnabled then + playerDropDown:Hide() + end + end +end) + +--[[ End of popup handling ]]-- + +local function CreatePlayerChatMessage(settings, playerChatType, sendingPlayer, chattedMessage, receivingPlayer) + local this = CreateChatMessage() + + this.Settings = settings + this.PlayerChatType = playerChatType + this.SendingPlayer = sendingPlayer + this.RawMessageContent = chattedMessage + this.ReceivingPlayer = receivingPlayer + this.ReceivedTime = tick() + + this.Neutral = this.SendingPlayer and this.SendingPlayer.Neutral or true + this.TeamColor = this.SendingPlayer and this.SendingPlayer.TeamColor or BrickColor.new("White") + + function this:OnResize(containerSize) + if this.Container and this.ChatMessage then + this.Container.Size = UDim2.new(1,0,0,1000) + local textHeight = this.ChatMessage.TextBounds.Y + local newContainerHeight = textHeight + 5 + this.Container.Size = UDim2.new(1,0,0,newContainerHeight) + return newContainerHeight + end + end + + function this:FormatMessage() + local result = "" + if this.RawMessageContent then + local message = this.RawMessageContent + result = message + end + return result + end + + function this:FormatChatType() + if this.PlayerChatType then + if this.PlayerChatType == Enum.PlayerChatType.All then + --return "[All]" + elseif this.PlayerChatType == Enum.PlayerChatType.Team then + return "[Team]" + elseif this.PlayerChatType == Enum.PlayerChatType.Whisper then + -- nothing! + end + end + end + + function this:FormatPlayerNameText() + local playerName = "" + -- If we are sending a whisper to someone, then we should show their name + if this.PlayerChatType == Enum.PlayerChatType.Whisper and this.SendingPlayer and this.SendingPlayer == Player then + playerName = (this.ReceivingPlayer and this.ReceivingPlayer.Name or "") + else + playerName = (this.SendingPlayer and this.SendingPlayer.Name or "") + end + return "[" .. playerName .. "]:" + end + + function this:FadeIn() + local gui = this:GetGui() + if gui then + gui.Visible = true + for _, routine in pairs(this.FadeRoutines) do + routine:Cancel() + end + this.FadeRoutines = {} + local tweenableObjects = { + this.WhisperToText; + this.WhisperFromText; + this.ChatModeButton; + this.UserNameButton; + this.ChatMessage; + } + for _, object in pairs(tweenableObjects) do + object.TextTransparency = 0; + object.TextStrokeTransparency = this.Settings.TextStrokeTransparency; + object.Active = true + end + if this.UserNameDot then + this.UserNameDot.ImageTransparency = 0 + end + + if this.MessageBackgroundImage then + this.MessageBackgroundImage.Visible = InputService.VREnabled + end + end + end + + function this:FadeOut(instant) + local gui = this:GetGui() + if gui then + if instant then + gui.Visible = false + else + local tweenableObjects = { + this.WhisperToText; + this.WhisperFromText; + this.ChatModeButton; + this.UserNameButton; + this.ChatMessage; + } + for _, object in pairs(tweenableObjects) do + table.insert(this.FadeRoutines, Util.PropertyTweener(object, 'TextTransparency', object.TextTransparency, 1, 1, Util.Linear)) + table.insert(this.FadeRoutines, Util.PropertyTweener(object, 'TextStrokeTransparency', object.TextStrokeTransparency, 1, 0.85, Util.Linear)) + object.Active = false + end + if this.UserNameDot then + table.insert(this.FadeRoutines, Util.PropertyTweener(this.UserNameDot, 'ImageTransparency', this.UserNameDot.ImageTransparency, 1, 1, Util.Linear)) + end + end + if this.MessageBackgroundImage then + this.MessageBackgroundImage.Visible = false + end + end + end + + function this:Destroy() + if this.Container ~= nil then + this.Container:Destroy() + this.Container = nil + end + this.ClickedOnModeConn = Util.DisconnectEvent(this.ClickedOnModeConn) + this.ClickedOnPlayerConn = Util.DisconnectEvent(this.ClickedOnPlayerConn) + this.RightClickedOnPlayerConn = Util.DisconnectEvent(this.RightClickedOnPlayerConn) + end + + local function CreateMessageGuiElement() + local fontSize = this:GetMessageFontSize(this.Settings) + + local toMesasgeDisplayText = "To " + local toMessageSize = Util.GetStringTextBounds(toMesasgeDisplayText, this.Settings.Font, fontSize) + local fromMesasgeDisplayText = "From " + local fromMessageSize = Util.GetStringTextBounds(fromMesasgeDisplayText, this.Settings.Font, fontSize) + local chatTypeDisplayText = this:FormatChatType() + local chatTypeSize = chatTypeDisplayText and Util.GetStringTextBounds(chatTypeDisplayText, this.Settings.Font, fontSize) or Vector2.new(0,0) + local playerNameDisplayText = this:FormatPlayerNameText() + local playerNameSize = Util.GetStringTextBounds(playerNameDisplayText, this.Settings.Font, fontSize) + + local singleSpaceSize = Util.GetStringTextBounds(" ", this.Settings.Font, fontSize) + local numNeededSpaces = math.ceil(playerNameSize.X / singleSpaceSize.X) + 1 + local chatMessageDisplayText = string.rep(" ", numNeededSpaces) .. this:FormatMessage() + local chatMessageSize = Util.GetStringTextBounds(chatMessageDisplayText, this.Settings.Font, fontSize, UDim2.new(0, 400 - 5 - playerNameSize.X, 0, 1000)) + + + local playerColor = this.Settings.DefaultMessageTextColor + if this.SendingPlayer then + if this.PlayerChatType == Enum.PlayerChatType.Whisper then + if this.SendingPlayer == Player and this.ReceivingPlayer then + playerColor = Util.ComputeChatColor(this.ReceivingPlayer.Name) + else + playerColor = Util.ComputeChatColor(this.SendingPlayer.Name) + end + else + if this.SendingPlayer.Neutral then + playerColor = Util.ComputeChatColor(this.SendingPlayer.Name) + else + playerColor = this.SendingPlayer.TeamColor.Color + end + end + end + + local container = Util.Create'Frame' + { + Name = 'MessageContainer'; + Position = UDim2.new(0, 0, 0, 0); + ZIndex = 1; + BackgroundColor3 = Color3.new(0, 0, 0); + BackgroundTransparency = 1; + }; + this.MessageBackgroundImage = Util.Create'ImageLabel' + { + Name = 'TextEntryBackground'; + Size = UDim2.new(1,0,1,-2); + Position = UDim2.new(0,0,0,1); + Image = 'rbxasset://textures/ui/Chat/VRChatBackground.png'; + ScaleType = Enum.ScaleType.Slice; + SliceCenter = Rect.new(8,8,56,56); + BackgroundTransparency = 1; + ImageTransparency = 0.3; + BorderSizePixel = 0; + ZIndex = 1; + Visible = InputService.VREnabled; + Parent = container; + } + + local xOffset = InputService.VREnabled and 4 or 0 + + if this.SendingPlayer and this.SendingPlayer == Player and this.PlayerChatType == Enum.PlayerChatType.Whisper then + local whisperToText = Util.Create'TextLabel' + { + Name = 'WhisperTo'; + Position = UDim2.new(0, 0, 0, 0); + Size = UDim2.new(0, toMessageSize.X, 0, toMessageSize.Y); + Text = toMesasgeDisplayText; + ZIndex = 1; + BackgroundColor3 = Color3.new(0, 0, 0); + BackgroundTransparency = 1; + TextXAlignment = Enum.TextXAlignment.Left; + TextYAlignment = Enum.TextYAlignment.Top; + TextWrapped = true; + TextColor3 = this.Settings.DefaultMessageTextColor; + FontSize = fontSize; + Font = this.Settings.Font; + TextStrokeColor3 = this.Settings.TextStrokeColor; + TextStrokeTransparency = this.Settings.TextStrokeTransparency; + Parent = container; + }; + xOffset = xOffset + toMessageSize.X + this.WhisperToText = whisperToText + elseif this.SendingPlayer and this.SendingPlayer ~= Player and this.PlayerChatType == Enum.PlayerChatType.Whisper then + local whisperFromText = Util.Create'TextLabel' + { + Name = 'WhisperFromText'; + Position = UDim2.new(0, 0, 0, 0); + Size = UDim2.new(0, fromMessageSize.X, 0, fromMessageSize.Y); + Text = fromMesasgeDisplayText; + ZIndex = 1; + BackgroundColor3 = Color3.new(0, 0, 0); + BackgroundTransparency = 1; + TextXAlignment = Enum.TextXAlignment.Left; + TextYAlignment = Enum.TextYAlignment.Top; + TextWrapped = true; + TextColor3 = this.Settings.DefaultMessageTextColor; + FontSize = fontSize; + Font = this.Settings.Font; + TextStrokeColor3 = this.Settings.TextStrokeColor; + TextStrokeTransparency = this.Settings.TextStrokeTransparency; + Parent = container; + }; + xOffset = xOffset + fromMessageSize.X + this.WhisperFromText = whisperFromText + end + if chatTypeDisplayText then + local chatModeButton = Util.Create(Util.IsTouchDevice() and 'TextLabel' or 'TextButton') + { + Name = 'ChatMode'; + BackgroundTransparency = 1; + ZIndex = 2; + Text = chatTypeDisplayText; + TextColor3 = this.Settings.DefaultMessageTextColor; + Position = UDim2.new(0, xOffset, 0, 0); + TextXAlignment = Enum.TextXAlignment.Left; + TextYAlignment = Enum.TextYAlignment.Top; + FontSize = fontSize; + Font = this.Settings.Font; + Size = UDim2.new(0, chatTypeSize.X, 0, chatTypeSize.Y); + TextStrokeColor3 = this.Settings.TextStrokeColor; + TextStrokeTransparency = this.Settings.TextStrokeTransparency; + Parent = container + } + if chatModeButton:IsA('TextButton') then + this.ClickedOnModeConn = chatModeButton.MouseButton1Click:connect(function() + SelectChatModeEvent:fire(this.PlayerChatType) + end) + end + if this.PlayerChatType == Enum.PlayerChatType.Team then + chatModeButton.TextColor3 = playerColor + end + xOffset = xOffset + chatTypeSize.X + 1 + this.ChatModeButton = chatModeButton + end + local userNameButton = Util.Create(Util.IsTouchDevice() and 'TextLabel' or 'TextButton') + { + Name = 'PlayerName'; + BackgroundTransparency = 1; + BackgroundColor3 = Color3.new(0, 1, 1); + BorderSizePixel = 0; + ZIndex = 2; + Text = playerNameDisplayText; + TextColor3 = playerColor; + Position = UDim2.new(0, xOffset, 0, 0); + TextXAlignment = Enum.TextXAlignment.Left; + TextYAlignment = Enum.TextYAlignment.Top; + FontSize = fontSize; + Font = this.Settings.Font; + Size = UDim2.new(0, playerNameSize.X, 0, playerNameSize.Y); + TextStrokeColor3 = this.Settings.TextStrokeColor; + TextStrokeTransparency = this.Settings.TextStrokeTransparency; + Parent = container + } + if userNameButton:IsA('TextButton') then + this.ClickedOnPlayerConn = userNameButton.MouseButton1Click:connect(function() + local gui = this:GetGui() + if gui and gui.Visible then + if this.PlayerChatType == Enum.PlayerChatType.Whisper and this.SendingPlayer == Player and this.ReceivingPlayer then + SelectPlayerEvent:fire(this.ReceivingPlayer) + else + SelectPlayerEvent:fire(this.SendingPlayer) + end + end + end) + this.RightClickedOnPlayerConn = userNameButton.MouseButton2Click:connect(function() + local gui = this:GetGui() + if gui and gui.Visible then + if IsPlayerDropDownEnabled and playerDropDown then + if this.SendingPlayer and this.SendingPlayer ~= Player then + createPopupFrame(this.SendingPlayer, userNameButton) + end + end + end + end) + end + + local chatMessage = Util.Create'TextLabel' + { + Name = 'ChatMessage'; + Position = UDim2.new(0, xOffset, 0, 0); + Size = UDim2.new(1, -xOffset, 1, 0); + Text = chatMessageDisplayText; + ZIndex = 1; + BackgroundColor3 = Color3.new(0, 0, 0); + BackgroundTransparency = 1; + TextXAlignment = Enum.TextXAlignment.Left; + TextYAlignment = Enum.TextYAlignment.Top; + TextWrapped = true; + TextColor3 = this.Settings.DefaultMessageTextColor; + FontSize = fontSize; + Font = this.Settings.Font; + TextStrokeColor3 = this.Settings.TextStrokeColor; + TextStrokeTransparency = this.Settings.TextStrokeTransparency; + Parent = container; + }; + if InputService.VREnabled then + chatMessage.Size = chatMessage.Size - UDim2.new(0,4,0,0) + end + -- Check if they got moderated and put up a real message instead of Label + if chatMessage.Text == 'Label' and chatMessageDisplayText ~= 'Label' then + chatMessage.Text = string.rep(" ", numNeededSpaces) .. '[Content Deleted]' + end + if this.SendingPlayer and Util.IsPlayerAdminAsync(this.SendingPlayer) then + chatMessage.TextColor3 = this.Settings.AdminTextColor + end + chatMessage.Size = chatMessage.Size + UDim2.new(0, 0, 0, chatMessage.TextBounds.Y); + + container.Size = UDim2.new(1, 0, 0, math.max(chatMessageSize.Y + 1, userNameButton.Size.Y.Offset + 1)); + this.Container = container + this.ChatMessage = chatMessage + this.UserNameButton = userNameButton + end + + CreateMessageGuiElement() + + return this +end + +local function CreateChatBarWidget(settings) + local this = {} + + -- MessageModes: {All, Team, Whisper} + this.MessageMode = 'All' + this.TargetWhisperPlayer = nil + this.Settings = settings + + this.WidgetVisible = false + this.FadedIn = true + + this.ChatBarGainedFocusEvent = Util.Signal() + this.ChatBarLostFocusEvent = Util.Signal() + this.ChatCommandEvent = Util.Signal() -- Signal Signatue: success, actionType, [captures] + this.ChatErrorEvent = Util.Signal() -- Signal Signatue: success, actionType, [captures] + this.ChatBarFloodEvent = Util.Signal() + + this.unfocusedAt = 0 + + local chatCoreGuiEnabled = true + + -- This function while lets string.find work case-insensitively without clobbering the case of the captures + local function nocase(s) + s = string.gsub(s, "%a", function (c) + return string.format("[%s%s]", string.lower(c), + string.upper(c)) + end) + return s + end + + this.ChatMatchingRegex = + { + [function(chatBarText) return string.find(chatBarText, nocase("^/w ") .. "(%w+_?%w+)") end] = "Whisper"; + [function(chatBarText) return string.find(chatBarText, nocase("^/whisper ") .. "(%w+_?%w+)") end] = "Whisper"; + + [function(chatBarText) return string.find(chatBarText, "^%%") end] = "Team"; + [function(chatBarText) return string.find(chatBarText, "^%(TEAM%)") end] = "Team"; + [function(chatBarText) return string.find(chatBarText, nocase("^/t")) end] = "Team"; + [function(chatBarText) return string.find(chatBarText, nocase("^/team")) end] = "Team"; + + [function(chatBarText) return string.find(chatBarText, nocase("^/a")) end] = "All"; + [function(chatBarText) return string.find(chatBarText, nocase("^/all")) end] = "All"; + [function(chatBarText) return string.find(chatBarText, nocase("^/s")) end] = "All"; + [function(chatBarText) return string.find(chatBarText, nocase("^/say")) end] = "All"; + + [function(chatBarText) return string.find(chatBarText, nocase("^/e")) end] = "Emote"; + [function(chatBarText) return string.find(chatBarText, nocase("^/emote")) end] = "Emote"; + + [function(chatBarText) return string.find(chatBarText, "^/%?") end] = "Help"; + [function(chatBarText) return string.find(chatBarText, nocase("^/help")) end] = "Help"; + + [function(chatBarText) return string.find(chatBarText, nocase("^/block ") .. "(%w+_?%w+)") end] = "Block"; + + [function(chatBarText) return string.find(chatBarText, nocase("^/unblock ") .. "(%w+_?%w+)") end] = "Unblock"; + + [function(chatBarText) return string.find(chatBarText, nocase("^/mute ") .. "(%w+_?%w+)") end] = "Mute"; + + [function(chatBarText) return string.find(chatBarText, nocase("^/unmute ") .. "(%w+_?%w+)") end] = "Unmute"; + } + + local ChatModesDict = + { + ['Whisper'] = 'Whisper'; + ['Team'] = 'Team'; + ['All'] = 'All'; + [Enum.PlayerChatType.Whisper] = 'Whisper'; + [Enum.PlayerChatType.Team] = 'Team'; + [Enum.PlayerChatType.All] = 'All'; + } + + local function TearDownEvents() + this.ClickToChatButtonConn = Util.DisconnectEvent(this.ClickToChatButtonConn) + this.ChatBarFocusLostConn = Util.DisconnectEvent(this.ChatBarFocusLostConn) + this.ChatBarLostFocusConn = Util.DisconnectEvent(this.ChatBarLostFocusConn) + this.SelectChatModeConn = Util.DisconnectEvent(this.SelectChatModeConn) + this.SelectPlayerConn = Util.DisconnectEvent(this.SelectPlayerConn) + this.FocusChatBarInputBeganConn = Util.DisconnectEvent(this.FocusChatBarInputBeganConn) + this.InputBeganConn = Util.DisconnectEvent(this.InputBeganConn) + this.ChatBarChangedConn = Util.DisconnectEvent(this.ChatBarChangedConn) + end + + local function HookUpEvents() + TearDownEvents() -- Cleanup old events + + if this.ClickToChatButton then this.ClickToChatButtonConn = this.ClickToChatButton.MouseButton1Click:connect(function() this:FocusChatBar() end) end + + if this.ChatBar then + -- Use a count to check for double backspace out of a chatmode + local count = 0 + if not Util.IsTouchDevice() then + this.FocusChatBarInputBeganConn = Util.DisconnectEvent(this.FocusChatBarInputBeganConn) + this.FocusChatBarInputBeganConn = InputService.InputBegan:connect(function(inputObj) + if inputObj.KeyCode == Enum.KeyCode.Backspace and this:GetChatBarText() == "" then + if count == 0 then + count = count + 1 + else + this:SetMessageMode('All') + end + else + count = 0 + end + end) + end + + this.ChatBarFocusLostConn = this.ChatBar.FocusLost:connect(function(...) + count = 0 + this.unfocusedAt = tick() + this.ChatBarLostFocusEvent:fire(...) + end) + this.ChatBarChangedConn = this.ChatBar.Changed:connect(function(prop) + if prop == "Text" then + this:OnChatBarTextChanged() + elseif prop == 'TextFits' or prop == 'TextBounds' or prop == 'Visible' then + this:OnChatBarBoundsChanged() + end + end) + end + + if this.ChatBarLostFocusEvent then this.ChatBarLostFocusConn = this.ChatBarLostFocusEvent:connect(function(...) this:OnChatBarFocusLost(...) end) end + + this.SelectChatModeConn = SelectChatModeEvent:connect(function(chatType) + this:SetMessageMode(chatType) + this:FocusChatBar() + end) + + this.SelectPlayerConn = SelectPlayerEvent:connect(function(chatPlayer) + this.TargetWhisperPlayer = chatPlayer + this:SetMessageMode("Whisper") + this:FocusChatBar() + end) + + this.InputBeganConn = InputService.InputBegan:connect(function(inputObject) + if inputObject.KeyCode == Enum.KeyCode.Escape then + -- Clear text when they press escape + this:SetChatBarText("") + end + end) + end + + function this:CalculateVisibility() + if this.ChatBarContainer then + local enabled = self.WidgetVisible and chatCoreGuiEnabled and not NON_CORESCRIPT_MODE + if enabled then + HookUpEvents() + else + TearDownEvents() + end + this.ChatBarContainer.Visible = enabled and self.FadedIn and (not chatBarDisabled) + end + end + + function this:ToggleVisibility(visible) + if visible ~= self.WidgetVisible then + self.WidgetVisible = visible + self:CalculateVisibility() + end + if NON_CORESCRIPT_MODE or chatBarDisabled then + this.ChatBarContainer.Visible = false + end + end + + function this:FadeIn() + self.FadedIn = true + self:CalculateVisibility() + end + + function this:FadeOut() + self.FadedIn = false + self:CalculateVisibility() + end + + function this:CoreGuiChanged(coreGuiType, enabled) + if coreGuiType == Enum.CoreGuiType.Chat or coreGuiType == Enum.CoreGuiType.All then + chatCoreGuiEnabled = enabled + self:CalculateVisibility() + end + end + + function this:IsAChatMode(mode) + return ChatModesDict[mode] ~= nil + end + + function this:ProcessChatBarModes(requireWhitespaceAfterChatMode) + local matchedAChatCommand = false + if this.ChatBar then + local chatBarText = this:SanitizeInput(this:GetChatBarText()) + for regexFunc, actionType in pairs(this.ChatMatchingRegex) do + local start, finish, capture = regexFunc(chatBarText) + if start and finish then + -- The following line is for whether or not to try setting the chatmode as-you-type + -- versus when you press enter. + local whitespaceAfterSlashCommand = string.find(string.sub(chatBarText, finish+1, finish+1), "%s") + if (not requireWhitespaceAfterChatMode and finish == #chatBarText) or whitespaceAfterSlashCommand then + if this:IsAChatMode(actionType) then + if actionType == "Whisper" then + local targetPlayer = capture and Util.GetPlayerByName(capture) + if targetPlayer then --and targetPlayer ~= Player then + this.TargetWhisperPlayer = targetPlayer + -- start from two over to eat the space or tab character after the slash command + this:SetChatBarText(string.sub(chatBarText, finish + 2)) + this:SetMessageMode(actionType) + this.ChatCommandEvent:fire(true, actionType, capture) + else + -- This is an indirect way of detecting if they used enter to close submit this chat + if not requireWhitespaceAfterChatMode then + this:SetChatBarText("") + this.ChatCommandEvent:fire(false, actionType, capture) + end + end + else + -- start from two over to eat the space or tab character after the slash command + this:SetChatBarText(string.sub(chatBarText, finish + 2)) + this:SetMessageMode(actionType) + this.ChatCommandEvent:fire(true, actionType, capture) + end + elseif actionType == "Emote" then + -- You can only emote to everyone. + this:SetMessageMode('All') + elseif not requireWhitespaceAfterChatMode then -- Some non-chat related command + if actionType == "Help" then + this:SetChatBarText("") -- Clear the chat so we don't send /? to everyone + end + this.ChatCommandEvent:fire(true, actionType, capture) + end + -- should we break here since we already matched a slash command or keep going? + matchedAChatCommand = true + end + end + end + end + return matchedAChatCommand + end + + local previousText = "" + function this:OnChatBarTextChanged() + if not Util.IsTouchDevice() then + this:ProcessChatBarModes(true) + local originalText = this:GetChatBarText() + local newText = Util.FilterUnprintableCharacters(originalText) + if newText ~= originalText then + previousText = newText + end + + local fixedText = newText + if #newText > this.Settings.MaxCharactersInMessage or originalText ~= newText then + -- This is a hack to deal with the bug that holding down a key for repeated input doesn't trigger the textChanged event + if #newText == #previousText + 1 then + fixedText = string.sub(previousText, 1, this.Settings.MaxCharactersInMessage) + else + fixedText = string.sub(newText, 1, this.Settings.MaxCharactersInMessage) + end + end + this:SetChatBarText(fixedText) + previousText = fixedText + end + end + + function this:OnChatBarBoundsChanged() + if this.ChatBarContainer and this.ChatBar then + local currSize = this.ChatBarContainer.Size + if this.ChatBar.Visible and not this.ChatBar.TextFits then + local textBounds = Util.GetStringTextBounds(this.ChatBar.Text, this.ChatBar.Font, this.ChatBar.FontSize, UDim2.new(0, this.ChatBar.AbsoluteSize.X, 0, 1000)) + if textBounds.Y <= 36 then + this.ChatBarContainer.Size = UDim2.new(currSize.X.Scale, currSize.X.Offset, currSize.Y.Scale, 58) + else --if currSize.Y.Offset <= 54 then + this.ChatBarContainer.Size = UDim2.new(currSize.X.Scale, currSize.X.Offset, currSize.Y.Scale, 76) + end + elseif this.ChatBar.Visible == false or this.ChatBar.TextBounds.Y <= 18 then + if currSize.Y.Offset ~= 40 then + this.ChatBarContainer.Size = UDim2.new(currSize.X.Scale, currSize.X.Offset, currSize.Y.Scale, 40) + end + elseif this.ChatBar.TextBounds.Y <= 36 then + this.ChatBarContainer.Size = UDim2.new(currSize.X.Scale, currSize.X.Offset, currSize.Y.Scale, 58) + end + end + end + + function this:GetChatBarText() + return this.ChatBar and this.ChatBar.Text or "" + end + + function this:SetChatBarText(newText) + if this.ChatBar and newText ~= this.ChatBar.Text then + this.ChatBar.Text = newText + end + end + + function this:GetMessageMode() + return this.MessageMode + end + + function this:SetMessageMode(newMessageMode) + newMessageMode = ChatModesDict[newMessageMode] + + local chatRecipientText = "[" .. (this.TargetWhisperPlayer and this.TargetWhisperPlayer.Name or "") .. "]" + if this.MessageMode ~= newMessageMode or (newMessageMode == 'Whisper' and this.ChatModeText and chatRecipientText ~= this.ChatModeText.Text) then + if this.ChatModeText then + this.MessageMode = newMessageMode + if newMessageMode == 'Whisper' then + local chatRecipientTextBounds = Util.GetStringTextBounds(chatRecipientText, this.ChatModeText.Font, this.ChatModeText.FontSize) + + this.ChatModeText.TextColor3 = this.Settings.WhisperTextColor + this.ChatModeText.Text = chatRecipientText + this.ChatModeText.Size = UDim2.new(0, chatRecipientTextBounds.X, 1, 0) + elseif newMessageMode == 'Team' then + local chatTeamText = '[Team]' + local chatTeamTextBounds = Util.GetStringTextBounds(chatTeamText, this.ChatModeText.Font, this.ChatModeText.FontSize) + + this.ChatModeText.TextColor3 = this.Settings.TeamTextColor + this.ChatModeText.Text = "[Team]" + this.ChatModeText.Size = UDim2.new(0, chatTeamTextBounds.X, 1, 0) + else + this.ChatModeText.Text = "" + this.ChatModeText.Size = UDim2.new(0, 0, 1, 0) + end + if this.ChatBar then + local offset = this.ChatModeText.Size.X.Offset + this.ChatModeText.Position.X.Offset + this.ChatBar.Size = UDim2.new(1, -14 - offset, 1, 0) + this.ChatBar.Position = UDim2.new(0, 7 + offset, 0, 0) + end + end + end + end + + function this:FocusChatBar() + if this.ChatBar and not chatBarDisabled then + this.ChatBar.Visible = true + this.ChatBar:CaptureFocus() + if self.ClickToChatButton then + self.ClickToChatButton.Visible = false + end + if this.ChatModeText then + this.ChatModeText.Visible = true + end + if Util.IsTouchDevice() or InputService.VREnabled then + this:SetMessageMode('All') -- Don't remember message mode on mobile devices or VR + end + -- Update chatbar properties when chatbar is focused + this:OnChatBarBoundsChanged() + if this.ChatBarContainer then + if self.ChatBarInnerBackground then + self.ChatBarInnerBackground.BackgroundTransparency = 0 + end + end + this.ChatBarGainedFocusEvent:fire() + end + end + + function this:RemoveFocus() + if self:IsFocused() then + self.ChatBar:ReleaseFocus() + end + end + + function this:IsFocused() + return self.ChatBar and self.ChatBar == InputService:GetFocusedTextBox() + end + + function this:WasFocused() + return (tick() - this.unfocusedAt) < VR_CHAT_CLICK_DEBOUNCE + end + + function this:SanitizeInput(input) + local sanitizedInput = input + -- Chomp the whitespace at the front and end of the string + -- TODO: maybe only chop off the front space if there are more than a few? + local _, _, capture = string.find(sanitizedInput, "^%s*(.*)%s*$") + sanitizedInput = capture or "" + + return sanitizedInput + end + + + local sentMessageTimeQueue = {} + function this:FloodCheck() + if not GetLuaChatFilteringFlag() then + return false + end + + while sentMessageTimeQueue[1] and tick() - sentMessageTimeQueue[1] > FLOOD_CHECK_MESSAGE_INTERVAL do + table.remove(sentMessageTimeQueue, 1) + end + if #sentMessageTimeQueue > FLOOD_CHECK_MESSAGE_COUNT then + return true + end + return false + end + + function this:OnChatBarFocusLost(enterPressed) + if self.ChatBar then + self.ChatBar.Visible = false + -- TODO: remove this when API for VR to set enterPressed is released + if enterPressed or InputService.VREnabled then + local didMatchSlashCommand = self:ProcessChatBarModes(false) + local cText = self:SanitizeInput(self:GetChatBarText()) + if cText ~= "" then + if self:FloodCheck() then -- and not didMatchSlashCommand then + self.ChatBarFloodEvent:fire() + else + -- For now we will let any slash command go through, NOTE: these will show up in bubble-chat + --if not didMatchSlashCommand and string.sub(cText,1,1) == "/" then + -- self.ChatCommandEvent:fire(false, "Unknown", cText) + --else + local currentMessageMode = self:GetMessageMode() + -- {All, Team, Whisper} + if currentMessageMode == 'Team' then + if Player and Player.Neutral == true then + self.ChatErrorEvent:fire("You're not on a team.") + else + pcall(function() PlayersService:TeamChat(cText) end) + end + elseif currentMessageMode == 'Whisper' then + if self.TargetWhisperPlayer then + if self.TargetWhisperPlayer == Player then + self.ChatErrorEvent:fire("You cannot send a whisper to yourself.") + else + pcall(function() PlayersService:WhisperChat(cText, self.TargetWhisperPlayer) end) + end + else + self.ChatErrorEvent:fire("Invalid whisper target.") + end + elseif currentMessageMode == 'All' then + pcall(function() PlayersService:Chat(cText) end) + else + spawn(function() error("ChatScript: Unknown Message Mode of " .. tostring(currentMessageMode)) end) + end + table.insert(sentMessageTimeQueue, tick()) + --end + self:SetChatBarText("") + end + end + end + end + if self.ClickToChatButton then + self.ClickToChatButton.Visible = true + -- Fade-back in the text so it doesn't abruptly appear + -- Normally I would like to cancel the old tween but it is so short that it doesn't matter + self.ClickToChatButton.TextTransparency = 1 + Util.PropertyTweener(self.ClickToChatButton, 'TextTransparency', 1, 0, 0.25, Util.Linear) + end + if self.ChatModeText then + self.ChatModeText.Visible = false + end + if this.ChatBarContainer then + local currSize = this.ChatBarContainer.Size + this.ChatBarContainer.Size = UDim2.new(currSize.X.Scale, currSize.X.Offset, currSize.Y.Scale, 32) + if self.ChatBarInnerBackground then + self.ChatBarInnerBackground.BackgroundTransparency = 0.5 + end + end + this.ChatBarChangedConn = Util.DisconnectEvent(this.ChatBarChangedConn) + this.FocusChatBarInputBeganConn = Util.DisconnectEvent(this.FocusChatBarInputBeganConn) + end + + local function CreateChatBar() + local chatBarContainer = Util.Create'Frame' + { + Name = 'ChatBarContainer'; + Position = UDim2.new(0, 0, 1, 0); + Size = UDim2.new(1, 0, 0, 20); + ZIndex = 1; + BackgroundColor3 = Color3.new(0, 0, 0); + BackgroundTransparency = 0.25; + BorderSizePixel = 0; + }; + chatBarContainer.BackgroundColor3 = Color3.new(31/255, 31/255, 31/255); + chatBarContainer.BackgroundTransparency = 0.5; + local chatBarInnerBackground = Util.Create'Frame' + { + Name = 'InnerBackground'; + Position = UDim2.new(0, 7, 0, 5); + Size = UDim2.new(1, -14, 1, -10); + ZIndex = 1; + BackgroundColor3 = Color3.new(209/255, 216/255, 221/255); + BackgroundTransparency = 0.5; + BorderSizePixel = 0; + }; + local clickToChatButton = Util.Create'TextButton' + { + Name = 'ClickToChat'; + Position = UDim2.new(0,9,0,0); + Size = UDim2.new(1, -9, 1, 0); + BackgroundTransparency = 1; + AutoButtonColor = false; + ZIndex = 3; + Text = 'To chat click here or press "/" key'; + TextColor3 = this.Settings.GlobalTextColor; + TextXAlignment = Enum.TextXAlignment.Left; + TextYAlignment = Enum.TextYAlignment.Top; + Font = Enum.Font.SourceSansBold; + FontSize = Enum.FontSize.Size18; + Parent = chatBarContainer; + } + clickToChatButton.TextWrapped = true; + clickToChatButton.Position = UDim2.new(0, 7, 0, 0); + clickToChatButton.Size = UDim2.new(1, -14, 1, 0); + clickToChatButton.TextYAlignment = Enum.TextYAlignment.Center; + if Util.IsTouchDevice() then + clickToChatButton.Text = "Tap here to chat" + end + + local chatBar = Util.Create'TextBox' + { + Name = 'ChatBar'; + Position = UDim2.new(0, 9, 0, 0); + Size = UDim2.new(1, -9, 1, 0); + Text = ""; + ZIndex = 1; + BackgroundColor3 = Color3.new(0, 0, 0); + Active = false; + BackgroundTransparency = 1; + TextXAlignment = Enum.TextXAlignment.Left; + TextYAlignment = Enum.TextYAlignment.Top; + TextColor3 = this.Settings.GlobalTextColor; + Font = Enum.Font.SourceSansBold; + FontSize = Enum.FontSize.Size18; + ClearTextOnFocus = false; + Visible = not Util.IsTouchDevice(); + Parent = chatBarContainer; + SelectionImageObject = emptySelectionImage; + } + chatBar.TextWrapped = true; + chatBar.Position = UDim2.new(0, 7, 0, 0); + chatBar.Size = UDim2.new(1, -14, 1, 0); + chatBar.TextYAlignment = Enum.TextYAlignment.Center; + chatBar.Visible = false; + + local chatModeText = Util.Create'TextButton' + { + Name = 'ChatModeText'; + Position = UDim2.new(0, 9, 0, 0); + Size = UDim2.new(1, -9, 1, 0); + AutoButtonColor = false; + BackgroundTransparency = 1; + ZIndex = 2; + Text = ''; + TextColor3 = this.Settings.WhisperTextColor; + TextXAlignment = Enum.TextXAlignment.Left; + TextYAlignment = Enum.TextYAlignment.Top; + Font = Enum.Font.SourceSansBold; + FontSize = Enum.FontSize.Size18; + Parent = chatBarContainer; + } + chatModeText.Position = UDim2.new(0, 7, 0, 0); + chatModeText.Size = UDim2.new(1, -14, 1, 0); + chatModeText.TextYAlignment = Enum.TextYAlignment.Center; + -- Create grey background for text + chatBarInnerBackground.Parent = chatBarContainer; + clickToChatButton.Parent = chatBarInnerBackground; + chatBar.Parent = chatBarInnerBackground; + chatModeText.Parent = chatBarInnerBackground; + + this.ChatBarContainer = chatBarContainer + this.ChatBarInnerBackground = chatBarInnerBackground + this.ClickToChatButton = clickToChatButton + this.ChatBar = chatBar + this.ChatModeText = chatModeText + this.ChatBarContainer.Parent = GuiRoot + + local function RobloxClientScreenSizeChanged(newSize) + if chatBarContainer then + local chatbarVisible = this.ChatBar and this.ChatBar.Visible + local bubbleChatIsOn = not PlayersService.ClassicChat and PlayersService.BubbleChat + -- Phone + if newSize.X <= PHONE_SCREEN_WIDTH then + chatBarContainer.Size = UDim2.new(0.5, 0,0, chatbarVisible and 40 or 32) + if bubbleChatIsOn then + chatBarContainer.Position = UDim2.new(0, 0, 0, 2) + else + chatBarContainer.Position = UDim2.new(0, 0, 0.5, 2) + end + -- Tablet + elseif newSize.X <= TABLET_SCREEN_WIDTH then + chatBarContainer.Size = UDim2.new(0.4, 0,0, chatbarVisible and 40 or 32) + if bubbleChatIsOn then + chatBarContainer.Position = UDim2.new(0, 0, 0, 2) + else + chatBarContainer.Position = UDim2.new(0, 0, 0.3, 2) + end + -- Desktop + else + chatBarContainer.Size = UDim2.new(0.3, 0,0, chatbarVisible and 40 or 32) + if bubbleChatIsOn then + chatBarContainer.Position = UDim2.new(0, 0, 0, 2) + else + chatBarContainer.Position = UDim2.new(0,0,0.25, 2) + end + end + + if Util.IsTouchDevice() or InputService.VREnabled then + -- Hide the chatbar on mobile and in VR so they can't see it. + chatBarContainer.Position = UDim2.new(0,0,1,20); + end + end + end + + GuiRoot.Changed:connect(function(prop) if prop == "AbsoluteSize" and not chatRepositioned then RobloxClientScreenSizeChanged(GuiRoot.AbsoluteSize) end end) + RobloxClientScreenSizeChanged(GuiRoot.AbsoluteSize) + end + + + CreateChatBar() + return this +end + +local function CreateChatWindowWidget(settings) + local this = {} + this.Settings = settings + this.Chats = {} + this.BackgroundVisible = false + this.ChatsVisible = false + this.WidgetVisible = false + this.NewUnreadMessage = false + this.MessageCount = 0 + + this.MessageCountChanged = Util.Signal() + this.FadeInSignal = Util.Signal() + this.FadeOutSignal = Util.Signal() + + this.ChatWindowPagingConn = nil + + local lastMoveTime = tick() + local lastEnterTime = tick() + local lastLeaveTime = tick() + + local lastFadeOutTime = 0 + local lastFadeInTime = 0 + local lastChatActivity = 0 + + local FadeLock = false + + local chatCoreGuiEnabled = true + + local function PointInChatWindow(pt) + local point0 = this.ChatContainer.AbsolutePosition + local point1 = point0 + this.ChatContainer.AbsoluteSize + -- HACK, this is so the "ChatWindow" includes the chatbar box, TODO: refactor the fadeing code to include the chatbar + point1 = point1 + Vector2.new(0, 34) + return point0.X <= pt.X and point1.X >= pt.X and + point0.Y <= pt.Y and point1.Y >= pt.Y + end + + function this:IsHovering() + if this.ChatContainer and this.LastMousePosition and self:CalculateVisibility() then + return PointInChatWindow(this.LastMousePosition) + end + return false + end + + function this:SetFadeLock(lock) + FadeLock = lock + end + + function this:GetFadeLock() + return FadeLock + end + + function this:SetCanvasPosition(newCanvasPosition) + if this.ScrollingFrame then + local maxSize = Vector2.new(math.max(0, this.ScrollingFrame.CanvasSize.X.Offset - this.ScrollingFrame.AbsoluteWindowSize.X), + math.max(0, this.ScrollingFrame.CanvasSize.Y.Offset - this.ScrollingFrame.AbsoluteWindowSize.Y)) + this.ScrollingFrame.CanvasPosition = Vector2.new(Util.Clamp(0, maxSize.X, newCanvasPosition.X), + Util.Clamp(0, maxSize.Y, newCanvasPosition.Y)) + end + end + + function this:ScrollToBottom() + if this.ScrollingFrame then + this:SetCanvasPosition(Vector2.new(this.ScrollingFrame.CanvasPosition.X, this.ScrollingFrame.CanvasSize.Y.Offset)) + end + end + + function this:FadeIn(duration, lockFade) + if not FadeLock then + duration = duration or 0.75 + local backgroundTransparency = InputService.VREnabled and 1 or 0.5 + -- fade in + if this.BackgroundTweener then + this.BackgroundTweener:Cancel() + end + lastFadeInTime = tick() + lastChatActivity = tick() + this.ScrollingFrame.ScrollingEnabled = true + this.ScrollingFrame.ScrollBarThickness = SCROLLBAR_THICKNESS + this.BackgroundTweener = Util.PropertyTweener(this.ChatContainer, 'BackgroundTransparency', this.ChatContainer.BackgroundTransparency, backgroundTransparency, duration, Util.Linear) + this.BackgroundVisible = true + this:FadeInChats() + + this.ChatWindowPagingConn = Util.DisconnectEvent(this.ChatWindowPagingConn) + this.ChatWindowPagingConn = InputService.InputBegan:connect(function(inputObject) + local key = inputObject.KeyCode + if key == Enum.KeyCode.PageUp then + this:SetCanvasPosition(this.ScrollingFrame.CanvasPosition - Vector2.new(0, this.ScrollingFrame.AbsoluteWindowSize.Y)) + elseif key == Enum.KeyCode.PageDown then + this:SetCanvasPosition(this.ScrollingFrame.CanvasPosition + Vector2.new(0, this.ScrollingFrame.AbsoluteWindowSize.Y)) + elseif key == Enum.KeyCode.Home then + this:SetCanvasPosition(Vector2.new(0, 0)) + elseif key == Enum.KeyCode.End then + this:ScrollToBottom() + end + end) + if this.FadeInSignal then + this.FadeInSignal:fire() + end + end + end + + function this:FadeOut(duration, unlockFade) + if not FadeLock then + duration = duration or 0.75 + -- fade out + if this.BackgroundTweener then + this.BackgroundTweener:Cancel() + end + lastFadeOutTime = tick() + lastChatActivity = tick() + this.ScrollingFrame.ScrollingEnabled = false + this.ScrollingFrame.ScrollBarThickness = 0 + this.BackgroundTweener = Util.PropertyTweener(this.ChatContainer, 'BackgroundTransparency', this.ChatContainer.BackgroundTransparency, 1, duration, Util.Linear) + this.BackgroundVisible = false + + this.ChatWindowPagingConn = Util.DisconnectEvent(this.ChatWindowPagingConn) + if this.FadeOutSignal then + this.FadeOutSignal:fire() + end + end + end + + function this:FadeInChats() + if this.ChatsVisible == true then return end + this.ChatsVisible = true + for index, message in pairs(this.Chats) do + message:FadeIn() + end + end + + function this:FadeOutChats() + if InputService.VREnabled then return end + if this.ChatsVisible == false then return end + this.ChatsVisible = false + if IsPlayerDropDownEnabled and playerDropDown then + playerDropDown:Hide() + end + for index, message in pairs(this.Chats) do + local messageGui = message:GetGui() + local instant = false + if messageGui and this.ScrollingFrame then + -- If the chat is not in the visible frame then don't waste cpu cycles fading it out + if messageGui.AbsolutePosition.Y > (this.ScrollingFrame.AbsolutePosition + this.ScrollingFrame.AbsoluteWindowSize).Y or + messageGui.AbsolutePosition.Y + messageGui.AbsoluteSize.Y < this.ScrollingFrame.AbsolutePosition.Y then + instant = true + end + end + message:FadeOut(instant) + end + end + + local ResizeCount = 0 + function this:OnResize() + ResizeCount = ResizeCount + 1 + local currentResizeCount = ResizeCount + local isScrolledDown = this:IsScrolledDown() + -- Unfortunately there is a race condition so we need this wait here. + wait() + if this.ScrollingFrame then + if currentResizeCount ~= ResizeCount then return end + local scrollingFrameAbsoluteSize = this.ScrollingFrame.AbsoluteWindowSize + if scrollingFrameAbsoluteSize ~= nil and scrollingFrameAbsoluteSize.X > 0 and scrollingFrameAbsoluteSize.Y > 0 then + local ySize = 0 + + if this.ScrollingFrame then + for _, message in pairs(this.Chats) do + local newHeight = message:OnResize(scrollingFrameAbsoluteSize) + if newHeight then + local chatMessageElement = message:GetGui() + if chatMessageElement then + local chatMessageElementYSize = chatMessageElement.Size.Y.Offset + chatMessageElement.Position = UDim2.new(0, 0, 0, ySize) + ySize = ySize + chatMessageElementYSize + end + end + end + end + if this.MessageContainer and this.ScrollingFrame then + this.MessageContainer.Size = UDim2.new( + this.MessageContainer.Size.X.Scale, + this.MessageContainer.Size.X.Offset, + 0, + ySize) + this.MessageContainer.Position = UDim2.new(0, 0, 1, -this.MessageContainer.Size.Y.Offset) + this.ScrollingFrame.CanvasSize = UDim2.new(this.ScrollingFrame.CanvasSize.X.Scale, this.ScrollingFrame.CanvasSize.X.Offset, this.ScrollingFrame.CanvasSize.Y.Scale, ySize) + end + end + this:ScrollToBottom() + end + end + + function this:FilterMessage(playerChatType, sendingPlayer, chattedMessage, receivingPlayer) + if chattedMessage and string.sub(chattedMessage, 1, 1) ~= '/' then + return true + end + return false + end + + function this:PushMessageIntoQueue(chatMessage, silently) + table.insert(this.Chats, chatMessage) + + local isScrolledDown = this:IsScrolledDown() + + local chatMessageElement = chatMessage:GetGui() + + chatMessageElement.Parent = this.MessageContainer + local chatMessageHeight = chatMessage:OnResize() or 10 + local ySize = this.MessageContainer.Size.Y.Offset + local chatMessageElementYSize = UDim2.new(0, 0, 0, chatMessageHeight) + + if not silently then + this.MessageCount = this.MessageCount + 1 + end + + chatMessageElement.Position = chatMessageElement.Position + UDim2.new(0, 0, 0, ySize) + this.MessageContainer.Size = this.MessageContainer.Size + chatMessageElementYSize + this.ScrollingFrame.CanvasSize = this.ScrollingFrame.CanvasSize + chatMessageElementYSize + + if this.Settings.MaxWindowChatMessages < #this.Chats then + this:RemoveOldestMessage() + end + if isScrolledDown then + this:ScrollToBottom() + elseif not silently then + -- Raise unread message alert! + this.NewUnreadMessage = true + end + + if silently then + if this.ChatsVisible == false then + chatMessage:FadeOut(true) + end + else + this:FadeInChats() + lastChatActivity = tick() + this.MessageCountChanged:fire(this.MessageCount) + end + + -- NOTE: Sort of hacky, but if we are approaching the max 16 bit size + -- we need to rebase y back to 0 which can be done with the resize function + if ySize > (MAX_UDIM_SIZE / 2) then + self:OnResize() + end + end + + function this:AddSystemChatMessage(chattedMessage, silently) + local chatMessage = CreateSystemChatMessage(this.Settings, chattedMessage) + this:PushMessageIntoQueue(chatMessage, silently) + end + + local function checkEnum(enumItems, value) + for _, enum in pairs(enumItems) do + if enum.Value == value then + return enum + end + end + return nil + end + + -- We only need to copy the top level for the settings table + local function shallowCopy(tableToCopy) + local newTable = {} + for key, value in pairs(tableToCopy) do + newTable[key] = value + end + return newTable + end + + function this:AddDeveloperSystemChatMessage(informationTable) + local settings = shallowCopy(this.Settings) + + if informationTable["Text"] and type(informationTable["Text"]) == "string" then + if informationTable["Color"] and pcall(function() Color3.new(informationTable["Color"].r, informationTable["Color"].g, informationTable["Color"].b) end) then + settings.DefaultMessageTextColor = informationTable["Color"] + end + if informationTable["Font"] then + local success, value = pcall(function() return checkEnum(Enum.Font:GetEnumItems(), informationTable["Font"].Value) end) + if success and value ~= nil then + settings.Font = value + end + end + if informationTable["FontSize"] then + local success, value = pcall(function() return checkEnum(Enum.FontSize:GetEnumItems(), informationTable["FontSize"].Value) end) + if success and value ~= nil then + settings.FontSize = value + end + end + local chatMessage = CreateSystemChatMessage(settings, informationTable["Text"]) + this:PushMessageIntoQueue(chatMessage, false) + end + end + + function this:AddChatMessage(playerChatType, sendingPlayer, chattedMessage, receivingPlayer, silently) + local fixedChattedMessage = Util.FilterUnprintableCharacters(chattedMessage) + if this:FilterMessage(playerChatType, sendingPlayer, fixedChattedMessage, receivingPlayer) then + local chatMessage = CreatePlayerChatMessage(this.Settings, playerChatType, sendingPlayer, fixedChattedMessage, receivingPlayer) + this:PushMessageIntoQueue(chatMessage, silently) + end + end + + function this:RemoveOldestMessage() + local oldestChat = this.Chats[1] + if oldestChat then + return this:RemoveChatMessage(oldestChat) + end + end + + function this:RemoveChatMessage(chatMessage) + if chatMessage then + for index, message in pairs(this.Chats) do + if chatMessage == message then + local guiObj = chatMessage:GetGui() + if guiObj then + local ySize = guiObj.Size.Y.Offset + this.ScrollingFrame.CanvasSize = this.ScrollingFrame.CanvasSize - UDim2.new(0,0,0,ySize) + -- Clamp the canvasposition + this:SetCanvasPosition(this.ScrollingFrame.CanvasPosition) + guiObj.Parent = nil + end + message:Destroy() + return table.remove(this.Chats, index) + end + end + end + end + + function this:IsScrolledDown() + if this.ScrollingFrame then + local yCanvasSize = this.ScrollingFrame.CanvasSize.Y.Offset + local yContainerSize = this.ScrollingFrame.AbsoluteWindowSize.Y + local yScrolledPosition = this.ScrollingFrame.CanvasPosition.Y + -- Check if the messages are at the bottom + return yCanvasSize < yContainerSize or + yCanvasSize - yScrolledPosition <= yContainerSize + 5 -- a little wiggle room + end + return false + end + + function this:GetMessageCount() + return this.MessageCount + end + + function this:CalculateVisibility() + return this.WidgetVisible and ((chatCoreGuiEnabled and PlayersService.ClassicChat) or NON_CORESCRIPT_MODE) + end + + function this:ToggleVisibility(visible) + if visible ~= self.WidgetVisible then + self.WidgetVisible = visible + if this.ChatContainer then + this.ChatContainer.Visible = self:CalculateVisibility() + end + end + if NON_CORESCRIPT_MODE then + this.ChatContainer.Visible = true + end + end + + function this:CoreGuiChanged(coreGuiType, enabled) + if coreGuiType == Enum.CoreGuiType.Chat or coreGuiType == Enum.CoreGuiType.All then + chatCoreGuiEnabled = enabled + if this.ChatContainer then + this.ChatContainer.Visible = self:CalculateVisibility() + end + end + end + + local function CreateChatWindow() + local container = Util.Create'TextButton' + { + Name = 'ChatWindowContainer'; + Size = UDim2.new(0.3, 0, 0.25, 0); + Position = UDim2.new(0, 8, 0, 37); + ZIndex = 1; + BackgroundColor3 = Color3.new(0, 0, 0); + BackgroundTransparency = 1; + BorderSizePixel = 0; + Text = ""; + SelectionImageObject = emptySelectionImage; + }; + container.Position = UDim2.new(0,0,0,37); + container.BackgroundColor3 = Color3.new(31/255, 31/255, 31/255); + local scrollingFrame = Util.Create'ScrollingFrame' + { + Name = 'ChatWindow'; + Size = UDim2.new(1, -4 - 10, 1, -20); + CanvasSize = UDim2.new(1, -4 - 10, 0, 0); + Position = UDim2.new(0, 10, 0, 10); + ZIndex = 1; + BackgroundColor3 = Color3.new(0, 0, 0); + BackgroundTransparency = 1; + BottomImage = "rbxasset://textures/ui/scroll-bottom.png"; + MidImage = "rbxasset://textures/ui/scroll-middle.png"; + TopImage = "rbxasset://textures/ui/scroll-top.png"; + ScrollBarThickness = 0; + BorderSizePixel = 0; + ScrollingEnabled = false; + Parent = container; + }; + local messageContainer = Util.Create'Frame' + { + Name = 'MessageContainer'; + Size = UDim2.new(1, -SCROLLBAR_THICKNESS - 1, 0, 0); + Position = UDim2.new(0, 0, 1, 0); + ZIndex = 1; + BackgroundColor3 = Color3.new(0, 0, 0); + BackgroundTransparency = 1; + Parent = scrollingFrame + }; + + -- This is some trickery we are doing to make the first chat messages appear at the bottom and go towards the top. + local function OnChatWindowResize(prop) + if prop == 'AbsoluteSize' then + messageContainer.Position = UDim2.new(0, 0, 1, -messageContainer.Size.Y.Offset) + end + if prop == 'CanvasPosition' then + if this.ScrollingFrame then + if this:IsScrolledDown() then + this.NewUnreadMessage = false + end + end + end + end + container.Changed:connect(function(prop) if prop == 'AbsoluteSize' then this:OnResize() end end) + + local function RobloxClientScreenSizeChanged(newSize) + if container then + container.Position = UDim2.new(0,0,0,2); + if InputService.VREnabled then + container.Size = UDim2.new(1,0,1,0) + -- Phone + elseif newSize.X <= 640 then + container.Size = UDim2.new(0.5,0,0.5,0) - container.Position + -- Tablet + elseif newSize.X <= 1024 then + container.Size = UDim2.new(0.4,0,0.3,0) - container.Position + -- Desktop + else + container.Size = UDim2.new(0.3,0,0.25,0) - container.Position + end + end + end + + GuiRoot.Changed:connect(function(prop) if prop == "AbsoluteSize" and not chatRepositioned then RobloxClientScreenSizeChanged(GuiRoot.AbsoluteSize) end end) + RobloxClientScreenSizeChanged(GuiRoot.AbsoluteSize) + + messageContainer.Changed:connect(OnChatWindowResize) + scrollingFrame.Changed:connect(OnChatWindowResize) + + this.ChatContainer = container + this.ScrollingFrame = scrollingFrame + this.MessageContainer = messageContainer + this.ChatContainer.Parent = GuiRoot + + + -- It is important to set this to true in NON_CORESCRIPT_MODE because normally the topbar sets + -- the chat window to visible + if NON_CORESCRIPT_MODE then + this:ToggleVisibility(true) + end + + --- BACKGROUND FADING CODE --- + -- This is so we don't accidentally fade out when we are scrolling and mess with the scrollbar. + local dontFadeOutOnMouseLeave = false + + if Util:IsTouchDevice() then + local touchCount = 0 + this.InputBeganConn = InputService.InputBegan:connect(function(inputObject) + if inputObject.UserInputType == Enum.UserInputType.Touch and inputObject.UserInputState == Enum.UserInputState.Begin then + if PointInChatWindow(Vector2.new(inputObject.Position.X, inputObject.Position.Y)) then + touchCount = touchCount + 1 + dontFadeOutOnMouseLeave = true + end + end + end) + + this.InputEndedConn = InputService.InputEnded:connect(function(inputObject) + if inputObject.UserInputType == Enum.UserInputType.Touch and inputObject.UserInputState == Enum.UserInputState.End then + local endedCount = touchCount + wait(2) + if touchCount == endedCount then + dontFadeOutOnMouseLeave = false + end + end + end) + + spawn(function() + local now = tick() + while true do + wait() + now = tick() + if this.BackgroundVisible then + if not dontFadeOutOnMouseLeave then + this:FadeOut(0.25) + end + -- If background is not visible/in-focus + elseif this.ChatsVisible and now > lastChatActivity + MESSAGES_FADE_OUT_TIME then + this:FadeOutChats() + end + end + end) + else + this.LastMousePosition = Vector2.new() + + this.MouseEnterFrameConn = this.ChatContainer.MouseEnter:connect(function() + lastEnterTime = tick() + if this.BackgroundTweener and not this.BackgroundTweener:IsFinished() and not this.BackgroundVisible then + this:FadeIn() + end + end) + + this.MouseMoveConn = InputService.InputChanged:connect(function(inputObject) + if inputObject.UserInputType == Enum.UserInputType.MouseMovement then + lastMoveTime = tick() + this.LastMousePosition = Vector2.new(inputObject.Position.X, inputObject.Position.Y) + if this.BackgroundTweener and this.BackgroundTweener:GetPercentComplete() < 0.5 and this.BackgroundVisible then + if not dontFadeOutOnMouseLeave then + this:FadeOut() + end + end + end + end) + + local clickCount = 0 + this.InputBeganConn = InputService.InputBegan:connect(function(inputObject) + if inputObject.UserInputType == Enum.UserInputType.MouseButton1 and inputObject.UserInputState == Enum.UserInputState.Begin then + if PointInChatWindow(Vector2.new(inputObject.Position.X, inputObject.Position.Y)) then + clickCount = clickCount + 1 + dontFadeOutOnMouseLeave = true + end + end + end) + + this.InputEndedConn = InputService.InputEnded:connect(function(inputObject) + if inputObject.UserInputType == Enum.UserInputType.MouseButton1 and inputObject.UserInputState == Enum.UserInputState.End then + local nowCount = clickCount + wait(1.3) + if nowCount == clickCount then + dontFadeOutOnMouseLeave = false + end + end + end) + + this.MouseLeaveFrameConn = this.ChatContainer.MouseLeave:connect(function() + lastLeaveTime = tick() + if this.BackgroundTweener and not this.BackgroundTweener:IsFinished() and this.BackgroundVisible then + if not dontFadeOutOnMouseLeave then + this:FadeOut() + end + end + end) + + spawn(function() + while true do + wait() + local now = tick() + if this:IsHovering() then + if now - lastMoveTime > 1.3 and not this.BackgroundVisible then + this:FadeIn() + end + else -- not this:IsHovering() + if this.BackgroundVisible then + if not dontFadeOutOnMouseLeave then + this:FadeOut(0.25) + end + -- If background is not visible/in-focus + elseif this.ChatsVisible and now > lastChatActivity + MESSAGES_FADE_OUT_TIME then + this:FadeOutChats() + end + end + end + end) + end + --- END OF BACKGROUND FADING CODE --- + end + + CreateChatWindow() + + return this +end + + +local function CreateChat() + local this = {} + + this.Settings = + { + GlobalTextColor = Color3.new(112/255, 110/255, 106/255); + WhisperTextColor = Color3.new(77/255, 139/255, 255/255); + TeamTextColor = Color3.new(230/255, 207/255, 0); + DefaultMessageTextColor = Color3.new(255/255, 255/255, 243/255); + AdminTextColor = Color3.new(1, 215/255, 0); + TextStrokeTransparency = 0.75; + TextStrokeColor = Color3.new(34/255,34/255,34/255); + Font = Enum.Font.SourceSansBold; + SmallScreenFontSize = Enum.FontSize.Size14; + FontSize = Enum.FontSize.Size18; + MaxWindowChatMessages = 50; + MaxCharactersInMessage = 140; + } + + this.CurrentWindowMessageCountChanged = nil + this.VisibilityStateChanged = Util.Signal() + this.ChatBarFocusChanged = Util.Signal() + this.Visible = false + + function this:CoreGuiChanged(coreGuiType, enabled) + enabled = enabled and (topbarEnabled or InputService.VREnabled) + if coreGuiType == Enum.CoreGuiType.Chat or coreGuiType == Enum.CoreGuiType.All then + if enabled then + pcall(function() + self.SpecialKeyPressedConn = Util.DisconnectEvent(self.SpecialKeyPressedConn) + GuiService:AddSpecialKey(Enum.SpecialKey.ChatHotkey) + self.SpecialKeyPressedConn = GuiService.SpecialKeyPressed:connect(function(key) + if key == Enum.SpecialKey.ChatHotkey then + if self.Visible == false then + self:ToggleVisibility() + end + if self.ChatBarWidget then + self.ChatBarWidget:FocusChatBar() + end + end + end) + end) + else + pcall(function() GuiService:RemoveSpecialKey(Enum.SpecialKey.ChatHotkey) end) + self.SpecialKeyPressedConn = Util.DisconnectEvent(self.SpecialKeyPressedConn) + end + if this.MobileChatButton then + if enabled == true then + this.MobileChatButton.Parent = GuiRoot + -- we need to set it to be visible in-case we missed a lost focus event while chat was turned off. + this.MobileChatButton.Visible = true + else + this.MobileChatButton.Parent = nil + end + end + end + if this.ChatWindowWidget then + this.ChatWindowWidget:CoreGuiChanged(coreGuiType, enabled) + end + if this.ChatBarWidget then + this.ChatBarWidget:CoreGuiChanged(coreGuiType, enabled) + end + end + + -- This event has 4 callback arguments + -- Enum.PlayerChatType.{All|Team|Whisper}, chatPlayer, message, targetPlayer + function this:OnPlayerChatted(playerChatType, sendingPlayer, chattedMessage, receivingPlayer) + if this.ChatWindowWidget then + -- Don't add messages from blocked players, don't show message if is a debug command + local isDebugCommand = false + pcall(function() + if sendingPlayer == PlayersService.LocalPlayer then + isDebugCommand = game:GetService("GuiService"):ShowStatsBasedOnInputString(chattedMessage) + end + end) + if not (this:IsPlayerBlocked(sendingPlayer) or this:IsPlayerMuted(sendingPlayer) or isDebugCommand) then + this.ChatWindowWidget:AddChatMessage(playerChatType, sendingPlayer, chattedMessage, receivingPlayer) + end + end + end + + function this:OnPlayerAdded(newPlayer) + if newPlayer then + spawn(function() Util.IsPlayerAdminAsync(newPlayer) end) + end + if NON_CORESCRIPT_MODE then + newPlayer.Chatted:connect(function(msg, recipient) + this:OnPlayerChatted(Enum.PlayerChatType.All, newPlayer, msg, recipient) + end) + else + this.PlayerChattedConn = Util.DisconnectEvent(this.PlayerChattedConn) + this.PlayerChattedConn = PlayersService.PlayerChatted:connect(function(...) + this:OnPlayerChatted(...) + end) + end + end + + function this:IsPlayerBlocked(player) + if blockingUtility then + return player and blockingUtility:IsPlayerBlockedByUserId(player.userId) + else + return false + end + end + + function this:BlockPlayerAsync(playerToBlock) + if playerToBlock and Player ~= playerToBlock then + local blockUserId = playerToBlock.userId + local playerToBlockName = playerToBlock.Name + if blockUserId > 0 then + if not this:IsPlayerBlocked(playerToBlock) then + if blockingUtility then + blockingUtility:BlockPlayerAsync(playerToBlock) + this.ChatWindowWidget:AddSystemChatMessage(playerToBlockName .. " is now blocked.") + end + else + this.ChatWindowWidget:AddSystemChatMessage(playerToBlockName .. " is already blocked.") + end + else + this.ChatWindowWidget:AddSystemChatMessage("You cannot block guests.") + end + else + this.ChatWindowWidget:AddSystemChatMessage("You cannot block yourself.") + end + end + + function this:UnblockPlayerAsync(playerToUnblock) + if playerToUnblock then + local unblockUserId = playerToUnblock.userId + local playerToUnblockName = playerToUnblock.Name + + if this:IsPlayerBlocked(playerToUnblock) then + if blockingUtility then + this.ChatWindowWidget:AddSystemChatMessage(playerToUnblockName .. " is no longer blocked.") + blockingUtility:UnblockPlayerAsync(playerToUnblock) + end + else + this.ChatWindowWidget:AddSystemChatMessage(playerToUnblockName .. " is not blocked.") + end + end + end + + function this:IsPlayerMuted(player) + if blockingUtility then + return player and blockingUtility:IsPlayerMutedByUserId(player.userId) + else + return false + end + end + + function this:MutePlayer(playerToMute) + if playerToMute and playerToMute ~= Player then + if playerToMute.UserId > 0 then + if not this:IsPlayerMuted(playerToMute) then + if blockingUtility then + blockingUtility:MutePlayer(playerToMute) + this.ChatWindowWidget:AddSystemChatMessage(playerToMute.Name .. " is now muted.") + end + else + this.ChatWindowWidget:AddSystemChatMessage(playerToMute.Name .. " is already muted.") + end + else + this.ChatWindowWidget:AddSystemChatMessage("You cannot mute guests.") + end + else + this.ChatWindowWidget:AddSystemChatMessage("You cannot mute yourself.") + end + end + + function this:UnmutePlayer(playerToUnmute) + if playerToUnmute then + if this:IsPlayerMuted(playerToUnmute) then + if blockingUtility then + blockingUtility:UnmutePlayer(playerToUnmute) + this.ChatWindowWidget:AddSystemChatMessage(playerToUnmute.Name .. " is no longer muted.") + end + else + this.ChatWindowWidget:AddSystemChatMessage(playerToUnmute.Name .. " is not muted.") + end + end + end + + function this:CreateTouchDeviceChatButton() + return Util.Create'ImageButton' + { + Name = 'TouchDeviceChatButton'; + Size = UDim2.new(0, 128, 0, 32); + Position = UDim2.new(0, 88, 0, 0); + BackgroundTransparency = 1.0; + Image = 'http://www.roblox.com/asset/?id=97078724'; + }; + end + + function this:PrintWelcome() + if this.ChatWindowWidget then + if Util.IsTouchDevice() then + this.ChatWindowWidget:AddSystemChatMessage("Please press the '...' icon to chat", true) + end + this.ChatWindowWidget:AddSystemChatMessage("Please chat '/?' for a list of commands", true) + end + end + + local doOnceVRWelcome = false + function this:PrintVRWelcome() + if this.ChatWindowWidget and not doOnceVRWelcome then + if InputService.VREnabled then + this.ChatWindowWidget:AddSystemChatMessage("Press here to chat", true) + doOnceVRWelcome = true + end + end + end + + function this:PrintHelp() + if this.ChatWindowWidget then + this.ChatWindowWidget:AddSystemChatMessage("Help Menu") + this.ChatWindowWidget:AddSystemChatMessage("Chat Commands:") + this.ChatWindowWidget:AddSystemChatMessage("/w [PlayerName] or /whisper [PlayerName] - Whisper Chat") + this.ChatWindowWidget:AddSystemChatMessage("/t or /team - Team Chat") + this.ChatWindowWidget:AddSystemChatMessage("/a or /all - All Chat") + + this.ChatWindowWidget:AddSystemChatMessage("/block [PlayerName] - Block communications from Target Player") + this.ChatWindowWidget:AddSystemChatMessage("/unblock [PlayerName] - Restore communications with Target Player") + this.ChatWindowWidget:AddSystemChatMessage("/mute [PlayerName] - Mute in-game communications from Target Player") + this.ChatWindowWidget:AddSystemChatMessage("/unmute [PlayerName] - Restore in-game communications with Target Player") + end + end + + local focusCount = 0 + function this:CreateGUI() + if FORCE_CHAT_GUI or Player.ChatMode == Enum.ChatMode.TextAndMenu and + game:GetService("UserInputService"):GetPlatform() ~= Enum.Platform.XBoxOne + then + if NON_CORESCRIPT_MODE then + local chatGui = Instance.new("ScreenGui") + chatGui.Name = "RobloxGui" + chatGui.Parent = Player:WaitForChild('PlayerGui') + GuiRoot.Parent = chatGui + end + + -- NOTE: eventually we will make multiple chat window frames + this.ChatWindowWidget = CreateChatWindowWidget(this.Settings) + this.ChatBarWidget = CreateChatBarWidget(this.Settings) + this.CurrentWindowMessageCountChanged = this.ChatWindowWidget.MessageCountChanged + + this.ChatWindowWidget.FadeInSignal:connect(function() + this.ChatBarWidget:FadeIn() + end) + this.ChatWindowWidget.FadeOutSignal:connect(function() + this.ChatBarWidget:FadeOut() + end) + + this.ChatWindowWidget:FadeOut(0) + this.ChatBarWidget.ChatBarGainedFocusEvent:connect(function() + focusCount = focusCount + 1 + this.ChatWindowWidget:FadeIn(0.25) + this.ChatWindowWidget:SetFadeLock(true) + this.ChatBarFocusChanged:fire(true) + end) + this.ChatBarWidget.ChatBarLostFocusEvent:connect(function() + local focusNow = focusCount + if Util:IsTouchDevice() then + delay(2, function() + if focusNow == focusCount then + this.ChatWindowWidget:SetFadeLock(false) + end + end) + else + this.ChatWindowWidget:SetFadeLock(false) + end + this.ChatBarFocusChanged:fire(false) + end) + this.ChatBarWidget.ChatBarFloodEvent:connect(function() + if this.ChatWindowWidget then + this.ChatWindowWidget:AddSystemChatMessage("Wait before sending another message.") + end + end) + + this.ChatBarWidget.ChatErrorEvent:connect(function(msg) + if msg then + this.ChatWindowWidget:AddSystemChatMessage(msg) + end + end) + + this.ChatBarWidget.ChatCommandEvent:connect(function(success, actionType, capture) + if actionType == "Help" then + this:PrintHelp() + elseif actionType == "Block" then + local blockPlayerName = capture and tostring(capture) or "" + local playerToBlock = Util.GetPlayerByName(blockPlayerName) + if playerToBlock then + spawn(function() this:BlockPlayerAsync(playerToBlock) end) + else + this.ChatWindowWidget:AddSystemChatMessage("Cannot block " .. blockPlayerName .. " because they are not in the game.") + end + elseif actionType == "Unblock" then + local unblockPlayerName = capture and tostring(capture) or "" + local playerToBlock = Util.GetPlayerByName(unblockPlayerName) + if playerToBlock then + spawn(function() this:UnblockPlayerAsync(playerToBlock) end) + else + this.ChatWindowWidget:AddSystemChatMessage("Cannot unblock " .. unblockPlayerName .. " because they are not in the game.") + end + elseif actionType == "Mute" then + local mutePlayerName = capture and tostring(capture) or "" + local playerToMute = Util.GetPlayerByName(mutePlayerName) + if playerToMute then + this:MutePlayer(playerToMute) + else + this.ChatWindowWidget:AddSystemChatMessage("Cannot mute " .. mutePlayerName .. " because they are not in the game.") + end + elseif actionType == "Unmute" then + local unmutePlayerName = capture and tostring(capture) or "" + local playerToUnmute = Util.GetPlayerByName(unmutePlayerName) + if playerToUnmute then + this:UnmutePlayer(playerToUnmute) + else + this.ChatWindowWidget:AddSystemChatMessage("Cannot unmute " .. unmutePlayerName .. " because they are not in the game.") + end + elseif actionType == "Whisper" then + if success == false then + local playerName = capture and tostring(capture) or "Unknown" + this.ChatWindowWidget:AddSystemChatMessage("Unable to Send a Whisper to Player: " .. playerName) + end + elseif actionType == "Unknown" then + if success == false then + local commandText = capture and tostring(capture) or "Unknown" + this.ChatWindowWidget:AddSystemChatMessage("Invalid Slash Command: " .. commandText) + end + end + end) + + if not NON_CORESCRIPT_MODE then + local function onVREnabled() + if InputService.VREnabled then + self.Settings.TextStrokeTransparency = 1 + self:PrintVRWelcome() + local Panel3D = require(CoreGuiService:WaitForChild('RobloxGui').Modules.VR.Panel3D) + local panel = Panel3D.Get("Chat") + panel:LinkTo("Keyboard") + panel:SetType(Panel3D.Type.Fixed) + panel:ResizePixels(300, 125) + GuiRoot.Parent = panel:GetGUI() + + if this.ChatWindowWidget and this.ChatWindowWidget.ChatContainer then + this.ChatWindowWidget.ChatContainer.MouseButton1Click:connect(function() + if this.ChatBarWidget then + if this.ChatBarWidget:WasFocused() then + this.ChatBarWidget:RemoveFocus() + else + self:FocusChatBar() + end + end + end) + end + + function panel:CalculateTransparency() + return 0 + end + else + self.Settings.TextStrokeTransparency = 0.75 + GuiRoot.Parent = CoreGuiService:WaitForChild('RobloxGui') + end + end + onVREnabled() + InputService.Changed:connect(function(prop) + if prop == 'VREnabled' then + onVREnabled() + end + end) + end + end + end + + local toggleCount = 0 + local function SetVisbility(newVisibility) + this.Visible = newVisibility + if this.ChatWindowWidget then + this.ChatWindowWidget:ToggleVisibility(this.Visible) + if this.Visible then + toggleCount = toggleCount + 1 + local thisToggle = toggleCount + local thisFocusCount = focusCount + this.ChatWindowWidget:FadeIn() + this.ChatWindowWidget:SetFadeLock(true) + delay(5, function() + if thisToggle == toggleCount and thisFocusCount == focusCount then + this.ChatWindowWidget:SetFadeLock(false) + end + end) + end + end + if this.ChatBarWidget then + this.ChatBarWidget:ToggleVisibility(this.Visible) + if this.Visible then + this.ChatBarWidget:FadeIn() + end + if InputService.VREnabled and not this.Visible then + this.ChatBarWidget:RemoveFocus() + end + end + if IsPlayerDropDownEnabled and playerDropDown then + if not this.Visible then + playerDropDown:Hide() + end + end + if InputService.VREnabled then + local Panel3D = require(CoreGuiService:WaitForChild('RobloxGui').Modules.VR.Panel3D) + local panel = Panel3D.Get("Chat") + if this.Visible then + local headLook = Panel3D.GetHeadLookXZ(true) + panel.localCF = headLook * CFrame.Angles(math.rad(5), 0, 0) * CFrame.new(0, 0, 6.5) + panel:ForceShowUntilLookedAt() + else + panel:SetVisible(this.Visible) + end + end + this.VisibilityStateChanged:fire(this.Visible) + end + + function this:ToggleVisibility() + SetVisbility(not self.Visible) + end + + function this:SetVisible(visible) + SetVisbility(visible) + end + + function this:FocusChatBar() + if self.ChatBarWidget and this.Visible then + self.ChatBarWidget:FocusChatBar() + end + end + + function this:IsFocused(useWasFocused) + if not self.ChatBarWidget then return false end + return self.ChatBarWidget:IsFocused() or (useWasFocused and self.ChatBarWidget:WasFocused()) + end + + function this:GetCurrentWindowMessageCount() + if this.ChatWindowWidget then + return this.ChatWindowWidget:GetMessageCount() + end + return 0 + end + + function this:TopbarEnabledChanged(enabled) + topbarEnabled = enabled + -- Update coregui to reflect new topbar status + self:CoreGuiChanged(Enum.CoreGuiType.Chat, StarterGui:GetCoreGuiEnabled(Enum.CoreGuiType.Chat)) + end + + function this:Initialize() + --[[ Developer Customization API ]]-- + if not NON_CORESCRIPT_MODE then + game:WaitForChild("StarterGui"):RegisterSetCore("ChatMakeSystemMessage", function(informationTable) + if this.ChatWindowWidget then + this.ChatWindowWidget:AddDeveloperSystemChatMessage(informationTable) + end + end) + local function isUDim2Value(value) + local success, value = pcall(function() return UDim2.new(value.X.Scale, value.X.Offset, value.Y.Scale, value.Y.Offset) end) + return success and value or nil + end + + local function isBubbleChatOn() + return not PlayersService.ClassicChat and PlayersService.BubbleChat + end + + if allowMoveChat then + game.StarterGui:RegisterSetCore("ChatWindowPosition", function(value) + if this.ChatWindowWidget and this.ChatBarWidget then + value = isUDim2Value(value) + if value ~= nil and not isBubbleChatOn() then + chatRepositioned = true -- Prevent chat from moving back to the original position on screen resolution change + this.ChatWindowWidget.ChatContainer.Position = value + this.ChatBarWidget.ChatBarContainer.Position = value + UDim2.new(0, 0, this.ChatWindowWidget.ChatContainer.Size.Y.Scale, this.ChatWindowWidget.ChatContainer.Size.Y.Offset + 2) + end + end + end) + + game.StarterGui:RegisterSetCore("ChatWindowSize", function(value) + if this.ChatWindowWidget and this.ChatBarWidget then + value = isUDim2Value(value) + if value ~= nil and not isBubbleChatOn() then + chatRepositioned = true + this.ChatWindowWidget.ChatContainer.Size = value + this.ChatBarWidget.ChatBarContainer.Size = UDim2.new(this.ChatWindowWidget.ChatContainer.Size.X.Scale, this.ChatWindowWidget.ChatContainer.Size.X.Offset, this.ChatBarWidget.ChatBarContainer.Size.Y.Scale, this.ChatBarWidget.ChatBarContainer.Size.Y.Offset) + this.ChatBarWidget.ChatBarContainer.Position = this.ChatWindowWidget.ChatContainer.Position + UDim2.new(0, 0, this.ChatWindowWidget.ChatContainer.Size.Y.Scale, this.ChatWindowWidget.ChatContainer.Size.Y.Offset + 2) + end + end + end) + + else + game.StarterGui:RegisterSetCore("ChatWindowPosition", function() end) + game.StarterGui:RegisterSetCore("ChatWindowSize", function() end) + end + + game.StarterGui:RegisterGetCore("ChatWindowPosition", function() + if this.ChatWindowWidget then + return this.ChatWindowWidget.ChatContainer.Position + else + return nil + end + end) + + game.StarterGui:RegisterGetCore("ChatWindowSize", function() + if this.ChatWindowWidget then + return this.ChatWindowWidget.ChatContainer.Size + else + return nil + end + end) + + if allowDisableChatBar then + game.StarterGui:RegisterSetCore("ChatBarDisabled", function(value) + if this.ChatBarWidget then + if type(value) == "boolean" then + chatBarDisabled = value + if value == true then + this.ChatBarWidget:ToggleVisibility(false) + end + end + end + end) + else + game.StarterGui:RegisterSetCore("ChatBarDisabled", function() end) + end + + game.StarterGui:RegisterGetCore("ChatBarDisabled", function() return chatBarDisabled end) + end + + this:OnPlayerAdded(Player) + -- Upsettingly, it seems everytime a player is added, you have to redo the connection + -- NOTE: PlayerAdded only fires on the server, hence ChildAdded is used here + PlayersService.ChildAdded:connect(function(child) + if child:IsA('Player') then + this:OnPlayerAdded(child) + end + end) + this:CreateGUI() + + + this:CoreGuiChanged(Enum.CoreGuiType.Chat, StarterGui:GetCoreGuiEnabled(Enum.CoreGuiType.Chat)) + this.CoreGuiChangedConn = Util.DisconnectEvent(this.CoreGuiChangedConn) + pcall(function() + this.CoreGuiChangedConn = StarterGui.CoreGuiChangedSignal:connect( + function(coreGuiType,enabled) + this:CoreGuiChanged(coreGuiType, enabled) + end) + end) + + if not NON_CORESCRIPT_MODE then + this:PrintWelcome() + end + + --SetVisbility(true) + end + + return this +end + +local moduleApiTable = {} +-- Main Entry Point +do + local ChatInstance = CreateChat() + ChatInstance:Initialize() + + function moduleApiTable:ToggleVisibility() + ChatInstance:ToggleVisibility() + end + + function moduleApiTable:SetVisible(visible) + ChatInstance:SetVisible(visible) + end + + function moduleApiTable:FocusChatBar() + ChatInstance:FocusChatBar() + end + + function moduleApiTable:GetVisibility() + return ChatInstance.Visible + end + + function moduleApiTable:GetMessageCount() + return ChatInstance:GetCurrentWindowMessageCount() + end + + function moduleApiTable:TopbarEnabledChanged(...) + return ChatInstance:TopbarEnabledChanged(...) + end + + function moduleApiTable:IsFocused(useWasFocused) + return ChatInstance:IsFocused(useWasFocused) + end + + moduleApiTable.ChatBarFocusChanged = ChatInstance.ChatBarFocusChanged + moduleApiTable.VisibilityStateChanged = ChatInstance.VisibilityStateChanged + moduleApiTable.MessagesChanged = ChatInstance.CurrentWindowMessageCountChanged + +end + +return moduleApiTable + diff --git a/2016/content/scripts/Modules/Panel3D.lua b/2016/content/scripts/Modules/Panel3D.lua new file mode 100644 index 0000000..a672056 --- /dev/null +++ b/2016/content/scripts/Modules/Panel3D.lua @@ -0,0 +1,491 @@ +--Panel3D: 3D GUI panels for VR +--written by 0xBAADF00D +local PIXELS_PER_STUD = 64 +local SETTINGS_DISTANCE = 3.5 + +local CURSOR_HIDE_TIME = 2 +local CURSOR_FADE_TIME = 0.125 + +local CoreGui = game:GetService('CoreGui') +local RobloxGui = CoreGui:WaitForChild("RobloxGui") + +local Panel3D = {} + +Panel3D.Panels = { + Lower = 1, + Hamburger = 2, + Settings = 3, + Keyboard = 4, + Chat = 5 +} + +Panel3D.Orientation = { + Horizontal = 1, + Fixed = 2 +} + +Panel3D.Visibility = { + BelowAngleThreshold = 1, + Modal = 2, + Normal = 3 +} + +local panelDefaultVectors = { + [Panel3D.Panels.Lower] = CFrame.Angles(math.rad(-45), 0, 0):vectorToWorldSpace(Vector3.new(0, 0, -5)), + [Panel3D.Panels.Hamburger] = CFrame.Angles(math.rad(-55), 0, 0):vectorToWorldSpace(Vector3.new(0, 0, -5)), + [Panel3D.Panels.Settings] = Vector3.new(0, 0, -SETTINGS_DISTANCE), + [Panel3D.Panels.Keyboard] = CFrame.Angles(math.rad(-22.5), 0, 0):vectorToWorldSpace(Vector3.new(0, 0, -5)), + [Panel3D.Panels.Chat] = CFrame.Angles(math.rad(5), 0, 0):vectorToWorldSpace(Vector3.new(0, 0, -5)) +} +local DEFAULT_PANEL_LOCK_THRESHOLD = math.rad(-25) +local panelTransparencyBias = { --tuned values; raise the opacity value to this power + [Panel3D.Panels.Lower] = 6.5, + [Panel3D.Panels.Hamburger] = 8, + [Panel3D.Panels.Settings] = 0, + [Panel3D.Panels.Keyboard] = 1.5, + [Panel3D.Panels.Chat] = 1.5 +} +local panels = {} + +local headScale = 1 + +local renderStepName = "Panel3D" + +local cursor = Instance.new("ImageLabel") +cursor.Image = "rbxasset://textures/Cursors/Gamepad/Pointer.png" +cursor.Size = UDim2.new(0, 8, 0, 8) +cursor.BackgroundTransparency = 1 +cursor.ZIndex = 10 + +local resetOrientationFlag = false +local currentModalPanel = nil + +local GuiService = game:GetService("GuiService") +local UserInputService = game:GetService("UserInputService") + +local cursorHidden = false +local hasTool = false +local lastMouseMove = tick() + +local function OnCharacterAdded(character) + hasTool = false + for i, v in ipairs(character:GetChildren()) do + if v:IsA("Tool") then + hasTool = true + end + end + character.ChildAdded:connect(function(child) + if child:IsA("Tool") then + hasTool = true + lastMouseMove = tick() --kick the mouse when a tool is equipped + end + end) + character.ChildRemoved:connect(function(child) + if child:IsA("Tool") then + hasTool = false + end + end) +end +spawn(function() + while not game.Players.LocalPlayer do wait() end + game.Players.LocalPlayer.CharacterAdded:connect(OnCharacterAdded) + if game.Players.LocalPlayer.Character then OnCharacterAdded(game.Players.LocalPlayer.Character) end +end) +local function autoHideCursor(hide) + if not UserInputService.VREnabled then + cursorHidden = false + return + end + if hide then + --don't hide if there's a tool in the character + local character = game.Players.LocalPlayer.Character + if character and hasTool then + return + end + cursorHidden = true + UserInputService.OverrideMouseIconBehavior = Enum.OverrideMouseIconBehavior.ForceHide + else + cursorHidden = false + UserInputService.OverrideMouseIconBehavior = Enum.OverrideMouseIconBehavior.None + end +end + +local function isCursorVisible() + --if ForceShow, the cursor is definitely visible at all times + if UserInputService.OverrideMouseIconBehavior == Enum.OverrideMouseIconBehavior.ForceShow then + return true + end + --if ForceHide, the cursor is definitely NOT visible + if UserInputService.OverrideMouseIconBehavior == Enum.OverrideMouseIconBehavior.ForceHide then + return false + end + --Otherwise, we need to check if the developer set MouseIconEnabled=false + if UserInputService.MouseIconEnabled and UserInputService.OverrideMouseIconBehavior == Enum.OverrideMouseIconBehavior.None then + return true + end + return false +end + +UserInputService.InputChanged:connect(function(inputObj, processed) + if inputObj.UserInputType == Enum.UserInputType.MouseMovement then + lastMouseMove = tick() + autoHideCursor(false) + end +end) +game:GetService("RunService").Heartbeat:connect(function() + if isCursorVisible() then + cursorHidden = false + end + if lastMouseMove + CURSOR_HIDE_TIME < tick() and not GuiService.MenuIsOpen and not cursorHidden then + autoHideCursor(true) + end +end) + +local function createPanel() + local panelPart = Instance.new("Part") + panelPart.Transparency = 1 + panelPart.CanCollide = false + panelPart.Anchored = true + panelPart.Archivable = false + panelPart.Size = Vector3.new(1.5, 1.5, 1) + panelPart.Parent = workspace.CurrentCamera + local panelGUI = Instance.new("SurfaceGui", CoreGui) + panelGUI.Name = "GUI" + panelGUI.Adornee = panelPart + panelGUI.ToolPunchThroughDistance = 1000 + panelGUI.Active = true + pcall(function() --todo: remove this when api is live + panelGUI.AlwaysOnTop = true + end) + return panelPart, panelGUI +end + +function Panel3D.Get(panelId) + local panel = panels[panelId] + if not panel then + local panelName + for name, value in pairs(Panel3D.Panels) do + if value == panelId then + panelName = name + break + end + end + if not panelName then + error("Tried to request an invalid 3D panel") + end + + local part, gui = createPanel() + + panel = {} + panel.part = part + panel.part.Name = "GUI"--("%sPanel3D"):format(panelName) + panel.gui = gui + panel.gui.Name = ("%sPanelGUI"):format(panelName) + + panel.vector = panelDefaultVectors[panelId] + panel.horizontalVector = Vector3.new(panel.vector.x, 0, panel.vector.z).unit + panel.pitchAngle = math.asin(panel.vector.unit.y) + panel.verticalRange = math.rad(5) + panel.horizontalRange = math.rad(5) + + panel.transparencyCallbacks = {} + + panel.OnMouseEnter = nil + panel.OnMouseLeave = nil + + panel.pixelScale = 1 + + panel.visible = true + panel.visibilityBehavior = Panel3D.Visibility.BelowAngleThreshold + + panel.orientationMode = Panel3D.Orientation.Horizontal + panel.orientation = nil + + panel.cursorEnabled = true + + panel.width = 1 + panel.height = 1 + + function panel:AddTransparencyCallback(callback) + table.insert(panel.transparencyCallbacks, callback) + end + + function panel:Resize(width, height, pixelsPerStud) + panel.width = width + panel.height = height + + pixelsPerStud = pixelsPerStud or PIXELS_PER_STUD + panel.pixelScale = pixelsPerStud / PIXELS_PER_STUD + panel.part.Size = Vector3.new(panel.width * headScale, panel.height * headScale, 1) + panel.gui.CanvasSize = Vector2.new(pixelsPerStud * panel.width, pixelsPerStud * panel.height) + + local distance = panel.vector.magnitude + panel.verticalRange = math.atan(panel.part.Size.Y / (2 * distance)) * 2 + panel.horizontalRange = math.atan(panel.part.Size.X / (2 * distance)) * 2 + end + + function panel:ResizePixels(width, height) + local widthStuds = width / PIXELS_PER_STUD + local heightStuds = height / PIXELS_PER_STUD + panel:Resize(widthStuds, heightStuds) + end + + function panel:SetModal() + panel.visible = false + panel.visibilityBehavior = Panel3D.Visibility.Modal + + if panel.visible then + currentModalPanel = panel + if panel.orientationMode == Panel3D.Orientation.Fixed then + local userHeadCFrame = UserInputService:GetUserCFrame(Enum.UserCFrame.Head) + panel.orientation = userHeadCFrame * CFrame.new(0, 0, -panel.vector.magnitude) * CFrame.Angles(0, math.pi, 0) + end + end + end + + function panel:SetVisible(visible) + panel.visible = visible + + if visible and panel.visibilityBehavior == Panel3D.Visibility.Modal then + currentModalPanel = panel + if panel.orientationMode == Panel3D.Orientation.Fixed then + local userHeadCFrame = UserInputService:GetUserCFrame(Enum.UserCFrame.Head) + panel.orientation = userHeadCFrame * CFrame.new(0, 0, -panel.vector.magnitude) * CFrame.Angles(0, math.pi, 0) + end + else + if currentModalPanel == panel then + currentModalPanel = nil + end + end + end + + panels[panelId] = panel + end + return panel +end + +function Panel3D.ResetOrientation() + resetOrientationFlag = true +end + +function Panel3D.GetGUI(panel) + local panelGUI = panelGUIs[panel] + if not panelGUI then + local part = Panel3D.GetPart(panel) + panelGUI = panelGUIs[panel] + end + return panelGUI +end + +local zeroVector = Vector3.new(0, 0, 0) +local headXZ = CFrame.new() +local headOffset = Vector3.new() +local currentHoverPanel = nil +local savedMouseBehavior = Enum.MouseBehavior.Default +function Panel3D.OnRenderStep() + if not UserInputService.VREnabled then + return + end + local cameraCFrame = workspace.CurrentCamera.CFrame + local cameraRenderCFrame = workspace.CurrentCamera:GetRenderCFrame() + local userHeadCFrame = UserInputService:GetUserCFrame(Enum.UserCFrame.Head) + + local userHeadLook = userHeadCFrame.lookVector + local userHeadHorizontalVector = Vector3.new(userHeadLook.X, 0, userHeadLook.Z).unit + local userHeadPitch = math.asin(userHeadLook.Y) + + local panelLockThreshold = DEFAULT_PANEL_LOCK_THRESHOLD + + for panelId, panel in pairs(panels) do + if panel.pitchLockThreshold and panel.visible then + panelLockThreshold = math.max(panelLockThreshold, panel.pitchLockThreshold) + end + end + + local isAboveThreshold = false + if userHeadPitch > panelLockThreshold or resetOrientationFlag then + isAboveThreshold = true + headXZ = CFrame.new(zeroVector, userHeadHorizontalVector) + headOffset = userHeadCFrame.p + resetOrientationFlag = false + end + + local panelsOrigin = cameraCFrame * CFrame.new(headOffset) * headXZ + for panelId, panel in pairs(panels) do + if panel.visibilityBehavior == Panel3D.Visibility.BelowAngleThreshold then + panel.visible = not (isAboveThreshold or currentModalPanel) + end + + if not panel.visible then + panel.part.Parent = nil + panel.gui.Adornee = nil + else + panel.part.Parent = workspace.CurrentCamera --TODO: move to new 3D gui space + panel.gui.Adornee = panel.part + + local panelCFrame; + if panel.orientationMode == Panel3D.Orientation.Fixed and panel.orientation then + local pos = panel.orientation.p * headScale + panel.part.CFrame = workspace.CurrentCamera.CFrame * ((panel.orientation - panel.orientation.p) + pos) + panelCFrame = panel.part.CFrame + else + local panelPosition = panelsOrigin:pointToWorldSpace(panel.vector * headScale) + panelCFrame = CFrame.new(panelPosition, panelsOrigin.p) + panel.part.CFrame = panelCFrame + end + + local toPanel = (panelCFrame.p - cameraRenderCFrame.p).unit + + local transparency = panel.visible and 1 - (math.max(0, cameraRenderCFrame.lookVector:Dot(toPanel)) ^ panelTransparencyBias[panelId]) or 1 + for _, callback in pairs(panel.transparencyCallbacks) do + callback(transparency) + end + end + end + + --Render a cursor overlaid onto the panels + local cframe = cameraRenderCFrame + local ray = Ray.new(cframe.p, cframe.lookVector * 999) + local ignoreList = { game.Players.LocalPlayer.Character } + local part, endpoint = workspace:FindPartOnRayWithIgnoreList(ray, ignoreList) + local hitPanel = nil + local hitPanelId = nil + for panelId, panel in pairs(panels) do + if part == panel.part then + hitPanel = panel + hitPanelId = panelId + end + end + if hitPanel then + if not currentHoverPanel then + savedMouseBehavior = UserInputService.MouseBehavior + UserInputService.MouseBehavior = Enum.MouseBehavior.LockCenter + else + if currentHoverPanel ~= hitPanel then + if currentHoverPanel.OnMouseLeave then + currentHoverPanel:OnMouseLeave() + end + end + end + if hitPanel.OnMouseEnter and currentHoverPanel ~= hitPanel then + hitPanel:OnMouseEnter() + end + + currentHoverPanel = hitPanel + + UserInputService.OverrideMouseIconBehavior = Enum.OverrideMouseIconBehavior.ForceHide + if hitPanel.cursorEnabled then + cursor.Parent = hitPanel.gui + else + cursor.Parent = nil + end + + local localEndpoint = part:GetRenderCFrame():pointToObjectSpace(endpoint) + local x = (localEndpoint.X / part.Size.X) + 0.5 + local y = (localEndpoint.Y / part.Size.Y) + 0.5 + x = 1 - x + y = 1 - y + cursor.Size = UDim2.new(0, 8 * hitPanel.pixelScale, 0, 8 * hitPanel.pixelScale) + cursor.Position = UDim2.new(x, -cursor.AbsoluteSize.x * 0.5, y, -cursor.AbsoluteSize.y * 0.5) + + if hitPanel.visible and not modalPanelIsOpen then + hitPanel.part.Parent = workspace.CurrentCamera + for _, callback in pairs(hitPanel.transparencyCallbacks) do + callback(0) + end + end + else + if currentHoverPanel then + UserInputService.MouseBehavior = savedMouseBehavior + + if currentHoverPanel.OnMouseLeave then + currentHoverPanel:OnMouseLeave() + end + end + currentHoverPanel = false + cursor.Parent = nil + end +end + + + +-- RayPlaneIntersection + +-- http://www.siggraph.org/education/materials/HyperGraph/raytrace/rayplane_intersection.htm +local function RayPlaneIntersection(ray, planeNormal, pointOnPlane) + planeNormal = planeNormal.unit + ray = ray.Unit + -- compute Pn (dot) Rd = Vd and check if Vd == 0 then we know ray is parallel to plane + local Vd = planeNormal:Dot(ray.Direction) + + -- could fuzzy equals this a little bit to account for imprecision or very close angles to zero + if Vd == 0 then -- parallel, no intersection + return nil + end + + local V0 = planeNormal:Dot(pointOnPlane - ray.Origin) + local t = V0 / Vd + + if t < 0 then --plane is behind ray origin, and thus there is no intersection + return nil + end + + return ray.Origin + ray.Direction * t +end + +function Panel3D.FindHoveredGuiElement(panel, elements) + local cameraRenderCFrame = workspace.CurrentCamera and workspace.CurrentCamera:GetRenderCFrame() + local panelPart = panel.part + if cameraRenderCFrame and panelPart then + local panelPartSize = panelPart.Size + local panelSurfaceCFrame = panelPart.CFrame + panelPart.CFrame.lookVector * (panelPartSize.Z * 0.5) + local intersectionPt = RayPlaneIntersection(Ray.new(cameraRenderCFrame.p, cameraRenderCFrame.lookVector), panelSurfaceCFrame.lookVector, panelSurfaceCFrame.p) + if intersectionPt then + local localPoint = panelSurfaceCFrame:pointToObjectSpace(intersectionPt) * Vector3.new(-1, 1, 1) + Vector3.new(panelPartSize.X/2, -panelPartSize.Y/2, 0) + local guiPoint = Vector2.new((localPoint.X / panelPartSize.X) * panel.gui.AbsoluteSize.X, (localPoint.Y / panelPartSize.Y) * -panel.gui.AbsoluteSize.Y) + + local x = guiPoint.x + local y = guiPoint.y + for _, item in pairs(elements) do + local minPt = item.AbsolutePosition + local maxPt = item.AbsolutePosition + item.AbsoluteSize + if minPt.X <= x and maxPt.X >= x and minPt.Y <= y and maxPt.Y >= y then + return item + end + end + end + end +end + + + + + +game:GetService("RunService"):BindToRenderStep(renderStepName, Enum.RenderPriority.Last.Value, Panel3D.OnRenderStep) + +local function OnCameraChanged(prop) + if prop == "HeadScale" then + pcall(function() + headScale = workspace.CurrentCamera.HeadScale + end) + for i, v in pairs(panels) do + v:Resize(v.width, v.height, v.pixelScale * PIXELS_PER_STUD) + end + end +end +local cameraChangedConn = nil +workspace.Changed:connect(function(prop) + if prop == "CurrentCamera" then + OnCameraChanged("HeadScale") + if cameraChangedConn then + cameraChangedConn:disconnect() + end + cameraChangedConn = workspace.CurrentCamera.Changed:connect(OnCameraChanged) + end +end) +if workspace.CurrentCamera then + OnCameraChanged("HeadScale") + cameraChangedConn = workspace.CurrentCamera.Changed:connect(OnCameraChanged) +end + +return Panel3D \ No newline at end of file diff --git a/2016/content/scripts/Modules/PlayerDropDown.lua b/2016/content/scripts/Modules/PlayerDropDown.lua new file mode 100644 index 0000000..017a54d --- /dev/null +++ b/2016/content/scripts/Modules/PlayerDropDown.lua @@ -0,0 +1,628 @@ +--[[ + // FileName: PlayerDropDown.lua + // Written by: TheGamer101 + // Description: Code for the player drop down in the PlayerList and Chat +]] +local moduleApiTable = {} + +--[[ Services ]]-- +local CoreGui = game:GetService('CoreGui') +local HttpService = game:GetService('HttpService') +local HttpRbxApiService = game:GetService('HttpRbxApiService') +local PlayersService = game:GetService('Players') + +--[[ Script Variables ]]-- +local LocalPlayer = PlayersService.LocalPlayer + +--[[ Constants ]]-- +local POPUP_ENTRY_SIZE_Y = 24 +local ENTRY_PAD = 2 +local BG_TRANSPARENCY = 0.5 +local BG_COLOR = Color3.new(31/255, 31/255, 31/255) +local TEXT_STROKE_TRANSPARENCY = 0.75 +local TEXT_COLOR = Color3.new(1, 1, 243/255) +local TEXT_STROKE_COLOR = Color3.new(34/255, 34/255, 34/255) +local MAX_FRIEND_COUNT = 200 +local FRIEND_IMAGE = 'http://www.roblox.com/thumbs/avatar.ashx?userId=' + +--[[ Fast Flags ]]-- +local followerSuccess, isFollowersEnabled = pcall(function() return settings():GetFFlag("EnableLuaFollowers") end) +local IsFollowersEnabled = followerSuccess and isFollowersEnabled + +local serverFollowersSuccess, serverFollowersEnabled = pcall(function() return settings():GetFFlag("UserServerFollowers") end) +local IsServerFollowers = serverFollowersSuccess and serverFollowersEnabled + +--[[ Modules ]]-- +local RobloxGui = CoreGui:WaitForChild('RobloxGui') +local reportAbuseMenu = require(RobloxGui.Modules.Settings.Pages.ReportAbuseMenu) + +--[[ Bindables ]]-- +local BinbableFunction_SendNotification = nil +spawn(function() + BinbableFunction_SendNotification = RobloxGui:WaitForChild("SendNotification") +end) + +--[[ Remotes ]]-- +local RemoteEvent_NewFollower = nil + +spawn(function() + local RobloxReplicatedStorage = game:GetService('RobloxReplicatedStorage') + RemoteEvent_NewFollower = RobloxReplicatedStorage:WaitForChild('NewFollower') +end) + +--[[ Utility Functions ]]-- +local function createSignal() + local sig = {} + + local mSignaler = Instance.new('BindableEvent') + + local mArgData = nil + local mArgDataCount = nil + + function sig:fire(...) + mArgData = {...} + mArgDataCount = select('#', ...) + mSignaler:Fire() + end + + function sig:connect(f) + if not f then error("connect(nil)", 2) end + return mSignaler.Event:connect(function() + f(unpack(mArgData, 1, mArgDataCount)) + end) + end + + function sig:wait() + mSignaler.Event:wait() + assert(mArgData, "Missing arg data, likely due to :TweenSize/Position corrupting threadrefs.") + return unpack(mArgData, 1, mArgDataCount) + end + + return sig +end + +--[[ Events ]]-- +local BlockStatusChanged = createSignal() + +--[[ Personal Server Stuff ]]-- +local IsPersonalServer = false +local PersonalServerService = nil +if game.Workspace:FindFirstChild('PSVariable') then + IsPersonalServer = true + PersonalServerService = game:GetService('PersonalServerService') +end +game.Workspace.ChildAdded:connect(function(child) + if child.Name == 'PSVariable' and child:IsA('BoolValue') then + IsPersonalServer = true + PersonalServerService = game:GetService('PersonalServerService') + end +end) + +local PRIVILEGE_LEVEL = { + OWNER = 255, + ADMIN = 240, + MEMBER = 128, + VISITOR = 10, + BANNED = 0, +} + +local function onPrivilegeLevelSelect(player, rank) + while player.PersonalServerRank < rank do + PersonalServerService:Promote(player) + end + while player.PersonalServerRank > rank do + PersonalServerService:Demote(player) + end +end + +--[[ Follower Notifications ]]-- +local function sendNotification(title, text, image, duration, callback) + if BinbableFunction_SendNotification then + BinbableFunction_SendNotification:Invoke(title, text, image, duration, callback) + end +end + +--[[ Friend Functions ]]-- +local function getFriendStatus(selectedPlayer) + if selectedPlayer == LocalPlayer then + return Enum.FriendStatus.NotFriend + else + local success, result = pcall(function() + -- NOTE: Core script only + return LocalPlayer:GetFriendStatus(selectedPlayer) + end) + if success then + return result + else + return Enum.FriendStatus.NotFriend + end + end +end + +-- if userId = nil, then it will get count for local player +local function getFriendCountAsync(userId) + local friendCount = nil + local wasSuccess, result = pcall(function() + local str = 'user/get-friendship-count' + if userId then + str = str..'?userId='..tostring(userId) + end + return HttpRbxApiService:GetAsync(str, true) + end) + if not wasSuccess then + print("getFriendCountAsync() failed because", result) + return nil + end + result = HttpService:JSONDecode(result) + + if result["success"] and result["count"] then + friendCount = result["count"] + end + + return friendCount +end + +-- checks if we can send a friend request. Right now the only way we +-- can't is if one of the players is at the max friend limit +local function canSendFriendRequestAsync(otherPlayer) + local theirFriendCount = getFriendCountAsync(otherPlayer.userId) + local myFriendCount = getFriendCountAsync() + + -- assume max friends if web call fails + if not myFriendCount or not theirFriendCount then + return false + end + if myFriendCount < MAX_FRIEND_COUNT and theirFriendCount < MAX_FRIEND_COUNT then + return true + elseif myFriendCount >= MAX_FRIEND_COUNT then + sendNotification("Cannot send friend request", "You are at the max friends limit.", "", 5, function() end) + return false + elseif theirFriendCount >= MAX_FRIEND_COUNT then + sendNotification("Cannot send friend request", otherPlayer.Name.." is at the max friends limit.", "", 5, function() end) + return false + end +end + +--[[ Follower Functions ]]-- + +-- Returns whether followerUserId is following userId +local function isFollowing(userId, followerUserId) + local apiPath = "user/following-exists?userId=" + local params = userId.."&followerUserId="..followerUserId + local success, result = pcall(function() + return HttpRbxApiService:GetAsync(apiPath..params, true) + end) + if not success then + print("isFollowing() failed because", result) + return false + end + + -- can now parse web response + result = HttpService:JSONDecode(result) + return result["success"] and result["isFollowing"] +end + +--[[ Functions for Blocking users ]]-- +local BlockedList = {} +local MutedList = {} + +local function GetBlockedPlayersAsync() + local userId = LocalPlayer.userId + local apiPath = "userblock/getblockedusers" .. "?" .. "userId=" .. tostring(userId) .. "&" .. "page=" .. "1" + if userId > 0 then + local blockList = nil + local success, msg = pcall(function() + local request = HttpRbxApiService:GetAsync(apiPath) + blockList = request and game:GetService('HttpService'):JSONDecode(request) + end) + if blockList and blockList['success'] == true and blockList['userList'] then + return blockList['userList'] + end + end + return {} +end + +spawn(function() + BlockedList = GetBlockedPlayersAsync() +end) + +local function isBlocked(userId) + if (BlockedList[userId] ~= nil and BlockedList[userId] == true) then + return true + end + return false +end + +local function isMuted(userId) + if (MutedList[userId] ~= nil and MutedList[userId] == true) then + return true + end + return false +end + +local function BlockPlayerAsync(playerToBlock) + if playerToBlock and LocalPlayer ~= playerToBlock then + local blockUserId = playerToBlock.UserId + if blockUserId > 0 then + if not isBlocked(blockUserId) then + BlockedList[blockUserId] = true + BlockStatusChanged:fire(blockUserId, true) + pcall(function() + local success = PlayersService:BlockUser(LocalPlayer.userId, blockUserId) + end) + end + end + end +end + +local function UnblockPlayerAsync(playerToUnblock) + if playerToUnblock then + local unblockUserId = playerToUnblock.userId + + if isBlocked(unblockUserId) then + BlockedList[unblockUserId] = nil + BlockStatusChanged:fire(unblockUserId, false) + pcall(function() + local success = PlayersService:UnblockUser(LocalPlayer.userId, unblockUserId) + end) + end + end +end + +local function MutePlayer(playerToMute) + if playerToMute and LocalPlayer ~= playerToMute then + local muteUserId = playerToMute.UserId + if muteUserId > 0 then + if not isMuted(muteUserId) then + MutedList[muteUserId] = true + end + end + end +end + +local function UnmutePlayer(playerToUnmute) + if playerToUnmute then + local unmuteUserId = playerToUnmute.UserId + MutedList[unmuteUserId] = nil + end +end + +--[[ Function to create DropDown class ]]-- +function createPlayerDropDown() + local playerDropDown = {} + playerDropDown.Player = nil + playerDropDown.PopupFrame = nil + playerDropDown.HidePopupImmediately = false + playerDropDown.PopupFrameOffScreenPosition = nil -- if this is set the popup frame tweens to a different offscreen position than the default + + playerDropDown.HiddenSignal = createSignal() + + --[[ Functions for when options in the dropdown are pressed ]]-- + local function onFriendButtonPressed() + if playerDropDown.Player then + local status = getFriendStatus(playerDropDown.Player) + if status == Enum.FriendStatus.Friend then + LocalPlayer:RevokeFriendship(playerDropDown.Player) + elseif status == Enum.FriendStatus.Unknown or status == Enum.FriendStatus.NotFriend then + -- cache and spawn + local cachedLastSelectedPlayer = playerDropDown.Player + spawn(function() + -- check for max friends before letting them send the request + if canSendFriendRequestAsync(cachedLastSelectedPlayer) then -- Yields + if cachedLastSelectedPlayer and cachedLastSelectedPlayer.Parent == PlayersService then + LocalPlayer:RequestFriendship(cachedLastSelectedPlayer) + end + end + end) + elseif status == Enum.FriendStatus.FriendRequestSent then + LocalPlayer:RevokeFriendship(playerDropDown.Player) + elseif status == Enum.FriendStatus.FriendRequestReceived then + LocalPlayer:RequestFriendship(playerDropDown.Player) + end + + playerDropDown:Hide() + end + end + + local function onDeclineFriendButonPressed() + if playerDropDown.Player then + LocalPlayer:RevokeFriendship(playerDropDown.Player) + playerDropDown:Hide() + end + end + + -- Client unfollows followedUserId + local function onUnfollowButtonPressed() + if not playerDropDown.Player then return end + -- + local apiPath = "user/unfollow" + local params = "followedUserId="..tostring(playerDropDown.Player.userId) + local success, result = pcall(function() + return HttpRbxApiService:PostAsync(apiPath, params, true, Enum.ThrottlingPriority.Default, Enum.HttpContentType.ApplicationUrlEncoded) + end) + if not success then + print("unfollowPlayer() failed because", result) + playerDropDown:Hide() + return + end + + result = HttpService:JSONDecode(result) + if result["success"] then + if RemoteEvent_NewFollower then + RemoteEvent_NewFollower:FireServer(playerDropDown.Player, false) + end + moduleApiTable.FollowerStatusChanged:fire() + end + + playerDropDown:Hide() + -- no need to send notification when someone unfollows + end + + local function onBlockButtonPressed() + if playerDropDown.Player then + local cachedPlayer = playerDropDown.Player + spawn(function() + BlockPlayerAsync(cachedPlayer) + end) + playerDropDown:Hide() + end + end + + local function onUnblockButtonPressed() + if playerDropDown.Player then + local cachedPlayer = playerDropDown.Player + spawn(function() + UnblockPlayerAsync(cachedPlayer) + end) + playerDropDown:Hide() + end + end + + local function onReportButtonPressed() + if playerDropDown.Player then + reportAbuseMenu:ReportPlayer(playerDropDown.Player) + playerDropDown:Hide() + end + end + + -- Client follows followedUserId + local function onFollowButtonPressed() + if not playerDropDown.Player then return end + -- + local followedUserId = tostring(playerDropDown.Player.userId) + local apiPath = "user/follow" + local params = "followedUserId="..followedUserId + local success, result = pcall(function() + return HttpRbxApiService:PostAsync(apiPath, params, true, Enum.ThrottlingPriority.Default, Enum.HttpContentType.ApplicationUrlEncoded) + end) + if not success then + print("followPlayer() failed because", result) + playerDropDown:Hide() + return + end + + result = HttpService:JSONDecode(result) + if result["success"] then + sendNotification("You are", "now following "..playerDropDown.Player.Name, FRIEND_IMAGE..followedUserId.."&x=48&y=48", 5, function() end) + if RemoteEvent_NewFollower then + RemoteEvent_NewFollower:FireServer(playerDropDown.Player, true) + end + moduleApiTable.FollowerStatusChanged:fire() + end + + playerDropDown:Hide() + end + + --[[ GUI Creation Functions ]]-- + local function createPersonalServerDialog(buttons, selectedPlayer) + local showPersonalServerRanks = IsPersonalServer and LocalPlayer.PersonalServerRank >= PRIVILEGE_LEVEL.ADMIN and LocalPlayer.PersonalServerRank > selectedPlayer.PersonalServerRank + if showPersonalServerRanks then + table.insert(buttons, { + Name = "BanButton", + Text = "Ban", + OnPress = function() + playerDropDown:Hide() + onPrivilegeLevelSelect(selectedPlayer, PRIVILEGE_LEVEL.BANNED) + end, + }) + table.insert(buttons, { + Name = "VistorButton", + Text = "Visitor", + OnPress = function() + onPrivilegeLevelSelect(selectedPlayer, PRIVILEGE_LEVEL.VISITOR) + end, + }) + table.insert(buttons, { + Name = "MemberButton", + Text = "Member", + OnPress = function() + onPrivilegeLevelSelect(selectedPlayer, PRIVILEGE_LEVEL.MEMBER) + end, + }) + table.insert(buttons, { + Name = "AdminButton", + Text = "Admin", + OnPress = function() + onPrivilegeLevelSelect(selectedPlayer, PRIVILEGE_LEVEL.ADMIN) + end, + }) + end + end + + local function createPopupFrame(buttons) + local frame = Instance.new('Frame') + frame.Name = "PopupFrame" + frame.Size = UDim2.new(1, 0, 0, (POPUP_ENTRY_SIZE_Y * #buttons) + (#buttons - ENTRY_PAD)) + frame.Position = UDim2.new(1, 1, 0, 0) + frame.BackgroundTransparency = 1 + + for i,button in ipairs(buttons) do + local btn = Instance.new('TextButton') + btn.Name = button.Name + btn.Size = UDim2.new(1, 0, 0, POPUP_ENTRY_SIZE_Y) + btn.Position = UDim2.new(0, 0, 0, POPUP_ENTRY_SIZE_Y * (i - 1) + ((i - 1) * ENTRY_PAD)) + btn.BackgroundTransparency = BG_TRANSPARENCY + btn.BackgroundColor3 = BG_COLOR + btn.BorderSizePixel = 0 + btn.Text = button.Text + btn.Font = Enum.Font.SourceSans + btn.FontSize = Enum.FontSize.Size14 + btn.TextColor3 = TEXT_COLOR + btn.TextStrokeTransparency = TEXT_STROKE_TRANSPARENCY + btn.TextStrokeColor3 = TEXT_STROKE_COLOR + btn.AutoButtonColor = true + btn.Parent = frame + + btn.MouseButton1Click:connect(button.OnPress) + end + + return frame + end + + --[[ PlayerDropDown Functions ]]-- + function playerDropDown:Hide() + if playerDropDown.PopupFrame then + local offscreenPosition = (playerDropDown.PopupFrameOffScreenPosition ~= nil and playerDropDown.PopupFrameOffScreenPosition or UDim2.new(1, 1, 0, playerDropDown.PopupFrame.Position.Y.Offset)) + if not playerDropDown.HidePopupImmediately then + playerDropDown.PopupFrame:TweenPosition(offscreenPosition, Enum.EasingDirection.InOut, + Enum.EasingStyle.Quad, TWEEN_TIME, true, function() + if playerDropDown.PopupFrame then + playerDropDown.PopupFrame:Destroy() + playerDropDown.PopupFrame = nil + end + end) + else + playerDropDown.PopupFrame:Destroy() + playerDropDown.PopupFrame = nil + end + end + if playerDropDown.Player then + playerDropDown.Player = nil + end + playerDropDown.HiddenSignal:fire() + end + + function playerDropDown:CreatePopup(Player) + playerDropDown.Player = Player + + local buttons = {} + + local status = getFriendStatus(playerDropDown.Player) + local friendText = "" + local canDeclineFriend = false + if status == Enum.FriendStatus.Friend then + friendText = "Unfriend Player" + elseif status == Enum.FriendStatus.Unknown or status == Enum.FriendStatus.NotFriend then + friendText = "Send Friend Request" + elseif status == Enum.FriendStatus.FriendRequestSent then + friendText = "Revoke Friend Request" + elseif status == Enum.FriendStatus.FriendRequestReceived then + friendText = "Accept Friend Request" + canDeclineFriend = true + end + + local blocked = isBlocked(playerDropDown.Player.userId) + + if not blocked then + table.insert(buttons, { + Name = "FriendButton", + Text = friendText, + OnPress = onFriendButtonPressed, + }) + end + + if canDeclineFriend and not blocked then + table.insert(buttons, { + Name = "DeclineFriend", + Text = "Decline Friend Request", + OnPress = onDeclineFriendButonPressed, + }) + end + -- following status + if IsServerFollowers or IsFollowersEnabled then + local following = isFollowing(playerDropDown.Player.userId, LocalPlayer.userId) + local followerText = following and "Unfollow Player" or "Follow Player" + + if not blocked then + table.insert(buttons, { + Name = "FollowerButton", + Text = followerText, + OnPress = following and onUnfollowButtonPressed or onFollowButtonPressed, + }) + end + end + + local blockedText = blocked and "Unblock Player" or "Block Player" + table.insert(buttons, { + Name = "BlockButton", + Text = blockedText, + OnPress = blocked and onUnblockButtonPressed or onBlockButtonPressed, + }) + table.insert(buttons, { + Name = "ReportButton", + Text = "Report Abuse", + OnPress = onReportButtonPressed, + }) + + createPersonalServerDialog(buttons, playerDropDown.Player) + if playerDropDown.PopupFrame then + playerDropDown.PopupFrame:Destroy() + end + playerDropDown.PopupFrame = createPopupFrame(buttons) + return playerDropDown.PopupFrame + end + + --[[ PlayerRemoving Connection ]]-- + PlayersService.PlayerRemoving:connect(function(leavingPlayer) + if playerDropDown.Player == leavingPlayer then + playerDropDown:Hide() + end + end) + + return playerDropDown +end + + +do + moduleApiTable.FollowerStatusChanged = createSignal() + + function moduleApiTable:CreatePlayerDropDown() + return createPlayerDropDown() + end + + function moduleApiTable:CreateBlockingUtility() + local blockingUtility = {} + + function blockingUtility:BlockPlayerAsync(player) + return BlockPlayerAsync(player) + end + + function blockingUtility:UnblockPlayerAsync(player) + return UnblockPlayerAsync(player) + end + + function blockingUtility:MutePlayer(player) + return MutePlayer(player) + end + + function blockingUtility:UnmutePlayer(player) + return UnmutePlayer(player) + end + + function blockingUtility:IsPlayerBlockedByUserId(userId) + return isBlocked(userId) + end + + function blockingUtility:GetBlockedStatusChangedEvent() + return BlockStatusChanged + end + + function blockingUtility:IsPlayerMutedByUserId(userId) + return isMuted(userId) + end + + return blockingUtility + end +end + +return moduleApiTable diff --git a/2016/content/scripts/Modules/PlayerlistModule.lua b/2016/content/scripts/Modules/PlayerlistModule.lua new file mode 100644 index 0000000..502698a --- /dev/null +++ b/2016/content/scripts/Modules/PlayerlistModule.lua @@ -0,0 +1,1752 @@ +--[[ + // FileName: PlayerlistModule.lua + // Version 1.3 + // Written by: jmargh + // Description: Implementation of in game player list and leaderboard +]] + +local CoreGui = game:GetService('CoreGui') +local GuiService = game:GetService('GuiService') -- NOTE: Can only use in core scripts +local UserInputService = game:GetService('UserInputService') +local HttpService = game:GetService('HttpService') +local HttpRbxApiService = game:GetService('HttpRbxApiService') +local Players = game:GetService('Players') +local TeamsService = game:FindService('Teams') +local ContextActionService = game:GetService('ContextActionService') +local StarterGui = game:GetService('StarterGui') + +local RbxGuiLibrary = nil +if LoadLibrary then + RbxGuiLibrary = LoadLibrary("RbxGui") +end + +while not Players.LocalPlayer do + wait() +end +local Player = Players.LocalPlayer +local RobloxGui = CoreGui:WaitForChild('RobloxGui') + +local TenFootInterface = require(RobloxGui.Modules.TenFootInterface) +local isTenFootInterface = TenFootInterface:IsEnabled() + +local playerDropDownModule = require(RobloxGui.Modules.PlayerDropDown) +local blockingUtility = playerDropDownModule:CreateBlockingUtility() +local playerDropDown = playerDropDownModule:CreatePlayerDropDown() + +--[[ Fast Flags ]]-- +local followerSuccess, isFollowersEnabled = pcall(function() return settings():GetFFlag("EnableLuaFollowers") end) +local IsFollowersEnabled = followerSuccess and isFollowersEnabled + +local serverFollowersSuccess, serverFollowersEnabled = pcall(function() return settings():GetFFlag("UserServerFollowers") end) +local IsServerFollowers = serverFollowersSuccess and serverFollowersEnabled + +--[[ Remotes ]]-- +local RemoveEvent_OnFollowRelationshipChanged = nil +local RemoteFunc_GetFollowRelationships = nil + +--[[ Start Module ]]-- +local Playerlist = {} + +--[[ Public Event API ]]-- +-- Parameters: Sorted Array - see GameStats below +Playerlist.OnLeaderstatsChanged = Instance.new('BindableEvent') +-- Parameters: nameOfStat(string), formatedStringOfStat(string) +Playerlist.OnStatChanged = Instance.new('BindableEvent') + +--[[ Client Stat Table ]]-- +-- Sorted Array of tables +local GameStats = {} +-- Fields + -- Name: String the developer has given the stat + -- Text: Formated string of the stat value + -- AddId: Child add order id + -- IsPrimary: Is this the primary stat + -- Priority: Sorting priority +-- NOTE: IsPrimary and Priority are unofficially supported. They are left over legacy from the old player list. +-- They can be un-supported at anytime. You should prefer using child add order to order your stats in the leader board. + +--[[ Script Variables ]]-- +local topbarEnabled = true +local playerlistCoreGuiEnabled = true +local MyPlayerEntryTopFrame = nil +local PlayerEntries = {} +local StatAddId = 0 +local TeamEntries = {} +local TeamAddId = 0 +local NeutralTeam = nil +local IsShowingNeutralFrame = false +local LastSelectedFrame = nil +local LastSelectedPlayer = nil +local MinContainerSize = UDim2.new(0, 165, 0.5, 0) +if isTenFootInterface then + MinContainerSize = UDim2.new(0, 1000, 0, 720) +end +local TempHideKeys = {} + +local PlayerEntrySizeY = 24 +if isTenFootInterface then + PlayerEntrySizeY = 80 +end + +local TeamEntrySizeY = 18 + +if isTenFootInterface then + TeamEntrySizeY = 32 +end + +local NameEntrySizeX = 170 +if isTenFootInterface then + NameEntrySizeX = 350 +end + +local StatEntrySizeX = 75 +if isTenFootInterface then + StatEntrySizeX = 250 +end + +local IsSmallScreenDevice = UserInputService.TouchEnabled and GuiService:GetScreenResolution().Y <= 500 + +local BaseUrl = game:GetService('ContentProvider').BaseUrl:lower() +BaseUrl = string.gsub(BaseUrl, "/m.", "/www.") +AssetGameUrl = string.gsub(BaseUrl, 'www', 'assetgame') + +--[[ Constants ]]-- +local ENTRY_PAD = 2 +local BG_TRANSPARENCY = 0.5 +local BG_COLOR = Color3.new(31/255, 31/255, 31/255) +local BG_COLOR_TOP = Color3.new(106/255, 106/255, 106/255) +local TEXT_STROKE_TRANSPARENCY = 0.75 +local TEXT_COLOR = Color3.new(1, 1, 243/255) +local TEXT_STROKE_COLOR = Color3.new(34/255, 34/255, 34/255) +local TWEEN_TIME = 0.15 +local MAX_LEADERSTATS = 4 +local MAX_STR_LEN = 12 +local TILE_SPACING = 2 +if isTenFootInterface then + BG_COLOR_TOP = Color3.new(25/255, 25/255, 25/255) + BG_COLOR = Color3.new(60/255, 60/255, 60/255) + BG_TRANSPARENCY = 0.25 + TEXT_STROKE_TRANSPARENCY = 1 + TILE_SPACING = 5 +end +local SHADOW_IMAGE = 'rbxasset://textures/ui/PlayerList/TileShadowMissingTop.png'--'http://www.roblox.com/asset?id=286965900' +local SHADOW_SLICE_SIZE = 5 +local SHADOW_SLICE_RECT = Rect.new(SHADOW_SLICE_SIZE+1, SHADOW_SLICE_SIZE+1, SHADOW_SLICE_SIZE*2-1, SHADOW_SLICE_SIZE*2-1) + +local ADMINS = { -- Admins with special icons + ['123'] = 'http://www.roblox.com/asset/?id=134032333', -- Jeditkacheff + ['13268404'] = 'http://www.roblox.com/asset/?id=113059239', -- Sorcus + ['1'] = 'http://www.retblox.tk/asset/?id=105897927', -- shedlestky + ['20396599'] = 'http://www.roblox.com/asset/?id=161078086', -- Robloxsai +} + +local ABUSES = { + "Swearing", + "Bullying", + "Scamming", + "Dating", + "Cheating/Exploiting", + "Personal Questions", + "Offsite Links", + "Bad Username", +} + +local FOLLOWER_STATUS = { + FOLLOWER = 0, + FOLLOWING = 1, + MUTUAL = 2, +} + +--[[ Images ]]-- +local CHAT_ICON = 'rbxasset://textures/ui/chat_teamButton.png' +local ADMIN_ICON = 'rbxasset://textures/ui/icon_admin-16.png' +local PLACE_OWNER_ICON = 'rbxasset://textures/ui/icon_placeowner.png' +local BC_ICON = 'rbxasset://textures/ui/icon_BC-16.png' +local TBC_ICON = 'rbxasset://textures/ui/icon_TBC-16.png' +local OBC_ICON = 'rbxasset://textures/ui/icon_OBC-16.png' +local BLOCKED_ICON = 'rbxasset://textures/ui/PlayerList/BlockedIcon.png' +local FRIEND_ICON = 'rbxasset://textures/ui/icon_friends_16.png' +local FRIEND_REQUEST_ICON = 'rbxasset://textures/ui/icon_friendrequestsent_16.png' +local FRIEND_RECEIVED_ICON = 'rbxasset://textures/ui/icon_friendrequestrecieved-16.png' + +local FOLLOWER_ICON = 'rbxasset://textures/ui/icon_follower-16.png' +local FOLLOWING_ICON = 'rbxasset://textures/ui/icon_following-16.png' +local MUTUAL_FOLLOWING_ICON = 'rbxasset://textures/ui/icon_mutualfollowing-16.png' + +local CHARACTER_BACKGROUND_IMAGE = 'rbxasset://textures/ui/PlayerList/CharacterBackgroundImage.png' + +--[[ Helper Functions ]]-- +local function clamp(value, min, max) + if value < min then + value = min + elseif value > max then + value = max + end + + return value +end + +-- Returns whether followerUserId is following userId +local function isFollowing(userId, followerUserId) + local apiPath = "user/following-exists?userId=" + local params = userId.."&followerUserId="..followerUserId + local success, result = pcall(function() + return HttpRbxApiService:GetAsync(apiPath..params, true) + end) + if not success then + print("isFollowing() failed because", result) + return false + end + + -- can now parse web response + result = HttpService:JSONDecode(result) + return result["success"] and result["isFollowing"] +end + +-- TODO: Once server followers is good to go, remove this function and all code paths +local function getFollowerStatus(selectedPlayer) + -- we're going to check this flag first in case of a condition were the two flags are not set in sync + -- in that case, followers will be disabled + if not IsFollowersEnabled then + return nil + end + + if selectedPlayer == Player then + return nil + end + + -- ignore guest + if selectedPlayer.userId <= 0 or Player.userId <= 0 then + return + end + + local myUserId = tostring(Player.userId) + local theirUserId = tostring(selectedPlayer.userId) + + local isFollowingMe = isFollowing(myUserId, theirUserId) + local isFollowingThem = isFollowing(theirUserId, myUserId) + + if isFollowingMe and isFollowingThem then -- mutual + return FOLLOWER_STATUS.MUTUAL + elseif isFollowingMe then + return FOLLOWER_STATUS.FOLLOWER + elseif isFollowingThem then + return FOLLOWER_STATUS.FOLLOWING + else + return nil + end +end + +local function getFriendStatusIcon(friendStatus) + if friendStatus == Enum.FriendStatus.Unknown or friendStatus == Enum.FriendStatus.NotFriend then + return nil + elseif friendStatus == Enum.FriendStatus.Friend then + return FRIEND_ICON + elseif friendStatus == Enum.FriendStatus.FriendRequestSent then + return FRIEND_REQUEST_ICON + elseif friendStatus == Enum.FriendStatus.FriendRequestReceived then + return FRIEND_RECEIVED_ICON + else + error("PlayerList: Unknown value for friendStatus: "..tostring(friendStatus)) + end +end + +local function getFollowerStatusIcon(followerStatus) + if followerStatus == FOLLOWER_STATUS.MUTUAL then + return MUTUAL_FOLLOWING_ICON + elseif followerStatus == FOLLOWER_STATUS.FOLLOWING then + return FOLLOWING_ICON + elseif followerStatus == FOLLOWER_STATUS.FOLLOWER then + return FOLLOWER_ICON + else + return nil + end +end + +local function getAdminIcon(player) + local userIdStr = tostring(player.userId) + if ADMINS[userIdStr] then return nil end + -- + local success, result = pcall(function() + return player:IsInGroup(1200769) -- yields + end) + if not success then + print("PlayerListScript2: getAdminIcon() failed because", result) + return nil + end + -- + if result then + return ADMIN_ICON + end +end + +local function setAvatarIconAsync(player, iconImage) + -- this function is pretty much for xbox right now and makes use of modules that are part + -- of the xbox app. Please see Kip or Jason if you have any questions + local useSubdomainsFlagExists, useSubdomainsFlagValue = pcall(function() return settings():GetFFlag("UseNewSubdomainsInCoreScripts") end) + local thumbsUrl = BaseUrl + if(useSubdomainsFlagExists and useSubdomainsFlagValue and AssetGameUrl~=nil) then + thumbsUrl = AssetGameUrl + end + + local thumbnailLoader = nil + pcall(function() + thumbnailLoader = require(RobloxGui.Modules.ThumbnailLoader) + end) + + local isFinalSuccess = false + if thumbnailLoader then + local loader = thumbnailLoader:Create(iconImage, player.userId, + thumbnailLoader.Sizes.Small, thumbnailLoader.AssetType.Avatar, true) + isFinalSuccess = loader:LoadAsync(false, true, nil) + end + + if not isFinalSuccess then + iconImage.Image = 'rbxasset://textures/ui/Shell/Icons/DefaultProfileIcon.png' + end +end + +local function getMembershipIcon(player) + if isTenFootInterface then + -- return nothing, we need to spawn off setAvatarIconAsync() as a later time to not block + return "" + else + if blockingUtility:IsPlayerBlockedByUserId(player.userId) then + return BLOCKED_ICON + else + local userIdStr = tostring(player.userId) + local membershipType = player.MembershipType + if ADMINS[userIdStr] then + return ADMINS[userIdStr] + elseif player.userId == game.CreatorId and game.CreatorType == Enum.CreatorType.User then + return PLACE_OWNER_ICON + elseif membershipType == Enum.MembershipType.None then + return "" + elseif membershipType == Enum.MembershipType.BuildersClub then + return BC_ICON + elseif membershipType == Enum.MembershipType.TurboBuildersClub then + return TBC_ICON + elseif membershipType == Enum.MembershipType.OutrageousBuildersClub then + return OBC_ICON + else + return "" + end + end + end + + return "" +end + +local function isValidStat(obj) + return obj:IsA('StringValue') or obj:IsA('IntValue') or obj:IsA('BoolValue') or obj:IsA('NumberValue') or + obj:IsA('DoubleConstrainedValue') or obj:IsA('IntConstrainedValue') +end + +local function sortPlayerEntries(a, b) + if a.PrimaryStat == b.PrimaryStat then + return a.Player.Name:upper() < b.Player.Name:upper() + end + if not a.PrimaryStat then return false end + if not b.PrimaryStat then return true end + return a.PrimaryStat > b.PrimaryStat +end + +local function sortLeaderStats(a, b) + if a.IsPrimary ~= b.IsPrimary then + return a.IsPrimary + end + if a.Priority == b.Priority then + return a.AddId < b.AddId + end + return a.Priority < b.Priority +end + +local function sortTeams(a, b) + if a.TeamScore == b.TeamScore then + return a.Id < b.Id + end + if not a.TeamScore then return false end + if not b.TeamScore then return true end + return a.TeamScore < b.TeamScore +end + +-- Start of Gui Creation +local Container = Instance.new('Frame') +Container.Name = "PlayerListContainer" +if isTenFootInterface then + Container.Position = UDim2.new(0.5, -MinContainerSize.X.Offset/2, 0.25, 0) + Container.Size = MinContainerSize +else + Container.Position = UDim2.new(1, -167, 0, 2) + Container.Size = MinContainerSize +end + +Container.BackgroundTransparency = 1 +Container.Visible = false +Container.Parent = RobloxGui + +-- Scrolling Frame +local noSelectionObject = Instance.new("Frame") +noSelectionObject.BackgroundTransparency = 1 +noSelectionObject.BorderSizePixel = 0 + +local ScrollList = Instance.new('ScrollingFrame') +ScrollList.Name = "ScrollList" +ScrollList.Size = UDim2.new(1, -1, 0, 0) +if isTenFootInterface then + ScrollList.Position = UDim2.new(0, 0, 0, PlayerEntrySizeY + TILE_SPACING) + ScrollList.Size = UDim2.new(1, 19, 0, 0) +end +ScrollList.BackgroundTransparency = 1 +ScrollList.BackgroundColor3 = Color3.new() +ScrollList.BorderSizePixel = 0 +ScrollList.CanvasSize = UDim2.new(0, 0, 0, 0) -- NOTE: Look into if x needs to be set to anything +ScrollList.ScrollBarThickness = 6 +ScrollList.BottomImage = 'rbxasset://textures/ui/scroll-bottom.png' +ScrollList.MidImage = 'rbxasset://textures/ui/scroll-middle.png' +ScrollList.TopImage = 'rbxasset://textures/ui/scroll-top.png' +ScrollList.SelectionImageObject = noSelectionObject +ScrollList.Parent = Container + +-- PlayerDropDown clipping frame +local PopupClipFrame = Instance.new('Frame') +PopupClipFrame.Name = "PopupClipFrame" +PopupClipFrame.Size = UDim2.new(0, 150, 1.5, 0) +PopupClipFrame.Position = UDim2.new(0, -150 - ENTRY_PAD, 0, 0) +PopupClipFrame.BackgroundTransparency = 1 +PopupClipFrame.ClipsDescendants = true +PopupClipFrame.Parent = Container + + +--[[ Creation Helper Functions ]]-- +local function createEntryFrame(name, sizeYOffset, isTopStat) + local containerFrame = Instance.new('Frame') + containerFrame.Name = name + containerFrame.Position = UDim2.new(0, 0, 0, 0) + containerFrame.Size = UDim2.new(1, 0, 0, sizeYOffset) + if isTenFootInterface then + containerFrame.Position = UDim2.new(0, 10, 0, 0) + containerFrame.Size = containerFrame.Size + UDim2.new(0, -20, 0, 0) + end + containerFrame.BackgroundTransparency = 1 + containerFrame.ZIndex = isTenFootInterface and 2 or 1 + + local nameFrame = Instance.new('TextButton') + nameFrame.Name = "BGFrame" + nameFrame.Position = UDim2.new(0, 0, 0, 0) + nameFrame.Size = UDim2.new(0, NameEntrySizeX, 0, sizeYOffset) + nameFrame.BackgroundTransparency = isTopStat and 0 or BG_TRANSPARENCY + nameFrame.BackgroundColor3 = isTopStat and BG_COLOR_TOP or BG_COLOR + nameFrame.BorderSizePixel = 0 + nameFrame.AutoButtonColor = false + nameFrame.Text = "" + nameFrame.Parent = containerFrame + nameFrame.ZIndex = isTenFootInterface and 2 or 1 + + return containerFrame, nameFrame +end + +local function createEntryNameText(name, text, sizeXOffset, posXOffset) + local nameLabel = Instance.new('TextLabel') + nameLabel.Name = name + nameLabel.Size = UDim2.new(-0.01, sizeXOffset, 1, 0) + nameLabel.Position = UDim2.new(0.01, posXOffset, 0, 0) + nameLabel.BackgroundTransparency = 1 + nameLabel.Font = Enum.Font.SourceSans + if isTenFootInterface then + nameLabel.FontSize = Enum.FontSize.Size32 + else + nameLabel.FontSize = Enum.FontSize.Size14 + end + nameLabel.TextColor3 = TEXT_COLOR + nameLabel.TextStrokeTransparency = TEXT_STROKE_TRANSPARENCY + nameLabel.TextStrokeColor3 = TEXT_STROKE_COLOR + nameLabel.TextXAlignment = Enum.TextXAlignment.Left + nameLabel.ClipsDescendants = true + nameLabel.Text = text + nameLabel.ZIndex = isTenFootInterface and 2 or 1 + + return nameLabel +end + +local function createStatFrame(offset, parent, name, isTopStat) + local statFrame = Instance.new('Frame') + statFrame.Name = name + statFrame.Size = UDim2.new(0, StatEntrySizeX, 1, 0) + statFrame.Position = UDim2.new(0, offset + TILE_SPACING, 0, 0) + statFrame.BackgroundTransparency = isTopStat and 0 or BG_TRANSPARENCY + statFrame.BackgroundColor3 = isTopStat and BG_COLOR_TOP or BG_COLOR + statFrame.BorderSizePixel = 0 + statFrame.Parent = parent + + if isTenFootInterface then + statFrame.ZIndex = 2 + + local shadow = Instance.new("ImageLabel") + shadow.BackgroundTransparency = 1 + shadow.Name = 'Shadow' + shadow.Image = SHADOW_IMAGE + shadow.Position = UDim2.new(0, -SHADOW_SLICE_SIZE, 0, 0) + shadow.Size = UDim2.new(1, SHADOW_SLICE_SIZE*2, 1, SHADOW_SLICE_SIZE) + shadow.ScaleType = 'Slice' + shadow.SliceCenter = SHADOW_SLICE_RECT + shadow.Parent = statFrame + end + + return statFrame +end + +local function createStatText(parent, text, isTopStat, isTeamStat) + local statText = Instance.new('TextLabel') + statText.Name = "StatText" + statText.Size = isTopStat and UDim2.new(1, 0, 0.5, 0) or UDim2.new(1, 0, 1, 0) + statText.Position = isTopStat and UDim2.new(0, 0, 0.5, 0) or UDim2.new(0, 0, 0, 0) + statText.BackgroundTransparency = 1 + statText.Font = isTopStat and Enum.Font.SourceSansBold or Enum.Font.SourceSans + if isTenFootInterface then + statText.FontSize = Enum.FontSize.Size32 + else + statText.FontSize = Enum.FontSize.Size14 + end + statText.TextColor3 = TEXT_COLOR + statText.TextStrokeColor3 = TEXT_STROKE_COLOR + statText.TextStrokeTransparency = TEXT_STROKE_TRANSPARENCY + statText.Text = text + statText.Active = true + statText.Parent = parent + if isTenFootInterface then + statText.ZIndex = 2 + end + + if isTopStat then + local statName = statText:Clone() + statName.Name = "StatName" + statName.Text = tostring(parent.Name) + statName.Position = UDim2.new(0,0,0,0) + statName.Font = Enum.Font.SourceSans + statName.ClipsDescendants = true + statName.Parent = parent + if isTenFootInterface then + statName.ZIndex = 2 + end + end + + if isTeamStat then + statText.Font = 'SourceSansBold' + end + + return statText +end + +local function createImageIcon(image, name, xOffset, parent) + local imageLabel = Instance.new('ImageLabel') + imageLabel.Name = name + if isTenFootInterface then + imageLabel.Size = UDim2.new(0, 64, 0, 64) + imageLabel.ZIndex = 2 + + local background = Instance.new("ImageLabel", imageLabel) + background.Name = 'Background' + background.BackgroundTransparency = 1 + background.Image = CHARACTER_BACKGROUND_IMAGE + background.Size = UDim2.new(0, 66, 0, 66) + background.Position = UDim2.new(0.5, -66/2, 0.5, -66/2) + background.ZIndex = 2 + else + imageLabel.Size = UDim2.new(0, 16, 0, 16) + end + imageLabel.Position = UDim2.new(0.01, xOffset, 0.5, -imageLabel.Size.Y.Offset/2) + imageLabel.BackgroundTransparency = 1 + imageLabel.Image = image + imageLabel.BorderSizePixel = 0 + imageLabel.Parent = parent + + return imageLabel +end + +local function getScoreValue(statObject) + if statObject:IsA('DoubleConstrainedValue') or statObject:IsA('IntConstrainedValue') then + return statObject.ConstrainedValue + elseif statObject:IsA('BoolValue') then + if statObject.Value then return 1 else return 0 end + else + return statObject.Value + end +end + +local THIN_CHARS = "[^%[iIl\%.,']" +local function strWidth(str) + return string.len(str) - math.floor(string.len(string.gsub(str, THIN_CHARS, "")) / 2) +end + +local function formatNumber(value) + local _,_,minusSign, int, fraction = tostring(value):find('([-]?)(%d+)([.]?%d*)') + int = int:reverse():gsub("%d%d%d", "%1,") + return minusSign..int:reverse():gsub("^,", "")..fraction +end + +local function formatStatString(text) + local numberValue = tonumber(text) + if numberValue then + text = formatNumber(numberValue) + end + + if strWidth(text) <= MAX_STR_LEN then + return text + else + return string.sub(text, 1, MAX_STR_LEN - 3).."..." + end +end + +--[[ Resize Functions ]]-- +local LastMaxScrollSize = 0 +local function setScrollListSize() + local teamSize = #TeamEntries * TeamEntrySizeY + local playerSize = #PlayerEntries * PlayerEntrySizeY + local spacing = #PlayerEntries * ENTRY_PAD + #TeamEntries * ENTRY_PAD + local canvasSize = teamSize + playerSize + spacing + if #TeamEntries > 0 and NeutralTeam and IsShowingNeutralFrame then + canvasSize = canvasSize + TeamEntrySizeY + ENTRY_PAD + end + ScrollList.CanvasSize = UDim2.new(0, 0, 0, canvasSize) + local newScrollListSize = math.min(canvasSize, Container.AbsoluteSize.y) + if ScrollList.Size.Y.Offset == LastMaxScrollSize then + if isTenFootInterface then + ScrollList.Size = UDim2.new(1, 20, 0, newScrollListSize) + else + ScrollList.Size = UDim2.new(1, 0, 0, newScrollListSize) + end + end + LastMaxScrollSize = newScrollListSize +end + +--[[ Re-position Functions ]]-- +local function setPlayerEntryPositions() + local position = 0 + for i = 1, #PlayerEntries do + if isTenFootInterface and PlayerEntries[i].Frame ~= MyPlayerEntryTopFrame then + PlayerEntries[i].Frame.Position = UDim2.new(0, 10, 0, position) + position = position + PlayerEntrySizeY + TILE_SPACING + elseif PlayerEntries[i].Frame ~= MyPlayerEntryTopFrame then + PlayerEntries[i].Frame.Position = UDim2.new(0, 0, 0, position) + position = position + PlayerEntrySizeY + TILE_SPACING + end + end +end + +local function setTeamEntryPositions() + local teams = {} + for _,teamEntry in ipairs(TeamEntries) do + local team = teamEntry.Team + teams[tostring(team.TeamColor)] = {} + end + if NeutralTeam then + teams.Neutral = {} + end + + for _,playerEntry in ipairs(PlayerEntries) do + if playerEntry.Frame ~= MyPlayerEntryTopFrame then + local player = playerEntry.Player + if player.Neutral then + table.insert(teams.Neutral, playerEntry) + elseif teams[tostring(player.TeamColor)] then + table.insert(teams[tostring(player.TeamColor)], playerEntry) + else + table.insert(teams.Neutral, playerEntry) + end + end + end + + local position = 0 + for _,teamEntry in ipairs(TeamEntries) do + local team = teamEntry.Team + teamEntry.Frame.Position = UDim2.new(0, isTenFootInterface and 10 or 0, 0, position) + position = position + TeamEntrySizeY + TILE_SPACING + local players = teams[tostring(team.TeamColor)] + for _,playerEntry in ipairs(players) do + playerEntry.Frame.Position = UDim2.new(0, isTenFootInterface and 10 or 0, 0, position) + position = position + PlayerEntrySizeY + TILE_SPACING + end + end + if NeutralTeam then + NeutralTeam.Frame.Position = UDim2.new(0, isTenFootInterface and 10 or 0, 0, position) + position = position + TeamEntrySizeY + TILE_SPACING + if #teams.Neutral > 0 then + IsShowingNeutralFrame = true + local players = teams.Neutral + for _,playerEntry in ipairs(players) do + playerEntry.Frame.Position = UDim2.new(0, isTenFootInterface and 10 or 0, 0, position) + position = position + PlayerEntrySizeY + TILE_SPACING + end + else + IsShowingNeutralFrame = false + end + end +end + +local function setEntryPositions() + table.sort(PlayerEntries, sortPlayerEntries) + if #TeamEntries > 0 then + setTeamEntryPositions() + else + setPlayerEntryPositions() + end +end + +local function updateSocialIcon(newIcon, bgFrame) + local socialIcon = bgFrame:FindFirstChild('SocialIcon') + local nameFrame = bgFrame:FindFirstChild('PlayerName') + local offset = 19 + if socialIcon then + if newIcon then + socialIcon.Image = newIcon + else + if nameFrame then + local newSize = nameFrame.Size.X.Offset + socialIcon.Size.X.Offset + 2 + nameFrame.Size = UDim2.new(-0.01, newSize, 0.5, 0) + nameFrame.Position = UDim2.new(0.01, offset, 0.245, 0) + end + socialIcon:Destroy() + end + elseif newIcon and bgFrame then + socialIcon = createImageIcon(newIcon, "SocialIcon", offset, bgFrame) + offset = offset + socialIcon.Size.X.Offset + 2 + if nameFrame then + local newSize = bgFrame.Size.X.Offset - offset + nameFrame.Size = UDim2.new(-0.01, newSize, 0.5, 0) + nameFrame.Position = UDim2.new(0.01, offset, 0.245, 0) + end + end +end + +local function getFriendStatus(selectedPlayer) + if selectedPlayer == Player then + return Enum.FriendStatus.NotFriend + else + local success, result = pcall(function() + -- NOTE: Core script only + return Player:GetFriendStatus(selectedPlayer) + end) + if success then + return result + else + return Enum.FriendStatus.NotFriend + end + end +end + +local function onFollowerStatusChanged() + -- TODO: Remove this event completely when server version is stable + if not IsFollowersEnabled and not LastSelectedFrame or not LastSelectedPlayer then + return + end + + -- don't update icon if already friends + local friendStatus = getFriendStatus(LastSelectedPlayer) + if friendStatus == Enum.FriendStatus.Friend then + return + end + + local bgFrame = LastSelectedFrame:FindFirstChild('BGFrame') + local followerStatus = getFollowerStatus(LastSelectedPlayer) + local newIcon = getFollowerStatusIcon(followerStatus) + if bgFrame then + updateSocialIcon(newIcon, bgFrame) + end +end +-- Don't listen/show rbx follower status on xbox +if not isTenFootInterface then + playerDropDownModule.FollowerStatusChanged:connect(onFollowerStatusChanged) +end + +function popupHidden() + if LastSelectedFrame then + for _,childFrame in pairs(LastSelectedFrame:GetChildren()) do + if childFrame:IsA('TextButton') or childFrame:IsA('Frame') then + childFrame.BackgroundColor3 = BG_COLOR + end + end + end + ScrollList.ScrollingEnabled = true + LastSelectedFrame = nil + LastSelectedPlayer = nil +end +playerDropDown.HiddenSignal:connect(popupHidden) + +local function onEntryFrameSelected(selectedFrame, selectedPlayer) + if selectedPlayer ~= Player and selectedPlayer.userId > 1 and Player.userId > 1 then + if LastSelectedFrame ~= selectedFrame then + if LastSelectedFrame then + for _,childFrame in pairs(LastSelectedFrame:GetChildren()) do + if childFrame:IsA('TextButton') or childFrame:IsA('Frame') then + childFrame.BackgroundColor3 = BG_COLOR + end + end + end + LastSelectedFrame = selectedFrame + LastSelectedPlayer = selectedPlayer + for _,childFrame in pairs(selectedFrame:GetChildren()) do + if childFrame:IsA('TextButton') or childFrame:IsA('Frame') then + childFrame.BackgroundColor3 = Color3.new(0, 1, 1) + end + end + -- NOTE: Core script only + ScrollList.ScrollingEnabled = false + + local PopupFrame = playerDropDown:CreatePopup(selectedPlayer) + PopupFrame.Position = UDim2.new(1, 1, 0, selectedFrame.Position.Y.Offset - ScrollList.CanvasPosition.y) + PopupFrame.Parent = PopupClipFrame + PopupFrame:TweenPosition(UDim2.new(0, 0, 0, selectedFrame.Position.Y.Offset - ScrollList.CanvasPosition.y), Enum.EasingDirection.InOut, Enum.EasingStyle.Quad, TWEEN_TIME, true) + else + playerDropDown:Hide() + LastSelectedFrame = nil + LastSelectedPlayer = nil + end + end +end + +local function onFriendshipChanged(otherPlayer, newFriendStatus) + local entryToUpdate = nil + for _,entry in ipairs(PlayerEntries) do + if entry.Player == otherPlayer then + entryToUpdate = entry + break + end + end + if not entryToUpdate then + return + end + local newIcon = getFriendStatusIcon(newFriendStatus) + local frame = entryToUpdate.Frame + local bgFrame = frame:FindFirstChild('BGFrame') + if bgFrame then + --no longer friends, but might still be following + if not IsServerFollowers and IsFollowersEnabled and not newIcon then + local followerStatus = getFollowerStatus(otherPlayer) + newIcon = getFollowerStatusIcon(followerStatus) + end + + updateSocialIcon(newIcon, bgFrame) + end +end + +-- NOTE: Core script only. This fires when a player joins the game. +-- Don't listen/show rbx friends status on xbox +if not isTenFootInterface then + Player.FriendStatusChanged:connect(onFriendshipChanged) +end + +--[[ Begin New Server Followers ]]-- +local function setFollowRelationshipsView(relationshipTable) + if not relationshipTable then + return + end + + for i = 1, #PlayerEntries do + local entry = PlayerEntries[i] + local player = entry.Player + local userId = tostring(player.userId) + + -- don't update icon if already friends + local friendStatus = getFriendStatus(player) + if friendStatus == Enum.FriendStatus.Friend then + return + end + + local icon = nil + if relationshipTable[userId] then + local relationship = relationshipTable[userId] + if relationship.IsMutual == true then + icon = MUTUAL_FOLLOWING_ICON + elseif relationship.IsFollowing == true then + icon = FOLLOWING_ICON + elseif relationship.IsFollower == true then + icon = FOLLOWER_ICON + end + end + + local frame = entry.Frame + local bgFrame = frame:FindFirstChild('BGFrame') + if bgFrame then + updateSocialIcon(icon, bgFrame) + end + end +end + +local function getFollowRelationships() + local result = nil + if RemoteFunc_GetFollowRelationships then + result = RemoteFunc_GetFollowRelationships:InvokeServer() + end + return result +end + +--[[ End New Server Followers ]]-- + +local function updateAllTeamScores() + local teamScores = {} + for _,playerEntry in ipairs(PlayerEntries) do + local player = playerEntry.Player + local leaderstats = player:FindFirstChild('leaderstats') + local team = player.Neutral and 'Neutral' or tostring(player.TeamColor) + local isInValidColor = true + if team ~= 'Neutral' then + for _,teamEntry in ipairs(TeamEntries) do + local color = teamEntry.Team.TeamColor + if team == tostring(color) then + isInValidColor = false + break + end + end + end + if isInValidColor then + team = 'Neutral' + end + if not teamScores[team] then + teamScores[team] = {} + end + if playerEntry.Frame ~= MyPlayerEntryTopFrame then + if leaderstats then + for _,stat in ipairs(GameStats) do + local statObject = leaderstats:FindFirstChild(stat.Name) + if statObject and not statObject:IsA('StringValue') then + if not teamScores[team][stat.Name] then + teamScores[team][stat.Name] = 0 + end + teamScores[team][stat.Name] = teamScores[team][stat.Name] + getScoreValue(statObject) + end + end + end + end + end + + for _,teamEntry in ipairs(TeamEntries) do + local team = teamEntry.Team + local frame = teamEntry.Frame + local color = tostring(team.TeamColor) + local stats = teamScores[color] + if stats then + for statName,statValue in pairs(stats) do + local statFrame = frame:FindFirstChild(statName) + if statFrame then + local statText = statFrame:FindFirstChild('StatText') + if statText then + statText.Text = formatStatString(tostring(statValue)) + end + end + end + else + for _,childFrame in pairs(frame:GetChildren()) do + local statText = childFrame:FindFirstChild('StatText') + if statText then + statText.Text = '' + end + end + end + end + if NeutralTeam then + local frame = NeutralTeam.Frame + local stats = teamScores['Neutral'] + if stats then + frame.Visible = true + for statName,statValue in pairs(stats) do + local statFrame = frame:FindFirstChild(statName) + if statFrame then + local statText = statFrame:FindFirstChild('StatText') + if statText then + statText.Text = formatStatString(tostring(statValue)) + end + end + end + else + frame.Visible = false + end + end +end + +local function updateTeamEntry(entry) + local frame = entry.Frame + local team = entry.Team + local color = team.TeamColor.Color + local offset = NameEntrySizeX + for _,stat in ipairs(GameStats) do + local statFrame = frame:FindFirstChild(stat.Name) + if not statFrame then + statFrame = createStatFrame(offset, frame, stat.Name) + statFrame.BackgroundColor3 = color + createStatText(statFrame, "", false, true) + end + statFrame.Position = UDim2.new(0, offset + TILE_SPACING, 0, 0) + offset = offset + statFrame.Size.X.Offset + TILE_SPACING + end +end + +local function updatePrimaryStats(statName) + for _,entry in ipairs(PlayerEntries) do + local player = entry.Player + local leaderstats = player:FindFirstChild('leaderstats') + entry.PrimaryStat = nil + if leaderstats then + local statObject = leaderstats:FindFirstChild(statName) + if statObject then + local scoreValue = getScoreValue(statObject) + entry.PrimaryStat = scoreValue + end + end + end +end + +local updateLeaderstatFrames = nil +-- TODO: fire event to top bar? +local function initializeStatText(stat, statObject, entry, statFrame, index, isTopStat) + local player = entry.Player + local statValue = getScoreValue(statObject) + if statObject.Name == GameStats[1].Name then + entry.PrimaryStat = statValue + end + local statText = createStatText(statFrame, formatStatString(tostring(statValue)), isTopStat) + -- Top Bar insertion + if player == Player then + stat.Text = statText.Text + end + + statObject.Changed:connect(function(newValue) + local scoreValue = getScoreValue(statObject) + statText.Text = formatStatString(tostring(scoreValue)) + if statObject.Name == GameStats[1].Name then + entry.PrimaryStat = scoreValue + end + -- Top bar changed event + if player == Player then + stat.Text = statText.Text + Playerlist.OnStatChanged:Fire(stat.Name, stat.Text) + end + updateAllTeamScores() + setEntryPositions() + end) + statObject.ChildAdded:connect(function(child) + if child.Name == "IsPrimary" then + GameStats[1].IsPrimary = false + stat.IsPrimary = true + updatePrimaryStats(stat.Name) + if updateLeaderstatFrames then updateLeaderstatFrames() end + Playerlist.OnLeaderstatsChanged:Fire(GameStats) + end + end) +end + +updateLeaderstatFrames = function() + table.sort(GameStats, sortLeaderStats) + if #TeamEntries > 0 then + for _,entry in ipairs(TeamEntries) do + updateTeamEntry(entry) + end + if NeutralTeam then + updateTeamEntry(NeutralTeam) + end + end + + for _,entry in ipairs(PlayerEntries) do + local player = entry.Player + local mainFrame = entry.Frame + local offset = NameEntrySizeX + local leaderstats = player:FindFirstChild('leaderstats') + local isTopStat = (entry.Frame == MyPlayerEntryTopFrame) + + if leaderstats then + for _,stat in ipairs(GameStats) do + local statObject = leaderstats:FindFirstChild(stat.Name) + local statFrame = mainFrame:FindFirstChild(stat.Name) + + if not statFrame then + statFrame = createStatFrame(offset, mainFrame, stat.Name, isTopStat) + if statObject then + initializeStatText(stat, statObject, entry, statFrame, _, isTopStat) + end + elseif statObject then + local statText = statFrame:FindFirstChild('StatText') + if not statText then + initializeStatText(stat, statObject, entry, statFrame, _, isTopStat) + end + end + statFrame.Position = UDim2.new(0, offset + TILE_SPACING, 0, 0) + offset = offset + statFrame.Size.X.Offset + TILE_SPACING + end + else + for _,stat in ipairs(GameStats) do + local statFrame = mainFrame:FindFirstChild(stat.Name) + if not statFrame then + statFrame = createStatFrame(offset, mainFrame, stat.Name, isTopStat) + end + offset = offset + statFrame.Size.X.Offset + TILE_SPACING + end + end + + if entry.Frame ~= MyPlayerEntryTopFrame then + if isTenFootInterface then + Container.Position = UDim2.new(0.5, -offset/2, 0, 110) + Container.Size = UDim2.new(0, offset, 0.8, 0) + else + Container.Position = UDim2.new(1, -offset, 0, 2) + Container.Size = UDim2.new(0, offset, 0.5, 0) + end + + local newMinContainerOffset = offset + MinContainerSize = UDim2.new(0, newMinContainerOffset, 0.5, 0) + end + end + updateAllTeamScores() + setEntryPositions() + Playerlist.OnLeaderstatsChanged:Fire(GameStats) +end + +local function addNewStats(leaderstats) + for i,stat in ipairs(leaderstats:GetChildren()) do + if isValidStat(stat) and #GameStats < MAX_LEADERSTATS then + local gameHasStat = false + for _,gStat in ipairs(GameStats) do + if stat.Name == gStat.Name then + gameHasStat = true + break + end + end + + if not gameHasStat then + local newStat = {} + newStat.Name = stat.Name + newStat.Text = "-" + newStat.Priority = 0 + local priority = stat:FindFirstChild('Priority') + if priority then newStat.Priority = priority end + newStat.IsPrimary = false + local isPrimary = stat:FindFirstChild('IsPrimary') + if isPrimary then + newStat.IsPrimary = true + end + newStat.AddId = StatAddId + StatAddId = StatAddId + 1 + table.insert(GameStats, newStat) + table.sort(GameStats, sortLeaderStats) + if #GameStats == 1 then + setScrollListSize() + setEntryPositions() + end + end + end + end +end + +local function removeStatFrameFromEntry(stat, frame) + local statFrame = frame:FindFirstChild(stat.Name) + if statFrame then + statFrame:Destroy() + end +end + +local function doesStatExists(stat) + local doesExists = false + for _,entry in ipairs(PlayerEntries) do + local player = entry.Player + if player then + local leaderstats = player:FindFirstChild('leaderstats') + if leaderstats and leaderstats:FindFirstChild(stat.Name) then + doesExists = true + break + end + end + end + + return doesExists +end + +local function onStatRemoved(oldStat, entry) + if isValidStat(oldStat) then + removeStatFrameFromEntry(oldStat, entry.Frame) + local statExists = doesStatExists(oldStat) + -- + local toRemove = nil + for i, stat in ipairs(GameStats) do + if stat.Name == oldStat.Name then + toRemove = i + break + end + end + -- removed from player but not from game; another player still has this stat + if statExists then + if toRemove and entry.Player == Player then + GameStats[toRemove].Text = "-" + Playerlist.OnStatChanged:Fire(GameStats[toRemove].Name, GameStats[toRemove].Text) + end + -- removed from game + else + for _,playerEntry in ipairs(PlayerEntries) do + removeStatFrameFromEntry(oldStat, playerEntry.Frame) + end + for _,teamEntry in ipairs(TeamEntries) do + removeStatFrameFromEntry(oldStat, teamEntry.Frame) + end + if toRemove then + table.remove(GameStats, toRemove) + table.sort(GameStats, sortLeaderStats) + end + end + if GameStats[1] then + updatePrimaryStats(GameStats[1].Name) + end + updateLeaderstatFrames() + end +end + +local function onStatAdded(leaderstats, entry) + leaderstats.ChildAdded:connect(function(newStat) + if isValidStat(newStat) then + addNewStats(newStat.Parent) + updateLeaderstatFrames() + end + end) + leaderstats.ChildRemoved:connect(function(child) + onStatRemoved(child, entry) + end) + addNewStats(leaderstats) + updateLeaderstatFrames() +end + +local function setLeaderStats(entry) + local player = entry.Player + local leaderstats = player:FindFirstChild('leaderstats') + + if leaderstats then + onStatAdded(leaderstats, entry) + end + + local function onPlayerChildChanged(property, child) + if property == 'Name' and child.Name == 'leaderstats' then + onStatAdded(child, entry) + end + end + + player.ChildAdded:connect(function(child) + if child.Name == 'leaderstats' then + onStatAdded(child, entry) + end + child.Changed:connect(function(property) onPlayerChildChanged(property, child) end) + end) + for _,child in pairs(player:GetChildren()) do + child.Changed:connect(function(property) onPlayerChildChanged(property, child) end) + end + + player.ChildRemoved:connect(function(child) + if child.Name == 'leaderstats' then + for i,stat in ipairs(child:GetChildren()) do + onStatRemoved(stat, entry) + end + updateLeaderstatFrames() + end + end) +end + +local offsetSize = 18 +if isTenFootInterface then offsetSize = 32 end + +local function createPlayerEntry(player, isTopStat) + local playerEntry = {} + local name = player.Name + + local containerFrame, entryFrame = createEntryFrame(name, PlayerEntrySizeY, isTopStat) + entryFrame.Active = true + + if not isTenFootInterface then + local function localEntrySelected() + onEntryFrameSelected(containerFrame, player) + end + entryFrame.MouseButton1Click:connect(localEntrySelected) + end + + local currentXOffset = 1 + + -- check membership + local membershipIconImage = getMembershipIcon(player) + local membershipIcon = nil + if membershipIconImage then + membershipIcon = createImageIcon(membershipIconImage, "MembershipIcon", currentXOffset, entryFrame) + currentXOffset = currentXOffset + membershipIcon.Size.X.Offset + 2 + else + currentXOffset = currentXOffset + offsetSize + end + + spawn(function() + if isTenFootInterface and membershipIcon then + setAvatarIconAsync(player, membershipIcon) + end + end) + + -- Some functions yield, so we need to spawn off in order to not cause a race condition with other events like Players.ChildRemoved + spawn(function() + local success, result = pcall(function() + return player:GetRankInGroup(game.CreatorId) == 255 + end) + if success then + if game.CreatorType == Enum.CreatorType.Group and result then + membershipIconImage = PLACE_OWNER_ICON + if not membershipIcon then + membershipIcon = createImageIcon(membershipIconImage, "MembershipIcon", 1, entryFrame) + else + membershipIcon.Image = membershipIconImage + end + end + else + print("PlayerList: GetRankInGroup failed because", result) + end + local adminIconImage = getAdminIcon(player) + if adminIconImage then + if not membershipIcon then + membershipIcon = createImageIcon(adminIconImage, "MembershipIcon", 1, entryFrame) + else + membershipIcon.Image = adminIconImage + end + end + -- Friendship and Follower status is checked by onFriendshipChanged, which is called by the FriendStatusChanged + -- event. This event is fired when any player joins the game. onFriendshipChanged will check Follower status in + -- the case that we are not friends with the new player who is joining. + end) + + local playerNameXSize = entryFrame.Size.X.Offset - currentXOffset + local playerName = createEntryNameText("PlayerName", name, playerNameXSize, currentXOffset) + playerName.Parent = entryFrame + playerEntry.Player = player + playerEntry.Frame = containerFrame + + if isTenFootInterface then + local shadow = Instance.new("ImageLabel") + shadow.BackgroundTransparency = 1 + shadow.Name = 'Shadow' + shadow.Image = SHADOW_IMAGE + shadow.Position = UDim2.new(0, -SHADOW_SLICE_SIZE, 0, 0) + shadow.Size = UDim2.new(1, SHADOW_SLICE_SIZE*2, 1, SHADOW_SLICE_SIZE) + shadow.ScaleType = 'Slice' + shadow.SliceCenter = SHADOW_SLICE_RECT + shadow.Parent = entryFrame + end + + if isTopStat then + playerName.Font = 'SourceSansBold' + end + + return playerEntry +end + +local function createTeamEntry(team) + local teamEntry = {} + teamEntry.Team = team + teamEntry.TeamScore = 0 + + local containerFrame, entryFrame = createEntryFrame(team.Name, TeamEntrySizeY) + entryFrame.BackgroundColor3 = team.TeamColor.Color + + local teamName = createEntryNameText("TeamName", team.Name, entryFrame.AbsoluteSize.x, 1) + teamName.Parent = entryFrame + + teamEntry.Frame = containerFrame + + if isTenFootInterface then + local shadow = Instance.new("ImageLabel") + shadow.BackgroundTransparency = 1 + shadow.Name = 'Shadow' + shadow.Image = SHADOW_IMAGE + shadow.Position = UDim2.new(0, -SHADOW_SLICE_SIZE, 0, 0) + shadow.Size = UDim2.new(1, SHADOW_SLICE_SIZE*2, 1, SHADOW_SLICE_SIZE) + shadow.ScaleType = 'Slice' + shadow.SliceCenter = SHADOW_SLICE_RECT + shadow.Parent = entryFrame + end + + -- connections + team.Changed:connect(function(property) + if property == 'Name' then + teamName.Text = team.Name + elseif property == 'TeamColor' then + for _,childFrame in pairs(containerFrame:GetChildren()) do + if childFrame:IsA('GuiObject') then + childFrame.BackgroundColor3 = team.TeamColor.Color + end + end + + setTeamEntryPositions() + updateAllTeamScores() + setEntryPositions() + setScrollListSize() + end + end) + + return teamEntry +end + +local function createNeutralTeam() + if not NeutralTeam then + local team = Instance.new('Team') + team.Name = 'Neutral' + team.TeamColor = BrickColor.new('White') + NeutralTeam = createTeamEntry(team) + NeutralTeam.Frame.Parent = ScrollList + end +end + +--[[ Insert/Remove Player Functions ]]-- +local function setupEntry(player, newEntry, isTopStat) + setLeaderStats(newEntry) + + if isTopStat then + newEntry.Frame.Parent = Container + table.insert(PlayerEntries, newEntry) + else + newEntry.Frame.Parent = ScrollList + table.insert(PlayerEntries, newEntry) + setScrollListSize() + end + + updateLeaderstatFrames() + + player.Changed:connect(function(property) + if #TeamEntries > 0 and (property == 'Neutral' or property == 'TeamColor') then + setTeamEntryPositions() + updateAllTeamScores() + setEntryPositions() + setScrollListSize() + end + end) +end + +local function insertPlayerEntry(player) + local entry = createPlayerEntry(player) + setupEntry(player, entry) + + -- create an entry on the top of the playerlist + if player == Player and isTenFootInterface then + local localEntry = createPlayerEntry(player, true) + MyPlayerEntryTopFrame = localEntry.Frame + MyPlayerEntryTopFrame.BackgroundTransparency = 1 + MyPlayerEntryTopFrame.BorderSizePixel = 0 + setupEntry(player, localEntry, true) + end +end + +local function removePlayerEntry(player) + for i = 1, #PlayerEntries do + if PlayerEntries[i].Player == player then + PlayerEntries[i].Frame:Destroy() + table.remove(PlayerEntries, i) + break + end + end + setEntryPositions() + setScrollListSize() +end + +--[[ Team Functions ]]-- +local function onTeamAdded(team) + for i = 1, #TeamEntries do + if TeamEntries[i].Team.TeamColor == team.TeamColor then + TeamEntries[i].Frame:Destroy() + table.remove(TeamEntries, i) + break + end + end + local entry = createTeamEntry(team) + entry.Id = TeamAddId + TeamAddId = TeamAddId + 1 + if not NeutralTeam then + createNeutralTeam() + end + table.insert(TeamEntries, entry) + table.sort(TeamEntries, sortTeams) + setTeamEntryPositions() + updateLeaderstatFrames() + setScrollListSize() + entry.Frame.Parent = ScrollList +end + +local function onTeamRemoved(removedTeam) + for i = 1, #TeamEntries do + local team = TeamEntries[i].Team + if team.Name == removedTeam.Name then + TeamEntries[i].Frame:Destroy() + table.remove(TeamEntries, i) + break + end + end + if #TeamEntries == 0 then + if NeutralTeam then + NeutralTeam.Frame:Destroy() + NeutralTeam.Team:Destroy() + NeutralTeam = nil + IsShowingNeutralFrame = false + end + end + setEntryPositions() + updateLeaderstatFrames() + setScrollListSize() +end + +--[[ Resize/Position Functions ]]-- +local function clampCanvasPosition() + local maxCanvasPosition = ScrollList.CanvasSize.Y.Offset - ScrollList.Size.Y.Offset + if maxCanvasPosition >= 0 and ScrollList.CanvasPosition.y > maxCanvasPosition then + ScrollList.CanvasPosition = Vector2.new(0, maxCanvasPosition) + end +end + +local function resizePlayerList() + setScrollListSize() + clampCanvasPosition() +end + +RobloxGui.Changed:connect(function(property) + if property == 'AbsoluteSize' then + spawn(function() -- must spawn because F11 delays when abs size is set + resizePlayerList() + end) + end +end) + +UserInputService.InputBegan:connect(function(inputObject, isProcessed) + if isProcessed then return end + local inputType = inputObject.UserInputType + if (inputType == Enum.UserInputType.Touch and inputObject.UserInputState == Enum.UserInputState.Begin) or + inputType == Enum.UserInputType.MouseButton1 then + if LastSelectedFrame then + playerDropDown:Hide() + end + end +end) + +-- NOTE: Core script only + +--[[ Player Add/Remove Connections ]]-- +Players.ChildAdded:connect(function(child) + if child:IsA('Player') then + insertPlayerEntry(child) + end +end) +for _,player in pairs(Players:GetPlayers()) do + insertPlayerEntry(player) +end + +--[[ Begin new Server Followers ]]-- +-- Don't listen/show rbx followers status on console +if IsServerFollowers and not isTenFootInterface then + -- spawn so we don't block script + spawn(function() + local RobloxReplicatedStorage = game:GetService('RobloxReplicatedStorage') + RemoveEvent_OnFollowRelationshipChanged = RobloxReplicatedStorage:WaitForChild('FollowRelationshipChanged') + RemoteFunc_GetFollowRelationships = RobloxReplicatedStorage:WaitForChild('GetFollowRelationships') + + RemoveEvent_OnFollowRelationshipChanged.OnClientEvent:connect(function(result) + setFollowRelationshipsView(result) + end) + + local result = getFollowRelationships() + setFollowRelationshipsView(result) + end) +end + +Players.ChildRemoved:connect(function(child) + if child:IsA('Player') then + if LastSelectedPlayer and child == LastSelectedPlayer then + playerDropDown:Hide() + end + removePlayerEntry(child) + end +end) + +--[[ Teams ]]-- +local function initializeTeams(teams) + for _,team in pairs(teams:GetTeams()) do + onTeamAdded(team) + end + + teams.ChildAdded:connect(function(team) + if team:IsA('Team') then + onTeamAdded(team) + end + end) + + teams.ChildRemoved:connect(function(team) + if team:IsA('Team') then + onTeamRemoved(team) + end + end) +end + +TeamsService = game:FindService('Teams') +if TeamsService then + initializeTeams(TeamsService) +end + +game.ChildAdded:connect(function(child) + if child:IsA('Teams') then + initializeTeams(child) + end +end) + +--[[ Public API ]]-- +Playerlist.GetStats = function() + return GameStats +end + +local noOpFunc = function ( ) +end + +local isOpen = not isTenFootInterface + +local closeListFunc = function(name, state, input) + if state ~= Enum.UserInputState.Begin then return end + + isOpen = false + Container.Visible = false + spawn(function() GuiService:SetMenuIsOpen(false) end) + ContextActionService:UnbindCoreAction("CloseList") + ContextActionService:UnbindCoreAction("StopAction") + GuiService.SelectedCoreObject = nil + UserInputService.OverrideMouseIconBehavior = Enum.OverrideMouseIconBehavior.None +end + +local setVisible = function(state, fromTemp) + Container.Visible = state + + if state then + local children = ScrollList:GetChildren() + if children and #children > 0 then + local frame = children[1] + local frameChildren = frame:GetChildren() + for i = 1, #frameChildren do + if frameChildren[i]:IsA("TextButton") then + local lastInputType = UserInputService:GetLastInputType() + local isUsingGamepad = (lastInputType == Enum.UserInputType.Gamepad1 or lastInputType == Enum.UserInputType.Gamepad2 or + lastInputType == Enum.UserInputType.Gamepad3 or lastInputType == Enum.UserInputType.Gamepad4) + if not isTenFootInterface then + if isUsingGamepad and not fromTemp then + GuiService.SelectedCoreObject = frameChildren[i] + end + elseif not fromTemp then + GuiService.SelectedCoreObject = ScrollList + end + + if isUsingGamepad and not fromTemp then + UserInputService.OverrideMouseIconBehavior = Enum.OverrideMouseIconBehavior.ForceHide + ContextActionService:BindCoreAction("StopAction", noOpFunc, false, Enum.UserInputType.Gamepad1) + ContextActionService:BindCoreAction("CloseList", closeListFunc, false, Enum.KeyCode.ButtonB, Enum.KeyCode.ButtonStart) + end + break + end + end + end + else + if isUsingGamepad then + UserInputService.OverrideMouseIconBehavior = Enum.OverrideMouseIconBehavior.None + end + + ContextActionService:UnbindCoreAction("CloseList") + ContextActionService:UnbindCoreAction("StopAction") + + if GuiService.SelectedCoreObject and GuiService.SelectedCoreObject:IsDescendantOf(Container) then + GuiService.SelectedCoreObject = nil + end + end +end + +Playerlist.ToggleVisibility = function(name, inputState, inputObject) + if inputState and inputState ~= Enum.UserInputState.Begin then return end + if IsSmallScreenDevice then return end + if not playerlistCoreGuiEnabled then return end + + isOpen = not isOpen + + if next(TempHideKeys) == nil then + setVisible(isOpen) + end +end + +Playerlist.IsOpen = function() + return isOpen +end + +Playerlist.HideTemp = function(self, key, hidden) + if not playerlistCoreGuiEnabled then return end + if IsSmallScreenDevice then return end + + TempHideKeys[key] = hidden and true or nil + + if next(TempHideKeys) == nil then + if isOpen then + setVisible(true, true) + end + else + if isOpen then + setVisible(false, true) + end + end +end +local topStat = nil +if isTenFootInterface then + topStat = TenFootInterface:SetupTopStat() +end + +--[[ Core Gui Changed events ]]-- +-- NOTE: Core script only +local function onCoreGuiChanged(coreGuiType, enabled) + if coreGuiType == Enum.CoreGuiType.All or coreGuiType == Enum.CoreGuiType.PlayerList then + playerlistCoreGuiEnabled = enabled and topbarEnabled + + -- not visible on small screen devices + if IsSmallScreenDevice then + Container.Visible = false + return + end + + setVisible(playerlistCoreGuiEnabled and isOpen and next(TempHideKeys) == nil, true) + + if isTenFootInterface and topStat then + topStat:SetTopStatEnabled(playerlistCoreGuiEnabled) + end + + if playerlistCoreGuiEnabled then + ContextActionService:BindCoreAction("RbxPlayerListToggle", Playerlist.ToggleVisibility, false, Enum.KeyCode.Tab) + else + ContextActionService:UnbindCoreAction("RbxPlayerListToggle") + end + end +end + +Playerlist.TopbarEnabledChanged = function(enabled) + topbarEnabled = enabled + -- Update coregui to reflect new topbar status + onCoreGuiChanged(Enum.CoreGuiType.PlayerList, StarterGui:GetCoreGuiEnabled(Enum.CoreGuiType.PlayerList)) +end + +onCoreGuiChanged(Enum.CoreGuiType.PlayerList, StarterGui:GetCoreGuiEnabled(Enum.CoreGuiType.PlayerList)) +StarterGui.CoreGuiChangedSignal:connect(onCoreGuiChanged) + +resizePlayerList() + +if GuiService then + if isTenFootInterface then + GuiService:AddSelectionTuple("PlayerListSelection", ScrollList) + else + GuiService:AddSelectionParent("PlayerListSelection", Container) + end +end + +local blockStatusChanged = function(userId, isBlocked) + if userId < 0 then return end + + for _,playerEntry in ipairs(PlayerEntries) do + if playerEntry.Player.UserId == userId then + playerEntry.Frame.BGFrame.MembershipIcon.Image = getMembershipIcon(playerEntry.Player) + return + end + end +end + +blockingUtility:GetBlockedStatusChangedEvent():connect(blockStatusChanged) + +return Playerlist diff --git a/2016/content/scripts/Modules/Settings/Pages/GameSettings.lua b/2016/content/scripts/Modules/Settings/Pages/GameSettings.lua new file mode 100644 index 0000000..89e5aa5 --- /dev/null +++ b/2016/content/scripts/Modules/Settings/Pages/GameSettings.lua @@ -0,0 +1,790 @@ +--[[ + Filename: GameSettings.lua + Written by: jeditkacheff + Version 1.1 + Description: Takes care of the Game Settings Tab in Settings Menu +--]] + +-------------- SERVICES -------------- +local CoreGui = game:GetService("CoreGui") +local RobloxGui = CoreGui:WaitForChild("RobloxGui") +local GuiService = game:GetService("GuiService") +local UserInputService = game:GetService("UserInputService") +local PlatformService = nil +pcall(function() PlatformService = game:GetService("PlatformService") end) +local ContextActionService = game:GetService("ContextActionService") +local StarterGui = game:GetService("StarterGui") +local Settings = UserSettings() +local GameSettings = Settings.GameSettings + +-------------- CONSTANTS -------------- +local GRAPHICS_QUALITY_LEVELS = 10 +local GRAPHICS_QUALITY_TO_INT = { + ["Enum.SavedQualitySetting.Automatic"] = 0, + ["Enum.SavedQualitySetting.QualityLevel1"] = 1, + ["Enum.SavedQualitySetting.QualityLevel2"] = 2, + ["Enum.SavedQualitySetting.QualityLevel3"] = 3, + ["Enum.SavedQualitySetting.QualityLevel4"] = 4, + ["Enum.SavedQualitySetting.QualityLevel5"] = 5, + ["Enum.SavedQualitySetting.QualityLevel6"] = 6, + ["Enum.SavedQualitySetting.QualityLevel7"] = 7, + ["Enum.SavedQualitySetting.QualityLevel8"] = 8, + ["Enum.SavedQualitySetting.QualityLevel9"] = 9, + ["Enum.SavedQualitySetting.QualityLevel10"] = 10, +} +local PC_CHANGED_PROPS = { + DevComputerMovementMode = true, + DevComputerCameraMode = true, + DevEnableMouseLock = true, +} +local TOUCH_CHANGED_PROPS = { + DevTouchMovementMode = true, + DevTouchCameraMode = true, +} +local CAMERA_MODE_DEFAULT_STRING = UserInputService.TouchEnabled and "Default (Follow)" or "Default (Classic)" + +local MOVEMENT_MODE_DEFAULT_STRING = UserInputService.TouchEnabled and "Default (Thumbstick)" or "Default (Keyboard)" +local MOVEMENT_MODE_KEYBOARDMOUSE_STRING = "Keyboard + Mouse" +local MOVEMENT_MODE_CLICKTOMOVE_STRING = UserInputService.TouchEnabled and "Tap to Move" or "Click to Move" + +----------- UTILITIES -------------- +local utility = require(RobloxGui.Modules.Settings.Utility) + +------------ Variables ------------------- +RobloxGui:WaitForChild("Modules"):WaitForChild("TenFootInterface") +RobloxGui:WaitForChild("Modules"):WaitForChild("Settings"):WaitForChild("SettingsHub") +local isTenFootInterface = require(RobloxGui.Modules.TenFootInterface):IsEnabled() +local HasVRAPI = false +pcall(function() HasVRAPI = UserInputService.GetUserCFrame ~= nil end) +local PageInstance = nil +local LocalPlayer = game.Players.LocalPlayer +local platform = UserInputService:GetPlatform() +local overscanScreen = nil + +----------- CLASS DECLARATION -------------- + +local function Initialize() + local settingsPageFactory = require(RobloxGui.Modules.Settings.SettingsPageFactory) + local this = settingsPageFactory:CreateNewPage() + + ----------- FUNCTIONS --------------- + local function createGraphicsOptions() + + ------------------ Fullscreen Selection GUI Setup ------------------ + local fullScreenInit = 1 + if not GameSettings:InFullScreen() then + fullScreenInit = 2 + end + + this.FullscreenFrame, + this.FullscreenLabel, + this.FullscreenEnabler = utility:AddNewRow(this, "Fullscreen", "Selector", {"On", "Off"}, fullScreenInit) + + local fullScreenSelectionFrame = this.FullscreenEnabler.SliderFrame and this.FullscreenEnabler.SliderFrame or this.FullscreenEnabler.SelectorFrame + + this.FullscreenEnabler.IndexChanged:connect(function(newIndex) + GuiService:ToggleFullscreen() + end) + + ------------------ Gfx Enabler Selection GUI Setup ------------------ + local graphicsEnablerStart = 1 + if GameSettings.SavedQualityLevel ~= Enum.SavedQualitySetting.Automatic then + graphicsEnablerStart = 2 + end + + this.GraphicsEnablerFrame, + this.GraphicsEnablerLabel, + this.GraphicsQualityEnabler = utility:AddNewRow(this, "Graphics Mode", "Selector", {"Automatic", "Manual"}, graphicsEnablerStart) + + ------------------ Gfx Slider GUI Setup ------------------ + this.GraphicsQualityFrame, + this.GraphicsQualityLabel, + this.GraphicsQualitySlider = utility:AddNewRow(this, "Graphics Quality", "Slider", GRAPHICS_QUALITY_LEVELS, 1) + this.GraphicsQualitySlider:SetMinStep(1) + + ------------------------- Connection Setup ---------------------------- + settings().Rendering.EnableFRM = true + + function SetGraphicsQuality(newValue, automaticSettingAllowed) + local percentage = newValue/GRAPHICS_QUALITY_LEVELS + local newQualityLevel = math.floor((settings().Rendering:GetMaxQualityLevel() - 1) * percentage) + if newQualityLevel == 20 then + newQualityLevel = 21 + elseif newValue == 1 then + newQualityLevel = 1 + elseif newValue < 1 and not automaticSettingAllowed then + newValue = 1 + newQualityLevel = 1 + elseif newQualityLevel > settings().Rendering:GetMaxQualityLevel() then + newQualityLevel = settings().Rendering:GetMaxQualityLevel() - 1 + end + + GameSettings.SavedQualityLevel = newValue + settings().Rendering.QualityLevel = newQualityLevel + end + + local function setGraphicsToAuto() + this.GraphicsQualitySlider:SetZIndex(1) + this.GraphicsQualityLabel.ZIndex = 1 + this.GraphicsQualitySlider:SetInteractable(false) + + SetGraphicsQuality(Enum.QualityLevel.Automatic.Value, true) + end + local function setGraphicsToManual(level) + this.GraphicsQualitySlider:SetZIndex(2) + this.GraphicsQualityLabel.ZIndex = 2 + this.GraphicsQualitySlider:SetInteractable(true) + + -- need to force the quality change if slider is already at this position + if this.GraphicsQualitySlider:GetValue() == level then + SetGraphicsQuality(level) + else + this.GraphicsQualitySlider:SetValue(level) + end + end + + game.GraphicsQualityChangeRequest:connect(function(isIncrease) + if settings().Rendering.QualityLevel == Enum.QualityLevel.Automatic then return end + -- + local currentGraphicsSliderValue = this.GraphicsQualitySlider:GetValue() + if isIncrease then + currentGraphicsSliderValue = currentGraphicsSliderValue + 1 + else + currentGraphicsSliderValue = currentGraphicsSliderValue - 1 + end + + this.GraphicsQualitySlider:SetValue(currentGraphicsSliderValue) + end) + + this.GraphicsQualitySlider.ValueChanged:connect(function(newValue) + SetGraphicsQuality(newValue) + end) + + this.GraphicsQualityEnabler.IndexChanged:connect(function(newIndex) + if newIndex == 1 then + setGraphicsToAuto() + elseif newIndex == 2 then + setGraphicsToManual( this.GraphicsQualitySlider:GetValue() ) + end + end) + + -- initialize the slider position + if GameSettings.SavedQualityLevel == Enum.SavedQualitySetting.Automatic then + this.GraphicsQualitySlider:SetValue(5) + setGraphicsToAuto() + else + local graphicsLevel = tostring(GameSettings.SavedQualityLevel) + if GRAPHICS_QUALITY_TO_INT[graphicsLevel] then + graphicsLevel = GRAPHICS_QUALITY_TO_INT[graphicsLevel] + else + graphicsLevel = GRAPHICS_QUALITY_LEVELS + end + + spawn(function() + this.GraphicsQualitySlider:SetValue(graphicsLevel) + end) + end + end + + local function createCameraModeOptions(movementModeEnabled) + ------------------------------------------------------ + ------------------ + ------------------ Shift Lock Switch ----------------- + if UserInputService.MouseEnabled then + this.ShiftLockFrame, + this.ShiftLockLabel, + this.ShiftLockMode, + this.ShiftLockOverrideText = nil + + if UserInputService.MouseEnabled and UserInputService.KeyboardEnabled then + local startIndex = 2 + if GameSettings.ControlMode == Enum.ControlMode.MouseLockSwitch then + startIndex = 1 + end + + this.ShiftLockFrame, + this.ShiftLockLabel, + this.ShiftLockMode = utility:AddNewRow(this, "Shift Lock Switch", "Selector", {"On", "Off"}, startIndex) + + this.ShiftLockOverrideText = utility:Create'TextLabel' + { + Name = "ShiftLockOverrideLabel", + Text = "Set by Developer", + TextColor3 = Color3.new(1,1,1), + Font = Enum.Font.SourceSans, + FontSize = Enum.FontSize.Size24, + BackgroundTransparency = 1, + Size = UDim2.new(0,200,1,0), + Position = UDim2.new(1,-350,0,0), + Visible = false, + ZIndex = 2, + Parent = this.ShiftLockFrame + }; + + this.ShiftLockMode.IndexChanged:connect(function(newIndex) + if newIndex == 1 then + GameSettings.ControlMode = Enum.ControlMode.MouseLockSwitch + else + GameSettings.ControlMode = Enum.ControlMode.Classic + end + end) + end + end + + + ------------------------------------------------------ + ------------------ + ------------------ Camera Mode ----------------------- + do + local enumItems = nil + local startingCameraEnumItem = 1 + if UserInputService.TouchEnabled then + enumItems = Enum.TouchCameraMovementMode:GetEnumItems() + else + enumItems = Enum.ComputerCameraMovementMode:GetEnumItems() + end + + local cameraEnumNames = {} + local cameraEnumNameToItem = {} + for i = 1, #enumItems do + local displayName = enumItems[i].Name + if displayName == 'Default' then + displayName = CAMERA_MODE_DEFAULT_STRING + end + + if UserInputService.TouchEnabled then + if GameSettings.TouchCameraMovementMode == enumItems[i] then + startingCameraEnumItem = i + end + else + if GameSettings.ComputerCameraMovementMode == enumItems[i] then + startingCameraEnumItem = i + end + end + + cameraEnumNames[i] = displayName + cameraEnumNameToItem[displayName] = enumItems[i].Value + end + + this.CameraModeFrame, + this.CameraModeLabel, + this.CameraMode = utility:AddNewRow(this, "Camera Mode", "Selector", cameraEnumNames, startingCameraEnumItem) + + this.CameraModeOverrideText = utility:Create'TextLabel' + { + Name = "CameraDevOverrideLabel", + Text = "Set by Developer", + TextColor3 = Color3.new(1,1,1), + Font = Enum.Font.SourceSans, + FontSize = Enum.FontSize.Size24, + BackgroundTransparency = 1, + Size = UDim2.new(0,200,1,0), + Position = UDim2.new(1,-350,0,0), + Visible = false, + ZIndex = 2, + Parent = this.CameraModeFrame + }; + + this.CameraMode.IndexChanged:connect(function(newIndex) + local newEnumSetting = cameraEnumNameToItem[cameraEnumNames[newIndex]] + + if UserInputService.TouchEnabled then + GameSettings.TouchCameraMovementMode = newEnumSetting + else + GameSettings.ComputerCameraMovementMode = newEnumSetting + end + end) + end + + + ------------------------------------------------------ + ------------------ + ------------------ VR Camera Mode ----------------------- + + if HasVRAPI and UserInputService.VREnabled then + local VR_ROTATION_INTENSITY_OPTIONS = {"Low", "High", "Smooth"} + + if utility:IsSmallTouchScreen() then + this.VRRotationFrame, + this.VRRotationLabel, + this.VRRotationMode = utility:AddNewRow(this, "VR Camera Rotation", "Selector", VR_ROTATION_INTENSITY_OPTIONS, GameSettings.VRRotationIntensity) + else + this.VRRotationFrame, + this.VRRotationLabel, + this.VRRotationMode = utility:AddNewRow(this, "VR Camera Rotation", "Selector", VR_ROTATION_INTENSITY_OPTIONS, GameSettings.VRRotationIntensity, 3) + end + + StarterGui:RegisterGetCore("VRRotationIntensity", + function() + return VR_ROTATION_INTENSITY_OPTIONS[GameSettings.VRRotationIntensity] or VR_ROTATION_INTENSITY_OPTIONS[1] + end) + this.VRRotationMode.IndexChanged:connect(function(newIndex) + GameSettings.VRRotationIntensity = newIndex + end) + end + + ------------------------------------------------------ + ------------------ + ------------------ Movement Mode --------------------- + if movementModeEnabled then + local movementEnumItems = nil + local startingMovementEnumItem = 1 + if UserInputService.TouchEnabled then + movementEnumItems = Enum.TouchMovementMode:GetEnumItems() + else + movementEnumItems = Enum.ComputerMovementMode:GetEnumItems() + end + + local movementEnumNames = {} + local movementEnumNameToItem = {} + for i = 1, #movementEnumItems do + local displayName = movementEnumItems[i].Name + if displayName == "Default" then + displayName = MOVEMENT_MODE_DEFAULT_STRING + elseif displayName == "KeyboardMouse" then + displayName = MOVEMENT_MODE_KEYBOARDMOUSE_STRING + elseif displayName == "ClickToMove" then + displayName = MOVEMENT_MODE_CLICKTOMOVE_STRING + end + + if UserInputService.TouchEnabled then + if GameSettings.TouchMovementMode == movementEnumItems[i] then + startingMovementEnumItem = i + end + else + if GameSettings.ComputerMovementMode == movementEnumItems[i] then + startingMovementEnumItem = i + end + end + + movementEnumNames[i] = displayName + movementEnumNameToItem[displayName] = movementEnumItems[i] + end + + this.MovementModeFrame, + this.MovementModeLabel, + this.MovementMode = utility:AddNewRow(this, "Movement Mode", "Selector", movementEnumNames, startingMovementEnumItem) + + this.MovementModeOverrideText = utility:Create'TextLabel' + { + Name = "MovementDevOverrideLabel", + Text = "Set by Developer", + TextColor3 = Color3.new(1,1,1), + Font = Enum.Font.SourceSans, + FontSize = Enum.FontSize.Size24, + BackgroundTransparency = 1, + Size = UDim2.new(0,200,1,0), + Position = UDim2.new(1,-350,0,0), + Visible = false, + ZIndex = 2, + Parent = this.MovementModeFrame + }; + + this.MovementMode.IndexChanged:connect(function(newIndex) + local newEnumSetting = movementEnumNameToItem[movementEnumNames[newIndex]] + + if UserInputService.TouchEnabled then + GameSettings.TouchMovementMode = newEnumSetting + else + GameSettings.ComputerMovementMode = newEnumSetting + end + end) + end + + + ------------------------------------------------------ + ------------------ + ------------------------- Connection Setup ----------- + function setCameraModeVisible(visible) + if this.CameraMode then + this.CameraMode.SelectorFrame.Visible = visible + this.CameraMode:SetInteractable(visible) + end + end + + function setMovementModeVisible(visible) + if this.MovementMode then + this.MovementMode.SelectorFrame.Visible = visible + this.MovementMode:SetInteractable(visible) + end + end + + function setShiftLockVisible(visible) + if this.ShiftLockMode then + this.ShiftLockMode.SelectorFrame.Visible = visible + this.ShiftLockMode:SetInteractable(visible) + end + end + + do -- initial set of dev vs user choice for guis + local isUserChoiceCamera = false + if UserInputService.TouchEnabled then + isUserChoiceCamera = LocalPlayer.DevTouchCameraMode == Enum.DevTouchCameraMovementMode.UserChoice + else + isUserChoiceCamera = LocalPlayer.DevComputerCameraMode == Enum.DevComputerCameraMovementMode.UserChoice + end + + if not isUserChoiceCamera then + this.CameraModeOverrideText.Visible = true + setCameraModeVisible(false) + else + this.CameraModeOverrideText.Visible = false + setCameraModeVisible(true) + end + + + local isUserChoiceMovement = false + if UserInputService.TouchEnabled then + isUserChoiceMovement = LocalPlayer.DevTouchMovementMode == Enum.DevTouchMovementMode.UserChoice + else + isUserChoiceMovement = LocalPlayer.DevComputerMovementMode == Enum.DevComputerMovementMode.UserChoice + end + + if this.MovementModeOverrideText then + if not isUserChoiceMovement then + this.MovementModeOverrideText.Visible = true + setMovementModeVisible(false) + else + this.MovementModeOverrideText.Visible = false + setMovementModeVisible(true) + end + end + + if this.ShiftLockOverrideText then + this.ShiftLockOverrideText.Visible = not LocalPlayer.DevEnableMouseLock + setShiftLockVisible(LocalPlayer.DevEnableMouseLock) + end + end + + local function updateUserSettingsMenu(property) + if this.ShiftLockOverrideText and property == "DevEnableMouseLock" then + this.ShiftLockOverrideText.Visible = not LocalPlayer.DevEnableMouseLock + setShiftLockVisible(LocalPlayer.DevEnableMouseLock) + elseif property == "DevComputerCameraMode" then + local isUserChoice = LocalPlayer.DevComputerCameraMode == Enum.DevComputerCameraMovementMode.UserChoice + setCameraModeVisible(isUserChoice) + this.CameraModeOverrideText.Visible = not isUserChoice + elseif property == "DevComputerMovementMode" then + local isUserChoice = LocalPlayer.DevComputerMovementMode == Enum.DevComputerMovementMode.UserChoice + setMovementModeVisible(isUserChoice) + if this.MovementModeOverrideText then + this.MovementModeOverrideText.Visible = not isUserChoice + end + -- TOUCH + elseif property == "DevTouchMovementMode" then + local isUserChoice = LocalPlayer.DevTouchMovementMode == Enum.DevTouchMovementMode.UserChoice + setMovementModeVisible(isUserChoice) + if this.MovementModeOverrideText then + this.MovementModeOverrideText.Visible = not isUserChoice + end + elseif property == "DevTouchCameraMode" then + local isUserChoice = LocalPlayer.DevTouchCameraMode == Enum.DevTouchCameraMovementMode.UserChoice + setCameraModeVisible(isUserChoice) + this.CameraModeOverrideText.Visible = not isUserChoice + end + end + + LocalPlayer.Changed:connect(function(property) + if IsTouchClient then + if TOUCH_CHANGED_PROPS[property] then + updateUserSettingsMenu(property) + end + else + if PC_CHANGED_PROPS[property] then + updateUserSettingsMenu(property) + end + end + end) + end + + local function createVolumeOptions() + local startVolumeLevel = math.floor(GameSettings.MasterVolume * 10) + this.VolumeFrame, + this.VolumeLabel, + this.VolumeSlider = utility:AddNewRow(this, "Volume", "Slider", 10, startVolumeLevel) + + local volumeSound = Instance.new("Sound", game.CoreGui.RobloxGui.Sounds) + volumeSound.Name = "VolumeChangeSound" + volumeSound.SoundId = "rbxasset://sounds/metalstone2.mp3" + + this.VolumeSlider.ValueChanged:connect(function(newValue) + local soundPercent = newValue/10 + volumeSound.Volume = soundPercent + volumeSound:Play() + GameSettings.MasterVolume = soundPercent + end) + end + + local function createMouseOptions() + local MouseSteps = 10 + local MinMouseSensitivity = 0.2 + local AdvancedSuccess, AdvancedValue = pcall(function() return settings():GetFFlag("AdvancedMouseSensitivityEnabled") end) + local AdvancedEnabled = AdvancedSuccess and AdvancedValue + + -- equations below map a function to include points (0, 0.2) (5, 1) (10, 4) + -- where x is the slider position, y is the mouse sensitivity + local function translateEngineMouseSensitivityToGui(engineSensitivity) + return math.floor((2.0/3.0) * (math.sqrt(75.0 * engineSensitivity - 11.0) - 2)) + end + + local function translateGuiMouseSensitivityToEngine(guiSensitivity) + return 0.03 * math.pow(guiSensitivity,2) + (0.08 * guiSensitivity) + MinMouseSensitivity + end + + local startMouseLevel = translateEngineMouseSensitivityToGui(GameSettings.MouseSensitivity) + + ------------------ Mouse Selection GUI Setup ------------------ + -- switch between basic mode and advanced mode. + local MouseModeEnablerStart = 2 + if GameSettings.UseBasicMouseSensitivity or not AdvancedEnabled then + MouseModeEnablerStart = 1 + end + + -- auto-detect mouse invert + local MouseInvertStart = 1 + if GameSettings.MouseSensitivityFirstPerson.y < 0 then + MouseInvertStart = 2 + end + + if AdvancedEnabled then + this.MouseModeFrame, + this.MouseModeLabel, + this.MouseModeEnabler = utility:AddNewRow(this, "Mouse Sensitivity Mode", "Selector", {"Basic", "Advanced"}, MouseModeEnablerStart) + end + + ------------------ Basic Mouse Sensitivity Slider ------------------ + -- basic quantized sensitivity with a weird number of settings. + local SliderLabel = "Basic Mouse Sensitivity" + if not AdvancedEnabled then + SliderLabel = "Mouse Sensitivity" + end + this.MouseSensitivityFrame, + this.MouseSensitivityLabel, + this.MouseSensitivitySlider = utility:AddNewRow(this, SliderLabel, "Slider", MouseSteps, startMouseLevel) + this.MouseSensitivitySlider:SetMinStep(1) + + this.MouseSensitivitySlider.ValueChanged:connect(function(newValue) + GameSettings.MouseSensitivity = translateGuiMouseSensitivityToEngine(newValue) + end) + + ------------------ 3D Sensitivity ------------------ + -- affects both first and third person. + if AdvancedEnabled then + local MouseAdvancedStart = tostring(GameSettings.MouseSensitivityFirstPerson.y) + this.MouseAdvancedFrame, + this.MouseAdvancedLabel, + this.MouseAdvancedEntry = utility:AddNewRow(this, "Advanced Mouse Sensitivity", "TextEntry", 1.0, 1.0, MouseAdvancedStart) + + this.MouseAdvancedEntry.ValueChanged:connect(function(newValueText) + local currentFirstSensitivity = GameSettings.MouseSensitivityFirstPerson + local currentThirdSensitivity = GameSettings.MouseSensitivityThirdPerson + + local newValue = tonumber(newValueText) + if not newValue then + this.MouseAdvancedEntry:SetValue(string.format("%.3f",currentFirstSensitivity.x)) + return + end + + -- inverted mouse will be handled later + if newValue < 0.0 then + newValue = -newValue + end + + -- * assume a minimum that allows a 16000 dpi mouse a full 800mm travel for 360deg + -- ~0.0029: min of 0.001 seems ok. + -- * assume a max that allows a 400 dpi mouse a 360deg travel in 10mm + -- ~9.2: max of 10 seems ok, but users will want to have a bit of fun with crazy settings. + if newValue > 100.0 then + newValue = 100.0 + elseif newValue < 0.001 then + newValue = 0.001 + end + + -- try to keep ratios the same, even though they aren't exposed to the GUI + local firstPersonX = newValue + local firstPersonY = newValue * (currentFirstSensitivity.y / currentFirstSensitivity.x) + local thirdPersonX = newValue * (currentFirstSensitivity.x / currentThirdSensitivity.x) + local thirdPersonY = thirdPersonX * (currentThirdSensitivity.y / currentThirdSensitivity.x) + + -- handle invert + if currentFirstSensitivity.y < 0.0 then + firstPersonY = -firstPersonY + end + if currentThirdSensitivity.y < 0.0 then + thirdPersonY = -thirdPersonY + end + + GameSettings.MouseSensitivityFirstPerson = Vector2.new(firstPersonX, firstPersonY) + GameSettings.MouseSensitivityThirdPerson = Vector2.new(thirdPersonX, thirdPersonY) + this.MouseAdvancedEntry:SetValue(string.format("%.3f",firstPersonX)) + + end) + end + + ------------------ Mouse Invert ------------------ + -- This is a common setting in games, even if it is rare + if AdvancedEnabled then + this.MouseInvertFrame, + this.MouseInvertLabel, + this.MouseInvertEnabler = utility:AddNewRow(this, "Advanced Mouse Invert", "Selector", {"Normal", "Inverted"}, MouseInvertStart) + + this.MouseInvertEnabler.IndexChanged:connect(function(newIndex) + local currentFirstSensitivity = GameSettings.MouseSensitivityFirstPerson + local currentThirdSensitivity = GameSettings.MouseSensitivityThirdPerson + + if newIndex == 1 then + if currentFirstSensitivity.y < 0.0 then + currentFirstSensitivity = Vector2.new(currentFirstSensitivity.x, -currentFirstSensitivity.y) + currentThirdSensitivity = Vector2.new(currentThirdSensitivity.x, -currentThirdSensitivity.y) + end + elseif newIndex == 2 then + if currentFirstSensitivity.y > 0.0 then + currentFirstSensitivity = Vector2.new(currentFirstSensitivity.x, -currentFirstSensitivity.y) + currentThirdSensitivity = Vector2.new(currentThirdSensitivity.x, -currentThirdSensitivity.y) + end + end + GameSettings.MouseSensitivityFirstPerson = currentFirstSensitivity + GameSettings.MouseSensitivityThirdPerson = currentThirdSensitivity + end) + end + + ------------------ Init ------------------ + if AdvancedEnabled then + local function setMouseModeToBasic() + this.MouseSensitivitySlider:SetZIndex(2) + this.MouseSensitivityLabel.ZIndex = 2 + this.MouseSensitivitySlider:SetInteractable(true) + this.MouseSensitivitySlider:SetValue(translateEngineMouseSensitivityToGui(GameSettings.MouseSensitivity)) + + this.MouseAdvancedLabel.ZIndex = 1 + this.MouseAdvancedEntry:SetInteractable(false) + + this.MouseInvertLabel.ZIndex = 1 + this.MouseInvertEnabler:SetInteractable(false) + + end + local function setMouseModeToAdvanced() + this.MouseSensitivitySlider:SetZIndex(1) + this.MouseSensitivityLabel.ZIndex = 1 + this.MouseSensitivitySlider:SetInteractable(false) + + this.MouseAdvancedLabel.ZIndex = 2 + this.MouseAdvancedEntry:SetInteractable(true) + local MouseSensitivity3d = GameSettings.MouseSensitivityFirstPerson + this.MouseAdvancedEntry:SetValue(tostring(MouseSensitivity3d.x)); + + this.MouseInvertLabel.ZIndex = 2 + this.MouseInvertEnabler:SetInteractable(true) + + end + + this.MouseModeEnabler.IndexChanged:connect(function(newIndex) + if newIndex == 1 then + GameSettings.UseBasicMouseSensitivity = true + setMouseModeToBasic() + elseif newIndex == 2 then + GameSettings.UseBasicMouseSensitivity = false + setMouseModeToAdvanced() + end + end) + + if GameSettings.UseBasicMouseSensitivity then + setMouseModeToBasic() + this.MouseAdvancedEntry:SetValue(tostring(MouseAdvancedStart)) + else + setMouseModeToAdvanced() + end + end + + end + + local function createOverscanOption() + local showOverscanScreen = function() + + if not overscanScreen then + local createOverscanFunc = require(RobloxGui.Modules.OverscanScreen) + overscanScreen = createOverscanFunc(RobloxGui) + overscanScreen:SetStyleForInGame() + end + + local MenuModule = require(RobloxGui.Modules.Settings.SettingsHub) + MenuModule:SetVisibility(false, true) + + local closedCon = nil + closedCon = overscanScreen.Closed:connect(function() + closedCon:disconnect() + pcall(function() PlatformService.BlurIntensity = 0 end) + ContextActionService:UnbindCoreAction("RbxStopOverscanMovement") + MenuModule:SetVisibility(true, true) + end) + + pcall(function() PlatformService.BlurIntensity = 10 end) + + local noOpFunc = function() end + ContextActionService:BindCoreAction("RbxStopOverscanMovement", noOpFunc, false, + Enum.UserInputType.Gamepad1, Enum.UserInputType.Gamepad2, + Enum.UserInputType.Gamepad3, Enum.UserInputType.Gamepad4) + + local ScreenManager = require(RobloxGui.Modules.ScreenManager) + ScreenManager:OpenScreen(overscanScreen) + + end + + local adjustButton, adjustText, setButtonRowRef = utility:MakeStyledButton("AdjustButton", "Adjust", UDim2.new(0,300,1,-20), showOverscanScreen, this) + adjustText.Font = Enum.Font.SourceSans + adjustButton.Position = UDim2.new(1,-400,0,12) + + local row = utility:AddNewRowObject(this, "Safe Zone", adjustButton) + setButtonRowRef(row) + end + + createCameraModeOptions(not isTenFootInterface and + (UserInputService.TouchEnabled or UserInputService.MouseEnabled or UserInputService.KeyboardEnabled)) + + if UserInputService.MouseEnabled then + createMouseOptions() + end + + createVolumeOptions() + + if platform == Enum.Platform.Windows or platform == Enum.Platform.UWP or platform == Enum.Platform.OSX then + createGraphicsOptions() + end + + if isTenFootInterface then + createOverscanOption() + end + + ------ TAB CUSTOMIZATION ------- + this.TabHeader.Name = "GameSettingsTab" + + this.TabHeader.Icon.Image = "rbxasset://textures/ui/Settings/MenuBarIcons/GameSettingsTab.png" + if utility:IsSmallTouchScreen() then + this.TabHeader.Icon.Size = UDim2.new(0,34,0,34) + this.TabHeader.Icon.Position = UDim2.new(this.TabHeader.Icon.Position.X.Scale,this.TabHeader.Icon.Position.X.Offset,0.5,-17) + this.TabHeader.Size = UDim2.new(0,125,1,0) + elseif isTenFootInterface then + this.TabHeader.Icon.Image = "rbxasset://textures/ui/Settings/MenuBarIcons/GameSettingsTab@2x.png" + this.TabHeader.Icon.Size = UDim2.new(0,90,0,90) + this.TabHeader.Icon.Position = UDim2.new(0,0,0.5,-43) + this.TabHeader.Size = UDim2.new(0,280,1,0) + else + this.TabHeader.Icon.Size = UDim2.new(0,45,0,45) + this.TabHeader.Icon.Position = UDim2.new(0,15,0.5,-22) + end + + + this.TabHeader.Icon.Title.Text = "Settings" + + ------ PAGE CUSTOMIZATION ------- + this.Page.ZIndex = 5 + + return this +end + + +----------- Page Instantiation -------------- + +PageInstance = Initialize() + +return PageInstance diff --git a/2016/content/scripts/Modules/Settings/Pages/Help.lua b/2016/content/scripts/Modules/Settings/Pages/Help.lua new file mode 100644 index 0000000..7156dba --- /dev/null +++ b/2016/content/scripts/Modules/Settings/Pages/Help.lua @@ -0,0 +1,489 @@ +--[[ + Filename: Help.lua + Written by: jeditkacheff + Version 1.0 + Description: Takes care of the help page in Settings Menu +--]] +-------------- CONSTANTS -------------- +local KEYBOARD_MOUSE_TAG = "KeyboardMouse" +local TOUCH_TAG = "Touch" +local GAMEPAD_TAG = "Gamepad" +local PC_TABLE_SPACING = 4 + +-------------- SERVICES -------------- +local CoreGui = game:GetService("CoreGui") +local RobloxGui = CoreGui:WaitForChild("RobloxGui") +local UserInputService = game:GetService("UserInputService") +local GuiService = game:GetService("GuiService") + +----------- UTILITIES -------------- +local utility = require(RobloxGui.Modules.Settings.Utility) + +------------ Variables ------------------- +local PageInstance = nil +RobloxGui:WaitForChild("Modules"):WaitForChild("TenFootInterface") +local isTenFootInterface = require(RobloxGui.Modules.TenFootInterface):IsEnabled() + +----------- CLASS DECLARATION -------------- + +local function Initialize() + local settingsPageFactory = require(RobloxGui.Modules.Settings.SettingsPageFactory) + local this = settingsPageFactory:CreateNewPage() + this.HelpPages = {} + + -- TODO: Change dev console script to parent this to somewhere other than an engine created gui + local ControlFrame = RobloxGui:WaitForChild('ControlFrame') + local ToggleDevConsoleBindableFunc = ControlFrame:WaitForChild('ToggleDevConsole') + local lastInputType = nil + + function this:GetCurrentInputType() + if lastInputType == nil then -- we don't know what controls the user has, just use reasonable defaults + local platform = UserInputService:GetPlatform() + if platform == Enum.Platform.XBoxOne or platform == Enum.Platform.WiiU then + + return GAMEPAD_TAG + elseif platform == Enum.Platform.Windows or platform == Enum.Platform.OSX then + return KEYBOARD_MOUSE_TAG + else + return TOUCH_TAG + end + end + + if lastInputType == Enum.UserInputType.Keyboard or lastInputType == Enum.UserInputType.MouseMovement or + lastInputType == Enum.UserInputType.MouseButton1 or lastInputType == Enum.UserInputType.MouseButton2 or + lastInputType == Enum.UserInputType.MouseButton3 or lastInputType == Enum.UserInputType.MouseWheel then + return KEYBOARD_MOUSE_TAG + elseif lastInputType == Enum.UserInputType.Touch then + return TOUCH_TAG + elseif lastInputType == Enum.UserInputType.Gamepad1 or lastInputType == Enum.UserInputType.Gamepad2 or + inputType == Enum.UserInputType.Gamepad3 or lastInputType == Enum.UserInputType.Gamepad4 then + return GAMEPAD_TAG + end + + return KEYBOARD_MOUSE_TAG + end + + + local function createPCHelp(parentFrame) + local function createPCGroup(title, actionInputBindings) + local textIndent = 9 + + local pcGroupFrame = utility:Create'Frame' + { + Size = UDim2.new(1/3,-PC_TABLE_SPACING,1,0), + BackgroundTransparency = 1, + Name = "PCGroupFrame" .. tostring(title) + }; + local pcGroupTitle = utility:Create'TextLabel' + { + Position = UDim2.new(0,textIndent,0,0), + Size = UDim2.new(1,-textIndent,0,30), + BackgroundTransparency = 1, + Text = title, + Font = Enum.Font.SourceSansBold, + FontSize = Enum.FontSize.Size18, + TextColor3 = Color3.new(1,1,1), + TextXAlignment = Enum.TextXAlignment.Left, + Name = "PCGroupTitle" .. tostring(title), + ZIndex = 2, + Parent = pcGroupFrame + }; + + local count = 0 + local frameHeight = 42 + local spacing = 2 + local offset = pcGroupTitle.Size.Y.Offset + for i = 1, #actionInputBindings do + for actionName, inputName in pairs(actionInputBindings[i]) do + local actionInputFrame = utility:Create'Frame' + { + Size = UDim2.new(1,0,0,frameHeight), + Position = UDim2.new(0,0,0, offset + ((frameHeight + spacing) * count)), + BackgroundTransparency = 0.65, + BorderSizePixel = 0, + ZIndex = 2, + Name = "ActionInputBinding" .. tostring(actionName), + Parent = pcGroupFrame + }; + + local nameLabel = utility:Create'TextLabel' + { + Size = UDim2.new(0.4,-textIndent,0,frameHeight), + Position = UDim2.new(0,textIndent,0,0), + BackgroundTransparency = 1, + Text = actionName, + Font = Enum.Font.SourceSansBold, + FontSize = Enum.FontSize.Size18, + TextColor3 = Color3.new(1,1,1), + TextXAlignment = Enum.TextXAlignment.Left, + Name = actionName .. "Label", + ZIndex = 2, + Parent = actionInputFrame + }; + + local inputLabel = utility:Create'TextLabel' + { + Size = UDim2.new(0.6,0,0,frameHeight), + Position = UDim2.new(0.5,-4,0,0), + BackgroundTransparency = 1, + Text = inputName, + Font = Enum.Font.SourceSans, + FontSize = Enum.FontSize.Size18, + TextColor3 = Color3.new(1,1,1), + TextXAlignment = Enum.TextXAlignment.Left, + Name = inputName .. "Label", + ZIndex = 2, + Parent = actionInputFrame + }; + + count = count + 1 + end + end + + pcGroupFrame.Size = UDim2.new(pcGroupFrame.Size.X.Scale,pcGroupFrame.Size.X.Offset, + 0, offset + ((frameHeight + spacing) * count)) + + return pcGroupFrame + end + + local rowOffset = 50 + local isOSX = UserInputService:GetPlatform() == Enum.Platform.OSX + + local charMoveFrame = createPCGroup( "Character Movement", {[1] = {["Move Forward"] = "W/Up Arrow"}, + [2] = {["Move Backward"] = "S/Down Arrow"}, + [3] = {["Move Left"] = "A/Left Arrow"}, + [4] = {["Move Right"] = "D/Right Arrow"}, + [5] = {["Jump"] = "Space"}} ) + charMoveFrame.Parent = parentFrame + + local accessoriesFrame = createPCGroup("Accessories", { [1] = {["Equip Tools"] = "1,2,3..."}, + [2] = {["Unequip Tools"] = "1,2,3..."}, + [3] = {["Drop Tool"] = "Backspace"}, + [4] = {["Use Tool"] = "Left Mouse Button"}, + [5] = {["Drop Hats"] = "+"} }) + accessoriesFrame.Position = UDim2.new(1/3,PC_TABLE_SPACING,0,0) + accessoriesFrame.Parent = parentFrame + + local miscFrame = nil + local hideHudSuccess, hideHudFlagValue = pcall(function() return settings():GetFFlag("AllowHideHudShortcut") end) + if (hideHudSuccess and hideHudFlagValue) then + miscFrame = createPCGroup("Misc", { [1] = {["Screenshot"] = "Print Screen"}, + [2] = {["Record Video"] = isOSX and "F12/fn + F12" or "F12"}, + [3] = {["Hide HUD"] = isOSX and "F7/fn + F7" or "F7"}, + [4] = {["Dev Console"] = isOSX and "F9/fn + F9" or "F9"}, + [5] = {["Mouselock"] = "Shift"}, + [6] = {["Graphics Level"] = isOSX and "F10/fn + F10" or "F10"}, + [7] = {["Fullscreen"] = isOSX and "F11/fn + F11" or "F11"} }) + else + miscFrame = createPCGroup("Misc", { [1] = {["Screenshot"] = "Print Screen"}, + [2] = {["Record Video"] = isOSX and "F12/fn + F12" or "F12"}, + [3] = {["Dev Console"] = isOSX and "F9/fn + F9" or "F9"}, + [4] = {["Mouselock"] = "Shift"}, + [5] = {["Graphics Level"] = isOSX and "F10/fn + F10" or "F10"}, + [6] = {["Fullscreen"] = isOSX and "F11/fn + F11" or "F11"} }) + end + miscFrame.Position = UDim2.new(2/3,PC_TABLE_SPACING * 2,0,0) + miscFrame.Parent = parentFrame + + local camFrame = createPCGroup("Camera Movement", { [1] = {["Rotate"] = "Right Mouse Button"}, + [2] = {["Zoom In/Out"] = "Mouse Wheel"}, + [3] = {["Zoom In"] = "I"}, + [4] = {["Zoom Out"] = "O"} }) + camFrame.Position = UDim2.new(0,0,charMoveFrame.Size.Y.Scale,charMoveFrame.Size.Y.Offset + rowOffset) + camFrame.Parent = parentFrame + + local menuFrame = createPCGroup("Menu Items", { [1] = {["ROBLOX Menu"] = "ESC"}, + [2] = {["Backpack"] = "~"}, + [3] = {["Playerlist"] = "TAB"}, + [4] = {["Chat"] = "/"} }) + menuFrame.Position = UDim2.new(1/3,PC_TABLE_SPACING,charMoveFrame.Size.Y.Scale,charMoveFrame.Size.Y.Offset + rowOffset) + menuFrame.Parent = parentFrame + + parentFrame.Size = UDim2.new(parentFrame.Size.X.Scale, parentFrame.Size.X.Offset, 0, + menuFrame.Size.Y.Offset + menuFrame.Position.Y.Offset) + end + + local function createGamepadHelp(parentFrame) + local gamepadImage = "rbxasset://textures/ui/Settings/Help/GenericController.png" + local imageSize = UDim2.new(0,650,0,239) + local imagePosition = UDim2.new(0.5,-imageSize.X.Offset/2,0.5,-imageSize.Y.Offset/2) + if UserInputService:GetPlatform() == Enum.Platform.XBoxOne or UserInputService:GetPlatform() == Enum.Platform.XBox360 then + gamepadImage = "rbxasset://textures/ui/Settings/Help/XboxController.png" + imageSize = UDim2.new(0,1334,0,570) + imagePosition = UDim2.new(0.5, (-imageSize.X.Offset/2) - 50, 0.5, -imageSize.Y.Offset/2) + elseif UserInputService:GetPlatform() == Enum.Platform.PS4 or UserInputService:GetPlatform() == Enum.Platform.PS3 then + gamepadImage = "rbxasset://textures/ui/Settings/Help/PSController.png" + end + + local gamepadImageLabel = utility:Create'ImageLabel' + { + Name = "GamepadImage", + Size = imageSize, + Position = imagePosition, + Image = gamepadImage, + BackgroundTransparency = 1, + ZIndex = 2, + Parent = parentFrame + }; + parentFrame.Size = UDim2.new(parentFrame.Size.X.Scale, parentFrame.Size.X.Offset, 0, gamepadImageLabel.Size.Y.Offset + 100) + + local gamepadFontSize = isTenFootInterface and Enum.FontSize.Size36 or Enum.FontSize.Size24 + local function createGamepadLabel(text, position, size) + local nameLabel = utility:Create'TextLabel' + { + Position = position, + Size = size, + BackgroundTransparency = 1, + Text = text, + TextXAlignment = Enum.TextXAlignment.Left, + Font = Enum.Font.SourceSansBold, + FontSize = gamepadFontSize, + TextColor3 = Color3.new(1,1,1), + Name = text .. "Label", + ZIndex = 2, + Parent = gamepadImageLabel + }; + end + + local textVerticalSize = (gamepadFontSize == Enum.FontSize.Size36) and 36 or 24 + + if gamepadImage == "rbxasset://textures/ui/Settings/Help/XboxController.png" then + createGamepadLabel("Switch Tool", UDim2.new(0,50,0,-textVerticalSize/2), UDim2.new(0,100,0,textVerticalSize)) + createGamepadLabel("Game Menu Toggle", UDim2.new(0,-38,0.15,-textVerticalSize/2), UDim2.new(0,164,0,textVerticalSize)) + createGamepadLabel("Move", UDim2.new(0,-80,0.31,-textVerticalSize/2), UDim2.new(0,46,0,textVerticalSize)) + createGamepadLabel("Menu Navigation", UDim2.new(0,-50,0.46,-textVerticalSize/2), UDim2.new(0,164,0,textVerticalSize)) + createGamepadLabel("Use Tool", UDim2.new(0.96,0,0,-textVerticalSize/2), UDim2.new(0,73,0,textVerticalSize)) + createGamepadLabel("ROBLOX Menu", UDim2.new(0.96,0,0.15,-textVerticalSize/2), UDim2.new(0,122,0,textVerticalSize)) + createGamepadLabel("Back", UDim2.new(0.96,0,0.31,-textVerticalSize/2), UDim2.new(0,43,0,textVerticalSize)) + createGamepadLabel("Jump", UDim2.new(0.96,0,0.46,-textVerticalSize/2), UDim2.new(0,49,0,textVerticalSize)) + createGamepadLabel("Rotate Camera", UDim2.new(1,0,0.62,-textVerticalSize/2), UDim2.new(0,132,0,textVerticalSize)) + createGamepadLabel("Camera Zoom", UDim2.new(1,0,0.77,-textVerticalSize/2), UDim2.new(0,122,0,textVerticalSize)) + else + createGamepadLabel("Switch Tool", UDim2.new(-0.01,0,0,-textVerticalSize/2), UDim2.new(0,100,0,textVerticalSize)) + createGamepadLabel("Game Menu Toggle", UDim2.new(-0.11,0,0.15,-textVerticalSize/2), UDim2.new(0,164,0,textVerticalSize)) + createGamepadLabel("Move", UDim2.new(-0.08,0,0.31,-textVerticalSize/2), UDim2.new(0,46,0,textVerticalSize)) + createGamepadLabel("Menu Navigation", UDim2.new(-0.125,0,0.46,-textVerticalSize/2), UDim2.new(0,164,0,textVerticalSize)) + createGamepadLabel("Use Tool", UDim2.new(0.96,0,0,-textVerticalSize/2), UDim2.new(0,73,0,textVerticalSize)) + createGamepadLabel("ROBLOX Menu", UDim2.new(0.9,0,0.15,-textVerticalSize/2), UDim2.new(0,122,0,textVerticalSize)) + createGamepadLabel("Back", UDim2.new(1.01,0,0.31,-textVerticalSize/2), UDim2.new(0,43,0,textVerticalSize)) + createGamepadLabel("Jump", UDim2.new(0.91,0,0.46,-textVerticalSize/2), UDim2.new(0,49,0,textVerticalSize)) + createGamepadLabel("Rotate Camera", UDim2.new(0.91,0,0.62,-textVerticalSize/2), UDim2.new(0,132,0,textVerticalSize)) + createGamepadLabel("Camera Zoom", UDim2.new(0.91,0,0.77,-textVerticalSize/2), UDim2.new(0,122,0,textVerticalSize)) + end + + + -- todo: turn on dev console button when dev console is ready + --[[local openDevConsoleFunc = function() + this.HubRef:SetVisibility(false) + ToggleDevConsoleBindableFunc:Invoke() + end + local devConsoleButton = utility:MakeStyledButton("ConsoleButton", " Toggle Dev Console", UDim2.new(0,300,0,44), openDevConsoleFunc) + devConsoleButton.Size = UDim2.new(devConsoleButton.Size.X.Scale, devConsoleButton.Size.X.Offset, 0, 60) + devConsoleButton.Position = UDim2.new(1,-300,1,30) + if UserInputService.GamepadEnabled and not UserInputService.TouchEnabled and not UserInputService.MouseEnabled and not UserInputService.KeyboardEnabled then + devConsoleButton.ImageTransparency = 1 + end + devConsoleButton.Parent = gamepadImageLabel + local aButtonImage = utility:Create'ImageLabel' + { + Name = "AButtonImage", + Size = UDim2.new(0,55,0,55), + Position = UDim2.new(0,5,0.5,-28), + Image = "rbxasset://textures/ui/Settings/Help/AButtonDark.png", + BackgroundTransparency = 1, + ZIndex = 2, + Parent = devConsoleButton + }; + + this:AddRow(nil, nil, devConsoleButton, 340)]] + end + + local function createTouchHelp(parentFrame) + local smallScreen = utility:IsSmallTouchScreen() + local ySize = GuiService:GetScreenResolution().y - 350 + if smallScreen then + ySize = GuiService:GetScreenResolution().y - 100 + end + parentFrame.Size = UDim2.new(1,0,0,ySize) + + local function createTouchLabel(text, position, size, parent) + local nameLabel = utility:Create'TextLabel' + { + Position = position, + Size = size, + BackgroundTransparency = 1, + Text = text, + Font = Enum.Font.SourceSansBold, + FontSize = Enum.FontSize.Size14, + TextColor3 = Color3.new(1,1,1), + Name = text .. "Label", + ZIndex = 2, + Parent = parent + }; + if not smallScreen then + nameLabel.FontSize = Enum.FontSize.Size18 + nameLabel.Size = UDim2.new(nameLabel.Size.X.Scale, nameLabel.Size.X.Offset, nameLabel.Size.Y.Scale, nameLabel.Size.Y.Offset + 4) + end + local nameBackgroundImage = utility:Create'ImageLabel' + { + Name = text .. "BackgroundImage", + Size = UDim2.new(1,0,1,0), + Position = UDim2.new(0,0,0,2), + BackgroundTransparency = 1, + Image = "rbxasset://textures/ui/Settings/Radial/RadialLabel.png", + ScaleType = Enum.ScaleType.Slice, + SliceCenter = Rect.new(12,2,65,21), + ZIndex = 2, + Parent = nameLabel + }; + + return nameLabel + end + + local function createTouchGestureImage(name, image, position, size, parent) + local gestureImage = utility:Create'ImageLabel' + { + Name = name, + Size = size, + Position = position, + BackgroundTransparency = 1, + Image = image, + ZIndex = 2, + Parent = parent + }; + + return gestureImage + end + + local xSizeOffset = 30 + local ySize = 25 + if smallScreen then xSizeOffset = 0 end + + local moveLabel = createTouchLabel("Move", UDim2.new(0.06,0,0.58,0), UDim2.new(0,77 + xSizeOffset,0,ySize), parentFrame) + if not smallScreen then moveLabel.Position = UDim2.new(-0.03,0,0.7,0) end + local jumpLabel = createTouchLabel("Jump", UDim2.new(0.8,0,0.58,0), UDim2.new(0,77 + xSizeOffset,0,ySize), parentFrame) + if not smallScreen then jumpLabel.Position = UDim2.new(0.85,0,0.7,0) end + local equipLabel = createTouchLabel("Equip/Unequip Tools", UDim2.new(0.5,-60,0.64,0), UDim2.new(0,120 + xSizeOffset,0,ySize), parentFrame) + if not smallScreen then equipLabel.Position = UDim2.new(0.5,-60,0.95,0) end + + local zoomLabel = createTouchLabel("Zoom In/Out", UDim2.new(0.15,-60,0.02,0), UDim2.new(0,120,0,ySize), parentFrame) + createTouchGestureImage("ZoomImage", "rbxasset://textures/ui/Settings/Help/ZoomGesture.png", UDim2.new(0.5,-26,1,3), UDim2.new(0,53,0,59), zoomLabel) + local rotateLabel = createTouchLabel("Rotate Camera", UDim2.new(0.5,-60,0.02,0), UDim2.new(0,120,0,ySize), parentFrame) + createTouchGestureImage("RotateImage", "rbxasset://textures/ui/Settings/Help/RotateCameraGesture.png", UDim2.new(0.5,-32,1,3), UDim2.new(0,65,0,48), rotateLabel) + local useToolLabel = createTouchLabel("Use Tool", UDim2.new(0.85,-60,0.02,0), UDim2.new(0,120,0,ySize), parentFrame) + createTouchGestureImage("ToolImage", "rbxasset://textures/ui/Settings/Help/UseToolGesture.png", UDim2.new(0.5,-19,1,3), UDim2.new(0,38,0,52), useToolLabel) + + end + + local function createHelpDisplay(typeOfHelp) + local helpFrame = utility:Create'Frame' + { + Size = UDim2.new(1,0,1,0), + BackgroundTransparency = 1, + Name = "HelpFrame" .. tostring(typeOfHelp) + }; + + if typeOfHelp == KEYBOARD_MOUSE_TAG then + createPCHelp(helpFrame) + elseif typeOfHelp == GAMEPAD_TAG then + createGamepadHelp(helpFrame) + elseif typeOfHelp == TOUCH_TAG then + createTouchHelp(helpFrame) + end + + return helpFrame + end + + local function displayHelp(currentPage) + for i, helpPage in pairs(this.HelpPages) do + if helpPage == currentPage then + helpPage.Parent = this.Page + this.Page.Size = helpPage.Size + else + helpPage.Parent = nil + end + end + if UserInputService:GetPlatform() == Enum.Platform.XBoxOne then + this.HubRef.PageViewClipper.ClipsDescendants = false + this.HubRef.PageView.ClipsDescendants = false + end + end + + local function switchToHelp(typeOfHelp) + local helpPage = this.HelpPages[typeOfHelp] + if helpPage then + displayHelp(helpPage) + else + this.HelpPages[typeOfHelp] = createHelpDisplay(typeOfHelp) + switchToHelp(typeOfHelp) + end + end + + local function showTypeOfHelp() + switchToHelp(this:GetCurrentInputType()) + end + + ------ TAB CUSTOMIZATION ------- + this.TabHeader.Name = "HelpTab" + + this.TabHeader.Icon.Image = "rbxasset://textures/ui/Settings/MenuBarIcons/HelpTab.png" + + if utility:IsSmallTouchScreen() then + this.TabHeader.Icon.Size = UDim2.new(0,33,0,33) + this.TabHeader.Icon.Position = UDim2.new(this.TabHeader.Icon.Position.X.Scale,this.TabHeader.Icon.Position.X.Offset,0.5,-16) + this.TabHeader.Size = UDim2.new(0,100,1,0) + elseif isTenFootInterface then + this.TabHeader.Icon.Image = "rbxasset://textures/ui/Settings/MenuBarIcons/HelpTab@2x.png" + this.TabHeader.Icon.Size = UDim2.new(0,90,0,90) + this.TabHeader.Icon.Position = UDim2.new(0,0,0.5,-43) + this.TabHeader.Size = UDim2.new(0,210,1,0) + else + this.TabHeader.Icon.Size = UDim2.new(0,44,0,44) + this.TabHeader.Icon.Position = UDim2.new(this.TabHeader.Icon.Position.X.Scale,this.TabHeader.Icon.Position.X.Offset,0.5,-22) + this.TabHeader.Size = UDim2.new(0,130,1,0) + end + + this.TabHeader.Icon.Title.Text = "Help" + + + ------ PAGE CUSTOMIZATION ------- + this.Page.Name = "Help" + + UserInputService.InputBegan:connect(function(inputObject) + local inputType = inputObject.UserInputType + if inputType ~= Enum.UserInputType.Focus and inputType ~= Enum.UserInputType.None then + lastInputType = inputObject.UserInputType + showTypeOfHelp() + end + end) + + return this +end + + +----------- Public Facing API Additions -------------- +do + PageInstance = Initialize() + + PageInstance.Displayed.Event:connect(function() + if PageInstance:GetCurrentInputType() == TOUCH_TAG then + if PageInstance.HubRef.BottomButtonFrame and not utility:IsSmallTouchScreen() then + PageInstance.HubRef.BottomButtonFrame.Visible = false + end + end + end) + + PageInstance.Hidden.Event:connect(function() + PageInstance.HubRef.PageViewClipper.ClipsDescendants = true + PageInstance.HubRef.PageView.ClipsDescendants = true + + PageInstance.HubRef:ShowShield() + + if PageInstance:GetCurrentInputType() == TOUCH_TAG then + PageInstance.HubRef.BottomButtonFrame.Visible = true + end + end) +end + + +return PageInstance \ No newline at end of file diff --git a/2016/content/scripts/Modules/Settings/Pages/LeaveGame.lua b/2016/content/scripts/Modules/Settings/Pages/LeaveGame.lua new file mode 100644 index 0000000..e79086a --- /dev/null +++ b/2016/content/scripts/Modules/Settings/Pages/LeaveGame.lua @@ -0,0 +1,124 @@ +--[[ + Filename: LeaveGame.lua + Written by: jeditkacheff + Version 1.0 + Description: Takes care of the leave game in Settings Menu +--]] + + +-------------- CONSTANTS ------------- +local LEAVE_GAME_ACTION = "LeaveGameCancelAction" + +-------------- SERVICES -------------- +local CoreGui = game:GetService("CoreGui") +local ContextActionService = game:GetService("ContextActionService") +local RobloxGui = CoreGui:WaitForChild("RobloxGui") +local GuiService = game:GetService("GuiService") + +----------- UTILITIES -------------- +local utility = require(RobloxGui.Modules.Settings.Utility) + +------------ Variables ------------------- +local PageInstance = nil +RobloxGui:WaitForChild("Modules"):WaitForChild("TenFootInterface") +local isTenFootInterface = require(RobloxGui.Modules.TenFootInterface):IsEnabled() + + +----------- CLASS DECLARATION -------------- + +local function Initialize() + local settingsPageFactory = require(RobloxGui.Modules.Settings.SettingsPageFactory) + local this = settingsPageFactory:CreateNewPage() + + this.DontLeaveFunc = function(isUsingGamepad) + if this.HubRef then + this.HubRef:PopMenu(isUsingGamepad, true) + end + end + this.DontLeaveFromHotkey = function(name, state, input) + if state == Enum.UserInputState.Begin then + local isUsingGamepad = input.UserInputType == Enum.UserInputType.Gamepad1 or input.UserInputType == Enum.UserInputType.Gamepad2 + or input.UserInputType == Enum.UserInputType.Gamepad3 or input.UserInputType == Enum.UserInputType.Gamepad4 + + this.DontLeaveFunc(isUsingGamepad) + end + end + this.DontLeaveFromButton = function(isUsingGamepad) + this.DontLeaveFunc(isUsingGamepad) + end + + ------ TAB CUSTOMIZATION ------- + this.TabHeader = nil -- no tab for this page + + ------ PAGE CUSTOMIZATION ------- + this.Page.Name = "LeaveGamePage" + + local leaveGameText = utility:Create'TextLabel' + { + Name = "LeaveGameText", + Text = "Are you sure you want to leave the game?", + Font = Enum.Font.SourceSansBold, + FontSize = Enum.FontSize.Size36, + TextColor3 = Color3.new(1,1,1), + BackgroundTransparency = 1, + Size = UDim2.new(1,0,0,200), + TextWrapped = true, + ZIndex = 2, + Parent = this.Page + }; + if utility:IsSmallTouchScreen() then + leaveGameText.FontSize = Enum.FontSize.Size24 + leaveGameText.Size = UDim2.new(1,0,0,100) + elseif isTenFootInterface then + leaveGameText.FontSize = Enum.FontSize.Size48 + end + + local buttonSpacing = 20 + local buttonSize = UDim2.new(0, 200, 0, 50) + if isTenFootInterface then + leaveGameText.Position = UDim2.new(0,0,0,100) + buttonSize = UDim2.new(0, 300, 0, 80) + end + + this.LeaveGameButton = utility:MakeStyledButton("LeaveGame", "Leave", buttonSize) + this.LeaveGameButton.NextSelectionRight = nil + this.LeaveGameButton:SetVerb("Exit") + if utility:IsSmallTouchScreen() then + this.LeaveGameButton.Position = UDim2.new(0.5, -buttonSize.X.Offset - buttonSpacing, 1, 0) + else + this.LeaveGameButton.Position = UDim2.new(0.5, -buttonSize.X.Offset - buttonSpacing, 1, -30) + end + this.LeaveGameButton.Parent = leaveGameText + + + ------------- Init ---------------------------------- + + local dontleaveGameButton = utility:MakeStyledButton("DontLeaveGame", "Don't Leave", buttonSize, this.DontLeaveFromButton) + dontleaveGameButton.NextSelectionLeft = nil + if utility:IsSmallTouchScreen() then + dontleaveGameButton.Position = UDim2.new(0.5, buttonSpacing, 1, 0) + else + dontleaveGameButton.Position = UDim2.new(0.5, buttonSpacing, 1, -30) + end + dontleaveGameButton.Parent = leaveGameText + + this.Page.Size = UDim2.new(1,0,0,dontleaveGameButton.AbsolutePosition.Y + dontleaveGameButton.AbsoluteSize.Y) + + return this +end + + +----------- Public Facing API Additions -------------- +PageInstance = Initialize() + +PageInstance.Displayed.Event:connect(function() + GuiService.SelectedCoreObject = PageInstance.LeaveGameButton + ContextActionService:BindCoreAction(LEAVE_GAME_ACTION, PageInstance.DontLeaveFromHotkey, false, Enum.KeyCode.ButtonB) +end) + +PageInstance.Hidden.Event:connect(function() + ContextActionService:UnbindCoreAction(LEAVE_GAME_ACTION) +end) + + +return PageInstance \ No newline at end of file diff --git a/2016/content/scripts/Modules/Settings/Pages/Record.lua b/2016/content/scripts/Modules/Settings/Pages/Record.lua new file mode 100644 index 0000000..7f69056 --- /dev/null +++ b/2016/content/scripts/Modules/Settings/Pages/Record.lua @@ -0,0 +1,170 @@ +--[[r + Filename: Record.lua + Written by: jeditkacheff + Version 1.0 + Description: Takes care of the Record Tab in Settings Menu +--]] +-------------- SERVICES -------------- +local CoreGui = game:GetService("CoreGui") +local RobloxGui = CoreGui:WaitForChild("RobloxGui") +local GuiService = game:GetService("GuiService") +local Settings = UserSettings() +local GameSettings = Settings.GameSettings + +----------- UTILITIES -------------- +RobloxGui:WaitForChild("Modules"):WaitForChild("TenFootInterface") +local utility = require(RobloxGui.Modules.Settings.Utility) +local isTenFootInterface = require(RobloxGui.Modules.TenFootInterface):IsEnabled() + +------------ Variables ------------------- +local PageInstance = nil + +----------- CLASS DECLARATION -------------- + +local function Initialize() + local settingsPageFactory = require(RobloxGui.Modules.Settings.SettingsPageFactory) + local this = settingsPageFactory:CreateNewPage() + local isRecordingVideo = false + + local recordingEvent = Instance.new("BindableEvent") + recordingEvent.Name = "RecordingEvent" + this.RecordingChanged = recordingEvent.Event + function this:IsRecording() + return isRecordingVideo + end + + ------ TAB CUSTOMIZATION ------- + this.TabHeader.Name = "RecordTab" + + this.TabHeader.Icon.Image = "rbxasset://textures/ui/Settings/MenuBarIcons/RecordTab.png" + this.TabHeader.Icon.Size = UDim2.new(0,41,0,40) + this.TabHeader.Icon.Position = UDim2.new(0,5,0.5,-20) + + this.TabHeader.Icon.Title.Text = "Record" + + this.TabHeader.Size = UDim2.new(0,130,1,0) + + + ------ PAGE CUSTOMIZATION ------- + this.Page.Name = "Record" + + local function makeTextLabel(name, text, bold, size, pos, parent) + local textLabel = utility:Create'TextLabel' + { + Name = name, + BackgroundTransparency = 1, + Text = text, + TextWrapped = true, + Font = Enum.Font.SourceSans, + FontSize = Enum.FontSize.Size24, + TextColor3 = Color3.new(1,1,1), + Size = size, + Position = pos, + TextXAlignment = Enum.TextXAlignment.Left, + TextYAlignment = Enum.TextYAlignment.Top, + ZIndex = 2, + Parent = parent + }; + if bold then textLabel.Font = Enum.Font.SourceSansBold end + + return textLabel + end + + -- need to override this function from SettingsPageFactory + -- DropDown menus require hub to to be set when they are initialized + function this:SetHub(newHubRef) + this.HubRef = newHubRef + + local recordEnumNames = {} + recordEnumNames[1] = "Save To Disk" + recordEnumNames[2] = "Upload to YouTube" + + local startSetting = 2 + if GameSettings.VideoUploadPromptBehavior == Enum.UploadSetting["Never"] then + startSetting = 1 + end + + ---------------------------------- SCREENSHOT ------------------------------------- + local screenshotTitle = makeTextLabel("ScreenshotTitle", + "Screenshot", + true, UDim2.new(1,0,0,36), UDim2.new(0,10,0.05,0), this.Page) + screenshotTitle.FontSize = Enum.FontSize.Size36 + + local screenshotBody = makeTextLabel("ScreenshotBody", + "By clicking the 'Take Screenshot' button, the menu will close and take a screenshot and save it to your computer.", + false, UDim2.new(1,-10,0,70), UDim2.new(0,0,1,0), screenshotTitle) + + local closeSettingsFunc = function() + this.HubRef:SetVisibility(false, true) + end + this.ScreenshotButton = utility:MakeStyledButton("ScreenshotButton", "Take Screenshot", UDim2.new(0,300,0,44), closeSettingsFunc, this) + + this.ScreenshotButton.Position = UDim2.new(0,400,1,0) + this.ScreenshotButton.Parent = screenshotBody + + + ---------------------------------- VIDEO ------------------------------------- + local videoTitle = makeTextLabel("VideoTitle", + "Video", + true, UDim2.new(1,0,0,36), UDim2.new(0,10,0.5,0), this.Page) + videoTitle.FontSize = Enum.FontSize.Size36 + + local videoBody = makeTextLabel("VideoBody", + "By clicking the 'Record Video' button, the menu will close and start recording your screen.", + false, UDim2.new(1,-10,0,70), UDim2.new(0,0,1,0), videoTitle) + + this.VideoSettingsFrame, + this.VideoSettingsLabel, + this.VideoSettingsMode = utility:AddNewRow(this, "Video Settings", "Selector", recordEnumNames, startSetting, 270) + + this.VideoSettingsMode.IndexChanged:connect(function(newIndex) + if newIndex == 1 then + GameSettings.VideoUploadPromptBehavior = Enum.UploadSetting.Never + elseif newIndex == 2 then + GameSettings.VideoUploadPromptBehavior = Enum.UploadSetting.Always + end + end) + + + local recordButton = utility:MakeStyledButton("RecordButton", "Record Video", UDim2.new(0,300,0,44), closeSettingsFunc, this) + + recordButton.Position = UDim2.new(0,410,1,10) + recordButton.Parent = this.VideoSettingsMode.SelectorFrame.Parent + recordButton.MouseButton1Click:connect(function() + recordingEvent:Fire(not isRecordingVideo) + end) + + local gameOptions = settings():FindFirstChild("Game Options") + if gameOptions then + gameOptions.VideoRecordingChangeRequest:connect(function(recording) + isRecordingVideo = recording + if recording then + recordButton.RecordButtonTextLabel.Text = "Stop Recording" + else + recordButton.RecordButtonTextLabel.Text = "Record Video" + end + end) + end + + + recordButton:SetVerb("RecordToggle") + this.ScreenshotButton:SetVerb("Screenshot") + + this.Page.Size = UDim2.new(1,0,0,400) + end + + return this +end + + +----------- Public Facing API Additions -------------- +PageInstance = Initialize() + +PageInstance.Displayed.Event:connect(function(switchedFromGamepadInput) + if switchedFromGamepadInput then + GuiService.SelectedCoreObject = PageInstance.ScreenshotButton + end +end) + + +return PageInstance \ No newline at end of file diff --git a/2016/content/scripts/Modules/Settings/Pages/ReportAbuseMenu.lua b/2016/content/scripts/Modules/Settings/Pages/ReportAbuseMenu.lua new file mode 100644 index 0000000..d8c2b43 --- /dev/null +++ b/2016/content/scripts/Modules/Settings/Pages/ReportAbuseMenu.lua @@ -0,0 +1,311 @@ +--[[ + Filename: ReportAbuseMenu.lua + Written by: jeditkacheff + Version 1.0 + Description: Takes care of the report abuse page in Settings Menu +--]] + +-------------- SERVICES -------------- +local CoreGui = game:GetService("CoreGui") +local RobloxGui = CoreGui:WaitForChild("RobloxGui") +local GuiService = game:GetService("GuiService") +local PlayersService = game:GetService("Players") + +----------- UTILITIES -------------- +local utility = require(RobloxGui.Modules.Settings.Utility) + +------------ CONSTANTS ------------------- +local ABUSE_TYPES_PLAYER = { + "Swearing", + "Inappropriate Username", + "Bullying", + "Scamming", + "Dating", + "Cheating/Exploiting", + "Personal Question", + "Offsite Links", +} + +local ABUSE_TYPES_GAME = { + "Inappropriate Content", + "Bad Model or Script", + "Offsite Link", +} +local DEFAULT_ABUSE_DESC_TEXT = " Short Description (Optional)" +if utility:IsSmallTouchScreen() then + DEFAULT_ABUSE_DESC_TEXT = " (Optional)" +end + +------------ VARIABLES ------------------- +local PageInstance = nil + +----------- CLASS DECLARATION -------------- +local function Initialize() + local settingsPageFactory = require(RobloxGui.Modules.Settings.SettingsPageFactory) + local this = settingsPageFactory:CreateNewPage() + + local playerNames = {} + local nameToRbxPlayer = {} + + function this:GetPlayerFromIndex(index) + local playerName = playerNames[index] + if playerName then + return nameToRbxPlayer[nameToRbxPlayer] + end + + return nil + end + + function this:UpdatePlayerDropDown() + playerNames = {} + nameToRbxPlayer = {} + + local players = PlayersService:GetPlayers() + local index = 1 + for i = 1, #players do + local player = players[i] + if player ~= PlayersService.LocalPlayer and player.UserId > 0 then + playerNames[index] = player.Name + nameToRbxPlayer[player.Name] = player + index = index + 1 + end + end + + this.WhichPlayerMode:UpdateDropDownList(playerNames) + + if index == 1 then + this.GameOrPlayerMode:SetSelectionIndex(1) + this.TypeOfAbuseMode:UpdateDropDownList(ABUSE_TYPES_GAME) + end + + this.WhichPlayerMode:SetInteractable(index > 1 and this.GameOrPlayerMode.CurrentIndex ~= 1) + this.GameOrPlayerMode:SetInteractable(index > 1) + end + + ------ TAB CUSTOMIZATION ------- + this.TabHeader.Name = "ReportAbuseTab" + + this.TabHeader.Icon.Image = "rbxasset://textures/ui/Settings/MenuBarIcons/ReportAbuseTab.png" + if utility:IsSmallTouchScreen() then + this.TabHeader.Icon.Size = UDim2.new(0,27,0,32) + this.TabHeader.Size = UDim2.new(0,120,1,0) + else + this.TabHeader.Size = UDim2.new(0,150,1,0) + this.TabHeader.Icon.Size = UDim2.new(0,36,0,43) + end + this.TabHeader.Icon.Position = UDim2.new(this.TabHeader.Icon.Position.X.Scale, this.TabHeader.Icon.Position.X.Offset + 10, 0.5,-this.TabHeader.Icon.Size.Y.Offset/2) + + this.TabHeader.Icon.Title.Text = "Report" + + ------ PAGE CUSTOMIZATION ------- + this.Page.Name = "ReportAbusePage" + + -- need to override this function from SettingsPageFactory + -- DropDown menus require hub to to be set when they are initialized + function this:SetHub(newHubRef) + this.HubRef = newHubRef + + if utility:IsSmallTouchScreen() then + this.GameOrPlayerFrame, + this.GameOrPlayerLabel, + this.GameOrPlayerMode = utility:AddNewRow(this, "Game or Player?", "Selector", {"Game", "Player"}, 1) + else + this.GameOrPlayerFrame, + this.GameOrPlayerLabel, + this.GameOrPlayerMode = utility:AddNewRow(this, "Game or Player?", "Selector", {"Game", "Player"}, 1, 3) + end + + this.WhichPlayerFrame, + this.WhichPlayerLabel, + this.WhichPlayerMode = utility:AddNewRow(this, "Which Player?", "DropDown", {"update me"}) + this.WhichPlayerMode:SetInteractable(false) + this.WhichPlayerLabel.ZIndex = 1 + + this.TypeOfAbuseFrame, + this.TypeOfAbuseLabel, + this.TypeOfAbuseMode = utility:AddNewRow(this, "Type Of Abuse", "DropDown", ABUSE_TYPES_GAME) + + if utility:IsSmallTouchScreen() then + this.AbuseDescriptionFrame, + this.AbuseDescriptionLabel, + this.AbuseDescription = utility:AddNewRow(this, DEFAULT_ABUSE_DESC_TEXT, "TextBox", nil, nil) + else + this.AbuseDescriptionFrame, + this.AbuseDescriptionLabel, + this.AbuseDescription = utility:AddNewRow(this, DEFAULT_ABUSE_DESC_TEXT, "TextBox", nil, nil, 5) + end + + if utility:IsSmallTouchScreen() then + this.AbuseDescription.Selection.Size = UDim2.new(0, 290, 0, 30) + this.AbuseDescription.Selection.Position = UDim2.new(1,-345,this.AbuseDescription.Selection.Position.Y.Scale, this.AbuseDescription.Selection.Position.Y.Offset) + + this.AbuseDescriptionLabel = this.TypeOfAbuseLabel:clone() + this.AbuseDescriptionLabel.Text = "Abuse Description" + this.AbuseDescriptionLabel.Position = UDim2.new(this.AbuseDescriptionLabel.Position.X.Scale, this.AbuseDescriptionLabel.Position.X.Offset, + 0,50) + this.AbuseDescriptionLabel.Parent = this.Page + end + + local SelectionOverrideObject = utility:Create'ImageLabel' + { + Image = "", + BackgroundTransparency = 1 + }; + + local submitButton, submitText = nil, nil + + local function makeSubmitButtonActive() + submitButton.ZIndex = 2 + submitButton.Selectable = true + submitText.ZIndex = 2 + end + + local function makeSubmitButtonInactive() + submitButton.ZIndex = 1 + submitButton.Selectable = false + submitText.ZIndex = 1 + end + + local function updateAbuseDropDown() + this.WhichPlayerMode:ResetSelectionIndex() + this.TypeOfAbuseMode:ResetSelectionIndex() + + if this.GameOrPlayerMode.CurrentIndex == 1 then + this.TypeOfAbuseMode:UpdateDropDownList(ABUSE_TYPES_GAME) + this.WhichPlayerMode:SetInteractable(false) + this.WhichPlayerLabel.ZIndex = 1 + this.GameOrPlayerMode.SelectorFrame.NextSelectionDown = this.TypeOfAbuseMode.DropDownFrame + else + this.TypeOfAbuseMode:UpdateDropDownList(ABUSE_TYPES_PLAYER) + this.WhichPlayerMode:SetInteractable(true) + this.WhichPlayerLabel.ZIndex = 2 + this.GameOrPlayerMode.SelectorFrame.NextSelectionDown = this.WhichPlayerMode.DropDownFrame + end + makeSubmitButtonInactive() + end + + local function cleanupReportAbuseMenu() + updateAbuseDropDown() + this.AbuseDescription.Selection.Text = DEFAULT_ABUSE_DESC_TEXT + this.HubRef:SetVisibility(false, true) + end + + local function onReportSubmitted() + local abuseReason = nil + if this.GameOrPlayerMode.CurrentIndex == 2 then + abuseReason = ABUSE_TYPES_PLAYER[this.TypeOfAbuseMode.CurrentIndex] + + local currentAbusingPlayer = this:GetPlayerFromIndex(this.WhichPlayerMode.CurrentIndex) + if currentAbusingPlayer and abuseReason then + spawn(function() + game.Players:ReportAbuse(currentAbusingPlayer, abuseReason, this.AbuseDescription.Selection.Text) + end) + end + else + abuseReason = ABUSE_TYPES_GAME[this.TypeOfAbuseMode.CurrentIndex] + if abuseReason then + spawn(function() + game.Players:ReportAbuse(nil, abuseReason, this.AbuseDescription.Selection.Text) + end) + end + end + + if abuseReason then + local alertText = "Thanks for your report! Our moderators will review the chat logs and evaluate what happened." + + if abuseReason == 'Cheating/Exploiting' then + alertText = "Thanks for your report! We've recorded your report for evaluation." + elseif abuseReason == 'Inappropriate Username' then + alertText = "Thanks for your report! Our moderators will evaluate the username." + elseif abuseReason == "Bad Model or Script" or abuseReason == "Inappropriate Content" or abuseReason == "Offsite Link" or abuseReason == "Offsite Links" then + alertText = "Thanks for your report! Our moderators will review the place and make a determination." + end + + utility:ShowAlert(alertText, "Ok", this.HubRef, cleanupReportAbuseMenu) + + this.LastSelectedObject = nil + end + end + + submitButton, submitText = utility:MakeStyledButton("SubmitButton", "Submit", UDim2.new(0,198,0,50), onReportSubmitted, this) + if utility:IsSmallTouchScreen() then + submitButton.Position = UDim2.new(1,-220,1,5) + else + submitButton.Position = UDim2.new(1,-194,1,5) + end + submitButton.Selectable = false + submitButton.ZIndex = 1 + submitText.ZIndex = 1 + submitButton.Parent = this.AbuseDescription.Selection + + local function playerSelectionChanged(newIndex) + if newIndex ~= nil and this.TypeOfAbuseMode:GetSelectedIndex() ~= nil then + makeSubmitButtonActive() + else + makeSubmitButtonInactive() + end + end + this.WhichPlayerMode.IndexChanged:connect(playerSelectionChanged) + + local function typeOfAbuseChanged(newIndex) + if newIndex ~= nil then + if this.GameOrPlayerMode.CurrentIndex == 1 or this.WhichPlayerMode:GetSelectedIndex() ~= nil then + makeSubmitButtonActive() + else + makeSubmitButtonInactive() + end + else + makeSubmitButtonInactive() + end + end + this.TypeOfAbuseMode.IndexChanged:connect(typeOfAbuseChanged) + + this.GameOrPlayerMode.IndexChanged:connect(updateAbuseDropDown) + + this:AddRow(nil, nil, this.AbuseDescription) + + this.Page.Size = UDim2.new(1,0,0,submitButton.AbsolutePosition.Y + submitButton.AbsoluteSize.Y) + end + + return this +end + + +----------- Public Facing API Additions -------------- +do + PageInstance = Initialize() + + PageInstance.Displayed.Event:connect(function() + PageInstance:UpdatePlayerDropDown() + end) + + function PageInstance:ReportPlayer(player) + if player then + local setReportPlayerConnection = nil + setReportPlayerConnection = PageInstance.Displayed.Event:connect(function() + -- When we change the SelectionIndex of GameOrPlayerMode it waits until the tween is done + -- before it fires the IndexChanged signal. The WhichPlayerMode dropdown listens to this signal + -- and resets when it is fired. Therefore we need to listen to this signal and set the player we want + -- to report the frame after the dropdown is reset + local indexChangedConnection = nil + indexChangedConnection = PageInstance.GameOrPlayerMode.IndexChanged:connect(function() + if indexChangedConnection then + indexChangedConnection:disconnect() + indexChangedConnection = nil + end + PageInstance.WhichPlayerMode:SetSelectionByValue(player.Name) + end) + PageInstance.GameOrPlayerMode:SetSelectionIndex(2) + + if setReportPlayerConnection then + setReportPlayerConnection:disconnect() + setReportPlayerConnection = nil + end + end) + PageInstance.HubRef:SetVisibility(true, false, PageInstance) + end + end +end + + +return PageInstance diff --git a/2016/content/scripts/Modules/Settings/SettingsHub.lua b/2016/content/scripts/Modules/Settings/SettingsHub.lua new file mode 100644 index 0000000..5e3b108 --- /dev/null +++ b/2016/content/scripts/Modules/Settings/SettingsHub.lua @@ -0,0 +1,1122 @@ +--[[ + Filename: SettingsHub.lua + Written by: jeditkacheff + Version 1.0 + Description: Controls the settings menu navigation and contains the settings pages +--]] + +--[[ CONSTANTS ]] +local SETTINGS_SHIELD_COLOR = Color3.new(41/255,41/255,41/255) +local SETTINGS_SHIELD_TRANSPARENCY = 0.2 +local SETTINGS_SHIELD_VR_TRANSPARENCY = 1 +local SETTINGS_SHIELD_SIZE = UDim2.new(1, 0, 1, 0) +local SETTINGS_SHIELD_INACTIVE_POSITION = UDim2.new(0,0,-1,-36) +local SETTINGS_SHIELD_ACTIVE_POSITION = UDim2.new(0, 0, 0, 0) +local SETTINGS_BASE_ZINDEX = 2 +local DEV_CONSOLE_ACTION_NAME = "Open Dev Console" + +--[[ SERVICES ]] +local CoreGui = game:GetService("CoreGui") +local RobloxGui = CoreGui:WaitForChild("RobloxGui") +local ContextActionService = game:GetService("ContextActionService") +local GuiService = game:GetService("GuiService") +local UserInputService = game:GetService("UserInputService") +local RunService = game:GetService("RunService") + +--[[ UTILITIES ]] +local utility = require(RobloxGui.Modules.Settings.Utility) + +--[[ VARIABLES ]] +local isTouchDevice = UserInputService.TouchEnabled +local isSmallTouchScreen = utility:IsSmallTouchScreen() +RobloxGui:WaitForChild("Modules"):WaitForChild("TenFootInterface") +local isTenFootInterface = require(RobloxGui.Modules.TenFootInterface):IsEnabled() +local platform = UserInputService:GetPlatform() +-- TODO: Change dev console script to parent this to somewhere other than an engine created gui +local ControlFrame = RobloxGui:WaitForChild('ControlFrame') +local ToggleDevConsoleBindableFunc = ControlFrame:WaitForChild('ToggleDevConsole') +local lastInputChangedCon = nil +local chatWasVisible = false +local userlistSuccess, userlistFlagValue = pcall(function() return settings():GetFFlag("UseUserListMenu") end) +local useUserList = (userlistSuccess and userlistFlagValue == true) + +local VREnabled = false + +local function IsPlayMyPlaceEnabled() + if UserInputService:GetPlatform() == Enum.Platform.XBoxOne then + local playMyPlaceSuccess, playMyPlaceFlagValue = pcall(function() return settings():GetFFlag("XboxPlayMyPlace") end) + return (playMyPlaceSuccess and playMyPlaceFlagValue == true) + end + return false +end + + +--[[ CORE MODULES ]] +local chat = require(RobloxGui.Modules.Chat) + +if isSmallTouchScreen or isTenFootInterface then + SETTINGS_SHIELD_ACTIVE_POSITION = UDim2.new(0,0,0,0) + SETTINGS_SHIELD_SIZE = UDim2.new(1,0,1,0) +end + +local function CreateSettingsHub() + local this = {} + this.Visible = false + this.Active = false + this.Pages = {CurrentPage = nil, PageTable = {}} + this.MenuStack = {} + this.TabHeaders = {} + this.BottomBarButtons = {} + this.TabConnection = nil + this.LeaveGamePage = require(RobloxGui.Modules.Settings.Pages.LeaveGame) + this.ResetCharacterPage = require(RobloxGui.Modules.Settings.Pages.ResetCharacter) + this.SettingsShowSignal = utility:CreateSignal() + this.OpenStateChangedCount = 0 + + local pageChangeCon = nil + + local PoppedMenuEvent = Instance.new("BindableEvent") + PoppedMenuEvent.Name = "PoppedMenu" + this.PoppedMenu = PoppedMenuEvent.Event + + local function setBottomBarBindings() + for i = 1, #this.BottomBarButtons do + local buttonTable = this.BottomBarButtons[i] + local buttonName = buttonTable[1] + local hotKeyTable = buttonTable[2] + ContextActionService:BindCoreAction(buttonName, hotKeyTable[1], false, unpack(hotKeyTable[2])) + end + + if this.BottomButtonFrame then + this.BottomButtonFrame.Visible = true + end + end + + local function removeBottomBarBindings(delayBeforeRemoving) + for _, hotKeyTable in pairs(this.BottomBarButtons) do + ContextActionService:UnbindCoreAction(hotKeyTable[1]) + end + + local myOpenStateChangedCount = this.OpenStateChangedCount + local remove = function() + if this.OpenStateChangedCount == myOpenStateChangedCount and this.BottomButtonFrame then + this.BottomButtonFrame.Visible = false + end + end + + if delayBeforeRemoving then + delay(delayBeforeRemoving, remove) + else + remove() + end + end + + local function addBottomBarButton(name, text, gamepadImage, keyboardImage, position, clickFunc, hotkeys) + local buttonName = name .. "Button" + local textName = name .. "Text" + + local size = UDim2.new(0,260,0,70) + if isTenFootInterface then + size = UDim2.new(0,320,0,120) + end + + this[buttonName], this[textName] = utility:MakeStyledButton(name .. "Button", text, size, clickFunc, nil, this) + this[buttonName].Position = position + this[buttonName].Parent = this.BottomButtonFrame + if isTenFootInterface then + this[buttonName].ImageTransparency = 1 + end + + this[textName].FontSize = Enum.FontSize.Size24 + local hintLabel = nil + + if not isTouchDevice then + this[textName].Size = UDim2.new(1,0,1,0) + if isTenFootInterface then + this[textName].Position = UDim2.new(0,60,0,-4) + else + this[textName].Position = UDim2.new(0,10,0,-4) + end + + local hintNameText = name .. "HintText" + local hintName = name .. "Hint" + local image = "" + if UserInputService:GetGamepadConnected(Enum.UserInputType.Gamepad1) or platform == Enum.Platform.XBoxOne then + image = gamepadImage + else + image = keyboardImage + end + + hintLabel = utility:Create'ImageLabel' + { + Name = hintName, + Size = UDim2.new(0,60,0,60), + Position = UDim2.new(0,10,0,5), + ZIndex = this.Shield.ZIndex + 2, + BackgroundTransparency = 1, + Image = image, + Parent = this[buttonName] + }; + if isTenFootInterface then + hintLabel.Size = UDim2.new(0,90,0,90) + hintLabel.Position = UDim2.new(0,10,0.5,-45) + elseif UserInputService.MouseEnabled then + hintLabel.Image = keyboardImage + hintLabel.Size = UDim2.new(0,48,0,48) + hintLabel.Position = UDim2.new(0,10,0,8) + end + end + + if isTenFootInterface then + this[textName].FontSize = Enum.FontSize.Size36 + end + + UserInputService.InputBegan:connect(function(inputObject) + if inputObject.UserInputType == Enum.UserInputType.Gamepad1 or inputObject.UserInputType == Enum.UserInputType.Gamepad2 or + inputObject.UserInputType == Enum.UserInputType.Gamepad3 or inputObject.UserInputType == Enum.UserInputType.Gamepad4 then + if hintLabel then + hintLabel.Image = gamepadImage + if isTenFootInterface then + hintLabel.Size = UDim2.new(0,90,0,90) + hintLabel.Position = UDim2.new(0,10,0.5,-45) + else + hintLabel.Size = UDim2.new(0,60,0,60) + hintLabel.Position = UDim2.new(0,10,0,5) + end + end + elseif inputObject.UserInputType == Enum.UserInputType.Keyboard then + if hintLabel then + hintLabel.Image = keyboardImage + hintLabel.Size = UDim2.new(0,48,0,48) + hintLabel.Position = UDim2.new(0,10,0,8) + end + end + end) + + local hotKeyFunc = function(contextName, inputState, inputObject) + if inputState == Enum.UserInputState.Begin then + clickFunc() + end + end + + local hotKeyTable = {hotKeyFunc, hotkeys} + this.BottomBarButtons[#this.BottomBarButtons + 1] = {buttonName, hotKeyTable} + end + + local function createGui() + local PageViewSizeReducer = 0 + if isSmallTouchScreen then + PageViewSizeReducer = 5 + end + + this.ClippingShield = utility:Create'Frame' + { + Name = "SettingsShield", + Size = SETTINGS_SHIELD_SIZE, + Position = SETTINGS_SHIELD_ACTIVE_POSITION, + BorderSizePixel = 0, + ClipsDescendants = true, + BackgroundTransparency = 1, + Visible = true, + ZIndex = SETTINGS_BASE_ZINDEX, + Parent = RobloxGui + }; + + this.Shield = utility:Create'Frame' + { + Name = "SettingsShield", + Size = UDim2.new(1,0,1,0), + Position = SETTINGS_SHIELD_INACTIVE_POSITION, + BackgroundTransparency = SETTINGS_SHIELD_TRANSPARENCY, + BackgroundColor3 = SETTINGS_SHIELD_COLOR, + BorderSizePixel = 0, + Visible = false, + Active = true, + ZIndex = SETTINGS_BASE_ZINDEX, + Parent = this.ClippingShield + }; + + this.Modal = utility:Create'TextButton' -- Force unlocks the mouse, really need a way to do this via UIS + { + Name = 'Modal', + BackgroundTransparency = 1, + Position = UDim2.new(0, 0, 1, -1), + Size = UDim2.new(1, 0, 1, 0), + Modal = true, + Text = '', + Parent = this.Shield, + Selectable = false + } + + this.HubBar = utility:Create'ImageLabel' + { + Name = "HubBar", + ZIndex = this.Shield.ZIndex + 1, + BorderSizePixel = 0, + BackgroundColor3 = Color3.new(78/255, 84/255, 96/255), + BackgroundTransparency = 1, + Image = "rbxasset://textures/ui/Settings/MenuBarAssets/MenuBackground.png", + ScaleType = Enum.ScaleType.Slice, + SliceCenter = Rect.new(4,4,6,6), + Parent = this.Shield + }; + + local barHeight = 60 + if isSmallTouchScreen then + barHeight = 40 + this.HubBar.Size = UDim2.new(1,-10,0,40) + this.HubBar.Position = UDim2.new(0,5,0,6) + elseif isTenFootInterface then + barHeight = 100 + this.HubBar.Size = UDim2.new(0,1200,0,100) + this.HubBar.Position = UDim2.new(0.5,-600,0.1,0) + else + this.HubBar.Size = UDim2.new(0,800,0,60) + this.HubBar.Position = UDim2.new(0.5,-400,0.1,0) + end + + this.PageViewClipper = utility:Create'Frame' + { + Name = 'PageViewClipper', + BackgroundTransparency = 1, + Size = UDim2.new(this.HubBar.Size.X.Scale,this.HubBar.Size.X.Offset, + 1, -this.HubBar.Size.Y.Offset - this.HubBar.Position.Y.Offset - PageViewSizeReducer), + Position = UDim2.new(this.HubBar.Position.X.Scale, this.HubBar.Position.X.Offset, + this.HubBar.Position.Y.Scale, this.HubBar.Position.Y.Offset + this.HubBar.Size.Y.Offset + 1), + ClipsDescendants = true, + Parent = this.Shield, + + utility:Create'ImageButton'{ + Name = 'InputCapture', + BackgroundTransparency = 1, + Size = UDim2.new(1, 0, 1, 0), + Image = '' + } + } + + this.PageView = utility:Create'ScrollingFrame' + { + Name = "PageView", + Size = UDim2.new(1, 0, 1, 0), + ZIndex = this.Shield.ZIndex, + BackgroundTransparency = 1, + BorderSizePixel = 0, + Selectable = false, + Parent = this.PageViewClipper, + }; + if UserInputService.MouseEnabled then + this.PageViewClipper.Size = UDim2.new(this.HubBar.Size.X.Scale,this.HubBar.Size.X.Offset, + 0.5, -(this.HubBar.Position.Y.Offset - this.HubBar.Size.Y.Offset)) + end + + if isSmallTouchScreen then + this.PageView.CanvasSize = this.PageViewClipper.Size + else + local bottomOffset = 0 + if isTouchDevice and not UserInputService.MouseEnabled then + bottomOffset = 80 + end + this.BottomButtonFrame = utility:Create'Frame' + { + Name = "BottomButtonFrame", + Size = this.HubBar.Size, + Position = UDim2.new(0.5, -this.HubBar.Size.X.Offset/2, 1-this.HubBar.Position.Y.Scale-this.HubBar.Size.Y.Scale, -this.HubBar.Position.Y.Offset-this.HubBar.Size.Y.Offset), + ZIndex = this.Shield.ZIndex + 1, + BackgroundTransparency = 1, + Parent = this.Shield + }; + + local leaveGameFunc = function() + this:AddToMenuStack(this.Pages.CurrentPage) + this.HubBar.Visible = false + removeBottomBarBindings() + this:SwitchToPage(this.LeaveGamePage, nil, 1, true) + end + + local resetCharFunc = function() + this:AddToMenuStack(this.Pages.CurrentPage) + this.HubBar.Visible = false + removeBottomBarBindings() + this:SwitchToPage(this.ResetCharacterPage, nil, 1, true) + end + + -- Xbox Only + local inviteToGameFunc = function() + local platformService = game:GetService('PlatformService') + if platformService then + platformService:PopupGameInviteUI() + end + end + + local resumeFunc = function() + setVisibilityInternal(false) + end + + local buttonImageAppend = "" + + if isTenFootInterface then + buttonImageAppend = "@2x" + end + + if UserInputService:GetPlatform() == Enum.Platform.XBoxOne then + local function createInviteButton() + addBottomBarButton("InviteToGame", "Send Game Invites", "rbxasset://textures/ui/Settings/Help/XButtonLight" .. buttonImageAppend .. ".png", + "", UDim2.new(0.5,isTenFootInterface and -160 or -130,0.5,-25), + inviteToGameFunc, {Enum.KeyCode.ButtonX}) + end + + if IsPlayMyPlaceEnabled() then + spawn(function() + local PlatformService = nil + pcall(function() PlatformService = game:GetService('PlatformService') end) + local pmpCreatorId = PlatformService and PlatformService:BeginGetPMPCreatorId() + if pmpCreatorId == 0 then + createInviteButton() + end + end) + else + createInviteButton() + end + else + addBottomBarButton("LeaveGame", "Leave Game", "rbxasset://textures/ui/Settings/Help/XButtonLight" .. buttonImageAppend .. ".png", + "rbxasset://textures/ui/Settings/Help/LeaveIcon.png", UDim2.new(0.5,isTenFootInterface and -160 or -130,0.5,-25), + leaveGameFunc, {Enum.KeyCode.L, Enum.KeyCode.ButtonX}) + end + + addBottomBarButton("ResetCharacter", " Reset Character", "rbxasset://textures/ui/Settings/Help/YButtonLight" .. buttonImageAppend .. ".png", + "rbxasset://textures/ui/Settings/Help/ResetIcon.png", UDim2.new(0.5,isTenFootInterface and -550 or -400,0.5,-25), + resetCharFunc, {Enum.KeyCode.R, Enum.KeyCode.ButtonY}) + addBottomBarButton("Resume", "Resume Game", "rbxasset://textures/ui/Settings/Help/BButtonLight" .. buttonImageAppend .. ".png", + "rbxasset://textures/ui/Settings/Help/EscapeIcon.png", UDim2.new(0.5,isTenFootInterface and 200 or 140,0.5,-25), + resumeFunc, {Enum.KeyCode.ButtonB, Enum.KeyCode.ButtonStart}) + end + + local function onScreenSizeChanged() + local largestPageSize = 600 + local fullScreenSize = RobloxGui.AbsoluteSize.y + local bufferSize = (1-0.95) * fullScreenSize + if isTenFootInterface then + largestPageSize = 800 + bufferSize = 0.07 * fullScreenSize + elseif isSmallTouchScreen then + bufferSize = (1-0.99) * fullScreenSize + end + local barSize = this.HubBar.Size.Y.Offset + local extraSpace = bufferSize*2+barSize*2 + + + local usableScreenHeight = fullScreenSize - extraSpace + local minimumPageSize = 150 + local usePageSize = nil + + if largestPageSize < usableScreenHeight then + usePageSize = largestPageSize + this.HubBar.Position = UDim2.new( + this.HubBar.Position.X.Scale, + this.HubBar.Position.X.Offset, + 0.5, + -largestPageSize/2 - this.HubBar.Size.Y.Offset + ) + if this.BottomButtonFrame then + this.BottomButtonFrame.Position = UDim2.new( + this.BottomButtonFrame.Position.X.Scale, + this.BottomButtonFrame.Position.X.Offset, + 0.5, + largestPageSize/2 + ) + end + elseif usableScreenHeight < minimumPageSize then + usePageSize = minimumPageSize + this.HubBar.Position = UDim2.new( + this.HubBar.Position.X.Scale, + this.HubBar.Position.X.Offset, + 0.5, + -minimumPageSize/2 - this.HubBar.Size.Y.Offset + ) + if this.BottomButtonFrame then + this.BottomButtonFrame.Position = UDim2.new( + this.BottomButtonFrame.Position.X.Scale, + this.BottomButtonFrame.Position.X.Offset, + 0.5, + minimumPageSize/2 + ) + end + else + usePageSize = usableScreenHeight + this.HubBar.Position = UDim2.new( + this.HubBar.Position.X.Scale, + this.HubBar.Position.X.Offset, + 0, + bufferSize + ) + if this.BottomButtonFrame then + this.BottomButtonFrame.Position = UDim2.new( + this.BottomButtonFrame.Position.X.Scale, + this.BottomButtonFrame.Position.X.Offset, + 1, + -(bufferSize + barSize) + ) + end + end + + if useUserList and not isTenFootInterface then + if isSmallTouchScreen then + this.PageViewClipper.Size = UDim2.new( + this.PageViewClipper.Size.X.Scale, + this.PageViewClipper.Size.X.Offset, + 0, + usePageSize + 44 + ) + else + this.PageViewClipper.Size = UDim2.new( + this.PageViewClipper.Size.X.Scale, + this.PageViewClipper.Size.X.Offset, + 0, + usePageSize + ) + end + else + this.PageViewClipper.Size = UDim2.new( + this.PageViewClipper.Size.X.Scale, + this.PageViewClipper.Size.X.Offset, + 0, + usePageSize + ) + end + this.PageViewClipper.Position = UDim2.new( + this.PageViewClipper.Position.X.Scale, + this.PageViewClipper.Position.X.Offset, + 0.5, + -usePageSize/2 + ) + end + -- TODO: disconnect this event? + RobloxGui.Changed:connect(function(prop) + if prop == "AbsoluteSize" then + onScreenSizeChanged() + end + end) + onScreenSizeChanged() + end + + local function toggleDevConsole(actionName, inputState, inputObject) + if actionName == DEV_CONSOLE_ACTION_NAME then -- ContextActionService->F9 + if inputState and inputState == Enum.UserInputState.Begin and ToggleDevConsoleBindableFunc then + ToggleDevConsoleBindableFunc:Invoke() + end + end + end + + local lastInputUsedToSelectGui = isTenFootInterface + UserInputService.InputBegan:connect(function(input) + if input.UserInputType == Enum.UserInputType.Gamepad1 or input.UserInputType == Enum.UserInputType.Gamepad2 or input.UserInputType == Enum.UserInputType.Gamepad3 or input.UserInputType == Enum.UserInputType.Gamepad4 + or input.KeyCode == Enum.KeyCode.Left or input.KeyCode == Enum.KeyCode.Right or input.KeyCode == Enum.KeyCode.Up or input.KeyCode == Enum.KeyCode.Down or input.KeyCode == Enum.KeyCode.Tab then + lastInputUsedToSelectGui = true + elseif input.UserInputType == Enum.UserInputType.Touch or input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.MouseButton2 then + lastInputUsedToSelectGui = false + end + end) + UserInputService.InputChanged:connect(function(input) + if input.KeyCode == Enum.KeyCode.Thumbstick1 or input.KeyCode == Enum.KeyCode.Thumbstick2 then + if input.Position.magnitude >= 0.25 then + lastInputUsedToSelectGui = true + end + elseif input.UserInputType == Enum.UserInputType.Touch or input.UserInputType == Enum.UserInputType.MouseMovement then + lastInputUsedToSelectGui = false + end + end) + + + local switchTab = function(direction, cycle) + local currentTabPosition = GetHeaderPosition(this.Pages.CurrentPage) + if currentTabPosition < 0 then return end + + local newTabPosition = currentTabPosition + direction + if cycle then + if newTabPosition > #this.TabHeaders then + newTabPosition = 1 + elseif newTabPosition < 1 then + newTabPosition = #this.TabHeaders + end + end + local newHeader = this.TabHeaders[newTabPosition] + + if newHeader then + for pager,v in pairs(this.Pages.PageTable) do + if pager:GetTabHeader() == newHeader then + this:SwitchToPage(pager, true, direction) + break + end + end + end + end + + local switchTabFromBumpers = function(actionName, inputState, inputObject) + if inputState ~= Enum.UserInputState.Begin then return end + + local direction = 0 + if inputObject.KeyCode == Enum.KeyCode.ButtonR1 then + direction = 1 + elseif inputObject.KeyCode == Enum.KeyCode.ButtonL1 then + direction = -1 + end + + switchTab(direction, true, true) + end + + local switchTabFromKeyboard = function(input) + if input.KeyCode == Enum.KeyCode.Tab then + local direction = 0 + if UserInputService:IsKeyDown(Enum.KeyCode.LeftShift) or UserInputService:IsKeyDown(Enum.KeyCode.RightShift) then + direction = -1 + else + direction = 1 + end + + switchTab(direction, true, true) + end + end + + local scrollHotkeyFunc = function(actionName, inputState, inputObject) + if inputState ~= Enum.UserInputState.Begin then return end + + local direction = 0 + if inputObject.KeyCode == Enum.KeyCode.PageUp then + direction = -100 + elseif inputObject.KeyCode == Enum.KeyCode.PageDown then + direction = 100 + end + + this:ScrollPixels(direction) + end + + -- need some stuff for functions below so init here + createGui() + + function GetHeaderPosition(page) + local header = page:GetTabHeader() + if not header then return -1 end + + for i,v in pairs(this.TabHeaders) do + if v == header then + return i + end + end + + return -1 + end + + local setZIndex = nil + setZIndex = function(newZIndex, object) + if object:IsA("GuiObject") then + object.ZIndex = newZIndex + local children = object:GetChildren() + for i = 1, #children do + setZIndex(newZIndex, children[i]) + end + end + end + + local function AddHeader(newHeader, headerPage) + if not newHeader then return end + + this.TabHeaders[#this.TabHeaders + 1] = newHeader + headerPage.TabPosition = #this.TabHeaders + + local sizeOfTab = 1/#this.TabHeaders + for i = 1, #this.TabHeaders do + local tabMaxPos = (sizeOfTab * i) + local tabMinPos = (sizeOfTab * (i - 1)) + local pos = ((tabMaxPos - tabMinPos)/2) + tabMinPos + + local tab = this.TabHeaders[i] + tab.Position = UDim2.new(pos,-tab.Size.X.Offset/2,0,0) + end + + setZIndex(SETTINGS_BASE_ZINDEX + 1, newHeader) + newHeader.Parent = this.HubBar + end + + local function RemoveHeader(oldHeader) + local removedPos = nil + + for i = 1, #this.TabHeaders do + if this.TabHeaders[i] == oldHeader then + removedPos = i + table.remove(this.TabHeaders, i) + break + end + end + + if removedPos then + for i = removedPos, #this.TabHeaders do + local currentTab = this.TabHeaders[i] + currentTab.Position = UDim2.new(currentTab.Position.X.Scale, currentTab.Position.X.Offset - oldHeader.AbsoluteSize.X, + currentTab.Position.Y.Scale, currentTab.Position.Y.Offset) + end + end + + oldHeader.Parent = nil + end + + -- Page APIs + function this:AddPage(pageToAdd) + this.Pages.PageTable[pageToAdd] = true + AddHeader(pageToAdd:GetTabHeader(), pageToAdd) + pageToAdd.Page.Position = UDim2.new(pageToAdd.TabPosition - 1,0,0,0) + end + + function this:RemovePage(pageToRemove) + this.Pages.PageTable[pageToRemove] = nil + RemoveHeader(pageToRemove:GetTabHeader()) + end + + function this:HideBar() + this.HubBar.Visible = false + this.PageViewClipper.Visible = false + if this.BottomButtonFrame then + removeBottomBarBindings() + end + end + + function this:ShowBar() + this.HubBar.Visible = true + this.PageViewClipper.Visible = true + if this.BottomButtonFrame then + setBottomBarBindings() + end + end + + function this:ScrollPixels(pixels) + -- Only Y + local oldY = this.PageView.CanvasPosition.Y + local maxY = this.PageView.CanvasSize.Y.Offset - this.PageViewClipper.AbsoluteSize.y + local newY = math.max(0, math.min(oldY+pixels, maxY)) -- i.e. clamp + this.PageView.CanvasPosition = Vector2.new(0, newY) + end + + function this:ScrollToFrame(frame, forced) + if lastInputUsedToSelectGui or forced then + local ay = frame.AbsolutePosition.y - this.Pages.CurrentPage.Page.AbsolutePosition.y + local by = ay + frame.AbsoluteSize.y + + if ay < this.PageView.CanvasPosition.y then -- Scroll up to fit top + this.PageView.CanvasPosition = Vector2.new(0, ay) + elseif by - this.PageView.CanvasPosition.y > this.PageViewClipper.Size.Y.Offset then -- Scroll down to fit bottom + this.PageView.CanvasPosition = Vector2.new(0, by - this.PageViewClipper.Size.Y.Offset) + end + end + end + + function this:SwitchToPage(pageToSwitchTo, ignoreStack, direction, skipAnimation) + if this.Pages.PageTable[pageToSwitchTo] == nil then return end + + -- detect direction + if direction == nil then + if this.Pages.CurrentPage and this.Pages.CurrentPage.TabHeader and pageToSwitchTo and pageToSwitchTo.TabHeader then + direction = this.Pages.CurrentPage.TabHeader.AbsolutePosition.x < pageToSwitchTo.TabHeader.AbsolutePosition.x and 1 or -1 + end + end + if direction == nil then + direction = 1 + end + + -- if we have a page we need to let it know to go away + if this.Pages.CurrentPage then + pageChangeCon:disconnect() + this.Pages.CurrentPage.Active = false + end + + -- make sure all pages are in right position + local newPagePos = pageToSwitchTo.TabPosition + for page, _ in pairs(this.Pages.PageTable) do + if page ~= pageToSwitchTo then + page:Hide(-direction, newPagePos, skipAnimation) + end + end + + if this.BottomButtonFrame then + this.BottomButtonFrame.Visible = (pageToSwitchTo ~= this.ResetCharacterPage and pageToSwitchTo ~= this.LeaveGamePage) + this.HubBar.Visible = this.BottomButtonFrame.Visible + end + + -- make sure page is visible + this.Pages.CurrentPage = pageToSwitchTo + this.Pages.CurrentPage:Display(this.PageView, skipAnimation) + this.Pages.CurrentPage.Active = true + + local pageSize = this.Pages.CurrentPage:GetSize() + this.PageView.CanvasSize = UDim2.new(0,pageSize.X,0,pageSize.Y) + + pageChangeCon = this.Pages.CurrentPage.Page.Changed:connect(function(prop) + if prop == "AbsoluteSize" then + local pageSize = this.Pages.CurrentPage:GetSize() + this.PageView.CanvasSize = UDim2.new(0,pageSize.X,0,pageSize.Y) + end + end) + + if this.MenuStack[#this.MenuStack] ~= this.Pages.CurrentPage and not ignoreStack then + this.MenuStack[#this.MenuStack + 1] = this.Pages.CurrentPage + end + end + + function this:SetActive(active) + this.Active = active + + if this.Pages.CurrentPage then + this.Pages.CurrentPage.Active = active + end + end + + function clearMenuStack() + while this.MenuStack and #this.MenuStack > 0 do + this:PopMenu() + end + end + + function setOverrideMouseIconBehavior() + pcall(function() + if UserInputService:GetLastInputType() == Enum.UserInputType.Gamepad1 then + UserInputService.OverrideMouseIconBehavior = Enum.OverrideMouseIconBehavior.ForceHide + else + UserInputService.OverrideMouseIconBehavior = Enum.OverrideMouseIconBehavior.ForceShow + end + end) + end + + function setVisibilityInternal(visible, noAnimation, customStartPage) + this.OpenStateChangedCount = this.OpenStateChangedCount + 1 + local switchedFromGamepadInput = switchedFromGamepadInput or isTenFootInterface + this.Visible = visible + + + this.Modal.Visible = this.Visible + + if this.TabConnection then + this.TabConnection:disconnect() + this.TabConnection = nil + end + + local playerList = require(RobloxGui.Modules.PlayerlistModule) + + if this.Visible then + this.SettingsShowSignal:fire(this.Visible) + + pcall(function() GuiService:SetMenuIsOpen(true) end) + this.Shield.Visible = this.Visible + if noAnimation or not this.Shield:IsDescendantOf(game) then + this.Shield.Position = SETTINGS_SHIELD_ACTIVE_POSITION + else + this.Shield:TweenPosition(SETTINGS_SHIELD_ACTIVE_POSITION, Enum.EasingDirection.InOut, Enum.EasingStyle.Quart, 0.5, true) + end + + local noOpFunc = function() end + ContextActionService:BindCoreAction("RbxSettingsHubStopCharacter", noOpFunc, false, + Enum.PlayerActions.CharacterForward, + Enum.PlayerActions.CharacterBackward, + Enum.PlayerActions.CharacterLeft, + Enum.PlayerActions.CharacterRight, + Enum.PlayerActions.CharacterJump, + Enum.KeyCode.LeftShift, + Enum.KeyCode.RightShift, + Enum.KeyCode.Tab, + Enum.UserInputType.Gamepad1, Enum.UserInputType.Gamepad2, Enum.UserInputType.Gamepad3, Enum.UserInputType.Gamepad4) + + ContextActionService:BindCoreAction("RbxSettingsHubSwitchTab", switchTabFromBumpers, false, Enum.KeyCode.ButtonR1, Enum.KeyCode.ButtonL1) + ContextActionService:BindCoreAction("RbxSettingsScrollHotkey", scrollHotkeyFunc, false, Enum.KeyCode.PageUp, Enum.KeyCode.PageDown) + setBottomBarBindings() + + this.TabConnection = UserInputService.InputBegan:connect(switchTabFromKeyboard) + + + setOverrideMouseIconBehavior() + pcall(function() lastInputChangedCon = UserInputService.LastInputTypeChanged:connect(setOverrideMouseIconBehavior) end) + if UserInputService.MouseEnabled then + pcall(function() + UserInputService.OverrideMouseIconBehavior = Enum.OverrideMouseIconBehavior.ForceShow + end) + end + + if customStartPage then + removeBottomBarBindings() + this:SwitchToPage(customStartPage, nil, 1, true) + else + if useUserList and not isTenFootInterface then + this:SwitchToPage(this.PlayersPage, nil, 1, true) + else + if this.HomePage then + this:SwitchToPage(this.HomePage, nil, 1, true) + else + this:SwitchToPage(this.GameSettingsPage, nil, 1, true) + end + end + end + + playerList:HideTemp('SettingsMenu', true) + + if chat:GetVisibility() then + chatWasVisible = true + chat:ToggleVisibility() + end + + local backpack = require(RobloxGui.Modules.BackpackScript) + if backpack.IsOpen then + backpack:OpenClose() + end + else + if noAnimation then + this.Shield.Position = SETTINGS_SHIELD_INACTIVE_POSITION + this.Shield.Visible = this.Visible + this.SettingsShowSignal:fire(this.Visible) + pcall(function() GuiService:SetMenuIsOpen(false) end) + else + this.Shield:TweenPosition(SETTINGS_SHIELD_INACTIVE_POSITION, Enum.EasingDirection.In, Enum.EasingStyle.Quad, 0.4, true, function() + this.Shield.Visible = this.Visible + this.SettingsShowSignal:fire(this.Visible) + if not this.Visible then pcall(function() GuiService:SetMenuIsOpen(false) end) end + end) + end + + if lastInputChangedCon then + lastInputChangedCon:disconnect() + end + + playerList:HideTemp('SettingsMenu', false) + + if chatWasVisible then + chat:ToggleVisibility() + chatWasVisible = false + end + + pcall(function() UserInputService.OverrideMouseIconBehavior = Enum.OverrideMouseIconBehavior.None end) + + clearMenuStack() + ContextActionService:UnbindCoreAction("RbxSettingsHubSwitchTab") + ContextActionService:UnbindCoreAction("RbxSettingsHubStopCharacter") + ContextActionService:UnbindCoreAction("RbxSettingsScrollHotkey") + removeBottomBarBindings(0.4) + + GuiService.SelectedCoreObject = nil + end + end + + function this:SetVisibility(visible, noAnimation, customStartPage, switchedFromGamepadInput) + if this.Visible == visible then return end + + setVisibilityInternal(visible, noAnimation, customStartPage, switchedFromGamepadInput) + end + + function this:ToggleVisibility(switchedFromGamepadInput) + setVisibilityInternal(not this.Visible, nil, nil, switchedFromGamepadInput) + end + + function this:AddToMenuStack(newItem) + if this.MenuStack[#this.MenuStack] ~= newItem then + this.MenuStack[#this.MenuStack + 1] = newItem + end + end + + + function this:PopMenu(switchedFromGamepadInput, skipAnimation) + if this.MenuStack and #this.MenuStack > 0 then + local lastStackItem = this.MenuStack[#this.MenuStack] + + if type(lastStackItem) ~= "table" then + PoppedMenuEvent:Fire(lastStackItem) + end + + if lastStackItem == this.LeaveGamePage or lastStackItem == this.ResetCharacterPage then + setBottomBarBindings() + end + + table.remove(this.MenuStack, #this.MenuStack) + this:SwitchToPage(this.MenuStack[#this.MenuStack], true, 1, skipAnimation) + if #this.MenuStack == 0 then + this:SetVisibility(false) + this.Pages.CurrentPage:Hide(0, 0) + end + else + this.MenuStack = {} + PoppedMenuEvent:Fire() + this:ToggleVisibility() + end + end + + function this:ShowShield() + this.Shield.BackgroundTransparency = VREnabled and SETTINGS_SHIELD_VR_TRANSPARENCY or SETTINGS_SHIELD_TRANSPARENCY + end + function this:HideShield() + this.Shield.BackgroundTransparency = 1 + end + + local function enableVR() + local Panel3D = require(RobloxGui.Modules.VR.Panel3D) + local panel = Panel3D.Get("SettingsMenu") + panel:ResizeStuds(3, 3, 256) + panel:SetType(Panel3D.Type.Fixed) + panel:SetVisible(false) + panel:SetCanFade(false) + + this.ClippingShield.Parent = panel:GetGUI() + this.Shield.Parent.ClipsDescendants = false + this:HideShield() + + GuiService.MenuOpened:connect(function() + local headLook = Panel3D.GetHeadLookXZ(true) + panel.localCF = headLook * CFrame.Angles(math.rad(5), 0, 0) * CFrame.new(0, 0, 5) + panel:SetVisible(true, true) + end) + GuiService.MenuClosed:connect(function() + panel:SetVisible(false, false) + end) + end + + local UISChanged; + local function OnVREnabled(prop) + if prop == "VREnabled" and UserInputService.VREnabled then + VREnabled = true + enableVR() + if UISChanged then + UISChanged:disconnect() + UISChanged = nil + end + end + end + UISChanged = UserInputService.Changed:connect(OnVREnabled) + OnVREnabled("VREnabled") + + + local closeMenuFunc = function(name, inputState, input) + if inputState ~= Enum.UserInputState.Begin then return end + this:PopMenu(false, true) + end + ContextActionService:BindCoreAction("RBXEscapeMainMenu", closeMenuFunc, false, Enum.KeyCode.Escape) + + this.ResetCharacterPage:SetHub(this) + this.LeaveGamePage:SetHub(this) + + -- full page initialization + if not useUserList then + if utility:IsSmallTouchScreen() then + this.HomePage = require(RobloxGui.Modules.Settings.Pages.Home) + this.HomePage:SetHub(this) + end + end + + this.GameSettingsPage = require(RobloxGui.Modules.Settings.Pages.GameSettings) + this.GameSettingsPage:SetHub(this) + + if platform ~= Enum.Platform.XBoxOne and platform ~= Enum.Platform.PS4 then + this.ReportAbusePage = require(RobloxGui.Modules.Settings.Pages.ReportAbuseMenu) + this.ReportAbusePage:SetHub(this) + end + + this.HelpPage = require(RobloxGui.Modules.Settings.Pages.Help) + this.HelpPage:SetHub(this) + + if platform == Enum.Platform.Windows then + this.RecordPage = require(RobloxGui.Modules.Settings.Pages.Record) + this.RecordPage:SetHub(this) + end + + if useUserList and not isTenFootInterface then + this.PlayersPage = require(RobloxGui.Modules.Settings.Pages.Players) + this.PlayersPage:SetHub(this) + end + + -- page registration + if useUserList and not isTenFootInterface then + this:AddPage(this.PlayersPage) + end + this:AddPage(this.ResetCharacterPage) + this:AddPage(this.LeaveGamePage) + if not useUserList then + if this.HomePage then + this:AddPage(this.HomePage) + end + end + this:AddPage(this.GameSettingsPage) + if this.ReportAbusePage then + this:AddPage(this.ReportAbusePage) + end + this:AddPage(this.HelpPage) + if this.RecordPage then + this:AddPage(this.RecordPage) + end + + if useUserList and not isTenFootInterface then + this:SwitchToPage(this.PlayerPage, true, 1) + else + if this.HomePage then + this:SwitchToPage(this.HomePage, true, 1) + else + this:SwitchToPage(this.GameSettingsPage, true, 1) + end + end + -- hook up to necessary signals + + -- connect back button on android + GuiService.ShowLeaveConfirmation:connect(function() + if #this.MenuStack == 0 then + this:SetVisibility(true) + this:SwitchToPage(this.LeaveGamePage, nil, 1) + else + this:PopMenu(false, true) + end + end) + + -- Dev Console Connections + ContextActionService:BindCoreAction(DEV_CONSOLE_ACTION_NAME, toggleDevConsole, false, Enum.KeyCode.F9) + + -- Keyboard control + UserInputService.InputBegan:connect(function(input) + if input.KeyCode == Enum.KeyCode.Left or input.KeyCode == Enum.KeyCode.Right or input.KeyCode == Enum.KeyCode.Up or input.KeyCode == Enum.KeyCode.Down then + if this.Visible and this.Active then + if this.Pages.CurrentPage then + if GuiService.SelectedCoreObject == nil then + this.Pages.CurrentPage:SelectARow() + end + end + end + end + end) + + return this +end + + +-- Main Entry Point + +local moduleApiTable = {} + + local SettingsHubInstance = CreateSettingsHub() + + function moduleApiTable:SetVisibility(visible, noAnimation, customStartPage, switchedFromGamepadInput) + SettingsHubInstance:SetVisibility(visible, noAnimation, customStartPage, switchedFromGamepadInput) + end + + function moduleApiTable:ToggleVisibility(switchedFromGamepadInput) + SettingsHubInstance:ToggleVisibility(switchedFromGamepadInput) + end + + function moduleApiTable:SwitchToPage(pageToSwitchTo, ignoreStack) + SettingsHubInstance:SwitchToPage(pageToSwitchTo, ignoreStack, 1) + end + + function moduleApiTable:GetVisibility() + return SettingsHubInstance.Visible + end + + function moduleApiTable:ShowShield() + SettingsHubInstance:ShowShield() + end + + function moduleApiTable:HideShield() + SettingsHubInstance:HideShield() + end + + moduleApiTable.SettingsShowSignal = SettingsHubInstance.SettingsShowSignal + + moduleApiTable.Instance = SettingsHubInstance + +return moduleApiTable \ No newline at end of file diff --git a/2016/content/scripts/Modules/Settings/Utility.lua b/2016/content/scripts/Modules/Settings/Utility.lua new file mode 100644 index 0000000..4c6bebf --- /dev/null +++ b/2016/content/scripts/Modules/Settings/Utility.lua @@ -0,0 +1,2155 @@ +--[[ + Filename: SettingsPage.lua + Written by: jeditkacheff + Version 1.0 + Description: Base Page Functionality for all Settings Pages +--]] + +------------------ CONSTANTS -------------------- +local SELECTED_COLOR = Color3.new(0,162/255,1) +local NON_SELECTED_COLOR = Color3.new(78/255,84/255,96/255) + +local SELECTED_LEFT_IMAGE = "rbxasset://textures/ui/Settings/Slider/SelectedBarLeft.png" +local NON_SELECTED_LEFT_IMAGE = "rbxasset://textures/ui/Settings/Slider/BarLeft.png" +local SELECTED_RIGHT_IMAGE = "rbxasset://textures/ui/Settings/Slider/SelectedBarRight.png" +local NON_SELECTED_RIGHT_IMAGE= "rbxasset://textures/ui/Settings/Slider/BarRight.png" + +local CONTROLLER_SCROLL_DELTA = 0.2 +local CONTROLLER_THUMBSTICK_DEADZONE = 0.8 + +------------- SERVICES ---------------- +local HttpService = game:GetService("HttpService") +local UserInputService = game:GetService("UserInputService") +local GuiService = game:GetService("GuiService") +local RunService = game:GetService("RunService") +local CoreGui = game:GetService("CoreGui") +local RobloxGui = CoreGui:FindFirstChild("RobloxGui") +local ContextActionService = game:GetService("ContextActionService") + +------------------ VARIABLES -------------------- +local tenFootInterfaceEnabled = false +do + RobloxGui:WaitForChild("Modules"):WaitForChild("TenFootInterface") + tenFootInterfaceEnabled = require(RobloxGui.Modules.TenFootInterface):IsEnabled() +end + + + +----------- UTILITIES -------------- +local Util = {} +do + function Util.Create(instanceType) + return function(data) + local obj = Instance.new(instanceType) + for k, v in pairs(data) do + if type(k) == 'number' then + v.Parent = obj + else + obj[k] = v + end + end + return obj + end + end +end + + +-- used by several guis to show no selection adorn +local noSelectionObject = Util.Create'ImageLabel' +{ + Image = "", + BackgroundTransparency = 1 +}; + + +-- MATH -- +function clamp(low, high, input) + return math.max(low, math.min(high, input)) +end + +function ClampVector2(low, high, input) + return Vector2.new(clamp(low.x, high.x, input.x), clamp(low.y, high.y, input.y)) +end + +---- TWEENZ ---- +local Linear = function(t, b, c, d) + if t >= d then return b + c end + + return c*t/d + b +end + +local EaseOutQuad = function(t, b, c, d) + if t >= d then return b + c end + + t = t/d; + return -c * t*(t-2) + b +end + +local EaseInOutQuad = function(t, b, c, d) + if t >= d then return b + c end + + t = t / (d/2); + if (t < 1) then return c/2*t*t + b end; + t = t - 1; + return -c/2 * (t*(t-2) - 1) + b; +end + +function PropertyTweener(instance, prop, start, final, duration, easingFunc, cbFunc) + local this = {} + this.StartTime = tick() + this.EndTime = this.StartTime + duration + this.Cancelled = false + + local finished = false + local percentComplete = 0 + + local function finalize() + if instance then + instance[prop] = easingFunc(1, start, final - start, 1) + end + finished = true + percentComplete = 1 + if cbFunc then + cbFunc() + end + end + + -- Initial set + instance[prop] = easingFunc(0, start, final - start, duration) + spawn(function() + local now = tick() + while now < this.EndTime and instance do + if this.Cancelled then + return + end + instance[prop] = easingFunc(now - this.StartTime, start, final - start, duration) + percentComplete = clamp(0, 1, (now - this.StartTime) / duration) + RunService.RenderStepped:wait() + now = tick() + end + if this.Cancelled == false and instance then + finalize() + end + end) + + function this:GetFinal() + return final + end + + function this:GetPercentComplete() + return percentComplete + end + + function this:IsFinished() + return finished + end + + function this:Finish() + if not finished then + self:Cancel() + finalize() + end + end + + function this:Cancel() + this.Cancelled = true + end + + return this +end + +----------- CLASS DECLARATION -------------- + +local function CreateSignal() + local sig = {} + + local mSignaler = Instance.new('BindableEvent') + + local mArgData = nil + local mArgDataCount = nil + + function sig:fire(...) + mArgData = {...} + mArgDataCount = select('#', ...) + mSignaler:Fire() + end + + function sig:connect(f) + if not f then error("connect(nil)", 2) end + return mSignaler.Event:connect(function() + f(unpack(mArgData, 1, mArgDataCount)) + end) + end + + function sig:wait() + mSignaler.Event:wait() + assert(mArgData, "Missing arg data, likely due to :TweenSize/Position corrupting threadrefs.") + return unpack(mArgData, 1, mArgDataCount) + end + + return sig +end + +local function getViewportSize() + while not game.Workspace.CurrentCamera do + game.Workspace.Changed:wait() + end + + while game.Workspace.CurrentCamera.ViewportSize == Vector2.new(0,0) do + game.Workspace.CurrentCamera.Changed:wait() + end + + return game.Workspace.CurrentCamera.ViewportSize +end + +local function isSmallTouchScreen() + return UserInputService.TouchEnabled and getViewportSize().Y <= 500 +end + +local function isTenFootInterface() + return tenFootInterfaceEnabled +end + +local function usesSelectedObject() + if UserInputService.TouchEnabled and not UserInputService.GamepadEnabled then return false end + + return true +end + +local function isPosOverGui(pos, gui, debug) -- does not account for rotation + local ax, ay = gui.AbsolutePosition.x, gui.AbsolutePosition.y + local sx, sy = gui.AbsoluteSize.x, gui.AbsoluteSize.y + local bx, by = ax+sx, ay+sy + + if pos.x > ax and pos.x < bx and pos.y > ay and pos.y < by then + return true + else + return false + end +end + +local function isPosOverGuiWithClipping(pos, gui) -- isPosOverGui, accounts for clipping and visibility, does not account for rotation + if not isPosOverGui(pos, gui) then + return false + end + + local clipping = false + local check = gui + while true do + if check == nil or (not check:IsA'GuiObject' and not check:IsA'LayerCollector') then + clipping = true + if check and check:IsA'CoreGui' then + clipping = false + end + break + end + + if check:IsA'GuiObject' and not check.Visible then + clipping = true + break + end + if check:IsA'LayerCollector' or check.ClipsDescendants then + if not isPosOverGui(pos, check) then + clipping = true + break + end + end + + check = check.Parent + end + + if clipping then + return false + else + return true + end +end + +local function areGuisIntersecting(a, b) -- does not account for rotation + local aax, aay = a.AbsolutePosition.x, a.AbsolutePosition.y + local asx, asy = a.AbsoluteSize.x, a.AbsoluteSize.y + local abx, aby = aax+asx, aay+asy + local bax, bay = b.AbsolutePosition.x, b.AbsolutePosition.y + local bsx, bsy = b.AbsoluteSize.x, b.AbsoluteSize.y + local bbx, bby = bax+bsx, bay+bsy + + local intersectingX = aax < bbx and abx > bax + local intersectingY = aay < bby and aby > bay + local intersecting = intersectingX and intersectingY + + return intersecting +end + +local function isGuiVisible(gui, debug) -- true if any part of the gui is visible on the screen, considers clipping, does not account for rotation + local clipping = false + local check = gui + while true do + if check == nil or not check:IsA'GuiObject' and not check:IsA'LayerCollector' then + clipping = true + if check and check:IsA'CoreGui' then + clipping = false + end + break + end + + if check:IsA'GuiObject' and not check.Visible then + clipping = true + break + end + if check:IsA'LayerCollector' or check.ClipsDescendants then + if not areGuisIntersecting(check, gui) then + clipping = true + break + end + end + + check = check.Parent + end + + if clipping then + return false + else + return true + end +end + +local function MakeButton(name, text, size, clickFunc, pageRef, hubRef) + local SelectionOverrideObject = Util.Create'ImageLabel' + { + Image = "", + BackgroundTransparency = 1, + }; + + local button = Util.Create'ImageButton' + { + Name = name .. "Button", + Image = "rbxasset://textures/ui/Settings/MenuBarAssets/MenuButton.png", + ScaleType = Enum.ScaleType.Slice, + SliceCenter = Rect.new(8,6,46,44), + AutoButtonColor = false, + BackgroundTransparency = 1, + Size = size, + ZIndex = 2, + SelectionImageObject = SelectionOverrideObject + }; + button.NextSelectionLeft = button + button.NextSelectionRight = button + + local enabled = Util.Create'BoolValue' + { + Name = 'Enabled', + Parent = button, + Value = true + } + + if clickFunc then + button.MouseButton1Click:connect(function() + local lastInputType = nil + pcall(function() lastInputType = UserInputService:GetLastInputType() end) + if lastInputType then + clickFunc(lastInputTypee == Enum.UserInputType.Gamepad1 or lastInputType == Enum.UserInputType.Gamepad2 or + lastInputType == Enum.UserInputType.Gamepad3 or lastInputType == Enum.UserInputType.Gamepad4) + else + clickFunc(false) + end + end) + end + + local function isPointerInput(inputObject) + return (inputObject.UserInputType == Enum.UserInputType.MouseMovement or inputObject.UserInputType == Enum.UserInputType.Touch) + end + + local function selectButton() + local hub = hubRef + if hub == nil then + if pageRef then + hub = pageRef.HubRef + end + end + + if (hub and hub.Active or hub == nil) then + button.Image = "rbxasset://textures/ui/Settings/MenuBarAssets/MenuButtonSelected.png" + + local scrollTo = button + if rowRef then + scrollTo = rowRef + end + if hub then + hub:ScrollToFrame(scrollTo) + end + end + end + + local function deselectButton() + button.Image = "rbxasset://textures/ui/Settings/MenuBarAssets/MenuButton.png" + end + + button.InputBegan:connect(function(inputObject) + if button.Selectable and isPointerInput(inputObject) then + selectButton() + end + end) + button.InputEnded:connect(function(inputObject) + if button.Selectable and GuiService.SelectedCoreObject ~= button and isPointerInput(inputObject) then + deselectButton() + end + end) + + local rowRef = nil + local function setRowRef(ref) + rowRef = ref + end + button.SelectionGained:connect(function() + selectButton() + end) + button.SelectionLost:connect(function() + deselectButton() + end) + + local textLabel = Util.Create'TextLabel' + { + Name = name .. "TextLabel", + BackgroundTransparency = 1, + BorderSizePixel = 0, + Size = UDim2.new(1, 0, 1, -8), + Position = UDim2.new(0,0,0,0), + TextColor3 = Color3.new(1,1,1), + TextYAlignment = Enum.TextYAlignment.Center, + Font = Enum.Font.SourceSansBold, + FontSize = Enum.FontSize.Size24, + Text = text, + TextWrapped = true, + ZIndex = 2, + Parent = button + }; + + if isSmallTouchScreen() then + textLabel.FontSize = Enum.FontSize.Size18 + elseif isTenFootInterface() then + textLabel.FontSize = Enum.FontSize.Size36 + end + + local guiServiceCon = GuiService.Changed:connect(function(prop) + if prop ~= "SelectedCoreObject" then return end + if not usesSelectedObject() then return end + + if GuiService.SelectedCoreObject == nil or GuiService.SelectedCoreObject ~= button then + deselectButton() + return + end + + if button.Selectable then + selectButton() + end + end) + + return button, textLabel, setRowRef +end + +local function CreateDropDown(dropDownStringTable, startPosition, settingsHub) + -------------------- CONSTANTS ------------------------ + local DEFAULT_DROPDOWN_TEXT = "Choose One" + local SCROLLING_FRAME_PIXEL_OFFSET = 25 + local SELECTION_TEXT_COLOR_NORMAL = Color3.new(0.7,0.7,0.7) + local SELECTION_TEXT_COLOR_HIGHLIGHTED = Color3.new(1,1,1) + + -------------------- VARIABLES ------------------------ + local lastSelectedCoreObject= nil + + -------------------- SETUP ------------------------ + local this = {} + this.CurrentIndex = nil + + local indexChangedEvent = Instance.new("BindableEvent") + indexChangedEvent.Name = "IndexChanged" + + if type(dropDownStringTable) ~= "table" then + error("CreateDropDown dropDownStringTable (first arg) is not a table") + return this + end + + local indexChangedEvent = Instance.new("BindableEvent") + indexChangedEvent.Name = "IndexChanged" + + local interactable = true + local guid = HttpService:GenerateGUID(false) + local dropDownButtonEnabled + + this.CurrentIndex = 0 + + ----------------- GUI SETUP ------------------------ + local DropDownFullscreenFrame = Util.Create'ImageButton' + { + Name = "DropDownFullscreenFrame", + BackgroundTransparency = 0.2, + BorderSizePixel = 0, + Size = UDim2.new(1, 0, 1, 0), + BackgroundColor3 = Color3.new(0,0,0), + ZIndex = 10, + Active = true, + Visible = false, + Selectable = false, + AutoButtonColor = false, + Parent = CoreGui.RobloxGui + }; + + local DropDownSelectionFrame = Util.Create'ImageLabel' + { + Name = "DropDownSelectionFrame", + Image = "rbxasset://textures/ui/Settings/MenuBarAssets/MenuButton.png", + ScaleType = Enum.ScaleType.Slice, + SliceCenter = Rect.new(8,6,46,44), + BackgroundTransparency = 1, + Size = UDim2.new(0, 400, 0.9, 0), + Position = UDim2.new(0.5, -200, 0.05, 0), + ZIndex = 10, + Parent = DropDownFullscreenFrame + }; + + local DropDownScrollingFrame = Util.Create'ScrollingFrame' + { + Name = "DropDownScrollingFrame", + BackgroundTransparency = 1, + BorderSizePixel = 0, + Size = UDim2.new(1, -20, 1, -SCROLLING_FRAME_PIXEL_OFFSET), + Position = UDim2.new(0, 10, 0, 10), + ZIndex = 10, + Parent = DropDownSelectionFrame + }; + + local guiServiceChangeCon = nil + local active = false + local hideDropDownSelection = function(name, inputState) + if name ~= nil and inputState ~= Enum.UserInputState.Begin then return end + this.DropDownFrame.Selectable = interactable + + if DropDownFullscreenFrame.Visible and usesSelectedObject() then + GuiService.SelectedCoreObject = lastSelectedCoreObject + end + DropDownFullscreenFrame.Visible = false + if guiServiceChangeCon then guiServiceChangeCon:disconnect() end + ContextActionService:UnbindCoreAction(guid .. "Action") + ContextActionService:UnbindCoreAction(guid .. "FreezeAction") + + settingsHub:SetActive(true) + + dropDownButtonEnabled.Value = interactable + active = false + end + local noOpFunc = function() end + + local DropDownFrameClicked = function() + if not interactable then return end + + this.DropDownFrame.Selectable = false + active = true + + DropDownFullscreenFrame.Visible = true + if not this.CurrentIndex then this.CurrentIndex = 1 end + if this.CurrentIndex <= 0 then this.CurrentIndex = 1 end + + lastSelectedCoreObject = this.DropDownFrame + GuiService.SelectedCoreObject = this.Selections[this.CurrentIndex] + + guiServiceChangeCon = GuiService.Changed:connect(function(prop) + if not prop == "SelectedCoreObject" then return end + for i = 1, #this.Selections do + if GuiService.SelectedCoreObject == this.Selections[i] then + this.Selections[i].TextColor3 = SELECTION_TEXT_COLOR_HIGHLIGHTED + else + this.Selections[i].TextColor3 = SELECTION_TEXT_COLOR_NORMAL + end + end + end) + + ContextActionService:BindCoreAction(guid .. "FreezeAction", noOpFunc, false, Enum.UserInputType.Keyboard, Enum.UserInputType.Gamepad1) + ContextActionService:BindCoreAction(guid .. "Action", hideDropDownSelection, false, Enum.KeyCode.ButtonB, Enum.KeyCode.Escape) + + settingsHub:SetActive(false) + + dropDownButtonEnabled.Value = false + end + + local dropDownFrameSize = UDim2.new(0,400,0,44) + if isSmallTouchScreen() then + dropDownFrameSize = UDim2.new(0,300,0,44) + end + this.DropDownFrame = MakeButton("DropDownFrame", DEFAULT_DROPDOWN_TEXT, dropDownFrameSize, DropDownFrameClicked) + dropDownButtonEnabled = this.DropDownFrame.Enabled + local selectedTextLabel = this.DropDownFrame.DropDownFrameTextLabel + local dropDownImage = Util.Create'ImageLabel' + { + Name = "DropDownImage", + Image = "rbxasset://textures/ui/Settings/DropDown/DropDown.png", + BackgroundTransparency = 1, + Size = UDim2.new(0,15,0,10), + Position = UDim2.new(1, -45,0.5,-7), + ZIndex = 2, + Parent = this.DropDownFrame + }; + + + ---------------------- FUNCTIONS ----------------------------------- + local function setSelection(index) + local shouldFireChanged = false + for i, selectionLabel in pairs(this.Selections) do + if i == index then + selectedTextLabel.Text = selectionLabel.Text + this.CurrentIndex = i + + shouldFireChanged = true + end + end + + if shouldFireChanged then + indexChangedEvent:Fire(index) + end + end + + local function setSelectionByValue(value) + local shouldFireChanged = false + for i, selectionLabel in pairs(this.Selections) do + if selectionLabel.Text == value then + selectedTextLabel.Text = selectionLabel.Text + this.CurrentIndex = i + + shouldFireChanged = true + end + end + + if shouldFireChanged then + indexChangedEvent:Fire(this.CurrentIndex) + end + return shouldFireChanged + end + + local enterIsDown = false + local function processInput(input) + if input.UserInputState == Enum.UserInputState.Begin then + if input.KeyCode == Enum.KeyCode.Return then + if GuiService.SelectedCoreObject == this.DropDownFrame or this.SelectionInfo and this.SelectionInfo[GuiService.SelectedCoreObject] then + enterIsDown = true + end + end + elseif input.UserInputState == Enum.UserInputState.End then + if input.KeyCode == Enum.KeyCode.Return and enterIsDown then + enterIsDown = false + if GuiService.SelectedCoreObject == this.DropDownFrame then + DropDownFrameClicked() + elseif this.SelectionInfo and this.SelectionInfo[GuiService.SelectedCoreObject] then + local info = this.SelectionInfo[GuiService.SelectedCoreObject] + info.Clicked() + end + end + end + end + + + --------------------- PUBLIC FACING FUNCTIONS ----------------------- + this.IndexChanged = indexChangedEvent.Event + + function this:SetSelectionIndex(newIndex) + setSelection(newIndex) + end + + function this:SetSelectionByValue(value) + return setSelectionByValue(value) + end + + function this:ResetSelectionIndex() + this.CurrentIndex = nil + selectedTextLabel.Text = DEFAULT_DROPDOWN_TEXT + hideDropDownSelection() + end + + function this:GetSelectedIndex() + return this.CurrentIndex + end + + function this:SetZIndex(newZIndex) + this.DropDownFrame.ZIndex = newZIndex + dropDownImage.ZIndex = newZIndex + selectedTextLabel.ZIndex = newZIndex + end + + function this:SetInteractable(value) + interactable = value + this.DropDownFrame.Selectable = interactable + + if not interactable then + hideDropDownSelection() + this:SetZIndex(1) + else + this:SetZIndex(2) + end + + dropDownButtonEnabled.Value = value and not active + end + + + function this:UpdateDropDownList(dropDownStringTable) + if this.Selections then + for i = 1, #this.Selections do + this.Selections[i]:Destroy() + end + end + + this.Selections = {} + this.SelectionInfo = {} + + for i,v in pairs(dropDownStringTable) do + local SelectionOverrideObject = Util.Create'Frame' + { + BackgroundTransparency = 0.7, + BorderSizePixel = 0, + Size = UDim2.new(1, 0, 1, 0) + }; + + local nextSelection = Util.Create'TextButton' + { + Name = "Selection" .. tostring(i), + BackgroundTransparency = 1, + BorderSizePixel = 0, + AutoButtonColor = false, + Size = UDim2.new(1, -28, 0, 50), + Position = UDim2.new(0,14,0, (i - 1) * 51), + TextColor3 = SELECTION_TEXT_COLOR_NORMAL, + Font = Enum.Font.SourceSans, + FontSize = Enum.FontSize.Size24, + Text = v, + ZIndex = 10, + SelectionImageObject = SelectionOverrideObject, + Parent = DropDownScrollingFrame + }; + + if i == startPosition then + this.CurrentIndex = i + selectedTextLabel.Text = v + nextSelection.TextColor3 = SELECTION_TEXT_COLOR_HIGHLIGHTED + elseif not startPosition and i == 1 then + nextSelection.TextColor3 = SELECTION_TEXT_COLOR_HIGHLIGHTED + end + + local clicked = function() + selectedTextLabel.Text = nextSelection.Text + hideDropDownSelection() + this.CurrentIndex = i + indexChangedEvent:Fire(i) + end + + nextSelection.MouseButton1Click:connect(clicked) + + nextSelection.MouseEnter:connect(function() + if usesSelectedObject() then + GuiService.SelectedCoreObject = nextSelection + end + end) + + this.Selections[i] = nextSelection + this.SelectionInfo[nextSelection] = {Clicked = clicked} + end + + GuiService:RemoveSelectionGroup(guid) + GuiService:AddSelectionTuple(guid, unpack(this.Selections)) + + DropDownScrollingFrame.CanvasSize = UDim2.new(1,-20,0,#dropDownStringTable * 51) + + local function updateDropDownSize() + if DropDownScrollingFrame.CanvasSize.Y.Offset < (DropDownFullscreenFrame.AbsoluteSize.Y - 10) then + DropDownSelectionFrame.Size = UDim2.new(DropDownSelectionFrame.Size.X.Scale, DropDownSelectionFrame.Size.X.Offset, + 0,DropDownScrollingFrame.CanvasSize.Y.Offset + SCROLLING_FRAME_PIXEL_OFFSET) + DropDownSelectionFrame.Position = UDim2.new(DropDownSelectionFrame.Position.X.Scale, DropDownSelectionFrame.Position.X.Offset, + 0.5, -DropDownSelectionFrame.Size.Y.Offset/2) + else + DropDownSelectionFrame.Size = UDim2.new(0, 400, 0.9, 0) + DropDownSelectionFrame.Position = UDim2.new(0.5, -200, 0.05, 0) + end + end + + DropDownFullscreenFrame.Changed:connect(function(prop) + if prop ~= "AbsoluteSize" then return end + updateDropDownSize() + end) + + updateDropDownSize() + end + + ----------------------- CONNECTIONS/SETUP -------------------------------- + this:UpdateDropDownList(dropDownStringTable) + + DropDownFullscreenFrame.MouseButton1Click:connect(hideDropDownSelection) + + settingsHub.PoppedMenu:connect(function(poppedMenu) + if poppedMenu == DropDownFullscreenFrame then + hideDropDownSelection() + end + end) + + UserInputService.InputBegan:connect(processInput) + UserInputService.InputEnded:connect(processInput) + + return this +end + + +local function CreateSelector(selectionStringTable, startPosition) + + -------------------- VARIABLES ------------------------ + local lastInputDirection = 0 + local TweenTime = 0.15 + + -------------------- SETUP ------------------------ + local this = {} + this.HubRef = nil + + if type(selectionStringTable) ~= "table" then + error("CreateSelector selectionStringTable (first arg) is not a table") + return this + end + + local indexChangedEvent = Instance.new("BindableEvent") + indexChangedEvent.Name = "IndexChanged" + + local interactable = true + + this.CurrentIndex = 0 + + ----------------- GUI SETUP ------------------------ + this.SelectorFrame = Util.Create'ImageButton' + { + Name = "Selector", + Image = "", + AutoButtonColor = false, + NextSelectionLeft = this.SelectorFrame, + NextSelectionRight = this.SelectorFrame, + BackgroundTransparency = 1, + Size = UDim2.new(0,502,0,50), + ZIndex = 2, + SelectionImageObject = noSelectionObject + }; + if isSmallTouchScreen() then + this.SelectorFrame.Size = UDim2.new(0,400,0,50) + end + + local leftButton = Util.Create'ImageButton' + { + Name = "LeftButton", + BackgroundTransparency = 1, + Position = UDim2.new(0,-10,0.5,-25), + Size = UDim2.new(0,60,0,50), + Image = "", + ZIndex = 3, + Selectable = false, + Active = true, + Parent = this.SelectorFrame + }; + local rightButton = Util.Create'ImageButton' + { + Name = "RightButton", + BackgroundTransparency = 1, + Position = UDim2.new(1,-50,0.5,-25), + Size = UDim2.new(0,50,0,50), + Image = "", + ZIndex = 3, + Selectable = false, + Parent = this.SelectorFrame + }; + + local leftButtonImage = Util.Create'ImageLabel' + { + Name = "LeftButton", + BackgroundTransparency = 1, + Position = UDim2.new(1,-24,0.5,-15), + Size = UDim2.new(0,18,0,30), + Image = "rbxasset://textures/ui/Settings/Slider/Left.png", + ZIndex = 2, + Active = true, + Parent = leftButton + }; + local rightButtonImage = Util.Create'ImageLabel' + { + Name = "RightButton", + BackgroundTransparency = 1, + Position = UDim2.new(0,6,0.5,-15), + Size = UDim2.new(0,18,0,30), + Image = "rbxasset://textures/ui/Settings/Slider/Right.png", + ZIndex = 2, + Parent = rightButton + }; + + + this.Selections = {} + local isSelectionLabelVisible = {} + local isAutoSelectButton = {} + + for i,v in pairs(selectionStringTable) do + local nextSelection = Util.Create'TextLabel' + { + Name = "Selection" .. tostring(i), + BackgroundTransparency = 1, + BorderSizePixel = 0, + Size = UDim2.new(1,leftButton.Size.X.Offset * -2, 1, 0), + Position = UDim2.new(1,0,0,0), + TextColor3 = Color3.new(1,1,1), + TextYAlignment = Enum.TextYAlignment.Center, + TextTransparency = 0.5, + Font = Enum.Font.SourceSans, + FontSize = Enum.FontSize.Size24, + Text = v, + ZIndex = 2, + Visible = false, + Parent = this.SelectorFrame + }; + if isTenFootInterface() then + nextSelection.FontSize = Enum.FontSize.Size36 + end + + if i == startPosition then + this.CurrentIndex = i + nextSelection.Position = UDim2.new(0,leftButton.Size.X.Offset,0,0) + nextSelection.Visible = true + + isSelectionLabelVisible[nextSelection] = true + else + isSelectionLabelVisible[nextSelection] = false + end + + local autoSelectButton = Util.Create'ImageButton'{ + Name = 'AutoSelectButton', + BackgroundTransparency = 1, + Image = '', + Size = UDim2.new(1, 0, 1, 0), + Parent = nextSelection, + ZIndex = 2 + } + autoSelectButton.MouseButton1Click:connect(function() + local newIndex = this.CurrentIndex + 1 + if newIndex > #this.Selections then + newIndex = 1 + end + this:SetSelectionIndex(newIndex) + if usesSelectedObject() then + GuiService.SelectedCoreObject = this.SelectorFrame + end + end) + isAutoSelectButton[autoSelectButton] = true + + this.Selections[i] = nextSelection + end + + + ---------------------- FUNCTIONS ----------------------------------- + local function setSelection(index, direction) + for i, selectionLabel in pairs(this.Selections) do + local isSelected = (i == index) + + if not selectionLabel:IsDescendantOf(game) then + this.CurrentIndex = i + indexChangedEvent:Fire(index) + return + end + + local tweenPos = UDim2.new(0,leftButton.Size.X.Offset * direction * 3,0,0) + if isSelectionLabelVisible[selectionLabel] then + tweenPos = UDim2.new(0,leftButton.Size.X.Offset * -direction * 3,0,0) + end + + if tweenPos.X.Offset < 0 then + tweenPos = UDim2.new(0,tweenPos.X.Offset + (selectionLabel.AbsoluteSize.X/4),0,0) + end + + if isSelected then + isSelectionLabelVisible[selectionLabel] = true + selectionLabel.Position = tweenPos + selectionLabel.Visible = true + PropertyTweener(selectionLabel, "TextTransparency", 1, 0, TweenTime * 1.1, EaseOutQuad) + selectionLabel:TweenPosition(UDim2.new(0,leftButton.Size.X.Offset,0,0), Enum.EasingDirection.In, Enum.EasingStyle.Quad, TweenTime, true) + this.CurrentIndex = i + indexChangedEvent:Fire(index) + elseif isSelectionLabelVisible[selectionLabel] then + isSelectionLabelVisible[selectionLabel] = false + PropertyTweener(selectionLabel, "TextTransparency", 0, 1, TweenTime * 1.1, EaseOutQuad) + selectionLabel:TweenPosition(tweenPos, Enum.EasingDirection.Out, Enum.EasingStyle.Quad, TweenTime * 0.9, true) + end + end + end + + local function stepFunc(inputObject, step) + if not interactable then return end + + if inputObject ~= nil and inputObject.UserInputType ~= Enum.UserInputType.MouseButton1 and + inputObject.UserInputType ~= Enum.UserInputType.Gamepad1 and inputObject.UserInputType ~= Enum.UserInputType.Gamepad2 and + inputObject.UserInputType ~= Enum.UserInputType.Gamepad3 and inputObject.UserInputType ~= Enum.UserInputType.Gamepad4 and + inputObject.UserInputType ~= Enum.UserInputType.Keyboard then return end + + if usesSelectedObject() then + GuiService.SelectedCoreObject = this.SelectorFrame + end + + local newIndex = step + this.CurrentIndex + + local direction = 0 + if newIndex > this.CurrentIndex then + direction = 1 + else + direction = -1 + end + + if newIndex > #this.Selections then + newIndex = 1 + elseif newIndex < 1 then + newIndex = #this.Selections + end + + setSelection(newIndex, direction) + end + + local guiServiceCon = nil + local function connectToGuiService() + guiServiceCon = GuiService.Changed:connect(function(prop) + if prop == "SelectedCoreObject" then + if GuiService.SelectedCoreObject == this.SelectorFrame then + this.Selections[this.CurrentIndex].TextTransparency = 0 + else + if GuiService.SelectedCoreObject ~= nil and isAutoSelectButton[GuiService.SelectedCoreObject] then + GuiService.SelectedCoreObject = this.SelectorFrame + else + this.Selections[this.CurrentIndex].TextTransparency = 0.5 + end + end + end + end) + end + + --------------------- PUBLIC FACING FUNCTIONS ----------------------- + this.IndexChanged = indexChangedEvent.Event + + function this:SetSelectionIndex(newIndex) + setSelection(newIndex, 1) + end + + function this:GetSelectedIndex() + return this.CurrentIndex + end + + function this:SetZIndex(newZIndex) + leftButton.ZIndex = newZIndex + rightButton.ZIndex = newZIndex + leftButtonImage.ZIndex = newZIndex + rightButtonImage.ZIndex = newZIndex + + for i = 1, #this.Selections do + this.Selections[i].ZIndex = newZIndex + end + end + + function this:SetInteractable(value) + interactable = value + this.SelectorFrame.Selectable = interactable + if not interactable then + for i, selectionLabel in pairs(this.Selections) do + selectionLabel.TextColor3 = Color3.new(49/255, 49/255, 49/255) + end + else + for i, selectionLabel in pairs(this.Selections) do + selectionLabel.TextColor3 = Color3.new(1, 1, 1) + end + end + end + + --------------------- SETUP ----------------------- + leftButton.InputBegan:connect(function(inputObject) + if inputObject.UserInputType == Enum.UserInputType.Touch then + stepFunc(nil, -1) + end + end) + leftButton.MouseButton1Click:connect(function() + if not UserInputService.TouchEnabled then + stepFunc(nil, -1) + end + end) + rightButton.InputBegan:connect(function(inputObject) + if inputObject.UserInputType == Enum.UserInputType.Touch then + stepFunc(nil, 1) + end + end) + rightButton.MouseButton1Click:connect(function() + if not UserInputService.TouchEnabled then + stepFunc(nil, 1) + end + end) + + local isInTree = true + + UserInputService.InputBegan:connect(function(inputObject) + if not interactable then return end + if not isInTree then return end + + if inputObject.UserInputType ~= Enum.UserInputType.Gamepad1 and inputObject.UserInputType ~= Enum.UserInputType.Keyboard then return end + if GuiService.SelectedCoreObject ~= this.SelectorFrame then return end + + if inputObject.KeyCode == Enum.KeyCode.DPadLeft or inputObject.KeyCode == Enum.KeyCode.Left or inputObject.KeyCode == Enum.KeyCode.A then + stepFunc(inputObject, -1) + elseif inputObject.KeyCode == Enum.KeyCode.DPadRight or inputObject.KeyCode == Enum.KeyCode.Right or inputObject.KeyCode == Enum.KeyCode.D then + stepFunc(inputObject, 1) + end + end) + + UserInputService.InputChanged:connect(function(inputObject) + if not interactable then return end + if not isInTree then lastInputDirection = 0 return end + + if inputObject.UserInputType ~= Enum.UserInputType.Gamepad1 then return end + if GuiService.SelectedCoreObject ~= this.SelectorFrame then return end + if inputObject.KeyCode ~= Enum.KeyCode.Thumbstick1 then return end + + + if inputObject.Position.X > CONTROLLER_THUMBSTICK_DEADZONE and inputObject.Delta.X > 0 and lastInputDirection ~= 1 then + lastInputDirection = 1 + stepFunc(inputObject, lastInputDirection) + elseif inputObject.Position.X < -CONTROLLER_THUMBSTICK_DEADZONE and inputObject.Delta.X < 0 and lastInputDirection ~= -1 then + lastInputDirection = -1 + stepFunc(inputObject, lastInputDirection) + elseif math.abs(inputObject.Position.X) < CONTROLLER_THUMBSTICK_DEADZONE then + lastInputDirection = 0 + end + end) + + this.SelectorFrame.AncestryChanged:connect(function(child, parent) + isInTree = parent + if not isInTree then + if guiServiceCon then guiServiceCon:disconnect() end + else + connectToGuiService() + end + end) + + connectToGuiService() + + return this +end + +local function ShowAlert(alertMessage, okButtonText, settingsHub, okPressedFunc, hasBackground) + if CoreGui.RobloxGui:FindFirstChild("AlertViewFullScreen") then return end + + local NON_SELECTED_TEXT_COLOR = Color3.new(59/255, 166/255, 241/255) + local SELECTED_TEXT_COLOR = Color3.new(1,1,1) + + local AlertViewBacking = Util.Create'ImageLabel' + { + Name = "AlertViewBacking", + Image = "rbxasset://textures/ui/Settings/MenuBarAssets/MenuButton.png", + ScaleType = Enum.ScaleType.Slice, + SliceCenter = Rect.new(8,6,46,44), + BackgroundTransparency = 1, + ImageTransparency = 1, + Size = UDim2.new(0, 400, 0, 350), + Position = UDim2.new(0.5, -200, 0.5, -175), + ZIndex = 9, + Parent = CoreGui.RobloxGui + }; + if hasBackground then + AlertViewBacking.ImageTransparency = 0 + else + AlertViewBacking.Size = UDim2.new(0.8, 0, 0, 350) + AlertViewBacking.Position = UDim2.new(0.1, 0, 0.1, 0) + end + + if CoreGui.RobloxGui.AbsoluteSize.Y <= AlertViewBacking.Size.Y.Offset then + AlertViewBacking.Size = UDim2.new(AlertViewBacking.Size.X.Scale, AlertViewBacking.Size.X.Offset, + AlertViewBacking.Size.Y.Scale, CoreGui.RobloxGui.AbsoluteSize.Y) + AlertViewBacking.Position = UDim2.new(0.5, -AlertViewBacking.Size.X.Offset/2, 0.5, -AlertViewBacking.Size.Y.Offset/2) + end + + local AlertViewText = Util.Create'TextLabel' + { + Name = "AlertViewText", + BackgroundTransparency = 1, + Size = UDim2.new(0.95, 0, 0.6, 0), + Position = UDim2.new(0.025, 0, 0.05, 0), + Font = Enum.Font.SourceSansBold, + FontSize = Enum.FontSize.Size36, + Text = alertMessage, + TextWrapped = true, + TextColor3 = Color3.new(1,1,1), + TextXAlignment = Enum.TextXAlignment.Center, + TextYAlignment = Enum.TextYAlignment.Center, + ZIndex = 10, + Parent = AlertViewBacking + }; + + local SelectionOverrideObject = Util.Create'ImageLabel' + { + Image = "", + BackgroundTransparency = 1 + }; + + local removeId = HttpService:GenerateGUID(false) + + local destroyAlert = function() + AlertViewBacking:Destroy() + if okPressedFunc then + okPressedFunc() + end + ContextActionService:UnbindCoreAction(removeId) + Game.GuiService.SelectedCoreObject = nil + if settingsHub then + settingsHub:ShowBar() + end + end + + local AlertViewButtonSize = UDim2.new(1, -20, 0, 60) + local AlertViewButtonPosition = UDim2.new(0, 10, 0.65, 0) + if not hasBackground then + AlertViewButtonSize = UDim2.new(0, 200, 0, 50) + AlertViewButtonPosition = UDim2.new(0.5, -100, 0.65, 0) + end + + local AlertViewButton, AlertViewText = MakeButton("AlertViewButton", okButtonText, AlertViewButtonSize, destroyAlert) + AlertViewButton.Position = AlertViewButtonPosition + AlertViewButton.NextSelectionLeft = AlertViewButton + AlertViewButton.NextSelectionRight = AlertViewButton + AlertViewButton.NextSelectionUp = AlertViewButton + AlertViewButton.NextSelectionDown = AlertViewButton + AlertViewButton.ZIndex = 10 + AlertViewText.ZIndex = AlertViewButton.ZIndex + AlertViewButton.Parent = AlertViewBacking + + if usesSelectedObject() then + Game.GuiService.SelectedCoreObject = AlertViewButton + end + + GuiService.SelectedCoreObject = AlertViewButton + + ContextActionService:BindCoreAction(removeId, destroyAlert, false, Enum.KeyCode.Escape, Enum.KeyCode.ButtonB, Enum.KeyCode.ButtonA) + + if settingsHub then + settingsHub:HideBar() + settingsHub.Pages.CurrentPage:Hide(1, 1) + end +end + +local function CreateNewSlider(numOfSteps, startStep, minStep) + -------------------- SETUP ------------------------ + local this = {} + + local spacing = 4 + local initialSpacing = 8 + local steps = tonumber(numOfSteps) + local currentStep = startStep + + local lastInputDirection = 0 + local timeAtLastInput = nil + + local interactable = true + + local renderStepBindName = HttpService:GenerateGUID(false) + + -- this is done to prevent using these values below (trying to keep the variables consistent) + numOfSteps = "" + startStep = "" + + if steps <= 0 then + error("CreateNewSlider failed because numOfSteps (first arg) is 0 or negative, please supply a positive integer") + return + end + + local valueChangedEvent = Instance.new("BindableEvent") + valueChangedEvent.Name = "ValueChanged" + + ----------------- GUI SETUP ------------------------ + this.SliderFrame = Util.Create'ImageButton' + { + Name = "Slider", + Image = "", + AutoButtonColor = false, + NextSelectionLeft = this.SliderFrame, + NextSelectionRight = this.SliderFrame, + BackgroundTransparency = 1, + Size = UDim2.new(0,502,0,50), + SelectionImageObject = noSelectionObject, + ZIndex = 2 + }; + if isSmallTouchScreen() then + this.SliderFrame.Size = UDim2.new(0,400,0,30) + end + + local leftButton = Util.Create'ImageButton' + { + Name = "LeftButton", + BackgroundTransparency = 1, + Position = UDim2.new(0,0,0.5,-25), + Size = UDim2.new(0,50,0,50), + Image = "", + ZIndex = 2, + Selectable = false, + Active = true, + Parent = this.SliderFrame + }; + local rightButton = Util.Create'ImageButton' + { + Name = "RightButton", + BackgroundTransparency = 1, + Position = UDim2.new(1,-50,0.5,-25), + Size = UDim2.new(0,50,0,50), + Image = "", + ZIndex = 2, + Selectable = false, + Active = true, + Parent = this.SliderFrame + }; + + local leftButtonImage = Util.Create'ImageLabel' + { + Name = "LeftButton", + BackgroundTransparency = 1, + Position = UDim2.new(1,-24,0.5,-15), + Size = UDim2.new(0,18,0,30), + Image = "rbxasset://textures/ui/Settings/Slider/Left.png", + ZIndex = 2, + Parent = leftButton + }; + local rightButtonImage = Util.Create'ImageLabel' + { + Name = "RightButton", + BackgroundTransparency = 1, + Position = UDim2.new(0,6,0.5,-15), + Size = UDim2.new(0,18,0,30), + Image = "rbxasset://textures/ui/Settings/Slider/Right.png", + ZIndex = 2, + Parent = rightButton + }; + + + this.Steps = {} + local stepXSize = 35 + if isSmallTouchScreen() then + stepXSize = 25 + end + + for i = 1, steps do + local nextStep = Util.Create'ImageButton' + { + Name = "Step" .. tostring(i), + BackgroundColor3 = SELECTED_COLOR, + BackgroundTransparency = 0.36, + BorderSizePixel = 0, + AutoButtonColor = false, + Active = false, + Position = UDim2.new(0,initialSpacing + leftButton.Size.X.Offset + ((stepXSize + spacing) * (i - 1)),0.5,-12), + Size = UDim2.new(0,stepXSize,0, 24), + Image = "", + ZIndex = 2, + Selectable = false, + ImageTransparency = 0.36, + Parent = this.SliderFrame + }; + + if i > currentStep then + nextStep.BackgroundColor3 = NON_SELECTED_COLOR + end + + if i == 1 or i == steps then + nextStep.BackgroundTransparency = 1 + nextStep.ScaleType = Enum.ScaleType.Slice + nextStep.SliceCenter = Rect.new(3,3,32,21) + + if i <= currentStep then + if i == 1 then + nextStep.Image = SELECTED_LEFT_IMAGE + else + nextStep.Image = SELECTED_RIGHT_IMAGE + end + else + if i == 1 then + nextStep.Image = NON_SELECTED_LEFT_IMAGE + else + nextStep.Image = NON_SELECTED_RIGHT_IMAGE + end + end + end + + this.Steps[#this.Steps + 1] = nextStep + end + + local xSize = initialSpacing + (leftButton.Size.X.Offset) + this.Steps[#this.Steps].Size.X.Offset + + this.Steps[#this.Steps].Position.X.Offset + this.SliderFrame.Size = UDim2.new(0, xSize, 0, this.SliderFrame.Size.Y.Offset) + + + ------------------- FUNCTIONS --------------------- + local function hideSelection() + for i = 1, steps do + this.Steps[i].BackgroundColor3 = NON_SELECTED_COLOR + if i == 1 then + this.Steps[i].Image = NON_SELECTED_LEFT_IMAGE + elseif i == steps then + this.Steps[i].Image = NON_SELECTED_RIGHT_IMAGE + end + end + end + local function showSelection() + for i = 1, steps do + if i > currentStep then break end + this.Steps[i].BackgroundColor3 = SELECTED_COLOR + if i == 1 then + this.Steps[i].Image = SELECTED_LEFT_IMAGE + elseif i == steps then + this.Steps[i].Image = SELECTED_RIGHT_IMAGE + end + end + end + local function modifySelection(alpha) + for i = 1, steps do + if i == 1 or i == steps then + this.Steps[i].ImageTransparency = alpha + else + this.Steps[i].BackgroundTransparency = alpha + end + end + end + + local function setCurrentStep(newStepPosition) + if not minStep then minStep = 0 end + + leftButton.Visible = true + rightButton.Visible = true + + if newStepPosition <= minStep then + newStepPosition = minStep + leftButton.Visible = false + end + if newStepPosition >= steps then + newStepPosition = steps + rightButton.Visible = false + end + + if currentStep == newStepPosition then return end + + currentStep = newStepPosition + + hideSelection() + showSelection() + + timeAtLastInput = tick() + valueChangedEvent:Fire(currentStep) + end + + local function mouseDownFunc(inputObject, newStepPos, repeatAction) + if not interactable then return end + + if inputObject == nil then return end + if inputObject.UserInputType ~= Enum.UserInputType.MouseButton1 and inputObject.UserInputType ~= Enum.UserInputType.Touch then return end + + if usesSelectedObject() then + GuiService.SelectedCoreObject = this.SliderFrame + end + + if repeatAction then + lastInputDirection = newStepPos - currentStep + else + lastInputDirection = 0 + + local mouseInputMovedCon = nil + local mouseInputEndedCon = nil + mouseInputMovedCon = UserInputService.InputChanged:connect(function( inputObject ) + if inputObject.UserInputType ~= Enum.UserInputType.MouseMovement and inputObject.UserInputType ~= Enum.UserInputType.Touch then return end + + local mousePos = inputObject.Position.X + for i = 1, steps do + local stepPosition = this.Steps[i].AbsolutePosition.X + local stepSize = this.Steps[i].AbsoluteSize.X + if mousePos >= stepPosition and mousePos <= stepPosition + stepSize then + setCurrentStep(i) + break + elseif i == 1 and mousePos < stepPosition then + setCurrentStep(0) + break + elseif i == steps and mousePos >= stepPosition then + setCurrentStep(i) + break + end + end + end) + mouseInputEndedCon = UserInputService.InputEnded:connect(function( inputObject ) + if inputObject.UserInputType ~= Enum.UserInputType.MouseButton1 and inputObject.UserInputType ~= Enum.UserInputType.Touch then return end + + lastInputDirection = 0 + mouseInputEndedCon:disconnect() + mouseInputMovedCon:disconnect() + end) + end + + setCurrentStep(newStepPos) + end + + local function mouseUpFunc(inputObject) + if not interactable then return end + if inputObject.UserInputType ~= Enum.UserInputType.MouseButton1 then return end + + lastInputDirection = 0 + end + + local function touchClickFunc(inputObject, newStepPos, repeatAction) + mouseDownFunc(inputObject, newStepPos, repeatAction) + end + + --------------------- PUBLIC FACING FUNCTIONS ----------------------- + this.ValueChanged = valueChangedEvent.Event + + function this:SetValue(newValue) + setCurrentStep(newValue) + end + + function this:GetValue() + return currentStep + end + + function this:SetInteractable(value) + lastInputDirection = 0 + interactable = value + this.SliderFrame.Selectable = value + if not interactable then + hideSelection() + else + showSelection() + end + end + + function this:SetZIndex(newZIndex) + leftButton.ZIndex = newZIndex + rightButton.ZIndex = newZIndex + leftButtonImage.ZIndex = newZIndex + rightButtonImage.ZIndex = newZIndex + + for i = 1, #this.Steps do + this.Steps[i].ZIndex = newZIndex + end + end + + function this:SetMinStep(newMinStep) + if newMinStep >= 0 and newMinStep <= steps then + minStep = newMinStep + end + + if currentStep <= minStep then + currentStep = minStep + leftButton.Visible = false + end + if currentStep >= steps then + currentStep = steps + rightButton.Visible = false + end + end + + --------------------- SETUP ----------------------- + + leftButton.InputBegan:connect(function(inputObject) mouseDownFunc(inputObject, currentStep - 1, true) end) + leftButton.InputEnded:connect(function(inputObject) mouseUpFunc(inputObject) end) + leftButton.MouseButton1Click:connect(function() + if UserInputService.TouchEnabled and not UserInputService.GamepadEnabled then + touchClickFunc(inputObject, currentStep - 1, true) + end + end) + rightButton.InputBegan:connect(function(inputObject) mouseDownFunc(inputObject, currentStep + 1, true) end) + rightButton.InputEnded:connect(function(inputObject) mouseUpFunc(inputObject) end) + rightButton.MouseButton1Click:connect(function() + if UserInputService.TouchEnabled and not UserInputService.GamepadEnabled then + touchClickFunc(inputObject, currentStep + 1, true) + end + end) + + for i = 1, steps do + this.Steps[i].InputBegan:connect(function(inputObject) mouseDownFunc(inputObject, i) end) + this.Steps[i].InputEnded:connect(function(inputObject) mouseUpFunc(inputObject) end) + end + + this.SliderFrame.InputBegan:connect(function(inputObject) mouseDownFunc(inputObject, currentStep) end) + this.SliderFrame.InputEnded:connect(function(inputObject) mouseUpFunc(inputObject) end) + + + local stepSliderFunc = function() + if timeAtLastInput == nil then return end + + local currentTime = tick() + local timeSinceLastInput = currentTime - timeAtLastInput + + if timeSinceLastInput >= CONTROLLER_SCROLL_DELTA then + setCurrentStep(currentStep + lastInputDirection) + end + end + + local isInTree = true + UserInputService.InputBegan:connect(function(inputObject) + if not interactable then return end + if not isInTree then return end + + if inputObject.UserInputType ~= Enum.UserInputType.Gamepad1 and inputObject.UserInputType ~= Enum.UserInputType.Keyboard then return end + if GuiService.SelectedCoreObject ~= this.SliderFrame then return end + + if inputObject.KeyCode == Enum.KeyCode.DPadLeft or inputObject.KeyCode == Enum.KeyCode.Left or inputObject.KeyCode == Enum.KeyCode.A then + lastInputDirection = -1 + setCurrentStep(currentStep - 1) + elseif inputObject.KeyCode == Enum.KeyCode.DPadRight or inputObject.KeyCode == Enum.KeyCode.Right or inputObject.KeyCode == Enum.KeyCode.D then + lastInputDirection = 1 + setCurrentStep(currentStep + 1) + end + end) + + UserInputService.InputEnded:connect(function(inputObject) + if not interactable then return end + + if inputObject.UserInputType ~= Enum.UserInputType.Gamepad1 and inputObject.UserInputType ~= Enum.UserInputType.Keyboard then return end + if GuiService.SelectedCoreObject ~= this.SliderFrame then return end + + if inputObject.KeyCode == Enum.KeyCode.Thumbstick1 or inputObject.KeyCode == Enum.KeyCode.DPadLeft + or inputObject.KeyCode == Enum.KeyCode.DPadRight or inputObject.KeyCode == Enum.KeyCode.Left + or inputObject.KeyCode == Enum.KeyCode.A or inputObject.KeyCode == Enum.KeyCode.Right or inputObject.KeyCode == Enum.KeyCode.D then + lastInputDirection = 0 + end + end) + + UserInputService.InputChanged:connect(function(inputObject) + if not interactable then + lastInputDirection = 0 + return + end + if not isInTree then + lastInputDirection = 0 + return + end + + if inputObject.UserInputType ~= Enum.UserInputType.Gamepad1 then return end + if GuiService.SelectedCoreObject ~= this.SliderFrame then return end + if inputObject.KeyCode ~= Enum.KeyCode.Thumbstick1 then return end + + if inputObject.Position.X > CONTROLLER_THUMBSTICK_DEADZONE and inputObject.Delta.X > 0 and lastInputDirection ~= 1 then + lastInputDirection = 1 + setCurrentStep(currentStep + 1) + elseif inputObject.Position.X < -CONTROLLER_THUMBSTICK_DEADZONE and inputObject.Delta.X < 0 and lastInputDirection ~= -1 then + lastInputDirection = -1 + setCurrentStep(currentStep - 1) + elseif math.abs(inputObject.Position.X) < CONTROLLER_THUMBSTICK_DEADZONE then + lastInputDirection = 0 + end + end) + + GuiService.Changed:connect(function(prop) + if prop ~= "SelectedCoreObject" then return end + + if GuiService.SelectedCoreObject == this.SliderFrame then + modifySelection(0) + RunService:BindToRenderStep(renderStepBindName, Enum.RenderPriority.Input.Value + 1, stepSliderFunc) + else + modifySelection(0.36) + RunService:UnbindFromRenderStep(renderStepBindName) + end + end) + + this.SliderFrame.AncestryChanged:connect(function(child, parent) + isInTree = parent + end) + + setCurrentStep(currentStep) + + return this +end + +local ROW_HEIGHT = 50 +if isTenFootInterface() then ROW_HEIGHT = 90 end + +local nextPosTable = {} +local function AddNewRow(pageToAddTo, rowDisplayName, selectionType, rowValues, rowDefault, extraSpacing) + local nextRowPositionY = 0 + local isARealRow = selectionType ~= 'TextBox' -- Textboxes are constructed in this function - they don't have an associated class. + + if nextPosTable[pageToAddTo] then + nextRowPositionY = nextPosTable[pageToAddTo] + end + + local RowFrame = nil + RowFrame = Util.Create'ImageButton' + { + Name = rowDisplayName .. "Frame", + BackgroundTransparency = 1, + BorderSizePixel = 0, + Image = "", + Active = false, + AutoButtonColor = false, + Size = UDim2.new(1,0,0,ROW_HEIGHT), + Position = UDim2.new(0,0,0,nextRowPositionY), + ZIndex = 2, + Selectable = false, + Parent = pageToAddTo.Page + }; + + if RowFrame and extraSpacing then + RowFrame.Position = UDim2.new(RowFrame.Position.X.Scale,RowFrame.Position.X.Offset, + RowFrame.Position.Y.Scale,RowFrame.Position.Y.Offset + extraSpacing) + end + + local RowLabel = nil + RowLabel = Util.Create'TextLabel' + { + Name = rowDisplayName .. "Label", + Text = rowDisplayName, + Font = Enum.Font.SourceSansBold, + FontSize = Enum.FontSize.Size24, + TextColor3 = Color3.new(1,1,1), + TextXAlignment = Enum.TextXAlignment.Left, + BackgroundTransparency = 1, + Size = UDim2.new(0,200,1,0), + Position = UDim2.new(0,10,0,0), + ZIndex = 2, + Parent = RowFrame + }; + if isTenFootInterface() then + RowLabel.FontSize = Enum.FontSize.Size36 + end + if not isARealRow then + RowLabel.Text = '' + end + + local ValueChangerSelection = nil + local ValueChangerInstance = nil + if selectionType == "Slider" then + ValueChangerInstance = CreateNewSlider(rowValues, rowDefault) + ValueChangerInstance.SliderFrame.Position = UDim2.new(1,-ValueChangerInstance.SliderFrame.Size.X.Offset, + 0.5,-ValueChangerInstance.SliderFrame.Size.Y.Offset/2) + ValueChangerInstance.SliderFrame.Parent = RowFrame + ValueChangerSelection = ValueChangerInstance.SliderFrame + elseif selectionType == "Selector" then + ValueChangerInstance = CreateSelector(rowValues, rowDefault) + ValueChangerInstance.SelectorFrame.Position = UDim2.new(1,-ValueChangerInstance.SelectorFrame.Size.X.Offset, + 0.5,-ValueChangerInstance.SelectorFrame.Size.Y.Offset/2) + ValueChangerInstance.SelectorFrame.Parent = RowFrame + ValueChangerSelection = ValueChangerInstance.SelectorFrame + elseif selectionType == "DropDown" then + ValueChangerInstance = CreateDropDown(rowValues, rowDefault, pageToAddTo.HubRef) + ValueChangerInstance.DropDownFrame.Position = UDim2.new(1,-ValueChangerInstance.DropDownFrame.Size.X.Offset - 50, + 0.5,-ValueChangerInstance.DropDownFrame.Size.Y.Offset/2) + ValueChangerInstance.DropDownFrame.Parent = RowFrame + ValueChangerSelection = ValueChangerInstance.DropDownFrame + elseif selectionType == "TextBox" then + local isMouseOverRow = false + local forceReturnSelectionOnFocusLost = false + local SelectionOverrideObject = Util.Create'ImageLabel' + { + Image = "", + BackgroundTransparency = 1, + }; + + ValueChangerInstance = {} + ValueChangerInstance.HubRef = nil + + local box = Util.Create'TextBox' + { + Size = UDim2.new(1,-10,0,100), + Position = UDim2.new(0,5,0,nextRowPositionY), + Text = rowDisplayName, + TextColor3 = Color3.new(49/255, 49/255, 49/255), + BackgroundTransparency = 0.5, + BorderSizePixel = 0, + TextYAlignment = Enum.TextYAlignment.Top, + TextXAlignment = Enum.TextXAlignment.Left, + TextWrapped = true, + Font = Enum.Font.SourceSans, + FontSize = Enum.FontSize.Size24, + ZIndex = 2, + SelectionImageObject = SelectionOverrideObject, + ClearTextOnFocus = false, + Parent = pageToAddTo.Page + }; + ValueChangerSelection = box + + box.Focused:connect(function() + if usesSelectedObject() then + GuiService.SelectedCoreObject = box + end + + if box.Text == rowDisplayName then + box.Text = "" + end + end) + box.FocusLost:connect(function(enterPressed, inputObject) + if GuiService.SelectedCoreObject == box and (not isMouseOverRow or forceReturnSelectionOnFocusLost) then + GuiService.SelectedCoreObject = nil + end + forceReturnSelectionOnFocusLost = false + end) + if extraSpacing then + box.Position = UDim2.new(box.Position.X.Scale,box.Position.X.Offset, + box.Position.Y.Scale,box.Position.Y.Offset + extraSpacing) + end + + ValueChangerSelection.SelectionGained:connect(function() + if usesSelectedObject() then + box.BackgroundTransparency = 0.1 + + if ValueChangerInstance.HubRef then + ValueChangerInstance.HubRef:ScrollToFrame(ValueChangerSelection) + end + end + end) + ValueChangerSelection.SelectionLost:connect(function() + if usesSelectedObject() then + box.BackgroundTransparency = 0.5 + end + end) + + local setRowSelection = function() + local fullscreenDropDown = CoreGui.RobloxGui:FindFirstChild("DropDownFullscreenFrame") + if fullscreenDropDown and fullscreenDropDown.Visible then return end + + local valueFrame = ValueChangerSelection + + if valueFrame and valueFrame.Visible and valueFrame.ZIndex > 1 and usesSelectedObject() and pageToAddTo.Active then + GuiService.SelectedCoreObject = valueFrame + isMouseOverRow = true + end + end + local function processInput(input) + if input.UserInputState == Enum.UserInputState.Begin then + if input.KeyCode == Enum.KeyCode.Return then + if GuiService.SelectedCoreObject == ValueChangerSelection then + forceReturnSelectionOnFocusLost = true + box:CaptureFocus() + end + end + end + end + RowFrame.MouseEnter:connect(setRowSelection) + RowFrame.Size = UDim2.new(1, 0, 0, 100) + + UserInputService.InputBegan:connect(processInput) + + elseif selectionType == "TextEntry" then + local isMouseOverRow = false + local forceReturnSelectionOnFocusLost = false + local SelectionOverrideObject = Util.Create'ImageLabel' + { + Image = "", + BackgroundTransparency = 1, + }; + + ValueChangerInstance = {} + ValueChangerInstance.HubRef = nil + + local box = Util.Create'TextBox' + { + Size = UDim2.new(0.4,-10,0,40), + Position = UDim2.new(0.5,5,0,nextRowPositionY+5), + Text = rowDisplayName, + TextColor3 = Color3.new(0.7, 0.7, 0.7), + BackgroundTransparency = 1.0, + BorderSizePixel = 0, + TextYAlignment = Enum.TextYAlignment.Center, + TextXAlignment = Enum.TextXAlignment.Center, + TextWrapped = false, + Font = Enum.Font.SourceSans, + FontSize = Enum.FontSize.Size24, + ZIndex = 2, + SelectionImageObject = SelectionOverrideObject, + ClearTextOnFocus = false, + Parent = pageToAddTo.Page + }; + ValueChangerSelection = box + + box.Focused:connect(function() + if usesSelectedObject() then + GuiService.SelectedCoreObject = box + end + + if box.Text == rowDisplayName then + box.Text = "" + end + end) + box.FocusLost:connect(function(enterPressed, inputObject) + if GuiService.SelectedCoreObject == box and (not isMouseOverRow or forceReturnSelectionOnFocusLost) then + GuiService.SelectedCoreObject = nil + end + forceReturnSelectionOnFocusLost = false + end) + if extraSpacing then + box.Position = UDim2.new(box.Position.X.Scale,box.Position.X.Offset, + box.Position.Y.Scale,box.Position.Y.Offset + extraSpacing) + end + + ValueChangerSelection.SelectionGained:connect(function() + if usesSelectedObject() then + box.BackgroundTransparency = 0.8 + + if ValueChangerInstance.HubRef then + ValueChangerInstance.HubRef:ScrollToFrame(ValueChangerSelection) + end + end + end) + ValueChangerSelection.SelectionLost:connect(function() + if usesSelectedObject() then + box.BackgroundTransparency = 1.0 + end + end) + + local setRowSelection = function() + local fullscreenDropDown = CoreGui.RobloxGui:FindFirstChild("DropDownFullscreenFrame") + if fullscreenDropDown and fullscreenDropDown.Visible then return end + + local valueFrame = ValueChangerSelection + + if valueFrame and valueFrame.Visible and valueFrame.ZIndex > 1 and usesSelectedObject() and pageToAddTo.Active then + GuiService.SelectedCoreObject = valueFrame + isMouseOverRow = true + end + end + local function processInput(input) + if input.UserInputState == Enum.UserInputState.Begin then + if input.KeyCode == Enum.KeyCode.Return then + if GuiService.SelectedCoreObject == ValueChangerSelection then + forceReturnSelectionOnFocusLost = true + box:CaptureFocus() + end + end + end + end + RowFrame.MouseEnter:connect(setRowSelection) + + function ValueChangerInstance:SetZIndex(newZIndex) + box.ZIndex = newZIndex + end + + function ValueChangerInstance:SetInteractable(value) + interactable = value + box.Selectable = interactable + if not interactable then + box.TextColor3 = Color3.new(49/255, 49/255, 49/255) + box.ZIndex = 1 + else + box.TextColor3 = Color3.new(0.7, 0.7, 0.7) + box.ZIndex = 2 + end + end + + function ValueChangerInstance:SetValue(value) -- should this do more? + box.Text = value + end + + local valueChangedEvent = Instance.new("BindableEvent") + valueChangedEvent.Name = "ValueChanged" + + box.FocusLost:connect(function() + valueChangedEvent:Fire(box.Text) + end) + + ValueChangerInstance.ValueChanged = valueChangedEvent.Event + + UserInputService.InputBegan:connect(processInput) + end + + ValueChangerInstance.Name = rowDisplayName .. "ValueChanger" + + nextRowPositionY = nextRowPositionY + ROW_HEIGHT + if extraSpacing then + nextRowPositionY = nextRowPositionY + extraSpacing + end + + nextPosTable[pageToAddTo] = nextRowPositionY + + if isARealRow then + local setRowSelection = function() + local fullscreenDropDown = CoreGui.RobloxGui:FindFirstChild("DropDownFullscreenFrame") + if fullscreenDropDown and fullscreenDropDown.Visible then return end + + local valueFrame = ValueChangerInstance.SliderFrame + if not valueFrame then + valueFrame = ValueChangerInstance.SliderFrame + end + if not valueFrame then + valueFrame = ValueChangerInstance.DropDownFrame + end + if not valueFrame then + valueFrame = ValueChangerInstance.SelectorFrame + end + + if valueFrame and valueFrame.Visible and valueFrame.ZIndex > 1 and usesSelectedObject() and pageToAddTo.Active then + GuiService.SelectedCoreObject = valueFrame + end + end + RowFrame.MouseEnter:connect(setRowSelection) + + ValueChangerSelection.SelectionGained:connect(function() + if usesSelectedObject() then + RowFrame.BackgroundTransparency = 0.5 + + if ValueChangerInstance.HubRef then + ValueChangerInstance.HubRef:ScrollToFrame(RowFrame) + end + end + end) + ValueChangerSelection.SelectionLost:connect(function() + if usesSelectedObject() then + RowFrame.BackgroundTransparency = 1 + end + end) + end + + pageToAddTo:AddRow(RowFrame, RowLabel, ValueChangerInstance, extraSpacing, false) + + ValueChangerInstance.Selection = ValueChangerSelection + + return RowFrame, RowLabel, ValueChangerInstance +end + +local function AddNewRowObject(pageToAddTo, rowDisplayName, rowObject, extraSpacing) + local nextRowPositionY = 0 + + if nextPosTable[pageToAddTo] then + nextRowPositionY = nextPosTable[pageToAddTo] + end + + local RowFrame = Util.Create'ImageButton' + { + Name = rowDisplayName .. "Frame", + BackgroundTransparency = 1, + BorderSizePixel = 0, + Image = "", + Active = false, + AutoButtonColor = false, + Size = UDim2.new(1,0,0,ROW_HEIGHT), + Position = UDim2.new(0,0,0,nextRowPositionY), + ZIndex = 2, + Selectable = false, + SelectionImageObject = noSelectionObject, + Parent = pageToAddTo.Page + }; + RowFrame.SelectionGained:connect(function() + RowFrame.BackgroundTransparency = 0.5 + end) + RowFrame.SelectionLost:connect(function() + RowFrame.BackgroundTransparency = 1 + end) + + local RowLabel = Util.Create'TextLabel' + { + Name = rowDisplayName .. "Label", + Text = rowDisplayName, + Font = Enum.Font.SourceSansBold, + FontSize = Enum.FontSize.Size24, + TextColor3 = Color3.new(1,1,1), + TextXAlignment = Enum.TextXAlignment.Left, + BackgroundTransparency = 1, + Size = UDim2.new(0,200,1,0), + Position = UDim2.new(0,10,0,0), + ZIndex = 2, + Parent = RowFrame + }; + if isTenFootInterface() then + RowLabel.FontSize = Enum.FontSize.Size36 + end + + if extraSpacing then + RowFrame.Position = UDim2.new(RowFrame.Position.X.Scale,RowFrame.Position.X.Offset, + RowFrame.Position.Y.Scale,RowFrame.Position.Y.Offset + extraSpacing) + end + + nextRowPositionY = nextRowPositionY + ROW_HEIGHT + if extraSpacing then + nextRowPositionY = nextRowPositionY + extraSpacing + end + + nextPosTable[pageToAddTo] = nextRowPositionY + + local setRowSelection = function() + if RowFrame.Visible then + GuiService.SelectedCoreObject = RowFrame + end + end + RowFrame.MouseEnter:connect(setRowSelection) + + rowObject.SelectionImageObject = noSelectionObject + + rowObject.SelectionGained:connect(function() + RowFrame.BackgroundTransparency = 0.5 + end) + rowObject.SelectionLost:connect(function() + RowFrame.BackgroundTransparency = 1 + end) + + rowObject.Parent = RowFrame + + pageToAddTo:AddRow(RowFrame, RowLabel, rowObject, extraSpacing, true) + return RowFrame +end + +-------- public facing API ---------------- +local moduleApiTable = {} + +function moduleApiTable:Create(instanceType) + return function(data) + local obj = Instance.new(instanceType) + for k, v in pairs(data) do + if type(k) == 'number' then + v.Parent = obj + else + obj[k] = v + end + end + return obj + end +end + +function moduleApiTable:GetEaseLinear() + return Linear +end +function moduleApiTable:GetEaseOutQuad() + return EaseOutQuad +end +function moduleApiTable:GetEaseInOutQuad() + return EaseInOutQuad +end + +function moduleApiTable:CreateNewSlider(numOfSteps, startStep, minStep) + return CreateNewSlider(numOfSteps, startStep, minStep) +end + +function moduleApiTable:CreateNewSelector(selectionStringTable, startPosition) + return CreateSelector(selectionStringTable, startPosition) +end + +function moduleApiTable:CreateNewDropDown(dropDownStringTable, startPosition) + return CreateDropDown(dropDownStringTable, startPosition, nil) +end + +function moduleApiTable:AddNewRow(pageToAddTo, rowDisplayName, selectionType, rowValues, rowDefault, extraSpacing) + return AddNewRow(pageToAddTo, rowDisplayName, selectionType, rowValues, rowDefault, extraSpacing) +end + +function moduleApiTable:AddNewRowObject(pageToAddTo, rowDisplayName, rowObject, extraSpacing) + return AddNewRowObject(pageToAddTo, rowDisplayName, rowObject, extraSpacing) +end + +function moduleApiTable:ShowAlert(alertMessage, okButtonText, settingsHub, okPressedFunc, hasBackground) + ShowAlert(alertMessage, okButtonText, settingsHub, okPressedFunc, hasBackground) +end + +function moduleApiTable:IsSmallTouchScreen() + return isSmallTouchScreen() +end + +function moduleApiTable:MakeStyledButton(name, text, size, clickFunc, pageRef, hubRef) + return MakeButton(name, text, size, clickFunc, pageRef, hubRef) +end + +function moduleApiTable:CreateSignal() + return CreateSignal() +end + +function moduleApiTable:UsesSelectedObject() + return usesSelectedObject(); +end + +function moduleApiTable:TweenProperty(instance, prop, start, final, duration, easingFunc, cbFunc) + return PropertyTweener(instance, prop, start, final, duration, easingFunc, cbFunc) +end + +return moduleApiTable + diff --git a/2016/content/scripts/Modules/TenFootInterface.lua b/2016/content/scripts/Modules/TenFootInterface.lua new file mode 100644 index 0000000..0e92d97 --- /dev/null +++ b/2016/content/scripts/Modules/TenFootInterface.lua @@ -0,0 +1,345 @@ +--[[ + Filename: TenFootInterface.lua + Written by: jeditkacheff + Version 1.0 + Description: Setups up some special UI for ROBLOX TV gaming +--]] +-------------- CONSTANTS -------------- +local HEALTH_GREEN_COLOR = Color3.new(27/255, 252/255, 107/255) +local DISPLAY_POS_INIT_INSET = 0 +local DISPLAY_ITEM_OFFSET = 4 +local FORCE_TEN_FOOT_INTERFACE = false + +-------------- SERVICES -------------- +local CoreGui = game:GetService("CoreGui") +local RobloxGui = CoreGui:WaitForChild("RobloxGui") +local UserInputService = game:GetService("UserInputService") +local GuiService = game:GetService("GuiService") + +------------------ VARIABLES -------------------- +local tenFootInterfaceEnabled = false +do + local platform = UserInputService:GetPlatform() + + tenFootInterfaceEnabled = (platform == Enum.Platform.XBoxOne or platform == Enum.Platform.WiiU or platform == Enum.Platform.PS4 or + platform == Enum.Platform.AndroidTV or platform == Enum.Platform.XBox360 or platform == Enum.Platform.PS3 or + platform == Enum.Platform.Ouya or platform == Enum.Platform.SteamOS) +end + +if FORCE_TEN_FOOT_INTERFACE then + tenFootInterfaceEnabled = true +end + +local Util = {} +do + function Util.Create(instanceType) + return function(data) + local obj = Instance.new(instanceType) + for k, v in pairs(data) do + if type(k) == 'number' then + v.Parent = obj + else + obj[k] = v + end + end + return obj + end + end +end + +local function CreateModule() + local this = {} + local nextObjectDisplayYPos = DISPLAY_POS_INIT_INSET + local displayStack = {} + + -- setup base gui + local function createContainer() + if not this.Container then + this.Container = Util.Create'ImageButton' + { + Name = "TopRightContainer"; + Size = UDim2.new(0, 350, 0, 100); + Position = UDim2.new(1,-360,0,10); + AutoButtonColor = false; + Image = ""; + Active = false; + BackgroundTransparency = 1; + Parent = RobloxGui; + }; + end + end + + function removeFromDisplayStack(displayObject) + local moveUpFromHere = nil + + for i = 1, #displayStack do + if displayStack[i] == displayObject then + moveUpFromHere = i + 1 + break + end + end + + local prevObject = displayObject + for i = moveUpFromHere, #displayStack do + local objectToMoveUp = displayStack[i] + objectToMoveUp.Position = UDim2.new(objectToMoveUp.Position.X.Scale, objectToMoveUp.Position.X.Offset, + objectToMoveUp.Position.Y.Scale, prevObject.AbsolutePosition.Y) + prevObject = objectToMoveUp + end + end + + function addBackToDisplayStack(displayObject) + for i = 1, #displayStack do + if displayStack[i] == displayObject then + moveDownFromHere = i + 1 + break + end + end + + local prevObject = displayObject + for i = moveDownFromHere, #displayStack do + local objectToMoveDown = displayStack[i] + local nextDisplayPos = prevObject.AbsolutePosition.Y + prevObject.AbsoluteSize.Y + DISPLAY_ITEM_OFFSET + objectToMoveDown.Position = UDim2.new(objectToMoveDown.Position.X.Scale, objectToMoveDown.Position.X.Offset, + objectToMoveDown.Position.Y.Scale, nextDisplayPos) + prevObject = objectToMoveDown + end + end + + function addToDisplayStack(displayObject) + local lastDisplayed = nil + if #displayStack > 0 then + lastDisplayed = displayStack[#displayStack] + end + displayStack[#displayStack + 1] = displayObject + + local nextDisplayPos = DISPLAY_POS_INIT_INSET + if lastDisplayed then + nextDisplayPos = lastDisplayed.AbsolutePosition.Y + lastDisplayed.AbsoluteSize.Y + DISPLAY_ITEM_OFFSET + end + + displayObject.Position = UDim2.new(displayObject.Position.X.Scale, displayObject.Position.X.Offset, + displayObject.Position.Y.Scale, nextDisplayPos) + + createContainer() + displayObject.Parent = this.Container + + displayObject.Changed:connect(function(prop) + if prop == "Visible" then + if not displayObject.Visible then + removeFromDisplayStack(displayObject) + else + addBackToDisplayStack(displayObject) + end + end + end) + end + + function this:CreateHealthBar() + this.HealthContainer = Util.Create'Frame'{ + Name = "HealthContainer"; + Size = UDim2.new(1, -86, 0, 50); + Position = UDim2.new(0, 92, 0, 0); + BorderSizePixel = 0; + BackgroundColor3 = Color3.new(0,0,0); + BackgroundTransparency = 0.5; + }; + + local healthFillHolder = Util.Create'Frame'{ + Name = "HealthFillHolder"; + Size = UDim2.new(1, -10, 1, -10); + Position = UDim2.new(0, 5, 0, 5); + BorderSizePixel = 0; + BackgroundColor3 = Color3.new(1,1,1); + BackgroundTransparency = 1.0; + Parent = this.HealthContainer; + }; + + local healthFill = Util.Create'Frame'{ + Name = "HealthFill"; + Size = UDim2.new(1, 0, 1, 0); + Position = UDim2.new(0, 0, 0, 0); + BorderSizePixel = 0; + BackgroundTransparency = 0.0; + BackgroundColor3 = HEALTH_GREEN_COLOR; + Parent = healthFillHolder; + }; + + local healthText = Util.Create'TextLabel'{ + Name = "HealthText"; + Size = UDim2.new(0, 98, 0, 50); + Position = UDim2.new(0, -100, 0, 0); + BackgroundTransparency = 0.5; + BackgroundColor3 = Color3.new(0,0,0); + Font = Enum.Font.SourceSans; + FontSize = Enum.FontSize.Size36; + Text = "Health"; + TextColor3 = Color3.new(1,1,1); + BorderSizePixel = 0; + Parent = this.HealthContainer; + }; + + local username = Util.Create'TextLabel'{ + Visible = false + } + + addToDisplayStack(this.HealthContainer) + createContainer() + + return this.Container, username, this.HealthContainer, healthFill + end + + function this:SetupTopStat() + local topStatEnabled = true + local displayedStat = nil + local displayedStatChangedCon = nil + local displayedStatParentedCon = nil + local leaderstatsChildAddedCon = nil + local tenFootInterfaceStat = nil + + local function makeTenFootInterfaceStat() + if tenFootInterfaceStat then return end + + tenFootInterfaceStat = Util.Create'Frame'{ + Name = "OneStatFrame"; + Size = UDim2.new(1, 0, 0, 36); + Position = UDim2.new(0, 0, 0, 0); + BorderSizePixel = 0; + BackgroundTransparency = 1; + }; + local statName = Util.Create'TextLabel'{ + Name = "StatName"; + Size = UDim2.new(0.5,0,0,36); + BackgroundTransparency = 1; + Font = Enum.Font.SourceSans; + FontSize = Enum.FontSize.Size36; + TextStrokeColor3 = Color3.new(104/255, 104/255, 104/255); + TextStrokeTransparency = 0; + Text = " StatName:"; + TextColor3 = Color3.new(1,1,1); + TextXAlignment = Enum.TextXAlignment.Left; + BorderSizePixel = 0; + ClipsDescendants = true; + Parent = tenFootInterfaceStat; + }; + local statValue = statName:clone() + statValue.Position = UDim2.new(0.5,0,0,0) + statValue.Name = "StatValue" + statValue.Text = "123,643,231" + statValue.TextXAlignment = Enum.TextXAlignment.Right + statValue.Parent = tenFootInterfaceStat + + addToDisplayStack(tenFootInterfaceStat) + end + + local function setDisplayedStat(newStat) + if displayedStatChangedCon then displayedStatChangedCon:disconnect() displayedStatChangedCon = nil end + if displayedStatParentedCon then displayedStatParentedCon:disconnect() displayedStatParentedCon = nil end + + displayedStat = newStat + + if displayedStat then + makeTenFootInterfaceStat() + updateTenFootStat(displayedStat) + displayedStatParentedCon = displayedStat.AncestryChanged:connect(function() updateTenFootStat(displayedStat, "Parent") end) + displayedStatChangedCon = displayedStat.Changed:connect(function(prop) updateTenFootStat(displayedStat, prop) end) + end + end + + function updateTenFootStat(statObj, property) + if property and property == "Parent" then + tenFootInterfaceStat.StatName.Text = "" + tenFootInterfaceStat.StatValue.Text = "" + setDisplayedStat(nil) + + tenFootInterfaceChanged() + else + if topStatEnabled then + tenFootInterfaceStat.StatName.Text = " " .. tostring(statObj.Name) .. ":" + tenFootInterfaceStat.StatValue.Text = tostring(statObj.Value) + else + tenFootInterfaceStat.StatName.Text = "" + tenFootInterfaceStat.StatValue.Text = "" + end + end + end + + local function isValidStat(obj) + return obj:IsA('StringValue') or obj:IsA('IntValue') or obj:IsA('BoolValue') or obj:IsA('NumberValue') or + obj:IsA('DoubleConstrainedValue') or obj:IsA('IntConstrainedValue') + end + + local function tenFootInterfaceNewStat( newStat ) + if not displayedStat and isValidStat(newStat) then + setDisplayedStat(newStat) + end + end + + function tenFootInterfaceChanged() + game:WaitForChild("Players") + while not game.Players.LocalPlayer do + wait() + end + + local leaderstats = game.Players.LocalPlayer:FindFirstChild('leaderstats') + if leaderstats then + local statChildren = leaderstats:GetChildren() + for i = 1, #statChildren do + tenFootInterfaceNewStat(statChildren[i]) + end + if leaderstatsChildAddedCon then leaderstatsChildAddedCon:disconnect() end + leaderstatsChildAddedCon = leaderstats.ChildAdded:connect(function(newStat) + tenFootInterfaceNewStat(newStat) + end) + end + end + + game:WaitForChild("Players") + while not game.Players.LocalPlayer do + wait() + end + + local leaderstats = game.Players.LocalPlayer:FindFirstChild('leaderstats') + if leaderstats then + tenFootInterfaceChanged() + else + game.Players.LocalPlayer.ChildAdded:connect(tenFootInterfaceChanged) + end + + --Top Stat Public API + + local topStatApiTable = {} + + function topStatApiTable:SetTopStatEnabled(value) + topStatEnabled = value + if displayedStat then + updateTenFootStat(displayedStat, "") + end + end + + return topStatApiTable + end + + return this +end + + +-- Public API + +local moduleApiTable = {} + + local TenFootInterfaceModule = CreateModule() + + function moduleApiTable:IsEnabled() + return tenFootInterfaceEnabled + end + + function moduleApiTable:CreateHealthBar() + return TenFootInterfaceModule:CreateHealthBar() + end + + function moduleApiTable:SetupTopStat() + return TenFootInterfaceModule:SetupTopStat() + end + +return moduleApiTable \ No newline at end of file diff --git a/2016/content/scripts/Modules/VR/Panel3D.lua b/2016/content/scripts/Modules/VR/Panel3D.lua new file mode 100644 index 0000000..d928754 --- /dev/null +++ b/2016/content/scripts/Modules/VR/Panel3D.lua @@ -0,0 +1,808 @@ +--Panel3D: 3D GUI panels for VR +--written by 0xBAADF00D +--revised/refactored 5/11/16 + +local UserInputService = game:GetService("UserInputService") +local RunService = game:GetService("RunService") +local GuiService = game:GetService("GuiService") +local CoreGui = game:GetService("CoreGui") +local RobloxGui = CoreGui:WaitForChild("RobloxGui") +local PlayersService = game.Players + + +--Util +local Util = {} +do + function Util.Create(instanceType) + return function(data) + local obj = Instance.new(instanceType) + for k, v in pairs(data) do + if type(k) == 'number' then + v.Parent = obj + else + obj[k] = v + end + end + return obj + end + end + + -- RayPlaneIntersection (shortened) + -- http://www.siggraph.org/education/materials/HyperGraph/raytrace/rayplane_intersection.htm + function Util.RayPlaneIntersection(ray, planeNormal, pointOnPlane) + planeNormal = planeNormal.unit + ray = ray.Unit + + local Vd = planeNormal:Dot(ray.Direction) + if Vd == 0 then -- parallel, no intersection + return nil + end + + local V0 = planeNormal:Dot(pointOnPlane - ray.Origin) + local t = V0 / Vd + if t < 0 then --plane is behind ray origin, and thus there is no intersection + return nil + end + + return ray.Origin + ray.Direction * t + end +end +--End of Util + + +--Panel3D State variables +local renderStepName = "Panel3DRenderStep-" .. game:GetService("HttpService"):GenerateGUID() +local defaultPixelsPerStud = 64 +local pointUpCF = CFrame.Angles(math.rad(-90), math.rad(180), 0) +local zeroVector = Vector3.new(0, 0, 0) +local zeroVector2 = Vector2.new(0, 0) +local turnAroundCF = CFrame.Angles(0, math.rad(180), 0) +local fullyOpaqueAtPixelsFromEdge = 10 +local fullyTransparentAtPixelsFromEdge = 80 +local partThickness = 0.2 + +local cursorHidden = false +local cursorHideTime = 2.5 + +local currentModal = nil +local lastModal = nil +local currentMaxDist = math.huge +local currentClosest = nil +local lastClosest = nil +local currentHeadScale = 1 +local panels = {} +local floorRotation = CFrame.new() +local cursor = Util.Create "ImageLabel" { + Image = "rbxasset://textures/Cursors/Gamepad/Pointer.png", + Size = UDim2.new(0, 8, 0, 8), + BackgroundTransparency = 1, + ZIndex = 10 +} +--End of Panel3D State variables + + +--Panel3D Declaration and enumerations +local Panel3D = {} +Panel3D.Type = { + None = 0, + Floor = 1, + Fixed = 2, + HorizontalFollow = 3, + FixedToHead = 4 +} + +Panel3D.OnPanelClosed = Util.Create 'BindableEvent' { + Name = 'OnPanelClosed' +} + +function Panel3D.GetHeadLookXZ(withTranslation) + local userHeadCF = UserInputService:GetUserCFrame(Enum.UserCFrame.Head) + local headLook = userHeadCF.lookVector + local headYaw = math.atan2(-headLook.Z, headLook.X) + math.rad(90) + local cf = CFrame.Angles(0, headYaw, 0) + + if withTranslation then + cf = cf + userHeadCF.p + end + return cf +end + +function Panel3D.FindContainerOf(element) + for i, v in pairs(panels) do + if v.gui and v.gui:IsAncestorOf(element) then + return v + end + end + return nil +end + +function Panel3D.SetModalPanel(panel) + if currentModal == panel then + return + end + if currentModal then + currentModal:OnModalChanged(false) + end + if panel then + panel:OnModalChanged(true) + end + lastModal = currentModal + currentModal = panel +end +--End of Panel3D Declaration and enumerations + + +--Cursor autohiding methods +local cursorHidden = false +local hasTool = false +local lastMouseActivity = tick() +local lastMouseBehavior = Enum.MouseBehavior.Default + +local function OnCharacterAdded(character) + hasTool = false + for i, v in ipairs(character:GetChildren()) do + if v:IsA("Tool") then + hasTool = true + end + end + character.ChildAdded:connect(function(child) + if child:IsA("Tool") then + hasTool = true + lastMouseActivity = tick() --kick the mouse when a tool is equipped + end + end) + character.ChildRemoved:connect(function(child) + if child:IsA("Tool") then + hasTool = false + end + end) +end +spawn(function() + while not PlayersService.LocalPlayer do wait() end + PlayersService.LocalPlayer.CharacterAdded:connect(OnCharacterAdded) + if PlayersService.LocalPlayer.Character then OnCharacterAdded(PlayersService.LocalPlayer.Character) end +end) +local function autoHideCursor(hide) + if not UserInputService.VREnabled then + cursorHidden = false + return + end + if hide then + --don't hide if there's a tool in the character + local character = PlayersService.LocalPlayer.Character + if character and hasTool then + return + end + cursorHidden = true + UserInputService.OverrideMouseIconBehavior = Enum.OverrideMouseIconBehavior.ForceHide + else + cursorHidden = false + UserInputService.OverrideMouseIconBehavior = Enum.OverrideMouseIconBehavior.None + end +end + +local function isCursorVisible() + --if ForceShow, the cursor is definitely visible at all times + if UserInputService.OverrideMouseIconBehavior == Enum.OverrideMouseIconBehavior.ForceShow then + return true + end + --if ForceHide, the cursor is definitely NOT visible + if UserInputService.OverrideMouseIconBehavior == Enum.OverrideMouseIconBehavior.ForceHide then + return false + end + --Otherwise, we need to check if the developer set MouseIconEnabled=false + if UserInputService.MouseIconEnabled and UserInputService.OverrideMouseIconBehavior == Enum.OverrideMouseIconBehavior.None then + return true + end + return false +end + +--End of cursor autohiding methods + + +--Panel class implementation +local Panel = {} +Panel.mt = { __index = Panel } +function Panel.new(name) + local instance = { + name = name, + + part = nil, + gui = nil, + + width = 1, + height = 1, + + isVisible = false, + isEnabled = false, + panelType = Panel3D.Type.None, + pixelScale = 1, + showCursor = true, + canFade = true, + shouldFindLookAtGuiElement = false, + ignoreModal = false, + + linkedTo = nil, + subpanels = {}, + + transparency = 1, + forceShowUntilLookedAt = false, + isLookedAt = false, + isOffscreen = true, + lookAtPixel = Vector2.new(-1, -1), + lookAtDistance = math.huge, + lookAtGuiElement = nil, + isClosest = true + } + + if panels[name] then + error("A panel by the name of " .. name .. " already exists.") + end + panels[name] = instance + + return setmetatable(instance, Panel.mt) +end + +--Panel accessor methods +function Panel:GetPart() + if not self.part then + self.part = Util.Create "Part" { + Name = self.name, + Parent = nil, + + Transparency = 1, + + CanCollide = false, + Anchored = true, + Archivable = false, + + Size = Vector3.new(1, 1, partThickness) + } + end + return self.part +end + +function Panel:GetGUI() + if not self.gui then + local part = self:GetPart() + self.gui = Util.Create "SurfaceGui" { + Parent = CoreGui, + Adornee = part, + Active = true, + ToolPunchThroughDistance = 1000, + CanvasSize = Vector2.new(0, 0), + Enabled = self.isEnabled, + AlwaysOnTop = true + } + end + return self.gui +end + +function Panel:FindHoveredGuiElement(elements) + local x, y = self.lookAtPixel.X, self.lookAtPixel.Y + for i, v in pairs(elements) do + local minPt = v.AbsolutePosition + local maxPt = v.AbsolutePosition + v.AbsoluteSize + if minPt.X <= x and maxPt.X >= x and + minPt.Y <= y and maxPt.Y >= y then + return v, i + end + end +end +--End of panel accessor methods + + +--Panel update methods +function Panel:SetPartCFrame(cframe) + self:GetPart().CFrame = cframe * CFrame.new(0, 0, -0.5 * partThickness) +end + +function Panel:SetEnabled(enabled) + if self.isEnabled == enabled then + return + end + + self.isEnabled = enabled + if enabled then + self:GetPart().Parent = workspace.CurrentCamera --todo: Perhaps this can change soon. + self:GetGUI().Enabled = true + for i, v in pairs(self.subpanels) do + v:GetPart().Parent = workspace.CurrentCamera + v:GetGUI().Enabled = true + end + else + self:GetPart().Parent = nil + self:GetGUI().Enabled = false + for i, v in pairs(self.subpanels) do + v:GetPart().Parent = nil + v:GetGUI().Enabled = false + end + end + + self:OnEnabled(enabled) +end + +function Panel:EvaluatePositioning(cameraCF, cameraRenderCF, userHeadCF) + if self.panelType == Panel3D.Type.Floor then + --Floor panels simply... go on the floor. + --Panel will be in camera's local space (which is assumed to be horizontal), + --and floorRotation is derived from the user's head rotation (yaw only) + local floorCF = cameraCF * CFrame.new(0, -headHeightFromFloor * currentHeadScale, 0) * floorRotation + self:SetPartCFrame(floorCF * pointUpCF) + elseif self.panelType == Panel3D.Type.Fixed then + --Places the panel in the camera's local space, but doesn't follow the user's head. + --Useful if you know what you're doing. localCF can be updated in PreUpdate for animation. + local cf = self.localCF - self.localCF.p + cf = cf + (self.localCF.p * currentHeadScale) + self:SetPartCFrame(cameraCF * cf) + elseif self.panelType == Panel3D.Type.HorizontalFollow then + local headLook = userHeadCF.lookVector + local headYaw = math.atan2(-headLook.Z, headLook.X) + math.rad(90) + local headForwardCF = CFrame.Angles(0, headYaw, 0) + userHeadCF.p + local localCF = (headForwardCF * self.angleFromForward) * --Rotate about Y (left-right) + self.angleFromHorizon * --Rotate about X (up-down) + (currentHeadScale * self.distance) * --Move into scene + turnAroundCF --Turn around to face character + self:SetPartCFrame(cameraCF * localCF) + elseif self.panelType == Panel3D.Type.FixedToHead then + --Places the panel in the user's head local space. localCF can be updated in PreUpdate for animation. + local cf = self.localCF - self.localCF.p + cf = cf + (self.localCF.p * currentHeadScale) + self:SetPartCFrame(cameraRenderCF * cf) + end +end + +function Panel:EvaluateGaze(cameraCF, cameraRenderCF, userHeadCF, lookRay) + --reset distance data + self.isClosest = false + self.lookAtPixel = zeroVector2 + self.lookAtDistance = math.huge + + --Evaluate the lookRay versus this panel + local planeCF = self:GetPart().CFrame + local planeNormal = planeCF.lookVector + local pointOnPlane = planeCF.p + (planeNormal * partThickness * 0.5) --Move the point out by half the thickness of the part + + local worldIntersectPoint = Util.RayPlaneIntersection(lookRay, planeNormal, pointOnPlane) + if worldIntersectPoint then + self.isOffscreen = false + + --transform worldIntersectPoint to gui space + local gui = self:GetGUI() + local guiWidth, guiHeight = gui.AbsoluteSize.X, gui.AbsoluteSize.Y + local localIntersectPoint = (planeCF:pointToObjectSpace(worldIntersectPoint) / currentHeadScale) * Vector3.new(-1, 1, 1) + Vector3.new(self.width / 2, -self.height / 2, 0) + self.lookAtPixel = Vector2.new((localIntersectPoint.X / self.width) * gui.AbsoluteSize.X, (localIntersectPoint.Y / self.height) * -gui.AbsoluteSize.Y) + + --fire mouse enter/leave events if necessary + local guiX, guiY = self.lookAtPixel.X, self.lookAtPixel.Y + if guiX >= 0 and guiX <= guiWidth and + guiY >= 0 and guiY <= guiHeight then + if not self.isLookedAt then + self.isLookedAt = true + self:OnMouseEnter(guiX, guiY) + if self.forceShowUntilLookedAt then + self.forceShowUntilLookedAt = false + end + end + else + if self.isLookedAt then + self.isLookedAt = false + self:OnMouseLeave(guiX, guiY) + end + end + + --evaluate distance + self.lookAtDistance = (worldIntersectPoint - cameraRenderCF.p).magnitude + if self.isLookedAt and self.lookAtDistance < currentMaxDist and self.showCursor then + currentMaxDist = self.lookAtDistance + currentClosest = self + end + else + self.isOffscreen = true + + --Not looking at the plane at all, so fire off mouseleave if necessary. + if self.isLookedAt then + self.isLookedAt = false + self:OnMouseLeave(self.lookAtPixel.X, self.lookAtPixel.Y) + end + end +end + +function Panel:EvaluateTransparency() + --Early exit if force shown + if self.forceShowUntilLookedAt then + self.transparency = 0 + return + end + --Early exit if we're looking at the panel (no transparency!) + if self.isLookedAt then + self.transparency = 0 + return + end + --Similarly, exit if we can't possibly see the panel. + if self.isOffscreen then + self.transparency = 1 + return + end + --Otherwise, we'll want to calculate the transparency. + self.transparency = self:CalculateTransparency() +end + +function Panel:Update(cameraCF, cameraRenderCF, userHeadCF, lookRay) + if self.forceShowUntilLookedAt and not self.part then + self:GetPart() + self:GetGUI() + end + if not self.part then + return + end + + local isModal = (currentModal == self) + if not isModal and self.linkedTo and self.linkedTo == currentModal then + isModal = true + end + if currentModal and not isModal then + self:SetEnabled(false) + return + end + + self:PreUpdate(cameraCF, cameraRenderCF, userHeadCF, lookRay) + if self.isVisible then + self:EvaluatePositioning(cameraCF, cameraRenderCF, userHeadCF) + self:EvaluateGaze(cameraCF, cameraRenderCF, userHeadCF, lookRay) + + self:EvaluateTransparency(cameraCF, cameraRenderCF) + end +end +--End of Panel update methods + +--Panel virtual methods +function Panel:PreUpdate() --virtual: handle positioning here +end + +function Panel:OnUpdate() --virtual: handle transparency here +end + +function Panel:OnMouseEnter(x, y) --virtual +end + +function Panel:OnMouseLeave(x, y) --virtual +end + +function Panel:OnEnabled(enabled) --virtual +end + +function Panel:OnModalChanged(isModal) --virtual +end + +function Panel:OnVisibilityChanged(visible) --virtual +end + +function Panel:CalculateTransparency() --virtual + if not self.canFade then + return 0 + end + + local guiWidth, guiHeight = self.gui.AbsoluteSize.X, self.gui.AbsoluteSize.Y + local lookX, lookY = self.lookAtPixel.X, self.lookAtPixel.Y + + --Determine the distance from the edge; + --if x is negative it's on the left side, meaning the distance is just absolute value + --if x is positive it's on the right side, meaning the distance is x minus the width + local xEdgeDist = lookX < 0 and -lookX or (lookX - guiWidth) + local yEdgeDist = lookY < 0 and -lookY or (lookY - guiHeight) + if lookX > 0 and lookX < guiWidth then + xEdgeDist = 0 + end + if lookY > 0 and lookY < guiHeight then + yEdgeDist = 0 + end + local edgeDist = math.sqrt(xEdgeDist ^ 2 + yEdgeDist ^ 2) + + --since transparency is 0-1, we know how many pixels will give us 0 and how many will give us 1. + local offset = fullyOpaqueAtPixelsFromEdge + local interval = fullyTransparentAtPixelsFromEdge + --then we just clamp between 0 and 1. + return math.max(0, math.min(1, (edgeDist - offset) / interval)) +end +--End of Panel virtual methods + + +--Panel configuration methods +function Panel:ResizeStuds(width, height, pixelsPerStud) + pixelsPerStud = pixelsPerStud or defaultPixelsPerStud + + self.width = width + self.height = height + + self.pixelScale = pixelsPerStud / defaultPixelsPerStud + + local part = self:GetPart() + part.Size = Vector3.new(self.width * currentHeadScale, self.height * currentHeadScale, partThickness) + + local gui = self:GetGUI() + gui.CanvasSize = Vector2.new(pixelsPerStud * self.width, pixelsPerStud * self.height) +end + +function Panel:ResizePixels(width, height, pixelsPerStud) + pixelsPerStud = pixelsPerStud or defaultPixelsPerStud + + local widthInStuds = width / pixelsPerStud + local heightInStuds = height / pixelsPerStud + self:ResizeStuds(widthInStuds, heightInStuds, pixelsPerStud) +end + +function Panel:OnHeadScaleChanged(newHeadScale) + local pixelsPerStud = self.pixelScale * defaultPixelsPerStud + self:ResizeStuds(self.width, self.height, pixelsPerStud) +end + +function Panel:SetType(panelType, config) + self.panelType = panelType + + --clear out old type-specific members + self.floorPos = nil + + self.localCF = nil + + self.angleFromHorizon = nil + self.angleFromForward = nil + self.distance = nil + + if not config then + config = {} + end + + if panelType == Panel3D.Type.None then + --nothing to do + return + elseif panelType == Panel3D.Type.Floor then + self.floorPos = config.FloorPosition or Vector3.new(0, 0, 0) + elseif panelType == Panel3D.Type.Fixed then + self.localCF = config.CFrame or CFrame.new() + elseif panelType == Panel3D.Type.HorizontalFollow then + self.angleFromHorizon = CFrame.Angles(config.angleFromHorizon or 0, 0, 0) + self.angleFromForward = CFrame.Angles(0, config.angleFromForward or 0, 0) + self.distance = CFrame.new(0, 0, config.distance or 5) + elseif panelType == Panel3D.Type.FixedToHead then + self.localCF = config.CFrame or CFrame.new() + else + error("Invalid Panel type") + end +end + +function Panel:SetVisible(visible, modal) + if visible ~= self.isVisible then + self:OnVisibilityChanged(visible) + if not visible then + Panel3D.OnPanelClosed:Fire(self.name) + end + end + + self.isVisible = visible + self:SetEnabled(visible) + if visible and modal then + Panel3D.SetModalPanel(self) + end + if not visible and currentModal == self then + if modal and not doNotRestore then + --restore last modal panel + Panel3D.SetModalPanel(lastModal) + else + Panel3D.SetModalPanel(nil) + + --if the coder explicitly wanted to hide this modal panel, + --it follows that they don't want it to be restored when the next + --modal panel is hidden. + if lastModal == self then + lastModal = nil + end + end + end + + if not visible and self.forceShowUntilLookedAt then + self.forceShowUntilLookedAt = false + end +end + +function Panel:LinkTo(panelName) + if type(panelName) == "string" then + self.linkedTo = Panel3D.Get(panelName) + else + self.linkedTo = panelName + end +end + +function Panel:ForceShowUntilLookedAt(makeModal) + --ensure the part exists + self:GetPart() + self:GetGUI() + + self:SetVisible(true, makeModal) + self.forceShowUntilLookedAt = true +end + +function Panel:SetCanFade(canFade) + self.canFade = canFade +end + +--Child class, Subpanel +local Subpanel = {} +local Subpanel_mt = {} +function Subpanel.new(guiElement) + local instance = { + guiElement = guiElement + } + return setmetatable(instance, Subpanel_mt) +end + +function Subpanel:GetPart() + warn("Subpanel:GetPart() not yet implemented") + return nil +end + +function Subpanel:GetGUI() + warn("Subpanel:GetGUI() not yet implemented") + return nil +end + +function Panel:AddSubpanel(guiElement) + local subpanel = Subpanel.new(guiElement) + self.subpanels[guiElement] = subpanel +end + +function Panel:RemoveSubpanel(guiElement) + self.subpanels[guiElement] = nil +end +--End of Panel configuration methods +--End of Panel class implementation + + +--Panel3D API +function Panel3D.Get(name) + local panel = panels[name] + if not panels[name] then + panels[name] = Panel.new(name) + panel = panels[name] + end + return panel +end +--End of Panel3D API + + +--Panel3D Setup +local function onRenderStep() + if not UserInputService.VREnabled then + return + end + + + --reset distance info + currentClosest = nil + currentMaxDist = math.huge + + --figure out some useful stuff + local camera = workspace.CurrentCamera + local cameraCF = camera.CFrame + local cameraRenderCF = camera:GetRenderCFrame() + local userHeadCF = UserInputService:GetUserCFrame(Enum.UserCFrame.Head) + local lookRay = Ray.new(cameraRenderCF.p, cameraRenderCF.lookVector) + + --allow all panels to run their own update code + for i, v in pairs(panels) do + v:Update(cameraCF, cameraRenderCF, userHeadCF, lookRay) + end + + --evaluate linked panels + local processed = {} + for i, v in pairs(panels) do + if not processed[v] and v.linkedTo and v.isVisible and v.linkedTo.isVisible then + processed[v] = true + processed[v.linkedTo] = true + + local minTransparency = math.min(v.transparency, v.linkedTo.transparency) + v.transparency = minTransparency + v.linkedTo.transparency = minTransparency + end + end + + --run post update because the distance information hasn't been + --finalized until now. + for i, v in pairs(panels) do + --If the part is fully transparent, we don't want to keep it around in the workspace. + if v.part and v.gui then + --check if this panel is the current modal panel + local isModal = (currentModal == v) + --but also check if this panel is linked to the current modal panel + if not isModal and v.linkedTo and v.linkedTo == currentModal then + isModal = true + end + + local show = v.isVisible + if not isModal and currentModal then + show = false + end + if v.transparency >= 1 then + show = false + end + + if v.forceShowUntilLookedAt then + show = true + end + if not v.canFade and v.isVisible then + show = true + end + + v:SetEnabled(show) + end + + v:OnUpdate() + end + + --place the cursor on the closest panel (for now) + if not currentClosest and lastClosest then + UserInputService.MouseBehavior = lastMouseBehavior + elseif currentClosest and not lastClosest then + lastMouseBehavior = UserInputService.MouseBehavior + end + + if currentClosest then + UserInputService.MouseBehavior = Enum.MouseBehavior.LockCenter + UserInputService.OverrideMouseIconBehavior = Enum.OverrideMouseIconBehavior.ForceHide + cursor.Parent = currentClosest:GetGUI() + + local x, y = currentClosest.lookAtPixel.X, currentClosest.lookAtPixel.Y + cursor.Size = UDim2.new(0, 8 * currentClosest.pixelScale, 0, 8 * currentClosest.pixelScale) + cursor.Position = UDim2.new(0, x - cursor.AbsoluteSize.x * 0.5, 0, y - cursor.AbsoluteSize.y * 0.5) + else + cursor.Parent = nil + end + lastClosest = currentClosest +end +RunService:BindToRenderStep(renderStepName, Enum.RenderPriority.Last.Value, onRenderStep) + +--Implement cursor autohide functionality +UserInputService.InputChanged:connect(function(inputObj, processed) + if inputObj.UserInputType == Enum.UserInputType.MouseMovement then + lastMouseActivity = tick() + autoHideCursor(false) + end +end) +local function onHeartbeat() + if isCursorVisible() then + cursorHidden = false + end + if lastMouseActivity + cursorHideTime < tick() and not GuiService.MenuIsOpen and not cursorHidden then + autoHideCursor(true) + end +end +RunService.Heartbeat:connect(onHeartbeat) + +--Handle camera changes +local cameraChangedConnection = nil +local function onCameraChanged(prop) + if prop == "HeadScale" then + pcall(function() + currentHeadScale = workspace.CurrentCamera.HeadScale + end) + for i, v in pairs(panels) do + v:OnHeadScaleChanged(currentHeadScale) + end + end +end + +local function onWorkspaceChanged(prop) + if prop == "CurrentCamera" then + onCameraChanged("HeadScale") + if cameraChangedConnection then + cameraChangedConnection:disconnect() + end + cameraChangedConnection = workspace.CurrentCamera.Changed:connect(onCameraChanged) + end +end +if workspace.CurrentCamera then + onWorkspaceChanged("CurrentCamera") +end +workspace.Changed:connect(onWorkspaceChanged) + +return Panel3D \ No newline at end of file diff --git a/2016/content/scripts/Modules/VR/VirtualKeyboard.lua b/2016/content/scripts/Modules/VR/VirtualKeyboard.lua new file mode 100644 index 0000000..b632a77 --- /dev/null +++ b/2016/content/scripts/Modules/VR/VirtualKeyboard.lua @@ -0,0 +1,1151 @@ +-- VirtualKeyboard.lua -- +-- Written by Kip Turner, copyright ROBLOX 2016 -- + + +local CoreGui = game:GetService('CoreGui') +local RunService = game:GetService('RunService') +local UserInputService = game:GetService('UserInputService') +local GuiService = game:GetService('GuiService') +local HttpService = game:GetService('HttpService') +local ContextActionService = game:GetService('ContextActionService') +local PlayersService = game:GetService('Players') +local TextService = game:GetService('TextService') + +local RobloxGui = CoreGui:WaitForChild("RobloxGui") +local Util = require(RobloxGui.Modules.Settings.Utility) + +local vrKeyboardSuccess, vrKeyboardFlagValue = pcall(function() return settings():GetFFlag("UseVRKeyboardInLua") end) +local useVRKeyboard = (vrKeyboardSuccess and vrKeyboardFlagValue == true) + +local BACKGROUND_OPACITY = 0.3 +local NORMAL_KEY_COLOR = Color3.new(49/255,49/255,49/255) +local HOVER_KEY_COLOR = Color3.new(49/255,49/255,49/255) +local PRESSED_KEY_COLOR = Color3.new(0,162/255,1) +local SET_KEY_COLOR = Color3.new(0,162/255,1) + +local KEY_TEXT_COLOR = Color3.new(1,1,1) +---------------------------------------- KEYBOARD LAYOUT -------------------------------------- +local MINIMAL_KEYBOARD_LAYOUT = HttpService:JSONDecode([==[ +[ + [ + { + "a": 7, + "w": 0.8 + }, + "*", + "Q", + "W", + "E", + "R", + "T", + "Y", + "U", + "I", + "O", + "P", + { + "w": 1.8 + }, + "Delete" + ], + [ + { + "w": 1.6 + }, + "Caps", + "A", + "S", + "D", + "F", + "G", + "H", + "J", + "K", + "L", + "?", + { + "h": 2, + "w2": 2.4, + "h2": 1, + "x2": -1.4, + "y2": 1 + }, + "Enter" + ], + [ + { + "w": 2.2 + }, + "Shift", + "Z", + "X", + "C", + "V", + "B", + "N", + "M", + "." + ], + [ + { + "w": 2.2 + }, + "123/sym", + { + "w": 8 + }, + "", + { + "w": 2.4 + }, + "" + ] +] +]==]) + +local MINIMAL_KEYBOARD_LAYOUT_SYMBOLS = HttpService:JSONDecode([==[ +[ + [ + { + "a": 7, + "w": 0.8 + }, + "*", + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9", + "0", + { + "w": 1.8 + }, + "Delete" + ], + [ + { + "w": 1.6 + }, + "!", + "@", + "#", + "$", + "%", + "^", + "&", + "(", + ")", + "=", + "?", + { + "h": 2, + "w2": 2.4, + "h2": 1, + "x2": -1.4, + "y2": 1 + }, + "Enter" + ], + [ + { + "w": 1.2 + }, + "/", + "-", + "+", + "_", + ":", + ";", + "'", + "\"", + ",", + "." + ], + [ + { + "w": 2.2 + }, + "abc", + { + "w": 8 + }, + "", + { + "w": 2.4 + }, + "" + ] +] +]==]) + + +---------------------------------------- END KEYBOARD LAYOUT -------------------------------------- + + +local function tokenizeString(str, tokenChar) + local words = {} + for word in string.gmatch(str, '([^' .. tokenChar .. ']+)') do + table.insert(words, word) + end + return words +end + +local function ConvertFontSizeEnumToInt(fontSizeEnum) + local result = string.match(fontSizeEnum.Name, '%d+') + return (result and tostring(result)) or 12 +end + + +-- RayPlaneIntersection + +-- http://www.siggraph.org/education/materials/HyperGraph/raytrace/rayplane_intersection.htm +local function RayPlaneIntersection(ray, planeNormal, pointOnPlane) + planeNormal = planeNormal.unit + ray = ray.Unit + -- compute Pn (dot) Rd = Vd and check if Vd == 0 then we know ray is parallel to plane + local Vd = planeNormal:Dot(ray.Direction) + + -- could fuzzy equals this a little bit to account for imprecision or very close angles to zero + if Vd == 0 then -- parallel, no intersection + return nil + end + + local V0 = planeNormal:Dot(pointOnPlane - ray.Origin) + local t = V0 / Vd + + if t < 0 then --plane is behind ray origin, and thus there is no intersection + return nil + end + + return ray.Origin + ray.Direction * t +end + +function Clamp(low, high, input) + return math.max(low, math.min(high, input)) +end + +-- No rotation as of yet +local function PointInGuiObject(object, x, y) + local minPt = object.AbsolutePosition + local maxPt = object.AbsolutePosition + object.AbsoluteSize + if minPt.X <= x and maxPt.X >= x and minPt.Y <= y and maxPt.Y >= y then + return true + end + return false +end + + +local function ExtendedInstance(instance) + local this = {} + do + local mt = + { + __index = function (t, k) + return instance[k] + end; + + __newindex = function (t, k, v) + instance[k] = v + end; + } + setmetatable(this, mt) + end + return this +end + +local function IsVoiceToTextEnabled() + return false +end + +local function CreateVRButton(instance) + local newButton = ExtendedInstance(instance) + + rawset(newButton, "OnEnter", function(self) + end) + rawset(newButton, "OnLeave", function(self) + end) + rawset(newButton, "OnDown", function(self) + end) + rawset(newButton, "OnUp", function(self) + end) + rawset(newButton, "ContainsPoint", function(self, x, y) + return PointInGuiObject(instance, x, y) + end) + rawset(newButton, "Update", function(self) + end) + + return newButton +end + +local selectionRing = Util:Create'ImageLabel' +{ + Name = 'SelectionRing'; + Size = UDim2.new(1, -6, 1, -6); + Position = UDim2.new(0, 4, 0, 3); + Image = 'rbxasset://textures/ui/menu/buttonHover.png'; + ScaleType = Enum.ScaleType.Slice; + SliceCenter = Rect.new(94/2, 94/2, 94/2, 94/2); + BackgroundTransparency = 1; +} + +local KEY_ICONS = +{ + [""] = {Asset = "rbxasset://textures/ui/Keyboard/mic_icon.png", AspectRatio = 0.615}; +} + +local function CreateKeyboardKey(keyboard, layoutData, keyData) + local isSpecialShapeKey = layoutData['width2'] and layoutData['height2'] and layoutData['x2'] and layoutData['y2'] + + local newKeyElement = Util:Create'ImageButton' + { + Name = keyData[1]; + Position = UDim2.new(layoutData['x'], 0, layoutData['y'], 0); + Size = UDim2.new(layoutData['width'], 0, layoutData['height'], 0); + BorderSizePixel = 0; + Image = ""; + BackgroundTransparency = 1; + ZIndex = 1; + } + local keyText = Util:Create'TextLabel' + { + Name = "KeyText"; + Text = keyData[#keyData]; + Position = UDim2.new(0, -10, 0, -10); + Size = UDim2.new(1, 0, 1, 0); + Font = Enum.Font.SourceSansBold; + FontSize = Enum.FontSize.Size96; + TextColor3 = KEY_TEXT_COLOR; + BackgroundTransparency = 1; + Selectable = true; + ZIndex = 2; + Parent = newKeyElement; + } + local backgroundImage = Util:Create'Frame' + { + Name = 'KeyBackground'; + Size = UDim2.new(1,-10,1,-10); + Position = UDim2.new(0,-5,0,-5); + BackgroundColor3 = NORMAL_KEY_COLOR; + BackgroundTransparency = BACKGROUND_OPACITY; + BorderSizePixel = 0; + Parent = newKeyElement; + } + + local selectionObject = Util:Create'ImageLabel' + { + Name = 'SelectionObject'; + Size = UDim2.new(1,0,1,0); + BackgroundTransparency = 1; + Image = "rbxasset://textures/ui/Keyboard/key_selection_9slice.png"; + ImageTransparency = 0; + ScaleType = Enum.ScaleType.Slice; + SliceCenter = Rect.new(12,12,52,52); + BorderSizePixel = 0; + } + + newKeyElement.SelectionImageObject = Util:Create'ImageLabel' + { + Visible = false; + } + + -- Special silly enter key nonsense + local secondBackgroundImage = nil + local specialSelectionObject, specialSelectionObject2, specialSelectionObject3 = nil, nil, nil + if isSpecialShapeKey then + secondBackgroundImage = Util:Create'ImageButton' + { + Name = 'KeyBackground'; + Position = UDim2.new(layoutData['x2'] / layoutData['width'], -5, layoutData['y2'] / layoutData['height'], -5); + Size = UDim2.new(layoutData['width2'] / layoutData['width'], 0, layoutData['height2'] / layoutData['height'], -10); + BackgroundColor3 = NORMAL_KEY_COLOR; + BackgroundTransparency = BACKGROUND_OPACITY; + BorderSizePixel = 0; + AutoButtonColor = false; + Parent = newKeyElement; + } + if layoutData['x2'] <= 0 then + keyText.Size = secondBackgroundImage.Size - UDim2.new(0,10,0,0) + keyText.Position = secondBackgroundImage.Position + secondBackgroundImage.Size = secondBackgroundImage.Size - UDim2.new(1,0,0,0) + end + + do + specialSelectionObject = Util:Create'Frame' + { + Name = 'SpecialSelectionObject'; + Size = UDim2.new(1,0,0.5,0); + Position = UDim2.new(0,0,0.5,0); + BackgroundTransparency = 1; + ClipsDescendants = true; + Util:Create'ImageLabel' + { + Name = 'Borders'; + Position = UDim2.new(-1,0,-1,0); + Size = UDim2.new(2,0,2,0); + BackgroundTransparency = 1; + Image = "rbxasset://textures/ui/Keyboard/key_selection_9slice.png"; + ImageTransparency = 0; + ScaleType = Enum.ScaleType.Slice; + SliceCenter = Rect.new(12,12,52,52); + }; + } + specialSelectionObject2 = specialSelectionObject:Clone() + specialSelectionObject2.Size = UDim2.new(1,0,0.5,5) + specialSelectionObject2.Position = UDim2.new(0,0,0,0) + specialSelectionObject2.Borders.Size = UDim2.new(1,0,1,30) + specialSelectionObject2.Borders.Position = UDim2.new(0,0,0,0) + + specialSelectionObject3 = specialSelectionObject:Clone() + specialSelectionObject3.Size = UDim2.new(1,5,1,0) + specialSelectionObject3.Position = UDim2.new(0,0,0,0) + specialSelectionObject3.Borders.Size = UDim2.new(1,30,1,0) + specialSelectionObject3.Borders.Position = UDim2.new(0,0,0,0) + end + -- End of nonsense + end + + local newKey = CreateVRButton(newKeyElement) + + local hovering = false + local pressed = false + local isAlpha = #keyData == 1 and type(keyData[1]) == 'string' and #keyData[1] == 1 and + string.byte(keyData[1]) >= string.byte("A") and string.byte(keyData[1]) <= string.byte("z") + + local icon = nil + if keyData[1] and KEY_ICONS[keyData[1]] then + keyText.Visible = false + icon = Util:Create'ImageLabel' + { + Name = 'KeyIcon'; + Size = UDim2.new(KEY_ICONS[keyData[1]].AspectRatio, -20, 1, -20); + SizeConstraint = Enum.SizeConstraint.RelativeYY; + BackgroundTransparency = 1; + Image = KEY_ICONS[keyData[1]].Asset; + Parent = backgroundImage; + } + + local function onChanged(prop) + if prop == 'AbsoluteSize' then + icon.Position = UDim2.new(0.5,-icon.AbsoluteSize.X/2,0.5,-icon.AbsoluteSize.Y/2); + end + end + icon.Changed:connect(onChanged) + onChanged('AbsoluteSize') + end + + local function isEnabled() + if newKey:GetCurrentKeyValue() == "" then + return IsVoiceToTextEnabled() + end + return true + end + + local function onClicked() + local keyValue = nil + local currentKeySetting = newKey:GetCurrentKeyValue() + + if currentKeySetting == 'Shift' then + keyboard:SetShift(not keyboard:GetShift()) + elseif currentKeySetting == 'Caps' then + keyboard:SetCaps(not keyboard:GetCaps()) + elseif currentKeySetting == 'Enter' then + keyboard:SubmitText(true, true) + elseif currentKeySetting == 'Delete' then + keyboard:BackspaceAtCursor() + elseif currentKeySetting == "123/sym" then + keyboard:SetCurrentKeyset(2) + elseif currentKeySetting == "abc" then + keyboard:SetCurrentKeyset(1) + elseif currentKeySetting == "" then + keyboard:SetVoiceMode(true) + elseif currentKeySetting == 'Tab' then + keyValue = '\t' + else + keyValue = currentKeySetting + end + + if keyValue ~= nil then + keyboard:SubmitCharacter(keyValue, isAlpha) + end + end + + local function setKeyColor(newColor, hovering) + backgroundImage.BackgroundColor3 = newColor + if secondBackgroundImage then + secondBackgroundImage.BackgroundColor3 = newColor + end + if isSpecialShapeKey then + specialSelectionObject.Parent = hovering and backgroundImage or nil + specialSelectionObject2.Parent = hovering and backgroundImage or nil + specialSelectionObject3.Parent = hovering and secondBackgroundImage or nil + else + selectionObject.Parent = hovering and backgroundImage or nil + end + end + + local function update() + local currentKey = newKey:GetCurrentKeyValue() + + if pressed then + setKeyColor(PRESSED_KEY_COLOR, false) + elseif hovering then + setKeyColor(HOVER_KEY_COLOR, true) + elseif currentKey == 'Caps' and keyboard:GetCaps() then + setKeyColor(SET_KEY_COLOR, false) + elseif currentKey == 'Shift' and keyboard:GetShift() then + setKeyColor(SET_KEY_COLOR, false) + elseif currentKey == 'abc' then + setKeyColor(SET_KEY_COLOR, false) + else + setKeyColor(NORMAL_KEY_COLOR, false) + end + + if icon then + icon.ImageTransparency = isEnabled() and 0 or 0.5 + end + + keyText.Text = newKey:GetCurrentKeyValue() + end + + local hoveringGuiElements = {} + + rawset(newKey, "OnEnter", function(self) + hovering = true + update() + end) + rawset(newKey, "OnLeave", function(self) + if not next(hoveringGuiElements) then + hovering = false + pressed = false + update() + end + end) + rawset(newKey, "OnDown", function(self) + pressed = true + update() + end) + rawset(newKey, "OnUp", function(self) + pressed = false + update() + end) + rawset(newKey, "GetCurrentKeyValue", function(self) + local shiftEnabled = keyboard:GetShift() + local capsEnabled = keyboard:GetCaps() + + if isAlpha then + if capsEnabled and shiftEnabled then + return string.lower(keyData[#keyData]) + elseif capsEnabled or shiftEnabled then + return keyData[1] + else + return string.lower(keyData[#keyData]) + end + end + + if shiftEnabled then + return keyData[1] + end + + return keyData[#keyData] + end) + rawset(newKey, "ContainsPoint", function(self, x, y) + return PointInGuiObject(backgroundImage, x, y) or + (secondBackgroundImage and PointInGuiObject(secondBackgroundImage, x, y)) + end) + rawset(newKey, "Update", function(self) + update() + end) + rawset(newKey, "GetInstance", function(self) + return newKeyElement + end) + + newKeyElement.MouseButton1Down:connect(function() newKey:OnDown() end) + newKeyElement.MouseButton1Up:connect(function() newKey:OnUp() end) + newKeyElement.SelectionGained:connect(function() hoveringGuiElements[newKeyElement] = true newKey:OnEnter() end) + newKeyElement.SelectionLost:connect(function() hoveringGuiElements[newKeyElement] = nil newKey:OnLeave() end) + newKeyElement.MouseButton1Click:connect(function() onClicked() end) + if secondBackgroundImage then + secondBackgroundImage.MouseButton1Click:connect(onClicked) + secondBackgroundImage.MouseButton1Down:connect(function() newKey:OnDown() end) + secondBackgroundImage.MouseButton1Up:connect(function() newKey:OnUp() end) + secondBackgroundImage.SelectionGained:connect(function() + hoveringGuiElements[secondBackgroundImage] = true + newKey:OnEnter() + end) + secondBackgroundImage.SelectionLost:connect(function() + hoveringGuiElements[secondBackgroundImage] = nil + newKey:OnLeave() + end) + end + + update() + + return newKey +end + + + +local function ConstructKeyboardUI(keyboardLayoutDefinitions) + local Panel3D = require(RobloxGui.Modules.VR.Panel3D) + local panel = Panel3D.Get("Keyboard") + panel:SetVisible(false) + + -- DEBUG setting + -- panel:GetGUI().Parent = workspace + + + local buttons = {} + + local keyboardContainer = Util:Create'Frame' + { + Name = 'VirtualKeyboard'; + Size = UDim2.new(1, 0, 1, 0); + Position = UDim2.new(0, 0, 0, 0); + BackgroundTransparency = 1; + Active = true; + Visible = false; + }; + + local textEntryBackground = Util:Create'ImageLabel' + { + Name = 'TextEntryBackground'; + Size = UDim2.new(0.5,0,0.125,0); + Position = UDim2.new(0.25,0,0,0); + Image = ""; + BackgroundTransparency = 0.5; + BackgroundColor3 = Color3.new(31/255,31/255,31/255); + BorderSizePixel = 0; + ClipsDescendants = true; + Parent = keyboardContainer; + } + local textfieldBackground = Util:Create'Frame' + { + Name = 'TextfieldBackground'; + Position = UDim2.new(0,2,0,2); + Size = UDim2.new(1, -4, 1, -4); + BackgroundTransparency = 0; + BackgroundColor3 = Color3.new(209/255,216/255,221/255); + BorderSizePixel = 0; + Visible = true; + Parent = textEntryBackground; + }; + local textEntryField = Util:Create'TextButton' + { + Name = "TextEntryField"; + Text = ""; + Position = UDim2.new(0,4,0,4); + Size = UDim2.new(1, -8, 1, -8); + Font = Enum.Font.SourceSans; + FontSize = Enum.FontSize.Size60; + TextXAlignment = Enum.TextXAlignment.Left; + BackgroundTransparency = 1; + BorderSizePixel = 0; + Parent = textfieldBackground; + } + local textfieldCursor = Util:Create'Frame' + { + Name = 'TextfieldCursor'; + Size = UDim2.new(0, 5, 0.9, 0); + Position = UDim2.new(0, 0, 0.05, 0); + BackgroundTransparency = 0; + BackgroundColor3 = SET_KEY_COLOR; + BorderSizePixel = 0; + Visible = true; + ZIndex = 2; + Parent = textEntryField; + }; + + local closeButtonElement = Util:Create'ImageButton' + { + Name = 'CloseButton'; + Size = UDim2.new(0.075,-10,0.198,-10); + Position = UDim2.new(0,-5,0,-35); + Image = "rbxasset://textures/ui/Keyboard/close_button_background.png"; + BackgroundTransparency = 1; + AutoButtonColor = false; + Parent = keyboardContainer; + } + do + closeButtonElement.SelectionImageObject = Util:Create'ImageLabel' + { + Name = 'Selection'; + Size = UDim2.new(0.9,0,0.9,0); + Position = UDim2.new(0.05,0,0.05,0); + Image = "rbxasset://textures/ui/Keyboard/close_button_selection.png"; + BackgroundTransparency = 1; + } + Util:Create'ImageLabel' + { + Name = 'Icon'; + Size = UDim2.new(0.5,0,0.5,0); + Position = UDim2.new(0.25,0,0.25,0); + Image = "rbxasset://textures/ui/Keyboard/close_button_icon.png"; + BackgroundTransparency = 1; + Parent = closeButtonElement; + } + end + local closeButton = CreateVRButton(closeButtonElement) + table.insert(buttons, closeButton) + + local voiceRecognitionContainer = Util:Create'Frame' + { + Name = 'VoiceRecognitionContainer'; + Size = UDim2.new(1, 0, 0.85, 0); + Position = UDim2.new(0, 0, 0.15, 0); + BackgroundTransparency = 1; + Active = true; + Visible = false; + Parent = keyboardContainer; + }; + do + local voiceRecognitionBackground1 = Util:Create'Frame' + { + Name = 'voiceRecognitionBackground1'; + Size = UDim2.new(1, 0, 0.75, 0); + Position = UDim2.new(0, 0, 0, 0); + BackgroundColor3 = Color3.new(0,0,0); + BackgroundTransparency = 0.5; + BorderSizePixel = 0; + Active = true; + Parent = voiceRecognitionContainer; + }; + local voiceRecognitionBackground2 = voiceRecognitionBackground1:Clone() + voiceRecognitionBackground2.Size = UDim2.new(0.75, 0, 0.25, 0) + voiceRecognitionBackground2.Position = UDim2.new(0, 0, 0.75, 0) + voiceRecognitionBackground2.Parent = voiceRecognitionContainer + end + + local voiceDoneButton = CreateVRButton(Util:Create'ImageButton' + { + Name = 'DoneButton'; + Size = UDim2.new(0.25,-5,0.25,-5); + Position = UDim2.new(0.75,5,0.75,5); + Image = ""; + BackgroundTransparency = 0; + AutoButtonColor = false; + BorderSizePixel = 0; + Parent = voiceRecognitionContainer; + }) + table.insert(buttons, voiceDoneButton) + + local newKeyboard = ExtendedInstance(keyboardContainer) + + local keyboardOptions = nil + local keysets = {} + + local capsLockEnabled = false + local shiftEnabled = false + + local textfieldCursorPosition = 0 + + local closedEvent = Instance.new('BindableEvent') + local opened = false + + local function SetTextFieldCursorPosition(newPosition) + textfieldCursorPosition = Clamp(0, #textEntryField.Text, newPosition) + if not textEntryField.TextFits then + textfieldCursorPosition = #textEntryField.Text + end + + local textSize = TextService:GetTextSize( + string.sub(textEntryField.Text, 1, textfieldCursorPosition), + ConvertFontSizeEnumToInt(textEntryField.FontSize), + textEntryField.Font, + textEntryField.AbsoluteSize) + textfieldCursor.Position = UDim2.new(0, textSize.x, textfieldCursor.Position.Y.Scale, textfieldCursor.Position.Y.Offset) + end + + local function UpdateTextEntryFieldText(newText) + textEntryField.Text = newText + SetTextFieldCursorPosition(textfieldCursorPosition) + end + + local buffer = "" + local function getBufferText() + if keyboardOptions and keyboardOptions.TextBox then + return keyboardOptions.TextBox.Text + end + return buffer + end + local function setBufferText(newBufferText) + if keyboardOptions and keyboardOptions.TextBox then + keyboardOptions.TextBox.Text = newBufferText + elseif buffer ~= newBufferText then + buffer = newBufferText + UpdateTextEntryFieldText(buffer) + end + end + + local function calculateTextCursorPosition(x, y) + x = x - textEntryField.AbsolutePosition.x + y = y - textEntryField.AbsolutePosition.y + + for i = 1, #textEntryField.Text do + local textSize = TextService:GetTextSize( + string.sub(textEntryField.Text, 1, i), + ConvertFontSizeEnumToInt(textEntryField.FontSize), + textEntryField.Font, + textEntryField.AbsoluteSize) + if textSize.x > x then + return i - 1 + end + end + + return #textEntryField.Text + end + + local currentKeyset = nil + + rawset(newKeyboard, "ClosedEvent", closedEvent.Event) + + rawset(newKeyboard, "GetCurrentKeyset", function(self) + return keysets[currentKeyset] + end) + + rawset(newKeyboard, "SetCurrentKeyset", function(self, newKeyset) + if newKeyset ~= currentKeyset and keysets[newKeyset] ~= nil then + if keysets[currentKeyset] and keysets[currentKeyset].container then + keysets[currentKeyset].container.Visible = false + end + + currentKeyset = newKeyset + + if keysets[currentKeyset] and keysets[currentKeyset].container then + keysets[currentKeyset].container.Visible = true + end + end + end) + + rawset(newKeyboard, "SetVoiceMode", function(self, inVoiceMode) + inVoiceMode = inVoiceMode and IsVoiceToTextEnabled() + + local currentKeysetObject = self:GetCurrentKeyset() + if currentKeysetObject and currentKeysetObject.container then + currentKeysetObject.container.Visible = not inVoiceMode + end + + voiceRecognitionContainer.Visible = inVoiceMode + end) + + rawset(newKeyboard, "GetCaps", function(self) + return capsLockEnabled + end) + + rawset(newKeyboard, "SetCaps", function(self, newCaps) + capsLockEnabled = newCaps + for _, key in pairs(self:GetCurrentKeyset().keys) do + key:Update() + end + end) + + rawset(newKeyboard, "GetShift", function(self) + return shiftEnabled + end) + + rawset(newKeyboard, "SetShift", function(self, newShift) + shiftEnabled = newShift + for _, key in pairs(self:GetCurrentKeyset().keys) do + key:Update() + end + end) + + local textChangedConn = nil + local panelClosedConn = nil + rawset(newKeyboard, "Open", function(self, options) + if opened then return end + opened = true + + keyboardOptions = options + + self:SetCurrentKeyset(1) + self:SetVoiceMode(false) + keyboardContainer.Visible = true + + panel:ResizeStuds(5.9, 2.25, 320) + + local localCF = CFrame.new() + + if textChangedConn then textChangedConn:disconnect() end + textChangedConn = nil + if options.TextBox then + textChangedConn = options.TextBox.Changed:connect(function(prop) + if prop == 'Text' then + UpdateTextEntryFieldText(options.TextBox.Text) + end + end) + options.TextBox.FocusLost:connect(function(submitted) + self:Close(submitted) + end) + if options.TextBox.ClearTextOnFocus then + setBufferText("") + else + UpdateTextEntryFieldText(options.TextBox.Text) + end + + local textboxPanel = Panel3D.FindContainerOf(options.TextBox) + if textboxPanel then + panelClosedConn = Panel3D.OnPanelClosed.Event:connect(function(closedPanelName) + if closedPanelName == textboxPanel.name then + self:Close(false) + end + end) + + --Attach to it if it's in the same space + if textboxPanel.panelType == Panel3D.Type.Fixed then + local panelCF = textboxPanel.localCF + localCF = panelCF * CFrame.new(0, (-textboxPanel.height / 2) - 0.5, 0) * + CFrame.Angles(math.rad(30), 0, 0) * + CFrame.new(0, (-panel.height / 2) - 0.5, 0) + else + --Otherwise, best-guess where it should go based on the user's head. + local headForwardCF = Panel3D.GetHeadLookXZ(true) + localCF = headForwardCF * CFrame.Angles(math.rad(22.5), 0, 0) * CFrame.new(0, -1, 5) + end + end + else + setBufferText("") + end + + ContextActionService:BindCoreAction("VirtualKeyboardControllerInput", + function(actionName, inputState, inputObject) + if inputState == Enum.UserInputState.End then + if inputObject.KeyCode == Enum.KeyCode.ButtonL1 then + SetTextFieldCursorPosition(textfieldCursorPosition - 1) + elseif inputObject.KeyCode == Enum.KeyCode.ButtonR1 then + SetTextFieldCursorPosition(textfieldCursorPosition + 1) + elseif inputObject.KeyCode == Enum.KeyCode.ButtonX then + self:BackspaceAtCursor() + elseif inputObject.KeyCode == Enum.KeyCode.ButtonY then + self:SubmitCharacter(" ", false) + elseif inputObject.KeyCode == Enum.KeyCode.ButtonL2 then + if currentKeyset then + -- Go to the next keyset + self:SetCurrentKeyset((currentKeyset % #keysets) + 1) + end + elseif inputObject.KeyCode == Enum.KeyCode.ButtonL3 then + self:SetCaps(not self:GetCaps()) + end + end + end, + false, + Enum.KeyCode.ButtonL1, Enum.KeyCode.ButtonR1, Enum.KeyCode.ButtonL2, Enum.KeyCode.ButtonL3, Enum.KeyCode.ButtonX, Enum.KeyCode.ButtonY) + + self.Parent = panel:GetGUI() + + panel:SetType(Panel3D.Type.Fixed, { CFrame = localCF }) + panel:SetCanFade(false) + panel:SetVisible(true, true) + panel:ForceShowUntilLookedAt() + + function panel:OnUpdate() + end + end) + + rawset(newKeyboard, "Close", function(self, submit) + submit = (submit == true) + + if not opened then return end + opened = false + + + if textChangedConn then textChangedConn:disconnect() end + textChangedConn = nil + if panelClosedConn then panelClosedConn:disconnect() end + panelClosedConn = nil + + ContextActionService:UnbindCoreAction("VirtualKeyboardControllerInput") + -- Clean-up + panel:OnMouseLeave() + panel:SetVisible(false, true) + keyboardContainer.Visible = false + + self:SubmitText(submit, false) + end) + + rawset(newKeyboard, "SubmitText", function(self, submit, keepKeyboardOpen) + local keyboardTextbox = keyboardOptions and keyboardOptions.TextBox + if keyboardTextbox then + if submit then + keyboardTextbox.Text = getBufferText() + end + keyboardTextbox:ReleaseFocus(submit) + if keepKeyboardOpen then + keyboardTextbox:CaptureFocus() + end + end + end) + + rawset(newKeyboard, "GetCurrentOptions", function(self) + return keyboardOptions + end) + + rawset(newKeyboard, "BackspaceAtCursor", function(self) + if textfieldCursorPosition >= 1 then + local bufferText = getBufferText() + local newBufferText = string.sub(bufferText, 1, textfieldCursorPosition - 1) .. string.sub(bufferText, textfieldCursorPosition + 1, #bufferText) + local newCursorPosition = textfieldCursorPosition - 1 + setBufferText(newBufferText) + SetTextFieldCursorPosition(newCursorPosition) + end + end) + + rawset(newKeyboard, "SubmitCharacter", function(self, character, isAnAlphaKey) + local bufferText = getBufferText() + local newBufferText = string.sub(bufferText, 1, textfieldCursorPosition) .. character .. string.sub(bufferText, textfieldCursorPosition + 1, #bufferText) + setBufferText(newBufferText) + SetTextFieldCursorPosition(textfieldCursorPosition + #character) + + if isAnAlphaKey and self:GetShift() then + self:SetShift(false) + end + end) + + do -- Parse input definition + for _, keyboardKeyset in pairs(keyboardLayoutDefinitions) do + local keys = {} + local keyboardSizeConstrainer = Util:Create'Frame' + { + Name = 'KeyboardSizeConstrainer'; + Size = UDim2.new(1, 0, 1, -20); + Position = UDim2.new(0, 0, 0, 20); + BackgroundTransparency = 1; + Parent = keyboardContainer; + }; + + local maxWidth = 0 + local maxHeight = 0 + local y = 0 + for rowNum, rowData in pairs(keyboardKeyset) do + local x = 0 + local width = 1 + local height = 1 + local width2, height2, x2, y2; + for columnNum, columnData in pairs(rowData) do + if type(columnData) == 'table' then + if columnData['w'] then width = columnData['w'] end + if columnData['h'] then height = columnData['h'] end + if columnData['x'] then x = x + columnData['x'] end + if columnData['y'] then y = y + columnData['y'] end + if columnData['x2'] then x2 = columnData['x2'] end + if columnData['y2'] then y2 = columnData['y2'] end + if columnData['w2'] then width2 = columnData['w2'] end + if columnData['h2'] then height2 = columnData['h2'] end + elseif type(columnData) == 'string' then + if columnData == "" then + columnData = " " + end + -- put key + local key = CreateKeyboardKey( + newKeyboard, + {x = x, y = y, width = width, height = height, x2 = x2, y2 = y2, width2 = width2, height2 = height2}, + tokenizeString(columnData, '\n')) + table.insert(keys, key) + + x = x + width + maxWidth = math.max(maxWidth, x) + maxHeight = math.max(maxHeight, y + height) + -- reset for the next key + width = 1 + height = 1 + width2, height2, x2, y2 = nil, nil, nil, nil + end + end + y = y + 1 + end + + -- Fix the positions and sizes to fit in our KeyboardContainer + for _, element in pairs(keys) do + element.Position = UDim2.new(element.Position.X.Scale / maxWidth, 0, element.Position.Y.Scale / maxHeight, 0) + element.Size = UDim2.new(element.Size.X.Scale / maxWidth, 0, element.Size.Y.Scale / maxHeight, 0) + element.Parent = keyboardSizeConstrainer + end + + keyboardSizeConstrainer.SizeConstraint = Enum.SizeConstraint.RelativeXX + keyboardSizeConstrainer.Size = UDim2.new(1, 0, -maxHeight / maxWidth, 0) + keyboardSizeConstrainer.Position = UDim2.new(0, 0, 1, 0) + keyboardSizeConstrainer.Visible = false + + table.insert(keysets, {keys = keys, container = keyboardSizeConstrainer}) + end + newKeyboard:SetCurrentKeyset(1) + end + + textEntryField.MouseButton1Click:connect(function() + SetTextFieldCursorPosition(calculateTextCursorPosition(panel.lookAtPixel.X, panel.lookAtPixel.Y)) + end) + + closeButton.MouseButton1Click:connect(function() + newKeyboard:Close(false) + closedEvent:Fire() + end) + + voiceDoneButton.MouseButton1Click:connect(function() + newKeyboard:SetVoiceMode(false) + end) + + return newKeyboard +end + + +local Keyboard = nil; +local function GetKeyboard() + if Keyboard == nil then + Keyboard = ConstructKeyboardUI({MINIMAL_KEYBOARD_LAYOUT, MINIMAL_KEYBOARD_LAYOUT_SYMBOLS}) + end + return Keyboard +end + + + +local VirtualKeyboardClass = {} + + +function VirtualKeyboardClass:CreateVirtualKeyboardOptions(textbox) + local keyboardOptions = {} + + keyboardOptions.TextBox = textbox + + return keyboardOptions +end + +local VirtualKeyboardPlatform = false +do + -- iOS, Android and Xbox already have platform specific keyboards + local platform = UserInputService:GetPlatform() + VirtualKeyboardPlatform = platform == Enum.Platform.Windows or + platform == Enum.Platform.OSX +end + + +function VirtualKeyboardClass:ShowVirtualKeyboard(virtualKeyboardOptions) + if VirtualKeyboardPlatform and UserInputService.VREnabled then + GetKeyboard():Open(virtualKeyboardOptions) + end +end + +function VirtualKeyboardClass:CloseVirtualKeyboard() + if VirtualKeyboardPlatform and UserInputService.VREnabled then + local currentKeyboard = GetKeyboard() + currentKeyboard:Close(false) + end +end + +VirtualKeyboardClass.ClosedEvent = GetKeyboard().ClosedEvent + + +if VirtualKeyboardPlatform and useVRKeyboard then + UserInputService.TextBoxFocused:connect(function(textbox) + VirtualKeyboardClass:ShowVirtualKeyboard(VirtualKeyboardClass:CreateVirtualKeyboardOptions(textbox)) + end) + + UserInputService.TextBoxFocusReleased:connect(function(textbox) + VirtualKeyboardClass:CloseVirtualKeyboard() + end) +end + + +return VirtualKeyboardClass diff --git a/2016/content/scripts/ServerCoreScripts/ServerSocialScript.lua b/2016/content/scripts/ServerCoreScripts/ServerSocialScript.lua new file mode 100644 index 0000000..e21716b --- /dev/null +++ b/2016/content/scripts/ServerCoreScripts/ServerSocialScript.lua @@ -0,0 +1,216 @@ +--[[ + // FileName: PlayerlistModule.lua + // Version 1.0 + // Written by: jmargh + // Description: Implements social features that need to be ran on the server + + // TODO + We need to get module script working on the server. When we get that working + This should be moved to a module, and http helper functions should be moved + to a utility module. +]] +local HttpService = game:GetService('HttpService') +local HttpRbxApiService = game:GetService('HttpRbxApiService') +local Players = game:GetService('Players') +local RobloxReplicatedStorage = game:GetService('RobloxReplicatedStorage') +local RunService = game:GetService('RunService') + +local GET_MULTI_FOLLOW = "user/multi-following-exists" + +local PlayerToRelationshipMap = {} + +--[[ Remotes ]]-- +local RemoteEvent_FollowRelationshipChanged = Instance.new('RemoteEvent') +RemoteEvent_FollowRelationshipChanged.Name = "FollowRelationshipChanged" +RemoteEvent_FollowRelationshipChanged.Parent = RobloxReplicatedStorage + +local RemoteEvent_NewFollower = Instance.new("RemoteEvent") +RemoteEvent_NewFollower.Name = "NewFollower" +RemoteEvent_NewFollower.Parent = RobloxReplicatedStorage + +local RemoteFunc_GetFollowRelationships = Instance.new('RemoteFunction') +RemoteFunc_GetFollowRelationships.Name = "GetFollowRelationships" +RemoteFunc_GetFollowRelationships.Parent = RobloxReplicatedStorage + +--[[ Helper Functions ]]-- +local function decodeJSON(json) + local success, result = pcall(function() + return HttpService:JSONDecode(json) + end) + if not success then + print("decodeJSON() failed because", result, "Input:", json) + return nil + end + + return result +end + +local function rbxApiPostAsync(path, params, useHttps, throttlePriority, contentType) + local success, result = pcall(function() + return HttpRbxApiService:PostAsync(path, params, useHttps, throttlePriority, contentType) + end) + -- + if not success then + local label = string.format("%s: - path: %s, \njson: %s", tostring(result), tostring(path), tostring(params)) + return nil + end + + return decodeJSON(result) +end + +--[[ + // Return - table + Key: FollowingDetails + Value: Arrary of details + Key: UserId1 + Value: number - userId of new client + Key: UserId2 + Value: number - userId of other client + Key: User1FollowsUser2 + Value: boolean + Key: User2FollowsUser1 + Value: boolean +]] +local function getFollowRelationshipsAsync(uid) + if RunService:IsStudio() then + return + end + + local otherUserIdTable = {} + for _,player in pairs(Players:GetPlayers()) do + if player.UserId > 0 then + table.insert(otherUserIdTable, player.UserId) + end + end + + if #otherUserIdTable > 0 and uid and uid > 0 then + local jsonPostBody = { + userId = uid; + otherUserIds = otherUserIdTable; + } + jsonPostBody = HttpService:JSONEncode(jsonPostBody) + + if jsonPostBody then + return rbxApiPostAsync(GET_MULTI_FOLLOW, jsonPostBody, true, Enum.ThrottlingPriority.Default, Enum.HttpContentType.ApplicationJson) + end + end +end + +local function createRelationshipObject(user1FollowsUser2, user2FollowsUser1) + local object = {} + object.IsFollower = user2FollowsUser1 + object.IsFollowing = user1FollowsUser2 + object.IsMutual = user1FollowsUser2 and user2FollowsUser1 + + return object +end + +local function updateAndNotifyClients(resultTable, newUserIdStr, newPlayer) + local followingDetails = resultTable["FollowingDetails"] + if followingDetails then + local relationshipTable = PlayerToRelationshipMap[newUserIdStr] or {} + + for i = 1, #followingDetails do + local detail = followingDetails[i] + local otherUserId = detail["UserId2"] + local otherUserIdStr = tostring(otherUserId) + + local followsOther = detail["User1FollowsUser2"] + local followsNewPlayer = detail["User2FollowsUser1"] + + relationshipTable[otherUserIdStr] = createRelationshipObject(followsOther, followsNewPlayer) + + -- update other use + local otherRelationshipTable = PlayerToRelationshipMap[otherUserIdStr] + if otherRelationshipTable then + local newRelationship = createRelationshipObject(followsNewPlayer, followsOther) + otherRelationshipTable[newUserIdStr] = newRelationship + + local otherPlayer = Players:GetPlayerByUserId(otherUserId) + if otherPlayer then + -- create single entry table (keep format same) and send to other client + local deltaTable = {} + deltaTable[newUserIdStr] = newRelationship + RemoteEvent_FollowRelationshipChanged:FireClient(otherPlayer, deltaTable) + end + end + end + + PlayerToRelationshipMap[newUserIdStr] = relationshipTable + RemoteEvent_FollowRelationshipChanged:FireClient(newPlayer, relationshipTable) + end +end + +--[[ Connections ]]-- +function RemoteFunc_GetFollowRelationships.OnServerInvoke(player) + local uid = player.userId + local uidStr = tostring(player.userId) + if uid and uid > 0 and PlayerToRelationshipMap[uidStr] then + return PlayerToRelationshipMap[uidStr] + else + return {} + end +end + +-- client fires event to server on new follow +RemoteEvent_NewFollower.OnServerEvent:connect(function(player1, player2, player1FollowsPlayer2) + if player1FollowsPlayer2 == nil then + return + end + local userId1 = tostring(player1.userId) + local userId2 = tostring(player2.userId) + + local user1map = PlayerToRelationshipMap[userId1] + local user2map = PlayerToRelationshipMap[userId2] + + if user1map then + local relationTable = user1map[userId2] + if relationTable then + relationTable.IsFollowing = player1FollowsPlayer2 + relationTable.IsMutual = relationTable.IsFollowing and relationTable.IsFollower + + local delta = {} + delta[userId2] = relationTable + RemoteEvent_FollowRelationshipChanged:FireClient(player1, delta) + -- this should be updated, but current NotificationScript listens to this + if player1FollowsPlayer2 then + RemoteEvent_NewFollower:FireClient(player2, player1) + end + end + end + + if user2map then + local relationTable = user2map[userId1] + if relationTable then + relationTable.IsFollower = player1FollowsPlayer2 + relationTable.IsMutual = relationTable.IsFollowing and relationTable.IsFollower + + local delta = {} + delta[userId1] = relationTable + RemoteEvent_FollowRelationshipChanged:FireClient(player2, delta) + end + end +end) + +local function onPlayerAdded(newPlayer) + local uid = newPlayer.UserId + if uid > 0 then + local uidStr = tostring(uid) + local result = getFollowRelationshipsAsync(uid) + if result then + updateAndNotifyClients(result, uidStr, newPlayer) + end + end +end + +Players.PlayerAdded:connect(onPlayerAdded) +for _,player in pairs(Players:GetPlayers()) do + onPlayerAdded(player) +end + +Players.PlayerRemoving:connect(function(prevPlayer) + local uid = tostring(prevPlayer.UserId) + if PlayerToRelationshipMap[uid] then + PlayerToRelationshipMap[uid] = nil + end +end) diff --git a/2016/content/scripts/ServerStarterScript.lua b/2016/content/scripts/ServerStarterScript.lua new file mode 100644 index 0000000..48efbfd --- /dev/null +++ b/2016/content/scripts/ServerStarterScript.lua @@ -0,0 +1,56 @@ +--[[ + // Filename: ServerStarterScript.lua + // Version: 1.0 + // Description: Server core script that handles core script server side logic. +]]-- + +-- Prevent server script from running in Studio when not in run mode +local runService = nil +while runService == nil or not runService:IsRunning() do + wait(0.1) + runService = game:GetService('RunService') +end + +--[[ Services ]]-- +local RobloxReplicatedStorage = game:GetService('RobloxReplicatedStorage') +local ScriptContext = game:GetService('ScriptContext') + +--[[ Fast Flags ]]-- +local serverFollowersSuccess, serverFollowersEnabled = pcall(function() return settings():GetFFlag("UserServerFollowers") end) +local IsServerFollowers = serverFollowersSuccess and serverFollowersEnabled + +local RemoteEvent_NewFollower = nil + +--[[ Add Server CoreScript ]]-- +-- TODO: FFlag check +if IsServerFollowers then + ScriptContext:AddCoreScriptLocal("ServerCoreScripts/ServerSocialScript", script.Parent) +else + -- above script will create this now + RemoteEvent_NewFollower = Instance.new('RemoteEvent') + RemoteEvent_NewFollower.Name = "NewFollower" + RemoteEvent_NewFollower.Parent = RobloxReplicatedStorage +end + +--[[ Remote Events ]]-- +local RemoteEvent_SetDialogInUse = Instance.new("RemoteEvent") +RemoteEvent_SetDialogInUse.Name = "SetDialogInUse" +RemoteEvent_SetDialogInUse.Parent = RobloxReplicatedStorage + +--[[ Event Connections ]]-- +-- Params: + -- followerRbxPlayer: player object of the new follower, this is the client who wants to follow another + -- followedRbxPlayer: player object of the person being followed +local function onNewFollower(followerRbxPlayer, followedRbxPlayer) + RemoteEvent_NewFollower:FireClient(followedRbxPlayer, followerRbxPlayer) +end +if RemoteEvent_NewFollower then + RemoteEvent_NewFollower.OnServerEvent:connect(onNewFollower) +end + +local function setDialogInUse(player, dialog, value) + if dialog ~= nil then + dialog.InUse = value + end +end +RemoteEvent_SetDialogInUse.OnServerEvent:connect(setDialogInUse) diff --git a/2016/content/scripts/StarterScript.lua b/2016/content/scripts/StarterScript.lua new file mode 100644 index 0000000..eb57fe5 --- /dev/null +++ b/2016/content/scripts/StarterScript.lua @@ -0,0 +1,60 @@ +-- Creates all neccessary scripts for the gui on initial load, everything except build tools +-- Created by Ben T. 10/29/10 +-- Please note that these are loaded in a specific order to diminish errors/perceived load time by user + +local scriptContext = game:GetService("ScriptContext") +local touchEnabled = game:GetService("UserInputService").TouchEnabled + +local RobloxGui = game:GetService("CoreGui"):WaitForChild("RobloxGui") + +local soundFolder = Instance.new("Folder") +soundFolder.Name = "Sounds" +soundFolder.Parent = RobloxGui + +-- TopBar +scriptContext:AddCoreScriptLocal("CoreScripts/Topbar", RobloxGui) + +-- SettingsScript +local luaControlsSuccess, luaControlsFlagValue = pcall(function() return settings():GetFFlag("UseLuaCameraAndControl") end) + +local vrKeyboardSuccess, vrKeyboardFlagValue = pcall(function() return settings():GetFFlag("UseVRKeyboardInLua") end) +local useVRKeyboard = (vrKeyboardSuccess and vrKeyboardFlagValue == true) + +-- MainBotChatScript (the Lua part of Dialogs) +scriptContext:AddCoreScriptLocal("CoreScripts/MainBotChatScript2", RobloxGui) + +-- Developer Console Script +scriptContext:AddCoreScriptLocal("CoreScripts/DeveloperConsole", RobloxGui) + +-- In-game notifications script +scriptContext:AddCoreScriptLocal("CoreScripts/NotificationScript2", RobloxGui) + +-- Chat script +spawn(function() require(RobloxGui.Modules.Chat) end) +spawn(function() require(RobloxGui.Modules.PlayerlistModule) end) + +scriptContext:AddCoreScriptLocal("CoreScripts/BubbleChat", RobloxGui) + +-- Purchase Prompt Script +scriptContext:AddCoreScriptLocal("CoreScripts/PurchasePromptScript2", RobloxGui) + +-- Backpack! +spawn(function() require(RobloxGui.Modules.BackpackScript) end) + +scriptContext:AddCoreScriptLocal("CoreScripts/VehicleHud", RobloxGui) + +scriptContext:AddCoreScriptLocal("CoreScripts/GamepadMenu", RobloxGui) + +if touchEnabled then -- touch devices don't use same control frame + -- only used for touch device button generation + scriptContext:AddCoreScriptLocal("CoreScripts/ContextActionTouch", RobloxGui) + + RobloxGui:WaitForChild("ControlFrame") + RobloxGui.ControlFrame:WaitForChild("BottomLeftControl") + RobloxGui.ControlFrame.BottomLeftControl.Visible = false +end + +if useVRKeyboard then + require(RobloxGui.Modules.VR.VirtualKeyboard) +end + diff --git a/2016/content/sky/lensflare.jpg b/2016/content/sky/lensflare.jpg new file mode 100644 index 0000000..c53f2ec Binary files /dev/null and b/2016/content/sky/lensflare.jpg differ diff --git a/2016/content/sky/moon-alpha.jpg b/2016/content/sky/moon-alpha.jpg new file mode 100644 index 0000000..5e193d5 Binary files /dev/null and b/2016/content/sky/moon-alpha.jpg differ diff --git a/2016/content/sky/moon.jpg b/2016/content/sky/moon.jpg new file mode 100644 index 0000000..247b6cd Binary files /dev/null and b/2016/content/sky/moon.jpg differ diff --git a/2016/content/sky/null_plainsky512_bk.jpg b/2016/content/sky/null_plainsky512_bk.jpg new file mode 100644 index 0000000..a01c9ef Binary files /dev/null and b/2016/content/sky/null_plainsky512_bk.jpg differ diff --git a/2016/content/sky/null_plainsky512_dn.jpg b/2016/content/sky/null_plainsky512_dn.jpg new file mode 100644 index 0000000..75f16c1 Binary files /dev/null and b/2016/content/sky/null_plainsky512_dn.jpg differ diff --git a/2016/content/sky/null_plainsky512_ft.jpg b/2016/content/sky/null_plainsky512_ft.jpg new file mode 100644 index 0000000..253cb31 Binary files /dev/null and b/2016/content/sky/null_plainsky512_ft.jpg differ diff --git a/2016/content/sky/null_plainsky512_lf.jpg b/2016/content/sky/null_plainsky512_lf.jpg new file mode 100644 index 0000000..aa3626b Binary files /dev/null and b/2016/content/sky/null_plainsky512_lf.jpg differ diff --git a/2016/content/sky/null_plainsky512_rt.jpg b/2016/content/sky/null_plainsky512_rt.jpg new file mode 100644 index 0000000..45b5071 Binary files /dev/null and b/2016/content/sky/null_plainsky512_rt.jpg differ diff --git a/2016/content/sky/null_plainsky512_up.jpg b/2016/content/sky/null_plainsky512_up.jpg new file mode 100644 index 0000000..49940da Binary files /dev/null and b/2016/content/sky/null_plainsky512_up.jpg differ diff --git a/2016/content/sky/skyspheremap.jpg b/2016/content/sky/skyspheremap.jpg new file mode 100644 index 0000000..947a7ee Binary files /dev/null and b/2016/content/sky/skyspheremap.jpg differ diff --git a/2016/content/sky/sun-rays.jpg b/2016/content/sky/sun-rays.jpg new file mode 100644 index 0000000..a76a4d5 Binary files /dev/null and b/2016/content/sky/sun-rays.jpg differ diff --git a/2016/content/sky/sun.jpg b/2016/content/sky/sun.jpg new file mode 100644 index 0000000..12b3829 Binary files /dev/null and b/2016/content/sky/sun.jpg differ diff --git a/2016/content/sounds/Kerplunk.mp3 b/2016/content/sounds/Kerplunk.mp3 new file mode 100644 index 0000000..1211b02 Binary files /dev/null and b/2016/content/sounds/Kerplunk.mp3 differ diff --git a/2016/content/sounds/Kid saying Ouch.mp3 b/2016/content/sounds/Kid saying Ouch.mp3 new file mode 100644 index 0000000..b3f87e0 Binary files /dev/null and b/2016/content/sounds/Kid saying Ouch.mp3 differ diff --git a/2016/content/sounds/Rubber band sling shot.mp3 b/2016/content/sounds/Rubber band sling shot.mp3 new file mode 100644 index 0000000..430f96c Binary files /dev/null and b/2016/content/sounds/Rubber band sling shot.mp3 differ diff --git a/2016/content/sounds/Rubber band.mp3 b/2016/content/sounds/Rubber band.mp3 new file mode 100644 index 0000000..f815a17 Binary files /dev/null and b/2016/content/sounds/Rubber band.mp3 differ diff --git a/2016/content/sounds/SWITCH3.mp3 b/2016/content/sounds/SWITCH3.mp3 new file mode 100644 index 0000000..0132c84 Binary files /dev/null and b/2016/content/sounds/SWITCH3.mp3 differ diff --git a/2016/content/sounds/action_falling.mp3 b/2016/content/sounds/action_falling.mp3 new file mode 100644 index 0000000..6408717 Binary files /dev/null and b/2016/content/sounds/action_falling.mp3 differ diff --git a/2016/content/sounds/action_footsteps_plastic.mp3 b/2016/content/sounds/action_footsteps_plastic.mp3 new file mode 100644 index 0000000..6804420 Binary files /dev/null and b/2016/content/sounds/action_footsteps_plastic.mp3 differ diff --git a/2016/content/sounds/action_get_up.mp3 b/2016/content/sounds/action_get_up.mp3 new file mode 100644 index 0000000..ababd77 Binary files /dev/null and b/2016/content/sounds/action_get_up.mp3 differ diff --git a/2016/content/sounds/action_jump.mp3 b/2016/content/sounds/action_jump.mp3 new file mode 100644 index 0000000..7159074 Binary files /dev/null and b/2016/content/sounds/action_jump.mp3 differ diff --git a/2016/content/sounds/action_jump_land.mp3 b/2016/content/sounds/action_jump_land.mp3 new file mode 100644 index 0000000..3d68ce1 Binary files /dev/null and b/2016/content/sounds/action_jump_land.mp3 differ diff --git a/2016/content/sounds/action_swim.mp3 b/2016/content/sounds/action_swim.mp3 new file mode 100644 index 0000000..95dd2d5 Binary files /dev/null and b/2016/content/sounds/action_swim.mp3 differ diff --git a/2016/content/sounds/bass.mp3 b/2016/content/sounds/bass.mp3 new file mode 100644 index 0000000..ffd6286 Binary files /dev/null and b/2016/content/sounds/bass.mp3 differ diff --git a/2016/content/sounds/bfsl-minifigfoots1.mp3 b/2016/content/sounds/bfsl-minifigfoots1.mp3 new file mode 100644 index 0000000..ca2e697 Binary files /dev/null and b/2016/content/sounds/bfsl-minifigfoots1.mp3 differ diff --git a/2016/content/sounds/bfsl-minifigfoots2.mp3 b/2016/content/sounds/bfsl-minifigfoots2.mp3 new file mode 100644 index 0000000..113ad8f Binary files /dev/null and b/2016/content/sounds/bfsl-minifigfoots2.mp3 differ diff --git a/2016/content/sounds/button.mp3 b/2016/content/sounds/button.mp3 new file mode 100644 index 0000000..1136b2b Binary files /dev/null and b/2016/content/sounds/button.mp3 differ diff --git a/2016/content/sounds/clickfast.mp3 b/2016/content/sounds/clickfast.mp3 new file mode 100644 index 0000000..12bfbff Binary files /dev/null and b/2016/content/sounds/clickfast.mp3 differ diff --git a/2016/content/sounds/collide.mp3 b/2016/content/sounds/collide.mp3 new file mode 100644 index 0000000..8f69cf0 Binary files /dev/null and b/2016/content/sounds/collide.mp3 differ diff --git a/2016/content/sounds/electronicpingshort.mp3 b/2016/content/sounds/electronicpingshort.mp3 new file mode 100644 index 0000000..bfb3eb0 Binary files /dev/null and b/2016/content/sounds/electronicpingshort.mp3 differ diff --git a/2016/content/sounds/flashbulb.mp3 b/2016/content/sounds/flashbulb.mp3 new file mode 100644 index 0000000..fdcf7f6 Binary files /dev/null and b/2016/content/sounds/flashbulb.mp3 differ diff --git a/2016/content/sounds/grass.mp3 b/2016/content/sounds/grass.mp3 new file mode 100644 index 0000000..e79fb5b Binary files /dev/null and b/2016/content/sounds/grass.mp3 differ diff --git a/2016/content/sounds/grass2.mp3 b/2016/content/sounds/grass2.mp3 new file mode 100644 index 0000000..1a1ad7a Binary files /dev/null and b/2016/content/sounds/grass2.mp3 differ diff --git a/2016/content/sounds/grass3.mp3 b/2016/content/sounds/grass3.mp3 new file mode 100644 index 0000000..131602a Binary files /dev/null and b/2016/content/sounds/grass3.mp3 differ diff --git a/2016/content/sounds/grassstone.mp3 b/2016/content/sounds/grassstone.mp3 new file mode 100644 index 0000000..4e9397c Binary files /dev/null and b/2016/content/sounds/grassstone.mp3 differ diff --git a/2016/content/sounds/grassstone2.mp3 b/2016/content/sounds/grassstone2.mp3 new file mode 100644 index 0000000..0a5f1c1 Binary files /dev/null and b/2016/content/sounds/grassstone2.mp3 differ diff --git a/2016/content/sounds/grassstone3.mp3 b/2016/content/sounds/grassstone3.mp3 new file mode 100644 index 0000000..51df635 Binary files /dev/null and b/2016/content/sounds/grassstone3.mp3 differ diff --git a/2016/content/sounds/hit.mp3 b/2016/content/sounds/hit.mp3 new file mode 100644 index 0000000..a299c1a Binary files /dev/null and b/2016/content/sounds/hit.mp3 differ diff --git a/2016/content/sounds/ice.mp3 b/2016/content/sounds/ice.mp3 new file mode 100644 index 0000000..db528cc Binary files /dev/null and b/2016/content/sounds/ice.mp3 differ diff --git a/2016/content/sounds/ice2.mp3 b/2016/content/sounds/ice2.mp3 new file mode 100644 index 0000000..dc4cb7b Binary files /dev/null and b/2016/content/sounds/ice2.mp3 differ diff --git a/2016/content/sounds/ice3.mp3 b/2016/content/sounds/ice3.mp3 new file mode 100644 index 0000000..7f3e5b1 Binary files /dev/null and b/2016/content/sounds/ice3.mp3 differ diff --git a/2016/content/sounds/icegrass.mp3 b/2016/content/sounds/icegrass.mp3 new file mode 100644 index 0000000..2561aff Binary files /dev/null and b/2016/content/sounds/icegrass.mp3 differ diff --git a/2016/content/sounds/icegrass2.mp3 b/2016/content/sounds/icegrass2.mp3 new file mode 100644 index 0000000..db6f6d2 Binary files /dev/null and b/2016/content/sounds/icegrass2.mp3 differ diff --git a/2016/content/sounds/icegrass3.mp3 b/2016/content/sounds/icegrass3.mp3 new file mode 100644 index 0000000..b72c2db Binary files /dev/null and b/2016/content/sounds/icegrass3.mp3 differ diff --git a/2016/content/sounds/icemetal.mp3 b/2016/content/sounds/icemetal.mp3 new file mode 100644 index 0000000..5c9d2d4 Binary files /dev/null and b/2016/content/sounds/icemetal.mp3 differ diff --git a/2016/content/sounds/icemetal2.mp3 b/2016/content/sounds/icemetal2.mp3 new file mode 100644 index 0000000..60f9e4d Binary files /dev/null and b/2016/content/sounds/icemetal2.mp3 differ diff --git a/2016/content/sounds/icemetal3.mp3 b/2016/content/sounds/icemetal3.mp3 new file mode 100644 index 0000000..2ee4312 Binary files /dev/null and b/2016/content/sounds/icemetal3.mp3 differ diff --git a/2016/content/sounds/icestone.mp3 b/2016/content/sounds/icestone.mp3 new file mode 100644 index 0000000..37b99bb Binary files /dev/null and b/2016/content/sounds/icestone.mp3 differ diff --git a/2016/content/sounds/icestone2.mp3 b/2016/content/sounds/icestone2.mp3 new file mode 100644 index 0000000..1f5e264 Binary files /dev/null and b/2016/content/sounds/icestone2.mp3 differ diff --git a/2016/content/sounds/icestone3.mp3 b/2016/content/sounds/icestone3.mp3 new file mode 100644 index 0000000..e51ce3d Binary files /dev/null and b/2016/content/sounds/icestone3.mp3 differ diff --git a/2016/content/sounds/impact_bodyfall.mp3 b/2016/content/sounds/impact_bodyfall.mp3 new file mode 100644 index 0000000..d7bf3ae Binary files /dev/null and b/2016/content/sounds/impact_bodyfall.mp3 differ diff --git a/2016/content/sounds/impact_explosion_01.mp3 b/2016/content/sounds/impact_explosion_01.mp3 new file mode 100644 index 0000000..3e03015 Binary files /dev/null and b/2016/content/sounds/impact_explosion_01.mp3 differ diff --git a/2016/content/sounds/impact_explosion_02.mp3 b/2016/content/sounds/impact_explosion_02.mp3 new file mode 100644 index 0000000..df33b3b Binary files /dev/null and b/2016/content/sounds/impact_explosion_02.mp3 differ diff --git a/2016/content/sounds/impact_explosion_03.mp3 b/2016/content/sounds/impact_explosion_03.mp3 new file mode 100644 index 0000000..4501c83 Binary files /dev/null and b/2016/content/sounds/impact_explosion_03.mp3 differ diff --git a/2016/content/sounds/impact_water.mp3 b/2016/content/sounds/impact_water.mp3 new file mode 100644 index 0000000..741862b Binary files /dev/null and b/2016/content/sounds/impact_water.mp3 differ diff --git a/2016/content/sounds/metal.mp3 b/2016/content/sounds/metal.mp3 new file mode 100644 index 0000000..32473b1 Binary files /dev/null and b/2016/content/sounds/metal.mp3 differ diff --git a/2016/content/sounds/metal2.mp3 b/2016/content/sounds/metal2.mp3 new file mode 100644 index 0000000..023273f Binary files /dev/null and b/2016/content/sounds/metal2.mp3 differ diff --git a/2016/content/sounds/metal3.mp3 b/2016/content/sounds/metal3.mp3 new file mode 100644 index 0000000..e407be0 Binary files /dev/null and b/2016/content/sounds/metal3.mp3 differ diff --git a/2016/content/sounds/metalgrass.mp3 b/2016/content/sounds/metalgrass.mp3 new file mode 100644 index 0000000..46fdef4 Binary files /dev/null and b/2016/content/sounds/metalgrass.mp3 differ diff --git a/2016/content/sounds/metalgrass2.mp3 b/2016/content/sounds/metalgrass2.mp3 new file mode 100644 index 0000000..3a7dad2 Binary files /dev/null and b/2016/content/sounds/metalgrass2.mp3 differ diff --git a/2016/content/sounds/metalgrass3.mp3 b/2016/content/sounds/metalgrass3.mp3 new file mode 100644 index 0000000..e8172ad Binary files /dev/null and b/2016/content/sounds/metalgrass3.mp3 differ diff --git a/2016/content/sounds/metalstone.mp3 b/2016/content/sounds/metalstone.mp3 new file mode 100644 index 0000000..6910e46 Binary files /dev/null and b/2016/content/sounds/metalstone.mp3 differ diff --git a/2016/content/sounds/metalstone2.mp3 b/2016/content/sounds/metalstone2.mp3 new file mode 100644 index 0000000..0dd924e Binary files /dev/null and b/2016/content/sounds/metalstone2.mp3 differ diff --git a/2016/content/sounds/metalstone3.mp3 b/2016/content/sounds/metalstone3.mp3 new file mode 100644 index 0000000..37e1198 Binary files /dev/null and b/2016/content/sounds/metalstone3.mp3 differ diff --git a/2016/content/sounds/plasticgrass.mp3 b/2016/content/sounds/plasticgrass.mp3 new file mode 100644 index 0000000..579d4ab Binary files /dev/null and b/2016/content/sounds/plasticgrass.mp3 differ diff --git a/2016/content/sounds/plasticgrass2.mp3 b/2016/content/sounds/plasticgrass2.mp3 new file mode 100644 index 0000000..f77843a Binary files /dev/null and b/2016/content/sounds/plasticgrass2.mp3 differ diff --git a/2016/content/sounds/plasticgrass3.mp3 b/2016/content/sounds/plasticgrass3.mp3 new file mode 100644 index 0000000..9274ff0 Binary files /dev/null and b/2016/content/sounds/plasticgrass3.mp3 differ diff --git a/2016/content/sounds/plasticice.mp3 b/2016/content/sounds/plasticice.mp3 new file mode 100644 index 0000000..668ba91 Binary files /dev/null and b/2016/content/sounds/plasticice.mp3 differ diff --git a/2016/content/sounds/plasticice2.mp3 b/2016/content/sounds/plasticice2.mp3 new file mode 100644 index 0000000..041e4ca Binary files /dev/null and b/2016/content/sounds/plasticice2.mp3 differ diff --git a/2016/content/sounds/plasticice3.mp3 b/2016/content/sounds/plasticice3.mp3 new file mode 100644 index 0000000..180b476 Binary files /dev/null and b/2016/content/sounds/plasticice3.mp3 differ diff --git a/2016/content/sounds/plasticmetal.mp3 b/2016/content/sounds/plasticmetal.mp3 new file mode 100644 index 0000000..1eadf0c Binary files /dev/null and b/2016/content/sounds/plasticmetal.mp3 differ diff --git a/2016/content/sounds/plasticmetal2.mp3 b/2016/content/sounds/plasticmetal2.mp3 new file mode 100644 index 0000000..6d4119a Binary files /dev/null and b/2016/content/sounds/plasticmetal2.mp3 differ diff --git a/2016/content/sounds/plasticmetal3.mp3 b/2016/content/sounds/plasticmetal3.mp3 new file mode 100644 index 0000000..c777ee4 Binary files /dev/null and b/2016/content/sounds/plasticmetal3.mp3 differ diff --git a/2016/content/sounds/plasticplastic.mp3 b/2016/content/sounds/plasticplastic.mp3 new file mode 100644 index 0000000..7283013 Binary files /dev/null and b/2016/content/sounds/plasticplastic.mp3 differ diff --git a/2016/content/sounds/plasticplastic2.mp3 b/2016/content/sounds/plasticplastic2.mp3 new file mode 100644 index 0000000..f9710c7 Binary files /dev/null and b/2016/content/sounds/plasticplastic2.mp3 differ diff --git a/2016/content/sounds/plasticplastic3.mp3 b/2016/content/sounds/plasticplastic3.mp3 new file mode 100644 index 0000000..c7cd1ca Binary files /dev/null and b/2016/content/sounds/plasticplastic3.mp3 differ diff --git a/2016/content/sounds/plasticstone.mp3 b/2016/content/sounds/plasticstone.mp3 new file mode 100644 index 0000000..d33e553 Binary files /dev/null and b/2016/content/sounds/plasticstone.mp3 differ diff --git a/2016/content/sounds/plasticstone2.mp3 b/2016/content/sounds/plasticstone2.mp3 new file mode 100644 index 0000000..cd33d00 Binary files /dev/null and b/2016/content/sounds/plasticstone2.mp3 differ diff --git a/2016/content/sounds/plasticstone3.mp3 b/2016/content/sounds/plasticstone3.mp3 new file mode 100644 index 0000000..5732f38 Binary files /dev/null and b/2016/content/sounds/plasticstone3.mp3 differ diff --git a/2016/content/sounds/snap.mp3 b/2016/content/sounds/snap.mp3 new file mode 100644 index 0000000..8dd8d5a Binary files /dev/null and b/2016/content/sounds/snap.mp3 differ diff --git a/2016/content/sounds/splat.mp3 b/2016/content/sounds/splat.mp3 new file mode 100644 index 0000000..934a634 Binary files /dev/null and b/2016/content/sounds/splat.mp3 differ diff --git a/2016/content/sounds/stone.mp3 b/2016/content/sounds/stone.mp3 new file mode 100644 index 0000000..e9dd548 Binary files /dev/null and b/2016/content/sounds/stone.mp3 differ diff --git a/2016/content/sounds/stone2.mp3 b/2016/content/sounds/stone2.mp3 new file mode 100644 index 0000000..f582a22 Binary files /dev/null and b/2016/content/sounds/stone2.mp3 differ diff --git a/2016/content/sounds/stone3.mp3 b/2016/content/sounds/stone3.mp3 new file mode 100644 index 0000000..b8bfa31 Binary files /dev/null and b/2016/content/sounds/stone3.mp3 differ diff --git a/2016/content/sounds/switch.mp3 b/2016/content/sounds/switch.mp3 new file mode 100644 index 0000000..69e9442 Binary files /dev/null and b/2016/content/sounds/switch.mp3 differ diff --git a/2016/content/sounds/swoosh.mp3 b/2016/content/sounds/swoosh.mp3 new file mode 100644 index 0000000..99014d0 Binary files /dev/null and b/2016/content/sounds/swoosh.mp3 differ diff --git a/2016/content/sounds/swordlunge.mp3 b/2016/content/sounds/swordlunge.mp3 new file mode 100644 index 0000000..c5b017a Binary files /dev/null and b/2016/content/sounds/swordlunge.mp3 differ diff --git a/2016/content/sounds/swordslash.mp3 b/2016/content/sounds/swordslash.mp3 new file mode 100644 index 0000000..cf5b902 Binary files /dev/null and b/2016/content/sounds/swordslash.mp3 differ diff --git a/2016/content/sounds/unsheath.mp3 b/2016/content/sounds/unsheath.mp3 new file mode 100644 index 0000000..6913873 Binary files /dev/null and b/2016/content/sounds/unsheath.mp3 differ diff --git a/2016/content/sounds/uuhhh.mp3 b/2016/content/sounds/uuhhh.mp3 new file mode 100644 index 0000000..81b3565 Binary files /dev/null and b/2016/content/sounds/uuhhh.mp3 differ diff --git a/2016/content/sounds/victory.mp3 b/2016/content/sounds/victory.mp3 new file mode 100644 index 0000000..793b1ba Binary files /dev/null and b/2016/content/sounds/victory.mp3 differ diff --git a/2016/content/sounds/woodgrass.mp3 b/2016/content/sounds/woodgrass.mp3 new file mode 100644 index 0000000..f70237c Binary files /dev/null and b/2016/content/sounds/woodgrass.mp3 differ diff --git a/2016/content/sounds/woodgrass2.mp3 b/2016/content/sounds/woodgrass2.mp3 new file mode 100644 index 0000000..0d12b62 Binary files /dev/null and b/2016/content/sounds/woodgrass2.mp3 differ diff --git a/2016/content/sounds/woodgrass3.mp3 b/2016/content/sounds/woodgrass3.mp3 new file mode 100644 index 0000000..f234835 Binary files /dev/null and b/2016/content/sounds/woodgrass3.mp3 differ diff --git a/2016/content/sounds/woodice.mp3 b/2016/content/sounds/woodice.mp3 new file mode 100644 index 0000000..5604dcf Binary files /dev/null and b/2016/content/sounds/woodice.mp3 differ diff --git a/2016/content/sounds/woodice2.mp3 b/2016/content/sounds/woodice2.mp3 new file mode 100644 index 0000000..dc3a586 Binary files /dev/null and b/2016/content/sounds/woodice2.mp3 differ diff --git a/2016/content/sounds/woodice3.mp3 b/2016/content/sounds/woodice3.mp3 new file mode 100644 index 0000000..300dea9 Binary files /dev/null and b/2016/content/sounds/woodice3.mp3 differ diff --git a/2016/content/sounds/woodmetal.mp3 b/2016/content/sounds/woodmetal.mp3 new file mode 100644 index 0000000..666db63 Binary files /dev/null and b/2016/content/sounds/woodmetal.mp3 differ diff --git a/2016/content/sounds/woodmetal2.mp3 b/2016/content/sounds/woodmetal2.mp3 new file mode 100644 index 0000000..60e87dc Binary files /dev/null and b/2016/content/sounds/woodmetal2.mp3 differ diff --git a/2016/content/sounds/woodmetal3.mp3 b/2016/content/sounds/woodmetal3.mp3 new file mode 100644 index 0000000..29ec64a Binary files /dev/null and b/2016/content/sounds/woodmetal3.mp3 differ diff --git a/2016/content/sounds/woodplastic.mp3 b/2016/content/sounds/woodplastic.mp3 new file mode 100644 index 0000000..d909b8a Binary files /dev/null and b/2016/content/sounds/woodplastic.mp3 differ diff --git a/2016/content/sounds/woodplastic2.mp3 b/2016/content/sounds/woodplastic2.mp3 new file mode 100644 index 0000000..c4e9b19 Binary files /dev/null and b/2016/content/sounds/woodplastic2.mp3 differ diff --git a/2016/content/sounds/woodplastic3.mp3 b/2016/content/sounds/woodplastic3.mp3 new file mode 100644 index 0000000..4398179 Binary files /dev/null and b/2016/content/sounds/woodplastic3.mp3 differ diff --git a/2016/content/sounds/woodstone.mp3 b/2016/content/sounds/woodstone.mp3 new file mode 100644 index 0000000..3f7c071 Binary files /dev/null and b/2016/content/sounds/woodstone.mp3 differ diff --git a/2016/content/sounds/woodstone2.mp3 b/2016/content/sounds/woodstone2.mp3 new file mode 100644 index 0000000..1b4505a Binary files /dev/null and b/2016/content/sounds/woodstone2.mp3 differ diff --git a/2016/content/sounds/woodstone3.mp3 b/2016/content/sounds/woodstone3.mp3 new file mode 100644 index 0000000..6e04dec Binary files /dev/null and b/2016/content/sounds/woodstone3.mp3 differ diff --git a/2016/content/sounds/woodwood.mp3 b/2016/content/sounds/woodwood.mp3 new file mode 100644 index 0000000..8279e0c Binary files /dev/null and b/2016/content/sounds/woodwood.mp3 differ diff --git a/2016/content/sounds/woodwood2.mp3 b/2016/content/sounds/woodwood2.mp3 new file mode 100644 index 0000000..ad29d7f Binary files /dev/null and b/2016/content/sounds/woodwood2.mp3 differ diff --git a/2016/content/sounds/woodwood3.mp3 b/2016/content/sounds/woodwood3.mp3 new file mode 100644 index 0000000..e8bf04f Binary files /dev/null and b/2016/content/sounds/woodwood3.mp3 differ diff --git a/2016/content/textures/AnchorCursor.png b/2016/content/textures/AnchorCursor.png new file mode 100644 index 0000000..5c4cac7 Binary files /dev/null and b/2016/content/textures/AnchorCursor.png differ diff --git a/2016/content/textures/ArrowCursor.png b/2016/content/textures/ArrowCursor.png new file mode 100644 index 0000000..0f839d0 Binary files /dev/null and b/2016/content/textures/ArrowCursor.png differ diff --git a/2016/content/textures/ArrowCursorDecalDrag.png b/2016/content/textures/ArrowCursorDecalDrag.png new file mode 100644 index 0000000..0f839d0 Binary files /dev/null and b/2016/content/textures/ArrowCursorDecalDrag.png differ diff --git a/2016/content/textures/ArrowFarCursor.png b/2016/content/textures/ArrowFarCursor.png new file mode 100644 index 0000000..c3ce391 Binary files /dev/null and b/2016/content/textures/ArrowFarCursor.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ColorSelection/gr-box-shadow.png b/2016/content/textures/AvatarEditorIcons/ColorSelection/gr-box-shadow.png new file mode 100644 index 0000000..dbf0835 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ColorSelection/gr-box-shadow.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ColorSelection/gr-box-shadow@2x.png b/2016/content/textures/AvatarEditorIcons/ColorSelection/gr-box-shadow@2x.png new file mode 100644 index 0000000..d15e068 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ColorSelection/gr-box-shadow@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ColorSelection/gr-box-shadow@3x.png b/2016/content/textures/AvatarEditorIcons/ColorSelection/gr-box-shadow@3x.png new file mode 100644 index 0000000..9b1da34 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ColorSelection/gr-box-shadow@3x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ColorSelection/gr-circle-shadow.png b/2016/content/textures/AvatarEditorIcons/ColorSelection/gr-circle-shadow.png new file mode 100644 index 0000000..fd714e0 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ColorSelection/gr-circle-shadow.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ColorSelection/gr-circle-shadow@2x.png b/2016/content/textures/AvatarEditorIcons/ColorSelection/gr-circle-shadow@2x.png new file mode 100644 index 0000000..6844a53 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ColorSelection/gr-circle-shadow@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ColorSelection/gr-circle-shadow@3x.png b/2016/content/textures/AvatarEditorIcons/ColorSelection/gr-circle-shadow@3x.png new file mode 100644 index 0000000..6b085e9 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ColorSelection/gr-circle-shadow@3x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ColorSelection/gr-circle-white.png b/2016/content/textures/AvatarEditorIcons/ColorSelection/gr-circle-white.png new file mode 100644 index 0000000..c07a31c Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ColorSelection/gr-circle-white.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ColorSelection/gr-circle-white@2x.png b/2016/content/textures/AvatarEditorIcons/ColorSelection/gr-circle-white@2x.png new file mode 100644 index 0000000..ff2648c Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ColorSelection/gr-circle-white@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ColorSelection/gr-circle-white@3x.png b/2016/content/textures/AvatarEditorIcons/ColorSelection/gr-circle-white@3x.png new file mode 100644 index 0000000..cb4d460 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ColorSelection/gr-circle-white@3x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ColorSelection/gr-ring-selector.png b/2016/content/textures/AvatarEditorIcons/ColorSelection/gr-ring-selector.png new file mode 100644 index 0000000..0a21099 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ColorSelection/gr-ring-selector.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ColorSelection/gr-ring-selector@2x.png b/2016/content/textures/AvatarEditorIcons/ColorSelection/gr-ring-selector@2x.png new file mode 100644 index 0000000..714333c Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ColorSelection/gr-ring-selector@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ColorSelection/gr-ring-selector@3x.png b/2016/content/textures/AvatarEditorIcons/ColorSelection/gr-ring-selector@3x.png new file mode 100644 index 0000000..b6cb5ed Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ColorSelection/gr-ring-selector@3x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-climb-on.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-climb-on.png new file mode 100644 index 0000000..5110ef7 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-climb-on.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-climb-on@2x.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-climb-on@2x.png new file mode 100644 index 0000000..34bf8cc Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-climb-on@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-climb.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-climb.png new file mode 100644 index 0000000..d49188b Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-climb.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-climb@2x.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-climb@2x.png new file mode 100644 index 0000000..7629efb Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-climb@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-fall-on.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-fall-on.png new file mode 100644 index 0000000..6239c5f Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-fall-on.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-fall-on@2x.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-fall-on@2x.png new file mode 100644 index 0000000..87d75c3 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-fall-on@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-fall.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-fall.png new file mode 100644 index 0000000..6e77436 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-fall.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-fall@2x.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-fall@2x.png new file mode 100644 index 0000000..a636247 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-fall@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-idle-on.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-idle-on.png new file mode 100644 index 0000000..10b2619 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-idle-on.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-idle-on@2x.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-idle-on@2x.png new file mode 100644 index 0000000..2f57bd5 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-idle-on@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-idle.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-idle.png new file mode 100644 index 0000000..929b857 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-idle.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-idle@2x.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-idle@2x.png new file mode 100644 index 0000000..5ce36a5 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-idle@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-jump-on.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-jump-on.png new file mode 100644 index 0000000..4a98080 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-jump-on.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-jump-on@2x.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-jump-on@2x.png new file mode 100644 index 0000000..e86ceb3 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-jump-on@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-jump.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-jump.png new file mode 100644 index 0000000..a60c4b6 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-jump.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-jump@2x.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-jump@2x.png new file mode 100644 index 0000000..abd0c65 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-jump@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-run-on.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-run-on.png new file mode 100644 index 0000000..9498276 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-run-on.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-run-on@2x.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-run-on@2x.png new file mode 100644 index 0000000..c66d529 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-run-on@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-run.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-run.png new file mode 100644 index 0000000..890c03f Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-run.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-run@2x.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-run@2x.png new file mode 100644 index 0000000..a0fcda8 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-run@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-swim-on.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-swim-on.png new file mode 100644 index 0000000..7ebc2f6 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-swim-on.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-swim-on@2x.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-swim-on@2x.png new file mode 100644 index 0000000..ad1ba9a Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-swim-on@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-swim.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-swim.png new file mode 100644 index 0000000..246a40a Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-swim.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-swim@2x.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-swim@2x.png new file mode 100644 index 0000000..f0716c2 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-swim@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-walk-on.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-walk-on.png new file mode 100644 index 0000000..83779ea Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-walk-on.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-walk-on@2x.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-walk-on@2x.png new file mode 100644 index 0000000..2a79b58 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-walk-on@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-walk.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-walk.png new file mode 100644 index 0000000..7d9f16a Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-walk.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-walk@2x.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-walk@2x.png new file mode 100644 index 0000000..9662ff4 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Avatar-Animation/ic-walk@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-color-on.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-color-on.png new file mode 100644 index 0000000..b06ffa1 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-color-on.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-color-on@2x.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-color-on@2x.png new file mode 100644 index 0000000..cd7ae04 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-color-on@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-color.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-color.png new file mode 100644 index 0000000..8e37148 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-color.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-color@2x.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-color@2x.png new file mode 100644 index 0000000..8939757 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-color@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-head-on.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-head-on.png new file mode 100644 index 0000000..89d1d5b Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-head-on.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-head-on@2x.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-head-on@2x.png new file mode 100644 index 0000000..cd4592f Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-head-on@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-head.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-head.png new file mode 100644 index 0000000..7a13fc1 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-head.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-head@2x.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-head@2x.png new file mode 100644 index 0000000..2ceb951 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-head@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-left-arm-on.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-left-arm-on.png new file mode 100644 index 0000000..3f240bf Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-left-arm-on.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-left-arm-on@2x.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-left-arm-on@2x.png new file mode 100644 index 0000000..9038745 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-left-arm-on@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-left-arm.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-left-arm.png new file mode 100644 index 0000000..a9a0792 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-left-arm.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-left-arm@2x.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-left-arm@2x.png new file mode 100644 index 0000000..96ec26d Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-left-arm@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-left-leg-on.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-left-leg-on.png new file mode 100644 index 0000000..3b6ff26 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-left-leg-on.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-left-leg-on@2x.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-left-leg-on@2x.png new file mode 100644 index 0000000..6b127d2 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-left-leg-on@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-left-leg.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-left-leg.png new file mode 100644 index 0000000..308117b Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-left-leg.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-left-leg@2x.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-left-leg@2x.png new file mode 100644 index 0000000..7fbaa9d Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-left-leg@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-right-arm-on.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-right-arm-on.png new file mode 100644 index 0000000..0d5d7d6 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-right-arm-on.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-right-arm-on@2x.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-right-arm-on@2x.png new file mode 100644 index 0000000..6ddccf1 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-right-arm-on@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-right-arm.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-right-arm.png new file mode 100644 index 0000000..659d3e3 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-right-arm.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-right-arm@2x.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-right-arm@2x.png new file mode 100644 index 0000000..213f897 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-right-arm@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-right-leg-on.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-right-leg-on.png new file mode 100644 index 0000000..5f1f628 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-right-leg-on.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-right-leg-on@2x.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-right-leg-on@2x.png new file mode 100644 index 0000000..53b31be Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-right-leg-on@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-right-leg.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-right-leg.png new file mode 100644 index 0000000..fb3d8bc Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-right-leg.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-right-leg@2x.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-right-leg@2x.png new file mode 100644 index 0000000..0b0eb48 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-right-leg@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-scaling-on.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-scaling-on.png new file mode 100644 index 0000000..0eb90af Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-scaling-on.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-scaling-on@2x.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-scaling-on@2x.png new file mode 100644 index 0000000..e560032 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-scaling-on@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-scaling.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-scaling.png new file mode 100644 index 0000000..3dd09f3 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-scaling.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-scaling@2x.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-scaling@2x.png new file mode 100644 index 0000000..6960e31 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-scaling@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-torso-on.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-torso-on.png new file mode 100644 index 0000000..aaf5e2e Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-torso-on.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-torso-on@2x.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-torso-on@2x.png new file mode 100644 index 0000000..e6b923c Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-torso-on@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-torso.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-torso.png new file mode 100644 index 0000000..6bf65c1 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-torso.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-torso@2x.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-torso@2x.png new file mode 100644 index 0000000..37f14b2 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Body-Part/ic-torso@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Category/ic-all-on.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Category/ic-all-on.png new file mode 100644 index 0000000..c2cf761 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Category/ic-all-on.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Category/ic-all-on@2x.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Category/ic-all-on@2x.png new file mode 100644 index 0000000..58b70b2 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Category/ic-all-on@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Category/ic-all.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Category/ic-all.png new file mode 100644 index 0000000..4fad02a Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Category/ic-all.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Category/ic-all@2x.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Category/ic-all@2x.png new file mode 100644 index 0000000..9222c8a Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Category/ic-all@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Category/ic-avatar-animation-on.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Category/ic-avatar-animation-on.png new file mode 100644 index 0000000..f8d407f Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Category/ic-avatar-animation-on.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Category/ic-avatar-animation-on@2x.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Category/ic-avatar-animation-on@2x.png new file mode 100644 index 0000000..f9c241a Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Category/ic-avatar-animation-on@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Category/ic-avatar-animation.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Category/ic-avatar-animation.png new file mode 100644 index 0000000..8806d02 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Category/ic-avatar-animation.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Category/ic-avatar-animation@2x.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Category/ic-avatar-animation@2x.png new file mode 100644 index 0000000..d785c2e Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Category/ic-avatar-animation@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Category/ic-body-part-on.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Category/ic-body-part-on.png new file mode 100644 index 0000000..1a5fd2c Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Category/ic-body-part-on.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Category/ic-body-part-on@2x.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Category/ic-body-part-on@2x.png new file mode 100644 index 0000000..5514bd0 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Category/ic-body-part-on@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Category/ic-body-part.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Category/ic-body-part.png new file mode 100644 index 0000000..cd8de7b Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Category/ic-body-part.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Category/ic-body-part@2x.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Category/ic-body-part@2x.png new file mode 100644 index 0000000..cd3bb4e Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Category/ic-body-part@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Category/ic-clothing-on.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Category/ic-clothing-on.png new file mode 100644 index 0000000..6a9b5aa Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Category/ic-clothing-on.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Category/ic-clothing-on@2x.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Category/ic-clothing-on@2x.png new file mode 100644 index 0000000..40c125c Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Category/ic-clothing-on@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Category/ic-clothing.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Category/ic-clothing.png new file mode 100644 index 0000000..068444b Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Category/ic-clothing.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Category/ic-clothing@2x.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Category/ic-clothing@2x.png new file mode 100644 index 0000000..5bf6053 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Category/ic-clothing@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Category/ic-recent-on.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Category/ic-recent-on.png new file mode 100644 index 0000000..722ed36 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Category/ic-recent-on.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Category/ic-recent-on@2x.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Category/ic-recent-on@2x.png new file mode 100644 index 0000000..252d1a8 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Category/ic-recent-on@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Category/ic-recent.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Category/ic-recent.png new file mode 100644 index 0000000..6a1887b Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Category/ic-recent.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Category/ic-recent@2x.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Category/ic-recent@2x.png new file mode 100644 index 0000000..bcd520d Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Category/ic-recent@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-back-on.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-back-on.png new file mode 100644 index 0000000..4e01247 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-back-on.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-back-on@2x.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-back-on@2x.png new file mode 100644 index 0000000..05e34ba Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-back-on@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-back.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-back.png new file mode 100644 index 0000000..9ffc3fd Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-back.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-back@2x.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-back@2x.png new file mode 100644 index 0000000..1696bee Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-back@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-bundle-on.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-bundle-on.png new file mode 100644 index 0000000..592446e Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-bundle-on.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-bundle-on@2x.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-bundle-on@2x.png new file mode 100644 index 0000000..0cf2479 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-bundle-on@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-bundle.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-bundle.png new file mode 100644 index 0000000..f4807f0 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-bundle.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-bundle@2x.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-bundle@2x.png new file mode 100644 index 0000000..ee0ed3a Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-bundle@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-face-on.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-face-on.png new file mode 100644 index 0000000..7d1f252 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-face-on.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-face-on@2x.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-face-on@2x.png new file mode 100644 index 0000000..fef2fca Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-face-on@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-face.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-face.png new file mode 100644 index 0000000..18e058d Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-face.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-face@2x.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-face@2x.png new file mode 100644 index 0000000..42fff2e Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-face@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-front-on.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-front-on.png new file mode 100644 index 0000000..7ccda61 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-front-on.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-front-on@2x.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-front-on@2x.png new file mode 100644 index 0000000..f67a372 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-front-on@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-front.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-front.png new file mode 100644 index 0000000..3ef5286 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-front.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-front@2x.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-front@2x.png new file mode 100644 index 0000000..59b6c9c Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-front@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-gear-on.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-gear-on.png new file mode 100644 index 0000000..9c9dec9 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-gear-on.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-gear-on@2x.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-gear-on@2x.png new file mode 100644 index 0000000..7f5b302 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-gear-on@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-gear.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-gear.png new file mode 100644 index 0000000..902dfea Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-gear.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-gear@2x.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-gear@2x.png new file mode 100644 index 0000000..1a49bef Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-gear@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-hair-on.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-hair-on.png new file mode 100644 index 0000000..c8ec0c3 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-hair-on.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-hair-on@2x.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-hair-on@2x.png new file mode 100644 index 0000000..1bc870f Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-hair-on@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-hair.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-hair.png new file mode 100644 index 0000000..5fd0f0f Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-hair.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-hair@2x.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-hair@2x.png new file mode 100644 index 0000000..5ba6549 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-hair@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-hat-on.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-hat-on.png new file mode 100644 index 0000000..06f5e9e Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-hat-on.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-hat-on@2x.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-hat-on@2x.png new file mode 100644 index 0000000..74bb62c Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-hat-on@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-hat.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-hat.png new file mode 100644 index 0000000..da95ee8 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-hat.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-hat@2x.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-hat@2x.png new file mode 100644 index 0000000..284f82f Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-hat@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-neck-on.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-neck-on.png new file mode 100644 index 0000000..828d4b4 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-neck-on.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-neck-on@2x.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-neck-on@2x.png new file mode 100644 index 0000000..6f79fae Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-neck-on@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-neck.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-neck.png new file mode 100644 index 0000000..39bc0af Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-neck.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-neck@2x.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-neck@2x.png new file mode 100644 index 0000000..eb95b49 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-neck@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-pants-on.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-pants-on.png new file mode 100644 index 0000000..ad75422 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-pants-on.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-pants-on@2x.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-pants-on@2x.png new file mode 100644 index 0000000..5826d3c Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-pants-on@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-pants.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-pants.png new file mode 100644 index 0000000..07105ee Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-pants.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-pants@2x.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-pants@2x.png new file mode 100644 index 0000000..a4a09ec Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-pants@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-shirt-on.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-shirt-on.png new file mode 100644 index 0000000..ab81aa4 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-shirt-on.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-shirt-on@2x.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-shirt-on@2x.png new file mode 100644 index 0000000..ce05827 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-shirt-on@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-shirt.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-shirt.png new file mode 100644 index 0000000..ee0f4b7 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-shirt.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-shirt@2x.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-shirt@2x.png new file mode 100644 index 0000000..98a1a22 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-shirt@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-shoulder-on.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-shoulder-on.png new file mode 100644 index 0000000..6718a40 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-shoulder-on.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-shoulder-on@2x.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-shoulder-on@2x.png new file mode 100644 index 0000000..e2498fe Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-shoulder-on@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-shoulder.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-shoulder.png new file mode 100644 index 0000000..5e6e315 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-shoulder.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-shoulder@2x.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-shoulder@2x.png new file mode 100644 index 0000000..d766353 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-shoulder@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-tshirt-on.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-tshirt-on.png new file mode 100644 index 0000000..5d51286 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-tshirt-on.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-tshirt-on@2x.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-tshirt-on@2x.png new file mode 100644 index 0000000..3d66c50 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-tshirt-on@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-tshirt.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-tshirt.png new file mode 100644 index 0000000..d7217c9 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-tshirt.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-tshirt@2x.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-tshirt@2x.png new file mode 100644 index 0000000..ce5b39a Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-tshirt@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-waist-on.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-waist-on.png new file mode 100644 index 0000000..813a347 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-waist-on.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-waist-on@2x.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-waist-on@2x.png new file mode 100644 index 0000000..686e43b Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-waist-on@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-waist.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-waist.png new file mode 100644 index 0000000..747a369 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-waist.png differ diff --git a/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-waist@2x.png b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-waist@2x.png new file mode 100644 index 0000000..bc7af09 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/PageIcons/Clothing/ic-waist@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/Scaling/bar-empty-head.png b/2016/content/textures/AvatarEditorIcons/Scaling/bar-empty-head.png new file mode 100644 index 0000000..3a617fc Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/Scaling/bar-empty-head.png differ diff --git a/2016/content/textures/AvatarEditorIcons/Scaling/bar-empty-head@2x.png b/2016/content/textures/AvatarEditorIcons/Scaling/bar-empty-head@2x.png new file mode 100644 index 0000000..90f6a86 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/Scaling/bar-empty-head@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/Scaling/bar-empty-head@3x.png b/2016/content/textures/AvatarEditorIcons/Scaling/bar-empty-head@3x.png new file mode 100644 index 0000000..a381a6e Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/Scaling/bar-empty-head@3x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/Scaling/bar-empty-mid.png b/2016/content/textures/AvatarEditorIcons/Scaling/bar-empty-mid.png new file mode 100644 index 0000000..10484bc Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/Scaling/bar-empty-mid.png differ diff --git a/2016/content/textures/AvatarEditorIcons/Scaling/bar-empty-mid@2x.png b/2016/content/textures/AvatarEditorIcons/Scaling/bar-empty-mid@2x.png new file mode 100644 index 0000000..77f2a9e Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/Scaling/bar-empty-mid@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/Scaling/bar-empty-mid@3x.png b/2016/content/textures/AvatarEditorIcons/Scaling/bar-empty-mid@3x.png new file mode 100644 index 0000000..150de62 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/Scaling/bar-empty-mid@3x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/Scaling/bar-empty-tail.png b/2016/content/textures/AvatarEditorIcons/Scaling/bar-empty-tail.png new file mode 100644 index 0000000..30d8f9b Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/Scaling/bar-empty-tail.png differ diff --git a/2016/content/textures/AvatarEditorIcons/Scaling/bar-empty-tail@2x.png b/2016/content/textures/AvatarEditorIcons/Scaling/bar-empty-tail@2x.png new file mode 100644 index 0000000..89ebcc3 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/Scaling/bar-empty-tail@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/Scaling/bar-empty-tail@3x.png b/2016/content/textures/AvatarEditorIcons/Scaling/bar-empty-tail@3x.png new file mode 100644 index 0000000..b62de9f Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/Scaling/bar-empty-tail@3x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/Scaling/bar-full-head.png b/2016/content/textures/AvatarEditorIcons/Scaling/bar-full-head.png new file mode 100644 index 0000000..58bd777 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/Scaling/bar-full-head.png differ diff --git a/2016/content/textures/AvatarEditorIcons/Scaling/bar-full-head@2x.png b/2016/content/textures/AvatarEditorIcons/Scaling/bar-full-head@2x.png new file mode 100644 index 0000000..4dda0a0 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/Scaling/bar-full-head@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/Scaling/bar-full-head@3x.png b/2016/content/textures/AvatarEditorIcons/Scaling/bar-full-head@3x.png new file mode 100644 index 0000000..bab795a Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/Scaling/bar-full-head@3x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/Scaling/bar-full-mid.png b/2016/content/textures/AvatarEditorIcons/Scaling/bar-full-mid.png new file mode 100644 index 0000000..a5bbb4d Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/Scaling/bar-full-mid.png differ diff --git a/2016/content/textures/AvatarEditorIcons/Scaling/bar-full-mid@2x.png b/2016/content/textures/AvatarEditorIcons/Scaling/bar-full-mid@2x.png new file mode 100644 index 0000000..21bd8f2 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/Scaling/bar-full-mid@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/Scaling/bar-full-mid@3x.png b/2016/content/textures/AvatarEditorIcons/Scaling/bar-full-mid@3x.png new file mode 100644 index 0000000..53e8674 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/Scaling/bar-full-mid@3x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/Scaling/bar-full-tail.png b/2016/content/textures/AvatarEditorIcons/Scaling/bar-full-tail.png new file mode 100644 index 0000000..20db4ad Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/Scaling/bar-full-tail.png differ diff --git a/2016/content/textures/AvatarEditorIcons/Scaling/bar-full-tail@2x.png b/2016/content/textures/AvatarEditorIcons/Scaling/bar-full-tail@2x.png new file mode 100644 index 0000000..4edf579 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/Scaling/bar-full-tail@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/Scaling/bar-full-tail@3x.png b/2016/content/textures/AvatarEditorIcons/Scaling/bar-full-tail@3x.png new file mode 100644 index 0000000..6f6d0b3 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/Scaling/bar-full-tail@3x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/Scaling/dragger-highlight.png b/2016/content/textures/AvatarEditorIcons/Scaling/dragger-highlight.png new file mode 100644 index 0000000..9418d5d Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/Scaling/dragger-highlight.png differ diff --git a/2016/content/textures/AvatarEditorIcons/Scaling/dragger-highlight@2x.png b/2016/content/textures/AvatarEditorIcons/Scaling/dragger-highlight@2x.png new file mode 100644 index 0000000..1cea038 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/Scaling/dragger-highlight@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/Scaling/dragger-highlight@3x.png b/2016/content/textures/AvatarEditorIcons/Scaling/dragger-highlight@3x.png new file mode 100644 index 0000000..6b17fe4 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/Scaling/dragger-highlight@3x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/Scaling/dragger.png b/2016/content/textures/AvatarEditorIcons/Scaling/dragger.png new file mode 100644 index 0000000..e5e8d55 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/Scaling/dragger.png differ diff --git a/2016/content/textures/AvatarEditorIcons/Scaling/dragger@2x.png b/2016/content/textures/AvatarEditorIcons/Scaling/dragger@2x.png new file mode 100644 index 0000000..17a10b6 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/Scaling/dragger@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/Scaling/dragger@3x.png b/2016/content/textures/AvatarEditorIcons/Scaling/dragger@3x.png new file mode 100644 index 0000000..1ea04a6 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/Scaling/dragger@3x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ic-avatareditor-filled.png b/2016/content/textures/AvatarEditorIcons/ic-avatareditor-filled.png new file mode 100644 index 0000000..bd7e834 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ic-avatareditor-filled.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ic-avatareditor.png b/2016/content/textures/AvatarEditorIcons/ic-avatareditor.png new file mode 100644 index 0000000..a7282db Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ic-avatareditor.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ic-back-white.png b/2016/content/textures/AvatarEditorIcons/ic-back-white.png new file mode 100644 index 0000000..ed596f2 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ic-back-white.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ic-back.png b/2016/content/textures/AvatarEditorIcons/ic-back.png new file mode 100644 index 0000000..81f2ef0 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ic-back.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ic-bundle-white.png b/2016/content/textures/AvatarEditorIcons/ic-bundle-white.png new file mode 100644 index 0000000..ec710f2 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ic-bundle-white.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ic-bundle.png b/2016/content/textures/AvatarEditorIcons/ic-bundle.png new file mode 100644 index 0000000..2cf7e31 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ic-bundle.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ic-close-white.png b/2016/content/textures/AvatarEditorIcons/ic-close-white.png new file mode 100644 index 0000000..3e4cce9 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ic-close-white.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ic-close.png b/2016/content/textures/AvatarEditorIcons/ic-close.png new file mode 100644 index 0000000..39e4de4 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ic-close.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ic-color-filled.png b/2016/content/textures/AvatarEditorIcons/ic-color-filled.png new file mode 100644 index 0000000..3a19dc6 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ic-color-filled.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ic-color.png b/2016/content/textures/AvatarEditorIcons/ic-color.png new file mode 100644 index 0000000..94de27b Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ic-color.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ic-download.png b/2016/content/textures/AvatarEditorIcons/ic-download.png new file mode 100644 index 0000000..3296f06 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ic-download.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ic-face-white.png b/2016/content/textures/AvatarEditorIcons/ic-face-white.png new file mode 100644 index 0000000..ffd6b64 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ic-face-white.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ic-face.png b/2016/content/textures/AvatarEditorIcons/ic-face.png new file mode 100644 index 0000000..dc6ce84 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ic-face.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ic-gear-white.png b/2016/content/textures/AvatarEditorIcons/ic-gear-white.png new file mode 100644 index 0000000..992a918 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ic-gear-white.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ic-gear.png b/2016/content/textures/AvatarEditorIcons/ic-gear.png new file mode 100644 index 0000000..d4a5047 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ic-gear.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ic-hat-gray4.png b/2016/content/textures/AvatarEditorIcons/ic-hat-gray4.png new file mode 100644 index 0000000..0c9f03f Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ic-hat-gray4.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ic-hat-white.png b/2016/content/textures/AvatarEditorIcons/ic-hat-white.png new file mode 100644 index 0000000..0b7f584 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ic-hat-white.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ic-hat.png b/2016/content/textures/AvatarEditorIcons/ic-hat.png new file mode 100644 index 0000000..7d71cf2 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ic-hat.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ic-head-white.png b/2016/content/textures/AvatarEditorIcons/ic-head-white.png new file mode 100644 index 0000000..fee4f7e Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ic-head-white.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ic-head.png b/2016/content/textures/AvatarEditorIcons/ic-head.png new file mode 100644 index 0000000..5cd6926 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ic-head.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ic-history-white.png b/2016/content/textures/AvatarEditorIcons/ic-history-white.png new file mode 100644 index 0000000..f7fdbff Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ic-history-white.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ic-history.png b/2016/content/textures/AvatarEditorIcons/ic-history.png new file mode 100644 index 0000000..569cf03 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ic-history.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ic-leftarm-white.png b/2016/content/textures/AvatarEditorIcons/ic-leftarm-white.png new file mode 100644 index 0000000..dc58ea8 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ic-leftarm-white.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ic-leftarm.png b/2016/content/textures/AvatarEditorIcons/ic-leftarm.png new file mode 100644 index 0000000..9b1f4f6 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ic-leftarm.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ic-leftleg-white.png b/2016/content/textures/AvatarEditorIcons/ic-leftleg-white.png new file mode 100644 index 0000000..b39a1a8 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ic-leftleg-white.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ic-leftleg.png b/2016/content/textures/AvatarEditorIcons/ic-leftleg.png new file mode 100644 index 0000000..60ee918 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ic-leftleg.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ic-pant-white.png b/2016/content/textures/AvatarEditorIcons/ic-pant-white.png new file mode 100644 index 0000000..54b9dc4 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ic-pant-white.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ic-pant.png b/2016/content/textures/AvatarEditorIcons/ic-pant.png new file mode 100644 index 0000000..44442df Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ic-pant.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ic-rewind.png b/2016/content/textures/AvatarEditorIcons/ic-rewind.png new file mode 100644 index 0000000..f284a20 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ic-rewind.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ic-rightarm-white.png b/2016/content/textures/AvatarEditorIcons/ic-rightarm-white.png new file mode 100644 index 0000000..aa8ef6a Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ic-rightarm-white.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ic-rightarm.png b/2016/content/textures/AvatarEditorIcons/ic-rightarm.png new file mode 100644 index 0000000..f49246e Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ic-rightarm.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ic-rightleg-white.png b/2016/content/textures/AvatarEditorIcons/ic-rightleg-white.png new file mode 100644 index 0000000..22c8603 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ic-rightleg-white.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ic-rightleg.png b/2016/content/textures/AvatarEditorIcons/ic-rightleg.png new file mode 100644 index 0000000..64c3223 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ic-rightleg.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ic-robux-filled.png b/2016/content/textures/AvatarEditorIcons/ic-robux-filled.png new file mode 100644 index 0000000..ce91ea6 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ic-robux-filled.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ic-robux.png b/2016/content/textures/AvatarEditorIcons/ic-robux.png new file mode 100644 index 0000000..af668dd Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ic-robux.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ic-scale-filled.png b/2016/content/textures/AvatarEditorIcons/ic-scale-filled.png new file mode 100644 index 0000000..1f500c6 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ic-scale-filled.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ic-scale-filled@2x.png b/2016/content/textures/AvatarEditorIcons/ic-scale-filled@2x.png new file mode 100644 index 0000000..60960c3 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ic-scale-filled@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ic-scale.png b/2016/content/textures/AvatarEditorIcons/ic-scale.png new file mode 100644 index 0000000..3dd09f3 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ic-scale.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ic-scale@2x.png b/2016/content/textures/AvatarEditorIcons/ic-scale@2x.png new file mode 100644 index 0000000..6960e31 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ic-scale@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ic-search.png b/2016/content/textures/AvatarEditorIcons/ic-search.png new file mode 100644 index 0000000..ccb38bb Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ic-search.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ic-star-filled.png b/2016/content/textures/AvatarEditorIcons/ic-star-filled.png new file mode 100644 index 0000000..c94565b Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ic-star-filled.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ic-star.png b/2016/content/textures/AvatarEditorIcons/ic-star.png new file mode 100644 index 0000000..8d079d9 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ic-star.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ic-tee-white.png b/2016/content/textures/AvatarEditorIcons/ic-tee-white.png new file mode 100644 index 0000000..649d856 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ic-tee-white.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ic-tee.png b/2016/content/textures/AvatarEditorIcons/ic-tee.png new file mode 100644 index 0000000..7081f0a Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ic-tee.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ic-torso-white.png b/2016/content/textures/AvatarEditorIcons/ic-torso-white.png new file mode 100644 index 0000000..d507163 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ic-torso-white.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ic-torso.png b/2016/content/textures/AvatarEditorIcons/ic-torso.png new file mode 100644 index 0000000..1668e7e Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ic-torso.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ic-tshirt-white.png b/2016/content/textures/AvatarEditorIcons/ic-tshirt-white.png new file mode 100644 index 0000000..cad415c Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ic-tshirt-white.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ic-tshirt.png b/2016/content/textures/AvatarEditorIcons/ic-tshirt.png new file mode 100644 index 0000000..f86d4c3 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ic-tshirt.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ingame/btn-expand.png b/2016/content/textures/AvatarEditorIcons/ingame/btn-expand.png new file mode 100644 index 0000000..f8b815a Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ingame/btn-expand.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ingame/gr-card corner.png b/2016/content/textures/AvatarEditorIcons/ingame/gr-card corner.png new file mode 100644 index 0000000..21ee3f9 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ingame/gr-card corner.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ingame/gr-card corner@2x.png b/2016/content/textures/AvatarEditorIcons/ingame/gr-card corner@2x.png new file mode 100644 index 0000000..dc30616 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ingame/gr-card corner@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ingame/gr-category-selector.png b/2016/content/textures/AvatarEditorIcons/ingame/gr-category-selector.png new file mode 100644 index 0000000..ca2d139 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ingame/gr-category-selector.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ingame/gr-category-selector@2x.png b/2016/content/textures/AvatarEditorIcons/ingame/gr-category-selector@2x.png new file mode 100644 index 0000000..9e2794c Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ingame/gr-category-selector@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ingame/gr-corner.png b/2016/content/textures/AvatarEditorIcons/ingame/gr-corner.png new file mode 100644 index 0000000..8f52f73 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ingame/gr-corner.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ingame/gr-half-circle.png b/2016/content/textures/AvatarEditorIcons/ingame/gr-half-circle.png new file mode 100644 index 0000000..b47e912 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ingame/gr-half-circle.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ingame/gr-half-circle@2x.png b/2016/content/textures/AvatarEditorIcons/ingame/gr-half-circle@2x.png new file mode 100644 index 0000000..6ac7879 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ingame/gr-half-circle@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ingame/gr-orange-circle.png b/2016/content/textures/AvatarEditorIcons/ingame/gr-orange-circle.png new file mode 100644 index 0000000..e835c71 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ingame/gr-orange-circle.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ingame/gr-orange-circle@2x.png b/2016/content/textures/AvatarEditorIcons/ingame/gr-orange-circle@2x.png new file mode 100644 index 0000000..909cd07 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ingame/gr-orange-circle@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ingame/gr-ring01.png b/2016/content/textures/AvatarEditorIcons/ingame/gr-ring01.png new file mode 100644 index 0000000..6b18c18 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ingame/gr-ring01.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ingame/gr-ring01@2x.png b/2016/content/textures/AvatarEditorIcons/ingame/gr-ring01@2x.png new file mode 100644 index 0000000..0b8b5ef Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ingame/gr-ring01@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ingame/gr-tail.png b/2016/content/textures/AvatarEditorIcons/ingame/gr-tail.png new file mode 100644 index 0000000..6883f42 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ingame/gr-tail.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ingame/gr-tail@2x.png b/2016/content/textures/AvatarEditorIcons/ingame/gr-tail@2x.png new file mode 100644 index 0000000..f432203 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ingame/gr-tail@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ingame/gra-toggle-button.png b/2016/content/textures/AvatarEditorIcons/ingame/gra-toggle-button.png new file mode 100644 index 0000000..787a890 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ingame/gra-toggle-button.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ingame/gra-toggle-button@2x.png b/2016/content/textures/AvatarEditorIcons/ingame/gra-toggle-button@2x.png new file mode 100644 index 0000000..8c1f33b Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ingame/gra-toggle-button@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ingame/gra-toggle-frame.png b/2016/content/textures/AvatarEditorIcons/ingame/gra-toggle-frame.png new file mode 100644 index 0000000..d0e9f5e Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ingame/gra-toggle-frame.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ingame/gra-toggle-frame@2x.png b/2016/content/textures/AvatarEditorIcons/ingame/gra-toggle-frame@2x.png new file mode 100644 index 0000000..61eca73 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ingame/gra-toggle-frame@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ingame/ic-back-white.png b/2016/content/textures/AvatarEditorIcons/ingame/ic-back-white.png new file mode 100644 index 0000000..8b28084 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ingame/ic-back-white.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ingame/ic-back-white@2x.png b/2016/content/textures/AvatarEditorIcons/ingame/ic-back-white@2x.png new file mode 100644 index 0000000..a15f877 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ingame/ic-back-white@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ingame/ic-close.png b/2016/content/textures/AvatarEditorIcons/ingame/ic-close.png new file mode 100644 index 0000000..288d2bc Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ingame/ic-close.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ingame/ic-close@2x.png b/2016/content/textures/AvatarEditorIcons/ingame/ic-close@2x.png new file mode 100644 index 0000000..cea10e9 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ingame/ic-close@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ingame/ic-up-black.png b/2016/content/textures/AvatarEditorIcons/ingame/ic-up-black.png new file mode 100644 index 0000000..16bf1ed Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ingame/ic-up-black.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ingame/ic-up-black@2x.png b/2016/content/textures/AvatarEditorIcons/ingame/ic-up-black@2x.png new file mode 100644 index 0000000..9af58dc Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ingame/ic-up-black@2x.png differ diff --git a/2016/content/textures/AvatarEditorIcons/ingame/img-selector-box.png b/2016/content/textures/AvatarEditorIcons/ingame/img-selector-box.png new file mode 100644 index 0000000..4cc5f53 Binary files /dev/null and b/2016/content/textures/AvatarEditorIcons/ingame/img-selector-box.png differ diff --git a/2016/content/textures/BWGradient.png b/2016/content/textures/BWGradient.png new file mode 100644 index 0000000..0a5edb5 Binary files /dev/null and b/2016/content/textures/BWGradient.png differ diff --git a/2016/content/textures/BackgroundImage.png b/2016/content/textures/BackgroundImage.png new file mode 100644 index 0000000..9f76324 Binary files /dev/null and b/2016/content/textures/BackgroundImage.png differ diff --git a/2016/content/textures/Blank.png b/2016/content/textures/Blank.png new file mode 100644 index 0000000..d8860f6 Binary files /dev/null and b/2016/content/textures/Blank.png differ diff --git a/2016/content/textures/Clone.png b/2016/content/textures/Clone.png new file mode 100644 index 0000000..31915a9 Binary files /dev/null and b/2016/content/textures/Clone.png differ diff --git a/2016/content/textures/CloneCursor.png b/2016/content/textures/CloneCursor.png new file mode 100644 index 0000000..afe32c0 Binary files /dev/null and b/2016/content/textures/CloneCursor.png differ diff --git a/2016/content/textures/CloneDownCursor.png b/2016/content/textures/CloneDownCursor.png new file mode 100644 index 0000000..b33240d Binary files /dev/null and b/2016/content/textures/CloneDownCursor.png differ diff --git a/2016/content/textures/CloneOverCursor.png b/2016/content/textures/CloneOverCursor.png new file mode 100644 index 0000000..5c97ee1 Binary files /dev/null and b/2016/content/textures/CloneOverCursor.png differ diff --git a/2016/content/textures/ConstraintCursor.png b/2016/content/textures/ConstraintCursor.png new file mode 100644 index 0000000..d7af8ef Binary files /dev/null and b/2016/content/textures/ConstraintCursor.png differ diff --git a/2016/content/textures/Cursors/Gamepad/Pointer.png b/2016/content/textures/Cursors/Gamepad/Pointer.png new file mode 100644 index 0000000..d14627c Binary files /dev/null and b/2016/content/textures/Cursors/Gamepad/Pointer.png differ diff --git a/2016/content/textures/Cursors/Gamepad/Pointer@2x.png b/2016/content/textures/Cursors/Gamepad/Pointer@2x.png new file mode 100644 index 0000000..cd8c978 Binary files /dev/null and b/2016/content/textures/Cursors/Gamepad/Pointer@2x.png differ diff --git a/2016/content/textures/Cursors/Gamepad/PointerOver.png b/2016/content/textures/Cursors/Gamepad/PointerOver.png new file mode 100644 index 0000000..61fee5d Binary files /dev/null and b/2016/content/textures/Cursors/Gamepad/PointerOver.png differ diff --git a/2016/content/textures/Cursors/Gamepad/PointerOver@2x.png b/2016/content/textures/Cursors/Gamepad/PointerOver@2x.png new file mode 100644 index 0000000..54f37cc Binary files /dev/null and b/2016/content/textures/Cursors/Gamepad/PointerOver@2x.png differ diff --git a/2016/content/textures/DialogHelp.png b/2016/content/textures/DialogHelp.png new file mode 100644 index 0000000..073e3b7 Binary files /dev/null and b/2016/content/textures/DialogHelp.png differ diff --git a/2016/content/textures/DialogQuest.png b/2016/content/textures/DialogQuest.png new file mode 100644 index 0000000..0eb475c Binary files /dev/null and b/2016/content/textures/DialogQuest.png differ diff --git a/2016/content/textures/DialogShop.png b/2016/content/textures/DialogShop.png new file mode 100644 index 0000000..5e5d503 Binary files /dev/null and b/2016/content/textures/DialogShop.png differ diff --git a/2016/content/textures/DragCursor.png b/2016/content/textures/DragCursor.png new file mode 100644 index 0000000..a8f1894 Binary files /dev/null and b/2016/content/textures/DragCursor.png differ diff --git a/2016/content/textures/DropperCursor.png b/2016/content/textures/DropperCursor.png new file mode 100644 index 0000000..d98bcb6 Binary files /dev/null and b/2016/content/textures/DropperCursor.png differ diff --git a/2016/content/textures/Exit.png b/2016/content/textures/Exit.png new file mode 100644 index 0000000..523d2c5 Binary files /dev/null and b/2016/content/textures/Exit.png differ diff --git a/2016/content/textures/Exit_dn.png b/2016/content/textures/Exit_dn.png new file mode 100644 index 0000000..b2359c5 Binary files /dev/null and b/2016/content/textures/Exit_dn.png differ diff --git a/2016/content/textures/Exit_ovr.png b/2016/content/textures/Exit_ovr.png new file mode 100644 index 0000000..b2359c5 Binary files /dev/null and b/2016/content/textures/Exit_ovr.png differ diff --git a/2016/content/textures/FillCursor.png b/2016/content/textures/FillCursor.png new file mode 100644 index 0000000..752cebc Binary files /dev/null and b/2016/content/textures/FillCursor.png differ diff --git a/2016/content/textures/FlagCursor.png b/2016/content/textures/FlagCursor.png new file mode 100644 index 0000000..59c3798 Binary files /dev/null and b/2016/content/textures/FlagCursor.png differ diff --git a/2016/content/textures/FlatCursor.png b/2016/content/textures/FlatCursor.png new file mode 100644 index 0000000..feba33a Binary files /dev/null and b/2016/content/textures/FlatCursor.png differ diff --git a/2016/content/textures/GrabCursor.png b/2016/content/textures/GrabCursor.png new file mode 100644 index 0000000..d411bae Binary files /dev/null and b/2016/content/textures/GrabCursor.png differ diff --git a/2016/content/textures/GrabRotateCursor.png b/2016/content/textures/GrabRotateCursor.png new file mode 100644 index 0000000..0cd0c13 Binary files /dev/null and b/2016/content/textures/GrabRotateCursor.png differ diff --git a/2016/content/textures/Grass_Texture.jpg b/2016/content/textures/Grass_Texture.jpg new file mode 100644 index 0000000..cd273dc Binary files /dev/null and b/2016/content/textures/Grass_Texture.jpg differ diff --git a/2016/content/textures/GunCursor.png b/2016/content/textures/GunCursor.png new file mode 100644 index 0000000..d1b6afc Binary files /dev/null and b/2016/content/textures/GunCursor.png differ diff --git a/2016/content/textures/GunWaitCursor.png b/2016/content/textures/GunWaitCursor.png new file mode 100644 index 0000000..0c812be Binary files /dev/null and b/2016/content/textures/GunWaitCursor.png differ diff --git a/2016/content/textures/HammerCursor.png b/2016/content/textures/HammerCursor.png new file mode 100644 index 0000000..ad2b622 Binary files /dev/null and b/2016/content/textures/HammerCursor.png differ diff --git a/2016/content/textures/HammerDownCursor.png b/2016/content/textures/HammerDownCursor.png new file mode 100644 index 0000000..cdbcfe2 Binary files /dev/null and b/2016/content/textures/HammerDownCursor.png differ diff --git a/2016/content/textures/HammerOverCursor.png b/2016/content/textures/HammerOverCursor.png new file mode 100644 index 0000000..4182d69 Binary files /dev/null and b/2016/content/textures/HammerOverCursor.png differ diff --git a/2016/content/textures/HingeCursor.png b/2016/content/textures/HingeCursor.png new file mode 100644 index 0000000..e507cd3 Binary files /dev/null and b/2016/content/textures/HingeCursor.png differ diff --git a/2016/content/textures/LockCursor.png b/2016/content/textures/LockCursor.png new file mode 100644 index 0000000..4c4c6b2 Binary files /dev/null and b/2016/content/textures/LockCursor.png differ diff --git a/2016/content/textures/MotorCursor.png b/2016/content/textures/MotorCursor.png new file mode 100644 index 0000000..c363ab6 Binary files /dev/null and b/2016/content/textures/MotorCursor.png differ diff --git a/2016/content/textures/MouseLockedCursor.png b/2016/content/textures/MouseLockedCursor.png new file mode 100644 index 0000000..c3b44db Binary files /dev/null and b/2016/content/textures/MouseLockedCursor.png differ diff --git a/2016/content/textures/ResizeCursor.png b/2016/content/textures/ResizeCursor.png new file mode 100644 index 0000000..e9e06f5 Binary files /dev/null and b/2016/content/textures/ResizeCursor.png differ diff --git a/2016/content/textures/Roblox-loading-glow.png b/2016/content/textures/Roblox-loading-glow.png new file mode 100644 index 0000000..bc757b1 Binary files /dev/null and b/2016/content/textures/Roblox-loading-glow.png differ diff --git a/2016/content/textures/Roblox-loading-glow@2x.png b/2016/content/textures/Roblox-loading-glow@2x.png new file mode 100644 index 0000000..a1107c4 Binary files /dev/null and b/2016/content/textures/Roblox-loading-glow@2x.png differ diff --git a/2016/content/textures/Roblox-loading.png b/2016/content/textures/Roblox-loading.png new file mode 100644 index 0000000..c4d13ae Binary files /dev/null and b/2016/content/textures/Roblox-loading.png differ diff --git a/2016/content/textures/Roblox-loading@2x.png b/2016/content/textures/Roblox-loading@2x.png new file mode 100644 index 0000000..0530a1a Binary files /dev/null and b/2016/content/textures/Roblox-loading@2x.png differ diff --git a/2016/content/textures/Roblox.bmp b/2016/content/textures/Roblox.bmp new file mode 100644 index 0000000..362aa34 Binary files /dev/null and b/2016/content/textures/Roblox.bmp differ diff --git a/2016/content/textures/RustGradient.png b/2016/content/textures/RustGradient.png new file mode 100644 index 0000000..0180253 Binary files /dev/null and b/2016/content/textures/RustGradient.png differ diff --git a/2016/content/textures/Smoke.png b/2016/content/textures/Smoke.png new file mode 100644 index 0000000..b86df5d Binary files /dev/null and b/2016/content/textures/Smoke.png differ diff --git a/2016/content/textures/SpawnCursor.png b/2016/content/textures/SpawnCursor.png new file mode 100644 index 0000000..37fb08e Binary files /dev/null and b/2016/content/textures/SpawnCursor.png differ diff --git a/2016/content/textures/SpawnLocation.png b/2016/content/textures/SpawnLocation.png new file mode 100644 index 0000000..049c2d3 Binary files /dev/null and b/2016/content/textures/SpawnLocation.png differ diff --git a/2016/content/textures/SurfacesDefault.png b/2016/content/textures/SurfacesDefault.png new file mode 100644 index 0000000..53b1505 Binary files /dev/null and b/2016/content/textures/SurfacesDefault.png differ diff --git a/2016/content/textures/UnAnchorCursor.png b/2016/content/textures/UnAnchorCursor.png new file mode 100644 index 0000000..fa4e9cb Binary files /dev/null and b/2016/content/textures/UnAnchorCursor.png differ diff --git a/2016/content/textures/UnlockCursor.png b/2016/content/textures/UnlockCursor.png new file mode 100644 index 0000000..052a07a Binary files /dev/null and b/2016/content/textures/UnlockCursor.png differ diff --git a/2016/content/textures/WeldCursor.png b/2016/content/textures/WeldCursor.png new file mode 100644 index 0000000..c2a4292 Binary files /dev/null and b/2016/content/textures/WeldCursor.png differ diff --git a/2016/content/textures/WhiteCircle.png b/2016/content/textures/WhiteCircle.png new file mode 100644 index 0000000..78f4075 Binary files /dev/null and b/2016/content/textures/WhiteCircle.png differ diff --git a/2016/content/textures/advClosed-hand-no-weld.png b/2016/content/textures/advClosed-hand-no-weld.png new file mode 100644 index 0000000..beb2fd4 Binary files /dev/null and b/2016/content/textures/advClosed-hand-no-weld.png differ diff --git a/2016/content/textures/advClosed-hand-weld.png b/2016/content/textures/advClosed-hand-weld.png new file mode 100644 index 0000000..b79d71b Binary files /dev/null and b/2016/content/textures/advClosed-hand-weld.png differ diff --git a/2016/content/textures/advClosed-hand.png b/2016/content/textures/advClosed-hand.png new file mode 100644 index 0000000..38fcea4 Binary files /dev/null and b/2016/content/textures/advClosed-hand.png differ diff --git a/2016/content/textures/advCursor-default.png b/2016/content/textures/advCursor-default.png new file mode 100644 index 0000000..58c115b Binary files /dev/null and b/2016/content/textures/advCursor-default.png differ diff --git a/2016/content/textures/advCursor-openedHand.png b/2016/content/textures/advCursor-openedHand.png new file mode 100644 index 0000000..c972e29 Binary files /dev/null and b/2016/content/textures/advCursor-openedHand.png differ diff --git a/2016/content/textures/advCursor-white.png b/2016/content/textures/advCursor-white.png new file mode 100644 index 0000000..8a68e4f Binary files /dev/null and b/2016/content/textures/advCursor-white.png differ diff --git a/2016/content/textures/advancedMove.png b/2016/content/textures/advancedMove.png new file mode 100644 index 0000000..da15757 Binary files /dev/null and b/2016/content/textures/advancedMove.png differ diff --git a/2016/content/textures/advancedMoveResize.png b/2016/content/textures/advancedMoveResize.png new file mode 100644 index 0000000..8b1264a Binary files /dev/null and b/2016/content/textures/advancedMoveResize.png differ diff --git a/2016/content/textures/advancedMove_joint.png b/2016/content/textures/advancedMove_joint.png new file mode 100644 index 0000000..17079e0 Binary files /dev/null and b/2016/content/textures/advancedMove_joint.png differ diff --git a/2016/content/textures/advancedMove_keysOnly.png b/2016/content/textures/advancedMove_keysOnly.png new file mode 100644 index 0000000..36eb233 Binary files /dev/null and b/2016/content/textures/advancedMove_keysOnly.png differ diff --git a/2016/content/textures/advancedMove_noJoint.png b/2016/content/textures/advancedMove_noJoint.png new file mode 100644 index 0000000..62752c4 Binary files /dev/null and b/2016/content/textures/advancedMove_noJoint.png differ diff --git a/2016/content/textures/blackBkg_round.png b/2016/content/textures/blackBkg_round.png new file mode 100644 index 0000000..7070a7c Binary files /dev/null and b/2016/content/textures/blackBkg_round.png differ diff --git a/2016/content/textures/blackBkg_square.png b/2016/content/textures/blackBkg_square.png new file mode 100644 index 0000000..dc97acf Binary files /dev/null and b/2016/content/textures/blackBkg_square.png differ diff --git a/2016/content/textures/chatBubble_botBlue_bkg.png b/2016/content/textures/chatBubble_botBlue_bkg.png new file mode 100644 index 0000000..9f0b008 Binary files /dev/null and b/2016/content/textures/chatBubble_botBlue_bkg.png differ diff --git a/2016/content/textures/chatBubble_botBlue_notify_bkg.png b/2016/content/textures/chatBubble_botBlue_notify_bkg.png new file mode 100644 index 0000000..0b03982 Binary files /dev/null and b/2016/content/textures/chatBubble_botBlue_notify_bkg.png differ diff --git a/2016/content/textures/chatBubble_botBlue_tail.png b/2016/content/textures/chatBubble_botBlue_tail.png new file mode 100644 index 0000000..316bc9d Binary files /dev/null and b/2016/content/textures/chatBubble_botBlue_tail.png differ diff --git a/2016/content/textures/chatBubble_botBlue_tailRight.png b/2016/content/textures/chatBubble_botBlue_tailRight.png new file mode 100644 index 0000000..da047a8 Binary files /dev/null and b/2016/content/textures/chatBubble_botBlue_tailRight.png differ diff --git a/2016/content/textures/chatBubble_botGreen_bkg.png b/2016/content/textures/chatBubble_botGreen_bkg.png new file mode 100644 index 0000000..e158c85 Binary files /dev/null and b/2016/content/textures/chatBubble_botGreen_bkg.png differ diff --git a/2016/content/textures/chatBubble_botGreen_notify_bkg.png b/2016/content/textures/chatBubble_botGreen_notify_bkg.png new file mode 100644 index 0000000..d0a0c47 Binary files /dev/null and b/2016/content/textures/chatBubble_botGreen_notify_bkg.png differ diff --git a/2016/content/textures/chatBubble_botGreen_tail.png b/2016/content/textures/chatBubble_botGreen_tail.png new file mode 100644 index 0000000..01e6a00 Binary files /dev/null and b/2016/content/textures/chatBubble_botGreen_tail.png differ diff --git a/2016/content/textures/chatBubble_botGreen_tailRight.png b/2016/content/textures/chatBubble_botGreen_tailRight.png new file mode 100644 index 0000000..8cd6293 Binary files /dev/null and b/2016/content/textures/chatBubble_botGreen_tailRight.png differ diff --git a/2016/content/textures/chatBubble_botRed_bkg.png b/2016/content/textures/chatBubble_botRed_bkg.png new file mode 100644 index 0000000..66e411f Binary files /dev/null and b/2016/content/textures/chatBubble_botRed_bkg.png differ diff --git a/2016/content/textures/chatBubble_botRed_notify_bkg.png b/2016/content/textures/chatBubble_botRed_notify_bkg.png new file mode 100644 index 0000000..e7376eb Binary files /dev/null and b/2016/content/textures/chatBubble_botRed_notify_bkg.png differ diff --git a/2016/content/textures/chatBubble_botRed_tail.png b/2016/content/textures/chatBubble_botRed_tail.png new file mode 100644 index 0000000..b29c2af Binary files /dev/null and b/2016/content/textures/chatBubble_botRed_tail.png differ diff --git a/2016/content/textures/chatBubble_botRed_tailRight.png b/2016/content/textures/chatBubble_botRed_tailRight.png new file mode 100644 index 0000000..1e39788 Binary files /dev/null and b/2016/content/textures/chatBubble_botRed_tailRight.png differ diff --git a/2016/content/textures/chatBubble_bot_notifyGray_dotDotDot.png b/2016/content/textures/chatBubble_bot_notifyGray_dotDotDot.png new file mode 100644 index 0000000..f5b017d Binary files /dev/null and b/2016/content/textures/chatBubble_bot_notifyGray_dotDotDot.png differ diff --git a/2016/content/textures/chatBubble_bot_notify_bang.png b/2016/content/textures/chatBubble_bot_notify_bang.png new file mode 100644 index 0000000..1ccef6c Binary files /dev/null and b/2016/content/textures/chatBubble_bot_notify_bang.png differ diff --git a/2016/content/textures/chatBubble_bot_notify_dotDotDot.png b/2016/content/textures/chatBubble_bot_notify_dotDotDot.png new file mode 100644 index 0000000..4318458 Binary files /dev/null and b/2016/content/textures/chatBubble_bot_notify_dotDotDot.png differ diff --git a/2016/content/textures/chatBubble_bot_notify_money.png b/2016/content/textures/chatBubble_bot_notify_money.png new file mode 100644 index 0000000..54f58c5 Binary files /dev/null and b/2016/content/textures/chatBubble_bot_notify_money.png differ diff --git a/2016/content/textures/chatBubble_bot_notify_question.png b/2016/content/textures/chatBubble_bot_notify_question.png new file mode 100644 index 0000000..0a91c4f Binary files /dev/null and b/2016/content/textures/chatBubble_bot_notify_question.png differ diff --git a/2016/content/textures/chatBubble_white_bkg.png b/2016/content/textures/chatBubble_white_bkg.png new file mode 100644 index 0000000..7e6648c Binary files /dev/null and b/2016/content/textures/chatBubble_white_bkg.png differ diff --git a/2016/content/textures/chatBubble_white_notify_bkg.png b/2016/content/textures/chatBubble_white_notify_bkg.png new file mode 100644 index 0000000..828e362 Binary files /dev/null and b/2016/content/textures/chatBubble_white_notify_bkg.png differ diff --git a/2016/content/textures/chatBubble_white_tail.png b/2016/content/textures/chatBubble_white_tail.png new file mode 100644 index 0000000..77d1bd4 Binary files /dev/null and b/2016/content/textures/chatBubble_white_tail.png differ diff --git a/2016/content/textures/dirt.jpg b/2016/content/textures/dirt.jpg new file mode 100644 index 0000000..05f5c94 Binary files /dev/null and b/2016/content/textures/dirt.jpg differ diff --git a/2016/content/textures/explosion.png b/2016/content/textures/explosion.png new file mode 100644 index 0000000..5124cb2 Binary files /dev/null and b/2016/content/textures/explosion.png differ diff --git a/2016/content/textures/face.png b/2016/content/textures/face.png new file mode 100644 index 0000000..e57e342 Binary files /dev/null and b/2016/content/textures/face.png differ diff --git a/2016/content/textures/fire_0.png b/2016/content/textures/fire_0.png new file mode 100644 index 0000000..bbada0f Binary files /dev/null and b/2016/content/textures/fire_0.png differ diff --git a/2016/content/textures/glow.png b/2016/content/textures/glow.png new file mode 100644 index 0000000..db4a99e Binary files /dev/null and b/2016/content/textures/glow.png differ diff --git a/2016/content/textures/gradient.png b/2016/content/textures/gradient.png new file mode 100644 index 0000000..4278521 Binary files /dev/null and b/2016/content/textures/gradient.png differ diff --git a/2016/content/textures/loading/cancelButton.png b/2016/content/textures/loading/cancelButton.png new file mode 100644 index 0000000..4020631 Binary files /dev/null and b/2016/content/textures/loading/cancelButton.png differ diff --git a/2016/content/textures/loading/darkLoadingTexture.png b/2016/content/textures/loading/darkLoadingTexture.png new file mode 100644 index 0000000..1cae38f Binary files /dev/null and b/2016/content/textures/loading/darkLoadingTexture.png differ diff --git a/2016/content/textures/loading/loadingCircle.png b/2016/content/textures/loading/loadingCircle.png new file mode 100644 index 0000000..aa1c650 Binary files /dev/null and b/2016/content/textures/loading/loadingCircle.png differ diff --git a/2016/content/textures/loading/loadingTexture.png b/2016/content/textures/loading/loadingTexture.png new file mode 100644 index 0000000..ba9b60d Binary files /dev/null and b/2016/content/textures/loading/loadingTexture.png differ diff --git a/2016/content/textures/loading/loadingvignette.png b/2016/content/textures/loading/loadingvignette.png new file mode 100644 index 0000000..1398ef7 Binary files /dev/null and b/2016/content/textures/loading/loadingvignette.png differ diff --git a/2016/content/textures/loading/robloxlogo.png b/2016/content/textures/loading/robloxlogo.png new file mode 100644 index 0000000..180233d Binary files /dev/null and b/2016/content/textures/loading/robloxlogo.png differ diff --git a/2016/content/textures/lua.png b/2016/content/textures/lua.png new file mode 100644 index 0000000..2791c43 Binary files /dev/null and b/2016/content/textures/lua.png differ diff --git a/2016/content/textures/meshPartFallback.png b/2016/content/textures/meshPartFallback.png new file mode 100644 index 0000000..f008be8 Binary files /dev/null and b/2016/content/textures/meshPartFallback.png differ diff --git a/2016/content/textures/particles/common_alpha.dds b/2016/content/textures/particles/common_alpha.dds new file mode 100644 index 0000000..2cc9c9c Binary files /dev/null and b/2016/content/textures/particles/common_alpha.dds differ diff --git a/2016/content/textures/particles/explosion01_core_alpha.png b/2016/content/textures/particles/explosion01_core_alpha.png new file mode 100644 index 0000000..2dbf12f Binary files /dev/null and b/2016/content/textures/particles/explosion01_core_alpha.png differ diff --git a/2016/content/textures/particles/explosion01_core_main.dds b/2016/content/textures/particles/explosion01_core_main.dds new file mode 100644 index 0000000..44fd908 Binary files /dev/null and b/2016/content/textures/particles/explosion01_core_main.dds differ diff --git a/2016/content/textures/particles/explosion01_implosion_color.png b/2016/content/textures/particles/explosion01_implosion_color.png new file mode 100644 index 0000000..385bed7 Binary files /dev/null and b/2016/content/textures/particles/explosion01_implosion_color.png differ diff --git a/2016/content/textures/particles/explosion01_implosion_main.dds b/2016/content/textures/particles/explosion01_implosion_main.dds new file mode 100644 index 0000000..a5bf1b5 Binary files /dev/null and b/2016/content/textures/particles/explosion01_implosion_main.dds differ diff --git a/2016/content/textures/particles/explosion01_shockwave_main.dds b/2016/content/textures/particles/explosion01_shockwave_main.dds new file mode 100644 index 0000000..7a30ca6 Binary files /dev/null and b/2016/content/textures/particles/explosion01_shockwave_main.dds differ diff --git a/2016/content/textures/particles/explosion01_smoke_alpha.dds b/2016/content/textures/particles/explosion01_smoke_alpha.dds new file mode 100644 index 0000000..99807c7 Binary files /dev/null and b/2016/content/textures/particles/explosion01_smoke_alpha.dds differ diff --git a/2016/content/textures/particles/explosion01_smoke_color_new.dds b/2016/content/textures/particles/explosion01_smoke_color_new.dds new file mode 100644 index 0000000..fd4df8f Binary files /dev/null and b/2016/content/textures/particles/explosion01_smoke_color_new.dds differ diff --git a/2016/content/textures/particles/explosion01_smoke_main.dds b/2016/content/textures/particles/explosion01_smoke_main.dds new file mode 100644 index 0000000..c37f99a Binary files /dev/null and b/2016/content/textures/particles/explosion01_smoke_main.dds differ diff --git a/2016/content/textures/particles/explosion_alpha.dds b/2016/content/textures/particles/explosion_alpha.dds new file mode 100644 index 0000000..add095f Binary files /dev/null and b/2016/content/textures/particles/explosion_alpha.dds differ diff --git a/2016/content/textures/particles/explosion_color.dds b/2016/content/textures/particles/explosion_color.dds new file mode 100644 index 0000000..f69e2cc Binary files /dev/null and b/2016/content/textures/particles/explosion_color.dds differ diff --git a/2016/content/textures/particles/fire_alpha.dds b/2016/content/textures/particles/fire_alpha.dds new file mode 100644 index 0000000..812a506 Binary files /dev/null and b/2016/content/textures/particles/fire_alpha.dds differ diff --git a/2016/content/textures/particles/fire_color.dds b/2016/content/textures/particles/fire_color.dds new file mode 100644 index 0000000..5d569ad Binary files /dev/null and b/2016/content/textures/particles/fire_color.dds differ diff --git a/2016/content/textures/particles/fire_main.dds b/2016/content/textures/particles/fire_main.dds new file mode 100644 index 0000000..bd398ae Binary files /dev/null and b/2016/content/textures/particles/fire_main.dds differ diff --git a/2016/content/textures/particles/fire_sparks_color.dds b/2016/content/textures/particles/fire_sparks_color.dds new file mode 100644 index 0000000..8876db1 Binary files /dev/null and b/2016/content/textures/particles/fire_sparks_color.dds differ diff --git a/2016/content/textures/particles/fire_sparks_main.dds b/2016/content/textures/particles/fire_sparks_main.dds new file mode 100644 index 0000000..4468e5a Binary files /dev/null and b/2016/content/textures/particles/fire_sparks_main.dds differ diff --git a/2016/content/textures/particles/forcefield_alpha.dds b/2016/content/textures/particles/forcefield_alpha.dds new file mode 100644 index 0000000..03fdac0 Binary files /dev/null and b/2016/content/textures/particles/forcefield_alpha.dds differ diff --git a/2016/content/textures/particles/forcefield_glow_alpha.dds b/2016/content/textures/particles/forcefield_glow_alpha.dds new file mode 100644 index 0000000..326310f Binary files /dev/null and b/2016/content/textures/particles/forcefield_glow_alpha.dds differ diff --git a/2016/content/textures/particles/forcefield_glow_color.dds b/2016/content/textures/particles/forcefield_glow_color.dds new file mode 100644 index 0000000..39dfb8e Binary files /dev/null and b/2016/content/textures/particles/forcefield_glow_color.dds differ diff --git a/2016/content/textures/particles/forcefield_glow_main.dds b/2016/content/textures/particles/forcefield_glow_main.dds new file mode 100644 index 0000000..d1a6472 Binary files /dev/null and b/2016/content/textures/particles/forcefield_glow_main.dds differ diff --git a/2016/content/textures/particles/forcefield_vortex_color.dds b/2016/content/textures/particles/forcefield_vortex_color.dds new file mode 100644 index 0000000..fe33e22 Binary files /dev/null and b/2016/content/textures/particles/forcefield_vortex_color.dds differ diff --git a/2016/content/textures/particles/forcefield_vortex_main.dds b/2016/content/textures/particles/forcefield_vortex_main.dds new file mode 100644 index 0000000..d67cf49 Binary files /dev/null and b/2016/content/textures/particles/forcefield_vortex_main.dds differ diff --git a/2016/content/textures/particles/legacy_fire_alpha_color.dds b/2016/content/textures/particles/legacy_fire_alpha_color.dds new file mode 100644 index 0000000..da0fb05 Binary files /dev/null and b/2016/content/textures/particles/legacy_fire_alpha_color.dds differ diff --git a/2016/content/textures/particles/smoke_color.dds b/2016/content/textures/particles/smoke_color.dds new file mode 100644 index 0000000..a4d0a4f Binary files /dev/null and b/2016/content/textures/particles/smoke_color.dds differ diff --git a/2016/content/textures/particles/smoke_main.dds b/2016/content/textures/particles/smoke_main.dds new file mode 100644 index 0000000..1aaef8d Binary files /dev/null and b/2016/content/textures/particles/smoke_main.dds differ diff --git a/2016/content/textures/particles/sparkles_color.dds b/2016/content/textures/particles/sparkles_color.dds new file mode 100644 index 0000000..4fd1f85 Binary files /dev/null and b/2016/content/textures/particles/sparkles_color.dds differ diff --git a/2016/content/textures/particles/sparkles_main.dds b/2016/content/textures/particles/sparkles_main.dds new file mode 100644 index 0000000..d1875fd Binary files /dev/null and b/2016/content/textures/particles/sparkles_main.dds differ diff --git a/2016/content/textures/roblox-logo.png b/2016/content/textures/roblox-logo.png new file mode 100644 index 0000000..cf5d0c2 Binary files /dev/null and b/2016/content/textures/roblox-logo.png differ diff --git a/2016/content/textures/rotationArrow.png b/2016/content/textures/rotationArrow.png new file mode 100644 index 0000000..427aa20 Binary files /dev/null and b/2016/content/textures/rotationArrow.png differ diff --git a/2016/content/textures/script.png b/2016/content/textures/script.png new file mode 100644 index 0000000..0f9ed4d Binary files /dev/null and b/2016/content/textures/script.png differ diff --git a/2016/content/textures/shadowmask.png b/2016/content/textures/shadowmask.png new file mode 100644 index 0000000..47ed550 Binary files /dev/null and b/2016/content/textures/shadowmask.png differ diff --git a/2016/content/textures/spark.png b/2016/content/textures/spark.png new file mode 100644 index 0000000..486f47c Binary files /dev/null and b/2016/content/textures/spark.png differ diff --git a/2016/content/textures/sparkle.png b/2016/content/textures/sparkle.png new file mode 100644 index 0000000..5fa5e2a Binary files /dev/null and b/2016/content/textures/sparkle.png differ diff --git a/2016/content/textures/transformFiveDegrees.png b/2016/content/textures/transformFiveDegrees.png new file mode 100644 index 0000000..542315f Binary files /dev/null and b/2016/content/textures/transformFiveDegrees.png differ diff --git a/2016/content/textures/transformNinetyDegrees.png b/2016/content/textures/transformNinetyDegrees.png new file mode 100644 index 0000000..8f6f8fe Binary files /dev/null and b/2016/content/textures/transformNinetyDegrees.png differ diff --git a/2016/content/textures/transformOneDegree.png b/2016/content/textures/transformOneDegree.png new file mode 100644 index 0000000..aa93f1e Binary files /dev/null and b/2016/content/textures/transformOneDegree.png differ diff --git a/2016/content/textures/transformTwentyTwoDegrees.png b/2016/content/textures/transformTwentyTwoDegrees.png new file mode 100644 index 0000000..cf9e6a1 Binary files /dev/null and b/2016/content/textures/transformTwentyTwoDegrees.png differ diff --git a/2016/content/textures/ui/Backpack/Backpack.png b/2016/content/textures/ui/Backpack/Backpack.png new file mode 100644 index 0000000..3aab561 Binary files /dev/null and b/2016/content/textures/ui/Backpack/Backpack.png differ diff --git a/2016/content/textures/ui/Backpack/Backpack@2x.png b/2016/content/textures/ui/Backpack/Backpack@2x.png new file mode 100644 index 0000000..c13f00b Binary files /dev/null and b/2016/content/textures/ui/Backpack/Backpack@2x.png differ diff --git a/2016/content/textures/ui/Backpack/Backpack_Down.png b/2016/content/textures/ui/Backpack/Backpack_Down.png new file mode 100644 index 0000000..c2f0fdd Binary files /dev/null and b/2016/content/textures/ui/Backpack/Backpack_Down.png differ diff --git a/2016/content/textures/ui/Backpack/Backpack_Down@2x.png b/2016/content/textures/ui/Backpack/Backpack_Down@2x.png new file mode 100644 index 0000000..56e9c4b Binary files /dev/null and b/2016/content/textures/ui/Backpack/Backpack_Down@2x.png differ diff --git a/2016/content/textures/ui/Backpack/ScrollDownArrow.png b/2016/content/textures/ui/Backpack/ScrollDownArrow.png new file mode 100644 index 0000000..00fdf63 Binary files /dev/null and b/2016/content/textures/ui/Backpack/ScrollDownArrow.png differ diff --git a/2016/content/textures/ui/Backpack/ScrollUpArrow.png b/2016/content/textures/ui/Backpack/ScrollUpArrow.png new file mode 100644 index 0000000..70be819 Binary files /dev/null and b/2016/content/textures/ui/Backpack/ScrollUpArrow.png differ diff --git a/2016/content/textures/ui/Backpack_Close.png b/2016/content/textures/ui/Backpack_Close.png new file mode 100644 index 0000000..ed2442b Binary files /dev/null and b/2016/content/textures/ui/Backpack_Close.png differ diff --git a/2016/content/textures/ui/Backpack_Close@2x.png b/2016/content/textures/ui/Backpack_Close@2x.png new file mode 100644 index 0000000..73098da Binary files /dev/null and b/2016/content/textures/ui/Backpack_Close@2x.png differ diff --git a/2016/content/textures/ui/Backpack_Open.png b/2016/content/textures/ui/Backpack_Open.png new file mode 100644 index 0000000..d6ddd0b Binary files /dev/null and b/2016/content/textures/ui/Backpack_Open.png differ diff --git a/2016/content/textures/ui/Backpack_Open@2x.png b/2016/content/textures/ui/Backpack_Open@2x.png new file mode 100644 index 0000000..d3a58cd Binary files /dev/null and b/2016/content/textures/ui/Backpack_Open@2x.png differ diff --git a/2016/content/textures/ui/ButtonLeft.png b/2016/content/textures/ui/ButtonLeft.png new file mode 100644 index 0000000..3ccafc8 Binary files /dev/null and b/2016/content/textures/ui/ButtonLeft.png differ diff --git a/2016/content/textures/ui/ButtonLeftDown.png b/2016/content/textures/ui/ButtonLeftDown.png new file mode 100644 index 0000000..a17d93c Binary files /dev/null and b/2016/content/textures/ui/ButtonLeftDown.png differ diff --git a/2016/content/textures/ui/ButtonRight.png b/2016/content/textures/ui/ButtonRight.png new file mode 100644 index 0000000..e6f3e3e Binary files /dev/null and b/2016/content/textures/ui/ButtonRight.png differ diff --git a/2016/content/textures/ui/ButtonRightDown.png b/2016/content/textures/ui/ButtonRightDown.png new file mode 100644 index 0000000..70f1bc7 Binary files /dev/null and b/2016/content/textures/ui/ButtonRightDown.png differ diff --git a/2016/content/textures/ui/Chat/Chat.png b/2016/content/textures/ui/Chat/Chat.png new file mode 100644 index 0000000..4a81845 Binary files /dev/null and b/2016/content/textures/ui/Chat/Chat.png differ diff --git a/2016/content/textures/ui/Chat/Chat@2x.png b/2016/content/textures/ui/Chat/Chat@2x.png new file mode 100644 index 0000000..52cdff1 Binary files /dev/null and b/2016/content/textures/ui/Chat/Chat@2x.png differ diff --git a/2016/content/textures/ui/Chat/ChatDown.png b/2016/content/textures/ui/Chat/ChatDown.png new file mode 100644 index 0000000..a8e354f Binary files /dev/null and b/2016/content/textures/ui/Chat/ChatDown.png differ diff --git a/2016/content/textures/ui/Chat/ChatDown@2x.png b/2016/content/textures/ui/Chat/ChatDown@2x.png new file mode 100644 index 0000000..1bc47fd Binary files /dev/null and b/2016/content/textures/ui/Chat/ChatDown@2x.png differ diff --git a/2016/content/textures/ui/Chat/MessageCounter.png b/2016/content/textures/ui/Chat/MessageCounter.png new file mode 100644 index 0000000..ad062c4 Binary files /dev/null and b/2016/content/textures/ui/Chat/MessageCounter.png differ diff --git a/2016/content/textures/ui/Chat/MessageCounter@2x.png b/2016/content/textures/ui/Chat/MessageCounter@2x.png new file mode 100644 index 0000000..d978e2e Binary files /dev/null and b/2016/content/textures/ui/Chat/MessageCounter@2x.png differ diff --git a/2016/content/textures/ui/Chat/ToggleChat.png b/2016/content/textures/ui/Chat/ToggleChat.png new file mode 100644 index 0000000..49a4eb1 Binary files /dev/null and b/2016/content/textures/ui/Chat/ToggleChat.png differ diff --git a/2016/content/textures/ui/Chat/ToggleChat@2x.png b/2016/content/textures/ui/Chat/ToggleChat@2x.png new file mode 100644 index 0000000..20bdca8 Binary files /dev/null and b/2016/content/textures/ui/Chat/ToggleChat@2x.png differ diff --git a/2016/content/textures/ui/Chat/ToggleChatDown.png b/2016/content/textures/ui/Chat/ToggleChatDown.png new file mode 100644 index 0000000..16c5acb Binary files /dev/null and b/2016/content/textures/ui/Chat/ToggleChatDown.png differ diff --git a/2016/content/textures/ui/Chat/ToggleChatDown@2x.png b/2016/content/textures/ui/Chat/ToggleChatDown@2x.png new file mode 100644 index 0000000..9f07a8d Binary files /dev/null and b/2016/content/textures/ui/Chat/ToggleChatDown@2x.png differ diff --git a/2016/content/textures/ui/Chat/VRChatBackground.png b/2016/content/textures/ui/Chat/VRChatBackground.png new file mode 100644 index 0000000..f98269a Binary files /dev/null and b/2016/content/textures/ui/Chat/VRChatBackground.png differ diff --git a/2016/content/textures/ui/CloneButton.png b/2016/content/textures/ui/CloneButton.png new file mode 100644 index 0000000..7e24cc6 Binary files /dev/null and b/2016/content/textures/ui/CloneButton.png differ diff --git a/2016/content/textures/ui/CloneButton_dn.png b/2016/content/textures/ui/CloneButton_dn.png new file mode 100644 index 0000000..adbfe60 Binary files /dev/null and b/2016/content/textures/ui/CloneButton_dn.png differ diff --git a/2016/content/textures/ui/CloseButton.png b/2016/content/textures/ui/CloseButton.png new file mode 100644 index 0000000..59d62c0 Binary files /dev/null and b/2016/content/textures/ui/CloseButton.png differ diff --git a/2016/content/textures/ui/CloseButton_dn.png b/2016/content/textures/ui/CloseButton_dn.png new file mode 100644 index 0000000..2a92663 Binary files /dev/null and b/2016/content/textures/ui/CloseButton_dn.png differ diff --git a/2016/content/textures/ui/Concrete.png b/2016/content/textures/ui/Concrete.png new file mode 100644 index 0000000..79ee458 Binary files /dev/null and b/2016/content/textures/ui/Concrete.png differ diff --git a/2016/content/textures/ui/CorrodedMetal.png b/2016/content/textures/ui/CorrodedMetal.png new file mode 100644 index 0000000..76483c7 Binary files /dev/null and b/2016/content/textures/ui/CorrodedMetal.png differ diff --git a/2016/content/textures/ui/DPadSheet.png b/2016/content/textures/ui/DPadSheet.png new file mode 100644 index 0000000..dbef643 Binary files /dev/null and b/2016/content/textures/ui/DPadSheet.png differ diff --git a/2016/content/textures/ui/DeleteButton.png b/2016/content/textures/ui/DeleteButton.png new file mode 100644 index 0000000..7f5757c Binary files /dev/null and b/2016/content/textures/ui/DeleteButton.png differ diff --git a/2016/content/textures/ui/DeleteButton_dn.png b/2016/content/textures/ui/DeleteButton_dn.png new file mode 100644 index 0000000..184a615 Binary files /dev/null and b/2016/content/textures/ui/DeleteButton_dn.png differ diff --git a/2016/content/textures/ui/DiamondPlate.png b/2016/content/textures/ui/DiamondPlate.png new file mode 100644 index 0000000..ad9d4d0 Binary files /dev/null and b/2016/content/textures/ui/DiamondPlate.png differ diff --git a/2016/content/textures/ui/ErrorIcon.png b/2016/content/textures/ui/ErrorIcon.png new file mode 100644 index 0000000..e69c486 Binary files /dev/null and b/2016/content/textures/ui/ErrorIcon.png differ diff --git a/2016/content/textures/ui/ErrorIconSmall.png b/2016/content/textures/ui/ErrorIconSmall.png new file mode 100644 index 0000000..16a49a7 Binary files /dev/null and b/2016/content/textures/ui/ErrorIconSmall.png differ diff --git a/2016/content/textures/ui/Foil.png b/2016/content/textures/ui/Foil.png new file mode 100644 index 0000000..7cf51fc Binary files /dev/null and b/2016/content/textures/ui/Foil.png differ diff --git a/2016/content/textures/ui/Gear.png b/2016/content/textures/ui/Gear.png new file mode 100644 index 0000000..de60a6a Binary files /dev/null and b/2016/content/textures/ui/Gear.png differ diff --git a/2016/content/textures/ui/Gear_dn.png b/2016/content/textures/ui/Gear_dn.png new file mode 100644 index 0000000..53c8366 Binary files /dev/null and b/2016/content/textures/ui/Gear_dn.png differ diff --git a/2016/content/textures/ui/Glue.png b/2016/content/textures/ui/Glue.png new file mode 100644 index 0000000..3ceed9c Binary files /dev/null and b/2016/content/textures/ui/Glue.png differ diff --git a/2016/content/textures/ui/Grass.png b/2016/content/textures/ui/Grass.png new file mode 100644 index 0000000..fd390c4 Binary files /dev/null and b/2016/content/textures/ui/Grass.png differ diff --git a/2016/content/textures/ui/GroupMoveButton.png b/2016/content/textures/ui/GroupMoveButton.png new file mode 100644 index 0000000..61a48b4 Binary files /dev/null and b/2016/content/textures/ui/GroupMoveButton.png differ diff --git a/2016/content/textures/ui/GroupMoveButton_dn.png b/2016/content/textures/ui/GroupMoveButton_dn.png new file mode 100644 index 0000000..7500d53 Binary files /dev/null and b/2016/content/textures/ui/GroupMoveButton_dn.png differ diff --git a/2016/content/textures/ui/Health-BKG-Center.png b/2016/content/textures/ui/Health-BKG-Center.png new file mode 100644 index 0000000..eb0f3a4 Binary files /dev/null and b/2016/content/textures/ui/Health-BKG-Center.png differ diff --git a/2016/content/textures/ui/Health-BKG-Center@2x.png b/2016/content/textures/ui/Health-BKG-Center@2x.png new file mode 100644 index 0000000..e875086 Binary files /dev/null and b/2016/content/textures/ui/Health-BKG-Center@2x.png differ diff --git a/2016/content/textures/ui/Health-BKG-Left-Cap.png b/2016/content/textures/ui/Health-BKG-Left-Cap.png new file mode 100644 index 0000000..4437d29 Binary files /dev/null and b/2016/content/textures/ui/Health-BKG-Left-Cap.png differ diff --git a/2016/content/textures/ui/Health-BKG-Left-Cap@2x.png b/2016/content/textures/ui/Health-BKG-Left-Cap@2x.png new file mode 100644 index 0000000..1f7c652 Binary files /dev/null and b/2016/content/textures/ui/Health-BKG-Left-Cap@2x.png differ diff --git a/2016/content/textures/ui/Health-BKG-Right-Cap.png b/2016/content/textures/ui/Health-BKG-Right-Cap.png new file mode 100644 index 0000000..12db34b Binary files /dev/null and b/2016/content/textures/ui/Health-BKG-Right-Cap.png differ diff --git a/2016/content/textures/ui/Health-BKG-Right-Cap@2x.png b/2016/content/textures/ui/Health-BKG-Right-Cap@2x.png new file mode 100644 index 0000000..49a0e50 Binary files /dev/null and b/2016/content/textures/ui/Health-BKG-Right-Cap@2x.png differ diff --git a/2016/content/textures/ui/Hinge.png b/2016/content/textures/ui/Hinge.png new file mode 100644 index 0000000..c2ab9c9 Binary files /dev/null and b/2016/content/textures/ui/Hinge.png differ diff --git a/2016/content/textures/ui/Ice.png b/2016/content/textures/ui/Ice.png new file mode 100644 index 0000000..e9d0a32 Binary files /dev/null and b/2016/content/textures/ui/Ice.png differ diff --git a/2016/content/textures/ui/Inlets.png b/2016/content/textures/ui/Inlets.png new file mode 100644 index 0000000..cac89e3 Binary files /dev/null and b/2016/content/textures/ui/Inlets.png differ diff --git a/2016/content/textures/ui/InsertButton.png b/2016/content/textures/ui/InsertButton.png new file mode 100644 index 0000000..4058f36 Binary files /dev/null and b/2016/content/textures/ui/InsertButton.png differ diff --git a/2016/content/textures/ui/InsertButton_dn.png b/2016/content/textures/ui/InsertButton_dn.png new file mode 100644 index 0000000..03e72b2 Binary files /dev/null and b/2016/content/textures/ui/InsertButton_dn.png differ diff --git a/2016/content/textures/ui/Keyboard/close_button_background.png b/2016/content/textures/ui/Keyboard/close_button_background.png new file mode 100644 index 0000000..3dc2d16 Binary files /dev/null and b/2016/content/textures/ui/Keyboard/close_button_background.png differ diff --git a/2016/content/textures/ui/Keyboard/close_button_icon.png b/2016/content/textures/ui/Keyboard/close_button_icon.png new file mode 100644 index 0000000..7c7df46 Binary files /dev/null and b/2016/content/textures/ui/Keyboard/close_button_icon.png differ diff --git a/2016/content/textures/ui/Keyboard/close_button_selection.png b/2016/content/textures/ui/Keyboard/close_button_selection.png new file mode 100644 index 0000000..3d1f9ac Binary files /dev/null and b/2016/content/textures/ui/Keyboard/close_button_selection.png differ diff --git a/2016/content/textures/ui/Keyboard/key_selection_9slice.png b/2016/content/textures/ui/Keyboard/key_selection_9slice.png new file mode 100644 index 0000000..e60de88 Binary files /dev/null and b/2016/content/textures/ui/Keyboard/key_selection_9slice.png differ diff --git a/2016/content/textures/ui/Keyboard/mic_icon.png b/2016/content/textures/ui/Keyboard/mic_icon.png new file mode 100644 index 0000000..7ada225 Binary files /dev/null and b/2016/content/textures/ui/Keyboard/mic_icon.png differ diff --git a/2016/content/textures/ui/LoadingBKG.png b/2016/content/textures/ui/LoadingBKG.png new file mode 100644 index 0000000..212468c Binary files /dev/null and b/2016/content/textures/ui/LoadingBKG.png differ diff --git a/2016/content/textures/ui/LoadingScreen/BackgroundDark.png b/2016/content/textures/ui/LoadingScreen/BackgroundDark.png new file mode 100644 index 0000000..2298e31 Binary files /dev/null and b/2016/content/textures/ui/LoadingScreen/BackgroundDark.png differ diff --git a/2016/content/textures/ui/LoadingScreen/BackgroundLight.png b/2016/content/textures/ui/LoadingScreen/BackgroundLight.png new file mode 100644 index 0000000..af930bb Binary files /dev/null and b/2016/content/textures/ui/LoadingScreen/BackgroundLight.png differ diff --git a/2016/content/textures/ui/LoadingScreen/LoadingSpinner.png b/2016/content/textures/ui/LoadingScreen/LoadingSpinner.png new file mode 100644 index 0000000..ef2623a Binary files /dev/null and b/2016/content/textures/ui/LoadingScreen/LoadingSpinner.png differ diff --git a/2016/content/textures/ui/MaterialButton.png b/2016/content/textures/ui/MaterialButton.png new file mode 100644 index 0000000..4191aab Binary files /dev/null and b/2016/content/textures/ui/MaterialButton.png differ diff --git a/2016/content/textures/ui/MaterialButton_dn.png b/2016/content/textures/ui/MaterialButton_dn.png new file mode 100644 index 0000000..d61978c Binary files /dev/null and b/2016/content/textures/ui/MaterialButton_dn.png differ diff --git a/2016/content/textures/ui/MaterialMenu.png b/2016/content/textures/ui/MaterialMenu.png new file mode 100644 index 0000000..c4a1c73 Binary files /dev/null and b/2016/content/textures/ui/MaterialMenu.png differ diff --git a/2016/content/textures/ui/Menu/Hamburger.png b/2016/content/textures/ui/Menu/Hamburger.png new file mode 100644 index 0000000..29520b8 Binary files /dev/null and b/2016/content/textures/ui/Menu/Hamburger.png differ diff --git a/2016/content/textures/ui/Menu/Hamburger@2x.png b/2016/content/textures/ui/Menu/Hamburger@2x.png new file mode 100644 index 0000000..e17c15f Binary files /dev/null and b/2016/content/textures/ui/Menu/Hamburger@2x.png differ diff --git a/2016/content/textures/ui/Menu/HamburgerDown.png b/2016/content/textures/ui/Menu/HamburgerDown.png new file mode 100644 index 0000000..6d4fe9c Binary files /dev/null and b/2016/content/textures/ui/Menu/HamburgerDown.png differ diff --git a/2016/content/textures/ui/Menu/HamburgerDown@2x.png b/2016/content/textures/ui/Menu/HamburgerDown@2x.png new file mode 100644 index 0000000..b788db9 Binary files /dev/null and b/2016/content/textures/ui/Menu/HamburgerDown@2x.png differ diff --git a/2016/content/textures/ui/Menu/buttonActive.png b/2016/content/textures/ui/Menu/buttonActive.png new file mode 100644 index 0000000..f812f35 Binary files /dev/null and b/2016/content/textures/ui/Menu/buttonActive.png differ diff --git a/2016/content/textures/ui/Menu/buttonBackground.png b/2016/content/textures/ui/Menu/buttonBackground.png new file mode 100644 index 0000000..9f402da Binary files /dev/null and b/2016/content/textures/ui/Menu/buttonBackground.png differ diff --git a/2016/content/textures/ui/Menu/buttonHover.png b/2016/content/textures/ui/Menu/buttonHover.png new file mode 100644 index 0000000..fb360d0 Binary files /dev/null and b/2016/content/textures/ui/Menu/buttonHover.png differ diff --git a/2016/content/textures/ui/Menu/hamburger3D.png b/2016/content/textures/ui/Menu/hamburger3D.png new file mode 100644 index 0000000..db81766 Binary files /dev/null and b/2016/content/textures/ui/Menu/hamburger3D.png differ diff --git a/2016/content/textures/ui/Menu/hoverPopupLeft.png b/2016/content/textures/ui/Menu/hoverPopupLeft.png new file mode 100644 index 0000000..317b2e1 Binary files /dev/null and b/2016/content/textures/ui/Menu/hoverPopupLeft.png differ diff --git a/2016/content/textures/ui/Menu/hoverPopupMid.png b/2016/content/textures/ui/Menu/hoverPopupMid.png new file mode 100644 index 0000000..fb8da3d Binary files /dev/null and b/2016/content/textures/ui/Menu/hoverPopupMid.png differ diff --git a/2016/content/textures/ui/Menu/hoverPopupRight.png b/2016/content/textures/ui/Menu/hoverPopupRight.png new file mode 100644 index 0000000..8266e24 Binary files /dev/null and b/2016/content/textures/ui/Menu/hoverPopupRight.png differ diff --git a/2016/content/textures/ui/Menu/rectBackground.png b/2016/content/textures/ui/Menu/rectBackground.png new file mode 100644 index 0000000..3e8bba8 Binary files /dev/null and b/2016/content/textures/ui/Menu/rectBackground.png differ diff --git a/2016/content/textures/ui/Menu/rectBackgroundWhite.png b/2016/content/textures/ui/Menu/rectBackgroundWhite.png new file mode 100644 index 0000000..f31ddf6 Binary files /dev/null and b/2016/content/textures/ui/Menu/rectBackgroundWhite.png differ diff --git a/2016/content/textures/ui/Modal.png b/2016/content/textures/ui/Modal.png new file mode 100644 index 0000000..ff98cf8 Binary files /dev/null and b/2016/content/textures/ui/Modal.png differ diff --git a/2016/content/textures/ui/Motor.png b/2016/content/textures/ui/Motor.png new file mode 100644 index 0000000..e9b63eb Binary files /dev/null and b/2016/content/textures/ui/Motor.png differ diff --git a/2016/content/textures/ui/PaintButton.png b/2016/content/textures/ui/PaintButton.png new file mode 100644 index 0000000..03b99a7 Binary files /dev/null and b/2016/content/textures/ui/PaintButton.png differ diff --git a/2016/content/textures/ui/PaintButton_dn.png b/2016/content/textures/ui/PaintButton_dn.png new file mode 100644 index 0000000..af4c64d Binary files /dev/null and b/2016/content/textures/ui/PaintButton_dn.png differ diff --git a/2016/content/textures/ui/PartMoveButton.png b/2016/content/textures/ui/PartMoveButton.png new file mode 100644 index 0000000..a8f8fce Binary files /dev/null and b/2016/content/textures/ui/PartMoveButton.png differ diff --git a/2016/content/textures/ui/PartMoveButton_dn.png b/2016/content/textures/ui/PartMoveButton_dn.png new file mode 100644 index 0000000..3c866db Binary files /dev/null and b/2016/content/textures/ui/PartMoveButton_dn.png differ diff --git a/2016/content/textures/ui/PerformanceStats/BackgroundRounded.png b/2016/content/textures/ui/PerformanceStats/BackgroundRounded.png new file mode 100644 index 0000000..48550b2 Binary files /dev/null and b/2016/content/textures/ui/PerformanceStats/BackgroundRounded.png differ diff --git a/2016/content/textures/ui/PerformanceStats/OvalKey.png b/2016/content/textures/ui/PerformanceStats/OvalKey.png new file mode 100644 index 0000000..417202c Binary files /dev/null and b/2016/content/textures/ui/PerformanceStats/OvalKey.png differ diff --git a/2016/content/textures/ui/PerformanceStats/TargetFiller.png b/2016/content/textures/ui/PerformanceStats/TargetFiller.png new file mode 100644 index 0000000..09ebe72 Binary files /dev/null and b/2016/content/textures/ui/PerformanceStats/TargetFiller.png differ diff --git a/2016/content/textures/ui/PerformanceStats/TargetKey.png b/2016/content/textures/ui/PerformanceStats/TargetKey.png new file mode 100644 index 0000000..33cd653 Binary files /dev/null and b/2016/content/textures/ui/PerformanceStats/TargetKey.png differ diff --git a/2016/content/textures/ui/PerformanceStats/TargetLine.png b/2016/content/textures/ui/PerformanceStats/TargetLine.png new file mode 100644 index 0000000..cfc8a4d Binary files /dev/null and b/2016/content/textures/ui/PerformanceStats/TargetLine.png differ diff --git a/2016/content/textures/ui/Plastic.png b/2016/content/textures/ui/Plastic.png new file mode 100644 index 0000000..8f8bbf3 Binary files /dev/null and b/2016/content/textures/ui/Plastic.png differ diff --git a/2016/content/textures/ui/PlayerList/BlockedIcon.png b/2016/content/textures/ui/PlayerList/BlockedIcon.png new file mode 100644 index 0000000..6505f14 Binary files /dev/null and b/2016/content/textures/ui/PlayerList/BlockedIcon.png differ diff --git a/2016/content/textures/ui/PlayerList/CharacterImageBackground.png b/2016/content/textures/ui/PlayerList/CharacterImageBackground.png new file mode 100644 index 0000000..624bc78 Binary files /dev/null and b/2016/content/textures/ui/PlayerList/CharacterImageBackground.png differ diff --git a/2016/content/textures/ui/PlayerList/TileShadowMissingTop.png b/2016/content/textures/ui/PlayerList/TileShadowMissingTop.png new file mode 100644 index 0000000..64b90fc Binary files /dev/null and b/2016/content/textures/ui/PlayerList/TileShadowMissingTop.png differ diff --git a/2016/content/textures/ui/PlayerListFriendRequestReceivedIcon.png b/2016/content/textures/ui/PlayerListFriendRequestReceivedIcon.png new file mode 100644 index 0000000..ab292da Binary files /dev/null and b/2016/content/textures/ui/PlayerListFriendRequestReceivedIcon.png differ diff --git a/2016/content/textures/ui/PlayerListFriendRequestSentIcon.png b/2016/content/textures/ui/PlayerListFriendRequestSentIcon.png new file mode 100644 index 0000000..e10634b Binary files /dev/null and b/2016/content/textures/ui/PlayerListFriendRequestSentIcon.png differ diff --git a/2016/content/textures/ui/PlayerlistFriendIcon.png b/2016/content/textures/ui/PlayerlistFriendIcon.png new file mode 100644 index 0000000..21619a5 Binary files /dev/null and b/2016/content/textures/ui/PlayerlistFriendIcon.png differ diff --git a/2016/content/textures/ui/PropertyButton.png b/2016/content/textures/ui/PropertyButton.png new file mode 100644 index 0000000..254e00d Binary files /dev/null and b/2016/content/textures/ui/PropertyButton.png differ diff --git a/2016/content/textures/ui/PropertyButton_dn.png b/2016/content/textures/ui/PropertyButton_dn.png new file mode 100644 index 0000000..c95ec8d Binary files /dev/null and b/2016/content/textures/ui/PropertyButton_dn.png differ diff --git a/2016/content/textures/ui/RecordDown.png b/2016/content/textures/ui/RecordDown.png new file mode 100644 index 0000000..0e815a2 Binary files /dev/null and b/2016/content/textures/ui/RecordDown.png differ diff --git a/2016/content/textures/ui/RecordStop.png b/2016/content/textures/ui/RecordStop.png new file mode 100644 index 0000000..6b86baf Binary files /dev/null and b/2016/content/textures/ui/RecordStop.png differ diff --git a/2016/content/textures/ui/ResetIcon.png b/2016/content/textures/ui/ResetIcon.png new file mode 100644 index 0000000..b9558d4 Binary files /dev/null and b/2016/content/textures/ui/ResetIcon.png differ diff --git a/2016/content/textures/ui/RobuxIcon.png b/2016/content/textures/ui/RobuxIcon.png new file mode 100644 index 0000000..ce39cb5 Binary files /dev/null and b/2016/content/textures/ui/RobuxIcon.png differ diff --git a/2016/content/textures/ui/ScaleButton.png b/2016/content/textures/ui/ScaleButton.png new file mode 100644 index 0000000..05ab151 Binary files /dev/null and b/2016/content/textures/ui/ScaleButton.png differ diff --git a/2016/content/textures/ui/ScaleButton_dn.png b/2016/content/textures/ui/ScaleButton_dn.png new file mode 100644 index 0000000..c5010fa Binary files /dev/null and b/2016/content/textures/ui/ScaleButton_dn.png differ diff --git a/2016/content/textures/ui/Scroll/scroll-bottom.png b/2016/content/textures/ui/Scroll/scroll-bottom.png new file mode 100644 index 0000000..74b6f8e Binary files /dev/null and b/2016/content/textures/ui/Scroll/scroll-bottom.png differ diff --git a/2016/content/textures/ui/Scroll/scroll-bottom@2x.png b/2016/content/textures/ui/Scroll/scroll-bottom@2x.png new file mode 100644 index 0000000..351081f Binary files /dev/null and b/2016/content/textures/ui/Scroll/scroll-bottom@2x.png differ diff --git a/2016/content/textures/ui/Scroll/scroll-middle.png b/2016/content/textures/ui/Scroll/scroll-middle.png new file mode 100644 index 0000000..0702f1e Binary files /dev/null and b/2016/content/textures/ui/Scroll/scroll-middle.png differ diff --git a/2016/content/textures/ui/Scroll/scroll-middle@2x.png b/2016/content/textures/ui/Scroll/scroll-middle@2x.png new file mode 100644 index 0000000..86ffc6f Binary files /dev/null and b/2016/content/textures/ui/Scroll/scroll-middle@2x.png differ diff --git a/2016/content/textures/ui/Scroll/scroll-top.png b/2016/content/textures/ui/Scroll/scroll-top.png new file mode 100644 index 0000000..dd426d1 Binary files /dev/null and b/2016/content/textures/ui/Scroll/scroll-top.png differ diff --git a/2016/content/textures/ui/Scroll/scroll-top@2x.png b/2016/content/textures/ui/Scroll/scroll-top@2x.png new file mode 100644 index 0000000..29f9243 Binary files /dev/null and b/2016/content/textures/ui/Scroll/scroll-top@2x.png differ diff --git a/2016/content/textures/ui/SearchIcon.png b/2016/content/textures/ui/SearchIcon.png new file mode 100644 index 0000000..d72741c Binary files /dev/null and b/2016/content/textures/ui/SearchIcon.png differ diff --git a/2016/content/textures/ui/SelectionBox.png b/2016/content/textures/ui/SelectionBox.png new file mode 100644 index 0000000..ab76dee Binary files /dev/null and b/2016/content/textures/ui/SelectionBox.png differ diff --git a/2016/content/textures/ui/SelectionBox@2x.png b/2016/content/textures/ui/SelectionBox@2x.png new file mode 100644 index 0000000..54621f5 Binary files /dev/null and b/2016/content/textures/ui/SelectionBox@2x.png differ diff --git a/2016/content/textures/ui/Settings/DropDown/DropDown.png b/2016/content/textures/ui/Settings/DropDown/DropDown.png new file mode 100644 index 0000000..6088030 Binary files /dev/null and b/2016/content/textures/ui/Settings/DropDown/DropDown.png differ diff --git a/2016/content/textures/ui/Settings/DropDown/DropDown@2x.png b/2016/content/textures/ui/Settings/DropDown/DropDown@2x.png new file mode 100644 index 0000000..0d82f2b Binary files /dev/null and b/2016/content/textures/ui/Settings/DropDown/DropDown@2x.png differ diff --git a/2016/content/textures/ui/Settings/Help/AButtonDark.png b/2016/content/textures/ui/Settings/Help/AButtonDark.png new file mode 100644 index 0000000..5b761d0 Binary files /dev/null and b/2016/content/textures/ui/Settings/Help/AButtonDark.png differ diff --git a/2016/content/textures/ui/Settings/Help/AButtonDark@2x.png b/2016/content/textures/ui/Settings/Help/AButtonDark@2x.png new file mode 100644 index 0000000..b913a96 Binary files /dev/null and b/2016/content/textures/ui/Settings/Help/AButtonDark@2x.png differ diff --git a/2016/content/textures/ui/Settings/Help/AButtonLight.png b/2016/content/textures/ui/Settings/Help/AButtonLight.png new file mode 100644 index 0000000..344af4c Binary files /dev/null and b/2016/content/textures/ui/Settings/Help/AButtonLight.png differ diff --git a/2016/content/textures/ui/Settings/Help/AButtonLight@2x.png b/2016/content/textures/ui/Settings/Help/AButtonLight@2x.png new file mode 100644 index 0000000..436be8e Binary files /dev/null and b/2016/content/textures/ui/Settings/Help/AButtonLight@2x.png differ diff --git a/2016/content/textures/ui/Settings/Help/AButtonLightSmall.png b/2016/content/textures/ui/Settings/Help/AButtonLightSmall.png new file mode 100644 index 0000000..5f95aa4 Binary files /dev/null and b/2016/content/textures/ui/Settings/Help/AButtonLightSmall.png differ diff --git a/2016/content/textures/ui/Settings/Help/BButtonDark.png b/2016/content/textures/ui/Settings/Help/BButtonDark.png new file mode 100644 index 0000000..f00a6db Binary files /dev/null and b/2016/content/textures/ui/Settings/Help/BButtonDark.png differ diff --git a/2016/content/textures/ui/Settings/Help/BButtonDark@2x.png b/2016/content/textures/ui/Settings/Help/BButtonDark@2x.png new file mode 100644 index 0000000..22d6007 Binary files /dev/null and b/2016/content/textures/ui/Settings/Help/BButtonDark@2x.png differ diff --git a/2016/content/textures/ui/Settings/Help/BButtonLight.png b/2016/content/textures/ui/Settings/Help/BButtonLight.png new file mode 100644 index 0000000..6314785 Binary files /dev/null and b/2016/content/textures/ui/Settings/Help/BButtonLight.png differ diff --git a/2016/content/textures/ui/Settings/Help/BButtonLight@2x.png b/2016/content/textures/ui/Settings/Help/BButtonLight@2x.png new file mode 100644 index 0000000..46737cf Binary files /dev/null and b/2016/content/textures/ui/Settings/Help/BButtonLight@2x.png differ diff --git a/2016/content/textures/ui/Settings/Help/EscapeIcon.png b/2016/content/textures/ui/Settings/Help/EscapeIcon.png new file mode 100644 index 0000000..e49636e Binary files /dev/null and b/2016/content/textures/ui/Settings/Help/EscapeIcon.png differ diff --git a/2016/content/textures/ui/Settings/Help/GenericController.png b/2016/content/textures/ui/Settings/Help/GenericController.png new file mode 100644 index 0000000..c92f1e1 Binary files /dev/null and b/2016/content/textures/ui/Settings/Help/GenericController.png differ diff --git a/2016/content/textures/ui/Settings/Help/GenericController@2x.png b/2016/content/textures/ui/Settings/Help/GenericController@2x.png new file mode 100644 index 0000000..3b82e31 Binary files /dev/null and b/2016/content/textures/ui/Settings/Help/GenericController@2x.png differ diff --git a/2016/content/textures/ui/Settings/Help/LeaveIcon.png b/2016/content/textures/ui/Settings/Help/LeaveIcon.png new file mode 100644 index 0000000..cbe8d88 Binary files /dev/null and b/2016/content/textures/ui/Settings/Help/LeaveIcon.png differ diff --git a/2016/content/textures/ui/Settings/Help/ResetIcon.png b/2016/content/textures/ui/Settings/Help/ResetIcon.png new file mode 100644 index 0000000..64fedc8 Binary files /dev/null and b/2016/content/textures/ui/Settings/Help/ResetIcon.png differ diff --git a/2016/content/textures/ui/Settings/Help/RotateCameraGesture.png b/2016/content/textures/ui/Settings/Help/RotateCameraGesture.png new file mode 100644 index 0000000..53fd54e Binary files /dev/null and b/2016/content/textures/ui/Settings/Help/RotateCameraGesture.png differ diff --git a/2016/content/textures/ui/Settings/Help/UseToolGesture.png b/2016/content/textures/ui/Settings/Help/UseToolGesture.png new file mode 100644 index 0000000..1e4124b Binary files /dev/null and b/2016/content/textures/ui/Settings/Help/UseToolGesture.png differ diff --git a/2016/content/textures/ui/Settings/Help/XButtonDark.png b/2016/content/textures/ui/Settings/Help/XButtonDark.png new file mode 100644 index 0000000..83e45cd Binary files /dev/null and b/2016/content/textures/ui/Settings/Help/XButtonDark.png differ diff --git a/2016/content/textures/ui/Settings/Help/XButtonDark@2x.png b/2016/content/textures/ui/Settings/Help/XButtonDark@2x.png new file mode 100644 index 0000000..cd15ff2 Binary files /dev/null and b/2016/content/textures/ui/Settings/Help/XButtonDark@2x.png differ diff --git a/2016/content/textures/ui/Settings/Help/XButtonLight.png b/2016/content/textures/ui/Settings/Help/XButtonLight.png new file mode 100644 index 0000000..fd294c8 Binary files /dev/null and b/2016/content/textures/ui/Settings/Help/XButtonLight.png differ diff --git a/2016/content/textures/ui/Settings/Help/XButtonLight@2x.png b/2016/content/textures/ui/Settings/Help/XButtonLight@2x.png new file mode 100644 index 0000000..efffae4 Binary files /dev/null and b/2016/content/textures/ui/Settings/Help/XButtonLight@2x.png differ diff --git a/2016/content/textures/ui/Settings/Help/XboxController.png b/2016/content/textures/ui/Settings/Help/XboxController.png new file mode 100644 index 0000000..ae478c4 Binary files /dev/null and b/2016/content/textures/ui/Settings/Help/XboxController.png differ diff --git a/2016/content/textures/ui/Settings/Help/YButtonDark.png b/2016/content/textures/ui/Settings/Help/YButtonDark.png new file mode 100644 index 0000000..46d4284 Binary files /dev/null and b/2016/content/textures/ui/Settings/Help/YButtonDark.png differ diff --git a/2016/content/textures/ui/Settings/Help/YButtonDark@2x.png b/2016/content/textures/ui/Settings/Help/YButtonDark@2x.png new file mode 100644 index 0000000..81aaf13 Binary files /dev/null and b/2016/content/textures/ui/Settings/Help/YButtonDark@2x.png differ diff --git a/2016/content/textures/ui/Settings/Help/YButtonLight.png b/2016/content/textures/ui/Settings/Help/YButtonLight.png new file mode 100644 index 0000000..b8130fb Binary files /dev/null and b/2016/content/textures/ui/Settings/Help/YButtonLight.png differ diff --git a/2016/content/textures/ui/Settings/Help/YButtonLight@2x.png b/2016/content/textures/ui/Settings/Help/YButtonLight@2x.png new file mode 100644 index 0000000..b19c89e Binary files /dev/null and b/2016/content/textures/ui/Settings/Help/YButtonLight@2x.png differ diff --git a/2016/content/textures/ui/Settings/Help/ZoomGesture.png b/2016/content/textures/ui/Settings/Help/ZoomGesture.png new file mode 100644 index 0000000..23a8f62 Binary files /dev/null and b/2016/content/textures/ui/Settings/Help/ZoomGesture.png differ diff --git a/2016/content/textures/ui/Settings/MenuBarAssets/MenuBackground.png b/2016/content/textures/ui/Settings/MenuBarAssets/MenuBackground.png new file mode 100644 index 0000000..825c316 Binary files /dev/null and b/2016/content/textures/ui/Settings/MenuBarAssets/MenuBackground.png differ diff --git a/2016/content/textures/ui/Settings/MenuBarAssets/MenuButton.png b/2016/content/textures/ui/Settings/MenuBarAssets/MenuButton.png new file mode 100644 index 0000000..ca1fb48 Binary files /dev/null and b/2016/content/textures/ui/Settings/MenuBarAssets/MenuButton.png differ diff --git a/2016/content/textures/ui/Settings/MenuBarAssets/MenuButton@2x.png b/2016/content/textures/ui/Settings/MenuBarAssets/MenuButton@2x.png new file mode 100644 index 0000000..1406ca9 Binary files /dev/null and b/2016/content/textures/ui/Settings/MenuBarAssets/MenuButton@2x.png differ diff --git a/2016/content/textures/ui/Settings/MenuBarAssets/MenuButtonSelected.png b/2016/content/textures/ui/Settings/MenuBarAssets/MenuButtonSelected.png new file mode 100644 index 0000000..298a952 Binary files /dev/null and b/2016/content/textures/ui/Settings/MenuBarAssets/MenuButtonSelected.png differ diff --git a/2016/content/textures/ui/Settings/MenuBarAssets/MenuButtonSelected@2x.png b/2016/content/textures/ui/Settings/MenuBarAssets/MenuButtonSelected@2x.png new file mode 100644 index 0000000..4e25b24 Binary files /dev/null and b/2016/content/textures/ui/Settings/MenuBarAssets/MenuButtonSelected@2x.png differ diff --git a/2016/content/textures/ui/Settings/MenuBarAssets/MenuSelection.png b/2016/content/textures/ui/Settings/MenuBarAssets/MenuSelection.png new file mode 100644 index 0000000..0e79bfe Binary files /dev/null and b/2016/content/textures/ui/Settings/MenuBarAssets/MenuSelection.png differ diff --git a/2016/content/textures/ui/Settings/MenuBarAssets/MenuSelection@2x.png b/2016/content/textures/ui/Settings/MenuBarAssets/MenuSelection@2x.png new file mode 100644 index 0000000..da1a3a3 Binary files /dev/null and b/2016/content/textures/ui/Settings/MenuBarAssets/MenuSelection@2x.png differ diff --git a/2016/content/textures/ui/Settings/MenuBarIcons/GameSettingsTab.png b/2016/content/textures/ui/Settings/MenuBarIcons/GameSettingsTab.png new file mode 100644 index 0000000..81df477 Binary files /dev/null and b/2016/content/textures/ui/Settings/MenuBarIcons/GameSettingsTab.png differ diff --git a/2016/content/textures/ui/Settings/MenuBarIcons/GameSettingsTab@2x.png b/2016/content/textures/ui/Settings/MenuBarIcons/GameSettingsTab@2x.png new file mode 100644 index 0000000..8fa963f Binary files /dev/null and b/2016/content/textures/ui/Settings/MenuBarIcons/GameSettingsTab@2x.png differ diff --git a/2016/content/textures/ui/Settings/MenuBarIcons/HelpTab.png b/2016/content/textures/ui/Settings/MenuBarIcons/HelpTab.png new file mode 100644 index 0000000..2658eea Binary files /dev/null and b/2016/content/textures/ui/Settings/MenuBarIcons/HelpTab.png differ diff --git a/2016/content/textures/ui/Settings/MenuBarIcons/HelpTab@2x.png b/2016/content/textures/ui/Settings/MenuBarIcons/HelpTab@2x.png new file mode 100644 index 0000000..2910461 Binary files /dev/null and b/2016/content/textures/ui/Settings/MenuBarIcons/HelpTab@2x.png differ diff --git a/2016/content/textures/ui/Settings/MenuBarIcons/HomeTab.png b/2016/content/textures/ui/Settings/MenuBarIcons/HomeTab.png new file mode 100644 index 0000000..f05200f Binary files /dev/null and b/2016/content/textures/ui/Settings/MenuBarIcons/HomeTab.png differ diff --git a/2016/content/textures/ui/Settings/MenuBarIcons/HomeTab@2x.png b/2016/content/textures/ui/Settings/MenuBarIcons/HomeTab@2x.png new file mode 100644 index 0000000..7fe7075 Binary files /dev/null and b/2016/content/textures/ui/Settings/MenuBarIcons/HomeTab@2x.png differ diff --git a/2016/content/textures/ui/Settings/MenuBarIcons/PlayersTabIcon.png b/2016/content/textures/ui/Settings/MenuBarIcons/PlayersTabIcon.png new file mode 100644 index 0000000..2c95f9a Binary files /dev/null and b/2016/content/textures/ui/Settings/MenuBarIcons/PlayersTabIcon.png differ diff --git a/2016/content/textures/ui/Settings/MenuBarIcons/PlayersTabIcon@2x.png b/2016/content/textures/ui/Settings/MenuBarIcons/PlayersTabIcon@2x.png new file mode 100644 index 0000000..162471f Binary files /dev/null and b/2016/content/textures/ui/Settings/MenuBarIcons/PlayersTabIcon@2x.png differ diff --git a/2016/content/textures/ui/Settings/MenuBarIcons/RecordTab.png b/2016/content/textures/ui/Settings/MenuBarIcons/RecordTab.png new file mode 100644 index 0000000..4020a78 Binary files /dev/null and b/2016/content/textures/ui/Settings/MenuBarIcons/RecordTab.png differ diff --git a/2016/content/textures/ui/Settings/MenuBarIcons/RecordTab@2x.png b/2016/content/textures/ui/Settings/MenuBarIcons/RecordTab@2x.png new file mode 100644 index 0000000..63a7411 Binary files /dev/null and b/2016/content/textures/ui/Settings/MenuBarIcons/RecordTab@2x.png differ diff --git a/2016/content/textures/ui/Settings/MenuBarIcons/ReportAbuseTab.png b/2016/content/textures/ui/Settings/MenuBarIcons/ReportAbuseTab.png new file mode 100644 index 0000000..bddb28b Binary files /dev/null and b/2016/content/textures/ui/Settings/MenuBarIcons/ReportAbuseTab.png differ diff --git a/2016/content/textures/ui/Settings/MenuBarIcons/ReportAbuseTab@2x.png b/2016/content/textures/ui/Settings/MenuBarIcons/ReportAbuseTab@2x.png new file mode 100644 index 0000000..abb6674 Binary files /dev/null and b/2016/content/textures/ui/Settings/MenuBarIcons/ReportAbuseTab@2x.png differ diff --git a/2016/content/textures/ui/Settings/Radial/Alert.png b/2016/content/textures/ui/Settings/Radial/Alert.png new file mode 100644 index 0000000..4165e5c Binary files /dev/null and b/2016/content/textures/ui/Settings/Radial/Alert.png differ diff --git a/2016/content/textures/ui/Settings/Radial/Alert@2x.png b/2016/content/textures/ui/Settings/Radial/Alert@2x.png new file mode 100644 index 0000000..c4fd032 Binary files /dev/null and b/2016/content/textures/ui/Settings/Radial/Alert@2x.png differ diff --git a/2016/content/textures/ui/Settings/Radial/Backpack.png b/2016/content/textures/ui/Settings/Radial/Backpack.png new file mode 100644 index 0000000..fe7ed08 Binary files /dev/null and b/2016/content/textures/ui/Settings/Radial/Backpack.png differ diff --git a/2016/content/textures/ui/Settings/Radial/Backpack@2x.png b/2016/content/textures/ui/Settings/Radial/Backpack@2x.png new file mode 100644 index 0000000..70aa912 Binary files /dev/null and b/2016/content/textures/ui/Settings/Radial/Backpack@2x.png differ diff --git a/2016/content/textures/ui/Settings/Radial/Bottom.png b/2016/content/textures/ui/Settings/Radial/Bottom.png new file mode 100644 index 0000000..deb9a5d Binary files /dev/null and b/2016/content/textures/ui/Settings/Radial/Bottom.png differ diff --git a/2016/content/textures/ui/Settings/Radial/BottomLeft.png b/2016/content/textures/ui/Settings/Radial/BottomLeft.png new file mode 100644 index 0000000..9606a32 Binary files /dev/null and b/2016/content/textures/ui/Settings/Radial/BottomLeft.png differ diff --git a/2016/content/textures/ui/Settings/Radial/BottomLeftSelected.png b/2016/content/textures/ui/Settings/Radial/BottomLeftSelected.png new file mode 100644 index 0000000..c695162 Binary files /dev/null and b/2016/content/textures/ui/Settings/Radial/BottomLeftSelected.png differ diff --git a/2016/content/textures/ui/Settings/Radial/BottomRight.png b/2016/content/textures/ui/Settings/Radial/BottomRight.png new file mode 100644 index 0000000..470101a Binary files /dev/null and b/2016/content/textures/ui/Settings/Radial/BottomRight.png differ diff --git a/2016/content/textures/ui/Settings/Radial/BottomRightSelected.png b/2016/content/textures/ui/Settings/Radial/BottomRightSelected.png new file mode 100644 index 0000000..9752011 Binary files /dev/null and b/2016/content/textures/ui/Settings/Radial/BottomRightSelected.png differ diff --git a/2016/content/textures/ui/Settings/Radial/BottomSelected.png b/2016/content/textures/ui/Settings/Radial/BottomSelected.png new file mode 100644 index 0000000..8503642 Binary files /dev/null and b/2016/content/textures/ui/Settings/Radial/BottomSelected.png differ diff --git a/2016/content/textures/ui/Settings/Radial/Chat.png b/2016/content/textures/ui/Settings/Radial/Chat.png new file mode 100644 index 0000000..de382f9 Binary files /dev/null and b/2016/content/textures/ui/Settings/Radial/Chat.png differ diff --git a/2016/content/textures/ui/Settings/Radial/Chat@2x.png b/2016/content/textures/ui/Settings/Radial/Chat@2x.png new file mode 100644 index 0000000..7d2f835 Binary files /dev/null and b/2016/content/textures/ui/Settings/Radial/Chat@2x.png differ diff --git a/2016/content/textures/ui/Settings/Radial/EmptyBottom.png b/2016/content/textures/ui/Settings/Radial/EmptyBottom.png new file mode 100644 index 0000000..65bfc6a Binary files /dev/null and b/2016/content/textures/ui/Settings/Radial/EmptyBottom.png differ diff --git a/2016/content/textures/ui/Settings/Radial/EmptyBottomLeft.png b/2016/content/textures/ui/Settings/Radial/EmptyBottomLeft.png new file mode 100644 index 0000000..6944d53 Binary files /dev/null and b/2016/content/textures/ui/Settings/Radial/EmptyBottomLeft.png differ diff --git a/2016/content/textures/ui/Settings/Radial/EmptyBottomRight.png b/2016/content/textures/ui/Settings/Radial/EmptyBottomRight.png new file mode 100644 index 0000000..6ec4168 Binary files /dev/null and b/2016/content/textures/ui/Settings/Radial/EmptyBottomRight.png differ diff --git a/2016/content/textures/ui/Settings/Radial/EmptyTop.png b/2016/content/textures/ui/Settings/Radial/EmptyTop.png new file mode 100644 index 0000000..bd0bdda Binary files /dev/null and b/2016/content/textures/ui/Settings/Radial/EmptyTop.png differ diff --git a/2016/content/textures/ui/Settings/Radial/EmptyTopLeft.png b/2016/content/textures/ui/Settings/Radial/EmptyTopLeft.png new file mode 100644 index 0000000..fcb0312 Binary files /dev/null and b/2016/content/textures/ui/Settings/Radial/EmptyTopLeft.png differ diff --git a/2016/content/textures/ui/Settings/Radial/EmptyTopRight.png b/2016/content/textures/ui/Settings/Radial/EmptyTopRight.png new file mode 100644 index 0000000..5b17865 Binary files /dev/null and b/2016/content/textures/ui/Settings/Radial/EmptyTopRight.png differ diff --git a/2016/content/textures/ui/Settings/Radial/Leave.png b/2016/content/textures/ui/Settings/Radial/Leave.png new file mode 100644 index 0000000..90ee842 Binary files /dev/null and b/2016/content/textures/ui/Settings/Radial/Leave.png differ diff --git a/2016/content/textures/ui/Settings/Radial/Leave@2x.png b/2016/content/textures/ui/Settings/Radial/Leave@2x.png new file mode 100644 index 0000000..e9d11ad Binary files /dev/null and b/2016/content/textures/ui/Settings/Radial/Leave@2x.png differ diff --git a/2016/content/textures/ui/Settings/Radial/Menu.png b/2016/content/textures/ui/Settings/Radial/Menu.png new file mode 100644 index 0000000..c414691 Binary files /dev/null and b/2016/content/textures/ui/Settings/Radial/Menu.png differ diff --git a/2016/content/textures/ui/Settings/Radial/Menu@2x.png b/2016/content/textures/ui/Settings/Radial/Menu@2x.png new file mode 100644 index 0000000..5c65bd0 Binary files /dev/null and b/2016/content/textures/ui/Settings/Radial/Menu@2x.png differ diff --git a/2016/content/textures/ui/Settings/Radial/PlayerList.png b/2016/content/textures/ui/Settings/Radial/PlayerList.png new file mode 100644 index 0000000..b8da356 Binary files /dev/null and b/2016/content/textures/ui/Settings/Radial/PlayerList.png differ diff --git a/2016/content/textures/ui/Settings/Radial/PlayerList@2x.png b/2016/content/textures/ui/Settings/Radial/PlayerList@2x.png new file mode 100644 index 0000000..3ca6d5f Binary files /dev/null and b/2016/content/textures/ui/Settings/Radial/PlayerList@2x.png differ diff --git a/2016/content/textures/ui/Settings/Radial/RadialLabel.png b/2016/content/textures/ui/Settings/Radial/RadialLabel.png new file mode 100644 index 0000000..420552f Binary files /dev/null and b/2016/content/textures/ui/Settings/Radial/RadialLabel.png differ diff --git a/2016/content/textures/ui/Settings/Radial/RadialLabel@2x.png b/2016/content/textures/ui/Settings/Radial/RadialLabel@2x.png new file mode 100644 index 0000000..a75f44d Binary files /dev/null and b/2016/content/textures/ui/Settings/Radial/RadialLabel@2x.png differ diff --git a/2016/content/textures/ui/Settings/Radial/Top.png b/2016/content/textures/ui/Settings/Radial/Top.png new file mode 100644 index 0000000..e3cc6eb Binary files /dev/null and b/2016/content/textures/ui/Settings/Radial/Top.png differ diff --git a/2016/content/textures/ui/Settings/Radial/TopLeft.png b/2016/content/textures/ui/Settings/Radial/TopLeft.png new file mode 100644 index 0000000..b58730f Binary files /dev/null and b/2016/content/textures/ui/Settings/Radial/TopLeft.png differ diff --git a/2016/content/textures/ui/Settings/Radial/TopLeftSelected.png b/2016/content/textures/ui/Settings/Radial/TopLeftSelected.png new file mode 100644 index 0000000..03e85ff Binary files /dev/null and b/2016/content/textures/ui/Settings/Radial/TopLeftSelected.png differ diff --git a/2016/content/textures/ui/Settings/Radial/TopRight.png b/2016/content/textures/ui/Settings/Radial/TopRight.png new file mode 100644 index 0000000..120dcbf Binary files /dev/null and b/2016/content/textures/ui/Settings/Radial/TopRight.png differ diff --git a/2016/content/textures/ui/Settings/Radial/TopRightSelected.png b/2016/content/textures/ui/Settings/Radial/TopRightSelected.png new file mode 100644 index 0000000..2b447f0 Binary files /dev/null and b/2016/content/textures/ui/Settings/Radial/TopRightSelected.png differ diff --git a/2016/content/textures/ui/Settings/Radial/TopSelected.png b/2016/content/textures/ui/Settings/Radial/TopSelected.png new file mode 100644 index 0000000..6e94eed Binary files /dev/null and b/2016/content/textures/ui/Settings/Radial/TopSelected.png differ diff --git a/2016/content/textures/ui/Settings/Slider/BarLeft.png b/2016/content/textures/ui/Settings/Slider/BarLeft.png new file mode 100644 index 0000000..7c77f60 Binary files /dev/null and b/2016/content/textures/ui/Settings/Slider/BarLeft.png differ diff --git a/2016/content/textures/ui/Settings/Slider/BarLeft@2x.png b/2016/content/textures/ui/Settings/Slider/BarLeft@2x.png new file mode 100644 index 0000000..f116856 Binary files /dev/null and b/2016/content/textures/ui/Settings/Slider/BarLeft@2x.png differ diff --git a/2016/content/textures/ui/Settings/Slider/BarRight.png b/2016/content/textures/ui/Settings/Slider/BarRight.png new file mode 100644 index 0000000..52256d6 Binary files /dev/null and b/2016/content/textures/ui/Settings/Slider/BarRight.png differ diff --git a/2016/content/textures/ui/Settings/Slider/BarRight@2x.png b/2016/content/textures/ui/Settings/Slider/BarRight@2x.png new file mode 100644 index 0000000..41bfe69 Binary files /dev/null and b/2016/content/textures/ui/Settings/Slider/BarRight@2x.png differ diff --git a/2016/content/textures/ui/Settings/Slider/Left.png b/2016/content/textures/ui/Settings/Slider/Left.png new file mode 100644 index 0000000..a742728 Binary files /dev/null and b/2016/content/textures/ui/Settings/Slider/Left.png differ diff --git a/2016/content/textures/ui/Settings/Slider/Left@2x.png b/2016/content/textures/ui/Settings/Slider/Left@2x.png new file mode 100644 index 0000000..582699d Binary files /dev/null and b/2016/content/textures/ui/Settings/Slider/Left@2x.png differ diff --git a/2016/content/textures/ui/Settings/Slider/Right.png b/2016/content/textures/ui/Settings/Slider/Right.png new file mode 100644 index 0000000..0d47c0a Binary files /dev/null and b/2016/content/textures/ui/Settings/Slider/Right.png differ diff --git a/2016/content/textures/ui/Settings/Slider/Right@2x.png b/2016/content/textures/ui/Settings/Slider/Right@2x.png new file mode 100644 index 0000000..fb86118 Binary files /dev/null and b/2016/content/textures/ui/Settings/Slider/Right@2x.png differ diff --git a/2016/content/textures/ui/Settings/Slider/SelectedBarLeft.png b/2016/content/textures/ui/Settings/Slider/SelectedBarLeft.png new file mode 100644 index 0000000..42cbddf Binary files /dev/null and b/2016/content/textures/ui/Settings/Slider/SelectedBarLeft.png differ diff --git a/2016/content/textures/ui/Settings/Slider/SelectedBarLeft@2x.png b/2016/content/textures/ui/Settings/Slider/SelectedBarLeft@2x.png new file mode 100644 index 0000000..8c97cda Binary files /dev/null and b/2016/content/textures/ui/Settings/Slider/SelectedBarLeft@2x.png differ diff --git a/2016/content/textures/ui/Settings/Slider/SelectedBarRight.png b/2016/content/textures/ui/Settings/Slider/SelectedBarRight.png new file mode 100644 index 0000000..c1b3f78 Binary files /dev/null and b/2016/content/textures/ui/Settings/Slider/SelectedBarRight.png differ diff --git a/2016/content/textures/ui/Settings/Slider/SelectedBarRight@2x.png b/2016/content/textures/ui/Settings/Slider/SelectedBarRight@2x.png new file mode 100644 index 0000000..56010f0 Binary files /dev/null and b/2016/content/textures/ui/Settings/Slider/SelectedBarRight@2x.png differ diff --git a/2016/content/textures/ui/SettingsButton.png b/2016/content/textures/ui/SettingsButton.png new file mode 100644 index 0000000..196cf23 Binary files /dev/null and b/2016/content/textures/ui/SettingsButton.png differ diff --git a/2016/content/textures/ui/SettingsButton_dn.png b/2016/content/textures/ui/SettingsButton_dn.png new file mode 100644 index 0000000..e6f4799 Binary files /dev/null and b/2016/content/textures/ui/SettingsButton_dn.png differ diff --git a/2016/content/textures/ui/SettingsButton_ds.png b/2016/content/textures/ui/SettingsButton_ds.png new file mode 100644 index 0000000..2aca460 Binary files /dev/null and b/2016/content/textures/ui/SettingsButton_ds.png differ diff --git a/2016/content/textures/ui/SettingsButton_ovr.png b/2016/content/textures/ui/SettingsButton_ovr.png new file mode 100644 index 0000000..e6f4799 Binary files /dev/null and b/2016/content/textures/ui/SettingsButton_ovr.png differ diff --git a/2016/content/textures/ui/SingleButton.png b/2016/content/textures/ui/SingleButton.png new file mode 100644 index 0000000..6bf0fa0 Binary files /dev/null and b/2016/content/textures/ui/SingleButton.png differ diff --git a/2016/content/textures/ui/SingleButtonDown.png b/2016/content/textures/ui/SingleButtonDown.png new file mode 100644 index 0000000..b72335b Binary files /dev/null and b/2016/content/textures/ui/SingleButtonDown.png differ diff --git a/2016/content/textures/ui/Slate.png b/2016/content/textures/ui/Slate.png new file mode 100644 index 0000000..4f90fb8 Binary files /dev/null and b/2016/content/textures/ui/Slate.png differ diff --git a/2016/content/textures/ui/Slider-BKG-Center.png b/2016/content/textures/ui/Slider-BKG-Center.png new file mode 100644 index 0000000..34f9c13 Binary files /dev/null and b/2016/content/textures/ui/Slider-BKG-Center.png differ diff --git a/2016/content/textures/ui/Slider-BKG-Center@2x.png b/2016/content/textures/ui/Slider-BKG-Center@2x.png new file mode 100644 index 0000000..4c4e650 Binary files /dev/null and b/2016/content/textures/ui/Slider-BKG-Center@2x.png differ diff --git a/2016/content/textures/ui/Slider-BKG-Left-Cap.png b/2016/content/textures/ui/Slider-BKG-Left-Cap.png new file mode 100644 index 0000000..ae0ba4e Binary files /dev/null and b/2016/content/textures/ui/Slider-BKG-Left-Cap.png differ diff --git a/2016/content/textures/ui/Slider-BKG-Left-Cap@2x.png b/2016/content/textures/ui/Slider-BKG-Left-Cap@2x.png new file mode 100644 index 0000000..e97552f Binary files /dev/null and b/2016/content/textures/ui/Slider-BKG-Left-Cap@2x.png differ diff --git a/2016/content/textures/ui/Slider-BKG-Right-Cap.png b/2016/content/textures/ui/Slider-BKG-Right-Cap.png new file mode 100644 index 0000000..19ef545 Binary files /dev/null and b/2016/content/textures/ui/Slider-BKG-Right-Cap.png differ diff --git a/2016/content/textures/ui/Slider-BKG-Right-Cap@2x.png b/2016/content/textures/ui/Slider-BKG-Right-Cap@2x.png new file mode 100644 index 0000000..614b0f4 Binary files /dev/null and b/2016/content/textures/ui/Slider-BKG-Right-Cap@2x.png differ diff --git a/2016/content/textures/ui/Slider-Fill-Center.png b/2016/content/textures/ui/Slider-Fill-Center.png new file mode 100644 index 0000000..6f45d7a Binary files /dev/null and b/2016/content/textures/ui/Slider-Fill-Center.png differ diff --git a/2016/content/textures/ui/Slider-Fill-Center@2x.png b/2016/content/textures/ui/Slider-Fill-Center@2x.png new file mode 100644 index 0000000..9bf9420 Binary files /dev/null and b/2016/content/textures/ui/Slider-Fill-Center@2x.png differ diff --git a/2016/content/textures/ui/Slider-Fill-Left-Cap.png b/2016/content/textures/ui/Slider-Fill-Left-Cap.png new file mode 100644 index 0000000..1c1ccdc Binary files /dev/null and b/2016/content/textures/ui/Slider-Fill-Left-Cap.png differ diff --git a/2016/content/textures/ui/Slider-Fill-Left-Cap@2x.png b/2016/content/textures/ui/Slider-Fill-Left-Cap@2x.png new file mode 100644 index 0000000..cfd7689 Binary files /dev/null and b/2016/content/textures/ui/Slider-Fill-Left-Cap@2x.png differ diff --git a/2016/content/textures/ui/Slider-Fill-Right-Cap.png b/2016/content/textures/ui/Slider-Fill-Right-Cap.png new file mode 100644 index 0000000..7e74df5 Binary files /dev/null and b/2016/content/textures/ui/Slider-Fill-Right-Cap.png differ diff --git a/2016/content/textures/ui/Slider-Fill-Right-Cap@2x.png b/2016/content/textures/ui/Slider-Fill-Right-Cap@2x.png new file mode 100644 index 0000000..31b7fc1 Binary files /dev/null and b/2016/content/textures/ui/Slider-Fill-Right-Cap@2x.png differ diff --git a/2016/content/textures/ui/Slider.png b/2016/content/textures/ui/Slider.png new file mode 100644 index 0000000..63c4dea Binary files /dev/null and b/2016/content/textures/ui/Slider.png differ diff --git a/2016/content/textures/ui/Slider_dn.png b/2016/content/textures/ui/Slider_dn.png new file mode 100644 index 0000000..d98cb85 Binary files /dev/null and b/2016/content/textures/ui/Slider_dn.png differ diff --git a/2016/content/textures/ui/Slider_sel.png b/2016/content/textures/ui/Slider_sel.png new file mode 100644 index 0000000..d98cb85 Binary files /dev/null and b/2016/content/textures/ui/Slider_sel.png differ diff --git a/2016/content/textures/ui/Smooth.png b/2016/content/textures/ui/Smooth.png new file mode 100644 index 0000000..e4d6c4d Binary files /dev/null and b/2016/content/textures/ui/Smooth.png differ diff --git a/2016/content/textures/ui/StampToolButton.png b/2016/content/textures/ui/StampToolButton.png new file mode 100644 index 0000000..34e7994 Binary files /dev/null and b/2016/content/textures/ui/StampToolButton.png differ diff --git a/2016/content/textures/ui/StampToolButton_dn.png b/2016/content/textures/ui/StampToolButton_dn.png new file mode 100644 index 0000000..affebf4 Binary files /dev/null and b/2016/content/textures/ui/StampToolButton_dn.png differ diff --git a/2016/content/textures/ui/Studs.png b/2016/content/textures/ui/Studs.png new file mode 100644 index 0000000..194a02b Binary files /dev/null and b/2016/content/textures/ui/Studs.png differ diff --git a/2016/content/textures/ui/SurfaceButton.png b/2016/content/textures/ui/SurfaceButton.png new file mode 100644 index 0000000..78c90f0 Binary files /dev/null and b/2016/content/textures/ui/SurfaceButton.png differ diff --git a/2016/content/textures/ui/SurfaceButton_dn.png b/2016/content/textures/ui/SurfaceButton_dn.png new file mode 100644 index 0000000..850e099 Binary files /dev/null and b/2016/content/textures/ui/SurfaceButton_dn.png differ diff --git a/2016/content/textures/ui/SurfaceMenu.png b/2016/content/textures/ui/SurfaceMenu.png new file mode 100644 index 0000000..1582479 Binary files /dev/null and b/2016/content/textures/ui/SurfaceMenu.png differ diff --git a/2016/content/textures/ui/TinyBcIcon.png b/2016/content/textures/ui/TinyBcIcon.png new file mode 100644 index 0000000..1e2c7ef Binary files /dev/null and b/2016/content/textures/ui/TinyBcIcon.png differ diff --git a/2016/content/textures/ui/TinyObcIcon.png b/2016/content/textures/ui/TinyObcIcon.png new file mode 100644 index 0000000..f12104d Binary files /dev/null and b/2016/content/textures/ui/TinyObcIcon.png differ diff --git a/2016/content/textures/ui/TinyTbcIcon.png b/2016/content/textures/ui/TinyTbcIcon.png new file mode 100644 index 0000000..d5c37fe Binary files /dev/null and b/2016/content/textures/ui/TinyTbcIcon.png differ diff --git a/2016/content/textures/ui/TixIcon.png b/2016/content/textures/ui/TixIcon.png new file mode 100644 index 0000000..852d976 Binary files /dev/null and b/2016/content/textures/ui/TixIcon.png differ diff --git a/2016/content/textures/ui/ToggleFullScreen_ds.png b/2016/content/textures/ui/ToggleFullScreen_ds.png new file mode 100644 index 0000000..07d7de0 Binary files /dev/null and b/2016/content/textures/ui/ToggleFullScreen_ds.png differ diff --git a/2016/content/textures/ui/ToolButton.png b/2016/content/textures/ui/ToolButton.png new file mode 100644 index 0000000..ca9a395 Binary files /dev/null and b/2016/content/textures/ui/ToolButton.png differ diff --git a/2016/content/textures/ui/ToolButton_dn.png b/2016/content/textures/ui/ToolButton_dn.png new file mode 100644 index 0000000..e53c826 Binary files /dev/null and b/2016/content/textures/ui/ToolButton_dn.png differ diff --git a/2016/content/textures/ui/ToolButton_ds.png b/2016/content/textures/ui/ToolButton_ds.png new file mode 100644 index 0000000..016ae9c Binary files /dev/null and b/2016/content/textures/ui/ToolButton_ds.png differ diff --git a/2016/content/textures/ui/TopBar/dropshadow.png b/2016/content/textures/ui/TopBar/dropshadow.png new file mode 100644 index 0000000..8147254 Binary files /dev/null and b/2016/content/textures/ui/TopBar/dropshadow.png differ diff --git a/2016/content/textures/ui/TopBar/dropshadow@2x.png b/2016/content/textures/ui/TopBar/dropshadow@2x.png new file mode 100644 index 0000000..5b97175 Binary files /dev/null and b/2016/content/textures/ui/TopBar/dropshadow@2x.png differ diff --git a/2016/content/textures/ui/TouchControlsSheet.png b/2016/content/textures/ui/TouchControlsSheet.png new file mode 100644 index 0000000..d3b740e Binary files /dev/null and b/2016/content/textures/ui/TouchControlsSheet.png differ diff --git a/2016/content/textures/ui/Universal.png b/2016/content/textures/ui/Universal.png new file mode 100644 index 0000000..508fac8 Binary files /dev/null and b/2016/content/textures/ui/Universal.png differ diff --git a/2016/content/textures/ui/VR/button.png b/2016/content/textures/ui/VR/button.png new file mode 100644 index 0000000..991c0ce Binary files /dev/null and b/2016/content/textures/ui/VR/button.png differ diff --git a/2016/content/textures/ui/VR/buttonActive.png b/2016/content/textures/ui/VR/buttonActive.png new file mode 100644 index 0000000..f812f35 Binary files /dev/null and b/2016/content/textures/ui/VR/buttonActive.png differ diff --git a/2016/content/textures/ui/VR/buttonBackground.png b/2016/content/textures/ui/VR/buttonBackground.png new file mode 100644 index 0000000..9f402da Binary files /dev/null and b/2016/content/textures/ui/VR/buttonBackground.png differ diff --git a/2016/content/textures/ui/VR/buttonHover.png b/2016/content/textures/ui/VR/buttonHover.png new file mode 100644 index 0000000..fb360d0 Binary files /dev/null and b/2016/content/textures/ui/VR/buttonHover.png differ diff --git a/2016/content/textures/ui/VR/buttonSelected.png b/2016/content/textures/ui/VR/buttonSelected.png new file mode 100644 index 0000000..48e41d7 Binary files /dev/null and b/2016/content/textures/ui/VR/buttonSelected.png differ diff --git a/2016/content/textures/ui/VR/chat.png b/2016/content/textures/ui/VR/chat.png new file mode 100644 index 0000000..0d17b09 Binary files /dev/null and b/2016/content/textures/ui/VR/chat.png differ diff --git a/2016/content/textures/ui/VR/circleWhite.png b/2016/content/textures/ui/VR/circleWhite.png new file mode 100644 index 0000000..cabfe61 Binary files /dev/null and b/2016/content/textures/ui/VR/circleWhite.png differ diff --git a/2016/content/textures/ui/VR/closeButtonPadded.png b/2016/content/textures/ui/VR/closeButtonPadded.png new file mode 100644 index 0000000..870dc99 Binary files /dev/null and b/2016/content/textures/ui/VR/closeButtonPadded.png differ diff --git a/2016/content/textures/ui/VR/hamburger.png b/2016/content/textures/ui/VR/hamburger.png new file mode 100644 index 0000000..db81766 Binary files /dev/null and b/2016/content/textures/ui/VR/hamburger.png differ diff --git a/2016/content/textures/ui/VR/hoverPopupLeft.png b/2016/content/textures/ui/VR/hoverPopupLeft.png new file mode 100644 index 0000000..317b2e1 Binary files /dev/null and b/2016/content/textures/ui/VR/hoverPopupLeft.png differ diff --git a/2016/content/textures/ui/VR/hoverPopupMid.png b/2016/content/textures/ui/VR/hoverPopupMid.png new file mode 100644 index 0000000..fb8da3d Binary files /dev/null and b/2016/content/textures/ui/VR/hoverPopupMid.png differ diff --git a/2016/content/textures/ui/VR/hoverPopupRight.png b/2016/content/textures/ui/VR/hoverPopupRight.png new file mode 100644 index 0000000..8266e24 Binary files /dev/null and b/2016/content/textures/ui/VR/hoverPopupRight.png differ diff --git a/2016/content/textures/ui/VR/notifications.png b/2016/content/textures/ui/VR/notifications.png new file mode 100644 index 0000000..02b53d0 Binary files /dev/null and b/2016/content/textures/ui/VR/notifications.png differ diff --git a/2016/content/textures/ui/VR/notifier_glow.png b/2016/content/textures/ui/VR/notifier_glow.png new file mode 100644 index 0000000..0eeee5a Binary files /dev/null and b/2016/content/textures/ui/VR/notifier_glow.png differ diff --git a/2016/content/textures/ui/VR/recenter.png b/2016/content/textures/ui/VR/recenter.png new file mode 100644 index 0000000..1378155 Binary files /dev/null and b/2016/content/textures/ui/VR/recenter.png differ diff --git a/2016/content/textures/ui/VR/recenterFrame.png b/2016/content/textures/ui/VR/recenterFrame.png new file mode 100644 index 0000000..2fea748 Binary files /dev/null and b/2016/content/textures/ui/VR/recenterFrame.png differ diff --git a/2016/content/textures/ui/VR/rectBackground.png b/2016/content/textures/ui/VR/rectBackground.png new file mode 100644 index 0000000..3e8bba8 Binary files /dev/null and b/2016/content/textures/ui/VR/rectBackground.png differ diff --git a/2016/content/textures/ui/VR/rectBackgroundWhite.png b/2016/content/textures/ui/VR/rectBackgroundWhite.png new file mode 100644 index 0000000..a93613c Binary files /dev/null and b/2016/content/textures/ui/VR/rectBackgroundWhite.png differ diff --git a/2016/content/textures/ui/VR/toggle2D.png b/2016/content/textures/ui/VR/toggle2D.png new file mode 100644 index 0000000..c0f7b04 Binary files /dev/null and b/2016/content/textures/ui/VR/toggle2D.png differ diff --git a/2016/content/textures/ui/Vehicle/SpeedBar.png b/2016/content/textures/ui/Vehicle/SpeedBar.png new file mode 100644 index 0000000..0bd0fb6 Binary files /dev/null and b/2016/content/textures/ui/Vehicle/SpeedBar.png differ diff --git a/2016/content/textures/ui/Vehicle/SpeedBar@2x.png b/2016/content/textures/ui/Vehicle/SpeedBar@2x.png new file mode 100644 index 0000000..403883b Binary files /dev/null and b/2016/content/textures/ui/Vehicle/SpeedBar@2x.png differ diff --git a/2016/content/textures/ui/Vehicle/SpeedBarBKG.png b/2016/content/textures/ui/Vehicle/SpeedBarBKG.png new file mode 100644 index 0000000..67cf7dd Binary files /dev/null and b/2016/content/textures/ui/Vehicle/SpeedBarBKG.png differ diff --git a/2016/content/textures/ui/Vehicle/SpeedBarBKG@2x.png b/2016/content/textures/ui/Vehicle/SpeedBarBKG@2x.png new file mode 100644 index 0000000..93f3e60 Binary files /dev/null and b/2016/content/textures/ui/Vehicle/SpeedBarBKG@2x.png differ diff --git a/2016/content/textures/ui/Vehicle/SpeedBarEmpty.png b/2016/content/textures/ui/Vehicle/SpeedBarEmpty.png new file mode 100644 index 0000000..23cef24 Binary files /dev/null and b/2016/content/textures/ui/Vehicle/SpeedBarEmpty.png differ diff --git a/2016/content/textures/ui/Vehicle/SpeedBarEmpty@2x.png b/2016/content/textures/ui/Vehicle/SpeedBarEmpty@2x.png new file mode 100644 index 0000000..fe7f6d6 Binary files /dev/null and b/2016/content/textures/ui/Vehicle/SpeedBarEmpty@2x.png differ diff --git a/2016/content/textures/ui/Weld.png b/2016/content/textures/ui/Weld.png new file mode 100644 index 0000000..d45375b Binary files /dev/null and b/2016/content/textures/ui/Weld.png differ diff --git a/2016/content/textures/ui/Wood.png b/2016/content/textures/ui/Wood.png new file mode 100644 index 0000000..93898de Binary files /dev/null and b/2016/content/textures/ui/Wood.png differ diff --git a/2016/content/textures/ui/btn_grey.png b/2016/content/textures/ui/btn_grey.png new file mode 100644 index 0000000..5e46696 Binary files /dev/null and b/2016/content/textures/ui/btn_grey.png differ diff --git a/2016/content/textures/ui/btn_greyTransp.png b/2016/content/textures/ui/btn_greyTransp.png new file mode 100644 index 0000000..df5989b Binary files /dev/null and b/2016/content/textures/ui/btn_greyTransp.png differ diff --git a/2016/content/textures/ui/btn_newBlue.png b/2016/content/textures/ui/btn_newBlue.png new file mode 100644 index 0000000..5a08d4b Binary files /dev/null and b/2016/content/textures/ui/btn_newBlue.png differ diff --git a/2016/content/textures/ui/btn_newBlue@2x.png b/2016/content/textures/ui/btn_newBlue@2x.png new file mode 100644 index 0000000..d20d595 Binary files /dev/null and b/2016/content/textures/ui/btn_newBlue@2x.png differ diff --git a/2016/content/textures/ui/btn_newBlueGlow.png b/2016/content/textures/ui/btn_newBlueGlow.png new file mode 100644 index 0000000..9376645 Binary files /dev/null and b/2016/content/textures/ui/btn_newBlueGlow.png differ diff --git a/2016/content/textures/ui/btn_newBlueGlow@2x.png b/2016/content/textures/ui/btn_newBlueGlow@2x.png new file mode 100644 index 0000000..b559d35 Binary files /dev/null and b/2016/content/textures/ui/btn_newBlueGlow@2x.png differ diff --git a/2016/content/textures/ui/btn_newGrey.png b/2016/content/textures/ui/btn_newGrey.png new file mode 100644 index 0000000..3868d8c Binary files /dev/null and b/2016/content/textures/ui/btn_newGrey.png differ diff --git a/2016/content/textures/ui/btn_newGrey@2x.png b/2016/content/textures/ui/btn_newGrey@2x.png new file mode 100644 index 0000000..967c988 Binary files /dev/null and b/2016/content/textures/ui/btn_newGrey@2x.png differ diff --git a/2016/content/textures/ui/btn_newGreyGlow.png b/2016/content/textures/ui/btn_newGreyGlow.png new file mode 100644 index 0000000..6782b53 Binary files /dev/null and b/2016/content/textures/ui/btn_newGreyGlow.png differ diff --git a/2016/content/textures/ui/btn_newGreyGlow@2x.png b/2016/content/textures/ui/btn_newGreyGlow@2x.png new file mode 100644 index 0000000..aba488a Binary files /dev/null and b/2016/content/textures/ui/btn_newGreyGlow@2x.png differ diff --git a/2016/content/textures/ui/btn_newWhite.png b/2016/content/textures/ui/btn_newWhite.png new file mode 100644 index 0000000..bd5efaf Binary files /dev/null and b/2016/content/textures/ui/btn_newWhite.png differ diff --git a/2016/content/textures/ui/btn_newWhite@2x.png b/2016/content/textures/ui/btn_newWhite@2x.png new file mode 100644 index 0000000..35c6494 Binary files /dev/null and b/2016/content/textures/ui/btn_newWhite@2x.png differ diff --git a/2016/content/textures/ui/btn_newWhiteGlow.png b/2016/content/textures/ui/btn_newWhiteGlow.png new file mode 100644 index 0000000..857274f Binary files /dev/null and b/2016/content/textures/ui/btn_newWhiteGlow.png differ diff --git a/2016/content/textures/ui/btn_newWhiteGlow@2x.png b/2016/content/textures/ui/btn_newWhiteGlow@2x.png new file mode 100644 index 0000000..f0dbb9d Binary files /dev/null and b/2016/content/textures/ui/btn_newWhiteGlow@2x.png differ diff --git a/2016/content/textures/ui/btn_red.png b/2016/content/textures/ui/btn_red.png new file mode 100644 index 0000000..17666e6 Binary files /dev/null and b/2016/content/textures/ui/btn_red.png differ diff --git a/2016/content/textures/ui/btn_redGlow.png b/2016/content/textures/ui/btn_redGlow.png new file mode 100644 index 0000000..5cf7081 Binary files /dev/null and b/2016/content/textures/ui/btn_redGlow.png differ diff --git a/2016/content/textures/ui/btn_white.png b/2016/content/textures/ui/btn_white.png new file mode 100644 index 0000000..d2a1cf2 Binary files /dev/null and b/2016/content/textures/ui/btn_white.png differ diff --git a/2016/content/textures/ui/chatBubble_blue_notify_bkg.png b/2016/content/textures/ui/chatBubble_blue_notify_bkg.png new file mode 100644 index 0000000..75871f9 Binary files /dev/null and b/2016/content/textures/ui/chatBubble_blue_notify_bkg.png differ diff --git a/2016/content/textures/ui/chatBubble_green_notify_bkg.png b/2016/content/textures/ui/chatBubble_green_notify_bkg.png new file mode 100644 index 0000000..5dd7ce5 Binary files /dev/null and b/2016/content/textures/ui/chatBubble_green_notify_bkg.png differ diff --git a/2016/content/textures/ui/chatBubble_red_notify_bkg.png b/2016/content/textures/ui/chatBubble_red_notify_bkg.png new file mode 100644 index 0000000..92ffa3b Binary files /dev/null and b/2016/content/textures/ui/chatBubble_red_notify_bkg.png differ diff --git a/2016/content/textures/ui/chatBubble_white_notify_bkg.png b/2016/content/textures/ui/chatBubble_white_notify_bkg.png new file mode 100644 index 0000000..45158ce Binary files /dev/null and b/2016/content/textures/ui/chatBubble_white_notify_bkg.png differ diff --git a/2016/content/textures/ui/chat_teamButton.png b/2016/content/textures/ui/chat_teamButton.png new file mode 100644 index 0000000..ad390aa Binary files /dev/null and b/2016/content/textures/ui/chat_teamButton.png differ diff --git a/2016/content/textures/ui/chat_teamButton@2x.png b/2016/content/textures/ui/chat_teamButton@2x.png new file mode 100644 index 0000000..b38e73f Binary files /dev/null and b/2016/content/textures/ui/chat_teamButton@2x.png differ diff --git a/2016/content/textures/ui/dialog_blue.png b/2016/content/textures/ui/dialog_blue.png new file mode 100644 index 0000000..734129b Binary files /dev/null and b/2016/content/textures/ui/dialog_blue.png differ diff --git a/2016/content/textures/ui/dialog_blue@2x.png b/2016/content/textures/ui/dialog_blue@2x.png new file mode 100644 index 0000000..7d17ee8 Binary files /dev/null and b/2016/content/textures/ui/dialog_blue@2x.png differ diff --git a/2016/content/textures/ui/dialog_ellipses.png b/2016/content/textures/ui/dialog_ellipses.png new file mode 100644 index 0000000..845c727 Binary files /dev/null and b/2016/content/textures/ui/dialog_ellipses.png differ diff --git a/2016/content/textures/ui/dialog_green.png b/2016/content/textures/ui/dialog_green.png new file mode 100644 index 0000000..b3b655c Binary files /dev/null and b/2016/content/textures/ui/dialog_green.png differ diff --git a/2016/content/textures/ui/dialog_green@2x.png b/2016/content/textures/ui/dialog_green@2x.png new file mode 100644 index 0000000..2daaacf Binary files /dev/null and b/2016/content/textures/ui/dialog_green@2x.png differ diff --git a/2016/content/textures/ui/dialog_purpose_help.png b/2016/content/textures/ui/dialog_purpose_help.png new file mode 100644 index 0000000..04c7c71 Binary files /dev/null and b/2016/content/textures/ui/dialog_purpose_help.png differ diff --git a/2016/content/textures/ui/dialog_purpose_quest.png b/2016/content/textures/ui/dialog_purpose_quest.png new file mode 100644 index 0000000..1fb351d Binary files /dev/null and b/2016/content/textures/ui/dialog_purpose_quest.png differ diff --git a/2016/content/textures/ui/dialog_purpose_shop.png b/2016/content/textures/ui/dialog_purpose_shop.png new file mode 100644 index 0000000..5e14018 Binary files /dev/null and b/2016/content/textures/ui/dialog_purpose_shop.png differ diff --git a/2016/content/textures/ui/dialog_red.png b/2016/content/textures/ui/dialog_red.png new file mode 100644 index 0000000..0cfce4d Binary files /dev/null and b/2016/content/textures/ui/dialog_red.png differ diff --git a/2016/content/textures/ui/dialog_red@2x.png b/2016/content/textures/ui/dialog_red@2x.png new file mode 100644 index 0000000..7c63527 Binary files /dev/null and b/2016/content/textures/ui/dialog_red@2x.png differ diff --git a/2016/content/textures/ui/dialog_tail.png b/2016/content/textures/ui/dialog_tail.png new file mode 100644 index 0000000..34e7d89 Binary files /dev/null and b/2016/content/textures/ui/dialog_tail.png differ diff --git a/2016/content/textures/ui/dialog_tail@2x.png b/2016/content/textures/ui/dialog_tail@2x.png new file mode 100644 index 0000000..461718b Binary files /dev/null and b/2016/content/textures/ui/dialog_tail@2x.png differ diff --git a/2016/content/textures/ui/dialog_white.png b/2016/content/textures/ui/dialog_white.png new file mode 100644 index 0000000..92cc922 Binary files /dev/null and b/2016/content/textures/ui/dialog_white.png differ diff --git a/2016/content/textures/ui/dialog_white@2x.png b/2016/content/textures/ui/dialog_white@2x.png new file mode 100644 index 0000000..3935a05 Binary files /dev/null and b/2016/content/textures/ui/dialog_white@2x.png differ diff --git a/2016/content/textures/ui/dropdown_arrow.png b/2016/content/textures/ui/dropdown_arrow.png new file mode 100644 index 0000000..e428280 Binary files /dev/null and b/2016/content/textures/ui/dropdown_arrow.png differ diff --git a/2016/content/textures/ui/dropdown_arrow@2x.png b/2016/content/textures/ui/dropdown_arrow@2x.png new file mode 100644 index 0000000..fec2bf9 Binary files /dev/null and b/2016/content/textures/ui/dropdown_arrow@2x.png differ diff --git a/2016/content/textures/ui/expandPlayerList.png b/2016/content/textures/ui/expandPlayerList.png new file mode 100644 index 0000000..beff417 Binary files /dev/null and b/2016/content/textures/ui/expandPlayerList.png differ diff --git a/2016/content/textures/ui/expandPlayerList@2x.png b/2016/content/textures/ui/expandPlayerList@2x.png new file mode 100644 index 0000000..6766d2a Binary files /dev/null and b/2016/content/textures/ui/expandPlayerList@2x.png differ diff --git a/2016/content/textures/ui/homeButton.png b/2016/content/textures/ui/homeButton.png new file mode 100644 index 0000000..0ad7744 Binary files /dev/null and b/2016/content/textures/ui/homeButton.png differ diff --git a/2016/content/textures/ui/homeButton@2x.png b/2016/content/textures/ui/homeButton@2x.png new file mode 100644 index 0000000..b0b5a0f Binary files /dev/null and b/2016/content/textures/ui/homeButton@2x.png differ diff --git a/2016/content/textures/ui/icon_BC-16.png b/2016/content/textures/ui/icon_BC-16.png new file mode 100644 index 0000000..57f0ce1 Binary files /dev/null and b/2016/content/textures/ui/icon_BC-16.png differ diff --git a/2016/content/textures/ui/icon_OBC-16.png b/2016/content/textures/ui/icon_OBC-16.png new file mode 100644 index 0000000..3d9b177 Binary files /dev/null and b/2016/content/textures/ui/icon_OBC-16.png differ diff --git a/2016/content/textures/ui/icon_TBC-16.png b/2016/content/textures/ui/icon_TBC-16.png new file mode 100644 index 0000000..ea803fe Binary files /dev/null and b/2016/content/textures/ui/icon_TBC-16.png differ diff --git a/2016/content/textures/ui/icon_admin-16.png b/2016/content/textures/ui/icon_admin-16.png new file mode 100644 index 0000000..544542b Binary files /dev/null and b/2016/content/textures/ui/icon_admin-16.png differ diff --git a/2016/content/textures/ui/icon_follower-16.png b/2016/content/textures/ui/icon_follower-16.png new file mode 100644 index 0000000..f5c057a Binary files /dev/null and b/2016/content/textures/ui/icon_follower-16.png differ diff --git a/2016/content/textures/ui/icon_following-16.png b/2016/content/textures/ui/icon_following-16.png new file mode 100644 index 0000000..3810904 Binary files /dev/null and b/2016/content/textures/ui/icon_following-16.png differ diff --git a/2016/content/textures/ui/icon_friendrequestrecieved-16.png b/2016/content/textures/ui/icon_friendrequestrecieved-16.png new file mode 100644 index 0000000..2e45d38 Binary files /dev/null and b/2016/content/textures/ui/icon_friendrequestrecieved-16.png differ diff --git a/2016/content/textures/ui/icon_friendrequestsent_16.png b/2016/content/textures/ui/icon_friendrequestsent_16.png new file mode 100644 index 0000000..fa7c6bd Binary files /dev/null and b/2016/content/textures/ui/icon_friendrequestsent_16.png differ diff --git a/2016/content/textures/ui/icon_friends_16.png b/2016/content/textures/ui/icon_friends_16.png new file mode 100644 index 0000000..649067e Binary files /dev/null and b/2016/content/textures/ui/icon_friends_16.png differ diff --git a/2016/content/textures/ui/icon_intern-16.png b/2016/content/textures/ui/icon_intern-16.png new file mode 100644 index 0000000..2a3cfd7 Binary files /dev/null and b/2016/content/textures/ui/icon_intern-16.png differ diff --git a/2016/content/textures/ui/icon_mutualfollowing-16.png b/2016/content/textures/ui/icon_mutualfollowing-16.png new file mode 100644 index 0000000..e08ba52 Binary files /dev/null and b/2016/content/textures/ui/icon_mutualfollowing-16.png differ diff --git a/2016/content/textures/ui/icon_placeowner.png b/2016/content/textures/ui/icon_placeowner.png new file mode 100644 index 0000000..1feb020 Binary files /dev/null and b/2016/content/textures/ui/icon_placeowner.png differ diff --git a/2016/content/textures/ui/mouseLock_off.png b/2016/content/textures/ui/mouseLock_off.png new file mode 100644 index 0000000..27b1272 Binary files /dev/null and b/2016/content/textures/ui/mouseLock_off.png differ diff --git a/2016/content/textures/ui/mouseLock_off@2x.png b/2016/content/textures/ui/mouseLock_off@2x.png new file mode 100644 index 0000000..4fdd594 Binary files /dev/null and b/2016/content/textures/ui/mouseLock_off@2x.png differ diff --git a/2016/content/textures/ui/mouseLock_on.png b/2016/content/textures/ui/mouseLock_on.png new file mode 100644 index 0000000..250c42a Binary files /dev/null and b/2016/content/textures/ui/mouseLock_on.png differ diff --git a/2016/content/textures/ui/mouseLock_on@2x.png b/2016/content/textures/ui/mouseLock_on@2x.png new file mode 100644 index 0000000..9614f3e Binary files /dev/null and b/2016/content/textures/ui/mouseLock_on@2x.png differ diff --git a/2016/content/textures/ui/newBkg_square.png b/2016/content/textures/ui/newBkg_square.png new file mode 100644 index 0000000..923826c Binary files /dev/null and b/2016/content/textures/ui/newBkg_square.png differ diff --git a/2016/content/textures/ui/newBkg_square@2x.png b/2016/content/textures/ui/newBkg_square@2x.png new file mode 100644 index 0000000..ab0e64c Binary files /dev/null and b/2016/content/textures/ui/newBkg_square@2x.png differ diff --git a/2016/content/textures/ui/scroll-bottom.png b/2016/content/textures/ui/scroll-bottom.png new file mode 100644 index 0000000..2db02a8 Binary files /dev/null and b/2016/content/textures/ui/scroll-bottom.png differ diff --git a/2016/content/textures/ui/scroll-bottom@2x.png b/2016/content/textures/ui/scroll-bottom@2x.png new file mode 100644 index 0000000..713ade5 Binary files /dev/null and b/2016/content/textures/ui/scroll-bottom@2x.png differ diff --git a/2016/content/textures/ui/scroll-middle.png b/2016/content/textures/ui/scroll-middle.png new file mode 100644 index 0000000..7ef7495 Binary files /dev/null and b/2016/content/textures/ui/scroll-middle.png differ diff --git a/2016/content/textures/ui/scroll-middle@2x.png b/2016/content/textures/ui/scroll-middle@2x.png new file mode 100644 index 0000000..9162507 Binary files /dev/null and b/2016/content/textures/ui/scroll-middle@2x.png differ diff --git a/2016/content/textures/ui/scroll-top.png b/2016/content/textures/ui/scroll-top.png new file mode 100644 index 0000000..2bcfd00 Binary files /dev/null and b/2016/content/textures/ui/scroll-top.png differ diff --git a/2016/content/textures/ui/scroll-top@2x.png b/2016/content/textures/ui/scroll-top@2x.png new file mode 100644 index 0000000..50e5389 Binary files /dev/null and b/2016/content/textures/ui/scroll-top@2x.png differ diff --git a/2016/content/textures/ui/scrollbar.png b/2016/content/textures/ui/scrollbar.png new file mode 100644 index 0000000..9d7a4ff Binary files /dev/null and b/2016/content/textures/ui/scrollbar.png differ diff --git a/2016/content/textures/ui/scrollbuttonDown.png b/2016/content/textures/ui/scrollbuttonDown.png new file mode 100644 index 0000000..a3e6539 Binary files /dev/null and b/2016/content/textures/ui/scrollbuttonDown.png differ diff --git a/2016/content/textures/ui/scrollbuttonDown_dn.png b/2016/content/textures/ui/scrollbuttonDown_dn.png new file mode 100644 index 0000000..f7002ce Binary files /dev/null and b/2016/content/textures/ui/scrollbuttonDown_dn.png differ diff --git a/2016/content/textures/ui/scrollbuttonDown_ds.png b/2016/content/textures/ui/scrollbuttonDown_ds.png new file mode 100644 index 0000000..eac4eb9 Binary files /dev/null and b/2016/content/textures/ui/scrollbuttonDown_ds.png differ diff --git a/2016/content/textures/ui/scrollbuttonDown_ovr.png b/2016/content/textures/ui/scrollbuttonDown_ovr.png new file mode 100644 index 0000000..f7002ce Binary files /dev/null and b/2016/content/textures/ui/scrollbuttonDown_ovr.png differ diff --git a/2016/content/textures/ui/scrollbuttonUp.png b/2016/content/textures/ui/scrollbuttonUp.png new file mode 100644 index 0000000..5754f55 Binary files /dev/null and b/2016/content/textures/ui/scrollbuttonUp.png differ diff --git a/2016/content/textures/ui/scrollbuttonUp_dn.png b/2016/content/textures/ui/scrollbuttonUp_dn.png new file mode 100644 index 0000000..f12d690 Binary files /dev/null and b/2016/content/textures/ui/scrollbuttonUp_dn.png differ diff --git a/2016/content/textures/ui/scrollbuttonUp_ds.png b/2016/content/textures/ui/scrollbuttonUp_ds.png new file mode 100644 index 0000000..1e1b9db Binary files /dev/null and b/2016/content/textures/ui/scrollbuttonUp_ds.png differ diff --git a/2016/content/textures/ui/scrollbuttonUp_ovr.png b/2016/content/textures/ui/scrollbuttonUp_ovr.png new file mode 100644 index 0000000..f12d690 Binary files /dev/null and b/2016/content/textures/ui/scrollbuttonUp_ovr.png differ diff --git a/2016/content/textures/ui/slider_new_tab.png b/2016/content/textures/ui/slider_new_tab.png new file mode 100644 index 0000000..8ecb85a Binary files /dev/null and b/2016/content/textures/ui/slider_new_tab.png differ diff --git a/2016/content/textures/ui/slider_new_tab@2x.png b/2016/content/textures/ui/slider_new_tab@2x.png new file mode 100644 index 0000000..674c6ff Binary files /dev/null and b/2016/content/textures/ui/slider_new_tab@2x.png differ diff --git a/2016/content/textures/ui/vr_active.png b/2016/content/textures/ui/vr_active.png new file mode 100644 index 0000000..a36deb9 Binary files /dev/null and b/2016/content/textures/ui/vr_active.png differ diff --git a/2016/content/textures/ui/vr_idle.png b/2016/content/textures/ui/vr_idle.png new file mode 100644 index 0000000..f101f5d Binary files /dev/null and b/2016/content/textures/ui/vr_idle.png differ diff --git a/2016/content/textures/water_Subsurface.dds b/2016/content/textures/water_Subsurface.dds new file mode 100644 index 0000000..0435f14 Binary files /dev/null and b/2016/content/textures/water_Subsurface.dds differ diff --git a/2016/content/textures/water_Wave.dds b/2016/content/textures/water_Wave.dds new file mode 100644 index 0000000..fc2f7a0 Binary files /dev/null and b/2016/content/textures/water_Wave.dds differ diff --git a/2016/content/textures/wrench.png b/2016/content/textures/wrench.png new file mode 100644 index 0000000..5c8213f Binary files /dev/null and b/2016/content/textures/wrench.png differ diff --git a/2016/fmod.dll b/2016/fmod.dll new file mode 100644 index 0000000..64e485b Binary files /dev/null and b/2016/fmod.dll differ diff --git a/2016/fmodex.dll b/2016/fmodex.dll new file mode 100644 index 0000000..d91f410 Binary files /dev/null and b/2016/fmodex.dll differ diff --git a/2016/msvcp110.dll b/2016/msvcp110.dll new file mode 100644 index 0000000..93fab56 Binary files /dev/null and b/2016/msvcp110.dll differ diff --git a/2016/msvcr110.dll b/2016/msvcr110.dll new file mode 100644 index 0000000..1ce960d Binary files /dev/null and b/2016/msvcr110.dll differ diff --git a/2016/openvr_api.dll b/2016/openvr_api.dll new file mode 100644 index 0000000..0b0cc0e Binary files /dev/null and b/2016/openvr_api.dll differ diff --git a/2016/shaders/keepme b/2016/shaders/keepme new file mode 100644 index 0000000..e69de29 diff --git a/2016/shaders/shaders_d3d10.pack b/2016/shaders/shaders_d3d10.pack new file mode 100644 index 0000000..2fb9437 Binary files /dev/null and b/2016/shaders/shaders_d3d10.pack differ diff --git a/2016/shaders/shaders_d3d10_1.pack b/2016/shaders/shaders_d3d10_1.pack new file mode 100644 index 0000000..d2e0043 Binary files /dev/null and b/2016/shaders/shaders_d3d10_1.pack differ diff --git a/2016/shaders/shaders_d3d11.pack b/2016/shaders/shaders_d3d11.pack new file mode 100644 index 0000000..e1e0d76 Binary files /dev/null and b/2016/shaders/shaders_d3d11.pack differ diff --git a/2016/shaders/shaders_d3d9.pack b/2016/shaders/shaders_d3d9.pack new file mode 100644 index 0000000..2ecd822 Binary files /dev/null and b/2016/shaders/shaders_d3d9.pack differ diff --git a/2016/shaders/shaders_glsl.pack b/2016/shaders/shaders_glsl.pack new file mode 100644 index 0000000..fd1c4ac Binary files /dev/null and b/2016/shaders/shaders_glsl.pack differ diff --git a/2016/shaders/shaders_glsl3.pack b/2016/shaders/shaders_glsl3.pack new file mode 100644 index 0000000..a3f8fc2 Binary files /dev/null and b/2016/shaders/shaders_glsl3.pack differ diff --git a/2016/tbb.dll b/2016/tbb.dll new file mode 100644 index 0000000..919da8b Binary files /dev/null and b/2016/tbb.dll differ diff --git a/2016/tbb_debug.dll b/2016/tbb_debug.dll new file mode 100644 index 0000000..c368a7e Binary files /dev/null and b/2016/tbb_debug.dll differ diff --git a/2018/AppSettings.xml b/2018/AppSettings.xml new file mode 100644 index 0000000..faae68e --- /dev/null +++ b/2018/AppSettings.xml @@ -0,0 +1,5 @@ + + + content + http://www.vortexi.cc + diff --git a/2018/PlatformContent/pc/fonts/NotoSansCJKjp-Regular.otf b/2018/PlatformContent/pc/fonts/NotoSansCJKjp-Regular.otf new file mode 100644 index 0000000..296fbeb Binary files /dev/null and b/2018/PlatformContent/pc/fonts/NotoSansCJKjp-Regular.otf differ diff --git a/2018/PlatformContent/pc/terrain/diffuse.dds b/2018/PlatformContent/pc/terrain/diffuse.dds new file mode 100644 index 0000000..8024eba Binary files /dev/null and b/2018/PlatformContent/pc/terrain/diffuse.dds differ diff --git a/2018/PlatformContent/pc/terrain/diffusearray.dds b/2018/PlatformContent/pc/terrain/diffusearray.dds new file mode 100644 index 0000000..af28a9e Binary files /dev/null and b/2018/PlatformContent/pc/terrain/diffusearray.dds differ diff --git a/2018/PlatformContent/pc/terrain/materials.json b/2018/PlatformContent/pc/terrain/materials.json new file mode 100644 index 0000000..3de6276 --- /dev/null +++ b/2018/PlatformContent/pc/terrain/materials.json @@ -0,0 +1,191 @@ +{ + "platform": "pc", + "atlas": + { + "pc": { + "width": 2048, + "height": 2048, + "tileSize": 256, + "tileCount": 6, + + "sliceSize": 512, + + "borderSize": 42 + }, + "ios": { + "width": 2048, + "height": 2048, + "tileSize": 256, + "tileCount": 6, + + "borderSize": 42 + }, + "android": { + "width": 2048, + "height": 2048, + "tileSize": 256, + "tileCount": 6, + + "borderSize": 42 + }, + "durango": { + "width": 32, + "height": 32, + "tileSize": 4, + "tileCount": 6, + + "sliceSize": 512, + + "borderSize": 42 + } + }, + "materials": + [ + { + "name": "Air" + }, + { + "name": "Water", + "water": 0.5 + }, + { + "name": "Grass", + "base_color": [ 106, 127, 63 ], + "texture_top": { "tiling": 0.25, "detiling": 0.25, "rotation": 1.0 }, + "texture_side": { "tiling": 0.2, "detiling": 0.2 }, + "texture_bottom": { "tiling": 0.45, "detiling": 0.45 } + }, + { + "name": "Slate", + "base_color": [ 63, 127, 107 ], + "shift": 0.1, + "texture": { "tiling": 0.55, "detiling": 0.55 } + }, + { + "name": "Concrete", + "base_color": [ 127, 102, 63 ], + "quantize": 0.5, + "type": "hard", + "texture_top": { "tiling": 0.5, "detiling": 0.8 }, + "texture_side": { "tiling": 0.4, "detiling": 0.4 } + }, + { + "name": "Brick", + "base_color": [ 138, 86, 62 ], + "cubify": 1, + "type": "hard", + "mapping": "cube", + "texture": { "tiling": 0.80, "detiling": 0.20 } + }, + { + "name": "Sand", + "base_color": [ 143, 126, 95 ], + "texture_top": { "tiling": 0.25, "detiling": 0.25 }, + "texture_side": { "tiling": 0.25, "detiling": 0.55 } + }, + { + "name": "WoodPlanks", + "base_color": [ 139, 109, 79 ], + "cubify": 1.0, + "type": "hard", + "mapping": "cube", + "texture": { "tiling": 0.8, "detiling": 0.5 } + }, + { + "name": "Rock", + "base_color": [ 102, 108, 111 ], + "shift": 0.3, + "type": "hardsoft", + "texture": { "tiling": 0.55, "detiling": 0.55, "rotation": 0.5 } + }, + { + "name": "Glacier", + "base_color": [ 101, 176, 234 ], + "texture_top": { "tiling": 0.23, "detiling": 0.55 }, + "texture_side": { "tiling": 0.2, "detiling": 0.9 }, + "texture_bottom": { "tiling": 0.23, "detiling": 0.6 } + }, + { + "name": "Snow", + "base_color": [ 195, 199, 218 ], + "texture": { "tiling": 0.3, "detiling": 0.3 } + }, + { + "name": "Sandstone", + "base_color": [ 137, 90, 71 ], + "texture_top": { "tiling": 0.5, "detiling": 0.7, "rotation": 0.5 }, + "texture_side": { "tiling": 0.3, "detiling": 0.5003 }, + "texture_bottom": { "tiling": 0.45, "detiling": 0.45 } + }, + { + "name": "Mud", + "base_color": [ 58, 46, 36 ], + "texture": { "tiling": 0.3, "detiling": 0.1 } + }, + { + "name": "Basalt", + "base_color": [ 30, 30, 37 ], + "shift": 0.2, + "type": "hardsoft", + "texture": { "tiling": 0.55, "detiling": 0.55 } + }, + { + "name": "Ground", + "base_color": [ 102, 92, 59 ], + "texture": { "tiling": 0.3, "detiling": 0.3, "rotation": 0.5 } + }, + { + "name": "CrackedLava", + "base_color": [ 232, 156, 74 ], + "shift": 0.1, + "texture": { "tiling": 0.28, "detiling": 0.3, "rotation": 0.5 } + }, + { + "name": "Asphalt", + "base_color": [ 115, 123, 107 ], + "texture_top": { "tiling": 0.25, "detiling": 0.23 }, + "texture_side": { "tiling": 0.2, "detiling": 0.9 } + }, + { + "name": "Cobblestone", + "base_color": [ 132, 123, 90 ], + "quantize": 0.15, + "type": "hardsoft", + "texture_top": { "tiling": 0.23, "detiling": 0.25 }, + "texture_side": { "tiling": 0.2, "detiling": 0.9 } + }, + { + "name": "Ice", + "base_color": [ 129, 194, 224 ], + "shift": 0.15, + "texture_top": { "tiling": 0.25, "detiling": 0.25, "rotation": 0.1 }, + "texture_side": { "tiling": 0.25, "detiling": 0.25 } + }, + { + "name": "LeafyGrass", + "base_color": [ 115, 132, 74 ], + "texture_top": { "tiling": 0.25, "detiling": 0.33, "rotation": 1 }, + "texture_side": { "tiling": 0.25, "detiling": 0.25 } + }, + { + "name": "Salt", + "base_color": [ 198, 189, 181 ], + "texture_top": { "tiling": 0.23, "detiling": 0.55 }, + "texture_side": { "tiling": 0.2, "detiling": 0.9} + }, + { + "name": "Limestone", + "base_color": [ 206, 173, 148 ], + "texture_top": { "tiling": 0.25, "detiling": 0.55, "rotation": 0.1 }, + "texture_side": { "tiling": 0.25, "detiling": 0.5 } + }, + { + "name": "Pavement", + "base_color": [ 148, 148, 140 ], + "quantize": 0.25, + "type": "hardsoft", + "texture_top": { "tiling": 0.46, "detiling": 0.25 }, + "texture_side": { "tiling": 0.46, "detiling": 0.25 } + } + ] +} diff --git a/2018/PlatformContent/pc/terrain/normal.dds b/2018/PlatformContent/pc/terrain/normal.dds new file mode 100644 index 0000000..7da4097 Binary files /dev/null and b/2018/PlatformContent/pc/terrain/normal.dds differ diff --git a/2018/PlatformContent/pc/terrain/normalarray.dds b/2018/PlatformContent/pc/terrain/normalarray.dds new file mode 100644 index 0000000..5d3417b Binary files /dev/null and b/2018/PlatformContent/pc/terrain/normalarray.dds differ diff --git a/2018/PlatformContent/pc/terrain/specular.dds b/2018/PlatformContent/pc/terrain/specular.dds new file mode 100644 index 0000000..8c2d0bf Binary files /dev/null and b/2018/PlatformContent/pc/terrain/specular.dds differ diff --git a/2018/PlatformContent/pc/terrain/speculararray.dds b/2018/PlatformContent/pc/terrain/speculararray.dds new file mode 100644 index 0000000..0440b68 Binary files /dev/null and b/2018/PlatformContent/pc/terrain/speculararray.dds differ diff --git a/2018/PlatformContent/pc/textures/aluminum/diffuse.dds b/2018/PlatformContent/pc/textures/aluminum/diffuse.dds new file mode 100644 index 0000000..fee64f0 Binary files /dev/null and b/2018/PlatformContent/pc/textures/aluminum/diffuse.dds differ diff --git a/2018/PlatformContent/pc/textures/aluminum/normal.dds b/2018/PlatformContent/pc/textures/aluminum/normal.dds new file mode 100644 index 0000000..466fcb4 Binary files /dev/null and b/2018/PlatformContent/pc/textures/aluminum/normal.dds differ diff --git a/2018/PlatformContent/pc/textures/aluminum/normaldetail.dds b/2018/PlatformContent/pc/textures/aluminum/normaldetail.dds new file mode 100644 index 0000000..818b2a8 Binary files /dev/null and b/2018/PlatformContent/pc/textures/aluminum/normaldetail.dds differ diff --git a/2018/PlatformContent/pc/textures/aluminum/specular.dds b/2018/PlatformContent/pc/textures/aluminum/specular.dds new file mode 100644 index 0000000..1cd4a27 Binary files /dev/null and b/2018/PlatformContent/pc/textures/aluminum/specular.dds differ diff --git a/2018/PlatformContent/pc/textures/brick/diffuse.dds b/2018/PlatformContent/pc/textures/brick/diffuse.dds new file mode 100644 index 0000000..7f3af23 Binary files /dev/null and b/2018/PlatformContent/pc/textures/brick/diffuse.dds differ diff --git a/2018/PlatformContent/pc/textures/brick/normal.dds b/2018/PlatformContent/pc/textures/brick/normal.dds new file mode 100644 index 0000000..1548f2a Binary files /dev/null and b/2018/PlatformContent/pc/textures/brick/normal.dds differ diff --git a/2018/PlatformContent/pc/textures/brick/normaldetail.dds b/2018/PlatformContent/pc/textures/brick/normaldetail.dds new file mode 100644 index 0000000..818b2a8 Binary files /dev/null and b/2018/PlatformContent/pc/textures/brick/normaldetail.dds differ diff --git a/2018/PlatformContent/pc/textures/brick/specular.dds b/2018/PlatformContent/pc/textures/brick/specular.dds new file mode 100644 index 0000000..0ff01dd Binary files /dev/null and b/2018/PlatformContent/pc/textures/brick/specular.dds differ diff --git a/2018/PlatformContent/pc/textures/cobblestone/diffuse.dds b/2018/PlatformContent/pc/textures/cobblestone/diffuse.dds new file mode 100644 index 0000000..1e1eab9 Binary files /dev/null and b/2018/PlatformContent/pc/textures/cobblestone/diffuse.dds differ diff --git a/2018/PlatformContent/pc/textures/cobblestone/normal.dds b/2018/PlatformContent/pc/textures/cobblestone/normal.dds new file mode 100644 index 0000000..2cfc1ad Binary files /dev/null and b/2018/PlatformContent/pc/textures/cobblestone/normal.dds differ diff --git a/2018/PlatformContent/pc/textures/cobblestone/normaldetail.dds b/2018/PlatformContent/pc/textures/cobblestone/normaldetail.dds new file mode 100644 index 0000000..818b2a8 Binary files /dev/null and b/2018/PlatformContent/pc/textures/cobblestone/normaldetail.dds differ diff --git a/2018/PlatformContent/pc/textures/cobblestone/specular.dds b/2018/PlatformContent/pc/textures/cobblestone/specular.dds new file mode 100644 index 0000000..6d14457 Binary files /dev/null and b/2018/PlatformContent/pc/textures/cobblestone/specular.dds differ diff --git a/2018/PlatformContent/pc/textures/concrete/diffuse.dds b/2018/PlatformContent/pc/textures/concrete/diffuse.dds new file mode 100644 index 0000000..2174765 Binary files /dev/null and b/2018/PlatformContent/pc/textures/concrete/diffuse.dds differ diff --git a/2018/PlatformContent/pc/textures/concrete/normal.dds b/2018/PlatformContent/pc/textures/concrete/normal.dds new file mode 100644 index 0000000..dfd9bb8 Binary files /dev/null and b/2018/PlatformContent/pc/textures/concrete/normal.dds differ diff --git a/2018/PlatformContent/pc/textures/concrete/normaldetail.dds b/2018/PlatformContent/pc/textures/concrete/normaldetail.dds new file mode 100644 index 0000000..5c11a43 Binary files /dev/null and b/2018/PlatformContent/pc/textures/concrete/normaldetail.dds differ diff --git a/2018/PlatformContent/pc/textures/concrete/specular.dds b/2018/PlatformContent/pc/textures/concrete/specular.dds new file mode 100644 index 0000000..bfeb384 Binary files /dev/null and b/2018/PlatformContent/pc/textures/concrete/specular.dds differ diff --git a/2018/PlatformContent/pc/textures/diamondplate/diffuse.dds b/2018/PlatformContent/pc/textures/diamondplate/diffuse.dds new file mode 100644 index 0000000..e4f5f3a Binary files /dev/null and b/2018/PlatformContent/pc/textures/diamondplate/diffuse.dds differ diff --git a/2018/PlatformContent/pc/textures/diamondplate/normal.dds b/2018/PlatformContent/pc/textures/diamondplate/normal.dds new file mode 100644 index 0000000..88ece5f Binary files /dev/null and b/2018/PlatformContent/pc/textures/diamondplate/normal.dds differ diff --git a/2018/PlatformContent/pc/textures/diamondplate/normaldetail.dds b/2018/PlatformContent/pc/textures/diamondplate/normaldetail.dds new file mode 100644 index 0000000..818b2a8 Binary files /dev/null and b/2018/PlatformContent/pc/textures/diamondplate/normaldetail.dds differ diff --git a/2018/PlatformContent/pc/textures/diamondplate/specular.dds b/2018/PlatformContent/pc/textures/diamondplate/specular.dds new file mode 100644 index 0000000..9154362 Binary files /dev/null and b/2018/PlatformContent/pc/textures/diamondplate/specular.dds differ diff --git a/2018/PlatformContent/pc/textures/fabric/diffuse.dds b/2018/PlatformContent/pc/textures/fabric/diffuse.dds new file mode 100644 index 0000000..a0efd50 Binary files /dev/null and b/2018/PlatformContent/pc/textures/fabric/diffuse.dds differ diff --git a/2018/PlatformContent/pc/textures/fabric/normal.dds b/2018/PlatformContent/pc/textures/fabric/normal.dds new file mode 100644 index 0000000..4025a92 Binary files /dev/null and b/2018/PlatformContent/pc/textures/fabric/normal.dds differ diff --git a/2018/PlatformContent/pc/textures/fabric/normaldetail.dds b/2018/PlatformContent/pc/textures/fabric/normaldetail.dds new file mode 100644 index 0000000..818b2a8 Binary files /dev/null and b/2018/PlatformContent/pc/textures/fabric/normaldetail.dds differ diff --git a/2018/PlatformContent/pc/textures/fabric/specular.dds b/2018/PlatformContent/pc/textures/fabric/specular.dds new file mode 100644 index 0000000..e3c973d Binary files /dev/null and b/2018/PlatformContent/pc/textures/fabric/specular.dds differ diff --git a/2018/PlatformContent/pc/textures/glass/diffuse.dds b/2018/PlatformContent/pc/textures/glass/diffuse.dds new file mode 100644 index 0000000..76365f7 Binary files /dev/null and b/2018/PlatformContent/pc/textures/glass/diffuse.dds differ diff --git a/2018/PlatformContent/pc/textures/glass/normal.dds b/2018/PlatformContent/pc/textures/glass/normal.dds new file mode 100644 index 0000000..2159af6 Binary files /dev/null and b/2018/PlatformContent/pc/textures/glass/normal.dds differ diff --git a/2018/PlatformContent/pc/textures/glass/normaldetail.dds b/2018/PlatformContent/pc/textures/glass/normaldetail.dds new file mode 100644 index 0000000..818b2a8 Binary files /dev/null and b/2018/PlatformContent/pc/textures/glass/normaldetail.dds differ diff --git a/2018/PlatformContent/pc/textures/glass/specular.dds b/2018/PlatformContent/pc/textures/glass/specular.dds new file mode 100644 index 0000000..9bba956 Binary files /dev/null and b/2018/PlatformContent/pc/textures/glass/specular.dds differ diff --git a/2018/PlatformContent/pc/textures/granite/diffuse.dds b/2018/PlatformContent/pc/textures/granite/diffuse.dds new file mode 100644 index 0000000..bd67946 Binary files /dev/null and b/2018/PlatformContent/pc/textures/granite/diffuse.dds differ diff --git a/2018/PlatformContent/pc/textures/granite/normal.dds b/2018/PlatformContent/pc/textures/granite/normal.dds new file mode 100644 index 0000000..1a168d9 Binary files /dev/null and b/2018/PlatformContent/pc/textures/granite/normal.dds differ diff --git a/2018/PlatformContent/pc/textures/granite/normaldetail.dds b/2018/PlatformContent/pc/textures/granite/normaldetail.dds new file mode 100644 index 0000000..818b2a8 Binary files /dev/null and b/2018/PlatformContent/pc/textures/granite/normaldetail.dds differ diff --git a/2018/PlatformContent/pc/textures/granite/specular.dds b/2018/PlatformContent/pc/textures/granite/specular.dds new file mode 100644 index 0000000..aba04d5 Binary files /dev/null and b/2018/PlatformContent/pc/textures/granite/specular.dds differ diff --git a/2018/PlatformContent/pc/textures/grass/diffuse.dds b/2018/PlatformContent/pc/textures/grass/diffuse.dds new file mode 100644 index 0000000..c526c08 Binary files /dev/null and b/2018/PlatformContent/pc/textures/grass/diffuse.dds differ diff --git a/2018/PlatformContent/pc/textures/grass/normal.dds b/2018/PlatformContent/pc/textures/grass/normal.dds new file mode 100644 index 0000000..ba00e17 Binary files /dev/null and b/2018/PlatformContent/pc/textures/grass/normal.dds differ diff --git a/2018/PlatformContent/pc/textures/grass/normaldetail.dds b/2018/PlatformContent/pc/textures/grass/normaldetail.dds new file mode 100644 index 0000000..818b2a8 Binary files /dev/null and b/2018/PlatformContent/pc/textures/grass/normaldetail.dds differ diff --git a/2018/PlatformContent/pc/textures/grass/specular.dds b/2018/PlatformContent/pc/textures/grass/specular.dds new file mode 100644 index 0000000..eb3fcbb Binary files /dev/null and b/2018/PlatformContent/pc/textures/grass/specular.dds differ diff --git a/2018/PlatformContent/pc/textures/ice/diffuse.dds b/2018/PlatformContent/pc/textures/ice/diffuse.dds new file mode 100644 index 0000000..fee64f0 Binary files /dev/null and b/2018/PlatformContent/pc/textures/ice/diffuse.dds differ diff --git a/2018/PlatformContent/pc/textures/ice/normal.dds b/2018/PlatformContent/pc/textures/ice/normal.dds new file mode 100644 index 0000000..8752407 Binary files /dev/null and b/2018/PlatformContent/pc/textures/ice/normal.dds differ diff --git a/2018/PlatformContent/pc/textures/ice/normaldetail.dds b/2018/PlatformContent/pc/textures/ice/normaldetail.dds new file mode 100644 index 0000000..818b2a8 Binary files /dev/null and b/2018/PlatformContent/pc/textures/ice/normaldetail.dds differ diff --git a/2018/PlatformContent/pc/textures/ice/specular.dds b/2018/PlatformContent/pc/textures/ice/specular.dds new file mode 100644 index 0000000..4689e14 Binary files /dev/null and b/2018/PlatformContent/pc/textures/ice/specular.dds differ diff --git a/2018/PlatformContent/pc/textures/marble/diffuse.dds b/2018/PlatformContent/pc/textures/marble/diffuse.dds new file mode 100644 index 0000000..ca63066 Binary files /dev/null and b/2018/PlatformContent/pc/textures/marble/diffuse.dds differ diff --git a/2018/PlatformContent/pc/textures/marble/normal.dds b/2018/PlatformContent/pc/textures/marble/normal.dds new file mode 100644 index 0000000..211ce43 Binary files /dev/null and b/2018/PlatformContent/pc/textures/marble/normal.dds differ diff --git a/2018/PlatformContent/pc/textures/marble/normaldetail.dds b/2018/PlatformContent/pc/textures/marble/normaldetail.dds new file mode 100644 index 0000000..818b2a8 Binary files /dev/null and b/2018/PlatformContent/pc/textures/marble/normaldetail.dds differ diff --git a/2018/PlatformContent/pc/textures/marble/specular.dds b/2018/PlatformContent/pc/textures/marble/specular.dds new file mode 100644 index 0000000..5902a8d Binary files /dev/null and b/2018/PlatformContent/pc/textures/marble/specular.dds differ diff --git a/2018/PlatformContent/pc/textures/metal/diffuse.dds b/2018/PlatformContent/pc/textures/metal/diffuse.dds new file mode 100644 index 0000000..72ac322 Binary files /dev/null and b/2018/PlatformContent/pc/textures/metal/diffuse.dds differ diff --git a/2018/PlatformContent/pc/textures/metal/normal.dds b/2018/PlatformContent/pc/textures/metal/normal.dds new file mode 100644 index 0000000..c4e5757 Binary files /dev/null and b/2018/PlatformContent/pc/textures/metal/normal.dds differ diff --git a/2018/PlatformContent/pc/textures/metal/normaldetail.dds b/2018/PlatformContent/pc/textures/metal/normaldetail.dds new file mode 100644 index 0000000..818b2a8 Binary files /dev/null and b/2018/PlatformContent/pc/textures/metal/normaldetail.dds differ diff --git a/2018/PlatformContent/pc/textures/metal/specular.dds b/2018/PlatformContent/pc/textures/metal/specular.dds new file mode 100644 index 0000000..98a9f60 Binary files /dev/null and b/2018/PlatformContent/pc/textures/metal/specular.dds differ diff --git a/2018/PlatformContent/pc/textures/noise.dds b/2018/PlatformContent/pc/textures/noise.dds new file mode 100644 index 0000000..9e6d65f Binary files /dev/null and b/2018/PlatformContent/pc/textures/noise.dds differ diff --git a/2018/PlatformContent/pc/textures/pebble/diffuse.dds b/2018/PlatformContent/pc/textures/pebble/diffuse.dds new file mode 100644 index 0000000..48b56cc Binary files /dev/null and b/2018/PlatformContent/pc/textures/pebble/diffuse.dds differ diff --git a/2018/PlatformContent/pc/textures/pebble/normal.dds b/2018/PlatformContent/pc/textures/pebble/normal.dds new file mode 100644 index 0000000..818b2a8 Binary files /dev/null and b/2018/PlatformContent/pc/textures/pebble/normal.dds differ diff --git a/2018/PlatformContent/pc/textures/pebble/normaldetail.dds b/2018/PlatformContent/pc/textures/pebble/normaldetail.dds new file mode 100644 index 0000000..818b2a8 Binary files /dev/null and b/2018/PlatformContent/pc/textures/pebble/normaldetail.dds differ diff --git a/2018/PlatformContent/pc/textures/pebble/specular.dds b/2018/PlatformContent/pc/textures/pebble/specular.dds new file mode 100644 index 0000000..bfeb384 Binary files /dev/null and b/2018/PlatformContent/pc/textures/pebble/specular.dds differ diff --git a/2018/PlatformContent/pc/textures/plastic/diffuse.dds b/2018/PlatformContent/pc/textures/plastic/diffuse.dds new file mode 100644 index 0000000..d4850dd Binary files /dev/null and b/2018/PlatformContent/pc/textures/plastic/diffuse.dds differ diff --git a/2018/PlatformContent/pc/textures/plastic/normal.dds b/2018/PlatformContent/pc/textures/plastic/normal.dds new file mode 100644 index 0000000..3c2bf19 Binary files /dev/null and b/2018/PlatformContent/pc/textures/plastic/normal.dds differ diff --git a/2018/PlatformContent/pc/textures/plastic/normaldetail.dds b/2018/PlatformContent/pc/textures/plastic/normaldetail.dds new file mode 100644 index 0000000..29140fd Binary files /dev/null and b/2018/PlatformContent/pc/textures/plastic/normaldetail.dds differ diff --git a/2018/PlatformContent/pc/textures/rust/diffuse.dds b/2018/PlatformContent/pc/textures/rust/diffuse.dds new file mode 100644 index 0000000..59a4221 Binary files /dev/null and b/2018/PlatformContent/pc/textures/rust/diffuse.dds differ diff --git a/2018/PlatformContent/pc/textures/rust/normal.dds b/2018/PlatformContent/pc/textures/rust/normal.dds new file mode 100644 index 0000000..7d15959 Binary files /dev/null and b/2018/PlatformContent/pc/textures/rust/normal.dds differ diff --git a/2018/PlatformContent/pc/textures/rust/normaldetail.dds b/2018/PlatformContent/pc/textures/rust/normaldetail.dds new file mode 100644 index 0000000..818b2a8 Binary files /dev/null and b/2018/PlatformContent/pc/textures/rust/normaldetail.dds differ diff --git a/2018/PlatformContent/pc/textures/rust/specular.dds b/2018/PlatformContent/pc/textures/rust/specular.dds new file mode 100644 index 0000000..9c3133e Binary files /dev/null and b/2018/PlatformContent/pc/textures/rust/specular.dds differ diff --git a/2018/PlatformContent/pc/textures/sand/diffuse.dds b/2018/PlatformContent/pc/textures/sand/diffuse.dds new file mode 100644 index 0000000..5b91413 Binary files /dev/null and b/2018/PlatformContent/pc/textures/sand/diffuse.dds differ diff --git a/2018/PlatformContent/pc/textures/sand/normal.dds b/2018/PlatformContent/pc/textures/sand/normal.dds new file mode 100644 index 0000000..c8a2c84 Binary files /dev/null and b/2018/PlatformContent/pc/textures/sand/normal.dds differ diff --git a/2018/PlatformContent/pc/textures/sand/normaldetail.dds b/2018/PlatformContent/pc/textures/sand/normaldetail.dds new file mode 100644 index 0000000..818b2a8 Binary files /dev/null and b/2018/PlatformContent/pc/textures/sand/normaldetail.dds differ diff --git a/2018/PlatformContent/pc/textures/sand/specular.dds b/2018/PlatformContent/pc/textures/sand/specular.dds new file mode 100644 index 0000000..6efec1b Binary files /dev/null and b/2018/PlatformContent/pc/textures/sand/specular.dds differ diff --git a/2018/PlatformContent/pc/textures/sky/sky512_bk.tex b/2018/PlatformContent/pc/textures/sky/sky512_bk.tex new file mode 100644 index 0000000..fcdd232 Binary files /dev/null and b/2018/PlatformContent/pc/textures/sky/sky512_bk.tex differ diff --git a/2018/PlatformContent/pc/textures/sky/sky512_dn.tex b/2018/PlatformContent/pc/textures/sky/sky512_dn.tex new file mode 100644 index 0000000..d63e52d Binary files /dev/null and b/2018/PlatformContent/pc/textures/sky/sky512_dn.tex differ diff --git a/2018/PlatformContent/pc/textures/sky/sky512_ft.tex b/2018/PlatformContent/pc/textures/sky/sky512_ft.tex new file mode 100644 index 0000000..215b51b Binary files /dev/null and b/2018/PlatformContent/pc/textures/sky/sky512_ft.tex differ diff --git a/2018/PlatformContent/pc/textures/sky/sky512_lf.tex b/2018/PlatformContent/pc/textures/sky/sky512_lf.tex new file mode 100644 index 0000000..a096acf Binary files /dev/null and b/2018/PlatformContent/pc/textures/sky/sky512_lf.tex differ diff --git a/2018/PlatformContent/pc/textures/sky/sky512_rt.tex b/2018/PlatformContent/pc/textures/sky/sky512_rt.tex new file mode 100644 index 0000000..6c0aaf1 Binary files /dev/null and b/2018/PlatformContent/pc/textures/sky/sky512_rt.tex differ diff --git a/2018/PlatformContent/pc/textures/sky/sky512_up.tex b/2018/PlatformContent/pc/textures/sky/sky512_up.tex new file mode 100644 index 0000000..a973654 Binary files /dev/null and b/2018/PlatformContent/pc/textures/sky/sky512_up.tex differ diff --git a/2018/PlatformContent/pc/textures/slate/diffuse.dds b/2018/PlatformContent/pc/textures/slate/diffuse.dds new file mode 100644 index 0000000..ff7ca6d Binary files /dev/null and b/2018/PlatformContent/pc/textures/slate/diffuse.dds differ diff --git a/2018/PlatformContent/pc/textures/slate/normal.dds b/2018/PlatformContent/pc/textures/slate/normal.dds new file mode 100644 index 0000000..6f38346 Binary files /dev/null and b/2018/PlatformContent/pc/textures/slate/normal.dds differ diff --git a/2018/PlatformContent/pc/textures/slate/normaldetail.dds b/2018/PlatformContent/pc/textures/slate/normaldetail.dds new file mode 100644 index 0000000..7e6b0ca Binary files /dev/null and b/2018/PlatformContent/pc/textures/slate/normaldetail.dds differ diff --git a/2018/PlatformContent/pc/textures/slate/specular.dds b/2018/PlatformContent/pc/textures/slate/specular.dds new file mode 100644 index 0000000..271b6c1 Binary files /dev/null and b/2018/PlatformContent/pc/textures/slate/specular.dds differ diff --git a/2018/PlatformContent/pc/textures/studs.dds b/2018/PlatformContent/pc/textures/studs.dds new file mode 100644 index 0000000..6ff77fb Binary files /dev/null and b/2018/PlatformContent/pc/textures/studs.dds differ diff --git a/2018/PlatformContent/pc/textures/wangIndex.dds b/2018/PlatformContent/pc/textures/wangIndex.dds new file mode 100644 index 0000000..e613ff1 Binary files /dev/null and b/2018/PlatformContent/pc/textures/wangIndex.dds differ diff --git a/2018/PlatformContent/pc/textures/water/normal_01.dds b/2018/PlatformContent/pc/textures/water/normal_01.dds new file mode 100644 index 0000000..e5b879d Binary files /dev/null and b/2018/PlatformContent/pc/textures/water/normal_01.dds differ diff --git a/2018/PlatformContent/pc/textures/water/normal_02.dds b/2018/PlatformContent/pc/textures/water/normal_02.dds new file mode 100644 index 0000000..1398f8e Binary files /dev/null and b/2018/PlatformContent/pc/textures/water/normal_02.dds differ diff --git a/2018/PlatformContent/pc/textures/water/normal_03.dds b/2018/PlatformContent/pc/textures/water/normal_03.dds new file mode 100644 index 0000000..16c5123 Binary files /dev/null and b/2018/PlatformContent/pc/textures/water/normal_03.dds differ diff --git a/2018/PlatformContent/pc/textures/water/normal_04.dds b/2018/PlatformContent/pc/textures/water/normal_04.dds new file mode 100644 index 0000000..c0c079f Binary files /dev/null and b/2018/PlatformContent/pc/textures/water/normal_04.dds differ diff --git a/2018/PlatformContent/pc/textures/water/normal_05.dds b/2018/PlatformContent/pc/textures/water/normal_05.dds new file mode 100644 index 0000000..5b1442c Binary files /dev/null and b/2018/PlatformContent/pc/textures/water/normal_05.dds differ diff --git a/2018/PlatformContent/pc/textures/water/normal_06.dds b/2018/PlatformContent/pc/textures/water/normal_06.dds new file mode 100644 index 0000000..dcc0e0a Binary files /dev/null and b/2018/PlatformContent/pc/textures/water/normal_06.dds differ diff --git a/2018/PlatformContent/pc/textures/water/normal_07.dds b/2018/PlatformContent/pc/textures/water/normal_07.dds new file mode 100644 index 0000000..2f32ea0 Binary files /dev/null and b/2018/PlatformContent/pc/textures/water/normal_07.dds differ diff --git a/2018/PlatformContent/pc/textures/water/normal_08.dds b/2018/PlatformContent/pc/textures/water/normal_08.dds new file mode 100644 index 0000000..1eeb6af Binary files /dev/null and b/2018/PlatformContent/pc/textures/water/normal_08.dds differ diff --git a/2018/PlatformContent/pc/textures/water/normal_09.dds b/2018/PlatformContent/pc/textures/water/normal_09.dds new file mode 100644 index 0000000..06ee34c Binary files /dev/null and b/2018/PlatformContent/pc/textures/water/normal_09.dds differ diff --git a/2018/PlatformContent/pc/textures/water/normal_10.dds b/2018/PlatformContent/pc/textures/water/normal_10.dds new file mode 100644 index 0000000..16ffff0 Binary files /dev/null and b/2018/PlatformContent/pc/textures/water/normal_10.dds differ diff --git a/2018/PlatformContent/pc/textures/water/normal_11.dds b/2018/PlatformContent/pc/textures/water/normal_11.dds new file mode 100644 index 0000000..177238c Binary files /dev/null and b/2018/PlatformContent/pc/textures/water/normal_11.dds differ diff --git a/2018/PlatformContent/pc/textures/water/normal_12.dds b/2018/PlatformContent/pc/textures/water/normal_12.dds new file mode 100644 index 0000000..250c48d Binary files /dev/null and b/2018/PlatformContent/pc/textures/water/normal_12.dds differ diff --git a/2018/PlatformContent/pc/textures/water/normal_13.dds b/2018/PlatformContent/pc/textures/water/normal_13.dds new file mode 100644 index 0000000..a3e06ae Binary files /dev/null and b/2018/PlatformContent/pc/textures/water/normal_13.dds differ diff --git a/2018/PlatformContent/pc/textures/water/normal_14.dds b/2018/PlatformContent/pc/textures/water/normal_14.dds new file mode 100644 index 0000000..dabe7ee Binary files /dev/null and b/2018/PlatformContent/pc/textures/water/normal_14.dds differ diff --git a/2018/PlatformContent/pc/textures/water/normal_15.dds b/2018/PlatformContent/pc/textures/water/normal_15.dds new file mode 100644 index 0000000..a0c2646 Binary files /dev/null and b/2018/PlatformContent/pc/textures/water/normal_15.dds differ diff --git a/2018/PlatformContent/pc/textures/water/normal_16.dds b/2018/PlatformContent/pc/textures/water/normal_16.dds new file mode 100644 index 0000000..f3dd37c Binary files /dev/null and b/2018/PlatformContent/pc/textures/water/normal_16.dds differ diff --git a/2018/PlatformContent/pc/textures/water/normal_17.dds b/2018/PlatformContent/pc/textures/water/normal_17.dds new file mode 100644 index 0000000..695042b Binary files /dev/null and b/2018/PlatformContent/pc/textures/water/normal_17.dds differ diff --git a/2018/PlatformContent/pc/textures/water/normal_18.dds b/2018/PlatformContent/pc/textures/water/normal_18.dds new file mode 100644 index 0000000..15c38f3 Binary files /dev/null and b/2018/PlatformContent/pc/textures/water/normal_18.dds differ diff --git a/2018/PlatformContent/pc/textures/water/normal_19.dds b/2018/PlatformContent/pc/textures/water/normal_19.dds new file mode 100644 index 0000000..40cdd00 Binary files /dev/null and b/2018/PlatformContent/pc/textures/water/normal_19.dds differ diff --git a/2018/PlatformContent/pc/textures/water/normal_20.dds b/2018/PlatformContent/pc/textures/water/normal_20.dds new file mode 100644 index 0000000..e427daf Binary files /dev/null and b/2018/PlatformContent/pc/textures/water/normal_20.dds differ diff --git a/2018/PlatformContent/pc/textures/water/normal_21.dds b/2018/PlatformContent/pc/textures/water/normal_21.dds new file mode 100644 index 0000000..f26a7eb Binary files /dev/null and b/2018/PlatformContent/pc/textures/water/normal_21.dds differ diff --git a/2018/PlatformContent/pc/textures/water/normal_22.dds b/2018/PlatformContent/pc/textures/water/normal_22.dds new file mode 100644 index 0000000..6d6af46 Binary files /dev/null and b/2018/PlatformContent/pc/textures/water/normal_22.dds differ diff --git a/2018/PlatformContent/pc/textures/water/normal_23.dds b/2018/PlatformContent/pc/textures/water/normal_23.dds new file mode 100644 index 0000000..f6f354c Binary files /dev/null and b/2018/PlatformContent/pc/textures/water/normal_23.dds differ diff --git a/2018/PlatformContent/pc/textures/water/normal_24.dds b/2018/PlatformContent/pc/textures/water/normal_24.dds new file mode 100644 index 0000000..bc2804c Binary files /dev/null and b/2018/PlatformContent/pc/textures/water/normal_24.dds differ diff --git a/2018/PlatformContent/pc/textures/water/normal_25.dds b/2018/PlatformContent/pc/textures/water/normal_25.dds new file mode 100644 index 0000000..6ea49fb Binary files /dev/null and b/2018/PlatformContent/pc/textures/water/normal_25.dds differ diff --git a/2018/PlatformContent/pc/textures/wood/diffuse.dds b/2018/PlatformContent/pc/textures/wood/diffuse.dds new file mode 100644 index 0000000..941b70f Binary files /dev/null and b/2018/PlatformContent/pc/textures/wood/diffuse.dds differ diff --git a/2018/PlatformContent/pc/textures/wood/normal.dds b/2018/PlatformContent/pc/textures/wood/normal.dds new file mode 100644 index 0000000..aa3190c Binary files /dev/null and b/2018/PlatformContent/pc/textures/wood/normal.dds differ diff --git a/2018/PlatformContent/pc/textures/wood/normaldetail.dds b/2018/PlatformContent/pc/textures/wood/normaldetail.dds new file mode 100644 index 0000000..5630e27 Binary files /dev/null and b/2018/PlatformContent/pc/textures/wood/normaldetail.dds differ diff --git a/2018/PlatformContent/pc/textures/wood/specular.dds b/2018/PlatformContent/pc/textures/wood/specular.dds new file mode 100644 index 0000000..f5a8470 Binary files /dev/null and b/2018/PlatformContent/pc/textures/wood/specular.dds differ diff --git a/2018/PlatformContent/pc/textures/woodplanks/diffuse.dds b/2018/PlatformContent/pc/textures/woodplanks/diffuse.dds new file mode 100644 index 0000000..502b627 Binary files /dev/null and b/2018/PlatformContent/pc/textures/woodplanks/diffuse.dds differ diff --git a/2018/PlatformContent/pc/textures/woodplanks/normal.dds b/2018/PlatformContent/pc/textures/woodplanks/normal.dds new file mode 100644 index 0000000..760869f Binary files /dev/null and b/2018/PlatformContent/pc/textures/woodplanks/normal.dds differ diff --git a/2018/PlatformContent/pc/textures/woodplanks/normaldetail.dds b/2018/PlatformContent/pc/textures/woodplanks/normaldetail.dds new file mode 100644 index 0000000..818b2a8 Binary files /dev/null and b/2018/PlatformContent/pc/textures/woodplanks/normaldetail.dds differ diff --git a/2018/PlatformContent/pc/textures/woodplanks/specular.dds b/2018/PlatformContent/pc/textures/woodplanks/specular.dds new file mode 100644 index 0000000..862b193 Binary files /dev/null and b/2018/PlatformContent/pc/textures/woodplanks/specular.dds differ diff --git a/2018/ReflectionMetadata.xml b/2018/ReflectionMetadata.xml new file mode 100644 index 0000000..8600cf6 --- /dev/null +++ b/2018/ReflectionMetadata.xml @@ -0,0 +1,7215 @@ + + + + + + BindableFunction + Scripting + Allow functions defined in one script to be called by another script + 40 + 66 + + + + + + Invoke + Causes the function assigned to OnInvoke to be called. Arguments passed to this function get passed to OnInvoke function. + + + + + + + OnInvoke + Should be defined as a function. This function is called when Invoke() is called. Number of arguments is variable. + + + + + + + BindableEvent + Scripting + Allow events defined in one script to be subscribed to by another script + + 50 + 67 + + + + + Fire + Used to make the custom event fire (see Event for more info). Arguments can be variable length. + + + + + + + Event + This event fires when the Fire() method is used. Receives the variable length arguments from Fire(). + + + + + + + TouchTransmitter + Used by networking and replication code to transmit touch events - no other purpose + + false + 30 + 37 + + + + + ForceField + Avatar + Prevents joint breakage from explosions, and stops Humanoids from taking damage + 30 + 37 + Model + Model + + + + + PluginManager + + + + + + TeleportService + Allows players to seamlessly leave a game and join another + + + + CustomizedTeleportUI + true + Deprecated + + + + + + + Plugin + + + + + + PluginMouse + + + + + + Glue + BasePart + BasePart + + + + + CollectionService + A service which provides collections of instances based on tags assigned to them. + + + + + ItemAdded + true + Deprecated. Use GetInstanceAddedSignal instead. + + + + + ItemRemoved + true + Deprecated. Use GetInstancedRemovedSignal instead. + + + + + + + GetCollection + true + Deprecated. Use GetTagged instead. + + + + + GetTagged + Returns an array of all of the instances in the data model which have the given tag. + + + + + AddTag + Adds a tag to an instance. + + + + + RemoveTag + Removes a tag to an instance. + + + + + GetTags + Returns a list of all the collections that an instance belongs to. + + + + + HasTag + Returns whether the given instance has the given tag. + + + + + GetInstanceAddedSignal + Returns a signal that fires when the given tag either has a new instance with that tag added to the data model or that tag is assigned to an instance within the data model. + + + + + GetInstanceRemovedSignal + Returns a signal that fires when the given tag either has an instance with that tag removed from the data model or that tag is removed from an instance within the data model. + + + + + + + JointsService + + + + + RunService + + + + + BadgeService + + + + + LogService + + + + + AssetService + A service used to set and get information about assets stored on the Roblox website. + + + + + RevertAsset + Reverts a given place id to the version number provided. Returns true if successful on reverting, false otherwise. + + + + + SetPlacePermissions + Sets the permissions for a placeID to the place accessType. An optional table (inviteList) can be included that will set the accessType for only the player names provided. The table should be set up as an array of usernames (strings). + + + + + GetPlacePermissions + Given a placeID, this function will return a table with the permissions of the place. Useful for determining what kind of permissions a particular user may have for a place. + + + + + GetAssetVersions + Given a placeID, this function will return a table with the version info of the place. An optional arg of page number can be used to page through all revisions (a single page may hold about 50 revisions). + + + + + GetCreatorAssetID + Given a creationID, this function will return the asset that created the creationID. If no other asset created the given creationID, 0 is returned. + + + + + + + HttpService + + + + + HttpEnabled + true + Enabling http requests from scripts + + + + + + + GetAsync + Server + + + + + PostAsync + Server + + + + + + + InsertService + A service used to insert objects stored on the website into the game. + + + + + AllowClientInsertModels + true + Can be set in non-filtering-enabled places to allow LoadAsset to be used in LocalScripts. + + + + + AllowInsertFreeModels + false + true + -1 + Allows free models to be inserted into place. + + + + + + + GetCollection + Returns a table for the assets stored in the category. A category is an setId from www.roblox.com that links to a set. <a href="http://wiki.roblox.com/index.php?title=API:Class/InsertService/GetCollection" target="_blank">More info on table format</a>. <a href="http://wiki.roblox.com/index.php/Sets" target="_blank">More info on sets</a> + + + + + Insert + Inserts the Instance into the workspace. It is recommended to use Instance.Parent = game.Workspace instead, as this can cause issues currently. + + + + + ApproveAssetId + true + Deprecated + + + + + ApproveAssetVersionId + true + Deprecated + + + + + + + + GetBaseSets + Returns a table containing a list of the various setIds that are ROBLOX approved. <a href="http://wiki.roblox.com/index.php/Sets" target="_blank">More info on sets</a> + + + + + GetUserSets + Returns a table containing a list of the various setIds that correspond to argument 'userId'. <a href="http://wiki.roblox.com/index.php/Sets" target="_blank">More info on sets</a> + + + + + GetBaseCategories + true + Deprecated. Use GetBaseSets() instead. + + + + + GetUserCategories + true + Deprecated. Use GetUserSets() instead. + + + + + LoadAsset + Returns a Model containing the Instance that resides at AssetId on the web. This call will also yield the script until the model is returned. Script execution can still continue, however, if you use a <a href="http://wiki.roblox.com/index.php?title=Coroutine" target="_blank">coroutine</a>. + + + + + LoadAssetVersion + Similar to LoadAsset, but instead an AssetVersionId is passed in, which refers to a particular version of the asset which is not neccessarily the latest version. + + + + + + + Hat + Avatar + 30 + 45 + true + + + + + Accessory + Avatar + 30 + 32 + Model + Model + + + + + LocalBackpack + + + + + LocalBackpackItem + + + + + MotorFeature + true + + + + + Attachment + Constraints + 30 + 81 + PVInstance + PVInstance + + + + + + Rotation + + + + + WorldRotation + true + Deprecated. Use WorldOrientation instead + + + + + Orientation + Euler angles applied in YXZ order + + + + + WorldOrientation + Euler angles applied in YXZ order + + + + + + + + Constraint + Physics + 30 + 86 + BasePart + BasePart + + + + + Enabled + Toggles whether or not this constraint is enabled. Disabled constraints will not render in game. + + + + + Color + The color of the in-game visual. + + + + + Visible + Toggles the in-game visual associated with this constraint. + + + + + + + + BallSocketConstraint + Constraints + 30 + 86 + BasePart + BasePart + + + + + LimitsEnabled + Enables the angular limit between the axis of Attachment0 and the axis of Attachment1. + + + + + UpperAngle + Maximum angle between the two main axes. Value in [0, 180]. + + + + + Restitution + Restitution of the limit, or how elastic it is. Value in [0, 1]. + + + + + TwistLimitsEnabled + Enables the angular limits around the main axis of Attachment1. + + + + + TwistUpperAngle + Upper angular limit around the axis of Attachment1. Value in [-180, 180]. + + + + + TwistLowerAngle + Lower angular limit around the axis of Attachment1. Value in [-180, 180]. + + + + + Radius + Radius of the in-game visual. Value in [0, inf). + + + + + + + + RopeConstraint + Constraints + 30 + 89 + BasePart + BasePart + + + + + Length + The length of the rope or the maximum distance between the two attachments. Value in [0, inf). + + + + + Restitution + Restitution of the rope, or how elastic it is. Value in [0, 1]. + + + + + CurrentDistance + Current distance between the two attachments. Value in [0, inf). + + + + + Thickness + The thickness of the in-game visual (diameter). Value in [0, inf). + + + + + + + + RodConstraint + Constraints + 30 + 90 + BasePart + BasePart + + + + + Length + The length of the rod or the distance to be maintained between the two attachments. Value in [0, inf). + + + + + CurrentDistance + Current distance between the two attachments. Value in [0, inf). + + + + + Thickness + The thickness of the in-game visual (diameter). Value in [0, inf). + + + + + + + + SpringConstraint + Constraints + 30 + 91 + BasePart + BasePart + + + + + LimitsEnabled + Enables limits on the length of the spring. + + + + + Stiffness + The stiffness parameter of the spring. Force is scaled based on distance from the free length. The units of this property are force / distance. Value in [0, inf). + + + + + Damping + The damping parameter of the spring. The force is scaled with respect to relative velocity. The units of this property are force / velocity. Value in [0, inf). + + + + + FreeLength + The distance (in studs) between the two attachments at which the spring exerts no stiffness force. Value in [0, inf). + + + + + MaxForce + The maximum force that the spring can apply. Useful to prevent instabilities. The units are mass * studs / seconds^2. Value in [0, inf). + + + + + MaxLength + Maximum spring length, or the maxium distance between the two attachments. Value in [0, inf). + + + + + MinLength + Minimum spring length, or the minimum distance between the two attachments. Value in [0, inf). + + + + + Radius + The radius of the in-game spring coil visual. Value in [0, inf). + + + + + Thickness + The thickness of the spring wire (diameter) in the in-game visual. Value in [0, inf). + + + + + Coils + The number of coils in the in-game visual. Value in [0, 8]. + + + + + CurrentLength + Current distance between the two attachments. Value in [0, inf). + + + + + + + + WeldConstraint + Constraints + 30 + 94 + PVInstance + PVInstance + + + + + + HingeConstraint + Constraints + 30 + 87 + BasePart + BasePart + + + + + ActuatorType + Type of the rotational actuator: None, Motor, or Servo. + + + + + LimitsEnabled + Enables the angular limits on rotations around the main axis of Attachment0. + + + + + UpperAngle + Upper limit for the angle from the SecondaryAxis of Attachment0 to the SecondaryAxis of Attachment1 around the rotation axis. Value in [-180, 180]. + + + + + LowerAngle + Lower limit for the angle from the SecondaryAxis of Attachment0 to the SecondaryAxis of Attachment1 around the rotation axis. Value in [-180, 180]. + + + + + AngularRestitution + Restitution of the two limits, or how elastic they are. Value in [0,1]. + + + + + AngularVelocity + The target angular velocity of the motor in radians per second around the rotation axis. Value in [0, inf). + + + + + MotorMaxTorque + The maximum torque the motor can apply to achieve the target angular velocity. Value in [0, inf). + + + + + MotorMaxAcceleration + The maximum angular acceleration of the motor in radians per second square. Value in [0, inf). + + + + + AngularSpeed + Target angular speed. This value is unsigned as the servo will always move toward its target. Value in [0, inf). + + + + + ServoMaxTorque + Maximum torque the servo motor can apply. Value in [0, inf). + + + + + TargetAngle + Target angle for the SecondaryAxis of Attachment1 from the SecondaryAxis of Attachment0 around the rotation axis. Value in [-180, 180]. + + + + + CurrentAngle + Signed angle between the SecondaryAxis of Attchement0 and the SecondaryAxis of Attachment1 around the rotation axis. Value in [-180, 180]. + + + + + Radius + Radius of the in-game visual. Value in [0, inf). + + + + + + + + SlidingBallConstraint + Constraints + 30 + 88 + BasePart + BasePart + + + + + ActuatorType + Type of linear actuator (along the axis of the slider): None, Motor, or Servo. + + + + + LimitsEnabled + Enables the limits on the linear motion along the axis of the slider. + + + + + LowerLimit + Lower limit for the position of Attachment1 with respect to Attachment0 along the slider axis. Value in (-inf, inf). + + + + + UpperLimit + Upper limit for the position of Attachment1 with respect to Attachment0 along the slider axis. Value in (-inf, inf). + + + + + Restitution + Restitution of the two limits, or how elastic they are. Value in [0, 1]. + + + + + Velocity + The target linear velocity of the motor in studs per second along the slider axis. Value in (-inf, inf). + + + + + MotorMaxForce + The maximum force the motor can apply to achieve the target velocity. Units are mass * studs / seconds^2. Value in [0, inf). + + + + + MotorMaxAcceleration + The maximum acceleration of the motor in studs per second squared. Value in [0, inf). + + + + + Speed + Target speed in studs per second. This value is unsigned as the servo will always move toward its target. Value in [0, inf). + + + + + ServoMaxForce + Maximum force the servo motor can apply. Units are mass * studs / seconds^2. Value in [0, inf). + + + + + TargetPosition + Target position of Attachment1 with respect to Attachment0 along the slider axis. Value in (-inf, inf). + + + + + CurrentPosition + Current position of Attachment1 with respect to Attachment0 along the slider axis. Value in (-inf, inf). + + + + + Size + Size of the in-game visual associated with this constraint. Value in [0, inf). + + + + + + + + PrismaticConstraint + Constraints + 30 + 88 + BasePart + BasePart + + + + + + CylindricalConstraint + Constraints + 30 + 95 + BasePart + BasePart + + + + + InclinationAngle + Direction of the rotation axis as an angle from the x-axis in the xy-plane of Attachment0. Value in [-180, 180]. + + + + + AngularActuatorType + Type of angular actuator: None, Motor, or Servo. + + + + + AngularLimitsEnabled + Enables the angular limits around the rotation axis. + + + + + UpperAngle + Upper limit for the angle (in degrees) between the reference axis and the SecondaryAxis of Attachment1 around the rotation axis. Value in [-180, 180]. + + + + + LowerAngle + Lower limit for the angle (in degrees) between the reference axis and the SecondaryAxis of Attachment1 around the rotation axis. Value in [-180, 180]. + + + + + AngularRestitution + Restitution of the two limits, or how elastic they are. Value in [0, 1]. + + + + + AngularVelocity + The target angular velocity of the motor in radians per second around the rotation axis. Value in [0, inf). + + + + + MotorMaxTorque + The maximum torque the motor can apply to achieve the target angular velocity. The units are mass * studs^2 / second^2. Value in [0, inf). + + + + + MotorMaxAngularAcceleration + The maximum angular acceleration of the motor in radians per second squared. Value in [0, inf). + + + + + AngularSpeed + Target angular speed. This value is unsigned as the servo will always move toward its target. In radians per second. Value in [0, inf). + + + + + ServoMaxTorque + Maximum torque the servo motor can apply. The units are mass * studs^2 / second^2. Value in [0, inf). + + + + + TargetAngle + Target angle (in degrees) between the reference axis and the secondary axis of Attachment1 around the rotation axis. Value in [-180, 180]. + + + + + CurrentAngle + Signed angle (in degrees) between the reference axis and the secondary axis of Attachment1 around the rotation axis. Value in [-180, 180]. + + + + + WorldRotationAxis + The unit vector direction of the rotation axis in world coordinates. + + + + + RotationAxisVisible + Enable the visibility of the rotation axis. + + + + + + + + AlignOrientation + Constraints + 30 + 82 + BasePart + BasePart + + + + + AlignPosition + Constraints + 30 + 82 + BasePart + BasePart + + + + + VectorForce + Constraints + 30 + 82 + Model + BasePart,Model + + + + + LineForce + Constraints + 30 + 82 + BasePart + BasePart + + + + + Torque + Constraints + 30 + 82 + BasePart + BasePart + + + + + Mouse + Used to receive input from the user. Actually tracks mouse events and keyboard events. + + + + + Hit + The CoordinateFrame of where the Mouse ray is currently hitting a 3D object in the Workspace. If the mouse is not over any 3D objects in the Workspace, this property is nil. + + + + + Icon + The current Texture of the Mouse Icon. Stored as a string, for more information on how to format the string <a href="http://wiki.roblox.com/index.php/Content" target="_blank">go here</a> + + + + + Origin + The CoordinateFrame of where the Mouse is when the mouse is not clicking. + + + + + Origin + The CoordinateFrame of where the Mouse is when the mouse is not clicking. This CoordinateFrame will be very close to the Camera.CoordinateFrame. + + + + + Target + The Part the mouse is currently over. If the mouse is not currently over any object (on the skybox, for example) this property is nil. + + + + + TargetFilter + A Part or Model that the Mouse will ignore when trying to find the Target, TargetSurface and Hit. + + + + + TargetSurface + The NormalId (Top, Left, Down, etc.) of the face of the part the Mouse is currently over. + + + + + UnitRay + The Unit Ray from where the mouse is (Origin) to the current Mouse.Target. + + + + + ViewSizeX + The viewport's (game window) width in pixels. + + + + + ViewSizeY + The viewport's (game window) height in pixels. + + + + + X + The absolute pixel position of the Mouse along the x-axis of the viewport (game window). Values start at 0 on the left hand side of the screen and increase to the right. + + + + + Y + The absolute pixel position of the Mouse along the y-axis of the viewport (game window). Values start at 0 on the top of the screen and increase to the bottom. + + + + + + + Button1Down + Fired when the first button (usually the left, but could be another) on the mouse is depressed. + + + + + Button1Up + Fired when the first button (usually the left, but could be another) on the mouse is release. + + + + + Button2Down + This event is currently non-operational. + + + + + Button2Up + This event is currently non-operational. + + + + + Idle + Fired constantly when the mouse is not firing any other event (i.e. the mouse isn't moving, nor any buttons being pressed or depressed). + + + + + KeyDown + Fired when a user presses a key on the keyboard. Argument is a string representation of the key. If the key has no string representation (such as space), the string passed in is the keycode for that character. Keycodes are currently in ASCII. + + + + + KeyUp + Fired when a user releases a key on the keyboard. Argument is a string representation of the key. If the key has no string representation (such as space), the string passed in is the keycode for that character. Keycodes are currently in ASCII. + + + + + Move + Fired when the mouse X or Y member changes. + + + + + WheelBackward + This event is currently non-operational. + + + + + WheelForward + This event is currently non-operational. + + + + + + + ProfilingItem + + + + + ChangeHistoryService + + + + + RotateP + BasePart + BasePart + + + + + RotateV + BasePart + BasePart + + + + + ScriptContext + + + + + Selection + + + + + VelocityMotor + BasePart + BasePart + + + + + Weld + 200 + 34 + BasePart + BasePart + + + + + TaskScheduler + false + + + + + SetThreadShare + true + Deprecated + + + + + + + StatsItem + + + + + Snap + 200 + 34 + BasePart + BasePart + + + + + FileMesh + BasePart + BasePart + + + + + ClickDetector + 3D Interfaces + Raises mouse events for parent object + 30 + 41 + BasePart + PVInstance + + + + + MaxActivationDistance + The maximum distance a Player's character can be from the ClickDetector's parent Part that will allow the Player's mouse to fire events on this object. + + + + + + + MouseClick + Fired when a player clicks on the parent Part of ClickDetector. The argument provided is always of type Player. + + + + + MouseHoverEnter + Fired when a player's mouse enters on the parent Part of ClickDetector. The argument provided is always of type Player. + + + + + MouseHoverLeave + Fired when a player's mouse leaves the parent Part of ClickDetector. The argument provided is always of type Player. + + + + + + + + Clothing + 20 + + + + + + Smoke + Effects + Makes the parent part or model object emit smoke + 30 + 59 + BasePart + BasePart + + + + + + Trail + Effects + Makes two attachments emit trail when moving + 30 + 93 + Model + BasePart,Model + + + + + LightEmission + 0 + 1 + + + + + + LightInfluence + 0 + 1 + + + + + + ZOffset + -1 + 1 + + + + + + Lifetime + 0 + 20 + + + + + + TextureLength + 0 + 5 + 40 + + + + + + MinLength + 0 + 1 + + + + + + + + + Beam + Effects + Makes beam between two attachments + 30 + 96 + BasePart + BasePart,Model + + + + + LightEmission + 0 + 1 + + + + + + LightInfluence + 0 + 1 + + + + + + TextureSpeed + -1 + 1 + + + + + + TextureLength + 0 + 5 + 40 + + + + + + CurveSize0 + -10 + 10 + + + + + + CurveSize1 + -10 + 10 + + + + + + ZOffset + -1 + 1 + + + + + + + + ParticleEmitter + Effects + A generic particle system. + 30 + 80 + BasePart + BasePart,Attachment + + + + + LightEmission + 0 + 1 + + + + + LightInfluence + Specifies the amount of influence lighting has on the particle emmitter. A value of 0 is unlit, 1 is fully lit. Fractional values blend from unlit to lit. + 0 + 1 + + + + + + Drag + 0 + 5 + + + + + VelocityInheritance + 0 + 1 + + + + + Rate + 0 + 100 + 100 + + + + + + Rotation + -180 + 180 + 72 + + + + + RotSpeed + -360 + 360 + 72 + + + + + Speed + 0 + 100 + 100 + + + + + Lifetime + 0 + 5 + + + + + + + + Sparkles + Effects + Makes the parent part or model object fantastic + 30 + 42 + BasePart + BasePart + + + + + Explosion + Effects + 30 + 36 + Creates an Explosion! This can be used as a purely graphical effect, or can be made to damage objects. + BasePart + Basepart,Model + + + + + BlastPressure + How much force this Explosion exerts on objects within it's BlastRadius. Setting this to 0 creates a purely graphical effect. A larger number will cause Parts to fly away at higher velocities. + + + + + BlastRadius + How big the Explosion is. This is a circle starting from the center of the Explosion's Position, the larger this property the larger the circle of destruction. + + + + + Position + Where the Explosion occurs in absolute world coordinates. + + + + + ExplosionType + Defines the behavior of the Explosion. <a href="http://wiki.roblox.com/index.php/ExplosionType" target="_blank">More info</a> + + + + + + + Fire + Effects + Makes the parent part or model object emit fire + 30 + 61 + BasePart + BasePart + + + + + Color + The color of the base of the fire. See SecondaryColor for more. + + + + + Heat + How hot the fire appears to be. The flame moves quicker the higher this value is set. + + + + + SecondaryColor + The color the fire interpolates to from Color. The longer a particle exists in the fire, the close to this color it becomes. + + + + + Size + How large the fire appears to be. + + + + + + + Seat + Interaction + 30 + 35 + + + + + Platform + + Equivalent to a seat, except that the character stands up rather than sits down. + 30 + 35 + + + + + SkateboardPlatform + true + 30 + 35 + + + + + VehicleSeat + Interaction + Automatically finds and powers hinge joints in an assembly. Ignores motors. + 30 + 35 + Model + Model + + + + + Tool + Interaction + 30 + 17 + StarterPack + StarterPack,Backpack + + + + + Flag + true + 30 + 38 + + + + + CanBeDropped + If someone is carrying this flag, this bool determines whether or not they can drop it and run. + + + + + TeamColor + The Team this flag is for. Corresponds with the TeamColors in the Teams service. + + + + + + + FlagStand + true + 30 + 39 + + + + + BackpackItem + 20 + + + + + Decal + 3D Interfaces + 40 + 7 + Descibes a texture that is placed on one of the sides of the Part it is parented to. + BasePart + BasePart + + + + + Face + Describes the face of the Part the decal will be applied to. <a href="http://wiki.roblox.com/index.php/NormalId" target="_blank">More info</a> + + + + + Shiny + How much light will appear to reflect off of the decal. + + + + + Specular + How light will react to the surface of the decal. + + + + + Transparency + How visible the decal is. 1 is completely invisible, while 0 is completely opaque + 0 + 1 + + + + + + + JointInstance + 200 + 34 + + + + + Message + 110 + 33 + true + StarterGui + StarterGui + + + + + Hint + true + 110 + 33 + + + + + IntValue + Values + 30 + 4 + Stores a int value in it's Value member. Useful to share int information across multiple scripts. + + + + + RayValue + Values + 30 + 4 + Stores a Ray value in it's Value member. Useful to share Ray information across multiple scripts. + + + + + IntConstrainedValue + true + Values + 30 + 4 + Stores an int value in it's Value member. Value is clamped to be in range of Min and MaxValue. Useful to share int information across multiple scripts. + + + + MaxValue + The maximum we allow this Value to be set. If Value is set higher than this, it automatically gets adjusted to MaxValue + + + + + MinValue + The minimum we allow this Value to be set. If Value is set lower than this, it automatically gets adjusted to MinValue + + + + + + DoubleConstrainedValue + true + Values + 30 + 4 + Stores a double value in it's Value member. Value is clamped to be in range of Min and MaxValue. Useful to share double information across multiple scripts. + + + + + MaxValue + The maximum we allow this Value to be set. If Value is set higher than this, it automatically gets adjusted to MaxValue + + + + + MinValue + The minimum we allow this Value to be set. If Value is set lower than this, it automatically gets adjusted to MinValue + + + + + + + BoolValue + Values + 30 + 4 + Stores a boolean value in it's Value member. Useful to share boolean information across multiple scripts. + + + + + CustomEvent + 30 + true + 4 + + + + + CustomEventReceiver + 30 + true + 4 + + + + + FloorWire + true + 30 + 4 + Renders a thin cylinder than can be adorned with textures that 'flow' from one object to the next. Has basic pathing abilities and attempts to to not intersect anything. <a href="http://wiki.roblox.com/index.php/FloorWire_Guide" target="_blank">More info</a> + + + + + CycleOffset + Controls how the decals are positioned along the wire. <a href="http://wiki.roblox.com/index.php/CycleOffset" target="_blank">More info</a> + + + + + From + The object the FloorWire 'emits' from + + + + + StudsBetweenTextures + The space between two textures on the wire. Note: studs are relative depending on how far the camera is from the FloorWire. + + + + + Texture + The image we use to render the textures that flow from beginning to end of the FloorWire. + + + + + TextureSize + The size in studs of the Texture we use to flow from one object to the next. + + + + + To + The object the FloorWire 'emits' to + + + + + Velocity + The rate of travel that the textures flow along the wire. + + + + + WireRadius + How thick the wire is. + + + + + + + NumberValue + Values + 30 + 4 + + + + + StringValue + Values + 30 + 4 + + + + + Vector3Value + Values + 30 + 4 + + + + + CFrameValue + Values + 30 + 4 + Stores a CFrame value in it's Value member. Useful to share CFrame information across multiple scripts. + + + + + Color3Value + Values + 30 + 4 + Stores a Color3 value in it's Value member. Useful to share Color3 information across multiple scripts. + + + + + BrickColorValue + Values + 30 + 4 + Stores a BrickColor value in it's Value member. Useful to share BrickColor information across multiple scripts. + + + + + ValueBase + Values + 30 + 4 + The base class to all Value Objects. + + + + + ObjectValue + Values + 30 + 4 + + + + + SpecialMesh + Meshes + 30 + 8 + BasePart + BasePart + + + + + BlockMesh + Meshes + 30 + 8 + BasePart + BasePart + + + + + CylinderMesh + Meshes + 30 + 8 + BasePart + BasePart + true + + + + + BevelMesh + Meshes + false + true + + + + + DataModelMesh + false + + + + + + Texture + 3D Interfaces + 40 + 10 + BasePart + BasePart + + + + + Sound + Sounds + 10 + 11 + SoundGroup,SoundService + + + + + play + true + Deprecated. Use Play() instead + + + + + + + PlayOnRemove + The sound will play when it is removed from the Workspace. Looped sounds don't play + + + + + + + + EchoSoundEffect + An echo audio effect that can be applied to a Sound or SoundGroup. + Sounds + 20 + 84 + Sound + Sound,SoundGroup + + + + + Delay + 0.1 + 5 + 100 + + + + + Feedback + 0 + 1 + 100 + + + + + DryLevel + -80 + 10 + 100 + + + + + WetLevel + -80 + 100 + 100 + + + + + + + + FlangeSoundEffect + A Flanging audio effect that can be applied to a Sound or SoundGroup. + Sounds + 20 + 84 + Sound + Sound,SoundGroup + + + + + Mix + 0 + 1 + 100 + + + + + Depth + 0.01 + 1 + 100 + + + + + Rate + 0 + 20 + 100 + + + + + + + + DistortionSoundEffect + A Distortion audio effect that can be applied to a Sound or SoundGroup. + Sounds + 20 + 84 + Sound + Sound,SoundGroup + + + + + Level + 0 + 1 + 100 + + + + + + + + PitchShiftSoundEffect + A Pitch Shifting audio effect that can be applied to a Sound or SoundGroup. + Sounds + 20 + 84 + Sound + Sound,SoundGroup + + + + + Octave + 0.5 + 2 + 100 + + + + + + + + ChorusSoundEffect + A Chorus audio effect that can be applied to a Sound or SoundGroup. + Sounds + 20 + 84 + Sound + Sound,SoundGroup + + + + + Mix + 0 + 1 + 100 + + + + + Rate + 0 + 20 + 100 + + + + + Depth + 0 + 1 + 100 + + + + + + + + TremoloSoundEffect + A Tremolo audio effect that can be applied to a Sound or SoundGroup. + Sounds + 20 + 84 + Sound + Sound,SoundGroup + + + + + Frequency + 0.1 + 20 + 100 + + + + + Depth + 0 + 1 + 100 + + + + + Duty + 0 + 1 + 100 + + + + + + + + ReverbSoundEffect + A Reverb audio effect that can be applied to a Sound or SoundGroup. + Sounds + 20 + 84 + Sound + Sound,SoundGroup + + + + + DecayTime + 0.1 + 20 + 100 + + + + + Diffusion + 0 + 1 + 100 + + + + + Density + 0 + 1 + 100 + + + + + DryLevel + -80 + 20 + 100 + + + + + WetLevel + -80 + 20 + 100 + + + + + + + + EqualizerSoundEffect + An Three-band Equalizer audio effect that can be applied to a Sound or SoundGroup. + Sounds + 20 + 84 + Sound + Sound,SoundGroup + + + + + LowGain + -80 + 10 + 100 + + + + + MidGain + -80 + 10 + 100 + + + + + HighGain + -80 + 10 + 100 + + + + + + + + CompressorSoundEffect + A Compressor audio effect that can be applied to a Sound or SoundGroup. + Sounds + 20 + 84 + Sound + Sound,SoundGroup + + + + + Threshold + -80 + 0 + 100 + + + + + Attack + 0.001 + 1 + 100 + + + + + Release + 0.001 + 5 + 100 + + + + + Ratio + 1 + 50 + 100 + + + + + GainMakeup + 0 + 30 + 100 + + + + + + + + SoundGroup + Sounds + 20 + 85 + SoundService + SoundService + + + + + + + + + StockSound + false + -1 + + + + + SoundService + 500 + 31 + + + + + + AmbientReverb + + The ambient sound environment. May not work when using hardware sound + + + + + DopplerScale + + The doppler scale is a general scaling factor for how much the pitch varies due to doppler shifting in 3D sound. Doppler is the pitch bending effect when a sound comes towards the listener or moves away from it, much like the effect you hear when a train goes past you with its horn sounding. With dopplerscale you can exaggerate or diminish the effect. + + + + + DistanceFactor + + the relative distance factor, compared to 1.0 meters. + + + + + RolloffScale + + Setting this value makes the sound drop off faster or slower. The higher the value, the faster volume will attenuate, and conversely the lower the value, the slower it will attenuate. For example a rolloff factor of 1 will simulate the real world, where as a value of 2 will make sounds attenuate 2 times quicker. + + + + + + + Backpack + 30 + 20 + false + Player + + + + + StarterPack + 30 + 20 + + + + + StarterPlayer + 30 + 79 + + + + + StarterGear + 30 + 20 + false + + + + + + CoreGui + 30 + 46 + + + + + + + PluginGuiService + 30 + 46 + + + + + + + Studio + + + + + Show Plugin GUI Service in Explorer + + + + + + + + UIGridStyleLayout + GUI + false + GuiBase2d + GuiObject,GuiBase2d + + + + + + SetCustomSortFunction + When SortOrder is set to Custom, this lua function is used to determine the ordering of elements. Function should take two arguments (each will be an Instance child to compare), and return true if a comes before b, otherwise return false. In other words, use this function the same way you would use a table.sort function. The sorting should be deterministic, otherwise sort will fail and fall back to name order. + true + + + + + ApplyLayout + Forces a relayout of all elements. Useful when sort is set to Custom. + + + + + + + + SortOrder + Determines how we decide which element to place next. Can be Name or Custom. If using Custom, make sure SetCustomSortFunction was called with an appropriate sort function. + + + + + FillDirection + Determines which direction to fill the grid. Can be Horizontal or Vertical. + + + + + HorizontalAlignment + Determines how grid is placed within it's parent's container in the x direction. Can be Left, Center, or Right. + + + + + VerticalAlignment + Determines how grid is placed within it's parent's container in the y direction. Can be Top, Center, or Bottom. + + + + + + + + UIListLayout + 30 + 26 + GUI + Sets the position of UI elements in a list. You can use a UIListLayout by parenting it to a GuiObject. The UIListLayout will then apply itself to all of its GuiObject siblings. + GuiBase2d + GuiObject,GuiBase2d + + + + + + Padding + Determines the amount of free space between each element. Can be set either using scale (Percentage of parent's size in the current direction) or offset (a static spacing value, similar to pixel size). + + + + + + + + UIGridLayout + 30 + 26 + GUI + Sets the position of UI elements in a 2D grid (this can be modified to 1D grid for list layout). This will also set the elements to a particular size, although this can be overridden with particular constraints on elements. You can use a UIGridLayout by parenting it to a GuiObject. The UIGridLayout will then apply itself to all of its GuiObject siblings. + GuiBase2d + GuiObject,GuiBase2d + + + + + + CellSize + Denotes what size each element should be. Can be overridden by elements using constraints on individual elements. + + + + + CellPadding + How much space between elements there should be. + + + + + FillDirectionMaxCells + Determines how many cells over in the FillDirection we go before starting a new row or column. Set to 0 for max cell count. Will be clamped if this is set higher than the parent container allows room for. + + + + + AbsoluteSize + Returns the current size of the grid. If more elements are added, this can increase. If elements are removed this can decrease. + + + + + StartCorner + Which corner we start laying the elements out from. Can be TopLeft, TopRight, BottomLeft, BottomRight. + + + + + + + + + UIPageLayout + 30 + 26 + GUI + Creates a paged viewing window, like the home screen of a mobile device. You can use a UIPageLayout by parenting it to a GuiObject. The UIPageLayout will then apply itself to all of its GuiObject siblings. + GuiBase2d + GuiObject,GuiBase2d + + + + + + CurrentPage + The page that is either currently being displayed or is the target of the current animation. + + + + + + Circular + Whether or not the page layout wraps around at the ends. + + + + + + Padding + Determines the amount that pages are separated from each other by. Can be set either using scale (Percentage of parent's size in the current direction) or offset (a static spacing value, similar to pixel size). + + + + + + Animated + Whether or not to animate transitions between pages. + + + + + + EasingStyle + The easing style to use when performing an animation. + + + + + + EasingDirection + The easing direction to use when performing an animation. + + + + + + TweenTime + The length of the animation. + + + + + + + + Next + Sets CurrentPage to the page after the current page and animates to it, or does nothing if there isn't a next page. + + + + + Previous + Sets CurrentPage to the page after the current page and animates to it, or does nothing if there isn't a next page. + + + + + JumpTo + If the instance is in the layout, then it sets CurrentPage to it and animtes to it. If circular layout is set, it will take the shortest path. + + + + + JumpToIndex + If the index is >= 0 and less than the size of the layout, acts like JumpTo. If it's out of bounds and circular is set, it will animate the full distance between the in-bounds index of CurrentPage and the new index. + + + + + + + + PageEnter + Fires when a page comes into view, and is going to be rendered. + + + + + PageLeave + Fires when a page leaves view, and will not be rendered. + + + + + Stopped + Fires when an animation to CurrentPage is completed without being cancelled, and the view stops scrolling. + + + + + + + + UITableLayout + 30 + 26 + GUI + Provides a layout of rows and columns that are sized based on the cells in them. + GuiBase2d + GuiObject,GuiBase2d + + + + + + Padding + The amount of padding to insert in between the cells of the table. + + + + + + FillEmptySpaceRows + Whether the table should expand to fill the available space of its container, row-wise. + + + + + + FillEmptySpaceColumns + Whether the table should expand to fill the available space of its container, column-wise. + + + + + + MajorAxis + Whether the direct siblings are considered the rows or the columns. The children of the direct siblings are the columns or rows, respectively. + + + + + + + + UISizeConstraint + 30 + 26 + GUI + Ensures a GuiObject does not become smaller or larger than the min and max size. If an element with a constraint is under the control of a layout, the constraint takes precedence in determining the element’s size, but not position. You can use a Constraint by parenting it to the element you wish to constrain. + GuiBase2d + GuiObject,GuiBase2d + + + + + + MinSize + The smallest size the GuiObject is allowed to be. + + + + + MaxSize + The biggest size the GuiObject is allowed to be. + + + + + + + + UITextSizeConstraint + 30 + 26 + GUI + Ensures a GuiObject with text does not allow the font size to become larger or smaller than min and max text sizes. If an element with a constraint is under the control of a layout, the constraint takes precedence in determining the element’s size, but not position. You can use a Constraint by parenting it to the element you wish to constrain. + GuiBase2d + GuiObject,GuiBase2d + + + + + + MinTextSize + The smallest size the font is allowed to be. + + + + + MaxTextSize + The biggest size the font is allowed to be. + + + + + + + + UIAspectRatioConstraint + 30 + 26 + GUI + Ensures a GuiObject will always have a particular aspect ratio. If an element with a constraint is under the control of a layout, the constraint takes precedence in determining the element’s size, but not position. You can use a Constraint by parenting it to the element you wish to constrain. + GuiObject,GuiBase2d + + + + + + AspectRatio + The aspect ratio to maintain. This is the width/height. Only positive numbers allowed. + + + + + AspectType + Describes how the aspect ratio will determine its size. Options are FitWithinMaxSize, ScaleWithParentSize. FitWithinMaxSize will make the element the maximum size it can be within the current possible AbsoluteSize of the element while maintaining the AspectRatio. ScaleWithParentSize will make the element the closest to the parent element’s maximum size while maintaining aspect ratio. + + + + + DominantAxis + Describes which axis to use when determining the new size of the element, while keeping respect to the aspect ratio. + + + + + + + + UIScale + 30 + 26 + GUI + Uniformly scales a GUI object and all its children. + GuiBase2d + GuiObject,GuiBase2d + + + + + + Scale + The scale factor to apply. + + + + + + + + UIPadding + 30 + 26 + GUI + Insets the children of the GuiObject this is parented to, by the specified padding. + GuiBase2d + GuiObject,GuiBase2d + + + + + + PaddingLeft + The padding to apply on the left side relative to the parent's normal size. + + + + + PaddingRight + The padding to apply on the right side relative to the parent's normal size. + + + + + PaddingTop + The padding to apply on the top side relative to the parent's normal size. + + + + + PaddingBottom + The padding to apply on the bottom side relative to the parent's normal size. + + + + + + + + TweenBase + false + + + + + + PlaybackState + The current state of how the tween is animating. Possible values are Begin, Playing, Paused, Completed and Cancelled. This property is modified by using functions such as Tween:Play(), Tween:Pause(), and Tween:Cancel(). Read-only. + + + + + + + + Play + Starts or resumes (if Tween.PlaybackState is Paused) the tween animation. If current PlaybackState is Cancelled, this property will reset the tween to the beginning properties and play the animations from the beginning. + + + + + Pause + Temporarily stops the tween animation. Animation can be resumed by calling Play(). + + + + + Cancel + Stops the tween animation. Animation can be restarted by calling Play(). Animation will start from the beginning values. + + + + + + + + Completed + Fires when the tween either reaches PlaybackState Completed or Cancelled. PlaybackState of one of these types is passed as the first arg to the function listening to this event. + + + + + + + + + Tween + An object linked to an instance that animates properties on the instance over a specified period of time. Useful for easily moving UI objects around, rotating objects, etc. without having to write a lot of code. To create a new tween, please use TweenService:Create. + + + + + + Instance + The object this tween is operating on. Read-only. + + + + + + TweenInfo + Specifies how the tween animates. Read-only. + + + + + + + + + TweenService + Service responsible for creating tweens on instances. + + + + + + + Create + Creates a Tween object bound to a particular Instance. The first arg is the Instance to tween. The second arg is a TweenInfo struct, which specifies how a tween should behave. The third arg is a table, which should specify the properties to tween as keys, with the end value specified as values to the keys. + + + + + + + + + + StarterGui + 30 + 46 + + + + + + SetCoreGuiEnabled + Will stop/begin certain core gui elements being rendered. See CoreGuiType for core guis that can be modified. + + + + + GetCoreGuiEnabled + Returns a boolean describing whether a CoreGuiType is currently being rendered. + + + + + + + + GuiService + The GuiService is a special service, which currently allows developers to control what GuiObject is currently being selected by the Gamepad Gui navigator, and allows clients to check if Roblox's main menu is currently open. This service has a lot of hidden members, which are mainly used internally by Roblox's CoreScripts. + + + + + + GetGuiInset + Returns a Tuple containing two Vector2 values representing the offset of user GUIs in pixels from the top right corner of the screen and the bottom right corner of the screen respectively. + + + + + + + + ContextActionService + A service used to bind input to various lua functions. + + + + + + BindAction + Binds 'functionToBind' to fire when any 'inputTypes' happen. InputTypes can be variable in number and type. Types can be Enum.KeyCode, single character strings corresponding to keys, or Enum.UserInputType. 'actionName' is a key used by many other ContextActionService functions to query state. 'createTouchButton' if true will create a button on screen on touch devices. This button will fire 'functionToBind' with three arguments: first argument is the actionName, second argument is the UserInputState of the input, and the third is the InputObject that fired this function. If 'functionToBind' yields or returns nil or Enum.ContextActionResult.Sink, the input will be sunk. If it returns Enum.ContextActionResult.Pass, the next bound action in the stack will be invoked. + + + + + SetTitle + If 'actionName' key contains a bound action, then 'title' is set as the title of the touch button. Does nothing if a touch button was not created. No guarantees are made whether title will be set when button is manipulated. + + + + + SetDescription + If 'actionName' key contains a bound action, then 'description' is set as the description of the bound action. This description will appear for users in a listing of current actions availables. + + + + + SetImage + If 'actionName' key contains a bound action, then 'image' is set as the image of the touch button. Does nothing if a touch button was not created. No guarantees are made whether image will be set when button is manipulated. + + + + + SetPosition + If 'actionName' key contains a bound action, then 'position' is set as the position of the touch button. Does nothing if a touch button was not created. No guarantees are made whether position will be set when button is manipulated. + + + + + UnbindAction + If 'actionName' key contains a bound action, removes function from being called by all input that it was bound by (if function was also bound by a different action name as well, those bound input are still active). Will also remove any touch button created (if button was manipulated manually there is no guarantee it will be cleaned up). + + + + + UnbindAllActions + Removes all functions bound. No actionNames will remain. All touch buttons will be removed. If button was manipulated manually there is no guarantee it will be cleaned up. + + + + + GetBoundActionInfo + Returns a table with info regarding the function bound with 'actionName'. Table has the keys 'title' (current title that was set with SetTitle) 'image' (image set with SetImage) 'description' (description set with SetDescription) 'inputTypes' (tuple containing all input bound for this 'actionName') 'createTouchButton' (whether or not we created a touch button for this 'actionName'). + + + + + GetAllBoundActionInfo + Returns a table with all bound action info. Each entry is a key with 'actionName' and value being the same table you would get from ContextActionService:GetBoundActionInfo('actionName'). + + + + + + + + GetButton + If 'actionName' key contains a bound action, then this will return the touch button (if was created). Returns nil if a touch button was not created. No guarantees are made whether button will be retrievable when button is manipulated. + + + + + + + + PointsService + A service used to query and award points for Roblox users using the universal point system. + true + + + + + + PointsAwarded + Fired when points are successfully awarded 'userId'. Also returns the updated balance of points for usedId in universe via 'userBalanceInUniverse', total points via 'userTotalBalance', and the amount points that were awarded via 'pointsAwarded'. This event fires on the server and also all clients in the game that awarded the points. + + + + + + + + AwardPoints + Will attempt to award the 'amount' points to 'userId', returns 'userId' awarded to, the number of points awarded, the new point total the user has in the game, and the total number of points the user now has. Will also fire PointsService.PointsAwarded. Works with server scripts ONLY. + + + + + GetPointBalance + Returns the overall balance of points that player with userId has (the sum of all points across all games). Works with server scripts ONLY. + + + + + GetGamePointBalance + Returns the balance of points that player with userId has in the current game (all placeID points combined within the game). Works with server scripts ONLY. + + + + + GetAwardablePoints + Returns the number of points the current universe can award to players. Works with server scripts ONLY. + + + + + + + + Chat + 510 + 33 + + + + + + + + + + ChatService + 510 + 33 + + + + + + + + LocalizationTable + 30 + 97 + Localization + LocalizationService + A database of strings used in the game and their translations. + + + + + + LocalizationService + 530 + 92 + + + + PreferredLanguage + Gets the system's preferred language (A Language enum). + + + + + GetLocaleId + Gets the system's LocaleId (Ex: "en-US"). + + + + + + + MarketplaceService + 46 + + + + + + PromptPurchase + Will prompt 'player' to purchase the item associated with 'assetId'. 'equipIfPurchased' is an optional argument that will give the item to the player immediately if they buy it (only applies to gear). 'currencyType' is also optional and will attempt to prompt the user with a specified currency if the product can be purchased with this currency, otherwise we use the default currency of the product. + + + + + + + + GetProductInfo + Takes one argument "assetId" which should be a number of an asset on www.roblox.com. Returns a table containing the product information (if this process fails, returns an empty table). + + + + + PlayerOwnsAsset + Checks to see if 'Player' owns the product associated with 'assetId'. Returns true if the player owns it, false otherwise. This call will produce a warning if called on a guest player. + + + + + + + ProcessReceipt + Callback that is executed for pending Developer Product receipts. + + If this function does not return Enum.ProductPurchaseDecision.PurchaseGranted, then you will not be granted the money for the purchase! + + The callback will be invoked with a table, containing the following informational fields: + PlayerId - the id of the player making the purchase. + PlaceIdWherePurchased - the specific place where the purchase was made. + PurchaseId - a unique identifier for the purchase, should be used to prevent granting an item multiple times for one purchase. + ProductId - the id of the purchased product. + CurrencyType - the type of currency used (Tix, Robux). + CurrencySpent - the amount of currency spent on the product for this purchase. + + + + + + + + PromptPurchaseFinished + Fired when a 'player' dismisses a purchase dialog for 'assetId'. If the player purchased the item 'isPurchased' will be true, otherwise it will be false. This call will produce a warning if called on a guest player. + + + + + + + + UserInputService + + + + + TouchEnabled + Returns true if the local device accepts touch input, false otherwise. + + + + + KeyboardEnabled + Returns true if the local device accepts keyboard input, false otherwise. + + + + + MouseEnabled + Returns true if the local device accepts mouse input, false otherwise. + + + + + AccelerometerEnabled + Returns true if the local device has an accelerometer, false otherwise. + + + + + GyroscopeEnabled + Returns true if the local device has an gyroscope, false otherwise. + + + + + + + + TouchTap + Fired when a user taps their finger on a TouchEnabled device. 'touchPositions' is a Lua array of Vector2, each indicating the position of all the fingers involved in the tap gesture. This event only fires locally. This event will always fire regardless of game state. + + + + + TouchPinch + Fired when a user pinches their fingers on a TouchEnabled device. 'touchPositions' is a Lua array of Vector2, each indicating the position of all the fingers involved in the pinch gesture. 'scale' is a float that indicates the difference from the beginning of the pinch gesture. 'velocity' is a float indicating how quickly the pinch gesture is happening. 'state' indicates the Enum.UserInputState of the gesture. This event only fires locally. This event will always fire regardless of game state. + + + + + TouchSwipe + Fired when a user swipes their fingers on a TouchEnabled device. 'swipeDirection' is an Enum.SwipeDirection, indicating the direction the user swiped. 'numberOfTouches' is an int that indicates how many touches were involved with the gesture. This event only fires locally. This event will always fire regardless of game state. + + + + + TouchLongPress + Fired when a user holds at least one finger for a short amount of time on the same screen position on a TouchEnabled device. 'touchPositions' is a Lua array of Vector2, each indicating the position of all the fingers involved in the gesture. 'state' indicates the Enum.UserInputState of the gesture. This event only fires locally. This event will always fire regardless of game state. + + + + + TouchRotate + Fired when a user rotates two fingers on a TouchEnabled device. 'touchPositions' is a Lua array of Vector2, each indicating the position of all the fingers involved in the gesture. 'rotation' is a float indicating how much the rotation has gone from the start of the gesture. 'velocity' is a float that indicates how quickly the gesture is being performed. 'state' indicates the Enum.UserInputState of the gesture. This event only fires locally. This event will always fire regardless of game state. + + + + + TouchPan + Fired when a user drags at least one finger on a TouchEnabled device. 'touchPositions' is a Lua array of Vector2, each indicating the position of all the fingers involved in the gesture. 'totalTranslation' is a Vector2, indicating how far the pan gesture has gone from its starting point. 'velocity' is a Vector2 that indicates how quickly the gesture is being performed in each dimension. 'state' indicates the Enum.UserInputState of the gesture. This event only fires locally. This event will always fire regardless of game state. + + + + + + TouchStarted + Fired when a user places their finger on a TouchEnabled device. 'touch' is an InputObject, which contains useful data for querying user input. This event only fires locally. This event will always fire regardless of game state. + + + + + TouchMoved + Fired when a user moves their finger on a TouchEnabled device. 'touch' is an InputObject, which contains useful data for querying user input. This event only fires locally. This event will always fire regardless of game state. + + + + + TouchEnded + Fired when a user moves their finger on a TouchEnabled device. 'touch' is an InputObject, which contains useful data for querying user input. This event only fires locally. This event will always fire regardless of game state. + + + + + + InputBegan + Fired when a user begins interacting via a Human-Computer Interface device (Mouse button down, touch begin, keyboard button down, etc.). 'inputObject' is an InputObject, which contains useful data for querying user input. This event only fires locally. This event will always fire regardless of game state. + + + + + InputChanged + Fired when a user changes interacting via a Human-Computer Interface device (Mouse move, touch move, mouse wheel, etc.). 'inputObject' is an InputObject, which contains useful data for querying user input. This event only fires locally. This event will always fire regardless of game state. + + + + + InputEnded + Fired when a user stops interacting via a Human-Computer Interface device (Mouse button up, touch end, keyboard button up, etc.). 'inputObject' is an InputObject, which contains useful data for querying user input. This event only fires locally. This event will always fire regardless of game state. + + + + + + TextBoxFocused + Fired when a user clicks/taps on a textbox to begin text entry. Argument is the textbox that was put in focus. This also fires if a textbox forces focus on the user. This event only fires locally. + + + + + TextBoxFocusReleased + Fired when a user stops text entry into a textbox (usually by pressing return or clicking/tapping somewhere else on the screen). Argument is the textbox that was taken out of focus. This event only fires locally. + + + + + DeviceAccelerationChanged + Fired when a user moves a device that has an accelerometer. This is fired with an InputObject, which has type Enum.InputType.Accelerometer, and position that shows the g force in each local device axis. This event only fires locally. + + + + + DeviceGravityChanged + Fired when the force of gravity changes on a device that has an accelerometer. This is fired with an InputObject, which has type Enum.InputType.Accelerometer, and position that shows the g force in each local device axis. This event only fires locally. + + + + + DeviceRotationChanged + Fired when a user rotates a device that has an gyroscope. This is fired with an InputObject, which has type Enum.InputType.Gyroscope, and position that shows total rotation in each local device axis. The delta property describes the amount of rotation that last happened. A second argument of Vector4 is the device's current quaternion rotation in reference to it's default reference frame. This event only fires locally. + + + + + + + + GetDeviceAcceleration + Returns an InputObject that describes the device's current acceleration. This is fired with an InputObject, which has type Enum.InputType.Accelerometer, and position that shows the g force in each local device axis. The delta property describes the amount of rotation that last happened. This event only fires locally. + + + + + GetDeviceGravity + Returns an InputObject that describes the device's current gravity vector. This is fired with an InputObject, which has type Enum.InputType.Accelerometer, and position that shows the g force in each local device axis. The delta property describes the amount of rotation that last happened. This event only fires locally. + + + + + GetDeviceRotation + Returns an InputObject and a Vector4 that describes the device's current rotation vector. This is fired with an InputObject, which has type Enum.InputType.Gyroscope, and position that shows total rotation in each local device axis. The delta property describes the amount of rotation that last happened. The Vector4 is the device's current quaternion rotation in reference to it's default reference frame. This event only fires locally. + + + + + + + + Sky + 5 + 28 + Lighting + Lighting + + + + + ColorCorrectionEffect + Post Processing Effects + 20 + 83 + Lighting + + + + + Brightness + -1 + 1 + + + + + Contrast + -1 + 1 + + + + + Saturation + -1 + 1 + + + + + + + BloomEffect + Post Processing Effects + 20 + 83 + Lighting + + + + + Intensity + 0 + 1 + + + + + Threshold + 0.8 + 4 + 1000 + + + + + Size + 0 + 56 + 56 + + + + + + + + BlurEffect + Post Processing Effects + 20 + 83 + Lighting + + + + + Size + 0 + 56 + 56 + + + + + + + + SunRaysEffect + Post Processing Effects + 20 + 83 + Lighting + + + + + Intensity + 0 + 1 + + + + + Spread + 0 + 1 + + + + + + + + Motor + 20 + false + BasePart + BasePart + + + + + Humanoid + Avatar + 30 + 9 + Model + Model + + + + + + MoveTo + Attempts to move the Humanoid and it's associated character to 'part'. 'location' is used as an offset from part's origin. + + + + + Jump + + + + + Sit + + + + + TakeDamage + Decreases health by the amount. Use this instead of changing health directly to make sure weapons are filtered for things such as ForceField(s). + + + + + UnequipTools + + Takes any active gear/tools that the Humanoid is using and puts them into the backpack. This function only works on Humanoids with a corresponding Player. + + + + + EquipTool + + Takes a specified tool and equips it to the Humanoid's Character. Tool argument should be of type 'Tool'. + + + + + ReplaceBodyPartR15 + Replaces the desired bodypart on the Humanoid's Character using a specified Enum.BodyPartR15 and BasePart. Returns a success boolean. + + + + + GetBodyPartR15 + Returns a Enum.BodyPartR15 given a body part in the Humanoid's Character. + + + + + + + NameOcclusion + + Sets how to display other humanoid names to this humanoid's player. <a href="http://wiki.roblox.com/index.php/NameOcclusion" target="_blank">More info</a> + + + Health + How many hit points the Humanoid has. When this number reaches 0 or goes below 0, the Humanoid's character falls apart and will respawn. + + + MaxHealth + The maximum number of hit points a Humanoid's health can reach. If the Humanoid's health is set over this amount, the health gets set to this value. + + + TargetPoint + The location that the Humanoid is trying to walk to. + + + Torso + Humanoid.RootPart will be the preferred way of getting a character's humanoid root part. + true + + + LeftLeg + In R6 this property get the player's left leg. In R15 this gets nothing. + true + + + RightLeg + In R6 this property get the player's right leg. In R15 this gets nothing. + true + + + + + + + BodyColors + Avatar + 20 + Model + Model + + + + + Shirt + Avatar + 20 + 43 + Model + Model + + + + + Pants + Avatar + 20 + 44 + Model + Model + + + + + ShirtGraphic + Avatar + 20 + 40 + Model + Model + + + + + Skin + true + 20 + + + + + DebugSettings + false + 20 + + + + + FaceInstance + false + + + + + GameSettings + false + 20 + + + + + GlobalSettings + false + 20 + + + + + Item + false + 20 + + + + + NetworkPeer + false + + + + + NetworkSettings + false + 20 + + + + + PVInstance + false + + + + + CoordinateFrame + true + Deprecated. Use CFrame instead + + + + + + + PackageLink + 1 + 98 + false + + + + + Status + Current status of the Package + true + + + + + + + RenderSettings + false + 20 + + + + + RootInstance + false + + + + + ServiceProvider + false + + + + + service + true + Use GetService() instead + + + + + GetService + Instance:isService:0 + + + + + FindService + Instance:isService:0 + + + + + + + ProfilingItem + false + + + + + NetworkMarker + false + + + + + + Hopper + true + Use StarterPack instead + 20 + + + + + + Instance + false + + + + + + Archivable + Determines whether or not an Instance can be saved when the game closes/attempts to save the game. Note: this only applies to games that use Data Persistence, or SavePlaceAsync. + + + + + ClassName + The string name of this Instance's most derived class. + + + + + Parent + The Instance that is directly above this Instance in the tree. + + + + + + + + + GetDebugId + false + This function is for internal testing. Don't use in production code + + + + + Clone + Returns a copy of this Object and all its children. The copy's Parent is nil + + + + + clone + true + Use Clone() instead + + + + + isA + true + Use IsA() instead + + + + + IsA + Returns a boolean if this Instance is of type 'className' or a is a subclass of type 'className'. If 'className' is not a valid class type in ROBLOX, this function will always return false. <a href="http://wiki.roblox.com/index.php/IsA" target="_blank">More info</a> + Instance:Any:0 + + + + + FindFirstChild + Returns the first child of this Instance that matches the first argument 'name'. The second argument 'recursive' is an optional boolean (defaults to false) that will force the call to traverse down thru all of this Instance's descendants until it finds an object with a name that matches the 'name' argument. The function will return nil if no Instance is found. + + + + + FindFirstChildOfClass + Returns the first child of this Instance that with a ClassName equal to 'className'. The function will return nil if no Instance is found. + Instance:isScriptCreatable:0 + + + + + FindFirstChildWhichIsA + Returns the first child of this Instance that :IsA(className). The second argument 'recursive' is an optional boolean (defaults to false) that will force the call to traverse down thru all of this Instance's descendants until it finds an object with a name that matches the 'className' argument. The function will return nil if no Instance is found. + Instance:Any:0 + + + + + FindFirstAncestor + Returns the first ancestor of this Instance that matches the first argument 'name'. The function will return nil if no Instance is found. + + + + + FindFirstAncestorOfClass + Returns the first ancestor of this Instance with a ClassName equal to 'className'. The function will return nil if no Instance is found. + Instance:isScriptCreatable:0 + + + + + FindFirstAncestorWhichIsA + Returns the first ancestor of this Instance that :IsA(className). The function will return nil if no Instance is found. + Instance:Any:0 + + + + + GetFullName + Returns a string that shows the path from the root node (DataModel) to this Instance. This string does not include the root node (DataModel). + + + + + children + true + Use GetChildren() instead + + + + + getChildren + true + Use GetChildren() instead + + + + + GetChildren + Returns a read-only table of this Object's children + + + + + GetDescendants + Returns an array containing all of the descendants of the instance. Returns in preorder traversal, or in other words, where the parents come before their children, depth first. + + + + + Remove + Deprecated. Use ClearAllChildren() to get rid of all child objects, or Destroy() to invalidate this object and its descendants + true + + + + + remove + true + Use Remove() instead + + + + + ClearAllChildren + Removes all children (but not this object) from the workspace. + + + + + Destroy + Removes object and all of its children from the workspace. Disconnects object and all children from open connections. Object and children may not be usable after calling Destroy. + + + + + findFirstChild + true + Use FindFirstChild() instead + + + + + + + + AncestryChanged + Fired when any of this object's ancestors change. First argument 'child' is the object whose parent changed. Second argument 'parent' is the first argument's new parent. + + + + + DescendantAdded + Fired after an Instance is parented to this object, or any of this object's descendants. The 'descendant' argument is the Instance that is being added. + + + + + DescendantRemoving + Fired after an Instance is unparented from this object, or any of this object's descendants. The 'descendant' argument is the Instance that is being added. + + + + + Changed + Fired after a property changes value. The property argument is the name of the property + + + + + + + + BodyGyro + Legacy Body Movers + Attempts to maintain a fixed orientation of its parent Part + 140 + 14 + BasePart + BasePart + + + + + + MaxTorque + The maximum torque that will be exerted on the Part + + + + + maxTorque + true + Use MaxTorque instead + + + + + D + The dampening factor applied to this force + + + + + P + The power continually applied to this force + + + + + CFrame + The cframe that this force is trying to orient its parent Part to. Note: this force only uses the rotation of the cframe, not the position. + + + + + cframe + true + Use CFrame instead + + + + + + + BodyPosition + Legacy Body Movers + 140 + 14 + BasePart + BasePart + + + + + + MaxForce + The maximum force that will be exerted on the Part + + + + + maxForce + true + Use MaxForce instead + + + + + D + The dampening factor applied to this force + + + + + P + The power factor continually applied to this force + + + + + Position + The Vector3 that this force is trying to position its parent Part to. + + + + + position + true + Use position instead + + + + + + + RocketPropulsion + Legacy Body Movers + 140 + 14 + A propulsion system that mimics a rocket + BasePart + BasePart + + + + + BodyVelocity + Legacy Body Movers + 140 + 14 + BasePart + BasePart + + + + + MaxForce + The maximum force that will be exerted on the Part in each axis + + + + + maxForce + true + Use MaxForce instead + + + + + P + The amount of power we add to the system. The higher the power, the quicker the force will achieve its goal. + + + + + Velocity + The velocity this system tries to achieve. How quickly the system reaches this velocity (if ever) is defined by P. + + + + + velocity + true + Use Velocity instead + + + + + + + BodyAngularVelocity + Legacy Body Movers + 140 + 14 + BasePart + BasePart + + + + MaxTorque + The maximum torque that will be exerted on the Part in each axis + + + maxTorque + true + Use MaxTorque instead + + + P + The amount of power we add to the system. The higher the power, the quicker the force will achieve its goal. + + + AngularVelocity + The rotational velocity this system tries to achieve. How quickly the system reaches this velocity is defined by P. + + + angularVelocity + true + Use AngularVelocity instead + + + + + + BodyForce + Legacy Body Movers + 140 + 14 + When parented to a physical part, BodyForce will continually exert a force upon its parent object. + BasePart + BasePart + + + + Force + The continual force exerted on an object, defined in each axis. + + + force + true + Use Force instead + + + + + + BodyThrust + Legacy Body Movers + 140 + 14 + BasePart + BasePart + + + + + + Force + The power continually applied to this force + + + + + force + true + Use Force instead + + + + + Location + The Vector3 location of where to apply the force to. + + + + + location + true + Use Location instead + + + + + + + Hole + true + 20 + + + + + Feature + 20 + + + + + + Teams + This Service-level object is the container for all Team objects in a level. A map that supports team games must have a Teams service. <a href="http://wiki.roblox.com/index.php/Team" target="_blank">More info</a> + 140 + 23 + Teams + Teams + + + + + GetPlayers + Returns a read-only table of players which are on this team. + + + + + + + Team + Interaction + The Team class is used to represent a faction in a team game. The only valid location for a Team object is under the Teams service. <a href="http://wiki.roblox.com/index.php/Team" target="_blank">More info</a> + 10 + 24 + Teams + Teams + + + + + SpawnLocation + Interaction + 30 + 25 + + + + + NetworkClient + false + 30 + 16 + + + + + NetworkServer + false + 30 + 15 + + + + + LuaSourceContainer + false + StarterPlayerScripts,StarterCharacterScripts,ServerScriptService + + + + + CurrentEditor + The name of the player who is currently editing the script in Team Create. + true + + + + + + + Script + Scripting + 30 + 6 + ServerStorage,ServerScriptService + + + + + + LinkedScript + + This property is under development. Do not use + + + + + + + + LocalScript + Scripting + 40 + 18 + ReplicatedFirst,ReplicatedStorage,StarterCharacterScripts,StarterPlayerScripts + A script that runs on clients, NOT servers. LocalScripts can only run when parented under one of the following: + 1) A player's Backpack. + 2) A player's Character model. + 3) A player's PlayerGui. + 4) A player's PlayerScripts. + 5) The ReplicatedFirst service. + + + + + + + RenderingTest + Scripting + 40 + dummy summary + 5 + + + + + + NetworkReplicator + 30 + 29 + + + + + + Model + 100 + 2 + A construct used to group Parts and other objects together, also allows manipulation of multiple objects. + PVInstance + PVInstance + + + + + BreakJoints + Breaks all surface joints contained within + + + + + GetModelCFrame + Returns a CFrame that has position of the centroid of all Parts in the Model. The rotation matrix is either the rotation matrix of the user-defined PrimaryPart, or if not specified then a part in the Model chosen by the engine. + + + + + GetModelSize + Returns a Vector3 that is union of the extents of all Parts in the model. + + + + + MakeJoints + Creates the appropriate SurfaceJoints between all touching Parts contrained within the model. Technically, this function calls MakeJoints() on all Parts inside the model. + + + + + MoveTo + Moves the centroid of the Model to the specified location, respecting all relative distances between parts in the model. + + + + + ResetOrientationToIdentity + Rotates all parts in the model to the orientation that was set using SetIdentityOrientation(). If this function has never been called, rotation is reset to GetModelCFrame()'s rotation. + + + + + SetIdentityOrientation + Takes the current rotation matrix of the model and stores it as the model's identity matrix. The rotation is applied when ResetOrientationToIdentity() is called. + + + + + TranslateBy + Similar to MoveTo(), except instead of moving to an explicit location, we use the model's current CFrame location and offset it. + + + + + GetPrimaryPartCFrame + Returns the cframe of the Model.PrimaryPart. If PrimaryPart is nil, then this function will throw an error. + + + + + SetPrimaryPartCFrame + Sets the cframe of the Model.PrimaryPart. If PrimaryPart is nil, then this function will throw an error. This also sets the cframe of all descendant Parts relative to the cframe change to PrimaryPart. + + + + + makeJoints + Use MakeJoints() instead + true + + + + + move + true + Use MoveTo() instead + + + + + + + PrimaryPart + A Part that serves as a reference for the Model's CFrame. Used in conjunction with GetModelPrimaryPartCFrame and SetModelPrimaryPartCFrame. Use this to rotate/translate all Parts relative to the PrimaryPart. + + + + + + + + Status + true + 100 + 2 + + + + + move + true + Use MoveTo() instead + + + + + + + + DataModel + The root of ROBLOX's parent-child hierarchy (commonly known as game after the global variable used to access it) + + + + + + OnClose + true + Deprecated. Use DataModel.BindToClose + + + + + + + + + + Workspace + + + + + workspace + true + Deprecated. Use Workspace + + + + + ShowMouse + true + Deprecated. Use Workspace.IsMouseCursorVisible + + + + + IsLoaded + Returns true if the game has finished loading, false otherwise. Check this before listening to the Loaded signal to ensure a script knows when a game finishes loading. + + + + + + + + Loaded + Fires when the game finishes loading. Use this to know when to remove your custom loading gui. It is best to check IsLoaded() before connecting to this event, as the game may load before the event is connected to. + + + + + + + + SetPlaceID + true + Use SetPlaceId() instead + + + + + SetCreatorID + true + Use SetCreatorId() instead + + + + + + + + DataStoreService + Responsible for storing data across multiple user created places + -1 + + + + + + GetDataStore + Returns a data store with the given name and scope + + + + + GetGlobalDataStore + Returns the default data store + + + + + GetOrderedDataStore + Returns an ordered data store with the given name and scope + + + + + + + + GlobalDataStore + Exposes functions for saving and loading data for the DataStoreService + -1 + + + + + + OnUpdate + Sets callback as a function to be executed any time the value associated with key is changed. It is important to disconnect the connection when the subscription to the key is no longer needed. + + + + + + + + GetAsync + Returns the value of the entry in the DataStore with the given key + + + + + IncrementAsync + Increments the value of a particular key amd returns the incremented value + + + + + SetAsync + Sets the value of the key. This overwrites any existing data stored in the key + + + + + UpdateAsync + Retrieves the value of the key from the website, and updates it with a new value. The callback until the value fetched matches the value on the web. Returning nil means it will not save. + + + + + + + + OrderedDataStore + A type of DataStore where values must be positive integers. This makes OrderedDataStore suitable for leaderboard related scripting where you are required to order large amounts of data efficiently. + -1 + + + + + + GetSortedAsync + Returns a DataStorePages object. The length of each page is determined by pageSize, and the order is determined by isAscending. minValue and maxValue are optional parameters which will filter the result. + + + + + + + + HopperBin + true + 240 + 22 + + + + + + Camera + 5 + 5 + Model + Model + + + + + CameraSubject + Where the Camera's focus is. Any rotation of the camera will be about this subject. + + + + + CameraType + Defines how the camera will behave. <a href="http://wiki.roblox.com/index.php/CameraType" target="_blank">More info</a> + + + + + CoordinateFrame + true + The current position and rotation of the Camera. For most CameraTypes, the rotation is set such that the CoordinateFrame lookVector is pointing at the Focus. + + + + + CFrame + The current position and rotation of the Camera. For most CameraTypes, the rotation is set such that the CoordinateFrame lookVector is pointing at the Focus. + + + + + FieldOfView + The current angle, or width, of what the camera can see. Current acceptable values are from 20 degrees to 80. + + + + + Focus + The current CoordinateFrame that the camera is looking at. Note: it is not always guaranteed that the camera is always looking here. + + + + + ViewportSize + Holds the x,y screen resolution of the viewport the camera is presenting (note: this can differ from the AbsoluteSize property of a full screen gui). + + + + + NearPlaneZ + The negative z-offset of the view frustum's near clipping plane. + + + + + + + GetRoll + Returns the camera's current roll. Roll is defined in radians, and is stored as the delta from the camera's y axis default normal vector. + + + + + WorldToScreenPoint + Takes a 3D position in the world and projects it onto x,y coordinates of screen space. Returns two values, first is a Vector3 that has x,y position and z position which is distance from camera (negative if behind camera, positive if in front). Second return value is a boolean indicating if the first argument is an on-screen coordinate. + + + + + ScreenPointToRay + Takes a 2D screen position and produces a Ray object to be used for 3D raycasting. Input is x,y screen coordinates, and a (optional, defaults to 0) z position which sets how far in the camera look vector to start the ray origin. + + + + + ViewportPointToRay + Same as ScreenPointToRay, except no GUI offsets are taken into account. Useful for things like casting a ray from the middle of the Camera.ViewportSize + + + + + WorldToViewportPoint + Same as WorldToScreenPoint, except no GUI offsets are taken into account. + + + + + SetRoll + Sets the camera's current roll. Roll is defined in radians, and is stored as the delta from the camera's y axis default normal vector. + + + + + + + + Players + 20 + 21 + + + + + CharacterAutoLoads + true + Set to true, when a player joins a game, they get a character automatically, as well as when they die. When set to false, characters do not auto load and will only load in using Player:LoadCharacter(). + + + + + + + players + true + Use GetPlayers() instead + + + + + + + + ReplicatedStorage + 30 + 70 + A container whose contents are replicated to all clients and the server. + + + + + + RobloxReplicatedStorage + false + + + + + + ReplicatedFirst + 30 + 70 + A container whose contents are replicated to all clients (but not back to the server) first before anything else. Useful for creating loading guis, tutorials, etc. + + + + + RemoveRobloxLoadingScreen + Removes the default Roblox loading screen from view. Call this when you are ready to either show your own loading gui, or when the game is ready to play. + + + + + + + + ServerStorage + 30 + 69 + A container whose contents are only on the server. + + + + + + ServerScriptService + 30 + 71 + A container whose contents should be scripts. Scripts that are added to the container are run on the server. + + + + + + StudioService + -1 + A service for interfacing with the current studio state from Lua. + + + + + + Lighting + 30 + 13 + Responsible for all lighting aspects of the world (affects how things are rendered). + + + + + GetMinutesAfterMidnight + The number of minutes that the current time is past midnight. If currently at midnight, returns 0. Will return decimal values if not at an exact minute. + + + + + GetMoonDirection + Returns the lookVector (Vector3) of the moon. If this lookVector was used in a CFrame, the Part would face the moon. + + + + + GetMoonPhase + Currently always returns 0.75. MoonPhase cannot be edited. + + + + + GetSunDirection + Returns the lookVector (Vector3) of the sun. If this lookVector was used in a CFrame, the Part would face the sun. + + + + + SetMinutesAfterMidnight + Sets the time to be a certain number of minutes after midnight. This works with integer and decimal values. + + + + + + + Ambient + The hue of the global lighting. Changing this changes the color tint of all objects in the Workspace. + + + + + Brightness + How much global light each Part in the Workspace receives. Standard range is 0 to 1 (0 being little light), but can be increased all the way to 5 (colors start to be appear very different at this value). + 0 + 2 + + + + + ExposureCompensation + Exposure compensation amount. Applies a bias to the exposure level prior to the tonemap step. +1 indicates twice as much exposure and -1 means half as much exposure. + -3 + 3 + 600 + + + + + ColorShift_Bottom + The hue of global lighting on the bottom surfaces of an object. + + + + + ColorShift_Top + The hue of global lighting on the top surfaces of an object. + + + + + FogColor + A Color3 value that changes the hue of distance fog. + + + + + FogEnd + The distance at which fog completely blocks your vision. This distance is relative to the camera position. Units are in studs + + + + + FogStart + The distance at which the fog gradient begins. This distance is relative to the camera position. Units are in studs. + + + + + GeographicLatitude + The latitude position the level is placed at. This affects sun position. <a href="http://wiki.roblox.com/index.php/GeographicLatitude" target="_blank">More info</a> + 0 + 360 + 360 + + + + + GlobalShadows + Flag enabling shadows from sun and moon in the place + + + + + OutdoorAmbient + Effective ambient value for outdoors, effectively shadow color outdoors (requires GlobalShadows enabled) + + + + + Outlines + Flag enabling or disabling outlines on parts and terrain + + + + + ShadowColor + Color the shadows appear as. Shadows are drawn mostly for characters, but depending on the lighting will also show for Parts in the Workspace. Rendering settings can also affect if shadows are drawn. + + + + + TimeOfDay + A string that represent the current time of day. Time is in 24-hour clock format "XX::YY:ZZ", where X is hour, Y is minute, and Z is seconds. + + + + + ClockTime + 0 + 24 + 240 + + + + + + + LightingChanged + Fired whenever a property of Lighting is changed, or a skybox is added or removed. Skyboxes are of type 'Sky' and should be parented directly to lighting. + + + + + + + + TestService + 1000 + 68 + + + + + + DebuggerManager + + + + + + + + ScriptDebugger + + + + + + + + DebuggerBreakpoint + + + + + + + + DebuggerWatch + + + + + + + + Debris + -1 + 30 + A service that provides utility in cleaning up objects + + + + + addItem + true + Use AddItem() instead + + + + + AddItem + Adds an Instance into the debris service that will later be destroyed. Second argument 'lifetime' is optional and specifies how long (in seconds) to wait before destroying the item. If no time is specified then the item added will automatically be destroyed in 10 seconds. + + + + + + + MaxItems + true + Deprecated. No replacement + + + + + + + + Accoutrement + 20 + 32 + false + + + + + + Player + false + 10 + 12 + + + + + + CharacterAppearance + false + Model + Model + + + + + CameraMode + An enum that describes how a Player's camera is allowed to behave. <a href="http://wiki.roblox.com/index.php/CameraMode" target="_blank">More info</a>. + + + + + DataReady + true + Read-only. If true, this Player's persistent data can be loaded, false otherwise. <a href="http://wiki.roblox.com/index.php/ROBLOX_Scripting_How_To:_Data_Persistence" target="_blank">Info on Data Persistence</a>. + + + + + DataComplexity + true + + + + + + + + LoadCharacter + true + Loads in a new character for this player. This will replace the player's current character, if they have one. This should be used in conjunction with Players.CharacterAutoLoads to control spawning of characters. This function only works from a server-side script (NOT a LocalScript). + + + + + LoadData + true + + + + + SaveData + true + + + + + SaveBoolean + true + + + + + SaveInstance + true + + + + + SaveString + true + + + + + LoadBoolean + true + + + + + LoadNumber + true + + + + + LoadString + true + + + + + LoadInstance + true + + + + + SaveNumber + true + + + + + playerFromCharacter + true + Use GetPlayerFromCharacter() instead + + + + + SetUnder13 + true + + + + + + + + WaitForDataReady + true + true + Yields until the persistent data for this Player is ready to be loaded. <a href="http://wiki.roblox.com/index.php/ROBLOX_Scripting_How_To:_Data_Persistence" target="_blank">Info on Data Persistence</a>. + + + + + + + + + Idled + Fired periodically after the user has been AFK for a while. Currently this event is only fired for the *local* Player. "time" is the time in seconds that the user has been idle. + + + + + + + + Workspace + 5 + 19 + + + + + FindPartsInRegion3 + Returns parts in the area defined by the Region3, up to specified maxCount or 100, whichever is less + + + + + FindPartsInRegion3WithIgnoreList + Returns parts in the area defined by the Region3, up to specified maxCount or 100, whichever is less + + + + + FindPartOnRay + Return type is (BasePart, Vector3) if the ray hits. If it misses it will return (nil, PointAtEndOfRay) + + + + + FindPartOnRayWithIgnoreList + Return type is (BasePart, Vector3) if the ray hits. If it misses it will return (nil, PointAtEndOfRay) + + + + + + + PGSPhysicsSolverEnabled + Boolean used to enable the new physics solver + + + + + FallenPartsDestroyHeight + Sets the height at which falling characters and parts are destroyed. This property is not scriptable and can only be set in Studio + + + + + + + + BasePart + A structural class, not creatable + 3 + false + + + + + + Color + Color3 of the part. + + + + + CFrame + Contains information regarding the Part's position and a matrix that defines the Part's rotation. Can read/write. <a href="http://wiki.roblox.com/index.php/Cframe" target="_blank">More info</a> + + + + + CanCollide + Determines whether physical interactions with other Parts are respected. If true, will collide and react with physics to other Parts. If false, other parts will pass thru instead of colliding + + + + + Anchored + Determines whether or not physics acts upon the Part. If true, part stays 'Anchored' in space, not moving regardless of any collision/forces acting upon it. If false, physics works normally on the part. + + + + + Elasticity + A float value ranging from 0.0f to 1.0f. Sets how much the Part will rebound against another. a value of 1 is like a superball, and 0 is like a lead block. + 0 + 1 + + + + + Friction + A float value ranging from 0.0f to 1.0f. Sets how much the Part will be able to slide. a value of 1 is no sliding, and 0 is no friction, so infinite sliding. + 0 + 2 + + + + + Locked + Determines whether building tools (in-game and studio) can manipulate this Part. If true, no editing allowed. If false, editing is allowed. + + + + + Material + Specifies the look and feel the Part should have. Note: this does not define the color the Part is, see BrickColor for that. <a href="http://wiki.roblox.com/index.php/Material" target="_blank">More info</a> + + + + + Reflectance + Specifies how shiny the Part is. A value of 1 is completely reflective (chrome), while a value of 0 is no reflectance (concrete wall) + 0 + 1 + + + + + ResizeIncrement + Sets the value for the smallest change in size allowable by the Resize(NormalId, int) function. + + + + + ResizeableFaces + Sets the value for the faces allowed to be resized by the Resize(NormalId, int) function. + + + + + Transparency + Sets how visible an object is. A value of 1 makes the object invisible, while a value of 0 makes the object opaque. + 0 + 1 + + + + + Velocity + How fast the Part is traveling in studs/second. This property is NOT recommended to be modified directly, unless there is good reason. Otherwise, try using a BodyForce to move a Part. + + + + + PositionLocal + Position relative to parent part, or global space if there is no parent. + + + + + OrientationLocal + Orientation relative to parent part, or global space if there is no parent. + + + + + Orientation + Rotation around X, Y, and Z axis. Rotations applied in YXZ order. + + + + + Rotation + + + + + CenterOfMass + + + + + + + + makeJoints + Use MakeJoints() instead + true + + + + + MakeJoints + Creates the appropriate SurfaceJoints with all parts that are touching this Instance (including internal joints in the Instance, as in a Model). This uses the SurfaceTypes defined on the surfaces of parts to create the appropriate welds. <a href="http://wiki.roblox.com/index.php/MakeJoints" target="_blank">More info</a> + + + + + BreakJoints + Destroys SurfaceJoints with all parts that are touching this Instance (including internal joints in the Instance, as in a Model). + + + + + GetMass + Returns a number that is the mass of this Instance. Mass of a Part is immutable, and is changed only by the size of the Part. + + + + + Resize + Resizes a Part in the direction of the face defined by 'NormalId', by the amount specified by 'deltaAmount'. If the operation will expand the part to intersect another Instance, the part will not resize at all. Return true if the call is successful, false otherwise. + + + + + getMass + Use GetMass() instead + true + + + + + + + OutfitChanged + true + + + + + LocalSimulationTouched + true + Deprecated. Use Touched instead + + + + + StoppedTouching + + Deprecated. Use TouchEnded instead + + + + + TouchEnded + Fired when the part stops touching another part + + + + + + + Part + Parts + A plastic building block - the fundamental component of ROBLOX + 110 + 1 + Workspace + Workspace + + + + + TrussPart + Parts + An extendable building truss + 120 + 1 + Model + Model + + + + + WedgePart + Parts + A Wedge Part + 120 + 1 + Model + Model + + + + + PrismPart + A Prism Part + false + true + 120 + 1 + + + + + PyramidPart + A Pyramid Part + false + true + 120 + 1 + + + + + ParallelRampPart + A ParallelRamp Part + false + true + 120 + 1 + + + + + RightAngleRampPart + A RightAngleRamp Part + false + true + 120 + 1 + + + + + CornerWedgePart + Parts + A CornerWedge Part + 120 + 1 + Workspace + Workspace,Model + + + + + PlayerGui + A container instance that syncs data between a single player and the server. ScreenGui objects that are placed in this container will be shown to the Player parent only + 130 + 46 + + + + + SelectionImageObject + Overrides the default selection adornment (used for gamepads). For best results, this should point to a GuiObject. + + + + + + + PlayerScripts + A container instance that contains LocalScripts. LocalScript objects that are placed in this container will be exectue only when a Player is the parent. + 130 + 78 + + + + + StarterPlayerScripts + A container instance that contains LocalScripts. LocalScript objects that are placed in this container will be copied to new Players on startup. + 130 + 78 + false + + + + + StarterCharacterScripts + A container instance that contains LocalScripts. LocalScript objects that are placed in this container will be copied to new characters on startup. + 130 + 78 + false + + + + + + GuiMain + Deprecated, please use ScreenGui + true + 140 + 47 + + + + + + LayerCollector + The base class of ScreenGui, BillboardGui, and SurfaceGui. + false + + + + Enabled + Whether or not this should be displayed. + + + ZIndexBehavior + Controls the behavior of the ZIndex property for descendants of this object. It can be set to Global (Default) or Sibling. + + + + + + + ScreenGui + GUI + The core GUI object on which tools are built. Add Frames/Labels/Buttons to this object to have them rendered as a 2D overlay + 140 + 47 + BasePlayerGui + BasePlayerGui + + + + + FunctionalTest + Deprecated. Use TestService instead + true + 10 + + + + + BillboardGui + GUI + A GUI that adorns an object in the 3D world. Add Frames/Labels/Buttons to this object to have them rendered while attached to a 3D object + 140 + 64 + GuiBase2d + GuiBase2d + + + + + + Adornee + The Object the billboard gui uses as its base to render from. Currently, the only way to set this property is thru a script, and must exist in the workspace. This will only render if the object assigned derives from BasePart. + + + + + AbsolutePosition + A read-only Vector2 value that is the GuiObject's current position (x,y) in pixel space, from the top left corner of the GuiObject. + + + + + AbsoluteSize + A read-only Vector2 value that is the GuiObject's current size (width, height) in pixel space. + + + + + Active + If true, this GuiObject can fire mouse events and will pass them to any GuiObjects layered underneath, while false will do neither. + + + + + AlwaysOnTop + If true, billboard gui does not get occluded by 3D objects, but always renders on the screen. + + + + + Enabled + If true, billboard gui will render, otherwise rendering will be skipped. + + + + + ExtentsOffset + A Vector3 (x,y,z) defined in studs that will offset the gui from the extents of the 3d object it is rendering from. + + + + + PlayerToHideFrom + Specifies a Player that the BillboardGui will not render to. + + + + + StudsOffset + A Vector3 (x,y,z) defined in studs that will offset the gui from the centroid of the 3d object it is rendering from + + + + + SizeOffset + A Vector2 (x,y) defined in studs that will offset the gui size from it's current size. + + + + + Size + A UDim2 value describing the size of the BillboardGui. More information on UDim2 is available <a href="http://wiki.roblox.com/index.php/UDim2" target="_blank">here</a>. Relative values are defined as one-to-one with studs. + + + + + LightInfluence + Specifies the amount of influence lighting has on the billboard gui. A value of 0 is unlit, 1 is fully lit. Fractional values blend from unlit to lit. + 0 + 1 + + + + + + + + SurfaceGui + GUI + Renders its contained GuiObjects flat against the face of a part. + 140 + 64 + GuiBase2d + GuiBase2d + + + + + + Adornee + The Object the surface gui uses as its base to render from. Currently, the only way to set this property is thru a script, and must exist in the workspace. This will only render if the object assigned derives from BasePart. + + + + + Active + If true, this GuiObject can fire mouse events and will pass them to any GuiObjects layered underneath, while false will do neither. + + + + + Enabled + If true, surface gui will render, otherwise rendering will be skipped. + + + + + LightInfluence + Specifies the amount of influence lighting has on the surface gui. A value of 0 is unlit, 1 is fully lit. Fractional values blend from unlit to lit. + 0 + 1 + + + + + + + + + + GuiBase2d + false + LayerCollector,GuiBase2d + + + + + + AbsolutePosition + A read-only Vector2 value that is the GuiObject's current position (x,y) in pixel space, from the top left corner of the GuiObject. + + + + + AbsoluteSize + A read-only Vector2 value that is the GuiObject's current size (width, height) in pixel space. + + + + + + + + InputObject + An object that describes a particular user input, such as mouse movement, touches, keyboard, and more. + + + + + UserInputType + An enum that describes what kind of input this object is describing (mousebutton, touch, etc.). See Enum.UserInputType for more info. + + + + + UserInputState + An enum that describes what state of a particular input (touch began, touch moved, touch ended, etc.). See Enum.UserInputState for more info. + + + + + Position + A Vector3 value that describes a positional value of this input. For mouse and touch input, this is the screen position of the mouse/touch, described in the x and y components. For mouse wheel input, the z component describes whether the wheel was moved forward or backward. + + + + + KeyCode + An enum that describes what kind of input is being pressed. For types of input like Keyboard, this describes what key was pressed. For input like mousebutton, this provides no additional information. + + + + + + + + GuiObject + false + + + + + + TweenPosition + Smoothly moves a GuiObject from its current position to 'endPosition'. The only required argument is 'endPosition'. <a href="http://wiki.roblox.com/index.php/TweenPosition" target="_blank">More info</a> + + + + + TweenSize + Smoothly translates a GuiObject's current size to 'endSize'. The only required argument is 'endSize'. <a href="http://wiki.roblox.com/index.php/TweenSize" target="_blank">More info</a> + + + + + TweenSizeAndPosition + Smoothly translates a GuiObject's current size to 'endSize', and also smoothly translates the GuiObject's current position to 'endPosition'. The only required arguments are 'endSize' and 'endPosition'. <a href="http://wiki.roblox.com/index.php/TweenSizeAndPosition" target="_blank">More info</a> + + + + + + + + Active + If true, this GuiObject can fire mouse events and will pass them to any GuiObjects layered underneath, while false will do neither. + + + + + BackgroundColor3 + A Color3 value that specifies the background color for the GuiObject. This value is ignored if the Style property (not found on all GuiObjects) is set to something besides custom. + + + + + BackgroundTransparency + A number value that specifies how transparent the background of the GuiObject is. This value is ignored if the Style property (not found on all GuiObjects) is set to something besides custom. + 0 + 1 + + + + + BorderColor3 + A Color3 value that specifies the color of the outline of the GuiObject. This value is ignored if the Style property (not found on all GuiObjects) is set to something besides custom. + + + + + BorderSizePixel + A number value that specifies the thickness (in pixels) of the outline of the GuiObject. Currently this value can only be set to either 0 or 1, any other number has no effect. This value is ignored if the Style property (not found on all GuiObjects) is set to something besides custom. + + + + + ClipsDescendants + If set to true, any descendants of this GuiObject will only render if contained within it's borders. If set to false, all descendants will render regardless of position. + + + + + Draggable + true + If true, allows a GuiObject to be dragged by the user's mouse. The events 'DragBegin' and 'DragStopped' are fired when the appropriate action happens, and only will fire on Draggable=true GuiObjects. + + + + + Size + A UDim2 value describing the size of the GuiObject on screen in both absolute and relative coordinates. More information on UDim2 is available <a href="http://wiki.roblox.com/index.php/UDim2" target="_blank">here</a>. + + + + + Position + A UDim2 value describing the position of the top-left corner of the GuiObject on screen. More information on UDim2 is available <a href="http://wiki.roblox.com/index.php/UDim2" target="_blank">here</a>. + + + + + SizeConstraint + The direction(s) that an object can be resized in. <a href="http://wiki.roblox.com/index.php/SizeConstraint" target="_blank">More info</a>. + + + + + ZIndex + Describes the ordering in which overlapping GuiObjects will be drawn. A value of 1 is drawn first, while higher values are drawn in ascending order (each value draws over the last). + + + + + BackgroundColor + true + Deprecated. Use BackgroundColor3 instead + + + + + BorderColor + true + Deprecated. Use BorderColor3 instead + + + + + SelectionImageObject + Overrides the default selection adornment (used for gamepads). For best results, this should point to a GuiObject. + + + + + + + + DragBegin + true + Fired when a GuiObject with Draggable set to true starts to be dragged. 'InitialPosition' is a UDim2 value of the position of the GuiObject before any drag operation began. + + + + + DragStopped + true + Always fired after a DragBegin event, DragStopped is fired when the user releases the mouse button causing a drag operation on the GuiObject. Arguments 'x', and 'y' specify the top-left absolute position of the GuiObject when the event is fired. + + + + + MouseEnter + Fired when the mouse enters a GuiObject, as long as the GuiObject is active (see active property for more detail). Arguments 'x', and 'y' specify the absolute pixel position of the mouse. + + + + + MouseLeave + Fired when the mouse leaves a GuiObject, as long as the GuiObject is active (see active property for more detail). Arguments 'x', and 'y' specify the absolute pixel position of the mouse. + + + + + MouseMoved + Fired when the mouse is inside a GuiObject and moves, as long as the GuiObject is active (see active property for more detail). Arguments 'x', and 'y' specify the absolute pixel position of the mouse. + + + + + + TouchTap + Fired when a user taps their finger on a TouchEnabled device. 'touchPositions' is a Lua array of Vector2, each indicating the position of all the fingers involved in the tap gesture. This event only fires locally. This event will always fire regardless of game state. + + + + + TouchPinch + Fired when a user pinches their fingers on a TouchEnabled device. 'touchPositions' is a Lua array of Vector2, each indicating the position of all the fingers involved in the pinch gesture. 'scale' is a float that indicates the difference from the beginning of the pinch gesture. 'velocity' is a float indicating how quickly the pinch gesture is happening. 'state' indicates the Enum.UserInputState of the gesture. This event only fires locally. + + + + + TouchSwipe + Fired when a user swipes their fingers on a TouchEnabled device. 'swipeDirection' is an Enum.SwipeDirection, indicating the direction the user swiped. 'numberOfTouches' is an int that indicates how many touches were involved with the gesture. This event only fires locally. + + + + + TouchLongPress + Fired when a user holds at least one finger for a short amount of time on the same screen position on a TouchEnabled device. 'touchPositions' is a Lua array of Vector2, each indicating the position of all the fingers involved in the gesture. 'state' indicates the Enum.UserInputState of the gesture. This event only fires locally. + + + + + TouchRotate + Fired when a user rotates two fingers on a TouchEnabled device. 'touchPositions' is a Lua array of Vector2, each indicating the position of all the fingers involved in the gesture. 'rotation' is a float indicating how much the rotation has gone from the start of the gesture. 'velocity' is a float that indicates how quickly the gesture is being performed. 'state' indicates the Enum.UserInputState of the gesture. This event only fires locally. + + + + + TouchPan + Fired when a user drags at least one finger on a TouchEnabled device. 'touchPositions' is a Lua array of Vector2, each indicating the position of all the fingers involved in the gesture. 'totalTranslation' is a Vector2, indicating how far the pan gesture has gone from its starting point. 'velocity' is a Vector2 that indicates how quickly the gesture is being performed in each dimension. 'state' indicates the Enum.UserInputState of the gesture. + + + + + + InputBegan + Fired when a user begins interacting via a Human-Computer Interface device (Mouse button down, touch begin, keyboard button down, etc.). 'inputObject' is an InputObject, which contains useful data for querying user input. This event only fires locally. + + + + + InputChanged + Fired when a user changes interacting via a Human-Computer Interface device (Mouse move, touch move, mouse wheel, etc.). 'inputObject' is an InputObject, which contains useful data for querying user input. This event only fires locally. + + + + + InputEnded + Fired when a user stops interacting via a Human-Computer Interface device (Mouse button up, touch end, keyboard button up, etc.). 'inputObject' is an InputObject, which contains useful data for querying user input. This event only fires locally. + + + + + + + + + Frame + GUI + A container object used to layout other GUI objects + 150 + 48 + GuiBase2d + GuiBase2d + + + + + Style + Determines how a frame will look. Uses Enum.FrameStyle. <a href="http://wiki.roblox.com/index.php?title=API:Enum/FrameStyle" target="_blank">More info</a> + + + + + + + ScrollingFrame + GUI + A container object used to layout other GUI objects, and allows for scrolling. + 150 + 48 + GuiBase2d + GuiBase2d + + + + + ScrollingEnabled + Determines whether or not scrolling is allowed on this frame. If turned off, no scroll bars will be rendered. + + + + + CanvasSize + Determines the size of the area that is scrollable. The UDim2 is calculated using the parent gui's size, similar to the regular Size property on gui objects. + + + + + CanvasPosition + The absolute position the scroll frame is in respect to the canvas size. The minimum this can be set to is (0,0), while the max is the absolute canvas size - AbsoluteWindowSize. + + + + + AbsoluteWindowSize + The size in pixels of the frame, without the scrollbars. + + + + + ScrollBarThickness + How thick the scroll bar appears. This applies to both the horizontal and vertical scroll bars. Can be set to 0 for no bars render. + + + + + TopImage + The "Up" image on the vertical scrollbar. Size of this is always ScrollBarThickness by ScrollBarThickness. This is also used as the "left" image on the horizontal scroll bar. + + + + + MidImage + The "Middle" image on the vertical scrollbar. Size of this can vary in the y direction, but is always set at ScrollBarThickness in x direction. This is also used as the "mid" image on the horizontal scroll bar. + + + + + BottomImage + The "Down" image on the vertical scrollbar. Size of this is always ScrollBarThickness by ScrollBarThickness. This is also used as the "right" image on the horizontal scroll bar. + + + + + + + ImageLabel + GUI + A GUI object containing an Image + 180 + 49 + GuiBase2d + GuiBase2d + + + + + Image + Specifies the id of the texture to display. <a href="http://wiki.roblox.com/index.php?title=API:Class/ImageLabel/Image" target="_blank">More info</a> + + + + + ScaleType + Specifies how an image should be displayed. See ScaleType for more info. + + + + + SliceCenter + If ScaleType is set to Slice, this Rect is used to specify the central part of the image. Everything outside of this is considered to be the border. + + + + + TileSize + If ScaleType is set to Tile, this sets the size of the tile. + + + + + + + TextLabel + GUI + A GUI object containing text + 190 + 50 + GuiBase2d + GuiBase2d + + + + + TextColor + true + Deprecated. Use TextColor3 instead + + + + + + + TextButton + GUI + A GUI button containing text + 170 + 51 + GuiBase2d + GuiBase2d + + + + + TextColor + true + Deprecated. Use TextColor3 instead + + + + + + + TextBox + GUI + A text entry box + 170 + 51 + GuiBase2d + GuiBase2d + + + + + TextColor + true + Deprecated. Use TextColor3 instead + + + + + + + GuiButton + GUI + A GUI button containing an Image + false + 160 + 52 + + + + + AutoButtonColor + Determines whether a button changes color automatically when reacting to mouse events. + + + + + Modal + Allows the mouse to be free in first person mode. If a button with this property set to true is visible, the mouse is 'free' in first person mode. + + + + + Style + Determines how a button will look, including mouse event states. Uses Enum.ButtonStyle. <a href="http://wiki.roblox.com/index.php?title=API:Class/GuiButton/Style" target="_blank">More info</a> + + + + + + + MouseButton1Click + Fired when the mouse is over the button, and the mouse down and up events fire without the mouse leaving the button. + + + + + MouseButton1Down + Fired when the mouse button is pushed down on a button. + + + + + MouseButton1Up + Fired when the mouse button is released on a button. + + + + + MouseButton2Click + This function currently does not work :( + + + + + MouseButton2Down + This function currently does not work :( + + + + + MouseButton2Up + This function currently does not work :( + + + + + + + ViewportFrame + GUI + A GUI that can show 3D objects + 30 + 52 + GuiBase2d + GuiBase2d + + + + + CurrentCamera + Current Camera of children objects + + + + + + + ImageButton + GUI + A GUI button containing an Image + 160 + 52 + GuiBase2d + GuiBase2d + + + + + Image + Specifies the asset id of the texture to display. <a href="http://wiki.roblox.com/index.php?title=API:Class/ImageButton/Image" target="_blank">More info</a> + + + + + ScaleType + Specifies how an image should be displayed. See ScaleType for more info. + + + + + SliceCenter + If ScaleType is set to Slice, this Rect is used to specify the central part of the image. Everything outside of this is considered to be the border. + + + + + TileSize + If ScaleType is set to Tile, this sets the size of the tile. + + + + + + + Handles + Adornments + A 3D GUI object to represent draggable handles + + 190 + 53 + + + + + ArcHandles + Adornments + A 3D GUI object to represent draggable arc handles + + 200 + 56 + + + + + SelectionBox + Adornments + A 3D GUI object to represent the visible selection around an object + 210 + 54 + + + + + SelectionSphere + Adornments + A 3D GUI object to represent the visible selection around an object + 210 + 54 + + + + + SurfaceSelection + Adornments + A 3D GUI object to represent the visible selection around a face of an object + 210 + 55 + + + + + Configuration + An object that can be placed under parts to hold Value objects that represent that part's configuration + 220 + 58 + + + + + Folder + An object that can be created to hold and organize objects + 10 + 77 + Instance + + + + + SelectionPartLasso + true + A visual line drawn representation between two part objects + 220 + 57 + + + + + SelectionPointLasso + true + A visual line drawn representation between two positions + 220 + 57 + + + + + PartPairLasso + A visual line drawn representation between two parts. + 220 + 57 + + + + + Pose + The pose of a joint relative to it's parent part in a keyframe + 220 + 60 + false + + + + + Keyframe + One keyframe of an animation + 220 + 60 + false + + + + + Animation + Animations + Represents a linked animation object, containing keyframes and poses. + 220 + 60 + + + + + AnimationTrack + Returned by a call to LoadAnimation. Controls the playback of an animation on a Humanoid. + 220 + 60 + + + + + AnimationController + Animations + Allows animations to be played on joints of the parent object. + 220 + 60 + + + + + CharacterMesh + Meshes + Modifies the appearance of a body part. + 220 + 60 + Model + Model + + + + + Dialog + 3D Interfaces + An object used to make dialog trees to converse with players + 220 + 62 + + + + + ConversationDistance + The maximum distance that the player's character can be from the dialog's parent in order to use the dialog. + + + + + GoodbyeChoiceActive + Indicates whether or not an extra choice is available for the player to exit the dialog tree at this node. + + + + + GoodbyeDialog + The prompt text for an extra choice that allows the player to exit the dialog tree at this node. + + + + + InUse + Indicates whether or not the dialog is currently being used by one or more players. + + + + + InitialPrompt + The chat message that is displayed to the player when they first activate the dialog. + + + + + Purpose + Describes the purpose of the dialog, which is used to display a relevant icon on the dialog's activation button. + + + + + Tone + Describes the tone of the dialog, which is used to display a relevant color in the dialog interface. + + + + + BehaviorType + Indicates how the dialog may be used by players. Use Enum.DialogBehaviorType.SinglePlayer if only one player should interact with the dialog at a time, otherwise use Enum.DialogBehaviorType.MultiplePlayers. + + + + + + + GetCurrentPlayers + Returns an array of the players currently conversing with this dialog. + + + + + + + DialogChoice + 3D Interfaces + An object used to make dialog trees to converse with players + 220 + 63 + + + + + UnionOperation + A UnionOperation is a union of multiple parts + true + false + 20 + 73 + + + + + UsePartColor + Override the colors of the mesh with the part color. + + + + + + + NegateOperation + A NegateOperation can be used to create holes in other parts + true + false + 20 + 72 + + + + + UsePartColor + Override the colors of the mesh with the part color. + + + + + + + MeshPart + Parts + A MeshPart is a physically simulatable mesh + true + true + 20 + 73 + Model + Model + + + + + Terrain + Object representing a high performance bounded grid of static 4x4 parts + true + false + 5 + 65 + + + + + WaterTransparency + 0 + 1 + + + + + WaterWaveSize + 0 + 1 + + + + + WaterWaveSpeed + 0 + 100 + + + + + WaterReflectance + 0 + 1 + + + + + + + GetCell + Returns CellMaterial, CellBlock, CellOrientation + + + + + GetWaterCell + + Returns hasAnyWater, WaterForce, WaterDirection + + + + + SetWaterCell + + + + + + + + Light + Lights + Parent of all light objects + 30 + 13 + PVInstance + Basepart,Attachment,PVInstance + + + + + Brightness + 0 + 10 + 2000 + + + + + + + PointLight + Lights + Makes the parent part emit light in a spherical shape + 30 + 13 + PVInstance + PVInstance + + + + + Range + 0 + 60 + + + + + + + SpotLight + Lights + Makes the parent part emit light in a conical shape + 30 + 13 + PVInstance + PVInstance + + + + + Range + 0 + 60 + + + + + Angle + 0 + 180 + + + + + + + SurfaceLight + Lights + Makes the parent part emit light in a frustum shape from rectangle defined by part + 30 + 13 + PVInstance + PVInstance + + + + + Range + 0 + 60 + + + + + Brightness + 0 + 10 + + + + + Angle + 0 + 180 + + + + + + + RemoteFunction + Scripting + Allow functions defined in one script to be called by another script across client/server boundary + 40 + 74 + + + + + InvokeClient + Server + + + + + InvokeServer + Client + + + + + + + OnClientInvoke + Client + + + + + OnServerInvoke + Server + + + + + + + RemoteEvent + Scripting + Allow events defined in one script to be subscribed to by another script across client/server boundary + 50 + 75 + + + + + FireAllClients + Server + + + + + FireClient + Server + + + + + FireServer + Client + + + + + + + OnClientEvent + Client + + + + + OnServerEvent + Server + + + + + + + TerrainRegion + Object representing a snapshot of the region of terrain + true + 20 + 65 + false + + + + + ModuleScript + Scripting + A script fragment. Only runs when another script uses require() on it. + 50 + 76 + Instance + + + + + + + + ContextActionResult + + + + Sink + If 'functionToBind' from ContextActionService:BindAction() returns Enum.ContextActionResult.Sink, the input event will stop at that function and no other bound actions under it will be invoked. This is the default behavior if 'functionToBind' does not return anything or yields in any way. + + + + + Pass + If 'functionToBind' from ContextActionService:BindAction() returns Enum.ContextActionResult.Pass, the input event is considered to have not been handled by 'functionToBind' and will continue being passed to actions bound to the same input type. + + + + + + Material + + + + Air + false + + + + + Water + false + + + + + Rock + false + + + + + Glacier + false + + + + + Snow + false + + + + + Sandstone + false + + + + + Mud + false + + + + + Basalt + false + + + + + Ground + false + + + + + CrackedLava + false + + + + + Asphalt + false + + + + + LeafyGrass + false + + + + + Salt + false + + + + + Limestone + false + + + + + Pavement + false + + + + + + Status + true + + + + Poison + true + + + + + Confusion + true + + + + + + SaveFilter + true + + + + + PrivilegeType + true + + + + + Genre + true + + + + + GearGenreSetting + true + + + + + SortOrder + The ordering to use for sorting an array of GuiObjects. + + + + Name + Sort by alphabetical ordering of the Name property. + + + + + LayoutOrder + Sort using the less than operator on the LayoutOrder property of GuiObject. + + + + + Custom + true + + + + + + ZIndexBehavior + Controls the behavior of the ZIndex property. + + + + Global + The ZIndex property will override the default value computed from the depth in the hierarchy. + + + + + Sibling + The ZIndex property will control the order that the GuiObject will be rendered relative to its siblings. + + + + + + ScaleType + Controls how an image is displayed. + + + + Stretch + Force the image to fill the available space. + + + + + Slice + Use the SliceCenter property to stretch the middle of the image but maintain crisp borders. + + + + + Tile + Tile the image using the TileSize property. + + + + + Fit + Size the image to the largest size that will fit in the available space while maintaining aspect ratio. + + + + + Crop + Fill the available space, maintaining aspect ratio by cropping the edges if necessary. + + + + + diff --git a/2018/VortexiPlayerBeta.exe b/2018/VortexiPlayerBeta.exe new file mode 100644 index 0000000..efe6a71 Binary files /dev/null and b/2018/VortexiPlayerBeta.exe differ diff --git a/2018/content/avatar/character.rbxm b/2018/content/avatar/character.rbxm new file mode 100644 index 0000000..248da30 --- /dev/null +++ b/2018/content/avatar/character.rbxm @@ -0,0 +1,952 @@ + + null + nil + + + + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + erik.cassel + RBX1 + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 4 + 0 + 194 + + 0 + 19.5 + 22.5 + -1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + -1 + + true + + false + + 0.5 + 0.300000012 + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + true + 256 + Head + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + -0.5 + 0.5 + 0 + 0 + 0 + + 0 + 0 + 0 + + 0 + 1 + + 2 + 1 + 1 + + + + + 2 + 2 + + 0 + Mesh + + 0 + 0 + 0 + + + 1.25 + 1.25 + 1.25 + + + + 1 + 1 + 1 + + + + + + 5 + face + rbxasset://textures/face.png + 0 + + + + + + 0 + 0.600000024 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + HairAttachment + + + + + + 0 + 0.600000024 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + HatAttachment + + + + + + 0 + 0 + -0.600000024 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + FaceFrontAttachment + + + + + + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + FaceCenterAttachment + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 4 + 0 + 194 + + 0 + 18 + 22.5 + -1 + 0 + -0 + -0 + 1 + -0 + -0 + 0 + -1 + + true + + false + + 0.5 + 0.300000012 + -0.5 + 0.5 + 0 + 0 + 0 + 0 + 2 + 0 + true + 256 + Torso + 0 + 0 + 0 + 2 + 0 + + 0 + 0 + 0 + + -0.5 + 0.5 + 3 + 0 + 0 + + 0 + 0 + 0 + + 0 + 1 + + 2 + 2 + 1 + + + + + 5 + roblox + + 0 + + + + + + 0 + 1 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + NeckAttachment + + + + + + 0 + 0 + -0.5 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + BodyFrontAttachment + + + + + + 0 + 0 + 0.5 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + BodyBackAttachment + + + + + + -1 + 1 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + LeftCollarAttachment + + + + + + 1 + 1 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + RightCollarAttachment + + + + + + 0 + -1 + -0.5 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + WaistFrontAttachment + + + + + + 0 + -1 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + WaistCenterAttachment + + + + + + 0 + -1 + 0.5 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + WaistBackAttachment + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 4 + 0 + 194 + + 1.5 + 18 + 22.5 + -1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + -1 + + false + + false + + 0.5 + 0.300000012 + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + true + 256 + Left Arm + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + -0.5 + 0.5 + 3 + 0 + 0 + + 0 + 0 + 0 + + 0 + 1 + + 1 + 2 + 1 + + + + + + 0 + 1.0 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + LeftShoulderAttachment + + + + + + 0 + -1 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + LeftGripAttachment + + false + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 4 + 0 + 194 + + -1.5 + 18 + 22.5 + -1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + -1 + + false + + false + + 0.5 + 0.300000012 + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + true + 256 + Right Arm + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + -0.5 + 0.5 + 3 + 0 + 0 + + 0 + 0 + 0 + + 0 + 1 + + 1 + 2 + 1 + + + + + + 0 + 1.0 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + RightShoulderAttachment + + + + + + 0 + -1 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + RightGripAttachment + + false + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + 194 + + 0.5 + 16 + 22.5 + -1 + 0 + -0 + -0 + 1 + -0 + -0 + 0 + -1 + + false + + false + + 0.5 + 0.300000012 + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + true + 256 + Left Leg + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + -0.5 + 0.5 + 3 + 0 + 0 + + 0 + 0 + 0 + + 0 + 1 + + 1 + 2 + 1 + + + + + + 0 + -1 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + LeftFootAttachment + false + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + 194 + + -0.5 + 16 + 22.5 + -1 + 0 + -0 + -0 + 1 + -0 + -0 + 0 + -1 + + false + + false + + 0.5 + 0.300000012 + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + true + 256 + Right Leg + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + -0.5 + 0.5 + 3 + 0 + 0 + + 0 + 0 + 0 + + 0 + 1 + + 1 + 2 + 1 + + + + + + 0 + -1 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + RightFootAttachment + false + + + + + + 0 + 100 + 100 + 0 + 50 + 100 + 89 + Humanoid + 100 + 2 + 16 + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + 194 + + 0 + 18 + 22.5 + -1 + 0 + -0 + -0 + 1 + -0 + -0 + 0 + -1 + + false + + false + + 0.5 + 0.300000012 + -0.5 + 0.5 + 0 + 0 + 0 + 0 + 0 + 0 + true + 256 + HumanoidRootPart + 0 + 0 + 0 + 0 + 0 + + 0 + 0 + 0 + + -0.5 + 0.5 + 0 + 0 + 1 + + 0 + 0 + 0 + + 0 + 1 + + 2 + 2 + 1 + + + + + + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + RootAttachment + false + + + + + \ No newline at end of file diff --git a/2018/content/avatar/characterR15.rbxm b/2018/content/avatar/characterR15.rbxm new file mode 100644 index 0000000..0dc757a --- /dev/null +++ b/2018/content/avatar/characterR15.rbxm @@ -0,0 +1,2332 @@ + + null + nil + + + + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + Player + RBX9909D4D409004F18956C91B88A6A32A3 + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 4 + 0 + 311 + + -8.03512478 + 2.3499999 + -12.6754742 + 0.790692151 + 1.11743961e-035 + 0.612213969 + -5.6419155e-036 + 1 + -1.0965738e-035 + -0.612213969 + 5.21646317e-036 + 0.790692151 + + true + + false + + 0.5 + 0.300000012 + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + true + 256 + HumanoidRootPart + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + -0.5 + 0.5 + 3 + 0 + 1 + + -1.40129846e-045 + 0 + -1.40129846e-045 + + 1 + 1 + + 2 + 2 + 1 + + + + + + -0 + -0 + -0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + RootRigAttachment + false + + + + + + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + RootAttachment + false + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + 311 + + -9.2211628 + 2.14999962 + -11.7571526 + 0.790692151 + 1.11743961e-035 + 0.612213969 + -5.6419155e-036 + 1 + -1.0965738e-035 + -0.612213969 + 5.21646317e-036 + 0.790692151 + + false + 2 + + false + + 0.5 + 0.300000012 + -0.5 + 0.5 + 0 + 0 + + 0.999999762 + 0.299999982 + 0.999999881 + + -0.5 + 0.5 + 0 + 0 + true + 256 + http://www.roblox.com/asset/?id=532219986 + LeftHand + + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + + -0.5 + 0.5 + 0 + 0 + 0 + + -1.40129846e-045 + 0 + -1.40129846e-045 + + + 0.999999762 + 0.299999982 + 0.999999881 + + + + + + 0.000478863716 + 0.149999991 + 5.96046448e-008 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + LeftWristRigAttachment + false + + + + + + -1.1920929e-007 + -0.149999633 + -1.46306121e-007 + 1 + 0 + -0 + 0 + 6.12323426e-017 + 1 + 0 + -1 + 6.12323426e-017 + + LeftGripAttachment + false + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + 311 + + -9.2211628 + 2.84999967 + -11.7571526 + 0.790692151 + 1.11743961e-035 + 0.612213969 + -5.6419155e-036 + 1 + -1.0965738e-035 + -0.612213969 + 5.21646317e-036 + 0.790692151 + + false + 2 + + false + + 0.5 + 0.300000012 + -0.5 + 0.5 + 0 + 0 + + 0.999999762 + 1.20000029 + 1 + + -0.5 + 0.5 + 0 + 0 + true + 256 + http://www.roblox.com/asset/?id=532219991 + LeftLowerArm + + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + + -0.5 + 0.5 + 0 + 0 + 0 + + -1.40129846e-045 + 0 + -1.40129846e-045 + + + 0.999999762 + 1.20000029 + 1 + + + + + + 0.000478506088 + 0.25000003 + 7.64462551e-020 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + LeftElbowRigAttachment + false + + + + + + 0.000478506088 + -0.549999952 + 7.64462551e-020 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + LeftWristRigAttachment + false + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + 311 + + -9.22116375 + 3.29999995 + -11.7571526 + 0.790692151 + 1.11743961e-035 + 0.612213969 + -5.6419155e-036 + 1 + -1.0965738e-035 + -0.612213969 + 5.21646317e-036 + 0.790692151 + + false + 2 + + false + + 0.5 + 0.300000012 + -0.5 + 0.5 + 0 + 0 + + 0.999999762 + 1.40000033 + 0.99999994 + + -0.5 + 0.5 + 0 + 0 + true + 256 + http://www.roblox.com/asset/?id=532219996 + LeftUpperArm + + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + + -0.5 + 0.5 + 0 + 0 + 0 + + -1.40129846e-045 + 0 + -1.40129846e-045 + + + 0.999999762 + 1.40000033 + 0.99999994 + + + + + + 0.250109196 + 0.449999809 + 8.94069672e-008 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + LeftShoulderRigAttachment + false + + + + + + 0.000479102135 + -0.200000167 + 8.94069672e-008 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + LeftElbowRigAttachment + false + + + + + + 2.38418579e-007 + 0.700000286 + -2.70968314e-008 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + LeftShoulderAttachment + false + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + 311 + + -6.84908628 + 2.14999962 + -13.5937948 + 0.790692151 + 1.11743961e-035 + 0.612213969 + -5.6419155e-036 + 1 + -1.0965738e-035 + -0.612213969 + 5.21646317e-036 + 0.790692151 + + false + 2 + + false + + 0.5 + 0.300000012 + -0.5 + 0.5 + 0 + 0 + + 0.999999881 + 0.299999982 + 0.999999881 + + -0.5 + 0.5 + 0 + 0 + true + 256 + http://www.roblox.com/asset/?id=532219997 + RightHand + + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + + -0.5 + 0.5 + 0 + 0 + 0 + + -1.40129846e-045 + 0 + -1.40129846e-045 + + + 0.999999881 + 0.299999982 + 0.999999881 + + + + + + 3.57627869e-007 + 0.149999991 + 5.96046448e-008 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + RightWristRigAttachment + false + + + + + + 0 + -0.149999633 + -1.46306121e-007 + 1 + 0 + -0 + 0 + 6.12323426e-017 + 1 + 0 + -1 + 6.12323426e-017 + + RightGripAttachment + false + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + 311 + + -6.84908628 + 2.84999967 + -13.5937948 + 0.790692151 + 1.11743961e-035 + 0.612213969 + -5.6419155e-036 + 1 + -1.0965738e-035 + -0.612213969 + 5.21646317e-036 + 0.790692151 + + false + 2 + + false + + 0.5 + 0.300000012 + -0.5 + 0.5 + 0 + 0 + + 0.999999762 + 1.20000029 + 1 + + -0.5 + 0.5 + 0 + 0 + true + 256 + http://www.roblox.com/asset/?id=532219999 + RightLowerArm + + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + + -0.5 + 0.5 + 0 + 0 + 0 + + -1.40129846e-045 + 0 + -1.40129846e-045 + + + 0.999999762 + 1.20000029 + 1 + + + + + + 1.1920929e-007 + 0.25000003 + 7.64462551e-020 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + RightElbowRigAttachment + false + + + + + + 1.1920929e-007 + -0.549999952 + -6.86244753e-018 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + RightWristRigAttachment + false + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + 311 + + -6.84908581 + 3.29999995 + -13.5937958 + 0.790692151 + 1.11743961e-035 + 0.612213969 + -5.6419155e-036 + 1 + -1.0965738e-035 + -0.612213969 + 5.21646317e-036 + 0.790692151 + + false + 2 + + false + + 0.5 + 0.300000012 + -0.5 + 0.5 + 0 + 0 + + 0.999999642 + 1.40000033 + 0.99999994 + + -0.5 + 0.5 + 0 + 0 + true + 256 + http://www.roblox.com/asset/?id=532220004 + RightUpperArm + + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + + -0.5 + 0.5 + 0 + 0 + 0 + + -1.40129846e-045 + 0 + -1.40129846e-045 + + + 0.999999642 + 1.40000033 + 0.99999994 + + + + + + -0.250020266 + 0.449999809 + 8.94069672e-008 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + RightShoulderRigAttachment + false + + + + + + -5.96046448e-007 + -0.200000167 + 8.94069672e-008 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + RightElbowRigAttachment + false + + + + + + -9.53674316e-007 + 0.700000286 + -2.70968314e-008 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + RightShoulderAttachment + false + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + 311 + + -8.03512478 + 3.19999981 + -12.6754742 + 0.790692151 + 1.11743961e-035 + 0.612213969 + -5.6419155e-036 + 1 + -1.0965738e-035 + -0.612213969 + 5.21646317e-036 + 0.790692151 + + true + 2 + + false + + 0.5 + 0.300000012 + -0.5 + 0.5 + 0 + 0 + + 2 + 1.60000014 + 1.00000036 + + -0.5 + 0.5 + 0 + 0 + true + 256 + http://www.roblox.com/asset/?id=532220007 + UpperTorso + + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + + -0.5 + 0.5 + 0 + 0 + 0 + + -1.40129846e-045 + 0 + -1.40129846e-045 + + + 2 + 1.60000014 + 1.00000036 + + + + + + -5.96046448e-008 + -0.450000018 + 1.1920929e-007 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + WaistRigAttachment + false + + + + + + -5.96046448e-008 + 0.799999952 + 1.1920929e-007 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + NeckRigAttachment + false + + + + + + -1.24989128 + 0.549999952 + 1.1920929e-007 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + LeftShoulderRigAttachment + false + + + + + + 1.24998045 + 0.549999952 + 1.1920929e-007 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + RightShoulderRigAttachment + false + + + + + + -5.96046448e-008 + -0.200000048 + -0.499999881 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + BodyFrontAttachment + false + + + + + + -5.96046448e-008 + -0.200000048 + 0.5 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + BodyBackAttachment + false + + + + + + -0.999999881 + 0.800000191 + -7.27397378e-008 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + LeftCollarAttachment + false + + + + + + 0.99999994 + 0.799999952 + 4.61295997e-008 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + RightCollarAttachment + false + + + + + + 0.0 + 0.8 + 0.0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + NeckAttachment + false + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + 311 + + -8.43047047 + 0.150000095 + -12.3693666 + 0.790692151 + 1.11743961e-035 + 0.612213969 + -5.6419155e-036 + 1 + -1.0965738e-035 + -0.612213969 + 5.21646317e-036 + 0.790692151 + + false + 2 + + false + + 0.5 + 0.300000012 + -0.5 + 0.5 + 0 + 0 + + 1 + 0.300000191 + 1 + + -0.5 + 0.5 + 0 + 0 + true + 256 + http://www.roblox.com/asset/?id=532220012 + LeftFoot + + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + + -0.5 + 0.5 + 0 + 0 + 0 + + -1.40129846e-045 + 0 + -1.40129846e-045 + + + 1 + 0.300000191 + 1 + + + + + + 0 + 0.05 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + LeftAnkleRigAttachment + false + + + + + + 0 + -0.15 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + LeftFootAttachment + false + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + 311 + + -8.43047047 + 0.950000286 + -12.3693666 + 0.790692151 + 1.11743961e-035 + 0.612213969 + -5.6419155e-036 + 1 + -1.0965738e-035 + -0.612213969 + 5.21646317e-036 + 0.790692151 + + false + 2 + + false + + 0.5 + 0.300000012 + -0.5 + 0.5 + 0 + 0 + + 0.99999994 + 1.50000036 + 1.00000012 + + -0.5 + 0.5 + 0 + 0 + true + 256 + http://www.roblox.com/asset/?id=532220017 + LeftLowerLeg + + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + + -0.5 + 0.5 + 0 + 0 + 0 + + -1.40129846e-045 + 0 + -1.40129846e-045 + + + 0.99999994 + 1.50000036 + 1.00000012 + + + + + + -0 + 0.249999642 + -1.78813934e-007 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + LeftKneeRigAttachment + false + + + + + + -1.78813934e-007 + -0.749997616 + 6.29340548e-007 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + LeftAnkleRigAttachment + false + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + 311 + + -8.43047047 + 1.49999988 + -12.3693666 + 0.790692151 + 1.11743961e-035 + 0.612213969 + -5.6419155e-036 + 1 + -1.0965738e-035 + -0.612213969 + 5.21646317e-036 + 0.790692151 + + false + 2 + + false + + 0.5 + 0.300000012 + -0.5 + 0.5 + 0 + 0 + + 1.00000036 + 1.49999976 + 0.999999881 + + -0.5 + 0.5 + 0 + 0 + true + 256 + http://www.roblox.com/asset/?id=532220018 + LeftUpperLeg + + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + + -0.5 + 0.5 + 0 + 0 + 0 + + -1.40129846e-045 + 0 + -1.40129846e-045 + + + 1.00000036 + 1.49999976 + 0.999999881 + + + + + + 5.96046448e-008 + 0.5 + -1.63912773e-007 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + LeftHipRigAttachment + false + + + + + + 5.96046448e-008 + -0.299999952 + -1.63912773e-007 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + LeftKneeRigAttachment + false + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + 311 + + -7.63977861 + 0.150000095 + -12.9815807 + 0.790692151 + 1.11743961e-035 + 0.612213969 + -5.6419155e-036 + 1 + -1.0965738e-035 + -0.612213969 + 5.21646317e-036 + 0.790692151 + + false + 2 + + false + + 0.5 + 0.300000012 + -0.5 + 0.5 + 0 + 0 + + 0.99999994 + 0.300000191 + 1 + + -0.5 + 0.5 + 0 + 0 + true + 256 + http://www.roblox.com/asset/?id=532220020 + RightFoot + + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + + -0.5 + 0.5 + 0 + 0 + 0 + + -1.40129846e-045 + 0 + -1.40129846e-045 + + + 0.99999994 + 0.300000191 + 1 + + + + + + 0 + 0.05 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + RightAnkleRigAttachment + false + + + + + + 0 + -0.15 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + RightFootAttachment + false + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + 311 + + -7.63977861 + 0.950000286 + -12.9815807 + 0.790692151 + 1.11743961e-035 + 0.612213969 + -5.6419155e-036 + 1 + -1.0965738e-035 + -0.612213969 + 5.21646317e-036 + 0.790692151 + + false + 2 + + false + + 0.5 + 0.300000012 + -0.5 + 0.5 + 0 + 0 + + 0.99999994 + 1.50000036 + 1.00000012 + + -0.5 + 0.5 + 0 + 0 + true + 256 + http://www.roblox.com/asset/?id=532220027 + RightLowerLeg + + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + + -0.5 + 0.5 + 0 + 0 + 0 + + -1.40129846e-045 + 0 + -1.40129846e-045 + + + 0.99999994 + 1.50000036 + 1.00000012 + + + + + + -0 + 0.249999642 + 4.35260044e-005 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + RightKneeRigAttachment + false + + + + + + -0 + -0.750000477 + 9.82746205e-005 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + RightAnkleRigAttachment + false + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + 311 + + -7.63977861 + 1.49999988 + -12.9815807 + 0.790692151 + 1.11743961e-035 + 0.612213969 + -5.6419155e-036 + 1 + -1.0965738e-035 + -0.612213969 + 5.21646317e-036 + 0.790692151 + + false + 2 + + false + + 0.5 + 0.300000012 + -0.5 + 0.5 + 0 + 0 + + 1.00000048 + 1.49999976 + 0.999999881 + + -0.5 + 0.5 + 0 + 0 + true + 256 + http://www.roblox.com/asset/?id=532220031 + RightUpperLeg + + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + + -0.5 + 0.5 + 0 + 0 + 0 + + -1.40129846e-045 + 0 + -1.40129846e-045 + + + 1.00000048 + 1.49999976 + 0.999999881 + + + + + + -0 + 0.5 + -1.04308128e-007 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + RightHipRigAttachment + false + + + + + + -0 + -0.299999952 + 4.36005103e-005 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + RightKneeRigAttachment + false + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + 311 + + -8.03512478 + 2.19999981 + -12.6754742 + 0.790692151 + 1.11743961e-035 + 0.612213969 + -5.6419155e-036 + 1 + -1.0965738e-035 + -0.612213969 + 5.21646317e-036 + 0.790692151 + + true + 2 + + false + + 0.5 + 0.300000012 + -0.5 + 0.5 + 0 + 0 + + 1.99999976 + 0.399999976 + 1.00000012 + + -0.5 + 0.5 + 0 + 0 + true + 256 + http://www.roblox.com/asset/?id=532220036 + LowerTorso + + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + + -0.5 + 0.5 + 0 + 0 + 0 + + -1.40129846e-045 + 0 + -1.40129846e-045 + + + 1.99999976 + 0.399999976 + 1.00000012 + + + + + + -1.1920929e-007 + 0.150000036 + -0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + RootRigAttachment + false + + + + + + -1.1920929e-007 + 0.550000072 + 7.64462551e-020 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + WaistRigAttachment + false + + + + + + -0.500000119 + -0.199999958 + -0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + LeftHipRigAttachment + false + + + + + + 0.499999881 + -0.199999958 + -0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + RightHipRigAttachment + false + + + + + + 0.0 + -0.2 + 0.0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + WaistCenterAttachment + false + + + + + + 0.0 + -0.2 + -0.5 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + WaistFrontAttachment + false + + + + + + 0.0 + -0.2 + 0.5 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + WaistBackAttachment + false + + + + + + 0 + 100 + 100 + 1.35000002 + 50 + 100 + 89 + Humanoid + 100 + 2 + 1 + 16 + + + + Animator + + + + + BodyWidthScale + 1 + + + + + BodyHeightScale + 1 + + + + + BodyDepthScale + 1 + + + + + HeadScale + 1 + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + 311 + + -8.03495789 + 4.5 + -12.6752586 + 0.790692151 + 1.11743961e-035 + 0.612213969 + -5.6419155e-036 + 1 + -1.0965738e-035 + -0.612213969 + 5.21646317e-036 + 0.790692151 + + true + + false + + 0.5 + 0.300000012 + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + true + 256 + Head + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + -0.5 + 0.5 + 0 + 0 + 0 + + -1.40129846e-045 + 0 + -1.40129846e-045 + + 1 + 1 + + 2 + 1 + 1 + + + + + 2 + 2 + + 0 + Mesh + + 0 + 0 + 0 + + + 1.25 + 1.25 + 1.25 + + + + 1 + 1 + 1 + + + + + + + 3.93568822e-009 + 0 + -0.000272244215 + 1 + 7.87137555e-009 + 3.02998127e-015 + -7.87137555e-009 + 1 + -4.1444258e-016 + -3.02998127e-015 + 4.14442554e-016 + 1 + + FaceCenterAttachment + false + + + + + + 3.93568866e-009 + 0 + -0.600272298 + 1 + 7.87137555e-009 + 3.02998127e-015 + -7.87137555e-009 + 1 + -4.1444258e-016 + -3.02998127e-015 + 4.14442554e-016 + 1 + + FaceFrontAttachment + false + + + + + + 8.65851391e-009 + 0.599999905 + -0.000272244215 + 1 + 7.87137555e-009 + 3.02998127e-015 + -7.87137555e-009 + 1 + -4.1444258e-016 + -3.02998127e-015 + 4.14442554e-016 + 1 + + HairAttachment + false + + + + + + 8.65851391e-009 + 0.599999905 + -0.000272244215 + 1 + 7.87137555e-009 + 3.02998127e-015 + -7.87137555e-009 + 1 + -4.1444258e-016 + -3.02998127e-015 + 4.14442554e-016 + 1 + + HatAttachment + false + + + + + + -0 + -0.500000119 + -0.000272244215 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + NeckRigAttachment + false + + + + + 5 + face + rbxasset://textures/face.png + 0 + + + + + \ No newline at end of file diff --git a/2018/content/avatar/characterR15V2.rbxm b/2018/content/avatar/characterR15V2.rbxm new file mode 100644 index 0000000..b02f520 Binary files /dev/null and b/2018/content/avatar/characterR15V2.rbxm differ diff --git a/2018/content/avatar/characterR15V3.rbxm b/2018/content/avatar/characterR15V3.rbxm new file mode 100644 index 0000000..9168b74 Binary files /dev/null and b/2018/content/avatar/characterR15V3.rbxm differ diff --git a/2018/content/avatar/compositing/CompositExtraSlot0.mesh b/2018/content/avatar/compositing/CompositExtraSlot0.mesh new file mode 100644 index 0000000..87b9d85 Binary files /dev/null and b/2018/content/avatar/compositing/CompositExtraSlot0.mesh differ diff --git a/2018/content/avatar/compositing/CompositExtraSlot1.mesh b/2018/content/avatar/compositing/CompositExtraSlot1.mesh new file mode 100644 index 0000000..6874c5e Binary files /dev/null and b/2018/content/avatar/compositing/CompositExtraSlot1.mesh differ diff --git a/2018/content/avatar/compositing/CompositExtraSlot2.mesh b/2018/content/avatar/compositing/CompositExtraSlot2.mesh new file mode 100644 index 0000000..423f198 Binary files /dev/null and b/2018/content/avatar/compositing/CompositExtraSlot2.mesh differ diff --git a/2018/content/avatar/compositing/CompositExtraSlot3.mesh b/2018/content/avatar/compositing/CompositExtraSlot3.mesh new file mode 100644 index 0000000..de05ced Binary files /dev/null and b/2018/content/avatar/compositing/CompositExtraSlot3.mesh differ diff --git a/2018/content/avatar/compositing/CompositExtraSlot4.mesh b/2018/content/avatar/compositing/CompositExtraSlot4.mesh new file mode 100644 index 0000000..ff9cb62 Binary files /dev/null and b/2018/content/avatar/compositing/CompositExtraSlot4.mesh differ diff --git a/2018/content/avatar/compositing/CompositFullAtlasBaseTexture.mesh b/2018/content/avatar/compositing/CompositFullAtlasBaseTexture.mesh new file mode 100644 index 0000000..b7e6595 Binary files /dev/null and b/2018/content/avatar/compositing/CompositFullAtlasBaseTexture.mesh differ diff --git a/2018/content/avatar/compositing/CompositFullAtlasOverlayTexture.mesh b/2018/content/avatar/compositing/CompositFullAtlasOverlayTexture.mesh new file mode 100644 index 0000000..eda1938 Binary files /dev/null and b/2018/content/avatar/compositing/CompositFullAtlasOverlayTexture.mesh differ diff --git a/2018/content/avatar/compositing/CompositLeftArmBase.mesh b/2018/content/avatar/compositing/CompositLeftArmBase.mesh new file mode 100644 index 0000000..5bcc4ae Binary files /dev/null and b/2018/content/avatar/compositing/CompositLeftArmBase.mesh differ diff --git a/2018/content/avatar/compositing/CompositLeftLegBase.mesh b/2018/content/avatar/compositing/CompositLeftLegBase.mesh new file mode 100644 index 0000000..f4712ce Binary files /dev/null and b/2018/content/avatar/compositing/CompositLeftLegBase.mesh differ diff --git a/2018/content/avatar/compositing/CompositPantsTemplate.mesh b/2018/content/avatar/compositing/CompositPantsTemplate.mesh new file mode 100644 index 0000000..756ee03 Binary files /dev/null and b/2018/content/avatar/compositing/CompositPantsTemplate.mesh differ diff --git a/2018/content/avatar/compositing/CompositQuad.mesh b/2018/content/avatar/compositing/CompositQuad.mesh new file mode 100644 index 0000000..192abf2 Binary files /dev/null and b/2018/content/avatar/compositing/CompositQuad.mesh differ diff --git a/2018/content/avatar/compositing/CompositRightArmBase.mesh b/2018/content/avatar/compositing/CompositRightArmBase.mesh new file mode 100644 index 0000000..02f2721 Binary files /dev/null and b/2018/content/avatar/compositing/CompositRightArmBase.mesh differ diff --git a/2018/content/avatar/compositing/CompositRightLegBase.mesh b/2018/content/avatar/compositing/CompositRightLegBase.mesh new file mode 100644 index 0000000..b287939 Binary files /dev/null and b/2018/content/avatar/compositing/CompositRightLegBase.mesh differ diff --git a/2018/content/avatar/compositing/CompositShirtTemplate.mesh b/2018/content/avatar/compositing/CompositShirtTemplate.mesh new file mode 100644 index 0000000..75487e1 Binary files /dev/null and b/2018/content/avatar/compositing/CompositShirtTemplate.mesh differ diff --git a/2018/content/avatar/compositing/CompositTShirt.mesh b/2018/content/avatar/compositing/CompositTShirt.mesh new file mode 100644 index 0000000..b39b8ac Binary files /dev/null and b/2018/content/avatar/compositing/CompositTShirt.mesh differ diff --git a/2018/content/avatar/compositing/CompositTorsoBase.mesh b/2018/content/avatar/compositing/CompositTorsoBase.mesh new file mode 100644 index 0000000..0388bde Binary files /dev/null and b/2018/content/avatar/compositing/CompositTorsoBase.mesh differ diff --git a/2018/content/avatar/compositing/R15CompositLeftArmBase.mesh b/2018/content/avatar/compositing/R15CompositLeftArmBase.mesh new file mode 100644 index 0000000..c262d08 Binary files /dev/null and b/2018/content/avatar/compositing/R15CompositLeftArmBase.mesh differ diff --git a/2018/content/avatar/compositing/R15CompositRightArmBase.mesh b/2018/content/avatar/compositing/R15CompositRightArmBase.mesh new file mode 100644 index 0000000..c745b94 Binary files /dev/null and b/2018/content/avatar/compositing/R15CompositRightArmBase.mesh differ diff --git a/2018/content/avatar/compositing/R15CompositTorsoBase.mesh b/2018/content/avatar/compositing/R15CompositTorsoBase.mesh new file mode 100644 index 0000000..341d8b6 Binary files /dev/null and b/2018/content/avatar/compositing/R15CompositTorsoBase.mesh differ diff --git a/2018/content/avatar/heads/head.mesh b/2018/content/avatar/heads/head.mesh new file mode 100644 index 0000000..26db950 Binary files /dev/null and b/2018/content/avatar/heads/head.mesh differ diff --git a/2018/content/avatar/heads/headA.mesh b/2018/content/avatar/heads/headA.mesh new file mode 100644 index 0000000..76b2e72 Binary files /dev/null and b/2018/content/avatar/heads/headA.mesh differ diff --git a/2018/content/avatar/heads/headB.mesh b/2018/content/avatar/heads/headB.mesh new file mode 100644 index 0000000..7705a05 Binary files /dev/null and b/2018/content/avatar/heads/headB.mesh differ diff --git a/2018/content/avatar/heads/headC.mesh b/2018/content/avatar/heads/headC.mesh new file mode 100644 index 0000000..4672c59 Binary files /dev/null and b/2018/content/avatar/heads/headC.mesh differ diff --git a/2018/content/avatar/heads/headD.mesh b/2018/content/avatar/heads/headD.mesh new file mode 100644 index 0000000..ff6cd6c Binary files /dev/null and b/2018/content/avatar/heads/headD.mesh differ diff --git a/2018/content/avatar/heads/headE.mesh b/2018/content/avatar/heads/headE.mesh new file mode 100644 index 0000000..d722d29 Binary files /dev/null and b/2018/content/avatar/heads/headE.mesh differ diff --git a/2018/content/avatar/heads/headF.mesh b/2018/content/avatar/heads/headF.mesh new file mode 100644 index 0000000..7c0b311 Binary files /dev/null and b/2018/content/avatar/heads/headF.mesh differ diff --git a/2018/content/avatar/heads/headG.mesh b/2018/content/avatar/heads/headG.mesh new file mode 100644 index 0000000..38db235 Binary files /dev/null and b/2018/content/avatar/heads/headG.mesh differ diff --git a/2018/content/avatar/heads/headH.mesh b/2018/content/avatar/heads/headH.mesh new file mode 100644 index 0000000..fe7365b Binary files /dev/null and b/2018/content/avatar/heads/headH.mesh differ diff --git a/2018/content/avatar/heads/headI.mesh b/2018/content/avatar/heads/headI.mesh new file mode 100644 index 0000000..8ff7ba1 Binary files /dev/null and b/2018/content/avatar/heads/headI.mesh differ diff --git a/2018/content/avatar/heads/headJ.mesh b/2018/content/avatar/heads/headJ.mesh new file mode 100644 index 0000000..ff76d44 Binary files /dev/null and b/2018/content/avatar/heads/headJ.mesh differ diff --git a/2018/content/avatar/heads/headK.mesh b/2018/content/avatar/heads/headK.mesh new file mode 100644 index 0000000..b08bffc Binary files /dev/null and b/2018/content/avatar/heads/headK.mesh differ diff --git a/2018/content/avatar/heads/headL.mesh b/2018/content/avatar/heads/headL.mesh new file mode 100644 index 0000000..645531b Binary files /dev/null and b/2018/content/avatar/heads/headL.mesh differ diff --git a/2018/content/avatar/heads/headM.mesh b/2018/content/avatar/heads/headM.mesh new file mode 100644 index 0000000..ba144e8 Binary files /dev/null and b/2018/content/avatar/heads/headM.mesh differ diff --git a/2018/content/avatar/heads/headN.mesh b/2018/content/avatar/heads/headN.mesh new file mode 100644 index 0000000..6fc4620 Binary files /dev/null and b/2018/content/avatar/heads/headN.mesh differ diff --git a/2018/content/avatar/heads/headO.mesh b/2018/content/avatar/heads/headO.mesh new file mode 100644 index 0000000..a41f85f Binary files /dev/null and b/2018/content/avatar/heads/headO.mesh differ diff --git a/2018/content/avatar/heads/headP.mesh b/2018/content/avatar/heads/headP.mesh new file mode 100644 index 0000000..cdb1647 Binary files /dev/null and b/2018/content/avatar/heads/headP.mesh differ diff --git a/2018/content/avatar/meshes/leftarm.mesh b/2018/content/avatar/meshes/leftarm.mesh new file mode 100644 index 0000000..6e8bb63 Binary files /dev/null and b/2018/content/avatar/meshes/leftarm.mesh differ diff --git a/2018/content/avatar/meshes/leftleg.mesh b/2018/content/avatar/meshes/leftleg.mesh new file mode 100644 index 0000000..aba3a29 Binary files /dev/null and b/2018/content/avatar/meshes/leftleg.mesh differ diff --git a/2018/content/avatar/meshes/rightarm.mesh b/2018/content/avatar/meshes/rightarm.mesh new file mode 100644 index 0000000..14a52a4 Binary files /dev/null and b/2018/content/avatar/meshes/rightarm.mesh differ diff --git a/2018/content/avatar/meshes/rightleg.mesh b/2018/content/avatar/meshes/rightleg.mesh new file mode 100644 index 0000000..dab065d Binary files /dev/null and b/2018/content/avatar/meshes/rightleg.mesh differ diff --git a/2018/content/avatar/meshes/torso.mesh b/2018/content/avatar/meshes/torso.mesh new file mode 100644 index 0000000..43d58d1 Binary files /dev/null and b/2018/content/avatar/meshes/torso.mesh differ diff --git a/2018/content/avatar/morpherEditorR15.rbxmx b/2018/content/avatar/morpherEditorR15.rbxmx new file mode 100644 index 0000000..7af6e5d --- /dev/null +++ b/2018/content/avatar/morpherEditorR15.rbxmx @@ -0,0 +1,4041 @@ + + false + null + nil + + + + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + R15 + RBX081D55DA3E944921A37ACF5DF5DC888A + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 4 + 0 + + 7.66999817 + 2.30299997 + -6 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + true + 0 + 4293256415 + + false + + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + false + 256 + HumanoidRootPart + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + + -0.5 + 0.5 + 3 + 0 + 1 + + 0 + 0 + 0 + + 1 + 1 + + 2 + 1.96000004 + 1 + + + + + + 0 + -0.342999995 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + RootRigAttachment + + false + + + + OriginalPosition + + + 0 + -0.349999994 + 0 + + + + + + + OriginalSize + + + 2 + 2 + 1 + + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + + 6.16999769 + 2.10695553 + -6 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + false + 2 + 0 + 4293256415 + + false + + -0.5 + 0.5 + 0 + 0 + + 0.999999762 + 0.300030679 + 0.999999881 + + -0.5 + 0.5 + 0 + 0 + false + 256 + http://www.roblox.com/asset/?id=1699715537 + http://www.roblox.com/asset/?id=1699715537 + LeftHand + + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + + + -0.5 + 0.5 + 0 + 0 + 0 + + 0 + 0 + 0 + + + 0.999999762 + 0.29403007 + 0.999999881 + + + + + + 0.000478982925 + 0.122544497 + 5.96046448e-08 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + LeftWristRigAttachment + + false + + + + OriginalPosition + + + 0.000478982925 + 0.125045404 + 5.96046448e-08 + + + + + + + + 0 + -0.146955431 + -1.46306121e-07 + 1 + 0 + -0 + 0 + 6.12323426e-17 + 1 + 0 + -1 + 6.12323426e-17 + + LeftGripAttachment + + false + + + + OriginalPosition + + + 0 + -0.149954513 + -1.46306121e-07 + + + + + + + + 0.000478625298 + -0.490910143 + 7.64462551e-20 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + + 0.000478982925 + 0.122544497 + 5.96046448e-08 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + 0 + false + 0 + LeftWrist + RBX3F40768EF729487C8794F9B4240FB7C4 + RBX22C13C16C5FB47AABB4365E4AA62349F + + + + + + OriginalSize + + + 0.999999762 + 0.300030679 + 0.999999881 + + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + + 6.16999817 + 2.72041011 + -6 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + false + 2 + 0 + 4293256415 + + false + + -0.5 + 0.5 + 0 + 0 + + 0.999999642 + 1.05191803 + 1 + + -0.5 + 0.5 + 0 + 0 + false + 256 + http://www.roblox.com/asset/?id=1699715541 + http://www.roblox.com/asset/?id=1699715541 + LeftLowerArm + + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + + + -0.5 + 0.5 + 0 + 0 + 0 + + 0 + 0 + 0 + + + 0.999999642 + 1.03087974 + 1 + + + + + + 0.000478625298 + 0.253514439 + 7.64462551e-20 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + LeftElbowRigAttachment + + false + + + + OriginalPosition + + + 0.000478625298 + 0.258688211 + 7.64462551e-20 + + + + + + + + 0.000478625298 + -0.490910143 + 7.64462551e-20 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + LeftWristRigAttachment + + false + + + + OriginalPosition + + + 0.000478625298 + -0.5009287 + 7.64462551e-20 + + + + + + + + 0.000479221344 + -0.327375263 + 8.94069672e-08 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + + 0.000478625298 + 0.253514439 + 7.64462551e-20 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + 0 + false + 0 + LeftElbow + RBX65B95BED76AB4402A5C58B280CC87F73 + RBX3F40768EF729487C8794F9B4240FB7C4 + + + + + + OriginalSize + + + 0.999999642 + 1.05191803 + 1 + + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + + 6.16999769 + 3.30129981 + -6 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + false + 2 + 0 + 4293256415 + + false + + -0.5 + 0.5 + 0 + 0 + + 0.999999762 + 1.16867065 + 0.99999994 + + -0.5 + 0.5 + 0 + 0 + false + 256 + http://www.roblox.com/asset/?id=1699715550 + http://www.roblox.com/asset/?id=1699715550 + LeftUpperArm + + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + + + -0.5 + 0.5 + 0 + 0 + 0 + + 0 + 0 + 0 + + + 0.999999762 + 1.14529729 + 0.99999994 + + + + + + 0.500000358 + 0.386440158 + 8.94069672e-08 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + LeftShoulderRigAttachment + + false + + + + OriginalPosition + + + 0.500000358 + 0.394326687 + 8.94069672e-08 + + + + + + + + 0.000479221344 + -0.327375263 + 8.94069672e-08 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + LeftElbowRigAttachment + + false + + + + OriginalPosition + + + 0.000479221344 + -0.334056377 + 8.94069672e-08 + + + + + + + + 2.38418579e-07 + 0.572640121 + -2.70968314e-08 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + LeftShoulderAttachment + + false + + + + OriginalPosition + + + 2.38418579e-07 + 0.584326625 + -2.70968314e-08 + + + + + + + + -1 + 0.551756799 + 1.1920929e-07 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + + 0.500000358 + 0.386440158 + 8.94069672e-08 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + 0 + false + 0 + LeftShoulder + RBXA9943A145CA34B9199D5810AE7AC1AD5 + RBX65B95BED76AB4402A5C58B280CC87F73 + + + + + + OriginalSize + + + 0.999999762 + 1.16867065 + 0.99999994 + + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + + 9.16999817 + 2.10695553 + -6 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + false + 2 + 0 + 4293256415 + + false + + -0.5 + 0.5 + 0 + 0 + + 0.999999881 + 0.300030679 + 0.999999881 + + -0.5 + 0.5 + 0 + 0 + false + 256 + http://www.roblox.com/asset/?id=1699715557 + http://www.roblox.com/asset/?id=1699715557 + RightHand + + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + + + -0.5 + 0.5 + 0 + 0 + 0 + + 0 + 0 + 0 + + + 0.999999881 + 0.29403007 + 0.999999881 + + + + + + 3.57627869e-07 + 0.122544497 + 5.96046448e-08 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + RightWristRigAttachment + + false + + + + OriginalPosition + + + 3.57627869e-07 + 0.125045404 + 5.96046448e-08 + + + + + + + + 0 + -0.146955431 + -1.46306121e-07 + 1 + 0 + -0 + 0 + 6.12323426e-17 + 1 + 0 + -1 + 6.12323426e-17 + + RightGripAttachment + + false + + + + OriginalPosition + + + 0 + -0.149954513 + -1.46306121e-07 + + + + + + + + 1.1920929e-07 + -0.490910143 + -6.86244753e-18 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + + 3.57627869e-07 + 0.122544497 + 5.96046448e-08 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + 0 + false + 0 + RightWrist + RBX36AF3E43DBBF47F29C81B6C3A652EF28 + RBX138B2F31E7B64B03B104DB392895E6A2 + + + + + + OriginalSize + + + 0.999999881 + 0.300030679 + 0.999999881 + + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + + 9.16999817 + 2.72041011 + -6 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + false + 2 + 0 + 4293256415 + + false + + -0.5 + 0.5 + 0 + 0 + + 0.999999762 + 1.05191803 + 1 + + -0.5 + 0.5 + 0 + 0 + false + 256 + http://www.roblox.com/asset/?id=1699715562 + http://www.roblox.com/asset/?id=1699715562 + RightLowerArm + + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + + + -0.5 + 0.5 + 0 + 0 + 0 + + 0 + 0 + 0 + + + 0.999999762 + 1.03087974 + 1 + + + + + + 1.1920929e-07 + 0.253407896 + 7.64462551e-20 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + RightElbowRigAttachment + + false + + + + OriginalPosition + + + 1.1920929e-07 + 0.258579493 + 7.64462551e-20 + + + + + + + + 1.1920929e-07 + -0.490910143 + -6.86244753e-18 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + RightWristRigAttachment + + false + + + + OriginalPosition + + + 1.1920929e-07 + -0.5009287 + -6.86244753e-18 + + + + + + + + -5.96046448e-07 + -0.327481806 + 8.94069672e-08 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + + 1.1920929e-07 + 0.253407896 + 7.64462551e-20 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + 0 + false + 0 + RightElbow + RBXE08AA1E71CF7447581F14072A70CB0ED + RBX36AF3E43DBBF47F29C81B6C3A652EF28 + + + + + + OriginalSize + + + 0.999999762 + 1.05191803 + 1 + + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + + 9.16999912 + 3.30129981 + -6 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + false + 2 + 0 + 4293256415 + + false + + -0.5 + 0.5 + 0 + 0 + + 0.999999642 + 1.16867065 + 0.99999994 + + -0.5 + 0.5 + 0 + 0 + false + 256 + http://www.roblox.com/asset/?id=1699715576 + http://www.roblox.com/asset/?id=1699715576 + RightUpperArm + + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + + + -0.5 + 0.5 + 0 + 0 + 0 + + 0 + 0 + 0 + + + 0.999999642 + 1.14529729 + 0.99999994 + + + + + + -0.500000715 + 0.386440158 + 8.94069672e-08 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + RightShoulderRigAttachment + + false + + + + OriginalPosition + + + -0.500000715 + 0.394326687 + 8.94069672e-08 + + + + + + + + -5.96046448e-07 + -0.327481806 + 8.94069672e-08 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + RightElbowRigAttachment + + false + + + + OriginalPosition + + + -5.96046448e-07 + -0.334165096 + 8.94069672e-08 + + + + + + + + -8.34465027e-07 + 0.572640121 + -2.70968314e-08 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + RightShoulderAttachment + + false + + + + OriginalPosition + + + -8.34465027e-07 + 0.584326625 + -2.70968314e-08 + + + + + + + + 0.99999994 + 0.551756799 + 1.1920929e-07 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + + -0.500000715 + 0.386440158 + 8.94069672e-08 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + 0 + false + 0 + RightShoulder + RBXA9943A145CA34B9199D5810AE7AC1AD5 + RBXE08AA1E71CF7447581F14072A70CB0ED + + + + + + OriginalSize + + + 0.999999642 + 1.16867065 + 0.99999994 + + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + + 7.66999817 + 3.13598323 + -6 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + true + 2 + 0 + 4293256415 + + false + + -0.5 + 0.5 + 0 + 0 + + 2 + 1.60003424 + 1.00000036 + + -0.5 + 0.5 + 0 + 0 + false + 256 + http://www.roblox.com/asset/?id=1699715593 + http://www.roblox.com/asset/?id=1699715593 + UpperTorso + + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + + + -0.5 + 0.5 + 0 + 0 + 0 + + 0 + 0 + 0 + + + 2 + 1.56803358 + 1.00000036 + + + + + + -5.96046448e-08 + -0.783986032 + 1.1920929e-07 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + WaistRigAttachment + + false + + + + OriginalPosition + + + -5.96046448e-08 + -0.799985707 + 1.1920929e-07 + + + + + + + + -5.96046448e-08 + 0.784016788 + 1.1920929e-07 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + NeckRigAttachment + + false + + + + OriginalPosition + + + -5.96046448e-08 + 0.800017118 + 1.1920929e-07 + + + + + + + + -1 + 0.551756799 + 1.1920929e-07 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + LeftShoulderRigAttachment + + false + + + + OriginalPosition + + + -1 + 0.56301713 + 1.1920929e-07 + + + + + + + + 0.99999994 + 0.551756799 + 1.1920929e-07 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + RightShoulderRigAttachment + + false + + + + OriginalPosition + + + 0.99999994 + 0.56301713 + 1.1920929e-07 + + + + + + + + -5.96046448e-08 + -0.195985973 + -0.499999881 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + BodyFrontAttachment + + false + + + + OriginalPosition + + + -5.96046448e-08 + -0.199985683 + -0.499999881 + + + + + + + + -5.96046448e-08 + -0.195985973 + 0.5 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + BodyBackAttachment + + false + + + + OriginalPosition + + + -5.96046448e-08 + -0.199985683 + 0.5 + + + + + + + + -0.999999881 + 0.784016669 + -7.27397378e-08 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + LeftCollarAttachment + + false + + + + OriginalPosition + + + -0.999999881 + 0.800016999 + -7.27397378e-08 + + + + + + + + 0.99999994 + 0.78401643 + 4.61295997e-08 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + RightCollarAttachment + + false + + + + OriginalPosition + + + 0.99999994 + 0.800016761 + 4.61295997e-08 + + + + + + + + -5.05859497e-08 + 0.784016788 + 7.11172419e-08 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + NeckAttachment + + false + + + + OriginalPosition + + + -5.05859497e-08 + 0.800017118 + 7.11172419e-08 + + + + + + + + -1.1920929e-07 + 0.196024418 + 7.64462551e-20 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + + -5.96046448e-08 + -0.783986032 + 1.1920929e-07 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + 0 + false + 0 + Waist + RBXB8FFBCE768F34D8D8D966F48788528E0 + RBXA9943A145CA34B9199D5810AE7AC1AD5 + + + + + + OriginalSize + + + 2 + 1.60003424 + 1.00000036 + + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + + 7.16999817 + 0.147000074 + -6.00000095 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + false + 2 + 0 + 4293256415 + + false + + -0.5 + 0.5 + 0 + 0 + + 1 + 0.300000191 + 1 + + -0.5 + 0.5 + 0 + 0 + false + 256 + http://www.roblox.com/asset/?id=1699715602 + http://www.roblox.com/asset/?id=1699715602 + LeftFoot + + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + + + -0.5 + 0.5 + 0 + 0 + 0 + + 0 + 0 + 0 + + + 1 + 0.294000179 + 1 + + + + + + -1.78813934e-07 + 0.0999008864 + -1.7222776e-06 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + LeftAnkleRigAttachment + + false + + + + OriginalPosition + + + -1.78813934e-07 + 0.101939678 + -1.7222776e-06 + + + + + + + + -1.1920929e-07 + -0.536214054 + -2.21401592e-06 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + + -1.78813934e-07 + 0.0999008864 + -1.7222776e-06 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + 0 + false + 0 + LeftAnkle + RBX893C6CF7B2374480B69BBBE805825872 + RBX0FB02BF4485A49C89C7ABEF4D19DB3BE + + + + + + OriginalSize + + + 1 + 0.300000191 + 1 + + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + + 7.16999817 + 0.783115029 + -6.00000048 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + false + 2 + 0 + 4293256415 + + false + + -0.5 + 0.5 + 0 + 0 + + 0.99999994 + 1.1930927 + 0.999999523 + + -0.5 + 0.5 + 0 + 0 + false + 256 + http://www.roblox.com/asset/?id=1699715610 + http://www.roblox.com/asset/?id=1699715610 + LeftLowerLeg + + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + + + -0.5 + 0.5 + 0 + 0 + 0 + + 0 + 0 + 0 + + + 0.99999994 + 1.16923082 + 0.999999523 + + + + + + 2.98023224e-08 + 0.371438056 + -1.60860594e-07 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + LeftKneeRigAttachment + + false + + + + OriginalPosition + + + 2.98023224e-08 + 0.379018426 + -1.60860594e-07 + + + + + + + + -1.1920929e-07 + -0.536214054 + -2.21401592e-06 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + LeftAnkleRigAttachment + + false + + + + OriginalPosition + + + -1.1920929e-07 + -0.547157168 + -2.21401592e-06 + + + + + + + + 8.94069672e-08 + -0.393080324 + -4.29081496e-07 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + + 2.98023224e-08 + 0.371438056 + -1.60860594e-07 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + 0 + false + 0 + LeftKnee + RBXAF9FA9B09EA04DFEA9D919064EDE7D6F + RBX893C6CF7B2374480B69BBBE805825872 + + + + + + OriginalSize + + + 0.99999994 + 1.1930927 + 0.999999523 + + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + + 7.16999817 + 1.54763341 + -6 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + false + 2 + 0 + 4293256415 + + false + + -0.5 + 0.5 + 0 + 0 + + 1.00000036 + 1.21656859 + 0.999999881 + + -0.5 + 0.5 + 0 + 0 + false + 256 + http://www.roblox.com/asset/?id=1699715616 + http://www.roblox.com/asset/?id=1699715616 + LeftUpperLeg + + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + + + -0.5 + 0.5 + 0 + 0 + 0 + + 0 + 0 + 0 + + + 1.00000036 + 1.19223726 + 0.999999881 + + + + + + 5.96046448e-08 + 0.412366509 + -1.63912773e-07 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + LeftHipRigAttachment + + false + + + + OriginalPosition + + + 5.96046448e-08 + 0.420782149 + -1.63912773e-07 + + + + + + + + 8.94069672e-08 + -0.393080324 + -4.29081496e-07 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + LeftKneeRigAttachment + + false + + + + OriginalPosition + + + 8.94069672e-08 + -0.401102364 + -4.29081496e-07 + + + + + + + + -0.500000119 + -0.195972815 + -0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + + 5.96046448e-08 + 0.412366509 + -1.63912773e-07 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + 0 + false + 0 + LeftHip + RBXB8FFBCE768F34D8D8D966F48788528E0 + RBXAF9FA9B09EA04DFEA9D919064EDE7D6F + + + + + + OriginalSize + + + 1.00000036 + 1.21656859 + 0.999999881 + + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + + 8.16999817 + 0.147000074 + -5.99999952 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + false + 2 + 0 + 4293256415 + + false + + -0.5 + 0.5 + 0 + 0 + + 0.99999994 + 0.300000191 + 1 + + -0.5 + 0.5 + 0 + 0 + false + 256 + http://www.roblox.com/asset/?id=1699715627 + http://www.roblox.com/asset/?id=1699715627 + RightFoot + + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + + + -0.5 + 0.5 + 0 + 0 + 0 + + 0 + 0 + 0 + + + 0.99999994 + 0.294000179 + 1 + + + + + + -0 + 0.0999007672 + 7.64477954e-05 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + RightAnkleRigAttachment + + false + + + + OriginalPosition + + + -0 + 0.101939559 + 7.64477954e-05 + + + + + + + + -0 + -0.536214054 + 7.62689815e-05 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + + -0 + 0.0999007672 + 7.64477954e-05 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + 0 + false + 0 + RightAnkle + RBX934B19001E8E48CD955C16029E83167A + RBXC1076273B95B402B92B9B47AC621CE81 + + + + + + OriginalSize + + + 0.99999994 + 0.300000191 + 1 + + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + + 8.16999817 + 0.78311491 + -5.99999952 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + false + 2 + 0 + 4293256415 + + false + + -0.5 + 0.5 + 0 + 0 + + 0.99999994 + 1.19309282 + 1.00000012 + + -0.5 + 0.5 + 0 + 0 + false + 256 + http://www.roblox.com/asset/?id=1699715632 + http://www.roblox.com/asset/?id=1699715632 + RightLowerLeg + + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + + + -0.5 + 0.5 + 0 + 0 + 0 + + 0 + 0 + 0 + + + 0.99999994 + 1.16923094 + 1.00000012 + + + + + + -0 + 0.371590823 + 2.5553607e-05 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + RightKneeRigAttachment + + false + + + + OriginalPosition + + + -0 + 0.379174292 + 2.5553607e-05 + + + + + + + + -0 + -0.536214054 + 7.62689815e-05 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + RightAnkleRigAttachment + + false + + + + OriginalPosition + + + -0 + -0.547157168 + 7.62689815e-05 + + + + + + + + -0 + -0.392927587 + -2.18767891e-05 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + + -0 + 0.371590823 + 2.5553607e-05 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + 0 + false + 0 + RightKnee + RBX1174DFBAABA34412840A7F27FF9DDCE9 + RBX934B19001E8E48CD955C16029E83167A + + + + + + OriginalSize + + + 0.99999994 + 1.19309282 + 1.00000012 + + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + + 8.16999817 + 1.54763329 + -5.99995232 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + false + 2 + 0 + 4293256415 + + false + + -0.5 + 0.5 + 0 + 0 + + 1.00000048 + 1.21656859 + 0.99996686 + + -0.5 + 0.5 + 0 + 0 + false + 256 + http://www.roblox.com/asset/?id=1699715641 + http://www.roblox.com/asset/?id=1699715641 + RightUpperLeg + + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + + + -0.5 + 0.5 + 0 + 0 + 0 + + 0 + 0 + 0 + + + 1.00000048 + 1.19223726 + 0.99996686 + + + + + + -0 + 0.412366629 + -6.67300628e-05 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + RightHipRigAttachment + + false + + + + OriginalPosition + + + -0 + 0.420782268 + -6.67300628e-05 + + + + + + + + -0 + -0.392927587 + -2.18767891e-05 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + RightKneeRigAttachment + + false + + + + OriginalPosition + + + -0 + -0.400946498 + -2.18767891e-05 + + + + + + + + 0.499999881 + -0.195972815 + -1.91208565e-05 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + + -0 + 0.412366629 + -6.67300628e-05 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + 0 + false + 0 + RightHip + RBXB8FFBCE768F34D8D8D966F48788528E0 + RBX1174DFBAABA34412840A7F27FF9DDCE9 + + + + + + OriginalSize + + + 1.00000048 + 1.21656859 + 0.99996686 + + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + + 7.66999817 + 2.15597272 + -6 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + true + 2 + 0 + 4293256415 + + false + + -0.5 + 0.5 + 0 + 0 + + 1.99999976 + 0.400055438 + 1.00000012 + + -0.5 + 0.5 + 0 + 0 + false + 256 + http://www.roblox.com/asset/?id=1699715652 + http://www.roblox.com/asset/?id=1699715652 + LowerTorso + + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + + + -0.5 + 0.5 + 0 + 0 + 0 + + 0 + 0 + 0 + + + 1.99999976 + 0.392054349 + 1.00000012 + + + + + + -1.1920929e-07 + -0.195972815 + -0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + RootRigAttachment + + false + + + + OriginalPosition + + + -1.1920929e-07 + -0.199972257 + -0 + + + + + + + + -1.1920929e-07 + 0.196024418 + 7.64462551e-20 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + WaistRigAttachment + + false + + + + OriginalPosition + + + -1.1920929e-07 + 0.200024918 + 7.64462551e-20 + + + + + + + + -0.500000119 + -0.195972815 + -0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + LeftHipRigAttachment + + false + + + + OriginalPosition + + + -0.500000119 + -0.199972257 + -0 + + + + + + + + 0.499999881 + -0.195972815 + -1.91208565e-05 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + RightHipRigAttachment + + false + + + + OriginalPosition + + + 0.499999881 + -0.199972257 + -1.91208565e-05 + + + + + + + + -4.2200088e-07 + -0.195972815 + -1.65436123e-24 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + WaistCenterAttachment + + false + + + + OriginalPosition + + + -4.2200088e-07 + -0.199972257 + -1.65436123e-24 + + + + + + + + -1.32219867e-07 + -0.195972815 + -0.50000006 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + WaistFrontAttachment + + false + + + + OriginalPosition + + + -1.32219867e-07 + -0.199972257 + -0.50000006 + + + + + + + + -1.46413214e-07 + -0.195972815 + 0.50000006 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + WaistBackAttachment + + false + + + + OriginalPosition + + + -1.46413214e-07 + -0.199972257 + 0.50000006 + + + + + + + + 0 + -0.342999995 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + + -1.1920929e-07 + -0.195972815 + -0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + 0 + false + 0 + Root + RBX081D55DA3E944921A37ACF5DF5DC888A + RBXB8FFBCE768F34D8D8D966F48788528E0 + + + + + + OriginalSize + + + 1.99999976 + 0.400055438 + 1.00000012 + + + + + + + true + true + true + 2 + 0 + 0 + 100 + 1.32300007 + + 1 + 0.980000019 + 1 + + 1 + 50 + 100 + 89 + Humanoid + 100 + 2 + 1 + + 16 + + + + BodyDepthScale + + 1 + + + + + BodyHeightScale + + 0.98000001907348632813 + + + + + BodyProportionScale + + 0 + + + + + BodyTypeScale + + 0 + + + + + BodyWidthScale + + 1 + + + + + HeadScale + + 1 + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + + 7.66999817 + 4.42000008 + -5.99972773 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + true + 0 + 4293256415 + + false + + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + false + 256 + Head + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + + -0.5 + 0.5 + 0 + 0 + 0 + + 0 + 0 + 0 + + 1 + 1 + + 2 + 1 + 1 + + + + + 2 + 2 + + 0 + Mesh + + 0 + 0 + 0 + + + 1.25 + 1.25 + 1.25 + + + + + 1 + 1 + 1 + + + + + OriginalSize + + + 1.25 + 1.25 + 1.25 + + + + + + + + 3.93568822e-09 + 0 + -0.000272244215 + 1 + 7.87137555e-09 + 3.02998127e-15 + -7.87137555e-09 + 1 + -4.1444258e-16 + -3.02998127e-15 + 4.14442554e-16 + 1 + + FaceCenterAttachment + + false + + + + OriginalPosition + + + 3.93568822e-09 + 0 + -0.000272244215 + + + + + + + + 3.93568866e-09 + 0 + -0.600272298 + 1 + 7.87137555e-09 + 3.02998127e-15 + -7.87137555e-09 + 1 + -4.1444258e-16 + -3.02998127e-15 + 4.14442554e-16 + 1 + + FaceFrontAttachment + + false + + + + OriginalPosition + + + 3.93568866e-09 + 0 + -0.600272298 + + + + + + + + 8.65851391e-09 + 0.599999905 + -0.000272244215 + 1 + 7.87137555e-09 + 3.02998127e-15 + -7.87137555e-09 + 1 + -4.1444258e-16 + -3.02998127e-15 + 4.14442554e-16 + 1 + + HairAttachment + + false + + + + OriginalPosition + + + 8.65851391e-09 + 0.599999905 + -0.000272244215 + + + + + + + + 8.65851391e-09 + 0.599999905 + -0.000272244215 + 1 + 7.87137555e-09 + 3.02998127e-15 + -7.87137555e-09 + 1 + -4.1444258e-16 + -3.02998127e-15 + 4.14442554e-16 + 1 + + HatAttachment + + false + + + + OriginalPosition + + + 8.65851391e-09 + 0.599999905 + -0.000272244215 + + + + + + + + -0 + -0.500000119 + -0.000272244215 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + NeckRigAttachment + + false + + + + OriginalPosition + + + -0 + -0.500000119 + -0.000272244215 + + + + + + + 4294967295 + 5 + face + + rbxasset://textures/face.png + 0 + + + + + + -5.96046448e-08 + 0.784016788 + 1.1920929e-07 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + + -0 + -0.500000119 + -0.000272244215 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + 0 + false + 0 + Neck + RBXA9943A145CA34B9199D5810AE7AC1AD5 + RBX3A01263AEC0C4FB289F443C3B3EEF144 + + + + + + OriginalSize + + + 2 + 1 + 1 + + + + + + + false + + Animate + {023B546E-F0DD-4EFB-A64F-BC4BC43CBC7B} + + + + + + cheer + + + + + + http://www.roblox.com/asset/?id=507770677 + CheerAnim + + + + + + + climb + + + + + + http://www.roblox.com/asset/?id=507765644 + ClimbAnim + + + + + + + dance + + + + + + http://www.roblox.com/asset/?id=507771019 + Animation1 + + + + + Weight + + 10 + + + + + + http://www.roblox.com/asset/?id=507771955 + Animation2 + + + + + Weight + + 10 + + + + + + http://www.roblox.com/asset/?id=507772104 + Animation3 + + + + + Weight + + 10 + + + + + + + dance2 + + + + + + http://www.roblox.com/asset/?id=507776043 + Animation1 + + + + + Weight + + 10 + + + + + + http://www.roblox.com/asset/?id=507776720 + Animation2 + + + + + Weight + + 10 + + + + + + http://www.roblox.com/asset/?id=507776879 + Animation3 + + + + + Weight + + 10 + + + + + + + dance3 + + + + + + http://www.roblox.com/asset/?id=507777268 + Animation1 + + + + + Weight + + 10 + + + + + + http://www.roblox.com/asset/?id=507777451 + Animation2 + + + + + Weight + + 10 + + + + + + http://www.roblox.com/asset/?id=507777623 + Animation3 + + + + + Weight + + 10 + + + + + + + fall + + + + + + http://www.roblox.com/asset/?id=507767968 + FallAnim + + + + + + + idle + + + + + + http://www.roblox.com/asset/?id=507766388 + Animation1 + + + + + Weight + + 9 + + + + + + http://www.roblox.com/asset/?id=507766666 + Animation2 + + + + + Weight + + 1 + + + + + + + jump + + + + + + http://www.roblox.com/asset/?id=507765000 + JumpAnim + + + + + + + laugh + + + + + + http://www.roblox.com/asset/?id=507770818 + LaughAnim + + + + + + + point + + + + + + http://www.roblox.com/asset/?id=507770453 + PointAnim + + + + + + + run + + + + + + http://www.roblox.com/asset/?id=507767714 + RunAnim + + + + + + + sit + + + + + + http://www.roblox.com/asset/?id=507768133 + SitAnim + + + + + + + swim + + + + + + http://www.roblox.com/asset/?id=507784897 + Swim + + + + + + + swimidle + + + + + + http://www.roblox.com/asset/?id=481825862 + SwimIdle + + + + + + + toollunge + + + + + + http://www.roblox.com/asset/?id=522638767 + ToolLungeAnim + + + + + + + toolnone + + + + + + http://www.roblox.com/asset/?id=507768375 + ToolNoneAnim + + + + + + + toolslash + + + + + + http://www.roblox.com/asset/?id=522635514 + ToolSlashAnim + + + + + + + walk + + + + + + http://www.roblox.com/asset/?id=540798782 + WalkAnim + + + + + + + wave + + + + + + http://www.roblox.com/asset/?id=507770239 + WaveAnim + + + + + + + \ No newline at end of file diff --git a/2018/content/avatar/morpherEditorR6.rbxmx b/2018/content/avatar/morpherEditorR6.rbxmx new file mode 100644 index 0000000..ca7f595 --- /dev/null +++ b/2018/content/avatar/morpherEditorR6.rbxmx @@ -0,0 +1,1121 @@ + + false + null + nil + + + + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + R6 + RBX268D3553F8164BE0944302D499E3B918 + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 4 + 0 + + 10.7362061 + 5.16300297 + -2.11117506 + 0.766051888 + 0 + 0.642794013 + 0 + 1 + 0 + -0.642794013 + 0 + 0.766051888 + + true + 0 + 4288914085 + + false + + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + true + 256 + Head + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + + -0.5 + 0.5 + 0 + 0 + 0 + + 0 + 0 + 0 + + 0 + 1 + + 2 + 1 + 1 + + + + + 4294967295 + 5 + face + + rbxasset://textures/face.png + 0 + + + + + 2 + 2 + + 0 + Mesh + + 0 + 0 + 0 + + + 1.25 + 1.25 + 1.25 + + + + + 1 + 1 + 1 + + + + + + + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + FaceCenterAttachment + + false + + + + + + 0 + 0 + -0.600000024 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + FaceFrontAttachment + + false + + + + + + 0 + 0.600000024 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + HairAttachment + + false + + + + + + 0 + 0.600000024 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + HatAttachment + + false + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 4 + 0 + + 10.7362061 + 3.66300297 + -2.11117506 + 0.766051888 + 0 + 0.642794013 + 0 + 1 + 0 + -0.642794013 + 0 + 0.766051888 + + true + 0 + 4288914085 + + false + + -0.5 + 0.5 + 0 + 0 + 0 + 0 + 2 + 0 + true + 256 + Torso + 0 + 0 + 0 + 2 + 0 + + 0 + 0 + 0 + + + -0.5 + 0.5 + 3 + 0 + 0 + + 0 + 0 + 0 + + 0 + 1 + + 2 + 2 + 1 + + + + + + 1 + 0.5 + 0 + 0 + 0 + 1 + 0 + 1 + -0 + -1 + 0 + 0 + + + -0.5 + 0.5 + 0 + 0 + 0 + 1 + 0 + 1 + -0 + -1 + 0 + 0 + + 0 + false + 0.100000001 + Right Shoulder + RBX335EB02A1E034C03BDB8817CC0227D43 + RBXF656CD68CA394FF3B913BD5A491CF6F1 + + + + + + + -1 + 0.5 + 0 + 0 + 0 + -1 + 0 + 1 + 0 + 1 + 0 + 0 + + + 0.5 + 0.5 + 0 + 0 + 0 + -1 + 0 + 1 + 0 + 1 + 0 + 0 + + 0 + false + 0.100000001 + Left Shoulder + RBX335EB02A1E034C03BDB8817CC0227D43 + RBX6746C39D16F440CDAF23D54B9D99B38A + + + + + + + 1 + -1 + 0 + 0 + 0 + 1 + 0 + 1 + -0 + -1 + 0 + 0 + + + 0.5 + 1 + 0 + 0 + 0 + 1 + 0 + 1 + -0 + -1 + 0 + 0 + + 0 + false + 0.100000001 + Right Hip + RBX335EB02A1E034C03BDB8817CC0227D43 + RBXF436A38E2161481E82066DF8D79AB417 + + + + + + + -1 + -1 + 0 + 0 + 0 + -1 + 0 + 1 + 0 + 1 + 0 + 0 + + + -0.5 + 1 + 0 + 0 + 0 + -1 + 0 + 1 + 0 + 1 + 0 + 0 + + 0 + false + 0.100000001 + Left Hip + RBX335EB02A1E034C03BDB8817CC0227D43 + RBX1515CFDCBD8E4B02B9C4053FDCB3F8B7 + + + + + + + 0 + 1 + 0 + -1 + 0 + 0 + 0 + 0 + 1 + 0 + 1 + -0 + + + 0 + -0.5 + 0 + -1 + 0 + 0 + 0 + 0 + 1 + 0 + 1 + -0 + + 0 + false + 0.100000001 + Neck + RBX335EB02A1E034C03BDB8817CC0227D43 + RBX268D3553F8164BE0944302D499E3B918 + + + + + + + 0 + 0 + 0.5 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + BodyBackAttachment + + false + + + + + + 0 + 0 + -0.5 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + BodyFrontAttachment + + false + + + + + + -1 + 1 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + LeftCollarAttachment + + false + + + + + + 0 + 1 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + NeckAttachment + + false + + + + + + 1 + 1 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + RightCollarAttachment + + false + + + + + + 0 + -1 + 0.5 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + WaistBackAttachment + + false + + + + + + 0 + -1 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + WaistCenterAttachment + + false + + + + + + 0 + -1 + -0.5 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + WaistFrontAttachment + + false + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 4 + 0 + + 9.58712769 + 3.66300297 + -1.1469841 + 0.766051888 + 0 + 0.642794013 + 0 + 1 + 0 + -0.642794013 + 0 + 0.766051888 + + true + 0 + 4288914085 + + false + + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + true + 256 + Left Arm + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + + -0.5 + 0.5 + 3 + 0 + 0 + + 0 + 0 + 0 + + 0 + 1 + + 1 + 2 + 1 + + + + + + 0 + 0.5 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + LeftShoulderAttachment + + false + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 4 + 0 + + 11.8852844 + 3.66300297 + -3.07536602 + 0.766051888 + 0 + 0.642794013 + 0 + 1 + 0 + -0.642794013 + 0 + 0.766051888 + + true + 0 + 4294939796 + + false + + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + true + 256 + Right Arm + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + + -0.5 + 0.5 + 3 + 0 + 0 + + 0 + 0 + 0 + + 0 + 1 + + 1 + 2 + 1 + + + + + + 0 + 0.5 + 0 + 1 + 0 + 0 + 0 + 1 + 0 + 0 + 0 + 1 + + RightShoulderAttachment + + false + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + + 10.3531799 + 1.66300297 + -1.78977799 + 0.766051888 + 0 + 0.642794013 + 0 + 1 + 0 + -0.642794013 + 0 + 0.766051888 + + true + 0 + 4294939796 + + false + + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + true + 256 + Left Leg + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + + -0.5 + 0.5 + 3 + 0 + 0 + + 0 + 0 + 0 + + 0 + 1 + + 1 + 2 + 1 + + + + + + false + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + + 11.1192322 + 1.66300297 + -2.43257213 + 0.766051888 + 0 + 0.642794013 + 0 + 1 + 0 + -0.642794013 + 0 + 0.766051888 + + true + 0 + 4288914085 + + false + + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + true + 256 + Right Leg + 0 + -0.5 + 0.5 + 0 + 0 + + 0 + 0 + 0 + + + -0.5 + 0.5 + 3 + 0 + 0 + + 0 + 0 + 0 + + 0 + 1 + + 1 + 2 + 1 + + + + + + true + true + true + 2 + 100 + 0 + 0 + 0 + + 1 + 1 + 1 + + 1 + 50 + 0 + 89 + Humanoid + 100 + 2 + 0 + + 16 + + + + + true + -0.5 + 0.5 + 0 + 0 + -0.5 + 0.5 + 0 + 0 + + 10.7362061 + 3.66300297 + -2.11117506 + 0.766051888 + 2.24691483e-39 + 0.642794013 + 2.93314189e-39 + 1 + 0 + -0.642794013 + -1.88538683e-39 + 0.766051888 + + true + 0 + 4279069100 + + false + + -0.5 + 0.5 + 0 + 0 + 0 + 0 + 0 + 0 + true + 256 + HumanoidRootPart + 0 + 0 + 0 + 0 + 0 + + 0 + 0 + 0 + + + -0.5 + 0.5 + 0 + 0 + 1 + + 0 + 0 + 0 + + 0 + 1 + + 2 + 2 + 1 + + + + + + 0 + 0 + 0 + -1 + 0 + 0 + 0 + 0 + 1 + 0 + 1 + -0 + + + 0 + 0 + 0 + -1 + 0 + 0 + 0 + 0 + 1 + 0 + 1 + -0 + + 0 + false + 0.100000001 + RootJoint + RBXC27DD24388A54334A651B4AE62D07FEC + RBX335EB02A1E034C03BDB8817CC0227D43 + + + + + + \ No newline at end of file diff --git a/2018/content/avatar/scripts/characterSound.rbxmx b/2018/content/avatar/scripts/characterSound.rbxmx new file mode 100644 index 0000000..792a4cf --- /dev/null +++ b/2018/content/avatar/scripts/characterSound.rbxmx @@ -0,0 +1,366 @@ + + null + nil + + + false + + Sound + + + + + + false + + LocalSound + + 0.5 then + Util.Resume(sound) + setSoundInPlayingLoopedSounds(sound) + else + stopPlayingLoopedSoundsExcept() + end + end; + + [Enum.HumanoidStateType.Swimming] = function() + if activeState ~= Enum.HumanoidStateType.Swimming and Util.VerticalSpeed(Head) > 0.1 then + local splashSound = Sounds[SFX.Splash] + splashSound.Volume = Util.Clamp( + Util.YForLineGivenXAndTwoPts( + Util.VerticalSpeed(Head), + 100, 0.28, + 350, 1), + 0,1) + Util.Play(splashSound) + end + + do + local sound = Sounds[SFX.Swimming] + stopPlayingLoopedSoundsExcept(sound) + Util.Resume(sound) + setSoundInPlayingLoopedSounds(sound) + end + end; + + [Enum.HumanoidStateType.Climbing] = function() + local sound = Sounds[SFX.Climbing] + if Util.VerticalSpeed(Head) > 0.1 then + Util.Resume(sound) + stopPlayingLoopedSoundsExcept(sound) + else + stopPlayingLoopedSoundsExcept() + end + setSoundInPlayingLoopedSounds(sound) + end; + + [Enum.HumanoidStateType.Jumping] = function() + if activeState == Enum.HumanoidStateType.Jumping then + return + end + stopPlayingLoopedSoundsExcept() + local sound = Sounds[SFX.Jumping] + Util.Play(sound) + end; + + [Enum.HumanoidStateType.GettingUp] = function() + stopPlayingLoopedSoundsExcept() + local sound = Sounds[SFX.GettingUp] + Util.Play(sound) + end; + + [Enum.HumanoidStateType.Freefall] = function() + if activeState == Enum.HumanoidStateType.Freefall then + return + end + local sound = Sounds[SFX.FreeFalling] + sound.Volume = 0 + stopPlayingLoopedSoundsExcept() + end; + + [Enum.HumanoidStateType.FallingDown] = function() + stopPlayingLoopedSoundsExcept() + end; + + [Enum.HumanoidStateType.Landed] = function() + stopPlayingLoopedSoundsExcept() + if Util.VerticalSpeed(Head) > 75 then + local landingSound = Sounds[SFX.Landing] + landingSound.Volume = Util.Clamp( + Util.YForLineGivenXAndTwoPts( + Util.VerticalSpeed(Head), + 50, 0, + 100, 1), + 0,1) + Util.Play(landingSound) + end + end; + + [Enum.HumanoidStateType.Seated] = function() + stopPlayingLoopedSoundsExcept() + end; + } + + -- Handle state event fired or OnChange fired + function stateUpdated(state) + if stateUpdateHandler[state] ~= nil then + stateUpdateHandler[state]() + end + activeState = state + end + + Humanoid.Died:connect( function() stateUpdated(Enum.HumanoidStateType.Dead) end) + Humanoid.Running:connect( function() stateUpdated(Enum.HumanoidStateType.Running) end) + Humanoid.Swimming:connect( function() stateUpdated(Enum.HumanoidStateType.Swimming) end) + Humanoid.Climbing:connect( function() stateUpdated(Enum.HumanoidStateType.Climbing) end) + Humanoid.Jumping:connect( function() stateUpdated(Enum.HumanoidStateType.Jumping) end) + Humanoid.GettingUp:connect( function() stateUpdated(Enum.HumanoidStateType.GettingUp) end) + Humanoid.FreeFalling:connect( function() stateUpdated(Enum.HumanoidStateType.Freefall) end) + Humanoid.FallingDown:connect( function() stateUpdated(Enum.HumanoidStateType.FallingDown) end) + + -- required for proper handling of Landed event + Humanoid.StateChanged:connect(function(old, new) + stateUpdated(new) + end) + + + function onUpdate(stepDeltaSeconds, tickSpeedSeconds) + local stepScale = stepDeltaSeconds / tickSpeedSeconds + do + local sound = Sounds[SFX.FreeFalling] + if activeState == Enum.HumanoidStateType.Freefall then + if Head.Velocity.Y < 0 and Util.VerticalSpeed(Head) > 75 then + Util.Resume(sound) + + --Volume takes 1.1 seconds to go from volume 0 to 1 + local ANIMATION_LENGTH_SECONDS = 1.1 + + local normalizedIncrement = tickSpeedSeconds / ANIMATION_LENGTH_SECONDS + sound.Volume = Util.Clamp(sound.Volume + normalizedIncrement * stepScale, 0, 1) + else + sound.Volume = 0 + end + else + Util.Pause(sound) + end + end + + do + local sound = Sounds[SFX.Running] + if activeState == Enum.HumanoidStateType.Running then + if Util.HorizontalSpeed(Head) < 0.5 then + Util.Pause(sound) + end + end + end + end + + local lastTick = tick() + local TICK_SPEED_SECONDS = 0.25 + while true do + onUpdate(tick() - lastTick,TICK_SPEED_SECONDS) + lastTick = tick() + wait(TICK_SPEED_SECONDS) + end +end +]]> + + + + \ No newline at end of file diff --git a/2018/content/avatar/scripts/humanoidAnimateLocalKeyframe.rbxm b/2018/content/avatar/scripts/humanoidAnimateLocalKeyframe.rbxm new file mode 100644 index 0000000..ad71482 --- /dev/null +++ b/2018/content/avatar/scripts/humanoidAnimateLocalKeyframe.rbxm @@ -0,0 +1,664 @@ + + null + nil + + + false + + Animate + animTable[animName][idx].weight) do + roll = roll - animTable[animName][idx].weight + idx = idx + 1 + end +-- print(animName .. " " .. idx .. " [" .. origRoll .. "]") + local anim = animTable[animName][idx].anim + + -- switch animation + if (anim ~= currentAnimInstance) then + + if (currentAnimTrack ~= nil) then + currentAnimTrack:Stop(transitionTime) + currentAnimTrack:Destroy() + end + + currentAnimSpeed = 1.0 + + -- load it to the humanoid; get AnimationTrack + currentAnimTrack = humanoid:LoadAnimation(anim) + currentAnimTrack.Priority = Enum.AnimationPriority.Core + + -- play the animation + currentAnimTrack:Play(transitionTime) + currentAnim = animName + currentAnimInstance = anim + + -- set up keyframe name triggers + if (currentAnimKeyframeHandler ~= nil) then + currentAnimKeyframeHandler:disconnect() + end + currentAnimKeyframeHandler = currentAnimTrack.KeyframeReached:connect(keyFrameReachedFunc) + + end + +end + +------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------- + +local toolAnimName = "" +local toolAnimTrack = nil +local toolAnimInstance = nil +local currentToolAnimKeyframeHandler = nil + +function toolKeyFrameReachedFunc(frameName) + if (frameName == "End") then +-- print("Keyframe : ".. frameName) + playToolAnimation(toolAnimName, 0.0, Humanoid) + end +end + + +function playToolAnimation(animName, transitionTime, humanoid, priority) + + local roll = math.random(1, animTable[animName].totalWeight) + local origRoll = roll + local idx = 1 + while (roll > animTable[animName][idx].weight) do + roll = roll - animTable[animName][idx].weight + idx = idx + 1 + end +-- print(animName .. " * " .. idx .. " [" .. origRoll .. "]") + local anim = animTable[animName][idx].anim + + if (toolAnimInstance ~= anim) then + + if (toolAnimTrack ~= nil) then + toolAnimTrack:Stop() + toolAnimTrack:Destroy() + transitionTime = 0 + end + + -- load it to the humanoid; get AnimationTrack + toolAnimTrack = humanoid:LoadAnimation(anim) + if priority then + toolAnimTrack.Priority = priority + end + + -- play the animation + toolAnimTrack:Play(transitionTime) + toolAnimName = animName + toolAnimInstance = anim + + currentToolAnimKeyframeHandler = toolAnimTrack.KeyframeReached:connect(toolKeyFrameReachedFunc) + end +end + +function stopToolAnimations() + local oldAnim = toolAnimName + + if (currentToolAnimKeyframeHandler ~= nil) then + currentToolAnimKeyframeHandler:disconnect() + end + + toolAnimName = "" + toolAnimInstance = nil + if (toolAnimTrack ~= nil) then + toolAnimTrack:Stop() + toolAnimTrack:Destroy() + toolAnimTrack = nil + end + + + return oldAnim +end + +------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------- + + +function onRunning(speed) + if speed > 0.01 then + playAnimation("walk", 0.1, Humanoid) + if currentAnimInstance and currentAnimInstance.AnimationId == "http://www.roblox.com/asset/?id=180426354" then + setAnimationSpeed(speed / 14.5) + end + pose = "Running" + else + if emoteNames[currentAnim] == nil then + playAnimation("idle", 0.1, Humanoid) + pose = "Standing" + end + end +end + +function onDied() + pose = "Dead" +end + +function onJumping() + playAnimation("jump", 0.1, Humanoid) + jumpAnimTime = jumpAnimDuration + pose = "Jumping" +end + +function onClimbing(speed) + playAnimation("climb", 0.1, Humanoid) + setAnimationSpeed(speed / 12.0) + pose = "Climbing" +end + +function onGettingUp() + pose = "GettingUp" +end + +function onFreeFall() + if (jumpAnimTime <= 0) then + playAnimation("fall", fallTransitionTime, Humanoid) + end + pose = "FreeFall" +end + +function onFallingDown() + pose = "FallingDown" +end + +function onSeated() + pose = "Seated" +end + +function onPlatformStanding() + pose = "PlatformStanding" +end + +function onSwimming(speed) + if speed > 0 then + pose = "Running" + else + pose = "Standing" + end +end + +function getTool() + for _, kid in ipairs(Figure:GetChildren()) do + if kid.className == "Tool" then return kid end + end + return nil +end + +function getToolAnim(tool) + for _, c in ipairs(tool:GetChildren()) do + if c.Name == "toolanim" and c.className == "StringValue" then + return c + end + end + return nil +end + +function animateTool() + + if (toolAnim == "None") then + playToolAnimation("toolnone", toolTransitionTime, Humanoid, Enum.AnimationPriority.Idle) + return + end + + if (toolAnim == "Slash") then + playToolAnimation("toolslash", 0, Humanoid, Enum.AnimationPriority.Action) + return + end + + if (toolAnim == "Lunge") then + playToolAnimation("toollunge", 0, Humanoid, Enum.AnimationPriority.Action) + return + end +end + +function moveSit() + RightShoulder.MaxVelocity = 0.15 + LeftShoulder.MaxVelocity = 0.15 + RightShoulder:SetDesiredAngle(3.14 /2) + LeftShoulder:SetDesiredAngle(-3.14 /2) + RightHip:SetDesiredAngle(3.14 /2) + LeftHip:SetDesiredAngle(-3.14 /2) +end + +local lastTick = 0 + +function move(time) + local amplitude = 1 + local frequency = 1 + local deltaTime = time - lastTick + lastTick = time + + local climbFudge = 0 + local setAngles = false + + if (jumpAnimTime > 0) then + jumpAnimTime = jumpAnimTime - deltaTime + end + + if (pose == "FreeFall" and jumpAnimTime <= 0) then + playAnimation("fall", fallTransitionTime, Humanoid) + elseif (pose == "Seated") then + playAnimation("sit", 0.5, Humanoid) + return + elseif (pose == "Running") then + playAnimation("walk", 0.1, Humanoid) + elseif (pose == "Dead" or pose == "GettingUp" or pose == "FallingDown" or pose == "Seated" or pose == "PlatformStanding") then +-- print("Wha " .. pose) + stopAllAnimations() + amplitude = 0.1 + frequency = 1 + setAngles = true + end + + if (setAngles) then + local desiredAngle = amplitude * math.sin(time * frequency) + + RightShoulder:SetDesiredAngle(desiredAngle + climbFudge) + LeftShoulder:SetDesiredAngle(desiredAngle - climbFudge) + RightHip:SetDesiredAngle(-desiredAngle) + LeftHip:SetDesiredAngle(-desiredAngle) + end + + -- Tool Animation handling + local tool = getTool() + if tool and tool:FindFirstChild("Handle") then + + local animStringValueObject = getToolAnim(tool) + + if animStringValueObject then + toolAnim = animStringValueObject.Value + -- message recieved, delete StringValue + animStringValueObject.Parent = nil + toolAnimTime = time + .3 + end + + if time > toolAnimTime then + toolAnimTime = 0 + toolAnim = "None" + end + + animateTool() + else + stopToolAnimations() + toolAnim = "None" + toolAnimInstance = nil + toolAnimTime = 0 + end +end + +-- connect events +Humanoid.Died:connect(onDied) +Humanoid.Running:connect(onRunning) +Humanoid.Jumping:connect(onJumping) +Humanoid.Climbing:connect(onClimbing) +Humanoid.GettingUp:connect(onGettingUp) +Humanoid.FreeFalling:connect(onFreeFall) +Humanoid.FallingDown:connect(onFallingDown) +Humanoid.Seated:connect(onSeated) +Humanoid.PlatformStanding:connect(onPlatformStanding) +Humanoid.Swimming:connect(onSwimming) + +-- setup emote chat hook +game:GetService("Players").LocalPlayer.Chatted:connect(function(msg) + local emote = "" + if msg == "/e dance" then + emote = dances[math.random(1, #dances)] + elseif (string.sub(msg, 1, 3) == "/e ") then + emote = string.sub(msg, 4) + elseif (string.sub(msg, 1, 7) == "/emote ") then + emote = string.sub(msg, 8) + end + + if (pose == "Standing" and emoteNames[emote] ~= nil) then + playAnimation(emote, 0.1, Humanoid) + end + +end) + + +-- main program + +-- initialize to idle +playAnimation("idle", 0.1, Humanoid) +pose = "Standing" + +while Figure.Parent ~= nil do + local _, time = wait(0.1) + move(time) +end + + +]]> + + + + idle + + + + + http://www.roblox.com/asset/?id=180435571 + Animation1 + + + + Weight + 9 + + + + + + http://www.roblox.com/asset/?id=180435792 + Animation2 + + + + Weight + 1 + + + + + + + walk + + + + + http://www.roblox.com/asset/?id=180426354 + WalkAnim + + + + + + run + + + + + http://www.roblox.com/asset/?id=180426354 + RunAnim + + + + + + jump + + + + + http://www.roblox.com/asset/?id=125750702 + JumpAnim + + + + + + climb + + + + + http://www.roblox.com/asset/?id=180436334 + ClimbAnim + + + + + + toolnone + + + + + http://www.roblox.com/asset/?id=182393478 + ToolNoneAnim + + + + + + fall + + + + + http://www.roblox.com/asset/?id=180436148 + FallAnim + + + + + + sit + + + + + http://www.roblox.com/asset/?id=178130996 + SitAnim + + + + + \ No newline at end of file diff --git a/2018/content/avatar/scripts/humanoidAnimateR15.rbxm b/2018/content/avatar/scripts/humanoidAnimateR15.rbxm new file mode 100644 index 0000000..bfb4da2 --- /dev/null +++ b/2018/content/avatar/scripts/humanoidAnimateR15.rbxm @@ -0,0 +1,1032 @@ + + null + nil + + + false + + Animate + {0C2E6BF6-AFE6-4BAA-9650-0D7405850A49} + animTable[animName][idx].weight) do + roll = roll - animTable[animName][idx].weight + idx = idx + 1 + end + return idx +end + +function playAnimation(animName, transitionTime, humanoid) + local idx = rollAnimation(animName) + local anim = animTable[animName][idx].anim + + -- switch animation + if (anim ~= currentAnimInstance) then + + if (currentAnimTrack ~= nil) then + currentAnimTrack:Stop(transitionTime) + currentAnimTrack:Destroy() + end + + if (runAnimTrack ~= nil) then + runAnimTrack:Stop(transitionTime) + runAnimTrack:Destroy() + if userNoUpdateOnLoop == true then + runAnimTrack = nil + end + end + + currentAnimSpeed = 1.0 + + -- load it to the humanoid; get AnimationTrack + currentAnimTrack = humanoid:LoadAnimation(anim) + currentAnimTrack.Priority = Enum.AnimationPriority.Core + + -- play the animation + currentAnimTrack:Play(transitionTime) + currentAnim = animName + currentAnimInstance = anim + + -- set up keyframe name triggers + if (currentAnimKeyframeHandler ~= nil) then + currentAnimKeyframeHandler:disconnect() + end + currentAnimKeyframeHandler = currentAnimTrack.KeyframeReached:connect(keyFrameReachedFunc) + + -- check to see if we need to blend a walk/run animation + if animName == "walk" then + local runAnimName = "run" + local runIdx = rollAnimation(runAnimName) + + runAnimTrack = humanoid:LoadAnimation(animTable[runAnimName][runIdx].anim) + runAnimTrack.Priority = Enum.AnimationPriority.Core + runAnimTrack:Play(transitionTime) + + if (runAnimKeyframeHandler ~= nil) then + runAnimKeyframeHandler:disconnect() + end + runAnimKeyframeHandler = runAnimTrack.KeyframeReached:connect(keyFrameReachedFunc) + end + end + +end + +------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------- + +local toolAnimName = "" +local toolAnimTrack = nil +local toolAnimInstance = nil +local currentToolAnimKeyframeHandler = nil + +function toolKeyFrameReachedFunc(frameName) + if (frameName == "End") then + playToolAnimation(toolAnimName, 0.0, Humanoid) + end +end + + +function playToolAnimation(animName, transitionTime, humanoid, priority) + local idx = rollAnimation(animName) + local anim = animTable[animName][idx].anim + + if (toolAnimInstance ~= anim) then + + if (toolAnimTrack ~= nil) then + toolAnimTrack:Stop() + toolAnimTrack:Destroy() + transitionTime = 0 + end + + -- load it to the humanoid; get AnimationTrack + toolAnimTrack = humanoid:LoadAnimation(anim) + if priority then + toolAnimTrack.Priority = priority + end + + -- play the animation + toolAnimTrack:Play(transitionTime) + toolAnimName = animName + toolAnimInstance = anim + + currentToolAnimKeyframeHandler = toolAnimTrack.KeyframeReached:connect(toolKeyFrameReachedFunc) + end +end + +function stopToolAnimations() + local oldAnim = toolAnimName + + if (currentToolAnimKeyframeHandler ~= nil) then + currentToolAnimKeyframeHandler:disconnect() + end + + toolAnimName = "" + toolAnimInstance = nil + if (toolAnimTrack ~= nil) then + toolAnimTrack:Stop() + toolAnimTrack:Destroy() + toolAnimTrack = nil + end + + return oldAnim +end + +------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------- +-- STATE CHANGE HANDLERS + +function onRunning(speed) + if speed > 0.5 then + local scale = 16.0 + playAnimation("walk", 0.2, Humanoid) + setAnimationSpeed(speed / scale) + pose = "Running" + else + if emoteNames[currentAnim] == nil then + playAnimation("idle", 0.2, Humanoid) + pose = "Standing" + end + end +end + +function onDied() + pose = "Dead" +end + +function onJumping() + playAnimation("jump", 0.1, Humanoid) + jumpAnimTime = jumpAnimDuration + pose = "Jumping" +end + +function onClimbing(speed) + local scale = 5.0 + playAnimation("climb", 0.1, Humanoid) + setAnimationSpeed(speed / scale) + pose = "Climbing" +end + +function onGettingUp() + pose = "GettingUp" +end + +function onFreeFall() + if (jumpAnimTime <= 0) then + playAnimation("fall", fallTransitionTime, Humanoid) + end + pose = "FreeFall" +end + +function onFallingDown() + pose = "FallingDown" +end + +function onSeated() + pose = "Seated" +end + +function onPlatformStanding() + pose = "PlatformStanding" +end + +------------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------- + +function onSwimming(speed) + if speed > 1.00 then + local scale = 10.0 + playAnimation("swim", 0.4, Humanoid) + setAnimationSpeed(speed / scale) + pose = "Swimming" + else + playAnimation("swimidle", 0.4, Humanoid) + pose = "Standing" + end +end + +function animateTool() + if (toolAnim == "None") then + playToolAnimation("toolnone", toolTransitionTime, Humanoid, Enum.AnimationPriority.Idle) + return + end + + if (toolAnim == "Slash") then + playToolAnimation("toolslash", 0, Humanoid, Enum.AnimationPriority.Action) + return + end + + if (toolAnim == "Lunge") then + playToolAnimation("toollunge", 0, Humanoid, Enum.AnimationPriority.Action) + return + end +end + +function getToolAnim(tool) + for _, c in ipairs(tool:GetChildren()) do + if c.Name == "toolanim" and c.className == "StringValue" then + return c + end + end + return nil +end + +local lastTick = 0 + +function stepAnimate(currentTime) + local amplitude = 1 + local frequency = 1 + local deltaTime = currentTime - lastTick + lastTick = currentTime + + local climbFudge = 0 + local setAngles = false + + if (jumpAnimTime > 0) then + jumpAnimTime = jumpAnimTime - deltaTime + end + + if (pose == "FreeFall" and jumpAnimTime <= 0) then + playAnimation("fall", fallTransitionTime, Humanoid) + elseif (pose == "Seated") then + playAnimation("sit", 0.5, Humanoid) + return + elseif (pose == "Running") then + playAnimation("walk", 0.2, Humanoid) + elseif (pose == "Dead" or pose == "GettingUp" or pose == "FallingDown" or pose == "Seated" or pose == "PlatformStanding") then + stopAllAnimations() + amplitude = 0.1 + frequency = 1 + setAngles = true + end + + -- Tool Animation handling + local tool = Character:FindFirstChildOfClass("Tool") + if tool and tool:FindFirstChild("Handle") then + local animStringValueObject = getToolAnim(tool) + + if animStringValueObject then + toolAnim = animStringValueObject.Value + -- message recieved, delete StringValue + animStringValueObject.Parent = nil + toolAnimTime = currentTime + .3 + end + + if currentTime > toolAnimTime then + toolAnimTime = 0 + toolAnim = "None" + end + + animateTool() + else + stopToolAnimations() + toolAnim = "None" + toolAnimInstance = nil + toolAnimTime = 0 + end +end + +-- connect events +Humanoid.Died:connect(onDied) +Humanoid.Running:connect(onRunning) +Humanoid.Jumping:connect(onJumping) +Humanoid.Climbing:connect(onClimbing) +Humanoid.GettingUp:connect(onGettingUp) +Humanoid.FreeFalling:connect(onFreeFall) +Humanoid.FallingDown:connect(onFallingDown) +Humanoid.Seated:connect(onSeated) +Humanoid.PlatformStanding:connect(onPlatformStanding) +Humanoid.Swimming:connect(onSwimming) + +-- setup emote chat hook +game:GetService("Players").LocalPlayer.Chatted:connect(function(msg) + local emote = "" + if (string.sub(msg, 1, 3) == "/e ") then + emote = string.sub(msg, 4) + elseif (string.sub(msg, 1, 7) == "/emote ") then + emote = string.sub(msg, 8) + end + + if (pose == "Standing" and emoteNames[emote] ~= nil) then + playAnimation(emote, 0.1, Humanoid) + end +end) + + + +-- initialize to idle +playAnimation("idle", 0.1, Humanoid) +pose = "Standing" + +-- loop to handle timed state transitions and tool animations +while Character.Parent ~= nil do + local _, currentGameTime = wait(0.1) + stepAnimate(currentGameTime) +end + +]]> + + + + + cheer + + + + + + http://www.roblox.com/asset/?id=507770677 + CheerAnim + + + + + + + climb + + + + + + http://www.roblox.com/asset/?id=507765644 + ClimbAnim + + + + + + + dance + + + + + + http://www.roblox.com/asset/?id=507771019 + Animation1 + + + + + Weight + + 10 + + + + + + http://www.roblox.com/asset/?id=507771955 + Animation2 + + + + + Weight + + 10 + + + + + + http://www.roblox.com/asset/?id=507772104 + Animation3 + + + + + Weight + + 10 + + + + + + + dance2 + + + + + + http://www.roblox.com/asset/?id=507776043 + Animation1 + + + + + Weight + + 10 + + + + + + http://www.roblox.com/asset/?id=507776720 + Animation2 + + + + + Weight + + 10 + + + + + + http://www.roblox.com/asset/?id=507776879 + Animation3 + + + + + Weight + + 10 + + + + + + + dance3 + + + + + + http://www.roblox.com/asset/?id=507777268 + Animation1 + + + + + Weight + + 10 + + + + + + http://www.roblox.com/asset/?id=507777451 + Animation2 + + + + + Weight + + 10 + + + + + + http://www.roblox.com/asset/?id=507777623 + Animation3 + + + + + Weight + + 10 + + + + + + + fall + + + + + + http://www.roblox.com/asset/?id=507767968 + FallAnim + + + + + + + idle + + + + + + http://www.roblox.com/asset/?id=507766388 + Animation1 + + + + + Weight + + 9 + + + + + + http://www.roblox.com/asset/?id=507766666 + Animation2 + + + + + Weight + + 1 + + + + + + + jump + + + + + + http://www.roblox.com/asset/?id=507765000 + JumpAnim + + + + + + + laugh + + + + + + http://www.roblox.com/asset/?id=507770818 + LaughAnim + + + + + + + point + + + + + + http://www.roblox.com/asset/?id=507770453 + PointAnim + + + + + + + run + + + + + + http://www.roblox.com/asset/?id=507767714 + RunAnim + + + + + + + sit + + + + + + http://www.roblox.com/asset/?id=507768133 + SitAnim + + + + + + + swim + + + + + + http://www.roblox.com/asset/?id=507784897 + Swim + + + + + + + swimidle + + + + + + http://www.roblox.com/asset/?id=481825862 + SwimIdle + + + + + + + toollunge + + + + + + http://www.roblox.com/asset/?id=522638767 + ToolLungeAnim + + + + + + + toolnone + + + + + + http://www.roblox.com/asset/?id=507768375 + ToolNoneAnim + + + + + + + toolslash + + + + + + http://www.roblox.com/asset/?id=522635514 + ToolSlashAnim + + + + + + + walk + + + + + + http://www.roblox.com/asset/?id=540798782 + WalkAnim + + + + + + + wave + + + + + + http://www.roblox.com/asset/?id=507770239 + WaveAnim + + + + + + \ No newline at end of file diff --git a/2018/content/avatar/scripts/humanoidAnimateR15Scaled.rbxm b/2018/content/avatar/scripts/humanoidAnimateR15Scaled.rbxm new file mode 100644 index 0000000..8dcd53b Binary files /dev/null and b/2018/content/avatar/scripts/humanoidAnimateR15Scaled.rbxm differ diff --git a/2018/content/avatar/scripts/humanoidAnimateR15ScaledV2.rbxm b/2018/content/avatar/scripts/humanoidAnimateR15ScaledV2.rbxm new file mode 100644 index 0000000..7131b16 Binary files /dev/null and b/2018/content/avatar/scripts/humanoidAnimateR15ScaledV2.rbxm differ diff --git a/2018/content/avatar/scripts/humanoidHealthRegenScript.rbxmx b/2018/content/avatar/scripts/humanoidHealthRegenScript.rbxmx new file mode 100644 index 0000000..ece49f1 --- /dev/null +++ b/2018/content/avatar/scripts/humanoidHealthRegenScript.rbxmx @@ -0,0 +1,32 @@ + + null + nil + + + false + + Health + {EC3A881D-5F49-4644-A69D-FB60F2E59FF2} + + + + \ No newline at end of file diff --git a/2018/content/fonts/AccanthisADFStd-Regular.otf b/2018/content/fonts/AccanthisADFStd-Regular.otf new file mode 100644 index 0000000..b3d6f03 Binary files /dev/null and b/2018/content/fonts/AccanthisADFStd-Regular.otf differ diff --git a/2018/content/fonts/Balthazar-Regular.ttf b/2018/content/fonts/Balthazar-Regular.ttf new file mode 100644 index 0000000..fff2ff7 Binary files /dev/null and b/2018/content/fonts/Balthazar-Regular.ttf differ diff --git a/2018/content/fonts/ComicNeue-Angular-Bold.ttf b/2018/content/fonts/ComicNeue-Angular-Bold.ttf new file mode 100644 index 0000000..d70a258 Binary files /dev/null and b/2018/content/fonts/ComicNeue-Angular-Bold.ttf differ diff --git a/2018/content/fonts/Guru-Regular.otf b/2018/content/fonts/Guru-Regular.otf new file mode 100644 index 0000000..20d7398 Binary files /dev/null and b/2018/content/fonts/Guru-Regular.otf differ diff --git a/2018/content/fonts/HWYGOTH.ttf b/2018/content/fonts/HWYGOTH.ttf new file mode 100644 index 0000000..20ac3e2 Binary files /dev/null and b/2018/content/fonts/HWYGOTH.ttf differ diff --git a/2018/content/fonts/Inconsolata-Regular.ttf b/2018/content/fonts/Inconsolata-Regular.ttf new file mode 100644 index 0000000..bbc9647 Binary files /dev/null and b/2018/content/fonts/Inconsolata-Regular.ttf differ diff --git a/2018/content/fonts/PressStart2P-Regular.ttf b/2018/content/fonts/PressStart2P-Regular.ttf new file mode 100644 index 0000000..e659e95 Binary files /dev/null and b/2018/content/fonts/PressStart2P-Regular.ttf differ diff --git a/2018/content/fonts/RomanAntique.otf b/2018/content/fonts/RomanAntique.otf new file mode 100644 index 0000000..dac6f3d Binary files /dev/null and b/2018/content/fonts/RomanAntique.otf differ diff --git a/2018/content/fonts/SourceSansPro-Bold.ttf b/2018/content/fonts/SourceSansPro-Bold.ttf new file mode 100644 index 0000000..be46652 Binary files /dev/null and b/2018/content/fonts/SourceSansPro-Bold.ttf differ diff --git a/2018/content/fonts/SourceSansPro-It.ttf b/2018/content/fonts/SourceSansPro-It.ttf new file mode 100644 index 0000000..c689cd2 Binary files /dev/null and b/2018/content/fonts/SourceSansPro-It.ttf differ diff --git a/2018/content/fonts/SourceSansPro-Light.ttf b/2018/content/fonts/SourceSansPro-Light.ttf new file mode 100644 index 0000000..5094f90 Binary files /dev/null and b/2018/content/fonts/SourceSansPro-Light.ttf differ diff --git a/2018/content/fonts/SourceSansPro-Regular.ttf b/2018/content/fonts/SourceSansPro-Regular.ttf new file mode 100644 index 0000000..24962c7 Binary files /dev/null and b/2018/content/fonts/SourceSansPro-Regular.ttf differ diff --git a/2018/content/fonts/SourceSansPro-Semibold.ttf b/2018/content/fonts/SourceSansPro-Semibold.ttf new file mode 100644 index 0000000..96be817 Binary files /dev/null and b/2018/content/fonts/SourceSansPro-Semibold.ttf differ diff --git a/2018/content/fonts/arial.ttf b/2018/content/fonts/arial.ttf new file mode 100644 index 0000000..729da61 Binary files /dev/null and b/2018/content/fonts/arial.ttf differ diff --git a/2018/content/fonts/arialbd.ttf b/2018/content/fonts/arialbd.ttf new file mode 100644 index 0000000..aac564c Binary files /dev/null and b/2018/content/fonts/arialbd.ttf differ diff --git a/2018/content/fonts/gamecontrollerdb.txt b/2018/content/fonts/gamecontrollerdb.txt new file mode 100644 index 0000000..dd49836 --- /dev/null +++ b/2018/content/fonts/gamecontrollerdb.txt @@ -0,0 +1,89 @@ +# Windows - DINPUT +8f0e1200000000000000504944564944,Acme,platform:Windows,x:b2,a:b0,b:b1,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2, +341a3608000000000000504944564944,Afterglow PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +ffff0000000000000000504944564944,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows, +6d0416c2000000000000504944564944,Generic DirectInput Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +6d0419c2000000000000504944564944,Logitech F710 Gamepad,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows, +88880803000000000000504944564944,PS3 Controller,a:b2,b:b1,back:b8,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b9,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:b7,rightx:a3,righty:a4,start:b11,x:b0,y:b3,platform:Windows, +4c056802000000000000504944564944,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Windows, +25090500000000000000504944564944,PS3 DualShock,a:b2,b:b1,back:b9,dpdown:h0.8,dpleft:h0.4,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a2,righty:a3,start:b8,x:b0,y:b3,platform:Windows, +4c05c405000000000000504944564944,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Windows, +6d0418c2000000000000504944564944,Logitech RumblePad 2 USB,platform:Windows,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3, +36280100000000000000504944564944,OUYA Controller,platform:Windows,a:b0,b:b3,y:b2,x:b1,start:b14,guide:b15,leftstick:b6,rightstick:b7,leftshoulder:b4,rightshoulder:b5,dpup:b8,dpleft:b10,dpdown:b9,dpright:b11,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b12,righttrigger:b13, +4f0400b3000000000000504944564944,Thrustmaster Firestorm Dual Power,a:b0,b:b2,y:b3,x:b1,start:b10,guide:b8,back:b9,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Windows, +00f00300000000000000504944564944,RetroUSB.com RetroPad,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Windows, +00f0f100000000000000504944564944,RetroUSB.com Super RetroPort,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Windows, +28040140000000000000504944564944,GamePad Pro USB,platform:Windows,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,leftshoulder:b4,rightshoulder:b5,leftx:a0,lefty:a1,lefttrigger:b6,righttrigger:b7, +ff113133000000000000504944564944,SVEN X-PAD,platform:Windows,a:b2,b:b3,y:b1,x:b0,start:b5,back:b4,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b8,righttrigger:b9, +8f0e0300000000000000504944564944,Piranha xtreme,platform:Windows,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2, +8f0e0d31000000000000504944564944,Multilaser JS071 USB,platform:Windows,a:b1,b:b2,y:b3,x:b0,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7, +10080300000000000000504944564944,PS2 USB,platform:Windows,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a4,righty:a2,lefttrigger:b4,righttrigger:b5, +79000600000000000000504944564944,G-Shark GS-GP702,a:b2,b:b1,x:b3,y:b0,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b6,righttrigger:b7,platform:Windows, +4b12014d000000000000504944564944,NYKO AIRFLO,a:b0,b:b1,x:b2,y:b3,back:b8,guide:b10,start:b9,leftstick:a0,rightstick:a2,leftshoulder:a3,rightshoulder:b5,dpup:h0.1,dpdown:h0.0,dpleft:h0.8,dpright:h0.2,leftx:h0.6,lefty:h0.12,rightx:h0.9,righty:h0.4,lefttrigger:b6,righttrigger:b7,platform:Windows, +d6206dca000000000000504944564944,PowerA Pro Ex,a:b1,b:b2,x:b0,y:b3,back:b8,guide:b12,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.0,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows, +a3060cff000000000000504944564944,Saitek P2500,a:b2,b:b3,y:b1,x:b0,start:b4,guide:b10,back:b5,leftstick:b8,rightstick:b9,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,platform:Windows, +8f0e0300000000000000504944564944,Trust GTX 28,a:b2,b:b1,y:b0,x:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,platform:Windows, +4f0415b3000000000000504944564944,Thrustmaster Dual Analog 3.2,platform:Windows,x:b1,a:b0,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3, + +# OS X +0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Mac OS X, +6d0400000000000016c2000000000000,Logitech F310 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +6d0400000000000018c2000000000000,Logitech F510 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +6d040000000000001fc2000000000000,Logitech F710 Gamepad (XInput),a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +6d0400000000000019c2000000000000,Logitech Wireless Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Mac OS X, +4c050000000000006802000000000000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Mac OS X, +4c05000000000000c405000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,Platform:Mac OS X, +5e040000000000008e02000000000000,X360 Controller,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,platform:Mac OS X, +891600000000000000fd000000000000,Razer Onza Tournament,a:b0,b:b1,y:b3,x:b2,start:b8,guide:b10,back:b9,leftstick:b6,rightstick:b7,leftshoulder:b4,rightshoulder:b5,dpup:b11,dpleft:b13,dpdown:b12,dpright:b14,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Mac OS X, +4f0400000000000000b3000000000000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,y:b3,x:b1,start:b10,guide:b8,back:b9,leftstick:b11,rightstick:,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Mac OS X, +8f0e0000000000000300000000000000,Piranha xtreme,platform:Mac OS X,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2, +0d0f0000000000004d00000000000000,HORI Gem Pad 3,platform:Mac OS X,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7, +79000000000000000600000000000000,G-Shark GP-702,a:b2,b:b1,x:b3,y:b0,back:b8,start:b9,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b6,righttrigger:b7,platform:Mac OS X, +4f0400000000000015b3000000000000,Thrustmaster Dual Analog 3.2,platform:Mac OS X,x:b1,a:b0,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3, + +# Linux +0500000047532047616d657061640000,GameStop Gamepad,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux, +03000000ba2200002010000001010000,Jess Technology USB Game Controller,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,righttrigger:b7,rightx:a3,righty:a2,start:b9,x:b3,y:b0,platform:Linux, +030000006d04000019c2000010010000,Logitech Cordless RumblePad 2,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000006d0400001dc2000014400000,Logitech F310 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006d0400001ec2000020200000,Logitech F510 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000006d04000019c2000011010000,Logitech F710 Gamepad (DInput),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux, +030000006d0400001fc2000005030000,Logitech F710 Gamepad (XInput),a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000004c0500006802000011010000,PS3 Controller,a:b14,b:b13,back:b0,dpdown:b6,dpleft:b7,dpright:b5,dpup:b4,guide:b16,leftshoulder:b10,leftstick:b1,lefttrigger:b8,leftx:a0,lefty:a1,rightshoulder:b11,rightstick:b2,righttrigger:b9,rightx:a2,righty:a3,start:b3,x:b15,y:b12,platform:Linux, +030000004c050000c405000011010000,Sony DualShock 4,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:b7,platform:Linux, +03000000de280000ff11000001000000,Valve Streaming Gamepad,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e0400008e02000014010000,X360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e0400008e02000010010000,X360 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +030000005e0400001907000000010000,X360 Wireless Controller,a:b0,b:b1,back:b6,dpdown:b14,dpleft:b11,dpright:b12,dpup:b13,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,platform:Linux, +03000000100800000100000010010000,Twin USB PS2 Adapter,a:b2,b:b1,y:b0,x:b3,start:b9,guide:,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a2,lefttrigger:b4,righttrigger:b5,platform:Linux, +03000000a306000023f6000011010000,Saitek Cyborg V.1 Game Pad,a:b1,b:b2,y:b3,x:b0,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a4,lefttrigger:b6,righttrigger:b7,platform:Linux, +030000004f04000020b3000010010000,Thrustmaster 2 in 1 DT,a:b0,b:b2,y:b3,x:b1,start:b9,guide:,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Linux, +030000004f04000023b3000000010000,Thrustmaster Dual Trigger 3-in-1,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a5, +030000008f0e00000300000010010000,GreenAsia Inc. USB Joystick ,platform:Linux,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b6,lefttrigger:b4,rightshoulder:b7,righttrigger:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2, +030000008f0e00001200000010010000,GreenAsia Inc. USB Joystick ,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b5,rightshoulder:b6,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a2, +030000005e0400009102000007010000,X360 Wireless Controller,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:b13,dpleft:b11,dpdown:b14,dpright:b12,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux, +030000006d04000016c2000010010000,Logitech Logitech Dual Action,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3, +03000000260900008888000000010000,GameCube {WiseGroup USB box},a:b0,b:b2,y:b3,x:b1,start:b7,leftshoulder:,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,rightstick:,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,platform:Linux, +030000006d04000011c2000010010000,Logitech WingMan Cordless RumblePad,a:b0,b:b1,y:b4,x:b3,start:b8,guide:b5,back:b2,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:b9,righttrigger:b10,platform:Linux, +030000006d04000018c2000010010000,Logitech Logitech RumblePad 2 USB,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3, +05000000d6200000ad0d000001000000,Moga Pro,platform:Linux,a:b0,b:b1,y:b3,x:b2,start:b6,leftstick:b7,rightstick:b8,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a5,righttrigger:a4, +030000004f04000009d0000000010000,Thrustmaster Run N Drive Wireless PS3,platform:Linux,a:b1,b:b2,x:b0,y:b3,start:b9,guide:b12,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7, +030000004f04000008d0000000010000,Thrustmaster Run N Drive Wireless,platform:Linux,a:b1,b:b2,x:b0,y:b3,start:b9,back:b8,leftstick:b10,rightstick:b11,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a5,lefttrigger:b6,righttrigger:b7, +0300000000f000000300000000010000,RetroUSB.com RetroPad,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Linux, +0300000000f00000f100000000010000,RetroUSB.com Super RetroPort,a:b1,b:b5,x:b0,y:b4,back:b2,start:b3,leftshoulder:b6,rightshoulder:b7,leftx:a0,lefty:a1,platform:Linux, +030000006f0e00001f01000000010000,Generic X-Box pad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4, +03000000280400000140000000010000,Gravis GamePad Pro USB ,platform:Linux,x:b0,a:b1,b:b2,y:b3,back:b8,start:b9,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftx:a0,lefty:a1, +030000005e0400008902000021010000,Microsoft X-Box pad v2 (US),platform:Linux,x:b3,a:b0,b:b1,y:b4,back:b6,start:b7,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b5,lefttrigger:a2,rightshoulder:b2,righttrigger:a5,leftstick:b8,rightstick:b9,leftx:a0,lefty:a1,rightx:a3,righty:a4, +030000006f0e00001e01000011010000,Rock Candy Gamepad for PS3,platform:Linux,a:b1,b:b2,x:b0,y:b3,back:b8,start:b9,guide:b12,leftshoulder:b4,rightshoulder:b5,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b6,righttrigger:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2, +03000000250900000500000000010000,Sony PS2 pad with SmartJoy adapter,platform:Linux,a:b2,b:b1,y:b0,x:b3,start:b8,back:b9,leftstick:b10,rightstick:b11,leftshoulder:b6,rightshoulder:b7,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b4,righttrigger:b5, +030000008916000000fd000024010000,Razer Onza Tournament,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:b13,dpleft:b11,dpdown:b14,dpright:b12,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux, +030000004f04000000b3000010010000,Thrustmaster Firestorm Dual Power,a:b0,b:b2,y:b3,x:b1,start:b10,guide:b8,back:b9,leftstick:b11,rightstick:b12,leftshoulder:b4,rightshoulder:b6,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b5,righttrigger:b7,platform:Linux, +03000000ad1b000001f5000033050000,Hori Pad EX Turbo 2,a:b0,b:b1,y:b3,x:b2,start:b7,guide:b8,back:b6,leftstick:b9,rightstick:b10,leftshoulder:b4,rightshoulder:b5,dpup:h0.1,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,leftx:a0,lefty:a1,rightx:a3,righty:a4,lefttrigger:a2,righttrigger:a5,platform:Linux, +050000004c050000c405000000010000,PS4 Controller (Bluetooth),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,platform:Linux, +060000004c0500006802000000010000,PS3 Controller (Bluetooth),a:b14,b:b13,y:b12,x:b15,start:b3,guide:b16,back:b0,leftstick:b1,rightstick:b2,leftshoulder:b10,rightshoulder:b11,dpup:b4,dpleft:b7,dpdown:b6,dpright:b5,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b8,righttrigger:b9,platform:Linux, +03000000790000000600000010010000,DragonRise Inc. Generic USB Joystick ,platform:Linux,x:b3,a:b2,b:b1,y:b0,back:b8,start:b9,dpleft:h0.8,dpdown:h0.4,dpright:h0.2,dpup:h0.1,leftshoulder:b4,lefttrigger:b6,rightshoulder:b5,righttrigger:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a3,righty:a4, +03000000666600000488000000010000,Super Joy Box 5 Pro,platform:Linux,a:b2,b:b1,x:b3,y:b0,back:b9,start:b8,leftshoulder:b6,rightshoulder:b7,leftstick:b10,rightstick:b11,leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:b4,righttrigger:b5,dpup:b12,dpleft:b15,dpdown:b14,dpright:b13, +05000000362800000100000002010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,platform:Linux,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2, +05000000362800000100000003010000,OUYA Game Controller,a:b0,b:b3,dpdown:b9,dpleft:b10,dpright:b11,dpup:b8,guide:b14,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,platform:Linux,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,x:b1,y:b2, +030000008916000001fd000024010000,Razer Onza Classic Edition,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:b11,dpdown:b14,dpright:b12,dpup:b13,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4, +030000005e040000d102000001010000,Microsoft X-Box One pad,platform:Linux,x:b2,a:b0,b:b1,y:b3,back:b6,guide:b8,start:b7,dpleft:h0.8,dpdown:h0.0,dpdown:h0.4,dpright:h0.0,dpright:h0.2,dpup:h0.0,dpup:h0.1,leftshoulder:h0.0,leftshoulder:b4,lefttrigger:a2,rightshoulder:b5,righttrigger:a5,leftstick:b9,rightstick:b10,leftx:a0,lefty:a1,rightx:a3,righty:a4, \ No newline at end of file diff --git a/2018/content/fonts/humanoidSoundNewLocal.rbxmx b/2018/content/fonts/humanoidSoundNewLocal.rbxmx new file mode 100644 index 0000000..d0fb982 --- /dev/null +++ b/2018/content/fonts/humanoidSoundNewLocal.rbxmx @@ -0,0 +1,191 @@ + + null + nil + + + false + + Sound + + + + + false + + LocalSound + 0.1) then + local vol = math.min(1.0, math.max(0.0, (fallSpeed - 50) / 110)) + sLanding.Volume = vol + sLanding:Play() + fallSpeed = 0 + end + if speed>0.5 then + sRunning:Resume() + sRunning.Pitch = speed / 8.0 + else + sRunning:Pause() + end + prevState = "Run" +end + +function onSwimming(speed) + if (prevState ~= "Swim" and speed > 0.1) then + local volume = math.min(1.0, speed / 350) + sSplash.Volume = volume + sSplash:Play() + prevState = "Swim" + end + sClimbing:Stop() + sRunning:Stop() + sSwimming.Pitch = 1.6 + sSwimming:Resume() +end + +function onClimbing(speed) + sRunning:Stop() + sSwimming:Stop() + if speed>0.01 then + sClimbing:Resume() + sClimbing.Pitch = speed / 5.5 + else + sClimbing:Pause() + end + prevState = "Climb" +end +-- connect up + +function stopLoopedSounds() + sRunning:Stop() + sClimbing:Stop() + sSwimming:Stop() +end + +Humanoid.Died:connect(onDied) +Humanoid.Running:connect(onRunning) +Humanoid.Swimming:connect(onSwimming) +Humanoid.Climbing:connect(onClimbing) +Humanoid.Jumping:connect(function(state) onStateNoStop(state, sJumping) prevState = "Jump" end) +Humanoid.GettingUp:connect(function(state) stopLoopedSounds() onStateNoStop(state, sGettingUp) prevState = "GetUp" end) +Humanoid.FreeFalling:connect(function(state) stopLoopedSounds() onStateFall(state, sFreeFalling) prevState = "FreeFall" end) +Humanoid.FallingDown:connect(function(state) stopLoopedSounds() end) +Humanoid.StateChanged:connect(function(old, new) + if not (new.Name == "Dead" or + new.Name == "Running" or + new.Name == "RunningNoPhysics" or + new.Name == "Swimming" or + new.Name == "Jumping" or + new.Name == "GettingUp" or + new.Name == "Freefall" or + new.Name == "FallingDown") then + stopLoopedSounds() + end +end) + +]]> + + + + \ No newline at end of file diff --git a/2018/content/fonts/zekton_rg.ttf b/2018/content/fonts/zekton_rg.ttf new file mode 100644 index 0000000..8ad2dd1 Binary files /dev/null and b/2018/content/fonts/zekton_rg.ttf differ diff --git a/2018/content/models/AvatarContextMenu/AvatarContextArrow.rbxm b/2018/content/models/AvatarContextMenu/AvatarContextArrow.rbxm new file mode 100644 index 0000000..f8cc772 Binary files /dev/null and b/2018/content/models/AvatarContextMenu/AvatarContextArrow.rbxm differ diff --git a/2018/content/sky/moon.jpg b/2018/content/sky/moon.jpg new file mode 100644 index 0000000..247b6cd Binary files /dev/null and b/2018/content/sky/moon.jpg differ diff --git a/2018/content/sky/sun.jpg b/2018/content/sky/sun.jpg new file mode 100644 index 0000000..12b3829 Binary files /dev/null and b/2018/content/sky/sun.jpg differ diff --git a/2018/content/sky/sun3.png b/2018/content/sky/sun3.png new file mode 100644 index 0000000..c815c3e Binary files /dev/null and b/2018/content/sky/sun3.png differ diff --git a/2018/content/sounds/action_falling.mp3 b/2018/content/sounds/action_falling.mp3 new file mode 100644 index 0000000..6408717 Binary files /dev/null and b/2018/content/sounds/action_falling.mp3 differ diff --git a/2018/content/sounds/action_footsteps_plastic.mp3 b/2018/content/sounds/action_footsteps_plastic.mp3 new file mode 100644 index 0000000..6804420 Binary files /dev/null and b/2018/content/sounds/action_footsteps_plastic.mp3 differ diff --git a/2018/content/sounds/action_get_up.mp3 b/2018/content/sounds/action_get_up.mp3 new file mode 100644 index 0000000..ababd77 Binary files /dev/null and b/2018/content/sounds/action_get_up.mp3 differ diff --git a/2018/content/sounds/action_jump.mp3 b/2018/content/sounds/action_jump.mp3 new file mode 100644 index 0000000..7159074 Binary files /dev/null and b/2018/content/sounds/action_jump.mp3 differ diff --git a/2018/content/sounds/action_jump_land.mp3 b/2018/content/sounds/action_jump_land.mp3 new file mode 100644 index 0000000..3d68ce1 Binary files /dev/null and b/2018/content/sounds/action_jump_land.mp3 differ diff --git a/2018/content/sounds/action_swim.mp3 b/2018/content/sounds/action_swim.mp3 new file mode 100644 index 0000000..95dd2d5 Binary files /dev/null and b/2018/content/sounds/action_swim.mp3 differ diff --git a/2018/content/sounds/bass.wav b/2018/content/sounds/bass.wav new file mode 100644 index 0000000..5f4b791 Binary files /dev/null and b/2018/content/sounds/bass.wav differ diff --git a/2018/content/sounds/impact_explosion_03.mp3 b/2018/content/sounds/impact_explosion_03.mp3 new file mode 100644 index 0000000..4501c83 Binary files /dev/null and b/2018/content/sounds/impact_explosion_03.mp3 differ diff --git a/2018/content/sounds/impact_water.mp3 b/2018/content/sounds/impact_water.mp3 new file mode 100644 index 0000000..741862b Binary files /dev/null and b/2018/content/sounds/impact_water.mp3 differ diff --git a/2018/content/sounds/snap.mp3 b/2018/content/sounds/snap.mp3 new file mode 100644 index 0000000..8dd8d5a Binary files /dev/null and b/2018/content/sounds/snap.mp3 differ diff --git a/2018/content/sounds/uuhhh.mp3 b/2018/content/sounds/uuhhh.mp3 new file mode 100644 index 0000000..81b3565 Binary files /dev/null and b/2018/content/sounds/uuhhh.mp3 differ diff --git a/2018/content/textures/AnchorCursor.png b/2018/content/textures/AnchorCursor.png new file mode 100644 index 0000000..cb00a6a Binary files /dev/null and b/2018/content/textures/AnchorCursor.png differ diff --git a/2018/content/textures/AnimationEditor/Checkmark.png b/2018/content/textures/AnimationEditor/Checkmark.png new file mode 100644 index 0000000..2d7a684 Binary files /dev/null and b/2018/content/textures/AnimationEditor/Checkmark.png differ diff --git a/2018/content/textures/AnimationEditor/Close.png b/2018/content/textures/AnimationEditor/Close.png new file mode 100644 index 0000000..2281cae Binary files /dev/null and b/2018/content/textures/AnimationEditor/Close.png differ diff --git a/2018/content/textures/AnimationEditor/RoundedBackground.png b/2018/content/textures/AnimationEditor/RoundedBackground.png new file mode 100644 index 0000000..602e90f Binary files /dev/null and b/2018/content/textures/AnimationEditor/RoundedBackground.png differ diff --git a/2018/content/textures/AnimationEditor/RoundedBorder.png b/2018/content/textures/AnimationEditor/RoundedBorder.png new file mode 100644 index 0000000..8335459 Binary files /dev/null and b/2018/content/textures/AnimationEditor/RoundedBorder.png differ diff --git a/2018/content/textures/AnimationEditor/ScrollbarBottom.png b/2018/content/textures/AnimationEditor/ScrollbarBottom.png new file mode 100644 index 0000000..f84d082 Binary files /dev/null and b/2018/content/textures/AnimationEditor/ScrollbarBottom.png differ diff --git a/2018/content/textures/AnimationEditor/ScrollbarMiddle.png b/2018/content/textures/AnimationEditor/ScrollbarMiddle.png new file mode 100644 index 0000000..0e90165 Binary files /dev/null and b/2018/content/textures/AnimationEditor/ScrollbarMiddle.png differ diff --git a/2018/content/textures/AnimationEditor/ScrollbarTop.png b/2018/content/textures/AnimationEditor/ScrollbarTop.png new file mode 100644 index 0000000..beb8d14 Binary files /dev/null and b/2018/content/textures/AnimationEditor/ScrollbarTop.png differ diff --git a/2018/content/textures/AnimationEditor/button_control_end.png b/2018/content/textures/AnimationEditor/button_control_end.png new file mode 100644 index 0000000..9493b62 Binary files /dev/null and b/2018/content/textures/AnimationEditor/button_control_end.png differ diff --git a/2018/content/textures/AnimationEditor/button_control_next.png b/2018/content/textures/AnimationEditor/button_control_next.png new file mode 100644 index 0000000..e498efc Binary files /dev/null and b/2018/content/textures/AnimationEditor/button_control_next.png differ diff --git a/2018/content/textures/AnimationEditor/button_control_play.png b/2018/content/textures/AnimationEditor/button_control_play.png new file mode 100644 index 0000000..7e13020 Binary files /dev/null and b/2018/content/textures/AnimationEditor/button_control_play.png differ diff --git a/2018/content/textures/AnimationEditor/button_control_previous.png b/2018/content/textures/AnimationEditor/button_control_previous.png new file mode 100644 index 0000000..95ad3cf Binary files /dev/null and b/2018/content/textures/AnimationEditor/button_control_previous.png differ diff --git a/2018/content/textures/AnimationEditor/button_control_start.png b/2018/content/textures/AnimationEditor/button_control_start.png new file mode 100644 index 0000000..2a13172 Binary files /dev/null and b/2018/content/textures/AnimationEditor/button_control_start.png differ diff --git a/2018/content/textures/AnimationEditor/button_hierarchy_closed.png b/2018/content/textures/AnimationEditor/button_hierarchy_closed.png new file mode 100644 index 0000000..2a70e31 Binary files /dev/null and b/2018/content/textures/AnimationEditor/button_hierarchy_closed.png differ diff --git a/2018/content/textures/AnimationEditor/button_hierarchy_opened.png b/2018/content/textures/AnimationEditor/button_hierarchy_opened.png new file mode 100644 index 0000000..c2d1e6d Binary files /dev/null and b/2018/content/textures/AnimationEditor/button_hierarchy_opened.png differ diff --git a/2018/content/textures/AnimationEditor/button_lock.png b/2018/content/textures/AnimationEditor/button_lock.png new file mode 100644 index 0000000..cf9ca95 Binary files /dev/null and b/2018/content/textures/AnimationEditor/button_lock.png differ diff --git a/2018/content/textures/AnimationEditor/button_loop.png b/2018/content/textures/AnimationEditor/button_loop.png new file mode 100644 index 0000000..e585d2f Binary files /dev/null and b/2018/content/textures/AnimationEditor/button_loop.png differ diff --git a/2018/content/textures/AnimationEditor/button_pause_white@2x.png b/2018/content/textures/AnimationEditor/button_pause_white@2x.png new file mode 100644 index 0000000..7215f9b Binary files /dev/null and b/2018/content/textures/AnimationEditor/button_pause_white@2x.png differ diff --git a/2018/content/textures/AnimationEditor/button_popup_close.png b/2018/content/textures/AnimationEditor/button_popup_close.png new file mode 100644 index 0000000..3511f7c Binary files /dev/null and b/2018/content/textures/AnimationEditor/button_popup_close.png differ diff --git a/2018/content/textures/AnimationEditor/button_radio_background.png b/2018/content/textures/AnimationEditor/button_radio_background.png new file mode 100644 index 0000000..1f15a29 Binary files /dev/null and b/2018/content/textures/AnimationEditor/button_radio_background.png differ diff --git a/2018/content/textures/AnimationEditor/button_radio_default.png b/2018/content/textures/AnimationEditor/button_radio_default.png new file mode 100644 index 0000000..5c54fd1 Binary files /dev/null and b/2018/content/textures/AnimationEditor/button_radio_default.png differ diff --git a/2018/content/textures/AnimationEditor/button_radio_innercircle.png b/2018/content/textures/AnimationEditor/button_radio_innercircle.png new file mode 100644 index 0000000..b6a9efe Binary files /dev/null and b/2018/content/textures/AnimationEditor/button_radio_innercircle.png differ diff --git a/2018/content/textures/AnimationEditor/button_zoom.png b/2018/content/textures/AnimationEditor/button_zoom.png new file mode 100644 index 0000000..966d410 Binary files /dev/null and b/2018/content/textures/AnimationEditor/button_zoom.png differ diff --git a/2018/content/textures/AnimationEditor/button_zoom_default_left.png b/2018/content/textures/AnimationEditor/button_zoom_default_left.png new file mode 100644 index 0000000..e371819 Binary files /dev/null and b/2018/content/textures/AnimationEditor/button_zoom_default_left.png differ diff --git a/2018/content/textures/AnimationEditor/button_zoom_default_left@2x.png b/2018/content/textures/AnimationEditor/button_zoom_default_left@2x.png new file mode 100644 index 0000000..45c7cc7 Binary files /dev/null and b/2018/content/textures/AnimationEditor/button_zoom_default_left@2x.png differ diff --git a/2018/content/textures/AnimationEditor/button_zoom_default_right.png b/2018/content/textures/AnimationEditor/button_zoom_default_right.png new file mode 100644 index 0000000..e371819 Binary files /dev/null and b/2018/content/textures/AnimationEditor/button_zoom_default_right.png differ diff --git a/2018/content/textures/AnimationEditor/button_zoom_default_right@2x.png b/2018/content/textures/AnimationEditor/button_zoom_default_right@2x.png new file mode 100644 index 0000000..45c7cc7 Binary files /dev/null and b/2018/content/textures/AnimationEditor/button_zoom_default_right@2x.png differ diff --git a/2018/content/textures/AnimationEditor/button_zoom_hoverpressed_left.png b/2018/content/textures/AnimationEditor/button_zoom_hoverpressed_left.png new file mode 100644 index 0000000..4d19d86 Binary files /dev/null and b/2018/content/textures/AnimationEditor/button_zoom_hoverpressed_left.png differ diff --git a/2018/content/textures/AnimationEditor/button_zoom_hoverpressed_left@2x.png b/2018/content/textures/AnimationEditor/button_zoom_hoverpressed_left@2x.png new file mode 100644 index 0000000..3b2f615 Binary files /dev/null and b/2018/content/textures/AnimationEditor/button_zoom_hoverpressed_left@2x.png differ diff --git a/2018/content/textures/AnimationEditor/button_zoom_hoverpressed_right.png b/2018/content/textures/AnimationEditor/button_zoom_hoverpressed_right.png new file mode 100644 index 0000000..4d19d86 Binary files /dev/null and b/2018/content/textures/AnimationEditor/button_zoom_hoverpressed_right.png differ diff --git a/2018/content/textures/AnimationEditor/button_zoom_hoverpressed_right@2x.png b/2018/content/textures/AnimationEditor/button_zoom_hoverpressed_right@2x.png new file mode 100644 index 0000000..3b2f615 Binary files /dev/null and b/2018/content/textures/AnimationEditor/button_zoom_hoverpressed_right@2x.png differ diff --git a/2018/content/textures/AnimationEditor/ic-checkbox-active.png b/2018/content/textures/AnimationEditor/ic-checkbox-active.png new file mode 100644 index 0000000..b897b38 Binary files /dev/null and b/2018/content/textures/AnimationEditor/ic-checkbox-active.png differ diff --git a/2018/content/textures/AnimationEditor/ic-checkbox-off.png b/2018/content/textures/AnimationEditor/ic-checkbox-off.png new file mode 100644 index 0000000..09fd802 Binary files /dev/null and b/2018/content/textures/AnimationEditor/ic-checkbox-off.png differ diff --git a/2018/content/textures/AnimationEditor/icon_checkmark.png b/2018/content/textures/AnimationEditor/icon_checkmark.png new file mode 100644 index 0000000..a61f1f2 Binary files /dev/null and b/2018/content/textures/AnimationEditor/icon_checkmark.png differ diff --git a/2018/content/textures/AnimationEditor/icon_close.png b/2018/content/textures/AnimationEditor/icon_close.png new file mode 100644 index 0000000..04e03cf Binary files /dev/null and b/2018/content/textures/AnimationEditor/icon_close.png differ diff --git a/2018/content/textures/AnimationEditor/icon_dark_warning.png b/2018/content/textures/AnimationEditor/icon_dark_warning.png new file mode 100644 index 0000000..c8385d3 Binary files /dev/null and b/2018/content/textures/AnimationEditor/icon_dark_warning.png differ diff --git a/2018/content/textures/AnimationEditor/icon_delete.png b/2018/content/textures/AnimationEditor/icon_delete.png new file mode 100644 index 0000000..f643c9b Binary files /dev/null and b/2018/content/textures/AnimationEditor/icon_delete.png differ diff --git a/2018/content/textures/AnimationEditor/icon_delete_disabled.png b/2018/content/textures/AnimationEditor/icon_delete_disabled.png new file mode 100644 index 0000000..8eac738 Binary files /dev/null and b/2018/content/textures/AnimationEditor/icon_delete_disabled.png differ diff --git a/2018/content/textures/AnimationEditor/icon_error.png b/2018/content/textures/AnimationEditor/icon_error.png new file mode 100644 index 0000000..fe8e0de Binary files /dev/null and b/2018/content/textures/AnimationEditor/icon_error.png differ diff --git a/2018/content/textures/AnimationEditor/icon_hierarchy_end_white.png b/2018/content/textures/AnimationEditor/icon_hierarchy_end_white.png new file mode 100644 index 0000000..4b9fc99 Binary files /dev/null and b/2018/content/textures/AnimationEditor/icon_hierarchy_end_white.png differ diff --git a/2018/content/textures/AnimationEditor/icon_keyIndicator.png b/2018/content/textures/AnimationEditor/icon_keyIndicator.png new file mode 100644 index 0000000..9d92ac4 Binary files /dev/null and b/2018/content/textures/AnimationEditor/icon_keyIndicator.png differ diff --git a/2018/content/textures/AnimationEditor/icon_keyIndicator_selected.png b/2018/content/textures/AnimationEditor/icon_keyIndicator_selected.png new file mode 100644 index 0000000..ed16d3c Binary files /dev/null and b/2018/content/textures/AnimationEditor/icon_keyIndicator_selected.png differ diff --git a/2018/content/textures/AnimationEditor/icon_pin.png b/2018/content/textures/AnimationEditor/icon_pin.png new file mode 100644 index 0000000..523ed1e Binary files /dev/null and b/2018/content/textures/AnimationEditor/icon_pin.png differ diff --git a/2018/content/textures/AnimationEditor/icon_warning.png b/2018/content/textures/AnimationEditor/icon_warning.png new file mode 100644 index 0000000..a563e29 Binary files /dev/null and b/2018/content/textures/AnimationEditor/icon_warning.png differ diff --git a/2018/content/textures/AnimationEditor/icon_warning_ik.png b/2018/content/textures/AnimationEditor/icon_warning_ik.png new file mode 100644 index 0000000..67c98b2 Binary files /dev/null and b/2018/content/textures/AnimationEditor/icon_warning_ik.png differ diff --git a/2018/content/textures/AnimationEditor/icon_whitetriangle_down.png b/2018/content/textures/AnimationEditor/icon_whitetriangle_down.png new file mode 100644 index 0000000..09c5db8 Binary files /dev/null and b/2018/content/textures/AnimationEditor/icon_whitetriangle_down.png differ diff --git a/2018/content/textures/AnimationEditor/icon_whitetriangle_up.png b/2018/content/textures/AnimationEditor/icon_whitetriangle_up.png new file mode 100644 index 0000000..5bdc664 Binary files /dev/null and b/2018/content/textures/AnimationEditor/icon_whitetriangle_up.png differ diff --git a/2018/content/textures/AnimationEditor/image_keyframe_bounce_selected.png b/2018/content/textures/AnimationEditor/image_keyframe_bounce_selected.png new file mode 100644 index 0000000..6e8863f Binary files /dev/null and b/2018/content/textures/AnimationEditor/image_keyframe_bounce_selected.png differ diff --git a/2018/content/textures/AnimationEditor/image_keyframe_bounce_unselected.png b/2018/content/textures/AnimationEditor/image_keyframe_bounce_unselected.png new file mode 100644 index 0000000..391c175 Binary files /dev/null and b/2018/content/textures/AnimationEditor/image_keyframe_bounce_unselected.png differ diff --git a/2018/content/textures/AnimationEditor/image_keyframe_constant_selected.png b/2018/content/textures/AnimationEditor/image_keyframe_constant_selected.png new file mode 100644 index 0000000..5d68420 Binary files /dev/null and b/2018/content/textures/AnimationEditor/image_keyframe_constant_selected.png differ diff --git a/2018/content/textures/AnimationEditor/image_keyframe_constant_unselected.png b/2018/content/textures/AnimationEditor/image_keyframe_constant_unselected.png new file mode 100644 index 0000000..1c976e6 Binary files /dev/null and b/2018/content/textures/AnimationEditor/image_keyframe_constant_unselected.png differ diff --git a/2018/content/textures/AnimationEditor/image_keyframe_cubic_selected.png b/2018/content/textures/AnimationEditor/image_keyframe_cubic_selected.png new file mode 100644 index 0000000..67a63a0 Binary files /dev/null and b/2018/content/textures/AnimationEditor/image_keyframe_cubic_selected.png differ diff --git a/2018/content/textures/AnimationEditor/image_keyframe_cubic_unselected.png b/2018/content/textures/AnimationEditor/image_keyframe_cubic_unselected.png new file mode 100644 index 0000000..2a9d7db Binary files /dev/null and b/2018/content/textures/AnimationEditor/image_keyframe_cubic_unselected.png differ diff --git a/2018/content/textures/AnimationEditor/image_keyframe_elastic_selected.png b/2018/content/textures/AnimationEditor/image_keyframe_elastic_selected.png new file mode 100644 index 0000000..7216182 Binary files /dev/null and b/2018/content/textures/AnimationEditor/image_keyframe_elastic_selected.png differ diff --git a/2018/content/textures/AnimationEditor/image_keyframe_elastic_unselected.png b/2018/content/textures/AnimationEditor/image_keyframe_elastic_unselected.png new file mode 100644 index 0000000..e56ad88 Binary files /dev/null and b/2018/content/textures/AnimationEditor/image_keyframe_elastic_unselected.png differ diff --git a/2018/content/textures/AnimationEditor/image_keyframe_linear_selected.png b/2018/content/textures/AnimationEditor/image_keyframe_linear_selected.png new file mode 100644 index 0000000..3d4d969 Binary files /dev/null and b/2018/content/textures/AnimationEditor/image_keyframe_linear_selected.png differ diff --git a/2018/content/textures/AnimationEditor/image_keyframe_linear_unselected.png b/2018/content/textures/AnimationEditor/image_keyframe_linear_unselected.png new file mode 100644 index 0000000..3f3709c Binary files /dev/null and b/2018/content/textures/AnimationEditor/image_keyframe_linear_unselected.png differ diff --git a/2018/content/textures/AnimationEditor/image_scrollbar_vertical_bot.png b/2018/content/textures/AnimationEditor/image_scrollbar_vertical_bot.png new file mode 100644 index 0000000..b419435 Binary files /dev/null and b/2018/content/textures/AnimationEditor/image_scrollbar_vertical_bot.png differ diff --git a/2018/content/textures/AnimationEditor/image_scrollbar_vertical_mid.png b/2018/content/textures/AnimationEditor/image_scrollbar_vertical_mid.png new file mode 100644 index 0000000..56558a3 Binary files /dev/null and b/2018/content/textures/AnimationEditor/image_scrollbar_vertical_mid.png differ diff --git a/2018/content/textures/AnimationEditor/image_scrollbar_vertical_top.png b/2018/content/textures/AnimationEditor/image_scrollbar_vertical_top.png new file mode 100644 index 0000000..e0437c5 Binary files /dev/null and b/2018/content/textures/AnimationEditor/image_scrollbar_vertical_top.png differ diff --git a/2018/content/textures/AnimationEditor/img_dark_scalebar_arrows.png b/2018/content/textures/AnimationEditor/img_dark_scalebar_arrows.png new file mode 100644 index 0000000..a5b5527 Binary files /dev/null and b/2018/content/textures/AnimationEditor/img_dark_scalebar_arrows.png differ diff --git a/2018/content/textures/AnimationEditor/img_dark_scalebar_bar.png b/2018/content/textures/AnimationEditor/img_dark_scalebar_bar.png new file mode 100644 index 0000000..b5627c7 Binary files /dev/null and b/2018/content/textures/AnimationEditor/img_dark_scalebar_bar.png differ diff --git a/2018/content/textures/AnimationEditor/img_dark_scrubberhead.png b/2018/content/textures/AnimationEditor/img_dark_scrubberhead.png new file mode 100644 index 0000000..1d4abcb Binary files /dev/null and b/2018/content/textures/AnimationEditor/img_dark_scrubberhead.png differ diff --git a/2018/content/textures/AnimationEditor/img_dark_timetag_bg.png b/2018/content/textures/AnimationEditor/img_dark_timetag_bg.png new file mode 100644 index 0000000..f4b0ecb Binary files /dev/null and b/2018/content/textures/AnimationEditor/img_dark_timetag_bg.png differ diff --git a/2018/content/textures/AnimationEditor/img_forwardslash.png b/2018/content/textures/AnimationEditor/img_forwardslash.png new file mode 100644 index 0000000..ebe9092 Binary files /dev/null and b/2018/content/textures/AnimationEditor/img_forwardslash.png differ diff --git a/2018/content/textures/AnimationEditor/img_key_border.png b/2018/content/textures/AnimationEditor/img_key_border.png new file mode 100644 index 0000000..bac1fe3 Binary files /dev/null and b/2018/content/textures/AnimationEditor/img_key_border.png differ diff --git a/2018/content/textures/AnimationEditor/img_key_indicator_border.png b/2018/content/textures/AnimationEditor/img_key_indicator_border.png new file mode 100644 index 0000000..bb35719 Binary files /dev/null and b/2018/content/textures/AnimationEditor/img_key_indicator_border.png differ diff --git a/2018/content/textures/AnimationEditor/img_key_indicator_inner.png b/2018/content/textures/AnimationEditor/img_key_indicator_inner.png new file mode 100644 index 0000000..10b29f5 Binary files /dev/null and b/2018/content/textures/AnimationEditor/img_key_indicator_inner.png differ diff --git a/2018/content/textures/AnimationEditor/img_key_indicator_selected_border.png b/2018/content/textures/AnimationEditor/img_key_indicator_selected_border.png new file mode 100644 index 0000000..309841e Binary files /dev/null and b/2018/content/textures/AnimationEditor/img_key_indicator_selected_border.png differ diff --git a/2018/content/textures/AnimationEditor/img_key_indicator_selected_inner.png b/2018/content/textures/AnimationEditor/img_key_indicator_selected_inner.png new file mode 100644 index 0000000..10b29f5 Binary files /dev/null and b/2018/content/textures/AnimationEditor/img_key_indicator_selected_inner.png differ diff --git a/2018/content/textures/AnimationEditor/img_key_inner.png b/2018/content/textures/AnimationEditor/img_key_inner.png new file mode 100644 index 0000000..c281f85 Binary files /dev/null and b/2018/content/textures/AnimationEditor/img_key_inner.png differ diff --git a/2018/content/textures/AnimationEditor/img_key_selected_border.png b/2018/content/textures/AnimationEditor/img_key_selected_border.png new file mode 100644 index 0000000..84868ec Binary files /dev/null and b/2018/content/textures/AnimationEditor/img_key_selected_border.png differ diff --git a/2018/content/textures/AnimationEditor/img_key_selected_inner.png b/2018/content/textures/AnimationEditor/img_key_selected_inner.png new file mode 100644 index 0000000..03fd465 Binary files /dev/null and b/2018/content/textures/AnimationEditor/img_key_selected_inner.png differ diff --git a/2018/content/textures/AnimationEditor/img_scalebar_arrows.png b/2018/content/textures/AnimationEditor/img_scalebar_arrows.png new file mode 100644 index 0000000..92c86ae Binary files /dev/null and b/2018/content/textures/AnimationEditor/img_scalebar_arrows.png differ diff --git a/2018/content/textures/AnimationEditor/img_scalebar_arrows_border.png b/2018/content/textures/AnimationEditor/img_scalebar_arrows_border.png new file mode 100644 index 0000000..33af34a Binary files /dev/null and b/2018/content/textures/AnimationEditor/img_scalebar_arrows_border.png differ diff --git a/2018/content/textures/AnimationEditor/img_scrubberhead.png b/2018/content/textures/AnimationEditor/img_scrubberhead.png new file mode 100644 index 0000000..8bed057 Binary files /dev/null and b/2018/content/textures/AnimationEditor/img_scrubberhead.png differ diff --git a/2018/content/textures/AnimationEditor/img_timetag.png b/2018/content/textures/AnimationEditor/img_timetag.png new file mode 100644 index 0000000..99a0999 Binary files /dev/null and b/2018/content/textures/AnimationEditor/img_timetag.png differ diff --git a/2018/content/textures/AnimationEditor/img_timetag_border.png b/2018/content/textures/AnimationEditor/img_timetag_border.png new file mode 100644 index 0000000..49a59e7 Binary files /dev/null and b/2018/content/textures/AnimationEditor/img_timetag_border.png differ diff --git a/2018/content/textures/AnimationEditor/img_triangle.png b/2018/content/textures/AnimationEditor/img_triangle.png new file mode 100644 index 0000000..1516c70 Binary files /dev/null and b/2018/content/textures/AnimationEditor/img_triangle.png differ diff --git a/2018/content/textures/AnimationEditor/menu_shadow_bottom.png b/2018/content/textures/AnimationEditor/menu_shadow_bottom.png new file mode 100644 index 0000000..64c5ca8 Binary files /dev/null and b/2018/content/textures/AnimationEditor/menu_shadow_bottom.png differ diff --git a/2018/content/textures/AnimationEditor/menu_shadow_side_left.png b/2018/content/textures/AnimationEditor/menu_shadow_side_left.png new file mode 100644 index 0000000..3e1e14b Binary files /dev/null and b/2018/content/textures/AnimationEditor/menu_shadow_side_left.png differ diff --git a/2018/content/textures/AnimationEditor/menu_shadow_side_right.png b/2018/content/textures/AnimationEditor/menu_shadow_side_right.png new file mode 100644 index 0000000..dc3a41f Binary files /dev/null and b/2018/content/textures/AnimationEditor/menu_shadow_side_right.png differ diff --git a/2018/content/textures/AnimationEditor/menu_shadow_top.png b/2018/content/textures/AnimationEditor/menu_shadow_top.png new file mode 100644 index 0000000..47003ca Binary files /dev/null and b/2018/content/textures/AnimationEditor/menu_shadow_top.png differ diff --git a/2018/content/textures/ArrowCursor.png b/2018/content/textures/ArrowCursor.png new file mode 100644 index 0000000..694c26a Binary files /dev/null and b/2018/content/textures/ArrowCursor.png differ diff --git a/2018/content/textures/ArrowCursorDecalDrag.png b/2018/content/textures/ArrowCursorDecalDrag.png new file mode 100644 index 0000000..694c26a Binary files /dev/null and b/2018/content/textures/ArrowCursorDecalDrag.png differ diff --git a/2018/content/textures/ArrowFarCursor.png b/2018/content/textures/ArrowFarCursor.png new file mode 100644 index 0000000..daf5471 Binary files /dev/null and b/2018/content/textures/ArrowFarCursor.png differ diff --git a/2018/content/textures/AvatarEditorImages/Landscape/gr-color-block-mask-tablet.png b/2018/content/textures/AvatarEditorImages/Landscape/gr-color-block-mask-tablet.png new file mode 100644 index 0000000..976bc95 Binary files /dev/null and b/2018/content/textures/AvatarEditorImages/Landscape/gr-color-block-mask-tablet.png differ diff --git a/2018/content/textures/AvatarEditorImages/Landscape/gr-color-block-mask-tablet@2x.png b/2018/content/textures/AvatarEditorImages/Landscape/gr-color-block-mask-tablet@2x.png new file mode 100644 index 0000000..94e99b2 Binary files /dev/null and b/2018/content/textures/AvatarEditorImages/Landscape/gr-color-block-mask-tablet@2x.png differ diff --git a/2018/content/textures/AvatarEditorImages/Landscape/gr-color-block-mask-tablet@3x.png b/2018/content/textures/AvatarEditorImages/Landscape/gr-color-block-mask-tablet@3x.png new file mode 100644 index 0000000..7200e5d Binary files /dev/null and b/2018/content/textures/AvatarEditorImages/Landscape/gr-color-block-mask-tablet@3x.png differ diff --git a/2018/content/textures/AvatarEditorImages/Landscape/gr-primary-nav-tablet.png b/2018/content/textures/AvatarEditorImages/Landscape/gr-primary-nav-tablet.png new file mode 100644 index 0000000..aa973ad Binary files /dev/null and b/2018/content/textures/AvatarEditorImages/Landscape/gr-primary-nav-tablet.png differ diff --git a/2018/content/textures/AvatarEditorImages/Landscape/gr-primary-nav-tablet@2x.png b/2018/content/textures/AvatarEditorImages/Landscape/gr-primary-nav-tablet@2x.png new file mode 100644 index 0000000..f443f8f Binary files /dev/null and b/2018/content/textures/AvatarEditorImages/Landscape/gr-primary-nav-tablet@2x.png differ diff --git a/2018/content/textures/AvatarEditorImages/Landscape/gr-primary-nav-tablet@3x.png b/2018/content/textures/AvatarEditorImages/Landscape/gr-primary-nav-tablet@3x.png new file mode 100644 index 0000000..953f760 Binary files /dev/null and b/2018/content/textures/AvatarEditorImages/Landscape/gr-primary-nav-tablet@3x.png differ diff --git a/2018/content/textures/AvatarEditorImages/Landscape/gr-selection-corner-tablet.png b/2018/content/textures/AvatarEditorImages/Landscape/gr-selection-corner-tablet.png new file mode 100644 index 0000000..9791c4e Binary files /dev/null and b/2018/content/textures/AvatarEditorImages/Landscape/gr-selection-corner-tablet.png differ diff --git a/2018/content/textures/AvatarEditorImages/Landscape/gr-selection-corner-tablet@2x.png b/2018/content/textures/AvatarEditorImages/Landscape/gr-selection-corner-tablet@2x.png new file mode 100644 index 0000000..38911ce Binary files /dev/null and b/2018/content/textures/AvatarEditorImages/Landscape/gr-selection-corner-tablet@2x.png differ diff --git a/2018/content/textures/AvatarEditorImages/Landscape/gr-selection-corner-tablet@3x.png b/2018/content/textures/AvatarEditorImages/Landscape/gr-selection-corner-tablet@3x.png new file mode 100644 index 0000000..16485f5 Binary files /dev/null and b/2018/content/textures/AvatarEditorImages/Landscape/gr-selection-corner-tablet@3x.png differ diff --git a/2018/content/textures/AvatarEditorImages/Portrait/gr-color-block-mask-phone.png b/2018/content/textures/AvatarEditorImages/Portrait/gr-color-block-mask-phone.png new file mode 100644 index 0000000..2d581ca Binary files /dev/null and b/2018/content/textures/AvatarEditorImages/Portrait/gr-color-block-mask-phone.png differ diff --git a/2018/content/textures/AvatarEditorImages/Portrait/gr-color-block-mask-phone@2x.png b/2018/content/textures/AvatarEditorImages/Portrait/gr-color-block-mask-phone@2x.png new file mode 100644 index 0000000..4103540 Binary files /dev/null and b/2018/content/textures/AvatarEditorImages/Portrait/gr-color-block-mask-phone@2x.png differ diff --git a/2018/content/textures/AvatarEditorImages/Portrait/gr-color-block-mask-phone@3x.png b/2018/content/textures/AvatarEditorImages/Portrait/gr-color-block-mask-phone@3x.png new file mode 100644 index 0000000..03c36b0 Binary files /dev/null and b/2018/content/textures/AvatarEditorImages/Portrait/gr-color-block-mask-phone@3x.png differ diff --git a/2018/content/textures/AvatarEditorImages/Portrait/gr-primary-nav-half circle@2x.png b/2018/content/textures/AvatarEditorImages/Portrait/gr-primary-nav-half circle@2x.png new file mode 100644 index 0000000..67bfc03 Binary files /dev/null and b/2018/content/textures/AvatarEditorImages/Portrait/gr-primary-nav-half circle@2x.png differ diff --git a/2018/content/textures/AvatarEditorImages/Portrait/gr-primary-nav-half-circle.png b/2018/content/textures/AvatarEditorImages/Portrait/gr-primary-nav-half-circle.png new file mode 100644 index 0000000..fc3b6f0 Binary files /dev/null and b/2018/content/textures/AvatarEditorImages/Portrait/gr-primary-nav-half-circle.png differ diff --git a/2018/content/textures/AvatarEditorImages/Portrait/gr-primary-nav-half-circle@3x.png b/2018/content/textures/AvatarEditorImages/Portrait/gr-primary-nav-half-circle@3x.png new file mode 100644 index 0000000..12faccc Binary files /dev/null and b/2018/content/textures/AvatarEditorImages/Portrait/gr-primary-nav-half-circle@3x.png differ diff --git a/2018/content/textures/AvatarEditorImages/Portrait/gr-primary-nav-rectangle.png b/2018/content/textures/AvatarEditorImages/Portrait/gr-primary-nav-rectangle.png new file mode 100644 index 0000000..715da91 Binary files /dev/null and b/2018/content/textures/AvatarEditorImages/Portrait/gr-primary-nav-rectangle.png differ diff --git a/2018/content/textures/AvatarEditorImages/Portrait/gr-primary-nav-rectangle@2x.png b/2018/content/textures/AvatarEditorImages/Portrait/gr-primary-nav-rectangle@2x.png new file mode 100644 index 0000000..17400eb Binary files /dev/null and b/2018/content/textures/AvatarEditorImages/Portrait/gr-primary-nav-rectangle@2x.png differ diff --git a/2018/content/textures/AvatarEditorImages/Portrait/gr-primary-nav-rectangle@3x.png b/2018/content/textures/AvatarEditorImages/Portrait/gr-primary-nav-rectangle@3x.png new file mode 100644 index 0000000..ef52d0b Binary files /dev/null and b/2018/content/textures/AvatarEditorImages/Portrait/gr-primary-nav-rectangle@3x.png differ diff --git a/2018/content/textures/AvatarEditorImages/Portrait/gr-selection-corner-phone.png b/2018/content/textures/AvatarEditorImages/Portrait/gr-selection-corner-phone.png new file mode 100644 index 0000000..954df6e Binary files /dev/null and b/2018/content/textures/AvatarEditorImages/Portrait/gr-selection-corner-phone.png differ diff --git a/2018/content/textures/AvatarEditorImages/Portrait/gr-selection-corner-phone@2x.png b/2018/content/textures/AvatarEditorImages/Portrait/gr-selection-corner-phone@2x.png new file mode 100644 index 0000000..3d7216e Binary files /dev/null and b/2018/content/textures/AvatarEditorImages/Portrait/gr-selection-corner-phone@2x.png differ diff --git a/2018/content/textures/AvatarEditorImages/Portrait/gr-selection-corner-phone@3x.png b/2018/content/textures/AvatarEditorImages/Portrait/gr-selection-corner-phone@3x.png new file mode 100644 index 0000000..083af8b Binary files /dev/null and b/2018/content/textures/AvatarEditorImages/Portrait/gr-selection-corner-phone@3x.png differ diff --git a/2018/content/textures/AvatarEditorImages/Sheet.png b/2018/content/textures/AvatarEditorImages/Sheet.png new file mode 100644 index 0000000..efb94f4 Binary files /dev/null and b/2018/content/textures/AvatarEditorImages/Sheet.png differ diff --git a/2018/content/textures/AvatarEditorImages/Sliders/gr-default-point-empty.png b/2018/content/textures/AvatarEditorImages/Sliders/gr-default-point-empty.png new file mode 100644 index 0000000..5043d1d Binary files /dev/null and b/2018/content/textures/AvatarEditorImages/Sliders/gr-default-point-empty.png differ diff --git a/2018/content/textures/AvatarEditorImages/Sliders/gr-default-point-empty@2x.png b/2018/content/textures/AvatarEditorImages/Sliders/gr-default-point-empty@2x.png new file mode 100644 index 0000000..fba16ba Binary files /dev/null and b/2018/content/textures/AvatarEditorImages/Sliders/gr-default-point-empty@2x.png differ diff --git a/2018/content/textures/AvatarEditorImages/Sliders/gr-default-point-empty@3x.png b/2018/content/textures/AvatarEditorImages/Sliders/gr-default-point-empty@3x.png new file mode 100644 index 0000000..29e91f3 Binary files /dev/null and b/2018/content/textures/AvatarEditorImages/Sliders/gr-default-point-empty@3x.png differ diff --git a/2018/content/textures/AvatarEditorImages/Sliders/gr-default-point-fill.png b/2018/content/textures/AvatarEditorImages/Sliders/gr-default-point-fill.png new file mode 100644 index 0000000..63ced88 Binary files /dev/null and b/2018/content/textures/AvatarEditorImages/Sliders/gr-default-point-fill.png differ diff --git a/2018/content/textures/AvatarEditorImages/Sliders/gr-default-point-fill@2x.png b/2018/content/textures/AvatarEditorImages/Sliders/gr-default-point-fill@2x.png new file mode 100644 index 0000000..3fb53a6 Binary files /dev/null and b/2018/content/textures/AvatarEditorImages/Sliders/gr-default-point-fill@2x.png differ diff --git a/2018/content/textures/AvatarEditorImages/Sliders/gr-default-point-fill@3x.png b/2018/content/textures/AvatarEditorImages/Sliders/gr-default-point-fill@3x.png new file mode 100644 index 0000000..5cc69fa Binary files /dev/null and b/2018/content/textures/AvatarEditorImages/Sliders/gr-default-point-fill@3x.png differ diff --git a/2018/content/textures/AvatarEditorImages/Sliders/gr-slide-bar-empty.png b/2018/content/textures/AvatarEditorImages/Sliders/gr-slide-bar-empty.png new file mode 100644 index 0000000..cc1a2a5 Binary files /dev/null and b/2018/content/textures/AvatarEditorImages/Sliders/gr-slide-bar-empty.png differ diff --git a/2018/content/textures/AvatarEditorImages/Sliders/gr-slide-bar-empty@2x.png b/2018/content/textures/AvatarEditorImages/Sliders/gr-slide-bar-empty@2x.png new file mode 100644 index 0000000..b9fd04b Binary files /dev/null and b/2018/content/textures/AvatarEditorImages/Sliders/gr-slide-bar-empty@2x.png differ diff --git a/2018/content/textures/AvatarEditorImages/Sliders/gr-slide-bar-empty@3x.png b/2018/content/textures/AvatarEditorImages/Sliders/gr-slide-bar-empty@3x.png new file mode 100644 index 0000000..7bfe852 Binary files /dev/null and b/2018/content/textures/AvatarEditorImages/Sliders/gr-slide-bar-empty@3x.png differ diff --git a/2018/content/textures/AvatarEditorImages/Sliders/gr-slide-bar-fill.png b/2018/content/textures/AvatarEditorImages/Sliders/gr-slide-bar-fill.png new file mode 100644 index 0000000..bc50d10 Binary files /dev/null and b/2018/content/textures/AvatarEditorImages/Sliders/gr-slide-bar-fill.png differ diff --git a/2018/content/textures/AvatarEditorImages/Sliders/gr-slide-bar-fill@2x.png b/2018/content/textures/AvatarEditorImages/Sliders/gr-slide-bar-fill@2x.png new file mode 100644 index 0000000..30c1c22 Binary files /dev/null and b/2018/content/textures/AvatarEditorImages/Sliders/gr-slide-bar-fill@2x.png differ diff --git a/2018/content/textures/AvatarEditorImages/Sliders/gr-slide-bar-fill@3x.png b/2018/content/textures/AvatarEditorImages/Sliders/gr-slide-bar-fill@3x.png new file mode 100644 index 0000000..5f4ab0f Binary files /dev/null and b/2018/content/textures/AvatarEditorImages/Sliders/gr-slide-bar-fill@3x.png differ diff --git a/2018/content/textures/AvatarEditorImages/Sliders/gr-slider.png b/2018/content/textures/AvatarEditorImages/Sliders/gr-slider.png new file mode 100644 index 0000000..12022f4 Binary files /dev/null and b/2018/content/textures/AvatarEditorImages/Sliders/gr-slider.png differ diff --git a/2018/content/textures/AvatarEditorImages/Sliders/gr-slider@2x.png b/2018/content/textures/AvatarEditorImages/Sliders/gr-slider@2x.png new file mode 100644 index 0000000..1ae093c Binary files /dev/null and b/2018/content/textures/AvatarEditorImages/Sliders/gr-slider@2x.png differ diff --git a/2018/content/textures/AvatarEditorImages/Sliders/gr-slider@3x.png b/2018/content/textures/AvatarEditorImages/Sliders/gr-slider@3x.png new file mode 100644 index 0000000..6d6ef28 Binary files /dev/null and b/2018/content/textures/AvatarEditorImages/Sliders/gr-slider@3x.png differ diff --git a/2018/content/textures/AvatarEditorImages/Stretch/bar-empty-mid.png b/2018/content/textures/AvatarEditorImages/Stretch/bar-empty-mid.png new file mode 100644 index 0000000..c2c751e Binary files /dev/null and b/2018/content/textures/AvatarEditorImages/Stretch/bar-empty-mid.png differ diff --git a/2018/content/textures/AvatarEditorImages/Stretch/bar-empty-mid@2x.png b/2018/content/textures/AvatarEditorImages/Stretch/bar-empty-mid@2x.png new file mode 100644 index 0000000..32d55f8 Binary files /dev/null and b/2018/content/textures/AvatarEditorImages/Stretch/bar-empty-mid@2x.png differ diff --git a/2018/content/textures/AvatarEditorImages/Stretch/bar-empty-mid@3x.png b/2018/content/textures/AvatarEditorImages/Stretch/bar-empty-mid@3x.png new file mode 100644 index 0000000..de31bc7 Binary files /dev/null and b/2018/content/textures/AvatarEditorImages/Stretch/bar-empty-mid@3x.png differ diff --git a/2018/content/textures/AvatarEditorImages/Stretch/bar-full-mid.png b/2018/content/textures/AvatarEditorImages/Stretch/bar-full-mid.png new file mode 100644 index 0000000..5990100 Binary files /dev/null and b/2018/content/textures/AvatarEditorImages/Stretch/bar-full-mid.png differ diff --git a/2018/content/textures/AvatarEditorImages/Stretch/bar-full-mid@2x.png b/2018/content/textures/AvatarEditorImages/Stretch/bar-full-mid@2x.png new file mode 100644 index 0000000..a4f9403 Binary files /dev/null and b/2018/content/textures/AvatarEditorImages/Stretch/bar-full-mid@2x.png differ diff --git a/2018/content/textures/AvatarEditorImages/Stretch/bar-full-mid@3x.png b/2018/content/textures/AvatarEditorImages/Stretch/bar-full-mid@3x.png new file mode 100644 index 0000000..eeb9e7e Binary files /dev/null and b/2018/content/textures/AvatarEditorImages/Stretch/bar-full-mid@3x.png differ diff --git a/2018/content/textures/AvatarEditorImages/Stretch/gr-tail.png b/2018/content/textures/AvatarEditorImages/Stretch/gr-tail.png new file mode 100644 index 0000000..deb2988 Binary files /dev/null and b/2018/content/textures/AvatarEditorImages/Stretch/gr-tail.png differ diff --git a/2018/content/textures/AvatarEditorImages/Stretch/gr-tail@2x.png b/2018/content/textures/AvatarEditorImages/Stretch/gr-tail@2x.png new file mode 100644 index 0000000..1a88af0 Binary files /dev/null and b/2018/content/textures/AvatarEditorImages/Stretch/gr-tail@2x.png differ diff --git a/2018/content/textures/AvatarEditorImages/btn.png b/2018/content/textures/AvatarEditorImages/btn.png new file mode 100644 index 0000000..112e4c3 Binary files /dev/null and b/2018/content/textures/AvatarEditorImages/btn.png differ diff --git a/2018/content/textures/AvatarEditorImages/btn@2x.png b/2018/content/textures/AvatarEditorImages/btn@2x.png new file mode 100644 index 0000000..4e4394d Binary files /dev/null and b/2018/content/textures/AvatarEditorImages/btn@2x.png differ diff --git a/2018/content/textures/AvatarEditorImages/btn@3x.png b/2018/content/textures/AvatarEditorImages/btn@3x.png new file mode 100644 index 0000000..113a28c Binary files /dev/null and b/2018/content/textures/AvatarEditorImages/btn@3x.png differ diff --git a/2018/content/textures/AvatarEditorImages/circle_blue.png b/2018/content/textures/AvatarEditorImages/circle_blue.png new file mode 100644 index 0000000..63ced88 Binary files /dev/null and b/2018/content/textures/AvatarEditorImages/circle_blue.png differ diff --git a/2018/content/textures/AvatarEditorImages/circle_blue@2x.png b/2018/content/textures/AvatarEditorImages/circle_blue@2x.png new file mode 100644 index 0000000..3fb53a6 Binary files /dev/null and b/2018/content/textures/AvatarEditorImages/circle_blue@2x.png differ diff --git a/2018/content/textures/AvatarEditorImages/circle_blue@3x.png b/2018/content/textures/AvatarEditorImages/circle_blue@3x.png new file mode 100644 index 0000000..5cc69fa Binary files /dev/null and b/2018/content/textures/AvatarEditorImages/circle_blue@3x.png differ diff --git a/2018/content/textures/AvatarEditorImages/circle_gray4.png b/2018/content/textures/AvatarEditorImages/circle_gray4.png new file mode 100644 index 0000000..5043d1d Binary files /dev/null and b/2018/content/textures/AvatarEditorImages/circle_gray4.png differ diff --git a/2018/content/textures/AvatarEditorImages/circle_gray4@2x.png b/2018/content/textures/AvatarEditorImages/circle_gray4@2x.png new file mode 100644 index 0000000..fba16ba Binary files /dev/null and b/2018/content/textures/AvatarEditorImages/circle_gray4@2x.png differ diff --git a/2018/content/textures/AvatarEditorImages/circle_gray4@3x.png b/2018/content/textures/AvatarEditorImages/circle_gray4@3x.png new file mode 100644 index 0000000..29e91f3 Binary files /dev/null and b/2018/content/textures/AvatarEditorImages/circle_gray4@3x.png differ diff --git a/2018/content/textures/AvatarEditorImages/gr-selection-border.png b/2018/content/textures/AvatarEditorImages/gr-selection-border.png new file mode 100644 index 0000000..95d8647 Binary files /dev/null and b/2018/content/textures/AvatarEditorImages/gr-selection-border.png differ diff --git a/2018/content/textures/AvatarEditorImages/gr-selection-border@2x.png b/2018/content/textures/AvatarEditorImages/gr-selection-border@2x.png new file mode 100644 index 0000000..1541ea9 Binary files /dev/null and b/2018/content/textures/AvatarEditorImages/gr-selection-border@2x.png differ diff --git a/2018/content/textures/AvatarEditorImages/gr-selection-border@3x.png b/2018/content/textures/AvatarEditorImages/gr-selection-border@3x.png new file mode 100644 index 0000000..a7d560e Binary files /dev/null and b/2018/content/textures/AvatarEditorImages/gr-selection-border@3x.png differ diff --git a/2018/content/textures/Blank.png b/2018/content/textures/Blank.png new file mode 100644 index 0000000..3add73f Binary files /dev/null and b/2018/content/textures/Blank.png differ diff --git a/2018/content/textures/CollisionGroupsEditor/ToolbarIcon.png b/2018/content/textures/CollisionGroupsEditor/ToolbarIcon.png new file mode 100644 index 0000000..08542c9 Binary files /dev/null and b/2018/content/textures/CollisionGroupsEditor/ToolbarIcon.png differ diff --git a/2018/content/textures/CollisionGroupsEditor/assign-hover.png b/2018/content/textures/CollisionGroupsEditor/assign-hover.png new file mode 100644 index 0000000..91f7db7 Binary files /dev/null and b/2018/content/textures/CollisionGroupsEditor/assign-hover.png differ diff --git a/2018/content/textures/CollisionGroupsEditor/assign.png b/2018/content/textures/CollisionGroupsEditor/assign.png new file mode 100644 index 0000000..fc915f6 Binary files /dev/null and b/2018/content/textures/CollisionGroupsEditor/assign.png differ diff --git a/2018/content/textures/CollisionGroupsEditor/checked-bluebg.png b/2018/content/textures/CollisionGroupsEditor/checked-bluebg.png new file mode 100644 index 0000000..3dddcfb Binary files /dev/null and b/2018/content/textures/CollisionGroupsEditor/checked-bluebg.png differ diff --git a/2018/content/textures/CollisionGroupsEditor/checked-whitebg.png b/2018/content/textures/CollisionGroupsEditor/checked-whitebg.png new file mode 100644 index 0000000..78bdb73 Binary files /dev/null and b/2018/content/textures/CollisionGroupsEditor/checked-whitebg.png differ diff --git a/2018/content/textures/CollisionGroupsEditor/delete-hover.png b/2018/content/textures/CollisionGroupsEditor/delete-hover.png new file mode 100644 index 0000000..a0b6401 Binary files /dev/null and b/2018/content/textures/CollisionGroupsEditor/delete-hover.png differ diff --git a/2018/content/textures/CollisionGroupsEditor/delete.png b/2018/content/textures/CollisionGroupsEditor/delete.png new file mode 100644 index 0000000..9437121 Binary files /dev/null and b/2018/content/textures/CollisionGroupsEditor/delete.png differ diff --git a/2018/content/textures/CollisionGroupsEditor/manage-hover.png b/2018/content/textures/CollisionGroupsEditor/manage-hover.png new file mode 100644 index 0000000..273f99e Binary files /dev/null and b/2018/content/textures/CollisionGroupsEditor/manage-hover.png differ diff --git a/2018/content/textures/CollisionGroupsEditor/manage.png b/2018/content/textures/CollisionGroupsEditor/manage.png new file mode 100644 index 0000000..81c6517 Binary files /dev/null and b/2018/content/textures/CollisionGroupsEditor/manage.png differ diff --git a/2018/content/textures/CollisionGroupsEditor/rename-hover.png b/2018/content/textures/CollisionGroupsEditor/rename-hover.png new file mode 100644 index 0000000..df47a4b Binary files /dev/null and b/2018/content/textures/CollisionGroupsEditor/rename-hover.png differ diff --git a/2018/content/textures/CollisionGroupsEditor/rename.png b/2018/content/textures/CollisionGroupsEditor/rename.png new file mode 100644 index 0000000..bd26275 Binary files /dev/null and b/2018/content/textures/CollisionGroupsEditor/rename.png differ diff --git a/2018/content/textures/CollisionGroupsEditor/unchecked.png b/2018/content/textures/CollisionGroupsEditor/unchecked.png new file mode 100644 index 0000000..dd8aa02 Binary files /dev/null and b/2018/content/textures/CollisionGroupsEditor/unchecked.png differ diff --git a/2018/content/textures/ConstraintCursor.png b/2018/content/textures/ConstraintCursor.png new file mode 100644 index 0000000..a89d0ad Binary files /dev/null and b/2018/content/textures/ConstraintCursor.png differ diff --git a/2018/content/textures/Cursors/Gamepad/Pointer.png b/2018/content/textures/Cursors/Gamepad/Pointer.png new file mode 100644 index 0000000..5c406dc Binary files /dev/null and b/2018/content/textures/Cursors/Gamepad/Pointer.png differ diff --git a/2018/content/textures/Cursors/Gamepad/Pointer@2x.png b/2018/content/textures/Cursors/Gamepad/Pointer@2x.png new file mode 100644 index 0000000..e896fbb Binary files /dev/null and b/2018/content/textures/Cursors/Gamepad/Pointer@2x.png differ diff --git a/2018/content/textures/Cursors/Gamepad/PointerOver.png b/2018/content/textures/Cursors/Gamepad/PointerOver.png new file mode 100644 index 0000000..7663ea1 Binary files /dev/null and b/2018/content/textures/Cursors/Gamepad/PointerOver.png differ diff --git a/2018/content/textures/Cursors/Gamepad/PointerOver@2x.png b/2018/content/textures/Cursors/Gamepad/PointerOver@2x.png new file mode 100644 index 0000000..e0dbd85 Binary files /dev/null and b/2018/content/textures/Cursors/Gamepad/PointerOver@2x.png differ diff --git a/2018/content/textures/DevConsole/Arrow.png b/2018/content/textures/DevConsole/Arrow.png new file mode 100644 index 0000000..f55bbff Binary files /dev/null and b/2018/content/textures/DevConsole/Arrow.png differ diff --git a/2018/content/textures/DevConsole/Clear.png b/2018/content/textures/DevConsole/Clear.png new file mode 100644 index 0000000..9f1bf3a Binary files /dev/null and b/2018/content/textures/DevConsole/Clear.png differ diff --git a/2018/content/textures/DevConsole/Close.png b/2018/content/textures/DevConsole/Close.png new file mode 100644 index 0000000..31d348a Binary files /dev/null and b/2018/content/textures/DevConsole/Close.png differ diff --git a/2018/content/textures/DevConsole/Error.png b/2018/content/textures/DevConsole/Error.png new file mode 100644 index 0000000..470b6e5 Binary files /dev/null and b/2018/content/textures/DevConsole/Error.png differ diff --git a/2018/content/textures/DevConsole/Filter-filled.png b/2018/content/textures/DevConsole/Filter-filled.png new file mode 100644 index 0000000..1f43780 Binary files /dev/null and b/2018/content/textures/DevConsole/Filter-filled.png differ diff --git a/2018/content/textures/DevConsole/Filter-stroke.png b/2018/content/textures/DevConsole/Filter-stroke.png new file mode 100644 index 0000000..6c00c0e Binary files /dev/null and b/2018/content/textures/DevConsole/Filter-stroke.png differ diff --git a/2018/content/textures/DevConsole/Info.png b/2018/content/textures/DevConsole/Info.png new file mode 100644 index 0000000..d6a13bb Binary files /dev/null and b/2018/content/textures/DevConsole/Info.png differ diff --git a/2018/content/textures/DevConsole/Maximize.png b/2018/content/textures/DevConsole/Maximize.png new file mode 100644 index 0000000..8016be6 Binary files /dev/null and b/2018/content/textures/DevConsole/Maximize.png differ diff --git a/2018/content/textures/DevConsole/Minimize.png b/2018/content/textures/DevConsole/Minimize.png new file mode 100644 index 0000000..0065af8 Binary files /dev/null and b/2018/content/textures/DevConsole/Minimize.png differ diff --git a/2018/content/textures/DevConsole/Search.png b/2018/content/textures/DevConsole/Search.png new file mode 100644 index 0000000..b9c95cb Binary files /dev/null and b/2018/content/textures/DevConsole/Search.png differ diff --git a/2018/content/textures/DevConsole/Sort.png b/2018/content/textures/DevConsole/Sort.png new file mode 100644 index 0000000..152394d Binary files /dev/null and b/2018/content/textures/DevConsole/Sort.png differ diff --git a/2018/content/textures/DevConsole/Warning.png b/2018/content/textures/DevConsole/Warning.png new file mode 100644 index 0000000..d614a50 Binary files /dev/null and b/2018/content/textures/DevConsole/Warning.png differ diff --git a/2018/content/textures/FillCursor.png b/2018/content/textures/FillCursor.png new file mode 100644 index 0000000..752cebc Binary files /dev/null and b/2018/content/textures/FillCursor.png differ diff --git a/2018/content/textures/FlatCursor.png b/2018/content/textures/FlatCursor.png new file mode 100644 index 0000000..7d6e845 Binary files /dev/null and b/2018/content/textures/FlatCursor.png differ diff --git a/2018/content/textures/GameSettings/ErrorIcon.png b/2018/content/textures/GameSettings/ErrorIcon.png new file mode 100644 index 0000000..e15c23e Binary files /dev/null and b/2018/content/textures/GameSettings/ErrorIcon.png differ diff --git a/2018/content/textures/GameSettings/RadioButton.png b/2018/content/textures/GameSettings/RadioButton.png new file mode 100644 index 0000000..533340c Binary files /dev/null and b/2018/content/textures/GameSettings/RadioButton.png differ diff --git a/2018/content/textures/GameSettings/ToolbarIcon.png b/2018/content/textures/GameSettings/ToolbarIcon.png new file mode 100644 index 0000000..be1bedf Binary files /dev/null and b/2018/content/textures/GameSettings/ToolbarIcon.png differ diff --git a/2018/content/textures/GameSettings/Warning.png b/2018/content/textures/GameSettings/Warning.png new file mode 100644 index 0000000..6e5f9e6 Binary files /dev/null and b/2018/content/textures/GameSettings/Warning.png differ diff --git a/2018/content/textures/GlueCursor.png b/2018/content/textures/GlueCursor.png new file mode 100644 index 0000000..fdba03c Binary files /dev/null and b/2018/content/textures/GlueCursor.png differ diff --git a/2018/content/textures/HingeCursor.png b/2018/content/textures/HingeCursor.png new file mode 100644 index 0000000..99700b1 Binary files /dev/null and b/2018/content/textures/HingeCursor.png differ diff --git a/2018/content/textures/Icon_Stream_Off.png b/2018/content/textures/Icon_Stream_Off.png new file mode 100644 index 0000000..bbda9be Binary files /dev/null and b/2018/content/textures/Icon_Stream_Off.png differ diff --git a/2018/content/textures/Icon_Stream_Off@2x.png b/2018/content/textures/Icon_Stream_Off@2x.png new file mode 100644 index 0000000..979ef9c Binary files /dev/null and b/2018/content/textures/Icon_Stream_Off@2x.png differ diff --git a/2018/content/textures/Icon_Stream_Off@3x.png b/2018/content/textures/Icon_Stream_Off@3x.png new file mode 100644 index 0000000..e365e43 Binary files /dev/null and b/2018/content/textures/Icon_Stream_Off@3x.png differ diff --git a/2018/content/textures/LockCursor.png b/2018/content/textures/LockCursor.png new file mode 100644 index 0000000..4520327 Binary files /dev/null and b/2018/content/textures/LockCursor.png differ diff --git a/2018/content/textures/MaterialCursor.png b/2018/content/textures/MaterialCursor.png new file mode 100644 index 0000000..f43fa99 Binary files /dev/null and b/2018/content/textures/MaterialCursor.png differ diff --git a/2018/content/textures/MorpherEditor/mainButtonIcon.png b/2018/content/textures/MorpherEditor/mainButtonIcon.png new file mode 100644 index 0000000..3b2f615 Binary files /dev/null and b/2018/content/textures/MorpherEditor/mainButtonIcon.png differ diff --git a/2018/content/textures/MotorCursor.png b/2018/content/textures/MotorCursor.png new file mode 100644 index 0000000..64efe3e Binary files /dev/null and b/2018/content/textures/MotorCursor.png differ diff --git a/2018/content/textures/MouseLockedCursor.png b/2018/content/textures/MouseLockedCursor.png new file mode 100644 index 0000000..2ab5527 Binary files /dev/null and b/2018/content/textures/MouseLockedCursor.png differ diff --git a/2018/content/textures/RoactStudioWidgets/button_default.png b/2018/content/textures/RoactStudioWidgets/button_default.png new file mode 100644 index 0000000..28eb7a7 Binary files /dev/null and b/2018/content/textures/RoactStudioWidgets/button_default.png differ diff --git a/2018/content/textures/RoactStudioWidgets/button_hover.png b/2018/content/textures/RoactStudioWidgets/button_hover.png new file mode 100644 index 0000000..5184f6d Binary files /dev/null and b/2018/content/textures/RoactStudioWidgets/button_hover.png differ diff --git a/2018/content/textures/RoactStudioWidgets/button_pressed.png b/2018/content/textures/RoactStudioWidgets/button_pressed.png new file mode 100644 index 0000000..5484114 Binary files /dev/null and b/2018/content/textures/RoactStudioWidgets/button_pressed.png differ diff --git a/2018/content/textures/RoactStudioWidgets/button_radiobutton_chosen.png b/2018/content/textures/RoactStudioWidgets/button_radiobutton_chosen.png new file mode 100644 index 0000000..2b1bbec Binary files /dev/null and b/2018/content/textures/RoactStudioWidgets/button_radiobutton_chosen.png differ diff --git a/2018/content/textures/RoactStudioWidgets/button_radiobutton_default.png b/2018/content/textures/RoactStudioWidgets/button_radiobutton_default.png new file mode 100644 index 0000000..fbb0cff Binary files /dev/null and b/2018/content/textures/RoactStudioWidgets/button_radiobutton_default.png differ diff --git a/2018/content/textures/RoactStudioWidgets/checkbox_square.png b/2018/content/textures/RoactStudioWidgets/checkbox_square.png new file mode 100644 index 0000000..af883a9 Binary files /dev/null and b/2018/content/textures/RoactStudioWidgets/checkbox_square.png differ diff --git a/2018/content/textures/RoactStudioWidgets/icon_tick.png b/2018/content/textures/RoactStudioWidgets/icon_tick.png new file mode 100644 index 0000000..997f788 Binary files /dev/null and b/2018/content/textures/RoactStudioWidgets/icon_tick.png differ diff --git a/2018/content/textures/RoactStudioWidgets/slider_caret.png b/2018/content/textures/RoactStudioWidgets/slider_caret.png new file mode 100644 index 0000000..5f5e4b1 Binary files /dev/null and b/2018/content/textures/RoactStudioWidgets/slider_caret.png differ diff --git a/2018/content/textures/RoactStudioWidgets/slider_caret_disabled.png b/2018/content/textures/RoactStudioWidgets/slider_caret_disabled.png new file mode 100644 index 0000000..5f5e4b1 Binary files /dev/null and b/2018/content/textures/RoactStudioWidgets/slider_caret_disabled.png differ diff --git a/2018/content/textures/StudioToolbox/ArrowDownIconWhite.png b/2018/content/textures/StudioToolbox/ArrowDownIconWhite.png new file mode 100644 index 0000000..c5f9c2a Binary files /dev/null and b/2018/content/textures/StudioToolbox/ArrowDownIconWhite.png differ diff --git a/2018/content/textures/StudioToolbox/AudioPreview/light_pause.png b/2018/content/textures/StudioToolbox/AudioPreview/light_pause.png new file mode 100644 index 0000000..907703d Binary files /dev/null and b/2018/content/textures/StudioToolbox/AudioPreview/light_pause.png differ diff --git a/2018/content/textures/StudioToolbox/AudioPreview/light_pause_hover.png b/2018/content/textures/StudioToolbox/AudioPreview/light_pause_hover.png new file mode 100644 index 0000000..1e7caf6 Binary files /dev/null and b/2018/content/textures/StudioToolbox/AudioPreview/light_pause_hover.png differ diff --git a/2018/content/textures/StudioToolbox/AudioPreview/light_play.png b/2018/content/textures/StudioToolbox/AudioPreview/light_play.png new file mode 100644 index 0000000..c1ca46a Binary files /dev/null and b/2018/content/textures/StudioToolbox/AudioPreview/light_play.png differ diff --git a/2018/content/textures/StudioToolbox/AudioPreview/light_play_hover.png b/2018/content/textures/StudioToolbox/AudioPreview/light_play_hover.png new file mode 100644 index 0000000..6b30a21 Binary files /dev/null and b/2018/content/textures/StudioToolbox/AudioPreview/light_play_hover.png differ diff --git a/2018/content/textures/StudioToolbox/AudioPreview/pause.png b/2018/content/textures/StudioToolbox/AudioPreview/pause.png new file mode 100644 index 0000000..3fb55b7 Binary files /dev/null and b/2018/content/textures/StudioToolbox/AudioPreview/pause.png differ diff --git a/2018/content/textures/StudioToolbox/AudioPreview/pause_hover.png b/2018/content/textures/StudioToolbox/AudioPreview/pause_hover.png new file mode 100644 index 0000000..56d26d0 Binary files /dev/null and b/2018/content/textures/StudioToolbox/AudioPreview/pause_hover.png differ diff --git a/2018/content/textures/StudioToolbox/AudioPreview/play-audio.PNG b/2018/content/textures/StudioToolbox/AudioPreview/play-audio.PNG new file mode 100644 index 0000000..a39b548 Binary files /dev/null and b/2018/content/textures/StudioToolbox/AudioPreview/play-audio.PNG differ diff --git a/2018/content/textures/StudioToolbox/AudioPreview/play.png b/2018/content/textures/StudioToolbox/AudioPreview/play.png new file mode 100644 index 0000000..e65db01 Binary files /dev/null and b/2018/content/textures/StudioToolbox/AudioPreview/play.png differ diff --git a/2018/content/textures/StudioToolbox/AudioPreview/play_hover.png b/2018/content/textures/StudioToolbox/AudioPreview/play_hover.png new file mode 100644 index 0000000..561e7dc Binary files /dev/null and b/2018/content/textures/StudioToolbox/AudioPreview/play_hover.png differ diff --git a/2018/content/textures/StudioToolbox/Clear.png b/2018/content/textures/StudioToolbox/Clear.png new file mode 100644 index 0000000..0d00fe3 Binary files /dev/null and b/2018/content/textures/StudioToolbox/Clear.png differ diff --git a/2018/content/textures/StudioToolbox/ClearHover.png b/2018/content/textures/StudioToolbox/ClearHover.png new file mode 100644 index 0000000..fee06ad Binary files /dev/null and b/2018/content/textures/StudioToolbox/ClearHover.png differ diff --git a/2018/content/textures/StudioToolbox/EndorsedBadge.png b/2018/content/textures/StudioToolbox/EndorsedBadge.png new file mode 100644 index 0000000..b3f5fb4 Binary files /dev/null and b/2018/content/textures/StudioToolbox/EndorsedBadge.png differ diff --git a/2018/content/textures/StudioToolbox/NoBackgroundIcon.png b/2018/content/textures/StudioToolbox/NoBackgroundIcon.png new file mode 100644 index 0000000..1c1e179 Binary files /dev/null and b/2018/content/textures/StudioToolbox/NoBackgroundIcon.png differ diff --git a/2018/content/textures/StudioToolbox/RoundedBackground.png b/2018/content/textures/StudioToolbox/RoundedBackground.png new file mode 100644 index 0000000..602e90f Binary files /dev/null and b/2018/content/textures/StudioToolbox/RoundedBackground.png differ diff --git a/2018/content/textures/StudioToolbox/RoundedBorder.png b/2018/content/textures/StudioToolbox/RoundedBorder.png new file mode 100644 index 0000000..8335459 Binary files /dev/null and b/2018/content/textures/StudioToolbox/RoundedBorder.png differ diff --git a/2018/content/textures/StudioToolbox/ScrollBarBottom.png b/2018/content/textures/StudioToolbox/ScrollBarBottom.png new file mode 100644 index 0000000..235055a Binary files /dev/null and b/2018/content/textures/StudioToolbox/ScrollBarBottom.png differ diff --git a/2018/content/textures/StudioToolbox/ScrollBarMiddle.png b/2018/content/textures/StudioToolbox/ScrollBarMiddle.png new file mode 100644 index 0000000..ed7ca4a Binary files /dev/null and b/2018/content/textures/StudioToolbox/ScrollBarMiddle.png differ diff --git a/2018/content/textures/StudioToolbox/ScrollBarTop.png b/2018/content/textures/StudioToolbox/ScrollBarTop.png new file mode 100644 index 0000000..d01c82f Binary files /dev/null and b/2018/content/textures/StudioToolbox/ScrollBarTop.png differ diff --git a/2018/content/textures/StudioToolbox/Search.png b/2018/content/textures/StudioToolbox/Search.png new file mode 100644 index 0000000..f4934f7 Binary files /dev/null and b/2018/content/textures/StudioToolbox/Search.png differ diff --git a/2018/content/textures/StudioToolbox/ToolboxIcon.png b/2018/content/textures/StudioToolbox/ToolboxIcon.png new file mode 100644 index 0000000..2e99ec3 Binary files /dev/null and b/2018/content/textures/StudioToolbox/ToolboxIcon.png differ diff --git a/2018/content/textures/StudioToolbox/Voting/Thumb.png b/2018/content/textures/StudioToolbox/Voting/Thumb.png new file mode 100644 index 0000000..21a239b Binary files /dev/null and b/2018/content/textures/StudioToolbox/Voting/Thumb.png differ diff --git a/2018/content/textures/StudioToolbox/Voting/thumb-down.png b/2018/content/textures/StudioToolbox/Voting/thumb-down.png new file mode 100644 index 0000000..d36de77 Binary files /dev/null and b/2018/content/textures/StudioToolbox/Voting/thumb-down.png differ diff --git a/2018/content/textures/StudioToolbox/Voting/thumbs-down-filled.png b/2018/content/textures/StudioToolbox/Voting/thumbs-down-filled.png new file mode 100644 index 0000000..1976341 Binary files /dev/null and b/2018/content/textures/StudioToolbox/Voting/thumbs-down-filled.png differ diff --git a/2018/content/textures/StudioToolbox/Voting/thumbs-up-filled.png b/2018/content/textures/StudioToolbox/Voting/thumbs-up-filled.png new file mode 100644 index 0000000..f97cbdd Binary files /dev/null and b/2018/content/textures/StudioToolbox/Voting/thumbs-up-filled.png differ diff --git a/2018/content/textures/StudioToolbox/Voting/thumbup.png b/2018/content/textures/StudioToolbox/Voting/thumbup.png new file mode 100644 index 0000000..babd290 Binary files /dev/null and b/2018/content/textures/StudioToolbox/Voting/thumbup.png differ diff --git a/2018/content/textures/StudioUIEditor/icon_resize1.png b/2018/content/textures/StudioUIEditor/icon_resize1.png new file mode 100644 index 0000000..23aef57 Binary files /dev/null and b/2018/content/textures/StudioUIEditor/icon_resize1.png differ diff --git a/2018/content/textures/StudioUIEditor/icon_resize2.png b/2018/content/textures/StudioUIEditor/icon_resize2.png new file mode 100644 index 0000000..b50268f Binary files /dev/null and b/2018/content/textures/StudioUIEditor/icon_resize2.png differ diff --git a/2018/content/textures/StudioUIEditor/icon_resize3.png b/2018/content/textures/StudioUIEditor/icon_resize3.png new file mode 100644 index 0000000..3258512 Binary files /dev/null and b/2018/content/textures/StudioUIEditor/icon_resize3.png differ diff --git a/2018/content/textures/StudioUIEditor/icon_resize4.png b/2018/content/textures/StudioUIEditor/icon_resize4.png new file mode 100644 index 0000000..2ac469f Binary files /dev/null and b/2018/content/textures/StudioUIEditor/icon_resize4.png differ diff --git a/2018/content/textures/StudioUIEditor/icon_rotate1.png b/2018/content/textures/StudioUIEditor/icon_rotate1.png new file mode 100644 index 0000000..849be92 Binary files /dev/null and b/2018/content/textures/StudioUIEditor/icon_rotate1.png differ diff --git a/2018/content/textures/StudioUIEditor/icon_rotate2.png b/2018/content/textures/StudioUIEditor/icon_rotate2.png new file mode 100644 index 0000000..ee35889 Binary files /dev/null and b/2018/content/textures/StudioUIEditor/icon_rotate2.png differ diff --git a/2018/content/textures/StudioUIEditor/icon_rotate3.png b/2018/content/textures/StudioUIEditor/icon_rotate3.png new file mode 100644 index 0000000..a87e5bc Binary files /dev/null and b/2018/content/textures/StudioUIEditor/icon_rotate3.png differ diff --git a/2018/content/textures/StudioUIEditor/icon_rotate4.png b/2018/content/textures/StudioUIEditor/icon_rotate4.png new file mode 100644 index 0000000..e6934f7 Binary files /dev/null and b/2018/content/textures/StudioUIEditor/icon_rotate4.png differ diff --git a/2018/content/textures/StudioUIEditor/icon_rotate5.png b/2018/content/textures/StudioUIEditor/icon_rotate5.png new file mode 100644 index 0000000..2b69bc6 Binary files /dev/null and b/2018/content/textures/StudioUIEditor/icon_rotate5.png differ diff --git a/2018/content/textures/StudioUIEditor/icon_rotate6.png b/2018/content/textures/StudioUIEditor/icon_rotate6.png new file mode 100644 index 0000000..70dedbd Binary files /dev/null and b/2018/content/textures/StudioUIEditor/icon_rotate6.png differ diff --git a/2018/content/textures/StudioUIEditor/icon_rotate7.png b/2018/content/textures/StudioUIEditor/icon_rotate7.png new file mode 100644 index 0000000..048264c Binary files /dev/null and b/2018/content/textures/StudioUIEditor/icon_rotate7.png differ diff --git a/2018/content/textures/StudioUIEditor/icon_rotate8.png b/2018/content/textures/StudioUIEditor/icon_rotate8.png new file mode 100644 index 0000000..33afb5d Binary files /dev/null and b/2018/content/textures/StudioUIEditor/icon_rotate8.png differ diff --git a/2018/content/textures/StudioUIEditor/resizeHandleDropShadow.png b/2018/content/textures/StudioUIEditor/resizeHandleDropShadow.png new file mode 100644 index 0000000..b0aaf29 Binary files /dev/null and b/2018/content/textures/StudioUIEditor/resizeHandleDropShadow.png differ diff --git a/2018/content/textures/StudioUIEditor/valueBoxRoundedRectangle.png b/2018/content/textures/StudioUIEditor/valueBoxRoundedRectangle.png new file mode 100644 index 0000000..602e90f Binary files /dev/null and b/2018/content/textures/StudioUIEditor/valueBoxRoundedRectangle.png differ diff --git a/2018/content/textures/SurfacesDefault.png b/2018/content/textures/SurfacesDefault.png new file mode 100644 index 0000000..be149ad Binary files /dev/null and b/2018/content/textures/SurfacesDefault.png differ diff --git a/2018/content/textures/TerrainTools/button_arrow.png b/2018/content/textures/TerrainTools/button_arrow.png new file mode 100644 index 0000000..31b851c Binary files /dev/null and b/2018/content/textures/TerrainTools/button_arrow.png differ diff --git a/2018/content/textures/TerrainTools/button_arrow_down.png b/2018/content/textures/TerrainTools/button_arrow_down.png new file mode 100644 index 0000000..f3c6616 Binary files /dev/null and b/2018/content/textures/TerrainTools/button_arrow_down.png differ diff --git a/2018/content/textures/TerrainTools/button_default.png b/2018/content/textures/TerrainTools/button_default.png new file mode 100644 index 0000000..28eb7a7 Binary files /dev/null and b/2018/content/textures/TerrainTools/button_default.png differ diff --git a/2018/content/textures/TerrainTools/button_hover.png b/2018/content/textures/TerrainTools/button_hover.png new file mode 100644 index 0000000..5184f6d Binary files /dev/null and b/2018/content/textures/TerrainTools/button_hover.png differ diff --git a/2018/content/textures/TerrainTools/button_pressed.png b/2018/content/textures/TerrainTools/button_pressed.png new file mode 100644 index 0000000..5484114 Binary files /dev/null and b/2018/content/textures/TerrainTools/button_pressed.png differ diff --git a/2018/content/textures/TerrainTools/checkbox_square.png b/2018/content/textures/TerrainTools/checkbox_square.png new file mode 100644 index 0000000..af883a9 Binary files /dev/null and b/2018/content/textures/TerrainTools/checkbox_square.png differ diff --git a/2018/content/textures/TerrainTools/icon_regions_copy.png b/2018/content/textures/TerrainTools/icon_regions_copy.png new file mode 100644 index 0000000..c303407 Binary files /dev/null and b/2018/content/textures/TerrainTools/icon_regions_copy.png differ diff --git a/2018/content/textures/TerrainTools/icon_regions_delete.png b/2018/content/textures/TerrainTools/icon_regions_delete.png new file mode 100644 index 0000000..f198e81 Binary files /dev/null and b/2018/content/textures/TerrainTools/icon_regions_delete.png differ diff --git a/2018/content/textures/TerrainTools/icon_regions_fill.png b/2018/content/textures/TerrainTools/icon_regions_fill.png new file mode 100644 index 0000000..5599b1b Binary files /dev/null and b/2018/content/textures/TerrainTools/icon_regions_fill.png differ diff --git a/2018/content/textures/TerrainTools/icon_regions_move.png b/2018/content/textures/TerrainTools/icon_regions_move.png new file mode 100644 index 0000000..69dac91 Binary files /dev/null and b/2018/content/textures/TerrainTools/icon_regions_move.png differ diff --git a/2018/content/textures/TerrainTools/icon_regions_paste.png b/2018/content/textures/TerrainTools/icon_regions_paste.png new file mode 100644 index 0000000..c10af88 Binary files /dev/null and b/2018/content/textures/TerrainTools/icon_regions_paste.png differ diff --git a/2018/content/textures/TerrainTools/icon_regions_resize.png b/2018/content/textures/TerrainTools/icon_regions_resize.png new file mode 100644 index 0000000..eec2340 Binary files /dev/null and b/2018/content/textures/TerrainTools/icon_regions_resize.png differ diff --git a/2018/content/textures/TerrainTools/icon_regions_rotate.png b/2018/content/textures/TerrainTools/icon_regions_rotate.png new file mode 100644 index 0000000..f9ffa77 Binary files /dev/null and b/2018/content/textures/TerrainTools/icon_regions_rotate.png differ diff --git a/2018/content/textures/TerrainTools/icon_regions_select.png b/2018/content/textures/TerrainTools/icon_regions_select.png new file mode 100644 index 0000000..7b87052 Binary files /dev/null and b/2018/content/textures/TerrainTools/icon_regions_select.png differ diff --git a/2018/content/textures/TerrainTools/icon_shape_cube.png b/2018/content/textures/TerrainTools/icon_shape_cube.png new file mode 100644 index 0000000..30b4f5a Binary files /dev/null and b/2018/content/textures/TerrainTools/icon_shape_cube.png differ diff --git a/2018/content/textures/TerrainTools/icon_shape_sphere.png b/2018/content/textures/TerrainTools/icon_shape_sphere.png new file mode 100644 index 0000000..41458ef Binary files /dev/null and b/2018/content/textures/TerrainTools/icon_shape_sphere.png differ diff --git a/2018/content/textures/TerrainTools/icon_terrain_big.png b/2018/content/textures/TerrainTools/icon_terrain_big.png new file mode 100644 index 0000000..6c27ece Binary files /dev/null and b/2018/content/textures/TerrainTools/icon_terrain_big.png differ diff --git a/2018/content/textures/TerrainTools/icon_tick.png b/2018/content/textures/TerrainTools/icon_tick.png new file mode 100644 index 0000000..997f788 Binary files /dev/null and b/2018/content/textures/TerrainTools/icon_tick.png differ diff --git a/2018/content/textures/TerrainTools/icon_tick_grey.png b/2018/content/textures/TerrainTools/icon_tick_grey.png new file mode 100644 index 0000000..d451338 Binary files /dev/null and b/2018/content/textures/TerrainTools/icon_tick_grey.png differ diff --git a/2018/content/textures/TerrainTools/mt_add.png b/2018/content/textures/TerrainTools/mt_add.png new file mode 100644 index 0000000..f9e0c40 Binary files /dev/null and b/2018/content/textures/TerrainTools/mt_add.png differ diff --git a/2018/content/textures/TerrainTools/mt_erode.png b/2018/content/textures/TerrainTools/mt_erode.png new file mode 100644 index 0000000..5ace872 Binary files /dev/null and b/2018/content/textures/TerrainTools/mt_erode.png differ diff --git a/2018/content/textures/TerrainTools/mt_generate.png b/2018/content/textures/TerrainTools/mt_generate.png new file mode 100644 index 0000000..dffcf7d Binary files /dev/null and b/2018/content/textures/TerrainTools/mt_generate.png differ diff --git a/2018/content/textures/TerrainTools/mt_grow.png b/2018/content/textures/TerrainTools/mt_grow.png new file mode 100644 index 0000000..76e9333 Binary files /dev/null and b/2018/content/textures/TerrainTools/mt_grow.png differ diff --git a/2018/content/textures/TerrainTools/mt_paint.png b/2018/content/textures/TerrainTools/mt_paint.png new file mode 100644 index 0000000..03096f5 Binary files /dev/null and b/2018/content/textures/TerrainTools/mt_paint.png differ diff --git a/2018/content/textures/TerrainTools/mt_regions.png b/2018/content/textures/TerrainTools/mt_regions.png new file mode 100644 index 0000000..f9aaae8 Binary files /dev/null and b/2018/content/textures/TerrainTools/mt_regions.png differ diff --git a/2018/content/textures/TerrainTools/mt_smooth.png b/2018/content/textures/TerrainTools/mt_smooth.png new file mode 100644 index 0000000..76aadbc Binary files /dev/null and b/2018/content/textures/TerrainTools/mt_smooth.png differ diff --git a/2018/content/textures/TerrainTools/mt_subtract.png b/2018/content/textures/TerrainTools/mt_subtract.png new file mode 100644 index 0000000..a9b2a6a Binary files /dev/null and b/2018/content/textures/TerrainTools/mt_subtract.png differ diff --git a/2018/content/textures/TerrainTools/mtrl_asphalt.png b/2018/content/textures/TerrainTools/mtrl_asphalt.png new file mode 100644 index 0000000..7b35820 Binary files /dev/null and b/2018/content/textures/TerrainTools/mtrl_asphalt.png differ diff --git a/2018/content/textures/TerrainTools/mtrl_basalt.png b/2018/content/textures/TerrainTools/mtrl_basalt.png new file mode 100644 index 0000000..aaccf88 Binary files /dev/null and b/2018/content/textures/TerrainTools/mtrl_basalt.png differ diff --git a/2018/content/textures/TerrainTools/mtrl_brick.png b/2018/content/textures/TerrainTools/mtrl_brick.png new file mode 100644 index 0000000..e0feaac Binary files /dev/null and b/2018/content/textures/TerrainTools/mtrl_brick.png differ diff --git a/2018/content/textures/TerrainTools/mtrl_cobblestone.png b/2018/content/textures/TerrainTools/mtrl_cobblestone.png new file mode 100644 index 0000000..f36e40b Binary files /dev/null and b/2018/content/textures/TerrainTools/mtrl_cobblestone.png differ diff --git a/2018/content/textures/TerrainTools/mtrl_concrete.png b/2018/content/textures/TerrainTools/mtrl_concrete.png new file mode 100644 index 0000000..8786719 Binary files /dev/null and b/2018/content/textures/TerrainTools/mtrl_concrete.png differ diff --git a/2018/content/textures/TerrainTools/mtrl_crackedlava.png b/2018/content/textures/TerrainTools/mtrl_crackedlava.png new file mode 100644 index 0000000..03dcd6c Binary files /dev/null and b/2018/content/textures/TerrainTools/mtrl_crackedlava.png differ diff --git a/2018/content/textures/TerrainTools/mtrl_glacier.png b/2018/content/textures/TerrainTools/mtrl_glacier.png new file mode 100644 index 0000000..bd795db Binary files /dev/null and b/2018/content/textures/TerrainTools/mtrl_glacier.png differ diff --git a/2018/content/textures/TerrainTools/mtrl_grass.png b/2018/content/textures/TerrainTools/mtrl_grass.png new file mode 100644 index 0000000..bb58cb5 Binary files /dev/null and b/2018/content/textures/TerrainTools/mtrl_grass.png differ diff --git a/2018/content/textures/TerrainTools/mtrl_ground.png b/2018/content/textures/TerrainTools/mtrl_ground.png new file mode 100644 index 0000000..b605720 Binary files /dev/null and b/2018/content/textures/TerrainTools/mtrl_ground.png differ diff --git a/2018/content/textures/TerrainTools/mtrl_ice.png b/2018/content/textures/TerrainTools/mtrl_ice.png new file mode 100644 index 0000000..535b8b2 Binary files /dev/null and b/2018/content/textures/TerrainTools/mtrl_ice.png differ diff --git a/2018/content/textures/TerrainTools/mtrl_leafygrass.png b/2018/content/textures/TerrainTools/mtrl_leafygrass.png new file mode 100644 index 0000000..fd4a10f Binary files /dev/null and b/2018/content/textures/TerrainTools/mtrl_leafygrass.png differ diff --git a/2018/content/textures/TerrainTools/mtrl_limestone.png b/2018/content/textures/TerrainTools/mtrl_limestone.png new file mode 100644 index 0000000..a0c1419 Binary files /dev/null and b/2018/content/textures/TerrainTools/mtrl_limestone.png differ diff --git a/2018/content/textures/TerrainTools/mtrl_mud.png b/2018/content/textures/TerrainTools/mtrl_mud.png new file mode 100644 index 0000000..44ccbbc Binary files /dev/null and b/2018/content/textures/TerrainTools/mtrl_mud.png differ diff --git a/2018/content/textures/TerrainTools/mtrl_pavement.png b/2018/content/textures/TerrainTools/mtrl_pavement.png new file mode 100644 index 0000000..4306661 Binary files /dev/null and b/2018/content/textures/TerrainTools/mtrl_pavement.png differ diff --git a/2018/content/textures/TerrainTools/mtrl_rock.png b/2018/content/textures/TerrainTools/mtrl_rock.png new file mode 100644 index 0000000..a66785e Binary files /dev/null and b/2018/content/textures/TerrainTools/mtrl_rock.png differ diff --git a/2018/content/textures/TerrainTools/mtrl_salt.png b/2018/content/textures/TerrainTools/mtrl_salt.png new file mode 100644 index 0000000..00d8c17 Binary files /dev/null and b/2018/content/textures/TerrainTools/mtrl_salt.png differ diff --git a/2018/content/textures/TerrainTools/mtrl_sand.png b/2018/content/textures/TerrainTools/mtrl_sand.png new file mode 100644 index 0000000..df3431b Binary files /dev/null and b/2018/content/textures/TerrainTools/mtrl_sand.png differ diff --git a/2018/content/textures/TerrainTools/mtrl_sandstone.png b/2018/content/textures/TerrainTools/mtrl_sandstone.png new file mode 100644 index 0000000..9a31639 Binary files /dev/null and b/2018/content/textures/TerrainTools/mtrl_sandstone.png differ diff --git a/2018/content/textures/TerrainTools/mtrl_slate.png b/2018/content/textures/TerrainTools/mtrl_slate.png new file mode 100644 index 0000000..e2b4a65 Binary files /dev/null and b/2018/content/textures/TerrainTools/mtrl_slate.png differ diff --git a/2018/content/textures/TerrainTools/mtrl_snow.png b/2018/content/textures/TerrainTools/mtrl_snow.png new file mode 100644 index 0000000..9698dda Binary files /dev/null and b/2018/content/textures/TerrainTools/mtrl_snow.png differ diff --git a/2018/content/textures/TerrainTools/mtrl_water.png b/2018/content/textures/TerrainTools/mtrl_water.png new file mode 100644 index 0000000..0b9595a Binary files /dev/null and b/2018/content/textures/TerrainTools/mtrl_water.png differ diff --git a/2018/content/textures/TerrainTools/mtrl_woodplanks.png b/2018/content/textures/TerrainTools/mtrl_woodplanks.png new file mode 100644 index 0000000..d7a3cee Binary files /dev/null and b/2018/content/textures/TerrainTools/mtrl_woodplanks.png differ diff --git a/2018/content/textures/TerrainTools/progress_bar.png b/2018/content/textures/TerrainTools/progress_bar.png new file mode 100644 index 0000000..4c8be1c Binary files /dev/null and b/2018/content/textures/TerrainTools/progress_bar.png differ diff --git a/2018/content/textures/TerrainTools/radio_button_bullet.png b/2018/content/textures/TerrainTools/radio_button_bullet.png new file mode 100644 index 0000000..0f96b39 Binary files /dev/null and b/2018/content/textures/TerrainTools/radio_button_bullet.png differ diff --git a/2018/content/textures/TerrainTools/radio_button_bullet_dark.png b/2018/content/textures/TerrainTools/radio_button_bullet_dark.png new file mode 100644 index 0000000..c846d72 Binary files /dev/null and b/2018/content/textures/TerrainTools/radio_button_bullet_dark.png differ diff --git a/2018/content/textures/TerrainTools/radio_button_frame.png b/2018/content/textures/TerrainTools/radio_button_frame.png new file mode 100644 index 0000000..fbb0cff Binary files /dev/null and b/2018/content/textures/TerrainTools/radio_button_frame.png differ diff --git a/2018/content/textures/TerrainTools/radio_button_frame_dark.png b/2018/content/textures/TerrainTools/radio_button_frame_dark.png new file mode 100644 index 0000000..b3d9af0 Binary files /dev/null and b/2018/content/textures/TerrainTools/radio_button_frame_dark.png differ diff --git a/2018/content/textures/TerrainTools/sliderbar_blue.png b/2018/content/textures/TerrainTools/sliderbar_blue.png new file mode 100644 index 0000000..0fbbf6b Binary files /dev/null and b/2018/content/textures/TerrainTools/sliderbar_blue.png differ diff --git a/2018/content/textures/TerrainTools/sliderbar_button.png b/2018/content/textures/TerrainTools/sliderbar_button.png new file mode 100644 index 0000000..0f8e1c7 Binary files /dev/null and b/2018/content/textures/TerrainTools/sliderbar_button.png differ diff --git a/2018/content/textures/TerrainTools/sliderbar_grey.png b/2018/content/textures/TerrainTools/sliderbar_grey.png new file mode 100644 index 0000000..dd1cdaa Binary files /dev/null and b/2018/content/textures/TerrainTools/sliderbar_grey.png differ diff --git a/2018/content/textures/UnAnchorCursor.png b/2018/content/textures/UnAnchorCursor.png new file mode 100644 index 0000000..4ca5381 Binary files /dev/null and b/2018/content/textures/UnAnchorCursor.png differ diff --git a/2018/content/textures/UnlockCursor.png b/2018/content/textures/UnlockCursor.png new file mode 100644 index 0000000..b765c16 Binary files /dev/null and b/2018/content/textures/UnlockCursor.png differ diff --git a/2018/content/textures/WeldCursor.png b/2018/content/textures/WeldCursor.png new file mode 100644 index 0000000..a686be3 Binary files /dev/null and b/2018/content/textures/WeldCursor.png differ diff --git a/2018/content/textures/advClosed-hand-anchored.png b/2018/content/textures/advClosed-hand-anchored.png new file mode 100644 index 0000000..1d71af1 Binary files /dev/null and b/2018/content/textures/advClosed-hand-anchored.png differ diff --git a/2018/content/textures/advClosed-hand-no-weld.png b/2018/content/textures/advClosed-hand-no-weld.png new file mode 100644 index 0000000..d914399 Binary files /dev/null and b/2018/content/textures/advClosed-hand-no-weld.png differ diff --git a/2018/content/textures/advClosed-hand-weld.png b/2018/content/textures/advClosed-hand-weld.png new file mode 100644 index 0000000..2a8e734 Binary files /dev/null and b/2018/content/textures/advClosed-hand-weld.png differ diff --git a/2018/content/textures/advClosed-hand.png b/2018/content/textures/advClosed-hand.png new file mode 100644 index 0000000..1adb82f Binary files /dev/null and b/2018/content/textures/advClosed-hand.png differ diff --git a/2018/content/textures/advCursor-default.png b/2018/content/textures/advCursor-default.png new file mode 100644 index 0000000..289c415 Binary files /dev/null and b/2018/content/textures/advCursor-default.png differ diff --git a/2018/content/textures/advCursor-openedHand.png b/2018/content/textures/advCursor-openedHand.png new file mode 100644 index 0000000..1aea61b Binary files /dev/null and b/2018/content/textures/advCursor-openedHand.png differ diff --git a/2018/content/textures/advCursor-white.png b/2018/content/textures/advCursor-white.png new file mode 100644 index 0000000..0ec7adc Binary files /dev/null and b/2018/content/textures/advCursor-white.png differ diff --git a/2018/content/textures/advancedMove.png b/2018/content/textures/advancedMove.png new file mode 100644 index 0000000..8621f0f Binary files /dev/null and b/2018/content/textures/advancedMove.png differ diff --git a/2018/content/textures/advancedMoveResize.png b/2018/content/textures/advancedMoveResize.png new file mode 100644 index 0000000..a7421be Binary files /dev/null and b/2018/content/textures/advancedMoveResize.png differ diff --git a/2018/content/textures/advancedMove_joint.png b/2018/content/textures/advancedMove_joint.png new file mode 100644 index 0000000..76f7f0a Binary files /dev/null and b/2018/content/textures/advancedMove_joint.png differ diff --git a/2018/content/textures/advancedMove_keysOnly.png b/2018/content/textures/advancedMove_keysOnly.png new file mode 100644 index 0000000..1b55927 Binary files /dev/null and b/2018/content/textures/advancedMove_keysOnly.png differ diff --git a/2018/content/textures/advancedMove_noJoint.png b/2018/content/textures/advancedMove_noJoint.png new file mode 100644 index 0000000..6066608 Binary files /dev/null and b/2018/content/textures/advancedMove_noJoint.png differ diff --git a/2018/content/textures/blackBkg_round.png b/2018/content/textures/blackBkg_round.png new file mode 100644 index 0000000..2796afa Binary files /dev/null and b/2018/content/textures/blackBkg_round.png differ diff --git a/2018/content/textures/blackBkg_square.png b/2018/content/textures/blackBkg_square.png new file mode 100644 index 0000000..0382ce3 Binary files /dev/null and b/2018/content/textures/blackBkg_square.png differ diff --git a/2018/content/textures/blockUpperLeft.png b/2018/content/textures/blockUpperLeft.png new file mode 100644 index 0000000..93a8190 Binary files /dev/null and b/2018/content/textures/blockUpperLeft.png differ diff --git a/2018/content/textures/chatBubble_bot_notifyGray_dotDotDot.png b/2018/content/textures/chatBubble_bot_notifyGray_dotDotDot.png new file mode 100644 index 0000000..cd76f6f Binary files /dev/null and b/2018/content/textures/chatBubble_bot_notifyGray_dotDotDot.png differ diff --git a/2018/content/textures/emoji/page0.png b/2018/content/textures/emoji/page0.png new file mode 100644 index 0000000..0c22723 Binary files /dev/null and b/2018/content/textures/emoji/page0.png differ diff --git a/2018/content/textures/emoji/page1.png b/2018/content/textures/emoji/page1.png new file mode 100644 index 0000000..1fc38ea Binary files /dev/null and b/2018/content/textures/emoji/page1.png differ diff --git a/2018/content/textures/emoji/page10.png b/2018/content/textures/emoji/page10.png new file mode 100644 index 0000000..abc37a3 Binary files /dev/null and b/2018/content/textures/emoji/page10.png differ diff --git a/2018/content/textures/emoji/page11.png b/2018/content/textures/emoji/page11.png new file mode 100644 index 0000000..ba4f0b7 Binary files /dev/null and b/2018/content/textures/emoji/page11.png differ diff --git a/2018/content/textures/emoji/page12.png b/2018/content/textures/emoji/page12.png new file mode 100644 index 0000000..02a9817 Binary files /dev/null and b/2018/content/textures/emoji/page12.png differ diff --git a/2018/content/textures/emoji/page13.png b/2018/content/textures/emoji/page13.png new file mode 100644 index 0000000..aa8ce1a Binary files /dev/null and b/2018/content/textures/emoji/page13.png differ diff --git a/2018/content/textures/emoji/page14.png b/2018/content/textures/emoji/page14.png new file mode 100644 index 0000000..d7a1d56 Binary files /dev/null and b/2018/content/textures/emoji/page14.png differ diff --git a/2018/content/textures/emoji/page2.png b/2018/content/textures/emoji/page2.png new file mode 100644 index 0000000..a292446 Binary files /dev/null and b/2018/content/textures/emoji/page2.png differ diff --git a/2018/content/textures/emoji/page3.png b/2018/content/textures/emoji/page3.png new file mode 100644 index 0000000..578c214 Binary files /dev/null and b/2018/content/textures/emoji/page3.png differ diff --git a/2018/content/textures/emoji/page4.png b/2018/content/textures/emoji/page4.png new file mode 100644 index 0000000..47dd7c4 Binary files /dev/null and b/2018/content/textures/emoji/page4.png differ diff --git a/2018/content/textures/emoji/page5.png b/2018/content/textures/emoji/page5.png new file mode 100644 index 0000000..b6c21df Binary files /dev/null and b/2018/content/textures/emoji/page5.png differ diff --git a/2018/content/textures/emoji/page6.png b/2018/content/textures/emoji/page6.png new file mode 100644 index 0000000..0544b1d Binary files /dev/null and b/2018/content/textures/emoji/page6.png differ diff --git a/2018/content/textures/emoji/page7.png b/2018/content/textures/emoji/page7.png new file mode 100644 index 0000000..01f34a3 Binary files /dev/null and b/2018/content/textures/emoji/page7.png differ diff --git a/2018/content/textures/emoji/page8.png b/2018/content/textures/emoji/page8.png new file mode 100644 index 0000000..f9e2eb0 Binary files /dev/null and b/2018/content/textures/emoji/page8.png differ diff --git a/2018/content/textures/emoji/page9.png b/2018/content/textures/emoji/page9.png new file mode 100644 index 0000000..810037b Binary files /dev/null and b/2018/content/textures/emoji/page9.png differ diff --git a/2018/content/textures/explosion.png b/2018/content/textures/explosion.png new file mode 100644 index 0000000..5c5787d Binary files /dev/null and b/2018/content/textures/explosion.png differ diff --git a/2018/content/textures/face.png b/2018/content/textures/face.png new file mode 100644 index 0000000..08254c0 Binary files /dev/null and b/2018/content/textures/face.png differ diff --git a/2018/content/textures/glow.png b/2018/content/textures/glow.png new file mode 100644 index 0000000..886de92 Binary files /dev/null and b/2018/content/textures/glow.png differ diff --git a/2018/content/textures/gradient.png b/2018/content/textures/gradient.png new file mode 100644 index 0000000..540d93a Binary files /dev/null and b/2018/content/textures/gradient.png differ diff --git a/2018/content/textures/grid16.png b/2018/content/textures/grid16.png new file mode 100644 index 0000000..4c17cb0 Binary files /dev/null and b/2018/content/textures/grid16.png differ diff --git a/2018/content/textures/grid2.png b/2018/content/textures/grid2.png new file mode 100644 index 0000000..c9379c8 Binary files /dev/null and b/2018/content/textures/grid2.png differ diff --git a/2018/content/textures/grid4.png b/2018/content/textures/grid4.png new file mode 100644 index 0000000..55d88e3 Binary files /dev/null and b/2018/content/textures/grid4.png differ diff --git a/2018/content/textures/icon_ROBUX.png b/2018/content/textures/icon_ROBUX.png new file mode 100644 index 0000000..9e5c0f8 Binary files /dev/null and b/2018/content/textures/icon_ROBUX.png differ diff --git a/2018/content/textures/icon_ROBUX@2x.png b/2018/content/textures/icon_ROBUX@2x.png new file mode 100644 index 0000000..0b2a791 Binary files /dev/null and b/2018/content/textures/icon_ROBUX@2x.png differ diff --git a/2018/content/textures/loading/cancelButton.png b/2018/content/textures/loading/cancelButton.png new file mode 100644 index 0000000..77e6a39 Binary files /dev/null and b/2018/content/textures/loading/cancelButton.png differ diff --git a/2018/content/textures/loading/darkLoadingTexture.png b/2018/content/textures/loading/darkLoadingTexture.png new file mode 100644 index 0000000..90a0910 Binary files /dev/null and b/2018/content/textures/loading/darkLoadingTexture.png differ diff --git a/2018/content/textures/loading/loadingCircle.png b/2018/content/textures/loading/loadingCircle.png new file mode 100644 index 0000000..6788c78 Binary files /dev/null and b/2018/content/textures/loading/loadingCircle.png differ diff --git a/2018/content/textures/loading/loadingTexture.png b/2018/content/textures/loading/loadingTexture.png new file mode 100644 index 0000000..b58f420 Binary files /dev/null and b/2018/content/textures/loading/loadingTexture.png differ diff --git a/2018/content/textures/loading/loadingvignette.png b/2018/content/textures/loading/loadingvignette.png new file mode 100644 index 0000000..5952539 Binary files /dev/null and b/2018/content/textures/loading/loadingvignette.png differ diff --git a/2018/content/textures/loading/robloxTilt.png b/2018/content/textures/loading/robloxTilt.png new file mode 100644 index 0000000..068fe31 Binary files /dev/null and b/2018/content/textures/loading/robloxTilt.png differ diff --git a/2018/content/textures/loading/robloxTiltRed.png b/2018/content/textures/loading/robloxTiltRed.png new file mode 100644 index 0000000..8cfc292 Binary files /dev/null and b/2018/content/textures/loading/robloxTiltRed.png differ diff --git a/2018/content/textures/loading/robloxlogo.png b/2018/content/textures/loading/robloxlogo.png new file mode 100644 index 0000000..2d05445 Binary files /dev/null and b/2018/content/textures/loading/robloxlogo.png differ diff --git a/2018/content/textures/localizationExport.png b/2018/content/textures/localizationExport.png new file mode 100644 index 0000000..591c2c9 Binary files /dev/null and b/2018/content/textures/localizationExport.png differ diff --git a/2018/content/textures/localizationImport.png b/2018/content/textures/localizationImport.png new file mode 100644 index 0000000..10dda0e Binary files /dev/null and b/2018/content/textures/localizationImport.png differ diff --git a/2018/content/textures/localizationTargetEnglish.png b/2018/content/textures/localizationTargetEnglish.png new file mode 100644 index 0000000..5d528f1 Binary files /dev/null and b/2018/content/textures/localizationTargetEnglish.png differ diff --git a/2018/content/textures/localizationTargetSpanish.png b/2018/content/textures/localizationTargetSpanish.png new file mode 100644 index 0000000..34e1db9 Binary files /dev/null and b/2018/content/textures/localizationTargetSpanish.png differ diff --git a/2018/content/textures/localizationTestingIcon.png b/2018/content/textures/localizationTestingIcon.png new file mode 100644 index 0000000..dad16bd Binary files /dev/null and b/2018/content/textures/localizationTestingIcon.png differ diff --git a/2018/content/textures/localizationUIScrapingOff.png b/2018/content/textures/localizationUIScrapingOff.png new file mode 100644 index 0000000..ca3fc50 Binary files /dev/null and b/2018/content/textures/localizationUIScrapingOff.png differ diff --git a/2018/content/textures/localizationUIScrapingOn.png b/2018/content/textures/localizationUIScrapingOn.png new file mode 100644 index 0000000..e034998 Binary files /dev/null and b/2018/content/textures/localizationUIScrapingOn.png differ diff --git a/2018/content/textures/menuDownArrow.png b/2018/content/textures/menuDownArrow.png new file mode 100644 index 0000000..286ecd8 Binary files /dev/null and b/2018/content/textures/menuDownArrow.png differ diff --git a/2018/content/textures/meshPartFallback.png b/2018/content/textures/meshPartFallback.png new file mode 100644 index 0000000..1c1e179 Binary files /dev/null and b/2018/content/textures/meshPartFallback.png differ diff --git a/2018/content/textures/particles/common_alpha.dds b/2018/content/textures/particles/common_alpha.dds new file mode 100644 index 0000000..2cc9c9c Binary files /dev/null and b/2018/content/textures/particles/common_alpha.dds differ diff --git a/2018/content/textures/particles/explosion01_core_alpha.png b/2018/content/textures/particles/explosion01_core_alpha.png new file mode 100644 index 0000000..47ae484 Binary files /dev/null and b/2018/content/textures/particles/explosion01_core_alpha.png differ diff --git a/2018/content/textures/particles/explosion01_core_main.dds b/2018/content/textures/particles/explosion01_core_main.dds new file mode 100644 index 0000000..44fd908 Binary files /dev/null and b/2018/content/textures/particles/explosion01_core_main.dds differ diff --git a/2018/content/textures/particles/explosion01_implosion_color.png b/2018/content/textures/particles/explosion01_implosion_color.png new file mode 100644 index 0000000..2f1e9ed Binary files /dev/null and b/2018/content/textures/particles/explosion01_implosion_color.png differ diff --git a/2018/content/textures/particles/explosion01_implosion_main.dds b/2018/content/textures/particles/explosion01_implosion_main.dds new file mode 100644 index 0000000..a5bf1b5 Binary files /dev/null and b/2018/content/textures/particles/explosion01_implosion_main.dds differ diff --git a/2018/content/textures/particles/explosion01_shockwave_main.dds b/2018/content/textures/particles/explosion01_shockwave_main.dds new file mode 100644 index 0000000..7a30ca6 Binary files /dev/null and b/2018/content/textures/particles/explosion01_shockwave_main.dds differ diff --git a/2018/content/textures/particles/explosion01_smoke_alpha.dds b/2018/content/textures/particles/explosion01_smoke_alpha.dds new file mode 100644 index 0000000..99807c7 Binary files /dev/null and b/2018/content/textures/particles/explosion01_smoke_alpha.dds differ diff --git a/2018/content/textures/particles/explosion01_smoke_color_new.dds b/2018/content/textures/particles/explosion01_smoke_color_new.dds new file mode 100644 index 0000000..fd4df8f Binary files /dev/null and b/2018/content/textures/particles/explosion01_smoke_color_new.dds differ diff --git a/2018/content/textures/particles/explosion01_smoke_main.dds b/2018/content/textures/particles/explosion01_smoke_main.dds new file mode 100644 index 0000000..c37f99a Binary files /dev/null and b/2018/content/textures/particles/explosion01_smoke_main.dds differ diff --git a/2018/content/textures/particles/explosion_alpha.dds b/2018/content/textures/particles/explosion_alpha.dds new file mode 100644 index 0000000..add095f Binary files /dev/null and b/2018/content/textures/particles/explosion_alpha.dds differ diff --git a/2018/content/textures/particles/explosion_color.dds b/2018/content/textures/particles/explosion_color.dds new file mode 100644 index 0000000..f69e2cc Binary files /dev/null and b/2018/content/textures/particles/explosion_color.dds differ diff --git a/2018/content/textures/particles/fire_alpha.dds b/2018/content/textures/particles/fire_alpha.dds new file mode 100644 index 0000000..812a506 Binary files /dev/null and b/2018/content/textures/particles/fire_alpha.dds differ diff --git a/2018/content/textures/particles/fire_color.dds b/2018/content/textures/particles/fire_color.dds new file mode 100644 index 0000000..5d569ad Binary files /dev/null and b/2018/content/textures/particles/fire_color.dds differ diff --git a/2018/content/textures/particles/fire_main.dds b/2018/content/textures/particles/fire_main.dds new file mode 100644 index 0000000..22a5049 Binary files /dev/null and b/2018/content/textures/particles/fire_main.dds differ diff --git a/2018/content/textures/particles/fire_sparks_color.dds b/2018/content/textures/particles/fire_sparks_color.dds new file mode 100644 index 0000000..8876db1 Binary files /dev/null and b/2018/content/textures/particles/fire_sparks_color.dds differ diff --git a/2018/content/textures/particles/fire_sparks_main.dds b/2018/content/textures/particles/fire_sparks_main.dds new file mode 100644 index 0000000..4468e5a Binary files /dev/null and b/2018/content/textures/particles/fire_sparks_main.dds differ diff --git a/2018/content/textures/particles/forcefield_alpha.dds b/2018/content/textures/particles/forcefield_alpha.dds new file mode 100644 index 0000000..03fdac0 Binary files /dev/null and b/2018/content/textures/particles/forcefield_alpha.dds differ diff --git a/2018/content/textures/particles/forcefield_glow_alpha.dds b/2018/content/textures/particles/forcefield_glow_alpha.dds new file mode 100644 index 0000000..326310f Binary files /dev/null and b/2018/content/textures/particles/forcefield_glow_alpha.dds differ diff --git a/2018/content/textures/particles/forcefield_glow_color.dds b/2018/content/textures/particles/forcefield_glow_color.dds new file mode 100644 index 0000000..39dfb8e Binary files /dev/null and b/2018/content/textures/particles/forcefield_glow_color.dds differ diff --git a/2018/content/textures/particles/forcefield_glow_main.dds b/2018/content/textures/particles/forcefield_glow_main.dds new file mode 100644 index 0000000..d1a6472 Binary files /dev/null and b/2018/content/textures/particles/forcefield_glow_main.dds differ diff --git a/2018/content/textures/particles/forcefield_vortex_color.dds b/2018/content/textures/particles/forcefield_vortex_color.dds new file mode 100644 index 0000000..fe33e22 Binary files /dev/null and b/2018/content/textures/particles/forcefield_vortex_color.dds differ diff --git a/2018/content/textures/particles/forcefield_vortex_main.dds b/2018/content/textures/particles/forcefield_vortex_main.dds new file mode 100644 index 0000000..d67cf49 Binary files /dev/null and b/2018/content/textures/particles/forcefield_vortex_main.dds differ diff --git a/2018/content/textures/particles/legacy_fire_alpha_color.dds b/2018/content/textures/particles/legacy_fire_alpha_color.dds new file mode 100644 index 0000000..da0fb05 Binary files /dev/null and b/2018/content/textures/particles/legacy_fire_alpha_color.dds differ diff --git a/2018/content/textures/particles/smoke_color.dds b/2018/content/textures/particles/smoke_color.dds new file mode 100644 index 0000000..a4d0a4f Binary files /dev/null and b/2018/content/textures/particles/smoke_color.dds differ diff --git a/2018/content/textures/particles/smoke_main.dds b/2018/content/textures/particles/smoke_main.dds new file mode 100644 index 0000000..1aaef8d Binary files /dev/null and b/2018/content/textures/particles/smoke_main.dds differ diff --git a/2018/content/textures/particles/sparkles_color.dds b/2018/content/textures/particles/sparkles_color.dds new file mode 100644 index 0000000..4fd1f85 Binary files /dev/null and b/2018/content/textures/particles/sparkles_color.dds differ diff --git a/2018/content/textures/particles/sparkles_main.dds b/2018/content/textures/particles/sparkles_main.dds new file mode 100644 index 0000000..d1875fd Binary files /dev/null and b/2018/content/textures/particles/sparkles_main.dds differ diff --git a/2018/content/textures/rotationArrow.png b/2018/content/textures/rotationArrow.png new file mode 100644 index 0000000..5bd9eb5 Binary files /dev/null and b/2018/content/textures/rotationArrow.png differ diff --git a/2018/content/textures/shadowblurmask.png b/2018/content/textures/shadowblurmask.png new file mode 100644 index 0000000..ae33768 Binary files /dev/null and b/2018/content/textures/shadowblurmask.png differ diff --git a/2018/content/textures/sparkle.png b/2018/content/textures/sparkle.png new file mode 100644 index 0000000..510b061 Binary files /dev/null and b/2018/content/textures/sparkle.png differ diff --git a/2018/content/textures/transformFiveDegrees.png b/2018/content/textures/transformFiveDegrees.png new file mode 100644 index 0000000..1201cea Binary files /dev/null and b/2018/content/textures/transformFiveDegrees.png differ diff --git a/2018/content/textures/transformNinetyDegrees.png b/2018/content/textures/transformNinetyDegrees.png new file mode 100644 index 0000000..253ad36 Binary files /dev/null and b/2018/content/textures/transformNinetyDegrees.png differ diff --git a/2018/content/textures/transformOneDegree.png b/2018/content/textures/transformOneDegree.png new file mode 100644 index 0000000..79cb61f Binary files /dev/null and b/2018/content/textures/transformOneDegree.png differ diff --git a/2018/content/textures/transformTwentyTwoDegrees.png b/2018/content/textures/transformTwentyTwoDegrees.png new file mode 100644 index 0000000..556b024 Binary files /dev/null and b/2018/content/textures/transformTwentyTwoDegrees.png differ diff --git a/2018/content/textures/ui/Backpack/Backpack.png b/2018/content/textures/ui/Backpack/Backpack.png new file mode 100644 index 0000000..8d9048a Binary files /dev/null and b/2018/content/textures/ui/Backpack/Backpack.png differ diff --git a/2018/content/textures/ui/Backpack/Backpack@2x.png b/2018/content/textures/ui/Backpack/Backpack@2x.png new file mode 100644 index 0000000..9814297 Binary files /dev/null and b/2018/content/textures/ui/Backpack/Backpack@2x.png differ diff --git a/2018/content/textures/ui/Backpack/Backpack_Down.png b/2018/content/textures/ui/Backpack/Backpack_Down.png new file mode 100644 index 0000000..b687a19 Binary files /dev/null and b/2018/content/textures/ui/Backpack/Backpack_Down.png differ diff --git a/2018/content/textures/ui/Backpack/Backpack_Down@2x.png b/2018/content/textures/ui/Backpack/Backpack_Down@2x.png new file mode 100644 index 0000000..5c46d4a Binary files /dev/null and b/2018/content/textures/ui/Backpack/Backpack_Down@2x.png differ diff --git a/2018/content/textures/ui/Backpack/ScrollDownArrow.png b/2018/content/textures/ui/Backpack/ScrollDownArrow.png new file mode 100644 index 0000000..68e14aa Binary files /dev/null and b/2018/content/textures/ui/Backpack/ScrollDownArrow.png differ diff --git a/2018/content/textures/ui/Backpack/ScrollUpArrow.png b/2018/content/textures/ui/Backpack/ScrollUpArrow.png new file mode 100644 index 0000000..3824e05 Binary files /dev/null and b/2018/content/textures/ui/Backpack/ScrollUpArrow.png differ diff --git a/2018/content/textures/ui/Backpack_Close.png b/2018/content/textures/ui/Backpack_Close.png new file mode 100644 index 0000000..2b3679b Binary files /dev/null and b/2018/content/textures/ui/Backpack_Close.png differ diff --git a/2018/content/textures/ui/Backpack_Close@2x.png b/2018/content/textures/ui/Backpack_Close@2x.png new file mode 100644 index 0000000..1716f55 Binary files /dev/null and b/2018/content/textures/ui/Backpack_Close@2x.png differ diff --git a/2018/content/textures/ui/Backpack_Open.png b/2018/content/textures/ui/Backpack_Open.png new file mode 100644 index 0000000..24fba15 Binary files /dev/null and b/2018/content/textures/ui/Backpack_Open.png differ diff --git a/2018/content/textures/ui/Backpack_Open@2x.png b/2018/content/textures/ui/Backpack_Open@2x.png new file mode 100644 index 0000000..a56634c Binary files /dev/null and b/2018/content/textures/ui/Backpack_Open@2x.png differ diff --git a/2018/content/textures/ui/ButtonLeft.png b/2018/content/textures/ui/ButtonLeft.png new file mode 100644 index 0000000..f2654bd Binary files /dev/null and b/2018/content/textures/ui/ButtonLeft.png differ diff --git a/2018/content/textures/ui/ButtonLeftDown.png b/2018/content/textures/ui/ButtonLeftDown.png new file mode 100644 index 0000000..67cdc7f Binary files /dev/null and b/2018/content/textures/ui/ButtonLeftDown.png differ diff --git a/2018/content/textures/ui/ButtonRight.png b/2018/content/textures/ui/ButtonRight.png new file mode 100644 index 0000000..8defe2e Binary files /dev/null and b/2018/content/textures/ui/ButtonRight.png differ diff --git a/2018/content/textures/ui/ButtonRightDown.png b/2018/content/textures/ui/ButtonRightDown.png new file mode 100644 index 0000000..218f2d2 Binary files /dev/null and b/2018/content/textures/ui/ButtonRightDown.png differ diff --git a/2018/content/textures/ui/Chat/Chat.png b/2018/content/textures/ui/Chat/Chat.png new file mode 100644 index 0000000..d42e4ea Binary files /dev/null and b/2018/content/textures/ui/Chat/Chat.png differ diff --git a/2018/content/textures/ui/Chat/Chat@2x.png b/2018/content/textures/ui/Chat/Chat@2x.png new file mode 100644 index 0000000..57ea151 Binary files /dev/null and b/2018/content/textures/ui/Chat/Chat@2x.png differ diff --git a/2018/content/textures/ui/Chat/ChatDown.png b/2018/content/textures/ui/Chat/ChatDown.png new file mode 100644 index 0000000..002119b Binary files /dev/null and b/2018/content/textures/ui/Chat/ChatDown.png differ diff --git a/2018/content/textures/ui/Chat/ChatDown@2x.png b/2018/content/textures/ui/Chat/ChatDown@2x.png new file mode 100644 index 0000000..f25f80d Binary files /dev/null and b/2018/content/textures/ui/Chat/ChatDown@2x.png differ diff --git a/2018/content/textures/ui/Chat/ChatDownFlip.png b/2018/content/textures/ui/Chat/ChatDownFlip.png new file mode 100644 index 0000000..9523d39 Binary files /dev/null and b/2018/content/textures/ui/Chat/ChatDownFlip.png differ diff --git a/2018/content/textures/ui/Chat/ChatDownFlip@2x.png b/2018/content/textures/ui/Chat/ChatDownFlip@2x.png new file mode 100644 index 0000000..dd6b15e Binary files /dev/null and b/2018/content/textures/ui/Chat/ChatDownFlip@2x.png differ diff --git a/2018/content/textures/ui/Chat/ChatFlip.png b/2018/content/textures/ui/Chat/ChatFlip.png new file mode 100644 index 0000000..f0b508a Binary files /dev/null and b/2018/content/textures/ui/Chat/ChatFlip.png differ diff --git a/2018/content/textures/ui/Chat/ChatFlip@2x.png b/2018/content/textures/ui/Chat/ChatFlip@2x.png new file mode 100644 index 0000000..1e8d6d1 Binary files /dev/null and b/2018/content/textures/ui/Chat/ChatFlip@2x.png differ diff --git a/2018/content/textures/ui/Chat/MessageCounter.png b/2018/content/textures/ui/Chat/MessageCounter.png new file mode 100644 index 0000000..4ba3cbd Binary files /dev/null and b/2018/content/textures/ui/Chat/MessageCounter.png differ diff --git a/2018/content/textures/ui/Chat/MessageCounter@2x.png b/2018/content/textures/ui/Chat/MessageCounter@2x.png new file mode 100644 index 0000000..de2cc47 Binary files /dev/null and b/2018/content/textures/ui/Chat/MessageCounter@2x.png differ diff --git a/2018/content/textures/ui/Chat/ToggleChat.png b/2018/content/textures/ui/Chat/ToggleChat.png new file mode 100644 index 0000000..1bc7450 Binary files /dev/null and b/2018/content/textures/ui/Chat/ToggleChat.png differ diff --git a/2018/content/textures/ui/Chat/ToggleChat@2x.png b/2018/content/textures/ui/Chat/ToggleChat@2x.png new file mode 100644 index 0000000..5ab133e Binary files /dev/null and b/2018/content/textures/ui/Chat/ToggleChat@2x.png differ diff --git a/2018/content/textures/ui/Chat/ToggleChatDown.png b/2018/content/textures/ui/Chat/ToggleChatDown.png new file mode 100644 index 0000000..2956a50 Binary files /dev/null and b/2018/content/textures/ui/Chat/ToggleChatDown.png differ diff --git a/2018/content/textures/ui/Chat/ToggleChatDown@2x.png b/2018/content/textures/ui/Chat/ToggleChatDown@2x.png new file mode 100644 index 0000000..065be38 Binary files /dev/null and b/2018/content/textures/ui/Chat/ToggleChatDown@2x.png differ diff --git a/2018/content/textures/ui/Chat/ToggleChatDownFlip.png b/2018/content/textures/ui/Chat/ToggleChatDownFlip.png new file mode 100644 index 0000000..34d7376 Binary files /dev/null and b/2018/content/textures/ui/Chat/ToggleChatDownFlip.png differ diff --git a/2018/content/textures/ui/Chat/ToggleChatDownFlip@2x.png b/2018/content/textures/ui/Chat/ToggleChatDownFlip@2x.png new file mode 100644 index 0000000..c9a6dff Binary files /dev/null and b/2018/content/textures/ui/Chat/ToggleChatDownFlip@2x.png differ diff --git a/2018/content/textures/ui/Chat/ToggleChatFlip.png b/2018/content/textures/ui/Chat/ToggleChatFlip.png new file mode 100644 index 0000000..e929cfa Binary files /dev/null and b/2018/content/textures/ui/Chat/ToggleChatFlip.png differ diff --git a/2018/content/textures/ui/Chat/ToggleChatFlip@2x.png b/2018/content/textures/ui/Chat/ToggleChatFlip@2x.png new file mode 100644 index 0000000..1d02265 Binary files /dev/null and b/2018/content/textures/ui/Chat/ToggleChatFlip@2x.png differ diff --git a/2018/content/textures/ui/Chat/VRChatBackground.png b/2018/content/textures/ui/Chat/VRChatBackground.png new file mode 100644 index 0000000..694a50f Binary files /dev/null and b/2018/content/textures/ui/Chat/VRChatBackground.png differ diff --git a/2018/content/textures/ui/CloseButton.png b/2018/content/textures/ui/CloseButton.png new file mode 100644 index 0000000..6ba8d7b Binary files /dev/null and b/2018/content/textures/ui/CloseButton.png differ diff --git a/2018/content/textures/ui/CloseButton_dn.png b/2018/content/textures/ui/CloseButton_dn.png new file mode 100644 index 0000000..ee4b9ff Binary files /dev/null and b/2018/content/textures/ui/CloseButton_dn.png differ diff --git a/2018/content/textures/ui/DPadSheet.png b/2018/content/textures/ui/DPadSheet.png new file mode 100644 index 0000000..046e2e7 Binary files /dev/null and b/2018/content/textures/ui/DPadSheet.png differ diff --git a/2018/content/textures/ui/ErrorIcon.png b/2018/content/textures/ui/ErrorIcon.png new file mode 100644 index 0000000..420b21b Binary files /dev/null and b/2018/content/textures/ui/ErrorIcon.png differ diff --git a/2018/content/textures/ui/ErrorIconSmall.png b/2018/content/textures/ui/ErrorIconSmall.png new file mode 100644 index 0000000..213a1ff Binary files /dev/null and b/2018/content/textures/ui/ErrorIconSmall.png differ diff --git a/2018/content/textures/ui/ErrorPrompt/PrimaryButton.png b/2018/content/textures/ui/ErrorPrompt/PrimaryButton.png new file mode 100644 index 0000000..afae8bb Binary files /dev/null and b/2018/content/textures/ui/ErrorPrompt/PrimaryButton.png differ diff --git a/2018/content/textures/ui/ErrorPrompt/PrimaryButton@2x.png b/2018/content/textures/ui/ErrorPrompt/PrimaryButton@2x.png new file mode 100644 index 0000000..0f8157c Binary files /dev/null and b/2018/content/textures/ui/ErrorPrompt/PrimaryButton@2x.png differ diff --git a/2018/content/textures/ui/ErrorPrompt/PrimaryButton@3x.png b/2018/content/textures/ui/ErrorPrompt/PrimaryButton@3x.png new file mode 100644 index 0000000..72a5371 Binary files /dev/null and b/2018/content/textures/ui/ErrorPrompt/PrimaryButton@3x.png differ diff --git a/2018/content/textures/ui/ErrorPrompt/SecondaryButton.png b/2018/content/textures/ui/ErrorPrompt/SecondaryButton.png new file mode 100644 index 0000000..70b102b Binary files /dev/null and b/2018/content/textures/ui/ErrorPrompt/SecondaryButton.png differ diff --git a/2018/content/textures/ui/ErrorPrompt/SecondaryButton@2x.png b/2018/content/textures/ui/ErrorPrompt/SecondaryButton@2x.png new file mode 100644 index 0000000..cee0a86 Binary files /dev/null and b/2018/content/textures/ui/ErrorPrompt/SecondaryButton@2x.png differ diff --git a/2018/content/textures/ui/ErrorPrompt/SecondaryButton@3x.png b/2018/content/textures/ui/ErrorPrompt/SecondaryButton@3x.png new file mode 100644 index 0000000..0ac6f5c Binary files /dev/null and b/2018/content/textures/ui/ErrorPrompt/SecondaryButton@3x.png differ diff --git a/2018/content/textures/ui/ErrorPrompt/ShimmerOverlay.png b/2018/content/textures/ui/ErrorPrompt/ShimmerOverlay.png new file mode 100644 index 0000000..a38dcc8 Binary files /dev/null and b/2018/content/textures/ui/ErrorPrompt/ShimmerOverlay.png differ diff --git a/2018/content/textures/ui/ErrorPrompt/ShimmerOverlay@2x.png b/2018/content/textures/ui/ErrorPrompt/ShimmerOverlay@2x.png new file mode 100644 index 0000000..4747f05 Binary files /dev/null and b/2018/content/textures/ui/ErrorPrompt/ShimmerOverlay@2x.png differ diff --git a/2018/content/textures/ui/ErrorPrompt/ShimmerOverlay@3x.png b/2018/content/textures/ui/ErrorPrompt/ShimmerOverlay@3x.png new file mode 100644 index 0000000..923705d Binary files /dev/null and b/2018/content/textures/ui/ErrorPrompt/ShimmerOverlay@3x.png differ diff --git a/2018/content/textures/ui/ExpandArrowSheet.png b/2018/content/textures/ui/ExpandArrowSheet.png new file mode 100644 index 0000000..d52edc1 Binary files /dev/null and b/2018/content/textures/ui/ExpandArrowSheet.png differ diff --git a/2018/content/textures/ui/Gear.png b/2018/content/textures/ui/Gear.png new file mode 100644 index 0000000..56a46db Binary files /dev/null and b/2018/content/textures/ui/Gear.png differ diff --git a/2018/content/textures/ui/Gear_dn.png b/2018/content/textures/ui/Gear_dn.png new file mode 100644 index 0000000..38df9a3 Binary files /dev/null and b/2018/content/textures/ui/Gear_dn.png differ diff --git a/2018/content/textures/ui/Health-BKG-Center.png b/2018/content/textures/ui/Health-BKG-Center.png new file mode 100644 index 0000000..dea1b3b Binary files /dev/null and b/2018/content/textures/ui/Health-BKG-Center.png differ diff --git a/2018/content/textures/ui/Health-BKG-Center@2x.png b/2018/content/textures/ui/Health-BKG-Center@2x.png new file mode 100644 index 0000000..3fe7101 Binary files /dev/null and b/2018/content/textures/ui/Health-BKG-Center@2x.png differ diff --git a/2018/content/textures/ui/Health-BKG-Left-Cap.png b/2018/content/textures/ui/Health-BKG-Left-Cap.png new file mode 100644 index 0000000..9baf764 Binary files /dev/null and b/2018/content/textures/ui/Health-BKG-Left-Cap.png differ diff --git a/2018/content/textures/ui/Health-BKG-Left-Cap@2x.png b/2018/content/textures/ui/Health-BKG-Left-Cap@2x.png new file mode 100644 index 0000000..6a7825c Binary files /dev/null and b/2018/content/textures/ui/Health-BKG-Left-Cap@2x.png differ diff --git a/2018/content/textures/ui/Health-BKG-Right-Cap.png b/2018/content/textures/ui/Health-BKG-Right-Cap.png new file mode 100644 index 0000000..66af73a Binary files /dev/null and b/2018/content/textures/ui/Health-BKG-Right-Cap.png differ diff --git a/2018/content/textures/ui/Health-BKG-Right-Cap@2x.png b/2018/content/textures/ui/Health-BKG-Right-Cap@2x.png new file mode 100644 index 0000000..7c3f951 Binary files /dev/null and b/2018/content/textures/ui/Health-BKG-Right-Cap@2x.png differ diff --git a/2018/content/textures/ui/ImageSet/AE/img_set_1x_1.png b/2018/content/textures/ui/ImageSet/AE/img_set_1x_1.png new file mode 100644 index 0000000..42adc76 Binary files /dev/null and b/2018/content/textures/ui/ImageSet/AE/img_set_1x_1.png differ diff --git a/2018/content/textures/ui/ImageSet/AE/img_set_2x_1.png b/2018/content/textures/ui/ImageSet/AE/img_set_2x_1.png new file mode 100644 index 0000000..921927e Binary files /dev/null and b/2018/content/textures/ui/ImageSet/AE/img_set_2x_1.png differ diff --git a/2018/content/textures/ui/ImageSet/AE/img_set_3x_1.png b/2018/content/textures/ui/ImageSet/AE/img_set_3x_1.png new file mode 100644 index 0000000..42c90e4 Binary files /dev/null and b/2018/content/textures/ui/ImageSet/AE/img_set_3x_1.png differ diff --git a/2018/content/textures/ui/ImageSet/LuaApp/img_set_1x_1.png b/2018/content/textures/ui/ImageSet/LuaApp/img_set_1x_1.png new file mode 100644 index 0000000..fbcc8f6 Binary files /dev/null and b/2018/content/textures/ui/ImageSet/LuaApp/img_set_1x_1.png differ diff --git a/2018/content/textures/ui/ImageSet/LuaApp/img_set_2x_1.png b/2018/content/textures/ui/ImageSet/LuaApp/img_set_2x_1.png new file mode 100644 index 0000000..901362d Binary files /dev/null and b/2018/content/textures/ui/ImageSet/LuaApp/img_set_2x_1.png differ diff --git a/2018/content/textures/ui/ImageSet/LuaApp/img_set_3x_1.png b/2018/content/textures/ui/ImageSet/LuaApp/img_set_3x_1.png new file mode 100644 index 0000000..f028f03 Binary files /dev/null and b/2018/content/textures/ui/ImageSet/LuaApp/img_set_3x_1.png differ diff --git a/2018/content/textures/ui/Input/DashedLine.png b/2018/content/textures/ui/Input/DashedLine.png new file mode 100644 index 0000000..f9e45e3 Binary files /dev/null and b/2018/content/textures/ui/Input/DashedLine.png differ diff --git a/2018/content/textures/ui/Input/DashedLine90.png b/2018/content/textures/ui/Input/DashedLine90.png new file mode 100644 index 0000000..59ae6c7 Binary files /dev/null and b/2018/content/textures/ui/Input/DashedLine90.png differ diff --git a/2018/content/textures/ui/Input/Disk_padded.png b/2018/content/textures/ui/Input/Disk_padded.png new file mode 100644 index 0000000..ccbda80 Binary files /dev/null and b/2018/content/textures/ui/Input/Disk_padded.png differ diff --git a/2018/content/textures/ui/Input/IntroCamera.png b/2018/content/textures/ui/Input/IntroCamera.png new file mode 100644 index 0000000..bcf3f9c Binary files /dev/null and b/2018/content/textures/ui/Input/IntroCamera.png differ diff --git a/2018/content/textures/ui/Input/IntroCameraPinch.png b/2018/content/textures/ui/Input/IntroCameraPinch.png new file mode 100644 index 0000000..9521250 Binary files /dev/null and b/2018/content/textures/ui/Input/IntroCameraPinch.png differ diff --git a/2018/content/textures/ui/Input/IntroMove.png b/2018/content/textures/ui/Input/IntroMove.png new file mode 100644 index 0000000..a435304 Binary files /dev/null and b/2018/content/textures/ui/Input/IntroMove.png differ diff --git a/2018/content/textures/ui/Input/IntroMove@2x.png b/2018/content/textures/ui/Input/IntroMove@2x.png new file mode 100644 index 0000000..1ce8682 Binary files /dev/null and b/2018/content/textures/ui/Input/IntroMove@2x.png differ diff --git a/2018/content/textures/ui/Input/Ring_padded.png b/2018/content/textures/ui/Input/Ring_padded.png new file mode 100644 index 0000000..54cd6eb Binary files /dev/null and b/2018/content/textures/ui/Input/Ring_padded.png differ diff --git a/2018/content/textures/ui/Input/TouchControlsSheetV2.png b/2018/content/textures/ui/Input/TouchControlsSheetV2.png new file mode 100644 index 0000000..1999108 Binary files /dev/null and b/2018/content/textures/ui/Input/TouchControlsSheetV2.png differ diff --git a/2018/content/textures/ui/Keyboard/close_button_background.png b/2018/content/textures/ui/Keyboard/close_button_background.png new file mode 100644 index 0000000..ceec973 Binary files /dev/null and b/2018/content/textures/ui/Keyboard/close_button_background.png differ diff --git a/2018/content/textures/ui/Keyboard/close_button_icon.png b/2018/content/textures/ui/Keyboard/close_button_icon.png new file mode 100644 index 0000000..bb306ad Binary files /dev/null and b/2018/content/textures/ui/Keyboard/close_button_icon.png differ diff --git a/2018/content/textures/ui/Keyboard/close_button_selection.png b/2018/content/textures/ui/Keyboard/close_button_selection.png new file mode 100644 index 0000000..87bbfed Binary files /dev/null and b/2018/content/textures/ui/Keyboard/close_button_selection.png differ diff --git a/2018/content/textures/ui/Keyboard/key_selection_9slice.png b/2018/content/textures/ui/Keyboard/key_selection_9slice.png new file mode 100644 index 0000000..9c6fc50 Binary files /dev/null and b/2018/content/textures/ui/Keyboard/key_selection_9slice.png differ diff --git a/2018/content/textures/ui/Keyboard/mic_icon.png b/2018/content/textures/ui/Keyboard/mic_icon.png new file mode 100644 index 0000000..7e09484 Binary files /dev/null and b/2018/content/textures/ui/Keyboard/mic_icon.png differ diff --git a/2018/content/textures/ui/LoadingBKG.png b/2018/content/textures/ui/LoadingBKG.png new file mode 100644 index 0000000..2fc377d Binary files /dev/null and b/2018/content/textures/ui/LoadingBKG.png differ diff --git a/2018/content/textures/ui/LoadingScreen/BackgroundDark.png b/2018/content/textures/ui/LoadingScreen/BackgroundDark.png new file mode 100644 index 0000000..6df6d97 Binary files /dev/null and b/2018/content/textures/ui/LoadingScreen/BackgroundDark.png differ diff --git a/2018/content/textures/ui/LoadingScreen/BackgroundLight.png b/2018/content/textures/ui/LoadingScreen/BackgroundLight.png new file mode 100644 index 0000000..d1b2701 Binary files /dev/null and b/2018/content/textures/ui/LoadingScreen/BackgroundLight.png differ diff --git a/2018/content/textures/ui/LoadingScreen/LoadingSpinner.png b/2018/content/textures/ui/LoadingScreen/LoadingSpinner.png new file mode 100644 index 0000000..b577d8e Binary files /dev/null and b/2018/content/textures/ui/LoadingScreen/LoadingSpinner.png differ diff --git a/2018/content/textures/ui/Lobby/Buttons/glow_nine_slice.png b/2018/content/textures/ui/Lobby/Buttons/glow_nine_slice.png new file mode 100644 index 0000000..f67905e Binary files /dev/null and b/2018/content/textures/ui/Lobby/Buttons/glow_nine_slice.png differ diff --git a/2018/content/textures/ui/Lobby/Buttons/more_nine_slice_button.png b/2018/content/textures/ui/Lobby/Buttons/more_nine_slice_button.png new file mode 100644 index 0000000..7e287ed Binary files /dev/null and b/2018/content/textures/ui/Lobby/Buttons/more_nine_slice_button.png differ diff --git a/2018/content/textures/ui/Lobby/Buttons/nine_slice_button.png b/2018/content/textures/ui/Lobby/Buttons/nine_slice_button.png new file mode 100644 index 0000000..adf36ae Binary files /dev/null and b/2018/content/textures/ui/Lobby/Buttons/nine_slice_button.png differ diff --git a/2018/content/textures/ui/Lobby/Buttons/scroll_button.png b/2018/content/textures/ui/Lobby/Buttons/scroll_button.png new file mode 100644 index 0000000..e40ed8c Binary files /dev/null and b/2018/content/textures/ui/Lobby/Buttons/scroll_button.png differ diff --git a/2018/content/textures/ui/Lobby/Buttons/scroll_down.png b/2018/content/textures/ui/Lobby/Buttons/scroll_down.png new file mode 100644 index 0000000..b7ca49b Binary files /dev/null and b/2018/content/textures/ui/Lobby/Buttons/scroll_down.png differ diff --git a/2018/content/textures/ui/Lobby/Buttons/scroll_left.png b/2018/content/textures/ui/Lobby/Buttons/scroll_left.png new file mode 100644 index 0000000..1ad66bb Binary files /dev/null and b/2018/content/textures/ui/Lobby/Buttons/scroll_left.png differ diff --git a/2018/content/textures/ui/Lobby/Buttons/scroll_right.png b/2018/content/textures/ui/Lobby/Buttons/scroll_right.png new file mode 100644 index 0000000..7c2fa78 Binary files /dev/null and b/2018/content/textures/ui/Lobby/Buttons/scroll_right.png differ diff --git a/2018/content/textures/ui/Lobby/Buttons/scroll_up.png b/2018/content/textures/ui/Lobby/Buttons/scroll_up.png new file mode 100644 index 0000000..c411535 Binary files /dev/null and b/2018/content/textures/ui/Lobby/Buttons/scroll_up.png differ diff --git a/2018/content/textures/ui/Lobby/Icons/back_icon.png b/2018/content/textures/ui/Lobby/Icons/back_icon.png new file mode 100644 index 0000000..501a503 Binary files /dev/null and b/2018/content/textures/ui/Lobby/Icons/back_icon.png differ diff --git a/2018/content/textures/ui/LuaApp/9-slice/gr-btn-blue-3px-pressed.png b/2018/content/textures/ui/LuaApp/9-slice/gr-btn-blue-3px-pressed.png new file mode 100644 index 0000000..935ab7b Binary files /dev/null and b/2018/content/textures/ui/LuaApp/9-slice/gr-btn-blue-3px-pressed.png differ diff --git a/2018/content/textures/ui/LuaApp/9-slice/gr-btn-blue-3px-pressed@2x.png b/2018/content/textures/ui/LuaApp/9-slice/gr-btn-blue-3px-pressed@2x.png new file mode 100644 index 0000000..cdfe139 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/9-slice/gr-btn-blue-3px-pressed@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/9-slice/gr-btn-blue-3px-pressed@3x.png b/2018/content/textures/ui/LuaApp/9-slice/gr-btn-blue-3px-pressed@3x.png new file mode 100644 index 0000000..6464926 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/9-slice/gr-btn-blue-3px-pressed@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/9-slice/gr-btn-blue-3px.png b/2018/content/textures/ui/LuaApp/9-slice/gr-btn-blue-3px.png new file mode 100644 index 0000000..9219b54 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/9-slice/gr-btn-blue-3px.png differ diff --git a/2018/content/textures/ui/LuaApp/9-slice/gr-btn-blue-3px@2x.png b/2018/content/textures/ui/LuaApp/9-slice/gr-btn-blue-3px@2x.png new file mode 100644 index 0000000..74ee0db Binary files /dev/null and b/2018/content/textures/ui/LuaApp/9-slice/gr-btn-blue-3px@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/9-slice/gr-btn-blue-3px@3x.png b/2018/content/textures/ui/LuaApp/9-slice/gr-btn-blue-3px@3x.png new file mode 100644 index 0000000..63a2428 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/9-slice/gr-btn-blue-3px@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/9-slice/gr-btn-white-3px-pressed.png b/2018/content/textures/ui/LuaApp/9-slice/gr-btn-white-3px-pressed.png new file mode 100644 index 0000000..6b57943 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/9-slice/gr-btn-white-3px-pressed.png differ diff --git a/2018/content/textures/ui/LuaApp/9-slice/gr-btn-white-3px-pressed@2x.png b/2018/content/textures/ui/LuaApp/9-slice/gr-btn-white-3px-pressed@2x.png new file mode 100644 index 0000000..35ce93e Binary files /dev/null and b/2018/content/textures/ui/LuaApp/9-slice/gr-btn-white-3px-pressed@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/9-slice/gr-btn-white-3px-pressed@3x.png b/2018/content/textures/ui/LuaApp/9-slice/gr-btn-white-3px-pressed@3x.png new file mode 100644 index 0000000..628ce50 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/9-slice/gr-btn-white-3px-pressed@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/9-slice/gr-btn-white-3px.png b/2018/content/textures/ui/LuaApp/9-slice/gr-btn-white-3px.png new file mode 100644 index 0000000..afaf307 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/9-slice/gr-btn-white-3px.png differ diff --git a/2018/content/textures/ui/LuaApp/9-slice/gr-btn-white-3px@2x.png b/2018/content/textures/ui/LuaApp/9-slice/gr-btn-white-3px@2x.png new file mode 100644 index 0000000..c3738c6 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/9-slice/gr-btn-white-3px@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/9-slice/gr-btn-white-3px@3x.png b/2018/content/textures/ui/LuaApp/9-slice/gr-btn-white-3px@3x.png new file mode 100644 index 0000000..88745ae Binary files /dev/null and b/2018/content/textures/ui/LuaApp/9-slice/gr-btn-white-3px@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/9-slice/gr-capsule-circle.png b/2018/content/textures/ui/LuaApp/9-slice/gr-capsule-circle.png new file mode 100644 index 0000000..ec4cc6b Binary files /dev/null and b/2018/content/textures/ui/LuaApp/9-slice/gr-capsule-circle.png differ diff --git a/2018/content/textures/ui/LuaApp/9-slice/gr-capsule-circle@2x.png b/2018/content/textures/ui/LuaApp/9-slice/gr-capsule-circle@2x.png new file mode 100644 index 0000000..3f8602e Binary files /dev/null and b/2018/content/textures/ui/LuaApp/9-slice/gr-capsule-circle@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/9-slice/gr-capsule-circle@3x.png b/2018/content/textures/ui/LuaApp/9-slice/gr-capsule-circle@3x.png new file mode 100644 index 0000000..d6bb42b Binary files /dev/null and b/2018/content/textures/ui/LuaApp/9-slice/gr-capsule-circle@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/9-slice/gr-loading-indicator.png b/2018/content/textures/ui/LuaApp/9-slice/gr-loading-indicator.png new file mode 100644 index 0000000..3f2bed0 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/9-slice/gr-loading-indicator.png differ diff --git a/2018/content/textures/ui/LuaApp/9-slice/gr-loading-indicator@2x.png b/2018/content/textures/ui/LuaApp/9-slice/gr-loading-indicator@2x.png new file mode 100644 index 0000000..92be6e5 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/9-slice/gr-loading-indicator@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/9-slice/gr-loading-indicator@3x.png b/2018/content/textures/ui/LuaApp/9-slice/gr-loading-indicator@3x.png new file mode 100644 index 0000000..cc157ad Binary files /dev/null and b/2018/content/textures/ui/LuaApp/9-slice/gr-loading-indicator@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/9-slice/gr-search.png b/2018/content/textures/ui/LuaApp/9-slice/gr-search.png new file mode 100644 index 0000000..323c743 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/9-slice/gr-search.png differ diff --git a/2018/content/textures/ui/LuaApp/9-slice/gr-search@2x.png b/2018/content/textures/ui/LuaApp/9-slice/gr-search@2x.png new file mode 100644 index 0000000..408c7c0 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/9-slice/gr-search@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/9-slice/gr-search@3x.png b/2018/content/textures/ui/LuaApp/9-slice/gr-search@3x.png new file mode 100644 index 0000000..3c30b7c Binary files /dev/null and b/2018/content/textures/ui/LuaApp/9-slice/gr-search@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/9-slice/gr-shadow.png b/2018/content/textures/ui/LuaApp/9-slice/gr-shadow.png new file mode 100644 index 0000000..15b9412 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/9-slice/gr-shadow.png differ diff --git a/2018/content/textures/ui/LuaApp/9-slice/gr-shadow@2x.png b/2018/content/textures/ui/LuaApp/9-slice/gr-shadow@2x.png new file mode 100644 index 0000000..c2ec7eb Binary files /dev/null and b/2018/content/textures/ui/LuaApp/9-slice/gr-shadow@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/9-slice/gr-shadow@3x.png b/2018/content/textures/ui/LuaApp/9-slice/gr-shadow@3x.png new file mode 100644 index 0000000..2cda209 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/9-slice/gr-shadow@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/9-slice/input-default.png b/2018/content/textures/ui/LuaApp/9-slice/input-default.png new file mode 100644 index 0000000..a1e3247 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/9-slice/input-default.png differ diff --git a/2018/content/textures/ui/LuaApp/9-slice/input-default@2x.png b/2018/content/textures/ui/LuaApp/9-slice/input-default@2x.png new file mode 100644 index 0000000..bad7c52 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/9-slice/input-default@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/9-slice/input-default@3x.png b/2018/content/textures/ui/LuaApp/9-slice/input-default@3x.png new file mode 100644 index 0000000..e92e175 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/9-slice/input-default@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/9-slice/white_button_9slices.png b/2018/content/textures/ui/LuaApp/9-slice/white_button_9slices.png new file mode 100644 index 0000000..70b102b Binary files /dev/null and b/2018/content/textures/ui/LuaApp/9-slice/white_button_9slices.png differ diff --git a/2018/content/textures/ui/LuaApp/9-slice/white_button_9slices@2x.png b/2018/content/textures/ui/LuaApp/9-slice/white_button_9slices@2x.png new file mode 100644 index 0000000..cee0a86 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/9-slice/white_button_9slices@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/9-slice/white_button_9slices@3x.png b/2018/content/textures/ui/LuaApp/9-slice/white_button_9slices@3x.png new file mode 100644 index 0000000..0ac6f5c Binary files /dev/null and b/2018/content/textures/ui/LuaApp/9-slice/white_button_9slices@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/category/ic-bc.png b/2018/content/textures/ui/LuaApp/category/ic-bc.png new file mode 100644 index 0000000..3877fb6 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/category/ic-bc.png differ diff --git a/2018/content/textures/ui/LuaApp/category/ic-bc@2x.png b/2018/content/textures/ui/LuaApp/category/ic-bc@2x.png new file mode 100644 index 0000000..b4ca553 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/category/ic-bc@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/category/ic-bc@3x.png b/2018/content/textures/ui/LuaApp/category/ic-bc@3x.png new file mode 100644 index 0000000..37afee5 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/category/ic-bc@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/category/ic-cancel.png b/2018/content/textures/ui/LuaApp/category/ic-cancel.png new file mode 100644 index 0000000..c9d92d0 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/category/ic-cancel.png differ diff --git a/2018/content/textures/ui/LuaApp/category/ic-cancel@2x.png b/2018/content/textures/ui/LuaApp/category/ic-cancel@2x.png new file mode 100644 index 0000000..bdcdf27 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/category/ic-cancel@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/category/ic-cancel@3x.png b/2018/content/textures/ui/LuaApp/category/ic-cancel@3x.png new file mode 100644 index 0000000..86f9a7b Binary files /dev/null and b/2018/content/textures/ui/LuaApp/category/ic-cancel@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/category/ic-default.png b/2018/content/textures/ui/LuaApp/category/ic-default.png new file mode 100644 index 0000000..1394221 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/category/ic-default.png differ diff --git a/2018/content/textures/ui/LuaApp/category/ic-default@2x.png b/2018/content/textures/ui/LuaApp/category/ic-default@2x.png new file mode 100644 index 0000000..44ed264 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/category/ic-default@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/category/ic-default@3x.png b/2018/content/textures/ui/LuaApp/category/ic-default@3x.png new file mode 100644 index 0000000..468a8ea Binary files /dev/null and b/2018/content/textures/ui/LuaApp/category/ic-default@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/category/ic-featured.png b/2018/content/textures/ui/LuaApp/category/ic-featured.png new file mode 100644 index 0000000..716f358 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/category/ic-featured.png differ diff --git a/2018/content/textures/ui/LuaApp/category/ic-featured@2x.png b/2018/content/textures/ui/LuaApp/category/ic-featured@2x.png new file mode 100644 index 0000000..a03cced Binary files /dev/null and b/2018/content/textures/ui/LuaApp/category/ic-featured@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/category/ic-featured@3x.png b/2018/content/textures/ui/LuaApp/category/ic-featured@3x.png new file mode 100644 index 0000000..712b018 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/category/ic-featured@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/category/ic-friend activity.png b/2018/content/textures/ui/LuaApp/category/ic-friend activity.png new file mode 100644 index 0000000..3dd503f Binary files /dev/null and b/2018/content/textures/ui/LuaApp/category/ic-friend activity.png differ diff --git a/2018/content/textures/ui/LuaApp/category/ic-friend activity@2x.png b/2018/content/textures/ui/LuaApp/category/ic-friend activity@2x.png new file mode 100644 index 0000000..5de2926 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/category/ic-friend activity@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/category/ic-friend activity@3x.png b/2018/content/textures/ui/LuaApp/category/ic-friend activity@3x.png new file mode 100644 index 0000000..315325a Binary files /dev/null and b/2018/content/textures/ui/LuaApp/category/ic-friend activity@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/category/ic-my favorite.png b/2018/content/textures/ui/LuaApp/category/ic-my favorite.png new file mode 100644 index 0000000..154fe4b Binary files /dev/null and b/2018/content/textures/ui/LuaApp/category/ic-my favorite.png differ diff --git a/2018/content/textures/ui/LuaApp/category/ic-my favorite@2x.png b/2018/content/textures/ui/LuaApp/category/ic-my favorite@2x.png new file mode 100644 index 0000000..58a148d Binary files /dev/null and b/2018/content/textures/ui/LuaApp/category/ic-my favorite@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/category/ic-my favorite@3x.png b/2018/content/textures/ui/LuaApp/category/ic-my favorite@3x.png new file mode 100644 index 0000000..9eab9f1 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/category/ic-my favorite@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/category/ic-my recent.png b/2018/content/textures/ui/LuaApp/category/ic-my recent.png new file mode 100644 index 0000000..8de756b Binary files /dev/null and b/2018/content/textures/ui/LuaApp/category/ic-my recent.png differ diff --git a/2018/content/textures/ui/LuaApp/category/ic-my recent@2x.png b/2018/content/textures/ui/LuaApp/category/ic-my recent@2x.png new file mode 100644 index 0000000..30c4466 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/category/ic-my recent@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/category/ic-my recent@3x.png b/2018/content/textures/ui/LuaApp/category/ic-my recent@3x.png new file mode 100644 index 0000000..b8e3dbb Binary files /dev/null and b/2018/content/textures/ui/LuaApp/category/ic-my recent@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/category/ic-popular in VR.png b/2018/content/textures/ui/LuaApp/category/ic-popular in VR.png new file mode 100644 index 0000000..a1fc643 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/category/ic-popular in VR.png differ diff --git a/2018/content/textures/ui/LuaApp/category/ic-popular in VR@2x.png b/2018/content/textures/ui/LuaApp/category/ic-popular in VR@2x.png new file mode 100644 index 0000000..9ca2410 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/category/ic-popular in VR@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/category/ic-popular in VR@3x.png b/2018/content/textures/ui/LuaApp/category/ic-popular in VR@3x.png new file mode 100644 index 0000000..3d5581b Binary files /dev/null and b/2018/content/textures/ui/LuaApp/category/ic-popular in VR@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/category/ic-popular in country.png b/2018/content/textures/ui/LuaApp/category/ic-popular in country.png new file mode 100644 index 0000000..10dd77a Binary files /dev/null and b/2018/content/textures/ui/LuaApp/category/ic-popular in country.png differ diff --git a/2018/content/textures/ui/LuaApp/category/ic-popular in country@2x.png b/2018/content/textures/ui/LuaApp/category/ic-popular in country@2x.png new file mode 100644 index 0000000..154bfcd Binary files /dev/null and b/2018/content/textures/ui/LuaApp/category/ic-popular in country@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/category/ic-popular in country@3x.png b/2018/content/textures/ui/LuaApp/category/ic-popular in country@3x.png new file mode 100644 index 0000000..cad0d22 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/category/ic-popular in country@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/category/ic-popular.png b/2018/content/textures/ui/LuaApp/category/ic-popular.png new file mode 100644 index 0000000..74becef Binary files /dev/null and b/2018/content/textures/ui/LuaApp/category/ic-popular.png differ diff --git a/2018/content/textures/ui/LuaApp/category/ic-popular@2x.png b/2018/content/textures/ui/LuaApp/category/ic-popular@2x.png new file mode 100644 index 0000000..bcf1fa1 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/category/ic-popular@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/category/ic-popular@3x.png b/2018/content/textures/ui/LuaApp/category/ic-popular@3x.png new file mode 100644 index 0000000..cd02edf Binary files /dev/null and b/2018/content/textures/ui/LuaApp/category/ic-popular@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/category/ic-purchased.png b/2018/content/textures/ui/LuaApp/category/ic-purchased.png new file mode 100644 index 0000000..5a0653d Binary files /dev/null and b/2018/content/textures/ui/LuaApp/category/ic-purchased.png differ diff --git a/2018/content/textures/ui/LuaApp/category/ic-purchased@2x.png b/2018/content/textures/ui/LuaApp/category/ic-purchased@2x.png new file mode 100644 index 0000000..b28f8af Binary files /dev/null and b/2018/content/textures/ui/LuaApp/category/ic-purchased@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/category/ic-purchased@3x.png b/2018/content/textures/ui/LuaApp/category/ic-purchased@3x.png new file mode 100644 index 0000000..6dd9b17 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/category/ic-purchased@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/category/ic-recommended.png b/2018/content/textures/ui/LuaApp/category/ic-recommended.png new file mode 100644 index 0000000..8749c0a Binary files /dev/null and b/2018/content/textures/ui/LuaApp/category/ic-recommended.png differ diff --git a/2018/content/textures/ui/LuaApp/category/ic-recommended@2x.png b/2018/content/textures/ui/LuaApp/category/ic-recommended@2x.png new file mode 100644 index 0000000..a1f953f Binary files /dev/null and b/2018/content/textures/ui/LuaApp/category/ic-recommended@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/category/ic-recommended@3x.png b/2018/content/textures/ui/LuaApp/category/ic-recommended@3x.png new file mode 100644 index 0000000..de4be52 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/category/ic-recommended@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/category/ic-top earning.png b/2018/content/textures/ui/LuaApp/category/ic-top earning.png new file mode 100644 index 0000000..6f47270 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/category/ic-top earning.png differ diff --git a/2018/content/textures/ui/LuaApp/category/ic-top earning@2x.png b/2018/content/textures/ui/LuaApp/category/ic-top earning@2x.png new file mode 100644 index 0000000..e11a731 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/category/ic-top earning@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/category/ic-top earning@3x.png b/2018/content/textures/ui/LuaApp/category/ic-top earning@3x.png new file mode 100644 index 0000000..cfb3188 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/category/ic-top earning@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/category/ic-top favorite.png b/2018/content/textures/ui/LuaApp/category/ic-top favorite.png new file mode 100644 index 0000000..6484b5f Binary files /dev/null and b/2018/content/textures/ui/LuaApp/category/ic-top favorite.png differ diff --git a/2018/content/textures/ui/LuaApp/category/ic-top favorite@2x.png b/2018/content/textures/ui/LuaApp/category/ic-top favorite@2x.png new file mode 100644 index 0000000..2fe5789 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/category/ic-top favorite@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/category/ic-top favorite@3x.png b/2018/content/textures/ui/LuaApp/category/ic-top favorite@3x.png new file mode 100644 index 0000000..52622f4 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/category/ic-top favorite@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/category/ic-top paid.png b/2018/content/textures/ui/LuaApp/category/ic-top paid.png new file mode 100644 index 0000000..e2b2a19 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/category/ic-top paid.png differ diff --git a/2018/content/textures/ui/LuaApp/category/ic-top paid@2x.png b/2018/content/textures/ui/LuaApp/category/ic-top paid@2x.png new file mode 100644 index 0000000..9d4a5bd Binary files /dev/null and b/2018/content/textures/ui/LuaApp/category/ic-top paid@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/category/ic-top paid@3x.png b/2018/content/textures/ui/LuaApp/category/ic-top paid@3x.png new file mode 100644 index 0000000..aecc6f4 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/category/ic-top paid@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/category/ic-top rated.png b/2018/content/textures/ui/LuaApp/category/ic-top rated.png new file mode 100644 index 0000000..1b6f08a Binary files /dev/null and b/2018/content/textures/ui/LuaApp/category/ic-top rated.png differ diff --git a/2018/content/textures/ui/LuaApp/category/ic-top rated@2x.png b/2018/content/textures/ui/LuaApp/category/ic-top rated@2x.png new file mode 100644 index 0000000..373be35 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/category/ic-top rated@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/category/ic-top rated@3x.png b/2018/content/textures/ui/LuaApp/category/ic-top rated@3x.png new file mode 100644 index 0000000..6a7dde2 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/category/ic-top rated@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/dropdown/gr-contextual menu.png b/2018/content/textures/ui/LuaApp/dropdown/gr-contextual menu.png new file mode 100644 index 0000000..e8f097d Binary files /dev/null and b/2018/content/textures/ui/LuaApp/dropdown/gr-contextual menu.png differ diff --git a/2018/content/textures/ui/LuaApp/dropdown/gr-contextual menu@2x.png b/2018/content/textures/ui/LuaApp/dropdown/gr-contextual menu@2x.png new file mode 100644 index 0000000..52172ff Binary files /dev/null and b/2018/content/textures/ui/LuaApp/dropdown/gr-contextual menu@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/dropdown/gr-contextual menu@3x.png b/2018/content/textures/ui/LuaApp/dropdown/gr-contextual menu@3x.png new file mode 100644 index 0000000..a26a828 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/dropdown/gr-contextual menu@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/dropdown/gr-tip-down.png b/2018/content/textures/ui/LuaApp/dropdown/gr-tip-down.png new file mode 100644 index 0000000..1270180 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/dropdown/gr-tip-down.png differ diff --git a/2018/content/textures/ui/LuaApp/dropdown/gr-tip-down@2x.png b/2018/content/textures/ui/LuaApp/dropdown/gr-tip-down@2x.png new file mode 100644 index 0000000..8f5cacc Binary files /dev/null and b/2018/content/textures/ui/LuaApp/dropdown/gr-tip-down@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/dropdown/gr-tip-down@3x.png b/2018/content/textures/ui/LuaApp/dropdown/gr-tip-down@3x.png new file mode 100644 index 0000000..72f0811 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/dropdown/gr-tip-down@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/dropdown/gr-tip-left.png b/2018/content/textures/ui/LuaApp/dropdown/gr-tip-left.png new file mode 100644 index 0000000..c8091a7 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/dropdown/gr-tip-left.png differ diff --git a/2018/content/textures/ui/LuaApp/dropdown/gr-tip-left@2x.png b/2018/content/textures/ui/LuaApp/dropdown/gr-tip-left@2x.png new file mode 100644 index 0000000..ee07594 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/dropdown/gr-tip-left@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/dropdown/gr-tip-left@3x.png b/2018/content/textures/ui/LuaApp/dropdown/gr-tip-left@3x.png new file mode 100644 index 0000000..d0a28d4 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/dropdown/gr-tip-left@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/dropdown/gr-tip-right.png b/2018/content/textures/ui/LuaApp/dropdown/gr-tip-right.png new file mode 100644 index 0000000..93d796e Binary files /dev/null and b/2018/content/textures/ui/LuaApp/dropdown/gr-tip-right.png differ diff --git a/2018/content/textures/ui/LuaApp/dropdown/gr-tip-right@2x.png b/2018/content/textures/ui/LuaApp/dropdown/gr-tip-right@2x.png new file mode 100644 index 0000000..ded858d Binary files /dev/null and b/2018/content/textures/ui/LuaApp/dropdown/gr-tip-right@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/dropdown/gr-tip-right@3x.png b/2018/content/textures/ui/LuaApp/dropdown/gr-tip-right@3x.png new file mode 100644 index 0000000..3d20dcf Binary files /dev/null and b/2018/content/textures/ui/LuaApp/dropdown/gr-tip-right@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/dropdown/gr-tip-up.png b/2018/content/textures/ui/LuaApp/dropdown/gr-tip-up.png new file mode 100644 index 0000000..73f833a Binary files /dev/null and b/2018/content/textures/ui/LuaApp/dropdown/gr-tip-up.png differ diff --git a/2018/content/textures/ui/LuaApp/dropdown/gr-tip-up@2x.png b/2018/content/textures/ui/LuaApp/dropdown/gr-tip-up@2x.png new file mode 100644 index 0000000..62314dd Binary files /dev/null and b/2018/content/textures/ui/LuaApp/dropdown/gr-tip-up@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/dropdown/gr-tip-up@3x.png b/2018/content/textures/ui/LuaApp/dropdown/gr-tip-up@3x.png new file mode 100644 index 0000000..a9c91b2 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/dropdown/gr-tip-up@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/graphic/gr-add.png b/2018/content/textures/ui/LuaApp/graphic/gr-add.png new file mode 100644 index 0000000..c863bce Binary files /dev/null and b/2018/content/textures/ui/LuaApp/graphic/gr-add.png differ diff --git a/2018/content/textures/ui/LuaApp/graphic/gr-add@2x.png b/2018/content/textures/ui/LuaApp/graphic/gr-add@2x.png new file mode 100644 index 0000000..7f8368f Binary files /dev/null and b/2018/content/textures/ui/LuaApp/graphic/gr-add@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/graphic/gr-add@3x.png b/2018/content/textures/ui/LuaApp/graphic/gr-add@3x.png new file mode 100644 index 0000000..b8a5b30 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/graphic/gr-add@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/graphic/gr-avatar mask-84x84.png b/2018/content/textures/ui/LuaApp/graphic/gr-avatar mask-84x84.png new file mode 100644 index 0000000..1ac156d Binary files /dev/null and b/2018/content/textures/ui/LuaApp/graphic/gr-avatar mask-84x84.png differ diff --git a/2018/content/textures/ui/LuaApp/graphic/gr-avatar mask-84x84@2x.png b/2018/content/textures/ui/LuaApp/graphic/gr-avatar mask-84x84@2x.png new file mode 100644 index 0000000..97f6bda Binary files /dev/null and b/2018/content/textures/ui/LuaApp/graphic/gr-avatar mask-84x84@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/graphic/gr-avatar mask-84x84@3x.png b/2018/content/textures/ui/LuaApp/graphic/gr-avatar mask-84x84@3x.png new file mode 100644 index 0000000..a167ba0 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/graphic/gr-avatar mask-84x84@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/graphic/gr-avatar mask-90x90.png b/2018/content/textures/ui/LuaApp/graphic/gr-avatar mask-90x90.png new file mode 100644 index 0000000..ac423bb Binary files /dev/null and b/2018/content/textures/ui/LuaApp/graphic/gr-avatar mask-90x90.png differ diff --git a/2018/content/textures/ui/LuaApp/graphic/gr-avatar mask-90x90@2x.png b/2018/content/textures/ui/LuaApp/graphic/gr-avatar mask-90x90@2x.png new file mode 100644 index 0000000..2e44709 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/graphic/gr-avatar mask-90x90@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/graphic/gr-avatar mask-90x90@3x.png b/2018/content/textures/ui/LuaApp/graphic/gr-avatar mask-90x90@3x.png new file mode 100644 index 0000000..1cf1cfa Binary files /dev/null and b/2018/content/textures/ui/LuaApp/graphic/gr-avatar mask-90x90@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/graphic/gr-avatar-frame-36x36.png b/2018/content/textures/ui/LuaApp/graphic/gr-avatar-frame-36x36.png new file mode 100644 index 0000000..3879628 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/graphic/gr-avatar-frame-36x36.png differ diff --git a/2018/content/textures/ui/LuaApp/graphic/gr-avatar-frame-36x36@2x.png b/2018/content/textures/ui/LuaApp/graphic/gr-avatar-frame-36x36@2x.png new file mode 100644 index 0000000..952a375 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/graphic/gr-avatar-frame-36x36@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/graphic/gr-avatar-frame-36x36@3x.png b/2018/content/textures/ui/LuaApp/graphic/gr-avatar-frame-36x36@3x.png new file mode 100644 index 0000000..baa0910 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/graphic/gr-avatar-frame-36x36@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/graphic/gr-bloom-circle.png b/2018/content/textures/ui/LuaApp/graphic/gr-bloom-circle.png new file mode 100644 index 0000000..5a41676 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/graphic/gr-bloom-circle.png differ diff --git a/2018/content/textures/ui/LuaApp/graphic/gr-bloom-circle@2x.png b/2018/content/textures/ui/LuaApp/graphic/gr-bloom-circle@2x.png new file mode 100644 index 0000000..e4347f1 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/graphic/gr-bloom-circle@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/graphic/gr-bloom-circle@3x.png b/2018/content/textures/ui/LuaApp/graphic/gr-bloom-circle@3x.png new file mode 100644 index 0000000..437fd5c Binary files /dev/null and b/2018/content/textures/ui/LuaApp/graphic/gr-bloom-circle@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/graphic/gr-card.png b/2018/content/textures/ui/LuaApp/graphic/gr-card.png new file mode 100644 index 0000000..4d02f21 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/graphic/gr-card.png differ diff --git a/2018/content/textures/ui/LuaApp/graphic/gr-card@2x.png b/2018/content/textures/ui/LuaApp/graphic/gr-card@2x.png new file mode 100644 index 0000000..0a0b1fe Binary files /dev/null and b/2018/content/textures/ui/LuaApp/graphic/gr-card@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/graphic/gr-card@3x.png b/2018/content/textures/ui/LuaApp/graphic/gr-card@3x.png new file mode 100644 index 0000000..cd78323 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/graphic/gr-card@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/graphic/gr-counter-slot-32x32.png b/2018/content/textures/ui/LuaApp/graphic/gr-counter-slot-32x32.png new file mode 100644 index 0000000..eae8762 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/graphic/gr-counter-slot-32x32.png differ diff --git a/2018/content/textures/ui/LuaApp/graphic/gr-counter-slot-32x32@2x.png b/2018/content/textures/ui/LuaApp/graphic/gr-counter-slot-32x32@2x.png new file mode 100644 index 0000000..466a94c Binary files /dev/null and b/2018/content/textures/ui/LuaApp/graphic/gr-counter-slot-32x32@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/graphic/gr-counter-slot-32x32@3x.png b/2018/content/textures/ui/LuaApp/graphic/gr-counter-slot-32x32@3x.png new file mode 100644 index 0000000..37eb5ca Binary files /dev/null and b/2018/content/textures/ui/LuaApp/graphic/gr-counter-slot-32x32@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/graphic/gr-notification badge.png b/2018/content/textures/ui/LuaApp/graphic/gr-notification badge.png new file mode 100644 index 0000000..ca7d97d Binary files /dev/null and b/2018/content/textures/ui/LuaApp/graphic/gr-notification badge.png differ diff --git a/2018/content/textures/ui/LuaApp/graphic/gr-notification badge@2x.png b/2018/content/textures/ui/LuaApp/graphic/gr-notification badge@2x.png new file mode 100644 index 0000000..6548bc0 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/graphic/gr-notification badge@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/graphic/gr-notification badge@3x.png b/2018/content/textures/ui/LuaApp/graphic/gr-notification badge@3x.png new file mode 100644 index 0000000..a09950e Binary files /dev/null and b/2018/content/textures/ui/LuaApp/graphic/gr-notification badge@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/graphic/gr-play-circle.png b/2018/content/textures/ui/LuaApp/graphic/gr-play-circle.png new file mode 100644 index 0000000..9350c52 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/graphic/gr-play-circle.png differ diff --git a/2018/content/textures/ui/LuaApp/graphic/gr-play-circle@2x.png b/2018/content/textures/ui/LuaApp/graphic/gr-play-circle@2x.png new file mode 100644 index 0000000..cb5fdcd Binary files /dev/null and b/2018/content/textures/ui/LuaApp/graphic/gr-play-circle@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/graphic/gr-play-circle@3x.png b/2018/content/textures/ui/LuaApp/graphic/gr-play-circle@3x.png new file mode 100644 index 0000000..3190433 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/graphic/gr-play-circle@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/graphic/gr-profile-150x150px.png b/2018/content/textures/ui/LuaApp/graphic/gr-profile-150x150px.png new file mode 100644 index 0000000..3608a54 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/graphic/gr-profile-150x150px.png differ diff --git a/2018/content/textures/ui/LuaApp/graphic/gr-profile-150x150px@2x.png b/2018/content/textures/ui/LuaApp/graphic/gr-profile-150x150px@2x.png new file mode 100644 index 0000000..3ca1bc2 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/graphic/gr-profile-150x150px@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/graphic/gr-profile-150x150px@3x.png b/2018/content/textures/ui/LuaApp/graphic/gr-profile-150x150px@3x.png new file mode 100644 index 0000000..cadf11a Binary files /dev/null and b/2018/content/textures/ui/LuaApp/graphic/gr-profile-150x150px@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/graphic/gr-profile-border-36x36.png b/2018/content/textures/ui/LuaApp/graphic/gr-profile-border-36x36.png new file mode 100644 index 0000000..ecab811 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/graphic/gr-profile-border-36x36.png differ diff --git a/2018/content/textures/ui/LuaApp/graphic/gr-profile-border-36x36@2x.png b/2018/content/textures/ui/LuaApp/graphic/gr-profile-border-36x36@2x.png new file mode 100644 index 0000000..03b94cc Binary files /dev/null and b/2018/content/textures/ui/LuaApp/graphic/gr-profile-border-36x36@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/graphic/gr-profile-border-36x36@3x.png b/2018/content/textures/ui/LuaApp/graphic/gr-profile-border-36x36@3x.png new file mode 100644 index 0000000..b0d22fe Binary files /dev/null and b/2018/content/textures/ui/LuaApp/graphic/gr-profile-border-36x36@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/graphic/noNetworkConnection.png b/2018/content/textures/ui/LuaApp/graphic/noNetworkConnection.png new file mode 100644 index 0000000..9c270b2 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/graphic/noNetworkConnection.png differ diff --git a/2018/content/textures/ui/LuaApp/graphic/noNetworkConnection@2x.png b/2018/content/textures/ui/LuaApp/graphic/noNetworkConnection@2x.png new file mode 100644 index 0000000..03c37c8 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/graphic/noNetworkConnection@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/graphic/noNetworkConnection@3x.png b/2018/content/textures/ui/LuaApp/graphic/noNetworkConnection@3x.png new file mode 100644 index 0000000..9379cf3 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/graphic/noNetworkConnection@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/graphic/ph-avatar-portrait.png b/2018/content/textures/ui/LuaApp/graphic/ph-avatar-portrait.png new file mode 100644 index 0000000..d3091db Binary files /dev/null and b/2018/content/textures/ui/LuaApp/graphic/ph-avatar-portrait.png differ diff --git a/2018/content/textures/ui/LuaApp/graphic/ph-avatar-portrait@2x.png b/2018/content/textures/ui/LuaApp/graphic/ph-avatar-portrait@2x.png new file mode 100644 index 0000000..a537692 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/graphic/ph-avatar-portrait@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/graphic/ph-avatar-portrait@3x.png b/2018/content/textures/ui/LuaApp/graphic/ph-avatar-portrait@3x.png new file mode 100644 index 0000000..6c3298f Binary files /dev/null and b/2018/content/textures/ui/LuaApp/graphic/ph-avatar-portrait@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/graphic/shimmer.png b/2018/content/textures/ui/LuaApp/graphic/shimmer.png new file mode 100644 index 0000000..2fd648e Binary files /dev/null and b/2018/content/textures/ui/LuaApp/graphic/shimmer.png differ diff --git a/2018/content/textures/ui/LuaApp/graphic/shimmer@2x.png b/2018/content/textures/ui/LuaApp/graphic/shimmer@2x.png new file mode 100644 index 0000000..3e8a1f0 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/graphic/shimmer@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-ROBUX.png b/2018/content/textures/ui/LuaApp/icons/ic-ROBUX.png new file mode 100644 index 0000000..7d690e8 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-ROBUX.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-ROBUX@2x.png b/2018/content/textures/ui/LuaApp/icons/ic-ROBUX@2x.png new file mode 100644 index 0000000..6d88c27 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-ROBUX@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-ROBUX@3x.png b/2018/content/textures/ui/LuaApp/icons/ic-ROBUX@3x.png new file mode 100644 index 0000000..16efb3c Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-ROBUX@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-add-down.png b/2018/content/textures/ui/LuaApp/icons/ic-add-down.png new file mode 100644 index 0000000..0a3bf2b Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-add-down.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-add-down@2x.png b/2018/content/textures/ui/LuaApp/icons/ic-add-down@2x.png new file mode 100644 index 0000000..5dcd81b Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-add-down@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-add-down@3x.png b/2018/content/textures/ui/LuaApp/icons/ic-add-down@3x.png new file mode 100644 index 0000000..80ca4f4 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-add-down@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-add.png b/2018/content/textures/ui/LuaApp/icons/ic-add.png new file mode 100644 index 0000000..649ae8f Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-add.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-add@2x.png b/2018/content/textures/ui/LuaApp/icons/ic-add@2x.png new file mode 100644 index 0000000..77e1f58 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-add@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-add@3x.png b/2018/content/textures/ui/LuaApp/icons/ic-add@3x.png new file mode 100644 index 0000000..2b12c24 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-add@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-arrow-down.png b/2018/content/textures/ui/LuaApp/icons/ic-arrow-down.png new file mode 100644 index 0000000..a711550 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-arrow-down.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-arrow-down@2x.png b/2018/content/textures/ui/LuaApp/icons/ic-arrow-down@2x.png new file mode 100644 index 0000000..36ac1d3 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-arrow-down@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-arrow-down@3x.png b/2018/content/textures/ui/LuaApp/icons/ic-arrow-down@3x.png new file mode 100644 index 0000000..112080d Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-arrow-down@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-arrow-right.png b/2018/content/textures/ui/LuaApp/icons/ic-arrow-right.png new file mode 100644 index 0000000..c490b34 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-arrow-right.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-arrow-right@2x.png b/2018/content/textures/ui/LuaApp/icons/ic-arrow-right@2x.png new file mode 100644 index 0000000..5ceb151 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-arrow-right@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-arrow-right@3x.png b/2018/content/textures/ui/LuaApp/icons/ic-arrow-right@3x.png new file mode 100644 index 0000000..256287d Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-arrow-right@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-avatar-on.png b/2018/content/textures/ui/LuaApp/icons/ic-avatar-on.png new file mode 100644 index 0000000..e43d2d1 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-avatar-on.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-avatar-on@2x.png b/2018/content/textures/ui/LuaApp/icons/ic-avatar-on@2x.png new file mode 100644 index 0000000..141c91e Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-avatar-on@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-avatar-on@3x.png b/2018/content/textures/ui/LuaApp/icons/ic-avatar-on@3x.png new file mode 100644 index 0000000..f43fb54 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-avatar-on@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-avatar.png b/2018/content/textures/ui/LuaApp/icons/ic-avatar.png new file mode 100644 index 0000000..b1d9812 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-avatar.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-avatar@2x.png b/2018/content/textures/ui/LuaApp/icons/ic-avatar@2x.png new file mode 100644 index 0000000..618e1bb Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-avatar@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-avatar@3x.png b/2018/content/textures/ui/LuaApp/icons/ic-avatar@3x.png new file mode 100644 index 0000000..1ed77b2 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-avatar@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-back.png b/2018/content/textures/ui/LuaApp/icons/ic-back.png new file mode 100644 index 0000000..15ac578 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-back.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-back@2x.png b/2018/content/textures/ui/LuaApp/icons/ic-back@2x.png new file mode 100644 index 0000000..0cc111a Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-back@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-back@3x.png b/2018/content/textures/ui/LuaApp/icons/ic-back@3x.png new file mode 100644 index 0000000..7b3e002 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-back@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-bc-small.png b/2018/content/textures/ui/LuaApp/icons/ic-bc-small.png new file mode 100644 index 0000000..001177e Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-bc-small.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-bc-small@2x.png b/2018/content/textures/ui/LuaApp/icons/ic-bc-small@2x.png new file mode 100644 index 0000000..e1aa587 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-bc-small@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-bc-small@3x.png b/2018/content/textures/ui/LuaApp/icons/ic-bc-small@3x.png new file mode 100644 index 0000000..69641dc Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-bc-small@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-bc.png b/2018/content/textures/ui/LuaApp/icons/ic-bc.png new file mode 100644 index 0000000..88136ed Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-bc.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-bc@2x.png b/2018/content/textures/ui/LuaApp/icons/ic-bc@2x.png new file mode 100644 index 0000000..b3efa46 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-bc@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-bc@3x.png b/2018/content/textures/ui/LuaApp/icons/ic-bc@3x.png new file mode 100644 index 0000000..1cd43b0 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-bc@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-blue-arrow.png b/2018/content/textures/ui/LuaApp/icons/ic-blue-arrow.png new file mode 100644 index 0000000..0990a7d Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-blue-arrow.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-blue-arrow@2x.png b/2018/content/textures/ui/LuaApp/icons/ic-blue-arrow@2x.png new file mode 100644 index 0000000..6168c51 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-blue-arrow@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-blue-arrow@3x.png b/2018/content/textures/ui/LuaApp/icons/ic-blue-arrow@3x.png new file mode 100644 index 0000000..1e551f2 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-blue-arrow@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-blue-dot.png b/2018/content/textures/ui/LuaApp/icons/ic-blue-dot.png new file mode 100644 index 0000000..2b1bbec Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-blue-dot.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-blue-dot@2x.png b/2018/content/textures/ui/LuaApp/icons/ic-blue-dot@2x.png new file mode 100644 index 0000000..f7987d6 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-blue-dot@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-blue-dot@3x.png b/2018/content/textures/ui/LuaApp/icons/ic-blue-dot@3x.png new file mode 100644 index 0000000..ffe172d Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-blue-dot@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-blue-online.png b/2018/content/textures/ui/LuaApp/icons/ic-blue-online.png new file mode 100644 index 0000000..48d0e73 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-blue-online.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-blue-online@2x.png b/2018/content/textures/ui/LuaApp/icons/ic-blue-online@2x.png new file mode 100644 index 0000000..16a3035 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-blue-online@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-blue-online@3x.png b/2018/content/textures/ui/LuaApp/icons/ic-blue-online@3x.png new file mode 100644 index 0000000..9fdb8f8 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-blue-online@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-catalog-on.png b/2018/content/textures/ui/LuaApp/icons/ic-catalog-on.png new file mode 100644 index 0000000..8098e30 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-catalog-on.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-catalog-on@2x.png b/2018/content/textures/ui/LuaApp/icons/ic-catalog-on@2x.png new file mode 100644 index 0000000..05844f0 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-catalog-on@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-catalog-on@3x.png b/2018/content/textures/ui/LuaApp/icons/ic-catalog-on@3x.png new file mode 100644 index 0000000..cbd43f7 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-catalog-on@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-catalog.png b/2018/content/textures/ui/LuaApp/icons/ic-catalog.png new file mode 100644 index 0000000..685d424 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-catalog.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-catalog@2x.png b/2018/content/textures/ui/LuaApp/icons/ic-catalog@2x.png new file mode 100644 index 0000000..520649e Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-catalog@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-catalog@3x.png b/2018/content/textures/ui/LuaApp/icons/ic-catalog@3x.png new file mode 100644 index 0000000..af341f7 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-catalog@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-chat-on.png b/2018/content/textures/ui/LuaApp/icons/ic-chat-on.png new file mode 100644 index 0000000..917e770 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-chat-on.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-chat-on@2x.png b/2018/content/textures/ui/LuaApp/icons/ic-chat-on@2x.png new file mode 100644 index 0000000..11be8d6 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-chat-on@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-chat-on@3x.png b/2018/content/textures/ui/LuaApp/icons/ic-chat-on@3x.png new file mode 100644 index 0000000..d0cdd33 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-chat-on@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-chat.png b/2018/content/textures/ui/LuaApp/icons/ic-chat.png new file mode 100644 index 0000000..33bc7da Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-chat.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-chat20x20.png b/2018/content/textures/ui/LuaApp/icons/ic-chat20x20.png new file mode 100644 index 0000000..577160d Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-chat20x20.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-chat20x20@2x.png b/2018/content/textures/ui/LuaApp/icons/ic-chat20x20@2x.png new file mode 100644 index 0000000..47429b9 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-chat20x20@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-chat20x20@3x.png b/2018/content/textures/ui/LuaApp/icons/ic-chat20x20@3x.png new file mode 100644 index 0000000..c5643d2 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-chat20x20@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-chat@2x.png b/2018/content/textures/ui/LuaApp/icons/ic-chat@2x.png new file mode 100644 index 0000000..cac93c4 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-chat@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-chat@3x.png b/2018/content/textures/ui/LuaApp/icons/ic-chat@3x.png new file mode 100644 index 0000000..14476b7 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-chat@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-clear.png b/2018/content/textures/ui/LuaApp/icons/ic-clear.png new file mode 100644 index 0000000..5b76be5 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-clear.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-clear@2x.png b/2018/content/textures/ui/LuaApp/icons/ic-clear@2x.png new file mode 100644 index 0000000..15cc996 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-clear@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-clear@3x.png b/2018/content/textures/ui/LuaApp/icons/ic-clear@3x.png new file mode 100644 index 0000000..ae72f99 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-clear@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-facebook.png b/2018/content/textures/ui/LuaApp/icons/ic-facebook.png new file mode 100644 index 0000000..078d622 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-facebook.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-favorite-filled.png b/2018/content/textures/ui/LuaApp/icons/ic-favorite-filled.png new file mode 100644 index 0000000..8fa0b77 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-favorite-filled.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-favorite-filled@2x.png b/2018/content/textures/ui/LuaApp/icons/ic-favorite-filled@2x.png new file mode 100644 index 0000000..9419d89 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-favorite-filled@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-favorite.png b/2018/content/textures/ui/LuaApp/icons/ic-favorite.png new file mode 100644 index 0000000..fd51ec1 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-favorite.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-favorite@2x.png b/2018/content/textures/ui/LuaApp/icons/ic-favorite@2x.png new file mode 100644 index 0000000..ef6f41b Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-favorite@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-friend-on.png b/2018/content/textures/ui/LuaApp/icons/ic-friend-on.png new file mode 100644 index 0000000..e52eab2 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-friend-on.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-friend-on@2x.png b/2018/content/textures/ui/LuaApp/icons/ic-friend-on@2x.png new file mode 100644 index 0000000..8942e4a Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-friend-on@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-friend-on@3x.png b/2018/content/textures/ui/LuaApp/icons/ic-friend-on@3x.png new file mode 100644 index 0000000..3e69033 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-friend-on@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-friend.png b/2018/content/textures/ui/LuaApp/icons/ic-friend.png new file mode 100644 index 0000000..93b6dc6 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-friend.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-friend@2x.png b/2018/content/textures/ui/LuaApp/icons/ic-friend@2x.png new file mode 100644 index 0000000..cfb5e10 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-friend@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-friend@3x.png b/2018/content/textures/ui/LuaApp/icons/ic-friend@3x.png new file mode 100644 index 0000000..d8cbbc9 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-friend@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-game.png b/2018/content/textures/ui/LuaApp/icons/ic-game.png new file mode 100644 index 0000000..b1b1b9a Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-game.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-game@2x.png b/2018/content/textures/ui/LuaApp/icons/ic-game@2x.png new file mode 100644 index 0000000..253963b Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-game@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-game@3x.png b/2018/content/textures/ui/LuaApp/icons/ic-game@3x.png new file mode 100644 index 0000000..e488025 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-game@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-games-on.png b/2018/content/textures/ui/LuaApp/icons/ic-games-on.png new file mode 100644 index 0000000..bb6f4cc Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-games-on.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-games-on@2x.png b/2018/content/textures/ui/LuaApp/icons/ic-games-on@2x.png new file mode 100644 index 0000000..4b97f66 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-games-on@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-games-on@3x.png b/2018/content/textures/ui/LuaApp/icons/ic-games-on@3x.png new file mode 100644 index 0000000..12293e0 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-games-on@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-games.png b/2018/content/textures/ui/LuaApp/icons/ic-games.png new file mode 100644 index 0000000..8d60528 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-games.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-games@2x.png b/2018/content/textures/ui/LuaApp/icons/ic-games@2x.png new file mode 100644 index 0000000..5efd3a2 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-games@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-games@3x.png b/2018/content/textures/ui/LuaApp/icons/ic-games@3x.png new file mode 100644 index 0000000..e27091b Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-games@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-google.png b/2018/content/textures/ui/LuaApp/icons/ic-google.png new file mode 100644 index 0000000..c346524 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-google.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-gray-arrow.png b/2018/content/textures/ui/LuaApp/icons/ic-gray-arrow.png new file mode 100644 index 0000000..68c24e7 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-gray-arrow.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-gray-arrow@2x.png b/2018/content/textures/ui/LuaApp/icons/ic-gray-arrow@2x.png new file mode 100644 index 0000000..d3dbaad Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-gray-arrow@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-gray-arrow@3x.png b/2018/content/textures/ui/LuaApp/icons/ic-gray-arrow@3x.png new file mode 100644 index 0000000..6d7af72 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-gray-arrow@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-green-dot.png b/2018/content/textures/ui/LuaApp/icons/ic-green-dot.png new file mode 100644 index 0000000..de85ab0 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-green-dot.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-green-dot@2x.png b/2018/content/textures/ui/LuaApp/icons/ic-green-dot@2x.png new file mode 100644 index 0000000..90f071d Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-green-dot@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-green-dot@3x.png b/2018/content/textures/ui/LuaApp/icons/ic-green-dot@3x.png new file mode 100644 index 0000000..208af03 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-green-dot@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-green-ingame.png b/2018/content/textures/ui/LuaApp/icons/ic-green-ingame.png new file mode 100644 index 0000000..c81a6c1 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-green-ingame.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-green-ingame@2x.png b/2018/content/textures/ui/LuaApp/icons/ic-green-ingame@2x.png new file mode 100644 index 0000000..41a9db2 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-green-ingame@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-green-ingame@3x.png b/2018/content/textures/ui/LuaApp/icons/ic-green-ingame@3x.png new file mode 100644 index 0000000..788502c Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-green-ingame@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-home-on.png b/2018/content/textures/ui/LuaApp/icons/ic-home-on.png new file mode 100644 index 0000000..98b3821 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-home-on.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-home-on@2x.png b/2018/content/textures/ui/LuaApp/icons/ic-home-on@2x.png new file mode 100644 index 0000000..765d45f Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-home-on@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-home-on@3x.png b/2018/content/textures/ui/LuaApp/icons/ic-home-on@3x.png new file mode 100644 index 0000000..b7110ff Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-home-on@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-home.png b/2018/content/textures/ui/LuaApp/icons/ic-home.png new file mode 100644 index 0000000..5f29669 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-home.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-home@2x.png b/2018/content/textures/ui/LuaApp/icons/ic-home@2x.png new file mode 100644 index 0000000..67459ba Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-home@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-home@3x.png b/2018/content/textures/ui/LuaApp/icons/ic-home@3x.png new file mode 100644 index 0000000..219941c Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-home@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-more-about.png b/2018/content/textures/ui/LuaApp/icons/ic-more-about.png new file mode 100644 index 0000000..9f15260 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-more-about.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-more-about@2x.png b/2018/content/textures/ui/LuaApp/icons/ic-more-about@2x.png new file mode 100644 index 0000000..27a89a7 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-more-about@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-more-about@3x.png b/2018/content/textures/ui/LuaApp/icons/ic-more-about@3x.png new file mode 100644 index 0000000..ba4742d Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-more-about@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-more-blog.png b/2018/content/textures/ui/LuaApp/icons/ic-more-blog.png new file mode 100644 index 0000000..cabd391 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-more-blog.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-more-blog@2x.png b/2018/content/textures/ui/LuaApp/icons/ic-more-blog@2x.png new file mode 100644 index 0000000..84d3181 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-more-blog@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-more-blog@3x.png b/2018/content/textures/ui/LuaApp/icons/ic-more-blog@3x.png new file mode 100644 index 0000000..9a71c4f Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-more-blog@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-more-builders-club.png b/2018/content/textures/ui/LuaApp/icons/ic-more-builders-club.png new file mode 100644 index 0000000..a729363 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-more-builders-club.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-more-builders-club@2x.png b/2018/content/textures/ui/LuaApp/icons/ic-more-builders-club@2x.png new file mode 100644 index 0000000..15ab42e Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-more-builders-club@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-more-builders-club@3x.png b/2018/content/textures/ui/LuaApp/icons/ic-more-builders-club@3x.png new file mode 100644 index 0000000..ecbfe67 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-more-builders-club@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-more-catalog.png b/2018/content/textures/ui/LuaApp/icons/ic-more-catalog.png new file mode 100644 index 0000000..d6d740c Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-more-catalog.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-more-catalog@2x.png b/2018/content/textures/ui/LuaApp/icons/ic-more-catalog@2x.png new file mode 100644 index 0000000..10f0c09 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-more-catalog@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-more-catalog@3x.png b/2018/content/textures/ui/LuaApp/icons/ic-more-catalog@3x.png new file mode 100644 index 0000000..a2b13c6 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-more-catalog@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-more-create.png b/2018/content/textures/ui/LuaApp/icons/ic-more-create.png new file mode 100644 index 0000000..7db7b0a Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-more-create.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-more-create@2x.png b/2018/content/textures/ui/LuaApp/icons/ic-more-create@2x.png new file mode 100644 index 0000000..ad53a89 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-more-create@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-more-create@3x.png b/2018/content/textures/ui/LuaApp/icons/ic-more-create@3x.png new file mode 100644 index 0000000..05498c8 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-more-create@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-more-events.png b/2018/content/textures/ui/LuaApp/icons/ic-more-events.png new file mode 100644 index 0000000..a586238 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-more-events.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-more-events@2x.png b/2018/content/textures/ui/LuaApp/icons/ic-more-events@2x.png new file mode 100644 index 0000000..0940fc0 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-more-events@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-more-events@3x.png b/2018/content/textures/ui/LuaApp/icons/ic-more-events@3x.png new file mode 100644 index 0000000..a76e24f Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-more-events@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-more-friends.png b/2018/content/textures/ui/LuaApp/icons/ic-more-friends.png new file mode 100644 index 0000000..75366b7 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-more-friends.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-more-friends@2x.png b/2018/content/textures/ui/LuaApp/icons/ic-more-friends@2x.png new file mode 100644 index 0000000..3629480 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-more-friends@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-more-friends@3x.png b/2018/content/textures/ui/LuaApp/icons/ic-more-friends@3x.png new file mode 100644 index 0000000..91e86f5 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-more-friends@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-more-groups.png b/2018/content/textures/ui/LuaApp/icons/ic-more-groups.png new file mode 100644 index 0000000..b07c7b9 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-more-groups.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-more-groups@2x.png b/2018/content/textures/ui/LuaApp/icons/ic-more-groups@2x.png new file mode 100644 index 0000000..1e111ac Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-more-groups@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-more-groups@3x.png b/2018/content/textures/ui/LuaApp/icons/ic-more-groups@3x.png new file mode 100644 index 0000000..412bf34 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-more-groups@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-more-help.png b/2018/content/textures/ui/LuaApp/icons/ic-more-help.png new file mode 100644 index 0000000..bbe33d6 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-more-help.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-more-help@2x.png b/2018/content/textures/ui/LuaApp/icons/ic-more-help@2x.png new file mode 100644 index 0000000..8529801 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-more-help@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-more-help@3x.png b/2018/content/textures/ui/LuaApp/icons/ic-more-help@3x.png new file mode 100644 index 0000000..6f569db Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-more-help@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-more-inventory.png b/2018/content/textures/ui/LuaApp/icons/ic-more-inventory.png new file mode 100644 index 0000000..6a7a91d Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-more-inventory.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-more-inventory@2x.png b/2018/content/textures/ui/LuaApp/icons/ic-more-inventory@2x.png new file mode 100644 index 0000000..df440ed Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-more-inventory@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-more-inventory@3x.png b/2018/content/textures/ui/LuaApp/icons/ic-more-inventory@3x.png new file mode 100644 index 0000000..b622838 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-more-inventory@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-more-message.png b/2018/content/textures/ui/LuaApp/icons/ic-more-message.png new file mode 100644 index 0000000..deaef34 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-more-message.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-more-message@2x.png b/2018/content/textures/ui/LuaApp/icons/ic-more-message@2x.png new file mode 100644 index 0000000..676fa23 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-more-message@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-more-message@3x.png b/2018/content/textures/ui/LuaApp/icons/ic-more-message@3x.png new file mode 100644 index 0000000..0b3e1cb Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-more-message@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-more-on.png b/2018/content/textures/ui/LuaApp/icons/ic-more-on.png new file mode 100644 index 0000000..3cd2bb0 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-more-on.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-more-on@2x.png b/2018/content/textures/ui/LuaApp/icons/ic-more-on@2x.png new file mode 100644 index 0000000..8733a9c Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-more-on@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-more-on@3x.png b/2018/content/textures/ui/LuaApp/icons/ic-more-on@3x.png new file mode 100644 index 0000000..8bdf1e5 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-more-on@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-more-profile.png b/2018/content/textures/ui/LuaApp/icons/ic-more-profile.png new file mode 100644 index 0000000..86450b1 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-more-profile.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-more-profile@2x.png b/2018/content/textures/ui/LuaApp/icons/ic-more-profile@2x.png new file mode 100644 index 0000000..d204bff Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-more-profile@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-more-profile@3x.png b/2018/content/textures/ui/LuaApp/icons/ic-more-profile@3x.png new file mode 100644 index 0000000..c570d88 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-more-profile@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-more-settings.png b/2018/content/textures/ui/LuaApp/icons/ic-more-settings.png new file mode 100644 index 0000000..7a0f9d1 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-more-settings.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-more-settings@2x.png b/2018/content/textures/ui/LuaApp/icons/ic-more-settings@2x.png new file mode 100644 index 0000000..03a254b Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-more-settings@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-more-settings@3x.png b/2018/content/textures/ui/LuaApp/icons/ic-more-settings@3x.png new file mode 100644 index 0000000..375b1e5 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-more-settings@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-more.png b/2018/content/textures/ui/LuaApp/icons/ic-more.png new file mode 100644 index 0000000..bad7231 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-more.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-more@2x.png b/2018/content/textures/ui/LuaApp/icons/ic-more@2x.png new file mode 100644 index 0000000..2f90207 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-more@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-more@3x.png b/2018/content/textures/ui/LuaApp/icons/ic-more@3x.png new file mode 100644 index 0000000..2bc8325 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-more@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-notification.png b/2018/content/textures/ui/LuaApp/icons/ic-notification.png new file mode 100644 index 0000000..d520e19 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-notification.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-notification@2x.png b/2018/content/textures/ui/LuaApp/icons/ic-notification@2x.png new file mode 100644 index 0000000..80e5165 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-notification@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-notification@3x.png b/2018/content/textures/ui/LuaApp/icons/ic-notification@3x.png new file mode 100644 index 0000000..5f42460 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-notification@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-obc-small.png b/2018/content/textures/ui/LuaApp/icons/ic-obc-small.png new file mode 100644 index 0000000..7d460f7 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-obc-small.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-obc-small@2x.png b/2018/content/textures/ui/LuaApp/icons/ic-obc-small@2x.png new file mode 100644 index 0000000..c650f77 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-obc-small@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-obc-small@3x.png b/2018/content/textures/ui/LuaApp/icons/ic-obc-small@3x.png new file mode 100644 index 0000000..4b07abc Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-obc-small@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-obc.png b/2018/content/textures/ui/LuaApp/icons/ic-obc.png new file mode 100644 index 0000000..9cd21cd Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-obc.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-obc@2x.png b/2018/content/textures/ui/LuaApp/icons/ic-obc@2x.png new file mode 100644 index 0000000..3901b32 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-obc@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-obc@3x.png b/2018/content/textures/ui/LuaApp/icons/ic-obc@3x.png new file mode 100644 index 0000000..a6840ac Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-obc@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-orange-dot.png b/2018/content/textures/ui/LuaApp/icons/ic-orange-dot.png new file mode 100644 index 0000000..53520fc Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-orange-dot.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-orange-dot@2x.png b/2018/content/textures/ui/LuaApp/icons/ic-orange-dot@2x.png new file mode 100644 index 0000000..e74f872 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-orange-dot@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-orange-dot@3x.png b/2018/content/textures/ui/LuaApp/icons/ic-orange-dot@3x.png new file mode 100644 index 0000000..d09f935 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-orange-dot@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-orange-instudio.png b/2018/content/textures/ui/LuaApp/icons/ic-orange-instudio.png new file mode 100644 index 0000000..e055475 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-orange-instudio.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-orange-instudio@2x.png b/2018/content/textures/ui/LuaApp/icons/ic-orange-instudio@2x.png new file mode 100644 index 0000000..c5db08f Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-orange-instudio@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-orange-instudio@3x.png b/2018/content/textures/ui/LuaApp/icons/ic-orange-instudio@3x.png new file mode 100644 index 0000000..aadd900 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-orange-instudio@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-profile.png b/2018/content/textures/ui/LuaApp/icons/ic-profile.png new file mode 100644 index 0000000..fdf6f87 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-profile.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-profile@2x.png b/2018/content/textures/ui/LuaApp/icons/ic-profile@2x.png new file mode 100644 index 0000000..8649c34 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-profile@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-profile@3x.png b/2018/content/textures/ui/LuaApp/icons/ic-profile@3x.png new file mode 100644 index 0000000..bd3fe06 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-profile@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-search-gray.png b/2018/content/textures/ui/LuaApp/icons/ic-search-gray.png new file mode 100644 index 0000000..5d21cfe Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-search-gray.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-search-gray@2x.png b/2018/content/textures/ui/LuaApp/icons/ic-search-gray@2x.png new file mode 100644 index 0000000..80441e1 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-search-gray@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-search-gray@3x.png b/2018/content/textures/ui/LuaApp/icons/ic-search-gray@3x.png new file mode 100644 index 0000000..0956ce1 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-search-gray@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-search.png b/2018/content/textures/ui/LuaApp/icons/ic-search.png new file mode 100644 index 0000000..fefae0c Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-search.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-search@2x.png b/2018/content/textures/ui/LuaApp/icons/ic-search@2x.png new file mode 100644 index 0000000..8585a75 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-search@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-search@3x.png b/2018/content/textures/ui/LuaApp/icons/ic-search@3x.png new file mode 100644 index 0000000..ed9ff2f Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-search@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-tbc-small.png b/2018/content/textures/ui/LuaApp/icons/ic-tbc-small.png new file mode 100644 index 0000000..00e38c1 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-tbc-small.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-tbc-small@2x.png b/2018/content/textures/ui/LuaApp/icons/ic-tbc-small@2x.png new file mode 100644 index 0000000..83a95d1 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-tbc-small@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-tbc-small@3x.png b/2018/content/textures/ui/LuaApp/icons/ic-tbc-small@3x.png new file mode 100644 index 0000000..671613d Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-tbc-small@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-tbc.png b/2018/content/textures/ui/LuaApp/icons/ic-tbc.png new file mode 100644 index 0000000..2e589d8 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-tbc.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-tbc@2x.png b/2018/content/textures/ui/LuaApp/icons/ic-tbc@2x.png new file mode 100644 index 0000000..719eea6 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-tbc@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-tbc@3x.png b/2018/content/textures/ui/LuaApp/icons/ic-tbc@3x.png new file mode 100644 index 0000000..064496c Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-tbc@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-thumb-down.png b/2018/content/textures/ui/LuaApp/icons/ic-thumb-down.png new file mode 100644 index 0000000..d36de77 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-thumb-down.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-thumb-down@2x.png b/2018/content/textures/ui/LuaApp/icons/ic-thumb-down@2x.png new file mode 100644 index 0000000..5c5a883 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-thumb-down@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-thumbs-down-filled.png b/2018/content/textures/ui/LuaApp/icons/ic-thumbs-down-filled.png new file mode 100644 index 0000000..1976341 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-thumbs-down-filled.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-thumbs-down-filled@2x.png b/2018/content/textures/ui/LuaApp/icons/ic-thumbs-down-filled@2x.png new file mode 100644 index 0000000..d22246f Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-thumbs-down-filled@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-thumbs-down.png b/2018/content/textures/ui/LuaApp/icons/ic-thumbs-down.png new file mode 100644 index 0000000..e433915 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-thumbs-down.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-thumbs-down@2x.png b/2018/content/textures/ui/LuaApp/icons/ic-thumbs-down@2x.png new file mode 100644 index 0000000..3a8d79d Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-thumbs-down@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-thumbs-up-filled.png b/2018/content/textures/ui/LuaApp/icons/ic-thumbs-up-filled.png new file mode 100644 index 0000000..f97cbdd Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-thumbs-up-filled.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-thumbs-up-filled@2x.png b/2018/content/textures/ui/LuaApp/icons/ic-thumbs-up-filled@2x.png new file mode 100644 index 0000000..cd79bf2 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-thumbs-up-filled@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-thumbs-up.png b/2018/content/textures/ui/LuaApp/icons/ic-thumbs-up.png new file mode 100644 index 0000000..903de78 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-thumbs-up.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-thumbs-up@2x.png b/2018/content/textures/ui/LuaApp/icons/ic-thumbs-up@2x.png new file mode 100644 index 0000000..759ec68 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-thumbs-up@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-thumbup.png b/2018/content/textures/ui/LuaApp/icons/ic-thumbup.png new file mode 100644 index 0000000..1019621 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-thumbup.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-thumbup@2x.png b/2018/content/textures/ui/LuaApp/icons/ic-thumbup@2x.png new file mode 100644 index 0000000..babd290 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-thumbup@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-thumbup@3x.png b/2018/content/textures/ui/LuaApp/icons/ic-thumbup@3x.png new file mode 100644 index 0000000..df94820 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-thumbup@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-twitter.png b/2018/content/textures/ui/LuaApp/icons/ic-twitter.png new file mode 100644 index 0000000..5885087 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-twitter.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-view-details20x20.png b/2018/content/textures/ui/LuaApp/icons/ic-view-details20x20.png new file mode 100644 index 0000000..b8ec87e Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-view-details20x20.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-view-details20x20@2x.png b/2018/content/textures/ui/LuaApp/icons/ic-view-details20x20@2x.png new file mode 100644 index 0000000..b5fa7e8 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-view-details20x20@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/ic-view-details20x20@3x.png b/2018/content/textures/ui/LuaApp/icons/ic-view-details20x20@3x.png new file mode 100644 index 0000000..f5f12f5 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/ic-view-details20x20@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/icon_retry_white.png b/2018/content/textures/ui/LuaApp/icons/icon_retry_white.png new file mode 100644 index 0000000..6f7e8af Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/icon_retry_white.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/icon_retry_white@2x.png b/2018/content/textures/ui/LuaApp/icons/icon_retry_white@2x.png new file mode 100644 index 0000000..eae0f3d Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/icon_retry_white@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/icons/icon_retry_white@3x.png b/2018/content/textures/ui/LuaApp/icons/icon_retry_white@3x.png new file mode 100644 index 0000000..d30d470 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/icons/icon_retry_white@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/voteBar/bar.png b/2018/content/textures/ui/LuaApp/voteBar/bar.png new file mode 100644 index 0000000..9328ab4 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/voteBar/bar.png differ diff --git a/2018/content/textures/ui/LuaApp/voteBar/bar@2x.png b/2018/content/textures/ui/LuaApp/voteBar/bar@2x.png new file mode 100644 index 0000000..5f6967f Binary files /dev/null and b/2018/content/textures/ui/LuaApp/voteBar/bar@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/voteBar/bar@3x.png b/2018/content/textures/ui/LuaApp/voteBar/bar@3x.png new file mode 100644 index 0000000..101c893 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/voteBar/bar@3x.png differ diff --git a/2018/content/textures/ui/LuaApp/voteBar/thumbup.png b/2018/content/textures/ui/LuaApp/voteBar/thumbup.png new file mode 100644 index 0000000..47d1b9f Binary files /dev/null and b/2018/content/textures/ui/LuaApp/voteBar/thumbup.png differ diff --git a/2018/content/textures/ui/LuaApp/voteBar/thumbup@2x.png b/2018/content/textures/ui/LuaApp/voteBar/thumbup@2x.png new file mode 100644 index 0000000..98b3a1d Binary files /dev/null and b/2018/content/textures/ui/LuaApp/voteBar/thumbup@2x.png differ diff --git a/2018/content/textures/ui/LuaApp/voteBar/thumbup@3x.png b/2018/content/textures/ui/LuaApp/voteBar/thumbup@3x.png new file mode 100644 index 0000000..e1c7b32 Binary files /dev/null and b/2018/content/textures/ui/LuaApp/voteBar/thumbup@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/9-slice/btn-control-sm.png b/2018/content/textures/ui/LuaChat/9-slice/btn-control-sm.png new file mode 100644 index 0000000..0623973 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/9-slice/btn-control-sm.png differ diff --git a/2018/content/textures/ui/LuaChat/9-slice/chat-bubble-right.png b/2018/content/textures/ui/LuaChat/9-slice/chat-bubble-right.png new file mode 100644 index 0000000..b0a79f4 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/9-slice/chat-bubble-right.png differ diff --git a/2018/content/textures/ui/LuaChat/9-slice/chat-bubble-right@2x.png b/2018/content/textures/ui/LuaChat/9-slice/chat-bubble-right@2x.png new file mode 100644 index 0000000..409dbfb Binary files /dev/null and b/2018/content/textures/ui/LuaChat/9-slice/chat-bubble-right@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/9-slice/chat-bubble-right@3x.png b/2018/content/textures/ui/LuaChat/9-slice/chat-bubble-right@3x.png new file mode 100644 index 0000000..22ed017 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/9-slice/chat-bubble-right@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/9-slice/chat-bubble-self-tip.png b/2018/content/textures/ui/LuaChat/9-slice/chat-bubble-self-tip.png new file mode 100644 index 0000000..e00403f Binary files /dev/null and b/2018/content/textures/ui/LuaChat/9-slice/chat-bubble-self-tip.png differ diff --git a/2018/content/textures/ui/LuaChat/9-slice/chat-bubble-self-tip@2x.png b/2018/content/textures/ui/LuaChat/9-slice/chat-bubble-self-tip@2x.png new file mode 100644 index 0000000..cb4b777 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/9-slice/chat-bubble-self-tip@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/9-slice/chat-bubble-self-tip@3x.png b/2018/content/textures/ui/LuaChat/9-slice/chat-bubble-self-tip@3x.png new file mode 100644 index 0000000..4f2ad91 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/9-slice/chat-bubble-self-tip@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/9-slice/chat-bubble-self.png b/2018/content/textures/ui/LuaChat/9-slice/chat-bubble-self.png new file mode 100644 index 0000000..e6c833d Binary files /dev/null and b/2018/content/textures/ui/LuaChat/9-slice/chat-bubble-self.png differ diff --git a/2018/content/textures/ui/LuaChat/9-slice/chat-bubble-self2.png b/2018/content/textures/ui/LuaChat/9-slice/chat-bubble-self2.png new file mode 100644 index 0000000..b6115fc Binary files /dev/null and b/2018/content/textures/ui/LuaChat/9-slice/chat-bubble-self2.png differ diff --git a/2018/content/textures/ui/LuaChat/9-slice/chat-bubble-self2@2x.png b/2018/content/textures/ui/LuaChat/9-slice/chat-bubble-self2@2x.png new file mode 100644 index 0000000..5bacef2 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/9-slice/chat-bubble-self2@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/9-slice/chat-bubble-self2@3x.png b/2018/content/textures/ui/LuaChat/9-slice/chat-bubble-self2@3x.png new file mode 100644 index 0000000..96fb44d Binary files /dev/null and b/2018/content/textures/ui/LuaChat/9-slice/chat-bubble-self2@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/9-slice/chat-bubble-self@2x.png b/2018/content/textures/ui/LuaChat/9-slice/chat-bubble-self@2x.png new file mode 100644 index 0000000..d1128bb Binary files /dev/null and b/2018/content/textures/ui/LuaChat/9-slice/chat-bubble-self@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/9-slice/chat-bubble-self@3x.png b/2018/content/textures/ui/LuaChat/9-slice/chat-bubble-self@3x.png new file mode 100644 index 0000000..9f824af Binary files /dev/null and b/2018/content/textures/ui/LuaChat/9-slice/chat-bubble-self@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/9-slice/chat-bubble-tip-right.png b/2018/content/textures/ui/LuaChat/9-slice/chat-bubble-tip-right.png new file mode 100644 index 0000000..517b79a Binary files /dev/null and b/2018/content/textures/ui/LuaChat/9-slice/chat-bubble-tip-right.png differ diff --git a/2018/content/textures/ui/LuaChat/9-slice/chat-bubble-tip-right@2x.png b/2018/content/textures/ui/LuaChat/9-slice/chat-bubble-tip-right@2x.png new file mode 100644 index 0000000..49fed32 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/9-slice/chat-bubble-tip-right@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/9-slice/chat-bubble-tip-right@3x.png b/2018/content/textures/ui/LuaChat/9-slice/chat-bubble-tip-right@3x.png new file mode 100644 index 0000000..96e8a1e Binary files /dev/null and b/2018/content/textures/ui/LuaChat/9-slice/chat-bubble-tip-right@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/9-slice/chat-bubble-tip.png b/2018/content/textures/ui/LuaChat/9-slice/chat-bubble-tip.png new file mode 100644 index 0000000..c3e7bf6 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/9-slice/chat-bubble-tip.png differ diff --git a/2018/content/textures/ui/LuaChat/9-slice/chat-bubble-tip@2x.png b/2018/content/textures/ui/LuaChat/9-slice/chat-bubble-tip@2x.png new file mode 100644 index 0000000..e0ef139 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/9-slice/chat-bubble-tip@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/9-slice/chat-bubble-tip@3x.png b/2018/content/textures/ui/LuaChat/9-slice/chat-bubble-tip@3x.png new file mode 100644 index 0000000..1701d5a Binary files /dev/null and b/2018/content/textures/ui/LuaChat/9-slice/chat-bubble-tip@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/9-slice/chat-bubble.png b/2018/content/textures/ui/LuaChat/9-slice/chat-bubble.png new file mode 100644 index 0000000..7c6ec32 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/9-slice/chat-bubble.png differ diff --git a/2018/content/textures/ui/LuaChat/9-slice/chat-bubble2.png b/2018/content/textures/ui/LuaChat/9-slice/chat-bubble2.png new file mode 100644 index 0000000..fc86247 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/9-slice/chat-bubble2.png differ diff --git a/2018/content/textures/ui/LuaChat/9-slice/chat-bubble2@2x.png b/2018/content/textures/ui/LuaChat/9-slice/chat-bubble2@2x.png new file mode 100644 index 0000000..f7b7d40 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/9-slice/chat-bubble2@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/9-slice/chat-bubble2@3x.png b/2018/content/textures/ui/LuaChat/9-slice/chat-bubble2@3x.png new file mode 100644 index 0000000..bd0302d Binary files /dev/null and b/2018/content/textures/ui/LuaChat/9-slice/chat-bubble2@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/9-slice/chat-bubble@2x.png b/2018/content/textures/ui/LuaChat/9-slice/chat-bubble@2x.png new file mode 100644 index 0000000..8800522 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/9-slice/chat-bubble@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/9-slice/chat-bubble@3x.png b/2018/content/textures/ui/LuaChat/9-slice/chat-bubble@3x.png new file mode 100644 index 0000000..b627cb4 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/9-slice/chat-bubble@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/9-slice/error-toast.png b/2018/content/textures/ui/LuaChat/9-slice/error-toast.png new file mode 100644 index 0000000..3fcdffd Binary files /dev/null and b/2018/content/textures/ui/LuaChat/9-slice/error-toast.png differ diff --git a/2018/content/textures/ui/LuaChat/9-slice/error-toast@2x.png b/2018/content/textures/ui/LuaChat/9-slice/error-toast@2x.png new file mode 100644 index 0000000..b514105 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/9-slice/error-toast@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/9-slice/error-toast@3x.png b/2018/content/textures/ui/LuaChat/9-slice/error-toast@3x.png new file mode 100644 index 0000000..0cf667d Binary files /dev/null and b/2018/content/textures/ui/LuaChat/9-slice/error-toast@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/9-slice/gr-mask-game-icon.png b/2018/content/textures/ui/LuaChat/9-slice/gr-mask-game-icon.png new file mode 100644 index 0000000..8e2ae96 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/9-slice/gr-mask-game-icon.png differ diff --git a/2018/content/textures/ui/LuaChat/9-slice/gr-mask-game-icon@2x.png b/2018/content/textures/ui/LuaChat/9-slice/gr-mask-game-icon@2x.png new file mode 100644 index 0000000..c7020c7 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/9-slice/gr-mask-game-icon@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/9-slice/gr-mask-game-icon@3x.png b/2018/content/textures/ui/LuaChat/9-slice/gr-mask-game-icon@3x.png new file mode 100644 index 0000000..0025b77 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/9-slice/gr-mask-game-icon@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/9-slice/hello-button.png b/2018/content/textures/ui/LuaChat/9-slice/hello-button.png new file mode 100644 index 0000000..22acfff Binary files /dev/null and b/2018/content/textures/ui/LuaChat/9-slice/hello-button.png differ diff --git a/2018/content/textures/ui/LuaChat/9-slice/hello-button@2x.png b/2018/content/textures/ui/LuaChat/9-slice/hello-button@2x.png new file mode 100644 index 0000000..415d1f5 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/9-slice/hello-button@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/9-slice/hello-button@3x.png b/2018/content/textures/ui/LuaChat/9-slice/hello-button@3x.png new file mode 100644 index 0000000..5935ab4 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/9-slice/hello-button@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/9-slice/input-default.png b/2018/content/textures/ui/LuaChat/9-slice/input-default.png new file mode 100644 index 0000000..a1e3247 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/9-slice/input-default.png differ diff --git a/2018/content/textures/ui/LuaChat/9-slice/input-default@2x.png b/2018/content/textures/ui/LuaChat/9-slice/input-default@2x.png new file mode 100644 index 0000000..bad7c52 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/9-slice/input-default@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/9-slice/input-default@3x.png b/2018/content/textures/ui/LuaChat/9-slice/input-default@3x.png new file mode 100644 index 0000000..e92e175 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/9-slice/input-default@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/9-slice/input-send-message.png b/2018/content/textures/ui/LuaChat/9-slice/input-send-message.png new file mode 100644 index 0000000..0384815 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/9-slice/input-send-message.png differ diff --git a/2018/content/textures/ui/LuaChat/9-slice/input-send-message@2x.png b/2018/content/textures/ui/LuaChat/9-slice/input-send-message@2x.png new file mode 100644 index 0000000..ea0a875 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/9-slice/input-send-message@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/9-slice/input-send-message@3x.png b/2018/content/textures/ui/LuaChat/9-slice/input-send-message@3x.png new file mode 100644 index 0000000..19d5308 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/9-slice/input-send-message@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/9-slice/modal.png b/2018/content/textures/ui/LuaChat/9-slice/modal.png new file mode 100644 index 0000000..b127799 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/9-slice/modal.png differ diff --git a/2018/content/textures/ui/LuaChat/9-slice/modal@2x.png b/2018/content/textures/ui/LuaChat/9-slice/modal@2x.png new file mode 100644 index 0000000..1ffc6a9 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/9-slice/modal@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/9-slice/modal@3x.png b/2018/content/textures/ui/LuaChat/9-slice/modal@3x.png new file mode 100644 index 0000000..12d0f90 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/9-slice/modal@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/9-slice/new-message-indicator.png b/2018/content/textures/ui/LuaChat/9-slice/new-message-indicator.png new file mode 100644 index 0000000..38dd53a Binary files /dev/null and b/2018/content/textures/ui/LuaChat/9-slice/new-message-indicator.png differ diff --git a/2018/content/textures/ui/LuaChat/9-slice/new-message-indicator@2x.png b/2018/content/textures/ui/LuaChat/9-slice/new-message-indicator@2x.png new file mode 100644 index 0000000..3aa02fd Binary files /dev/null and b/2018/content/textures/ui/LuaChat/9-slice/new-message-indicator@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/9-slice/new-message-indicator@3x.png b/2018/content/textures/ui/LuaChat/9-slice/new-message-indicator@3x.png new file mode 100644 index 0000000..1287b87 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/9-slice/new-message-indicator@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/9-slice/scroll-bar.png b/2018/content/textures/ui/LuaChat/9-slice/scroll-bar.png new file mode 100644 index 0000000..c47871b Binary files /dev/null and b/2018/content/textures/ui/LuaChat/9-slice/scroll-bar.png differ diff --git a/2018/content/textures/ui/LuaChat/9-slice/scroll-bar@2x.png b/2018/content/textures/ui/LuaChat/9-slice/scroll-bar@2x.png new file mode 100644 index 0000000..bb7c513 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/9-slice/scroll-bar@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/9-slice/scroll-bar@3x.png b/2018/content/textures/ui/LuaChat/9-slice/scroll-bar@3x.png new file mode 100644 index 0000000..3e15a0d Binary files /dev/null and b/2018/content/textures/ui/LuaChat/9-slice/scroll-bar@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/9-slice/search.png b/2018/content/textures/ui/LuaChat/9-slice/search.png new file mode 100644 index 0000000..6fdddea Binary files /dev/null and b/2018/content/textures/ui/LuaChat/9-slice/search.png differ diff --git a/2018/content/textures/ui/LuaChat/9-slice/search@2x.png b/2018/content/textures/ui/LuaChat/9-slice/search@2x.png new file mode 100644 index 0000000..857edd9 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/9-slice/search@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/9-slice/search@3x.png b/2018/content/textures/ui/LuaChat/9-slice/search@3x.png new file mode 100644 index 0000000..eb8a142 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/9-slice/search@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/9-slice/system-message.png b/2018/content/textures/ui/LuaChat/9-slice/system-message.png new file mode 100644 index 0000000..d26555b Binary files /dev/null and b/2018/content/textures/ui/LuaChat/9-slice/system-message.png differ diff --git a/2018/content/textures/ui/LuaChat/9-slice/system-message@2x.png b/2018/content/textures/ui/LuaChat/9-slice/system-message@2x.png new file mode 100644 index 0000000..3d85f6f Binary files /dev/null and b/2018/content/textures/ui/LuaChat/9-slice/system-message@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/9-slice/system-message@3x.png b/2018/content/textures/ui/LuaChat/9-slice/system-message@3x.png new file mode 100644 index 0000000..3e8c804 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/9-slice/system-message@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/9-slice/tag-bubble.png b/2018/content/textures/ui/LuaChat/9-slice/tag-bubble.png new file mode 100644 index 0000000..75f482a Binary files /dev/null and b/2018/content/textures/ui/LuaChat/9-slice/tag-bubble.png differ diff --git a/2018/content/textures/ui/LuaChat/9-slice/tag-bubble@2x.png b/2018/content/textures/ui/LuaChat/9-slice/tag-bubble@2x.png new file mode 100644 index 0000000..c1a412f Binary files /dev/null and b/2018/content/textures/ui/LuaChat/9-slice/tag-bubble@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/9-slice/tag-bubble@3x.png b/2018/content/textures/ui/LuaChat/9-slice/tag-bubble@3x.png new file mode 100644 index 0000000..7ba23b8 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/9-slice/tag-bubble@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/friendmask.png b/2018/content/textures/ui/LuaChat/graphic/friendmask.png new file mode 100644 index 0000000..a42205f Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/friendmask.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-game-border-24x24.png b/2018/content/textures/ui/LuaChat/graphic/gr-game-border-24x24.png new file mode 100644 index 0000000..35db759 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-game-border-24x24.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-game-border-24x24@2x.png b/2018/content/textures/ui/LuaChat/graphic/gr-game-border-24x24@2x.png new file mode 100644 index 0000000..4886ac6 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-game-border-24x24@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-game-border-24x24@3x.png b/2018/content/textures/ui/LuaChat/graphic/gr-game-border-24x24@3x.png new file mode 100644 index 0000000..b444c76 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-game-border-24x24@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-game-border-60x60.png b/2018/content/textures/ui/LuaChat/graphic/gr-game-border-60x60.png new file mode 100644 index 0000000..0deee67 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-game-border-60x60.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-game-border-60x60@2x.png b/2018/content/textures/ui/LuaChat/graphic/gr-game-border-60x60@2x.png new file mode 100644 index 0000000..34a58a7 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-game-border-60x60@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-game-border-60x60@3x.png b/2018/content/textures/ui/LuaChat/graphic/gr-game-border-60x60@3x.png new file mode 100644 index 0000000..8daff78 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-game-border-60x60@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-gamealbum-icon-52x52.png b/2018/content/textures/ui/LuaChat/graphic/gr-gamealbum-icon-52x52.png new file mode 100644 index 0000000..d3725fe Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-gamealbum-icon-52x52.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-gamealbum-icon-52x52@2x.png b/2018/content/textures/ui/LuaChat/graphic/gr-gamealbum-icon-52x52@2x.png new file mode 100644 index 0000000..c775cab Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-gamealbum-icon-52x52@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-indicator-ingame-10x10.png b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-ingame-10x10.png new file mode 100644 index 0000000..8d7fab3 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-ingame-10x10.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-indicator-ingame-10x10@2x.png b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-ingame-10x10@2x.png new file mode 100644 index 0000000..07f3a24 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-ingame-10x10@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-indicator-ingame-10x10@3x.png b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-ingame-10x10@3x.png new file mode 100644 index 0000000..a5de74f Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-ingame-10x10@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-indicator-ingame-12x12.png b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-ingame-12x12.png new file mode 100644 index 0000000..8b59d6a Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-ingame-12x12.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-indicator-ingame-12x12@2x.png b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-ingame-12x12@2x.png new file mode 100644 index 0000000..80c2bd4 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-ingame-12x12@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-indicator-ingame-12x12@3x.png b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-ingame-12x12@3x.png new file mode 100644 index 0000000..e9eb973 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-ingame-12x12@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-indicator-ingame-14x14.png b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-ingame-14x14.png new file mode 100644 index 0000000..1200f62 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-ingame-14x14.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-indicator-ingame-14x14@2x.png b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-ingame-14x14@2x.png new file mode 100644 index 0000000..6f214d9 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-ingame-14x14@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-indicator-ingame-14x14@3x.png b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-ingame-14x14@3x.png new file mode 100644 index 0000000..8afb3a6 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-ingame-14x14@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-indicator-ingame-6x6.png b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-ingame-6x6.png new file mode 100644 index 0000000..b9d4a49 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-ingame-6x6.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-indicator-ingame-6x6@2x.png b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-ingame-6x6@2x.png new file mode 100644 index 0000000..8b59d6a Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-ingame-6x6@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-indicator-ingame-6x6@3x.png b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-ingame-6x6@3x.png new file mode 100644 index 0000000..1f90cfd Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-ingame-6x6@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-indicator-ingame-8x8.png b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-ingame-8x8.png new file mode 100644 index 0000000..be8d8c5 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-ingame-8x8.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-indicator-ingame-8x8@2x.png b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-ingame-8x8@2x.png new file mode 100644 index 0000000..c9632ff Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-ingame-8x8@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-indicator-ingame-8x8@3x.png b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-ingame-8x8@3x.png new file mode 100644 index 0000000..0d194b0 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-ingame-8x8@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-indicator-ingame.png b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-ingame.png new file mode 100644 index 0000000..f622033 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-ingame.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-indicator-ingame@2x.png b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-ingame@2x.png new file mode 100644 index 0000000..24ff925 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-ingame@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-indicator-ingame@3x.png b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-ingame@3x.png new file mode 100644 index 0000000..6866f33 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-ingame@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-indicator-instudio-10x10.png b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-instudio-10x10.png new file mode 100644 index 0000000..70bef5b Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-instudio-10x10.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-indicator-instudio-10x10@2x.png b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-instudio-10x10@2x.png new file mode 100644 index 0000000..b7d0d3f Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-instudio-10x10@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-indicator-instudio-10x10@3x.png b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-instudio-10x10@3x.png new file mode 100644 index 0000000..1daa6c7 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-instudio-10x10@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-indicator-instudio-12x12.png b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-instudio-12x12.png new file mode 100644 index 0000000..32b5368 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-instudio-12x12.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-indicator-instudio-12x12@3x.png b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-instudio-12x12@3x.png new file mode 100644 index 0000000..7c38197 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-instudio-12x12@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-indicator-instudio-12x2@2x.png b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-instudio-12x2@2x.png new file mode 100644 index 0000000..6a0afba Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-instudio-12x2@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-indicator-instudio-14x14.png b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-instudio-14x14.png new file mode 100644 index 0000000..bb74b97 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-instudio-14x14.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-indicator-instudio-14x14@2x.png b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-instudio-14x14@2x.png new file mode 100644 index 0000000..1015a19 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-instudio-14x14@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-indicator-instudio-14x14@3x.png b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-instudio-14x14@3x.png new file mode 100644 index 0000000..eeb8cee Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-instudio-14x14@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-indicator-instudio-8x8.png b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-instudio-8x8.png new file mode 100644 index 0000000..3d1a10a Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-instudio-8x8.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-indicator-instudio-8x8@2x.png b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-instudio-8x8@2x.png new file mode 100644 index 0000000..f2d5ec5 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-instudio-8x8@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-indicator-instudio-8x8@3x.png b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-instudio-8x8@3x.png new file mode 100644 index 0000000..fb9489f Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-instudio-8x8@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-indicator-instudio.png b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-instudio.png new file mode 100644 index 0000000..94c64f4 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-instudio.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-indicator-instudio@2x.png b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-instudio@2x.png new file mode 100644 index 0000000..0c6d285 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-instudio@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-indicator-instudio@3x.png b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-instudio@3x.png new file mode 100644 index 0000000..db89806 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-instudio@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-indicator-instudio_6x6.png b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-instudio_6x6.png new file mode 100644 index 0000000..afd86c0 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-instudio_6x6.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-indicator-instudio_6x6@2x.png b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-instudio_6x6@2x.png new file mode 100644 index 0000000..32b5368 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-instudio_6x6@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-indicator-instudio_6x6@3x.png b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-instudio_6x6@3x.png new file mode 100644 index 0000000..970a691 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-instudio_6x6@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-indicator-online-10x10.png b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-online-10x10.png new file mode 100644 index 0000000..6dd796d Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-online-10x10.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-indicator-online-10x10@2x.png b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-online-10x10@2x.png new file mode 100644 index 0000000..6632f9b Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-online-10x10@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-indicator-online-10x10@3x.png b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-online-10x10@3x.png new file mode 100644 index 0000000..2c39a06 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-online-10x10@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-indicator-online-12x12.png b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-online-12x12.png new file mode 100644 index 0000000..e8b271d Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-online-12x12.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-indicator-online-12x12@2x.png b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-online-12x12@2x.png new file mode 100644 index 0000000..6c3645b Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-online-12x12@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-indicator-online-12x12@3x.png b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-online-12x12@3x.png new file mode 100644 index 0000000..3b76e80 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-online-12x12@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-indicator-online-14x14.png b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-online-14x14.png new file mode 100644 index 0000000..4ee79a3 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-online-14x14.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-indicator-online-14x14@2x.png b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-online-14x14@2x.png new file mode 100644 index 0000000..2673de7 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-online-14x14@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-indicator-online-14x14@3x.png b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-online-14x14@3x.png new file mode 100644 index 0000000..26b4071 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-online-14x14@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-indicator-online-6x6.png b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-online-6x6.png new file mode 100644 index 0000000..d9f9181 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-online-6x6.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-indicator-online-6x6@2x.png b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-online-6x6@2x.png new file mode 100644 index 0000000..e8b271d Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-online-6x6@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-indicator-online-6x6@3x.png b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-online-6x6@3x.png new file mode 100644 index 0000000..e3e9c60 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-online-6x6@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-indicator-online-8x8.png b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-online-8x8.png new file mode 100644 index 0000000..d26c309 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-online-8x8.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-indicator-online-8x8@2x.png b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-online-8x8@2x.png new file mode 100644 index 0000000..b3428ea Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-online-8x8@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-indicator-online-8x8@3x.png b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-online-8x8@3x.png new file mode 100644 index 0000000..6a14d5c Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-online-8x8@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-indicator-online.png b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-online.png new file mode 100644 index 0000000..a8efbec Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-online.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-indicator-online@2x.png b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-online@2x.png new file mode 100644 index 0000000..1133089 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-online@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-indicator-online@3x.png b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-online@3x.png new file mode 100644 index 0000000..5c61715 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-indicator-online@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-mask-game-icon-48x48.png b/2018/content/textures/ui/LuaChat/graphic/gr-mask-game-icon-48x48.png new file mode 100644 index 0000000..47bd340 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-mask-game-icon-48x48.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-mask-game-icon-48x48@2x.png b/2018/content/textures/ui/LuaChat/graphic/gr-mask-game-icon-48x48@2x.png new file mode 100644 index 0000000..578a10a Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-mask-game-icon-48x48@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-numbers.png b/2018/content/textures/ui/LuaChat/graphic/gr-numbers.png new file mode 100644 index 0000000..f59ead5 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-numbers.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-numbers@2x.png b/2018/content/textures/ui/LuaChat/graphic/gr-numbers@2x.png new file mode 100644 index 0000000..b4b9fbe Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-numbers@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-numbers@3x.png b/2018/content/textures/ui/LuaChat/graphic/gr-numbers@3x.png new file mode 100644 index 0000000..4f3279f Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-numbers@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-overlay-shadow.png b/2018/content/textures/ui/LuaChat/graphic/gr-overlay-shadow.png new file mode 100644 index 0000000..4c1fa77 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-overlay-shadow.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-overlay-shadow@2x.png b/2018/content/textures/ui/LuaChat/graphic/gr-overlay-shadow@2x.png new file mode 100644 index 0000000..42e5a34 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-overlay-shadow@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-overlay-shadow@3x.png b/2018/content/textures/ui/LuaChat/graphic/gr-overlay-shadow@3x.png new file mode 100644 index 0000000..64615ab Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-overlay-shadow@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-profile-border-36x36.png b/2018/content/textures/ui/LuaChat/graphic/gr-profile-border-36x36.png new file mode 100644 index 0000000..ecab811 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-profile-border-36x36.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-profile-border-36x36@2x.png b/2018/content/textures/ui/LuaChat/graphic/gr-profile-border-36x36@2x.png new file mode 100644 index 0000000..03b94cc Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-profile-border-36x36@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-profile-border-36x36@3x.png b/2018/content/textures/ui/LuaChat/graphic/gr-profile-border-36x36@3x.png new file mode 100644 index 0000000..b0d22fe Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-profile-border-36x36@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-profile-border-48x48-dotted.png b/2018/content/textures/ui/LuaChat/graphic/gr-profile-border-48x48-dotted.png new file mode 100644 index 0000000..5917d8d Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-profile-border-48x48-dotted.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-profile-border-48x48-dotted@2x.png b/2018/content/textures/ui/LuaChat/graphic/gr-profile-border-48x48-dotted@2x.png new file mode 100644 index 0000000..911d0f7 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-profile-border-48x48-dotted@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-profile-border-48x48-dotted@3x.png b/2018/content/textures/ui/LuaChat/graphic/gr-profile-border-48x48-dotted@3x.png new file mode 100644 index 0000000..c27bf49 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-profile-border-48x48-dotted@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-profile-border-48x48.png b/2018/content/textures/ui/LuaChat/graphic/gr-profile-border-48x48.png new file mode 100644 index 0000000..e2f28f8 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-profile-border-48x48.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-profile-border-48x48@2x.png b/2018/content/textures/ui/LuaChat/graphic/gr-profile-border-48x48@2x.png new file mode 100644 index 0000000..b1cd13b Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-profile-border-48x48@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-profile-border-48x48@3x.png b/2018/content/textures/ui/LuaChat/graphic/gr-profile-border-48x48@3x.png new file mode 100644 index 0000000..9a0a00a Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-profile-border-48x48@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-send-on.png b/2018/content/textures/ui/LuaChat/graphic/gr-send-on.png new file mode 100644 index 0000000..59255c1 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-send-on.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-send-on@2x.png b/2018/content/textures/ui/LuaChat/graphic/gr-send-on@2x.png new file mode 100644 index 0000000..407fa57 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-send-on@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-send-on@3x.png b/2018/content/textures/ui/LuaChat/graphic/gr-send-on@3x.png new file mode 100644 index 0000000..ed4ad48 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-send-on@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-send.png b/2018/content/textures/ui/LuaChat/graphic/gr-send.png new file mode 100644 index 0000000..b5f28b2 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-send.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-send@2x.png b/2018/content/textures/ui/LuaChat/graphic/gr-send@2x.png new file mode 100644 index 0000000..d647c1b Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-send@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/gr-send@3x.png b/2018/content/textures/ui/LuaChat/graphic/gr-send@3x.png new file mode 100644 index 0000000..aced5ec Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/gr-send@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/ic-checkbox-on.png b/2018/content/textures/ui/LuaChat/graphic/ic-checkbox-on.png new file mode 100644 index 0000000..0390cb4 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/ic-checkbox-on.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/ic-checkbox-on@2x.png b/2018/content/textures/ui/LuaChat/graphic/ic-checkbox-on@2x.png new file mode 100644 index 0000000..9ee440a Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/ic-checkbox-on@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/ic-checkbox-on@3x.png b/2018/content/textures/ui/LuaChat/graphic/ic-checkbox-on@3x.png new file mode 100644 index 0000000..b897b38 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/ic-checkbox-on@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/ic-checkbox.png b/2018/content/textures/ui/LuaChat/graphic/ic-checkbox.png new file mode 100644 index 0000000..cfd7260 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/ic-checkbox.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/ic-checkbox@2x.png b/2018/content/textures/ui/LuaChat/graphic/ic-checkbox@2x.png new file mode 100644 index 0000000..7a04603 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/ic-checkbox@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/ic-checkbox@3x.png b/2018/content/textures/ui/LuaChat/graphic/ic-checkbox@3x.png new file mode 100644 index 0000000..09fd802 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/ic-checkbox@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/indicator-background.png b/2018/content/textures/ui/LuaChat/graphic/indicator-background.png new file mode 100644 index 0000000..c36fb92 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/indicator-background.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/send-white.png b/2018/content/textures/ui/LuaChat/graphic/send-white.png new file mode 100644 index 0000000..e9df684 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/send-white.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/send-white@2x.png b/2018/content/textures/ui/LuaChat/graphic/send-white@2x.png new file mode 100644 index 0000000..030eeee Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/send-white@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/graphic/send-white@3x.png b/2018/content/textures/ui/LuaChat/graphic/send-white@3x.png new file mode 100644 index 0000000..af160d0 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/graphic/send-white@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-add-friends.png b/2018/content/textures/ui/LuaChat/icons/ic-add-friends.png new file mode 100644 index 0000000..a68367b Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-add-friends.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-add-friends@2x.png b/2018/content/textures/ui/LuaChat/icons/ic-add-friends@2x.png new file mode 100644 index 0000000..6e1b632 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-add-friends@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-add-friends@3x.png b/2018/content/textures/ui/LuaChat/icons/ic-add-friends@3x.png new file mode 100644 index 0000000..b2a1be0 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-add-friends@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-alert.png b/2018/content/textures/ui/LuaChat/icons/ic-alert.png new file mode 100644 index 0000000..85d6d39 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-alert.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-alert@2x.png b/2018/content/textures/ui/LuaChat/icons/ic-alert@2x.png new file mode 100644 index 0000000..7fb786a Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-alert@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-alert@3x.png b/2018/content/textures/ui/LuaChat/icons/ic-alert@3x.png new file mode 100644 index 0000000..ab44ae0 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-alert@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-back-android.png b/2018/content/textures/ui/LuaChat/icons/ic-back-android.png new file mode 100644 index 0000000..2fb40d1 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-back-android.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-back-android@2x.png b/2018/content/textures/ui/LuaChat/icons/ic-back-android@2x.png new file mode 100644 index 0000000..af6490d Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-back-android@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-back.png b/2018/content/textures/ui/LuaChat/icons/ic-back.png new file mode 100644 index 0000000..42a2433 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-back.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-back@2x.png b/2018/content/textures/ui/LuaChat/icons/ic-back@2x.png new file mode 100644 index 0000000..e2b4462 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-back@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-bc.png b/2018/content/textures/ui/LuaChat/icons/ic-bc.png new file mode 100644 index 0000000..acfbdb5 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-bc.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-bc@2x.png b/2018/content/textures/ui/LuaChat/icons/ic-bc@2x.png new file mode 100644 index 0000000..be1c042 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-bc@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-bc@3x.png b/2018/content/textures/ui/LuaChat/icons/ic-bc@3x.png new file mode 100644 index 0000000..85d2fbd Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-bc@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-chat-large.png b/2018/content/textures/ui/LuaChat/icons/ic-chat-large.png new file mode 100644 index 0000000..5a7141d Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-chat-large.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-chat-large@2x.png b/2018/content/textures/ui/LuaChat/icons/ic-chat-large@2x.png new file mode 100644 index 0000000..5673f80 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-chat-large@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-chat-large@3x.png b/2018/content/textures/ui/LuaChat/icons/ic-chat-large@3x.png new file mode 100644 index 0000000..f07c89e Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-chat-large@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-check.png b/2018/content/textures/ui/LuaChat/icons/ic-check.png new file mode 100644 index 0000000..26d3557 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-check.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-check@2x.png b/2018/content/textures/ui/LuaChat/icons/ic-check@2x.png new file mode 100644 index 0000000..7791da1 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-check@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-check@3x.png b/2018/content/textures/ui/LuaChat/icons/ic-check@3x.png new file mode 100644 index 0000000..38cc530 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-check@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-checkbox-on copy.png b/2018/content/textures/ui/LuaChat/icons/ic-checkbox-on copy.png new file mode 100644 index 0000000..511e290 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-checkbox-on copy.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-checkbox-on copy@2x.png b/2018/content/textures/ui/LuaChat/icons/ic-checkbox-on copy@2x.png new file mode 100644 index 0000000..d2aa085 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-checkbox-on copy@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-checkbox-on copy@3x.png b/2018/content/textures/ui/LuaChat/icons/ic-checkbox-on copy@3x.png new file mode 100644 index 0000000..fcd44c7 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-checkbox-on copy@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-clear-gray.png b/2018/content/textures/ui/LuaChat/icons/ic-clear-gray.png new file mode 100644 index 0000000..f39bdfc Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-clear-gray.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-clear-gray@2x.png b/2018/content/textures/ui/LuaChat/icons/ic-clear-gray@2x.png new file mode 100644 index 0000000..18e07bd Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-clear-gray@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-clear-gray@3x.png b/2018/content/textures/ui/LuaChat/icons/ic-clear-gray@3x.png new file mode 100644 index 0000000..c746437 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-clear-gray@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-clear-solid.png b/2018/content/textures/ui/LuaChat/icons/ic-clear-solid.png new file mode 100644 index 0000000..5839bd5 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-clear-solid.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-clear-solid@2x.png b/2018/content/textures/ui/LuaChat/icons/ic-clear-solid@2x.png new file mode 100644 index 0000000..48b7bbf Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-clear-solid@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-clear-solid@3x.png b/2018/content/textures/ui/LuaChat/icons/ic-clear-solid@3x.png new file mode 100644 index 0000000..5ec68b8 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-clear-solid@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-close-gray2.png b/2018/content/textures/ui/LuaChat/icons/ic-close-gray2.png new file mode 100644 index 0000000..1dd1e05 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-close-gray2.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-close-gray2@2x.png b/2018/content/textures/ui/LuaChat/icons/ic-close-gray2@2x.png new file mode 100644 index 0000000..3a845ff Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-close-gray2@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-close-gray2@3x.png b/2018/content/textures/ui/LuaChat/icons/ic-close-gray2@3x.png new file mode 100644 index 0000000..3326324 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-close-gray2@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-close-white.png b/2018/content/textures/ui/LuaChat/icons/ic-close-white.png new file mode 100644 index 0000000..af8f7b8 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-close-white.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-create-group.png b/2018/content/textures/ui/LuaChat/icons/ic-create-group.png new file mode 100644 index 0000000..72c902c Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-create-group.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-create-group@2x.png b/2018/content/textures/ui/LuaChat/icons/ic-create-group@2x.png new file mode 100644 index 0000000..6041c11 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-create-group@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-create-group@3x.png b/2018/content/textures/ui/LuaChat/icons/ic-create-group@3x.png new file mode 100644 index 0000000..569e60d Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-create-group@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-createchat1-24x24.png b/2018/content/textures/ui/LuaChat/icons/ic-createchat1-24x24.png new file mode 100644 index 0000000..ad3c8f9 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-createchat1-24x24.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-createchat1-24x24@2x.png b/2018/content/textures/ui/LuaChat/icons/ic-createchat1-24x24@2x.png new file mode 100644 index 0000000..2dfef75 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-createchat1-24x24@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-createchat1-24x24@3x.png b/2018/content/textures/ui/LuaChat/icons/ic-createchat1-24x24@3x.png new file mode 100644 index 0000000..73ee9b8 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-createchat1-24x24@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-friends.png b/2018/content/textures/ui/LuaChat/icons/ic-friends.png new file mode 100644 index 0000000..c2dddec Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-friends.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-friends@2x.png b/2018/content/textures/ui/LuaChat/icons/ic-friends@2x.png new file mode 100644 index 0000000..aafb10e Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-friends@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-friends@3x.png b/2018/content/textures/ui/LuaChat/icons/ic-friends@3x.png new file mode 100644 index 0000000..c2610a8 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-friends@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-game-pressed-24x24.png b/2018/content/textures/ui/LuaChat/icons/ic-game-pressed-24x24.png new file mode 100644 index 0000000..a04a67c Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-game-pressed-24x24.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-game-pressed-24x24@2x.png b/2018/content/textures/ui/LuaChat/icons/ic-game-pressed-24x24@2x.png new file mode 100644 index 0000000..a8ee17d Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-game-pressed-24x24@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-game-pressed-24x24@3x.png b/2018/content/textures/ui/LuaChat/icons/ic-game-pressed-24x24@3x.png new file mode 100644 index 0000000..9276f55 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-game-pressed-24x24@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-game.png b/2018/content/textures/ui/LuaChat/icons/ic-game.png new file mode 100644 index 0000000..aeb09dc Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-game.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-game@2x.png b/2018/content/textures/ui/LuaChat/icons/ic-game@2x.png new file mode 100644 index 0000000..233dbe2 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-game@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-game@3x.png b/2018/content/textures/ui/LuaChat/icons/ic-game@3x.png new file mode 100644 index 0000000..4334107 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-game@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-group-16x16.png b/2018/content/textures/ui/LuaChat/icons/ic-group-16x16.png new file mode 100644 index 0000000..4be38ac Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-group-16x16.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-group-16x16@2x.png b/2018/content/textures/ui/LuaChat/icons/ic-group-16x16@2x.png new file mode 100644 index 0000000..2d02bf0 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-group-16x16@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-group-16x16@3x.png b/2018/content/textures/ui/LuaChat/icons/ic-group-16x16@3x.png new file mode 100644 index 0000000..a3204eb Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-group-16x16@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-group.png b/2018/content/textures/ui/LuaChat/icons/ic-group.png new file mode 100644 index 0000000..db3b1b7 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-group.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-group@2x.png b/2018/content/textures/ui/LuaChat/icons/ic-group@2x.png new file mode 100644 index 0000000..48ec989 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-group@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-group@3x.png b/2018/content/textures/ui/LuaChat/icons/ic-group@3x.png new file mode 100644 index 0000000..38a5549 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-group@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-info.png b/2018/content/textures/ui/LuaChat/icons/ic-info.png new file mode 100644 index 0000000..0a9e434 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-info.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-info@2x.png b/2018/content/textures/ui/LuaChat/icons/ic-info@2x.png new file mode 100644 index 0000000..2801509 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-info@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-info@3x.png b/2018/content/textures/ui/LuaChat/icons/ic-info@3x.png new file mode 100644 index 0000000..2fb4765 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-info@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-leave.png b/2018/content/textures/ui/LuaChat/icons/ic-leave.png new file mode 100644 index 0000000..136f273 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-leave.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-leave@2x.png b/2018/content/textures/ui/LuaChat/icons/ic-leave@2x.png new file mode 100644 index 0000000..53f544f Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-leave@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-leave@3x.png b/2018/content/textures/ui/LuaChat/icons/ic-leave@3x.png new file mode 100644 index 0000000..57966c6 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-leave@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-more.png b/2018/content/textures/ui/LuaChat/icons/ic-more.png new file mode 100644 index 0000000..718010b Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-more.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-more@2x.png b/2018/content/textures/ui/LuaChat/icons/ic-more@2x.png new file mode 100644 index 0000000..d107f2f Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-more@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-more@3x.png b/2018/content/textures/ui/LuaChat/icons/ic-more@3x.png new file mode 100644 index 0000000..7d871a6 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-more@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-nametag.png b/2018/content/textures/ui/LuaChat/icons/ic-nametag.png new file mode 100644 index 0000000..eee203e Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-nametag.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-nametag@2x.png b/2018/content/textures/ui/LuaChat/icons/ic-nametag@2x.png new file mode 100644 index 0000000..1dc795d Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-nametag@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-nametag@3x.png b/2018/content/textures/ui/LuaChat/icons/ic-nametag@3x.png new file mode 100644 index 0000000..ad7710f Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-nametag@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-notification.png b/2018/content/textures/ui/LuaChat/icons/ic-notification.png new file mode 100644 index 0000000..7cc3f5d Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-notification.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-notification@2x.png b/2018/content/textures/ui/LuaChat/icons/ic-notification@2x.png new file mode 100644 index 0000000..7db1065 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-notification@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-notification@3x.png b/2018/content/textures/ui/LuaChat/icons/ic-notification@3x.png new file mode 100644 index 0000000..c49aa2b Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-notification@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-pin.png b/2018/content/textures/ui/LuaChat/icons/ic-pin.png new file mode 100644 index 0000000..f7a8d92 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-pin.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-pin@2x.png b/2018/content/textures/ui/LuaChat/icons/ic-pin@2x.png new file mode 100644 index 0000000..9befe4b Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-pin@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-pin@3x.png b/2018/content/textures/ui/LuaChat/icons/ic-pin@3x.png new file mode 100644 index 0000000..7387c33 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-pin@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-pinpressed.png b/2018/content/textures/ui/LuaChat/icons/ic-pinpressed.png new file mode 100644 index 0000000..b893f0b Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-pinpressed.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-pinpressed@2x.png b/2018/content/textures/ui/LuaChat/icons/ic-pinpressed@2x.png new file mode 100644 index 0000000..1103fa5 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-pinpressed@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-pinpressed@3x.png b/2018/content/textures/ui/LuaChat/icons/ic-pinpressed@3x.png new file mode 100644 index 0000000..37bfbc5 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-pinpressed@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-profile.png b/2018/content/textures/ui/LuaChat/icons/ic-profile.png new file mode 100644 index 0000000..fdf6f87 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-profile.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-profile@2x.png b/2018/content/textures/ui/LuaChat/icons/ic-profile@2x.png new file mode 100644 index 0000000..8649c34 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-profile@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-profile@3x.png b/2018/content/textures/ui/LuaChat/icons/ic-profile@3x.png new file mode 100644 index 0000000..bd3fe06 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-profile@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-remove.png b/2018/content/textures/ui/LuaChat/icons/ic-remove.png new file mode 100644 index 0000000..089dba9 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-remove.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-remove@2x.png b/2018/content/textures/ui/LuaChat/icons/ic-remove@2x.png new file mode 100644 index 0000000..a43d237 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-remove@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-remove@3x.png b/2018/content/textures/ui/LuaChat/icons/ic-remove@3x.png new file mode 100644 index 0000000..0185b15 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-remove@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-resend.png b/2018/content/textures/ui/LuaChat/icons/ic-resend.png new file mode 100644 index 0000000..464bc87 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-resend.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-resend@2x.png b/2018/content/textures/ui/LuaChat/icons/ic-resend@2x.png new file mode 100644 index 0000000..065d260 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-resend@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-resend@3x.png b/2018/content/textures/ui/LuaChat/icons/ic-resend@3x.png new file mode 100644 index 0000000..c93f1d8 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-resend@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-robux.png b/2018/content/textures/ui/LuaChat/icons/ic-robux.png new file mode 100644 index 0000000..30e32cf Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-robux.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-robux@2x.png b/2018/content/textures/ui/LuaChat/icons/ic-robux@2x.png new file mode 100644 index 0000000..b181a12 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-robux@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-robux@3x.png b/2018/content/textures/ui/LuaChat/icons/ic-robux@3x.png new file mode 100644 index 0000000..67f39f5 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-robux@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-search-gray.png b/2018/content/textures/ui/LuaChat/icons/ic-search-gray.png new file mode 100644 index 0000000..f2e0f74 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-search-gray.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-search-gray@2x.png b/2018/content/textures/ui/LuaChat/icons/ic-search-gray@2x.png new file mode 100644 index 0000000..52661b5 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-search-gray@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-search-gray@3x.png b/2018/content/textures/ui/LuaChat/icons/ic-search-gray@3x.png new file mode 100644 index 0000000..365865f Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-search-gray@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-search.png b/2018/content/textures/ui/LuaChat/icons/ic-search.png new file mode 100644 index 0000000..fefae0c Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-search.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-search@2x.png b/2018/content/textures/ui/LuaChat/icons/ic-search@2x.png new file mode 100644 index 0000000..8585a75 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-search@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-search@3x.png b/2018/content/textures/ui/LuaChat/icons/ic-search@3x.png new file mode 100644 index 0000000..ed9ff2f Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-search@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-send.png b/2018/content/textures/ui/LuaChat/icons/ic-send.png new file mode 100644 index 0000000..c6951c1 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-send.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-send@2x.png b/2018/content/textures/ui/LuaChat/icons/ic-send@2x.png new file mode 100644 index 0000000..d0afa8b Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-send@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-send@3x.png b/2018/content/textures/ui/LuaChat/icons/ic-send@3x.png new file mode 100644 index 0000000..41a0658 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-send@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-unpin-20x20.png b/2018/content/textures/ui/LuaChat/icons/ic-unpin-20x20.png new file mode 100644 index 0000000..61f6d2e Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-unpin-20x20.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-unpin-20x20@2x.png b/2018/content/textures/ui/LuaChat/icons/ic-unpin-20x20@2x.png new file mode 100644 index 0000000..6661058 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-unpin-20x20@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-unpin-20x20@3x.png b/2018/content/textures/ui/LuaChat/icons/ic-unpin-20x20@3x.png new file mode 100644 index 0000000..be0e5a8 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-unpin-20x20@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-viewdetails-20x20.png b/2018/content/textures/ui/LuaChat/icons/ic-viewdetails-20x20.png new file mode 100644 index 0000000..b8ec87e Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-viewdetails-20x20.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-viewdetails-20x20@2x.png b/2018/content/textures/ui/LuaChat/icons/ic-viewdetails-20x20@2x.png new file mode 100644 index 0000000..b5fa7e8 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-viewdetails-20x20@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/ic-viewdetails-20x20@3x.png b/2018/content/textures/ui/LuaChat/icons/ic-viewdetails-20x20@3x.png new file mode 100644 index 0000000..f5f12f5 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/ic-viewdetails-20x20@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/icon-share-game-24x24.png b/2018/content/textures/ui/LuaChat/icons/icon-share-game-24x24.png new file mode 100644 index 0000000..119547d Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/icon-share-game-24x24.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/icon-share-game-24x24@2x.png b/2018/content/textures/ui/LuaChat/icons/icon-share-game-24x24@2x.png new file mode 100644 index 0000000..47ecc6b Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/icon-share-game-24x24@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/icon-share-game-24x24@3x.png b/2018/content/textures/ui/LuaChat/icons/icon-share-game-24x24@3x.png new file mode 100644 index 0000000..0bc59ee Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/icon-share-game-24x24@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/icon-share-game-pressed-24x24.png b/2018/content/textures/ui/LuaChat/icons/icon-share-game-pressed-24x24.png new file mode 100644 index 0000000..e72edaa Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/icon-share-game-pressed-24x24.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/icon-share-game-pressed-24x24@2x.png b/2018/content/textures/ui/LuaChat/icons/icon-share-game-pressed-24x24@2x.png new file mode 100644 index 0000000..3691a33 Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/icon-share-game-pressed-24x24@2x.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/icon-share-game-pressed-24x24@3x.png b/2018/content/textures/ui/LuaChat/icons/icon-share-game-pressed-24x24@3x.png new file mode 100644 index 0000000..bf9e31b Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/icon-share-game-pressed-24x24@3x.png differ diff --git a/2018/content/textures/ui/LuaChat/icons/share-game-thumbnail.png b/2018/content/textures/ui/LuaChat/icons/share-game-thumbnail.png new file mode 100644 index 0000000..1c4b30e Binary files /dev/null and b/2018/content/textures/ui/LuaChat/icons/share-game-thumbnail.png differ diff --git a/2018/content/textures/ui/Menu/Hamburger.png b/2018/content/textures/ui/Menu/Hamburger.png new file mode 100644 index 0000000..6e0c2e4 Binary files /dev/null and b/2018/content/textures/ui/Menu/Hamburger.png differ diff --git a/2018/content/textures/ui/Menu/Hamburger@2x.png b/2018/content/textures/ui/Menu/Hamburger@2x.png new file mode 100644 index 0000000..a5ce478 Binary files /dev/null and b/2018/content/textures/ui/Menu/Hamburger@2x.png differ diff --git a/2018/content/textures/ui/Menu/HamburgerDown.png b/2018/content/textures/ui/Menu/HamburgerDown.png new file mode 100644 index 0000000..aaf1032 Binary files /dev/null and b/2018/content/textures/ui/Menu/HamburgerDown.png differ diff --git a/2018/content/textures/ui/Menu/HamburgerDown@2x.png b/2018/content/textures/ui/Menu/HamburgerDown@2x.png new file mode 100644 index 0000000..43ab55c Binary files /dev/null and b/2018/content/textures/ui/Menu/HamburgerDown@2x.png differ diff --git a/2018/content/textures/ui/Menu/buttonActive.png b/2018/content/textures/ui/Menu/buttonActive.png new file mode 100644 index 0000000..f685760 Binary files /dev/null and b/2018/content/textures/ui/Menu/buttonActive.png differ diff --git a/2018/content/textures/ui/Menu/buttonBackground.png b/2018/content/textures/ui/Menu/buttonBackground.png new file mode 100644 index 0000000..379241a Binary files /dev/null and b/2018/content/textures/ui/Menu/buttonBackground.png differ diff --git a/2018/content/textures/ui/Menu/buttonHover.png b/2018/content/textures/ui/Menu/buttonHover.png new file mode 100644 index 0000000..916ddff Binary files /dev/null and b/2018/content/textures/ui/Menu/buttonHover.png differ diff --git a/2018/content/textures/ui/Menu/hamburger3D.png b/2018/content/textures/ui/Menu/hamburger3D.png new file mode 100644 index 0000000..a9d70c5 Binary files /dev/null and b/2018/content/textures/ui/Menu/hamburger3D.png differ diff --git a/2018/content/textures/ui/Menu/hoverPopupLeft.png b/2018/content/textures/ui/Menu/hoverPopupLeft.png new file mode 100644 index 0000000..484b0d2 Binary files /dev/null and b/2018/content/textures/ui/Menu/hoverPopupLeft.png differ diff --git a/2018/content/textures/ui/Menu/hoverPopupMid.png b/2018/content/textures/ui/Menu/hoverPopupMid.png new file mode 100644 index 0000000..0f55008 Binary files /dev/null and b/2018/content/textures/ui/Menu/hoverPopupMid.png differ diff --git a/2018/content/textures/ui/Menu/hoverPopupRight.png b/2018/content/textures/ui/Menu/hoverPopupRight.png new file mode 100644 index 0000000..ea0b32a Binary files /dev/null and b/2018/content/textures/ui/Menu/hoverPopupRight.png differ diff --git a/2018/content/textures/ui/Menu/rectBackground.png b/2018/content/textures/ui/Menu/rectBackground.png new file mode 100644 index 0000000..758edfe Binary files /dev/null and b/2018/content/textures/ui/Menu/rectBackground.png differ diff --git a/2018/content/textures/ui/Menu/rectBackgroundWhite.png b/2018/content/textures/ui/Menu/rectBackgroundWhite.png new file mode 100644 index 0000000..6bbb4b6 Binary files /dev/null and b/2018/content/textures/ui/Menu/rectBackgroundWhite.png differ diff --git a/2018/content/textures/ui/Modal.png b/2018/content/textures/ui/Modal.png new file mode 100644 index 0000000..ec08e5b Binary files /dev/null and b/2018/content/textures/ui/Modal.png differ diff --git a/2018/content/textures/ui/Motor.png b/2018/content/textures/ui/Motor.png new file mode 100644 index 0000000..140c5cc Binary files /dev/null and b/2018/content/textures/ui/Motor.png differ diff --git a/2018/content/textures/ui/PerformanceStats/BackgroundRounded.png b/2018/content/textures/ui/PerformanceStats/BackgroundRounded.png new file mode 100644 index 0000000..763d78e Binary files /dev/null and b/2018/content/textures/ui/PerformanceStats/BackgroundRounded.png differ diff --git a/2018/content/textures/ui/PerformanceStats/OvalKey.png b/2018/content/textures/ui/PerformanceStats/OvalKey.png new file mode 100644 index 0000000..90678c2 Binary files /dev/null and b/2018/content/textures/ui/PerformanceStats/OvalKey.png differ diff --git a/2018/content/textures/ui/PerformanceStats/TargetFiller.png b/2018/content/textures/ui/PerformanceStats/TargetFiller.png new file mode 100644 index 0000000..839cc28 Binary files /dev/null and b/2018/content/textures/ui/PerformanceStats/TargetFiller.png differ diff --git a/2018/content/textures/ui/PerformanceStats/TargetKey.png b/2018/content/textures/ui/PerformanceStats/TargetKey.png new file mode 100644 index 0000000..9008605 Binary files /dev/null and b/2018/content/textures/ui/PerformanceStats/TargetKey.png differ diff --git a/2018/content/textures/ui/PerformanceStats/TargetLine.png b/2018/content/textures/ui/PerformanceStats/TargetLine.png new file mode 100644 index 0000000..c1b434a Binary files /dev/null and b/2018/content/textures/ui/PerformanceStats/TargetLine.png differ diff --git a/2018/content/textures/ui/Plastic.png b/2018/content/textures/ui/Plastic.png new file mode 100644 index 0000000..0dd2054 Binary files /dev/null and b/2018/content/textures/ui/Plastic.png differ diff --git a/2018/content/textures/ui/PlayerList/BlockedIcon.png b/2018/content/textures/ui/PlayerList/BlockedIcon.png new file mode 100644 index 0000000..1ddb436 Binary files /dev/null and b/2018/content/textures/ui/PlayerList/BlockedIcon.png differ diff --git a/2018/content/textures/ui/PlayerList/CharacterImageBackground.png b/2018/content/textures/ui/PlayerList/CharacterImageBackground.png new file mode 100644 index 0000000..2620ac5 Binary files /dev/null and b/2018/content/textures/ui/PlayerList/CharacterImageBackground.png differ diff --git a/2018/content/textures/ui/PlayerList/TileShadowMissingTop.png b/2018/content/textures/ui/PlayerList/TileShadowMissingTop.png new file mode 100644 index 0000000..d09f5fb Binary files /dev/null and b/2018/content/textures/ui/PlayerList/TileShadowMissingTop.png differ diff --git a/2018/content/textures/ui/RecordDown.png b/2018/content/textures/ui/RecordDown.png new file mode 100644 index 0000000..9708d84 Binary files /dev/null and b/2018/content/textures/ui/RecordDown.png differ diff --git a/2018/content/textures/ui/ResetIcon.png b/2018/content/textures/ui/ResetIcon.png new file mode 100644 index 0000000..b16996e Binary files /dev/null and b/2018/content/textures/ui/ResetIcon.png differ diff --git a/2018/content/textures/ui/RobloxNameIcon.png b/2018/content/textures/ui/RobloxNameIcon.png new file mode 100644 index 0000000..360d9c2 Binary files /dev/null and b/2018/content/textures/ui/RobloxNameIcon.png differ diff --git a/2018/content/textures/ui/RobuxIcon.png b/2018/content/textures/ui/RobuxIcon.png new file mode 100644 index 0000000..d14fe16 Binary files /dev/null and b/2018/content/textures/ui/RobuxIcon.png differ diff --git a/2018/content/textures/ui/Scroll/scroll-bottom.png b/2018/content/textures/ui/Scroll/scroll-bottom.png new file mode 100644 index 0000000..9c5695c Binary files /dev/null and b/2018/content/textures/ui/Scroll/scroll-bottom.png differ diff --git a/2018/content/textures/ui/Scroll/scroll-bottom@2x.png b/2018/content/textures/ui/Scroll/scroll-bottom@2x.png new file mode 100644 index 0000000..85b70e6 Binary files /dev/null and b/2018/content/textures/ui/Scroll/scroll-bottom@2x.png differ diff --git a/2018/content/textures/ui/Scroll/scroll-middle.png b/2018/content/textures/ui/Scroll/scroll-middle.png new file mode 100644 index 0000000..f4489d7 Binary files /dev/null and b/2018/content/textures/ui/Scroll/scroll-middle.png differ diff --git a/2018/content/textures/ui/Scroll/scroll-middle@2x.png b/2018/content/textures/ui/Scroll/scroll-middle@2x.png new file mode 100644 index 0000000..22d0f11 Binary files /dev/null and b/2018/content/textures/ui/Scroll/scroll-middle@2x.png differ diff --git a/2018/content/textures/ui/Scroll/scroll-top.png b/2018/content/textures/ui/Scroll/scroll-top.png new file mode 100644 index 0000000..bc6dcce Binary files /dev/null and b/2018/content/textures/ui/Scroll/scroll-top.png differ diff --git a/2018/content/textures/ui/Scroll/scroll-top@2x.png b/2018/content/textures/ui/Scroll/scroll-top@2x.png new file mode 100644 index 0000000..0ead0e8 Binary files /dev/null and b/2018/content/textures/ui/Scroll/scroll-top@2x.png differ diff --git a/2018/content/textures/ui/SearchIcon.png b/2018/content/textures/ui/SearchIcon.png new file mode 100644 index 0000000..58772d0 Binary files /dev/null and b/2018/content/textures/ui/SearchIcon.png differ diff --git a/2018/content/textures/ui/SelectionBox.png b/2018/content/textures/ui/SelectionBox.png new file mode 100644 index 0000000..290b647 Binary files /dev/null and b/2018/content/textures/ui/SelectionBox.png differ diff --git a/2018/content/textures/ui/SelectionBox@2x.png b/2018/content/textures/ui/SelectionBox@2x.png new file mode 100644 index 0000000..65d1711 Binary files /dev/null and b/2018/content/textures/ui/SelectionBox@2x.png differ diff --git a/2018/content/textures/ui/Settings/DropDown/DropDown.png b/2018/content/textures/ui/Settings/DropDown/DropDown.png new file mode 100644 index 0000000..39e6dc8 Binary files /dev/null and b/2018/content/textures/ui/Settings/DropDown/DropDown.png differ diff --git a/2018/content/textures/ui/Settings/DropDown/DropDown@2x.png b/2018/content/textures/ui/Settings/DropDown/DropDown@2x.png new file mode 100644 index 0000000..ccdd651 Binary files /dev/null and b/2018/content/textures/ui/Settings/DropDown/DropDown@2x.png differ diff --git a/2018/content/textures/ui/Settings/Help/AButtonDark.png b/2018/content/textures/ui/Settings/Help/AButtonDark.png new file mode 100644 index 0000000..da4ec7a Binary files /dev/null and b/2018/content/textures/ui/Settings/Help/AButtonDark.png differ diff --git a/2018/content/textures/ui/Settings/Help/AButtonDark@2x.png b/2018/content/textures/ui/Settings/Help/AButtonDark@2x.png new file mode 100644 index 0000000..b2e9cba Binary files /dev/null and b/2018/content/textures/ui/Settings/Help/AButtonDark@2x.png differ diff --git a/2018/content/textures/ui/Settings/Help/AButtonLight.png b/2018/content/textures/ui/Settings/Help/AButtonLight.png new file mode 100644 index 0000000..431e4a7 Binary files /dev/null and b/2018/content/textures/ui/Settings/Help/AButtonLight.png differ diff --git a/2018/content/textures/ui/Settings/Help/AButtonLight@2x.png b/2018/content/textures/ui/Settings/Help/AButtonLight@2x.png new file mode 100644 index 0000000..d140dba Binary files /dev/null and b/2018/content/textures/ui/Settings/Help/AButtonLight@2x.png differ diff --git a/2018/content/textures/ui/Settings/Help/AButtonLightSmall.png b/2018/content/textures/ui/Settings/Help/AButtonLightSmall.png new file mode 100644 index 0000000..50f8035 Binary files /dev/null and b/2018/content/textures/ui/Settings/Help/AButtonLightSmall.png differ diff --git a/2018/content/textures/ui/Settings/Help/BButtonDark.png b/2018/content/textures/ui/Settings/Help/BButtonDark.png new file mode 100644 index 0000000..9b607a9 Binary files /dev/null and b/2018/content/textures/ui/Settings/Help/BButtonDark.png differ diff --git a/2018/content/textures/ui/Settings/Help/BButtonDark@2x.png b/2018/content/textures/ui/Settings/Help/BButtonDark@2x.png new file mode 100644 index 0000000..df1a1a5 Binary files /dev/null and b/2018/content/textures/ui/Settings/Help/BButtonDark@2x.png differ diff --git a/2018/content/textures/ui/Settings/Help/BButtonLight.png b/2018/content/textures/ui/Settings/Help/BButtonLight.png new file mode 100644 index 0000000..598b7b9 Binary files /dev/null and b/2018/content/textures/ui/Settings/Help/BButtonLight.png differ diff --git a/2018/content/textures/ui/Settings/Help/BButtonLight@2x.png b/2018/content/textures/ui/Settings/Help/BButtonLight@2x.png new file mode 100644 index 0000000..e2e67db Binary files /dev/null and b/2018/content/textures/ui/Settings/Help/BButtonLight@2x.png differ diff --git a/2018/content/textures/ui/Settings/Help/EscapeIcon.png b/2018/content/textures/ui/Settings/Help/EscapeIcon.png new file mode 100644 index 0000000..7c53d55 Binary files /dev/null and b/2018/content/textures/ui/Settings/Help/EscapeIcon.png differ diff --git a/2018/content/textures/ui/Settings/Help/GenericController.png b/2018/content/textures/ui/Settings/Help/GenericController.png new file mode 100644 index 0000000..db52b1f Binary files /dev/null and b/2018/content/textures/ui/Settings/Help/GenericController.png differ diff --git a/2018/content/textures/ui/Settings/Help/GenericController@2x.png b/2018/content/textures/ui/Settings/Help/GenericController@2x.png new file mode 100644 index 0000000..3735735 Binary files /dev/null and b/2018/content/textures/ui/Settings/Help/GenericController@2x.png differ diff --git a/2018/content/textures/ui/Settings/Help/LeaveIcon.png b/2018/content/textures/ui/Settings/Help/LeaveIcon.png new file mode 100644 index 0000000..6d780ae Binary files /dev/null and b/2018/content/textures/ui/Settings/Help/LeaveIcon.png differ diff --git a/2018/content/textures/ui/Settings/Help/ResetIcon.png b/2018/content/textures/ui/Settings/Help/ResetIcon.png new file mode 100644 index 0000000..391ac31 Binary files /dev/null and b/2018/content/textures/ui/Settings/Help/ResetIcon.png differ diff --git a/2018/content/textures/ui/Settings/Help/RotateCameraGesture.png b/2018/content/textures/ui/Settings/Help/RotateCameraGesture.png new file mode 100644 index 0000000..c0147d6 Binary files /dev/null and b/2018/content/textures/ui/Settings/Help/RotateCameraGesture.png differ diff --git a/2018/content/textures/ui/Settings/Help/UseToolGesture.png b/2018/content/textures/ui/Settings/Help/UseToolGesture.png new file mode 100644 index 0000000..fe3c364 Binary files /dev/null and b/2018/content/textures/ui/Settings/Help/UseToolGesture.png differ diff --git a/2018/content/textures/ui/Settings/Help/XButtonDark.png b/2018/content/textures/ui/Settings/Help/XButtonDark.png new file mode 100644 index 0000000..cc71edc Binary files /dev/null and b/2018/content/textures/ui/Settings/Help/XButtonDark.png differ diff --git a/2018/content/textures/ui/Settings/Help/XButtonDark@2x.png b/2018/content/textures/ui/Settings/Help/XButtonDark@2x.png new file mode 100644 index 0000000..0d53c7a Binary files /dev/null and b/2018/content/textures/ui/Settings/Help/XButtonDark@2x.png differ diff --git a/2018/content/textures/ui/Settings/Help/XButtonLight.png b/2018/content/textures/ui/Settings/Help/XButtonLight.png new file mode 100644 index 0000000..62c13ec Binary files /dev/null and b/2018/content/textures/ui/Settings/Help/XButtonLight.png differ diff --git a/2018/content/textures/ui/Settings/Help/XButtonLight@2x.png b/2018/content/textures/ui/Settings/Help/XButtonLight@2x.png new file mode 100644 index 0000000..1d5bc77 Binary files /dev/null and b/2018/content/textures/ui/Settings/Help/XButtonLight@2x.png differ diff --git a/2018/content/textures/ui/Settings/Help/XboxController.png b/2018/content/textures/ui/Settings/Help/XboxController.png new file mode 100644 index 0000000..882124a Binary files /dev/null and b/2018/content/textures/ui/Settings/Help/XboxController.png differ diff --git a/2018/content/textures/ui/Settings/Help/XboxController@2x.png b/2018/content/textures/ui/Settings/Help/XboxController@2x.png new file mode 100644 index 0000000..9ea335a Binary files /dev/null and b/2018/content/textures/ui/Settings/Help/XboxController@2x.png differ diff --git a/2018/content/textures/ui/Settings/Help/YButtonDark.png b/2018/content/textures/ui/Settings/Help/YButtonDark.png new file mode 100644 index 0000000..131c8ca Binary files /dev/null and b/2018/content/textures/ui/Settings/Help/YButtonDark.png differ diff --git a/2018/content/textures/ui/Settings/Help/YButtonDark@2x.png b/2018/content/textures/ui/Settings/Help/YButtonDark@2x.png new file mode 100644 index 0000000..3b5e223 Binary files /dev/null and b/2018/content/textures/ui/Settings/Help/YButtonDark@2x.png differ diff --git a/2018/content/textures/ui/Settings/Help/YButtonLight.png b/2018/content/textures/ui/Settings/Help/YButtonLight.png new file mode 100644 index 0000000..56ce742 Binary files /dev/null and b/2018/content/textures/ui/Settings/Help/YButtonLight.png differ diff --git a/2018/content/textures/ui/Settings/Help/YButtonLight@2x.png b/2018/content/textures/ui/Settings/Help/YButtonLight@2x.png new file mode 100644 index 0000000..1a3ee30 Binary files /dev/null and b/2018/content/textures/ui/Settings/Help/YButtonLight@2x.png differ diff --git a/2018/content/textures/ui/Settings/Help/ZoomGesture.png b/2018/content/textures/ui/Settings/Help/ZoomGesture.png new file mode 100644 index 0000000..68ee910 Binary files /dev/null and b/2018/content/textures/ui/Settings/Help/ZoomGesture.png differ diff --git a/2018/content/textures/ui/Settings/MenuBarAssets/MenuBackground.png b/2018/content/textures/ui/Settings/MenuBarAssets/MenuBackground.png new file mode 100644 index 0000000..4614da6 Binary files /dev/null and b/2018/content/textures/ui/Settings/MenuBarAssets/MenuBackground.png differ diff --git a/2018/content/textures/ui/Settings/MenuBarAssets/MenuButton.png b/2018/content/textures/ui/Settings/MenuBarAssets/MenuButton.png new file mode 100644 index 0000000..632c7d2 Binary files /dev/null and b/2018/content/textures/ui/Settings/MenuBarAssets/MenuButton.png differ diff --git a/2018/content/textures/ui/Settings/MenuBarAssets/MenuButton@2x.png b/2018/content/textures/ui/Settings/MenuBarAssets/MenuButton@2x.png new file mode 100644 index 0000000..a7f7a27 Binary files /dev/null and b/2018/content/textures/ui/Settings/MenuBarAssets/MenuButton@2x.png differ diff --git a/2018/content/textures/ui/Settings/MenuBarAssets/MenuButtonSelected.png b/2018/content/textures/ui/Settings/MenuBarAssets/MenuButtonSelected.png new file mode 100644 index 0000000..4a4267e Binary files /dev/null and b/2018/content/textures/ui/Settings/MenuBarAssets/MenuButtonSelected.png differ diff --git a/2018/content/textures/ui/Settings/MenuBarAssets/MenuButtonSelected@2x.png b/2018/content/textures/ui/Settings/MenuBarAssets/MenuButtonSelected@2x.png new file mode 100644 index 0000000..3c33658 Binary files /dev/null and b/2018/content/textures/ui/Settings/MenuBarAssets/MenuButtonSelected@2x.png differ diff --git a/2018/content/textures/ui/Settings/MenuBarAssets/MenuSelection.png b/2018/content/textures/ui/Settings/MenuBarAssets/MenuSelection.png new file mode 100644 index 0000000..c0f8936 Binary files /dev/null and b/2018/content/textures/ui/Settings/MenuBarAssets/MenuSelection.png differ diff --git a/2018/content/textures/ui/Settings/MenuBarAssets/MenuSelection@2x.png b/2018/content/textures/ui/Settings/MenuBarAssets/MenuSelection@2x.png new file mode 100644 index 0000000..b3eb828 Binary files /dev/null and b/2018/content/textures/ui/Settings/MenuBarAssets/MenuSelection@2x.png differ diff --git a/2018/content/textures/ui/Settings/MenuBarIcons/GameSettingsTab.png b/2018/content/textures/ui/Settings/MenuBarIcons/GameSettingsTab.png new file mode 100644 index 0000000..5b0c02c Binary files /dev/null and b/2018/content/textures/ui/Settings/MenuBarIcons/GameSettingsTab.png differ diff --git a/2018/content/textures/ui/Settings/MenuBarIcons/GameSettingsTab@2x.png b/2018/content/textures/ui/Settings/MenuBarIcons/GameSettingsTab@2x.png new file mode 100644 index 0000000..61a2380 Binary files /dev/null and b/2018/content/textures/ui/Settings/MenuBarIcons/GameSettingsTab@2x.png differ diff --git a/2018/content/textures/ui/Settings/MenuBarIcons/HelpTab.png b/2018/content/textures/ui/Settings/MenuBarIcons/HelpTab.png new file mode 100644 index 0000000..a3a18c1 Binary files /dev/null and b/2018/content/textures/ui/Settings/MenuBarIcons/HelpTab.png differ diff --git a/2018/content/textures/ui/Settings/MenuBarIcons/HelpTab@2x.png b/2018/content/textures/ui/Settings/MenuBarIcons/HelpTab@2x.png new file mode 100644 index 0000000..c55cfad Binary files /dev/null and b/2018/content/textures/ui/Settings/MenuBarIcons/HelpTab@2x.png differ diff --git a/2018/content/textures/ui/Settings/MenuBarIcons/HomeTab.png b/2018/content/textures/ui/Settings/MenuBarIcons/HomeTab.png new file mode 100644 index 0000000..e1a6468 Binary files /dev/null and b/2018/content/textures/ui/Settings/MenuBarIcons/HomeTab.png differ diff --git a/2018/content/textures/ui/Settings/MenuBarIcons/HomeTab@2x.png b/2018/content/textures/ui/Settings/MenuBarIcons/HomeTab@2x.png new file mode 100644 index 0000000..edec627 Binary files /dev/null and b/2018/content/textures/ui/Settings/MenuBarIcons/HomeTab@2x.png differ diff --git a/2018/content/textures/ui/Settings/MenuBarIcons/PlayersTabIcon.png b/2018/content/textures/ui/Settings/MenuBarIcons/PlayersTabIcon.png new file mode 100644 index 0000000..fc253e4 Binary files /dev/null and b/2018/content/textures/ui/Settings/MenuBarIcons/PlayersTabIcon.png differ diff --git a/2018/content/textures/ui/Settings/MenuBarIcons/PlayersTabIcon@2x.png b/2018/content/textures/ui/Settings/MenuBarIcons/PlayersTabIcon@2x.png new file mode 100644 index 0000000..8ab99f7 Binary files /dev/null and b/2018/content/textures/ui/Settings/MenuBarIcons/PlayersTabIcon@2x.png differ diff --git a/2018/content/textures/ui/Settings/MenuBarIcons/RecordTab.png b/2018/content/textures/ui/Settings/MenuBarIcons/RecordTab.png new file mode 100644 index 0000000..37616b6 Binary files /dev/null and b/2018/content/textures/ui/Settings/MenuBarIcons/RecordTab.png differ diff --git a/2018/content/textures/ui/Settings/MenuBarIcons/RecordTab@2x.png b/2018/content/textures/ui/Settings/MenuBarIcons/RecordTab@2x.png new file mode 100644 index 0000000..ee7db49 Binary files /dev/null and b/2018/content/textures/ui/Settings/MenuBarIcons/RecordTab@2x.png differ diff --git a/2018/content/textures/ui/Settings/MenuBarIcons/ReportAbuseTab.png b/2018/content/textures/ui/Settings/MenuBarIcons/ReportAbuseTab.png new file mode 100644 index 0000000..69eb788 Binary files /dev/null and b/2018/content/textures/ui/Settings/MenuBarIcons/ReportAbuseTab.png differ diff --git a/2018/content/textures/ui/Settings/MenuBarIcons/ReportAbuseTab@2x.png b/2018/content/textures/ui/Settings/MenuBarIcons/ReportAbuseTab@2x.png new file mode 100644 index 0000000..8efb061 Binary files /dev/null and b/2018/content/textures/ui/Settings/MenuBarIcons/ReportAbuseTab@2x.png differ diff --git a/2018/content/textures/ui/Settings/Players/AddFriendIcon.png b/2018/content/textures/ui/Settings/Players/AddFriendIcon.png new file mode 100644 index 0000000..d63e933 Binary files /dev/null and b/2018/content/textures/ui/Settings/Players/AddFriendIcon.png differ diff --git a/2018/content/textures/ui/Settings/Players/AddFriendIcon@2x.png b/2018/content/textures/ui/Settings/Players/AddFriendIcon@2x.png new file mode 100644 index 0000000..ddb5658 Binary files /dev/null and b/2018/content/textures/ui/Settings/Players/AddFriendIcon@2x.png differ diff --git a/2018/content/textures/ui/Settings/Players/FriendIcon.png b/2018/content/textures/ui/Settings/Players/FriendIcon.png new file mode 100644 index 0000000..ce78c14 Binary files /dev/null and b/2018/content/textures/ui/Settings/Players/FriendIcon.png differ diff --git a/2018/content/textures/ui/Settings/Players/FriendIcon@2x.png b/2018/content/textures/ui/Settings/Players/FriendIcon@2x.png new file mode 100644 index 0000000..420f532 Binary files /dev/null and b/2018/content/textures/ui/Settings/Players/FriendIcon@2x.png differ diff --git a/2018/content/textures/ui/Settings/Players/ReportFlagIcon.png b/2018/content/textures/ui/Settings/Players/ReportFlagIcon.png new file mode 100644 index 0000000..667ce8b Binary files /dev/null and b/2018/content/textures/ui/Settings/Players/ReportFlagIcon.png differ diff --git a/2018/content/textures/ui/Settings/Players/ReportFlagIcon@2x.png b/2018/content/textures/ui/Settings/Players/ReportFlagIcon@2x.png new file mode 100644 index 0000000..e5346b0 Binary files /dev/null and b/2018/content/textures/ui/Settings/Players/ReportFlagIcon@2x.png differ diff --git a/2018/content/textures/ui/Settings/Radial/Alert.png b/2018/content/textures/ui/Settings/Radial/Alert.png new file mode 100644 index 0000000..314d122 Binary files /dev/null and b/2018/content/textures/ui/Settings/Radial/Alert.png differ diff --git a/2018/content/textures/ui/Settings/Radial/Alert@2x.png b/2018/content/textures/ui/Settings/Radial/Alert@2x.png new file mode 100644 index 0000000..6c3c966 Binary files /dev/null and b/2018/content/textures/ui/Settings/Radial/Alert@2x.png differ diff --git a/2018/content/textures/ui/Settings/Radial/Backpack.png b/2018/content/textures/ui/Settings/Radial/Backpack.png new file mode 100644 index 0000000..4658ae8 Binary files /dev/null and b/2018/content/textures/ui/Settings/Radial/Backpack.png differ diff --git a/2018/content/textures/ui/Settings/Radial/Backpack@2x.png b/2018/content/textures/ui/Settings/Radial/Backpack@2x.png new file mode 100644 index 0000000..d222525 Binary files /dev/null and b/2018/content/textures/ui/Settings/Radial/Backpack@2x.png differ diff --git a/2018/content/textures/ui/Settings/Radial/Bottom.png b/2018/content/textures/ui/Settings/Radial/Bottom.png new file mode 100644 index 0000000..edb40d9 Binary files /dev/null and b/2018/content/textures/ui/Settings/Radial/Bottom.png differ diff --git a/2018/content/textures/ui/Settings/Radial/BottomLeft.png b/2018/content/textures/ui/Settings/Radial/BottomLeft.png new file mode 100644 index 0000000..4560e63 Binary files /dev/null and b/2018/content/textures/ui/Settings/Radial/BottomLeft.png differ diff --git a/2018/content/textures/ui/Settings/Radial/BottomLeftSelected.png b/2018/content/textures/ui/Settings/Radial/BottomLeftSelected.png new file mode 100644 index 0000000..f678b7d Binary files /dev/null and b/2018/content/textures/ui/Settings/Radial/BottomLeftSelected.png differ diff --git a/2018/content/textures/ui/Settings/Radial/BottomRight.png b/2018/content/textures/ui/Settings/Radial/BottomRight.png new file mode 100644 index 0000000..34ea9d2 Binary files /dev/null and b/2018/content/textures/ui/Settings/Radial/BottomRight.png differ diff --git a/2018/content/textures/ui/Settings/Radial/BottomRightSelected.png b/2018/content/textures/ui/Settings/Radial/BottomRightSelected.png new file mode 100644 index 0000000..c044854 Binary files /dev/null and b/2018/content/textures/ui/Settings/Radial/BottomRightSelected.png differ diff --git a/2018/content/textures/ui/Settings/Radial/BottomSelected.png b/2018/content/textures/ui/Settings/Radial/BottomSelected.png new file mode 100644 index 0000000..eed548c Binary files /dev/null and b/2018/content/textures/ui/Settings/Radial/BottomSelected.png differ diff --git a/2018/content/textures/ui/Settings/Radial/Chat.png b/2018/content/textures/ui/Settings/Radial/Chat.png new file mode 100644 index 0000000..b0bc68c Binary files /dev/null and b/2018/content/textures/ui/Settings/Radial/Chat.png differ diff --git a/2018/content/textures/ui/Settings/Radial/Chat@2x.png b/2018/content/textures/ui/Settings/Radial/Chat@2x.png new file mode 100644 index 0000000..1b9e5bc Binary files /dev/null and b/2018/content/textures/ui/Settings/Radial/Chat@2x.png differ diff --git a/2018/content/textures/ui/Settings/Radial/EmptyBottom.png b/2018/content/textures/ui/Settings/Radial/EmptyBottom.png new file mode 100644 index 0000000..964257a Binary files /dev/null and b/2018/content/textures/ui/Settings/Radial/EmptyBottom.png differ diff --git a/2018/content/textures/ui/Settings/Radial/EmptyBottomLeft.png b/2018/content/textures/ui/Settings/Radial/EmptyBottomLeft.png new file mode 100644 index 0000000..a7b3a80 Binary files /dev/null and b/2018/content/textures/ui/Settings/Radial/EmptyBottomLeft.png differ diff --git a/2018/content/textures/ui/Settings/Radial/EmptyBottomRight.png b/2018/content/textures/ui/Settings/Radial/EmptyBottomRight.png new file mode 100644 index 0000000..87e8935 Binary files /dev/null and b/2018/content/textures/ui/Settings/Radial/EmptyBottomRight.png differ diff --git a/2018/content/textures/ui/Settings/Radial/EmptyTop.png b/2018/content/textures/ui/Settings/Radial/EmptyTop.png new file mode 100644 index 0000000..90da292 Binary files /dev/null and b/2018/content/textures/ui/Settings/Radial/EmptyTop.png differ diff --git a/2018/content/textures/ui/Settings/Radial/EmptyTopLeft.png b/2018/content/textures/ui/Settings/Radial/EmptyTopLeft.png new file mode 100644 index 0000000..84fd9a4 Binary files /dev/null and b/2018/content/textures/ui/Settings/Radial/EmptyTopLeft.png differ diff --git a/2018/content/textures/ui/Settings/Radial/EmptyTopRight.png b/2018/content/textures/ui/Settings/Radial/EmptyTopRight.png new file mode 100644 index 0000000..53be061 Binary files /dev/null and b/2018/content/textures/ui/Settings/Radial/EmptyTopRight.png differ diff --git a/2018/content/textures/ui/Settings/Radial/Leave.png b/2018/content/textures/ui/Settings/Radial/Leave.png new file mode 100644 index 0000000..5f69290 Binary files /dev/null and b/2018/content/textures/ui/Settings/Radial/Leave.png differ diff --git a/2018/content/textures/ui/Settings/Radial/Leave@2x.png b/2018/content/textures/ui/Settings/Radial/Leave@2x.png new file mode 100644 index 0000000..d4f66b5 Binary files /dev/null and b/2018/content/textures/ui/Settings/Radial/Leave@2x.png differ diff --git a/2018/content/textures/ui/Settings/Radial/Menu.png b/2018/content/textures/ui/Settings/Radial/Menu.png new file mode 100644 index 0000000..bff7118 Binary files /dev/null and b/2018/content/textures/ui/Settings/Radial/Menu.png differ diff --git a/2018/content/textures/ui/Settings/Radial/Menu@2x.png b/2018/content/textures/ui/Settings/Radial/Menu@2x.png new file mode 100644 index 0000000..b56e6b6 Binary files /dev/null and b/2018/content/textures/ui/Settings/Radial/Menu@2x.png differ diff --git a/2018/content/textures/ui/Settings/Radial/PlayerList.png b/2018/content/textures/ui/Settings/Radial/PlayerList.png new file mode 100644 index 0000000..fae417d Binary files /dev/null and b/2018/content/textures/ui/Settings/Radial/PlayerList.png differ diff --git a/2018/content/textures/ui/Settings/Radial/PlayerList@2x.png b/2018/content/textures/ui/Settings/Radial/PlayerList@2x.png new file mode 100644 index 0000000..9a91e3e Binary files /dev/null and b/2018/content/textures/ui/Settings/Radial/PlayerList@2x.png differ diff --git a/2018/content/textures/ui/Settings/Radial/RadialLabel.png b/2018/content/textures/ui/Settings/Radial/RadialLabel.png new file mode 100644 index 0000000..c7065c9 Binary files /dev/null and b/2018/content/textures/ui/Settings/Radial/RadialLabel.png differ diff --git a/2018/content/textures/ui/Settings/Radial/RadialLabel@2x.png b/2018/content/textures/ui/Settings/Radial/RadialLabel@2x.png new file mode 100644 index 0000000..349aed3 Binary files /dev/null and b/2018/content/textures/ui/Settings/Radial/RadialLabel@2x.png differ diff --git a/2018/content/textures/ui/Settings/Radial/Top.png b/2018/content/textures/ui/Settings/Radial/Top.png new file mode 100644 index 0000000..a87d6eb Binary files /dev/null and b/2018/content/textures/ui/Settings/Radial/Top.png differ diff --git a/2018/content/textures/ui/Settings/Radial/TopLeft.png b/2018/content/textures/ui/Settings/Radial/TopLeft.png new file mode 100644 index 0000000..64b0ec1 Binary files /dev/null and b/2018/content/textures/ui/Settings/Radial/TopLeft.png differ diff --git a/2018/content/textures/ui/Settings/Radial/TopLeftSelected.png b/2018/content/textures/ui/Settings/Radial/TopLeftSelected.png new file mode 100644 index 0000000..0069778 Binary files /dev/null and b/2018/content/textures/ui/Settings/Radial/TopLeftSelected.png differ diff --git a/2018/content/textures/ui/Settings/Radial/TopRight.png b/2018/content/textures/ui/Settings/Radial/TopRight.png new file mode 100644 index 0000000..73831c9 Binary files /dev/null and b/2018/content/textures/ui/Settings/Radial/TopRight.png differ diff --git a/2018/content/textures/ui/Settings/Radial/TopRightSelected.png b/2018/content/textures/ui/Settings/Radial/TopRightSelected.png new file mode 100644 index 0000000..9ead602 Binary files /dev/null and b/2018/content/textures/ui/Settings/Radial/TopRightSelected.png differ diff --git a/2018/content/textures/ui/Settings/Radial/TopSelected.png b/2018/content/textures/ui/Settings/Radial/TopSelected.png new file mode 100644 index 0000000..6c73255 Binary files /dev/null and b/2018/content/textures/ui/Settings/Radial/TopSelected.png differ diff --git a/2018/content/textures/ui/Settings/ShareGame/icons.png b/2018/content/textures/ui/Settings/ShareGame/icons.png new file mode 100644 index 0000000..73ccfdb Binary files /dev/null and b/2018/content/textures/ui/Settings/ShareGame/icons.png differ diff --git a/2018/content/textures/ui/Settings/ShareGame/icons@2x.png b/2018/content/textures/ui/Settings/ShareGame/icons@2x.png new file mode 100644 index 0000000..beb7acc Binary files /dev/null and b/2018/content/textures/ui/Settings/ShareGame/icons@2x.png differ diff --git a/2018/content/textures/ui/Settings/ShareGame/icons@3x.png b/2018/content/textures/ui/Settings/ShareGame/icons@3x.png new file mode 100644 index 0000000..ccc04e6 Binary files /dev/null and b/2018/content/textures/ui/Settings/ShareGame/icons@3x.png differ diff --git a/2018/content/textures/ui/Settings/Slider/BarLeft.png b/2018/content/textures/ui/Settings/Slider/BarLeft.png new file mode 100644 index 0000000..1787ff0 Binary files /dev/null and b/2018/content/textures/ui/Settings/Slider/BarLeft.png differ diff --git a/2018/content/textures/ui/Settings/Slider/BarLeft@2x.png b/2018/content/textures/ui/Settings/Slider/BarLeft@2x.png new file mode 100644 index 0000000..b6bb751 Binary files /dev/null and b/2018/content/textures/ui/Settings/Slider/BarLeft@2x.png differ diff --git a/2018/content/textures/ui/Settings/Slider/BarRight.png b/2018/content/textures/ui/Settings/Slider/BarRight.png new file mode 100644 index 0000000..04bca90 Binary files /dev/null and b/2018/content/textures/ui/Settings/Slider/BarRight.png differ diff --git a/2018/content/textures/ui/Settings/Slider/BarRight@2x.png b/2018/content/textures/ui/Settings/Slider/BarRight@2x.png new file mode 100644 index 0000000..26e8a6f Binary files /dev/null and b/2018/content/textures/ui/Settings/Slider/BarRight@2x.png differ diff --git a/2018/content/textures/ui/Settings/Slider/Left.png b/2018/content/textures/ui/Settings/Slider/Left.png new file mode 100644 index 0000000..c078d2c Binary files /dev/null and b/2018/content/textures/ui/Settings/Slider/Left.png differ diff --git a/2018/content/textures/ui/Settings/Slider/Left@2x.png b/2018/content/textures/ui/Settings/Slider/Left@2x.png new file mode 100644 index 0000000..3ec089d Binary files /dev/null and b/2018/content/textures/ui/Settings/Slider/Left@2x.png differ diff --git a/2018/content/textures/ui/Settings/Slider/Less.png b/2018/content/textures/ui/Settings/Slider/Less.png new file mode 100644 index 0000000..afbb0a6 Binary files /dev/null and b/2018/content/textures/ui/Settings/Slider/Less.png differ diff --git a/2018/content/textures/ui/Settings/Slider/More.png b/2018/content/textures/ui/Settings/Slider/More.png new file mode 100644 index 0000000..05edb54 Binary files /dev/null and b/2018/content/textures/ui/Settings/Slider/More.png differ diff --git a/2018/content/textures/ui/Settings/Slider/Right.png b/2018/content/textures/ui/Settings/Slider/Right.png new file mode 100644 index 0000000..a607724 Binary files /dev/null and b/2018/content/textures/ui/Settings/Slider/Right.png differ diff --git a/2018/content/textures/ui/Settings/Slider/Right@2x.png b/2018/content/textures/ui/Settings/Slider/Right@2x.png new file mode 100644 index 0000000..53ef3f8 Binary files /dev/null and b/2018/content/textures/ui/Settings/Slider/Right@2x.png differ diff --git a/2018/content/textures/ui/Settings/Slider/SelectedBarLeft.png b/2018/content/textures/ui/Settings/Slider/SelectedBarLeft.png new file mode 100644 index 0000000..6c98b40 Binary files /dev/null and b/2018/content/textures/ui/Settings/Slider/SelectedBarLeft.png differ diff --git a/2018/content/textures/ui/Settings/Slider/SelectedBarLeft@2x.png b/2018/content/textures/ui/Settings/Slider/SelectedBarLeft@2x.png new file mode 100644 index 0000000..6476f9e Binary files /dev/null and b/2018/content/textures/ui/Settings/Slider/SelectedBarLeft@2x.png differ diff --git a/2018/content/textures/ui/Settings/Slider/SelectedBarRight.png b/2018/content/textures/ui/Settings/Slider/SelectedBarRight.png new file mode 100644 index 0000000..a0e0162 Binary files /dev/null and b/2018/content/textures/ui/Settings/Slider/SelectedBarRight.png differ diff --git a/2018/content/textures/ui/Settings/Slider/SelectedBarRight@2x.png b/2018/content/textures/ui/Settings/Slider/SelectedBarRight@2x.png new file mode 100644 index 0000000..d5229bc Binary files /dev/null and b/2018/content/textures/ui/Settings/Slider/SelectedBarRight@2x.png differ diff --git a/2018/content/textures/ui/SingleButton.png b/2018/content/textures/ui/SingleButton.png new file mode 100644 index 0000000..27d2c0d Binary files /dev/null and b/2018/content/textures/ui/SingleButton.png differ diff --git a/2018/content/textures/ui/SingleButtonDown.png b/2018/content/textures/ui/SingleButtonDown.png new file mode 100644 index 0000000..4e50523 Binary files /dev/null and b/2018/content/textures/ui/SingleButtonDown.png differ diff --git a/2018/content/textures/ui/Slider-BKG-Center.png b/2018/content/textures/ui/Slider-BKG-Center.png new file mode 100644 index 0000000..7563293 Binary files /dev/null and b/2018/content/textures/ui/Slider-BKG-Center.png differ diff --git a/2018/content/textures/ui/Slider-BKG-Center@2x.png b/2018/content/textures/ui/Slider-BKG-Center@2x.png new file mode 100644 index 0000000..284dae0 Binary files /dev/null and b/2018/content/textures/ui/Slider-BKG-Center@2x.png differ diff --git a/2018/content/textures/ui/Slider-BKG-Left-Cap.png b/2018/content/textures/ui/Slider-BKG-Left-Cap.png new file mode 100644 index 0000000..ab76642 Binary files /dev/null and b/2018/content/textures/ui/Slider-BKG-Left-Cap.png differ diff --git a/2018/content/textures/ui/Slider-BKG-Left-Cap@2x.png b/2018/content/textures/ui/Slider-BKG-Left-Cap@2x.png new file mode 100644 index 0000000..defda45 Binary files /dev/null and b/2018/content/textures/ui/Slider-BKG-Left-Cap@2x.png differ diff --git a/2018/content/textures/ui/Slider-BKG-Right-Cap.png b/2018/content/textures/ui/Slider-BKG-Right-Cap.png new file mode 100644 index 0000000..82d19f3 Binary files /dev/null and b/2018/content/textures/ui/Slider-BKG-Right-Cap.png differ diff --git a/2018/content/textures/ui/Slider-BKG-Right-Cap@2x.png b/2018/content/textures/ui/Slider-BKG-Right-Cap@2x.png new file mode 100644 index 0000000..0dcd8be Binary files /dev/null and b/2018/content/textures/ui/Slider-BKG-Right-Cap@2x.png differ diff --git a/2018/content/textures/ui/Slider-Fill-Center.png b/2018/content/textures/ui/Slider-Fill-Center.png new file mode 100644 index 0000000..a9db65e Binary files /dev/null and b/2018/content/textures/ui/Slider-Fill-Center.png differ diff --git a/2018/content/textures/ui/Slider-Fill-Center@2x.png b/2018/content/textures/ui/Slider-Fill-Center@2x.png new file mode 100644 index 0000000..c3355cc Binary files /dev/null and b/2018/content/textures/ui/Slider-Fill-Center@2x.png differ diff --git a/2018/content/textures/ui/Slider-Fill-Left-Cap.png b/2018/content/textures/ui/Slider-Fill-Left-Cap.png new file mode 100644 index 0000000..5d796da Binary files /dev/null and b/2018/content/textures/ui/Slider-Fill-Left-Cap.png differ diff --git a/2018/content/textures/ui/Slider-Fill-Left-Cap@2x.png b/2018/content/textures/ui/Slider-Fill-Left-Cap@2x.png new file mode 100644 index 0000000..2ff6d0b Binary files /dev/null and b/2018/content/textures/ui/Slider-Fill-Left-Cap@2x.png differ diff --git a/2018/content/textures/ui/Slider-Fill-Right-Cap.png b/2018/content/textures/ui/Slider-Fill-Right-Cap.png new file mode 100644 index 0000000..188106b Binary files /dev/null and b/2018/content/textures/ui/Slider-Fill-Right-Cap.png differ diff --git a/2018/content/textures/ui/Slider-Fill-Right-Cap@2x.png b/2018/content/textures/ui/Slider-Fill-Right-Cap@2x.png new file mode 100644 index 0000000..84ae4c8 Binary files /dev/null and b/2018/content/textures/ui/Slider-Fill-Right-Cap@2x.png differ diff --git a/2018/content/textures/ui/Slider.png b/2018/content/textures/ui/Slider.png new file mode 100644 index 0000000..b11c5a3 Binary files /dev/null and b/2018/content/textures/ui/Slider.png differ diff --git a/2018/content/textures/ui/Slider_dn.png b/2018/content/textures/ui/Slider_dn.png new file mode 100644 index 0000000..2aa542e Binary files /dev/null and b/2018/content/textures/ui/Slider_dn.png differ diff --git a/2018/content/textures/ui/Slider_sel.png b/2018/content/textures/ui/Slider_sel.png new file mode 100644 index 0000000..2aa542e Binary files /dev/null and b/2018/content/textures/ui/Slider_sel.png differ diff --git a/2018/content/textures/ui/TixIcon.png b/2018/content/textures/ui/TixIcon.png new file mode 100644 index 0000000..8b08e62 Binary files /dev/null and b/2018/content/textures/ui/TixIcon.png differ diff --git a/2018/content/textures/ui/TopBar/Round.png b/2018/content/textures/ui/TopBar/Round.png new file mode 100644 index 0000000..a596802 Binary files /dev/null and b/2018/content/textures/ui/TopBar/Round.png differ diff --git a/2018/content/textures/ui/TopBar/dropshadow.png b/2018/content/textures/ui/TopBar/dropshadow.png new file mode 100644 index 0000000..0e9aa0b Binary files /dev/null and b/2018/content/textures/ui/TopBar/dropshadow.png differ diff --git a/2018/content/textures/ui/TopBar/dropshadow@2x.png b/2018/content/textures/ui/TopBar/dropshadow@2x.png new file mode 100644 index 0000000..9b14c0f Binary files /dev/null and b/2018/content/textures/ui/TopBar/dropshadow@2x.png differ diff --git a/2018/content/textures/ui/TouchControlsSheet.png b/2018/content/textures/ui/TouchControlsSheet.png new file mode 100644 index 0000000..da0293f Binary files /dev/null and b/2018/content/textures/ui/TouchControlsSheet.png differ diff --git a/2018/content/textures/ui/VR/Radial/Icons/2DUI.png b/2018/content/textures/ui/VR/Radial/Icons/2DUI.png new file mode 100644 index 0000000..23ce445 Binary files /dev/null and b/2018/content/textures/ui/VR/Radial/Icons/2DUI.png differ diff --git a/2018/content/textures/ui/VR/Radial/Icons/Backpack.png b/2018/content/textures/ui/VR/Radial/Icons/Backpack.png new file mode 100644 index 0000000..d8a6237 Binary files /dev/null and b/2018/content/textures/ui/VR/Radial/Icons/Backpack.png differ diff --git a/2018/content/textures/ui/VR/Radial/Icons/Recenter.png b/2018/content/textures/ui/VR/Radial/Icons/Recenter.png new file mode 100644 index 0000000..b21a586 Binary files /dev/null and b/2018/content/textures/ui/VR/Radial/Icons/Recenter.png differ diff --git a/2018/content/textures/ui/VR/Radial/SliceActive.png b/2018/content/textures/ui/VR/Radial/SliceActive.png new file mode 100644 index 0000000..8776b51 Binary files /dev/null and b/2018/content/textures/ui/VR/Radial/SliceActive.png differ diff --git a/2018/content/textures/ui/VR/Radial/SliceBackground.png b/2018/content/textures/ui/VR/Radial/SliceBackground.png new file mode 100644 index 0000000..fd9c037 Binary files /dev/null and b/2018/content/textures/ui/VR/Radial/SliceBackground.png differ diff --git a/2018/content/textures/ui/VR/Radial/SliceDisabled.png b/2018/content/textures/ui/VR/Radial/SliceDisabled.png new file mode 100644 index 0000000..ad926ad Binary files /dev/null and b/2018/content/textures/ui/VR/Radial/SliceDisabled.png differ diff --git a/2018/content/textures/ui/VR/VRPointerDiscBlue.png b/2018/content/textures/ui/VR/VRPointerDiscBlue.png new file mode 100644 index 0000000..ceab1b0 Binary files /dev/null and b/2018/content/textures/ui/VR/VRPointerDiscBlue.png differ diff --git a/2018/content/textures/ui/VR/VRPointerDiscRed.png b/2018/content/textures/ui/VR/VRPointerDiscRed.png new file mode 100644 index 0000000..ba88732 Binary files /dev/null and b/2018/content/textures/ui/VR/VRPointerDiscRed.png differ diff --git a/2018/content/textures/ui/VR/button.png b/2018/content/textures/ui/VR/button.png new file mode 100644 index 0000000..403dfde Binary files /dev/null and b/2018/content/textures/ui/VR/button.png differ diff --git a/2018/content/textures/ui/VR/buttonActive.png b/2018/content/textures/ui/VR/buttonActive.png new file mode 100644 index 0000000..f685760 Binary files /dev/null and b/2018/content/textures/ui/VR/buttonActive.png differ diff --git a/2018/content/textures/ui/VR/buttonBackground.png b/2018/content/textures/ui/VR/buttonBackground.png new file mode 100644 index 0000000..379241a Binary files /dev/null and b/2018/content/textures/ui/VR/buttonBackground.png differ diff --git a/2018/content/textures/ui/VR/buttonHover.png b/2018/content/textures/ui/VR/buttonHover.png new file mode 100644 index 0000000..916ddff Binary files /dev/null and b/2018/content/textures/ui/VR/buttonHover.png differ diff --git a/2018/content/textures/ui/VR/buttonSelected.png b/2018/content/textures/ui/VR/buttonSelected.png new file mode 100644 index 0000000..6759aea Binary files /dev/null and b/2018/content/textures/ui/VR/buttonSelected.png differ diff --git a/2018/content/textures/ui/VR/chat.png b/2018/content/textures/ui/VR/chat.png new file mode 100644 index 0000000..5017f20 Binary files /dev/null and b/2018/content/textures/ui/VR/chat.png differ diff --git a/2018/content/textures/ui/VR/circleWhite.png b/2018/content/textures/ui/VR/circleWhite.png new file mode 100644 index 0000000..728fe7b Binary files /dev/null and b/2018/content/textures/ui/VR/circleWhite.png differ diff --git a/2018/content/textures/ui/VR/closeButtonPadded.png b/2018/content/textures/ui/VR/closeButtonPadded.png new file mode 100644 index 0000000..0db5f8d Binary files /dev/null and b/2018/content/textures/ui/VR/closeButtonPadded.png differ diff --git a/2018/content/textures/ui/VR/hamburger.png b/2018/content/textures/ui/VR/hamburger.png new file mode 100644 index 0000000..a9d70c5 Binary files /dev/null and b/2018/content/textures/ui/VR/hamburger.png differ diff --git a/2018/content/textures/ui/VR/hoverPopupLeft.png b/2018/content/textures/ui/VR/hoverPopupLeft.png new file mode 100644 index 0000000..484b0d2 Binary files /dev/null and b/2018/content/textures/ui/VR/hoverPopupLeft.png differ diff --git a/2018/content/textures/ui/VR/hoverPopupMid.png b/2018/content/textures/ui/VR/hoverPopupMid.png new file mode 100644 index 0000000..0f55008 Binary files /dev/null and b/2018/content/textures/ui/VR/hoverPopupMid.png differ diff --git a/2018/content/textures/ui/VR/hoverPopupRight.png b/2018/content/textures/ui/VR/hoverPopupRight.png new file mode 100644 index 0000000..ea0b32a Binary files /dev/null and b/2018/content/textures/ui/VR/hoverPopupRight.png differ diff --git a/2018/content/textures/ui/VR/notifications.png b/2018/content/textures/ui/VR/notifications.png new file mode 100644 index 0000000..ce18573 Binary files /dev/null and b/2018/content/textures/ui/VR/notifications.png differ diff --git a/2018/content/textures/ui/VR/notifier_glow.png b/2018/content/textures/ui/VR/notifier_glow.png new file mode 100644 index 0000000..9483328 Binary files /dev/null and b/2018/content/textures/ui/VR/notifier_glow.png differ diff --git a/2018/content/textures/ui/VR/recenter.png b/2018/content/textures/ui/VR/recenter.png new file mode 100644 index 0000000..a287342 Binary files /dev/null and b/2018/content/textures/ui/VR/recenter.png differ diff --git a/2018/content/textures/ui/VR/recenterFrame.png b/2018/content/textures/ui/VR/recenterFrame.png new file mode 100644 index 0000000..1f02bdf Binary files /dev/null and b/2018/content/textures/ui/VR/recenterFrame.png differ diff --git a/2018/content/textures/ui/VR/rectBackground.png b/2018/content/textures/ui/VR/rectBackground.png new file mode 100644 index 0000000..758edfe Binary files /dev/null and b/2018/content/textures/ui/VR/rectBackground.png differ diff --git a/2018/content/textures/ui/VR/rectBackgroundWhite.png b/2018/content/textures/ui/VR/rectBackgroundWhite.png new file mode 100644 index 0000000..0446670 Binary files /dev/null and b/2018/content/textures/ui/VR/rectBackgroundWhite.png differ diff --git a/2018/content/textures/ui/VR/toggle2D.png b/2018/content/textures/ui/VR/toggle2D.png new file mode 100644 index 0000000..78def18 Binary files /dev/null and b/2018/content/textures/ui/VR/toggle2D.png differ diff --git a/2018/content/textures/ui/Vehicle/SpeedBar.png b/2018/content/textures/ui/Vehicle/SpeedBar.png new file mode 100644 index 0000000..1913f2b Binary files /dev/null and b/2018/content/textures/ui/Vehicle/SpeedBar.png differ diff --git a/2018/content/textures/ui/Vehicle/SpeedBar@2x.png b/2018/content/textures/ui/Vehicle/SpeedBar@2x.png new file mode 100644 index 0000000..3935f79 Binary files /dev/null and b/2018/content/textures/ui/Vehicle/SpeedBar@2x.png differ diff --git a/2018/content/textures/ui/Vehicle/SpeedBarBKG.png b/2018/content/textures/ui/Vehicle/SpeedBarBKG.png new file mode 100644 index 0000000..af55200 Binary files /dev/null and b/2018/content/textures/ui/Vehicle/SpeedBarBKG.png differ diff --git a/2018/content/textures/ui/Vehicle/SpeedBarBKG@2x.png b/2018/content/textures/ui/Vehicle/SpeedBarBKG@2x.png new file mode 100644 index 0000000..b85a6e5 Binary files /dev/null and b/2018/content/textures/ui/Vehicle/SpeedBarBKG@2x.png differ diff --git a/2018/content/textures/ui/Vehicle/SpeedBarEmpty.png b/2018/content/textures/ui/Vehicle/SpeedBarEmpty.png new file mode 100644 index 0000000..7889a14 Binary files /dev/null and b/2018/content/textures/ui/Vehicle/SpeedBarEmpty.png differ diff --git a/2018/content/textures/ui/Vehicle/SpeedBarEmpty@2x.png b/2018/content/textures/ui/Vehicle/SpeedBarEmpty@2x.png new file mode 100644 index 0000000..880b096 Binary files /dev/null and b/2018/content/textures/ui/Vehicle/SpeedBarEmpty@2x.png differ diff --git a/2018/content/textures/ui/account_over13.png b/2018/content/textures/ui/account_over13.png new file mode 100644 index 0000000..0a91b6c Binary files /dev/null and b/2018/content/textures/ui/account_over13.png differ diff --git a/2018/content/textures/ui/account_under13.png b/2018/content/textures/ui/account_under13.png new file mode 100644 index 0000000..8ecf24c Binary files /dev/null and b/2018/content/textures/ui/account_under13.png differ diff --git a/2018/content/textures/ui/btn_grey.png b/2018/content/textures/ui/btn_grey.png new file mode 100644 index 0000000..3ae3fff Binary files /dev/null and b/2018/content/textures/ui/btn_grey.png differ diff --git a/2018/content/textures/ui/btn_greyTransp.png b/2018/content/textures/ui/btn_greyTransp.png new file mode 100644 index 0000000..0a39a1e Binary files /dev/null and b/2018/content/textures/ui/btn_greyTransp.png differ diff --git a/2018/content/textures/ui/btn_newBlue.png b/2018/content/textures/ui/btn_newBlue.png new file mode 100644 index 0000000..d7b482e Binary files /dev/null and b/2018/content/textures/ui/btn_newBlue.png differ diff --git a/2018/content/textures/ui/btn_newBlue@2x.png b/2018/content/textures/ui/btn_newBlue@2x.png new file mode 100644 index 0000000..ca2f2e9 Binary files /dev/null and b/2018/content/textures/ui/btn_newBlue@2x.png differ diff --git a/2018/content/textures/ui/btn_newBlueGlow.png b/2018/content/textures/ui/btn_newBlueGlow.png new file mode 100644 index 0000000..1b49a6c Binary files /dev/null and b/2018/content/textures/ui/btn_newBlueGlow.png differ diff --git a/2018/content/textures/ui/btn_newBlueGlow@2x.png b/2018/content/textures/ui/btn_newBlueGlow@2x.png new file mode 100644 index 0000000..379ec28 Binary files /dev/null and b/2018/content/textures/ui/btn_newBlueGlow@2x.png differ diff --git a/2018/content/textures/ui/btn_newGrey.png b/2018/content/textures/ui/btn_newGrey.png new file mode 100644 index 0000000..fb6cb06 Binary files /dev/null and b/2018/content/textures/ui/btn_newGrey.png differ diff --git a/2018/content/textures/ui/btn_newGrey@2x.png b/2018/content/textures/ui/btn_newGrey@2x.png new file mode 100644 index 0000000..b877522 Binary files /dev/null and b/2018/content/textures/ui/btn_newGrey@2x.png differ diff --git a/2018/content/textures/ui/btn_newGreyGlow.png b/2018/content/textures/ui/btn_newGreyGlow.png new file mode 100644 index 0000000..fc3e25a Binary files /dev/null and b/2018/content/textures/ui/btn_newGreyGlow.png differ diff --git a/2018/content/textures/ui/btn_newGreyGlow@2x.png b/2018/content/textures/ui/btn_newGreyGlow@2x.png new file mode 100644 index 0000000..017b746 Binary files /dev/null and b/2018/content/textures/ui/btn_newGreyGlow@2x.png differ diff --git a/2018/content/textures/ui/btn_newWhite.png b/2018/content/textures/ui/btn_newWhite.png new file mode 100644 index 0000000..4e415ee Binary files /dev/null and b/2018/content/textures/ui/btn_newWhite.png differ diff --git a/2018/content/textures/ui/btn_newWhite@2x.png b/2018/content/textures/ui/btn_newWhite@2x.png new file mode 100644 index 0000000..82c0825 Binary files /dev/null and b/2018/content/textures/ui/btn_newWhite@2x.png differ diff --git a/2018/content/textures/ui/btn_newWhiteGlow.png b/2018/content/textures/ui/btn_newWhiteGlow.png new file mode 100644 index 0000000..0373243 Binary files /dev/null and b/2018/content/textures/ui/btn_newWhiteGlow.png differ diff --git a/2018/content/textures/ui/btn_newWhiteGlow@2x.png b/2018/content/textures/ui/btn_newWhiteGlow@2x.png new file mode 100644 index 0000000..e03f4dc Binary files /dev/null and b/2018/content/textures/ui/btn_newWhiteGlow@2x.png differ diff --git a/2018/content/textures/ui/btn_red.png b/2018/content/textures/ui/btn_red.png new file mode 100644 index 0000000..4ab7dec Binary files /dev/null and b/2018/content/textures/ui/btn_red.png differ diff --git a/2018/content/textures/ui/btn_redGlow.png b/2018/content/textures/ui/btn_redGlow.png new file mode 100644 index 0000000..5d6249e Binary files /dev/null and b/2018/content/textures/ui/btn_redGlow.png differ diff --git a/2018/content/textures/ui/btn_white.png b/2018/content/textures/ui/btn_white.png new file mode 100644 index 0000000..4c6d4c8 Binary files /dev/null and b/2018/content/textures/ui/btn_white.png differ diff --git a/2018/content/textures/ui/chatBubble_blue_notify_bkg.png b/2018/content/textures/ui/chatBubble_blue_notify_bkg.png new file mode 100644 index 0000000..a7925dc Binary files /dev/null and b/2018/content/textures/ui/chatBubble_blue_notify_bkg.png differ diff --git a/2018/content/textures/ui/chatBubble_green_notify_bkg.png b/2018/content/textures/ui/chatBubble_green_notify_bkg.png new file mode 100644 index 0000000..1f38d6a Binary files /dev/null and b/2018/content/textures/ui/chatBubble_green_notify_bkg.png differ diff --git a/2018/content/textures/ui/chatBubble_red_notify_bkg.png b/2018/content/textures/ui/chatBubble_red_notify_bkg.png new file mode 100644 index 0000000..7503309 Binary files /dev/null and b/2018/content/textures/ui/chatBubble_red_notify_bkg.png differ diff --git a/2018/content/textures/ui/chatBubble_white_notify_bkg.png b/2018/content/textures/ui/chatBubble_white_notify_bkg.png new file mode 100644 index 0000000..59be44c Binary files /dev/null and b/2018/content/textures/ui/chatBubble_white_notify_bkg.png differ diff --git a/2018/content/textures/ui/chat_teamButton.png b/2018/content/textures/ui/chat_teamButton.png new file mode 100644 index 0000000..ecceb50 Binary files /dev/null and b/2018/content/textures/ui/chat_teamButton.png differ diff --git a/2018/content/textures/ui/chat_teamButton@2x.png b/2018/content/textures/ui/chat_teamButton@2x.png new file mode 100644 index 0000000..d36c05e Binary files /dev/null and b/2018/content/textures/ui/chat_teamButton@2x.png differ diff --git a/2018/content/textures/ui/dialog_blue.png b/2018/content/textures/ui/dialog_blue.png new file mode 100644 index 0000000..96b9adb Binary files /dev/null and b/2018/content/textures/ui/dialog_blue.png differ diff --git a/2018/content/textures/ui/dialog_blue@2x.png b/2018/content/textures/ui/dialog_blue@2x.png new file mode 100644 index 0000000..c40fc31 Binary files /dev/null and b/2018/content/textures/ui/dialog_blue@2x.png differ diff --git a/2018/content/textures/ui/dialog_green.png b/2018/content/textures/ui/dialog_green.png new file mode 100644 index 0000000..64d012c Binary files /dev/null and b/2018/content/textures/ui/dialog_green.png differ diff --git a/2018/content/textures/ui/dialog_green@2x.png b/2018/content/textures/ui/dialog_green@2x.png new file mode 100644 index 0000000..775b4f9 Binary files /dev/null and b/2018/content/textures/ui/dialog_green@2x.png differ diff --git a/2018/content/textures/ui/dialog_purpose_help.png b/2018/content/textures/ui/dialog_purpose_help.png new file mode 100644 index 0000000..311d441 Binary files /dev/null and b/2018/content/textures/ui/dialog_purpose_help.png differ diff --git a/2018/content/textures/ui/dialog_purpose_quest.png b/2018/content/textures/ui/dialog_purpose_quest.png new file mode 100644 index 0000000..14efd26 Binary files /dev/null and b/2018/content/textures/ui/dialog_purpose_quest.png differ diff --git a/2018/content/textures/ui/dialog_purpose_shop.png b/2018/content/textures/ui/dialog_purpose_shop.png new file mode 100644 index 0000000..df2bb7f Binary files /dev/null and b/2018/content/textures/ui/dialog_purpose_shop.png differ diff --git a/2018/content/textures/ui/dialog_red.png b/2018/content/textures/ui/dialog_red.png new file mode 100644 index 0000000..6b3c644 Binary files /dev/null and b/2018/content/textures/ui/dialog_red.png differ diff --git a/2018/content/textures/ui/dialog_red@2x.png b/2018/content/textures/ui/dialog_red@2x.png new file mode 100644 index 0000000..c62b873 Binary files /dev/null and b/2018/content/textures/ui/dialog_red@2x.png differ diff --git a/2018/content/textures/ui/dialog_tail.png b/2018/content/textures/ui/dialog_tail.png new file mode 100644 index 0000000..b9686bc Binary files /dev/null and b/2018/content/textures/ui/dialog_tail.png differ diff --git a/2018/content/textures/ui/dialog_tail@2x.png b/2018/content/textures/ui/dialog_tail@2x.png new file mode 100644 index 0000000..ff18256 Binary files /dev/null and b/2018/content/textures/ui/dialog_tail@2x.png differ diff --git a/2018/content/textures/ui/dialog_white.png b/2018/content/textures/ui/dialog_white.png new file mode 100644 index 0000000..9911129 Binary files /dev/null and b/2018/content/textures/ui/dialog_white.png differ diff --git a/2018/content/textures/ui/dialog_white@2x.png b/2018/content/textures/ui/dialog_white@2x.png new file mode 100644 index 0000000..f80f843 Binary files /dev/null and b/2018/content/textures/ui/dialog_white@2x.png differ diff --git a/2018/content/textures/ui/dropdown_arrow.png b/2018/content/textures/ui/dropdown_arrow.png new file mode 100644 index 0000000..eddc0be Binary files /dev/null and b/2018/content/textures/ui/dropdown_arrow.png differ diff --git a/2018/content/textures/ui/dropdown_arrow@2x.png b/2018/content/textures/ui/dropdown_arrow@2x.png new file mode 100644 index 0000000..0db921e Binary files /dev/null and b/2018/content/textures/ui/dropdown_arrow@2x.png differ diff --git a/2018/content/textures/ui/homeButton.png b/2018/content/textures/ui/homeButton.png new file mode 100644 index 0000000..b9ad006 Binary files /dev/null and b/2018/content/textures/ui/homeButton.png differ diff --git a/2018/content/textures/ui/homeButton@2x.png b/2018/content/textures/ui/homeButton@2x.png new file mode 100644 index 0000000..2c2cdc0 Binary files /dev/null and b/2018/content/textures/ui/homeButton@2x.png differ diff --git a/2018/content/textures/ui/icon_BC-16.png b/2018/content/textures/ui/icon_BC-16.png new file mode 100644 index 0000000..dedd8d4 Binary files /dev/null and b/2018/content/textures/ui/icon_BC-16.png differ diff --git a/2018/content/textures/ui/icon_OBC-16.png b/2018/content/textures/ui/icon_OBC-16.png new file mode 100644 index 0000000..e539d5d Binary files /dev/null and b/2018/content/textures/ui/icon_OBC-16.png differ diff --git a/2018/content/textures/ui/icon_TBC-16.png b/2018/content/textures/ui/icon_TBC-16.png new file mode 100644 index 0000000..208dde3 Binary files /dev/null and b/2018/content/textures/ui/icon_TBC-16.png differ diff --git a/2018/content/textures/ui/icon_admin-16.png b/2018/content/textures/ui/icon_admin-16.png new file mode 100644 index 0000000..ae240d5 Binary files /dev/null and b/2018/content/textures/ui/icon_admin-16.png differ diff --git a/2018/content/textures/ui/icon_follower-16.png b/2018/content/textures/ui/icon_follower-16.png new file mode 100644 index 0000000..20dd9f1 Binary files /dev/null and b/2018/content/textures/ui/icon_follower-16.png differ diff --git a/2018/content/textures/ui/icon_following-16.png b/2018/content/textures/ui/icon_following-16.png new file mode 100644 index 0000000..a75dd9f Binary files /dev/null and b/2018/content/textures/ui/icon_following-16.png differ diff --git a/2018/content/textures/ui/icon_friendrequestrecieved-16.png b/2018/content/textures/ui/icon_friendrequestrecieved-16.png new file mode 100644 index 0000000..f7972f1 Binary files /dev/null and b/2018/content/textures/ui/icon_friendrequestrecieved-16.png differ diff --git a/2018/content/textures/ui/icon_friendrequestsent_16.png b/2018/content/textures/ui/icon_friendrequestsent_16.png new file mode 100644 index 0000000..947a5cf Binary files /dev/null and b/2018/content/textures/ui/icon_friendrequestsent_16.png differ diff --git a/2018/content/textures/ui/icon_friends_16.png b/2018/content/textures/ui/icon_friends_16.png new file mode 100644 index 0000000..17c5369 Binary files /dev/null and b/2018/content/textures/ui/icon_friends_16.png differ diff --git a/2018/content/textures/ui/icon_intern-16.png b/2018/content/textures/ui/icon_intern-16.png new file mode 100644 index 0000000..b4afb27 Binary files /dev/null and b/2018/content/textures/ui/icon_intern-16.png differ diff --git a/2018/content/textures/ui/icon_mutualfollowing-16.png b/2018/content/textures/ui/icon_mutualfollowing-16.png new file mode 100644 index 0000000..40adece Binary files /dev/null and b/2018/content/textures/ui/icon_mutualfollowing-16.png differ diff --git a/2018/content/textures/ui/icon_placeowner.png b/2018/content/textures/ui/icon_placeowner.png new file mode 100644 index 0000000..30f66ff Binary files /dev/null and b/2018/content/textures/ui/icon_placeowner.png differ diff --git a/2018/content/textures/ui/icon_star-16.png b/2018/content/textures/ui/icon_star-16.png new file mode 100644 index 0000000..189b9ca Binary files /dev/null and b/2018/content/textures/ui/icon_star-16.png differ diff --git a/2018/content/textures/ui/mouseLock_off.png b/2018/content/textures/ui/mouseLock_off.png new file mode 100644 index 0000000..c0b562a Binary files /dev/null and b/2018/content/textures/ui/mouseLock_off.png differ diff --git a/2018/content/textures/ui/mouseLock_off@2x.png b/2018/content/textures/ui/mouseLock_off@2x.png new file mode 100644 index 0000000..3773877 Binary files /dev/null and b/2018/content/textures/ui/mouseLock_off@2x.png differ diff --git a/2018/content/textures/ui/mouseLock_on.png b/2018/content/textures/ui/mouseLock_on.png new file mode 100644 index 0000000..9728774 Binary files /dev/null and b/2018/content/textures/ui/mouseLock_on.png differ diff --git a/2018/content/textures/ui/mouseLock_on@2x.png b/2018/content/textures/ui/mouseLock_on@2x.png new file mode 100644 index 0000000..c789d46 Binary files /dev/null and b/2018/content/textures/ui/mouseLock_on@2x.png differ diff --git a/2018/content/textures/ui/move.png b/2018/content/textures/ui/move.png new file mode 100644 index 0000000..d081458 Binary files /dev/null and b/2018/content/textures/ui/move.png differ diff --git a/2018/content/textures/ui/newBkg_square.png b/2018/content/textures/ui/newBkg_square.png new file mode 100644 index 0000000..901ffc1 Binary files /dev/null and b/2018/content/textures/ui/newBkg_square.png differ diff --git a/2018/content/textures/ui/newBkg_square@2x.png b/2018/content/textures/ui/newBkg_square@2x.png new file mode 100644 index 0000000..6956f48 Binary files /dev/null and b/2018/content/textures/ui/newBkg_square@2x.png differ diff --git a/2018/content/textures/ui/scroll-bottom.png b/2018/content/textures/ui/scroll-bottom.png new file mode 100644 index 0000000..f186156 Binary files /dev/null and b/2018/content/textures/ui/scroll-bottom.png differ diff --git a/2018/content/textures/ui/scroll-bottom@2x.png b/2018/content/textures/ui/scroll-bottom@2x.png new file mode 100644 index 0000000..3fb978f Binary files /dev/null and b/2018/content/textures/ui/scroll-bottom@2x.png differ diff --git a/2018/content/textures/ui/scroll-middle.png b/2018/content/textures/ui/scroll-middle.png new file mode 100644 index 0000000..1a7cfa7 Binary files /dev/null and b/2018/content/textures/ui/scroll-middle.png differ diff --git a/2018/content/textures/ui/scroll-middle@2x.png b/2018/content/textures/ui/scroll-middle@2x.png new file mode 100644 index 0000000..a101d48 Binary files /dev/null and b/2018/content/textures/ui/scroll-middle@2x.png differ diff --git a/2018/content/textures/ui/scroll-top.png b/2018/content/textures/ui/scroll-top.png new file mode 100644 index 0000000..1c85194 Binary files /dev/null and b/2018/content/textures/ui/scroll-top.png differ diff --git a/2018/content/textures/ui/scroll-top@2x.png b/2018/content/textures/ui/scroll-top@2x.png new file mode 100644 index 0000000..0720737 Binary files /dev/null and b/2018/content/textures/ui/scroll-top@2x.png differ diff --git a/2018/content/textures/ui/scrollbar.png b/2018/content/textures/ui/scrollbar.png new file mode 100644 index 0000000..1a3f361 Binary files /dev/null and b/2018/content/textures/ui/scrollbar.png differ diff --git a/2018/content/textures/ui/scrollbuttonDown.png b/2018/content/textures/ui/scrollbuttonDown.png new file mode 100644 index 0000000..fc6be92 Binary files /dev/null and b/2018/content/textures/ui/scrollbuttonDown.png differ diff --git a/2018/content/textures/ui/scrollbuttonDown_dn.png b/2018/content/textures/ui/scrollbuttonDown_dn.png new file mode 100644 index 0000000..38f1d5f Binary files /dev/null and b/2018/content/textures/ui/scrollbuttonDown_dn.png differ diff --git a/2018/content/textures/ui/scrollbuttonDown_ds.png b/2018/content/textures/ui/scrollbuttonDown_ds.png new file mode 100644 index 0000000..fb7f2f3 Binary files /dev/null and b/2018/content/textures/ui/scrollbuttonDown_ds.png differ diff --git a/2018/content/textures/ui/scrollbuttonDown_ovr.png b/2018/content/textures/ui/scrollbuttonDown_ovr.png new file mode 100644 index 0000000..38f1d5f Binary files /dev/null and b/2018/content/textures/ui/scrollbuttonDown_ovr.png differ diff --git a/2018/content/textures/ui/scrollbuttonUp.png b/2018/content/textures/ui/scrollbuttonUp.png new file mode 100644 index 0000000..311b520 Binary files /dev/null and b/2018/content/textures/ui/scrollbuttonUp.png differ diff --git a/2018/content/textures/ui/scrollbuttonUp_dn.png b/2018/content/textures/ui/scrollbuttonUp_dn.png new file mode 100644 index 0000000..aef3474 Binary files /dev/null and b/2018/content/textures/ui/scrollbuttonUp_dn.png differ diff --git a/2018/content/textures/ui/scrollbuttonUp_ds.png b/2018/content/textures/ui/scrollbuttonUp_ds.png new file mode 100644 index 0000000..551dbe7 Binary files /dev/null and b/2018/content/textures/ui/scrollbuttonUp_ds.png differ diff --git a/2018/content/textures/ui/scrollbuttonUp_ovr.png b/2018/content/textures/ui/scrollbuttonUp_ovr.png new file mode 100644 index 0000000..aef3474 Binary files /dev/null and b/2018/content/textures/ui/scrollbuttonUp_ovr.png differ diff --git a/2018/content/textures/ui/slider_new_tab.png b/2018/content/textures/ui/slider_new_tab.png new file mode 100644 index 0000000..ccc9ee1 Binary files /dev/null and b/2018/content/textures/ui/slider_new_tab.png differ diff --git a/2018/content/textures/ui/slider_new_tab@2x.png b/2018/content/textures/ui/slider_new_tab@2x.png new file mode 100644 index 0000000..07231fc Binary files /dev/null and b/2018/content/textures/ui/slider_new_tab@2x.png differ diff --git a/2018/content/textures/ui/vr_active.png b/2018/content/textures/ui/vr_active.png new file mode 100644 index 0000000..bda5347 Binary files /dev/null and b/2018/content/textures/ui/vr_active.png differ diff --git a/2018/content/textures/ui/vr_idle.png b/2018/content/textures/ui/vr_idle.png new file mode 100644 index 0000000..62b95c8 Binary files /dev/null and b/2018/content/textures/ui/vr_idle.png differ diff --git a/2018/content/textures/whiteCircle.png b/2018/content/textures/whiteCircle.png new file mode 100644 index 0000000..e1e5e4c Binary files /dev/null and b/2018/content/textures/whiteCircle.png differ diff --git a/2018/content/translations/CoreScriptLocalization.csv b/2018/content/translations/CoreScriptLocalization.csv new file mode 100644 index 0000000..fc9f650 --- /dev/null +++ b/2018/content/translations/CoreScriptLocalization.csv @@ -0,0 +1,452 @@ +Key,Context,Example,Source,de,en-us,es,es-es,fr,it,ja,ko,pt,pt-br,ru,zh-cn,zh-tw +Average,,,,Durchschnitt,Average,Promedio,Promedio,Moyen,Media,平均,평균,Média,Média,Среднее,平均,平均 +BACKPACK_SEARCH,,,,Suchen,Search,Buscar,Buscar,Rechercher,Cerca,サーチ,검색,Pesquisar,Pesquisar,Поиск,搜索,搜尋 +Current,,,,Aktuell,Current,Actual,Actual,Actuel,Attuale,現在,현재,Atual,Atual,Текущее,当前,目前 +FriendPlayerPrompt.DoPromptRequestFriendPlayer,,,,Möchtest du {RBX_NAME} eine Freundesanfrage senden?,Would you like to send {RBX_NAME} a Friend Request?,¿Quieres enviar a {RBX_NAME} una solicitud de amistad?,¿Quieres enviar a {RBX_NAME} una solicitud de amistad?,Souhaitez-vous envoyer une demande d'ami à {RBX_NAME} ?,Vuoi inviare una richiesta di amicizia a {RBX_NAME}?,{RBX_NAME} に友達リクエストを送りますか?,{RBX_NAME}님에게 친구 요청을 보낼까요?,Gostaria de enviar um pedido de amizade para {RBX_NAME}?,Gostaria de enviar um pedido de amizade para {RBX_NAME}?,Отправить пользователю {RBX_NAME} запрос дружбы?,你想要向“{RBX_NAME}”发送好友请求吗?,您是否要寄給{RBX_NAME}交友請求? +FriendPlayerPrompt.DoPromptUnfriendPlayer,,,,Möchtest du {RBX_NAME} von deiner Freundesliste entfernen?,Would you like to remove {RBX_NAME} from your friends list?,¿Quieres eliminar a {RBX_NAME} de tu lista de amigos?,¿Quieres eliminar a {RBX_NAME} de tu lista de amigos?,Souhaitez-vous retirer {RBX_NAME} de votre liste d'amis ?,Vuoi rimuovere {RBX_NAME} dalla tua lista amici?,{RBX_NAME} を友達リストから削除しますか?,{RBX_NAME}님을 친구 목록에서 삭제할까요?,Gostaria de remover {RBX_NAME} da sua lista de amigos?,Gostaria de remover {RBX_NAME} da sua lista de amigos?,Удалить пользователя {RBX_NAME} из списка друзей?,你想要将“{RBX_NAME}”从你的好友名单中移除吗?,您是否要將{RBX_NAME}自朋友清單移除? +FriendPlayerPrompt.promptCompletedCallback.AtFriendLimit,,,,"Du kannst {RBX_NAME} keine Freundesanfrage senden, da dieser Spieler die max. Anzahl an Freunden erreicht hat.",You can not send a friend request to {RBX_NAME} because they are at the max friend limit.,No puedes enviar una solicitud de amistad a {RBX_NAME} porque ha alcanzado el límite máximo de amigos.,No puedes enviar una solicitud de amistad a {RBX_NAME} porque ha alcanzado el límite máximo de amigos.,"Vous ne pouvez pas envoyer une demande d'ami à {RBX_NAME}, car il a atteint sa limite maximale d'amis.",Non puoi inviare una richiesta di amicizia a {RBX_NAME} perché ha raggiunto il limite massimo di amici.,{RBX_NAME}の友達が最大数に達しているため友達リクエストが送れませんでした。,대상의 최대 친구 목록이 초과되어 {RBX_NAME}에게 친구 요청을 보낼 수 없어요.,Você não pode enviar um pedido de amizade para {RBX_NAME} pois ele(a) alcançou o limite máximo de amigos.,Você não pode enviar um pedido de amizade para {RBX_NAME} pois ele(a) alcançou o limite máximo de amigos.,Нельзя отправить запрос дружбы пользователю {RBX_NAME}: количество его друзей достигло максимума.,由于对方已达到好友数量上限,你无法向“{RBX_NAME}”发送好友请求。,您無法寄送交友請求給{RBX_NAME},原因是對方的朋友已達上限。 +FriendPlayerPrompt.promptCompletedCallback.UnknownError,,,,Beim Senden der Freundesanfrage an {RBX_NAME} ist ein Fehler aufgetreten. Bitte versuche es später erneut.,An error occurred while sending {RBX_NAME} a friend request. Please try again later.,Se ha producido un error al enviar una solicitud de amistad a {RBX_NAME}. Inténtalo de nuevo más tarde.,Se ha producido un error al enviar una solicitud de amistad a {RBX_NAME}. Inténtalo de nuevo más tarde.,Une erreur est survenue lors de l'envoi de la demande d'ami à {RBX_NAME}. Veuillez réessayer plus tard.,Si è verificato un errore nell'invio della richiesta di amicizia a {RBX_NAME}. Riprova più tardi.,{RBX_NAME} への友達リクエスト中にエラーが発生しました。しばらくしてからやり直してください。,{RBX_NAME}님에게 친구 요청 전송 중 오류 발생. 나중에 다시 시도하세요.,Um erro ocorreu ao enviar um pedido de amizade para {RBX_NAME}. Tente de novo mais tarde.,Um erro ocorreu ao enviar um pedido de amizade para {RBX_NAME}. Tente de novo mais tarde.,При отправлении запроса дружбы пользователю {RBX_NAME} произошла ошибка. Повторите попытку позже.,向“{RBX_NAME}”发送好友请求时发生错误。请稍候重试。,寄給{RBX_NAME}交友請求時發生錯誤。請稍後再試。 +KEY_DESCRIPTION_OPTIONAL,,,,Optional,Optional,Opcional,Opcional,Optionnel,Opzionale,オプション,선택 항목,Opcional,Opcional,По усмотрению,可选,可選填 +KEY_DESCRIPTION_SHORT_DECRIPTION_OPTIONAL,,,,Kurzbeschreibung (optional),Short Description (Optional),Descripción breve (opcional),Descripción breve (opcional),Description brève (facultatif),Descrizione breve (opzionale),簡単な説明(オプション),간략한 설명(선택 항목),Breve descrição (opcional),Breve descrição (opcional),Короткое описание (необязательно),短描述(可选),簡短描述(可選填) +KEY_PLAYER_IDLE_DISCONNECT,,,,"Deine Verbindung wurde getrennt, da du {RBX_NUMBER} Minuten lang untätig warst.",You were disconnected for being idle {RBX_NUMBER} minutes,Se te ha desconectado por no mostrar actividad durante {RBX_NUMBER} minutos.,Se te ha desconectado por no mostrar actividad durante {RBX_NUMBER} minutos.,Vous avez été déconnecté car vous êtes resté inactif durant {RBX_NUMBER} minutes.,Sei stato disconnesso perché inattivo per {RBX_NUMBER} minuti,{RBX_NUMBER} 分間アイドル状態だったので切断されました。,{RBX_NUMBER}분 동안 기본 상태로 있어 연결이 끊겼어요,Você perdeu a conexão por ficar inativo(a) por {RBX_NUMBER} minutos,Você perdeu a conexão por ficar inativo(a) por {RBX_NUMBER} minutos,"Вы отключены, так как не были активны в течение {RBX_NUMBER} мин.",由于闲置超过 {RBX_NUMBER} 分钟,你已被断开,您的連線中斷導因於閒置 {RBX_NUMBER} 分鐘 +Network,,,,(Netzwerk),(Network),(Red),(Red),(Réseau),(Rete),(ネットワーク),(네트워크),(Rede),(Rede),(Сеть),(网络),(網路) +NotificationScrip2.onCurrentGraphicsQualityLevelChanged.Decreased,,,,Verringert auf {RBX_NUMBER},Decreased to {RBX_NUMBER},Reducción a {RBX_NUMBER},Reducción a {RBX_NUMBER},Réduit jusqu'à {RBX_NUMBER},Sceso a {RBX_NUMBER},{RBX_NUMBER}に減少,{RBX_NUMBER}(으)로 감소,Reduzido para {RBX_NUMBER},Reduzido para {RBX_NUMBER},Уменьшено до {RBX_NUMBER},减至 {RBX_NUMBER},減少至{RBX_NUMBER} +NotificationScrip2.onCurrentGraphicsQualityLevelChanged.Increased,,,,Erhöht auf {RBX_NUMBER},Increased to {RBX_NUMBER},Aumento hasta {RBX_NUMBER},Aumento hasta {RBX_NUMBER},Augmenté jusqu'à {RBX_NUMBER},Salito a {RBX_NUMBER},{RBX_NUMBER}に増加,{RBX_NUMBER}(으)로 증가,Aumentado para {RBX_NUMBER},Aumentado para {RBX_NUMBER},Увеличено до {RBX_NUMBER},增至 {RBX_NUMBER},增加至{RBX_NUMBER} +NotificationScript2.FriendRequestEvent.Accept,,,,Du bist jetzt Freunde mit {RBX_NAME}!,You are now friends with {RBX_NAME}!,Ahora eres amigo de {RBX_NAME}.,Ahora eres amigo de {RBX_NAME}.,Vous êtes maintenant ami avec {RBX_NAME}!,Sei ora amici di {RBX_NAME}!,あなたは{RBX_NAME}の友達です!,이제 {RBX_NAME}님과 친구예요!,Agora você é amigo do {RBX_NAME}!,Agora você é amigo do {RBX_NAME}!,Вы теперь друзья с {RBX_NAME}!,你现在与 {RBX_NAME} 成为好友了!,您現在與{RBX_NAME}已是朋友! +NotificationScript2.NewFollower,,,,Neuer Follower {RBX_NAME} folgt dir jetzt!,New Follower {RBX_NAME} is now following you!,Seguidor nuevo: ¡{RBX_NAME} te está siguiendo!,Seguidor nuevo: ¡{RBX_NAME} te está siguiendo!,"Désormais, le nouvel abonné, {RBX_NAME}, vous suit !",Il nuovo follower {RBX_NAME} ha cominciato a seguirti!,新規フォロワー {RBX_NAME} があなたをフォローしました!,새 팔로워 {RBX_NAME}님이 회원님을 팔로우합니다!,"O novo seguidor, {RBX_NAME}, está seguindo você agora!","O novo seguidor, {RBX_NAME}, está seguindo você agora!",На вас подписался пользователь {RBX_NAME}!,新粉丝“{RBX_NAME}”现在关注了你!,新關注者{RBX_NAME}現正關注您! +NotificationScript2.onPointsAwarded.multiple,,,,Du hast {RBX_NUMBER} Punkte erhalten!,You received {RBX_NUMBER} points!,¡Has recibido {RBX_NUMBER} puntos!,¡Has recibido {RBX_NUMBER} puntos!,Vous avez reçu {RBX_NUMBER} points !,Hai ricevuto {RBX_NUMBER} punti!,{RBX_NUMBER} ポイントをゲットしました!,{RBX_NUMBER} 포인트를 받았어요!,Você recebeu {RBX_NUMBER} pontos!,Você recebeu {RBX_NUMBER} pontos!,Вы получили {RBX_NUMBER} очк.!,你得到了 {RBX_NUMBER} 点!,您得到{RBX_NUMBER}點! +NotificationScript2.onPointsAwarded.single,,,,Du hast {RBX_NUMBER} Punkt erhalten!,You received {RBX_NUMBER} point!,¡Has recibido {RBX_NUMBER} punto!,¡Has recibido {RBX_NUMBER} punto!,Vous avez reçu {RBX_NUMBER} point !,Hai ricevuto {RBX_NUMBER} punto!,{RBX_NUMBER} ポイントをゲットしました!,{RBX_NUMBER} 포인트를 받았어요!,Você recebeu {RBX_NUMBER} ponto!,Você recebeu {RBX_NUMBER} ponto!,Вы получили {RBX_NUMBER} очк.!,你得到了 {RBX_NUMBER} 点!,您得到{RBX_NUMBER}點! +NotificationScript2.onPointsRewarded.negative,,,,Du hast {RBX_NUMBER} Punkte verloren!,You lost {RBX_NUMBER} points!,¡Has perdido {RBX_NUMBER} puntos!,¡Has perdido {RBX_NUMBER} puntos!,Vous avez perdu {RBX_NUMBER} points !,Hai perso {RBX_NUMBER} punti!,{RBX_NUMBER} ポイント失いました!,{RBX_NUMBER} 포인트를 잃었어요!,Você perdeu {RBX_NUMBER} pontos!,Você perdeu {RBX_NUMBER} pontos!,Вы потеряли {RBX_NUMBER} очк.!,你丢失了 {RBX_NUMBER} 点!,您失去{RBX_NUMBER}點! +PlayerDropDown.onFollowButtonPress.success,,,,folgst jetzt {RBX_NAME},now following {RBX_NAME},Estás siguiendo a {RBX_NAME},Estás siguiendo a {RBX_NAME},Vous suivez désormais {RBX_NAME}.,stai seguendo {RBX_NAME},{RBX_NAME}人をフォロー中,{RBX_NAME} 팔로우 중,agora seguindo {RBX_NAME},agora seguindo {RBX_NAME},подписались на {RBX_NAME},现正关注“{RBX_NAME}”,現正關注{RBX_NAME} +PlayerDropDown.onUnfollowButtonPress.success,,,,Folgst nicht mehr {RBX_NAME},No longer following {RBX_NAME}.,Ya no estás siguiendo a {RBX_NAME}.,Ya no estás siguiendo a {RBX_NAME}.,Vous ne suivez plus {RBX_NAME}.,Non stai seguendo ancora {RBX_NAME}.,あなたはもはや{RBX_NAME}に従っていません。,{RBX_NAME}님 팔로우 취소.,Você não está mais seguindo {RBX_NAME}.,Você não está mais seguindo {RBX_NAME}.,Вы перестали следовать {RBX_NAME}.,停止关注“{RBX_NAME}”。,不再關注{RBX_NAME}。 +PurchasePromptScript.ERROR_MSG.INVALID_FUNDS,,,,dein Konto nicht über genügend ROBUX verfügt,your account does not have enough ROBUX,tu cuenta no tiene suficientes ROBUX,tu cuenta no tiene suficientes ROBUX,votre compte ne possède pas assez de ROBUX,il tuo account non ha abbastanza ROBUX,アカウントのROBUXが足りません。,계정의 ROBUX가 부족해요,sua conta não tem ROBUX suficientes,sua conta não tem ROBUX suficientes,у вас недостаточно ROBUX,你的帐户没有足够的 Robux,您帳戶下的 ROBUX 不足 +PurchasePromptScript.ERROR_MSG.MAINTENANCE,,,,ROBLOX Wartungsarbeiten durchführt,ROBLOX is performing maintenance,ROBLOX está efectuando tareas de mantenimiento,ROBLOX está efectuando tareas de mantenimiento,ROBLOX est en cours de maintenance,ROBLOX sta effettuando la manutenzione,ROBLOXはメンテナンス中です。,ROBLOX에서 점검 중이에요,ROBLOX está em manutenção,ROBLOX está em manutenção,Проводится техническое обслуживание ROBLOX,Roblox 正在维护中,ROBLOX 正在進行維護 +PurchasePromptScript.ERROR_MSG.PURCHASE_DISABLED,,,,Käufe im Spiel derzeit deaktiviert sind,In-game purchases are temporarily disabled,las compras dentro de la aplicación están desactivadas temporalmente,las compras dentro de la aplicación están desactivadas temporalmente,Les achats intégrés sont temporairement désactivés,Gli acquisti all'interno del gioco sono temporaneamente disattivati,ゲーム内購入は一時的に無効になっています。,일시적으로 게임 내 구매를 이용할 수 없어요,As compras no jogo estão temporariamente desabilitadas,As compras no jogo estão temporariamente desabilitadas,Внутриигровые покупки временно недоступны,游戏内购买功能暂时停用,遊戲內購買暫時停用 +PurchasePromptScript.ERROR_MSG.UNKNOWN,,,,ein Problem aufgetreten ist,something went wrong,algo ha ido mal,algo ha ido mal,quelque chose s'est mal passé,qualcosa è andato storto,何かが違う,문제가 생겼어요,algo deu errado,algo deu errado,возникли проблемы,有地方出错,有地方出錯 +PurchasePromptScript.PURCHASE_FAILED.CANNOT_GET_BALANCE,,,,Dein Guthaben kann derzeit nicht abgerufen werden. Dein Konto wurde nicht belastet. Bitte versuche es später erneut.,Cannot retrieve your balance at this time. Your account has not been charged. Please try again later.,En este momento no es posible acceder a tu saldo. No se ha llevado a cabo ningún cobro en tu cuenta. Inténtalo de nuevo más tarde.,En este momento no es posible acceder a tu saldo. No se ha llevado a cabo ningún cobro en tu cuenta. Inténtalo de nuevo más tarde.,Impossible d'obtenir votre solde pour l'instant. Votre compte n'a pas été débité. Veuillez réessayer plus tard.,Impossibile recuperare i tuoi fondi in questo momento. Il tuo account non ha subito addebiti. Riprova più tardi.,現在は残額を参照できません。アカウントがチャージされませんでした。しばらくしてからやり直してください。,현재 잔액을 불러올 수 없어요. 계정에 비용이 청구되지 않아요. 나중에 다시 시도하세요.,Impossível obter seu saldo no momento. Nada foi cobrado da sua conta. Tente de novo mais tarde.,Impossível obter seu saldo no momento. Nada foi cobrado da sua conta. Tente de novo mais tarde.,Не удалось получить доступ к вашему балансу. Средства с вашей учетной записи не списаны. Повторите попытку позже.,当前无法读取你的余额。你的帐户未被扣款。请稍候重试。,此刻無法擷取您的餘額。未自您的帳戶收費。請稍後再試一次。 +PurchasePromptScript.PURCHASE_FAILED.CANNOT_GET_ITEM_PRICE,,,,Der Preis des Gegenstands kann derzeit nicht abgerufen werden. Dein Konto wurde nicht belastet. Bitte versuche es später erneut.,We couldn't retrieve the price of the item at this time. Your account has not been charged. Please try again later.,En este momento no podemos acceder al precio de este objeto. No se ha llevado a cabo ningún cobro en tu cuenta. Inténtalo de nuevo más tarde.,En este momento no podemos acceder al precio de este objeto. No se ha llevado a cabo ningún cobro en tu cuenta. Inténtalo de nuevo más tarde.,Nous ne pouvons pas récupérer le prix de cet objet pour l'instant. Votre compte n'a pas été débité. Veuillez réessayer plus tard.,Impossibile recuperare il prezzo dell'oggetto in questo momento. Il tuo account non ha subito addebiti. Riprova più tardi.,現在はアイテムの価格が参照できません。アカウントがチャージされませんでした。しばらくしてからやり直してください。,현재 아이템 가격을 불러올 수 없어요. 계정에 비용이 청구되지 않아요. 나중에 다시 시도하세요.,Não conseguimos obter o preço do item no momento. Nada foi cobrado da sua conta. Tente de novo mais tarde.,Não conseguimos obter o preço do item no momento. Nada foi cobrado da sua conta. Tente de novo mais tarde.,Не удалось получить данные о цене товара. Средства с вашей учетной записи не списаны. Повторите попытку позже.,当前无法读取物品的价格。你的帐户未被扣款。请稍候重试。,此刻無法擷取項目的價格。未自您的帳戶收費。請稍後再試一次。 +PurchasePromptScript.PURCHASE_FAILED.LIMITED,,,,Von diesem limitierten Gegenstand gibt es keine weiteren Exemplare. Such auf www.roblox.com nach einem anderen Verkäufer. Dein Konto wurde nicht belastet.,This limited item has no more copies. Try buying from another user on www.roblox.com. Your account has not been charged.,Este objeto limitado no tiene más copias. Intenta comprárselo a otro usuario en www.roblox.com. No se ha llevado a cabo ningún cobro en tu cuenta.,Este objeto limitado no tiene más copias. Intenta comprárselo a otro usuario en www.roblox.com. No se ha llevado a cabo ningún cobro en tu cuenta.,Il n'y a plus d'exemplaires de cet objet en série limitée. Essayez de l'acheter à un autre utilisateur sur www.roblox.com. Votre compte n'a pas été débité.,Questo oggetto limitato non è più disponibile. Prova ad acquistarlo da un altro utente sul sito www.roblox.com. Il tuo account non ha subito addebiti.,この限定アイテムはもう残っていません。www.roblox.com で他のユーザから購入してみてください。アカウントがチャージされませんでした。,이 한정 아이템은 더 이상 재고가 없어요. www.roblox.com에서 다른 사용자에게 구매해보세요. 계정에 비용이 청구되지 않아요.,Esgotaram-se as cópias deste item limitado. Tente comprar de outro usuário em www.roblox.com. Nada foi cobrado da sua conta.,Esgotaram-se as cópias deste item limitado. Tente comprar de outro usuário em www.roblox.com. Nada foi cobrado da sua conta.,Этого ограниченного товара больше нет в продаже. Попробуйте купить его у другого пользователя на сайте www.roblox.com. Средства с вашей учетной записи не списаны.,此限量物品已售完。请尝试在 www.roblox.com 上从别的用户手中购买。你的帐户未被扣款。,此限量項目已無複本。請嘗試在 www.roblox.com 向其他使用者購買。未自您的帳戶收費。 +PurchasePromptScript.PURCHASE_FAILED.NOT_ENOUGH_TIX,,,,"Dieser Gegenstand kostet mehr Tickets, als du derzeit besitzt. Auf www.roblox.com kannst du Währungen tauschen, um mehr Tickets zu erhalten.",This item cost more tickets than you currently have. Try trading currency on www.roblox.com to get more tickets.,Este objeto cuesta más tiques de los que tienes en este momento. Intenta convertir tipos de moneda en www.roblox.com para obtener más tiques.,Este objeto cuesta más tiques de los que tienes en este momento. Intenta convertir tipos de moneda en www.roblox.com para obtener más tiques.,Cet objet coûte plus de tickets que vous n'en avez. Essayez d'échanger des devises sur www.roblox.com pour obtenir plus de tickets.,Questo oggetto costa più ticket di quanti tu ne abbia. Prova a scambiare valuta sul sito www.roblox.com per ottenere più ticket.,このアイテムの入手には現在お持ちのチケットでは足りません。www.roblox.com でお金のトレーディングをしてチケットを手に入れよう。,이 아이템은 현재 소지한 티켓보다 더 비싸요. 더 많은 티켓을 받으려면 www.roblox.com에서 통화를 거래하세요.,Este item custa mais bilhetes do que você tem no momento. Experimente trocar moeda do jogo em www.roblox.com para obter mais.,Este item custa mais bilhetes do que você tem no momento. Experimente trocar moeda do jogo em www.roblox.com para obter mais.,"Цена товара превышает имеющееся у вас количество купонов. Обменяйте валюту на странице www.roblox.com, чтобы получить больше купонов.",此物品的价格超过你当前拥有的票单。在 www.roblox.com 上尝试交易货币以获取更多票单。,此項目所需票券超過您目前擁有。請嘗試在 www.roblox.com 交易貨幣以取得更多票券。 +PurchasePromptScript.PURCHASE_FAILED.NOT_FOR_SALE,,,,Dieser Gegenstand steht derzeit nicht zum Verkauf. Dein Konto wurde nicht belastet.,This item is not currently for sale. Your account has not been charged.,Este objeto no está a la venta en este momento. No se ha llevado a cabo ningún cobro en tu cuenta.,Este objeto no está a la venta en este momento. No se ha llevado a cabo ningún cobro en tu cuenta.,Cet objet n'est pas en vente pour l'instant. Votre compte n'a pas été débité.,Questo oggetto non è attualmente in vendita. Il tuo account non ha subito addebiti.,このアイテムは現在売られていません。アカウントがチャージされませんでした。,이 아이템은 현재 판매 중이 아니에요. 계정에 비용이 청구되지 않아요.,Este item não está disponível para compra no momento. Nada foi cobrado da sua conta.,Este item não está disponível para compra no momento. Nada foi cobrado da sua conta.,Этот товар в настоящее время не продается. Средства с вашей учетной записи не списаны.,此物品当前为非卖品。你的帐户未被扣款。,此項目目前為非賣品,未自您的帳戶收費。 +PurchasePromptScript.PURCHASE_FAILED.PROMPT_PURCHASE_ON_GUEST,,,,"Du musst ein ROBLOX-Konto erstellen, um Gegenstände zu kaufen. Auf www.roblox.com findest du weitere Infos.","You need to create a ROBLOX account to buy items, visit www.roblox.com for more info.",Tienes que crear una cuenta de ROBLOX para comprar objetos. Visita www.roblox.com para obtener más información.,Tienes que crear una cuenta de ROBLOX para comprar objetos. Visita www.roblox.com para obtener más información.,"Vous devez créer un compte ROBLOX pour acheter des objets, rendez-vous sur www.roblox.com pour plus d'informations.","Per poter comprare oggetti, devi creare un account ROBLOX. Visita il sito www.roblox.com per maggiori informazioni.",アイテムを購入するにはROBLOX アカウントを作る必要があります。詳しくは www.roblox.com で。,아이템을 구매하려면 ROBLOX 계정을 만들어야 해요. 자세한 정보는 www.roblox.com을 방문하세요.,Você precisa criar uma conta ROBLOX para comprar itens. Visite www.roblox.com para mais informações.,Você precisa criar uma conta ROBLOX para comprar itens. Visite www.roblox.com para mais informações.,"Создайте учетную запись ROBLOX, чтобы покупать предметы. Посетите сайт www.roblox.com.",你需要创建 ROBLOX 帐户以购买物品,访问 www.roblox.com 以获取更多信息。,您需要建立 ROBLOX 帳戶以購買項目,更多資訊請瀏覽 www.roblox.com。 +PurchasePromptScript.PURCHASE_FAILED.THIRD_PARTY_DISABLED,,,,Gegenstände von Drittanbietern können an diesem Ort nicht verkauft werden. Dein Konto wurde nicht belastet.,Third-party item sales have been disabled for this place. Your account has not been charged.,Las ventas de objetos de terceros están desactivadas para este lugar. No se ha llevado a cabo ningún cobro en tu cuenta.,Las ventas de objetos de terceros están desactivadas para este lugar. No se ha llevado a cabo ningún cobro en tu cuenta.,Les ventes d'objets par des tiers ont été désactivées pour cet emplacement. Votre compte n'a pas été débité.,Le vendite di oggetti di terzi sono state disattivate per questa località. Il tuo account non ha subito addebiti.,サードパーティ製のアイテムの販売はここでは禁止されています。アカウントがチャージされませんでした。,여기서는 제삼자 아이템 판매를 이용할 수 없어요. 계정에 비용이 청구되지 않아요.,Vendas de itens de terceiros foram desabilitadas para este local. Nada foi cobrado da sua conta.,Vendas de itens de terceiros foram desabilitadas para este local. Nada foi cobrado da sua conta.,Продажа сторонних товаров в этом месте запрещена. Средства с вашей учетной записи не списаны.,此地点的第三方物品拍卖已停用。你的帐户未被扣款。,此地點的第三方項目大拍賣已停用。並未自您的帳戶收費。 +PurchasePromptScript.PURCHASE_FAILED.UNDER_13,,,,Dein Konto ist für Spieler unter 13 Jahren. Der Kauf dieses Gegenstands ist nicht gestattet. Dein Konto wurde nicht belastet.,Your account is under 13. Purchase of this item is not allowed. Your account has not been charged.,Tu cuenta es para menores de 13 años. La compra de este objeto no está permitida. No se ha llevado a cabo ningún cobro en tu cuenta.,Tu cuenta es para menores de 13 años. La compra de este objeto no está permitida. No se ha llevado a cabo ningún cobro en tu cuenta.,Votre compte est Moins de 13 ans. L'achat de cet objet n'est pas permis. Votre compte n'a pas été débité.,Il tuo account è per giocatori con meno di 13 anni. L'acquisto di questo oggetto non è permesso. Il tuo account non ha subito addebiti.,あなたのアカウントは13才以下です。このアイテムの購入は認められていません。アカウントがチャージされませんでした。,만 13세 미만의 계정으로 이 아이템을 구매할 수 없어요. 계정에 비용이 청구되지 않아요.,Sua conta é para menor de 13 anos. A compra deste item não é permitida. Nada foi cobrado da sua conta.,Sua conta é para menor de 13 anos. A compra deste item não é permitida. Nada foi cobrado da sua conta.,Возраст владельца учетной записи не превышает 13 лет. Вы не можете купить этот товар. Средства с вашей учетной записи не списаны.,此帐户的用户未满 13 岁,不允许购买此物品。你的帐户未被扣款。,您的帳戶未滿 13 歲,不允許購買此項目。未自您的帳戶收費。 +PurchasePromptScript.PURCHASE_MSG.BALANCE_FUTURE,,,,Nach dieser Transaktion wird dein Guthaben {RBX_NUMBER} betragen.,Your balance after this transaction will be {RBX_NUMBER}.,Tu saldo después de esta transacción será de {RBX_NUMBER}.,Tu saldo después de esta transacción será de {RBX_NUMBER}.,Votre solde après cette transaction sera de {RBX_NUMBER}.,"Dopo la transazione, i tuoi fondi saranno {RBX_NUMBER}.",取引後の残高は{RBX_NUMBER}になります。,이 거래 후의 예상 잔액은 {RBX_NUMBER}이에요.,Seu saldo depois desta transação será de {RBX_NUMBER}.,Seu saldo depois desta transação será de {RBX_NUMBER}.,После этой операции ваш баланс составит {RBX_NUMBER},此次交易后,你的余额将为 {RBX_NUMBER}。,您此交易後的餘額將為 {RBX_NUMBER}。 +PurchasePromptScript.PURCHASE_MSG.BALANCE_NOW,,,,Dein Guthaben beträgt nun {RBX_NUMBER}.,Your balance is now {RBX_NUMBER}.,Tu saldo es ahora de {RBX_NUMBER}.,Tu saldo es ahora de {RBX_NUMBER}.,Votre solde est désormais de {RBX_NUMBER}.,Ora i tuoi fondi sono {RBX_NUMBER}.,残高は現在{RBX_NUMBER}です。,현재 잔액은 {RBX_NUMBER}이에요.,Seu saldo agora é {RBX_NUMBER}.,Seu saldo agora é {RBX_NUMBER}.,Сейчас ваш баланс составляет {RBX_NUMBER}.,你的当前余额为 {RBX_NUMBER}。,您的餘額現在為{RBX_NUMBER}。 +PurchasePromptScript.PURCHASE_MSG.FAILED,,,,"Du konntest „{RBX_NAME1}“ nicht kaufen, da {RBX_NAME2}. Dein Konto wurde nicht belastet. Bitte versuche es später erneut.",Your purchase of {RBX_NAME1} failed because {RBX_NAME2}. Your account has not been charged. Please try again later.,Tu compra de {RBX_NAME1} no ha funcionado porque {RBX_NAME2}. No se ha realizado ningún cobro. Inténtalo de nuevo más tarde.,Tu compra de {RBX_NAME1} no ha funcionado porque {RBX_NAME2}. No se ha realizado ningún cobro. Inténtalo de nuevo más tarde.,Votre achat de {RBX_NAME1} a échoué à cause de {RBX_NAME2}. Votre compte n'a pas été débité. Veuillez réessayer plus tard.,Il tuo acquisto di {RBX_NAME1} non è riuscito perché: {RBX_NAME2}. Il tuo account non ha subito addebiti. Riprova più tardi.,{RBX_NAME1}のため、{RBX_NAME2} の購入に失敗しました。アカウントがチャージされませんでした。しばらくしてからやり直してください。,{RBX_NAME1} 구매 실패. 실패 이유: {RBX_NAME2}. 계정에 비용이 청구되지 않았어요. 나중에 다시 시도하세요.,Sua compra de {RBX_NAME1} fracassou. Motivo: {RBX_NAME2}. Nada foi cobrado da sua conta. Tente de novo mais tarde.,Sua compra de {RBX_NAME1} fracassou. Motivo: {RBX_NAME2}. Nada foi cobrado da sua conta. Tente de novo mais tarde.,Не удалось купить товар {RBX_NAME1}: {RBX_NAME2}. Средства с вашей учетной записи не списаны. Повторите попытку позже.,由于“{RBX_NAME2}”,未能成功购买“{RBX_NAME1}”。你的帐户未被扣款。请稍候重试。,您購買{RBX_NAME1}未成,原因是{RBX_NAME2}。未自您的帳戶收費。請稍後再試一次。 +PurchasePromptScript.PURCHASE_MSG.FREE,,,,Möchtest du „{RBX_NAME2}“ gerne GRATIS nehmen?,Would you like to take {RBX_NAME2} for FREE?,¿Quieres obtener {RBX_NAME2} GRATIS?,¿Quieres obtener {RBX_NAME2} GRATIS?,Souhaitez-vous prendre l'objet {RBX_NAME2} GRATUITEMENT ?,Vuoi prendere l'oggetto {RBX_NAME2} GRATIS?,アイテム名{RBX_NAME2} を無料で入手したいですか?,무료로 {RBX_NAME2}을(를) 받을까요?,Gostaria de obter {RBX_NAME2} GRÁTIS?,Gostaria de obter {RBX_NAME2} GRÁTIS?,Хотите получить товар {RBX_NAME2} БЕСПЛАТНО?,你想要免费拿到“{RBX_NAME2}”吗?,您是否要免費收取{RBX_NAME2}? +PurchasePromptScript.PURCHASE_MSG.PURCHASE,,,,Möchtest du {RBX_NAME1} {RBX_NAME2} kaufen für:,Want to buy the {RBX_NAME1} {RBX_NAME2} for,¿Quieres comprar {RBX_NAME1} {RBX_NAME2} por,¿Quieres comprar {RBX_NAME1} {RBX_NAME2} por,Vous voulez acheter le {RBX_NAME1} {RBX_NAME2} pour,Vuoi comprare {RBX_NAME1} {RBX_NAME2} per,のために{RBX_NAME1} {RBX_NAME2} を購入希望,다음 금액으로 {RBX_NAME1} {RBX_NAME2}을(를) 구매할까요,Deseja comprar {RBX_NAME1} {RBX_NAME2} por,Deseja comprar {RBX_NAME1} {RBX_NAME2} por,Купить {RBX_NAME1} {RBX_NAME2} за,你想要以如下价格购买“{RBX_NAME1} - {RBX_NAME2}”:,想買{RBX_NAME1} {RBX_NAME2},花 +PurchasePromptScript.PURCHASE_MSG.SUCCEEDED,,,,Du hast „{RBX_NAME1}“ gekauft!,Your purchase of {RBX_NAME1} succeeded!,¡Tu compra de {RBX_NAME1} ha funcionado!,¡Tu compra de {RBX_NAME1} ha funcionado!,Votre achat de {RBX_NAME1} a réussi !,Il tuo acquisto di {RBX_NAME1} è andato a buon fine!,{RBX_NAME1} の購入に成功しました!,성공적으로 {RBX_NAME1}을(를) 구매했어요!,Sua compra de {RBX_NAME1} foi bem-sucedida!,Sua compra de {RBX_NAME1} foi bem-sucedida!,Вы купили товар {RBX_NAME1}!,购买“{RBX_NAME1}”成功!,您購買{RBX_NAME1}成功! +PurchasePromptScript.setBuyMoreRobuxDialog.PostBalanceText,,,,Die verbleibenden {RBX_NUMBER} ROBUX werden deinem Guthaben gutgeschrieben.,The remaining {RBX_NUMBER} ROBUX will be credited to your balance.,Los {RBX_NUMBER} ROBUX restantes se cargarán a tu saldo.,Los {RBX_NUMBER} ROBUX restantes se cargarán a tu saldo.,Les {RBX_NUMBER} ROBUX restants seront portés à votre solde.,I rimanenti {RBX_NUMBER} ROBUX verranno accreditati ai tuoi fondi.,残りの {RBX_NUMBER} ROBUX があなたの口座に返金されます。,남은 {RBX_NUMBER} ROBUX는 잔액에 추가돼요.,Os {RBX_NUMBER} ROBUX restantes serão somados ao seu saldo.,Os {RBX_NUMBER} ROBUX restantes serão somados ao seu saldo.,Оставшиеся {RBX_NUMBER} ROBUX будут перечислены на ваш баланс.,剩余的 {RBX_NUMBER} ROBUX 将计入你的余额。,剩餘的 {RBX_NUMBER} ROBUX 會計入您的餘額。 +PurchasePromptScript.setBuyMoreRobuxDialog.descriptionText,,,,"Du brauchst noch {RBX_NUMBER} ROBUX, um {RBX_NAME1} {RBX_NAME2} zu kaufen. Möchtest du mehr ROBUX kaufen?",You need {RBX_NUMBER} more ROBUX to buy the {RBX_NAME1} {RBX_NAME2}. Would you like to buy more ROBUX?,Necesitas {RBX_NUMBER} ROBUX más para comprar {RBX_NAME1} {RBX_NAME2}. ¿Quieres comprar más ROBUX?,Necesitas {RBX_NUMBER} ROBUX más para comprar {RBX_NAME1} {RBX_NAME2}. ¿Quieres comprar más ROBUX?,Vous avez besoin de {RBX_NUMBER} ROBUX de plus pour acheter le {RBX_NAME1} {RBX_NAME2}. Souhaitez-vous acheter plus de ROBUX ?,Hai bisogno di {RBX_NUMBER} ROBUX in più per comprare: {RBX_NAME1} {RBX_NAME2}. Vuoi acquistare altri ROBUX?,{RBX_NAME1} {RBX_NAME2}.を買うにはあと{RBX_NUMBER}のROBUXが必要です。もっとROBUXを買いますか?,{RBX_NAME1} {RBX_NAME2}을(를) 구매하려면 {RBX_NUMBER}개의 ROBUX가 더 필요해요. ROBUX를 더 구매할까요?,Você precisa de mais {RBX_NUMBER} ROBUX para comprar o(a) {RBX_NAME2} {RBX_NAME1}. Gostaria de comprar mais ROBUX?,Você precisa de mais {RBX_NUMBER} ROBUX para comprar o(a) {RBX_NAME2} {RBX_NAME1}. Gostaria de comprar mais ROBUX?,Для покупки товара {RBX_NAME1} {RBX_NAME2} требуется еще {RBX_NUMBER} ROBUX. Приобрести больше ROBUX?,你还需要 {RBX_NUMBER} ROBUX 才能购买 {RBX_NAME1} {RBX_NAME2}。你想要购买更多 ROBUX 吗?,您需要再多 {RBX_NUMBER} ROBUX 才能購買{RBX_NAME1} {RBX_NAME2}。您是否要加購 ROBUX? +PurchasePromptScript.setPurchaseDataInGui.invalidBC,,,,"Dieser Gegenstand erfordert {RBX_NAME1}. Klicke auf „Aufwerten“, um deinen Builders-Club-Status zu verbessern!",This item requires {RBX_NAME1}. Click 'Upgrade' to upgrade your Builders Club!,"Este objeto requiere {RBX_NAME1}. Dale a ""Mejorar"" para mejorar el Builders Club.","Este objeto requiere {RBX_NAME1}. Dale a ""Mejorar"" para mejorar el Builders Club.",Cet objet nécessite {RBX_NAME1}. Cliquez sur « Améliorer » pour améliorer votre Builders Club !,"Questo oggetto richiede: {RBX_NAME1}. Clicca su ""Migliora"" per potenziare il tuo Builders Club!",このアイテムには{RBX_NAME1}が必要です。「アップグレード」をクリックしてビルダーズクラブをアップグレード!,이 아이템에는 {RBX_NAME1}이(가) 필요해요. '업그레이드'를 클릭해 빌더스 클럽을 업그레이드하세요!,Este item requer {RBX_NAME1}. Clique em 'Melhorar' para melhorar seu Builders Club!,Este item requer {RBX_NAME1}. Clique em 'Melhorar' para melhorar seu Builders Club!,"Для этого предмета требуется: {RBX_NAME1}. Нажмите кнопку «Улучшение», чтобы улучшить клуб создателей!",此物品需要 {RBX_NAME1}。点按“升级”以升级你的 Builders Club !,此項目需要{RBX_NAME1}。按一下「升級」以升級您的建置者社團! +Received,,,,Empfangen,Received,Recibido,Recibido,Reçus,Ricevuti,受信済み,받음,Recebido,Recebido,Принято,已收到,收到 +Sent,,,,Gesendet,Sent,Enviado,Enviado,Envoyés,Inviati,送付済み,보냄,Enviado,Enviado,Отправлено,已发送,送出 +StatsUtil.KBps,,,,{RBX_NUMBER} KB/s,{RBX_NUMBER} KB/s,{RBX_NUMBER} KB/s,{RBX_NUMBER} KB/s,{RBX_NUMBER} Ko/s,{RBX_NUMBER} KB/s,{RBX_NUMBER} KB/s,{RBX_NUMBER} KB/s,{RBX_NUMBER} kB/s,{RBX_NUMBER} kB/s,{RBX_NUMBER} КБ/с,{RBX_NUMBER} KB/s,{RBX_NUMBER} KB/s +StatsUtil.MB,,,,{RBX_NUMBER} MB,{RBX_NUMBER} MB,{RBX_NUMBER} MB,{RBX_NUMBER} MB,{RBX_NUMBER} Mo,{RBX_NUMBER} MB,{RBX_NUMBER} MB,{RBX_NUMBER} MB,{RBX_NUMBER} MB,{RBX_NUMBER} MB,{RBX_NUMBER} МБ,{RBX_NUMBER} MB,{RBX_NUMBER} MB +StatsUtil.ms,,,,{RBX_NUMBER} ms,{RBX_NUMBER} ms,{RBX_NUMBER} ms,{RBX_NUMBER} ms,{RBX_NUMBER} ms,{RBX_NUMBER} ms,{RBX_NUMBER} ms,{RBX_NUMBER} ms,{RBX_NUMBER} ms,{RBX_NUMBER} ms,{RBX_NUMBER} мс,{RBX_NUMBER} ms,{RBX_NUMBER} ms +Target,,,,Ziel,Target,Objetivo,Objetivo,Cible,Scopo,目標,대상,Alvo,Alvo,Цель,目标,目標 +EnableVoiceKey,,,,Sprachchat aktivieren,Enable Voice Chat,Activar chat de voz,Activar chat de voz,Activer le chat vocal,Attiva chat vocale,ボイスチャットを有効にする,음성 채팅 활성화,Ativar conversa por chat,Ativar conversa por chat,Включить голосовой чат,启用语音聊天,啟用語音聊天 +DisableVoiceKey,,,,Sprachchat deaktivieren,Disable Voice Chat,Desactivar chat de voz,Desactivar chat de voz,Désactiver le chat vocal,Disattiva chat vocale,ボイスチャットを無効にする,음성 채팅 비활성화,Desativar conversa por chat,Desativar conversa por chat,Отключить голосовой чат,停用语音聊天,停用語音聊天 +,,,Account: Under 13 yrs,Konto: Unter 13 J.,,Cuenta: Menor de 13 años,Cuenta: Menor de 13 años,Compte : Moins de 13 ans,Account: meno di 13 anni,アカウント:13才以下,계정: 만 13세 미만,Conta: Menor de 13 anos,Conta: Menor de 13 anos,Учетная запись: Не старше 13 лет,帐户:13 岁以下,帳戶:未滿 13 歲 +,,,Right Mouse Button,Rechte Maustaste,,Botón derecho del ratón,Botón derecho del ratón,Bouton droit de la souris,Destro/Mouse,右マウスボタン,마우스 오른쪽 버튼,Mouse (direito),Mouse (direito),ПКМ,鼠标右键,右滑鼠鍵 +,,,Roblox Menu,Roblox-Menü,,Menú de Roblox,Menú de Roblox,Menu Roblox,Menu Roblox,Roblox メニュー,Roblox 메뉴,Menu Roblox,Menu Roblox,Меню Roblox,Roblox 菜单,Roblox 選單 +,,,Rotate,Drehen,,Rotar,Rotar,Tourner,Ruota,回転,회전,Girar,Girar,Вращение,旋转,旋轉 +,,,S/Down Arrow,S/Abwärtspfeil,,S/Cursor abajo,S/Cursor abajo,S/Flèche bas,S/Freccia GIÙ,S/下カーソル,S/아래쪽 화살표,S/seta para baixo,S/seta para baixo,S/стрелка вниз,S/下箭头,S 鍵 / 向下箭號 +,,,Save To Disk,Auf Festplatte speichern,,Guardar en disco,Guardar en disco,Sauvegarder sur le disque,Salva su disco,ディスクに保存,디스크에 저장,Salvar em disco,Salvar em disco,Сохранить на диск,保存至磁盘,儲存至磁碟 +,,,Scamming,Scamming,,Estafa,Estafa,Arnaque,Truffa,詐欺,신용 사기,Fraude,Fraude,Мошенничество,诈骗,詐騙 +,,,Screenshot,Screenshot,,Captura de pantalla,Captura de pantalla,Capture d'écran,Screenshot,スクリーンショット,스크린샷,Captura de tela,Captura de tela,Снимок экрана,屏幕截图,擷圖 +,,,Sent,Gesendet,,Enviado,Enviado,Envoyés,Inviato,送付済み,보냄,Enviado,Enviado,Отправленные,已发送,送出 +,,,Set by Developer,Vom Entwickler festgelegt,,Configurado por el desarrollador,Configurado por el desarrollador,Défini par développeur,Impostato da sviluppatore,開発者による設定,개발자 설정,Definido por desenvolvedor,Definido pelo desenvolvedor,Установлено разработчиком,由开发人员设置,開發人員所設定 +,,,Settings,Einstellungen,,Configuración,Configuración,Paramètres,Impostazioni,設定,설정,Configurações,Config.,Настройки,设置,設定 +,,,Are you sure you want to leave the game?,Möchtest du das Spiel wirklich verlassen?,,¿Seguro que deseas salir del juego?,¿Seguro que deseas salir del juego?,Voulez-vous vraiment quitter le jeu ?,Vuoi davvero uscire dal gioco?,ゲームをやめますか?,정말로 게임을 나갈까요?,Quer mesmo sair do jogo?,Quer mesmo sair do jogo?,Выйти из игры?,是否确定要离开游戏?,您確定要離開遊戲? +,,,Shift,Umschalttaste,,Mayúsculas,Mayúsculas,Maj,MAIUSC,シフト,Shift,Shift,Shift,Shift,Shift,Shift 鍵 +,,,Shift Lock Switch,Shift-Lock-Schalter,,Bloqueo de mayúsculas,Bloqueo de mayúsculas,Touche Verr. Vue,BLOC MAIUSC,シフトロックスイッチ,Shift Lock 전환,Trava do shift,Trava do shift,Переключение клавишей Shift,Shift Lock 开关,Shift Lock 開關 +,,,Space,Leertaste,,Espacio,Espacio,Espace,BARRA SPAZIATRICE,スペース,스페이스,Espaço,Espaço,Пробел,空格,空格鍵 +,,,Speed,Tempo,,Velocidad,Velocidad,Vitesse,Velocità,速さ,속도,Velocidade,Velocidade,Скорость,速度,速度 +,,,Submit,Senden,,Enviar,Enviar,Soumettre,Invia,送信,제출,Enviar,Enviar,Отправить,提交,提交 +,,,Swearing,Fluchen,,Palabras malsonantes,Palabras malsonantes,Insultes,Turpiloquio,ののしり,욕설,Palavrões,Palavrões,Ненормативная лексика,脏话谩骂,髒話謾罵 +,,,TAB,Tabulator,,TAB,TAB,TAB,TAB,TAB,TAB,TAB,TAB,TAB,TAB,TAB 鍵 +,,,Take Free,Gratis nehmen,,Obtener gratis,Obtener gratis,Prendre gratuitement,Prendi gratis,無料配布,무료 획득,Obter grátis,Obter grátis,Получить бесплатно,免费获取,免費收取 +,,,Take Screenshot,Screenshot machen,,Hacer captura de pantalla,Hacer captura de pantalla,Capture d'écran,Cattura screenshot,スクリーンショットを撮る,스크린샷 캡쳐,Captura de tela,Captura de tela,Сделать снимок экрана,截取屏幕快照,擷圖 +,,,This is a popup,Dies ist ein Pop-up.,,Esta es una ventana emergente.,Esta es una ventana emergente.,Ceci est une fenêtre popup,Questo è un popup,これはポップアップです,팝업 메뉴입니다,Este é um popup,Este é um popup,Всплывающее сообщение,这是弹出式窗口,這是一個快顯視窗 +,,,Are you sure you want to reset your character?,Möchtest du deinen Charakter wirklich zurücksetzen?,,¿Seguro que deseas reiniciar tu personaje?,¿Seguro que deseas reiniciar tu personaje?,Voulez-vous vraiment réinitialiser le personnage ?,Vuoi davvero azzerare il tuo personaggio?,キャラクターをリセットしてよろしいですか?,정말로 캐릭터를 재설정할까요?,Quer mesmo reiniciar o personagem?,Quer mesmo reiniciar o personagem?,Сбросить персонажа?,是否确定要重置人物?,您確定要重設您的人物? +,,,Type Of Abuse,Art des Verstoßes,,Tipo de abuso,Tipo de abuso,Type d'abus,Tipo di abuso,不正の種類,오용 유형,Tipo de abuso,Tipo de abuso,Тип нарушения,滥用类型,濫行類型 +,,,Unequip Tools,Werkzeuge deaktivieren,,Desequipar herramientas,Desequipar herramientas,Outils non équipés,Rimuovi strum.,ツールを外す,도구 장착 해제,Desequipar,Desequipar,Убрать инструм.,取消配备工具,取消配備工具 +,,,Upgrade,Aufwerten,,Mejorar,Mejorar,Améliorer,Migliora,アップグレード,업그레이드,Melhorar,Melhorar,Улучшение,升级,升級 +,,,Upload to YouTube,Auf YouTube hochladen,,Cargar a YouTube,Cargar a YouTube,Télécharger sur YouTube,Carica su YouTube,YouTubeにアップロード,YouTube에 업로드,Upload para o YouTube,Envio para o YouTube,Загрузить на YouTube,上传至 Youtube,上傳至 YouTube +,,,Use Tool,Werkzeug verwenden,,Utilizar herramienta,Utilizar herramienta,Utiliser outil,Usa strumento,ツールを使用,도구 사용,Usar,Usar,Использовать инструмент,使用工具,使用工具 +,,,Video,Video,,Vídeo,Vídeo,Vidéo,Video,ビデオ,비디오,Vídeo,Vídeo,Видео,视频,影片 +,,,Video Settings,Video-Einstellungen,,Configuración de vídeo,Configuración de vídeo,Paramètres vidéo,Impostazioni video,ビデオ設定,비디오 설정,Configurações de vídeo,Configurações de vídeo,Настройки видео,视频设置,影片設定 +,,,Volume,Lautstärke,,Volumen,Volumen,Volume,Volume,ボリューム,볼륨,Volume,Volume,Громкость,音量,音量 +,,,W/Up Arrow,W/Aufwärtspfeil,,W/Cursor arriba,W/Cursor arriba,W/Flèche haut,W/Freccia SU,W/上カーソル,W/위쪽 화살표,W/seta para cima,W/seta para cima,W/стрелка вверх,W/上箭头,W 鍵 / 向上箭號 +,,,Which Player?,Welcher Spieler?,,¿A qué jugador?,¿A qué jugador?,Quel joueur ?,Quale giocatore?,どのプレーヤーですか?,플레이어 선택,Qual jogador?,Qual jogador?,Какой игрок?,哪位玩家?,哪位玩家? +,,,Automatic,Automatisch,,Automático,Automático,Automatique,Automatico,自動,자동,Automático,Automático,Автоматически,自动,自動 +,,,Wipeouts,Auslöschungen,,Destrucciones,Destrucciones,Éliminations,Annientamenti,死亡回数,사망,Aniquilações,Aniquilações,Уничтожения,死亡数,殲滅數 +,,,Zoom In,Einzoomen,,Acercar,Acercar,Zoom avant,Ingrandisci,ズームイン,확대,Aproximar zoom,Aproximar zoom,Приблизить,放大,放大 +,,,Zoom In/Out,Ein-/Auszoomen,,Acercar/alejar,Acercar/alejar,Zoom avant/arrière,Aumenta/Riduci,ズームイン/ズームアウト,확대/축소,Aprox./afastar,Aprox./afastar,Приблизить/отдалить,放大/缩小,放大/縮小 +,,,Zoom Out,Auszoomen,,Alejar,Alejar,Zoom arrière,Riduci,ズームアウト,축소,Afastar zoom,Afastar zoom,Отдалить,缩小,縮小 +,,,update me,aktualisiere mich,,actualízame,actualízame,tenez-moi au courant,aggiornami,自分をアップデート,업데이트 요청,atualize-me,atualize-me,обновите меня,向我发送更新信息,給我新消息 +,,,Add Friend,Freund hinzufügen,,Añadir amigo,Añadir amigo,Ajouter ami,Aggiungi amico,友達を追加,친구 추가,Adicionar amigo,Adicionar amigo,Добавить друга,添加好友,新增朋友 +,,,"Server found, loading...","Server gefunden, wird geladen ...",,Servidor encontrado. Cargando...,Servidor encontrado. Cargando...,"Serveur trouvé, chargement en cours...","Server trovato, caricamento...",サーバが見つかりました、ロード中です...,"서버 발견, 로드 중...","Servidor encontrado, carregando...","Servidor encontrado, carregando...",Сервер найден. Загрузка...,找到服务器,正在加载...,找到伺服器,載入中… +,,,Badge Awarded,Abzeichen verliehen,,Emblema concedido,Emblema concedido,Badge accordé,Contrassegno conferito,授与されたバッジ,배지 획득,Emblema concedido,Emblema concedido,Получен значок,已获得徽章,已獲徽章 +,,,Block Player,Spieler sperren,,Bloquear jugador,Bloquear jugador,Bloquer joueur,Blocca giocatore,プレーヤーをブロック,플레이어 차단,Bloquear jogador,Bloquear jogador,Заблокировать игрока,取消屏蔽玩家,封鎖玩家 +,,,Follow Player,Spieler folgen,,Seguir a jugador,Seguir a jugador,Suivre joueur,Segui giocatore,プレーヤーをフォロー,플레이어 팔로우,Seguir jogador,Seguir jogador,Подписаться на игрока,关注玩家,關注玩家 +,,,Backpack,Rucksack,,Mochila,Mochila,Sac à dos,Zaino,バックパック,배낭,Mochila,Mochila,Рюкзак,背包,背包 +,,,Friend,Freund,,Amigo,Amigo,Ami,Amico,友達,친구,Amigo,Amigo,Друг,好友,朋友 +,,,New Friend,Neuer Freund,,Amigo nuevo,Amigo nuevo,Nouvel ami,Nuovo amico,新しい友達,새 친구,Novo amigo,Novo amigo,Новый друг,新好友,新朋友 +,,,Point Awarded,Punkt verliehen,,Punto concedido,Punto concedido,Point accordé,Punto attribuito,ポイント授与,획득한 포인트,Ponto concedido,Ponto concedido,Получено очко,已获得点数,已獲點數 +,,,Points Awarded,Punkte verliehen,,Puntos concedidos,Puntos concedidos,Points accordés,Punti attribuiti,ポイント授与,획득한 포인트,Pontos concedidos,Pontos concedidos,Получены очки,已获得点数,已獲點數 +,,,"{RBX_NAME} won {RBX_NAME}'s ""{RBX_NAME}"" award!",{RBX_NAME} wurde von {RBX_NAME} die Auszeichnung „{RBX_NAME}“ verliehen!,,"¡{RBX_NAME} ha ganado el galardón ""{RBX_NAME}"" de {RBX_NAME}!","¡{RBX_NAME} ha ganado el galardón ""{RBX_NAME}"" de {RBX_NAME}!",{RBX_NAME} a gagné la récompense « {RBX_NAME} » de {RBX_NAME} !,"{RBX_NAME} ha vinto il premio ""{RBX_NAME}"" di {RBX_NAME}!","{RBX_NAME} {RBX_NAME}'の ""{RBX_NAME}"" を受賞!","{RBX_NAME}이(가) {RBX_NAME}의 ""{RBX_NAME}"" 상을 획득했어요!","{RBX_NAME} ganhou o prêmio ""{RBX_NAME}“ de {RBX_NAME}!","{RBX_NAME} ganhou o prêmio ""{RBX_NAME}“ de {RBX_NAME}!",{RBX_NAME} получает награду {RBX_NAME} «{RBX_NAME}»!,{RBX_NAME}赢得了{RBX_NAME}的“{RBX_NAME}”奖!,{RBX_NAME}贏得{RBX_NAME}的「{RBX_NAME}」獎! +,,,Report Abuse,Verstoß melden,,Denunciar abuso,Denunciar abuso,Signaler infraction,Segnala abuso,不正を報告,신고하기,Denunciar abuso,Denunciar abuso,Сообщить о нарушении,举报滥用,提報濫行 +,,,Request Sent,Anfrage gesendet,,Solicitud enviada,Solicitud enviada,Demande envoyée,Richiesta inviata,送信リクエスト,요청 보냄,Pedido enviado,Pedido enviado,Запрос отправлен,请求已发送,請求已送出 +,,,Send Friend Request,Freundesanfrage senden,,Enviar solicitud de amistad,Enviar solicitud de amistad,Envoyer demande d'ami,Invia richiesta di amicizia,友達リクエストを送信,친구 요청 전송,Enviar pedido de amizade,Enviar pedido de amizade,Отправить запрос дружбы,发送好友请求,傳送交友請求 +,,,Backspace,Rücktaste,,Retroceso,Retroceso,Retour,BACKSPACE,バックスペース,백스페이스,Backspace,Backspace,Backspace,回退,退格鍵 +,,,Sent you a friend request!,hat dir eine Freundesanfrage gesendet!,,te ha enviado una solicitud de amistad!,te ha enviado una solicitud de amistad!,vous a envoyé une demande d'ami !,ti ha inviato una richiesta di amicizia!,君に友達リクエストを送ったよ!,친구 요청을 보냈어요!,enviou um pedido de amizade para você!,enviou um pedido de amizade para você!,отправил вам запрос дружбы!,已向你发送好友请求!,已寄給您交友請求! +,,,Unblock Player,Spieler nicht mehr sperren,,Desbloquear jugador,Desbloquear jugador,Débloquer joueur,Sblocca giocatore,プレーヤーのブロックを解除,플레이어 차단 해제,Desbloq. jogador,Desbloq. jogador,Разблокировать игрока,取消屏蔽玩家,解除封鎖玩家 +,,,Unfollow Player,Spieler nicht mehr folgen,,Dejar de seguir a jugador,Dejar de seguir a jugador,Ne plus suivre joueur,Non seguire giocatore,プレーヤーをフォローしない,플레이어 팔로우 취소,Parar de seguir jogador,Parar de seguir jogador,Отписаться от игрока,取消关注玩家,取消關注玩家 +,,,Unfriend Player,Spieler als Freund entfernen,,Cancelar amistad con jugador,Cancelar amistad con jugador,Ne plus être ami du joueur,Togli amicizia a giocatore,プレーヤーを友達解除,플레이어 친구 끊기,Cancelar amizade,Cancelar amizade,Удалить из друзей,与玩家解除好友关系,與玩家解除朋友關係 +,,,You are,Du,,Estás,Estás,Vous,Sei,あなたは,현재,Você está,Você está,Вы,你是,您 +,,,Your balance after this transaction will be R${RBX_NUMBER},Nach dieser Transaktion wird dein Guthaben {RBX_NUMBER} R$ betragen.,,Tu saldo después de esta transacción será de {RBX_NUMBER} R$.,Tu saldo después de esta transacción será de {RBX_NUMBER} R$.,Votre solde après cette transaction sera de {RBX_NUMBER} R$,"Dopo la transazione, avrai R${RBX_NUMBER}",この取引の後の残高は R${RBX_NUMBER}です,이 거래 후의 예상 잔액은 R${RBX_NUMBER}이에요.,Seu saldo depois desta transação será de R$ {RBX_NUMBER},Seu saldo depois desta transação será de R$ {RBX_NUMBER},После этой операции ваш баланс составит R${RBX_NUMBER},此次交易后,你的余额将为 R${RBX_NUMBER}。,您此交易後的餘額將為 R${RBX_NUMBER}。 +,,,Bullying,Mobbing,,Abusos,Abusos,Harcèlement,Bullismo,いじめ,괴롭힘,Bullying,Bullying,Агрессивное поведение,欺凌,霸凌 +,,,Abuse Description,Beschreibung des Verstoßes,,Descripción del abuso,Descripción del abuso,Description de l'infraction,Descrizione abuso,不正の詳細,오용 설명,Descrição do abuso,Descrição do abuso,Описание нарушения,滥用描述,濫行描述 +,,,Buy,Kaufen,,Comprar,Comprar,Acheter,Compra,購入,구매,Comprar,Comprar,Купить,买,買 +,,,Button,Schaltfläche,,Botón,Botón,Bouton,Pulsante,ボタン,버튼,Botão,Botão,Кнопка,按钮,按鈕 +,,,DPad,Steuerkreuz,,Cruceta,Cruceta,Croix directionnelle,Croce direzionale,DPad,DPad,Direcional,Direcional,Крестовина,DPad,十字鍵 +,,,Default (Follow),Standard (Folgen),,Predeterminado (seguir),Predeterminado (seguir),Par défaut (Suivre),Predefinita (Segui),デフォルト (フォロー),기본값 (팔로우),Padrão (seguir),Padrão (seguir),По умолчанию (слежение),默认(追随),預設 (追蹤鏡頭) +,,,Default (Thumbstick),Standard (Daumenstick),,Predeterminado (stick),Predeterminado (stick),Par défaut (Joystick),Predefinita (Levetta),デフォルト (サムスティック),기본값 (엄지스틱),Padrão (thumbstick),Padrão (thumbstick),По умолчанию (аналоговый стик),默认(摇杆),預設 (模擬搖桿) +,,,Equip/Unequip Tools,Werkzeuge aktivieren/deaktivieren,,Equipar/desequipar herramientas,Equipar/desequipar herramientas,Prendre/Lâcher outils,Equipaggia/Rimuovi,ツールを装備/外す,도구 장착/해제,Trocar ferramentas,Trocar ferramentas,Назначить/убрать инструменты,配备/取消配备工具,配備/取消配備 工具 +,,,Move,Bewegen,,Movimiento,Movimiento,Se déplacer,Muovi,移動,이동,Mover,Mover,Передвижение,移动,移動 +,,,Reset Character,Charakter zurücksetzen,,Reiniciar personaje,Reiniciar personaje,Réinitialiser le personnage,Azzera personaggio,キャラクターをリセット,캐릭터 재설정,Reiniciar,Reiniciar,Сброс персонажа,重置人物,旋轉攝影機 +,,,Rotate Camera,Kamera drehen,,Rotar cámara,Rotar cámara,Rotation de caméra,Ruota visuale,カメラを回転,카메라 회전,Girar câmera,Girar câmera,Вращение камеры,旋转镜头,旋轉相機 +,,,Tap to Move,Zum Bewegen tippen,,Tocar para mover,Tocar para mover,Toucher pour se déplacer,Tocca per muovere,タップして移動,눌러서 이동,Toque para mover,Toque para mover,Коснитесь для передвижения,轻点以移动,觸屏移動 +,,,Thumbpad,Daumenpad,,Cruceta,Cruceta,Pavé directionnel,Croce direzionale,サムパッド,엄지패드,Thumbpad,Thumbpad,Кнопочная панель,拇指垫,拇指鍵盤 +,,,Thumbstick,Daumenstick,,Stick,Stick,Joystick,Levetta,サムスティック,엄지스틱,Thumbstick,Thumbstick,Аналоговый стик,摇杆,模擬搖桿 +,,,Buy Now,Jetzt kaufen,,Comprar ahora,Comprar ahora,Acheter maintenant,Compra ora,すぐ買う,지금 구매,Comprar agora,Comprar agora,Купить,立即购买,立即購買 +,,,These are the basic chat commands.,Das sind die grundlegenden Chatbefehle.,,Estos son los comandos básicos del chat.,Estos son los comandos básicos del chat.,Voici les commandes de chat basiques.,Questi sono i comandi base della chat.,これらは基本的なチャットコマンドです。,기본 채팅 명령어에요.,Esses são os comandos de chat básicos.,Esses são os comandos de chat básicos.,Это основные команды чата.,这些是基本聊天指令。,這些是基本聊天指令。 +,,,/join or /j : join channel.,/join oder /j : Kanal beitreten,,/join o /j : unirse al canal.,/join o /j : unirse al canal.,/join ou /j  : rejoindre le canal.,/join o /j : accedi al canale.,/join または /j : で、チャンネルに参加。,/join <채널> 또는 /j <채널> : 채널 가입.,/join ou /j : juntar-se a um canal.,/join ou /j : juntar-se a um canal.,/join <канал> или /j <канал> : подключиться к каналу.,/join or /j : 加入频道。,/join or /j : 加入頻道。 +,,,/leave or /l : leave channel. (leaves current if none specified),/leave oder /l : Kanal verlassen. (Ohne Angabe des Kanals wird der aktuelle Kanal verlassen.),,/leave o /l : salir del canal (sale del canal actual si no se especifica ninguno).,/leave o /l : salir del canal (sale del canal actual si no se especifica ninguno).,/leave ou /l  : quitter canal. (reste sur le même si aucun n'est spécifié),/leave o /l : lascia il canale (quello attuale se non specificato).,/leave または /l : でチャンネルから退出。 (指定しなければ現在のチャネルから退出します),/leave <채널> 또는 /l <채널> : 채널 나가기. (미지정 시 현재 채널에서 나가기),/leave ou /l : sair do canal. (sai do atual se não especificado),/leave ou /l : sair do canal. (sai do atual se não especificado),"/leave <канал> или /l <канал> : покинуть канал. (Вы покинете текущий канал, если не укажете другой.)",/leave 或 /l : 离开频道。(若未指定,离开当前频道),/leave 或 /l : 離開頻道。(若未指定,指離開目前頻道) +,,,Buy R$,R$ kaufen,,Comprar R$,Comprar R$,Acheter des R$,Compra R$,R$ を買う,R$ 구매,Comprar R$,Comprar R$,Купить R$,购买 R$,買 R$ +,,,You must wait {RBX_NUMBER} second before sending another message!,"Du musst {RBX_NUMBER} Sekunde lang warten, bevor du eine weitere Nachricht senden kannst!",,¡Debes esperar {RBX_NUMBER} segundo antes de enviar otro mensaje!,¡Debes esperar {RBX_NUMBER} segundo antes de enviar otro mensaje!,Vous devez attendre {RBX_NUMBER} seconde avant d'envoyer un autre message !,Devi aspettare {RBX_NUMBER} secondo prima di inviare un altro messaggio!,{RBX_NUMBER} 秒待ってから次のメッセージを送ってください!,추가 메시지를 보내기 전에 {RBX_NUMBER}초 동안 기다려야 해요!,Você precisa esperar {RBX_NUMBER} segundo antes de enviar outra mensagem!,Você precisa esperar {RBX_NUMBER} segundo antes de enviar outra mensagem!,Вы сможете отправить новое сообщение только через {RBX_NUMBER} сек.!,发送另一条消息前你必须等待 {RBX_NUMBER} 秒!,傳送另一則訊息之前您必須等候 {RBX_NUMBER} 秒! +,,,Reset Character,Charakter zurücksetzen,,Reiniciar personaje,Reiniciar personaje,Réinitialiser le personnage,Azzera personaggio,キャラクターをリセット,캐릭터 재설정,Reiniciar,Reiniciar,Сброс персонажа,重置人物,旋轉攝影機 +,,,"By clicking the 'Record Video' button, the menu will close and start recording your screen.","Wenn du auf die Schaltfläche „Video aufnehmen“ klickst, schließt sich das Menü und dein Bildschirm wird aufgezeichnet.",,"Al hacer clic en el botón ""Grabar vídeo"", el menú se cerrará y se empezará a grabar tu pantalla.","Al hacer clic en el botón ""Grabar vídeo"", el menú se cerrará y se empezará a grabar tu pantalla.","En cliquant sur le bouton Enregistrer vidéo, le menu se fermera et l'enregistrement de votre écran débutera.","Clicca sul pulsante ""Registra video"" per chiudere il menu e iniziare a registrare quanto avviene sullo schermo.",「ビデオの録画」ボタンをクリックするとメニューが閉じて画面の録画が始まります。,‘비디오 녹화’ 버튼을 클릭하면 메뉴가 종료되고 화면 녹화가 시작돼요.,"Ao clicar no botão ‘Gravar vídeo’, o menu será fechado e a tela começará a ser gravada.","Ao clicar no botão ‘Gravar vídeo’, o menu será fechado e a tela começará a ser gravada.",После нажатия на кнопку «Запись видео» это меню закроется и начнется запись видео с экрана.,点按“录制视频”按钮,目录会关闭,并开始录制你的屏幕。,按一下「錄製影片」按鈕,選單會關閉並開始錄下您的畫面。 +,,,To {RBX_NAME},An {RBX_NAME},,Para {RBX_NAME},Para {RBX_NAME},À {RBX_NAME},A {RBX_NAME},To {RBX_NAME},수신: {RBX_NAME},Para {RBX_NAME},Para {RBX_NAME},Получатель: {RBX_NAME},至“{RBX_NAME}”,至{RBX_NAME} +,,,From {RBX_NAME},Von {RBX_NAME},,De {RBX_NAME},De {RBX_NAME},De {RBX_NAME},Da {RBX_NAME},From {RBX_NAME},발신: {RBX_NAME},De {RBX_NAME},De {RBX_NAME},Отправитель: {RBX_NAME},自“{RBX_NAME}”,自{RBX_NAME} +,,,You were kicked from '{RBX_NAME}' for the following reason(s): {RBX_NAME},Du wurdest aus folgenden Gründen aus „{RBX_NAME}“ entfernt: {RBX_NAME},,"Se te ha expulsado de ""{RBX_NAME}"" por el/los motivo/s siguiente/s: {RBX_NAME}","Se te ha expulsado de ""{RBX_NAME}"" por el/los motivo/s siguiente/s: {RBX_NAME}",Vous avez été expulsé de {RBX_NAME} pour la/les raison(s) suivante(s) : {RBX_NAME},"Sei stato rimosso da ""{RBX_NAME}"" per le seguenti motivazioni: {RBX_NAME}",あなたは '{RBX_NAME}' から次の理由により外されました: {RBX_NAME},{RBX_NAME}'에서 퇴장당했어요. 퇴장 이유: {RBX_NAME},Você foi expulso(a) de '{RBX_NAME}‘. Motivo(s): {RBX_NAME},Você foi expulso(a) de '{RBX_NAME}‘. Motivo(s): {RBX_NAME},Вы исключены из «{RBX_NAME}» по следующим причинам: {RBX_NAME},“{RBX_NAME}”已将你踢出,原因为:{RBX_NAME},您自「{RBX_NAME}」遭踢出,原因如下:{RBX_NAME} +,,,{RBX_NAME} was kicked for the following reason(s): {RBX_NAME},{RBX_NAME} wurde aus folgenden Gründen entfernt: {RBX_NAME},,Se ha expulsado a {RBX_NAME} por el/los motivo/s siguiente/s: {RBX_NAME},Se ha expulsado a {RBX_NAME} por el/los motivo/s siguiente/s: {RBX_NAME},{RBX_NAME} a été expulsé pour la/les raison(s) suivante(s) : {RBX_NAME},{RBX_NAME} è stato rimosso per le seguenti motivazioni: {RBX_NAME},{RBX_NAME} は次の理由により外されました: {RBX_NAME},{RBX_NAME}님이 퇴장당했어요. 퇴장 이유: {RBX_NAME},{RBX_NAME} foi expulso(a). Motivo(s): {RBX_NAME},{RBX_NAME} foi expulso(a). Motivo(s): {RBX_NAME},Пользователь {RBX_NAME} исключен по следующим причинам: {RBX_NAME},已将“{RBX_NAME}”踢出,原因为:{RBX_NAME},{RBX_NAME}遭踢出的理由如下:{RBX_NAME} +,,,You were kicked from '{RBX_NAME}',Du wurdest aus „{RBX_NAME}“ entfernt.,,"Se te ha expulsado de ""{RBX_NAME}"".","Se te ha expulsado de ""{RBX_NAME}"".",Vous avez été expulsé de {RBX_NAME},"Sei stato rimosso da ""{RBX_NAME}""",あなたは '{RBX_NAME}' から外されました。,{RBX_NAME}'에서 퇴장당했어요.,Você foi expulso(a) de '{RBX_NAME}',Você foi expulso(a) de '{RBX_NAME}',Вы исключены из «{RBX_NAME}».,“{RBX_NAME}”已将你踢出,您自「{RBX_NAME}」遭踢出 +,,,"By clicking the 'Take Screenshot' button, the menu will close and take a screenshot and save it to your computer.","Wenn du auf die Schaltfläche „Screenshot machen“ klickst, schließt sich das Menü und ein Screenshot wird auf deinem Computer gespeichert.",,"Al hacer clic en el botón ""Hacer captura de pantalla"", el menú se cerrará y se hará una captura de pantalla que se guardará en tu ordenador.","Al hacer clic en el botón ""Hacer captura de pantalla"", el menú se cerrará y se hará una captura de pantalla que se guardará en tu ordenador.","En cliquant sur le bouton Capture d'écran, le menu se fermera et une capture d'écran sera sauvegardée dans votre ordinateur.","Clicca sul pulsante ""Cattura screenshot"" per chiudere il menu, catturare uno screenshot e salvarlo sul computer.",「スクリーンショットを撮る」ボタンをクリックするとメニューが閉じてスクリーンショットがコンピュータに保存されます。,스크린샷 캡쳐' 버튼을 클릭하면 메뉴가 종료되고 스크린샷을 캡쳐해 컴퓨터에 저장해요.,"Ao clicar no botão ‘Captura de tela’, o menu será fechado e a tela será capturada e salva no seu computador.","Ao clicar no botão ‘Captura de tela’, o menu será fechado e a tela será capturada e salva no seu computador.",После нажатия на кнопку «Сделать снимок экрана» это меню закроется и снимок сохранится на вашем компьютере.,点按“截取屏幕快照”按钮,目录会关闭,截取屏幕快照并保存至你的电脑。,按一下「擷圖」按鈕,選單就會關閉並擷一張圖以儲存至您的電腦。 +,,,{RBX_NAME} was kicked,{RBX_NAME} wurde entfernt,,Se ha expulsado a {RBX_NAME}.,Se ha expulsado a {RBX_NAME}.,{RBX_NAME} a été expulsé,{RBX_NAME} è stato rimosso,{RBX_NAME} は外されました。,{RBX_NAME}님이 퇴장당했어요.,{RBX_NAME} foi expulso(a),{RBX_NAME} foi expulso(a),Пользователь {RBX_NAME} исключен,“{RBX_NAME}”被踢出,{RBX_NAME}遭踢出 +,,,{RBX_NAME} was muted for the following reason(s): {RBX_NAME},{RBX_NAME} wurde aus folgenden Gründen stummgeschaltet: {RBX_NAME},,Se ha silenciado a {RBX_NAME} por el/los motivo/s siguiente/s: {RBX_NAME},Se ha silenciado a {RBX_NAME} por el/los motivo/s siguiente/s: {RBX_NAME},{RBX_NAME} a été bâillonné pour la/les raison(s) suivante(s) : {RBX_NAME},{RBX_NAME} non ha più la parola per le seguenti motivazioni: {RBX_NAME},{RBX_NAME} は次の理由によりミュートされました: {RBX_NAME},{RBX_NAME}님이 음소거 되었어요. 음소거 이유: {RBX_NAME},{RBX_NAME} foi silenciado(a). Motivo(s): {RBX_NAME},{RBX_NAME} foi silenciado(a). Motivo(s): {RBX_NAME},Пользователь {RBX_NAME} добавлен в список игнорируемых по следующим причинам: {RBX_NAME},“{RBX_NAME}”被禁言的原因为:{RBX_NAME},{RBX_NAME}遭靜音的理由如下:{RBX_NAME} +,,,You are now chatting in channel: '{RBX_NAME}',Du chattest jetzt in Kanal „{RBX_NAME}“.,,"Estás chateando en el canal ""{RBX_NAME}"".","Estás chateando en el canal ""{RBX_NAME}"".","Maintenant, vous discutez sur le canal : {RBX_NAME}","Ora stai parlando nel canale: ""{RBX_NAME}""",あなたの現在のチャットチャンネルは: '{RBX_NAME}' です。,{RBX_NAME}' 채널에서 채팅 중이에요,Você agora está no canal de chat: '{RBX_NAME}',Você agora está no canal de chat: '{RBX_NAME}',Вы общаетесь на канале «{RBX_NAME}»,你当前聊天的频道为:“{RBX_NAME}”,您此刻聊天的頻道在:「{RBX_NAME}」 +,,,You have left channel '{RBX_NAME}',Du hast Kanal „{RBX_NAME}“ verlassen.,,"Has salido del canal ""{RBX_NAME}"".","Has salido del canal ""{RBX_NAME}"".",Vous avez quitté le canal {RBX_NAME},"Hai lasciato il canale ""{RBX_NAME}""",チャンネル '{RBX_NAME}' を退出しました。,{RBX_NAME}' 채널에서 나왔어요,Você saiu do canal '{RBX_NAME}',Você saiu do canal '{RBX_NAME}',Вы покинули канал «{RBX_NAME}»,你已离开频道“{RBX_NAME}”,您已離開「{RBX_NAME}」頻道 +,,,CPU,CPU,,CPU,CPU,UCT,CPU,CPU,CPU,CPU,CPU,Процессор,CPU,中央處理器 +,,,ROBLOX version is out of date. Please uninstall and try again.,Die ROBLOX-Version ist nicht aktuell. Bitte deinstallieren und erneut versuchen.,,"Esta versión de ROBLOX es obsoleta. Por favor, desinstálala y vuelve a intentarlo.","Esta versión de ROBLOX es obsoleta. Por favor, desinstálala y vuelve a intentarlo.",Cette version de ROBLOX est obsolète. Veuillez désinstaller et réessayer.,Versione di ROBLOX obsoleta. Disinstalla e riprova.,古いバージョンのROBLOXです。アンインストールしてリトライしてください。,ROBLOX가 최신 버전이 아니에요. 삭제 후 다시 시도하세요.,Sua versão do ROBLOX não está atualizada. Desinstale e tente novamente.,Sua versão do ROBLOX não está atualizada. Desinstale e tente novamente.,Эта версия ROBLOX устарела. Удалите приложение и повторите попытку.,Roblox 版本已过期。请解除安装并重试。,ROBLOX 版本過時,請解除安裝後再試一次。 +,,,Connection attempt failed.,Verbindungsaufbau fehlgeschlagen.,,Ha fallado el intento de conexión.,Ha fallado el intento de conexión.,Échec de la tentative de connexion.,Tentativo di connessione non riuscito.,接続に失敗しました。,연결 시도 실패.,Tentativa de conexão fracassada.,Tentativa de conexão fracassada.,Не удалось подключиться.,尝试连接失败。,連線嘗試失敗。 +,,,Version not compatible with server. Please uninstall and try again.,Version nicht mit Server kompatibel. Bitte deinstallieren und erneut versuchen.,,"Esta versión no es compatible con el servidor. Por favor, desinstálala y vuelve a intentarlo.","Esta versión no es compatible con el servidor. Por favor, desinstálala y vuelve a intentarlo.",Version incompatible avec le serveur. Veuillez désinstaller et réessayer.,Versione non compatibile con il server. Disinstalla e riprova.,サーバと互換性のないバージョンです。アンインストールしてリトライしてください。,버전이 서버와 호환되지 않아요. 삭제 후 다시 시도하세요.,Versão incompatível com servidor. Desinstale e tente novamente.,Versão incompatível com servidor. Desinstale e tente novamente.,Версия приложения несовместима с сервером. Удалите приложение и повторите попытку.,版本与服务器不匹配。请解除安装并重试。,版本與伺服器不相容。請解除安裝後重試。 +,,,Network error {RBX_NUMBER},Netzwerkfehler {RBX_NUMBER},,Error de red {RBX_NUMBER},Error de red {RBX_NUMBER},Erreur réseau {RBX_NUMBER},Errore di rete {RBX_NUMBER},ネットワークエラー {RBX_NUMBER},네트워크 오류 {RBX_NUMBER},Erro de rede {RBX_NUMBER},Erro de rede {RBX_NUMBER},Ошибка сети {RBX_NUMBER},网络错误 {RBX_NUMBER},網路錯誤 {RBX_NUMBER} +,,,Camera Mode,Kameramodus,,Modo de cámara,Modo de cámara,Mode caméra,Modalità visuale,カメラのモード,카메라 모드,Modo da câmera,Modo da câmera,Режим камеры,镜头模式,攝影機模式 +,,,This game is not available. Please try another,Dieses Spiel ist nicht verfügbar. Bitte probiere ein anderes.,,Este juego no está disponible. Inténtalo con otro.,Este juego no está disponible. Inténtalo con otro.,Ce jeu n'est pas disponible. Veuillez en essayer un autre,Questo gioco non è disponibile. Provane un altro,このゲームは利用できません。他を試してください。,이용할 수 없는 게임이에요. 다른 게임을 시도하세요,Este jogo não está disponível. Tente outro,Este jogo não está disponível. Tente outro,Эта игра недоступна. Попробуйте другую,此游戏不可用。请试试另一个,此遊戲無法使用,請試另一個 +,,,Failed to connect to the Game. (ID = {RBX_NUMBER}: {RBX_NAME}),Verbindung zum Spiel fehlgeschlagen. (ID = {RBX_NUMBER}: {RBX_NAME}),,No se ha podido conectar con el juego. (ID = {RBX_NUMBER}: {RBX_NAME}),No se ha podido conectar con el juego. (ID = {RBX_NUMBER}: {RBX_NAME}),Échec de la connexion au jeu. (ID = {RBX_NUMBER} : {RBX_NAME}),Connessione al gioco non riuscita. (ID = {RBX_NUMBER}: {RBX_NAME}),ゲームに接続できませんでした。(ID = {RBX_NUMBER}: {RBX_NAME}),게임 연결에 실패했어요. (ID = {RBX_NUMBER}: {RBX_NAME}),Falha ao conectar no jogo. (ID = {RBX_NUMBER}: {RBX_NAME}),Falha ao conectar no jogo. (ID = {RBX_NUMBER}: {RBX_NAME}),Не удалось подключиться к игре. (ID = {RBX_NUMBER}: {RBX_NAME}),无法连接至游戏。(ID = {RBX_NUMBER}: {RBX_NAME}),無法連線到遊戲。(ID = {RBX_NUMBER}: {RBX_NAME}) +,,,This game has shut down,Dieses Spiel wurde abgebrochen.,,Este juego ha sido cerrado.,Este juego ha sido cerrado.,Ce jeu a dû fermer.,Questo gioco è stato chiuso,このゲームはシャットダウン中です。,게임이 종료되었습니다.,Este jogo foi encerrado,Este jogo foi encerrado,Эта игра больше не доступна,此游戏已关闭,此遊戲已關閉 +,,,You have lost the connection to the game,Die Verbindung zum Spiel wurde unterbrochen.,,Has perdido la conexión con el juego.,Has perdido la conexión con el juego.,Votre connexion au jeu a été perdue.,Sei stato disconnesso dal gioco,ゲームへの接続が失われました。,게임 연결이 끊겼어요,Você perdeu a conexão com o jogo,Você perdeu a conexão com o jogo,Прервано подключение к игре,你已中断与游戏的连接,您的遊戲連線被中斷 +,,,Notifications,Benachrichtigungen,,Notificaciones,Notificaciones,Notifications,Notifiche,お知らせ,알림,Notificações,Notificações,Уведомления,通知,通知 +,,,Remove From Hotbar,Schnellzugriff entfernen,,Eliminar de la barra de acceso rápido,Eliminar de la barra de acceso rápido,Retirer de la barre de raccourcis,Togli da barra scelta rap.,ホットバーから削除,핫바 창에서 제거,Remover da barra,Remover da barra,Удалить из панели быстрого доступа,从快捷栏删除,自快捷列移除 +,,,Select/Swap,Auswählen/Austauschen,,Seleccionar/alternar,Seleccionar/alternar,Sélection/Échange,Selez./Scambia,選択/交換,선택/교체,Selecionar/trocar,Selecionar/trocar,Выбрать/сменить,选取/切换,選取/切換 +,,,Close Backpack,Rucksack schließen,,Cerrar mochila,Cerrar mochila,Fermer le sac à dos,Chiudi zaino,バックパックを閉じる,배낭 닫기,Fechar mochila,Fechar mochila,Закрыть рюкзак,关闭背包,關閉背包 +,,,You have no notifications,Du hast keine Benachrichtigungen.,,No tienes notificaciones,No tienes notificaciones,Vous n'avez aucune notification,Non hai notifiche,お知らせはありません,알림이 없어요,Você não possui notificações,Você não possui notificações,Уведомлений нет,你没有通知,您無通知 +,,,Switch Tool,Werkzeug wechseln,,Alternar herramienta,Alternar herramienta,Outil d'échange,Cambia strumento,ツールを交換,도구 전환,Trocar ferramenta,Trocar ferramenta,Сменить инструмент,切换工具,切換工具 +,,,Camera Movement,Kamerabewegung,,Movimiento de la cámara,Movimiento de la cámara,Déplacement caméra,Movimento visuale,カメラの動き,카메라 이동,Movimento da câmera,Movimento da câmera,Движение камеры,镜头移动模式,攝影機移動 +,,,Game Menu Toggle,Spielmenü umschalten,,Alternar menú del juego,Alternar menú del juego,Menu du jeu (act./désact.),Attiva/Disattiva menu di gioco,ゲームメニュートグル,게임 메뉴 전환,Ativar menu do jogo,Ativar menu do jogo,Переключение игрового меню,游戏菜单切换,遊戲選單切換 +,,,Menu Navigation,Menünavigation,,Navegación del menú,Navegación del menú,Navigation du menu,Menu di navigazione,メニューナビゲーション,메뉴 내비게이션,Navegação do menu,Navegação do menu,Навигация меню,菜单导航,選單導覽 +,,,Back,Zurück,,Atrás,Atrás,Retour,Indietro,戻る,뒤로,Voltar,Voltar,Назад,返回,背面 +,,,Camera Zoom,Kamerazoom,,Distancia de la cámara,Distancia de la cámara,Zoom caméra,Zoom visuale,カメラズーム,카메라 줌,Zoom da câmera,Zoom da câmera,Масштаб камеры,镜头缩放,攝影機縮放 +,,,Account: Over 13 yrs,Konto: Über 13 J.,,Cuenta: Mayor de 13 años,Cuenta: Mayor de 13 años,Compte : Plus de 13 ans,Account: più di 13 anni,アカウント:13才以上,계정: 만 13세 이상,Conta: Mais de 13 anos,Conta: Mais de 13 anos,Учетная запись: Старше 13 лет,帐户:超过 13 岁,帳戶:超過 13 歲 +,,,Dismiss,Verwerfen,,Descartar,Descartar,Rejeter,Ignora,却下,취소,Dispensar,Dispensar,Отклонить,关闭,關閉 +,,,New Follower,Neuer Follower,,Seguidor nuevo,Seguidor nuevo,Nouvel abonné,Nuovo follower,新規フォロワー,새 팔로워,Novo seguidor,Novo seguidor,Новый подписчик,新粉丝,新關注者 +,,,Cancel,Abbrechen,,Cancelar,Cancelar,Annuler,Annulla,キャンセル,취소,Cancelar,Cancelar,Отмена,取消,取消 +,,,An error occurred while unblocking {RBX_NAME}. Please try again later.,Bei der Aufhebung der Sperre von {RBX_NAME} ist ein Fehler aufgetreten. Bitte versuche es später erneut.,,Se ha producido un error al desbloquear a {RBX_NAME}. Inténtalo de nuevo más tarde.,Se ha producido un error al desbloquear a {RBX_NAME}. Inténtalo de nuevo más tarde.,Une erreur est survenue lors de la levée du blocage de {RBX_NAME}. Veuillez réessayer plus tard.,Si è verificato un errore nello sblocco di {RBX_NAME}. Riprova più tardi.,{RBX_NAME}のブロック解除中にエラーが発生しました。しばらくしてからやり直してください。,{RBX_NAME}님 차단을 해제하는 중 오류 발생. 나중에 다시 시도하세요.,Um erro ocorreu ao desbloquear {RBX_NAME}. Tente de novo mais tarde.,Um erro ocorreu ao desbloquear {RBX_NAME}. Tente de novo mais tarde.,При разблокировке пользователя {RBX_NAME} произошла ошибка. Повторите попытку позже.,取消屏蔽“{RBX_NAME}”时出错。请稍候重试。,解除封鎖{RBX_NAME}時發生錯誤。請稍後再試。 +,,,Would you like to unblock {RBX_NAME}?,Möchtest du die Sperre von {RBX_NAME} aufheben?,,¿Quieres desbloquear a {RBX_NAME}?,¿Quieres desbloquear a {RBX_NAME}?,Souhaitez-vous lever le blocage de {RBX_NAME} ?,Vuoi sbloccare {RBX_NAME}?,{RBX_NAME}をブロック解除しますか?,{RBX_NAME}님 차단을 해제할까요?,Gostaria de desbloquear {RBX_NAME}?,Gostaria de desbloquear {RBX_NAME}?,Разблокировать пользователя {RBX_NAME}?,你想要解除对“{RBX_NAME}”的屏蔽吗?,您是否要解除封鎖{RBX_NAME}? +,,,You are too far away to chat!,"Du bist zu weit entfernt, um zu chatten!",,¡Estás demasiado lejos para chatear!,¡Estás demasiado lejos para chatear!,Vous êtes trop loin pour discuter !,Sei troppo lontano per chattare!,遠すぎてチャット出来ません!,채팅하기에 너무 멀어요!,Você está longe demais para participar do chat!,Você está longe demais para participar do chat!,Вы слишком далеко и не можете общаться в чате!,距离太远,无法聊天!,您距離太遠,無法聊天! +,,,Chat ended because you walked away,"Chat wurde beendet, da du dich entfernt hast.",,El chat ha finalizado porque te has alejado.,El chat ha finalizado porque te has alejado.,Le chat a pris fin car vous êtes parti,"La chat terminata, ti sei allontanato",立ち去ったのでチャットが終了しました。,이탈하여 채팅이 종료되었어요,O chat terminou porque você se afastou,O chat terminou porque você se afastou,Чат завершен: вы ушли.,你已走开,聊天结束,因您走遠,聊天已結束 +,,,Chat ended because you didn't reply,"Chat wurde beendet, da du nicht geantwortet hast.",,El chat ha finalizado porque no has contestado.,El chat ha finalizado porque no has contestado.,Le chat a pris fin car vous n'avez pas répondu,"La chat terminata, non hai risposto",返事をしなかったのでチャットが終了しました。,대답하지 않아 채팅이 종료되었어요,O chat terminou porque você não respondeu,O chat terminou porque você não respondeu,Чат завершен: вы не ответили.,你没有回答,聊天结束,因您未回答,聊天已結束 +,,,Goodbye!,Tschüss!,,¡Hasta luego!,¡Hasta luego!,Au revoir !,Addio!,さようなら!,안녕히 가세요!,Tchau!,Tchau!,До свидания!,再见!,再會! +,,,Character Movement,Charakterbewegung,,Movimiento del personaje,Movimiento del personaje,Déplacement personnage,Movimento personaggio,キャラクターの動き,캐릭터 이동,Movimento de personagem,Movimento de personagem,Движение персонажа,人物移动模式,人物移動 +,,,Your account balance will not be affected by this transaction.,Das Guthaben deines Kontos wird durch diese Transaktion nicht beeinflusst.,,Esta transacción no modificará el saldo de tu cuenta.,Esta transacción no modificará el saldo de tu cuenta.,Le solde de votre compte ne sera pas affecté par cette transaction.,I fondi del tuo account non verranno intaccati da questa transazione.,この取引であなたのアカウントは変化しません。,계정 잔액은 이 거래의 영향을 받지 않아요.,O saldo da sua conta não será afetado por esta transação.,O saldo da sua conta não será afetado por esta transação.,После операции средства не будут списаны с вашей учетной записи.,你的帐户余额将不会收到此次交易的影响。,您的帳戶餘額不受此交易影響。 +,,,You already own this item. Your account has not been charged.,Diesen Gegenstand besitzt du bereits. Dein Konto wurde nicht belastet.,,Ya tienes este objeto. No se ha llevado a cabo ningún cobro en tu cuenta.,Ya tienes este objeto. No se ha llevado a cabo ningún cobro en tu cuenta.,Vous possédez déjà cet objet. Votre compte n'a pas été débité.,Possiedi già questo oggetto. Il tuo account non ha subito addebiti.,既にこのアイテムを持っています。アカウントがチャージされませんでした。,이 아이템을 이미 가지고 있어요. 계정에 비용이 청구되지 않아요.,Você já possui este item. Nada foi cobrado da sua conta.,Você já possui este item. Nada foi cobrado da sua conta.,У вас уже есть этот предмет. Средства с вашей учетной записи не списаны.,你已拥有这件物品。你的帐户未被扣款。,您已有此物,未自您的帳戶收費。 +,,,This is a test purchase; your account will not be charged.,Dies ist ein Testkauf. Dein Konto wird dadurch nicht belastet.,,Esta compra es una prueba; no se llevará a cabo ningún cobro en tu cuenta.,Esta compra es una prueba; no se llevará a cabo ningún cobro en tu cuenta.,Ceci est un achat test ; votre compte ne sera pas débité.,Questo è un acquisto di prova; il tuo account non subirà addebiti.,これはテスト購入です。アカウントはチャージされません。,테스트 구매입니다. 계정에 비용이 청구되지 않아요.,Esta é uma compra de teste. Nada será cobrado da sua conta.,Esta é uma compra de teste. Nada será cobrado da sua conta.,Это тестовая покупка; средства не будут списаны с вашей учетной записи.,此次购买为测试性质;你的帐户将不会被扣款。,此為測試性購買;不會自您的帳戶收費。 +,,,This was a test purchase.,Dies war ein Testkauf.,,Esta compra ha sido una prueba.,Esta compra ha sido una prueba.,C'était un achat test.,Questo era un acquisto di prova.,テスト購入でした。,이 구매는 테스트용입니다.,Esta foi uma compra de teste.,Esta foi uma compra de teste.,Это была тестовая покупка.,此次购买为测试性质。,此為測試性購買。 +,,,Chat,Chat,,Chat,Chat,Chat,Chat,チャット,채팅,Chat,Chat,Чат,聊天,聊天 +,,,Builders Club,Builders Club,,Builders Club,Builders Club,Builders Club,Builders Club,ビルダーズクラブ,,Builders Club,Builders Club,Клуб создателей,Builders Club, +,,,Turbo Builders Club,Turbo Builders Club,,Turbo Builders Club,Turbo Builders Club,Turbo Builders Club,Turbo Builders Club,ターボビルダーズクラブ,,Turbo Builders Club,Turbo Builders Club,Потрясающий клуб создателей,Turbo Builders Club, +,,,Outrageous Builders Club,Outrageous Builders Club,,Outrageous Builders Club,Outrageous Builders Club,Outrageous Builders Club,Turbo Builders Club,もの凄いビルダーズクラブ,,Outrageous Builders Club,Outrageous Builders Club,Невероятный клуб создателей,Outrageous Builders Club, +,,,Image,Bild,,Imagen,Imagen,Image,Immagine,イメージ,이미지,Imagem,Imagem,Изображение,图像,圖像 +,,,T-Shirt,T-Shirt,,Camiseta,Camiseta,Tee-shirt,Maglietta,Tシャツ,티셔츠,Camiseta,Camiseta,Футболка,T 恤,T恤 +,,,Audio,Audio,,Audio,Audio,Audio,Audio,オーディオ,오디오,Áudio,Áudio,Звук,音频,音訊 +,,,Mesh,Mesh,,Mesh,Mesh,Maillage,Mesh,メッシュ,Mesh,Malha,Malha,Сетка,网格,網格 +,,,Lua,Lua,,Lua,Lua,Lua,Lua,Lua,Lua,Lua,Lua,Lua,Lua ,Lua +,,,HTML,HTML,,HTML,HTML,HTML,HTML,HTML,HTML,HTML,HTML,HTML,HTML,HTML +,,,Text,Text,,Texto,Texto,Texte,Testo,テキスト,텍스트,Texto,Texto,Текст,文字,文字 +,,,Hat,Hut,,Sombrero,Sombrero,Chapeau,Cappello,帽子,모자,Chapéu,Chapéu,Головной убор,帽子,帽子 +,,,Place,Ort,,Lugar,Lugar,Emplacement,Località,プレース,장소,Local,Local,Разместить,地点,地點 +,,,Model,Modell,,Modelo,Modelo,Modèle,Modello,モデル,모델,Modelo,Modelo,Модель,模型,模型 +,,,Shirt,Hemd,,Camisa,Camisa,Chemise,Camicia,シャツ,셔츠,Camisa,Camisa,Рубашка,衬衫,上衣 +,,,Pants,Hose,,Pantalones,Pantalones,Pantalon,Pantaloni,パンツ,바지,Calças,Calças,Штаны,裤子,褲子 +,,,Decal,Decal,,Adhesivo,Adhesivo,Décalcomanie,Decalcomania,デカール,데칼,Decalque,Decalque,Наклейка,贴纸,貼花 +,,,Avatar,Avatar,,Avatar,Avatar,Avatar,Avatar,アバター,아바타,Avatar,Avatar,Аватар,虚拟形象,虛擬人偶 +,,,Head,Kopf,,Cabeza,Cabeza,Tête,Testa,頭,머리,Cabeça,Cabeça,Голова,头部,頭 +,,,Face,Gesicht,,Cara,Cara,Visage,Faccia,顔,얼굴,Rosto,Rosto,Лицо,脸部,臉 +,,,Gear,Ausrüstung,,Equipamiento,Equipamiento,Équipement,Attrezzatura,ギア,기어,Equipamento,Equipamento,Снаряжение,装备,裝備 +,,,Cheating/Exploiting,Schummeln/Ausnutzen von Spielfehlern,,Trampas/abuso de errores,Trampas/abuso de errores,Triche/Exploitation,Inganno/Sfruttamento,チート/悪用,속임수/악용,Trapaça/abuso,Trapaça/abuso,Жульничество,作弊/开挂,作弊/剝削 +,,,Badge,Abzeichen,,Emblema,Emblema,Badge,Contrassegno,バッジ,배지,Emblema,Emblema,Значок,徽章,徽章 +,,,Group Emblem,Gruppenemblem,,Emblema de grupo,Emblema de grupo,Emblème de groupe,Emblema gruppo,グループエンブレム,그룹 엠블렘,Emblema de grupo,Emblema de grupo,Эмблема группы,群组徽章,群組徽章 +,,,Animation,Animation,,Animación,Animación,Animation,Animazione,アニメーション,애니메이션,Animação,Animação,Анимация,动画,動畫 +,,,Arms,Arme,,Brazos,Brazos,Bras,Braccia,腕,팔,Braços,Braços,Руки,手臂,臂 +,,,Legs,Beine,,Piernas,Piernas,Jambes,Gambe,脚,다리,Pernas,Pernas,Ноги,腿部,腿 +,,,Torso,Körper,,Torso,Torso,Torse,Busto,胴体,상체,Tronco,Tronco,Корпус,身体主干,軀幹 +,,,Right Arm,Rechter Arm,,Brazo derecho,Brazo derecho,Bras droit,Braccio destro,右腕,오른팔,Braço direito,Braço direito,Правая рука,右臂,右臂 +,,,Left Arm,Linker Arm,,Brazo izquierdo,Brazo izquierdo,Bras gauche,Braccio sinistro,左腕,왼팔,Braço esquerdo,Braço esquerdo,Левая рука,左臂,左臂 +,,,Left Leg,Linkes Bein,,Pierna izquierda,Pierna izquierda,Jambe gauche,Gamba sinistra,左脚,왼쪽 다리,Perna esquerda,Perna esquerda,Левая нога,左腿,左腿 +,,,Right Leg,Rechtes Bein,,Pierna derecha,Pierna derecha,Jambe droite,Gamba destra,右脚,오른쪽 다리,Perna direita,Perna direita,Правая нога,右腿,右腿 +,,,Choose One,Wähle eine der folgenden Optionen,,Elige uno,Elige uno,En choisir un(e),Scegli,ひとつ選ぶ,한 가지 선택,Escolha um,Escolha um,Выберите один вариант,选择一项,請擇一 +,,,Package,Paket,,Paquete,Paquete,Pack,Pacchetto,パッケージ,패키지,Pacote,Pacote,Набор,套装,套件 +,,,YouTube Video,YouTube-Video,,Vídeo de YouTube,Vídeo de YouTube,Vidéo YouTube,Video su YouTube,YouTube ビデオ,YouTube 비디오,Vídeo do YouTube,Vídeo do YouTube,Видео YouTube,Youtube 视频,YouTube 影片 +,,,Game Pass,Spielpass,,Pase de juego,Pase de juego,Passe de jeu,Pass di gioco,ゲームパス,게임패스,Passe de jogo,Passe de jogo,Игровой пропуск,游戏通行证,遊戲通行證 +,,,Plugin,Plug-in,,Plugin,Plugin,Plugin,Plug-in,プラグイン,플러그인,Plugin,Plugin,Расширение,插件,外掛程式 +,,,SolidModel,SolidModel,,SolidModel,SolidModel,SolidModel,Modello solido,ソリッドモデル,,SolidModel,SolidModel,Твердая модель,SolidModel, +,,,MeshPart,MeshPart,,MeshPart,MeshPart,MeshPart,Parte mesh,メッシュパーツ,,SolidModel,SolidModel,Полигональная часть,MeshPart, +,,,Hair Accessory,Haar-Accessoire,,Accesorio para el pelo,Accesorio para el pelo,Accessoire de cheveux,Accessorio capelli,ヘアアクセサリ,헤어 액세서리,Acessório de cabelo,Acessório de cabelo,Аксессуар для волос,头发配饰,頭髮配件 +,,,Face Accessory,Gesichts-Accessoire,,Accesorio para la cara,Accesorio para la cara,Accessoire de visage,Accessorio faccia,顔アクセサリ,얼굴 액세서리,Acessório de rosto,Acessório de rosto,Аксессуар для лица,脸部配饰,臉部配件 +,,,Neck Accessory,Hals-Accessoire,,Accesorio para el cuello,Accesorio para el cuello,Accessoire de cou,Accessorio collo,首アクセサリ,목 액세서리,Acessório de pescoço,Acessório de pescoço,Аксессуар для шеи,颈部配饰,頸部配件 +,,,Shoulder Accessory,Schulter-Accessoire,,Accesorio para el hombro,Accesorio para el hombro,Accessoire d'épaule,Accessorio spalla,肩アクセサリ,어깨 액세서리,Acessório de ombro,Acessório de ombro,Аксессуар для плеч,肩部配饰,肩膀配件 +,,,Classic,Klassisch,,Clásico,Clásico,Classique,Classica,クラッシック,클래식,Clássico,Clássico,Классика,经典,古典 +,,,Front Accessory,Vorderseiten-Accessoire,,Accesorio frontal,Accesorio frontal,Accessoire avant,Accessorio anteriore,前面アクセサリ,가슴 액세서리,Acessório da frente,Acessório da frente,Передний аксессуар,正面配饰,正面配件 +,,,Back Accessory,Rückseiten-Accessoire,,Accesorio trasero,Accesorio trasero,Accessoire arrière,Accessorio posteriore,背面アクセサリ,등 액세서리,Acessório de trás,Acessório de trás,Задний аксессуар,背面配饰,背面配件 +,,,Waist Accessory,Taillen-Accessoire,,Accesorio para la cintura,Accesorio para la cintura,Accessoire de taille,Accessorio vita,ウエストアクセサリ,허리 액세서리,Acessório de cintura,Acessório de cintura,Аксессуар для талии,腰部配饰,腰部配件 +,,,Climb Animation,Kletteranimation,,Animación de escalada,Animación de escalada,Animation d'escalade,Animazione scalata,登りアニメーション,오르기 애니메이션,Animação de escalada,Animação de escalada,Анимация подъема,攀爬动画,攀爬動畫 +,,,Fall Animation,Fallanimation,,Animación de caída,Animación de caída,Animation de chute,Animazione caduta,落下アニメーション,낙하 애니메이션,Animação de queda,Animação de queda,Анимация падения,下降动画,下降動畫 +,,,Idle Animation,Untätigkeitsanimation,,Animación de inactividad,Animación de inactividad,Animation oisif,Animazione inattività,アイドル状態アニメーション,기본 애니메이션,Animação de inatividade,Animação de inatividade,Анимация ожидания,闲置动画,閒置動畫 +,,,Jump Animation,Springanimation,,Animación de salto,Animación de salto,Animation de saut,Animazione salto,ジャンプアニメーション,점프 애니메이션,Animação de salto,Animação de salto,Анимация прыжка,跳跃动画,跳躍動畫 +,,,Run Animation,Laufanimation,,Animación de carrera,Animación de carrera,Animation de course,Animazione corsa,ランアニメーション,달리기 애니메이션,Animação de corrida,Animação de corrida,Анимация бега,跑步动画,奔跑動畫 +,,,Swim Animation,Schwimmanimation,,Animación de natación,Animación de natación,Animation de nage,Animazione nuotata,泳ぎアニメーション,수영 애니메이션,Animação de nado,Animação de nado,Анимация плавания,游泳动画,游泳動畫 +,,,Walk Animation,Gehanimation,,Animación de marcha,Animación de marcha,Animation de marche,Animazione camminata,歩きアニメーション,걷기 애니메이션,Animação de caminhada,Animação de caminhada,Анимация ходьбы,行走动画,步行動畫 +,,,Click to Move,Zum Bewegen klicken,,Clic para moverse,Clic para moverse,Cliquer pour se déplacer,Clicca per muovere,クリックして移動,클릭해 이동,Clique para mover,Clique para mover,"Нажмите, чтобы передвигаться",点按以移动,滑鼠移動 +,,,This item cost more ROBUX than you have available. Please leave this game and go to the ROBUX screen to purchase more.,"Dieser Gegenstand kostet mehr ROBUX, als dir zur Verfügung stehen. Bitte verlasse dieses Spiel, gehe zum ROBUX-Menü und kaufe dort mehr.",,Este objeto cuesta más ROBUX de los que tienes disponibles. Sal de este juego y ve a la pantalla de ROBUX para comprar más.,Este objeto cuesta más ROBUX de los que tienes disponibles. Sal de este juego y ve a la pantalla de ROBUX para comprar más.,Cet objet coûte plus de ROBUX que vous n'en avez. Veuillez quitter le jeu et aller à l'écran ROBUX pour en acheter plus.,Questo oggetto costa più ROBUX di quanti tu ne abbia. Esci dal gioco e vai nella schermata dei ROBUX per acquistarne altri.,このアイテムを買うにはお持ちのROBUXでは足りません。ゲームをやめて購入のためROBUX画面に行ってください。,이 아이템의 가격은 소지한 ROBUX 보다 비싸요. 더 많은 ROBUX를 구매하려면 이 게임을 나간 후 ROBUX 화면으로 이동하세요.,Este item custa mais ROBUX do que você possui disponível. Saia do jogo e vá para a tela de ROBUX para comprar mais.,Este item custa mais ROBUX do que você possui disponível. Saia do jogo e vá para a tela de ROBUX para comprar mais.,"Цена товара превышает имеющееся у вас количество ROBUX. Выйдите из этой игры и перейдите в раздел ROBUX, чтобы купить больше.",此物品的价格超过了你拥有的 ROBUX。请离开此游戏,前往 ROBUX 屏幕以购买更多。,此項目花費的 ROBUX 超過您所能花用。請離開此遊戲,前往 ROBUX 畫面加購。 +,,,This item cost more ROBUX than you can purchase. Please visit www.roblox.com to purchase more ROBUX.,"Dieser Gegenstand kostet mehr ROBUX, als du kaufen kannst. Bitte besuche www.roblox.com, um mehr ROBUX zu kaufen.",,Este objeto cuesta más ROBUX de los que puedes comprar. Visita www.roblox.com para comprar más ROBUX.,Este objeto cuesta más ROBUX de los que puedes comprar. Visita www.roblox.com para comprar más ROBUX.,Cet objet coûte trop de ROBUX pour que vous l'achetiez. Veuillez vous rendre sur www.roblox.com pour acheter plus de ROBUX.,Questo oggetto costa più ROBUX di quanti tu possa acquistarne. Visita il sito www.roblox.com per acquistare altri ROBUX.,このアイテムを買うにはあなたが購入可能なROBUXでは足りません。www.roblox.com にアクセスしてROBUXを追加購入してください。,이 아이템 구매에는 더 많은 ROBUX가 필요해요. ROBUX를 더 구매하려면 www.roblox.com을 방문하세요.,Este item custa mais ROBUX do que você pode comprar. Visite www.roblox.com para comprar mais ROBUX.,Este item custa mais ROBUX do que você pode comprar. Visite www.roblox.com para comprar mais ROBUX.,"Цена товара превышает количество ROBUX, которое вы можете купить. Перейдите на страницу www.roblox.com, чтобы приобрести больше ROBUX.",此物品的价格超过了你拥有的 ROBUX。请前往 www.roblox.com 购买更多 ROBUX。,此項目花費的 ROBUX 超過您所能購買。請瀏覽 www.roblox.com 加購 ROBUX。 +,,,You need {RBX_NUMBER} more {RBX_NAME} to buy this item.,"Du benötigst noch {RBX_NUMBER} weitere {RBX_NAME}, um diesen Gegenstand zu kaufen.",,Necesitas {RBX_NUMBER} {RBX_NAME} más para comprar este objeto.,Necesitas {RBX_NUMBER} {RBX_NAME} más para comprar este objeto.,Vous avez besoin de {RBX_NUMBER} {RBX_NAME} de plus pour acheter cet objet.,Hai bisogno di {RBX_NUMBER} {RBX_NAME} in più per comprare questo oggetto.,このアイテムを買うにはあと {RBX_NUMBER} の {RBX_NAME} が必要です。,이 아이템을 구매하려면 {RBX_NAME}이(가) {RBX_NUMBER}개 더 필요해요.,Você precisa de mais {RBX_NUMBER} {RBX_NAME} para comprar este item.,Você precisa de mais {RBX_NUMBER} {RBX_NAME} para comprar este item.,Для покупки этого товара требуется на {RBX_NUMBER} больше {RBX_NAME}.,你还需要 {RBX_NUMBER} 个 “{RBX_NAME}” 才能购买此物品。,您需要再多 {RBX_NUMBER} 個{RBX_NAME}方能購買此項目。 +,,,Do you allow game to create new place in your inventory?,"Erlaubst du dem Spiel, mehr Platz in deinem Inventar zu schaffen?",,¿Quieres permitir que el juego cree un espacio nuevo en tu inventario?,¿Quieres permitir que el juego cree un espacio nuevo en tu inventario?,Autorisez-vous le jeu à créer un nouvel emplacement dans votre inventaire ?,Vuoi permettere al gioco di creare nuovo spazio nel tuo inventario?,あなたのインベントリに新しい場所を作成しても良いですか?,게임에서 인벤토리에 새로운 장소를 만들도록 할까요?,Você permite que o jogo crie um novo espaço em seu inventário?,Você permite que o jogo crie um novo espaço em seu inventário?,Разрешить игре создать новое место в вашем инвентаре?,你是否允许游戏在你的道具中创建新的地点?,您是否允許遊戲在您的庫存建立新位置? +,,,Hiding Core GUI,Grafische Standard-Benutzeroberfläche verbergen,,Ocultando GUI básica,Ocultando GUI básica,Cacher l'IGU principale,Nascondere interfaccia base,コア GUI を隠す。,코어 GUI 숨기기,Escondendo interface básica,Escondendo interface básica,Скрытие элементов основного интерфейса,隐藏核心 GUI,隱藏核心 GUI +,,,Ctrl-Shift-G again to restore.,Zum Wiederherstellen erneut Strg-Umschalt-G drücken.,,Vuelve a pulsar Ctrl-Mayús-G para restablecerla.,Vuelve a pulsar Ctrl-Mayús-G para restablecerla.,Ctrl-Maj-G pour la restaurer.,Ancora CTRL-MAIUSC-G per ripristinare.,Ctrl-Shift-G をもう一度押してリストア。,복원하려면 Ctrl-Shift-G를 클릭하세요.,Ctrl-Shift-G de novo para restaurar.,Ctrl-Shift-G de novo para restaurar.,"Снова нажмите Ctrl-Shift-G, чтобы восстановить.",重按 Ctrl-Shift-G 以还原。,再次按 Ctrl-Shift-G 鍵以復原。 +,,,Hiding Custom GUI,Individuelle grafische Benutzeroberfläche verbergen,,Ocultando GUI personalizada,Ocultando GUI personalizada,Cacher l'IGU personnalisée,Nascondere interfaccia personalizzata,カスタムGUIを隠す。,사용자 정의 GUI 숨기기,Escondendo interface personalizada,Escondendo interface personalizada,Скрытие элементов пользовательского интерфейса,隐藏自定义 GUI,隱藏自訂 GUI +,,,Ctrl-Shift-C again to restore.,Zum Wiederherstellen erneut Strg-Umschalt-C drücken.,,Vuelve a pulsar Ctrl-Mayús-C para restablecerla.,Vuelve a pulsar Ctrl-Mayús-C para restablecerla.,Ctrl-Maj-C pour la restaurer.,Ancora CTRL-MAIUSC-C per ripristinare.,Ctrl-Shift-Cをもう一度教えてリストア。,복원하려면 Ctrl-Shift-C를 클릭하세요.,Ctrl-Shift-C de novo para restaurar.,Ctrl-Shift-C de novo para restaurar.,"Снова нажмите Ctrl-Shift-C, чтобы восстановить.",重按 Ctrl-Shift-C 以还原。,再次按 Ctrl-Shift-C 鍵以復原。 +,,,"Requested game is full, retrying...",Gewünschtes Spiel ist voll. Neuer Versuch ...,,El juego solicitado está lleno. Intentándolo de nuevo...,El juego solicitado está lleno. Intentándolo de nuevo...,"Le jeu demandé est complet, nouvelle tentative...",Il gioco richiesto è al completo. Nuovo tentativo...,リクエストしたゲームは満員です。リトライ中...,요청한 게임이 가득 찼어요. 재시도 중...,O jogo solicitado está cheio. Tentando de novo...,O jogo solicitado está cheio. Tentando de novo...,Запрашиваемая игра переполнена. Новая попытка...,已请求的游戏已满员。正在重试...,請求的遊戲已滿額,重試中... +,,,Could not connect to game because game is disabled,"Verbindung zum Spiel konnte nicht hergestellt werden, da das Spiel deaktiviert ist.",,No se ha podido conectar al juego porque está desactivado.,No se ha podido conectar al juego porque está desactivado.,Impossible de se connecter au jeu car il a été désactivé,Impossibile connettersi al gioco perché è disattivato,ゲームが無効なため接続できませんでした。,게임이 비활성화되어 접속할 수 없어요,Impossível conectar pois o jogo está desabilitado,Impossível conectar pois o jogo está desabilitado,"Не удалось подключиться к игре, так как она недоступна.",此游戏已停用,无法连接。,無法連線到遊戲,因為遊戲已停用 +,,,Could not connect to game because game failed to start,"Verbindung zum Spiel konnte nicht hergestellt werden, da das Spiel nicht gestartet werden konnte.",,No se ha podido conectar al juego porque no se ha podido iniciar.,No se ha podido conectar al juego porque no se ha podido iniciar.,Impossible de se connecter au jeu car il n'a pas réussi à être lancé,Impossibile connettersi al gioco perché l'avvio non è riuscito,ゲームの起動に失敗したため接続できませんでした。,게임 시작에 실패하여 접속할 수 없어요,Impossível conectar pois o jogo não conseguiu iniciar,Impossível conectar pois o jogo não conseguiu iniciar,"Не удалось подключиться к игре, так как она не запустилась.",开始此游戏失败,无法连接。,無法連線到遊戲,因為遊戲無法啟動 +,,,D/Right Arrow,D/Rechtspfeil,,D/Cursor derecho,D/Cursor derecho,D/Flèche droite,D/Freccia DESTRA,D/右カーソル,D/오른쪽 화살표,D/seta direita,D/seta direita,D/стрелка вправо,D/右箭头,D 鍵 / 向右箭號 +,,,Could not connect to game because game has ended,"Verbindung zum Spiel konnte nicht hergestellt werden, da das Spiel beendet wurde.",,No se ha podido conectar al juego porque ha terminado.,No se ha podido conectar al juego porque ha terminado.,Impossible de se connecter au jeu car il est terminé,Impossibile connettersi al gioco perché è terminato,ゲームが終了したため接続できませんでした。,게임이 종료되어 접속할 수 없어요,Impossível conectar pois o jogo já acabou,Impossível conectar pois o jogo já acabou,"Не удалось подключиться к игре, так как она завершилась.",此游戏已结束,无法连接。,無法連線到遊戲,因為遊戲已結束 +,,,Could not connect to game because game is full,"Verbindung zum Spiel konnte nicht hergestellt werden, da das Spiel voll ist.",,No se ha podido conectar al juego porque está lleno.,No se ha podido conectar al juego porque está lleno.,Impossible de se connecter au jeu car il est complet,Impossibile connettersi al gioco perché è al completo,ゲームが満員なため接続できませんでした。,게임이 가득 차서 접속할 수 없어요,Impossível conectar pois o jogo está cheio,Impossível conectar pois o jogo está cheio,"Не удалось подключиться к игре, так как она переполнена.",此游戏已满员,无法连接。,無法連線到遊戲,因為此遊戲已滿額 +,,,Could not connect to game because user you were following has left the game,"Verbindung zum Spiel konnte nicht hergestellt werden, da der Benutzer, dem du gefolgt bist, das Spiel verlassen hat.",,No se ha podido conectar al juego porque el jugador al que seguías ha salido del mismo.,No se ha podido conectar al juego porque el jugador al que seguías ha salido del mismo.,Impossible de se connecter au jeu car l'utilisateur que vous suiviez l'a quitté,Impossibile connettersi al gioco perché l'utente che stavi seguendo è uscito,フォロー中のユーザーがゲームから退出したため接続できませんでした。,팔로우 중인 사용자가 게임에서 나가서 게임에 접속할 수 없어요,Impossível conectar pois o usuário que você estava seguindo saiu do jogo,Impossível conectar pois o usuário que você estava seguindo saiu do jogo,"Не удалось подключиться к игре, так как игрок, за которым вы последовали, ее покинул.",你关注的用户已离开游戏,因此无法连接。,無法連線至遊戲,因為您關注的使用者已離開遊戲 +,,,Could not connect to game because it is not available for your platform,"Verbindung zum Spiel konnte nicht hergestellt werden, da es für deine Plattform nicht verfügbar ist.",,No se ha podido conectar al juego porque no está disponible para tu plataforma.,No se ha podido conectar al juego porque no está disponible para tu plataforma.,Impossible de se connecter au jeu car il n'est pas disponible sur votre plateforme,Impossibile connettersi al gioco perché non è disponibile per la tua piattaforma,プラットフォームが非対応なため接続できませんでした。,플랫폼에서 이용할 수 없는 게임이므로 접속할 수 없어요,Impossível conectar pois o jogo não está disponível para a sua plataforma,Impossível conectar pois o jogo não está disponível para a sua plataforma,"Не удалось подключиться к игре, так как она недоступна на вашей платформе.",此游戏在你的平台上不可用,因此无法连接。,無法連線到遊戲,因為不適用於您的平台 +,,,Could not connect to game due to join script failure,"Verbindung zum Spiel konnte nicht hergestellt werden, da ein Problem mit dem Beitrittsskript aufgetreten ist.",,No se ha podido conectar al juego a causa de un error en el script de unión.,No se ha podido conectar al juego a causa de un error en el script de unión.,Impossible de se connecter au jeu du fait d'un échec du script pour le rejoindre,Impossibile connettersi al gioco per un errore dello script di accesso,参加スクリプトの失敗により接続できませんでした。,참가 스크립트를 가져오지 못해 게임에 접속할 수 없어요,Impossível conectar devido a uma falha no script de entrada,Impossível conectar devido a uma falha no script de entrada,Не удалось подключиться к игре из-за ошибки в сценарии подключения.,由于加入脚本失败,无法连接至游戏,無法連線到遊戲,原因是加入指令碼失敗 +,,,"Game join request expired or invalid, please try again.",Anfrage zum Spielbeitritt abgelaufen oder ungültig. Bitte versuche es erneut.,,La solicitud para unirse al juego ha caducado o no es válida. Inténtalo de nuevo.,La solicitud para unirse al juego ha caducado o no es válida. Inténtalo de nuevo.,"La demande pour rejoindre le jeu a expirée ou est invalide, veuillez réessayer.",Richiesta di accesso al gioco scaduta o non valida. Riprova.,ゲーム参加リクエストが期限切れか無効です。やり直してください。,게임 가입 요청이 만료되었거나 잘못되었어요. 다시 시도하세요.,Pedido de entrada no jogo expirado ou inválido. Tente novamente.,Pedido de entrada no jogo expirado ou inválido. Tente novamente.,"Срок приглашения в игру истек, или оно является недействительным. Повторите попытку.",加入游戏的请求已过期或无效,请重试。,遊戲加入請求過期或無效,請再試一次。 +,,,"Could not connect to game, please try again later.",Verbindung zum Spiel konnte nicht hergestellt werden. Bitte versuche es später erneut.,,No se ha podido conectar al juego. Inténtalo de nuevo más tarde.,No se ha podido conectar al juego. Inténtalo de nuevo más tarde.,"Impossible de se connecter au jeu, veuillez réessayer plus tard.",Impossibile connettersi al gioco. Riprova più tardi.,ゲームに接続できませんでした。しばらくしてからやり直してください。,게임에 접속할 수 없어요. 나중에 다시 시도하세요.,Impossível conectar ao jogo. Tente de novo mais tarde.,Impossível conectar ao jogo. Tente de novo mais tarde.,Не удалось подключиться к игре. Повторите попытку позже.,无法连接至游戏,请稍候重试。,無法連線到遊戲,請稍後再試 +,,,Confirm Unblock,Aufhebung der Sperre bestätigen,,Confirmar desbloqueo,Confirmar desbloqueo,Confirmer le déblocage,Conferma sblocco,ブロック解除を確認,차단 해제 확인,Confirmar desbloqueio,Confirmar desbloqueio,Подтверждение разблокировки,确认取消屏蔽,確認解除封鎖 +,,,Error Blocking Player,Fehler beim Sperren des Spielers,,Error al bloquear al jugador,Error al bloquear al jugador,Erreur en bloquant le joueur,Errore di blocco giocatore,プレーヤーブロックエラー,플레이어 차단 오류,Erro ao bloquear jogador,Erro ao bloquear jogador,Ошибка блокировки игрока,屏蔽玩家时出错,封鎖玩家時發生錯誤 +,,,Confirm Block,Sperre bestätigen,,Confirmar bloqueo,Confirmar bloqueo,Confirmer le blocage,Conferma blocco,ブロックを確認,차단 확인,Confirmar bloqueio,Confirmar bloqueio,Подтверждение блокировки,确认屏蔽,確認封鎖 +,,,Dating,Dating,,Solicitud de cita,Solicitud de cita,Drague,Appuntamento,デートの誘い,교제,Namoro,Namoro,Флирт,约会,約會 +,,,Error Unblocking Player,Fehler beim Aufheben der Sperre des Spielers,,Error al desbloquear al jugador,Error al desbloquear al jugador,Erreur en levant le blocage du joueur,Errore di sblocco giocatore,プレーヤーブロック解除エラー,플레이어 차단 해제 오류,Erro ao desbloquear jogador,Erro ao desbloquear jogador,Ошибка разблокировки игрока,取消屏蔽玩家时出错,解除封鎖玩家時發生錯誤 +,,,An error occurred while unfriending {RBX_NAME}. Please try again later.,Bei der Entfernung von {RBX_NAME} als Freund ist ein Fehler aufgetreten. Bitte versuche es später erneut.,,Se ha producido un error al cancelar la amistad con {RBX_NAME}. Inténtalo de nuevo más tarde.,Se ha producido un error al cancelar la amistad con {RBX_NAME}. Inténtalo de nuevo más tarde.,Une erreur est survenue lors de la suppression de l'ami {RBX_NAME}. Veuillez réessayer plus tard.,Si è verificato un errore nel togliere l'amicizia a {RBX_NAME}. Riprova più tardi.,{RBX_NAME}を友達解除する際にエラーが発生しました。しばらくしてからやり直してください。,{RBX_NAME}님을 친구 취소하는 도중 오류 발생. 나중에 다시 시도하세요.,Um erro ocorreu ao cancelar amizade com {RBX_NAME}. Tente de novo mais tarde.,Um erro ocorreu ao cancelar amizade com {RBX_NAME}. Tente de novo mais tarde.,При удалении пользователя {RBX_NAME} из друзей произошла ошибка. Повторите попытку позже.,与“{RBX_NAME}”解除好友关系时出错。请稍候重试。,與{RBX_NAME}解除朋友關係時發生錯誤。請稍後再試。 +,,,Okay,Okay,,Aceptar,Aceptar,D'accord,OK,OK,확인,Ok,Ok,ОК,好,好 +,,,Send Request,Anfrage senden,,Enviar solicitud,Enviar solicitud,Envoyer demande,Invia richiesta,リクエスト送信,요청 전송,Enviar pedido,Enviar pedido,Отправить запрос,发送请求,傳送要求 +,,,You can not send a friend request because you are at the max friend limit.,"Du kannst keine Freundesanfrage senden, da du die max. Anzahl an Freunden erreicht hast.",,No puedes enviar una solicitud de amistad porque has alcanzado el límite máximo de amigos.,No puedes enviar una solicitud de amistad porque has alcanzado el límite máximo de amigos.,Vous ne pouvez pas envoyer une demande d'ami car vous avez atteint votre limite maximale d'amis.,Non puoi inviare una richiesta di amicizia perché hai raggiunto il limite massimo di amici.,最大友達数に達したため友達リクエストが送れません。,최대 친구 목록이 초과되어 친구 요청을 보낼 수 없어요.,Você não pode enviar um pedido de amizade pois você alcançou o limite máximo de amigos.,Você não pode enviar um pedido de amizade pois você alcançou o limite máximo de amigos.,Вы не можете отправить запрос дружбы: количество ваших друзей достигло максимума.,由于你已达到好友数量上限,你无法发送好友请求。,您無法寄送交友請求,原因是您的朋友已達上限。 +,,,Friend Limit Reached,Max. Anzahl an Freunden erreicht,,Has alcanzado el límite de amigos,Has alcanzado el límite de amigos,Limite d'amis atteinte,Limiti di amici raggiunto,友達,친구 한도 도달,Limite de amigos alcançado,Limite de amigos alcançado,Достигнуто максимальное количество друзей,已达好友数量上限,已達朋友上限 +,,,Decline,Ablehnen,,Rechazar,Rechazar,Décliner,Declina,拒否する,거부,Recusar,Recusar,Отклонить,拒绝,拒絕 +,,,Account: 13+,Konto: 13+,,Cuenta: 13+,Cuenta: 13+,Compte : 13+,Account: più di 13 anni,アカウント:13+,계정: 만 13세 이상,Conta: 13+,Conta: 13+,Учетная запись: 13+,帐户:13+,帳戶:13+ +,,,Send Game Invites,Spieleinladungen senden,,Enviar invitaciones al juego,Enviar invitaciones al juego,Envoyer des invitations,Manda inviti di gioco,ゲームへの招待を送る,게임 초대 전송,Enviar convites,Enviar convites,Отправить приглашения,发送游戏邀请,傳送遊戲邀請 +,,,Safe Zone,Sichere Zone,,Zona segura,Zona segura,Zone sécurisée,Zona sicura,セーフゾーン,안전 구역,Zona de segurança,Zona de segurança,Безопасная зона,安全区,安全區 +,,,Adjust,Anpassen,,Ajustar,Ajustar,Ajuster,Modifica,調節,조정,Ajustar,Ajustar,Настроить,调整,調整 +,,,Joining server,Verbindung zum Server wird hergestellt,,Uniéndose al servidor...,Uniéndose al servidor...,Connexion au serveur...,Connessione al server,サーバーに接続中,서버 가입,Entrando no servidor,Entrando no servidor,Подключение к серверу,正在加入服务器,加入伺服器 +,,,Account: <13,Konto: <13,,Cuenta: <13,Cuenta: <13,Compte : <13,Account: <13,アカウント: <13,계정: 만 13세 미만,Conta: <13,Conta: <13,Учетная запись: <13,帐户:<13,帳戶:<13 +,,,Default (Classic),Standard (Klassisch),,Predeterminado (clásico),Predeterminado (clásico),Par défaut (Classique),Predefinita (Classica),デフォルト (クラッシック),기본값 (클래식),Padrão (clássico),Padrão (clássico),По умолчанию (классика),默认(经典),預設 (古典) +,,,Accept Friend Request,Freundschaftsanfrage akzeptieren,,Aceptar solicitud de amistad,Aceptar solicitud de amistad,Accepter l'invitation d'un ami,Accetta la richiesta di amicizia,友人のリクエストを受け入れる,친구 요청 수락,Aceitar solicitação de amizade,Aceitar solicitação de amizade,Принять запрос друга,接受好友请求,接受交友請求 +,,,Decline Friend Request,Freundschaftsanfrage ablehnen,,Rechazar solicitud de amistad,Rechazar solicitud de amistad,Refuser la demande d'ami,Declinare la richiesta di un amico,フレンドリクエストを拒否する,친구 요청 거부,Rejeitar pedido de amizade,Rejeitar pedido de amizade,Отклонить запрос друга,拒绝好友请求,拒絕交友請求 +,,,Developer Console,Entwicklerkonsole,,Consola de desarrollo,Consola de desarrollo,Console de développement,Console sviluppatore,デベロッパーコンソール,개발자 콘솔,Console de desenvolvimento,Console de desenvolvimento,Консоль разработчика,开发人员控制台,開發人員主機 +,,,Open,Öffnen,,Abrir,Abrir,Ouvert(e),Apri,開く,열기,Abrir,Abrir,Открыть,打开,開啟 +,,,Revoke Friend Request,Widerruf der Freundschaftsanfrage,,Revocar solicitud de amigo,Revocar solicitud de amigo,Révoquer une demande d'ami,Revoca richiesta amico,フレンドリクエストを取り消す,친구 요청 취소,Revocar pedido de amigo,Revocar pedido de amigo,Отменить запрос друга,撤销好友请求,撤銷交友請求 +,,,Screenshot Taken,Screenshot gespeichert,,Captura tomada,Captura tomada,Capture d'écran prise,Screenshot catturato,撮影したスクリーンショット,스크린샷 캡쳐 완료,Captura de tela salva,Captura de tela salva,Снимок экрана сделан,已截取屏幕快照,已拍螢幕畫面 +,,,Check out your screenshots folder to see it.,Sieh ihn dir im Ordner mit den Screenshots an.,,Puedes verla en la carpeta de capturas de pantalla.,Puedes verla en la carpeta de capturas de pantalla.,Ouvrez le dossier des captures d'écran pour la visualiser.,Vai nella cartella screenshot per vederlo.,確認するにはスクリーンショットフォルダをチェック。,확인하려면 스크린샷 폴더로 이동하세요.,Confira sua pasta de capturas de tela para vê-la.,Confira sua pasta de capturas de tela para vê-la.,"Откройте папку со снимками экрана, чтобы его увидеть.",请检查你的屏幕快照文件夹以查看。,請查閱您的擷圖資料夾以觀看。 +,,,Open Folder,Ordner öffnen,,Abrir carpeta,Abrir carpeta,Ouvrir le dossier,Apri cartella,フォルダを開く,폴더 열기,Abrir pasta,Abrir pasta,Открыть папку,打开文件夹,開啟資料夾 +,,,Video Recorded,Video aufgezeichnet,,Vídeo grabado,Vídeo grabado,Vidéo enregistrée,Video registrato,録画したビデオ,녹화한 비디오,Vídeo gravado,Vídeo gravado,Видео записано,视频已录制,已錄製影片 +,,,Default (Keyboard),Standard (Tastatur),,Predeterminado (teclado),Predeterminado (teclado),Par défaut (Clavier),Predefinita (Tastiera),デフォルト (キーボード),기본값 (키보드),Padrão (teclado),Padrão (teclado),По умолчанию (клавиатура),默认(键盘),預設 (鍵盤) +,,,Check out your videos folder to see it.,Sieh es dir im Ordner mit den Videos an.,,Puedes verlo en la carpeta de vídeos.,Puedes verlo en la carpeta de vídeos.,Ouvrez le dossier des vidéos pour la visualiser.,Vai nella cartella video per vederlo.,確認するにはビデオフォルダをチェック。,확인하려면 비디오 폴더로 이동하세요.,Confira sua pasta de vídeos para vê-lo.,Confira sua pasta de vídeos para vê-lo.,"Откройте папку с видеозаписями, чтобы его увидеть.",检查你的视频文件夹以查看。,請查看影片資料夾以觀看。 +,,,Thanks for your report! Our moderators will review the chat logs and evaluate what happened.,"Danke für deine Meldung! Unsere Moderatoren werden sich die Chatprotokolle ansehen und überprüfen, was vorgefallen ist.",,Gracias por denunciarlo. Nuestros moderadores comprobarán el registro del chat para analizar lo sucedido.,Gracias por denunciarlo. Nuestros moderadores comprobarán el registro del chat para analizar lo sucedido.,Merci pour ce signalement ! Nos modérateurs vont examiner le journal de chat et évaluer la situation.,Grazie della segnalazione! I moderatori controlleranno i registri della chat ed esamineranno l'accaduto.,ご報告ありがとうございます! モデレーターがチャットログから状況を確認致します。,신고해주셔서 감사합니다! 중재자가 채팅 기록을 검토하고 발생한 사항을 조사할 거예요.,Obrigado por sua denúncia! Nossos moderadores revisarão o histórico de chat e avaliarão o ocorrido.,Obrigado por sua denúncia! Nossos moderadores revisarão o histórico de chat e avaliarão o ocorrido.,"Спасибо за сообщение! Наши модераторы просмотрят журнал чата, чтобы оценить ситуацию.",感谢你的举报!我们的审查员将审阅聊天记录并进行评估。,感謝您的舉報!我們的仲裁者會檢視聊天記錄,評估發生的情形。 +,,,Thanks for your report! We've recorded your report for evaluation.,Danke für deine Meldung! Sie wurde zur Auswertung gespeichert.,,Gracias por denunciarlo. Hemos guardado la denuncia para analizar lo sucedido.,Gracias por denunciarlo. Hemos guardado la denuncia para analizar lo sucedido.,Merci pour ce signalement ! Nous l'avons bien pris en compte et allons l'examiner.,Grazie della segnalazione! La tua segnalazione è stata registrata per essere esaminata.,ご報告ありがとうございます! レポートは評価のため記録されました。,신고해주셔서 감사합니다! 평가를 위해 신고를 기록해두었어요.,Obrigado por sua denúncia! Registramos a sua denúncia para que seja avaliada.,Obrigado por sua denúncia! Registramos a sua denúncia para que seja avaliada.,Спасибо за сообщение! Оно будет рассмотрено.,感谢你的举报!我们已记录你的举报信息以进行评估。,感謝您的舉報!我們已記錄您的舉報以便評估。 +,,,Thanks for your report! Our moderators will evaluate the username.,Danke für deine Meldung! Unsere Moderatoren werden den Benutzernamen überprüfen.,,Gracias por denunciarlo. Nuestros moderadores analizarán el nombre de usuario.,Gracias por denunciarlo. Nuestros moderadores analizarán el nombre de usuario.,Merci pour ce signalement ! Nos modérateurs vont examiner le nom de cet utilisateur.,Grazie della segnalazione! I moderatori esamineranno il nome utente.,ご報告ありがとうございます! モデレーターが該当ユーザー名を確認致します。,신고해주셔서 감사합니다! 중재자가 사용자 이름을 조사할 거예요.,Obrigado por sua denúncia! Nossos moderadores avaliarão o nome de usuário.,Obrigado por sua denúncia! Nossos moderadores avaliarão o nome de usuário.,Спасибо за сообщение! Наши модераторы изучат поведение этого пользователя.,感谢你的举报!我们的审查员将对用户名进行评估。,感謝您的舉報!我們的仲裁者會評估此使用者名稱。 +,,,Thanks for your report! Our moderators will review the place and make a determination.,Danke für deine Meldung! Unsere Moderatoren werden sich den Ort ansehen und eine Entscheidung treffen.,,Gracias por denunciarlo. Nuestros moderadores analizarán el juego y tomarán una decisión.,Gracias por denunciarlo. Nuestros moderadores analizarán el juego y tomarán una decisión.,Merci pour ce signalement ! Nos modérateurs vont examiner le jeu avant de prendre une décision.,Grazie della segnalazione! I moderatori esamineranno il gioco e prenderanno una decisione.,ご報告ありがとうございます! モデレーターが場所を確認のうえ対応致します。,신고해주셔서 감사합니다! 중재자가 장소를 검토하고 결정을 내릴 거예요.,Obrigado por sua denúncia! Nossos moderadores verificarão o jogo e irão tomar uma decisão.,Obrigado por sua denúncia! Nossos moderadores verificarão o jogo e irão tomar uma decisão.,Спасибо за сообщение! Наши модераторы изучат это место и примут решение.,感谢你的举报!我们的审查员将查看该地点并进行评估。,感謝您的舉報!我們的仲裁者會檢視此地點並作出裁定。 +,,,Canceling...,Abbrechen ...,,Cancelando...,Cancelando...,Annulation...,Annullamento...,キャンセル中...,취소 중...,Cancelando...,Cancelando...,Отмена...,正在取消...,取消中... +,,,Memory,Speicher,,Memoria,Memoria,Mémoire,Memoria,メモリー,메모리,Memória,Memória,Память,内存,記憶體 +,,,Physics,Physik,,Física,Física,Physique,Fisica,物理エンジン,물리,Física,Física,Физика,物理,物理 +,,,Dev Console,Entwicklerkonsole,,Consola de desarrollo,Consola de desarrollo,Console de dév.,Console svilup.,Dev コンソール,개발자 콘솔,Console de dev.,Console de dev.,Консоль разработчика,开发控制台,開發主機 +,,,Camera Inverted,Kamera invertiert,,Cámara invertida,Cámara invertida,Caméra inversée,Macchina fotografica invertita,カメラの反転,카메라 반전,Câmera Invertida,Câmera Invertida,Перевернутая камера,镜头反转,攝影機反轉 +,,,Don't Leave,Nicht verlassen,,No salir,No salir,Ne pas quitter,Non uscire,やめない,나가지 않기,Não sair,Não sair,Не выходить,不要离开,勿離開 +,,,Don't Reset,Nicht zurücksetzen,,No reiniciar,No reiniciar,Ne pas réinitialiser,Non azzerare,リセットしない,재설정 안 하기,Não reiniciar,Não reiniciar,Не сбрасывать,不要重置,勿重設 +,,,Drop Tool,Werkzeug ablegen,,Soltar herramienta,Soltar herramienta,Lâcher outil,Lascia strumento,ドロップツール,도구 드롭,Largar,Largar,Выбросить инструм.,丢弃工具,投放工具 +,,,ESC,ESC,,ESC,ESC,ÉCHAP,ESC,ESC,ESC,ESC,ESC,ESC,ESC,ESC 鍵 +,,,Equip Tools,Werkzeuge aktivieren,,Equipar herramientas,Equipar herramientas,Prendre outils,Equipaggia strum.,ツールを装備する,도구 장착,Equipar,Equipar,Назначить инструм.,配备工具,配備工具 +,,,Follow,Folgen,,Seguir,Seguir,Suivre,Segui,フォロー,팔로우,Seguir,Seguir,Слежение,跟随,追蹤鏡頭 +,,,Fullscreen,Vollbild,,Pantalla completa,Pantalla completa,Plein écran,Schermo intero,フルスクリーン,전체 화면,Tela cheia,Tela cheia,Полный экран,全屏,全螢幕 +,,,GPU,GPU,,GPU,GPU,Processeur Graphique,GPU,GPU,GPU,GPU,GPU,Графический процессор,GPU,圖形處理器 (GPU) +,,,Game,Spiel,,Juego,Juego,Jeu,Gioco,ゲーム,게임,Jogo,Jogo,Игра,游戏,遊戲 +,,,Game or Player?,Spiel oder Spieler?,,¿Juego o jugador?,¿Juego o jugador?,Jeu ou joueur ?,Gioco o giocatore?,ゲームですかプレーヤーですか?,게임 혹은 플레이어?,Jogo ou jogador?,Jogo ou jogador?,Игра или игрок?,游戏或玩家?,遊戲或玩家? +,,,Goodbye!,Tschüss!,,¡Hasta luego!,¡Hasta luego!,Au revoir !,Addio!,さようなら!,안녕히 가세요!,Tchau!,Tchau!,До свидания!,再见!,再會! +,,,Graphics Level,Grafikstufe,,Nivel de gráficos,Nivel de gráficos,Niveau graphismes,Livello grafica,グラフィックレベル,그래픽 수준,Nível dos gráficos,Nível dos gráficos,Уровень графики,图形级别,圖形層級 +,,,Graphics Mode,Grafikmodus,,Modo de gráficos,Modo de gráficos,Mode graphismes,Modalità grafica,グラフィックモード,그래픽 모드,Modo de gráficos,Modo de gráficos,Режим графики,图形模式,圖形模式 +,,,Graphics Quality,Grafikqualität,,Calidad gráfica,Calidad gráfica,Qualité graphismes,Qualità grafica,グラフィック品質,그래픽 품질,Qualidade dos gráficos,Qualidade dos gráficos,Качество графики,图形画质,圖形畫質 +,,,Help,Hilfe,,Ayuda,Ayuda,Aide,Guida,ヘルプ,도움말,Ajuda,Ajuda,Справка,帮助,說明 +,,,Inappropriate Content,Unangemessener Inhalt,,Contenido inadecuado,Contenido inadecuado,Contenu inapproprié,Contenuto non appropriato,不適切なコンテンツ,부적절한 콘텐츠,Conteúdo inapropriado,Conteúdo inapropriado,Недопустимое содержимое,内容不当,內容不當 +,,,Inappropriate Username,Unangemessener Benutzername,,Nombre de usuario inadecuado,Nombre de usuario inadecuado,Nom d'utilisateur inapproprié,Nome utente non appropriato,不適切なユーザ名,부적절한 사용자 이름,Nome de usuário inapropriado,Nome de usuário inapropriado,Недопустимое имя пользователя,用户名不当,使用者名稱不當 +,,,Jump,Springen,,Saltar,Saltar,Sauter,Salta,ジャンプ,점프,Pular,Pular,Прыжок,跳跃,跳起 +,,,KOs,K.o.,,N.º de KO,N.º de KO,Ko,KO,KO回数,KO,Nocautes,Nocautes,Нокауты,击倒数,擊倒數 +,,,Keyboard + Mouse,Tastatur + Maus,,Teclado + ratón,Teclado + ratón,Clavier + souris,Tastiera e mouse,キーボード+ マウス,키보드 + 마우스,Teclado + mouse,Teclado + mouse,Клавиатура + мышь,键盘+鼠标,鍵盤 + 滑鼠 +,,,"1,2,3...","1,2,3...",,"1,2,3...","1,2,3...","1, 2, 3...","1, 2, 3...","1,2,3...","1,2,3...","1,2,3...","1,2,3...","1,2,3...","1,2,3...",1、2、3...... +,,,Label,Label,,Etiqueta,Etiqueta,Étiquette,Etichetta,ラベル,레이블,Rótulo,Rótulo,Метка,标签,標籤 +,,,Leave,Verlassen,,Salir,Salir,Quitter,Esci,やめる,나가기,Sair,Sair,Выйти,离开,離開 +,,,Leave Game,Spiel verlassen,,Salir del juego,Salir del juego,Quitter le jeu,Esci dal gioco,ゲームをやめる,게임 종료,Sair do jogo,Sair do jogo,Выйти из игры,离开游戏,離開遊戲 +,,,Left Mouse Button,Linke Maustaste,,Botón izquierdo del ratón,Botón izquierdo del ratón,Bouton gauche de la souris,Sinistro/Mouse,左マウスボタン,마우스 왼쪽 버튼,Mouse (esquerdo),Mouse (esquerdo),ЛКМ,鼠标左键,左滑鼠鍵 +,,,Loading,Laden,,Cargando,Cargando,En cours,Caricamento,ロード中,로드 중,Carregando,Carregando,Загрузка,正在载入,正在載入 +,,,Loading.,Laden.,,Cargando.,Cargando.,En cours.,Caricamento.,ロード中.,로드 중.,Carregando.,Carregando.,Загрузка,正在载入。,正在載入. +,,,Loading..,Laden ...,,Cargando..,Cargando..,En cours..,Caricamento..,ロード中..,로드 중..,Carregando..,Carregando..,Загрузка,正在载入..,正在載入.. +,,,Loading...,Laden ...,,Cargando...,Cargando...,En cours...,Caricam...,ロード中...,로드 중...,Carregando...,Carregando...,Загрузка,正在载入...,正在載入... +,,,Manual,Manuell,,Manual,Manual,Manuel,Manuale,マニュアル,수동,Manual,Manual,Вручную,手动,手動 +,,,Mem,Speicher,,Mem.,Mem.,Mém,Mem,メモリー,메모리,Mem.,Mem.,Память,内存,記憶體 +,,,A/Left Arrow,A/Linkspfeil,,A/Cursor izquierdo,A/Cursor izquierdo,A/Flèche gauche,A/Freccia SINISTRA,A/左カーソル,A/왼쪽 화살표,A/seta esquerda,A/seta esquerda,A/стрелка влево,A/左箭头,A 鍵 / 向左箭號 +,,,Menu Items,Menüobjekte,,Objetos del menú,Objetos del menú,Objets du menu,Oggetti menu,メニューアイテム,메뉴 아이템,Itens de menu,Itens de menu,Пункты меню,菜单项目,選單項目 +,,,Misc,Verschiedenes,,Misc.,Misc.,Divers,Vari,その他,기타,Misc.,Diversos,Разное,杂项,雜項 +,,,Mouse Sensitivity,Mausempfindlichkeit,,Sensibilidad del ratón,Sensibilidad del ratón,Sensibilité de la souris,Precisione mouse,マウス感度,마우스 감도,Sensibilidade do mouse,Sensibilidade do mouse,Чувствительность мыши,鼠标灵敏度,滑鼠靈敏度 +,,,Mouse Wheel,Mausrad,,Rueda del ratón,Rueda del ratón,Molette de la souris,Rotellina mouse,マウスホイール,마우스 휠,Roda do mouse,Roda do mouse,Колесо мыши,鼠标滚轮,滑鼠滾輪 +,,,Mouselock,Maussperre,,Bloqueo del ratón,Bloqueo del ratón,Verrouillage souris,Blocco mouse,マウスロック,마우스 잠금,Travar mouse,Travar mouse,Фиксация мыши,鼠标锁定,滑鼠鎖定 +,,,Move Backward,Rückwärts bewegen,,Moverse hacia atrás,Moverse hacia atrás,Reculer,Muovi indietro,後ろに移動,뒤로 이동,Mover (trás),Mover (trás),Назад,后退,倒退 +,,,Move Forward,Vorwärts bewegen,,Moverse hacia delante,Moverse hacia delante,Avancer,Muovi in avanti,前に移動,앞으로 이동,Mover (frente),Mover (frente),Вперед,向前,往前 +,,,Move Left,Nach links bewegen,,Moverse a la izquierda,Moverse a la izquierda,Aller à gauche,Muovi a sinistra,左に移動,왼쪽으로 이동,Mover (esquerda),Mover (esquerda),Влево,左移,左移 +,,,Move Right,Nach rechts bewegen,,Moverse a la derecha,Moverse a la derecha,Aller à droite,Muovi a destra,右に移動,오른쪽으로 이동,Mover (direita),Mover (direita),Вправо,右移,右移 +,,,Movement Mode,Bewegungsmodus,,Modo de movimiento,Modo de movimiento,Mode déplacement,Modalità movimento,動作モード,이동 모드,Modo de movimento,Modo de movimento,Режим передвижения,移动模式,移動模式 +,,,Accept,Annehmen,,Aceptar,Aceptar,Accepter,Accetta,同意する,수락,Aceitar,Aceitar,Принять,接受,接受 +,,,OK,Okay,,Aceptar,Aceptar,Ok,OK,OK,확인,OK,OK,OK,好,確定 +,,,Off,Aus,,Desactivado,Desactivado,Arrêt,Disattivato,Off,끔,Desligado,Desligado,Выкл.,关闭,關閉 +,,,Offsite Links,Externe Links,,Enlaces externos,Enlaces externos,Liens hors site,Collegamenti ad altri siti,外部リンク,외부 링크,Links externos,Links externos,Внешние ссылки,离线链接,異地連結 +,,,On,An,,Activado,Activado,Marche,Attivato,On,켬,Ligado,Ligado,Вкл.,开启,開啟 +,,,Perf. Stats,Leistungsw.,,Est. de rend.,Est. de rend.,Stats perf.,Stat. prest.,パフォーマンス状態,성능 상태,Estat. Des.,Estat. Des.,Показатели произ.,表现统计,表現統計 +,,,Performance Stats,Leistungswerte,,Estadísticas de rendimiento,Estadísticas de rendimiento,Stats de performance,Statistiche prestazioni,パフォーマンス状態,성능 상태,Estat. de desempenho,Estat. de desempenho,Показатели производительности,表现统计,表現統計 +,,,Personal Question,Persönliche Frage,,Pregunta personal,Pregunta personal,Question personnelle,Domanda personale,個人的な質問,개인 질문,Pergunta pessoal,Pergunta pessoal,Личный вопрос,私人问题,個人問題 +,,,Phys,Phys.,,Fís.,Fís.,Phys.,Fisico,物理,물리,Fís.,Fís.,Физ.,物理,物理 +,,,Player,Spieler,,Jugador,Jugador,Joueur,Giocatore,プレーヤー,플레이어,Jogador,Jogador,Игрок,玩家,玩家 +,,,Playerlist,Spielerliste,,Jugadores,Jugadores,Liste de joueurs,Lista giocatori,プレーヤーリスト,플레이어 목록,Jogadores,Jogadores,Список игроков,玩家名单,玩家名單 +,,,Accessories,Accessoires,,Accesorios,Accesorios,Accessoires,Accessori,アクセサリ,액세서리,Acessórios,Acessórios,Аксессуары,配饰,配件 +,,,Players,Spieler,,Jugadores,Jugadores,Joueurs,Giocatori,プレーヤー,플레이어,Jogadores,Jogadores,Игроки,玩家,玩家 +,,,Print Screen,Drucktaste,,Imprimir pantalla,Imprimir pantalla,Impression écran,STAMP,画面プリント,화면 캡쳐,Print screen,Captura de Tela,Print Screen,屏幕截图,PrtSc 鍵 +,,,Purchasing,Wird gekauft ...,,Compras,Compras,Achat,Acquisto,購入,구매 중,Comprando,Comprando,Покупка,正在购买,正在購買 +,,,Record,Aufnehmen,,Grabar,Grabar,Enregistrer,Registra,録画,녹화,Gravar,Gravar,Запись,录制,錄影 +,,,Record Video,Video aufnehmen,,Grabar vídeo,Grabar vídeo,Enregistrer vidéo,Registra video,ビデオ録画,비디오 녹화,Gravar vídeo,Gravar vídeo,Запись видео,录制视频,錄製影片 +,,,Recv,Empfangen,,Recib.,Recib.,Reçu,Ricev.,受信,받음,Receb.,Receb.,Получ.,收到,收到 +,,,Report,Melden,,Denunciar,Denunciar,Signaler,Segnala,レポート,신고,Denunciar,Denunciar,Сообщить,举报,舉報 +,,,Requesting Server...,Serveranfrage ...,,Solicitando servidor...,Solicitando servidor...,Demande serveur...,Richiesta server...,サーバーを要求...,서버 요청 중...,Solicitando servidor...,Solicitando servidor...,Запрос сервера...,正在向服务器发送请求...,正在要求伺服器... +,,,Reset,Zurücksetzen,,Reiniciar,Reiniciar,Réinitialiser,Azzera,リセット,재설정,Reiniciar,Reiniciar,Сброс,重置,重設 +,,,Resume Game,Spiel fortsetzen,,Seguir jugando,Seguir jugando,Reprendre le jeu,Riprendi gioco,ゲームを再開,게임 계속 진행,Continuar jogo,Continuar jogo,Возобновить,继续游戏,繼續遊戲 +,,,Stop Recording,Aufnahme beenden,,Detener grabación,Detener grabación,Arrêter l'enregistrement,Interrompi registrazione,録画を停止する,녹화 중지,Parar gravação,Parar gravação,Остановить запись,停止录音,停止錄製 +,,,Camera Sensitivity,Kameraempfindlichkeit,,Sensibilidad de la cámara,Sensibilidad de la cámara,Sensibilité de la caméra,Precisione telecamera,カメラ感度,카메라 민감도,Sensitividade da câmera,Sensitividade da câmera,Чувствительность камеры,相机敏感度,鏡頭靈敏度 +,,,Dynamic Thumbstick,Dynamischer Thumbstick,,Stick dinámico,Stick dinámico,Joystick dynamique,Levetta dinamica,ダイナミックサムスティック,다이내믹 엄지스틱,Thumbstick Dinâmico,Thumbstick Dinâmico,Динамический аналоговый стик,动态摇杆,動態拇指搖桿 +,,,"Developer has shut down all game servers or game server has shut down for other reasons, please reconnect",Der Entwickler hat alle Spielserver abgeschaltet oder die Verbindung zum Spielserver wurde aus anderen Gründen unterbrochen. Bitte erneut verbinden.,,El desarrollador ha cerrado todos los servidores del juego o el servidor del juego se ha cerrado por otras razones. Conéctate de nuevo.,El desarrollador ha cerrado todos los servidores del juego o el servidor del juego se ha cerrado por otras razones. Conéctate de nuevo.,"Le développeur a arrêté tous les serveurs du jeu, ou le serveur s'est arrêté pour d'autres raisons. Veuillez vous reconnecter.",Gli sviluppatori hanno chiuso tutti i server di gioco o il server si è chiuso per altri motivi. È necessario riconnettersi,ディベロッパーがすべてのゲームサーバーをシャットダウンしたか、他の理由でをシャットダウンしたようです。再接続してください,"개발자가 모든 게임 서버를 닫았거나, 다른 이유로 인해 게임 서버가 닫혔어요. 다시 연결하세요.",O desenvolvedor encerrou todos os servidores do jogo ou o servidor do jogo foi encerrado por outros motivos. Conecte-se novamente.,O desenvolvedor encerrou todos os servidores do jogo ou o servidor do jogo foi encerrado por outros motivos. Conecte-se novamente.,"Разработчик отключил все сервера игры или они не работают по какой-либо другой причине. Пожалуйста, установите соединение повторно.",开发人员已经关闭所有游戏服务器,或由于其他原因服务器已关闭,请重新连接,開發商已關閉所有遊戲伺服器,或因其他理由而關閉,請重新連接 +,,,Disconnected due to a bad hash,Verbindung aufgrund eines fehlerhaften Hashs unterbrochen,,Desconexión por un error de hash,Desconexión por un error de hash,Vous avez été déconnecté(e) en raison d'un mauvais hachage.,Disconnessione a causa di un cattivo funzionamento dell'hash,ハッシュが正しくないためコネクションが切断されました,잘못된 해시로 인해 연결 끊어짐,Desconexão devido a um erro de hash,Desconexão devido a um erro de hash,Соединение прервано из-за ошибок хеширования.,由于错误的哈希码,连接中断,因雜湊值不佳而斷線 +,,,Disconnected due to Security Key Mismatch,Verbindung aufgrund einer Sicherheitsschlüssel-Diskrepanz unterbrochen,,Desconexión por incompatibilidad de la clave de seguridad,Desconexión por incompatibilidad de la clave de seguridad,"Vous avez été déconnecté(e), car la clé de sécurité ne correspond pas.",Disconnessione a causa di una mancata corrispondenza della chiave di sicurezza,セキュリティキーの不一致によりコネクションが切断されました,보안 키 불일치로 인해 연결 끊어짐,Desconexão devido à incompatibilidade da Chave de Segurança,Desconexão devido à incompatibilidade da Chave de Segurança,Соединение прервано из-за несовпадения ключей безопасности.,由于安全密钥不匹配,连接中断,因安全性金鑰不符而斷線 +,,,Disconnected due to Security Key Mismatch,Verbindung aufgrund einer Sicherheitsschlüssel-Diskrepanz unterbrochen,,Desconexión por incompatibilidad de la clave de seguridad,Desconexión por incompatibilidad de la clave de seguridad,"Vous avez été déconnecté(e), car la clé de sécurité ne correspond pas.",Disconnessione a causa di una mancata corrispondenza della chiave di sicurezza,セキュリティキーの不一致によりコネクションが切断されました,보안 키 불일치로 인해 연결 끊어짐,Desconexão devido à incompatibilidade da Chave de Segurança,Desconexão devido à incompatibilidade da Chave de Segurança,Соединение прервано из-за несовпадения ключей безопасности.,由于安全密钥不匹配,连接中断,因安全性金鑰不符而斷線 +,,,"Protocol mismatch, please reconnect",Protokoll-Diskrepanz. Bitte erneut verbinden.,,Incompatibilidad del protocolo. Conéctate de nuevo.,Incompatibilidad del protocolo. Conéctate de nuevo.,"Le protocole ne correspond pas, veuillez vous reconnecter.",Mancata corrispondenza del protocollo; è necessario riconnettersi,プロトコルの不一致です。再接続してください,프로토콜이 일치하지 않아요. 다시 연결하세요.,Incompatibilidade do Protocolo. Conecte-se novamente.,Incompatibilidade do Protocolo. Conecte-se novamente.,"Несовпадение протокола, пожалуйста, установите соединение повторно.",协议不匹配,请重新连接,通訊協定不符,請重新連接 +,,,"Error while receiving data, please reconnect",Fehler beim Datenempfang. Bitte erneut verbinden,,Error al recibir los datos. Conéctate de nuevo.,Error al recibir los datos. Conéctate de nuevo.,"Erreur lors de la réception des données, veuillez vous reconnecter.",Errore di ricezione dei dati; è necessario riconnettersi,データを受信中にエラーが発生しました。再接続してください,데이터 수신 중 오류가 발생했어요. 다시 연결하세요.,Erro ao receber os dados. Conecte-se novamente.,Erro ao receber os dados. Conecte-se novamente.,"Ошибка при получении данных, пожалуйста, установите соединение повторно.",接收数据时出错,请重新连接,接收資料時發生錯誤,請重新連接 +,,,"Error while streaming data, please reconnect",Fehler bei der Datenübertragung. Bitte erneut verbinden.,,Error al transmitir los datos. Conéctate de nuevo.,Error al transmitir los datos. Conéctate de nuevo.,"Erreur lors de la diffusion des données, veuillez vous reconnecter.",Errore durante lo streaming dei dati; è necessario riconnettersi,データをストリーミング中にエラーが発生しました。再接続してください,데이터 스트리밍 중 오류가 발생했어요. 다시 연결하세요.,Erro ao transmitir os dados. Conecte-se novamente.,Erro ao transmitir os dados. Conecte-se novamente.,"Ошибка при передаче данных, пожалуйста, установите соединение повторно.",流式处理数据时出错,请重新连接,串流資料時發生錯誤,請重新連接 +,,,"Error while sending data, please reconnect",Fehler beim Senden der Daten. Bitte erneut verbinden.,,Error al enviar los datos. Conéctate de nuevo.,Error al enviar los datos. Conéctate de nuevo.,"Erreur lors de l'envoi des données, veuillez vous reconnecter.",Errore durante l'invio dei dati; è necessario riconnettersi,データを送信中にエラーが発生しました。再接続してください,데이터 전송 중 오류가 발생했어요. 다시 연결하세요.,Erro ao enviar os dados. Conecte-se novamente.,Erro ao enviar os dados. Conecte-se novamente.,"Ошибка при отправке данных, пожалуйста, установите соединение повторно.",发送数据时出错,请重新连接,傳送資料時發生錯誤,請重新連接 +,,,Invalid teleport destination,Ungültiger Teleport-Bestimmungsort,,Destino del teleport no válido,Destino del teleport no válido,Destination de téléportation non valide.,Destinazione del teletrasporto non valida,テレポートの移動先が無効です,잘못된 텔레포트 목적지,Destino de teleport inválido,Destino de teleport inválido,Некорректное назначение телепортирования.,传送目的地无效,無效的傳輸目的地 +,,,You are already playing a game. Please shut down the other game and try again,Du spielst bereits ein Spiel. Bitte brich das andere Spiel ab und versuche es erneut.,,Ya estás jugando a un juego. Cierra el otro juego e inténtalo de nuevo.,Ya estás jugando a un juego. Cierra el otro juego e inténtalo de nuevo.,"Vous êtes déjà dans un jeu. Veuillez le quitter, puis réessayez.",Stai già giocando a un gioco. Chiudi l'altro gioco e riprova,既にゲームをプレイ中です。ゲームを終了してもう一度試してください,게임을 플레이 중에요. 다른 게임을 닫고 다시 시도하세요.,Você já está jogando um jogo. Saia do jogo atual e tente novamente.,Você já está jogando um jogo. Saia do jogo atual e tente novamente.,"У вас уже запущена игра. Пожалуйста, закройте ее и попробуйте еще раз.",你已经在游戏中。请关闭其他游戏并重试,您已經在一場遊戲中。請關閉那場遊戲,然後再試一次 +,,,"Error processing ticket, please reconnect",Fehler bei der Ticketbearbeitung. Bitte erneut verbinden.,,Error al procesar un tique. Conéctate de nuevo.,Error al procesar un tique. Conéctate de nuevo.,"Erreur lors du traitement du ticket, veuillez vous reconnecter.",Errore di elaborazione della richiesta; è necessario riconnettersi,チケットの処理中にエラーが発生しました。再接続してください,티켓 처리 중 오류가 발생했어요. 다시 연결하세요.,Erro ao processar o tíquete. Conecte-se novamente.,Erro ao processar o tíquete. Conecte-se novamente.,"Сообщение об ошибке процесса, пожалуйста, установите соединение повторно.",处理票单时出错,请重新连接,處理票券時發生錯誤,請重新連接 +,,,Lost connection to server due to timeout,Die Verbindung zum Server wurde aufgrund einer Zeitüberschreitung unterbrochen.,,Se ha perdido la conexión con el servidor por agotamiento del tiempo de espera,Se ha perdido la conexión con el servidor por agotamiento del tiempo de espera,Connexion au serveur perdue ; la session a expiré.,Connessione persa con il server per un errore di time-out,タイムアウトでサーバーへの接続が失われました,시간 초과로 인해 연결 해제됨,A conexão com o servidor foi perdida pois o limite de tempo de espera foi atingido,A conexão com o servidor foi perdida pois o limite de tempo de espera foi atingido,Разрыв соединения с сервером из-за превышения времени ожидания.,由于超时,与服务器的连接已断开,因連線逾時,與伺服器失去連線 +,,,You have been kicked from the game,Du wurdest aus dem Spiel geworfen,,Se te ha expulsado del juego,Se te ha expulsado del juego,Vous avez été expulsé(e) du jeu.,Sei stato espulso dal gioco,ゲームからキックされました,게임에서 추방되었어요.,Você foi expulso do jogo,Você foi expulso do jogo,Вас исключили из игры.,你已被游戏踢出,您已被遊戲踢出 +,,,Kicked by server. Please close and rejoin another game,Vom Sever rausgeworfen. Bitte schließen und einem anderen Spiel beitreten.,,Expulsado del servidor. Cierra el juego y únete a otro.,Expulsado del servidor. Cierra el juego y únete a otro.,Le serveur vous a expulsé(e). Veuillez quitter le jeu et rejoindre une autre partie.,Espulso dal server. Chiudi e ricomincia una nuova partita,ゲームからキックされました。終了して別のゲームに参加してください,서버에서 추방되었어요. 게임을 닫은 후 다른 게임에 다시 참여하세요.,Você foi expulso pelo servidor. Feche a tela e entre em outro jogo.,Você foi expulso pelo servidor. Feche a tela e entre em outro jogo.,"Вы были исключены сервером. Пожалуйста, закройте игру и зайдите снова.",已被服务器踢出。请关闭并重新加入其他游戏,被伺服器踢出。請關閉並重新加入另一場遊戲 +,,,"Disconnected due to timeout, please reconnect",Aufgrund einer Zeitüberschreitung unterbrochen. Bitte erneut verbinden.,,Desconexión por agotamiento del tiempo de espera. Conéctate de nuevo.,Desconexión por agotamiento del tiempo de espera. Conéctate de nuevo.,"Vous avez été déconnecté(e), car votre session a expiré. Veuillez vous reconnecter.",Disconnessione a causa del time-out; è necessario riconnettersi,タイムアウトにより接続が失われました。再接続してください,시간 초과로 인해 연결이 끊어졌어요. 다시 연결하세요.,Desconexão devido ao limite de tempo de espera ter sido atingido. Conecte-se novamente.,Desconexão devido ao limite de tempo de espera ter sido atingido. Conecte-se novamente.,"Разрыв соединения из-за превышения времени ожидания, пожалуйста, установите соединение повторно.",由于超时,连接已断开。请重新连接,因連線逾時而斷線,請重新連接 +,,,"You have been disconnection from Team Create, please reconnect",Verbindung zu Team Create wurde unterbrochen. Bitte erneut verbinden.,,Te has desconectado del Team Create. Conéctate de nuevo.,Te has desconectado del Team Create. Conéctate de nuevo.,Vous avez été déconnecté(e) de la création d'équipe. Veuillez vous reconnecter.,Sei stato disconnesso dalla creazione della squadra; è necessario riconnettersi,Team Createとの接続が切断されました。再接続してください,Team Create 연결이 끊어졌어요. 다시 연결하세요.,Você foi desconectado do Team Create. Conecte-se novamente.,Você foi desconectado do Team Create. Conecte-se novamente.,"Соединение с командой создателей было прервано, пожалуйста, установите соединение повторно.",你已断开与团队开发的连接,请重新连接,您已從「建立隊伍」斷線,請重新連接 +,,,Server was shutdown due to no active players,"Der Server wurde abgeschaltet, weil keine aktiven Spieler vorhanden waren",,Se ha cerrado el servidor por inactividad de los jugadores,Se ha cerrado el servidor por inactividad de los jugadores,"Le serveur a été fermé, car aucun joueur n'était actif.",Il server è stato chiuso per mancanza di giocatori attivi,アクティブなプレイヤーがいないため、サーバーはシャットダウンされました,활성화된 플레이어가 없어 서버가 닫힘,O servidor foi encerrado pois não há jogadores ativos,O servidor foi encerrado pois não há jogadores ativos,Сервер был отключен из-за отсутствия игроков.,由于没有活跃玩家,服务器关闭,因無玩家上線,伺服器已關閉 +,,,"Disconnected from game, possibly due to game joined from another device",Verbindung zum Spiel wurde unterbochen. Möglicher Grund: Spielbeitritt von einem anderen Gerät.,,"Desconectado del juego, posiblemente por conectarse al juego desde otro dispositivo.","Desconectado del juego, posiblemente por conectarse al juego desde otro dispositivo.",Vous avez été déconnecté(e) du jeu ; il se peut que vous ayez rejoint le jeu depuis un autre appareil.,Sei stato disconnesso dal gioco forse perché hai giocato una partita con un altro dispositivo,他のデバイスから参加したゲームのために、ゲームへの接続から切断された可能性があります,게임 연결이 끊어졌어요. 다른 장치에서 게임에 참여했을 가능성이 있어요.,"Você foi desconectado do jogo, provavelmente porque entrou em um jogo através de outro dispositivo","Você foi desconectado do jogo, provavelmente porque entrou em um jogo através de outro dispositivo","Соединение с игрой прервано, возможно, из-за подключения к игре с другого устройства.",已断开与游戏的连接,可能是由于该游戏同时从另一个设备加入,已從遊戲斷線,可能是因從另一裝置加入遊戲而導致的 +,,,Developer has shut down this game server for maintenance,Der Entwickler hat diesen Spielserver aufgrund von Wartungsarbeiten abgeschaltet,,El desarrollador ha cerrado el servidor de este juego por mantenimiento,El desarrollador ha cerrado el servidor de este juego por mantenimiento,Le développeur a arrêté ce serveur de jeu pour effectuer la maintenance.,Lo sviluppatore ha chiuso questo server di gioco per manutenzione,メンテナンスのため、ディベロッパーによってゲームサーバーがシャットダウンされています。,개발자가 점검을 위해 이 게임 서버를 닫았어요.,O servidor deste jogo foi encerrado pelo desenvolvedor para manutenção,O servidor deste jogo foi encerrado pelo desenvolvedor para manutenção,Разработчик отключил игровой сервер для техобслуживания.,维护期间,开发人员已关闭此游戏服务器,為進行維護,開發商已關閉此遊戲伺服器 +,,,Roblox has shut down this game server for maintenance,Roblox hat diesen Spielserver aufgrund von Wartungsarbeiten abgeschaltet,,Roblox ha cerrado el servidor de este juego por mantenimiento,Roblox ha cerrado el servidor de este juego por mantenimiento,Roblox a arrêté ce serveur de jeu pour effectuer la maintenance.,Roblox ha chiuso questo server di gioco per manutenzione,メンテナンスのため、Roblox によってゲームサーバーがシャットダウンされています。,Roblox가 점검을 위해 이 게임 서버를 닫았어요.,O servidor deste jogo foi encerrado pelo Roblox para manutenção,O servidor deste jogo foi encerrado pelo Roblox para manutenção,Roblox отключил игровой сервер для техобслуживания.,维护期间,Roblox 已关闭此游戏服务器,為進行維護,Roblox已關閉此遊戲伺服器 +,,,This game has been disconnected because you have joined a game from another device,"Dieses Spiel wurde unterbrochen, weil du einem Spiel von einem anderen Gerät beigetreten bist",,Se ha desconectado este juego porque te has unido a un juego desde otro dispositivo,Se ha desconectado este juego porque te has unido a un juego desde otro dispositivo,"Vous avez été déconnecté(e) de ce jeu, car vous en avez rejoint un autre depuis un appareil différent.",Questo gioco è stato disconnesso perché hai giocato una partita con un altro dispositivo,別のデバイスからゲームに参加したため、このゲームへの接続が切断されました,다른 장치에서 게임에 참여하여 이 게임의 연결이 끊어졌어요.,Este jogo foi desconectado pois você entrou em um jogo através de outro dispositivo,Este jogo foi desconectado pois você entrou em um jogo através de outro dispositivo,"Соединение с этой игрой было прервано, так как вы стали играть с другого устройства.",由于你从另一设备加入游戏,此游戏已断开连接,因您從另一裝置加入了一場遊戲,因此此遊戲已斷線 +,,,"Disconnected from game, please reconnect",Verbindung zum Spiel unterbrochen. Bitte erneut verbinden.,,Desconectado del juego. Conéctate de nuevo.,Desconectado del juego. Conéctate de nuevo.,Vous avez été déconnecté(e) du jeu. Veuillez vous reconnecter.,Disconnesso dal gioco; è necessario riconnettersi,ゲームへの接続が切断されました。再接続してください,게임 연결이 끊어졌어요. 다시 연결하세요.,Você foi desconectado do jogo. Conecte-se novamente.,Você foi desconectado do jogo. Conecte-se novamente.,"Соединение и игрой прервано, пожалуйста, установите соединение повторно.",与游戏连接已断开,请重新连接,已從遊戲斷線,請重新連接 +,,,Waiting for an available server,Warten auf verfügbaren Server,,Esperando un servidor disponible,Esperando un servidor disponible,En attente d'un serveur disponible,In attesa di un server disponibile,使用可能なサーバを待機中,이용 가능한 서버를 기다리는 중,Aguardando um servidor disponível,Aguardando um servidor disponível,Ожидание доступного сервера,正在等待可用服务器,正在等候可用伺服器 +,,,"Server found, loading...","Server gefunden, wird geladen ...",,Servidor encontrado. Cargando...,Servidor encontrado. Cargando...,"Serveur trouvé, chargement en cours...","Server trovato, caricamento...",サーバが見つかりました、ロード中です...,"서버 발견, 로드 중...","Servidor encontrado, carregando...","Servidor encontrado, carregando...",Сервер найден. Загрузка...,找到服务器,正在加载...,找到伺服器,載入中… +,,,Joining server,Verbindung zum Server wird hergestellt,,Uniéndose a un servidor,Uniéndose a un servidor,Connexion au serveur...,Connessione al server,サーバーに接続中,서버 가입,Entrando no servidor,Entrando no servidor,Подключение к серверу,正在加入服务器,加入伺服器 +,,,This game is disabled,Dieses Spiel wurde deaktiviert,,Este juego está desactivado,Este juego está desactivado,Ce jeu est désactivé.,Questo gioco è stato disattivato,このゲームは無効です,이 게임은 비활성화되었어요.,Este jogo está desabilitado,Este jogo está desabilitado,Эта игра отключена,游戏已禁用,此遊戲已停用 +,,,Cannot find game server,Spielserver kann nicht gefunden werden,,No se ha encontrado el servidor del juego,No se ha encontrado el servidor del juego,Serveur de jeu introuvable.,Impossibile trovare il server di gioco,ゲームサーバーが見つかりません,게임 서버를 찾을 수 없음,Não foi possível encontrar o servidor do jogo,Não foi possível encontrar o servidor do jogo,Не могу найти игровой сервер,无法找到游戏服务器,無法找到遊戲伺服器 +,,,This game has ended,Dieses Spiel ist beendet,,Este juego ha finalizado,Este juego ha finalizado,Cette partie est terminée.,Questo gioco è stato chiuso,このゲームは終了しました,이 게임은 종료되었어요.,Este jogo acabou,Este jogo acabou,Эта игра закончена,此游戏已结束,此遊戲已結束 +,,,Requested game is full,Das angefragte Spiel ist voll,,El juego solicitado está lleno,El juego solicitado está lleno,La partie demandée est complète.,Il gioco richiesto è al completo,リクエストしたゲームは満員です。,요청한 게임이 가득 찼어요.,O jogo solicitado está cheio,O jogo solicitado está cheio,Запрашиваемая игра переполнена,请求的游戏已满员,要求的遊戲已滿 +,,,Followed user has left the game,"Der Benutzer, dem du folgst, hat das Spiel verlassen",,El usuario al que sigues ha abandonado el juego,El usuario al que sigues ha abandonado el juego,L'utilisateur que vous suiviez a quitté la partie.,L'utente seguito ha abbandonato il gioco,フォローしたユーザーがゲームを辞めました,팔로우 중인 사용자가 게임에서 나갔어요.,O usuário que você segue saiu do jogo,O usuário que você segue saiu do jogo,Отслеживаемый игрок вышел из игры,关注用户已离开游戏,您關注的使用者已離開遊戲 +,,,This game is restricted,Dieses Spiel ist begrenzt,,Este juego está restringido,Este juego está restringido,Ce jeu est en accès limité.,Questa partita è riservata,このゲームは制限されています,이 게임은 제한되어 있어요.,Este jogo é restrito,Este jogo é restrito,Эта игра запрещена,此游戏有限制,此遊戲已受限 +,,,Not authorized to join this game,"Du bist nicht befugt, diesem Spiel beizutreten",,No tienes autorización para unirte a este juego,No tienes autorización para unirte a este juego,Vous n'avez pas l'autorisation de rejoindre ce jeu.,Non hai l'autorizzazione per partecipare a questa partita,このゲームに参加する権限がありません,게임 참여 권한 없음,Você não tem autorização para entrar neste jogo,Você não tem autorização para entrar neste jogo,Не разрешено присоединяться к этой игре,没有加入此游戏的权限,無加入此遊戲的權限 +,,,Server is busy,Server ist ausgelastet,,El servidor está ocupado,El servidor está ocupado,Le serveur est occupé.,Il server è occupato,サーバーがビジー状態です,서버 사용량이 많아요.,Servidor ocupado,Servidor ocupado,Сервер занят,服务器忙,伺服器忙碌 +,,,Hash Expired,Hash abgelaufen,,El hash ha caducado,El hash ha caducado,Expiration du hachage.,Hash scaduto,ハッシュが期限切れです,해시 만료됨,Hash expirado,Hash expirado,Хеширование истекло,哈希码失效,雜湊值已過期 +,,,Hash Exception,Hash-Ausnahme,,Excepción del hash,Excepción del hash,Exception de hachage.,Eccezione hash,ハッシュが例外です,해시 예외,Exceção de hash,Exceção de hash,Исключение хеширования,哈希码例外,雜湊值例外狀況 +,,,Your party is too large to fit,Deine Party ist zu groß,,Tu equipo es demasiado grande,Tu equipo es demasiado grande,Votre groupe comporte trop de membres.,Il tuo gruppo è troppo grande,パーティーが大きすぎてフィットしません,파티가 너무 커서 맞지 않아요.,Seu time é muito grande,Seu time é muito grande,Ваша группа слишком велика,你的团队人数过多,无法加入,您的隊伍已超過可容納人數 +,,,A Http error has occured. Please close the client and try again.,Ein HTTP-Fehler ist aufgetreten. Schließe den Client und versuche es erneut.,,Error en el http. Cierra el cliente e inténtalo de nuevo.,Error en el http. Cierra el cliente e inténtalo de nuevo.,"Une erreur HTTP s'est produite. Veuillez fermer le client, puis réessayez.",Si è verificato un errore http. Chiudi il client e riprova.,HTTPエラーが発生しました。クライアントを終了して、もう一度試してください。,Http 오류가 발생했어요. 클라이언트를 닫고 다시 시도하세요.,Erro no http. Feche o cliente e tente novamente.,Erro no http. Feche o cliente e tente novamente.,"Произошла ошибка Http. Пожалуйста, закройте клиент и попробуйте снова.",发生 Http 错误。请关闭客户端并重试。,發生HTTP錯誤。請關閉客戶端並再試一次。 +,,,Can't join place {PLACEID:int}: {ERROR_REASON:translate},Beitritt zu {PLACEID:int} nicht möglich: {ERROR_REASON:translate},,No es posible unirse al lugar {PLACEID:int}: {ERROR_REASON:translate},No es posible unirse al lugar {PLACEID:int}: {ERROR_REASON:translate},Impossible de rejoindre l'emplacement {PLACEID:int} : {ERROR_REASON:translate},Impossibile raggiungere la località {PLACEID:int}: {ERROR_REASON:translate},{PLACEID:int}の場所に参加できません:{ERROR_REASON:translate},장소 {PLACEID:int}에 참여할 수 없음: {ERROR_REASON:translate},Não é possível entrar em {PLACEID:int}: {ERROR_REASON:translate},Não é possível entrar em {PLACEID:int}: {ERROR_REASON:translate},Нельзя присоединиться ({PLACEID:int}): {ERROR_REASON:translate},由于{ERROR_REASON:translate},你无法加入{PLACEID:int}:,因下列原因無法加入地點{PLACEID:int}:{ERROR_REASON:translate} +,,,Can't follow user: {ERROR_REASON:translate},Folgen von Benutzer nicht möglich: {ERROR_REASON:translate},,No es posible seguir al usuario: {ERROR_REASON:translate},No es posible seguir al usuario: {ERROR_REASON:translate},Impossible de suivre l'utilisateur : {ERROR_REASON:translate},Impossibile seguire l'utente: {ERROR_REASON:translate},ユーザーをフォローできません:{ERROR_REASON:translate},사용자를 팔로우할 수 없음: {ERROR_REASON:translate},Não é possível seguir o usuário: {ERROR_REASON:translate},Não é possível seguir o usuário: {ERROR_REASON:translate},Нельзя следить за пользователем: {ERROR_REASON:translate},由于{ERROR_REASON:translate},无法关注用户:,因下列原因無法關注使用者:{ERROR_REASON:translate} +,,,Cannot join private server: {ERROR_REASON:translate},Beitritt zu privatem Server nicht möglich: {ERROR_REASON:translate},,No es posible unirse al servidor privado: {ERROR_REASON:translate},No es posible unirse al servidor privado: {ERROR_REASON:translate},Impossible de rejoindre le serveur privé : {ERROR_REASON:translate},Impossibile accedere al server privato: {ERROR_REASON:translate},プライベートサーバーに参加できません:{ERROR_REASON:translate},비공개 서버에 참여할 수 없음: {ERROR_REASON:translate},Não é possível juntar-se ao servidor privado: {ERROR_REASON:translate},Não é possível juntar-se ao servidor privado: {ERROR_REASON:translate},Нельзя присоединиться к частному серверу: {ERROR_REASON:translate},由于{ERROR_REASON:translate},无法加入私人服务器:,因下列原因無法加入私人伺服器:{ERROR_REASON:translate} +,,,Cannot join game instance: {ERROR_REASON:translate},Beitritt zu Spielinstanz nicht möglich: {ERROR_REASON:translate},,No es posible unirse a una instancia del juego: {ERROR_REASON:translate},No es posible unirse a una instancia del juego: {ERROR_REASON:translate},Impossible de rejoindre l'instance de jeu : {ERROR_REASON:translate},Impossibile accedere all'area di gioco: {ERROR_REASON:translate},ゲームインスタンスに参加できません:{ERROR_REASON:translate},게임 인스턴스에 참여할 수 없음: {ERROR_REASON:translate},Não é possível juntar-se ao jogo: {ERROR_REASON:translate},Não é possível juntar-se ao jogo: {ERROR_REASON:translate},Нельзя войти в локацию игры: {ERROR_REASON:translate},由于{ERROR_REASON:translate},无法加入游戏:,因下列原因無法加入遊戲: {ERROR_REASON:translate} +,,,Invalid JSON response received,Ungültige JSON-Antwort erhalten,,Se ha recibido una respuesta JSON no válida,Se ha recibido una respuesta JSON no válida,Réponse JSON invalide reçue.,Ricevuta risposta JSON non valida,無効なJSON応答を受信しました,잘못된 JSON 응답 수신됨,Resposta do JSON inválida,Resposta do JSON inválida,Получен некорректный ответ JSON,接收到无效的 JSON,接收的JSON回應無效 +,,,Retrying,Neuer Versuch,,Intentándolo de nuevo,Intentándolo de nuevo,Nouvelle tentative,Nuovo tentativo,リトライ中,재시도 중,Tentando de novo,Tentando de novo,Новая попытка,正在重试,重試中 +,,,Waiting for an available server. ({COUNT:int}),Warten auf verfügbaren Server. ({COUNT:int}),,Esperando un servidor disponible. ({COUNT:int}),Esperando un servidor disponible. ({COUNT:int}),En attente d'un serveur disponible. ({COUNT:int}),In attesa di un server disponibile. ({COUNT:int}),使用可能なサーバを待機中 ({COUNT:int}),이용 가능한 서버를 기다리는 중 ({COUNT:int}),Aguardando um servidor disponível ({COUNT:int}),Aguardando um servidor disponível ({COUNT:int}),Ожидание доступного сервера ({COUNT:int}),正在等待可用服务器 ({COUNT:int}),正在等候可用伺服器 ({COUNT:int}) +,,,"Server found, loading.... ({COUNT:int})","Server gefunden, wird geladen .... ({COUNT:int})",,Servidor encontrado. Cargando.... ({COUNT:int}),Servidor encontrado. Cargando.... ({COUNT:int}),"Serveur trouvé, chargement en cours.... ({COUNT:int})","Server trovato, caricamento.... ({COUNT:int})",サーバが見つかりました、ロード中です... ({COUNT:int}),"서버 발견, 로드 중... ({COUNT:int})","Servidor encontrado, carregando... ({COUNT:int})","Servidor encontrado, carregando... ({COUNT:int})",Сервер найден. Загрузка... ({COUNT:int}),找到服务器,正在加载... ({COUNT:int}),找到伺服器,載入中… ({COUNT:int}) +,,,Joining server. ({COUNT:int}),Verbindung zum Server wird hergestellt. ({COUNT:int}),,Uniéndose a un servidor. ({COUNT:int}),Uniéndose a un servidor. ({COUNT:int}),Connexion au serveur.... ({COUNT:int}),Connessione al server. ({COUNT:int}),サーバーに接続中 ({COUNT:int}),서버 가입 ({COUNT:int}),Entrando no servidor ({COUNT:int}),Entrando no servidor ({COUNT:int}),Подключение к серверу ({COUNT:int}),正在加入服务器 ({COUNT:int}),加入伺服器 ({COUNT:int}) +,,,This game is disabled. ({COUNT:int}),Dieses Spiel wurde deaktiviert. ({COUNT:int}),,Este juego está desactivado. ({COUNT:int}),Este juego está desactivado. ({COUNT:int}),Ce jeu est désactivé.. ({COUNT:int}),Questo gioco è stato disattivato. ({COUNT:int}),このゲームは無効です ({COUNT:int}),이 게임은 비활성화되었어요. ({COUNT:int}),Este jogo está desabilitado ({COUNT:int}),Este jogo está desabilitado ({COUNT:int}),Эта игра отключена ({COUNT:int}),游戏已禁用 ({COUNT:int}),此遊戲已停用 ({COUNT:int}) +,,,Cannot find game server. ({COUNT:int}),Spielserver kann nicht gefunden werden. ({COUNT:int}),,No se ha encontrado el servidor del juego. ({COUNT:int}),No se ha encontrado el servidor del juego. ({COUNT:int}),Serveur de jeu introuvable.. ({COUNT:int}),Impossibile trovare il server di gioco. ({COUNT:int}),ゲームサーバーが見つかりません ({COUNT:int}),게임 서버를 찾을 수 없음 ({COUNT:int}),Não foi possível encontrar o servidor do jogo ({COUNT:int}),Não foi possível encontrar o servidor do jogo ({COUNT:int}),Не могу найти игровой сервер ({COUNT:int}),无法找到游戏服务器 ({COUNT:int}),無法找到遊戲伺服器 ({COUNT:int}) +,,,This game has ended. ({COUNT:int}),Dieses Spiel ist beendet. ({COUNT:int}),,Este juego ha finalizado. ({COUNT:int}),Este juego ha finalizado. ({COUNT:int}),Cette partie est terminée.. ({COUNT:int}),Questo gioco è stato chiuso. ({COUNT:int}),このゲームは終了しました ({COUNT:int}),이 게임은 종료되었어요. ({COUNT:int}),Este jogo acabou ({COUNT:int}),Este jogo acabou ({COUNT:int}),Эта игра закончена ({COUNT:int}),此游戏已结束 ({COUNT:int}),此遊戲已結束 ({COUNT:int}) +,,,Requested game is full. ({COUNT:int}),Das angefragte Spiel ist voll. ({COUNT:int}),,El juego solicitado está lleno. ({COUNT:int}),El juego solicitado está lleno. ({COUNT:int}),La partie demandée est complète.. ({COUNT:int}),Il gioco richiesto è al completo. ({COUNT:int}),リクエストしたゲームは満員です。 ({COUNT:int}),요청한 게임이 가득 찼어요. ({COUNT:int}),O jogo solicitado está cheio ({COUNT:int}),O jogo solicitado está cheio ({COUNT:int}),Запрашиваемая игра переполнена ({COUNT:int}),请求的游戏已满员 ({COUNT:int}),要求的遊戲已滿 ({COUNT:int}) +,,,Followed user has left the game. ({COUNT:int}),"Der Benutzer, dem du folgst, hat das Spiel verlassen. ({COUNT:int})",,El usuario al que sigues ha abandonado el juego. ({COUNT:int}),El usuario al que sigues ha abandonado el juego. ({COUNT:int}),L'utilisateur que vous suiviez a quitté la partie.. ({COUNT:int}),L'utente seguito ha abbandonato il gioco. ({COUNT:int}),フォローしたユーザーがゲームを辞めました ({COUNT:int}),팔로우 중인 사용자가 게임에서 나갔어요. ({COUNT:int}),O usuário que você segue saiu do jogo ({COUNT:int}),O usuário que você segue saiu do jogo ({COUNT:int}),Отслеживаемый игрок вышел из игры ({COUNT:int}),关注用户已离开游戏 ({COUNT:int}),您關注的使用者已離開遊戲 ({COUNT:int}) +,,,This game is restricted. ({COUNT:int}),Dieses Spiel ist begrenzt. ({COUNT:int}),,Este juego está restringido. ({COUNT:int}),Este juego está restringido. ({COUNT:int}),Ce jeu est en accès limité.. ({COUNT:int}),Questa partita è riservata. ({COUNT:int}),このゲームは制限されています ({COUNT:int}),이 게임은 제한되어 있어요. ({COUNT:int}),Este jogo é restrito ({COUNT:int}),Este jogo é restrito ({COUNT:int}),Эта игра запрещена ({COUNT:int}),此游戏有限制 ({COUNT:int}),此遊戲已受限 ({COUNT:int}) +,,,Not authorized to join this game. ({COUNT:int}),"Du bist nicht befugt, diesem Spiel beizutreten. ({COUNT:int})",,No tienes autorización para unirte a este juego. ({COUNT:int}),No tienes autorización para unirte a este juego. ({COUNT:int}),Vous n'avez pas l'autorisation de rejoindre ce jeu.. ({COUNT:int}),Non hai l'autorizzazione per partecipare a questa partita. ({COUNT:int}),このゲームに参加する権限がありません ({COUNT:int}),게임 참여 권한 없음 ({COUNT:int}),Você não tem autorização para entrar neste jogo ({COUNT:int}),Você não tem autorização para entrar neste jogo ({COUNT:int}),Не разрешено присоединяться к этой игре ({COUNT:int}),没有加入此游戏的权限 ({COUNT:int}),無加入此遊戲的權限 ({COUNT:int}) +,,,Server is busy. ({COUNT:int}),Server ist ausgelastet. ({COUNT:int}),,El servidor está ocupado. ({COUNT:int}),El servidor está ocupado. ({COUNT:int}),Le serveur est occupé.. ({COUNT:int}),Il server è occupato. ({COUNT:int}),サーバーがビジー状態です ({COUNT:int}),서버 사용량이 많아요. ({COUNT:int}),Servidor ocupado ({COUNT:int}),Servidor ocupado ({COUNT:int}),Сервер занят ({COUNT:int}),服务器忙 ({COUNT:int}),伺服器忙碌 ({COUNT:int}) +,,,Hash Expired. ({COUNT:int}),Hash abgelaufen. ({COUNT:int}),,El hash ha caducado. ({COUNT:int}),El hash ha caducado. ({COUNT:int}),Expiration du hachage.. ({COUNT:int}),Hash scaduto. ({COUNT:int}),ハッシュが期限切れです ({COUNT:int}),해시 만료됨 ({COUNT:int}),Hash expirado ({COUNT:int}),Hash expirado ({COUNT:int}),Хеширование истекло ({COUNT:int}),哈希码失效 ({COUNT:int}),雜湊值已過期 ({COUNT:int}) +,,,Hash Exception. ({COUNT:int}),Hash-Ausnahme. ({COUNT:int}),,Excepción del hash. ({COUNT:int}),Excepción del hash. ({COUNT:int}),Exception de hachage.. ({COUNT:int}),Eccezione hash. ({COUNT:int}),ハッシュが例外です ({COUNT:int}),해시 예외 ({COUNT:int}),Exceção de hash ({COUNT:int}),Exceção de hash ({COUNT:int}),Исключение хеширования ({COUNT:int}),哈希码例外 ({COUNT:int}),雜湊值例外狀況 ({COUNT:int}) +,,,Your party is too large to fit. ({COUNT:int}),Deine Party ist zu groß. ({COUNT:int}),,Tu equipo es demasiado grande. ({COUNT:int}),Tu equipo es demasiado grande. ({COUNT:int}),Votre groupe comporte trop de membres.. ({COUNT:int}),Il tuo gruppo è troppo grande. ({COUNT:int}),パーティーが大きすぎてフィットしません ({COUNT:int}),파티가 너무 커서 맞지 않아요. ({COUNT:int}),Seu time é muito grande ({COUNT:int}),Seu time é muito grande ({COUNT:int}),Ваша группа слишком велика ({COUNT:int}),你的团队人数过多,无法加入 ({COUNT:int}),您的隊伍已超過可容納人數 ({COUNT:int}) +,,,A Http error has occured. Please close the client and try again.. ({COUNT:int}),Ein HTTP-Fehler ist aufgetreten. Schließe den Client und versuche es erneut.. ({COUNT:int}),,Error en el http. Cierra el cliente e inténtalo de nuevo.. ({COUNT:int}),Error en el http. Cierra el cliente e inténtalo de nuevo.. ({COUNT:int}),"Une erreur HTTP s'est produite. Veuillez fermer le client, puis réessayez.. ({COUNT:int})",Si è verificato un errore http. Chiudi il client e riprova.. ({COUNT:int}),HTTPエラーが発生しました。クライアントを終了して、もう一度試してください。 ({COUNT:int}),Http 오류가 발생했어요. 클라이언트를 닫고 다시 시도하세요. ({COUNT:int}),Erro no http. Feche o cliente e tente novamente. ({COUNT:int}),Erro no http. Feche o cliente e tente novamente. ({COUNT:int}),"Произошла ошибка Http. Пожалуйста, закройте клиент и попробуйте снова. ({COUNT:int})",发生 Http 错误。请关闭客户端并重试。 ({COUNT:int}),發生HTTP錯誤。請關閉客戶端並再試一次。 ({COUNT:int}) +,,,Can't join place {PLACEID:int}: {ERROR_REASON:translate}. ({COUNT:int}),Beitritt zu {PLACEID:int} nicht möglich: {ERROR_REASON:translate}. ({COUNT:int}),,No es posible unirse al lugar {PLACEID:int}: {ERROR_REASON:translate}. ({COUNT:int}),No es posible unirse al lugar {PLACEID:int}: {ERROR_REASON:translate}. ({COUNT:int}),Impossible de rejoindre l'emplacement {PLACEID:int} : {ERROR_REASON:translate}. ({COUNT:int}),Impossibile raggiungere la località {PLACEID:int}: {ERROR_REASON:translate}. ({COUNT:int}),{PLACEID:int}の場所に参加できません:{ERROR_REASON:translate}. ({COUNT:int}),장소 {PLACEID:int}에 참여할 수 없음: {ERROR_REASON:translate}. ({COUNT:int}),Não é possível entrar em {PLACEID:int}: {ERROR_REASON:translate}. ({COUNT:int}),Não é possível entrar em {PLACEID:int}: {ERROR_REASON:translate}. ({COUNT:int}),Нельзя присоединиться ({PLACEID:int}): {ERROR_REASON:translate}. ({COUNT:int}),由于{ERROR_REASON:translate},你无法加入{PLACEID:int}:. ({COUNT:int}),正在等候可用伺服器. {RET:translate}...({COUNT:int}) +,,,Can't follow user: {ERROR_REASON:translate}. ({COUNT:int}),Folgen von Benutzer nicht möglich: {ERROR_REASON:translate}. ({COUNT:int}),,No es posible seguir al usuario: {ERROR_REASON:translate}. ({COUNT:int}),No es posible seguir al usuario: {ERROR_REASON:translate}. ({COUNT:int}),Impossible de suivre l'utilisateur : {ERROR_REASON:translate}. ({COUNT:int}),Impossibile seguire l'utente: {ERROR_REASON:translate}. ({COUNT:int}),ユーザーをフォローできません:{ERROR_REASON:translate}. ({COUNT:int}),사용자를 팔로우할 수 없음: {ERROR_REASON:translate}. ({COUNT:int}),Não é possível seguir o usuário: {ERROR_REASON:translate}. ({COUNT:int}),Não é possível seguir o usuário: {ERROR_REASON:translate}. ({COUNT:int}),Нельзя следить за пользователем: {ERROR_REASON:translate}. ({COUNT:int}),由于{ERROR_REASON:translate},无法关注用户:. ({COUNT:int}),找到伺服器,載入中…. {RET:translate}...({COUNT:int}) +,,,Cannot join private server: {ERROR_REASON:translate}. ({COUNT:int}),Beitritt zu privatem Server nicht möglich: {ERROR_REASON:translate}. ({COUNT:int}),,No es posible unirse al servidor privado: {ERROR_REASON:translate}. ({COUNT:int}),No es posible unirse al servidor privado: {ERROR_REASON:translate}. ({COUNT:int}),Impossible de rejoindre le serveur privé : {ERROR_REASON:translate}. ({COUNT:int}),Impossibile accedere al server privato: {ERROR_REASON:translate}. ({COUNT:int}),プライベートサーバーに参加できません:{ERROR_REASON:translate}. ({COUNT:int}),비공개 서버에 참여할 수 없음: {ERROR_REASON:translate}. ({COUNT:int}),Não é possível juntar-se ao servidor privado: {ERROR_REASON:translate}. ({COUNT:int}),Não é possível juntar-se ao servidor privado: {ERROR_REASON:translate}. ({COUNT:int}),Нельзя присоединиться к частному серверу: {ERROR_REASON:translate}. ({COUNT:int}),由于{ERROR_REASON:translate},无法加入私人服务器:. ({COUNT:int}),加入伺服器. {RET:translate}...({COUNT:int}) +,,,Cannot join game instance: {ERROR_REASON:translate}. ({COUNT:int}),Beitritt zu Spielinstanz nicht möglich: {ERROR_REASON:translate}. ({COUNT:int}),,No es posible unirse a una instancia del juego: {ERROR_REASON:translate}. ({COUNT:int}),No es posible unirse a una instancia del juego: {ERROR_REASON:translate}. ({COUNT:int}),Impossible de rejoindre l'instance de jeu : {ERROR_REASON:translate}. ({COUNT:int}),Impossibile accedere all'area di gioco: {ERROR_REASON:translate}. ({COUNT:int}),ゲームインスタンスに参加できません:{ERROR_REASON:translate}. ({COUNT:int}),게임 인스턴스에 참여할 수 없음: {ERROR_REASON:translate}. ({COUNT:int}),Não é possível juntar-se ao jogo: {ERROR_REASON:translate}. ({COUNT:int}),Não é possível juntar-se ao jogo: {ERROR_REASON:translate}. ({COUNT:int}),Нельзя войти в локацию игры: {ERROR_REASON:translate}. ({COUNT:int}),由于{ERROR_REASON:translate},无法加入游戏:. ({COUNT:int}),此遊戲已停用. {RET:translate}...({COUNT:int}) +,,,Roblox has shut down this game server for maintenance. {RET:translate}...({COUNT:int}),Roblox hat diesen Spielserver aufgrund von Wartungsarbeiten abgeschaltet. {RET:translate}...({COUNT:int}),,Roblox ha cerrado el servidor de este juego por mantenimiento. {RET:translate}...({COUNT:int}),Roblox ha cerrado el servidor de este juego por mantenimiento. {RET:translate}...({COUNT:int}),Roblox a arrêté ce serveur de jeu pour effectuer la maintenance.. {RET:translate}...({COUNT:int}),Roblox ha chiuso questo server di gioco per manutenzione. {RET:translate}...({COUNT:int}),メンテナンスのため、Roblox によってゲームサーバーがシャットダウンされています。. {RET:translate}...({COUNT:int}),Roblox가 점검을 위해 이 게임 서버를 닫았어요.. {RET:translate}...({COUNT:int}),O servidor deste jogo foi encerrado pelo Roblox para manutenção. {RET:translate}...({COUNT:int}),O servidor deste jogo foi encerrado pelo Roblox para manutenção. {RET:translate}...({COUNT:int}),Roblox отключил игровой сервер для техобслуживания.. {RET:translate}...({COUNT:int}),维护期间,Roblox 已关闭此游戏服务器. {RET:translate}...({COUNT:int}),無法找到遊戲伺服器. {RET:translate}...({COUNT:int}) +,,,This game has been disconnected because you have joined a game from another device. {RET:translate}...({COUNT:int}),"Dieses Spiel wurde unterbrochen, weil du einem Spiel von einem anderen Gerät beigetreten bist. {RET:translate}...({COUNT:int})",,Se ha desconectado este juego porque te has unido a un juego desde otro dispositivo. {RET:translate}...({COUNT:int}),Se ha desconectado este juego porque te has unido a un juego desde otro dispositivo. {RET:translate}...({COUNT:int}),"Vous avez été déconnecté(e) de ce jeu, car vous en avez rejoint un autre depuis un appareil différent.. {RET:translate}...({COUNT:int})",Questo gioco è stato disconnesso perché hai giocato una partita con un altro dispositivo. {RET:translate}...({COUNT:int}),別のデバイスからゲームに参加したため、このゲームへの接続が切断されました. {RET:translate}...({COUNT:int}),다른 장치에서 게임에 참여하여 이 게임의 연결이 끊어졌어요.. {RET:translate}...({COUNT:int}),Este jogo foi desconectado pois você entrou em um jogo através de outro dispositivo. {RET:translate}...({COUNT:int}),Este jogo foi desconectado pois você entrou em um jogo através de outro dispositivo. {RET:translate}...({COUNT:int}),"Соединение с этой игрой было прервано, так как вы стали играть с другого устройства.. {RET:translate}...({COUNT:int})",由于你从另一设备加入游戏,此游戏已断开连接. {RET:translate}...({COUNT:int}),此遊戲已結束. {RET:translate}...({COUNT:int}) +,,,"Disconnected from game, please reconnect. {RET:translate}...({COUNT:int})",Verbindung zum Spiel unterbrochen. Bitte erneut verbinden.. {RET:translate}...({COUNT:int}),,Desconectado del juego. Conéctate de nuevo.. {RET:translate}...({COUNT:int}),Desconectado del juego. Conéctate de nuevo.. {RET:translate}...({COUNT:int}),Vous avez été déconnecté(e) du jeu. Veuillez vous reconnecter.. {RET:translate}...({COUNT:int}),Disconnesso dal gioco; è necessario riconnettersi. {RET:translate}...({COUNT:int}),ゲームへの接続が切断されました。再接続してください. {RET:translate}...({COUNT:int}),게임 연결이 끊어졌어요. 다시 연결하세요.. {RET:translate}...({COUNT:int}),Você foi desconectado do jogo. Conecte-se novamente.. {RET:translate}...({COUNT:int}),Você foi desconectado do jogo. Conecte-se novamente.. {RET:translate}...({COUNT:int}),"Соединение и игрой прервано, пожалуйста, установите соединение повторно.. {RET:translate}...({COUNT:int})",与游戏连接已断开,请重新连接. {RET:translate}...({COUNT:int}),要求的遊戲已滿. {RET:translate}...({COUNT:int}) +,,,Waiting for an available server. {RET:translate}...({COUNT:int}),Warten auf verfügbaren Server. {RET:translate}...({COUNT:int}),,Esperando un servidor disponible. {RET:translate}...({COUNT:int}),Esperando un servidor disponible. {RET:translate}...({COUNT:int}),En attente d'un serveur disponible. {RET:translate}...({COUNT:int}),In attesa di un server disponibile. {RET:translate}...({COUNT:int}),使用可能なサーバを待機中. {RET:translate}...({COUNT:int}),이용 가능한 서버를 기다리는 중. {RET:translate}...({COUNT:int}),Aguardando um servidor disponível. {RET:translate}...({COUNT:int}),Aguardando um servidor disponível. {RET:translate}...({COUNT:int}),Ожидание доступного сервера. {RET:translate}...({COUNT:int}),正在等待可用服务器. {RET:translate}...({COUNT:int}),您關注的使用者已離開遊戲. {RET:translate}...({COUNT:int}) +,,,"Server found, loading.... {RET:translate}...({COUNT:int})","Server gefunden, wird geladen .... {RET:translate}...({COUNT:int})",,Servidor encontrado. Cargando.... {RET:translate}...({COUNT:int}),Servidor encontrado. Cargando.... {RET:translate}...({COUNT:int}),"Serveur trouvé, chargement en cours.... {RET:translate}...({COUNT:int})","Server trovato, caricamento.... {RET:translate}...({COUNT:int})",サーバが見つかりました、ロード中です.... {RET:translate}...({COUNT:int}),"서버 발견, 로드 중.... {RET:translate}...({COUNT:int})","Servidor encontrado, carregando.... {RET:translate}...({COUNT:int})","Servidor encontrado, carregando.... {RET:translate}...({COUNT:int})",Сервер найден. Загрузка.... {RET:translate}...({COUNT:int}),找到服务器,正在加载.... {RET:translate}...({COUNT:int}),此遊戲已受限. {RET:translate}...({COUNT:int}) +,,,Joining server. {RET:translate}...({COUNT:int}),Verbindung zum Server wird hergestellt. {RET:translate}...({COUNT:int}),,Uniéndose a un servidor. {RET:translate}...({COUNT:int}),Uniéndose a un servidor. {RET:translate}...({COUNT:int}),Connexion au serveur.... {RET:translate}...({COUNT:int}),Connessione al server. {RET:translate}...({COUNT:int}),サーバーに接続中. {RET:translate}...({COUNT:int}),서버 가입. {RET:translate}...({COUNT:int}),Entrando no servidor. {RET:translate}...({COUNT:int}),Entrando no servidor. {RET:translate}...({COUNT:int}),Подключение к серверу. {RET:translate}...({COUNT:int}),正在加入服务器. {RET:translate}...({COUNT:int}),無加入此遊戲的權限. {RET:translate}...({COUNT:int}) +,,,This game is disabled. {RET:translate}...({COUNT:int}),Dieses Spiel wurde deaktiviert. {RET:translate}...({COUNT:int}),,Este juego está desactivado. {RET:translate}...({COUNT:int}),Este juego está desactivado. {RET:translate}...({COUNT:int}),Ce jeu est désactivé.. {RET:translate}...({COUNT:int}),Questo gioco è stato disattivato. {RET:translate}...({COUNT:int}),このゲームは無効です. {RET:translate}...({COUNT:int}),이 게임은 비활성화되었어요.. {RET:translate}...({COUNT:int}),Este jogo está desabilitado. {RET:translate}...({COUNT:int}),Este jogo está desabilitado. {RET:translate}...({COUNT:int}),Эта игра отключена. {RET:translate}...({COUNT:int}),游戏已禁用. {RET:translate}...({COUNT:int}),伺服器忙碌. {RET:translate}...({COUNT:int}) +,,,Cannot find game server. {RET:translate}...({COUNT:int}),Spielserver kann nicht gefunden werden. {RET:translate}...({COUNT:int}),,No se ha encontrado el servidor del juego. {RET:translate}...({COUNT:int}),No se ha encontrado el servidor del juego. {RET:translate}...({COUNT:int}),Serveur de jeu introuvable.. {RET:translate}...({COUNT:int}),Impossibile trovare il server di gioco. {RET:translate}...({COUNT:int}),ゲームサーバーが見つかりません. {RET:translate}...({COUNT:int}),게임 서버를 찾을 수 없음. {RET:translate}...({COUNT:int}),Não foi possível encontrar o servidor do jogo. {RET:translate}...({COUNT:int}),Não foi possível encontrar o servidor do jogo. {RET:translate}...({COUNT:int}),Не могу найти игровой сервер. {RET:translate}...({COUNT:int}),无法找到游戏服务器. {RET:translate}...({COUNT:int}),雜湊值已過期. {RET:translate}...({COUNT:int}) +,,,This game has ended. {RET:translate}...({COUNT:int}),Dieses Spiel ist beendet. {RET:translate}...({COUNT:int}),,Este juego ha finalizado. {RET:translate}...({COUNT:int}),Este juego ha finalizado. {RET:translate}...({COUNT:int}),Cette partie est terminée.. {RET:translate}...({COUNT:int}),Questo gioco è stato chiuso. {RET:translate}...({COUNT:int}),このゲームは終了しました. {RET:translate}...({COUNT:int}),이 게임은 종료되었어요.. {RET:translate}...({COUNT:int}),Este jogo acabou. {RET:translate}...({COUNT:int}),Este jogo acabou. {RET:translate}...({COUNT:int}),Эта игра закончена. {RET:translate}...({COUNT:int}),此游戏已结束. {RET:translate}...({COUNT:int}),雜湊值例外狀況. {RET:translate}...({COUNT:int}) +,,,Requested game is full. {RET:translate}...({COUNT:int}),Das angefragte Spiel ist voll. {RET:translate}...({COUNT:int}),,El juego solicitado está lleno. {RET:translate}...({COUNT:int}),El juego solicitado está lleno. {RET:translate}...({COUNT:int}),La partie demandée est complète.. {RET:translate}...({COUNT:int}),Il gioco richiesto è al completo. {RET:translate}...({COUNT:int}),リクエストしたゲームは満員です。. {RET:translate}...({COUNT:int}),요청한 게임이 가득 찼어요.. {RET:translate}...({COUNT:int}),O jogo solicitado está cheio. {RET:translate}...({COUNT:int}),O jogo solicitado está cheio. {RET:translate}...({COUNT:int}),Запрашиваемая игра переполнена. {RET:translate}...({COUNT:int}),请求的游戏已满员. {RET:translate}...({COUNT:int}),您的隊伍已超過可容納人數. {RET:translate}...({COUNT:int}) +,,,Followed user has left the game. {RET:translate}...({COUNT:int}),"Der Benutzer, dem du folgst, hat das Spiel verlassen. {RET:translate}...({COUNT:int})",,El usuario al que sigues ha abandonado el juego. {RET:translate}...({COUNT:int}),El usuario al que sigues ha abandonado el juego. {RET:translate}...({COUNT:int}),L'utilisateur que vous suiviez a quitté la partie.. {RET:translate}...({COUNT:int}),L'utente seguito ha abbandonato il gioco. {RET:translate}...({COUNT:int}),フォローしたユーザーがゲームを辞めました. {RET:translate}...({COUNT:int}),팔로우 중인 사용자가 게임에서 나갔어요.. {RET:translate}...({COUNT:int}),O usuário que você segue saiu do jogo. {RET:translate}...({COUNT:int}),O usuário que você segue saiu do jogo. {RET:translate}...({COUNT:int}),Отслеживаемый игрок вышел из игры. {RET:translate}...({COUNT:int}),关注用户已离开游戏. {RET:translate}...({COUNT:int}),發生HTTP錯誤。請關閉客戶端並再試一次。. {RET:translate}...({COUNT:int}) +,,,This game is restricted. {RET:translate}...({COUNT:int}),Dieses Spiel ist begrenzt. {RET:translate}...({COUNT:int}),,Este juego está restringido. {RET:translate}...({COUNT:int}),Este juego está restringido. {RET:translate}...({COUNT:int}),Ce jeu est en accès limité.. {RET:translate}...({COUNT:int}),Questa partita è riservata. {RET:translate}...({COUNT:int}),このゲームは制限されています. {RET:translate}...({COUNT:int}),이 게임은 제한되어 있어요.. {RET:translate}...({COUNT:int}),Este jogo é restrito. {RET:translate}...({COUNT:int}),Este jogo é restrito. {RET:translate}...({COUNT:int}),Эта игра запрещена. {RET:translate}...({COUNT:int}),此游戏有限制. {RET:translate}...({COUNT:int}), +,,,Not authorized to join this game. {RET:translate}...({COUNT:int}),"Du bist nicht befugt, diesem Spiel beizutreten. {RET:translate}...({COUNT:int})",,No tienes autorización para unirte a este juego. {RET:translate}...({COUNT:int}),No tienes autorización para unirte a este juego. {RET:translate}...({COUNT:int}),Vous n'avez pas l'autorisation de rejoindre ce jeu.. {RET:translate}...({COUNT:int}),Non hai l'autorizzazione per partecipare a questa partita. {RET:translate}...({COUNT:int}),このゲームに参加する権限がありません. {RET:translate}...({COUNT:int}),게임 참여 권한 없음. {RET:translate}...({COUNT:int}),Você não tem autorização para entrar neste jogo. {RET:translate}...({COUNT:int}),Você não tem autorização para entrar neste jogo. {RET:translate}...({COUNT:int}),Не разрешено присоединяться к этой игре. {RET:translate}...({COUNT:int}),没有加入此游戏的权限. {RET:translate}...({COUNT:int}), +,,,Server is busy. {RET:translate}...({COUNT:int}),Server ist ausgelastet. {RET:translate}...({COUNT:int}),,El servidor está ocupado. {RET:translate}...({COUNT:int}),El servidor está ocupado. {RET:translate}...({COUNT:int}),Le serveur est occupé.. {RET:translate}...({COUNT:int}),Il server è occupato. {RET:translate}...({COUNT:int}),サーバーがビジー状態です. {RET:translate}...({COUNT:int}),서버 사용량이 많아요.. {RET:translate}...({COUNT:int}),Servidor ocupado. {RET:translate}...({COUNT:int}),Servidor ocupado. {RET:translate}...({COUNT:int}),Сервер занят. {RET:translate}...({COUNT:int}),服务器忙. {RET:translate}...({COUNT:int}), +,,,Hash Expired. {RET:translate}...({COUNT:int}),Hash abgelaufen. {RET:translate}...({COUNT:int}),,El hash ha caducado. {RET:translate}...({COUNT:int}),El hash ha caducado. {RET:translate}...({COUNT:int}),Expiration du hachage.. {RET:translate}...({COUNT:int}),Hash scaduto. {RET:translate}...({COUNT:int}),ハッシュが期限切れです. {RET:translate}...({COUNT:int}),해시 만료됨. {RET:translate}...({COUNT:int}),Hash expirado. {RET:translate}...({COUNT:int}),Hash expirado. {RET:translate}...({COUNT:int}),Хеширование истекло. {RET:translate}...({COUNT:int}),哈希码失效. {RET:translate}...({COUNT:int}), +Feature.SettingsHub.Action.InviteFriendsToPlay,,,Invite friends to play,Lade Freunde zum Spielen ein,Invite friends to play,Invitar amigos al juego,,Inviter des amis à jouer,Invita gli amici a giocare,友達を招待してプレイ,플레이할 친구 초대,,Convidar amigos para o jogo,Пригласить друзей в игру,邀请好友加入游戏,邀請朋友來玩 +Feature.SettingsHub.Heading.InviteFriends,,,Invite Friends,Freunde einladen,Invite Friends,Invitar amigos,,Inviter des amis,Invita amici,友達を招待,친구 초대,,Convidar amigos,Пригласить друзей,邀请好友,邀請朋友 +Feature.SettingsHub.Action.CancelSearch,,,Cancel,Abbrechen,Cancel,Cancelar,,Annuler,Annulla,キャンセル,취소,,Cancelar,Отмена,取消,取消 +Feature.SettingsHub.Action.InviteFriend,,,Invite,Einladen,Invite,Invitar,,Inviter,Invita,招待,초대,,Convidar,Пригласить,邀请,邀請 +Feature.SettingsHub.Action.InviteFriendsBack,,,Back,Zurück,Back,Volver,,Arrière,Indietro,戻る,뒤로,,Voltar,Назад,返回,返回 +Feature.SettingsHub.Label.Invited,,,Invited,Eingeladen,Invited,Invitado,,Invité,Invitato,招待済み,초대함,,Convidado,Приглашено,已邀请,已邀請 +Feature.SettingsHub.Label.SearchForFriendsPlaceholder,,,Search for friends,Suche nach Freunden,Search for friends,Buscar amigos,,Chercher des amis,Cerca amici,友だちを検索,친구 찾아보기,,Procurar amigos,Поиск друзей,搜索好友,搜尋朋友 +Feature.SettingsHub.Label.InviteSearchNoResults,,,No results found,Keine Suchergebnisse,No results found,Sin resultados,,Aucun résultat trouvé,Nessun risultato trovato,結果が見つかりませんでした,결과 없음,,Nenhum resultado,Нет результатов,未找到搜索结果,未找到結果 +Feature.SettingsHub.Label.NoFriendsScreen,,,Make friends so you can invite them to play with you!,"Finde Freunde und lade sie ein, mit dir zu spielen!",Make friends so you can invite them to play with you!,¡Haz amigos para que los invites a jugar contigo!,,Faites des amis pour que vous puissiez les inviter à jouer!,"Trova nuovi amici, così potrai invitarli a giocare con te!",ゲームを一緒にプレイするために友達を招待しましょう!,함께 플레이할 친구를 사귀고 초대하세요!,,Faça amigos e os convide para jogar,"Найдите друзей, чтобы играть вместе с ними!",认识更多朋友,邀请他们和你一起玩游戏!,廣結好友就能邀請他們跟你一起玩! +Common.Presence.Label.Online,,,Online,Online,Online,En línea,,En ligne,Online,オンライン,온라인,,On-line,В сети,在线,在線上 +Common.Presence.Label.InGame,,,In Game,Im Spiel,In Game,En el juego,,En Jeu,Nel gioco,ゲーム内,게임 이용 중,,No Jogo,В игре,正在游戏中,遊戲內 +Common.Presence.Label.InStudio,,,In Studio,In Studio,In Studio,En Studio,,En Studio,In Studio,スタジオ内,Studio 사용 중,,No Studio,В студии,正在 Studio 中,在 Studio 內 +Common.Presence.Label.Offline,,,Offline,Offline,Offline,Sin conexión,,Hors ligne,Offline,オフライン,오프라인,,Off-line,Не в сети,离线,離線 +Feature.SettingsHub.Label.Moderated,,,Moderated,Von einem Moderator angepasst,Moderated,Moderado,,Modéré,Moderato,フィルタリングされました,검토 요청됨,,Moderado,Проверено,已过滤,已仲裁 +Feature.SettingsHub.Label.LoadingFriendsListFailed,,,"An error occurred, please try again later.",Ein Fehler ist aufgetreten. Bitte versuche es später erneut.,"An error occurred, please try again later.",Se ha producido un error. Inténtalo de nuevo más tarde.,,"Une erreur s'est produite, veuillez reéssayer plus tard.",Si è verificato un errore. Riprova più tardi.,エラーが発生しました。後でもう一度お試しください。,"오류 발생, 나중에 다시 시도하세요.",,"Ocorreu um erro, tente novamente mais tarde.",Произошла ошибка. Повторите попытку позже.,发生错误,请稍候重试。,發生錯誤,請稍後再試。 +Feature.SettingsHub.Label.Sending,,,Sending,Wird gesendet,Sending,Enviando,,En cours d'envoi,Invio...,送信しています,보내는 중,,Enviando,Отправка,正在发送,正在傳送 +Feature.SettingsHub.Label.ModeratedInviteError,,,Game invite was moderated and not sent.,Spieleinladung wurde von einem Moderator angepasst und nicht gesendet.,Game invite was moderated and not sent.,La invitación al juego ha sido moderada y no se ha enviado.,,L'invitation au jeu a été modérée et n'a pu être envoyée.,L'invito di gioco è stato moderato e non inviato.,ゲームへの招待は、フィルタリングにより送信されませんでした。,게임 초대가 검토 요청을 받아 전송되지 않았어요.,,O convite de jogo foi moderado e não foi enviado.,Приглашение в игру было проверено и не было отправлено.,游戏邀请已被过滤,未能发送。,遊戲邀請因受到仲裁而未送出。 +Feature.SettingsHub.Label.GameInviteError,,,Game invite could not be sent. Please try again later.,Spieleinladung konnte nicht gesendet werden. Bitte versuche es später erneut.,Game invite could not be sent. Please try again later.,No se ha podido enviar la invitación al juego. Inténtalo de nuevo más tarde.,,L'invitation au jeu n'a pas pu être envoyée. Veuillez réessayer plus tard.,Non è stato possibile inviare l'invito di gioco. Riprova più tardi.,ゲームへの招待を送信できませんでした。しばらくしてからやり直してください。,게임 초대를 보내지 못했습니다. 나중에 다시 시도하십시오.,,O convite de jogo não pôde ser enviado. Tente de novo mais tarde.,"Приглашение от игры не было послано. Пожалуйста, повторите попытку.",无法发送游戏邀请。请稍后重试。,無法發送遊戲邀請,請稍後再試。 diff --git a/2018/fmod.dll b/2018/fmod.dll new file mode 100644 index 0000000..65cde34 Binary files /dev/null and b/2018/fmod.dll differ diff --git a/2018/shaders/keepme b/2018/shaders/keepme new file mode 100644 index 0000000..e69de29 diff --git a/2018/shaders/shaders_d3d10.pack b/2018/shaders/shaders_d3d10.pack new file mode 100644 index 0000000..7dd6675 Binary files /dev/null and b/2018/shaders/shaders_d3d10.pack differ diff --git a/2018/shaders/shaders_d3d10_1.pack b/2018/shaders/shaders_d3d10_1.pack new file mode 100644 index 0000000..44b077b Binary files /dev/null and b/2018/shaders/shaders_d3d10_1.pack differ diff --git a/2018/shaders/shaders_d3d11.pack b/2018/shaders/shaders_d3d11.pack new file mode 100644 index 0000000..898c8cb Binary files /dev/null and b/2018/shaders/shaders_d3d11.pack differ diff --git a/2018/shaders/shaders_d3d9.pack b/2018/shaders/shaders_d3d9.pack new file mode 100644 index 0000000..3df7b32 Binary files /dev/null and b/2018/shaders/shaders_d3d9.pack differ diff --git a/2018/shaders/shaders_glsl.pack b/2018/shaders/shaders_glsl.pack new file mode 100644 index 0000000..708acdb Binary files /dev/null and b/2018/shaders/shaders_glsl.pack differ diff --git a/2018/shaders/shaders_glsl3.pack b/2018/shaders/shaders_glsl3.pack new file mode 100644 index 0000000..5789d2d Binary files /dev/null and b/2018/shaders/shaders_glsl3.pack differ diff --git a/2018/shaders/shaders_glsl3_old.pack b/2018/shaders/shaders_glsl3_old.pack new file mode 100644 index 0000000..5cf2c72 Binary files /dev/null and b/2018/shaders/shaders_glsl3_old.pack differ diff --git a/2018/shaders/shaders_glsl_old.pack b/2018/shaders/shaders_glsl_old.pack new file mode 100644 index 0000000..8eda1aa Binary files /dev/null and b/2018/shaders/shaders_glsl_old.pack differ diff --git a/2018/shaders/shaders_vulkan_desktop.pack b/2018/shaders/shaders_vulkan_desktop.pack new file mode 100644 index 0000000..3eb9975 Binary files /dev/null and b/2018/shaders/shaders_vulkan_desktop.pack differ diff --git a/2018/shaders/shaders_vulkan_desktop_old.pack b/2018/shaders/shaders_vulkan_desktop_old.pack new file mode 100644 index 0000000..3c144f8 Binary files /dev/null and b/2018/shaders/shaders_vulkan_desktop_old.pack differ