From 7f493f682503f5186308de7b8f74b5b49233cfe4 Mon Sep 17 00:00:00 2001 From: chai <215380520@qq.com> Date: Thu, 2 Nov 2023 11:51:31 +0800 Subject: +init --- .gitignore | 1 + GameCode/.gitignore | 399 ++ GameCode/AchievementManager.cs | 78 + GameCode/AfterMatchUIManager.cs | 251 ++ GameCode/AimbotProjectile.cs | 166 + GameCode/AnimateSizeAndDestroy.cs | 30 + GameCode/ApplyUpgradeIndicatorColor.cs | 15 + GameCode/AttackCooldownAnimation.cs | 50 + GameCode/AudioDayNightFader.cs | 87 + GameCode/AudioSet.cs | 403 ++ GameCode/AutoAttack.cs | 102 + GameCode/AutoAttackHighestHealth.cs | 15 + GameCode/AutoAttackLowestHealth.cs | 17 + GameCode/AutoRevive.cs | 91 + GameCode/BackToTitlescreenUIHelper.cs | 9 + GameCode/BackupAudioListener.cs | 24 + GameCode/BakeTrail.cs | 38 + GameCode/BarricadeDamage.cs | 63 + GameCode/BeforeGamePopUp.cs | 11 + GameCode/BillboardAlign.cs | 18 + GameCode/BlacksmithUpgrade.cs | 88 + GameCode/BlacksmithUpgrades.cs | 35 + GameCode/BoatAnimation.cs | 37 + GameCode/BuildSlot.cs | 616 +++ GameCode/BuildingDestructionHandler.cs | 62 + GameCode/BuildingFXProcessor.cs | 65 + GameCode/BuildingInteractor.cs | 437 ++ GameCode/BuildingMeshTracker.cs | 59 + GameCode/CameraBounds.cs | 135 + GameCode/CameraController.cs | 56 + GameCode/CameraRig.cs | 120 + GameCode/CancelOrOpenPauseMenu.cs | 30 + GameCode/Checkbox.cs | 29 + GameCode/Choice.cs | 22 + GameCode/ChoiceManager.cs | 83 + GameCode/ChoiceUI.cs | 48 + GameCode/ChoiceUIFrameHelper.cs | 103 + GameCode/Coin.cs | 137 + GameCode/CoinSpawner.cs | 63 + GameCode/Coinslot.cs | 76 + GameCode/ColorAndLightManager.cs | 235 + GameCode/Colorscheme.cs | 98 + GameCode/CommandUnits.cs | 261 ++ GameCode/CostDisplay.cs | 256 ++ GameCode/CustomPostProcess.cs | 62 + GameCode/DamageModifyer.cs | 39 + GameCode/DayNightCycle.cs | 202 + GameCode/DaytimeDisplay.cs | 15 + GameCode/DaytimeSensitiveActivation.cs | 49 + GameCode/DaytimeSensitiveLight.cs | 83 + GameCode/DebugBuildingDestroyer.cs | 33 + GameCode/DebugCoinDisplay.cs | 19 + GameCode/DebugController.cs | 133 + GameCode/DemoQuitSwitch.cs | 11 + GameCode/DestroyAfter.cs | 15 + GameCode/DestroyOrDisableOnEnable.cs | 27 + GameCode/DisableOnStart.cs | 9 + GameCode/EnableAllChildren.cs | 12 + GameCode/EndOfMatchScoreUIHelper.cs | 636 +++ GameCode/EndOfMatchUI.cs | 39 + GameCode/EnemyScreenMarkerUIHelper.cs | 54 + GameCode/EnemySpawnManager.cs | 19 + GameCode/EnemySpawner.cs | 287 ++ GameCode/EnumSelector.cs | 163 + GameCode/EnumSelectorButtonAnimation.cs | 14 + GameCode/Equippable.cs | 15 + GameCode/EquippableBuildingUpgrade.cs | 6 + GameCode/EquippableMutation.cs | 7 + GameCode/EquippablePerk.cs | 6 + GameCode/EquippableWeapon.cs | 6 + GameCode/FakeChildTo.cs | 33 + GameCode/FakeTransorm.cs | 41 + GameCode/FireArcherBurn.cs | 83 + GameCode/FishingHarbour.cs | 58 + GameCode/FishingHarbourUpgrade.cs | 15 + GameCode/ForceCameraPosOnEnable.cs | 27 + GameCode/FromToAnimation.cs | 45 + GameCode/GPUInstanced.cs | 80 + GameCode/GPUInstancingManager.cs | 119 + GameCode/GateOpener.cs | 172 + GameCode/GlobalAudioListener.cs | 48 + GameCode/GraphDrawer.cs | 125 + GameCode/HealBoostMA.cs | 55 + GameCode/Healthbar.cs | 172 + GameCode/HealthbarMulti.cs | 46 + GameCode/HighscorePreviewUI.cs | 66 + GameCode/HighscoreTable.cs | 99 + GameCode/HotOilTower.cs | 97 + GameCode/Hp.cs | 375 ++ GameCode/InGameResignUIHelper.cs | 10 + GameCode/IncomeModifyer.cs | 17 + GameCode/InteractorBase.cs | 27 + GameCode/Invulnerable.cs | 16 + GameCode/KeepRelativeRotationTo.cs | 59 + GameCode/KeyframedBoss.cs | 178 + GameCode/LaunchableDefenseMechanismInteractor.cs | 83 + GameCode/LaunchableProjectile.cs | 66 + GameCode/LevelAudio.cs | 69 + GameCode/LevelBorder.cs | 98 + GameCode/LevelData.cs | 46 + GameCode/LevelInteractor.cs | 280 ++ GameCode/LevelProgressManager.cs | 57 + GameCode/LevelSelectManager.cs | 114 + GameCode/LevelSelectUIFrameHelper.cs | 17 + GameCode/LevelUpScreenAnimation.cs | 29 + GameCode/LimitDeltaTime.cs | 11 + GameCode/LimitedLifetime.cs | 11 + GameCode/LoadSceneOnTop.cs | 25 + GameCode/LoadoutUIHelper.cs | 398 ++ GameCode/LocalGamestate.cs | 131 + GameCode/LvlSelectTabButton.cs | 51 + GameCode/ManualAttack.cs | 247 + GameCode/MaterialFlasherFX.cs | 77 + GameCode/MetaLevel.cs | 9 + GameCode/MillRotor.cs | 44 + GameCode/Mill_ImprovedPlow.cs | 26 + GameCode/Mill_ImprovementExplosiveTrap.cs | 64 + GameCode/Mill_ImprovementWindSpirits.cs | 104 + GameCode/Mill_Improvement_Scarecrows.cs | 26 + GameCode/MineShaft.cs | 141 + GameCode/MusicManager.cs | 163 + GameCode/NightCall.cs | 140 + GameCode/NightLight.cs | 98 + GameCode/Nighthorn.cs | 168 + GameCode/NightscoreUI.cs | 295 ++ GameCode/OnDamageFeedbackHandler.cs | 28 + GameCode/OneShotAnimationBase.cs | 6 + GameCode/PathMesher.cs | 339 ++ GameCode/PathfindMovement.cs | 15 + GameCode/PathfindMovementEnemy.cs | 283 ++ GameCode/PathfindMovementPlayerunit.cs | 326 ++ GameCode/PauseUILoadoutHelper.cs | 161 + GameCode/PerkCooldownModifyer.cs | 20 + GameCode/PerkCostModifyer.cs | 21 + GameCode/PerkDamageModifyerPlayerunitAuto.cs | 26 + GameCode/PerkDestroyGameObjectModifyer.cs | 28 + GameCode/PerkHpModifyer.cs | 31 + GameCode/PerkIncomeModifyer.cs | 24 + GameCode/PerkIndestructible.cs | 24 + GameCode/PerkManager.cs | 193 + GameCode/PerkPoint.cs | 6 + GameCode/PerkRangeModifyer.cs | 28 + GameCode/PerkSelectionGroup.cs | 165 + GameCode/PerkSelectionItem.cs | 80 + GameCode/PerkSelectionTooltipHelper.cs | 115 + GameCode/PerkWeaponModifyer.cs | 19 + GameCode/PhysicalCoinAnimator.cs | 26 + GameCode/PlayLevelButton.cs | 40 + GameCode/PlayMusicOnStart.cs | 31 + GameCode/PlayOneShotAfterSeconds.cs | 22 + GameCode/PlayerAttack.cs | 30 + GameCode/PlayerAttackAnimator.cs | 27 + GameCode/PlayerAttackTargetFacer.cs | 66 + GameCode/PlayerCharacterAudio.cs | 94 + GameCode/PlayerHpRegen.cs | 60 + GameCode/PlayerInteraction.cs | 205 + GameCode/PlayerManager.cs | 68 + GameCode/PlayerMovement.cs | 152 + GameCode/PlayerScept.cs | 85 + GameCode/PlayerUpgradeManager.cs | 70 + GameCode/PlayerWeaponAudio.cs | 55 + GameCode/PlayerWeaponVisuals.cs | 31 + GameCode/PositionAnimation.cs | 42 + GameCode/PowerTowerPerk.cs | 56 + GameCode/PracticeTargetCoinDrop.cs | 33 + GameCode/PriorityAudioListener.cs | 27 + GameCode/ProductionBar.cs | 23 + GameCode/ProjectileAudio.cs | 37 + GameCode/ProjectileImpactParticles.cs | 22 + GameCode/ProjectileSpawnAudio.cs | 11 + GameCode/Quest.cs | 114 + GameCode/QuestConditionEquippable.cs | 33 + GameCode/QuestEntry.cs | 87 + GameCode/QuestMenu.cs | 21 + GameCode/QuestTagUI.cs | 107 + GameCode/RacerRoll.cs | 16 + GameCode/ReduceChildrensBuildRequirementIfPerk.cs | 24 + GameCode/ResetAudioSettings.cs | 13 + GameCode/ResolutionExtensions.cs | 13 + GameCode/RevivePanel.cs | 29 + GameCode/RidingDamager.cs | 75 + GameCode/RiverScroller.cs | 18 + GameCode/RotateForwardToRVOVelocity.cs | 64 + GameCode/SaveLoadManager.cs | 243 + GameCode/ScaleAnimation.cs | 42 + GameCode/ScalePulse.cs | 18 + GameCode/SceneNameToLevelData.cs | 6 + GameCode/SceneTransitionManager.cs | 254 ++ GameCode/ScoreManager.cs | 150 + GameCode/ScoreTag.cs | 21 + GameCode/ScreenMarker.cs | 197 + GameCode/ScreenMarkerCanvasHelper.cs | 19 + GameCode/ScreenMarkerIcon.cs | 6 + GameCode/ScreenMarkerManager.cs | 284 ++ GameCode/SelfDestructWhenInRangeOf.cs | 33 + GameCode/SetStateWhenMacOSX.cs | 13 + GameCode/SetWidthToTarget.cs | 29 + GameCode/SettingsAntiAliasing.cs | 26 + GameCode/SettingsAudioVolume.cs | 26 + GameCode/SettingsFullscreen.cs | 19 + GameCode/SettingsLanguage.cs | 32 + GameCode/SettingsLanguageReset.cs | 14 + GameCode/SettingsManager.cs | 370 ++ GameCode/SettingsPostProcessing.cs | 19 + GameCode/SettingsPostProcessingHelper.cs | 18 + GameCode/SettingsRenderScale.cs | 24 + GameCode/SettingsResetUnitsMorning.cs | 19 + GameCode/SettingsResetVideo.cs | 13 + GameCode/SettingsResolution.cs | 40 + GameCode/SettingsShadowResolution.cs | 26 + GameCode/SettingsUIHelper.cs | 114 + GameCode/SettingsUseLargeUI.cs | 22 + GameCode/SharpCornerMidigator.cs | 46 + GameCode/SimpleRotator.cs | 23 + GameCode/SimpleUIScaler.cs | 43 + GameCode/SimpleWalk.cs | 55 + GameCode/SizeRectangleToMeshBounds.cs | 20 + GameCode/Spawn.cs | 171 + GameCode/SpinAnimation.cs | 45 + GameCode/SplashDamageArea.cs | 51 + GameCode/StabMA.cs | 71 + GameCode/SteamManager.cs | 209 + GameCode/SuperSimpleOceanAnimation.cs | 47 + GameCode/SuspendPlayerCollisionUntilNoOverlap.cs | 96 + GameCode/TFUIAudioHelper.cs | 53 + GameCode/TFUIBlockoutElement.cs | 44 + GameCode/TFUICheckboxMouseCatcher.cs | 43 + GameCode/TFUIEnumMouseCatcher.cs | 51 + GameCode/TFUIEnumSelectorButton.cs | 40 + GameCode/TFUIEquippable.cs | 307 ++ GameCode/TFUISlider.cs | 141 + GameCode/TFUISliderDragArea.cs | 127 + GameCode/TFUITextButton.cs | 195 + GameCode/TFUIUpgradeChoice.cs | 203 + GameCode/TagManager.cs | 223 + GameCode/TaggedObject.cs | 59 + GameCode/TargetPriority.cs | 127 + GameCode/TextBackgroundFitter.cs | 24 + GameCode/Thronefall.csproj | 344 ++ GameCode/Thronefall.sln | 25 + GameCode/ThronefallAudioManager.cs | 342 ++ GameCode/ThronefallUIElement.cs | 166 + GameCode/TimesensitiveLight.cs | 68 + GameCode/TitleScreenPopUpHelper.cs | 28 + GameCode/TitleScreenUIHelper.cs | 21 + GameCode/Tooltip.cs | 63 + GameCode/TooltipManager.cs | 102 + GameCode/TreasureChestUIHelper.cs | 39 + GameCode/TreasuryUI.cs | 224 + GameCode/TutorialManager.cs | 662 +++ GameCode/UIFrame.cs | 331 ++ GameCode/UIFrameManager.cs | 286 ++ GameCode/UIParentResizer.cs | 40 + GameCode/UIScaleHandler.cs | 45 + GameCode/UnitAttackAnimator.cs | 31 + GameCode/UnitAudio.cs | 371 ++ GameCode/UnitCommandRadiusAnimation.cs | 69 + GameCode/UnitRespawnerForBuildings.cs | 113 + GameCode/UnitSpawnAppear.cs | 36 + GameCode/UnitySerializedDictionary.cs | 35 + GameCode/UpgradeAssassinsTraining.cs | 16 + GameCode/UpgradeBuildersGuild.cs | 51 + GameCode/UpgradeCastleUp.cs | 46 + GameCode/UpgradeCommander.cs | 47 + GameCode/UpgradeGodlyCurse.cs | 9 + GameCode/UpgradeMagicArmor.cs | 18 + GameCode/UpgradePlayerDmg.cs | 11 + GameCode/UpgradePlayerHp.cs | 17 + GameCode/VersionNumberDisplay.cs | 12 + GameCode/Wave.cs | 45 + GameCode/WaveCountPopUp.cs | 77 + GameCode/WaveDescriptionUI.cs | 26 + GameCode/Weapon.cs | 225 + GameCode/WeaponEquipper.cs | 29 + GameCode/Wiggler.cs | 46 + GameCode/WigglerAnimatedVelocity.cs | 45 + GameCode/WigglerAnimationState.cs | 6 + GameCode/WigglerVelocity.cs | 40 + GameCode/WishlistButton.cs | 9 + Rewired/Rewired.Data/UserDataStore_PlayerPrefs.cs | 1358 ++++++ .../ControllerUIEffect.cs | 57 + .../ControllerUIElement.cs | 186 + .../GamepadTemplateUI.cs | 417 ++ Rewired/Rewired.Demos/Bullet.cs | 30 + Rewired/Rewired.Demos/ControlRemappingDemo1.cs | 1797 ++++++++ Rewired/Rewired.Demos/CustomControllerDemo.cs | 144 + .../Rewired.Demos/CustomControllerDemo_Player.cs | 58 + Rewired/Rewired.Demos/CustomControllersTiltDemo.cs | 47 + .../DualShock4SpecialFeaturesExample.cs | 219 + .../Rewired.Demos/EightPlayersExample_Player.cs | 71 + .../FallbackJoystickIdentificationDemo.cs | 114 + Rewired/Rewired.Demos/PlayerMouseSpriteExample.cs | 116 + .../PlayerPointerEventHandlerExample.cs | 138 + .../PressAnyButtonToJoinExample_Assigner.cs | 57 + .../PressAnyButtonToJoinExample_GamePlayer.cs | 67 + .../PressStartToJoinExample_Assigner.cs | 87 + .../PressStartToJoinExample_GamePlayer.cs | 57 + .../SimpleCombinedKeyboardMouseRemapping.cs | 225 + Rewired/Rewired.Demos/SimpleControlRemapping.cs | 257 ++ Rewired/Rewired.Demos/TouchButtonExample.cs | 52 + Rewired/Rewired.Demos/TouchJoystickExample.cs | 110 + Rewired/Rewired.Demos/UIPointer.cs | 98 + .../PlayerPointerEventData.cs | 41 + .../PointerEventType.cs | 7 + .../RewiredEventSystem.cs | 49 + .../RewiredPointerInputModule.cs | 781 ++++ .../RewiredStandaloneInputModule.cs | 1415 ++++++ .../Rewired.Internal/ControllerTemplateFactory.cs | 59 + Rewired/Rewired.Utils/ExternalTools.cs | 171 + Rewired/Rewired/FlightPedalsTemplate.cs | 25 + Rewired/Rewired/FlightYokeTemplate.cs | 265 ++ Rewired/Rewired/GamepadTemplate.cs | 149 + Rewired/Rewired/HOTASTemplate.cs | 525 +++ Rewired/Rewired/IFlightPedalsTemplate.cs | 10 + Rewired/Rewired/IFlightYokeTemplate.cs | 102 + Rewired/Rewired/IGamepadTemplate.cs | 62 + Rewired/Rewired/IHOTASTemplate.cs | 180 + Rewired/Rewired/IRacingWheelTemplate.cs | 88 + Rewired/Rewired/ISixDofControllerTemplate.cs | 86 + Rewired/Rewired/InputManager.cs | 81 + Rewired/Rewired/RacingWheelTemplate.cs | 189 + Rewired/Rewired/SixDofControllerTemplate.cs | 229 + Thronefall/.gitignore | 399 ++ Thronefall/AchievementManager.cs | 78 + Thronefall/AfterMatchUIManager.cs | 251 ++ Thronefall/AimbotProjectile.cs | 166 + Thronefall/AnimateSizeAndDestroy.cs | 30 + Thronefall/ApplyUpgradeIndicatorColor.cs | 15 + Thronefall/Ara/AraTrail.cs | 947 ++++ Thronefall/Ara/ColorFromSpeed.cs | 40 + Thronefall/Ara/ElasticArray.cs | 160 + Thronefall/Ara/ElectricalArc.cs | 57 + Thronefall/Ara/TireTrack.cs | 50 + Thronefall/Ara/TrailSection.cs | 57 + Thronefall/AttackCooldownAnimation.cs | 50 + Thronefall/AudioDayNightFader.cs | 87 + Thronefall/AudioSet.cs | 403 ++ Thronefall/AutoAttack.cs | 102 + Thronefall/AutoAttackHighestHealth.cs | 15 + Thronefall/AutoAttackLowestHealth.cs | 17 + Thronefall/AutoRevive.cs | 91 + Thronefall/BackToTitlescreenUIHelper.cs | 9 + Thronefall/BackupAudioListener.cs | 24 + Thronefall/BakeTrail.cs | 38 + Thronefall/BarricadeDamage.cs | 63 + Thronefall/BeforeGamePopUp.cs | 11 + Thronefall/BillboardAlign.cs | 18 + Thronefall/BlacksmithUpgrade.cs | 88 + Thronefall/BlacksmithUpgrades.cs | 35 + Thronefall/BoatAnimation.cs | 37 + Thronefall/BuildSlot.cs | 616 +++ Thronefall/BuildingDestructionHandler.cs | 62 + Thronefall/BuildingFXProcessor.cs | 65 + Thronefall/BuildingInteractor.cs | 437 ++ Thronefall/BuildingMeshTracker.cs | 59 + Thronefall/CameraBounds.cs | 135 + Thronefall/CameraController.cs | 56 + Thronefall/CameraRig.cs | 120 + Thronefall/CancelOrOpenPauseMenu.cs | 30 + Thronefall/Checkbox.cs | 29 + Thronefall/Choice.cs | 22 + Thronefall/ChoiceManager.cs | 83 + Thronefall/ChoiceUI.cs | 48 + Thronefall/ChoiceUIFrameHelper.cs | 103 + Thronefall/Coin.cs | 137 + Thronefall/CoinSpawner.cs | 63 + Thronefall/Coinslot.cs | 76 + Thronefall/ColorAndLightManager.cs | 235 + Thronefall/Colorscheme.cs | 98 + Thronefall/CommandUnits.cs | 261 ++ Thronefall/CostDisplay.cs | 256 ++ Thronefall/CustomPostProcess.cs | 62 + Thronefall/DamageModifyer.cs | 39 + Thronefall/DayNightCycle.cs | 202 + Thronefall/DaytimeDisplay.cs | 15 + Thronefall/DaytimeSensitiveActivation.cs | 49 + Thronefall/DaytimeSensitiveLight.cs | 83 + Thronefall/DebugBuildingDestroyer.cs | 33 + Thronefall/DebugCoinDisplay.cs | 19 + Thronefall/DebugController.cs | 133 + Thronefall/DemoQuitSwitch.cs | 11 + Thronefall/DestroyAfter.cs | 15 + Thronefall/DestroyOrDisableOnEnable.cs | 27 + Thronefall/DisableOnStart.cs | 9 + Thronefall/EnableAllChildren.cs | 12 + Thronefall/EndOfMatchScoreUIHelper.cs | 636 +++ Thronefall/EndOfMatchUI.cs | 39 + Thronefall/EnemyScreenMarkerUIHelper.cs | 54 + Thronefall/EnemySpawnManager.cs | 19 + Thronefall/EnemySpawner.cs | 287 ++ Thronefall/EnumSelector.cs | 163 + Thronefall/EnumSelectorButtonAnimation.cs | 14 + Thronefall/Equippable.cs | 15 + Thronefall/EquippableBuildingUpgrade.cs | 6 + Thronefall/EquippableMutation.cs | 7 + Thronefall/EquippablePerk.cs | 6 + Thronefall/EquippableWeapon.cs | 6 + Thronefall/FakeChildTo.cs | 33 + Thronefall/FakeTransorm.cs | 41 + Thronefall/FireArcherBurn.cs | 83 + Thronefall/FishingHarbour.cs | 58 + Thronefall/FishingHarbourUpgrade.cs | 15 + Thronefall/FlatKit/BlitTexturePass.cs | 80 + Thronefall/FlatKit/Buoyancy.cs | 105 + Thronefall/FlatKit/FlatKitFog.cs | 175 + Thronefall/FlatKit/FlatKitOutline.cs | 139 + Thronefall/FlatKit/FogSettings.cs | 59 + Thronefall/FlatKit/OutlineSettings.cs | 61 + Thronefall/FlatKit/UvScroller.cs | 34 + Thronefall/ForceCameraPosOnEnable.cs | 27 + Thronefall/FromToAnimation.cs | 45 + Thronefall/GPUInstanced.cs | 80 + Thronefall/GPUInstancingManager.cs | 119 + Thronefall/GateOpener.cs | 172 + Thronefall/GlobalAudioListener.cs | 48 + Thronefall/GraphDrawer.cs | 125 + Thronefall/HealBoostMA.cs | 55 + Thronefall/Healthbar.cs | 172 + Thronefall/HealthbarMulti.cs | 46 + Thronefall/HighscorePreviewUI.cs | 66 + Thronefall/HighscoreTable.cs | 99 + Thronefall/HotOilTower.cs | 97 + Thronefall/Hp.cs | 375 ++ Thronefall/I2.Loc.SimpleJSON/JSON.cs | 9 + Thronefall/I2.Loc.SimpleJSON/JSONArray.cs | 127 + Thronefall/I2.Loc.SimpleJSON/JSONBinaryTag.cs | 12 + Thronefall/I2.Loc.SimpleJSON/JSONClass.cs | 171 + Thronefall/I2.Loc.SimpleJSON/JSONData.cs | 92 + Thronefall/I2.Loc.SimpleJSON/JSONLazyCreator.cs | 193 + Thronefall/I2.Loc.SimpleJSON/JSONNode.cs | 526 +++ Thronefall/I2.Loc/ArabicMapping.cs | 14 + Thronefall/I2.Loc/ArabicTable.cs | 80 + Thronefall/I2.Loc/AutoChangeCultureInfo.cs | 11 + Thronefall/I2.Loc/BaseSpecializationManager.cs | 52 + Thronefall/I2.Loc/CallbackNotification.cs | 15 + Thronefall/I2.Loc/CoroutineManager.cs | 40 + Thronefall/I2.Loc/CustomLocalizeCallback.cs | 26 + Thronefall/I2.Loc/EventCallback.cs | 29 + Thronefall/I2.Loc/Example_ChangeLanguage.cs | 29 + Thronefall/I2.Loc/Example_LocalizedString.cs | 31 + Thronefall/I2.Loc/GeneralArabicLetters.cs | 46 + Thronefall/I2.Loc/GlobalParametersExample.cs | 17 + Thronefall/I2.Loc/GoogleLanguages.cs | 2873 ++++++++++++ Thronefall/I2.Loc/GoogleTranslation.cs | 575 +++ Thronefall/I2.Loc/HindiFixer.cs | 83 + Thronefall/I2.Loc/I2BasePersistentStorage.cs | 197 + Thronefall/I2.Loc/I2CustomPersistentStorage.cs | 5 + Thronefall/I2.Loc/I2Utils.cs | 301 ++ Thronefall/I2.Loc/ILanguageSource.cs | 6 + Thronefall/I2.Loc/ILocalizationParamsManager.cs | 6 + Thronefall/I2.Loc/ILocalizeTarget.cs | 22 + Thronefall/I2.Loc/ILocalizeTargetDescriptor.cs | 16 + Thronefall/I2.Loc/IResourceManager_Bundles.cs | 9 + Thronefall/I2.Loc/IsolatedArabicLetters.cs | 46 + Thronefall/I2.Loc/LanguageData.cs | 67 + Thronefall/I2.Loc/LanguageSource.cs | 145 + Thronefall/I2.Loc/LanguageSourceAsset.cs | 21 + Thronefall/I2.Loc/LanguageSourceData.cs | 1661 +++++++ Thronefall/I2.Loc/LocalizationManager.cs | 1056 +++++ Thronefall/I2.Loc/LocalizationParamsManager.cs | 97 + Thronefall/I2.Loc/LocalizationReader.cs | 195 + Thronefall/I2.Loc/Localize.cs | 464 ++ Thronefall/I2.Loc/LocalizeDropdown.cs | 100 + Thronefall/I2.Loc/LocalizeTarget.cs | 25 + Thronefall/I2.Loc/LocalizeTargetDesc.cs | 17 + Thronefall/I2.Loc/LocalizeTargetDesc_Child.cs | 9 + Thronefall/I2.Loc/LocalizeTargetDesc_Prefab.cs | 9 + Thronefall/I2.Loc/LocalizeTargetDesc_Type.cs | 23 + .../I2.Loc/LocalizeTarget_TextMeshPro_Label.cs | 257 ++ .../I2.Loc/LocalizeTarget_TextMeshPro_UGUI.cs | 116 + .../LocalizeTarget_UnityStandard_AudioSource.cs | 68 + .../I2.Loc/LocalizeTarget_UnityStandard_Child.cs | 76 + .../LocalizeTarget_UnityStandard_MeshRenderer.cs | 89 + .../I2.Loc/LocalizeTarget_UnityStandard_Prefab.cs | 108 + .../LocalizeTarget_UnityStandard_SpriteRenderer.cs | 62 + .../LocalizeTarget_UnityStandard_TextMesh.cs | 92 + .../LocalizeTarget_UnityStandard_VideoPlayer.cs | 63 + Thronefall/I2.Loc/LocalizeTarget_UnityUI_Image.cs | 70 + .../I2.Loc/LocalizeTarget_UnityUI_RawImage.cs | 62 + Thronefall/I2.Loc/LocalizeTarget_UnityUI_Text.cs | 156 + Thronefall/I2.Loc/LocalizedString.cs | 45 + Thronefall/I2.Loc/PersistentStorage.cs | 104 + Thronefall/I2.Loc/RTLFixer.cs | 79 + Thronefall/I2.Loc/RTLFixerTool.cs | 404 ++ Thronefall/I2.Loc/RealTimeTranslation.cs | 118 + Thronefall/I2.Loc/RegisterBundlesManager.cs | 25 + .../I2.Loc/RegisterCallback_AllowSyncFromGoogle.cs | 26 + Thronefall/I2.Loc/RegisterGlobalParameters.cs | 25 + Thronefall/I2.Loc/ResourceManager.cs | 160 + Thronefall/I2.Loc/SetLanguage.cs | 22 + Thronefall/I2.Loc/SetLanguageDropdown.cs | 39 + Thronefall/I2.Loc/SpecializationManager.cs | 156 + Thronefall/I2.Loc/StringObfucator.cs | 64 + Thronefall/I2.Loc/TashkeelLocation.cs | 14 + Thronefall/I2.Loc/TermData.cs | 123 + Thronefall/I2.Loc/TermsPopup.cs | 13 + Thronefall/I2.Loc/ToggleLanguage.cs | 27 + Thronefall/I2.Loc/TranslationFlag.cs | 7 + Thronefall/I2.Loc/TranslationJob.cs | 24 + Thronefall/I2.Loc/TranslationJob_GET.cs | 72 + Thronefall/I2.Loc/TranslationJob_Main.cs | 96 + Thronefall/I2.Loc/TranslationJob_POST.cs | 51 + Thronefall/I2.Loc/TranslationJob_WEB.cs | 154 + Thronefall/I2.Loc/TranslationJob_WWW.cs | 17 + Thronefall/I2.Loc/TranslationQuery.cs | 16 + Thronefall/I2.Loc/eLanguageDataFlags.cs | 8 + Thronefall/I2.Loc/ePluralType.cs | 11 + Thronefall/I2.Loc/eSpreadsheetUpdateMode.cs | 9 + Thronefall/I2.Loc/eTermType.cs | 17 + Thronefall/InGameResignUIHelper.cs | 10 + Thronefall/IncomeModifyer.cs | 17 + Thronefall/InteractorBase.cs | 27 + Thronefall/Invulnerable.cs | 16 + Thronefall/KeepRelativeRotationTo.cs | 59 + Thronefall/KeyframedBoss.cs | 178 + Thronefall/LaunchableDefenseMechanismInteractor.cs | 83 + Thronefall/LaunchableProjectile.cs | 66 + Thronefall/LevelAudio.cs | 69 + Thronefall/LevelBorder.cs | 98 + Thronefall/LevelData.cs | 46 + Thronefall/LevelInteractor.cs | 280 ++ Thronefall/LevelProgressManager.cs | 57 + Thronefall/LevelSelectManager.cs | 114 + Thronefall/LevelSelectUIFrameHelper.cs | 17 + Thronefall/LevelUpScreenAnimation.cs | 29 + Thronefall/LimitDeltaTime.cs | 11 + Thronefall/LimitedLifetime.cs | 11 + Thronefall/LoadSceneOnTop.cs | 25 + Thronefall/LoadoutUIHelper.cs | 398 ++ Thronefall/LocalGamestate.cs | 131 + Thronefall/LvlSelectTabButton.cs | 51 + Thronefall/ManualAttack.cs | 247 + Thronefall/MaterialFlasherFX.cs | 77 + Thronefall/MetaLevel.cs | 9 + Thronefall/MillRotor.cs | 44 + Thronefall/Mill_ImprovedPlow.cs | 26 + Thronefall/Mill_ImprovementExplosiveTrap.cs | 64 + Thronefall/Mill_ImprovementWindSpirits.cs | 104 + Thronefall/Mill_Improvement_Scarecrows.cs | 26 + Thronefall/MineShaft.cs | 141 + .../MoreMountains.Feedbacks/OneShotAudioTrigger.cs | 18 + Thronefall/MusicManager.cs | 163 + Thronefall/NGS.MeshFusionPro/AfterCombineAction.cs | 8 + Thronefall/NGS.MeshFusionPro/BinaryTree.cs | 156 + Thronefall/NGS.MeshFusionPro/BinaryTreeDrawer.cs | 22 + Thronefall/NGS.MeshFusionPro/BinaryTreeNode.cs | 48 + Thronefall/NGS.MeshFusionPro/BoundsHelper.cs | 39 + .../NGS.MeshFusionPro/CombineErrorStrategy.cs | 7 + Thronefall/NGS.MeshFusionPro/CombineMethod.cs | 6 + Thronefall/NGS.MeshFusionPro/CombineSource.cs | 92 + Thronefall/NGS.MeshFusionPro/CombineTree.cs | 112 + Thronefall/NGS.MeshFusionPro/CombineTreeNode.cs | 45 + Thronefall/NGS.MeshFusionPro/CombinedLODGroup.cs | 265 ++ .../NGS.MeshFusionPro/CombinedLODGroupMatcher.cs | 20 + .../NGS.MeshFusionPro/CombinedLODGroupPart.cs | 49 + Thronefall/NGS.MeshFusionPro/CombinedMesh.cs | 86 + Thronefall/NGS.MeshFusionPro/CombinedMeshData.cs | 17 + .../NGS.MeshFusionPro/CombinedMeshDataInternal.cs | 124 + .../NGS.MeshFusionPro/CombinedMeshFactory.cs | 43 + Thronefall/NGS.MeshFusionPro/CombinedMeshPart.cs | 26 + .../NGS.MeshFusionPro/CombinedMeshPartInternal.cs | 16 + Thronefall/NGS.MeshFusionPro/CombinedObject.cs | 209 + .../NGS.MeshFusionPro/CombinedObjectMatcher.cs | 10 + Thronefall/NGS.MeshFusionPro/CombinedObjectPart.cs | 35 + .../NGS.MeshFusionPro/DynamicCombineSource.cs | 70 + .../NGS.MeshFusionPro/DynamicCombinedObject.cs | 155 + .../DynamicCombinedObjectMatcher.cs | 39 + .../NGS.MeshFusionPro/DynamicCombinedObjectPart.cs | 44 + .../DynamicCombinedObjectPartInternal.cs | 61 + .../NGS.MeshFusionPro/DynamicMeshFusionSource.cs | 130 + .../NGS.MeshFusionPro/DynamicObjectsCombiner.cs | 42 + .../NGS.MeshFusionPro/IAsyncCombinedMeshMover.cs | 10 + Thronefall/NGS.MeshFusionPro/IBinaryTreeNode.cs | 20 + Thronefall/NGS.MeshFusionPro/ICombineSource.cs | 25 + .../NGS.MeshFusionPro/ICombinedMeshFactory.cs | 8 + Thronefall/NGS.MeshFusionPro/ICombinedMeshMover.cs | 10 + Thronefall/NGS.MeshFusionPro/ICombinedObject.cs | 16 + .../NGS.MeshFusionPro/ICombinedObjectPart.cs | 18 + Thronefall/NGS.MeshFusionPro/IMeshCombiner.cs | 9 + Thronefall/NGS.MeshFusionPro/IMeshCutter.cs | 11 + Thronefall/NGS.MeshFusionPro/IMeshToolsFactory.cs | 8 + .../IMovableCombinedMeshFactory.cs | 6 + .../NGS.MeshFusionPro/ISourceTrackingStrategy.cs | 6 + Thronefall/NGS.MeshFusionPro/JobsMeshMoverLW.cs | 139 + Thronefall/NGS.MeshFusionPro/JobsMeshMoverSTD.cs | 144 + .../NGS.MeshFusionPro/JobsMovableMeshLWFactory.cs | 18 + .../NGS.MeshFusionPro/JobsMovableMeshSTDFactory.cs | 18 + .../NGS.MeshFusionPro/LODGroupCombineSource.cs | 106 + Thronefall/NGS.MeshFusionPro/LODGroupSettings.cs | 63 + Thronefall/NGS.MeshFusionPro/LODGroupsCombiner.cs | 34 + .../NGS.MeshFusionPro/LODMeshFusionSource.cs | 141 + Thronefall/NGS.MeshFusionPro/LightweightVertex.cs | 95 + Thronefall/NGS.MeshFusionPro/MatrixHelper.cs | 18 + Thronefall/NGS.MeshFusionPro/MeshCombineInfo.cs | 43 + Thronefall/NGS.MeshFusionPro/MeshCombinerBase.cs | 44 + .../NGS.MeshFusionPro/MeshCombinerSimpleLW.cs | 29 + .../NGS.MeshFusionPro/MeshCombinerSimpleSTD.cs | 42 + Thronefall/NGS.MeshFusionPro/MeshCutterSimpleLW.cs | 66 + .../NGS.MeshFusionPro/MeshCutterSimpleSTD.cs | 138 + Thronefall/NGS.MeshFusionPro/MeshCuttingInfo.cs | 20 + Thronefall/NGS.MeshFusionPro/MeshDataListsSTD.cs | 83 + .../NGS.MeshFusionPro/MeshDataNativeArraysLW.cs | 131 + .../NGS.MeshFusionPro/MeshDataNativeArraysSTD.cs | 104 + Thronefall/NGS.MeshFusionPro/MeshFusionSource.cs | 333 ++ .../NGS.MeshFusionPro/MeshSeparatorSimple.cs | 130 + Thronefall/NGS.MeshFusionPro/MeshType.cs | 7 + Thronefall/NGS.MeshFusionPro/MoveMethod.cs | 7 + Thronefall/NGS.MeshFusionPro/ObjectsCombiner.cs | 155 + Thronefall/NGS.MeshFusionPro/PartMoveInfo.cs | 16 + Thronefall/NGS.MeshFusionPro/RendererHelper.cs | 20 + Thronefall/NGS.MeshFusionPro/RendererSettings.cs | 43 + .../NGS.MeshFusionPro/RigidbodyTrackingStrategy.cs | 62 + Thronefall/NGS.MeshFusionPro/RuntimeMeshFusion.cs | 197 + Thronefall/NGS.MeshFusionPro/SimpleMeshMoverSTD.cs | 62 + .../SimpleMovableMeshSTDFactory.cs | 18 + .../NGS.MeshFusionPro/SimpleToolsLWFactory.cs | 14 + .../NGS.MeshFusionPro/SimpleToolsSTDFactory.cs | 14 + .../NGS.MeshFusionPro/SourceCombineStatus.cs | 10 + Thronefall/NGS.MeshFusionPro/SourceTracker.cs | 161 + .../StaticCombinedObjectMatcher.cs | 39 + .../NGS.MeshFusionPro/StaticMeshFusionSource.cs | 131 + .../NGS.MeshFusionPro/StaticObjectsCombiner.cs | 42 + Thronefall/NGS.MeshFusionPro/TrackingTarget.cs | 7 + .../NGS.MeshFusionPro/TransformTrackingStrategy.cs | 30 + .../NGS.MeshFusionPro/UniversalObjectsCombiner.cs | 102 + Thronefall/NGS.MeshFusionPro/VertexBufferUtil.cs | 124 + Thronefall/NightCall.cs | 140 + Thronefall/NightLight.cs | 98 + Thronefall/Nighthorn.cs | 168 + Thronefall/NightscoreUI.cs | 295 ++ Thronefall/OnDamageFeedbackHandler.cs | 28 + Thronefall/OneShotAnimationBase.cs | 6 + Thronefall/PathMesher.cs | 339 ++ Thronefall/PathfindMovement.cs | 15 + Thronefall/PathfindMovementEnemy.cs | 283 ++ Thronefall/PathfindMovementPlayerunit.cs | 326 ++ Thronefall/PauseUILoadoutHelper.cs | 161 + Thronefall/PerkCooldownModifyer.cs | 20 + Thronefall/PerkCostModifyer.cs | 21 + Thronefall/PerkDamageModifyerPlayerunitAuto.cs | 26 + Thronefall/PerkDestroyGameObjectModifyer.cs | 28 + Thronefall/PerkHpModifyer.cs | 31 + Thronefall/PerkIncomeModifyer.cs | 24 + Thronefall/PerkIndestructible.cs | 24 + Thronefall/PerkManager.cs | 193 + Thronefall/PerkPoint.cs | 6 + Thronefall/PerkRangeModifyer.cs | 28 + Thronefall/PerkSelectionGroup.cs | 165 + Thronefall/PerkSelectionItem.cs | 80 + Thronefall/PerkSelectionTooltipHelper.cs | 115 + Thronefall/PerkWeaponModifyer.cs | 19 + Thronefall/PhysicalCoinAnimator.cs | 26 + Thronefall/PlayLevelButton.cs | 40 + Thronefall/PlayMusicOnStart.cs | 31 + Thronefall/PlayOneShotAfterSeconds.cs | 22 + Thronefall/PlayerAttack.cs | 30 + Thronefall/PlayerAttackAnimator.cs | 27 + Thronefall/PlayerAttackTargetFacer.cs | 66 + Thronefall/PlayerCharacterAudio.cs | 94 + Thronefall/PlayerHpRegen.cs | 60 + Thronefall/PlayerInteraction.cs | 205 + Thronefall/PlayerManager.cs | 68 + Thronefall/PlayerMovement.cs | 152 + Thronefall/PlayerScept.cs | 85 + Thronefall/PlayerUpgradeManager.cs | 70 + Thronefall/PlayerWeaponAudio.cs | 55 + Thronefall/PlayerWeaponVisuals.cs | 31 + Thronefall/PositionAnimation.cs | 42 + Thronefall/PowerTowerPerk.cs | 56 + Thronefall/PracticeTargetCoinDrop.cs | 33 + Thronefall/PriorityAudioListener.cs | 27 + Thronefall/ProductionBar.cs | 23 + Thronefall/ProjectileAudio.cs | 37 + Thronefall/ProjectileImpactParticles.cs | 22 + Thronefall/ProjectileSpawnAudio.cs | 11 + Thronefall/Properties/AssemblyInfo.cs | 5 + Thronefall/Quest.cs | 114 + Thronefall/QuestConditionEquippable.cs | 33 + Thronefall/QuestEntry.cs | 87 + Thronefall/QuestMenu.cs | 21 + Thronefall/QuestTagUI.cs | 107 + Thronefall/RacerRoll.cs | 16 + .../ReduceChildrensBuildRequirementIfPerk.cs | 24 + Thronefall/ResetAudioSettings.cs | 13 + Thronefall/ResolutionExtensions.cs | 13 + Thronefall/RevivePanel.cs | 29 + .../Rewired.Data/UserDataStore_PlayerPrefs.cs | 1358 ++++++ .../ControllerUIEffect.cs | 57 + .../ControllerUIElement.cs | 186 + .../GamepadTemplateUI.cs | 417 ++ Thronefall/Rewired.Demos/Bullet.cs | 30 + Thronefall/Rewired.Demos/ControlRemappingDemo1.cs | 1797 ++++++++ Thronefall/Rewired.Demos/CustomControllerDemo.cs | 144 + .../Rewired.Demos/CustomControllerDemo_Player.cs | 58 + .../Rewired.Demos/CustomControllersTiltDemo.cs | 47 + .../DualShock4SpecialFeaturesExample.cs | 219 + .../Rewired.Demos/EightPlayersExample_Player.cs | 71 + .../FallbackJoystickIdentificationDemo.cs | 114 + .../Rewired.Demos/PlayerMouseSpriteExample.cs | 116 + .../PlayerPointerEventHandlerExample.cs | 138 + .../PressAnyButtonToJoinExample_Assigner.cs | 57 + .../PressAnyButtonToJoinExample_GamePlayer.cs | 67 + .../PressStartToJoinExample_Assigner.cs | 87 + .../PressStartToJoinExample_GamePlayer.cs | 57 + .../SimpleCombinedKeyboardMouseRemapping.cs | 225 + Thronefall/Rewired.Demos/SimpleControlRemapping.cs | 257 ++ Thronefall/Rewired.Demos/TouchButtonExample.cs | 52 + Thronefall/Rewired.Demos/TouchJoystickExample.cs | 110 + Thronefall/Rewired.Demos/UIPointer.cs | 98 + .../PlayerPointerEventData.cs | 41 + .../PointerEventType.cs | 7 + .../RewiredEventSystem.cs | 49 + .../RewiredPointerInputModule.cs | 781 ++++ .../RewiredStandaloneInputModule.cs | 1415 ++++++ .../Rewired.Internal/ControllerTemplateFactory.cs | 59 + Thronefall/Rewired.Utils/ExternalTools.cs | 171 + Thronefall/Rewired/FlightPedalsTemplate.cs | 25 + Thronefall/Rewired/FlightYokeTemplate.cs | 265 ++ Thronefall/Rewired/GamepadTemplate.cs | 149 + Thronefall/Rewired/HOTASTemplate.cs | 525 +++ Thronefall/Rewired/IFlightPedalsTemplate.cs | 10 + Thronefall/Rewired/IFlightYokeTemplate.cs | 102 + Thronefall/Rewired/IGamepadTemplate.cs | 62 + Thronefall/Rewired/IHOTASTemplate.cs | 180 + Thronefall/Rewired/IRacingWheelTemplate.cs | 88 + Thronefall/Rewired/ISixDofControllerTemplate.cs | 86 + Thronefall/Rewired/InputManager.cs | 81 + Thronefall/Rewired/RacingWheelTemplate.cs | 189 + Thronefall/Rewired/SixDofControllerTemplate.cs | 229 + Thronefall/RidingDamager.cs | 75 + Thronefall/RiverScroller.cs | 18 + Thronefall/RotateForwardToRVOVelocity.cs | 64 + Thronefall/SaveLoadManager.cs | 243 + Thronefall/ScaleAnimation.cs | 42 + Thronefall/ScalePulse.cs | 18 + Thronefall/SceneNameToLevelData.cs | 6 + Thronefall/SceneTransitionManager.cs | 254 ++ Thronefall/ScoreManager.cs | 150 + Thronefall/ScoreTag.cs | 21 + Thronefall/ScreenMarker.cs | 197 + Thronefall/ScreenMarkerCanvasHelper.cs | 19 + Thronefall/ScreenMarkerIcon.cs | 6 + Thronefall/ScreenMarkerManager.cs | 284 ++ Thronefall/SelfDestructWhenInRangeOf.cs | 33 + Thronefall/SetStateWhenMacOSX.cs | 13 + Thronefall/SetWidthToTarget.cs | 29 + Thronefall/SettingsAntiAliasing.cs | 26 + Thronefall/SettingsAudioVolume.cs | 26 + Thronefall/SettingsFullscreen.cs | 19 + Thronefall/SettingsLanguage.cs | 32 + Thronefall/SettingsLanguageReset.cs | 14 + Thronefall/SettingsManager.cs | 370 ++ Thronefall/SettingsPostProcessing.cs | 19 + Thronefall/SettingsPostProcessingHelper.cs | 18 + Thronefall/SettingsRenderScale.cs | 24 + Thronefall/SettingsResetUnitsMorning.cs | 19 + Thronefall/SettingsResetVideo.cs | 13 + Thronefall/SettingsResolution.cs | 40 + Thronefall/SettingsShadowResolution.cs | 26 + Thronefall/SettingsUIHelper.cs | 114 + Thronefall/SettingsUseLargeUI.cs | 22 + Thronefall/SharpCornerMidigator.cs | 46 + Thronefall/SimpleRotator.cs | 23 + Thronefall/SimpleUIScaler.cs | 43 + Thronefall/SimpleWalk.cs | 55 + Thronefall/SizeRectangleToMeshBounds.cs | 20 + Thronefall/Spawn.cs | 171 + Thronefall/SpinAnimation.cs | 45 + Thronefall/SplashDamageArea.cs | 51 + Thronefall/StabMA.cs | 71 + Thronefall/SteamManager.cs | 209 + Thronefall/SuperSimpleOceanAnimation.cs | 47 + Thronefall/SuspendPlayerCollisionUntilNoOverlap.cs | 96 + Thronefall/TFUIAudioHelper.cs | 53 + Thronefall/TFUIBlockoutElement.cs | 44 + Thronefall/TFUICheckboxMouseCatcher.cs | 43 + Thronefall/TFUIEnumMouseCatcher.cs | 51 + Thronefall/TFUIEnumSelectorButton.cs | 40 + Thronefall/TFUIEquippable.cs | 307 ++ Thronefall/TFUISlider.cs | 141 + Thronefall/TFUISliderDragArea.cs | 127 + Thronefall/TFUITextButton.cs | 195 + Thronefall/TFUIUpgradeChoice.cs | 203 + Thronefall/TagManager.cs | 223 + Thronefall/TaggedObject.cs | 59 + Thronefall/TargetPriority.cs | 127 + Thronefall/TextBackgroundFitter.cs | 24 + Thronefall/Thronefall.csproj | 344 ++ Thronefall/Thronefall.sln | 25 + Thronefall/ThronefallAudioManager.cs | 342 ++ Thronefall/ThronefallUIElement.cs | 166 + Thronefall/TimesensitiveLight.cs | 68 + Thronefall/TitleScreenPopUpHelper.cs | 28 + Thronefall/TitleScreenUIHelper.cs | 21 + Thronefall/Tooltip.cs | 63 + Thronefall/TooltipManager.cs | 102 + Thronefall/TreasureChestUIHelper.cs | 39 + Thronefall/TreasuryUI.cs | 224 + Thronefall/TutorialManager.cs | 662 +++ Thronefall/UIFrame.cs | 331 ++ Thronefall/UIFrameManager.cs | 286 ++ Thronefall/UIParentResizer.cs | 40 + Thronefall/UIScaleHandler.cs | 45 + Thronefall/UnitAttackAnimator.cs | 31 + Thronefall/UnitAudio.cs | 371 ++ Thronefall/UnitCommandRadiusAnimation.cs | 69 + Thronefall/UnitRespawnerForBuildings.cs | 113 + Thronefall/UnitSpawnAppear.cs | 36 + Thronefall/UnitySerializedDictionary.cs | 35 + ...itySourceGeneratedAssemblyMonoScriptTypes_v1.cs | 4756 ++++++++++++++++++++ Thronefall/UpgradeAssassinsTraining.cs | 16 + Thronefall/UpgradeBuildersGuild.cs | 51 + Thronefall/UpgradeCastleUp.cs | 46 + Thronefall/UpgradeCommander.cs | 47 + Thronefall/UpgradeGodlyCurse.cs | 9 + Thronefall/UpgradeMagicArmor.cs | 18 + Thronefall/UpgradePlayerDmg.cs | 11 + Thronefall/UpgradePlayerHp.cs | 17 + Thronefall/VersionNumberDisplay.cs | 12 + Thronefall/Wave.cs | 45 + Thronefall/WaveCountPopUp.cs | 77 + Thronefall/WaveDescriptionUI.cs | 26 + Thronefall/Weapon.cs | 225 + Thronefall/WeaponEquipper.cs | 29 + Thronefall/Wiggler.cs | 46 + Thronefall/WigglerAnimatedVelocity.cs | 45 + Thronefall/WigglerAnimationState.cs | 6 + Thronefall/WigglerVelocity.cs | 40 + Thronefall/WishlistButton.cs | 9 + 829 files changed, 94956 insertions(+) create mode 100644 .gitignore create mode 100644 GameCode/.gitignore create mode 100644 GameCode/AchievementManager.cs create mode 100644 GameCode/AfterMatchUIManager.cs create mode 100644 GameCode/AimbotProjectile.cs create mode 100644 GameCode/AnimateSizeAndDestroy.cs create mode 100644 GameCode/ApplyUpgradeIndicatorColor.cs create mode 100644 GameCode/AttackCooldownAnimation.cs create mode 100644 GameCode/AudioDayNightFader.cs create mode 100644 GameCode/AudioSet.cs create mode 100644 GameCode/AutoAttack.cs create mode 100644 GameCode/AutoAttackHighestHealth.cs create mode 100644 GameCode/AutoAttackLowestHealth.cs create mode 100644 GameCode/AutoRevive.cs create mode 100644 GameCode/BackToTitlescreenUIHelper.cs create mode 100644 GameCode/BackupAudioListener.cs create mode 100644 GameCode/BakeTrail.cs create mode 100644 GameCode/BarricadeDamage.cs create mode 100644 GameCode/BeforeGamePopUp.cs create mode 100644 GameCode/BillboardAlign.cs create mode 100644 GameCode/BlacksmithUpgrade.cs create mode 100644 GameCode/BlacksmithUpgrades.cs create mode 100644 GameCode/BoatAnimation.cs create mode 100644 GameCode/BuildSlot.cs create mode 100644 GameCode/BuildingDestructionHandler.cs create mode 100644 GameCode/BuildingFXProcessor.cs create mode 100644 GameCode/BuildingInteractor.cs create mode 100644 GameCode/BuildingMeshTracker.cs create mode 100644 GameCode/CameraBounds.cs create mode 100644 GameCode/CameraController.cs create mode 100644 GameCode/CameraRig.cs create mode 100644 GameCode/CancelOrOpenPauseMenu.cs create mode 100644 GameCode/Checkbox.cs create mode 100644 GameCode/Choice.cs create mode 100644 GameCode/ChoiceManager.cs create mode 100644 GameCode/ChoiceUI.cs create mode 100644 GameCode/ChoiceUIFrameHelper.cs create mode 100644 GameCode/Coin.cs create mode 100644 GameCode/CoinSpawner.cs create mode 100644 GameCode/Coinslot.cs create mode 100644 GameCode/ColorAndLightManager.cs create mode 100644 GameCode/Colorscheme.cs create mode 100644 GameCode/CommandUnits.cs create mode 100644 GameCode/CostDisplay.cs create mode 100644 GameCode/CustomPostProcess.cs create mode 100644 GameCode/DamageModifyer.cs create mode 100644 GameCode/DayNightCycle.cs create mode 100644 GameCode/DaytimeDisplay.cs create mode 100644 GameCode/DaytimeSensitiveActivation.cs create mode 100644 GameCode/DaytimeSensitiveLight.cs create mode 100644 GameCode/DebugBuildingDestroyer.cs create mode 100644 GameCode/DebugCoinDisplay.cs create mode 100644 GameCode/DebugController.cs create mode 100644 GameCode/DemoQuitSwitch.cs create mode 100644 GameCode/DestroyAfter.cs create mode 100644 GameCode/DestroyOrDisableOnEnable.cs create mode 100644 GameCode/DisableOnStart.cs create mode 100644 GameCode/EnableAllChildren.cs create mode 100644 GameCode/EndOfMatchScoreUIHelper.cs create mode 100644 GameCode/EndOfMatchUI.cs create mode 100644 GameCode/EnemyScreenMarkerUIHelper.cs create mode 100644 GameCode/EnemySpawnManager.cs create mode 100644 GameCode/EnemySpawner.cs create mode 100644 GameCode/EnumSelector.cs create mode 100644 GameCode/EnumSelectorButtonAnimation.cs create mode 100644 GameCode/Equippable.cs create mode 100644 GameCode/EquippableBuildingUpgrade.cs create mode 100644 GameCode/EquippableMutation.cs create mode 100644 GameCode/EquippablePerk.cs create mode 100644 GameCode/EquippableWeapon.cs create mode 100644 GameCode/FakeChildTo.cs create mode 100644 GameCode/FakeTransorm.cs create mode 100644 GameCode/FireArcherBurn.cs create mode 100644 GameCode/FishingHarbour.cs create mode 100644 GameCode/FishingHarbourUpgrade.cs create mode 100644 GameCode/ForceCameraPosOnEnable.cs create mode 100644 GameCode/FromToAnimation.cs create mode 100644 GameCode/GPUInstanced.cs create mode 100644 GameCode/GPUInstancingManager.cs create mode 100644 GameCode/GateOpener.cs create mode 100644 GameCode/GlobalAudioListener.cs create mode 100644 GameCode/GraphDrawer.cs create mode 100644 GameCode/HealBoostMA.cs create mode 100644 GameCode/Healthbar.cs create mode 100644 GameCode/HealthbarMulti.cs create mode 100644 GameCode/HighscorePreviewUI.cs create mode 100644 GameCode/HighscoreTable.cs create mode 100644 GameCode/HotOilTower.cs create mode 100644 GameCode/Hp.cs create mode 100644 GameCode/InGameResignUIHelper.cs create mode 100644 GameCode/IncomeModifyer.cs create mode 100644 GameCode/InteractorBase.cs create mode 100644 GameCode/Invulnerable.cs create mode 100644 GameCode/KeepRelativeRotationTo.cs create mode 100644 GameCode/KeyframedBoss.cs create mode 100644 GameCode/LaunchableDefenseMechanismInteractor.cs create mode 100644 GameCode/LaunchableProjectile.cs create mode 100644 GameCode/LevelAudio.cs create mode 100644 GameCode/LevelBorder.cs create mode 100644 GameCode/LevelData.cs create mode 100644 GameCode/LevelInteractor.cs create mode 100644 GameCode/LevelProgressManager.cs create mode 100644 GameCode/LevelSelectManager.cs create mode 100644 GameCode/LevelSelectUIFrameHelper.cs create mode 100644 GameCode/LevelUpScreenAnimation.cs create mode 100644 GameCode/LimitDeltaTime.cs create mode 100644 GameCode/LimitedLifetime.cs create mode 100644 GameCode/LoadSceneOnTop.cs create mode 100644 GameCode/LoadoutUIHelper.cs create mode 100644 GameCode/LocalGamestate.cs create mode 100644 GameCode/LvlSelectTabButton.cs create mode 100644 GameCode/ManualAttack.cs create mode 100644 GameCode/MaterialFlasherFX.cs create mode 100644 GameCode/MetaLevel.cs create mode 100644 GameCode/MillRotor.cs create mode 100644 GameCode/Mill_ImprovedPlow.cs create mode 100644 GameCode/Mill_ImprovementExplosiveTrap.cs create mode 100644 GameCode/Mill_ImprovementWindSpirits.cs create mode 100644 GameCode/Mill_Improvement_Scarecrows.cs create mode 100644 GameCode/MineShaft.cs create mode 100644 GameCode/MusicManager.cs create mode 100644 GameCode/NightCall.cs create mode 100644 GameCode/NightLight.cs create mode 100644 GameCode/Nighthorn.cs create mode 100644 GameCode/NightscoreUI.cs create mode 100644 GameCode/OnDamageFeedbackHandler.cs create mode 100644 GameCode/OneShotAnimationBase.cs create mode 100644 GameCode/PathMesher.cs create mode 100644 GameCode/PathfindMovement.cs create mode 100644 GameCode/PathfindMovementEnemy.cs create mode 100644 GameCode/PathfindMovementPlayerunit.cs create mode 100644 GameCode/PauseUILoadoutHelper.cs create mode 100644 GameCode/PerkCooldownModifyer.cs create mode 100644 GameCode/PerkCostModifyer.cs create mode 100644 GameCode/PerkDamageModifyerPlayerunitAuto.cs create mode 100644 GameCode/PerkDestroyGameObjectModifyer.cs create mode 100644 GameCode/PerkHpModifyer.cs create mode 100644 GameCode/PerkIncomeModifyer.cs create mode 100644 GameCode/PerkIndestructible.cs create mode 100644 GameCode/PerkManager.cs create mode 100644 GameCode/PerkPoint.cs create mode 100644 GameCode/PerkRangeModifyer.cs create mode 100644 GameCode/PerkSelectionGroup.cs create mode 100644 GameCode/PerkSelectionItem.cs create mode 100644 GameCode/PerkSelectionTooltipHelper.cs create mode 100644 GameCode/PerkWeaponModifyer.cs create mode 100644 GameCode/PhysicalCoinAnimator.cs create mode 100644 GameCode/PlayLevelButton.cs create mode 100644 GameCode/PlayMusicOnStart.cs create mode 100644 GameCode/PlayOneShotAfterSeconds.cs create mode 100644 GameCode/PlayerAttack.cs create mode 100644 GameCode/PlayerAttackAnimator.cs create mode 100644 GameCode/PlayerAttackTargetFacer.cs create mode 100644 GameCode/PlayerCharacterAudio.cs create mode 100644 GameCode/PlayerHpRegen.cs create mode 100644 GameCode/PlayerInteraction.cs create mode 100644 GameCode/PlayerManager.cs create mode 100644 GameCode/PlayerMovement.cs create mode 100644 GameCode/PlayerScept.cs create mode 100644 GameCode/PlayerUpgradeManager.cs create mode 100644 GameCode/PlayerWeaponAudio.cs create mode 100644 GameCode/PlayerWeaponVisuals.cs create mode 100644 GameCode/PositionAnimation.cs create mode 100644 GameCode/PowerTowerPerk.cs create mode 100644 GameCode/PracticeTargetCoinDrop.cs create mode 100644 GameCode/PriorityAudioListener.cs create mode 100644 GameCode/ProductionBar.cs create mode 100644 GameCode/ProjectileAudio.cs create mode 100644 GameCode/ProjectileImpactParticles.cs create mode 100644 GameCode/ProjectileSpawnAudio.cs create mode 100644 GameCode/Quest.cs create mode 100644 GameCode/QuestConditionEquippable.cs create mode 100644 GameCode/QuestEntry.cs create mode 100644 GameCode/QuestMenu.cs create mode 100644 GameCode/QuestTagUI.cs create mode 100644 GameCode/RacerRoll.cs create mode 100644 GameCode/ReduceChildrensBuildRequirementIfPerk.cs create mode 100644 GameCode/ResetAudioSettings.cs create mode 100644 GameCode/ResolutionExtensions.cs create mode 100644 GameCode/RevivePanel.cs create mode 100644 GameCode/RidingDamager.cs create mode 100644 GameCode/RiverScroller.cs create mode 100644 GameCode/RotateForwardToRVOVelocity.cs create mode 100644 GameCode/SaveLoadManager.cs create mode 100644 GameCode/ScaleAnimation.cs create mode 100644 GameCode/ScalePulse.cs create mode 100644 GameCode/SceneNameToLevelData.cs create mode 100644 GameCode/SceneTransitionManager.cs create mode 100644 GameCode/ScoreManager.cs create mode 100644 GameCode/ScoreTag.cs create mode 100644 GameCode/ScreenMarker.cs create mode 100644 GameCode/ScreenMarkerCanvasHelper.cs create mode 100644 GameCode/ScreenMarkerIcon.cs create mode 100644 GameCode/ScreenMarkerManager.cs create mode 100644 GameCode/SelfDestructWhenInRangeOf.cs create mode 100644 GameCode/SetStateWhenMacOSX.cs create mode 100644 GameCode/SetWidthToTarget.cs create mode 100644 GameCode/SettingsAntiAliasing.cs create mode 100644 GameCode/SettingsAudioVolume.cs create mode 100644 GameCode/SettingsFullscreen.cs create mode 100644 GameCode/SettingsLanguage.cs create mode 100644 GameCode/SettingsLanguageReset.cs create mode 100644 GameCode/SettingsManager.cs create mode 100644 GameCode/SettingsPostProcessing.cs create mode 100644 GameCode/SettingsPostProcessingHelper.cs create mode 100644 GameCode/SettingsRenderScale.cs create mode 100644 GameCode/SettingsResetUnitsMorning.cs create mode 100644 GameCode/SettingsResetVideo.cs create mode 100644 GameCode/SettingsResolution.cs create mode 100644 GameCode/SettingsShadowResolution.cs create mode 100644 GameCode/SettingsUIHelper.cs create mode 100644 GameCode/SettingsUseLargeUI.cs create mode 100644 GameCode/SharpCornerMidigator.cs create mode 100644 GameCode/SimpleRotator.cs create mode 100644 GameCode/SimpleUIScaler.cs create mode 100644 GameCode/SimpleWalk.cs create mode 100644 GameCode/SizeRectangleToMeshBounds.cs create mode 100644 GameCode/Spawn.cs create mode 100644 GameCode/SpinAnimation.cs create mode 100644 GameCode/SplashDamageArea.cs create mode 100644 GameCode/StabMA.cs create mode 100644 GameCode/SteamManager.cs create mode 100644 GameCode/SuperSimpleOceanAnimation.cs create mode 100644 GameCode/SuspendPlayerCollisionUntilNoOverlap.cs create mode 100644 GameCode/TFUIAudioHelper.cs create mode 100644 GameCode/TFUIBlockoutElement.cs create mode 100644 GameCode/TFUICheckboxMouseCatcher.cs create mode 100644 GameCode/TFUIEnumMouseCatcher.cs create mode 100644 GameCode/TFUIEnumSelectorButton.cs create mode 100644 GameCode/TFUIEquippable.cs create mode 100644 GameCode/TFUISlider.cs create mode 100644 GameCode/TFUISliderDragArea.cs create mode 100644 GameCode/TFUITextButton.cs create mode 100644 GameCode/TFUIUpgradeChoice.cs create mode 100644 GameCode/TagManager.cs create mode 100644 GameCode/TaggedObject.cs create mode 100644 GameCode/TargetPriority.cs create mode 100644 GameCode/TextBackgroundFitter.cs create mode 100644 GameCode/Thronefall.csproj create mode 100644 GameCode/Thronefall.sln create mode 100644 GameCode/ThronefallAudioManager.cs create mode 100644 GameCode/ThronefallUIElement.cs create mode 100644 GameCode/TimesensitiveLight.cs create mode 100644 GameCode/TitleScreenPopUpHelper.cs create mode 100644 GameCode/TitleScreenUIHelper.cs create mode 100644 GameCode/Tooltip.cs create mode 100644 GameCode/TooltipManager.cs create mode 100644 GameCode/TreasureChestUIHelper.cs create mode 100644 GameCode/TreasuryUI.cs create mode 100644 GameCode/TutorialManager.cs create mode 100644 GameCode/UIFrame.cs create mode 100644 GameCode/UIFrameManager.cs create mode 100644 GameCode/UIParentResizer.cs create mode 100644 GameCode/UIScaleHandler.cs create mode 100644 GameCode/UnitAttackAnimator.cs create mode 100644 GameCode/UnitAudio.cs create mode 100644 GameCode/UnitCommandRadiusAnimation.cs create mode 100644 GameCode/UnitRespawnerForBuildings.cs create mode 100644 GameCode/UnitSpawnAppear.cs create mode 100644 GameCode/UnitySerializedDictionary.cs create mode 100644 GameCode/UpgradeAssassinsTraining.cs create mode 100644 GameCode/UpgradeBuildersGuild.cs create mode 100644 GameCode/UpgradeCastleUp.cs create mode 100644 GameCode/UpgradeCommander.cs create mode 100644 GameCode/UpgradeGodlyCurse.cs create mode 100644 GameCode/UpgradeMagicArmor.cs create mode 100644 GameCode/UpgradePlayerDmg.cs create mode 100644 GameCode/UpgradePlayerHp.cs create mode 100644 GameCode/VersionNumberDisplay.cs create mode 100644 GameCode/Wave.cs create mode 100644 GameCode/WaveCountPopUp.cs create mode 100644 GameCode/WaveDescriptionUI.cs create mode 100644 GameCode/Weapon.cs create mode 100644 GameCode/WeaponEquipper.cs create mode 100644 GameCode/Wiggler.cs create mode 100644 GameCode/WigglerAnimatedVelocity.cs create mode 100644 GameCode/WigglerAnimationState.cs create mode 100644 GameCode/WigglerVelocity.cs create mode 100644 GameCode/WishlistButton.cs create mode 100644 Rewired/Rewired.Data/UserDataStore_PlayerPrefs.cs create mode 100644 Rewired/Rewired.Demos.GamepadTemplateUI/ControllerUIEffect.cs create mode 100644 Rewired/Rewired.Demos.GamepadTemplateUI/ControllerUIElement.cs create mode 100644 Rewired/Rewired.Demos.GamepadTemplateUI/GamepadTemplateUI.cs create mode 100644 Rewired/Rewired.Demos/Bullet.cs create mode 100644 Rewired/Rewired.Demos/ControlRemappingDemo1.cs create mode 100644 Rewired/Rewired.Demos/CustomControllerDemo.cs create mode 100644 Rewired/Rewired.Demos/CustomControllerDemo_Player.cs create mode 100644 Rewired/Rewired.Demos/CustomControllersTiltDemo.cs create mode 100644 Rewired/Rewired.Demos/DualShock4SpecialFeaturesExample.cs create mode 100644 Rewired/Rewired.Demos/EightPlayersExample_Player.cs create mode 100644 Rewired/Rewired.Demos/FallbackJoystickIdentificationDemo.cs create mode 100644 Rewired/Rewired.Demos/PlayerMouseSpriteExample.cs create mode 100644 Rewired/Rewired.Demos/PlayerPointerEventHandlerExample.cs create mode 100644 Rewired/Rewired.Demos/PressAnyButtonToJoinExample_Assigner.cs create mode 100644 Rewired/Rewired.Demos/PressAnyButtonToJoinExample_GamePlayer.cs create mode 100644 Rewired/Rewired.Demos/PressStartToJoinExample_Assigner.cs create mode 100644 Rewired/Rewired.Demos/PressStartToJoinExample_GamePlayer.cs create mode 100644 Rewired/Rewired.Demos/SimpleCombinedKeyboardMouseRemapping.cs create mode 100644 Rewired/Rewired.Demos/SimpleControlRemapping.cs create mode 100644 Rewired/Rewired.Demos/TouchButtonExample.cs create mode 100644 Rewired/Rewired.Demos/TouchJoystickExample.cs create mode 100644 Rewired/Rewired.Demos/UIPointer.cs create mode 100644 Rewired/Rewired.Integration.UnityUI/PlayerPointerEventData.cs create mode 100644 Rewired/Rewired.Integration.UnityUI/PointerEventType.cs create mode 100644 Rewired/Rewired.Integration.UnityUI/RewiredEventSystem.cs create mode 100644 Rewired/Rewired.Integration.UnityUI/RewiredPointerInputModule.cs create mode 100644 Rewired/Rewired.Integration.UnityUI/RewiredStandaloneInputModule.cs create mode 100644 Rewired/Rewired.Internal/ControllerTemplateFactory.cs create mode 100644 Rewired/Rewired.Utils/ExternalTools.cs create mode 100644 Rewired/Rewired/FlightPedalsTemplate.cs create mode 100644 Rewired/Rewired/FlightYokeTemplate.cs create mode 100644 Rewired/Rewired/GamepadTemplate.cs create mode 100644 Rewired/Rewired/HOTASTemplate.cs create mode 100644 Rewired/Rewired/IFlightPedalsTemplate.cs create mode 100644 Rewired/Rewired/IFlightYokeTemplate.cs create mode 100644 Rewired/Rewired/IGamepadTemplate.cs create mode 100644 Rewired/Rewired/IHOTASTemplate.cs create mode 100644 Rewired/Rewired/IRacingWheelTemplate.cs create mode 100644 Rewired/Rewired/ISixDofControllerTemplate.cs create mode 100644 Rewired/Rewired/InputManager.cs create mode 100644 Rewired/Rewired/RacingWheelTemplate.cs create mode 100644 Rewired/Rewired/SixDofControllerTemplate.cs create mode 100644 Thronefall/.gitignore create mode 100644 Thronefall/AchievementManager.cs create mode 100644 Thronefall/AfterMatchUIManager.cs create mode 100644 Thronefall/AimbotProjectile.cs create mode 100644 Thronefall/AnimateSizeAndDestroy.cs create mode 100644 Thronefall/ApplyUpgradeIndicatorColor.cs create mode 100644 Thronefall/Ara/AraTrail.cs create mode 100644 Thronefall/Ara/ColorFromSpeed.cs create mode 100644 Thronefall/Ara/ElasticArray.cs create mode 100644 Thronefall/Ara/ElectricalArc.cs create mode 100644 Thronefall/Ara/TireTrack.cs create mode 100644 Thronefall/Ara/TrailSection.cs create mode 100644 Thronefall/AttackCooldownAnimation.cs create mode 100644 Thronefall/AudioDayNightFader.cs create mode 100644 Thronefall/AudioSet.cs create mode 100644 Thronefall/AutoAttack.cs create mode 100644 Thronefall/AutoAttackHighestHealth.cs create mode 100644 Thronefall/AutoAttackLowestHealth.cs create mode 100644 Thronefall/AutoRevive.cs create mode 100644 Thronefall/BackToTitlescreenUIHelper.cs create mode 100644 Thronefall/BackupAudioListener.cs create mode 100644 Thronefall/BakeTrail.cs create mode 100644 Thronefall/BarricadeDamage.cs create mode 100644 Thronefall/BeforeGamePopUp.cs create mode 100644 Thronefall/BillboardAlign.cs create mode 100644 Thronefall/BlacksmithUpgrade.cs create mode 100644 Thronefall/BlacksmithUpgrades.cs create mode 100644 Thronefall/BoatAnimation.cs create mode 100644 Thronefall/BuildSlot.cs create mode 100644 Thronefall/BuildingDestructionHandler.cs create mode 100644 Thronefall/BuildingFXProcessor.cs create mode 100644 Thronefall/BuildingInteractor.cs create mode 100644 Thronefall/BuildingMeshTracker.cs create mode 100644 Thronefall/CameraBounds.cs create mode 100644 Thronefall/CameraController.cs create mode 100644 Thronefall/CameraRig.cs create mode 100644 Thronefall/CancelOrOpenPauseMenu.cs create mode 100644 Thronefall/Checkbox.cs create mode 100644 Thronefall/Choice.cs create mode 100644 Thronefall/ChoiceManager.cs create mode 100644 Thronefall/ChoiceUI.cs create mode 100644 Thronefall/ChoiceUIFrameHelper.cs create mode 100644 Thronefall/Coin.cs create mode 100644 Thronefall/CoinSpawner.cs create mode 100644 Thronefall/Coinslot.cs create mode 100644 Thronefall/ColorAndLightManager.cs create mode 100644 Thronefall/Colorscheme.cs create mode 100644 Thronefall/CommandUnits.cs create mode 100644 Thronefall/CostDisplay.cs create mode 100644 Thronefall/CustomPostProcess.cs create mode 100644 Thronefall/DamageModifyer.cs create mode 100644 Thronefall/DayNightCycle.cs create mode 100644 Thronefall/DaytimeDisplay.cs create mode 100644 Thronefall/DaytimeSensitiveActivation.cs create mode 100644 Thronefall/DaytimeSensitiveLight.cs create mode 100644 Thronefall/DebugBuildingDestroyer.cs create mode 100644 Thronefall/DebugCoinDisplay.cs create mode 100644 Thronefall/DebugController.cs create mode 100644 Thronefall/DemoQuitSwitch.cs create mode 100644 Thronefall/DestroyAfter.cs create mode 100644 Thronefall/DestroyOrDisableOnEnable.cs create mode 100644 Thronefall/DisableOnStart.cs create mode 100644 Thronefall/EnableAllChildren.cs create mode 100644 Thronefall/EndOfMatchScoreUIHelper.cs create mode 100644 Thronefall/EndOfMatchUI.cs create mode 100644 Thronefall/EnemyScreenMarkerUIHelper.cs create mode 100644 Thronefall/EnemySpawnManager.cs create mode 100644 Thronefall/EnemySpawner.cs create mode 100644 Thronefall/EnumSelector.cs create mode 100644 Thronefall/EnumSelectorButtonAnimation.cs create mode 100644 Thronefall/Equippable.cs create mode 100644 Thronefall/EquippableBuildingUpgrade.cs create mode 100644 Thronefall/EquippableMutation.cs create mode 100644 Thronefall/EquippablePerk.cs create mode 100644 Thronefall/EquippableWeapon.cs create mode 100644 Thronefall/FakeChildTo.cs create mode 100644 Thronefall/FakeTransorm.cs create mode 100644 Thronefall/FireArcherBurn.cs create mode 100644 Thronefall/FishingHarbour.cs create mode 100644 Thronefall/FishingHarbourUpgrade.cs create mode 100644 Thronefall/FlatKit/BlitTexturePass.cs create mode 100644 Thronefall/FlatKit/Buoyancy.cs create mode 100644 Thronefall/FlatKit/FlatKitFog.cs create mode 100644 Thronefall/FlatKit/FlatKitOutline.cs create mode 100644 Thronefall/FlatKit/FogSettings.cs create mode 100644 Thronefall/FlatKit/OutlineSettings.cs create mode 100644 Thronefall/FlatKit/UvScroller.cs create mode 100644 Thronefall/ForceCameraPosOnEnable.cs create mode 100644 Thronefall/FromToAnimation.cs create mode 100644 Thronefall/GPUInstanced.cs create mode 100644 Thronefall/GPUInstancingManager.cs create mode 100644 Thronefall/GateOpener.cs create mode 100644 Thronefall/GlobalAudioListener.cs create mode 100644 Thronefall/GraphDrawer.cs create mode 100644 Thronefall/HealBoostMA.cs create mode 100644 Thronefall/Healthbar.cs create mode 100644 Thronefall/HealthbarMulti.cs create mode 100644 Thronefall/HighscorePreviewUI.cs create mode 100644 Thronefall/HighscoreTable.cs create mode 100644 Thronefall/HotOilTower.cs create mode 100644 Thronefall/Hp.cs create mode 100644 Thronefall/I2.Loc.SimpleJSON/JSON.cs create mode 100644 Thronefall/I2.Loc.SimpleJSON/JSONArray.cs create mode 100644 Thronefall/I2.Loc.SimpleJSON/JSONBinaryTag.cs create mode 100644 Thronefall/I2.Loc.SimpleJSON/JSONClass.cs create mode 100644 Thronefall/I2.Loc.SimpleJSON/JSONData.cs create mode 100644 Thronefall/I2.Loc.SimpleJSON/JSONLazyCreator.cs create mode 100644 Thronefall/I2.Loc.SimpleJSON/JSONNode.cs create mode 100644 Thronefall/I2.Loc/ArabicMapping.cs create mode 100644 Thronefall/I2.Loc/ArabicTable.cs create mode 100644 Thronefall/I2.Loc/AutoChangeCultureInfo.cs create mode 100644 Thronefall/I2.Loc/BaseSpecializationManager.cs create mode 100644 Thronefall/I2.Loc/CallbackNotification.cs create mode 100644 Thronefall/I2.Loc/CoroutineManager.cs create mode 100644 Thronefall/I2.Loc/CustomLocalizeCallback.cs create mode 100644 Thronefall/I2.Loc/EventCallback.cs create mode 100644 Thronefall/I2.Loc/Example_ChangeLanguage.cs create mode 100644 Thronefall/I2.Loc/Example_LocalizedString.cs create mode 100644 Thronefall/I2.Loc/GeneralArabicLetters.cs create mode 100644 Thronefall/I2.Loc/GlobalParametersExample.cs create mode 100644 Thronefall/I2.Loc/GoogleLanguages.cs create mode 100644 Thronefall/I2.Loc/GoogleTranslation.cs create mode 100644 Thronefall/I2.Loc/HindiFixer.cs create mode 100644 Thronefall/I2.Loc/I2BasePersistentStorage.cs create mode 100644 Thronefall/I2.Loc/I2CustomPersistentStorage.cs create mode 100644 Thronefall/I2.Loc/I2Utils.cs create mode 100644 Thronefall/I2.Loc/ILanguageSource.cs create mode 100644 Thronefall/I2.Loc/ILocalizationParamsManager.cs create mode 100644 Thronefall/I2.Loc/ILocalizeTarget.cs create mode 100644 Thronefall/I2.Loc/ILocalizeTargetDescriptor.cs create mode 100644 Thronefall/I2.Loc/IResourceManager_Bundles.cs create mode 100644 Thronefall/I2.Loc/IsolatedArabicLetters.cs create mode 100644 Thronefall/I2.Loc/LanguageData.cs create mode 100644 Thronefall/I2.Loc/LanguageSource.cs create mode 100644 Thronefall/I2.Loc/LanguageSourceAsset.cs create mode 100644 Thronefall/I2.Loc/LanguageSourceData.cs create mode 100644 Thronefall/I2.Loc/LocalizationManager.cs create mode 100644 Thronefall/I2.Loc/LocalizationParamsManager.cs create mode 100644 Thronefall/I2.Loc/LocalizationReader.cs create mode 100644 Thronefall/I2.Loc/Localize.cs create mode 100644 Thronefall/I2.Loc/LocalizeDropdown.cs create mode 100644 Thronefall/I2.Loc/LocalizeTarget.cs create mode 100644 Thronefall/I2.Loc/LocalizeTargetDesc.cs create mode 100644 Thronefall/I2.Loc/LocalizeTargetDesc_Child.cs create mode 100644 Thronefall/I2.Loc/LocalizeTargetDesc_Prefab.cs create mode 100644 Thronefall/I2.Loc/LocalizeTargetDesc_Type.cs create mode 100644 Thronefall/I2.Loc/LocalizeTarget_TextMeshPro_Label.cs create mode 100644 Thronefall/I2.Loc/LocalizeTarget_TextMeshPro_UGUI.cs create mode 100644 Thronefall/I2.Loc/LocalizeTarget_UnityStandard_AudioSource.cs create mode 100644 Thronefall/I2.Loc/LocalizeTarget_UnityStandard_Child.cs create mode 100644 Thronefall/I2.Loc/LocalizeTarget_UnityStandard_MeshRenderer.cs create mode 100644 Thronefall/I2.Loc/LocalizeTarget_UnityStandard_Prefab.cs create mode 100644 Thronefall/I2.Loc/LocalizeTarget_UnityStandard_SpriteRenderer.cs create mode 100644 Thronefall/I2.Loc/LocalizeTarget_UnityStandard_TextMesh.cs create mode 100644 Thronefall/I2.Loc/LocalizeTarget_UnityStandard_VideoPlayer.cs create mode 100644 Thronefall/I2.Loc/LocalizeTarget_UnityUI_Image.cs create mode 100644 Thronefall/I2.Loc/LocalizeTarget_UnityUI_RawImage.cs create mode 100644 Thronefall/I2.Loc/LocalizeTarget_UnityUI_Text.cs create mode 100644 Thronefall/I2.Loc/LocalizedString.cs create mode 100644 Thronefall/I2.Loc/PersistentStorage.cs create mode 100644 Thronefall/I2.Loc/RTLFixer.cs create mode 100644 Thronefall/I2.Loc/RTLFixerTool.cs create mode 100644 Thronefall/I2.Loc/RealTimeTranslation.cs create mode 100644 Thronefall/I2.Loc/RegisterBundlesManager.cs create mode 100644 Thronefall/I2.Loc/RegisterCallback_AllowSyncFromGoogle.cs create mode 100644 Thronefall/I2.Loc/RegisterGlobalParameters.cs create mode 100644 Thronefall/I2.Loc/ResourceManager.cs create mode 100644 Thronefall/I2.Loc/SetLanguage.cs create mode 100644 Thronefall/I2.Loc/SetLanguageDropdown.cs create mode 100644 Thronefall/I2.Loc/SpecializationManager.cs create mode 100644 Thronefall/I2.Loc/StringObfucator.cs create mode 100644 Thronefall/I2.Loc/TashkeelLocation.cs create mode 100644 Thronefall/I2.Loc/TermData.cs create mode 100644 Thronefall/I2.Loc/TermsPopup.cs create mode 100644 Thronefall/I2.Loc/ToggleLanguage.cs create mode 100644 Thronefall/I2.Loc/TranslationFlag.cs create mode 100644 Thronefall/I2.Loc/TranslationJob.cs create mode 100644 Thronefall/I2.Loc/TranslationJob_GET.cs create mode 100644 Thronefall/I2.Loc/TranslationJob_Main.cs create mode 100644 Thronefall/I2.Loc/TranslationJob_POST.cs create mode 100644 Thronefall/I2.Loc/TranslationJob_WEB.cs create mode 100644 Thronefall/I2.Loc/TranslationJob_WWW.cs create mode 100644 Thronefall/I2.Loc/TranslationQuery.cs create mode 100644 Thronefall/I2.Loc/eLanguageDataFlags.cs create mode 100644 Thronefall/I2.Loc/ePluralType.cs create mode 100644 Thronefall/I2.Loc/eSpreadsheetUpdateMode.cs create mode 100644 Thronefall/I2.Loc/eTermType.cs create mode 100644 Thronefall/InGameResignUIHelper.cs create mode 100644 Thronefall/IncomeModifyer.cs create mode 100644 Thronefall/InteractorBase.cs create mode 100644 Thronefall/Invulnerable.cs create mode 100644 Thronefall/KeepRelativeRotationTo.cs create mode 100644 Thronefall/KeyframedBoss.cs create mode 100644 Thronefall/LaunchableDefenseMechanismInteractor.cs create mode 100644 Thronefall/LaunchableProjectile.cs create mode 100644 Thronefall/LevelAudio.cs create mode 100644 Thronefall/LevelBorder.cs create mode 100644 Thronefall/LevelData.cs create mode 100644 Thronefall/LevelInteractor.cs create mode 100644 Thronefall/LevelProgressManager.cs create mode 100644 Thronefall/LevelSelectManager.cs create mode 100644 Thronefall/LevelSelectUIFrameHelper.cs create mode 100644 Thronefall/LevelUpScreenAnimation.cs create mode 100644 Thronefall/LimitDeltaTime.cs create mode 100644 Thronefall/LimitedLifetime.cs create mode 100644 Thronefall/LoadSceneOnTop.cs create mode 100644 Thronefall/LoadoutUIHelper.cs create mode 100644 Thronefall/LocalGamestate.cs create mode 100644 Thronefall/LvlSelectTabButton.cs create mode 100644 Thronefall/ManualAttack.cs create mode 100644 Thronefall/MaterialFlasherFX.cs create mode 100644 Thronefall/MetaLevel.cs create mode 100644 Thronefall/MillRotor.cs create mode 100644 Thronefall/Mill_ImprovedPlow.cs create mode 100644 Thronefall/Mill_ImprovementExplosiveTrap.cs create mode 100644 Thronefall/Mill_ImprovementWindSpirits.cs create mode 100644 Thronefall/Mill_Improvement_Scarecrows.cs create mode 100644 Thronefall/MineShaft.cs create mode 100644 Thronefall/MoreMountains.Feedbacks/OneShotAudioTrigger.cs create mode 100644 Thronefall/MusicManager.cs create mode 100644 Thronefall/NGS.MeshFusionPro/AfterCombineAction.cs create mode 100644 Thronefall/NGS.MeshFusionPro/BinaryTree.cs create mode 100644 Thronefall/NGS.MeshFusionPro/BinaryTreeDrawer.cs create mode 100644 Thronefall/NGS.MeshFusionPro/BinaryTreeNode.cs create mode 100644 Thronefall/NGS.MeshFusionPro/BoundsHelper.cs create mode 100644 Thronefall/NGS.MeshFusionPro/CombineErrorStrategy.cs create mode 100644 Thronefall/NGS.MeshFusionPro/CombineMethod.cs create mode 100644 Thronefall/NGS.MeshFusionPro/CombineSource.cs create mode 100644 Thronefall/NGS.MeshFusionPro/CombineTree.cs create mode 100644 Thronefall/NGS.MeshFusionPro/CombineTreeNode.cs create mode 100644 Thronefall/NGS.MeshFusionPro/CombinedLODGroup.cs create mode 100644 Thronefall/NGS.MeshFusionPro/CombinedLODGroupMatcher.cs create mode 100644 Thronefall/NGS.MeshFusionPro/CombinedLODGroupPart.cs create mode 100644 Thronefall/NGS.MeshFusionPro/CombinedMesh.cs create mode 100644 Thronefall/NGS.MeshFusionPro/CombinedMeshData.cs create mode 100644 Thronefall/NGS.MeshFusionPro/CombinedMeshDataInternal.cs create mode 100644 Thronefall/NGS.MeshFusionPro/CombinedMeshFactory.cs create mode 100644 Thronefall/NGS.MeshFusionPro/CombinedMeshPart.cs create mode 100644 Thronefall/NGS.MeshFusionPro/CombinedMeshPartInternal.cs create mode 100644 Thronefall/NGS.MeshFusionPro/CombinedObject.cs create mode 100644 Thronefall/NGS.MeshFusionPro/CombinedObjectMatcher.cs create mode 100644 Thronefall/NGS.MeshFusionPro/CombinedObjectPart.cs create mode 100644 Thronefall/NGS.MeshFusionPro/DynamicCombineSource.cs create mode 100644 Thronefall/NGS.MeshFusionPro/DynamicCombinedObject.cs create mode 100644 Thronefall/NGS.MeshFusionPro/DynamicCombinedObjectMatcher.cs create mode 100644 Thronefall/NGS.MeshFusionPro/DynamicCombinedObjectPart.cs create mode 100644 Thronefall/NGS.MeshFusionPro/DynamicCombinedObjectPartInternal.cs create mode 100644 Thronefall/NGS.MeshFusionPro/DynamicMeshFusionSource.cs create mode 100644 Thronefall/NGS.MeshFusionPro/DynamicObjectsCombiner.cs create mode 100644 Thronefall/NGS.MeshFusionPro/IAsyncCombinedMeshMover.cs create mode 100644 Thronefall/NGS.MeshFusionPro/IBinaryTreeNode.cs create mode 100644 Thronefall/NGS.MeshFusionPro/ICombineSource.cs create mode 100644 Thronefall/NGS.MeshFusionPro/ICombinedMeshFactory.cs create mode 100644 Thronefall/NGS.MeshFusionPro/ICombinedMeshMover.cs create mode 100644 Thronefall/NGS.MeshFusionPro/ICombinedObject.cs create mode 100644 Thronefall/NGS.MeshFusionPro/ICombinedObjectPart.cs create mode 100644 Thronefall/NGS.MeshFusionPro/IMeshCombiner.cs create mode 100644 Thronefall/NGS.MeshFusionPro/IMeshCutter.cs create mode 100644 Thronefall/NGS.MeshFusionPro/IMeshToolsFactory.cs create mode 100644 Thronefall/NGS.MeshFusionPro/IMovableCombinedMeshFactory.cs create mode 100644 Thronefall/NGS.MeshFusionPro/ISourceTrackingStrategy.cs create mode 100644 Thronefall/NGS.MeshFusionPro/JobsMeshMoverLW.cs create mode 100644 Thronefall/NGS.MeshFusionPro/JobsMeshMoverSTD.cs create mode 100644 Thronefall/NGS.MeshFusionPro/JobsMovableMeshLWFactory.cs create mode 100644 Thronefall/NGS.MeshFusionPro/JobsMovableMeshSTDFactory.cs create mode 100644 Thronefall/NGS.MeshFusionPro/LODGroupCombineSource.cs create mode 100644 Thronefall/NGS.MeshFusionPro/LODGroupSettings.cs create mode 100644 Thronefall/NGS.MeshFusionPro/LODGroupsCombiner.cs create mode 100644 Thronefall/NGS.MeshFusionPro/LODMeshFusionSource.cs create mode 100644 Thronefall/NGS.MeshFusionPro/LightweightVertex.cs create mode 100644 Thronefall/NGS.MeshFusionPro/MatrixHelper.cs create mode 100644 Thronefall/NGS.MeshFusionPro/MeshCombineInfo.cs create mode 100644 Thronefall/NGS.MeshFusionPro/MeshCombinerBase.cs create mode 100644 Thronefall/NGS.MeshFusionPro/MeshCombinerSimpleLW.cs create mode 100644 Thronefall/NGS.MeshFusionPro/MeshCombinerSimpleSTD.cs create mode 100644 Thronefall/NGS.MeshFusionPro/MeshCutterSimpleLW.cs create mode 100644 Thronefall/NGS.MeshFusionPro/MeshCutterSimpleSTD.cs create mode 100644 Thronefall/NGS.MeshFusionPro/MeshCuttingInfo.cs create mode 100644 Thronefall/NGS.MeshFusionPro/MeshDataListsSTD.cs create mode 100644 Thronefall/NGS.MeshFusionPro/MeshDataNativeArraysLW.cs create mode 100644 Thronefall/NGS.MeshFusionPro/MeshDataNativeArraysSTD.cs create mode 100644 Thronefall/NGS.MeshFusionPro/MeshFusionSource.cs create mode 100644 Thronefall/NGS.MeshFusionPro/MeshSeparatorSimple.cs create mode 100644 Thronefall/NGS.MeshFusionPro/MeshType.cs create mode 100644 Thronefall/NGS.MeshFusionPro/MoveMethod.cs create mode 100644 Thronefall/NGS.MeshFusionPro/ObjectsCombiner.cs create mode 100644 Thronefall/NGS.MeshFusionPro/PartMoveInfo.cs create mode 100644 Thronefall/NGS.MeshFusionPro/RendererHelper.cs create mode 100644 Thronefall/NGS.MeshFusionPro/RendererSettings.cs create mode 100644 Thronefall/NGS.MeshFusionPro/RigidbodyTrackingStrategy.cs create mode 100644 Thronefall/NGS.MeshFusionPro/RuntimeMeshFusion.cs create mode 100644 Thronefall/NGS.MeshFusionPro/SimpleMeshMoverSTD.cs create mode 100644 Thronefall/NGS.MeshFusionPro/SimpleMovableMeshSTDFactory.cs create mode 100644 Thronefall/NGS.MeshFusionPro/SimpleToolsLWFactory.cs create mode 100644 Thronefall/NGS.MeshFusionPro/SimpleToolsSTDFactory.cs create mode 100644 Thronefall/NGS.MeshFusionPro/SourceCombineStatus.cs create mode 100644 Thronefall/NGS.MeshFusionPro/SourceTracker.cs create mode 100644 Thronefall/NGS.MeshFusionPro/StaticCombinedObjectMatcher.cs create mode 100644 Thronefall/NGS.MeshFusionPro/StaticMeshFusionSource.cs create mode 100644 Thronefall/NGS.MeshFusionPro/StaticObjectsCombiner.cs create mode 100644 Thronefall/NGS.MeshFusionPro/TrackingTarget.cs create mode 100644 Thronefall/NGS.MeshFusionPro/TransformTrackingStrategy.cs create mode 100644 Thronefall/NGS.MeshFusionPro/UniversalObjectsCombiner.cs create mode 100644 Thronefall/NGS.MeshFusionPro/VertexBufferUtil.cs create mode 100644 Thronefall/NightCall.cs create mode 100644 Thronefall/NightLight.cs create mode 100644 Thronefall/Nighthorn.cs create mode 100644 Thronefall/NightscoreUI.cs create mode 100644 Thronefall/OnDamageFeedbackHandler.cs create mode 100644 Thronefall/OneShotAnimationBase.cs create mode 100644 Thronefall/PathMesher.cs create mode 100644 Thronefall/PathfindMovement.cs create mode 100644 Thronefall/PathfindMovementEnemy.cs create mode 100644 Thronefall/PathfindMovementPlayerunit.cs create mode 100644 Thronefall/PauseUILoadoutHelper.cs create mode 100644 Thronefall/PerkCooldownModifyer.cs create mode 100644 Thronefall/PerkCostModifyer.cs create mode 100644 Thronefall/PerkDamageModifyerPlayerunitAuto.cs create mode 100644 Thronefall/PerkDestroyGameObjectModifyer.cs create mode 100644 Thronefall/PerkHpModifyer.cs create mode 100644 Thronefall/PerkIncomeModifyer.cs create mode 100644 Thronefall/PerkIndestructible.cs create mode 100644 Thronefall/PerkManager.cs create mode 100644 Thronefall/PerkPoint.cs create mode 100644 Thronefall/PerkRangeModifyer.cs create mode 100644 Thronefall/PerkSelectionGroup.cs create mode 100644 Thronefall/PerkSelectionItem.cs create mode 100644 Thronefall/PerkSelectionTooltipHelper.cs create mode 100644 Thronefall/PerkWeaponModifyer.cs create mode 100644 Thronefall/PhysicalCoinAnimator.cs create mode 100644 Thronefall/PlayLevelButton.cs create mode 100644 Thronefall/PlayMusicOnStart.cs create mode 100644 Thronefall/PlayOneShotAfterSeconds.cs create mode 100644 Thronefall/PlayerAttack.cs create mode 100644 Thronefall/PlayerAttackAnimator.cs create mode 100644 Thronefall/PlayerAttackTargetFacer.cs create mode 100644 Thronefall/PlayerCharacterAudio.cs create mode 100644 Thronefall/PlayerHpRegen.cs create mode 100644 Thronefall/PlayerInteraction.cs create mode 100644 Thronefall/PlayerManager.cs create mode 100644 Thronefall/PlayerMovement.cs create mode 100644 Thronefall/PlayerScept.cs create mode 100644 Thronefall/PlayerUpgradeManager.cs create mode 100644 Thronefall/PlayerWeaponAudio.cs create mode 100644 Thronefall/PlayerWeaponVisuals.cs create mode 100644 Thronefall/PositionAnimation.cs create mode 100644 Thronefall/PowerTowerPerk.cs create mode 100644 Thronefall/PracticeTargetCoinDrop.cs create mode 100644 Thronefall/PriorityAudioListener.cs create mode 100644 Thronefall/ProductionBar.cs create mode 100644 Thronefall/ProjectileAudio.cs create mode 100644 Thronefall/ProjectileImpactParticles.cs create mode 100644 Thronefall/ProjectileSpawnAudio.cs create mode 100644 Thronefall/Properties/AssemblyInfo.cs create mode 100644 Thronefall/Quest.cs create mode 100644 Thronefall/QuestConditionEquippable.cs create mode 100644 Thronefall/QuestEntry.cs create mode 100644 Thronefall/QuestMenu.cs create mode 100644 Thronefall/QuestTagUI.cs create mode 100644 Thronefall/RacerRoll.cs create mode 100644 Thronefall/ReduceChildrensBuildRequirementIfPerk.cs create mode 100644 Thronefall/ResetAudioSettings.cs create mode 100644 Thronefall/ResolutionExtensions.cs create mode 100644 Thronefall/RevivePanel.cs create mode 100644 Thronefall/Rewired.Data/UserDataStore_PlayerPrefs.cs create mode 100644 Thronefall/Rewired.Demos.GamepadTemplateUI/ControllerUIEffect.cs create mode 100644 Thronefall/Rewired.Demos.GamepadTemplateUI/ControllerUIElement.cs create mode 100644 Thronefall/Rewired.Demos.GamepadTemplateUI/GamepadTemplateUI.cs create mode 100644 Thronefall/Rewired.Demos/Bullet.cs create mode 100644 Thronefall/Rewired.Demos/ControlRemappingDemo1.cs create mode 100644 Thronefall/Rewired.Demos/CustomControllerDemo.cs create mode 100644 Thronefall/Rewired.Demos/CustomControllerDemo_Player.cs create mode 100644 Thronefall/Rewired.Demos/CustomControllersTiltDemo.cs create mode 100644 Thronefall/Rewired.Demos/DualShock4SpecialFeaturesExample.cs create mode 100644 Thronefall/Rewired.Demos/EightPlayersExample_Player.cs create mode 100644 Thronefall/Rewired.Demos/FallbackJoystickIdentificationDemo.cs create mode 100644 Thronefall/Rewired.Demos/PlayerMouseSpriteExample.cs create mode 100644 Thronefall/Rewired.Demos/PlayerPointerEventHandlerExample.cs create mode 100644 Thronefall/Rewired.Demos/PressAnyButtonToJoinExample_Assigner.cs create mode 100644 Thronefall/Rewired.Demos/PressAnyButtonToJoinExample_GamePlayer.cs create mode 100644 Thronefall/Rewired.Demos/PressStartToJoinExample_Assigner.cs create mode 100644 Thronefall/Rewired.Demos/PressStartToJoinExample_GamePlayer.cs create mode 100644 Thronefall/Rewired.Demos/SimpleCombinedKeyboardMouseRemapping.cs create mode 100644 Thronefall/Rewired.Demos/SimpleControlRemapping.cs create mode 100644 Thronefall/Rewired.Demos/TouchButtonExample.cs create mode 100644 Thronefall/Rewired.Demos/TouchJoystickExample.cs create mode 100644 Thronefall/Rewired.Demos/UIPointer.cs create mode 100644 Thronefall/Rewired.Integration.UnityUI/PlayerPointerEventData.cs create mode 100644 Thronefall/Rewired.Integration.UnityUI/PointerEventType.cs create mode 100644 Thronefall/Rewired.Integration.UnityUI/RewiredEventSystem.cs create mode 100644 Thronefall/Rewired.Integration.UnityUI/RewiredPointerInputModule.cs create mode 100644 Thronefall/Rewired.Integration.UnityUI/RewiredStandaloneInputModule.cs create mode 100644 Thronefall/Rewired.Internal/ControllerTemplateFactory.cs create mode 100644 Thronefall/Rewired.Utils/ExternalTools.cs create mode 100644 Thronefall/Rewired/FlightPedalsTemplate.cs create mode 100644 Thronefall/Rewired/FlightYokeTemplate.cs create mode 100644 Thronefall/Rewired/GamepadTemplate.cs create mode 100644 Thronefall/Rewired/HOTASTemplate.cs create mode 100644 Thronefall/Rewired/IFlightPedalsTemplate.cs create mode 100644 Thronefall/Rewired/IFlightYokeTemplate.cs create mode 100644 Thronefall/Rewired/IGamepadTemplate.cs create mode 100644 Thronefall/Rewired/IHOTASTemplate.cs create mode 100644 Thronefall/Rewired/IRacingWheelTemplate.cs create mode 100644 Thronefall/Rewired/ISixDofControllerTemplate.cs create mode 100644 Thronefall/Rewired/InputManager.cs create mode 100644 Thronefall/Rewired/RacingWheelTemplate.cs create mode 100644 Thronefall/Rewired/SixDofControllerTemplate.cs create mode 100644 Thronefall/RidingDamager.cs create mode 100644 Thronefall/RiverScroller.cs create mode 100644 Thronefall/RotateForwardToRVOVelocity.cs create mode 100644 Thronefall/SaveLoadManager.cs create mode 100644 Thronefall/ScaleAnimation.cs create mode 100644 Thronefall/ScalePulse.cs create mode 100644 Thronefall/SceneNameToLevelData.cs create mode 100644 Thronefall/SceneTransitionManager.cs create mode 100644 Thronefall/ScoreManager.cs create mode 100644 Thronefall/ScoreTag.cs create mode 100644 Thronefall/ScreenMarker.cs create mode 100644 Thronefall/ScreenMarkerCanvasHelper.cs create mode 100644 Thronefall/ScreenMarkerIcon.cs create mode 100644 Thronefall/ScreenMarkerManager.cs create mode 100644 Thronefall/SelfDestructWhenInRangeOf.cs create mode 100644 Thronefall/SetStateWhenMacOSX.cs create mode 100644 Thronefall/SetWidthToTarget.cs create mode 100644 Thronefall/SettingsAntiAliasing.cs create mode 100644 Thronefall/SettingsAudioVolume.cs create mode 100644 Thronefall/SettingsFullscreen.cs create mode 100644 Thronefall/SettingsLanguage.cs create mode 100644 Thronefall/SettingsLanguageReset.cs create mode 100644 Thronefall/SettingsManager.cs create mode 100644 Thronefall/SettingsPostProcessing.cs create mode 100644 Thronefall/SettingsPostProcessingHelper.cs create mode 100644 Thronefall/SettingsRenderScale.cs create mode 100644 Thronefall/SettingsResetUnitsMorning.cs create mode 100644 Thronefall/SettingsResetVideo.cs create mode 100644 Thronefall/SettingsResolution.cs create mode 100644 Thronefall/SettingsShadowResolution.cs create mode 100644 Thronefall/SettingsUIHelper.cs create mode 100644 Thronefall/SettingsUseLargeUI.cs create mode 100644 Thronefall/SharpCornerMidigator.cs create mode 100644 Thronefall/SimpleRotator.cs create mode 100644 Thronefall/SimpleUIScaler.cs create mode 100644 Thronefall/SimpleWalk.cs create mode 100644 Thronefall/SizeRectangleToMeshBounds.cs create mode 100644 Thronefall/Spawn.cs create mode 100644 Thronefall/SpinAnimation.cs create mode 100644 Thronefall/SplashDamageArea.cs create mode 100644 Thronefall/StabMA.cs create mode 100644 Thronefall/SteamManager.cs create mode 100644 Thronefall/SuperSimpleOceanAnimation.cs create mode 100644 Thronefall/SuspendPlayerCollisionUntilNoOverlap.cs create mode 100644 Thronefall/TFUIAudioHelper.cs create mode 100644 Thronefall/TFUIBlockoutElement.cs create mode 100644 Thronefall/TFUICheckboxMouseCatcher.cs create mode 100644 Thronefall/TFUIEnumMouseCatcher.cs create mode 100644 Thronefall/TFUIEnumSelectorButton.cs create mode 100644 Thronefall/TFUIEquippable.cs create mode 100644 Thronefall/TFUISlider.cs create mode 100644 Thronefall/TFUISliderDragArea.cs create mode 100644 Thronefall/TFUITextButton.cs create mode 100644 Thronefall/TFUIUpgradeChoice.cs create mode 100644 Thronefall/TagManager.cs create mode 100644 Thronefall/TaggedObject.cs create mode 100644 Thronefall/TargetPriority.cs create mode 100644 Thronefall/TextBackgroundFitter.cs create mode 100644 Thronefall/Thronefall.csproj create mode 100644 Thronefall/Thronefall.sln create mode 100644 Thronefall/ThronefallAudioManager.cs create mode 100644 Thronefall/ThronefallUIElement.cs create mode 100644 Thronefall/TimesensitiveLight.cs create mode 100644 Thronefall/TitleScreenPopUpHelper.cs create mode 100644 Thronefall/TitleScreenUIHelper.cs create mode 100644 Thronefall/Tooltip.cs create mode 100644 Thronefall/TooltipManager.cs create mode 100644 Thronefall/TreasureChestUIHelper.cs create mode 100644 Thronefall/TreasuryUI.cs create mode 100644 Thronefall/TutorialManager.cs create mode 100644 Thronefall/UIFrame.cs create mode 100644 Thronefall/UIFrameManager.cs create mode 100644 Thronefall/UIParentResizer.cs create mode 100644 Thronefall/UIScaleHandler.cs create mode 100644 Thronefall/UnitAttackAnimator.cs create mode 100644 Thronefall/UnitAudio.cs create mode 100644 Thronefall/UnitCommandRadiusAnimation.cs create mode 100644 Thronefall/UnitRespawnerForBuildings.cs create mode 100644 Thronefall/UnitSpawnAppear.cs create mode 100644 Thronefall/UnitySerializedDictionary.cs create mode 100644 Thronefall/UnitySourceGeneratedAssemblyMonoScriptTypes_v1.cs create mode 100644 Thronefall/UpgradeAssassinsTraining.cs create mode 100644 Thronefall/UpgradeBuildersGuild.cs create mode 100644 Thronefall/UpgradeCastleUp.cs create mode 100644 Thronefall/UpgradeCommander.cs create mode 100644 Thronefall/UpgradeGodlyCurse.cs create mode 100644 Thronefall/UpgradeMagicArmor.cs create mode 100644 Thronefall/UpgradePlayerDmg.cs create mode 100644 Thronefall/UpgradePlayerHp.cs create mode 100644 Thronefall/VersionNumberDisplay.cs create mode 100644 Thronefall/Wave.cs create mode 100644 Thronefall/WaveCountPopUp.cs create mode 100644 Thronefall/WaveDescriptionUI.cs create mode 100644 Thronefall/Weapon.cs create mode 100644 Thronefall/WeaponEquipper.cs create mode 100644 Thronefall/Wiggler.cs create mode 100644 Thronefall/WigglerAnimatedVelocity.cs create mode 100644 Thronefall/WigglerAnimationState.cs create mode 100644 Thronefall/WigglerVelocity.cs create mode 100644 Thronefall/WishlistButton.cs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3f7077b --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/Game \ No newline at end of file diff --git a/GameCode/.gitignore b/GameCode/.gitignore new file mode 100644 index 0000000..a4da27a --- /dev/null +++ b/GameCode/.gitignore @@ -0,0 +1,399 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.tlog +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio 6 auto-generated project file (contains which files were open etc.) +*.vbp + +# Visual Studio 6 workspace and project file (working project files containing files to include in project) +*.dsw +*.dsp + +# Visual Studio 6 technical files +*.ncb +*.aps + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# Visual Studio History (VSHistory) files +.vshistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd + +# VS Code files for those working on multiple tools +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace + +# Local History for Visual Studio Code +.history/ + +# Windows Installer files from build outputs +*.cab +*.msi +*.msix +*.msm +*.msp + +# JetBrains Rider +*.sln.iml +.vs diff --git a/GameCode/AchievementManager.cs b/GameCode/AchievementManager.cs new file mode 100644 index 0000000..0cedf23 --- /dev/null +++ b/GameCode/AchievementManager.cs @@ -0,0 +1,78 @@ +using System; +using Steamworks; +using UnityEngine; + +public class AchievementManager : MonoBehaviour +{ + public enum Achievements + { + START_TUTORIAL, + COMPLETE_TUTORIAL, + NORDFELS_BEATEN, + NORDFELS_QUESTSCOMPLETE, + DURSTSTEIN_BEATEN, + DURSTSTEIN_QUESTSCOMPLETE, + FROSTSEE_BEATEN, + FROSTSEE_QUESTSCOMPLETE, + MAXLEVEL_REACHED + } + + public static void UnlockAchievement(Achievements _achievement) + { + if (SteamManager.Initialized) + { + SteamUserStats.SetAchievement(_achievement.ToString()); + } + } + + public static void ResetAllAchievements() + { + if (!Application.isPlaying) + { + Debug.LogWarning("Warning: Resetting achievements only works while in play mode."); + return; + } + string[] names = Enum.GetNames(typeof(Achievements)); + for (int i = 0; i < names.Length; i++) + { + SteamUserStats.ClearAchievement(names[i]); + } + } + + public static void LevelBeaten(string _scene) + { + if (_scene == "Neuland(Tutorial)") + { + UnlockAchievement(Achievements.START_TUTORIAL); + UnlockAchievement(Achievements.COMPLETE_TUTORIAL); + } + if (_scene == "Nordfels") + { + UnlockAchievement(Achievements.NORDFELS_BEATEN); + } + if (_scene == "Durststein") + { + UnlockAchievement(Achievements.DURSTSTEIN_BEATEN); + } + if (_scene == "Frostsee") + { + UnlockAchievement(Achievements.FROSTSEE_BEATEN); + } + } + + public static void LevelAllQuestsComplete(string _scene) + { + if (_scene == "Nordfels") + { + UnlockAchievement(Achievements.NORDFELS_QUESTSCOMPLETE); + } + if (_scene == "Durststein") + { + UnlockAchievement(Achievements.DURSTSTEIN_QUESTSCOMPLETE); + } + if (_scene == "Frostsee") + { + UnlockAchievement(Achievements.FROSTSEE_QUESTSCOMPLETE); + } + } +} diff --git a/GameCode/AfterMatchUIManager.cs b/GameCode/AfterMatchUIManager.cs new file mode 100644 index 0000000..1310934 --- /dev/null +++ b/GameCode/AfterMatchUIManager.cs @@ -0,0 +1,251 @@ +using System.Collections; +using Rewired; +using TMPro; +using UnityEngine; +using UnityEngine.UI; + +public class AfterMatchUIManager : MonoBehaviour +{ + [Header("Score Screen")] + [SerializeField] + private GameObject scoreScreenUI; + + [SerializeField] + private TMP_Text ingameHighscore; + + [SerializeField] + private TMP_Text goldBonus; + + [SerializeField] + private TMP_Text mutationBonus; + + [SerializeField] + private TMP_Text totalScore; + + [SerializeField] + private GameObject newPersonalBest; + + [Header("Graphs")] + [SerializeField] + private GameObject graphs; + + [SerializeField] + private GraphDrawer graphDrawerA; + + [SerializeField] + private GraphDrawer graphDrawerB; + + [Header("Leveling")] + [SerializeField] + private GameObject levelingProgressUI; + + [SerializeField] + private TMP_Text currentLevelTxt1; + + [SerializeField] + private RectTransform levelingBarBack; + + [SerializeField] + private RectTransform levelingBarFront; + + [SerializeField] + private TMP_Text xpDisplay; + + [SerializeField] + private Image rewardPreview1; + + [Header("Rewards")] + [SerializeField] + private GameObject rewardDisplayUI; + + [SerializeField] + private TMP_Text currentLevelTxt2; + + [SerializeField] + private Image rewardPreview2; + + [SerializeField] + private TMP_Text itemName; + + [SerializeField] + private TMP_Text itemDescription; + + [Header("Max Level")] + [SerializeField] + private GameObject maxLevelReachedUI; + + [SerializeField] + private GameObject demoLockedUI; + + [Header("Settings")] + [SerializeField] + private float timeToFillUpABar = 5f; + + [SerializeField] + private float waitAtBeginning = 0.25f; + + [SerializeField] + private float waitAfterFillingUpABar = 0.25f; + + [SerializeField] + private float waitBeforeYouCanInteract = 0.25f; + + private PerkManager perkManager; + + private MetaLevel nextMetaLevel; + + private Player input; + + private void Start() + { + perkManager = PerkManager.instance; + StartCoroutine(ShowRewards()); + input = ReInput.players.GetPlayer(0); + } + + private IEnumerator ShowRewards() + { + EnableScoreUI(); + ingameHighscore.text = SceneTransitionManager.instance.IngameScoreFromLastMatch.ToString(); + goldBonus.text = "+" + SceneTransitionManager.instance.GoldBonusScoreFromLastMatch; + mutationBonus.text = "+" + SceneTransitionManager.instance.MutatorBonusScoreFromLastMatch; + totalScore.text = SceneTransitionManager.instance.TotalScoreFromLastMatch.ToString(); + newPersonalBest.SetActive(SceneTransitionManager.instance.TotalScoreFromLastMatchIsNewPersonalRecord); + yield return new WaitForSeconds(waitAtBeginning); + while (!input.GetButtonDown("Interact")) + { + yield return null; + } + int xpToGive = SceneTransitionManager.instance.TotalScoreFromLastMatch; + yield return SelectNextMetaLevel(); + EnableLevelingProgressUI(); + currentLevelTxt1.text = "Level " + perkManager.level; + rewardPreview1.sprite = nextMetaLevel.reward.icon; + UpdateLevelingBar(); + yield return new WaitForSeconds(waitAtBeginning); + float xPTrickleSpeed = (float)nextMetaLevel.requiredXp / timeToFillUpABar; + float xpTrickle = 0f; + while (xpToGive > 0) + { + xpTrickle += xPTrickleSpeed * Time.deltaTime; + int num = (int)xpTrickle; + xpTrickle -= (float)num; + xpToGive -= num; + if (xpToGive < 0) + { + num -= xpToGive; + } + perkManager.xp += num; + UpdateLevelingBar(); + if (perkManager.xp >= nextMetaLevel.requiredXp) + { + yield return new WaitForSeconds(waitAfterFillingUpABar); + EnableRewardDisplayUI(); + currentLevelTxt2.text = "Level " + (1 + perkManager.level); + rewardPreview2.sprite = nextMetaLevel.reward.icon; + itemName.text = nextMetaLevel.reward.displayName; + itemDescription.text = nextMetaLevel.reward.description; + yield return new WaitForSeconds(waitBeforeYouCanInteract); + while (!input.GetButtonDown("Interact")) + { + yield return null; + } + perkManager.xp -= nextMetaLevel.requiredXp; + perkManager.UnlockedEquippables.Add(nextMetaLevel.reward); + perkManager.level++; + yield return SelectNextMetaLevel(); + xPTrickleSpeed = (float)nextMetaLevel.requiredXp / timeToFillUpABar; + currentLevelTxt1.text = "Level " + perkManager.level; + rewardPreview1.sprite = nextMetaLevel.reward.icon; + EnableLevelingProgressUI(); + } + yield return null; + } + yield return null; + while (!input.GetButtonDown("Interact")) + { + yield return null; + } + LevelProgressManager.instance.GetLevelDataForScene(SceneTransitionManager.instance.ComingFromGameplayScene).SaveScoreAndStatsToBestIfBest(_endOfMatch: true); + SteamManager.Instance.UploadHighscore(SceneTransitionManager.instance.TotalScoreFromLastMatch, SceneTransitionManager.instance.ComingFromGameplayScene); + SaveLoadManager.instance.SaveGame(); + SceneTransitionManager.instance.TransitionFromEndScreenToLevelSelect(); + } + + private IEnumerator SelectNextMetaLevel() + { + nextMetaLevel = perkManager.NextMetaLevel; + if (nextMetaLevel == null) + { + EnableMaxLevelReachedUI(); + yield return new WaitForSeconds(waitBeforeYouCanInteract); + while (!input.GetButtonDown("Interact")) + { + yield return null; + } + SceneTransitionManager.instance.TransitionFromEndScreenToLevelSelect(); + StopAllCoroutines(); + yield return null; + } + } + + private void DisableAllUI() + { + levelingProgressUI.SetActive(value: false); + rewardDisplayUI.SetActive(value: false); + maxLevelReachedUI.SetActive(value: false); + graphs.SetActive(value: false); + scoreScreenUI.SetActive(value: false); + demoLockedUI.SetActive(value: false); + } + + private void EnableLevelingProgressUI() + { + DisableAllUI(); + levelingProgressUI.SetActive(value: true); + } + + private void EnableRewardDisplayUI() + { + DisableAllUI(); + rewardDisplayUI.SetActive(value: true); + } + + private void EnableMaxLevelReachedUI() + { + DisableAllUI(); + maxLevelReachedUI.SetActive(value: true); + } + + private void EnableDemoLockedUI() + { + DisableAllUI(); + demoLockedUI.SetActive(value: true); + } + + private void EnableGraphsUI() + { + DisableAllUI(); + graphs.SetActive(value: false); + } + + private void EnableScoreUI() + { + DisableAllUI(); + scoreScreenUI.SetActive(value: true); + } + + private void UpdateLevelingBar() + { + xpDisplay.text = perkManager.xp + " / " + nextMetaLevel.requiredXp; + SetLevelingParPercentage((float)perkManager.xp / (float)nextMetaLevel.requiredXp); + } + + private void SetLevelingParPercentage(float _percentage) + { + float width = levelingBarBack.rect.width; + float num = width * _percentage; + levelingBarFront.localScale = new Vector3(_percentage, 1f, 1f); + levelingBarFront.localPosition = new Vector3(num / 2f - width / 2f, 0f, 0f); + } +} diff --git a/GameCode/AimbotProjectile.cs b/GameCode/AimbotProjectile.cs new file mode 100644 index 0000000..546deeb --- /dev/null +++ b/GameCode/AimbotProjectile.cs @@ -0,0 +1,166 @@ +using UnityEngine; +using UnityEngine.Events; + +public class AimbotProjectile : MonoBehaviour +{ + private Weapon weapon; + + public bool shakeCameraOnDestroy; + + private Transform targetTransform; + + private Hp targetHp; + + private TaggedObject targetTaggedObject; + + private Vector3 rememberTarget; + + private Vector3 myLinearPosition; + + private Vector3 spawnPosition; + + private Vector3 previousPosition; + + private float finalDamageMultiplyer = 1f; + + private float remainingRange; + + private TaggedObject firedBy; + + private bool firedByPlayer; + + private bool targetIsFlying; + + [HideInInspector] + public UnityEvent onHit = new UnityEvent(); + + public Weapon Weapon + { + get + { + return weapon; + } + set + { + weapon = value; + } + } + + public void Fire(Weapon _weapon, Hp _target, float _chaseRange, Vector3 _backupTarget, TaggedObject _firedBy, float _finalDamageMultiplyer = 1f) + { + firedBy = _firedBy; + if ((bool)firedBy) + { + firedByPlayer = _firedBy.Tags.Contains(TagManager.ETag.Player); + } + weapon = _weapon; + if ((bool)_target) + { + targetTransform = _target.transform; + targetHp = _target; + targetTaggedObject = _target.GetComponent(); + if (targetTaggedObject.Tags.Contains(TagManager.ETag.Flying)) + { + targetIsFlying = true; + } + } + else + { + rememberTarget = _backupTarget; + } + myLinearPosition = base.transform.position; + spawnPosition = base.transform.position; + previousPosition = base.transform.position; + remainingRange = _chaseRange; + finalDamageMultiplyer = _finalDamageMultiplyer; + Update(); + } + + private void Update() + { + if ((bool)targetTransform) + { + if (targetTaggedObject.colliderForBigOjectsToMeasureDistance != null) + { + rememberTarget = targetTaggedObject.colliderForBigOjectsToMeasureDistance.ClosestPoint(spawnPosition); + } + else + { + rememberTarget = targetTransform.position + targetHp.hitFeedbackHeight * Vector3.up; + } + } + Vector3 vector = rememberTarget - myLinearPosition; + float num = weapon.projectileSpeed * Time.deltaTime; + if (num >= vector.magnitude) + { + Vector3 position = base.transform.position; + base.transform.position = rememberTarget; + if (targetTaggedObject != null && targetHp != null && targetTransform != null) + { + weapon.DealDamage(targetHp, finalDamageMultiplyer, firedBy); + } + else if (weapon.performRaycastWhenHittingEmptyPosition) + { + float raycastLength = weapon.raycastLength; + Vector3 normalized = (base.transform.position - position).normalized; + Physics.Raycast(base.transform.position - normalized * raycastLength, normalized, out var hitInfo, raycastLength, weapon.emptyPositionRaycastLayerMask); + if ((bool)hitInfo.collider) + { + Hp componentInParent = hitInfo.collider.GetComponentInParent(); + if ((bool)componentInParent) + { + weapon.DealDamage(componentInParent, finalDamageMultiplyer, firedBy); + } + } + } + if (!targetIsFlying && (bool)weapon.spawnOnGroundWhenTargetingGround) + { + if (targetTransform != null) + { + Object.Instantiate(weapon.spawnOnGroundWhenTargetingGround, targetTransform.position, Quaternion.identity); + } + else + { + Object.Instantiate(weapon.spawnOnGroundWhenTargetingGround, base.transform.position, Quaternion.identity); + } + } + onHit.Invoke(); + Object.Destroy(base.gameObject); + } + else + { + myLinearPosition += vector.normalized * num; + } + float magnitude = (rememberTarget - spawnPosition).magnitude; + float num4; + if (magnitude > 0.001f) + { + float num2 = (myLinearPosition - spawnPosition).magnitude / magnitude; + float num3 = Mathf.Max(0f, (magnitude + weapon.projectileParabulaOffset) * weapon.projectileParabulaFactor); + num4 = (0f - Mathf.Pow(2f * num2 - 1f, 2f) + 1f) * num3; + } + else + { + num4 = 0f; + } + base.transform.position = myLinearPosition + Vector3.up * num4; + if (weapon.projectileFacingDirection == Weapon.EFacingDirection.FaceVictim && base.transform.position != previousPosition) + { + base.transform.rotation = Quaternion.LookRotation(base.transform.position - previousPosition, Vector3.up); + } + previousPosition = base.transform.position; + remainingRange -= num; + if (remainingRange <= 0f) + { + targetTransform = null; + } + } + + private void OnDestroy() + { + if (shakeCameraOnDestroy && (bool)CameraController.instance) + { + CameraController.instance.ShakePunch(); + } + } +} diff --git a/GameCode/AnimateSizeAndDestroy.cs b/GameCode/AnimateSizeAndDestroy.cs new file mode 100644 index 0000000..7ec5b1a --- /dev/null +++ b/GameCode/AnimateSizeAndDestroy.cs @@ -0,0 +1,30 @@ +using System.Collections; +using UnityEngine; + +public class AnimateSizeAndDestroy : MonoBehaviour +{ + public AnimationCurve animationCurve; + + public float duration = 1f; + + private Vector3 initialScale; + + private void Start() + { + initialScale = base.transform.localScale; + StartCoroutine(AnimateScale()); + } + + private IEnumerator AnimateScale() + { + float time = 0f; + while (time <= duration) + { + float num = animationCurve.Evaluate(time / duration); + base.transform.localScale = initialScale * num; + time += Time.deltaTime; + yield return null; + } + Object.Destroy(base.gameObject); + } +} diff --git a/GameCode/ApplyUpgradeIndicatorColor.cs b/GameCode/ApplyUpgradeIndicatorColor.cs new file mode 100644 index 0000000..065accb --- /dev/null +++ b/GameCode/ApplyUpgradeIndicatorColor.cs @@ -0,0 +1,15 @@ +using Shapes; +using UnityEngine; + +[RequireComponent(typeof(Rectangle))] +public class ApplyUpgradeIndicatorColor : MonoBehaviour +{ + private void Start() + { + Rectangle component = GetComponent(); + if ((bool)ColorAndLightManager.currentColorscheme) + { + component.Color = ColorAndLightManager.currentColorscheme.upgradeInteractorColor; + } + } +} diff --git a/GameCode/AttackCooldownAnimation.cs b/GameCode/AttackCooldownAnimation.cs new file mode 100644 index 0000000..d4f65c5 --- /dev/null +++ b/GameCode/AttackCooldownAnimation.cs @@ -0,0 +1,50 @@ +using MoreMountains.Feedbacks; +using MPUIKIT; +using UnityEngine; + +public class AttackCooldownAnimation : MonoBehaviour +{ + public GameObject parent; + + public MPImage cooldownIndicator; + + public MMF_Player onShow; + + public MMF_Player onHide; + + private float currentCooldownPercentage; + + private bool inCooldown; + + private void Start() + { + parent.SetActive(value: false); + } + + public void SetCurrentCooldownPercentage(float value) + { + currentCooldownPercentage = value; + if (inCooldown && currentCooldownPercentage <= 0f) + { + onShow.StopFeedbacks(); + onHide.StopFeedbacks(); + onHide.PlayFeedbacks(); + inCooldown = false; + } + if (!inCooldown && currentCooldownPercentage > 0f) + { + onShow.StopFeedbacks(); + onHide.StopFeedbacks(); + onShow.PlayFeedbacks(); + inCooldown = true; + } + } + + private void Update() + { + if (currentCooldownPercentage > 0f) + { + cooldownIndicator.fillAmount = 1f - currentCooldownPercentage; + } + } +} diff --git a/GameCode/AudioDayNightFader.cs b/GameCode/AudioDayNightFader.cs new file mode 100644 index 0000000..7734d83 --- /dev/null +++ b/GameCode/AudioDayNightFader.cs @@ -0,0 +1,87 @@ +using System.Collections; +using UnityEngine; +using UnityEngine.Audio; + +public class AudioDayNightFader : MonoBehaviour, DayNightCycle.IDaytimeSensitive +{ + public float fadeTime = 0.5f; + + public AudioMixer mixer; + + public AudioClip nightMusic; + + public AudioClip finalNightMusic; + + public float nightMusicFadeInTime = 3f; + + public float nightMusicFadeOutTime = 4f; + + private float transitionClock; + + private float dayTargetVol; + + private float nightTargetVol; + + private void Start() + { + DayNightCycle.Instance.RegisterDaytimeSensitiveObject(this); + mixer.GetFloat("DayEnvVolume", out dayTargetVol); + mixer.GetFloat("NightEnvVolume", out nightTargetVol); + dayTargetVol = Mathf.Pow(10f, dayTargetVol / 20f); + nightTargetVol = Mathf.Pow(10f, nightTargetVol / 20f); + mixer.SetFloat("NightEnvVolume", Mathf.Log10(0.0001f) * 20f); + } + + public void OnDawn_AfterSunrise() + { + } + + public void OnDawn_BeforeSunrise() + { + StopAllCoroutines(); + StartCoroutine(FadeToDay()); + } + + public void OnDusk() + { + StopAllCoroutines(); + StartCoroutine(FadeToNight()); + } + + private IEnumerator FadeToNight() + { + if (EnemySpawner.instance.Wavenumber >= EnemySpawner.instance.waves.Count - 1) + { + MusicManager.instance.PlayMusic(finalNightMusic, nightMusicFadeInTime); + } + else + { + MusicManager.instance.PlayMusic(nightMusic, nightMusicFadeInTime); + } + while (transitionClock < 1f) + { + transitionClock += Time.deltaTime / fadeTime; + mixer.SetFloat("DayEnvVolume", Mathf.Log10(Mathf.Lerp(dayTargetVol, 0.0001f, transitionClock)) * 20f); + mixer.SetFloat("NightEnvVolume", Mathf.Log10(Mathf.Lerp(0.0001f, nightTargetVol, transitionClock)) * 20f); + yield return null; + } + transitionClock = 1f; + mixer.SetFloat("DayEnvVolume", Mathf.Log10(0.0001f) * 20f); + mixer.SetFloat("NightEnvVolume", Mathf.Log10(nightTargetVol) * 20f); + } + + private IEnumerator FadeToDay() + { + MusicManager.instance.PlayMusic(null, nightMusicFadeOutTime); + while (transitionClock > 0f) + { + transitionClock -= Time.deltaTime / fadeTime; + mixer.SetFloat("DayEnvVolume", Mathf.Log10(Mathf.Lerp(dayTargetVol, 0.0001f, transitionClock)) * 20f); + mixer.SetFloat("NightEnvVolume", Mathf.Log10(Mathf.Lerp(0.0001f, nightTargetVol, transitionClock)) * 20f); + yield return null; + } + transitionClock = 0f; + mixer.SetFloat("DayEnvVolume", Mathf.Log10(dayTargetVol) * 20f); + mixer.SetFloat("NightEnvVolume", Mathf.Log10(0.0001f) * 20f); + } +} diff --git a/GameCode/AudioSet.cs b/GameCode/AudioSet.cs new file mode 100644 index 0000000..99e201d --- /dev/null +++ b/GameCode/AudioSet.cs @@ -0,0 +1,403 @@ +using System; +using UnityEngine; +using UnityEngine.Audio; + +[CreateAssetMenu(fileName = "New Audio Set", menuName = "SimpleSiege/Audio Set")] +public class AudioSet : ScriptableObject +{ + [Serializable] + public class ClipArray + { + public AudioClip[] clips; + + public AudioClip GetRandomClip() + { + return clips[UnityEngine.Random.Range(0, clips.Length)]; + } + } + + [Header("MIXER GROUPS")] + public AudioMixerGroup mixGroupFX; + + [Header("DAY/NIGHT")] + [SerializeField] + private AudioClip nightSurvived; + + [SerializeField] + private AudioClip buildingRepair; + + [Header("BUILDING")] + [SerializeField] + private AudioClip coinslotFill; + + [SerializeField] + private AudioClip lastCoinslotFill; + + [SerializeField] + private AudioClip coinslotInteractionStart; + + [SerializeField] + private AudioClip payBackground; + + [SerializeField] + private AudioClip buildingBuild; + + [SerializeField] + private AudioClip buildingUpgrade; + + [SerializeField] + private ClipArray towerShot; + + [SerializeField] + private ClipArray ballistaShot; + + [SerializeField] + private AudioClip enemySpawn; + + [SerializeField] + private ClipArray defaultOnFootStep; + + [SerializeField] + private ClipArray giantStep; + + [SerializeField] + private ClipArray flyingSmall; + + [SerializeField] + private ClipArray siegeRoll; + + [SerializeField] + private ClipArray racerRoll; + + [SerializeField] + private ClipArray squishyBounce; + + [SerializeField] + private ClipArray exploderRoll; + + [SerializeField] + private ClipArray monsterRiderGallop; + + [SerializeField] + private ClipArray slimeStep; + + [SerializeField] + private ClipArray defaultSwordAttack; + + [SerializeField] + private ClipArray massiveBluntAttack; + + [SerializeField] + private ClipArray flyerSpit; + + [SerializeField] + private ClipArray flatbowShot; + + [SerializeField] + private ClipArray crossbowShow; + + [SerializeField] + private ClipArray catapultShot; + + [SerializeField] + private ClipArray ram; + + [SerializeField] + private ClipArray racerBite; + + [SerializeField] + private ClipArray hunterlingBite; + + [SerializeField] + private ClipArray slimeSpit; + + [SerializeField] + private ClipArray defaultHumanoidOnFootDamage; + + [SerializeField] + private ClipArray bigOrganicDamage; + + [SerializeField] + private ClipArray smallOrganicDamage; + + [SerializeField] + private ClipArray siegeDamage; + + [SerializeField] + private ClipArray defaultHumanoidOnFootDeath; + + [SerializeField] + private ClipArray bigOrganicDeath; + + [SerializeField] + private ClipArray siegeDeath; + + [SerializeField] + private ClipArray exploderDeath; + + [SerializeField] + private ClipArray eismolochAppear; + + [SerializeField] + private ClipArray eismolochSpawnUnits; + + [SerializeField] + private ClipArray eismolochScream; + + [SerializeField] + private ClipArray playerSword; + + [SerializeField] + private ClipArray playerSwordBigHit; + + [SerializeField] + private ClipArray playerBow; + + [SerializeField] + private ClipArray playerBowStab; + + [SerializeField] + private ClipArray playerBowStabMiss; + + [SerializeField] + private ClipArray playerCantUseActiveAbility; + + [SerializeField] + private ClipArray activeAbilityCooldownReadyToUse; + + [SerializeField] + private ClipArray playerSpear; + + [SerializeField] + private ClipArray playerDeath; + + [SerializeField] + private ClipArray playerDamage; + + [SerializeField] + private AudioClip playerRevive; + + [SerializeField] + private ClipArray addedUnitToCommanding; + + [SerializeField] + private ClipArray placeCommandingUnits; + + [SerializeField] + private ClipArray holdPosition; + + [SerializeField] + private ClipArray catapultImpact; + + [SerializeField] + private ClipArray buttonSelect; + + [SerializeField] + private ClipArray buttonApply; + + [SerializeField] + private ClipArray buttonApplyHero; + + [SerializeField] + private ClipArray coinCollect; + + [SerializeField] + private AudioClip nightCallStart; + + [SerializeField] + private AudioClip nightCallComplete; + + [SerializeField] + private AudioClip victory; + + [SerializeField] + private AudioClip defeat; + + [SerializeField] + private AudioClip pointLockInMinor; + + [SerializeField] + private AudioClip pointLockInMajor; + + [SerializeField] + private AudioClip pointScreenBuildA; + + [SerializeField] + private AudioClip pointScreenBuildB; + + [SerializeField] + private AudioClip pointScreenBuildC; + + [SerializeField] + private AudioClip pointFillStart; + + [SerializeField] + private AudioClip pointFill; + + [SerializeField] + private AudioClip newHighscore; + + [SerializeField] + private AudioClip levelUp; + + [SerializeField] + private AudioClip showWaveCount; + + [SerializeField] + private AudioClip closeWaveCount; + + [SerializeField] + private AudioClip showTooltip; + + public AudioClip NightSurvived => nightSurvived; + + public AudioClip BuildingRepair => buildingRepair; + + public AudioClip CoinslotFill => coinslotFill; + + public AudioClip LastCoinslotFill => lastCoinslotFill; + + public AudioClip CoinslotInteractionStart => coinslotInteractionStart; + + public AudioClip PayBackground => payBackground; + + public AudioClip BuildingBuild => buildingBuild; + + public AudioClip BuildingUpgrade => buildingUpgrade; + + public ClipArray TowerShot => towerShot; + + public ClipArray BallistaShot => ballistaShot; + + public AudioClip EnemySpawn => enemySpawn; + + public ClipArray DefaultOnFootStep => defaultOnFootStep; + + public ClipArray GiantStep => giantStep; + + public ClipArray FlyingSmall => flyingSmall; + + public ClipArray SiegeRoll => siegeRoll; + + public ClipArray RacerRoll => racerRoll; + + public ClipArray SquishyBounce => squishyBounce; + + public ClipArray ExploderRoll => exploderRoll; + + public ClipArray MonsterRiderGallop => monsterRiderGallop; + + public ClipArray SlimeStep => slimeStep; + + public ClipArray DefaultSwordAttack => defaultSwordAttack; + + public ClipArray MassiveBluntAttack => massiveBluntAttack; + + public ClipArray FlyerSpit => flyerSpit; + + public ClipArray FlatbowShot => flatbowShot; + + public ClipArray CrossbowShot => crossbowShow; + + public ClipArray CatapultShot => catapultShot; + + public ClipArray Ram => ram; + + public ClipArray RacerBite => racerBite; + + public ClipArray HunterlingBite => hunterlingBite; + + public ClipArray SlimeSpit => slimeSpit; + + public ClipArray DefaultHumanoidOnFootDamage => defaultHumanoidOnFootDamage; + + public ClipArray BigOrganicDamage => bigOrganicDamage; + + public ClipArray SmallOrganicDamage => smallOrganicDamage; + + public ClipArray SiegeDamage => siegeDamage; + + public ClipArray DefaultHumanoidOnFootDeath => defaultHumanoidOnFootDeath; + + public ClipArray BigOrganicDeath => bigOrganicDeath; + + public ClipArray SiegeDeath => siegeDeath; + + public ClipArray ExploderDeath => exploderDeath; + + public ClipArray EismolochAppear => eismolochAppear; + + public ClipArray EismolochSpawnUnits => eismolochSpawnUnits; + + public ClipArray EismolochScream => eismolochScream; + + public ClipArray PlayerSword => playerSword; + + public ClipArray PlayerSwordBigHit => playerSwordBigHit; + + public ClipArray PlayerBow => playerBow; + + public ClipArray PlayerBowStab => playerBowStab; + + public ClipArray PlayerBowStabMiss => playerBowStabMiss; + + public ClipArray PlayerCantUseActiveAbility => playerCantUseActiveAbility; + + public ClipArray ActiveAbilityCooldownReadyToUse => activeAbilityCooldownReadyToUse; + + public ClipArray PlayerSpear => playerSpear; + + public ClipArray PlayerDeath => playerDeath; + + public ClipArray PlayerDamage => playerDamage; + + public AudioClip PlayerRevive => playerRevive; + + public ClipArray AddedUnitToCommanding => addedUnitToCommanding; + + public ClipArray PlaceCommandingUnits => placeCommandingUnits; + + public ClipArray HoldPosition => holdPosition; + + public ClipArray CatapultImpact => catapultImpact; + + public ClipArray ButtonSelect => buttonSelect; + + public ClipArray ButtonApply => buttonApply; + + public ClipArray ButtonApplyHero => buttonApplyHero; + + public ClipArray CoinCollect => coinCollect; + + public AudioClip NightCallStart => nightCallStart; + + public AudioClip NightCallComplete => nightCallComplete; + + public AudioClip Victory => victory; + + public AudioClip Defeat => defeat; + + public AudioClip PointLockInMinor => pointLockInMinor; + + public AudioClip PointLockInMajor => pointLockInMajor; + + public AudioClip PointScreenBuildA => pointScreenBuildA; + + public AudioClip PointScreenBuildB => pointScreenBuildB; + + public AudioClip PointScreenBuildC => pointScreenBuildC; + + public AudioClip PointFillStart => pointFillStart; + + public AudioClip PointFill => pointFill; + + public AudioClip NewHighscore => newHighscore; + + public AudioClip LevelUp => levelUp; + + public AudioClip ShowWaveCount => showWaveCount; + + public AudioClip CloseWaveCount => closeWaveCount; + + public AudioClip ShowTooltip => showTooltip; +} diff --git a/GameCode/AutoAttack.cs b/GameCode/AutoAttack.cs new file mode 100644 index 0000000..71d1aec --- /dev/null +++ b/GameCode/AutoAttack.cs @@ -0,0 +1,102 @@ +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Events; + +public class AutoAttack : MonoBehaviour +{ + public float cooldownDuration = 1f; + + public float cooldownAfterSpawn = -1f; + + [Range(0f, 1f)] + public float cooldownRandomization; + + [Tooltip("How often this script checks if an attack is possible once the cooldown is down")] + public float recheckTargetInterval = 0.5f; + + public List targetPriorities = new List(); + + public Weapon weapon; + + public float spawnAttackHeight = 0.5f; + + private TaggedObject taggedObject; + + private float cooldown = -1f; + + private bool onCooldown; + + [Tooltip("While the getDisabledBy auto attack script is on cooldown, this auto attack script here can't attack.")] + public AutoAttack getsDisaledBy; + + private float damageMultiplyer = 1f; + + [HideInInspector] + public UnityEvent onAttackTriggered = new UnityEvent(); + + private Vector3 lastTargetPosition; + + public float DamageMultiplyer + { + get + { + return damageMultiplyer; + } + set + { + damageMultiplyer = value; + } + } + + public Vector3 LastTargetPosition => lastTargetPosition; + + public void ReduceCooldownBy(float _reduceBy) + { + cooldown -= _reduceBy; + } + + private void Start() + { + cooldown = cooldownAfterSpawn; + taggedObject = GetComponent(); + } + + private void Update() + { + bool flag = true; + if (getsDisaledBy != null && getsDisaledBy.onCooldown) + { + flag = false; + cooldown += Time.deltaTime; + } + cooldown -= Time.deltaTime; + if (cooldown <= 0f && flag) + { + TaggedObject taggedObject = FindAutoAttackTarget(); + if (taggedObject == null) + { + cooldown += recheckTargetInterval; + onCooldown = false; + return; + } + cooldown += cooldownDuration * (1f + (1f - 2f * Random.value) * cooldownRandomization); + weapon.Attack(base.transform.position + spawnAttackHeight * Vector3.up, taggedObject.Hp, Vector3.zero, this.taggedObject, damageMultiplyer); + lastTargetPosition = taggedObject.transform.position; + onAttackTriggered.Invoke(); + onCooldown = true; + } + } + + public virtual TaggedObject FindAutoAttackTarget() + { + for (int i = 0; i < targetPriorities.Count; i++) + { + TaggedObject taggedObject = targetPriorities[i].FindClosestTaggedObject(base.transform.position); + if (taggedObject != null) + { + return taggedObject; + } + } + return null; + } +} diff --git a/GameCode/AutoAttackHighestHealth.cs b/GameCode/AutoAttackHighestHealth.cs new file mode 100644 index 0000000..f489337 --- /dev/null +++ b/GameCode/AutoAttackHighestHealth.cs @@ -0,0 +1,15 @@ +public class AutoAttackHighestHealth : AutoAttack +{ + public override TaggedObject FindAutoAttackTarget() + { + for (int i = 0; i < targetPriorities.Count; i++) + { + TaggedObject taggedObject = targetPriorities[i].FindHighestHealthObjectInRange(base.transform.position); + if (taggedObject != null) + { + return taggedObject; + } + } + return null; + } +} diff --git a/GameCode/AutoAttackLowestHealth.cs b/GameCode/AutoAttackLowestHealth.cs new file mode 100644 index 0000000..4db887b --- /dev/null +++ b/GameCode/AutoAttackLowestHealth.cs @@ -0,0 +1,17 @@ +public class AutoAttackLowestHealth : AutoAttack +{ + public bool excludeFullHealthTargets = true; + + public override TaggedObject FindAutoAttackTarget() + { + for (int i = 0; i < targetPriorities.Count; i++) + { + TaggedObject taggedObject = targetPriorities[i].FindLowestHealthObjectInRange(base.transform.position, excludeFullHealthTargets); + if (taggedObject != null) + { + return taggedObject; + } + } + return null; + } +} diff --git a/GameCode/AutoRevive.cs b/GameCode/AutoRevive.cs new file mode 100644 index 0000000..63c2d75 --- /dev/null +++ b/GameCode/AutoRevive.cs @@ -0,0 +1,91 @@ +using UnityEngine; +using UnityEngine.Events; + +[RequireComponent(typeof(Hp))] +public class AutoRevive : MonoBehaviour, DayNightCycle.IDaytimeSensitive +{ + [HideInInspector] + public UnityEvent onReviveTrigger = new UnityEvent(); + + private Hp hp; + + public float reviveAfterBeingKnockedOutFor = 20f; + + private float hasBeenKnockedOutFor; + + private bool ringOfResurection; + + private bool quickReviveAvailable = true; + + private bool godOfDeathActive; + + [SerializeField] + private Equippable ringOfResurectionPerk; + + private float ReviveAfterBeingKnockedOutFor + { + get + { + if (ringOfResurection && quickReviveAvailable) + { + return 2f; + } + return reviveAfterBeingKnockedOutFor; + } + } + + public float TimeTillRevive + { + get + { + if (hasBeenKnockedOutFor <= 0f) + { + return -1f; + } + return ReviveAfterBeingKnockedOutFor - hasBeenKnockedOutFor; + } + } + + public void OnDusk() + { + } + + public void OnDawn_AfterSunrise() + { + quickReviveAvailable = true; + } + + public void OnDawn_BeforeSunrise() + { + } + + private void Start() + { + godOfDeathActive = PerkManager.instance.GodOfDeathActive; + if (godOfDeathActive) + { + reviveAfterBeingKnockedOutFor *= PerkManager.instance.godOfDeath_playerRespawnMultiplyer; + } + hp = GetComponent(); + ringOfResurection = PerkManager.IsEquipped(ringOfResurectionPerk); + DayNightCycle.Instance.RegisterDaytimeSensitiveObject(this); + } + + private void Update() + { + if (hp.KnockedOut) + { + hasBeenKnockedOutFor += Time.deltaTime; + if (hasBeenKnockedOutFor >= ReviveAfterBeingKnockedOutFor) + { + hp.Revive(); + onReviveTrigger.Invoke(); + quickReviveAvailable = false; + } + } + else + { + hasBeenKnockedOutFor = 0f; + } + } +} diff --git a/GameCode/BackToTitlescreenUIHelper.cs b/GameCode/BackToTitlescreenUIHelper.cs new file mode 100644 index 0000000..da76893 --- /dev/null +++ b/GameCode/BackToTitlescreenUIHelper.cs @@ -0,0 +1,9 @@ +using UnityEngine; + +public class BackToTitlescreenUIHelper : MonoBehaviour +{ + public void TransitionToMainMenu() + { + SceneTransitionManager.instance.TransitionToMainMenu(); + } +} diff --git a/GameCode/BackupAudioListener.cs b/GameCode/BackupAudioListener.cs new file mode 100644 index 0000000..276c372 --- /dev/null +++ b/GameCode/BackupAudioListener.cs @@ -0,0 +1,24 @@ +using UnityEngine; + +public class BackupAudioListener : MonoBehaviour +{ + public static BackupAudioListener Instance { get; private set; } + + private void Awake() + { + if (Instance == null) + { + Instance = this; + Object.DontDestroyOnLoad(base.gameObject); + } + else + { + Object.Destroy(base.gameObject); + } + } + + public void EnableBackupListener(bool enable) + { + GetComponent().enabled = enable; + } +} diff --git a/GameCode/BakeTrail.cs b/GameCode/BakeTrail.cs new file mode 100644 index 0000000..d06fd55 --- /dev/null +++ b/GameCode/BakeTrail.cs @@ -0,0 +1,38 @@ +using Ara; +using UnityEngine; + +[RequireComponent(typeof(AraTrail))] +public class BakeTrail : MonoBehaviour +{ + private AraTrail trail; + + private void Awake() + { + trail = GetComponent(); + } + + private void Update() + { + if (Input.GetKeyDown(KeyCode.Space)) + { + Bake(); + } + } + + private void Bake() + { + MeshFilter meshFilter = base.gameObject.AddComponent(); + MeshRenderer meshRenderer = base.gameObject.AddComponent(); + if (meshFilter != null && meshRenderer != null) + { + meshFilter.mesh = Object.Instantiate(trail.mesh); + meshRenderer.materials = trail.materials; + Object.Destroy(this); + Object.Destroy(trail); + } + else + { + Debug.LogError("[BakeTrail]: Could not bake the trail because the object already had a MeshRenderer."); + } + } +} diff --git a/GameCode/BarricadeDamage.cs b/GameCode/BarricadeDamage.cs new file mode 100644 index 0000000..09842f3 --- /dev/null +++ b/GameCode/BarricadeDamage.cs @@ -0,0 +1,63 @@ +using System.Collections.Generic; +using UnityEngine; + +public class BarricadeDamage : MonoBehaviour +{ + public float preSelectRadius = 4f; + + public float slowTime = 3f; + + public List damage; + + public LayerMask lmTakeDamage; + + private Collider[] overlapColliders = new Collider[50]; + + private float timeSinceLastCollisionCheck; + + private BoxCollider myCollider; + + private void Start() + { + myCollider = GetComponent(); + timeSinceLastCollisionCheck = Random.value; + } + + private void Update() + { + timeSinceLastCollisionCheck += Time.deltaTime; + if (timeSinceLastCollisionCheck < 0.2f) + { + return; + } + timeSinceLastCollisionCheck = 0f; + foreach (TaggedObject enemyUnit in TagManager.instance.EnemyUnits) + { + if (!(Vector3.Distance(base.transform.position, enemyUnit.transform.position) <= preSelectRadius) || enemyUnit.Hp.PathfindMovement.IsSlowed) + { + continue; + } + overlapColliders = Physics.OverlapBox(base.transform.position, myCollider.size, base.transform.rotation, lmTakeDamage); + Collider[] array = overlapColliders; + for (int i = 0; i < array.Length; i++) + { + TaggedObject componentInParent = array[i].GetComponentInParent(); + if (!componentInParent || !componentInParent.Tags.Contains(TagManager.ETag.EnemyOwned)) + { + continue; + } + Hp hp = componentInParent.Hp; + if ((bool)hp) + { + PathfindMovement pathfindMovement = hp.PathfindMovement; + if ((bool)pathfindMovement && !pathfindMovement.IsSlowed) + { + pathfindMovement.Slow(slowTime); + hp.TakeDamage(DamageModifyer.CalculateDamageOnTarget(componentInParent, damage)); + } + } + } + break; + } + } +} diff --git a/GameCode/BeforeGamePopUp.cs b/GameCode/BeforeGamePopUp.cs new file mode 100644 index 0000000..2850f57 --- /dev/null +++ b/GameCode/BeforeGamePopUp.cs @@ -0,0 +1,11 @@ +using System; + +[Serializable] +public class BeforeGamePopUp +{ + public UIFrame uiFrame; + + public bool showInDemoVersion = true; + + public bool showInFullVersion = true; +} diff --git a/GameCode/BillboardAlign.cs b/GameCode/BillboardAlign.cs new file mode 100644 index 0000000..480eb82 --- /dev/null +++ b/GameCode/BillboardAlign.cs @@ -0,0 +1,18 @@ +using UnityEngine; + +public class BillboardAlign : MonoBehaviour +{ + public bool negativeZ = true; + + private void Start() + { + if (negativeZ) + { + base.transform.forward = Camera.main.transform.forward; + } + else + { + base.transform.forward = Camera.main.transform.forward * -1f; + } + } +} diff --git a/GameCode/BlacksmithUpgrade.cs b/GameCode/BlacksmithUpgrade.cs new file mode 100644 index 0000000..9022dc2 --- /dev/null +++ b/GameCode/BlacksmithUpgrade.cs @@ -0,0 +1,88 @@ +using UnityEngine; + +public class BlacksmithUpgrade : MonoBehaviour, DayNightCycle.IDaytimeSensitive +{ + [SerializeField] + private BuildingInteractor buildingInteractor; + + [SerializeField] + private ProductionBar productionBar; + + [SerializeField] + private Weapon.EDamageAffectedByBlacksmithUpgrade upgrade; + + [SerializeField] + private float multiplyer = 1.2f; + + [SerializeField] + private int researchTime = 2; + + [SerializeField] + private Equippable researchSpeedPerk; + + private int researchTimeLeft; + + private void Start() + { + DayNightCycle.Instance.RegisterDaytimeSensitiveObject(this); + } + + public void OnDawn_AfterSunrise() + { + } + + public void OnDawn_BeforeSunrise() + { + if (!base.gameObject.activeInHierarchy) + { + return; + } + researchTimeLeft--; + Debug.Log(researchTimeLeft); + UpdateProgressBar(); + if (researchTimeLeft <= 0) + { + productionBar.gameObject.SetActive(value: false); + switch (upgrade) + { + case Weapon.EDamageAffectedByBlacksmithUpgrade.MultiplyBy_MeleeDamage: + BlacksmithUpgrades.instance.meleeDamage *= multiplyer; + break; + case Weapon.EDamageAffectedByBlacksmithUpgrade.MultiplyBy_RangedDamage: + BlacksmithUpgrades.instance.rangedDamage *= multiplyer; + break; + case Weapon.EDamageAffectedByBlacksmithUpgrade.DivideBy_MeleeResistance: + BlacksmithUpgrades.instance.meleeResistance *= multiplyer; + break; + case Weapon.EDamageAffectedByBlacksmithUpgrade.DivideBy_RangedResistance: + BlacksmithUpgrades.instance.rangedResistance *= multiplyer; + break; + } + buildingInteractor.buildingIsCurrentlyBusyAndCantBeUpgraded = false; + buildingInteractor.UpdateInteractionState(); + DayNightCycle.Instance.UnregisterDaytimeSensitiveObject(this); + } + } + + public void OnDusk() + { + } + + private void OnEnable() + { + researchTimeLeft = researchTime; + if (PerkManager.IsEquipped(researchSpeedPerk)) + { + researchTimeLeft--; + } + UpdateProgressBar(); + buildingInteractor.buildingIsCurrentlyBusyAndCantBeUpgraded = true; + buildingInteractor.UpdateInteractionState(); + } + + private void UpdateProgressBar() + { + productionBar.gameObject.SetActive(value: true); + productionBar.UpdateVisual(1f - (float)researchTimeLeft / ((float)researchTime + 0.1f)); + } +} diff --git a/GameCode/BlacksmithUpgrades.cs b/GameCode/BlacksmithUpgrades.cs new file mode 100644 index 0000000..e9b0f6a --- /dev/null +++ b/GameCode/BlacksmithUpgrades.cs @@ -0,0 +1,35 @@ +using UnityEngine; + +public class BlacksmithUpgrades : MonoBehaviour +{ + public static BlacksmithUpgrades instance; + + public float meleeDamage = 1f; + + public float rangedDamage = 1f; + + public float meleeResistance = 1f; + + public float rangedResistance = 1f; + + private void Awake() + { + instance = this; + } + + private void Start() + { + if (PerkManager.instance.MeleeResistenceActive) + { + meleeResistance *= PerkManager.instance.meleeResistence_AmountMulti; + } + if (PerkManager.instance.RangedResistenceActive) + { + rangedResistance *= PerkManager.instance.rangedResistence_AmountMulti; + } + } + + private void Update() + { + } +} diff --git a/GameCode/BoatAnimation.cs b/GameCode/BoatAnimation.cs new file mode 100644 index 0000000..d038afa --- /dev/null +++ b/GameCode/BoatAnimation.cs @@ -0,0 +1,37 @@ +using UnityEngine; + +public class BoatAnimation : MonoBehaviour +{ + private Vector3 startPosition; + + private Quaternion startRotation; + + private float time; + + [SerializeField] + private AnimationCurve yOffset; + + [SerializeField] + private AnimationCurve xRotation; + + [SerializeField] + private AnimationCurve yRotation; + + [SerializeField] + private AnimationCurve zRotation; + + private void Start() + { + time = Random.value * 10000f; + startPosition = base.transform.position; + startRotation = base.transform.rotation; + } + + private void Update() + { + time += Time.deltaTime; + Quaternion quaternion = Quaternion.Euler(xRotation.Evaluate(time), yRotation.Evaluate(time), zRotation.Evaluate(time)); + base.transform.rotation = startRotation * quaternion; + base.transform.position = startPosition + Vector3.up * yOffset.Evaluate(time); + } +} diff --git a/GameCode/BuildSlot.cs b/GameCode/BuildSlot.cs new file mode 100644 index 0000000..20fadac --- /dev/null +++ b/GameCode/BuildSlot.cs @@ -0,0 +1,616 @@ +using System; +using System.Collections.Generic; +using I2.Loc; +using Pathfinding; +using UnityEngine; +using UnityEngine.Events; + +[SelectionBase] +public class BuildSlot : MonoBehaviour, DayNightCycle.IDaytimeSensitive +{ + public enum BuildingState + { + Blueprint, + Built + } + + [Serializable] + public class Upgrade + { + public string upgradeTooltip; + + [Min(0f)] + public int cost = 3; + + public List upgradeBranches; + } + + [Serializable] + public class UpgradeBranch + { + [Tooltip("Only necessary when there are multiple options:")] + public Choice choiceDetails; + + public Mesh replacementMesh; + + public int goldIncomeChange; + + public int hpChange; + + public List objectsToActivate = new List(); + + public List objectsToDisable = new List(); + } + + public string buildingName; + + [Tooltip("The root is the required parent object no arrow points to, so this is pretty much always gonna be the casle center.E.g. this is set to 0 this building can not have a higher level than the castle center level.")] + [SerializeField] + private int requiredRootLevelDifference = -100; + + private BuildSlot requiredRoot; + + private List isRootOf = new List(); + + [SerializeField] + private bool startDeactivated = true; + + [SerializeField] + private BuildSlot activatorBuilding; + + [Min(0f)] + [SerializeField] + private int activatorLevel; + + [SerializeField] + private bool activatorUpgradesThis; + + public List upgrades = new List(); + + private int level; + + [SerializeField] + private GameObject buildingParent; + + [SerializeField] + private GameObject bluepringParent; + + [SerializeField] + private BuildingInteractor interactor; + + [SerializeField] + private MeshFilter mainMesh; + + [SerializeField] + private BoxCollider mainCollider; + + [SerializeField] + private BoxCollider damageCollider; + + [SerializeField] + private BoxCollider interactorCollider; + + [SerializeField] + private NavmeshCut navmeshCut; + + public bool hideGizmos; + + public float navmeshCutPadding = 1f; + + public BuildingMeshTracker buildingMeshTracker; + + [HideInInspector] + public BuildingInteractor buildingInteractor; + + private int goldIncome; + + [HideInInspector] + public UnityEvent OnUpgrade = new UnityEvent(); + + [HideInInspector] + public UnityEvent OnParentUpgrade = new UnityEvent(); + + [HideInInspector] + public UnityEvent OnUpgradeCancel = new UnityEvent(); + + private List builtSlotsThatRelyOnThisBuilding = new List(); + + private bool gotActivated; + + private Upgrade upgradeSelected; + + private PlayerInteraction playerInteractionSelected; + + public string LOCIDENTIFIER_NAME => "Building/" + buildingName; + + public List IsRootOf => isRootOf; + + public BuildSlot ActivatorBuilding => activatorBuilding; + + public int ActivatorLevel + { + get + { + return activatorLevel; + } + set + { + activatorLevel = value; + } + } + + public bool ActivatorUpgradesThis => activatorUpgradesThis; + + public List Upgrades + { + get + { + if (!activatorUpgradesThis) + { + return upgrades; + } + return activatorBuilding.Upgrades; + } + } + + public int Level + { + get + { + if (!activatorUpgradesThis) + { + return level; + } + return activatorBuilding.Level; + } + } + + public BuildingInteractor Interactor => interactor; + + public MeshFilter MainMesh => mainMesh; + + public BuildingState State + { + get + { + if (level < 1) + { + return BuildingState.Blueprint; + } + return BuildingState.Built; + } + } + + public int GoldIncome + { + get + { + return goldIncome; + } + set + { + goldIncome = value; + } + } + + public bool CanBeUpgraded + { + get + { + if (activatorUpgradesThis) + { + return activatorBuilding.CanBeUpgraded; + } + if (requiredRoot == null) + { + return level < upgrades.Count; + } + if (level < upgrades.Count) + { + if (requiredRoot.Level <= level + requiredRootLevelDifference && level != 0) + { + return requiredRoot.Level >= 3; + } + return true; + } + return false; + } + } + + public bool NextUpgradeIsChoice + { + get + { + if (CanBeUpgraded) + { + return upgrades[level].upgradeBranches.Count > 1; + } + return false; + } + } + + public int NextUpgradeOrBuildCost + { + get + { + if (activatorUpgradesThis) + { + return activatorBuilding.NextUpgradeOrBuildCost; + } + if (CanBeUpgraded) + { + return upgrades[level].cost; + } + return 100; + } + set + { + if (activatorUpgradesThis) + { + activatorBuilding.NextUpgradeOrBuildCost = value; + } + if (CanBeUpgraded) + { + upgrades[level].cost = value; + } + } + } + + public GameObject BuildingParent => buildingParent; + + private bool IsBlueprint => level == 0; + + public List BuiltSlotsThatRelyOnThisBuilding => builtSlotsThatRelyOnThisBuilding; + + public string GET_LOCIDENTIFIER_UPGRADE(int upgradeNumber) + { + return LOCIDENTIFIER_NAME + " Upgrade " + upgradeNumber; + } + + public string GET_LOCIDENTIFIER_CHOICENAME(Choice choice) + { + return LOCIDENTIFIER_NAME + " Choice " + choice.name; + } + + public string GET_LOCIDENTIFIER_CHOICEDESCRIPTION(Choice choice) + { + return GET_LOCIDENTIFIER_CHOICENAME(choice) + " Description"; + } + + public string ReturnTooltip() + { + if (!CanBeUpgraded) + { + return ""; + } + string text = ((level <= 0) ? LocalizationManager.GetTranslation("Tooltip/Build") : LocalizationManager.GetTranslation("Tooltip/Upgrade Building")); + string text2 = "" + text + " " + LocalizationManager.GetTranslation(LOCIDENTIFIER_NAME) + ":\n"; + text2 = text2 + "" + LocalizationManager.GetTranslation(GET_LOCIDENTIFIER_UPGRADE(level)) + "\n"; + text2 += ""; + int num = 0; + Hp componentInChildren = GetComponentInChildren(includeInactive: true); + if ((bool)componentInChildren) + { + num = (int)componentInChildren.maxHp; + } + List list = new List(); + List list2 = new List(); + foreach (UpgradeBranch upgradeBranch in upgrades[level].upgradeBranches) + { + int item = goldIncome + upgradeBranch.goldIncomeChange; + if (!list.Contains(item)) + { + list.Add(item); + } + int item2 = num + upgradeBranch.hpChange; + if (!list2.Contains(item2)) + { + list2.Add(item2); + } + } + list2.Sort(); + list.Sort(); + string text3 = ""; + string text4 = ""; + for (int i = 0; i < list.Count; i++) + { + if (i > 0) + { + text3 += "/"; + } + text3 += list[i]; + } + for (int j = 0; j < list2.Count; j++) + { + if (j > 0) + { + text4 += "/"; + } + text4 += list2[j]; + } + if (level > 0) + { + text2 = ((list2.Count <= 1 && list2[0] == num) ? (text2 + "\n" + num + "") : (text2 + "\n" + num + " " + text4 + "")); + if (list.Count > 1 || list[0] != goldIncome) + { + return text2 + "\n" + goldIncome + " " + text3 + ""; + } + return text2 + "\n" + goldIncome + ""; + } + text2 = ((list2.Count <= 1 && list2[0] == num) ? (text2 + "\n " + num + "") : (text2 + "\n " + text4 + "")); + if (list.Count > 1 || list[0] != goldIncome) + { + return text2 + "\n " + text3 + ""; + } + return text2 + "\n " + goldIncome + ""; + } + + private void OnEnable() + { + foreach (Upgrade upgrade in upgrades) + { + foreach (UpgradeBranch upgradeBranch in upgrade.upgradeBranches) + { + foreach (GameObject item in upgradeBranch.objectsToActivate) + { + item.SetActive(value: false); + } + } + } + } + + public List GetBuildSlotsThatWillUnlockWhenUpgraded() + { + List list = new List(); + for (int i = 0; i < builtSlotsThatRelyOnThisBuilding.Count; i++) + { + if (builtSlotsThatRelyOnThisBuilding[i].activatorLevel == level) + { + list.Add(builtSlotsThatRelyOnThisBuilding[i]); + } + } + return list; + } + + public List GetBlueprintPreviewsThatWillUnlockWhenUpgraded() + { + List list = new List(); + for (int i = 0; i < builtSlotsThatRelyOnThisBuilding.Count; i++) + { + if (builtSlotsThatRelyOnThisBuilding[i].activatorLevel == level) + { + if (builtSlotsThatRelyOnThisBuilding[i].State == BuildingState.Built || builtSlotsThatRelyOnThisBuilding[i].activatorUpgradesThis) + { + MeshFilter[] componentsInChildren = builtSlotsThatRelyOnThisBuilding[i].buildingParent.GetComponentsInChildren(); + list.AddRange(componentsInChildren); + } + else + { + MeshFilter[] componentsInChildren2 = builtSlotsThatRelyOnThisBuilding[i].bluepringParent.GetComponentsInChildren(); + list.AddRange(componentsInChildren2); + } + } + } + return list; + } + + public List GetGameObjectsThatWillUnlockWhenUpgraded(int _upgradeBranch) + { + if (level >= upgrades.Count) + { + return new List(); + } + return upgrades[level].upgradeBranches[_upgradeBranch % upgrades[level].upgradeBranches.Count].objectsToActivate; + } + + private void Start() + { + requiredRoot = this; + while (requiredRoot.activatorBuilding != null) + { + requiredRoot = requiredRoot.activatorBuilding; + } + if (requiredRoot != this) + { + requiredRoot.isRootOf.Add(this); + } + if ((bool)activatorBuilding) + { + activatorBuilding.builtSlotsThatRelyOnThisBuilding.Add(this); + } + if (startDeactivated) + { + base.gameObject.SetActive(value: false); + if ((bool)activatorBuilding) + { + activatorBuilding.OnUpgrade.AddListener(Activate); + } + } + else + { + Activate(); + } + DayNightCycle.Instance.RegisterDaytimeSensitiveObject(this); + } + + public void Activate() + { + if (!gotActivated && (!startDeactivated || activatorBuilding.Level > activatorLevel)) + { + gotActivated = true; + base.gameObject.SetActive(value: true); + ActivateOrDeactivateBuliding(State); + } + } + + private void ActivateOrDeactivateBuliding(BuildingState nextState) + { + switch (nextState) + { + case BuildingState.Blueprint: + buildingParent.SetActive(value: false); + bluepringParent.SetActive(value: true); + break; + case BuildingState.Built: + buildingParent.SetActive(value: true); + bluepringParent.SetActive(value: false); + break; + } + } + + public void TryToBuildOrUpgradeAndPay(PlayerInteraction player, bool _presentChoice = true) + { + if (!CanBeUpgraded) + { + return; + } + if (activatorUpgradesThis) + { + activatorBuilding.TryToBuildOrUpgradeAndPay(player, _presentChoice); + return; + } + for (int i = 0; i < builtSlotsThatRelyOnThisBuilding.Count; i++) + { + BuildSlot buildSlot = builtSlotsThatRelyOnThisBuilding[i]; + if (buildSlot.ActivatorUpgradesThis && buildSlot.activatorBuilding == this) + { + buildSlot.gameObject.SetActive(value: true); + buildSlot.ExecuteBuildOrUpgrade(player, _presentChoice: false); + } + } + ExecuteBuildOrUpgrade(player, _presentChoice); + for (int j = 0; j < builtSlotsThatRelyOnThisBuilding.Count; j++) + { + BuildSlot buildSlot2 = builtSlotsThatRelyOnThisBuilding[j]; + if ((bool)buildSlot2.buildingInteractor) + { + buildSlot2.buildingInteractor.UpdateInteractionState(); + } + } + if ((bool)buildingInteractor) + { + buildingInteractor.UpdateInteractionState(); + } + } + + public void ExecuteBuildOrUpgrade(PlayerInteraction _player, bool _presentChoice) + { + if (CanBeUpgraded) + { + ExecuteUpgrade(upgrades[level], _player, _presentChoice); + } + } + + private void ExecuteUpgrade(Upgrade _upg, PlayerInteraction _player, bool _presentChoice) + { + if (ChoiceManager.instance.ChoiceCoroutineRunning) + { + return; + } + List list = new List(); + foreach (UpgradeBranch upgradeBranch in _upg.upgradeBranches) + { + list.Add(upgradeBranch.choiceDetails); + } + upgradeSelected = _upg; + playerInteractionSelected = _player; + if (_presentChoice) + { + ChoiceManager.instance.PresentChoices(list, this, OnUpgradeChoiceComplete); + } + else + { + OnUpgradeChoiceComplete(_upg.upgradeBranches[UnityEngine.Random.Range(0, _upg.upgradeBranches.Count)].choiceDetails); + } + } + + public void OnUpgradeChoiceComplete(Choice _choiceMade) + { + if (_choiceMade == null) + { + OnUpgradeCancel.Invoke(); + return; + } + if (level == 0) + { + ActivateOrDeactivateBuliding(BuildingState.Built); + } + level++; + UpgradeBranch upgradeBranch = null; + foreach (UpgradeBranch upgradeBranch2 in upgradeSelected.upgradeBranches) + { + if (upgradeBranch2.choiceDetails == _choiceMade) + { + upgradeBranch = upgradeBranch2; + } + } + buildingMeshTracker.Unfreeze(); + buildingMeshTracker.FreezeMeshWithDelay(); + if (upgradeBranch.replacementMesh != null) + { + mainMesh.mesh = upgradeBranch.replacementMesh; + } + goldIncome += upgradeBranch.goldIncomeChange; + Hp component = buildingParent.GetComponent(); + if ((bool)component) + { + component.maxHp += upgradeBranch.hpChange; + component.Heal(upgradeBranch.hpChange); + } + foreach (GameObject item in upgradeBranch.objectsToActivate) + { + item.SetActive(value: true); + } + foreach (GameObject item2 in upgradeBranch.objectsToDisable) + { + item2.SetActive(value: false); + } + foreach (BuildSlot item3 in isRootOf) + { + BuildingInteractor[] componentsInChildren = item3.GetComponentsInChildren(); + for (int i = 0; i < componentsInChildren.Length; i++) + { + componentsInChildren[i].UpdateInteractionState(); + } + } + if (activatorUpgradesThis) + { + OnParentUpgrade.Invoke(); + return; + } + OnUpgrade.Invoke(); + TooltipManager.instance.SetInteractorRefreshFlag(); + } + + public void DEBUGUpgradeToMax() + { + while (CanBeUpgraded) + { + TryToBuildOrUpgradeAndPay(null, _presentChoice: false); + } + if ((bool)interactor) + { + interactor.UpdateInteractionState(); + } + } + + public void OnDusk() + { + if (IsBlueprint) + { + bluepringParent.SetActive(value: false); + } + } + + public void OnDawn_AfterSunrise() + { + if (IsBlueprint) + { + bluepringParent.SetActive(value: true); + } + } + + public void OnDawn_BeforeSunrise() + { + } +} diff --git a/GameCode/BuildingDestructionHandler.cs b/GameCode/BuildingDestructionHandler.cs new file mode 100644 index 0000000..d03a975 --- /dev/null +++ b/GameCode/BuildingDestructionHandler.cs @@ -0,0 +1,62 @@ +using UnityEngine; + +public class BuildingDestructionHandler : MonoBehaviour +{ + public bool shakeCamera; + + public MeshRenderer mainMesh; + + public ParticleSystem debrisParticles; + + public ParticleSystem smokeParticles; + + public AudioSource destructionSource; + + public float destructionPitchRange = 0.2f; + + private ParticleSystem.ShapeModule debrisShape; + + private ParticleSystem.ShapeModule smokeShape; + + private float debrisPlaytime = 5f; + + private float debrisClock; + + private void Awake() + { + debrisShape = debrisParticles.shape; + smokeShape = smokeParticles.shape; + } + + private void OnEnable() + { + if (shakeCamera && (bool)CameraController.instance) + { + CameraController.instance.ShakePunch(); + } + debrisParticles.transform.position = mainMesh.transform.position; + debrisParticles.transform.rotation = mainMesh.transform.rotation; + smokeParticles.transform.position = mainMesh.transform.position; + smokeParticles.transform.rotation = mainMesh.transform.rotation; + debrisShape.scale = mainMesh.localBounds.size; + debrisShape.position = mainMesh.localBounds.center; + smokeShape.scale = mainMesh.localBounds.size; + smokeShape.position = mainMesh.localBounds.center; + debrisClock = 0f; + debrisParticles.Play(); + destructionSource.pitch = Random.Range(1f - destructionPitchRange, 1f + destructionPitchRange); + destructionSource.Play(); + } + + private void Update() + { + if (debrisParticles.isPlaying) + { + debrisClock += Time.deltaTime; + if (debrisClock >= debrisPlaytime) + { + debrisParticles.Pause(); + } + } + } +} diff --git a/GameCode/BuildingFXProcessor.cs b/GameCode/BuildingFXProcessor.cs new file mode 100644 index 0000000..05ab937 --- /dev/null +++ b/GameCode/BuildingFXProcessor.cs @@ -0,0 +1,65 @@ +using System.Collections; +using MoreMountains.Feedbacks; +using UnityEngine; + +public class BuildingFXProcessor : MonoBehaviour +{ + public BuildSlot targetBuilding; + + public Hp targetHp; + + public MMF_Player onBuildFX; + + public MMF_Player onParentBuildFX; + + public MMF_Player onUpgradeFX; + + public MMF_Player onParentUpgradeFX; + + public MMF_Player onReviveFX; + + private void Start() + { + targetBuilding.OnUpgrade.AddListener(OnBuildingUpgrade); + targetBuilding.OnParentUpgrade.AddListener(OnParentBuildingUpgrade); + if ((bool)targetHp) + { + targetHp.OnRevive.AddListener(OnBuildingRevive); + } + } + + private void OnBuildingUpgrade() + { + if (targetBuilding.Level == 1) + { + onBuildFX.PlayFeedbacks(); + } + else if (targetBuilding.Level > 1) + { + onUpgradeFX.PlayFeedbacks(); + } + } + + private void OnParentBuildingUpgrade() + { + StartCoroutine(PlayDelayedParentUpgradeFeedback()); + } + + private IEnumerator PlayDelayedParentUpgradeFeedback() + { + yield return null; + if (targetBuilding.Level == 1) + { + onParentBuildFX.PlayFeedbacks(); + } + else if (targetBuilding.Level > 1) + { + onParentUpgradeFX.PlayFeedbacks(); + } + } + + private void OnBuildingRevive() + { + onReviveFX.PlayFeedbacks(); + } +} diff --git a/GameCode/BuildingInteractor.cs b/GameCode/BuildingInteractor.cs new file mode 100644 index 0000000..4648471 --- /dev/null +++ b/GameCode/BuildingInteractor.cs @@ -0,0 +1,437 @@ +using System.Collections.Generic; +using UnityEngine; + +public class BuildingInteractor : InteractorBase, DayNightCycle.IDaytimeSensitive +{ + public enum InteractionState + { + None, + Harvest, + Upgrade + } + + public static bool displayAllBuildPreviews; + + public BuildSlot targetBuilding; + + public Hp buildingHP; + + public CoinSpawner coinSpawner; + + public GameObject harvestCue; + + public GameObject harvestDeniedCue; + + public GameObject upgradeCue; + + public CostDisplay costDisplay; + + public Material previewMaterial; + + private List incomeModifiers = new List(); + + private InteractionState currentState; + + private bool knockedOutTonight; + + private bool harvestedToday; + + private bool focussed; + + private Mesh upgradePreviewMesh; + + private bool interactionComplete; + + private bool interactionStarted; + + private bool isWaitingForChoice; + + private PlayerInteraction bufferedPlayer; + + public bool buildingIsCurrentlyBusyAndCantBeUpgraded; + + public List IncomeModifiers => incomeModifiers; + + public bool KnockedOutTonight => knockedOutTonight; + + public bool canBeHarvested + { + get + { + if (targetBuilding.State == BuildSlot.BuildingState.Built && !harvestedToday && targetBuilding.GoldIncome > 0) + { + return !knockedOutTonight; + } + return false; + } + } + + public bool harvestIsDenied + { + get + { + if (targetBuilding.State == BuildSlot.BuildingState.Built && targetBuilding.GoldIncome > 0) + { + return knockedOutTonight; + } + return false; + } + } + + public int GoldIncome => targetBuilding.GoldIncome; + + public bool HarvestCueVisible => harvestCue.activeSelf; + + public bool UpgradeCueVisible => upgradeCue.activeSelf; + + public override bool CanBeInteractedWith => currentState != InteractionState.None; + + public bool IsWaitingForChoice => isWaitingForChoice; + + public Mesh UpgradePreviewMesh + { + get + { + if (targetBuilding.State == BuildSlot.BuildingState.Built) + { + if (!targetBuilding.CanBeUpgraded) + { + return null; + } + BuildSlot.Upgrade upgrade = targetBuilding.Upgrades[targetBuilding.Level]; + int num = Mathf.RoundToInt(Time.time * 2f); + return upgrade.upgradeBranches[num % upgrade.upgradeBranches.Count].replacementMesh; + } + return targetBuilding.MainMesh.mesh; + } + } + + public void MarkAsHarvested() + { + harvestedToday = true; + } + + public override string ReturnTooltip() + { + return targetBuilding.ReturnTooltip(); + } + + private void Start() + { + targetBuilding.buildingInteractor = this; + if ((bool)buildingHP) + { + buildingHP.OnKillOrKnockout.AddListener(OnKnockOut); + } + targetBuilding.OnUpgrade.AddListener(OnTargetUpgrade); + targetBuilding.OnUpgradeCancel.AddListener(OnTargetUpgradeCanceled); + DayNightCycle.Instance.RegisterDaytimeSensitiveObject(this); + UpdateInteractionState(); + if ((bool)TagManager.instance) + { + TagManager.instance.playerBuildingInteractors.Add(this); + } + } + + public override void InteractionBegin(PlayerInteraction player) + { + if (!isWaitingForChoice) + { + interactionStarted = true; + interactionComplete = false; + bufferedPlayer = player; + if (currentState == InteractionState.Upgrade) + { + ThronefallAudioManager.Oneshot(ThronefallAudioManager.AudioOneShot.CoinslotInteractionStart); + } + } + } + + public override void InteractionHold(PlayerInteraction player) + { + if (currentState != InteractionState.Upgrade || interactionComplete || !interactionStarted || isWaitingForChoice) + { + return; + } + if (costDisplay.CompletelyFilled) + { + isWaitingForChoice = targetBuilding.NextUpgradeIsChoice; + targetBuilding.TryToBuildOrUpgradeAndPay(player); + if (!isWaitingForChoice) + { + BuildComplete(); + } + else + { + costDisplay.gameObject.SetActive(value: false); + } + } + else if (player.Balance > 0) + { + if (costDisplay.FillUp()) + { + player.SpendCoins(1); + } + } + else + { + costDisplay.Deny(); + } + } + + public override void InteractionEnd(PlayerInteraction player) + { + if (!isWaitingForChoice && interactionStarted) + { + interactionStarted = false; + if (currentState == InteractionState.Upgrade) + { + costDisplay.CancelFill(player); + ThronefallAudioManager.Instance.MakeSureCoinFillSoundIsNotPlayingAnymore(); + } + } + } + + private void BuildComplete() + { + harvestedToday = true; + interactionComplete = true; + costDisplay.OnCompletion(); + UpdateInteractionState(); + } + + private void CancelBuild() + { + costDisplay.CancelFill(bufferedPlayer); + } + + private void OnTargetUpgrade() + { + if (isWaitingForChoice) + { + isWaitingForChoice = false; + costDisplay.gameObject.SetActive(value: true); + interactionStarted = false; + BuildComplete(); + } + } + + private void OnTargetUpgradeCanceled() + { + if (isWaitingForChoice) + { + isWaitingForChoice = false; + costDisplay.gameObject.SetActive(value: true); + interactionStarted = false; + CancelBuild(); + } + } + + public void OnDusk() + { + knockedOutTonight = false; + UpdateInteractionState(forceState: true); + } + + public void OnDawn_BeforeSunrise() + { + harvestedToday = false; + } + + public void OnDawn_AfterSunrise() + { + PlayerInteraction component = TagManager.instance.Players[0].GetComponent(); + Harvest(component); + foreach (IncomeModifyer incomeModifier in incomeModifiers) + { + incomeModifier.OnDawn(); + } + UpdateInteractionState(); + } + + public void UpdateInteractionState(bool forceState = false, InteractionState forcedState = InteractionState.None) + { + if (isWaitingForChoice) + { + return; + } + base.gameObject.SetActive(value: true); + if (canBeHarvested) + { + currentState = InteractionState.Harvest; + } + else if (targetBuilding.CanBeUpgraded) + { + currentState = InteractionState.Upgrade; + } + else + { + currentState = InteractionState.None; + } + if (forceState) + { + currentState = forcedState; + } + if (harvestIsDenied) + { + harvestDeniedCue.SetActive(value: true); + } + else + { + harvestDeniedCue.SetActive(value: false); + } + if (buildingIsCurrentlyBusyAndCantBeUpgraded) + { + currentState = InteractionState.None; + } + switch (currentState) + { + case InteractionState.None: + harvestCue.SetActive(value: false); + upgradeCue.SetActive(value: false); + DisableCostDisplay(); + break; + case InteractionState.Harvest: + harvestCue.SetActive(value: true); + upgradeCue.SetActive(targetBuilding.CanBeUpgraded); + DisableCostDisplay(); + break; + case InteractionState.Upgrade: + harvestCue.SetActive(value: false); + if (focussed) + { + ActivateCostDisplay(); + upgradeCue.SetActive(value: false); + break; + } + DisableCostDisplay(); + if (targetBuilding.State == BuildSlot.BuildingState.Built) + { + upgradeCue.SetActive(value: true); + } + else + { + upgradeCue.SetActive(value: false); + } + break; + } + } + + public override void Focus(PlayerInteraction player) + { + focussed = true; + UpdateInteractionState(); + if (currentState == InteractionState.Harvest) + { + Harvest(player); + } + } + + public void Harvest(PlayerInteraction player) + { + if (canBeHarvested) + { + coinSpawner.TriggerCoinSpawn(targetBuilding.GoldIncome, player); + harvestedToday = true; + UpdateInteractionState(); + } + } + + public override void Unfocus(PlayerInteraction player) + { + focussed = false; + if (!costDisplay.CompletelyEmpty) + { + costDisplay.CancelFill(player); + } + UpdateInteractionState(); + ThronefallAudioManager.Instance.MakeSureCoinFillSoundIsNotPlayingAnymore(); + } + + private void ActivateCostDisplay() + { + costDisplay.UpdateDisplay(targetBuilding.NextUpgradeOrBuildCost); + } + + private void DisableCostDisplay() + { + costDisplay.Hide(); + } + + public void OnKnockOut() + { + knockedOutTonight = true; + } + + private void Update() + { + if ((focussed || displayAllBuildPreviews) && currentState == InteractionState.Upgrade) + { + if (!targetBuilding.ActivatorUpgradesThis) + { + PreviewSelf(); + } + else + { + targetBuilding.ActivatorBuilding.buildingInteractor.PreviewSelf(); + } + } + } + + public void PreviewSelf() + { + MeshFilter mainMesh = targetBuilding.MainMesh; + if ((bool)UpgradePreviewMesh) + { + Graphics.DrawMesh(UpgradePreviewMesh, targetBuilding.MainMesh.transform.localToWorldMatrix, previewMaterial, 0); + } + else if (!mainMesh.gameObject.activeInHierarchy) + { + Graphics.DrawMesh(mainMesh.mesh, mainMesh.transform.localToWorldMatrix, previewMaterial, 0); + } + int upgradeBranch = Mathf.RoundToInt(Time.time * 2f); + List gameObjectsThatWillUnlockWhenUpgraded = targetBuilding.GetGameObjectsThatWillUnlockWhenUpgraded(upgradeBranch); + for (int i = 0; i < gameObjectsThatWillUnlockWhenUpgraded.Count; i++) + { + if (gameObjectsThatWillUnlockWhenUpgraded[i].transform.parent == null) + { + PreviewGameObject(gameObjectsThatWillUnlockWhenUpgraded[i]); + } + else if (gameObjectsThatWillUnlockWhenUpgraded[i].transform.parent.gameObject.activeSelf || gameObjectsThatWillUnlockWhenUpgraded.Contains(gameObjectsThatWillUnlockWhenUpgraded[i].transform.parent.gameObject)) + { + PreviewGameObject(gameObjectsThatWillUnlockWhenUpgraded[i]); + } + } + for (int j = 0; j < targetBuilding.BuiltSlotsThatRelyOnThisBuilding.Count; j++) + { + BuildSlot buildSlot = targetBuilding.BuiltSlotsThatRelyOnThisBuilding[j]; + if (buildSlot.ActivatorUpgradesThis && buildSlot.ActivatorBuilding == targetBuilding && (bool)buildSlot.buildingInteractor) + { + buildSlot.buildingInteractor.PreviewSelf(); + } + } + List blueprintPreviewsThatWillUnlockWhenUpgraded = targetBuilding.GetBlueprintPreviewsThatWillUnlockWhenUpgraded(); + for (int k = 0; k < blueprintPreviewsThatWillUnlockWhenUpgraded.Count; k++) + { + mainMesh = blueprintPreviewsThatWillUnlockWhenUpgraded[k]; + Graphics.DrawMesh(mainMesh.mesh, mainMesh.transform.localToWorldMatrix, previewMaterial, 0); + } + } + + private void PreviewGameObject(GameObject _go) + { + MeshFilter[] componentsInChildren = _go.GetComponentsInChildren(); + foreach (MeshFilter meshFilter in componentsInChildren) + { + Graphics.DrawMesh(meshFilter.mesh, meshFilter.transform.localToWorldMatrix, previewMaterial, 0); + } + } + + private void OnDestroy() + { + if ((bool)TagManager.instance) + { + TagManager.instance.playerBuildingInteractors.Remove(this); + } + } +} diff --git a/GameCode/BuildingMeshTracker.cs b/GameCode/BuildingMeshTracker.cs new file mode 100644 index 0000000..02e18e5 --- /dev/null +++ b/GameCode/BuildingMeshTracker.cs @@ -0,0 +1,59 @@ +using System.Collections; +using NGS.MeshFusionPro; +using UnityEngine; + +public class BuildingMeshTracker : MonoBehaviour +{ + public MeshFusionSource meshFuser; + + private Coroutine freezeWithDelay; + + private bool freezeWithDelayCoroRunning; + + private void OnEnable() + { + FreezeMeshWithDelay(); + } + + private void OnDisable() + { + Unfreeze(); + } + + public void Unfreeze() + { + if (freezeWithDelayCoroRunning) + { + StopCoroutine(freezeWithDelay); + freezeWithDelayCoroRunning = false; + } + meshFuser.UndoCombine(); + } + + public void FreezeMeshWithDelay() + { + if (!meshFuser.gameObject.activeInHierarchy) + { + return; + } + if (freezeWithDelay == null) + { + freezeWithDelay = StartCoroutine(FreezeMeshWithDelayCoro()); + return; + } + if (freezeWithDelayCoroRunning) + { + StopCoroutine(freezeWithDelay); + freezeWithDelayCoroRunning = false; + } + freezeWithDelay = StartCoroutine(FreezeMeshWithDelayCoro()); + } + + private IEnumerator FreezeMeshWithDelayCoro() + { + freezeWithDelayCoroRunning = true; + yield return new WaitForSeconds(2f); + meshFuser.AssignToController(); + freezeWithDelayCoroRunning = false; + } +} diff --git a/GameCode/CameraBounds.cs b/GameCode/CameraBounds.cs new file mode 100644 index 0000000..2eb79dc --- /dev/null +++ b/GameCode/CameraBounds.cs @@ -0,0 +1,135 @@ +using System.Collections.Generic; +using UnityEngine; + +[CreateAssetMenu] +public class CameraBounds : ScriptableObject +{ + public List bounds = new List(); + + private List boundsToUse = new List(); + + public void PrepareBounds(float offset) + { + boundsToUse = new List(bounds); + for (int i = 0; i < 10; i++) + { + GrowShrinkPoly(boundsToUse, offset / 10f, offset / 10f * 2f); + } + MakeBoundsConvex(boundsToUse); + } + + public static void GrowShrinkPoly(List bounds, float offset, float minDistance) + { + int count = bounds.Count; + for (int i = 0; i < count; i++) + { + Vector2 vector = bounds[(i - 1 + count) % count]; + Vector2 vector2 = bounds[i]; + Vector2 vector3 = bounds[(i + 1) % count]; + Vector2 normalized = (vector2 - vector).normalized; + Vector2 normalized2 = (vector3 - vector2).normalized; + Vector2 vector4 = new Vector2(0f - normalized.y, normalized.x); + Vector2 vector5 = new Vector2(0f - normalized2.y, normalized2.x); + Vector2 vector6 = (vector4 + vector5) / 2f; + Vector2 vector7 = vector2 + vector6 * offset; + float num = Vector2.Distance(vector7, vector); + float num2 = Vector2.Distance(vector7, vector3); + if (num >= minDistance && num2 >= minDistance) + { + bounds[i] = vector7; + } + } + } + + public static void BevelPolygon(List bounds, float percentageOfSideLength) + { + List list = new List(); + for (int i = 0; i < bounds.Count; i++) + { + Vector2 vector = bounds[(i - 1 + bounds.Count) % bounds.Count]; + Vector2 vector2 = bounds[i]; + Vector2 vector3 = bounds[(i + 1) % bounds.Count]; + Vector2 normalized = (vector - vector2).normalized; + Vector2 normalized2 = (vector3 - vector2).normalized; + float num = (vector - vector2).magnitude * percentageOfSideLength; + float num2 = (vector3 - vector2).magnitude * percentageOfSideLength; + Vector2 item = vector2 + normalized * num; + Vector2 item2 = vector2 + normalized2 * num2; + list.Add(item); + list.Add(item2); + } + bounds.Clear(); + bounds.AddRange(list); + } + + public static void DrawPolygonDebug(List bounds, float height) + { + int count = bounds.Count; + for (int i = 0; i < count; i++) + { + Vector3 start = new Vector3(bounds[i].x, height, bounds[i].y); + Vector3 end = new Vector3(bounds[(i + 1) % count].x, height, bounds[(i + 1) % count].y); + Debug.DrawLine(start, end, Color.red, Time.deltaTime * 3f); + } + } + + public static void MakeBoundsConvex(List bounds) + { + int num = 0; + while (num < bounds.Count) + { + Vector2 vector = bounds[num]; + Vector2 vector2 = bounds[(num + 1) % bounds.Count]; + Vector2 vector3 = bounds[(num + 2) % bounds.Count]; + float current = Mathf.Atan2(vector.y - vector2.y, vector.x - vector2.x) * 57.29578f; + float target = Mathf.Atan2(vector3.y - vector2.y, vector3.x - vector2.x) * 57.29578f; + if (Mathf.DeltaAngle(current, target) <= 0f) + { + bounds.RemoveAt((num + 1) % bounds.Count); + } + else + { + num++; + } + } + } + + public bool IsInBounds(Vector2 point) + { + bool flag = false; + int num = 0; + int index = boundsToUse.Count - 1; + while (num < boundsToUse.Count) + { + if (boundsToUse[num].y > point.y != boundsToUse[index].y > point.y && point.x < (boundsToUse[index].x - boundsToUse[num].x) * (point.y - boundsToUse[num].y) / (boundsToUse[index].y - boundsToUse[num].y) + boundsToUse[num].x) + { + flag = !flag; + } + index = num++; + } + return flag; + } + + public Vector2 ClosestPointOnBounds(Vector2 point) + { + Vector2 result = default(Vector2); + float num = float.MaxValue; + int num2 = 0; + int index = boundsToUse.Count - 1; + while (num2 < boundsToUse.Count) + { + Vector2 vector = boundsToUse[index]; + Vector2 vector2 = boundsToUse[num2]; + float num3 = Vector2.Dot(point - vector, vector2 - vector) / Vector2.Dot(vector2 - vector, vector2 - vector); + Vector2 vector3 = ((num3 < 0f) ? vector : ((!(num3 > 1f)) ? (vector + num3 * (vector2 - vector)) : vector2)); + float sqrMagnitude = (vector3 - point).sqrMagnitude; + if (sqrMagnitude < num) + { + num = sqrMagnitude; + result = vector3; + } + index = num2++; + } + return result; + } +} diff --git a/GameCode/CameraController.cs b/GameCode/CameraController.cs new file mode 100644 index 0000000..a95b27b --- /dev/null +++ b/GameCode/CameraController.cs @@ -0,0 +1,56 @@ +using System.Collections; +using UnityEngine; + +public class CameraController : MonoBehaviour +{ + public static CameraController instance; + + public AnimationCurve shakeCurve; + + public float shakeDuration = 1f; + + public float shakeScaleFactor = -1f; + + private Camera targetCamera; + + private float initialScale; + + private bool initialized; + + private void Awake() + { + if (instance != null) + { + Debug.LogWarning("More than one camera controller in the scene."); + } + instance = this; + } + + private void Start() + { + targetCamera = Camera.main; + initialScale = targetCamera.orthographicSize; + initialized = true; + } + + public void ShakePunch() + { + if (initialized) + { + StopAllCoroutines(); + StartCoroutine(ExecuteShake(shakeScaleFactor, shakeDuration)); + } + } + + private IEnumerator ExecuteShake(float scale, float duration) + { + float timer = 0f; + while (timer <= duration) + { + timer += Time.deltaTime; + targetCamera.orthographicSize = initialScale + shakeCurve.Evaluate(timer / duration) * scale; + yield return null; + } + targetCamera.orthographicSize = initialScale; + } +} diff --git a/GameCode/CameraRig.cs b/GameCode/CameraRig.cs new file mode 100644 index 0000000..7a87897 --- /dev/null +++ b/GameCode/CameraRig.cs @@ -0,0 +1,120 @@ +using System.Collections; +using UnityEngine; + +public class CameraRig : MonoBehaviour +{ + [Header("Forced Camera")] + [HideInInspector] + public Transform overrideCameraTarget; + + private Transform cameraTarget; + + private Transform currentTarget; + + private Quaternion startRotation; + + [SerializeField] + private float transitionSpeed = 1f; + + [Header("Camera Boundaries")] + [SerializeField] + private CameraBounds camBounds; + + [SerializeField] + private bool addCamBoundMode; + + [SerializeField] + private KeyCode debugAddCamBound; + + [SerializeField] + private KeyCode enableDisableCamBound; + + [SerializeField] + private bool boundsEnabled = true; + + [SerializeField] + private float outerBoundWidth = 12f; + + private Vector3 targetPosition; + + private bool transitionRunning; + + private void Start() + { + startRotation = base.transform.rotation; + cameraTarget = base.transform.parent; + base.transform.SetParent(null); + } + + private void Update() + { + targetPosition = base.transform.position; + if (overrideCameraTarget != null && currentTarget != overrideCameraTarget) + { + StartCoroutine(TransitionToTarget(overrideCameraTarget)); + } + else if (overrideCameraTarget == null && currentTarget != cameraTarget) + { + StartCoroutine(TransitionToTarget(cameraTarget)); + } + else if (!transitionRunning) + { + if (overrideCameraTarget != null) + { + base.transform.position = overrideCameraTarget.position; + base.transform.rotation = overrideCameraTarget.rotation; + } + else + { + base.transform.position = cameraTarget.position; + base.transform.rotation = startRotation; + } + } + } + + private void HandleBounds() + { + if (!camBounds) + { + base.transform.position = targetPosition; + return; + } + if (!boundsEnabled) + { + base.transform.position = targetPosition; + return; + } + if (camBounds.IsInBounds(new Vector2(targetPosition.x, targetPosition.z))) + { + base.transform.position = targetPosition; + return; + } + Vector2 vector = camBounds.ClosestPointOnBounds(new Vector2(targetPosition.x, targetPosition.z)); + float magnitude = (vector - new Vector2(targetPosition.x, targetPosition.z)).magnitude; + Vector3 vector2 = new Vector3(vector.x, targetPosition.y, vector.y); + float num = Mathf.Clamp01(magnitude / outerBoundWidth); + num = 0f - Mathf.Pow(num, 2f) + 2f * num; + Vector2 normalized = (new Vector2(targetPosition.x, targetPosition.z) - vector).normalized; + Vector3 b = vector2 + new Vector3(normalized.x, 0f, normalized.y) * outerBoundWidth * 0.5f; + base.transform.position = Vector3.Lerp(vector2, b, num); + } + + private IEnumerator TransitionToTarget(Transform newTarget) + { + transitionRunning = true; + Vector3 startPosition = base.transform.position; + Quaternion startRotation = base.transform.rotation; + float transitionTime2 = 0f; + while (targetPosition != newTarget.position || base.transform.rotation != newTarget.rotation) + { + transitionTime2 = Mathf.Clamp(transitionTime2, 0f, 1f); + float t = 3f * Mathf.Pow(transitionTime2, 2f) - 2f * Mathf.Pow(transitionTime2, 3f); + base.transform.position = Vector3.Lerp(startPosition, newTarget.position, t); + base.transform.rotation = Quaternion.Lerp(startRotation, newTarget.rotation, t); + transitionTime2 += Time.deltaTime * transitionSpeed; + yield return null; + } + currentTarget = newTarget; + transitionRunning = false; + } +} diff --git a/GameCode/CancelOrOpenPauseMenu.cs b/GameCode/CancelOrOpenPauseMenu.cs new file mode 100644 index 0000000..fc06dee --- /dev/null +++ b/GameCode/CancelOrOpenPauseMenu.cs @@ -0,0 +1,30 @@ +using Rewired; +using UnityEngine; + +public class CancelOrOpenPauseMenu : MonoBehaviour +{ + private Player input; + + private ChoiceManager choiceManager; + + private void Start() + { + input = ReInput.players.GetPlayer(0); + choiceManager = ChoiceManager.instance; + } + + private void Update() + { + if (input.GetButtonDown("Pause Menu & Cancel")) + { + if (choiceManager.ChoiceCoroutineRunning) + { + choiceManager.CancelChoice(); + } + else + { + SceneTransitionManager.instance.TransitionFromGameplayToEndScreen(ScoreManager.Instance.CurrentScore, 0, 0); + } + } + } +} diff --git a/GameCode/Checkbox.cs b/GameCode/Checkbox.cs new file mode 100644 index 0000000..40e1344 --- /dev/null +++ b/GameCode/Checkbox.cs @@ -0,0 +1,29 @@ +using UnityEngine; +using UnityEngine.Events; + +public class Checkbox : MonoBehaviour +{ + public UnityEvent onToggle = new UnityEvent(); + + public bool state; + + public GameObject checkObj; + + public void SetState(bool active) + { + state = active; + UpdateDisplay(); + } + + public void Toggle() + { + state = !state; + UpdateDisplay(); + onToggle.Invoke(); + } + + private void UpdateDisplay() + { + checkObj.SetActive(state); + } +} diff --git a/GameCode/Choice.cs b/GameCode/Choice.cs new file mode 100644 index 0000000..d638ebf --- /dev/null +++ b/GameCode/Choice.cs @@ -0,0 +1,22 @@ +using System; +using UnityEngine; + +[Serializable] +public class Choice +{ + public string name = ""; + + [TextArea] + public string tooltip = ""; + + public Sprite icon; + + public EquippableBuildingUpgrade requiresUnlocked; + + public Choice(string _name, string _tooltip, Sprite _icon = null) + { + name = _name; + tooltip = _tooltip; + icon = null; + } +} diff --git a/GameCode/ChoiceManager.cs b/GameCode/ChoiceManager.cs new file mode 100644 index 0000000..6ab87f9 --- /dev/null +++ b/GameCode/ChoiceManager.cs @@ -0,0 +1,83 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +public class ChoiceManager : MonoBehaviour +{ + public static ChoiceManager instance; + + private bool choiceCoroutineRunning; + + private bool choiceCanceled; + + [HideInInspector] + public List availableChoices = new List(); + + [HideInInspector] + public Choice choiceToReturn; + + [HideInInspector] + public BuildSlot currentOriginBuildSlot; + + public bool ChoiceCoroutineWaiting + { + get + { + if (!choiceCanceled) + { + return choiceToReturn == null; + } + return false; + } + } + + public bool ChoiceCoroutineRunning => choiceCoroutineRunning; + + public void CancelChoice() + { + choiceCanceled = true; + } + + private void Awake() + { + instance = this; + } + + public void PresentChoices(List _availableChoices, BuildSlot originBuildSlot, Action _onCompleteFunction) + { + if (!choiceCoroutineRunning) + { + currentOriginBuildSlot = originBuildSlot; + if (_availableChoices.Count == 0) + { + _onCompleteFunction(null); + return; + } + if (_availableChoices.Count == 1) + { + _onCompleteFunction(_availableChoices[0]); + return; + } + availableChoices = _availableChoices; + UIFrameManager.instance.PresentChoiceFrame(); + StartCoroutine(Choice(_availableChoices, _onCompleteFunction)); + } + } + + private IEnumerator Choice(List _availableChoices, Action _onCompleteFunction) + { + choiceToReturn = null; + choiceCoroutineRunning = true; + choiceCanceled = false; + LocalGamestate.Instance.SetPlayerFreezeState(frozen: true); + while (choiceToReturn == null && !choiceCanceled) + { + yield return null; + } + LocalGamestate.Instance.SetPlayerFreezeState(frozen: false); + yield return null; + _onCompleteFunction(choiceToReturn); + choiceCoroutineRunning = false; + } +} diff --git a/GameCode/ChoiceUI.cs b/GameCode/ChoiceUI.cs new file mode 100644 index 0000000..62415e2 --- /dev/null +++ b/GameCode/ChoiceUI.cs @@ -0,0 +1,48 @@ +using TMPro; +using UnityEngine; +using UnityEngine.UI; + +public class ChoiceUI : MonoBehaviour +{ + public Choice choice; + + public TMP_Text title; + + public TMP_Text description; + + public GameObject selected; + + public Image icon; + + public GameObject unlocked; + + public GameObject locked; + + private bool isunlocked; + + public bool IsUnlocked => isunlocked; + + public void SetChoice(Choice _choice) + { + if (!_choice.requiresUnlocked) + { + isunlocked = true; + } + else + { + isunlocked = PerkManager.instance.UnlockedEquippables.Contains(_choice.requiresUnlocked); + } + unlocked.SetActive(isunlocked); + locked.SetActive(!isunlocked); + choice = _choice; + title.text = _choice.name; + description.text = _choice.tooltip; + icon.sprite = _choice.icon; + SetHighlighted(_highlighted: false); + } + + public void SetHighlighted(bool _highlighted) + { + selected.SetActive(_highlighted); + } +} diff --git a/GameCode/ChoiceUIFrameHelper.cs b/GameCode/ChoiceUIFrameHelper.cs new file mode 100644 index 0000000..220e26a --- /dev/null +++ b/GameCode/ChoiceUIFrameHelper.cs @@ -0,0 +1,103 @@ +using System.Collections.Generic; +using I2.Loc; +using TMPro; +using UnityEngine; +using UnityEngine.UI; + +public class ChoiceUIFrameHelper : MonoBehaviour +{ + public UIFrame frame; + + public HorizontalLayoutGroup choicesParent; + + public TFUIUpgradeChoice upgradeChoiceButtonPrefab; + + public TextMeshProUGUI choiceTitle; + + public TextMeshProUGUI choiceDescription; + + private List choices = new List(); + + public void OnShow() + { + choices.Clear(); + foreach (Transform item in choicesParent.transform) + { + Object.Destroy(item.gameObject); + } + foreach (Choice availableChoice in ChoiceManager.instance.availableChoices) + { + AddChoiceTFUI(choicesParent, availableChoice); + } + RecomputeNavigation(); + } + + private void AddChoiceTFUI(HorizontalLayoutGroup parent, Choice _choice) + { + TFUIUpgradeChoice component = Object.Instantiate(upgradeChoiceButtonPrefab, parent.transform).GetComponent(); + component.SetData(_choice); + choices.Add(component); + } + + private void RecomputeNavigation() + { + for (int i = 0; i < choices.Count; i++) + { + TFUIUpgradeChoice tFUIUpgradeChoice = choices[i]; + if (i <= 0) + { + tFUIUpgradeChoice.leftNav = choices[choices.Count - 1]; + } + else + { + tFUIUpgradeChoice.leftNav = choices[i - 1]; + } + if (i >= choices.Count - 1) + { + tFUIUpgradeChoice.rightNav = choices[0]; + } + else + { + tFUIUpgradeChoice.rightNav = choices[i + 1]; + } + } + frame.firstSelected = choices[0]; + } + + public void UpdateSelectedChoice() + { + TFUIUpgradeChoice tFUIUpgradeChoice = null; + if (frame.CurrentFocus != null) + { + tFUIUpgradeChoice = frame.CurrentFocus as TFUIUpgradeChoice; + } + if (tFUIUpgradeChoice == null && frame.CurrentSelection != null) + { + tFUIUpgradeChoice = frame.CurrentSelection as TFUIUpgradeChoice; + } + if (tFUIUpgradeChoice != null) + { + if (!tFUIUpgradeChoice.Locked) + { + BuildSlot currentOriginBuildSlot = ChoiceManager.instance.currentOriginBuildSlot; + choiceTitle.text = LocalizationManager.GetTranslation(currentOriginBuildSlot.GET_LOCIDENTIFIER_CHOICENAME(tFUIUpgradeChoice.Data)); + choiceDescription.text = LocalizationManager.GetTranslation(currentOriginBuildSlot.GET_LOCIDENTIFIER_CHOICEDESCRIPTION(tFUIUpgradeChoice.Data)); + } + else + { + choiceTitle.text = LocalizationManager.GetTranslation("Menu/Locked"); + choiceDescription.text = LocalizationManager.GetTranslation("Menu/Locked Choice Description"); + } + } + } + + public void OnApply() + { + TFUIUpgradeChoice tFUIUpgradeChoice = frame.LastApplied as TFUIUpgradeChoice; + if (!(tFUIUpgradeChoice == null) && !tFUIUpgradeChoice.Locked) + { + ChoiceManager.instance.choiceToReturn = tFUIUpgradeChoice.Data; + UIFrameManager.instance.CloseActiveFrame(); + } + } +} diff --git a/GameCode/Coin.cs b/GameCode/Coin.cs new file mode 100644 index 0000000..9ba06a2 --- /dev/null +++ b/GameCode/Coin.cs @@ -0,0 +1,137 @@ +using UnityEngine; + +public class Coin : MonoBehaviour +{ + public Transform mesh; + + public float maxSpeed = 20f; + + public float accelerationTime = 1f; + + public AnimationCurve accelerationCurve; + + public float spawnAnimationDuration = 1f; + + public float spawnAnimationScale = 10f; + + public AnimationCurve spawnAnimationCurve; + + public bool groundOnSpawn; + + public LayerMask groundLayer; + + public Vector3 groundingOffset; + + public bool registerInTagManager; + + public GameObject onPickUpParticles; + + private PlayerInteraction target; + + private Vector3 targetOffset = Vector3.up * 2f; + + private float pickupRange = 0.1f; + + private float spawnAnimationClock; + + private Vector3 initialPosition; + + private float accelerationClock; + + private bool grounded; + + private Vector3 groundingPos; + + private float groundingVelocity; + + private bool particlesSpawned; + + public bool IsFree => target == null; + + private void Start() + { + mesh.rotation = Quaternion.Euler(Random.Range(0, 360), Random.Range(0, 360), Random.Range(0, 360)); + initialPosition = base.transform.position; + if (groundOnSpawn) + { + if (Physics.Raycast(new Ray(base.transform.position, Vector3.down), out var hitInfo, float.PositiveInfinity, groundLayer)) + { + groundingPos = hitInfo.point + groundingOffset; + initialPosition = groundingPos; + } + else + { + grounded = true; + } + } + if (registerInTagManager && (bool)TagManager.instance) + { + TagManager.instance.freeCoins.Add(this); + } + if ((bool)TagManager.instance) + { + TagManager.instance.coins.Add(this); + } + } + + private void Update() + { + mesh.Rotate(45f * Time.deltaTime, 120f * Time.deltaTime, 0f, Space.World); + if (groundOnSpawn && !grounded) + { + groundingVelocity += 9.81f * Time.deltaTime; + base.transform.position = Vector3.MoveTowards(base.transform.position, groundingPos, groundingVelocity); + if (Vector3.Distance(base.transform.position, groundingPos) < 0.05f) + { + base.transform.position = groundingPos; + grounded = true; + } + } + else if (spawnAnimationClock < spawnAnimationDuration) + { + spawnAnimationClock += Time.deltaTime; + base.transform.position = initialPosition + Vector3.up * spawnAnimationScale * spawnAnimationCurve.Evaluate(spawnAnimationClock / spawnAnimationDuration); + } + else + { + if (!target) + { + return; + } + accelerationClock += Time.deltaTime; + Vector3 vector = target.transform.position + targetOffset; + base.transform.position = Vector3.MoveTowards(base.transform.position, vector, maxSpeed * Time.deltaTime * accelerationCurve.Evaluate(accelerationClock / accelerationTime)); + if (!particlesSpawned && Vector3.Distance(vector, base.transform.position) < 3f) + { + if (onPickUpParticles != null) + { + Object.Instantiate(onPickUpParticles, vector, Quaternion.identity, target.transform); + } + particlesSpawned = true; + } + if (Vector3.Distance(vector, base.transform.position) < pickupRange) + { + target.AddCoin(); + ThronefallAudioManager.Oneshot(ThronefallAudioManager.AudioOneShot.CoinCollect); + Object.Destroy(base.gameObject); + } + } + } + + public void SetTarget(PlayerInteraction target) + { + this.target = target; + } + + private void OnDestroy() + { + if (registerInTagManager && (bool)TagManager.instance) + { + TagManager.instance.freeCoins.Remove(this); + } + if ((bool)TagManager.instance) + { + TagManager.instance.coins.Remove(this); + } + } +} diff --git a/GameCode/CoinSpawner.cs b/GameCode/CoinSpawner.cs new file mode 100644 index 0000000..0de0c20 --- /dev/null +++ b/GameCode/CoinSpawner.cs @@ -0,0 +1,63 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +public class CoinSpawner : MonoBehaviour +{ + public GameObject coinPrefab; + + public float interval = 0.5f; + + private int coinsLeft; + + public static List allCoinSpawners = new List(); + + public int CoinsLeft => coinsLeft; + + public static int AllCoinsLeftToBeSpawned + { + get + { + int num = 0; + for (int num2 = allCoinSpawners.Count - 1; num2 >= 0; num2--) + { + if (allCoinSpawners[num2] == null) + { + allCoinSpawners.RemoveAt(num2); + } + else + { + num += allCoinSpawners[num2].CoinsLeft; + } + } + return num; + } + } + + private void OnEnable() + { + allCoinSpawners.Add(this); + } + + private void OnDisable() + { + allCoinSpawners.Remove(this); + } + + public void TriggerCoinSpawn(int amount, PlayerInteraction player) + { + StartCoroutine(SpawnCoins(amount, interval, player)); + } + + private IEnumerator SpawnCoins(int amount, float delay, PlayerInteraction player) + { + coinsLeft = amount; + WaitForSeconds wait = new WaitForSeconds(delay); + for (int i = 0; i < amount; i++) + { + coinsLeft--; + Object.Instantiate(coinPrefab, base.transform.position, Quaternion.identity).GetComponent().SetTarget(player); + yield return wait; + } + } +} diff --git a/GameCode/Coinslot.cs b/GameCode/Coinslot.cs new file mode 100644 index 0000000..4a505f1 --- /dev/null +++ b/GameCode/Coinslot.cs @@ -0,0 +1,76 @@ +using MoreMountains.Feedbacks; +using UnityEngine; + +public class Coinslot : MonoBehaviour +{ + public Transform fillTarget; + + public AnimationCurve fillCurve; + + public MMF_Player fullFeedback; + + public MMF_Player deniedFeedback; + + public MMF_Player appearFeedback; + + public MMF_Player disappearFeedback; + + public MMF_Player fullCompleteFeedback; + + private float fill01; + + public bool isFull => fill01 >= 1f; + + public float CurrentFill01 => fill01; + + public bool AddFill(float percentage, bool isLastCoin) + { + fill01 += percentage; + fillTarget.localScale = Vector3.one * fillCurve.Evaluate(Mathf.Clamp01(fill01)); + if (isFull) + { + if (!isLastCoin) + { + fullFeedback.PlayFeedbacks(); + } + else + { + fullCompleteFeedback.PlayFeedbacks(); + } + return true; + } + return false; + } + + public void SetEmpty() + { + fill01 = 0f; + fillTarget.localScale = Vector3.zero; + } + + public void PlayDeny() + { + deniedFeedback.PlayFeedbacks(); + } + + public void Appear() + { + fullFeedback.StopFeedbacks(); + deniedFeedback.StopFeedbacks(); + appearFeedback.StopFeedbacks(); + disappearFeedback.StopFeedbacks(); + fill01 = 0f; + fillTarget.localScale = Vector3.zero; + base.transform.localScale = Vector3.zero; + appearFeedback.PlayFeedbacks(); + } + + public void Disappear() + { + fullFeedback.StopFeedbacks(); + deniedFeedback.StopFeedbacks(); + appearFeedback.StopFeedbacks(); + disappearFeedback.StopFeedbacks(); + disappearFeedback.PlayFeedbacks(); + } +} diff --git a/GameCode/ColorAndLightManager.cs b/GameCode/ColorAndLightManager.cs new file mode 100644 index 0000000..83afad1 --- /dev/null +++ b/GameCode/ColorAndLightManager.cs @@ -0,0 +1,235 @@ +using System.Collections; +using UnityEngine; + +public class ColorAndLightManager : MonoBehaviour, DayNightCycle.IDaytimeSensitive +{ + [SerializeField] + private Light sunlight; + + [SerializeField] + private Colorscheme colorscheme; + + [SerializeField] + private float transitionDuration = 3f; + + [SerializeField] + private Transform playerTransform; + + [SerializeField] + private Material enemyMaterial; + + [SerializeField] + private Material allyMaterial; + + [SerializeField] + private Material playerMaterial; + + [SerializeField] + private Material playerCapeMaterial; + + [SerializeField] + private Material playerCrownMaterial; + + [SerializeField] + private Material horseMaterial; + + [SerializeField] + private Material buildingMaterial; + + [SerializeField] + private Material buildingPreviewMaterial; + + [SerializeField] + private Material coinMaterial; + + [SerializeField] + private Material groundMaterial; + + [SerializeField] + private Material groundHigh; + + [SerializeField] + private Material groundLow; + + [SerializeField] + private Material groundPatches; + + [SerializeField] + private Material treeMaterial; + + [SerializeField] + private Material rockMaterial; + + [SerializeField] + private Material waterMaterial; + + [SerializeField] + private Material oceanMaterial; + + [SerializeField] + private Material roadMaterial; + + [SerializeField] + private Material shadowShapeMaterial; + + [SerializeField] + private Material customPostProcessingMaterial; + + public static Colorscheme currentColorscheme; + + public void OnDawn_AfterSunrise() + { + } + + public void OnDusk() + { + StopAllCoroutines(); + StartCoroutine(ToNight()); + } + + public void OnDawn_BeforeSunrise() + { + StopAllCoroutines(); + StartCoroutine(ToDay()); + } + + public void Daylight() + { + sunlight.color = colorscheme.dayLightColor; + AdjustAllOutlineColorsBasedOnLight(colorscheme.globalShadowColor, colorscheme.dayLightColor); + } + + public void SunsetLight() + { + sunlight.color = colorscheme.sunsetLightColor; + AdjustAllOutlineColorsBasedOnLight(colorscheme.globalShadowColor, colorscheme.sunsetLightColor); + } + + public void NightLight() + { + sunlight.color = colorscheme.nightLightColor; + AdjustAllOutlineColorsBasedOnLight(colorscheme.globalShadowColor, colorscheme.nightLightColor); + } + + private IEnumerator ToDay() + { + float timer2 = 0f; + sunlight.color = colorscheme.nightLightColor; + while (timer2 <= transitionDuration) + { + timer2 += Time.deltaTime; + sunlight.color = Color.Lerp(colorscheme.nightLightColor, colorscheme.sunsetLightColor, timer2 / transitionDuration); + AdjustAllOutlineColorsBasedOnLight(colorscheme.globalShadowColor, sunlight.color); + yield return null; + } + timer2 = 0f; + while (timer2 <= transitionDuration) + { + timer2 += Time.deltaTime; + sunlight.color = Color.Lerp(colorscheme.sunsetLightColor, colorscheme.dayLightColor, timer2 / transitionDuration); + AdjustAllOutlineColorsBasedOnLight(colorscheme.globalShadowColor, sunlight.color); + yield return null; + } + sunlight.color = colorscheme.dayLightColor; + AdjustAllOutlineColorsBasedOnLight(colorscheme.globalShadowColor, sunlight.color); + } + + private IEnumerator ToNight() + { + float timer = 0f; + sunlight.color = colorscheme.dayLightColor; + while (timer <= transitionDuration) + { + timer += Time.deltaTime; + sunlight.color = Color.Lerp(colorscheme.dayLightColor, colorscheme.nightLightColor, timer / transitionDuration); + AdjustAllOutlineColorsBasedOnLight(colorscheme.globalShadowColor, sunlight.color); + yield return null; + } + sunlight.color = colorscheme.nightLightColor; + AdjustAllOutlineColorsBasedOnLight(colorscheme.globalShadowColor, sunlight.color); + } + + private void Start() + { + sunlight.color = colorscheme.dayLightColor; + DayNightCycle.Instance.RegisterDaytimeSensitiveObject(this); + ApplayColorScheme(); + if ((bool)playerTransform && (bool)colorscheme.particlesToAttachToPlayer) + { + Object.Instantiate(colorscheme.particlesToAttachToPlayer, playerTransform).transform.localPosition = Vector3.zero; + } + } + + public void ApplayColorScheme() + { + ApplyColorScheme(colorscheme); + } + + public void ApplyColorScheme(Colorscheme _colorScheme) + { + SetMaterialColors(enemyMaterial, _colorScheme.enemyLightColor, _colorScheme.enemyMidColor, _colorScheme.globalShadowColor); + SetMaterialColors(allyMaterial, _colorScheme.allyLightColor, _colorScheme.allyMidColor, _colorScheme.globalShadowColor); + SetMaterialColors(playerMaterial, _colorScheme.playerLightColor, _colorScheme.playerMidColor, _colorScheme.globalShadowColor); + SetMaterialColors(playerCapeMaterial, _colorScheme.playerCapeLightColor, _colorScheme.playerCapeMidColor, _colorScheme.globalShadowColor); + SetMaterialColors(playerCrownMaterial, _colorScheme.playerCrownLightColor, _colorScheme.playerCrownMidColor, _colorScheme.globalShadowColor); + SetMaterialColors(horseMaterial, _colorScheme.horseLightColor, _colorScheme.horseMidColor, _colorScheme.globalShadowColor); + SetMaterialColors(buildingMaterial, _colorScheme.buildingLightColor, _colorScheme.buildingMidColor, _colorScheme.globalShadowColor); + SetMaterialColors(_lightCol: new Color(_colorScheme.buildingLightColor.r, _colorScheme.buildingLightColor.g, _colorScheme.buildingLightColor.b, 0.15f), _midCol: new Color(_colorScheme.buildingMidColor.r, _colorScheme.buildingMidColor.g, _colorScheme.buildingMidColor.b, 0.15f), _shadowCol: new Color(_colorScheme.globalShadowColor.r, _colorScheme.globalShadowColor.g, _colorScheme.globalShadowColor.b, 0.15f), _mat: buildingPreviewMaterial); + SetMaterialColors(coinMaterial, _colorScheme.coinLightColor, _colorScheme.coinMidColor, _colorScheme.globalShadowColor); + SetMaterialColors(groundMaterial, _colorScheme.groundColor, _colorScheme.globalShadowColor, _colorScheme.globalShadowColor); + SetMaterialColors(groundPatches, _colorScheme.groundColor, _colorScheme.globalShadowColor, _colorScheme.globalShadowColor); + SetMaterialColors(groundHigh, _colorScheme.groundColorHigh, _colorScheme.globalShadowColor, _colorScheme.globalShadowColor); + SetMaterialColors(groundLow, _colorScheme.groundColorLow, _colorScheme.globalShadowColor, _colorScheme.globalShadowColor); + SetMaterialColors(treeMaterial, _colorScheme.treeLightColor, _colorScheme.treeMidColor, _colorScheme.globalShadowColor); + SetMaterialColors(rockMaterial, _colorScheme.rockLightColor, _colorScheme.rockMidColor, _colorScheme.globalShadowColor); + SetMaterialColors(waterMaterial, _colorScheme.waterLightColor, _colorScheme.waterSecondaryColor, _colorScheme.globalShadowColor); + SetMaterialColors(oceanMaterial, _colorScheme.waterLightColor, _colorScheme.waterSecondaryColor, _colorScheme.globalShadowColor); + SetMaterialColors(roadMaterial, _colorScheme.roadColor, _colorScheme.globalShadowColor, _colorScheme.globalShadowColor); + SetMaterialColors(shadowShapeMaterial, _colorScheme.globalShadowColor, _colorScheme.globalShadowColor, _colorScheme.globalShadowColor); + SetMaterialColorsPostProcessing(customPostProcessingMaterial, _colorScheme.brightness, _colorScheme.topColorAdd, _colorScheme.botColorAdd, _colorScheme.contrast, _colorScheme.saturation, _colorScheme.mix); + currentColorscheme = _colorScheme; + } + + private void SetMaterialColors(Material _mat, Color _lightCol, Color _midCol, Color _shadowCol) + { + _mat.SetColor("_BaseColor", _lightCol); + _mat.SetColor("_ColorDim", _midCol); + _mat.SetColor("_ColorDimExtra", _shadowCol); + _mat.SetColor("_UnityShadowColor", _shadowCol); + _mat.SetColor("_OutlineColor", _shadowCol); + } + + public void AdjustAllOutlineColorsBasedOnLight(Color outlineColor, Color lightColor) + { + SetOutlineColorBasedOnLight(enemyMaterial, outlineColor, lightColor); + SetOutlineColorBasedOnLight(allyMaterial, outlineColor, lightColor); + SetOutlineColorBasedOnLight(playerMaterial, outlineColor, lightColor); + SetOutlineColorBasedOnLight(playerCapeMaterial, outlineColor, lightColor); + SetOutlineColorBasedOnLight(playerCrownMaterial, outlineColor, lightColor); + SetOutlineColorBasedOnLight(horseMaterial, outlineColor, lightColor); + SetOutlineColorBasedOnLight(buildingMaterial, outlineColor, lightColor); + SetOutlineColorBasedOnLight(coinMaterial, outlineColor, lightColor); + SetOutlineColorBasedOnLight(groundMaterial, outlineColor, lightColor); + SetOutlineColorBasedOnLight(groundPatches, outlineColor, lightColor); + SetOutlineColorBasedOnLight(treeMaterial, outlineColor, lightColor); + SetOutlineColorBasedOnLight(rockMaterial, outlineColor, lightColor); + SetOutlineColorBasedOnLight(waterMaterial, outlineColor, lightColor); + SetOutlineColorBasedOnLight(oceanMaterial, outlineColor, lightColor); + } + + private void SetOutlineColorBasedOnLight(Material _mat, Color _outlineCol, Color lightCol) + { + Color value = Color.Lerp(_outlineCol, _outlineCol * lightCol, _mat.GetFloat("_LightContribution")); + _mat.SetColor("_OutlineColor", value); + } + + private void SetMaterialColorsPostProcessing(Material _mat, float _brightness, Color _top, Color _bot, float _contrast, float _saturation, float _mix) + { + _mat.SetFloat("_Brightness", _brightness); + _mat.SetColor("_TopColorAdd", _top); + _mat.SetColor("_BotColorAdd", _bot); + _mat.SetFloat("_Contrast", _contrast); + _mat.SetFloat("_Saturation", _saturation); + _mat.SetFloat("_Mix", _mix); + } +} diff --git a/GameCode/Colorscheme.cs b/GameCode/Colorscheme.cs new file mode 100644 index 0000000..eac2adc --- /dev/null +++ b/GameCode/Colorscheme.cs @@ -0,0 +1,98 @@ +using UnityEngine; + +[CreateAssetMenu(fileName = "New Color Scheme", menuName = "SimpleSiege/Colorscheme")] +public class Colorscheme : ScriptableObject +{ + public readonly Color dayLightColor = Color.white; + + public Color sunsetLightColor; + + public Color nightLightColor; + + public Color globalShadowColor; + + [Header("Enemies")] + public Color enemyLightColor; + + public Color enemyMidColor; + + [Header("Allies")] + public Color allyLightColor; + + public Color allyMidColor; + + [Header("Player")] + public Color playerLightColor; + + public Color playerMidColor; + + public Color playerCapeLightColor; + + public Color playerCapeMidColor; + + public Color playerCrownLightColor; + + public Color playerCrownMidColor; + + public Color horseLightColor; + + public Color horseMidColor; + + [Header("Buildings")] + public Color buildingLightColor; + + public Color buildingMidColor; + + public Color coinLightColor; + + public Color coinMidColor; + + [Header("Environment")] + public Color groundColor; + + public Color groundColorHigh; + + public Color groundColorLow; + + public Color treeLightColor; + + public Color treeMidColor; + + public Color rockLightColor; + + public Color rockMidColor; + + public Color waterLightColor; + + public Color waterSecondaryColor; + + public Color roadColor; + + [Header("UI")] + public Color upgradeInteractorColor; + + [Header("Post Processing")] + public float brightness; + + public Color topColorAdd = Color.black; + + public Color botColorAdd = Color.black; + + public float contrast = 1f; + + public float saturation = 1f; + + public float mix = 1f; + + [Header("Particles")] + public GameObject particlesToAttachToPlayer; + + private void OnValidate() + { + ColorAndLightManager colorAndLightManager = Object.FindObjectOfType(); + if ((bool)colorAndLightManager) + { + colorAndLightManager.ApplyColorScheme(this); + } + } +} diff --git a/GameCode/CommandUnits.cs b/GameCode/CommandUnits.cs new file mode 100644 index 0000000..d439867 --- /dev/null +++ b/GameCode/CommandUnits.cs @@ -0,0 +1,261 @@ +using System.Collections.Generic; +using Pathfinding; +using Rewired; +using UnityEngine; + +public class CommandUnits : MonoBehaviour +{ + public static CommandUnits instance; + + public UnitCommandRadiusAnimation rangeIndicator; + + public GameObject commandingIndicator; + + public ParticleSystem dropWaypointFx; + + public int drowWaypointParticleCount = 100; + + public float attractRange; + + public string graphNameOfPlayerUnits; + + public float unitDistanceFromEachOther = 2f; + + public float unitDistanceMoveStep = 0.5f; + + public int maxPositioningRepeats = 5; + + public float holdToHoldPositionTime = 1f; + + private ThronefallAudioManager audioManager; + + private AudioSet audioSet; + + private NNConstraint nearestConstraint = new NNConstraint(); + + private List playerUnitsCommanding = new List(); + + private List playerUnitsCommandingBuffer = new List(); + + private Player input; + + [HideInInspector] + public bool commanding; + + private TagManager tagManager; + + private AstarPath astarPath; + + private PlayerUpgradeManager playerUPgradeManager; + + private Hp hpPlayer; + + private float timeSincePlace; + + private bool switchedToHold; + + private List autoAttacksToEnable = new List(); + + private void Awake() + { + instance = this; + } + + private void Start() + { + audioManager = ThronefallAudioManager.Instance; + audioSet = audioManager.audioContent; + input = ReInput.players.GetPlayer(0); + tagManager = TagManager.instance; + astarPath = AstarPath.active; + nearestConstraint.graphMask = GraphMask.FromGraphName(graphNameOfPlayerUnits); + playerUPgradeManager = PlayerUpgradeManager.instance; + hpPlayer = GetComponent(); + } + + private void Update() + { + if (!commanding) + { + if (input.GetButtonDown("Command Units")) + { + rangeIndicator.Activate(); + } + if (input.GetButton("Command Units") && hpPlayer.HpValue > 0f) + { + foreach (TaggedObject playerUnit in TagManager.instance.PlayerUnits) + { + if (tagManager.MeasureDistanceToTaggedObject(playerUnit, base.transform.position) <= attractRange) + { + OnUnitAdd(playerUnit); + } + } + } + else if (playerUnitsCommanding.Count > 0) + { + commanding = true; + } + } + else + { + if (input.GetButtonDown("Command Units") || hpPlayer.HpValue <= 0f) + { + PlaceCommandedUnitsAndCalculateTargetPositions(); + timeSincePlace = 0f; + switchedToHold = false; + } + if (input.GetButton("Command Units") && hpPlayer.HpValue > 0f) + { + timeSincePlace += Time.deltaTime; + if (timeSincePlace > holdToHoldPositionTime && !switchedToHold) + { + switchedToHold = true; + MakeUnitsInBufferHoldPosition(); + } + } + if (input.GetButtonUp("Command Units") || hpPlayer.HpValue <= 0f) + { + commanding = false; + timeSincePlace = 0f; + } + } + for (int num = playerUnitsCommanding.Count - 1; num >= 0; num--) + { + PathfindMovementPlayerunit pathfindMovementPlayerunit = playerUnitsCommanding[num]; + pathfindMovementPlayerunit.HomePosition = base.transform.position; + if (!pathfindMovementPlayerunit.enabled) + { + playerUnitsCommanding.RemoveAt(num); + OnUnitRemove(pathfindMovementPlayerunit); + } + } + if (playerUnitsCommanding.Count > 0 && !input.GetButton("Command Units")) + { + commandingIndicator.SetActive(value: true); + } + else + { + commandingIndicator.SetActive(value: false); + } + if (!input.GetButton("Command Units") && rangeIndicator.Active) + { + rangeIndicator.Deactivate(); + } + } + + public void MakeUnitsInBufferHoldPosition() + { + if (playerUnitsCommandingBuffer.Count > 0) + { + audioManager.PlaySoundAsOneShot(audioSet.HoldPosition, 0.45f, 0.9f + Random.value * 0.2f, audioManager.mgSFX, 10); + } + foreach (PathfindMovementPlayerunit item in playerUnitsCommandingBuffer) + { + item.HoldPosition = true; + } + } + + public void ForceCommandingEnd() + { + if (commanding) + { + PlaceCommandedUnitsAndCalculateTargetPositions(); + } + } + + public void PlaceCommandedUnitsAndCalculateTargetPositions() + { + if (!commanding) + { + return; + } + if (playerUnitsCommanding.Count > 0) + { + audioManager.PlaySoundAsOneShot(audioSet.PlaceCommandingUnits, 0.35f, 0.9f + Random.value * 0.2f, audioManager.mgSFX, 10); + } + dropWaypointFx.Emit(drowWaypointParticleCount); + foreach (PathfindMovementPlayerunit item in playerUnitsCommanding) + { + OnUnitRemove(item); + } + foreach (AutoAttack item2 in autoAttacksToEnable) + { + if ((bool)item2 && item2.GetComponent().HpValue > 0f) + { + item2.enabled = true; + } + } + autoAttacksToEnable.Clear(); + for (int i = 0; i < playerUnitsCommanding.Count; i++) + { + Vector3 vector = Quaternion.AngleAxis((float)(i / playerUnitsCommanding.Count) * 360f, Vector3.up) * Vector3.right * unitDistanceMoveStep; + playerUnitsCommanding[i].HomePosition = astarPath.GetNearest(base.transform.position + vector + new Vector3(Random.value - 0.5f, 0f, Random.value - 0.5f) * unitDistanceMoveStep * 0.1f, nearestConstraint).position; + } + for (int j = 0; j < maxPositioningRepeats; j++) + { + bool flag = false; + for (int k = 0; k < playerUnitsCommanding.Count; k++) + { + for (int l = k + 1; l < playerUnitsCommanding.Count; l++) + { + if (!((playerUnitsCommanding[k].HomePosition - playerUnitsCommanding[l].HomePosition).magnitude > unitDistanceFromEachOther)) + { + Vector3 vector2 = (playerUnitsCommanding[k].HomePosition - playerUnitsCommanding[l].HomePosition).normalized * unitDistanceMoveStep; + playerUnitsCommanding[k].HomePosition = astarPath.GetNearest(playerUnitsCommanding[k].HomePosition + vector2, nearestConstraint).position; + playerUnitsCommanding[l].HomePosition = astarPath.GetNearest(playerUnitsCommanding[l].HomePosition - vector2, nearestConstraint).position; + flag = true; + } + } + } + if (!flag) + { + break; + } + } + playerUnitsCommandingBuffer.Clear(); + playerUnitsCommandingBuffer.AddRange(playerUnitsCommanding); + playerUnitsCommanding.Clear(); + } + + public void OnUnitAdd(TaggedObject _t) + { + PathfindMovementPlayerunit pathfindMovementPlayerunit = (PathfindMovementPlayerunit)_t.Hp.PathfindMovement; + if (!playerUnitsCommanding.Contains(pathfindMovementPlayerunit)) + { + audioManager.PlaySoundAsOneShot(audioSet.AddedUnitToCommanding, 0.55f, 0.7f + (float)playerUnitsCommanding.Count * 0.025f, audioManager.mgSFX, 50); + playerUnitsCommanding.Add(pathfindMovementPlayerunit); + pathfindMovementPlayerunit.FollowPlayer(_follow: true); + MaterialFlasherFX componentInChildren = pathfindMovementPlayerunit.GetComponentInChildren(); + if ((bool)componentInChildren) + { + componentInChildren.SetSelected(_selected: true); + } + _t.Tags.Add(TagManager.ETag.AUTO_Commanded); + if (playerUPgradeManager.commander) + { + pathfindMovementPlayerunit.movementSpeed *= UpgradeCommander.instance.moveSpeedMultiplicator; + } + AutoAttack[] components = _t.GetComponents(); + foreach (AutoAttack autoAttack in components) + { + autoAttack.enabled = false; + autoAttacksToEnable.Add(autoAttack); + } + } + } + + public void OnUnitRemove(PathfindMovementPlayerunit _p) + { + _p.FollowPlayer(_follow: false); + MaterialFlasherFX componentInChildren = _p.GetComponentInChildren(); + if ((bool)componentInChildren) + { + componentInChildren.SetSelected(_selected: false); + } + _p.GetComponent().Tags.Remove(TagManager.ETag.AUTO_Commanded); + if (playerUPgradeManager.commander) + { + _p.movementSpeed /= UpgradeCommander.instance.moveSpeedMultiplicator; + } + } +} diff --git a/GameCode/CostDisplay.cs b/GameCode/CostDisplay.cs new file mode 100644 index 0000000..350a1cf --- /dev/null +++ b/GameCode/CostDisplay.cs @@ -0,0 +1,256 @@ +using System.Collections; +using System.Collections.Generic; +using MoreMountains.Feedbacks; +using TMPro; +using UnityEngine; + +public class CostDisplay : MonoBehaviour +{ + public Coinslot coinslotPrefab; + + public Coin coinPrefab; + + public RectTransform gridParent; + + public float horizontalSpacing; + + public int maxElementsPerRow = 5; + + public AnimationCurve yDistribution = new AnimationCurve(); + + public float peakYOffset = 50f; + + public float rowYSpacing = 100f; + + public Transform amountDisplayParent; + + public TextMeshProUGUI amountDisplay; + + public MMF_Player displayCostAmountShow; + + public MMF_Player displayCostAmountHide; + + private List coinslotPool = new List(); + + private List currentlyActiveCoinslots = new List(); + + private float elementWidth; + + private float yCurveLeftAnchor; + + private float yCurveRightAnchor; + + private bool reUpdateBecauseFuckUnityCanvas; + + private int currentAmount; + + private int currentlyFilledCoins; + + private float completeFillDuration = 1f; + + private float minFillDurationPerCoin = 0.15f; + + private bool denied; + + private bool inDisappearAnimation; + + private const float defaultScale = 0.01f; + + private const float largeUIScale = 0.0125f; + + public static int currentlyFilledCoinsFromLastActiveDisplay; + + public bool CompletelyFilled => currentlyFilledCoins >= currentAmount; + + public bool CompletelyEmpty => currentlyFilledCoins <= 0; + + private void Start() + { + elementWidth = coinslotPrefab.GetComponent().sizeDelta.x; + float num = (float)maxElementsPerRow * elementWidth + (float)(maxElementsPerRow - 1) * horizontalSpacing; + yCurveLeftAnchor = (0f - num) / 2f + elementWidth / 2f; + yCurveRightAnchor = num / 2f - elementWidth / 2f; + } + + private void Update() + { + if (reUpdateBecauseFuckUnityCanvas) + { + UpdateDisplay(currentAmount, dirty: false); + } + } + + public void UpdateDisplay(int amount, bool dirty = true) + { + if (SettingsManager.Instance.UseLargeInGameUI) + { + base.transform.localScale = Vector3.one * 0.0125f; + } + else + { + base.transform.localScale = Vector3.one * 0.01f; + } + inDisappearAnimation = false; + base.gameObject.SetActive(value: true); + StopAllCoroutines(); + currentAmount = amount; + reUpdateBecauseFuckUnityCanvas = dirty; + currentlyActiveCoinslots.Clear(); + currentlyFilledCoins = 0; + denied = false; + amountDisplayParent.gameObject.SetActive(value: false); + if (amount < 1) + { + foreach (Coinslot item in coinslotPool) + { + item.gameObject.SetActive(value: false); + } + return; + } + int num = amount - coinslotPool.Count; + for (int i = 0; i < num; i++) + { + coinslotPool.Add(Object.Instantiate(coinslotPrefab.gameObject, gridParent).GetComponent()); + } + int num2 = amount; + int num3 = num2; + if (num3 > maxElementsPerRow) + { + num3 = maxElementsPerRow; + } + int num4 = 0; + int num5 = 0; + float num6 = (0f - ((float)num3 * elementWidth + (float)(num3 - 1) * horizontalSpacing)) / 2f + elementWidth / 2f; + for (int j = 0; j < coinslotPool.Count; j++) + { + Coinslot coinslot = coinslotPool[j]; + if (j < amount) + { + coinslot.gameObject.SetActive(value: true); + currentlyActiveCoinslots.Add(coinslot); + coinslot.transform.localScale = Vector3.zero; + float num7 = num6 + ((float)num4 * elementWidth + (float)num4 * horizontalSpacing); + float y = peakYOffset * yDistribution.Evaluate(Mathf.InverseLerp(yCurveLeftAnchor, yCurveRightAnchor, num7)) + rowYSpacing * (float)num5; + coinslotPool[j].GetComponent().anchoredPosition = new Vector2(num7, y); + num4++; + num2--; + if (num4 >= maxElementsPerRow) + { + num3 = num2; + if (num3 > maxElementsPerRow) + { + num3 = maxElementsPerRow; + } + num4 = 0; + num5++; + num6 = (0f - ((float)num3 * elementWidth + (float)(num3 - 1) * horizontalSpacing)) / 2f + elementWidth / 2f; + } + } + else + { + coinslot.gameObject.SetActive(value: false); + } + } + foreach (Coinslot currentlyActiveCoinslot in currentlyActiveCoinslots) + { + currentlyActiveCoinslot.SetEmpty(); + } + float num8 = (float)currentlyActiveCoinslots.Count * minFillDurationPerCoin; + if (num8 < completeFillDuration) + { + num8 = 1f; + } + ThronefallAudioManager.SetCoinDisplayFillTime(num8); + StartCoroutine(AnimateShowSlots()); + } + + public bool FillUp() + { + currentlyFilledCoinsFromLastActiveDisplay = currentlyFilledCoins; + if (currentlyActiveCoinslots.Count > currentlyFilledCoins && currentlyActiveCoinslots[currentlyFilledCoins].AddFill(Time.deltaTime * (1f / Mathf.Clamp(completeFillDuration / (float)currentAmount, minFillDurationPerCoin, completeFillDuration)), currentlyActiveCoinslots.Count - 1 == currentlyFilledCoins)) + { + currentlyFilledCoins++; + currentlyFilledCoinsFromLastActiveDisplay = currentlyFilledCoins; + return true; + } + return false; + } + + public void Deny() + { + if (!denied) + { + currentlyActiveCoinslots[currentlyFilledCoins].PlayDeny(); + ThronefallAudioManager.Instance.MakeSureCoinFillSoundIsNotPlayingAnymore(); + denied = true; + } + } + + public void OnCompletion() + { + currentlyFilledCoins = 0; + currentlyFilledCoinsFromLastActiveDisplay = 0; + denied = false; + } + + public void CancelFill(PlayerInteraction player) + { + foreach (Coinslot currentlyActiveCoinslot in currentlyActiveCoinslots) + { + if (currentlyActiveCoinslot.isFull) + { + Object.Instantiate(coinPrefab, currentlyActiveCoinslot.transform.position, currentlyActiveCoinslot.transform.rotation).SetTarget(player); + } + currentlyActiveCoinslot.SetEmpty(); + } + ThronefallAudioManager.Oneshot(ThronefallAudioManager.AudioOneShot.CoinFillCancel); + currentlyFilledCoins = 0; + currentlyFilledCoinsFromLastActiveDisplay = 0; + denied = false; + } + + private IEnumerator AnimateShowSlots() + { + float waitTime = 0.2f / (float)currentAmount; + if (currentAmount > maxElementsPerRow) + { + amountDisplayParent.gameObject.SetActive(value: true); + amountDisplay.text = "x" + currentAmount; + displayCostAmountShow.PlayFeedbacks(); + yield return new WaitForSeconds(waitTime); + } + foreach (Coinslot currentlyActiveCoinslot in currentlyActiveCoinslots) + { + currentlyActiveCoinslot.Appear(); + yield return new WaitForSeconds(waitTime); + } + } + + public void Hide() + { + if (base.gameObject.activeSelf && !inDisappearAnimation) + { + inDisappearAnimation = true; + StopAllCoroutines(); + StartCoroutine(AnimateHideSlots()); + } + } + + private IEnumerator AnimateHideSlots() + { + float waitTime = 0.2f / (float)currentAmount; + if (amountDisplay.gameObject.activeInHierarchy) + { + displayCostAmountHide.PlayFeedbacks(); + yield return new WaitForSeconds(waitTime); + } + foreach (Coinslot currentlyActiveCoinslot in currentlyActiveCoinslots) + { + currentlyActiveCoinslot.Disappear(); + yield return new WaitForSeconds(waitTime); + } + yield return new WaitForSeconds(1f); + inDisappearAnimation = false; + base.gameObject.SetActive(value: false); + } +} diff --git a/GameCode/CustomPostProcess.cs b/GameCode/CustomPostProcess.cs new file mode 100644 index 0000000..6b88bfc --- /dev/null +++ b/GameCode/CustomPostProcess.cs @@ -0,0 +1,62 @@ +using System; +using UnityEngine; +using UnityEngine.Rendering; +using UnityEngine.Rendering.Universal; + +public class CustomPostProcess : ScriptableRendererFeature +{ + private class CustomRenderPass : ScriptableRenderPass + { + public RenderTargetIdentifier source; + + private Material mat; + + private RenderTargetHandle tempRenderTargetHandle; + + public CustomRenderPass(Material _mat) + { + mat = _mat; + tempRenderTargetHandle.Init("_TemporaryColorTexture"); + } + + public override void OnCameraSetup(CommandBuffer cmd, ref RenderingData renderingData) + { + } + + public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData) + { + CommandBuffer commandBuffer = CommandBufferPool.Get(); + commandBuffer.GetTemporaryRT(tempRenderTargetHandle.id, renderingData.cameraData.cameraTargetDescriptor); + Blit(commandBuffer, source, tempRenderTargetHandle.Identifier(), mat); + Blit(commandBuffer, tempRenderTargetHandle.Identifier(), source); + context.ExecuteCommandBuffer(commandBuffer); + CommandBufferPool.Release(commandBuffer); + } + + public override void OnCameraCleanup(CommandBuffer cmd) + { + } + } + + [Serializable] + public class Settings + { + public Material material; + } + + private CustomRenderPass m_ScriptablePass; + + public Settings settings; + + public override void Create() + { + m_ScriptablePass = new CustomRenderPass(settings.material); + m_ScriptablePass.renderPassEvent = RenderPassEvent.BeforeRenderingPostProcessing; + } + + public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData) + { + m_ScriptablePass.source = renderer.cameraColorTarget; + renderer.EnqueuePass(m_ScriptablePass); + } +} diff --git a/GameCode/DamageModifyer.cs b/GameCode/DamageModifyer.cs new file mode 100644 index 0000000..4e44e7b --- /dev/null +++ b/GameCode/DamageModifyer.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; + +[Serializable] +public class DamageModifyer +{ + public List requiredTags = new List(); + + public float damageAdded; + + public float damageMultiplyer = 1f; + + public bool AppliesTo(TaggedObject _taggedObject) + { + for (int i = 0; i < requiredTags.Count; i++) + { + if (!_taggedObject.Tags.Contains(requiredTags[i])) + { + return false; + } + } + return true; + } + + public static float CalculateDamageOnTarget(TaggedObject _taggedObject, List _damageModifyers, float _finalDamageMultiplyer = 1f) + { + float num = 0f; + for (int i = 0; i < _damageModifyers.Count; i++) + { + DamageModifyer damageModifyer = _damageModifyers[i]; + if (damageModifyer.AppliesTo(_taggedObject)) + { + num += damageModifyer.damageAdded; + num *= damageModifyer.damageMultiplyer; + } + } + return num * _finalDamageMultiplyer; + } +} diff --git a/GameCode/DayNightCycle.cs b/GameCode/DayNightCycle.cs new file mode 100644 index 0000000..348a641 --- /dev/null +++ b/GameCode/DayNightCycle.cs @@ -0,0 +1,202 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +public class DayNightCycle : MonoBehaviour +{ + public interface IDaytimeSensitive + { + void OnDusk(); + + void OnDawn_AfterSunrise(); + + void OnDawn_BeforeSunrise(); + } + + public enum Timestate + { + Day, + Night + } + + private static DayNightCycle instance; + + public float sunriseTime = 2.5f; + + private Timestate currentTimestate; + + private float currentNightLength; + + private List daytimeSensitiveObjects = new List(); + + private bool afterSunrise = true; + + public static DayNightCycle Instance => instance; + + public Timestate CurrentTimestate => currentTimestate; + + public float CurrentNightLength => currentNightLength; + + public bool AfterSunrise => afterSunrise; + + public int CoinCountToBeHarvested + { + get + { + int num = 0; + foreach (BuildingInteractor playerBuildingInteractor in TagManager.instance.playerBuildingInteractors) + { + if ((bool)playerBuildingInteractor.coinSpawner) + { + num += playerBuildingInteractor.coinSpawner.CoinsLeft; + } + if (playerBuildingInteractor.canBeHarvested) + { + num += playerBuildingInteractor.GoldIncome; + } + } + return num; + } + } + + private void Awake() + { + if (instance != null) + { + Object.Destroy(this); + } + else + { + instance = this; + } + } + + private void Update() + { + if (LocalGamestate.Instance.CurrentState == LocalGamestate.State.InMatch) + { + if (currentTimestate == Timestate.Night) + { + currentNightLength += Time.deltaTime; + } + if (currentTimestate == Timestate.Night && (bool)TagManager.instance && (bool)EnemySpawner.instance && !EnemySpawner.instance.SpawningInProgress && TagManager.instance.CountAllTaggedObjectsWithTag(TagManager.ETag.EnemyOwned) < 1 && base.gameObject.activeInHierarchy) + { + StartCoroutine(SwitchToDayCoroutine()); + } + } + } + + private void DawnCallAfterSunrise() + { + afterSunrise = true; + Hp.ReviveAllKnockedOutPlayerUnitsAndBuildings(); + for (int num = daytimeSensitiveObjects.Count - 1; num >= 0; num--) + { + if (daytimeSensitiveObjects[num] != null) + { + daytimeSensitiveObjects[num].OnDawn_AfterSunrise(); + } + else + { + daytimeSensitiveObjects.RemoveAt(num); + } + } + ThronefallAudioManager.Oneshot(ThronefallAudioManager.AudioOneShot.BuildingRepair); + LevelData levelDataForActiveScene = LevelProgressManager.instance.GetLevelDataForActiveScene(); + int networth = PlayerInteraction.instance.Networth; + networth += TagManager.instance.freeCoins.Count; + networth += CoinCountToBeHarvested; + levelDataForActiveScene.dayToDayNetworth.Add(networth); + PlayerInteraction component = TagManager.instance.Players[0].GetComponent(); + foreach (Coin freeCoin in TagManager.instance.freeCoins) + { + if (freeCoin.IsFree) + { + freeCoin.SetTarget(component); + } + } + } + + private void DawnCallBeforeSunrise() + { + afterSunrise = false; + for (int num = daytimeSensitiveObjects.Count - 1; num >= 0; num--) + { + if (daytimeSensitiveObjects[num] != null) + { + daytimeSensitiveObjects[num].OnDawn_BeforeSunrise(); + } + else + { + daytimeSensitiveObjects.RemoveAt(num); + } + } + ThronefallAudioManager.Oneshot(ThronefallAudioManager.AudioOneShot.NightSurvived); + } + + private void DuskCall() + { + afterSunrise = false; + currentNightLength = 0f; + for (int num = daytimeSensitiveObjects.Count - 1; num >= 0; num--) + { + if (daytimeSensitiveObjects[num] != null) + { + daytimeSensitiveObjects[num].OnDusk(); + } + else + { + daytimeSensitiveObjects.RemoveAt(num); + } + } + } + + public void ToggleDaytime() + { + if (currentTimestate == Timestate.Day) + { + currentTimestate = Timestate.Night; + DuskCall(); + } + else + { + currentTimestate = Timestate.Day; + DawnCallBeforeSunrise(); + DawnCallAfterSunrise(); + } + } + + private IEnumerator SwitchToDayCoroutine() + { + if (currentTimestate == Timestate.Night) + { + currentTimestate = Timestate.Day; + DawnCallBeforeSunrise(); + yield return new WaitForSeconds(sunriseTime); + DawnCallAfterSunrise(); + if (EnemySpawner.instance.Wavenumber >= EnemySpawner.instance.waves.Count - 1) + { + LocalGamestate.Instance.SetState(LocalGamestate.State.AfterMatchVictory); + } + } + } + + public void SwitchToNight() + { + if (currentTimestate != Timestate.Night) + { + currentTimestate = Timestate.Night; + DuskCall(); + } + } + + public void RegisterDaytimeSensitiveObject(IDaytimeSensitive obj) + { + daytimeSensitiveObjects.Add(obj); + } + + public void UnregisterDaytimeSensitiveObject(IDaytimeSensitive obj) + { + daytimeSensitiveObjects.Remove(obj); + } +} diff --git a/GameCode/DaytimeDisplay.cs b/GameCode/DaytimeDisplay.cs new file mode 100644 index 0000000..e179fcc --- /dev/null +++ b/GameCode/DaytimeDisplay.cs @@ -0,0 +1,15 @@ +using TMPro; +using UnityEngine; + +public class DaytimeDisplay : MonoBehaviour +{ + public TextMeshProUGUI display; + + private void Update() + { + if ((bool)DayNightCycle.Instance) + { + display.text = DayNightCycle.Instance.CurrentTimestate.ToString(); + } + } +} diff --git a/GameCode/DaytimeSensitiveActivation.cs b/GameCode/DaytimeSensitiveActivation.cs new file mode 100644 index 0000000..aef1a95 --- /dev/null +++ b/GameCode/DaytimeSensitiveActivation.cs @@ -0,0 +1,49 @@ +using UnityEngine; + +public class DaytimeSensitiveActivation : MonoBehaviour, DayNightCycle.IDaytimeSensitive +{ + public DayNightCycle.Timestate activeTime; + + public GameObject target; + + public void OnDawn_AfterSunrise() + { + if (activeTime == DayNightCycle.Timestate.Day) + { + target.SetActive(value: true); + } + else + { + target.SetActive(value: false); + } + } + + public void OnDawn_BeforeSunrise() + { + } + + public void OnDusk() + { + if (activeTime == DayNightCycle.Timestate.Night) + { + target.SetActive(value: true); + } + else + { + target.SetActive(value: false); + } + } + + private void Start() + { + DayNightCycle.Instance.RegisterDaytimeSensitiveObject(this); + if (DayNightCycle.Instance.CurrentTimestate == DayNightCycle.Timestate.Day) + { + target.SetActive(activeTime == DayNightCycle.Timestate.Day); + } + else + { + target.SetActive(activeTime == DayNightCycle.Timestate.Night); + } + } +} diff --git a/GameCode/DaytimeSensitiveLight.cs b/GameCode/DaytimeSensitiveLight.cs new file mode 100644 index 0000000..da571d3 --- /dev/null +++ b/GameCode/DaytimeSensitiveLight.cs @@ -0,0 +1,83 @@ +using System.Collections; +using UnityEngine; + +[RequireComponent(typeof(Light))] +public class DaytimeSensitiveLight : MonoBehaviour, DayNightCycle.IDaytimeSensitive +{ + [SerializeField] + private Color dayColor = Color.white; + + [SerializeField] + private Color sunsetColor; + + [SerializeField] + private Color nightColor; + + [SerializeField] + private float dayToSunsetDuration = 2f; + + [SerializeField] + private float sunsetToNightDuration = 2f; + + private Light targetLight; + + private void Start() + { + targetLight = GetComponent(); + DayNightCycle.Instance.RegisterDaytimeSensitiveObject(this); + } + + public void OnDawn_AfterSunrise() + { + } + + public void OnDusk() + { + StopAllCoroutines(); + StartCoroutine(ToNight()); + } + + public void OnDawn_BeforeSunrise() + { + StopAllCoroutines(); + StartCoroutine(ToDay()); + } + + private IEnumerator ToDay() + { + float timer2 = 0f; + while (timer2 <= sunsetToNightDuration) + { + timer2 += Time.deltaTime; + targetLight.color = Color.Lerp(nightColor, sunsetColor, timer2 / sunsetToNightDuration); + yield return null; + } + timer2 = 0f; + while (timer2 <= dayToSunsetDuration) + { + timer2 += Time.deltaTime; + targetLight.color = Color.Lerp(sunsetColor, dayColor, timer2 / dayToSunsetDuration); + yield return null; + } + targetLight.color = dayColor; + } + + private IEnumerator ToNight() + { + float timer2 = 0f; + while (timer2 <= dayToSunsetDuration) + { + timer2 += Time.deltaTime; + targetLight.color = Color.Lerp(dayColor, sunsetColor, timer2 / dayToSunsetDuration); + yield return null; + } + timer2 = 0f; + while (timer2 <= sunsetToNightDuration) + { + timer2 += Time.deltaTime; + targetLight.color = Color.Lerp(dayColor, nightColor, timer2 / sunsetToNightDuration); + yield return null; + } + targetLight.color = nightColor; + } +} diff --git a/GameCode/DebugBuildingDestroyer.cs b/GameCode/DebugBuildingDestroyer.cs new file mode 100644 index 0000000..4e9d10c --- /dev/null +++ b/GameCode/DebugBuildingDestroyer.cs @@ -0,0 +1,33 @@ +using UnityEngine; + +public class DebugBuildingDestroyer : MonoBehaviour +{ + public LayerMask interactionLayer; + + public float interactionRadius = 4f; + + private void Update() + { + Collider[] array = Physics.OverlapSphere(base.transform.position, interactionRadius, interactionLayer); + Hp hp = null; + float num = float.PositiveInfinity; + Collider[] array2 = array; + foreach (Collider collider in array2) + { + Hp componentInParent = collider.GetComponentInParent(); + if (!(componentInParent.gameObject == base.gameObject) && (bool)componentInParent) + { + float num2 = Vector3.Distance(base.transform.position, collider.ClosestPoint(base.transform.position)); + if (num2 < num) + { + hp = componentInParent; + num = num2; + } + } + } + if ((bool)hp && Input.GetKeyDown(KeyCode.LeftShift)) + { + hp.TakeDamage(hp.maxHp); + } + } +} diff --git a/GameCode/DebugCoinDisplay.cs b/GameCode/DebugCoinDisplay.cs new file mode 100644 index 0000000..b2f021d --- /dev/null +++ b/GameCode/DebugCoinDisplay.cs @@ -0,0 +1,19 @@ +using TMPro; +using UnityEngine; + +public class DebugCoinDisplay : MonoBehaviour +{ + public TextMeshProUGUI target; + + private PlayerInteraction player; + + private void Start() + { + player = Object.FindObjectOfType(); + } + + private void Update() + { + target.text = player.Balance.ToString(); + } +} diff --git a/GameCode/DebugController.cs b/GameCode/DebugController.cs new file mode 100644 index 0000000..878e6d7 --- /dev/null +++ b/GameCode/DebugController.cs @@ -0,0 +1,133 @@ +using UnityEngine; + +public class DebugController : MonoBehaviour +{ + public enum SaveLoadMode + { + Normal, + LoadEmptySaveFileOnStartup, + LoadMaxedOutSaveFileOnStartup + } + + [Tooltip("Set to -1 to disable")] + public int startGameInWave = -1; + + public static DebugController instance; + + [SerializeField] + private SaveLoadMode saveLoadMode; + + [SerializeField] + private bool saveTheGame = true; + + public KeyCode addCoin = KeyCode.Alpha2; + + public KeyCode removeCoin = KeyCode.Alpha3; + + public KeyCode getPoints = KeyCode.Alpha4; + + public KeyCode upgradeAllBuildingsToMax = KeyCode.Alpha9; + + public KeyCode reviveAllYourUnits = KeyCode.Alpha6; + + public KeyCode killAllEnemyUnits = KeyCode.Alpha7; + + public KeyCode restartScene = KeyCode.R; + + public KeyCode spawnNextWave = KeyCode.T; + + public KeyCode goToLevelSelect = KeyCode.Escape; + + public KeyCode instaWinLevel = KeyCode.End; + + public KeyCode causeLagSpike = KeyCode.L; + + public KeyCode openTestChoice = KeyCode.C; + + public KeyCode softWinLevel = KeyCode.Alpha8; + + public KeyCode deletePlayerPrefs = KeyCode.Minus; + + public KeyCode killPlayer = KeyCode.K; + + public KeyCode enableDisableUI = KeyCode.KeypadMinus; + + private PlayerInteraction playerInteraction; + + private float muteClock; + + private bool muted; + + private float initMasterVol; + + public int StartGameInWave => -1; + + public static SaveLoadMode SaveLoadModeToUse + { + get + { + if (instance == null) + { + return SaveLoadMode.Normal; + } + _ = instance.enabled; + return SaveLoadMode.Normal; + } + } + + public static bool SaveTheGame + { + get + { + if (instance == null) + { + return true; + } + _ = instance.enabled; + return true; + } + } + + private void Awake() + { + if (instance != null) + { + Object.Destroy(base.gameObject); + return; + } + instance = this; + Object.DontDestroyOnLoad(base.gameObject); + } + + public void EnableUICanvases() + { + NightCall.instance.gameObject.SetActive(value: true); + UIFrameManager.instance.gameObject.SetActive(value: true); + } + + private void Update() + { + } + + public void LogChoice(Choice _choice) + { + if (_choice != null) + { + Debug.Log(_choice.name); + } + else + { + Debug.Log("Choice cancelled."); + } + } + + public void Mute(float duration = 3f) + { + ThronefallAudioManager.Mute(); + muted = true; + if (duration > muteClock) + { + muteClock = duration; + } + } +} diff --git a/GameCode/DemoQuitSwitch.cs b/GameCode/DemoQuitSwitch.cs new file mode 100644 index 0000000..5f1f586 --- /dev/null +++ b/GameCode/DemoQuitSwitch.cs @@ -0,0 +1,11 @@ +using UnityEngine; + +public class DemoQuitSwitch : MonoBehaviour +{ + public UIFrame demoFrame; + + public void Trigger() + { + UIFrameManager.instance.QuitToDesktop(); + } +} diff --git a/GameCode/DestroyAfter.cs b/GameCode/DestroyAfter.cs new file mode 100644 index 0000000..b3a705b --- /dev/null +++ b/GameCode/DestroyAfter.cs @@ -0,0 +1,15 @@ +using UnityEngine; + +public class DestroyAfter : MonoBehaviour +{ + public float destroyAfter = 5f; + + private void Update() + { + destroyAfter -= Time.deltaTime; + if (destroyAfter <= 0f) + { + Object.Destroy(base.gameObject); + } + } +} diff --git a/GameCode/DestroyOrDisableOnEnable.cs b/GameCode/DestroyOrDisableOnEnable.cs new file mode 100644 index 0000000..5879f90 --- /dev/null +++ b/GameCode/DestroyOrDisableOnEnable.cs @@ -0,0 +1,27 @@ +using UnityEngine; + +public class DestroyOrDisableOnEnable : MonoBehaviour +{ + [SerializeField] + private Hp[] destroy; + + [SerializeField] + private GameObject[] disable; + + private void OnEnable() + { + Hp[] array = destroy; + foreach (Hp hp in array) + { + if (hp.gameObject.activeInHierarchy) + { + hp.TakeDamage(1E+09f); + } + } + GameObject[] array2 = disable; + for (int i = 0; i < array2.Length; i++) + { + array2[i].SetActive(value: false); + } + } +} diff --git a/GameCode/DisableOnStart.cs b/GameCode/DisableOnStart.cs new file mode 100644 index 0000000..2a38cf4 --- /dev/null +++ b/GameCode/DisableOnStart.cs @@ -0,0 +1,9 @@ +using UnityEngine; + +public class DisableOnStart : MonoBehaviour +{ + private void Start() + { + base.gameObject.SetActive(value: false); + } +} diff --git a/GameCode/EnableAllChildren.cs b/GameCode/EnableAllChildren.cs new file mode 100644 index 0000000..6f13300 --- /dev/null +++ b/GameCode/EnableAllChildren.cs @@ -0,0 +1,12 @@ +using UnityEngine; + +public class EnableAllChildren : MonoBehaviour +{ + private void Start() + { + for (int i = 0; i < base.transform.childCount; i++) + { + base.transform.GetChild(i).gameObject.SetActive(value: true); + } + } +} diff --git a/GameCode/EndOfMatchScoreUIHelper.cs b/GameCode/EndOfMatchScoreUIHelper.cs new file mode 100644 index 0000000..607cd37 --- /dev/null +++ b/GameCode/EndOfMatchScoreUIHelper.cs @@ -0,0 +1,636 @@ +using System.Collections; +using I2.Loc; +using MPUIKIT; +using Rewired; +using TMPro; +using UnityEngine; + +public class EndOfMatchScoreUIHelper : MonoBehaviour +{ + [Header("Pre Frame")] + public GameObject preFrameParent; + + public GameObject mainFrameParent; + + public GameObject preFrameVictory; + + public GameObject preFrameDefeat; + + public RectTransform preFrameMask; + + public CanvasGroup preFrameCG; + + public CanvasGroup mainFrameCG; + + public float preFrameMaskTargetHeight; + + public AnimationCurve preFrameMaskACCurve; + + public float preFrameAnimationTime = 0.75f; + + public float preFrameWaittime; + + public AudioSource audioSource; + + [Header("Main Frame")] + public TextMeshProUGUI baseScore; + + public TextMeshProUGUI goldScore; + + public TextMeshProUGUI mutatorScore; + + public TextMeshProUGUI overallScore; + + public TextMeshProUGUI bestScore; + + public TextMeshProUGUI levelDisplay; + + public TextMeshProUGUI xpDisplay; + + public TextMeshProUGUI levelUpLevelDisplay; + + public TextMeshProUGUI levelUpRewardDescription; + + public TextMeshProUGUI victoryDisplay; + + public TextMeshProUGUI defeatDisplay; + + public TextMeshProUGUI baseScoreName; + + public TextMeshProUGUI goldBonusName; + + public TextMeshProUGUI MutatorBonusName; + + public GameObject victoryParent; + + public GameObject defeatParent; + + public GameObject newHighscoreIndicator; + + public GameObject progressionBarParent; + + public GameObject demoMaxLevel; + + public GameObject regularMaxLevel; + + public GameObject rewardWaitIndicator; + + public GameObject victoryButtons; + + public GameObject defeatButtons; + + public GameObject dividerParent; + + public GameObject progressionBarORMaxLevelParent; + + public GameObject progressionBarOnly; + + public GameObject nextPerk; + + public MPImageBasic xpFill; + + public MPImageBasic nextUnlockIcon; + + public MPImageBasic nextunlockBG; + + public MPImageBasic levelUpRewardIcon; + + public MPImageBasic levelUpRewardBg; + + public MPImageBasic rewardWaitFill; + + public Color weaponBG; + + public Color perkBG; + + public Color mutatorBG; + + public Color perkpointBG; + + public Color buildingUpgradeBG; + + public ThronefallUIElement victorySelectedButton; + + public ThronefallUIElement defeatSelectedButton; + + public ThronefallUIElement rewardAcceptButton; + + public UIFrame rewardFrame; + + public AnimationCurve popShowCurve; + + public AnimationCurve bumpCurve; + + public AnimationCurve scoreFillWiggle; + + [Header("Settings")] + [SerializeField] + private float timeToFillUpABar = 3f; + + [SerializeField] + private float waitAtBeginning = 0.25f; + + [SerializeField] + private float waitAfterFillingUpABar = 0.25f; + + [SerializeField] + private float waitAfterReward = 2f; + + [SerializeField] + private float waitWhenMaxLevelAlreadyReached = 0.5f; + + private MetaLevel nextMetaLevel; + + private PerkManager perkManager; + + private Player input; + + private UIFrame frame; + + private bool inAnimation; + + private bool inScoreUnroll; + + private int baseScoreThisRound; + + private int goldScoreThisRound; + + private int mutatorScoreThisRound; + + private int overallScoreThisRound; + + private int animationNextScore; + + private float defaultWaitStep = 0.5f; + + private float minorWaitStep = 0.25f; + + private float animationStepA = 1.5f; + + private float animationStepB = 0.5f; + + private bool skipScoringAnimation; + + private Coroutine currentScoringAnimation; + + private void Update() + { + if (input.GetButtonDown("Interact") && inScoreUnroll) + { + if (currentScoringAnimation != null) + { + StopCoroutine(currentScoringAnimation); + } + currentScoringAnimation = null; + audioSource.Stop(); + skipScoringAnimation = true; + inScoreUnroll = false; + } + } + + public void OnActivate() + { + if (!inAnimation) + { + inAnimation = true; + inScoreUnroll = false; + skipScoringAnimation = false; + perkManager = PerkManager.instance; + input = ReInput.players.GetPlayer(0); + frame = GetComponent(); + mainFrameParent.SetActive(value: false); + preFrameParent.SetActive(value: true); + preFrameMask.sizeDelta = new Vector2(preFrameMask.sizeDelta.x, 0f); + preFrameCG.alpha = 0f; + if (LocalGamestate.Instance.CurrentState == LocalGamestate.State.AfterMatchVictory) + { + preFrameVictory.SetActive(value: true); + preFrameDefeat.SetActive(value: false); + audioSource.PlayOneShot(ThronefallAudioManager.Instance.audioContent.Victory); + } + else + { + preFrameVictory.SetActive(value: false); + preFrameDefeat.SetActive(value: true); + audioSource.PlayOneShot(ThronefallAudioManager.Instance.audioContent.Defeat); + } + StartCoroutine(ActivateAnimation()); + } + } + + public void OnContinue() + { + SceneTransitionManager.instance.TransitionFromEndScreenToLevelSelect(); + } + + public void OnTryAgain() + { + SceneTransitionManager.instance.RestartCurrentLevel(); + } + + private IEnumerator ActivateAnimation() + { + float preFrameTimer = 0f; + while (preFrameTimer < preFrameAnimationTime) + { + preFrameTimer += Time.unscaledDeltaTime; + float num = preFrameMaskACCurve.Evaluate(Mathf.InverseLerp(0f, preFrameAnimationTime, preFrameTimer)); + Vector2 sizeDelta = new Vector2(preFrameMask.sizeDelta.x, Mathf.Lerp(0f, preFrameMaskTargetHeight, num)); + preFrameMask.sizeDelta = sizeDelta; + preFrameCG.alpha = num; + yield return null; + } + preFrameMask.sizeDelta = new Vector2(preFrameMask.sizeDelta.x, preFrameMaskTargetHeight); + preFrameCG.alpha = 1f; + victoryDisplay.text = LocalizationManager.GetTranslation("Menu/Victory") + "."; + defeatDisplay.text = LocalizationManager.GetTranslation("Menu/Defeat") + "."; + if (LocalGamestate.Instance.CurrentState == LocalGamestate.State.AfterMatchDefeat) + { + victoryParent.SetActive(value: false); + defeatParent.SetActive(value: true); + } + else + { + victoryParent.SetActive(value: true); + defeatParent.SetActive(value: false); + } + baseScore.gameObject.SetActive(value: false); + baseScoreName.gameObject.SetActive(value: false); + goldScore.gameObject.SetActive(value: false); + goldBonusName.gameObject.SetActive(value: false); + mutatorScore.gameObject.SetActive(value: false); + MutatorBonusName.gameObject.SetActive(value: false); + dividerParent.SetActive(value: false); + progressionBarORMaxLevelParent.SetActive(value: false); + levelDisplay.gameObject.SetActive(value: false); + newHighscoreIndicator.SetActive(value: false); + victoryButtons.SetActive(value: false); + defeatButtons.SetActive(value: false); + demoMaxLevel.SetActive(value: false); + regularMaxLevel.SetActive(value: false); + progressionBarParent.SetActive(value: true); + yield return new WaitForSecondsRealtime(preFrameWaittime); + mainFrameCG.alpha = 0f; + mainFrameParent.SetActive(value: true); + float mainFrameFadeTimer = 0f; + float fadeTime = 0.25f; + while (mainFrameFadeTimer < fadeTime) + { + mainFrameFadeTimer += Time.unscaledDeltaTime; + mainFrameCG.alpha = mainFrameFadeTimer / fadeTime; + yield return null; + } + mainFrameCG.alpha = 1f; + preFrameParent.SetActive(value: false); + Time.timeScale = 0f; + currentScoringAnimation = StartCoroutine(UnrollScores()); + while (currentScoringAnimation != null) + { + yield return null; + } + if (skipScoringAnimation) + { + SkipUnrollScores(); + } + if (SceneTransitionManager.instance.TotalScoreFromLastMatchIsNewPersonalRecord) + { + newHighscoreIndicator.SetActive(value: true); + yield return StartCoroutine(PopShowTransform(newHighscoreIndicator.transform, ThronefallAudioManager.Instance.audioContent.NewHighscore, popShowCurve, 0.5f)); + yield return new WaitForSecondsRealtime(minorWaitStep); + } + else + { + newHighscoreIndicator.SetActive(value: false); + } + int xpToGive = SceneTransitionManager.instance.TotalScoreFromLastMatch; + GetNextMetaLevel(); + if (nextMetaLevel != null) + { + UpdateLevelingBar(); + } + levelDisplay.text = LocalizationManager.GetTranslation("Menu/Level") + " " + perkManager.level; + levelDisplay.gameObject.SetActive(value: true); + StartCoroutine(PopShowTransform(levelDisplay.transform, ThronefallAudioManager.Instance.audioContent.PointScreenBuildB, popShowCurve, animationStepB)); + yield return new WaitForSecondsRealtime(minorWaitStep); + progressionBarORMaxLevelParent.SetActive(value: true); + StartCoroutine(PopShowTransform(progressionBarORMaxLevelParent.transform, ThronefallAudioManager.Instance.audioContent.PointScreenBuildC, popShowCurve, animationStepB)); + yield return new WaitForSecondsRealtime(defaultWaitStep); + inAnimation = true; + if (nextMetaLevel != null) + { + nextUnlockIcon.sprite = nextMetaLevel.reward.icon; + nextunlockBG.color = GetColorForEquippable(nextMetaLevel.reward); + UpdateLevelingBar(); + yield return StartCoroutine(FillUpXPBar(xpToGive)); + } + else + { + yield return new WaitForSecondsRealtime(waitWhenMaxLevelAlreadyReached); + } + inAnimation = false; + LevelProgressManager.instance.GetLevelDataForScene(SceneTransitionManager.instance.ComingFromGameplayScene).SaveScoreAndStatsToBestIfBest(_endOfMatch: true); + SteamManager.Instance.UploadHighscore(SceneTransitionManager.instance.TotalScoreFromLastMatch, SceneTransitionManager.instance.ComingFromGameplayScene); + SaveLoadManager.instance.SaveGame(); + if (LocalGamestate.Instance.CurrentState == LocalGamestate.State.AfterMatchDefeat) + { + defeatButtons.SetActive(value: true); + frame.Select(defeatSelectedButton); + } + else + { + victoryButtons.SetActive(value: true); + frame.Select(victorySelectedButton); + } + inAnimation = false; + yield return null; + } + + private void GetNextMetaLevel() + { + nextMetaLevel = perkManager.NextMetaLevel; + if (nextMetaLevel == null) + { + EnableMaxLevelReachedUI(); + } + } + + private void EnableMaxLevelReachedUI() + { + progressionBarParent.SetActive(value: false); + regularMaxLevel.SetActive(value: true); + AchievementManager.UnlockAchievement(AchievementManager.Achievements.MAXLEVEL_REACHED); + } + + private void EnableDemoLockedUI() + { + progressionBarParent.SetActive(value: false); + demoMaxLevel.SetActive(value: true); + } + + private void EnableRewardDisplayUI() + { + levelUpLevelDisplay.text = LocalizationManager.GetTranslation("Menu/Level") + " " + (1 + perkManager.level); + levelUpRewardIcon.sprite = nextMetaLevel.reward.icon; + levelUpRewardBg.color = GetColorForEquippable(nextMetaLevel.reward); + levelUpRewardDescription.text = "" + LocalizationManager.GetTranslation(nextMetaLevel.reward.LOCIDENTIFIER_NAME) + "\n" + LocalizationManager.GetTranslation(nextMetaLevel.reward.LOCIDENTIFIER_DESCRIPTION); + UIFrameManager.ShowLevelUpReward(); + } + + private void UpdateLevelingBar() + { + xpDisplay.text = perkManager.xp + " / " + nextMetaLevel.requiredXp; + xpFill.fillAmount = (float)perkManager.xp / (float)nextMetaLevel.requiredXp; + } + + private IEnumerator UnrollScores() + { + inScoreUnroll = true; + baseScoreThisRound = SceneTransitionManager.instance.IngameScoreFromLastMatch; + goldScoreThisRound = SceneTransitionManager.instance.GoldBonusScoreFromLastMatch; + mutatorScoreThisRound = SceneTransitionManager.instance.MutatorBonusScoreFromLastMatch; + overallScoreThisRound = 0; + animationNextScore = 0; + baseScore.text = baseScoreThisRound.ToString(); + goldScore.text = goldScoreThisRound.ToString(); + mutatorScore.text = mutatorScoreThisRound.ToString(); + overallScore.text = overallScoreThisRound.ToString(); + bestScore.text = SceneTransitionManager.instance.LevelDataFromLastMatch.highscoreBest.ToString(); + dividerParent.SetActive(value: true); + StartCoroutine(PopShowTransform(dividerParent.transform, ThronefallAudioManager.Instance.audioContent.PointScreenBuildB, popShowCurve, animationStepB)); + baseScoreName.gameObject.SetActive(value: true); + StartCoroutine(PopShowTransform(baseScoreName.transform, null, popShowCurve, animationStepB)); + yield return new WaitForSecondsRealtime(minorWaitStep); + baseScore.gameObject.SetActive(value: true); + StartCoroutine(PopShowTransform(baseScore.transform, null, popShowCurve, animationStepB)); + yield return new WaitForSecondsRealtime(minorWaitStep); + yield return AddToOverallScore(baseScoreThisRound, animationStepA); + goldBonusName.gameObject.SetActive(value: true); + StartCoroutine(PopShowTransform(goldBonusName.transform, ThronefallAudioManager.Instance.audioContent.PointScreenBuildC, popShowCurve, animationStepB)); + yield return new WaitForSecondsRealtime(minorWaitStep); + goldScore.gameObject.SetActive(value: true); + StartCoroutine(PopShowTransform(goldScore.transform, ThronefallAudioManager.Instance.audioContent.PointScreenBuildA, popShowCurve, animationStepB)); + yield return new WaitForSecondsRealtime(minorWaitStep); + yield return AddToOverallScore(goldScoreThisRound, animationStepA); + MutatorBonusName.gameObject.SetActive(value: true); + StartCoroutine(PopShowTransform(MutatorBonusName.transform, ThronefallAudioManager.Instance.audioContent.PointScreenBuildC, popShowCurve, animationStepB)); + yield return new WaitForSecondsRealtime(minorWaitStep); + mutatorScore.gameObject.SetActive(value: true); + StartCoroutine(PopShowTransform(mutatorScore.transform, ThronefallAudioManager.Instance.audioContent.PointScreenBuildA, popShowCurve, animationStepB)); + yield return new WaitForSecondsRealtime(minorWaitStep); + yield return AddToOverallScore(mutatorScoreThisRound, animationStepA); + currentScoringAnimation = null; + } + + private void SkipUnrollScores() + { + baseScoreThisRound = SceneTransitionManager.instance.IngameScoreFromLastMatch; + goldScoreThisRound = SceneTransitionManager.instance.GoldBonusScoreFromLastMatch; + mutatorScoreThisRound = SceneTransitionManager.instance.MutatorBonusScoreFromLastMatch; + overallScoreThisRound = SceneTransitionManager.instance.TotalScoreFromLastMatch; + baseScore.text = baseScoreThisRound.ToString(); + goldScore.text = goldScoreThisRound.ToString(); + mutatorScore.text = mutatorScoreThisRound.ToString(); + overallScore.text = overallScoreThisRound.ToString(); + newHighscoreIndicator.SetActive(SceneTransitionManager.instance.TotalScoreFromLastMatchIsNewPersonalRecord); + bestScore.text = SceneTransitionManager.instance.LevelDataFromLastMatch.highscoreBest.ToString(); + dividerParent.SetActive(value: true); + baseScoreName.gameObject.SetActive(value: true); + baseScore.gameObject.SetActive(value: true); + goldBonusName.gameObject.SetActive(value: true); + goldScore.gameObject.SetActive(value: true); + MutatorBonusName.gameObject.SetActive(value: true); + mutatorScore.gameObject.SetActive(value: true); + dividerParent.transform.localScale = Vector3.one; + baseScoreName.transform.localScale = Vector3.one; + baseScore.transform.localScale = Vector3.one; + goldBonusName.transform.localScale = Vector3.one; + goldScore.transform.localScale = Vector3.one; + MutatorBonusName.transform.localScale = Vector3.one; + mutatorScore.transform.localScale = Vector3.one; + overallScore.transform.localScale = Vector3.one; + StartCoroutine(LockInScoreBump(0.5f)); + } + + private IEnumerator AddToOverallScore(int scoreToAdd, float animTime) + { + if (scoreToAdd == 0) + { + yield return new WaitForSecondsRealtime(0.15f); + yield break; + } + audioSource.clip = ThronefallAudioManager.Instance.audioContent.PointFill; + audioSource.loop = true; + audioSource.Play(); + animationNextScore += scoreToAdd; + float timer = 0f; + while (timer < animTime) + { + timer += Time.unscaledDeltaTime; + overallScore.text = Mathf.RoundToInt(Mathf.Lerp(overallScoreThisRound, animationNextScore, Mathf.InverseLerp(0f, animTime, timer))).ToString(); + yield return null; + } + overallScoreThisRound = animationNextScore; + overallScore.text = overallScoreThisRound.ToString(); + audioSource.Stop(); + audioSource.loop = false; + yield return StartCoroutine(LockInScoreBump(0.5f)); + } + + private IEnumerator LockInScoreBump(float animTime) + { + audioSource.PlayOneShot(ThronefallAudioManager.Instance.audioContent.PointLockInMajor, 0.85f); + float timer = 0f; + while (timer < animTime) + { + timer += Time.unscaledDeltaTime; + overallScore.transform.localScale = Vector3.one * bumpCurve.Evaluate(Mathf.InverseLerp(0f, animTime, timer)); + yield return null; + } + overallScore.transform.localScale = Vector3.one; + } + + private IEnumerator Bump(float animTime, Transform target, AudioClip clip) + { + if ((bool)clip) + { + audioSource.PlayOneShot(clip); + } + float timer = 0f; + while (timer < animTime) + { + timer += Time.unscaledDeltaTime; + target.transform.localScale = Vector3.one * bumpCurve.Evaluate(Mathf.InverseLerp(0f, animTime, timer)); + yield return null; + } + target.transform.localScale = Vector3.one; + } + + private IEnumerator PopShowTransform(Transform target, AudioClip clip, AnimationCurve curve, float animTime) + { + if ((bool)clip) + { + audioSource.PlayOneShot(clip); + } + float timer = 0f; + while (timer < animTime) + { + timer += Time.unscaledDeltaTime; + target.localScale = Vector3.one * curve.Evaluate(Mathf.InverseLerp(0f, animTime, timer)); + yield return null; + } + target.localScale = Vector3.one; + } + + private IEnumerator FillUpXPBar(int xp) + { + int xpToGive = xp; + float xpFillSpeed = (float)nextMetaLevel.requiredXp / timeToFillUpABar; + _ = perkManager.xp; + float xpFillFloat = perkManager.xp; + audioSource.clip = ThronefallAudioManager.Instance.audioContent.PointFill; + audioSource.loop = true; + audioSource.Play(); + float progressionBarWiggleTime = 0f; + while (xpToGive > 0 && nextMetaLevel != null) + { + if (!audioSource.isPlaying) + { + audioSource.Play(); + } + progressionBarWiggleTime += Time.unscaledDeltaTime * 10f; + progressionBarOnly.transform.localScale = Vector3.one * scoreFillWiggle.Evaluate(progressionBarWiggleTime); + int num = nextMetaLevel.requiredXp - perkManager.xp; + int num2; + if (input.GetButtonDown("Interact") || nextMetaLevel == null) + { + num2 = xpToGive; + } + else + { + xpFillFloat += xpFillSpeed * Time.unscaledDeltaTime; + num2 = Mathf.RoundToInt(xpFillFloat) - perkManager.xp; + } + if (num2 > num) + { + num2 = num; + } + perkManager.xp += num2; + xpToGive -= num2; + UpdateLevelingBar(); + if (nextMetaLevel != null && perkManager.xp >= nextMetaLevel.requiredXp) + { + audioSource.Stop(); + rewardAcceptButton.gameObject.SetActive(value: false); + rewardWaitIndicator.SetActive(value: true); + audioSource.PlayOneShot(ThronefallAudioManager.Instance.audioContent.LevelUp); + StartCoroutine(Bump(0.5f, nextPerk.transform, null)); + yield return new WaitForSecondsRealtime(0.5f); + EnableRewardDisplayUI(); + perkManager.xp = 0; + xpFillFloat = 0f; + perkManager.UnlockedEquippables.Add(nextMetaLevel.reward); + perkManager.level++; + GetNextMetaLevel(); + float timer = 0f; + while (timer < waitAfterReward && (timer == 0f || !input.GetButtonDown("Interact"))) + { + timer += Time.unscaledDeltaTime; + rewardWaitFill.fillAmount = timer / waitAfterReward; + yield return null; + } + rewardAcceptButton.gameObject.SetActive(value: true); + rewardWaitIndicator.SetActive(value: false); + rewardFrame.Select(rewardAcceptButton); + while (!frame.Interactable) + { + yield return null; + } + if (nextMetaLevel != null) + { + xpFillSpeed = (float)nextMetaLevel.requiredXp / timeToFillUpABar; + levelDisplay.text = LocalizationManager.GetTranslation("Menu/Level") + " " + perkManager.level; + nextUnlockIcon.sprite = nextMetaLevel.reward.icon; + nextunlockBG.color = GetColorForEquippable(nextMetaLevel.reward); + } + Time.timeScale = 0f; + } + yield return null; + } + progressionBarOnly.transform.localScale = Vector3.one; + audioSource.Stop(); + audioSource.loop = false; + StartCoroutine(Bump(animationStepB, progressionBarParent.transform, ThronefallAudioManager.Instance.audioContent.PointLockInMinor)); + yield return new WaitForSecondsRealtime(minorWaitStep); + } + + private Color GetColorForEquippable(Equippable e) + { + Color white = Color.white; + if (e is EquippableWeapon) + { + white = weaponBG; + } + if (e is EquippablePerk) + { + white = perkBG; + } + if (e is PerkPoint) + { + white = perkpointBG; + } + if (e is EquippableMutation) + { + white = mutatorBG; + } + if (e is EquippableBuildingUpgrade) + { + white = buildingUpgradeBG; + } + return white; + } + + private void OnDisable() + { + inAnimation = false; + } +} diff --git a/GameCode/EndOfMatchUI.cs b/GameCode/EndOfMatchUI.cs new file mode 100644 index 0000000..2dac632 --- /dev/null +++ b/GameCode/EndOfMatchUI.cs @@ -0,0 +1,39 @@ +using TMPro; +using UnityEngine; + +public class EndOfMatchUI : MonoBehaviour +{ + public GameObject victoryScreen; + + public GameObject defeatScreen; + + public TextMeshProUGUI scorePanel; + + private void Start() + { + victoryScreen.SetActive(value: false); + defeatScreen.SetActive(value: false); + scorePanel.gameObject.SetActive(value: false); + if ((bool)LocalGamestate.Instance) + { + LocalGamestate.Instance.OnGameStateChange.AddListener(GamestateHasChanged); + } + } + + private void GamestateHasChanged() + { + switch (LocalGamestate.Instance.CurrentState) + { + case LocalGamestate.State.AfterMatchDefeat: + defeatScreen.SetActive(value: true); + scorePanel.gameObject.SetActive(value: true); + scorePanel.text = "score: " + ScoreManager.Instance.CurrentScore; + break; + case LocalGamestate.State.AfterMatchVictory: + victoryScreen.SetActive(value: true); + scorePanel.gameObject.SetActive(value: true); + scorePanel.text = "score: " + ScoreManager.Instance.CurrentScore; + break; + } + } +} diff --git a/GameCode/EnemyScreenMarkerUIHelper.cs b/GameCode/EnemyScreenMarkerUIHelper.cs new file mode 100644 index 0000000..4d79edf --- /dev/null +++ b/GameCode/EnemyScreenMarkerUIHelper.cs @@ -0,0 +1,54 @@ +using MPUIKIT; +using TMPro; +using UnityEngine; + +public class EnemyScreenMarkerUIHelper : MonoBehaviour +{ + public GameObject defaultMarkerParent; + + public MPImageBasic enemyIcon; + + public TextMeshProUGUI enemyNumber; + + public GameObject largeMarkerParent; + + public MPImageBasic largeEnemyIcon; + + public TextMeshProUGUI largeEnemyNumber; + + public Vector2 largeDimensions = new Vector2(112f, 112f); + + private Vector2 regularDimensions; + + private RectTransform ownRT; + + private SettingsManager settings; + + private void Start() + { + settings = SettingsManager.Instance; + ownRT = GetComponent(); + regularDimensions = ownRT.sizeDelta; + } + + private void Update() + { + if (!(defaultMarkerParent == null) && !(largeMarkerParent == null)) + { + if (settings.UseLargeInGameUI) + { + defaultMarkerParent.SetActive(value: false); + largeMarkerParent.SetActive(value: true); + largeEnemyIcon.sprite = enemyIcon.sprite; + largeEnemyNumber.text = enemyNumber.text; + ownRT.sizeDelta = largeDimensions; + } + else + { + defaultMarkerParent.SetActive(value: true); + largeMarkerParent.SetActive(value: false); + ownRT.sizeDelta = regularDimensions; + } + } + } +} diff --git a/GameCode/EnemySpawnManager.cs b/GameCode/EnemySpawnManager.cs new file mode 100644 index 0000000..9a6fc6f --- /dev/null +++ b/GameCode/EnemySpawnManager.cs @@ -0,0 +1,19 @@ +using UnityEngine; + +public class EnemySpawnManager : MonoBehaviour +{ + public static EnemySpawnManager instance; + + public GameObject screenMarkerPrefabEnemySpawns; + + public GameObject screenMarkerPrefabOffscreenWarning; + + public Weapon weaponOnSpawn; + + public float weaponAttackHeight = 1f; + + private void Awake() + { + instance = this; + } +} diff --git a/GameCode/EnemySpawner.cs b/GameCode/EnemySpawner.cs new file mode 100644 index 0000000..92b85b8 --- /dev/null +++ b/GameCode/EnemySpawner.cs @@ -0,0 +1,287 @@ +using System.Collections.Generic; +using UnityEngine; + +public class EnemySpawner : MonoBehaviour, DayNightCycle.IDaytimeSensitive +{ + private PerkManager perkManager; + + private EnemySpawnManager enemySpawnManager; + + public static EnemySpawner instance; + + private TutorialManager tutorialManager; + + public int goldBalanceAtStart = 10; + + private bool spawningInProgress; + + public List waves = new List(); + + private List screenMarkersEnemySpawns = new List(); + + private List screenMarkersOffscreenWarnings = new List(); + + private int wavenumber = -1; + + private float lastSpawnPeriodDuration; + + private bool treasureHunterActive; + + private bool cheeseGodActive; + + private bool diseaseGodActive; + + private float timeToNextHpDecrease = 2.1f; + + public bool SpawningInProgress => spawningInProgress; + + public int WaveCount => waves.Count; + + public int Wavenumber => wavenumber; + + public bool MatchOver + { + get + { + if (wavenumber >= waves.Count - 1) + { + return !SpawningInProgress; + } + return false; + } + } + + public bool LevelBeatenAsSoonAsWaveFinished => wavenumber > waves.Count - 2; + + public bool FinalWaveComingUp => wavenumber == waves.Count - 2; + + public bool PreFinalWaveComingUp => wavenumber == waves.Count - 3; + + public float LastSpawnPeriodDuration => lastSpawnPeriodDuration; + + public bool InfinitelySpawning { get; set; } + + public void DebugSkipWave() + { + StopSpawnAfterWaveAndReset(); + wavenumber++; + } + + public void EnemySpawnersHornFocussed() + { + if ((bool)tutorialManager && !tutorialManager.MayShowEnemySpawn) + { + for (int i = 0; i < screenMarkersEnemySpawns.Count; i++) + { + screenMarkersEnemySpawns[i].showWhenOnScreen = false; + screenMarkersEnemySpawns[i].showWhenOffScreen = false; + } + for (int j = 0; j < screenMarkersOffscreenWarnings.Count; j++) + { + screenMarkersOffscreenWarnings[j].showWhenOnScreen = false; + screenMarkersOffscreenWarnings[j].showWhenOffScreen = false; + } + } + else + { + for (int k = 0; k < screenMarkersEnemySpawns.Count; k++) + { + screenMarkersEnemySpawns[k].showWhenOnScreen = true; + screenMarkersEnemySpawns[k].showWhenOffScreen = true; + } + for (int l = 0; l < screenMarkersOffscreenWarnings.Count; l++) + { + screenMarkersOffscreenWarnings[l].showWhenOnScreen = false; + screenMarkersOffscreenWarnings[l].showWhenOffScreen = false; + } + } + } + + public void EnemySpawnersHornUnFocussed() + { + if ((bool)tutorialManager && !tutorialManager.MayShowEnemySpawn) + { + for (int i = 0; i < screenMarkersEnemySpawns.Count; i++) + { + screenMarkersEnemySpawns[i].showWhenOnScreen = false; + screenMarkersEnemySpawns[i].showWhenOffScreen = false; + } + for (int j = 0; j < screenMarkersOffscreenWarnings.Count; j++) + { + screenMarkersOffscreenWarnings[j].showWhenOnScreen = false; + screenMarkersOffscreenWarnings[j].showWhenOffScreen = false; + } + } + else + { + for (int k = 0; k < screenMarkersEnemySpawns.Count; k++) + { + screenMarkersEnemySpawns[k].showWhenOnScreen = true; + screenMarkersEnemySpawns[k].showWhenOffScreen = true; + } + for (int l = 0; l < screenMarkersOffscreenWarnings.Count; l++) + { + screenMarkersOffscreenWarnings[l].showWhenOnScreen = false; + screenMarkersOffscreenWarnings[l].showWhenOffScreen = false; + } + } + } + + private void Awake() + { + instance = this; + } + + private void Start() + { + perkManager = PerkManager.instance; + enemySpawnManager = EnemySpawnManager.instance; + tutorialManager = TutorialManager.instance; + EnemySpawnersHornUnFocussed(); + if ((bool)DayNightCycle.Instance) + { + DayNightCycle.Instance.RegisterDaytimeSensitiveObject(this); + } + spawningInProgress = false; + wavenumber = -1; + if (DebugController.instance.StartGameInWave != -1) + { + wavenumber = DebugController.instance.StartGameInWave - 1; + } + PlayerMovement[] registeredPlayers = PlayerManager.Instance.RegisteredPlayers; + for (int i = 0; i < registeredPlayers.Length; i++) + { + registeredPlayers[i].GetComponent().AddCoin(goldBalanceAtStart); + } + LevelProgressManager.instance.GetLevelDataForActiveScene()?.dayToDayNetworth.Add(goldBalanceAtStart); + treasureHunterActive = PerkManager.instance.TreasureHunterActive; + cheeseGodActive = PerkManager.instance.CheeseGodActive; + if (cheeseGodActive) + { + for (int j = 0; j < Mathf.Min(3, waves.Count); j++) + { + foreach (Spawn spawn in waves[j].spawns) + { + spawn.count *= 2; + } + } + } + OnStartOfTheDay(); + } + + private void Update() + { + if (!spawningInProgress) + { + return; + } + lastSpawnPeriodDuration += Time.deltaTime; + waves[wavenumber].Update(); + if (!waves[wavenumber].HasFinished()) + { + return; + } + if (InfinitelySpawning) + { + if (TagManager.instance.CountAllTaggedObjectsWithTag(TagManager.ETag.EnemyOwned) > 0) + { + return; + } + { + foreach (Spawn spawn in waves[wavenumber].spawns) + { + spawn.Reset(_resetGold: false); + } + return; + } + } + StopSpawnAfterWaveAndReset(); + } + + public void OnStartOfTheDay() + { + if (wavenumber + 1 >= waves.Count) + { + return; + } + if (FinalWaveComingUp && treasureHunterActive) + { + PlayerMovement[] registeredPlayers = PlayerManager.Instance.RegisteredPlayers; + for (int i = 0; i < registeredPlayers.Length; i++) + { + registeredPlayers[i].GetComponent().AddCoin(PerkManager.instance.treasureHunterGoldAmount); + } + } + foreach (Spawn spawn in waves[wavenumber + 1].spawns) + { + Vector3 vector = (spawn.spawnLine.GetChild(0).position + spawn.spawnLine.GetChild(spawn.spawnLine.childCount - 1).position) / 2f; + Sprite sprite = spawn.enemyPrefab.GetComponent().sprite; + ScreenMarker screenMarker = null; + for (int j = 0; j < screenMarkersEnemySpawns.Count; j++) + { + if (!(screenMarkersEnemySpawns[j].Sprite != sprite) && !(screenMarkersEnemySpawns[j].transform.position != vector)) + { + screenMarker = screenMarkersEnemySpawns[j]; + screenMarker.SetNumber(screenMarker.Number + spawn.count); + } + } + if (!(screenMarker != null)) + { + ScreenMarker component = Object.Instantiate(enemySpawnManager.screenMarkerPrefabEnemySpawns, vector, Quaternion.identity).GetComponent(); + component.SetSprite(sprite); + component.SetNumber(spawn.count); + screenMarkersEnemySpawns.Add(component); + } + } + EnemySpawnersHornUnFocussed(); + } + + public void OnStartOfTheNight() + { + for (int num = screenMarkersEnemySpawns.Count - 1; num >= 0; num--) + { + Object.Destroy(screenMarkersEnemySpawns[num].gameObject); + } + screenMarkersEnemySpawns.Clear(); + for (int num2 = screenMarkersOffscreenWarnings.Count - 1; num2 >= 0; num2--) + { + Object.Destroy(screenMarkersOffscreenWarnings[num2].gameObject); + } + screenMarkersOffscreenWarnings.Clear(); + StartSpawning(); + } + + public void StartSpawning() + { + if (!spawningInProgress) + { + lastSpawnPeriodDuration = 0f; + wavenumber++; + wavenumber = Mathf.Clamp(wavenumber, 0, waves.Count - 1); + waves[wavenumber].Reset(); + spawningInProgress = true; + } + } + + public void StopSpawnAfterWaveAndReset() + { + if (spawningInProgress) + { + spawningInProgress = false; + } + } + + public void OnDusk() + { + OnStartOfTheNight(); + } + + public void OnDawn_AfterSunrise() + { + OnStartOfTheDay(); + } + + public void OnDawn_BeforeSunrise() + { + } +} diff --git a/GameCode/EnumSelector.cs b/GameCode/EnumSelector.cs new file mode 100644 index 0000000..8ad79be --- /dev/null +++ b/GameCode/EnumSelector.cs @@ -0,0 +1,163 @@ +using System.Collections.Generic; +using TMPro; +using UnityEngine; +using UnityEngine.Events; + +public class EnumSelector : MonoBehaviour +{ + public ThronefallUIElement target; + + public List options = new List(); + + private int index; + + public bool delayedApply; + + public GameObject applyButton; + + public ThronefallUIElement.NavigationDirection increase; + + public ThronefallUIElement.NavigationDirection decrease = ThronefallUIElement.NavigationDirection.Left; + + public TextMeshProUGUI display; + + public GameObject buttons; + + public UnityEvent onChange = new UnityEvent(); + + public UnityEvent onIncrease = new UnityEvent(); + + public UnityEvent onDecrease = new UnityEvent(); + + private bool unpropagatedChanges; + + private int bufferIndex; + + public int Index => index; + + private void Start() + { + target.onApply.AddListener(PropagateDelayedChange); + target.onSelectionStateChange.AddListener(OnLinkedTFUINavigate); + } + + private void UpdateDisplay() + { + if (unpropagatedChanges) + { + display.text = options[index] + " *"; + if ((bool)applyButton) + { + applyButton.SetActive(value: true); + } + } + else + { + display.text = options[index]; + if ((bool)applyButton) + { + applyButton.SetActive(value: false); + } + } + } + + public void Navigate(ThronefallUIElement.NavigationDirection direction) + { + if (direction == increase) + { + onIncrease.Invoke(); + index++; + } + else if (direction == decrease) + { + index--; + onDecrease.Invoke(); + } + if (index > options.Count - 1) + { + index = 0; + } + if (index < 0) + { + index = options.Count - 1; + } + if (delayedApply && index != bufferIndex) + { + unpropagatedChanges = true; + } + else + { + unpropagatedChanges = false; + } + UpdateDisplay(); + if (!delayedApply) + { + ApplyChanges(); + } + } + + public void Increase() + { + Navigate(increase); + } + + public void Decrease() + { + Navigate(decrease); + } + + public void OnTFUIStateChange() + { + if (target.CurrentState != 0) + { + buttons.SetActive(value: true); + } + else + { + buttons.SetActive(value: false); + } + } + + public void SetIndex(int i) + { + index = i; + if (index > options.Count - 1) + { + index = 0; + } + if (index < 0) + { + index = options.Count - 1; + } + bufferIndex = index; + UpdateDisplay(); + } + + public void OnLinkedTFUINavigate() + { + CancelChanges(); + } + + public void PropagateDelayedChange() + { + if (delayedApply) + { + ApplyChanges(); + } + } + + private void ApplyChanges() + { + bufferIndex = index; + onChange.Invoke(); + unpropagatedChanges = false; + UpdateDisplay(); + } + + private void CancelChanges() + { + index = bufferIndex; + unpropagatedChanges = false; + UpdateDisplay(); + } +} diff --git a/GameCode/EnumSelectorButtonAnimation.cs b/GameCode/EnumSelectorButtonAnimation.cs new file mode 100644 index 0000000..4cb6333 --- /dev/null +++ b/GameCode/EnumSelectorButtonAnimation.cs @@ -0,0 +1,14 @@ +using UnityEngine; + +public class EnumSelectorButtonAnimation : MonoBehaviour +{ + public Transform decreaseB; + + public Transform increaseB; + + private void OnEnable() + { + decreaseB.localScale = Vector3.zero; + increaseB.localScale = Vector3.zero; + } +} diff --git a/GameCode/Equippable.cs b/GameCode/Equippable.cs new file mode 100644 index 0000000..05b442d --- /dev/null +++ b/GameCode/Equippable.cs @@ -0,0 +1,15 @@ +using UnityEngine; + +public class Equippable : ScriptableObject +{ + public Sprite icon; + + public string displayName; + + [TextArea] + public string description; + + public string LOCIDENTIFIER_NAME => "Equippable/" + displayName; + + public string LOCIDENTIFIER_DESCRIPTION => LOCIDENTIFIER_NAME + " Description"; +} diff --git a/GameCode/EquippableBuildingUpgrade.cs b/GameCode/EquippableBuildingUpgrade.cs new file mode 100644 index 0000000..8120e18 --- /dev/null +++ b/GameCode/EquippableBuildingUpgrade.cs @@ -0,0 +1,6 @@ +using UnityEngine; + +[CreateAssetMenu(fileName = "Data", menuName = "SimpleSiege/Equippable Building Upgrade", order = 1)] +public class EquippableBuildingUpgrade : Equippable +{ +} diff --git a/GameCode/EquippableMutation.cs b/GameCode/EquippableMutation.cs new file mode 100644 index 0000000..5e3d0db --- /dev/null +++ b/GameCode/EquippableMutation.cs @@ -0,0 +1,7 @@ +using UnityEngine; + +[CreateAssetMenu(fileName = "Data", menuName = "SimpleSiege/Equippable Mutation", order = 1)] +public class EquippableMutation : Equippable +{ + public float scoreMultiplyerOnWin = 1.2f; +} diff --git a/GameCode/EquippablePerk.cs b/GameCode/EquippablePerk.cs new file mode 100644 index 0000000..b3b5468 --- /dev/null +++ b/GameCode/EquippablePerk.cs @@ -0,0 +1,6 @@ +using UnityEngine; + +[CreateAssetMenu(fileName = "Data", menuName = "SimpleSiege/Equippable Perk", order = 1)] +public class EquippablePerk : Equippable +{ +} diff --git a/GameCode/EquippableWeapon.cs b/GameCode/EquippableWeapon.cs new file mode 100644 index 0000000..134c067 --- /dev/null +++ b/GameCode/EquippableWeapon.cs @@ -0,0 +1,6 @@ +using UnityEngine; + +[CreateAssetMenu(fileName = "Data", menuName = "SimpleSiege/Equippable Weapon", order = 1)] +public class EquippableWeapon : Equippable +{ +} diff --git a/GameCode/FakeChildTo.cs b/GameCode/FakeChildTo.cs new file mode 100644 index 0000000..fe9d361 --- /dev/null +++ b/GameCode/FakeChildTo.cs @@ -0,0 +1,33 @@ +using UnityEngine; + +public class FakeChildTo : MonoBehaviour +{ + [SerializeField] + private Transform fakeParent; + + [SerializeField] + private bool unparentAtStart = true; + + private Vector3 offset; + + private void Start() + { + offset = base.transform.localPosition; + if (unparentAtStart) + { + base.transform.SetParent(null); + } + } + + private void Update() + { + if (!fakeParent) + { + Object.Destroy(base.gameObject); + } + else + { + base.transform.position = fakeParent.position + offset; + } + } +} diff --git a/GameCode/FakeTransorm.cs b/GameCode/FakeTransorm.cs new file mode 100644 index 0000000..3202c80 --- /dev/null +++ b/GameCode/FakeTransorm.cs @@ -0,0 +1,41 @@ +using System; +using UnityEngine; + +[Serializable] +public class FakeTransorm +{ + private Vector3 localPosition; + + private Vector3 localScale; + + private Quaternion localRotation; + + public FakeTransorm(Transform _transform) + { + SetToTransormValues(_transform); + } + + public void SetToTransormValues(Transform _transform) + { + localPosition = _transform.localPosition; + localScale = _transform.localScale; + localRotation = _transform.localRotation; + } + + public bool IsEqualTo(Transform _transform) + { + if (localPosition != _transform.localPosition) + { + return false; + } + if (localScale != _transform.localScale) + { + return false; + } + if (localRotation != _transform.localRotation) + { + return false; + } + return true; + } +} diff --git a/GameCode/FireArcherBurn.cs b/GameCode/FireArcherBurn.cs new file mode 100644 index 0000000..4f92b76 --- /dev/null +++ b/GameCode/FireArcherBurn.cs @@ -0,0 +1,83 @@ +using System.Collections.Generic; +using UnityEngine; + +public class FireArcherBurn : MonoBehaviour +{ + public ParticleSystem hotOilGround; + + public float hotOilGroundBurnTickDuration = 0.2f; + + public int hotOilGroundBurnTicks = 5; + + public float range = 3.5f; + + public List damageModifyers = new List(); + + public List mustHaveTags; + + public List mayNotHaveTags; + + public float timeTillSelfDestroy = 5f; + + private TagManager tagManager; + + private List foundTaggedObjects = new List(); + + private float timeTillTickEnds; + + private int ticksRemaining; + + private void Start() + { + tagManager = TagManager.instance; + if (DamageTick()) + { + timeTillTickEnds = hotOilGroundBurnTickDuration; + ticksRemaining = hotOilGroundBurnTicks - 1; + ParticleSystem.EmissionModule emission = hotOilGround.emission; + emission.enabled = true; + } + } + + private void Update() + { + if (timeTillTickEnds > 0f) + { + timeTillTickEnds -= Time.deltaTime; + if (timeTillTickEnds <= 0f) + { + ticksRemaining--; + if (ticksRemaining < 0) + { + ParticleSystem.EmissionModule emission = hotOilGround.emission; + emission.enabled = false; + } + else + { + DamageTick(); + timeTillTickEnds = hotOilGroundBurnTickDuration; + } + } + } + timeTillSelfDestroy -= Time.deltaTime; + if (timeTillSelfDestroy <= 0f) + { + Object.Destroy(base.gameObject); + } + } + + private bool DamageTick() + { + bool result = false; + tagManager.FindAllTaggedObjectsWithTags(foundTaggedObjects, mustHaveTags, mayNotHaveTags); + for (int i = 0; i < foundTaggedObjects.Count; i++) + { + if (!(tagManager.MeasureDistanceToTaggedObject(foundTaggedObjects[i], base.transform.position) > range)) + { + result = true; + foundTaggedObjects[i].Hp.TakeDamage(DamageModifyer.CalculateDamageOnTarget(foundTaggedObjects[i], damageModifyers) / (float)hotOilGroundBurnTicks); + } + } + return result; + } +} diff --git a/GameCode/FishingHarbour.cs b/GameCode/FishingHarbour.cs new file mode 100644 index 0000000..2214867 --- /dev/null +++ b/GameCode/FishingHarbour.cs @@ -0,0 +1,58 @@ +using System.Collections; +using UnityEngine; + +public class FishingHarbour : IncomeModifyer +{ + public int incomeIncreasePerTurn = 1; + + public int maximumIncome = 5; + + private int maximumBoats; + + public Transform activeChildOnIncomeIncrease; + + private int activationNr; + + [Header("Perk Upgrade")] + [SerializeField] + private Equippable perk; + + [SerializeField] + private int additionalBoatCapacity; + + private void Start() + { + buildingInteractor.IncomeModifiers.Add(this); + for (int i = 0; i < activeChildOnIncomeIncrease.childCount; i++) + { + activeChildOnIncomeIncrease.GetChild(i).gameObject.SetActive(value: false); + } + if (PerkManager.instance.CurrentlyEquipped.Contains(perk)) + { + maximumIncome += additionalBoatCapacity; + } + maximumBoats = maximumIncome; + } + + public override void OnDawn() + { + if (buildSlot.Level > 0 && !buildingInteractor.KnockedOutTonight) + { + StartCoroutine(IncreaseIncomeAndBuildShip()); + } + } + + private IEnumerator IncreaseIncomeAndBuildShip() + { + yield return null; + yield return null; + if (activationNr < maximumBoats) + { + activeChildOnIncomeIncrease.GetChild(activationNr).gameObject.SetActive(value: true); + } + activationNr++; + buildSlot.GoldIncome = Mathf.Min(buildSlot.GoldIncome + incomeIncreasePerTurn, maximumIncome); + buildSlot.Upgrades[1].upgradeBranches[0].goldIncomeChange = buildSlot.GoldIncome; + buildSlot.Interactor.MarkAsHarvested(); + } +} diff --git a/GameCode/FishingHarbourUpgrade.cs b/GameCode/FishingHarbourUpgrade.cs new file mode 100644 index 0000000..f8cc3ee --- /dev/null +++ b/GameCode/FishingHarbourUpgrade.cs @@ -0,0 +1,15 @@ +using UnityEngine; + +public class FishingHarbourUpgrade : MonoBehaviour +{ + [SerializeField] + private FishingHarbour fishingHarbour; + + private void OnEnable() + { + fishingHarbour.maximumIncome *= 2; + fishingHarbour.incomeIncreasePerTurn *= 2; + Object.Destroy(this); + Object.Destroy(base.gameObject); + } +} diff --git a/GameCode/ForceCameraPosOnEnable.cs b/GameCode/ForceCameraPosOnEnable.cs new file mode 100644 index 0000000..859dcff --- /dev/null +++ b/GameCode/ForceCameraPosOnEnable.cs @@ -0,0 +1,27 @@ +using UnityEngine; + +public class ForceCameraPosOnEnable : MonoBehaviour +{ + [SerializeField] + private CameraRig cameraRig; + + [SerializeField] + private Transform forcedPosition; + + [SerializeField] + private float duration; + + private void Update() + { + if (duration >= 0f) + { + cameraRig.overrideCameraTarget = forcedPosition; + duration -= Time.deltaTime; + } + else + { + cameraRig.overrideCameraTarget = null; + Object.Destroy(this); + } + } +} diff --git a/GameCode/FromToAnimation.cs b/GameCode/FromToAnimation.cs new file mode 100644 index 0000000..29807cc --- /dev/null +++ b/GameCode/FromToAnimation.cs @@ -0,0 +1,45 @@ +using System.Collections; +using UnityEngine; + +public class FromToAnimation : OneShotAnimationBase +{ + public AnimationCurve curve; + + public float duration = 0.75f; + + public Vector3 eulerTargetRotation; + + public Transform transformToAnimate; + + private Quaternion initialRotation; + + private Quaternion targetRotation; + + private void Start() + { + initialRotation = transformToAnimate.localRotation; + targetRotation = Quaternion.Euler(eulerTargetRotation.x, eulerTargetRotation.y, eulerTargetRotation.z); + } + + private IEnumerator Animate() + { + transformToAnimate.localRotation = initialRotation; + float timer = 0f; + while (timer < duration) + { + transformToAnimate.localRotation = Quaternion.Lerp(initialRotation, targetRotation, curve.Evaluate(timer / duration)); + timer += Time.deltaTime; + yield return null; + } + transformToAnimate.localRotation = Quaternion.Lerp(initialRotation, targetRotation, curve.Evaluate(1f)); + } + + public override void Trigger() + { + if (base.gameObject.activeInHierarchy) + { + StopAllCoroutines(); + StartCoroutine(Animate()); + } + } +} diff --git a/GameCode/GPUInstanced.cs b/GameCode/GPUInstanced.cs new file mode 100644 index 0000000..46c4d3e --- /dev/null +++ b/GameCode/GPUInstanced.cs @@ -0,0 +1,80 @@ +using UnityEngine; + +public class GPUInstanced : MonoBehaviour +{ + private MeshRenderer mr; + + private GPUInstancingManager gpui; + + private bool started; + + private bool eenabled; + + private Mesh mesh; + + private Material mat; + + private void Start() + { + if (mr == null) + { + mr = GetComponent(); + } + if (mr == null) + { + Object.Destroy(this); + return; + } + if (gpui == null) + { + gpui = GPUInstancingManager.Instance; + } + if (gpui == null) + { + Object.Destroy(this); + return; + } + mesh = mr.GetComponent().sharedMesh; + mat = mr.sharedMaterial; + if (eenabled) + { + mr.enabled = false; + gpui.AddVirtualMeshRenderer(mesh, mat, base.transform); + } + started = true; + } + + private void OnEnable() + { + eenabled = true; + if (started) + { + mr.enabled = false; + gpui.AddVirtualMeshRenderer(mesh, mat, base.transform); + } + } + + private void OnDisable() + { + eenabled = false; + if (started) + { + gpui.RemoveVirtualMeshRenderer(mesh, mat, base.transform); + } + } + + public void OnMeshOrMaterialUpdate(Mesh newMesh, Material newMat) + { + if (newMesh != mesh || newMat != mat) + { + gpui.UpdateVirtualMeshRenderer(mesh, mat, newMesh, newMat, base.transform); + mesh = newMesh; + mat = newMat; + } + } + + private void Update() + { + OnMeshOrMaterialUpdate(mesh, mr.sharedMaterial); + } +} diff --git a/GameCode/GPUInstancingManager.cs b/GameCode/GPUInstancingManager.cs new file mode 100644 index 0000000..99d9dab --- /dev/null +++ b/GameCode/GPUInstancingManager.cs @@ -0,0 +1,119 @@ +using System.Collections.Generic; +using UnityEngine; + +public class GPUInstancingManager : MonoBehaviour +{ + private struct MaterialMeshPair + { + public Material material; + + public Mesh mesh; + } + + private struct TransformMatrixPair + { + public List transforms; + + public List matrices; + } + + public static GPUInstancingManager Instance; + + [Tooltip("Do not change this during runtime!")] + [SerializeField] + private bool gpuInstancingEnabled = true; + + [SerializeField] + private bool debugLogs; + + private Dictionary matMeshPairToRenderersDictionary; + + private List transformMatricesBuffer = new List(); + + private void Awake() + { + if (gpuInstancingEnabled) + { + Instance = this; + } + else + { + Instance = null; + } + matMeshPairToRenderersDictionary = new Dictionary(); + } + + private void Update() + { + int num = 0; + int num2 = 0; + foreach (KeyValuePair item in matMeshPairToRenderersDictionary) + { + TransformMatrixPair value = item.Value; + for (int i = 0; i < value.transforms.Count; i++) + { + if (value.transforms[i] != null) + { + value.matrices[i] = value.transforms[i].localToWorldMatrix; + } + } + if (value.matrices.Count >= 1024) + { + Debug.LogWarning("Drawing too many meshes with mesh: " + item.Key.mesh.ToString()); + } + try + { + Graphics.DrawMeshInstanced(item.Key.mesh, 0, item.Key.material, value.matrices); + } + catch + { + Debug.LogError("GPU instancing with material failed: " + item.Key.material.ToString()); + } + num += value.transforms.Count; + num2++; + } + } + + public void AddVirtualMeshRenderer(Mesh mesh, Material material, Transform transform) + { + MaterialMeshPair key = default(MaterialMeshPair); + key.material = material; + key.mesh = mesh; + if (!matMeshPairToRenderersDictionary.TryGetValue(key, out var value)) + { + TransformMatrixPair transformMatrixPair = default(TransformMatrixPair); + transformMatrixPair.transforms = new List(); + transformMatrixPair.matrices = new List(); + value = transformMatrixPair; + matMeshPairToRenderersDictionary[key] = value; + } + value.transforms.Add(transform); + value.matrices.Add(transform.localToWorldMatrix); + } + + public void RemoveVirtualMeshRenderer(Mesh mesh, Material material, Transform transform) + { + MaterialMeshPair key = default(MaterialMeshPair); + key.material = material; + key.mesh = mesh; + if (matMeshPairToRenderersDictionary.TryGetValue(key, out var value)) + { + int num = value.transforms.IndexOf(transform); + if (num != -1) + { + value.transforms.RemoveAt(num); + value.matrices.RemoveAt(num); + } + if (value.transforms.Count == 0) + { + matMeshPairToRenderersDictionary.Remove(key); + } + } + } + + public void UpdateVirtualMeshRenderer(Mesh oldMesh, Material oldMaterial, Mesh newMesh, Material newMaterial, Transform transform) + { + RemoveVirtualMeshRenderer(oldMesh, oldMaterial, transform); + AddVirtualMeshRenderer(newMesh, newMaterial, transform); + } +} diff --git a/GameCode/GateOpener.cs b/GameCode/GateOpener.cs new file mode 100644 index 0000000..31d79a4 --- /dev/null +++ b/GameCode/GateOpener.cs @@ -0,0 +1,172 @@ +using System.Collections.Generic; +using UnityEngine; + +public class GateOpener : MonoBehaviour +{ + public enum Mode + { + Door, + Bars + } + + public float openDistance = 5f; + + public float clearDistance = 10f; + + public Mode mode; + + public Transform doorL; + + public Transform doorR; + + public float maxAngle; + + public Transform bars; + + public Vector3 openPositionOffset = new Vector3(0f, -3.6f, 0f); + + public float animationTime = 1f; + + private bool open; + + private List tagList = new List(new TagManager.ETag[2] + { + TagManager.ETag.Player, + TagManager.ETag.PlayerUnit + }); + + private float openAnimationClock; + + private IReadOnlyList playerUnits; + + private IReadOnlyList players; + + private Vector3 doorLInitRotation; + + private Vector3 doorRInitRotation; + + private Vector3 barsInitPosition; + + private bool isDoor => mode == Mode.Door; + + private bool isBars => mode == Mode.Bars; + + private void Start() + { + if ((bool)doorL) + { + doorLInitRotation = doorL.rotation.eulerAngles; + } + if ((bool)doorR) + { + doorRInitRotation = doorR.rotation.eulerAngles; + } + if ((bool)bars) + { + barsInitPosition = bars.transform.position; + } + if (!TagManager.instance) + { + Debug.LogError("No Tag Manager in scene."); + return; + } + playerUnits = TagManager.instance.PlayerUnits; + players = TagManager.instance.Players; + } + + private void Update() + { + if (!TagManager.instance) + { + return; + } + if (open) + { + bool flag = true; + foreach (TaggedObject playerUnit in TagManager.instance.PlayerUnits) + { + if (playerUnit.gameObject.activeInHierarchy && Vector3.Distance(base.transform.position, playerUnit.transform.position) <= clearDistance && playerUnit.Tags.Contains(TagManager.ETag.AUTO_Alive) && !(Vector3.Distance(playerUnit.transform.position, playerUnit.GetComponent().HomePosition) < 0.5f)) + { + flag = false; + break; + } + } + foreach (TaggedObject player in players) + { + if (player.gameObject.activeInHierarchy && Vector3.Distance(base.transform.position, player.transform.position) <= openDistance && player.Tags.Contains(TagManager.ETag.AUTO_Alive)) + { + flag = false; + } + } + if (flag) + { + Close(); + } + } + else + { + foreach (TaggedObject playerUnit2 in playerUnits) + { + if (playerUnit2.gameObject.activeInHierarchy && Vector3.Distance(base.transform.position, playerUnit2.transform.position) <= openDistance && playerUnit2.Tags.Contains(TagManager.ETag.AUTO_Alive) && !(Vector3.Distance(playerUnit2.transform.position, playerUnit2.GetComponent().HomePosition) < 0.5f)) + { + Open(); + return; + } + } + foreach (TaggedObject player2 in players) + { + if (player2.gameObject.activeInHierarchy && Vector3.Distance(base.transform.position, player2.transform.position) <= openDistance && player2.Tags.Contains(TagManager.ETag.AUTO_Alive)) + { + Open(); + } + } + } + if (open && openAnimationClock < animationTime) + { + openAnimationClock += Time.deltaTime; + if (openAnimationClock > animationTime) + { + openAnimationClock = animationTime; + } + } + else if (!open && openAnimationClock > 0f) + { + openAnimationClock -= Time.deltaTime; + if (openAnimationClock < 0f) + { + openAnimationClock = 0f; + } + } + switch (mode) + { + case Mode.Door: + { + float num = Mathf.SmoothStep(0f, maxAngle, openAnimationClock / animationTime); + doorL.rotation = Quaternion.Euler(doorLInitRotation + Vector3.forward * num); + doorR.rotation = Quaternion.Euler(doorRInitRotation + Vector3.forward * (0f - num)); + break; + } + case Mode.Bars: + bars.transform.position = Vector3.Slerp(barsInitPosition, barsInitPosition + openPositionOffset, openAnimationClock / animationTime); + break; + } + } + + private void Close() + { + open = false; + } + + private void Open() + { + open = true; + } + + private void OnDrawGizmosSelected() + { + Gizmos.color = Color.yellow; + Gizmos.DrawWireSphere(base.transform.position, openDistance); + Gizmos.color = Color.red; + Gizmos.DrawWireSphere(base.transform.position, clearDistance); + } +} diff --git a/GameCode/GlobalAudioListener.cs b/GameCode/GlobalAudioListener.cs new file mode 100644 index 0000000..28a5019 --- /dev/null +++ b/GameCode/GlobalAudioListener.cs @@ -0,0 +1,48 @@ +using UnityEngine; + +public class GlobalAudioListener : MonoBehaviour +{ + public static GlobalAudioListener instance; + + private PlayerInteraction bufferedPlayerInteraction; + + private Transform bufferedTargetTransform; + + private Vector3 offset = new Vector3(0f, 2f, 0f); + + private void Awake() + { + if (instance != null) + { + Object.Destroy(base.gameObject); + return; + } + instance = this; + Object.DontDestroyOnLoad(base.gameObject); + } + + private void Update() + { + PlayerInteraction playerInteraction = PlayerInteraction.instance; + if (bufferedPlayerInteraction != playerInteraction) + { + if (playerInteraction == null) + { + bufferedTargetTransform = null; + } + else + { + bufferedTargetTransform = playerInteraction.transform; + } + } + if (bufferedTargetTransform != null) + { + base.transform.position = bufferedTargetTransform.position + offset; + } + else + { + base.transform.position = Vector3.zero; + } + bufferedPlayerInteraction = playerInteraction; + } +} diff --git a/GameCode/GraphDrawer.cs b/GameCode/GraphDrawer.cs new file mode 100644 index 0000000..4776cdd --- /dev/null +++ b/GameCode/GraphDrawer.cs @@ -0,0 +1,125 @@ +using System.Collections.Generic; +using TMPro; +using UnityEngine; +using UnityEngine.UI; + +public class GraphDrawer : MonoBehaviour +{ + public enum Type + { + Networth, + Score + } + + public Type type; + + private List current; + + private List oldBest; + + [SerializeField] + private Color colorCurrent; + + [SerializeField] + private Color colorOldBest; + + [SerializeField] + private GameObject graphMarkersPrefab; + + [SerializeField] + private GameObject graphSclaeMarkerPrefab; + + [SerializeField] + private RectTransform graphSurface; + + private int xMaxScale; + + private int yMaxScale; + + private float width; + + private float height; + + private float wspacing; + + public void Generate(string _comingFromScene) + { + LevelData levelDataForScene = LevelProgressManager.instance.GetLevelDataForScene(_comingFromScene); + if (type == Type.Networth) + { + current = levelDataForScene.dayToDayNetworth; + oldBest = levelDataForScene.dayToDayNetworthBest; + } + else if (type == Type.Score) + { + current = levelDataForScene.dayToDayScore; + oldBest = levelDataForScene.dayToDayScoreBest; + } + xMaxScale = Mathf.Max(oldBest.Count, current.Count); + width = graphSurface.rect.width; + height = graphSurface.rect.height; + if (xMaxScale > 1) + { + wspacing = width / (float)(xMaxScale - 1); + } + else + { + wspacing = 0f; + } + yMaxScale = 1; + for (int i = 0; i < oldBest.Count; i++) + { + yMaxScale = Mathf.Max(yMaxScale, oldBest[i]); + } + for (int j = 0; j < current.Count; j++) + { + yMaxScale = Mathf.Max(yMaxScale, current[j]); + } + GameObject gameObject = Object.Instantiate(graphSclaeMarkerPrefab, graphSurface); + gameObject.transform.localPosition = new Vector3((0f - width) / 2f, (0f - height) / 2f); + gameObject.GetComponentInChildren().text = "0"; + gameObject = Object.Instantiate(graphSclaeMarkerPrefab, graphSurface); + gameObject.transform.localPosition = new Vector3((0f - width) / 2f, height / 2f); + if (yMaxScale < 1000) + { + gameObject.GetComponentInChildren().text = yMaxScale.ToString(); + } + else + { + int num = Mathf.FloorToInt((float)yMaxScale / 1000f); + int num2 = Mathf.FloorToInt((float)yMaxScale / 100f) - num * 10; + gameObject.GetComponentInChildren().text = num + "." + num2 + "K"; + } + PlotList(oldBest, colorOldBest); + PlotList(current, colorCurrent); + } + + private void PlotList(List _list, Color _color) + { + if (_list.Count <= 0) + { + return; + } + Vector3 vector = Vector3.zero; + for (int i = 0; i < _list.Count; i++) + { + float x = (float)i * wspacing - width / 2f; + float y = (float)_list[i] / (float)yMaxScale * height - height / 2f; + Vector3 vector2 = new Vector3(x, y, 0f); + if (i > 0 || _list.Count <= 1) + { + GameObject obj = Object.Instantiate(graphMarkersPrefab, graphSurface); + RectTransform component = obj.GetComponent(); + component.localPosition = vector2; + obj.GetComponent().color = _color; + if (i > 0) + { + component.localPosition = (vector + vector2) / 2f; + component.localScale = new Vector3((vector - vector2).magnitude / component.rect.width, component.localScale.y, component.localScale.z); + component.localRotation = Quaternion.Euler(0f, 0f, Vector2.SignedAngle(Vector2.right, vector - vector2)); + } + } + vector = vector2; + } + } +} diff --git a/GameCode/HealBoostMA.cs b/GameCode/HealBoostMA.cs new file mode 100644 index 0000000..48cdbbb --- /dev/null +++ b/GameCode/HealBoostMA.cs @@ -0,0 +1,55 @@ +using UnityEngine; + +public class HealBoostMA : ManualAttack +{ + public float attackSpeedBoost = 20f; + + public ManualAttack manualAttackToBoost; + + public ParticleSystem boostParticles; + + public float attackSpeedDuration = 2f; + + public float timeToFillUpHealth = 3f; + + public float attackSpeedDurationWhenLowHealth = 4f; + + private float disableBoostIn; + + private float attackSpeedOriginal; + + public override void Start() + { + base.Start(); + } + + public override void Attack() + { + attackSpeedOriginal = manualAttackToBoost.cooldownTime; + manualAttackToBoost.cooldownTime /= attackSpeedBoost; + ParticleSystem.EmissionModule emission = boostParticles.emission; + emission.enabled = true; + disableBoostIn = attackSpeedDuration; + if (hpPlayer.HpPercentage <= 0.33f) + { + disableBoostIn = attackSpeedDurationWhenLowHealth; + } + } + + public override void Update() + { + base.Update(); + disableBoostIn -= Time.deltaTime; + if (disableBoostIn > 0f) + { + hpPlayer.Heal(hpPlayer.maxHp * Time.deltaTime / timeToFillUpHealth); + cooldown = cooldownTime; + } + if (disableBoostIn + Time.deltaTime > 0f && disableBoostIn <= Time.deltaTime) + { + manualAttackToBoost.cooldownTime = attackSpeedOriginal; + ParticleSystem.EmissionModule emission = boostParticles.emission; + emission.enabled = false; + } + } +} diff --git a/GameCode/Healthbar.cs b/GameCode/Healthbar.cs new file mode 100644 index 0000000..e8e63e6 --- /dev/null +++ b/GameCode/Healthbar.cs @@ -0,0 +1,172 @@ +using MPUIKIT; +using UnityEngine; + +public class Healthbar : MonoBehaviour +{ + [SerializeField] + protected GameObject canvasParent; + + [SerializeField] + protected MPImageBasic fill; + + [SerializeField] + protected MPImageBasic delayedFill; + + [SerializeField] + protected Hp target; + + [SerializeField] + protected Color deathFillColor; + + [SerializeField] + private bool flashWhenBelowThreshold; + + [SerializeField] + [Range(0f, 1f)] + private float flashThreshhold; + + [SerializeField] + private float flashInterval = 0.25f; + + [SerializeField] + private Color flashColor; + + [SerializeField] + private MPImageBasic flashTarget; + + [SerializeField] + private float damageFlashSize = 1.2f; + + protected Color defaultDelayedFillColor; + + protected float hpLast; + + private float hpNow; + + private float damageFlash; + + private bool shouldUnparentAndDestroyOnDeath; + + private Color flashDefaultColor; + + private float flashClock; + + private readonly float finalDrainSpeed = 0.5f; + + private readonly float maxDrainSpeed = 1f; + + private readonly float minDrainSpeed = 0.1f; + + private void Start() + { + target.OnHpChange.AddListener(UpdateDisplay); + defaultDelayedFillColor = delayedFill.color; + UpdateDisplay(); + delayedFill.fillAmount = fill.fillAmount; + hpLast = 1f; + shouldUnparentAndDestroyOnDeath = !target.getsKnockedOutInsteadOfDying; + if (shouldUnparentAndDestroyOnDeath) + { + target.OnKillOrKnockout.AddListener(UnparentItself); + } + if (flashWhenBelowThreshold) + { + flashDefaultColor = flashTarget.color; + } + } + + private void Update() + { + hpNow = fill.fillAmount; + bool flag = Mathf.Approximately(hpNow, 0f); + if (!Mathf.Approximately(hpNow, delayedFill.fillAmount)) + { + if (!flag) + { + delayedFill.fillAmount = Mathf.MoveTowards(delayedFill.fillAmount, fill.fillAmount, Mathf.Lerp(minDrainSpeed, maxDrainSpeed, delayedFill.fillAmount - fill.fillAmount) * Time.deltaTime); + } + else + { + delayedFill.fillAmount = Mathf.MoveTowards(delayedFill.fillAmount, fill.fillAmount, Mathf.Lerp(finalDrainSpeed, maxDrainSpeed, delayedFill.fillAmount - fill.fillAmount) * Time.deltaTime); + } + } + if (hpNow < hpLast) + { + damageFlash = 2f; + } + if (flag && delayedFill.fillAmount < 0.01f) + { + if (shouldUnparentAndDestroyOnDeath) + { + Object.Destroy(base.gameObject); + } + else + { + canvasParent.SetActive(value: false); + base.enabled = false; + } + } + if (flashWhenBelowThreshold) + { + if (hpNow <= flashThreshhold && hpNow > 0f) + { + flashClock -= Time.deltaTime; + if (flashClock <= 0f) + { + flashClock = flashInterval; + if (flashTarget.color == flashColor) + { + flashTarget.color = flashDefaultColor; + } + else + { + flashTarget.color = flashColor; + } + } + } + else if (flashTarget.color != flashDefaultColor) + { + flashTarget.color = flashDefaultColor; + flashClock = 0f; + } + else + { + flashClock = 0f; + } + } + float num = Mathf.Lerp(1f, damageFlashSize, damageFlash); + base.transform.localScale = new Vector3(num, num, num); + damageFlash *= Mathf.Pow(0.1f, Time.deltaTime * 3f); + hpLast = hpNow; + } + + public virtual void UpdateDisplay() + { + if (target.HpPercentage == 1f) + { + canvasParent.SetActive(value: false); + base.enabled = false; + hpLast = 1f; + delayedFill.fillAmount = hpLast; + } + else + { + canvasParent.SetActive(value: true); + base.enabled = true; + } + fill.fillAmount = target.HpPercentage; + if (Mathf.Approximately(fill.fillAmount, 0f)) + { + delayedFill.color = deathFillColor; + } + else + { + delayedFill.color = defaultDelayedFillColor; + } + } + + private void UnparentItself() + { + base.transform.SetParent(null); + } +} diff --git a/GameCode/HealthbarMulti.cs b/GameCode/HealthbarMulti.cs new file mode 100644 index 0000000..8cfd05a --- /dev/null +++ b/GameCode/HealthbarMulti.cs @@ -0,0 +1,46 @@ +using UnityEngine; + +public class HealthbarMulti : Healthbar +{ + [SerializeField] + private int segments = 10; + + [SerializeField] + private Transform lifes; + + public override void UpdateDisplay() + { + float fillAmount = target.HpPercentage * (float)segments % 1f; + _ = target.HpPercentage * (float)segments % 1f; + int num = Mathf.FloorToInt(target.HpPercentage / (1f / (float)segments)); + for (int i = 0; i < lifes.childCount; i++) + { + lifes.GetChild(i).gameObject.SetActive(num > i); + } + if (target.invulnerable) + { + fillAmount = 1f; + } + if (target.HpPercentage == 1f) + { + canvasParent.SetActive(value: false); + base.enabled = false; + hpLast = 1f; + delayedFill.fillAmount = hpLast; + } + else + { + canvasParent.SetActive(value: true); + base.enabled = true; + } + fill.fillAmount = fillAmount; + if (Mathf.Approximately(fill.fillAmount, 0f)) + { + delayedFill.color = deathFillColor; + } + else + { + delayedFill.color = defaultDelayedFillColor; + } + } +} diff --git a/GameCode/HighscorePreviewUI.cs b/GameCode/HighscorePreviewUI.cs new file mode 100644 index 0000000..d8983f9 --- /dev/null +++ b/GameCode/HighscorePreviewUI.cs @@ -0,0 +1,66 @@ +using System.Collections.Generic; +using I2.Loc; +using Steamworks; +using TMPro; +using UnityEngine; + +public class HighscorePreviewUI : MonoBehaviour +{ + public TMP_Text highscore; + + public TMP_Text friendsRank; + + private bool subscribedToSteamManager; + + private readonly string lightTextCue = ""; + + private void OnEnable() + { + int highscoreBest = LevelProgressManager.instance.GetLevelDataForScene(LevelInteractor.lastActivatedLevelInteractor.sceneName).highscoreBest; + string text = ((highscoreBest != 0) ? highscoreBest.ToString() : "-"); + highscore.text = LocalizationManager.GetTranslation("Menu/Highscore") + ": " + lightTextCue + text; + friendsRank.text = LocalizationManager.GetTranslation("Menu/Friends Rank") + ": " + lightTextCue + "-"; + SubscribeToSteamManger(); + SteamManager.Instance.DownloadFriendsHighscores(LevelInteractor.lastActivatedLevelInteractor.sceneName); + } + + private void SubscribeToSteamManger() + { + if (!subscribedToSteamManager) + { + SteamManager.Instance.OnLeaderboardDownloadCallbackComplete.AddListener(RefreshUI); + subscribedToSteamManager = true; + } + } + + public void RefreshUI() + { + friendsRank.text = LocalizationManager.GetTranslation("Menu/Friends Rank") + ": " + lightTextCue; + List lastDownloadedLeaderboardEntires = SteamManager.Instance.lastDownloadedLeaderboardEntires; + if (lastDownloadedLeaderboardEntires.Count > 0) + { + int num = 0; + int num2 = 1; + foreach (SteamManager.LeaderboardEntry item in lastDownloadedLeaderboardEntires) + { + if (item.username == SteamFriends.GetPersonaName()) + { + num = num2; + break; + } + num2++; + } + if (num == 0) + { + friendsRank.text += "-"; + return; + } + TMP_Text tMP_Text = friendsRank; + tMP_Text.text = tMP_Text.text + "#" + num; + } + else + { + friendsRank.text += "-"; + } + } +} diff --git a/GameCode/HighscoreTable.cs b/GameCode/HighscoreTable.cs new file mode 100644 index 0000000..fbfdc4c --- /dev/null +++ b/GameCode/HighscoreTable.cs @@ -0,0 +1,99 @@ +using System.Collections.Generic; +using Steamworks; +using UnityEngine; + +public class HighscoreTable : MonoBehaviour +{ + private ScoreTag[] scoreTags = new ScoreTag[0]; + + private string currentHighscoreTableToCall = ""; + + public Transform scoreTagParent; + + public GameObject loading; + + public GameObject notConnectedToSteam; + + public GameObject noScore; + + public GameObject noFriends; + + private bool subscribedToSteamManager; + + public void SetAndDownloadHighscoreTable(string _highscoreTableName) + { + noScore.SetActive(value: false); + noFriends.SetActive(value: false); + currentHighscoreTableToCall = _highscoreTableName; + scoreTags = new ScoreTag[scoreTagParent.childCount]; + for (int i = 0; i < scoreTagParent.childCount; i++) + { + scoreTags[i] = scoreTagParent.GetChild(i).GetComponent(); + scoreTagParent.GetChild(i).gameObject.SetActive(value: false); + } + if (SteamManager.Initialized) + { + SubscribeToSteamManger(); + SteamManager.Instance.DownloadFriendsHighscores(currentHighscoreTableToCall); + loading.SetActive(value: true); + notConnectedToSteam.SetActive(value: false); + } + else + { + loading.SetActive(value: false); + notConnectedToSteam.SetActive(value: true); + } + } + + private void OnEnable() + { + SetAndDownloadHighscoreTable(LevelInteractor.lastActivatedLevelInteractor.sceneName); + } + + private void SubscribeToSteamManger() + { + if (!subscribedToSteamManager) + { + SteamManager.Instance.OnLeaderboardDownloadCallbackComplete.AddListener(RefreshUI); + subscribedToSteamManager = true; + } + } + + private void RefreshUI() + { + for (int i = 0; i < scoreTags.Length; i++) + { + scoreTags[i].gameObject.SetActive(value: false); + } + List lastDownloadedLeaderboardEntires = SteamManager.Instance.lastDownloadedLeaderboardEntires; + if (lastDownloadedLeaderboardEntires.Count > 0) + { + loading.SetActive(value: false); + notConnectedToSteam.SetActive(value: false); + bool flag = false; + foreach (SteamManager.LeaderboardEntry item in lastDownloadedLeaderboardEntires) + { + if (item.username == SteamFriends.GetPersonaName()) + { + flag = true; + break; + } + } + noScore.SetActive(!flag); + noFriends.SetActive(lastDownloadedLeaderboardEntires.Count == 1 && flag); + } + else + { + loading.SetActive(value: false); + notConnectedToSteam.SetActive(value: false); + noScore.SetActive(value: true); + noFriends.SetActive(value: true); + } + for (int j = 0; j < lastDownloadedLeaderboardEntires.Count && j <= scoreTags.Length - 1; j++) + { + bool isPlayer = lastDownloadedLeaderboardEntires[j].username == SteamFriends.GetPersonaName(); + scoreTags[j].gameObject.SetActive(value: true); + scoreTags[j].SetNameAndScore(lastDownloadedLeaderboardEntires[j].username, lastDownloadedLeaderboardEntires[j].score, j + 1, isPlayer); + } + } +} diff --git a/GameCode/HotOilTower.cs b/GameCode/HotOilTower.cs new file mode 100644 index 0000000..375a4e5 --- /dev/null +++ b/GameCode/HotOilTower.cs @@ -0,0 +1,97 @@ +using System.Collections.Generic; +using UnityEngine; + +public class HotOilTower : MonoBehaviour +{ + public ParticleSystem hotOilGround; + + public float hotOilGroundBurnTickDuration = 0.2f; + + public int hotOilGroundBurnTicks = 5; + + public float attackCooldown = 5f; + + public float checkRate = 1f; + + public float range = 3.5f; + + public List damageModifyers = new List(); + + public List mustHaveTags; + + public List mayNotHaveTags; + + private float cooldown; + + private TagManager tagManager; + + private List foundTaggedObjects = new List(); + + private float timeTillTickEnds; + + private int ticksRemaining; + + private void Start() + { + cooldown = Random.value; + tagManager = TagManager.instance; + } + + public void ReduceCooldownBy(float _reduceBy) + { + cooldown -= _reduceBy; + } + + private void Update() + { + cooldown -= Time.deltaTime; + if (timeTillTickEnds > 0f) + { + timeTillTickEnds -= Time.deltaTime; + if (timeTillTickEnds <= 0f) + { + ticksRemaining--; + if (ticksRemaining < 0) + { + ParticleSystem.EmissionModule emission = hotOilGround.emission; + emission.enabled = false; + } + else + { + DamageTick(); + timeTillTickEnds = hotOilGroundBurnTickDuration; + } + } + } + if (cooldown <= 0f) + { + if (DamageTick()) + { + cooldown = attackCooldown; + timeTillTickEnds = hotOilGroundBurnTickDuration; + ticksRemaining = hotOilGroundBurnTicks - 1; + ParticleSystem.EmissionModule emission2 = hotOilGround.emission; + emission2.enabled = true; + } + else + { + cooldown = checkRate; + } + } + } + + private bool DamageTick() + { + bool result = false; + tagManager.FindAllTaggedObjectsWithTags(foundTaggedObjects, mustHaveTags, mayNotHaveTags); + for (int i = 0; i < foundTaggedObjects.Count; i++) + { + if (!(tagManager.MeasureDistanceToTaggedObject(foundTaggedObjects[i], base.transform.position) > range)) + { + result = true; + foundTaggedObjects[i].Hp.TakeDamage(DamageModifyer.CalculateDamageOnTarget(foundTaggedObjects[i], damageModifyers) / (float)hotOilGroundBurnTicks); + } + } + return result; + } +} diff --git a/GameCode/Hp.cs b/GameCode/Hp.cs new file mode 100644 index 0000000..d28b16f --- /dev/null +++ b/GameCode/Hp.cs @@ -0,0 +1,375 @@ +using System.Collections.Generic; +using Pathfinding; +using Pathfinding.RVO; +using UnityEngine; +using UnityEngine.Events; + +[RequireComponent(typeof(TaggedObject))] +public class Hp : MonoBehaviour +{ + public float maxHp; + + public bool getsKnockedOutInsteadOfDying; + + private float hp; + + private TaggedObject taggedObject; + + [Tooltip("The hight where enemies aim at and where hit indicators are spawned")] + public float hitFeedbackHeight; + + [Tooltip("This child object is enabled when this unit is alive.")] + public GameObject aliveVisuals; + + [Tooltip("This child object is enabled when this unit is knocked out.")] + public GameObject knockedOutVisuals; + + public GameObject fxToSpawnOnDeath; + + public Vector3 deathFxSpawnOffset; + + public Transform deathFxSpawnWithPosAndRotOf; + + [HideInInspector] + public UnityEvent OnHpChange = new UnityEvent(); + + [HideInInspector] + public UnityEvent OnRevive = new UnityEvent(); + + [HideInInspector] + public UnityEvent OnHeal = new UnityEvent(); + + [HideInInspector] + public UnityEvent OnReceiveDamage = new UnityEvent(); + + [HideInInspector] + public UnityEvent OnKillOrKnockout = new UnityEvent(); + + private AutoAttack[] autoAttacks; + + private ManualAttack[] manualAttacks; + + private PathfindMovement pathfindMovement; + + private RVOController rvoController; + + private PlayerMovement playerMovement; + + private NavmeshCut[] navmeshCut; + + private PlayerInteraction playerInteraction; + + public GameObject coin; + + public float coinSpawnOffset; + + public int coinCount; + + [SerializeField] + private Weapon spwanAttackOnDeath; + + private float damageMultiplyer = 1f; + + private float healingMultiplyer = 1f; + + public bool invulnerable; + + public float HpValue => hp; + + public float HpPercentage => hp / maxHp; + + public bool KnockedOut => hp <= 0f; + + public TaggedObject TaggedObj => taggedObject; + + public PathfindMovement PathfindMovement => pathfindMovement; + + public Weapon SpwanAttackOnDeath + { + get + { + return spwanAttackOnDeath; + } + set + { + spwanAttackOnDeath = value; + } + } + + public float DamageMultiplyer + { + get + { + return damageMultiplyer; + } + set + { + damageMultiplyer = value; + } + } + + public void ScaleHp(float _multiply) + { + hp *= _multiply; + maxHp *= _multiply; + } + + private void Start() + { + playerInteraction = GetComponent(); + taggedObject = GetComponent(); + autoAttacks = GetComponents(); + manualAttacks = GetComponents(); + pathfindMovement = GetComponent(); + rvoController = GetComponent(); + playerMovement = GetComponent(); + navmeshCut = GetComponentsInChildren(); + taggedObject.AddTag(TagManager.ETag.AUTO_Alive); + Revive(callReviveEvent: false); + ActivateAndDeactivateChildrenAndCompements(_alive: true); + if (PerkManager.instance.HealingSpiritsActive && (bool)taggedObject && taggedObject.Tags.Contains(TagManager.ETag.PlayerOwned)) + { + healingMultiplyer *= PerkManager.instance.healingSpirits_healMulti; + } + } + + private void ActivateAndDeactivateChildrenAndCompements(bool _alive) + { + if ((bool)aliveVisuals) + { + aliveVisuals.SetActive(_alive); + } + if ((bool)knockedOutVisuals) + { + knockedOutVisuals.SetActive(!_alive); + } + if (autoAttacks.Length != 0) + { + AutoAttack[] array = autoAttacks; + for (int i = 0; i < array.Length; i++) + { + array[i].enabled = _alive; + } + } + if (manualAttacks.Length != 0) + { + ManualAttack[] array2 = manualAttacks; + for (int i = 0; i < array2.Length; i++) + { + array2[i].enabled = _alive; + } + } + if ((bool)pathfindMovement) + { + pathfindMovement.enabled = _alive; + if (!_alive) + { + pathfindMovement.ClearCurrentPath(); + } + } + if ((bool)rvoController) + { + rvoController.enabled = _alive; + } + if ((bool)playerMovement) + { + playerMovement.enabled = _alive; + } + NavmeshCut[] array3 = navmeshCut; + for (int i = 0; i < array3.Length; i++) + { + array3[i].enabled = _alive; + } + if ((bool)playerInteraction) + { + playerInteraction.enabled = _alive; + } + } + + public void Revive(bool callReviveEvent = true, float healthPercentage = 1f) + { + if (hp <= 0f) + { + if (callReviveEvent) + { + OnRevive.Invoke(); + } + taggedObject.RemoveTag(TagManager.ETag.AUTO_KnockedOutAndHealOnDawn); + taggedObject.AddTag(TagManager.ETag.AUTO_Alive); + ActivateAndDeactivateChildrenAndCompements(_alive: true); + hp = 0f; + } + else if (hp < maxHp) + { + OnHeal.Invoke(); + } + hp += maxHp * healthPercentage; + if (hp > maxHp) + { + hp = maxHp; + } + OnHpChange.Invoke(); + } + + public bool TakeDamage(float _amount, TaggedObject _damageComingFrom = null, bool causedByPlayer = false, bool invokeFeedbackEvents = true) + { + if (hp <= 0f) + { + return false; + } + if (invulnerable) + { + return false; + } + if (_amount <= 0f) + { + Heal(0f - _amount); + return false; + } + if ((bool)pathfindMovement) + { + pathfindMovement.GetAgroFromObject(_damageComingFrom); + } + hp -= _amount; + OnHpChange.Invoke(); + if (invokeFeedbackEvents) + { + OnReceiveDamage.Invoke(causedByPlayer); + } + if (hp <= 0f) + { + OnKillOrKnockout.Invoke(); + if ((bool)fxToSpawnOnDeath) + { + if ((bool)deathFxSpawnWithPosAndRotOf) + { + Object.Instantiate(fxToSpawnOnDeath, deathFxSpawnWithPosAndRotOf.position + deathFxSpawnOffset, deathFxSpawnWithPosAndRotOf.rotation, null); + } + else + { + Object.Instantiate(fxToSpawnOnDeath, base.transform.position + deathFxSpawnOffset, fxToSpawnOnDeath.transform.rotation, null); + } + } + if (getsKnockedOutInsteadOfDying) + { + taggedObject.RemoveTag(TagManager.ETag.AUTO_Alive); + taggedObject.AddTag(TagManager.ETag.AUTO_KnockedOutAndHealOnDawn); + ActivateAndDeactivateChildrenAndCompements(_alive: false); + } + else + { + Object.Destroy(base.gameObject); + if ((bool)coin) + { + for (int i = 0; i < coinCount; i++) + { + if (i > 1) + { + Object.Instantiate(coin, base.transform.position + Vector3.up * coinSpawnOffset + Quaternion.Euler(0f, 45f * (float)i, 0f) * Vector3.forward * 2f, Quaternion.identity); + } + else + { + Object.Instantiate(coin, base.transform.position + Vector3.up * coinSpawnOffset, Quaternion.identity); + } + } + } + } + if ((bool)spwanAttackOnDeath) + { + spwanAttackOnDeath.Attack(base.transform.position, null, Vector3.zero, taggedObject, damageMultiplyer); + } + return true; + } + return false; + } + + public void Heal(float _amount) + { + if (!(hp <= 0f) && !(_amount <= 0f)) + { + hp += _amount * healingMultiplyer; + if (hp > maxHp) + { + hp = maxHp; + } + OnHpChange.Invoke(); + } + } + + public static void ReviveAllUnitsWithTag(List _mustHaveTags, List _mayNotHaveTags, float _healthPercentage = 1f) + { + List list = new List(); + TagManager.instance.FindAllTaggedObjectsWithTags(list, _mustHaveTags, _mayNotHaveTags); + for (int i = 0; i < list.Count; i++) + { + list[i].Hp.Revive(callReviveEvent: true, _healthPercentage); + } + } + + public static void MarkDestroyedBuildingsAsDontRevive(List _mustHaveTags, List _mayNotHaveTags, float _healthPercentage = 1f) + { + List list = new List(); + TagManager.instance.FindAllTaggedObjectsWithTags(list, _mustHaveTags, _mayNotHaveTags); + for (int i = 0; i < list.Count; i++) + { + if (list[i].Tags.Contains(TagManager.ETag.AUTO_KnockedOutAndHealOnDawn)) + { + list[i].GetComponentInParent().Interactor.OnKnockOut(); + if (!list[i].Tags.Contains(TagManager.ETag.AUTO_NoReviveNextMorning)) + { + list[i].Tags.Add(TagManager.ETag.AUTO_NoReviveNextMorning); + } + else + { + list[i].Tags.Remove(TagManager.ETag.AUTO_NoReviveNextMorning); + } + } + } + } + + public static void KillAllUnitsWithTag(List _mustHaveTags, List _mayNotHaveTags) + { + List list = new List(); + TagManager.instance.FindAllTaggedObjectsWithTags(list, _mustHaveTags, _mayNotHaveTags); + for (int i = 0; i < list.Count; i++) + { + list[i].Hp.TakeDamage(float.MaxValue); + } + } + + public static void ReviveAllKnockedOutPlayerUnitsAndBuildings() + { + if (!PerkManager.instance.DestructionGodActive) + { + List list = new List(); + List list2 = new List(); + list.Add(TagManager.ETag.PlayerOwned); + list2.Add(TagManager.ETag.AUTO_NoReviveNextMorning); + ReviveAllUnitsWithTag(list, list2); + return; + } + List list3 = new List(); + List mayNotHaveTags = new List(); + list3.Add(TagManager.ETag.PlayerOwned); + list3.Add(TagManager.ETag.Building); + MarkDestroyedBuildingsAsDontRevive(list3, mayNotHaveTags); + List list4 = new List(); + mayNotHaveTags = new List(); + list4.Add(TagManager.ETag.PlayerOwned); + mayNotHaveTags.Add(TagManager.ETag.Building); + mayNotHaveTags.Add(TagManager.ETag.AUTO_NoReviveNextMorning); + ReviveAllUnitsWithTag(list4, mayNotHaveTags); + mayNotHaveTags.Clear(); + mayNotHaveTags.Add(TagManager.ETag.AUTO_NoReviveNextMorning); + list4.Add(TagManager.ETag.Building); + ReviveAllUnitsWithTag(list4, mayNotHaveTags, 0.33f); + } + + public static void KillAllEnemyUnits() + { + List list = new List(); + List mayNotHaveTags = new List(); + list.Add(TagManager.ETag.EnemyOwned); + KillAllUnitsWithTag(list, mayNotHaveTags); + } +} diff --git a/GameCode/InGameResignUIHelper.cs b/GameCode/InGameResignUIHelper.cs new file mode 100644 index 0000000..6f85c9e --- /dev/null +++ b/GameCode/InGameResignUIHelper.cs @@ -0,0 +1,10 @@ +using UnityEngine; + +public class InGameResignUIHelper : MonoBehaviour +{ + public void Resign() + { + UIFrameManager.instance.CloseAllFrames(); + LocalGamestate.Instance.SetState(LocalGamestate.State.AfterMatchDefeat, forceTransition: false, immediate: true); + } +} diff --git a/GameCode/IncomeModifyer.cs b/GameCode/IncomeModifyer.cs new file mode 100644 index 0000000..d8a523c --- /dev/null +++ b/GameCode/IncomeModifyer.cs @@ -0,0 +1,17 @@ +using UnityEngine; + +public class IncomeModifyer : MonoBehaviour +{ + public BuildSlot buildSlot; + + public BuildingInteractor buildingInteractor; + + private void Start() + { + buildingInteractor.IncomeModifiers.Add(this); + } + + public virtual void OnDawn() + { + } +} diff --git a/GameCode/InteractorBase.cs b/GameCode/InteractorBase.cs new file mode 100644 index 0000000..3c503c3 --- /dev/null +++ b/GameCode/InteractorBase.cs @@ -0,0 +1,27 @@ +using UnityEngine; + +public abstract class InteractorBase : MonoBehaviour +{ + public virtual bool CanBeInteractedWith => true; + + public virtual string ReturnTooltip() + { + return ""; + } + + public virtual void InteractionBegin(PlayerInteraction player) + { + } + + public virtual void InteractionHold(PlayerInteraction player) + { + } + + public virtual void InteractionEnd(PlayerInteraction player) + { + } + + public abstract void Focus(PlayerInteraction player); + + public abstract void Unfocus(PlayerInteraction player); +} diff --git a/GameCode/Invulnerable.cs b/GameCode/Invulnerable.cs new file mode 100644 index 0000000..9a7857c --- /dev/null +++ b/GameCode/Invulnerable.cs @@ -0,0 +1,16 @@ +using UnityEngine; + +public class Invulnerable : MonoBehaviour +{ + private Hp hp; + + private void Start() + { + hp = GetComponent(); + } + + private void Update() + { + hp.Heal(1000000f); + } +} diff --git a/GameCode/KeepRelativeRotationTo.cs b/GameCode/KeepRelativeRotationTo.cs new file mode 100644 index 0000000..94dbe16 --- /dev/null +++ b/GameCode/KeepRelativeRotationTo.cs @@ -0,0 +1,59 @@ +using UnityEngine; + +public class KeepRelativeRotationTo : MonoBehaviour +{ + [SerializeField] + private Transform transformToKeepRelativeRotationTo; + + [SerializeField] + private Vector3 upVector = Vector3.up; + + private Quaternion initialOffset; + + private Vector3 selfPosition; + + private Vector3 otherPosition; + + private Quaternion localRotationStart; + + private Vector3 upVectorAdjusted; + + private void PrepareData() + { + if ((bool)base.transform.parent) + { + selfPosition = base.transform.localPosition; + otherPosition = base.transform.parent.worldToLocalMatrix.MultiplyPoint(transformToKeepRelativeRotationTo.position); + upVectorAdjusted = upVector; + } + else + { + selfPosition = base.transform.position; + otherPosition = transformToKeepRelativeRotationTo.position; + upVectorAdjusted = upVector; + } + } + + private void Start() + { + if ((bool)base.transform.parent) + { + upVector = base.transform.localToWorldMatrix.MultiplyVector(upVector); + upVector = base.transform.parent.localToWorldMatrix.MultiplyVector(upVector); + upVector = upVector.normalized; + } + localRotationStart = base.transform.localRotation; + PrepareData(); + initialOffset = Quaternion.Inverse(Quaternion.LookRotation(otherPosition - selfPosition, upVectorAdjusted)); + } + + private void Update() + { + if ((bool)transformToKeepRelativeRotationTo) + { + PrepareData(); + Quaternion quaternion = Quaternion.LookRotation(otherPosition - selfPosition, upVectorAdjusted); + base.transform.localRotation = quaternion * initialOffset * localRotationStart; + } + } +} diff --git a/GameCode/KeyframedBoss.cs b/GameCode/KeyframedBoss.cs new file mode 100644 index 0000000..da32b2f --- /dev/null +++ b/GameCode/KeyframedBoss.cs @@ -0,0 +1,178 @@ +using System.Collections; +using UnityEngine; + +public class KeyframedBoss : MonoBehaviour +{ + [SerializeField] + private HealthbarMulti hpBarMulti; + + [SerializeField] + private Hp hp; + + [SerializeField] + private Transform stratKeyframe; + + [SerializeField] + private Transform cutsceneKeyframe; + + [SerializeField] + private float cutsceneHoldPosition = 4f; + + [SerializeField] + private Transform[] mainKeyframes; + + [SerializeField] + private Transform[] transitionalKeyframes; + + [SerializeField] + private float animationDuration; + + [SerializeField] + private float cutsceneAnimationDuration; + + [SerializeField] + private DestroyOrDisableOnEnable disablerComponent; + + private int bossStage; + + private bool coroutineRunning; + + [SerializeField] + private WigglerAnimationState wigglerAnimationState; + + [SerializeField] + private float spawnWarningTime = 2f; + + [SerializeField] + private Wave waveToSpawn; + + [SerializeField] + private float waveToSpawnInterval; + + [SerializeField] + private float waveToSpawnIntervalIncrease = 2f; + + private float waveToSpawnIntervalCurrent; + + private float cooldownToEnemySpawn; + + private bool waveRunning; + + private bool cutSceneAnimation; + + [SerializeField] + private AudioSource audioSourceSpawnsAndScream; + + private ThronefallAudioManager audioManager; + + private AudioSet audioSet; + + [SerializeField] + private float takeDamageDuringEnemySpawn = 100f; + + private void Start() + { + audioManager = ThronefallAudioManager.Instance; + audioSet = audioManager.audioContent; + waveToSpawnIntervalCurrent = waveToSpawnInterval; + base.transform.localPosition = stratKeyframe.localPosition; + base.transform.localRotation = stratKeyframe.localRotation; + StopAllCoroutines(); + StartCoroutine(StartAnimation()); + } + + private IEnumerator StartAnimation() + { + hp.invulnerable = true; + coroutineRunning = true; + yield return TransitionTo(cutsceneKeyframe, cutsceneAnimationDuration); + hp.invulnerable = true; + coroutineRunning = true; + cutSceneAnimation = true; + disablerComponent.enabled = true; + yield return new WaitForSeconds(cutsceneHoldPosition); + cutSceneAnimation = false; + yield return TransitionTo(mainKeyframes[0], animationDuration / 2f); + coroutineRunning = false; + hp.invulnerable = false; + } + + private void Update() + { + if (hp.HpPercentage <= (float)(mainKeyframes.Length - (bossStage + 1)) / (float)mainKeyframes.Length) + { + waveToSpawnIntervalCurrent = waveToSpawnInterval; + bossStage++; + StopAllCoroutines(); + StartCoroutine(TransitionOverTo(transitionalKeyframes[bossStage], mainKeyframes[bossStage], animationDuration)); + } + cooldownToEnemySpawn -= Time.deltaTime; + if (cooldownToEnemySpawn <= 0f && !coroutineRunning && !waveRunning) + { + cooldownToEnemySpawn = waveToSpawnIntervalCurrent; + waveToSpawnIntervalCurrent += waveToSpawnIntervalIncrease; + waveToSpawn.Reset(); + waveRunning = true; + } + if (waveRunning) + { + hp.TakeDamage(Time.deltaTime * takeDamageDuringEnemySpawn, null, causedByPlayer: false, invokeFeedbackEvents: false); + waveToSpawn.Update(); + if (waveToSpawn.HasFinished()) + { + waveRunning = false; + } + } + if (waveRunning || (cooldownToEnemySpawn <= spawnWarningTime && !coroutineRunning)) + { + if (wigglerAnimationState.animationState != 1) + { + audioSourceSpawnsAndScream.PlayOneShot(audioSet.EismolochSpawnUnits.clips[Random.Range(0, audioSet.EismolochSpawnUnits.clips.Length)]); + if (Random.value <= 0.33f) + { + audioSourceSpawnsAndScream.PlayOneShot(audioSet.EismolochScream.clips[Random.Range(0, audioSet.EismolochScream.clips.Length)]); + } + } + wigglerAnimationState.animationState = 1; + } + else if (cutSceneAnimation) + { + wigglerAnimationState.animationState = 1; + } + else + { + wigglerAnimationState.animationState = 0; + } + } + + private IEnumerator TransitionOverTo(Transform _transitionOver, Transform _transitionTo, float _animationDuration = 5f) + { + coroutineRunning = true; + yield return TransitionTo(_transitionOver, _animationDuration / 2f); + coroutineRunning = true; + yield return TransitionTo(_transitionTo, _animationDuration / 2f); + coroutineRunning = false; + } + + private IEnumerator TransitionTo(Transform _transitionTo, float _animationDuration = 5f) + { + hp.invulnerable = true; + hpBarMulti.UpdateDisplay(); + coroutineRunning = true; + Vector3 startPosition = base.transform.localPosition; + Quaternion startRotation = base.transform.localRotation; + for (float animProgress = 0f; animProgress < _animationDuration; animProgress += Time.deltaTime) + { + float f = animProgress / _animationDuration; + f = 3f * Mathf.Pow(f, 2f) - 2f * Mathf.Pow(f, 3f); + base.transform.localPosition = Vector3.Lerp(startPosition, _transitionTo.localPosition, f); + base.transform.localRotation = Quaternion.Lerp(startRotation, _transitionTo.localRotation, f); + yield return null; + } + base.transform.localPosition = _transitionTo.localPosition; + base.transform.localRotation = _transitionTo.localRotation; + coroutineRunning = false; + hp.invulnerable = false; + hpBarMulti.UpdateDisplay(); + } +} diff --git a/GameCode/LaunchableDefenseMechanismInteractor.cs b/GameCode/LaunchableDefenseMechanismInteractor.cs new file mode 100644 index 0000000..c408385 --- /dev/null +++ b/GameCode/LaunchableDefenseMechanismInteractor.cs @@ -0,0 +1,83 @@ +using UnityEngine; + +public class LaunchableDefenseMechanismInteractor : InteractorBase, DayNightCycle.IDaytimeSensitive +{ + public GameObject focusIndicator; + + public LaunchableProjectile projectilePrefab; + + public Transform projectileSpawn; + + public bool autoReloadOnDawn = true; + + private LaunchableProjectile currentProjectile; + + private void Start() + { + DayNightCycle.Instance.RegisterDaytimeSensitiveObject(this); + Reload(); + if (DayNightCycle.Instance.CurrentTimestate == DayNightCycle.Timestate.Day) + { + base.gameObject.SetActive(value: false); + } + } + + public override void Focus(PlayerInteraction player) + { + if ((bool)currentProjectile) + { + focusIndicator.SetActive(value: true); + } + } + + public override void InteractionBegin(PlayerInteraction player) + { + if ((bool)currentProjectile) + { + currentProjectile.Launch(); + currentProjectile.transform.parent = null; + currentProjectile = null; + Unfocus(player); + } + } + + public void OnDawn_AfterSunrise() + { + base.gameObject.SetActive(value: false); + if (autoReloadOnDawn) + { + Reload(); + } + } + + public void OnDawn_BeforeSunrise() + { + } + + public void OnDusk() + { + base.gameObject.SetActive(value: true); + } + + public override void Unfocus(PlayerInteraction player) + { + focusIndicator.SetActive(value: false); + } + + public void Reload() + { + if (!currentProjectile) + { + currentProjectile = Object.Instantiate(projectilePrefab, projectileSpawn.transform.position, projectileSpawn.transform.rotation, base.transform.parent); + } + } + + private void OnDrawGizmos() + { + Gizmos.color = Color.black; + Gizmos.DrawWireMesh(projectilePrefab.GetComponentInChildren().sharedMesh, 0, projectileSpawn.position, projectileSpawn.rotation, projectilePrefab.transform.localScale); + Gizmos.color = Color.magenta; + Gizmos.DrawLine(projectileSpawn.position, projectileSpawn.position + projectileSpawn.forward * 15f); + Gizmos.DrawWireSphere(projectileSpawn.position + projectileSpawn.forward * 15f, 0.3f); + } +} diff --git a/GameCode/LaunchableProjectile.cs b/GameCode/LaunchableProjectile.cs new file mode 100644 index 0000000..84f9fbd --- /dev/null +++ b/GameCode/LaunchableProjectile.cs @@ -0,0 +1,66 @@ +using System.Collections.Generic; +using UnityEngine; + +public class LaunchableProjectile : MonoBehaviour +{ + public float speed = 20f; + + public float lifetime = 3f; + + public bool groundedTranslation; + + public LayerMask groundLayer; + + public Vector3 groundingOfffset; + + public List dmgModifiers = new List(); + + public LayerMask hitLayer; + + public Vector3 damageBoxExtents; + + private bool launched; + + private float timer; + + private List touchedEnemies = new List(); + + public void Launch() + { + launched = true; + if (groundedTranslation && Physics.Raycast(new Ray(base.transform.position, Vector3.down), out var hitInfo, float.PositiveInfinity, groundLayer)) + { + base.transform.position = hitInfo.point + groundingOfffset; + } + } + + private void Update() + { + if (!launched) + { + return; + } + timer += Time.deltaTime; + base.transform.position += base.transform.forward * speed * Time.deltaTime; + Collider[] array = Physics.OverlapBox(base.transform.position, damageBoxExtents / 2f, base.transform.rotation, hitLayer); + for (int i = 0; i < array.Length; i++) + { + Hp componentInParent = array[i].GetComponentInParent(); + if ((bool)componentInParent && !touchedEnemies.Contains(componentInParent)) + { + touchedEnemies.Add(componentInParent); + componentInParent.TakeDamage(DamageModifyer.CalculateDamageOnTarget(componentInParent.TaggedObj, dmgModifiers)); + } + } + if (timer >= lifetime) + { + Object.Destroy(base.gameObject); + } + } + + private void OnDrawGizmos() + { + Gizmos.color = Color.magenta; + Gizmos.DrawWireCube(base.transform.position, damageBoxExtents); + } +} diff --git a/GameCode/LevelAudio.cs b/GameCode/LevelAudio.cs new file mode 100644 index 0000000..0ced3a9 --- /dev/null +++ b/GameCode/LevelAudio.cs @@ -0,0 +1,69 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +public class LevelAudio : MonoBehaviour +{ + [Serializable] + public class CivilisationAudioSource + { + public AudioSource audioSource; + + public float volumeAtCastleCenterBuild = 0.1f; + + public float targetVolume; + + public int targetBuildingAmount; + } + + public List managedCivAudioSources; + + private int buildingCount; + + private void OnValidate() + { + foreach (CivilisationAudioSource managedCivAudioSource in managedCivAudioSources) + { + if (managedCivAudioSource.audioSource != null) + { + managedCivAudioSource.targetVolume = managedCivAudioSource.audioSource.volume; + } + } + } + + private void Start() + { + for (int num = managedCivAudioSources.Count - 1; num >= 0; num--) + { + CivilisationAudioSource civilisationAudioSource = managedCivAudioSources[num]; + if (civilisationAudioSource.audioSource == null) + { + managedCivAudioSources.RemoveAt(num); + } + else + { + civilisationAudioSource.targetVolume = civilisationAudioSource.audioSource.volume; + civilisationAudioSource.audioSource.volume = 0f; + } + } + ThronefallAudioManager.Instance.onBuildingBuild.AddListener(OnNewBuildingBuilt); + } + + private void OnNewBuildingBuilt() + { + for (int num = managedCivAudioSources.Count - 1; num >= 0; num--) + { + CivilisationAudioSource civilisationAudioSource = managedCivAudioSources[num]; + civilisationAudioSource.audioSource.volume = Mathf.Lerp(civilisationAudioSource.volumeAtCastleCenterBuild, civilisationAudioSource.targetVolume, Mathf.InverseLerp(0f, civilisationAudioSource.targetBuildingAmount, buildingCount)); + if (buildingCount >= civilisationAudioSource.targetBuildingAmount) + { + managedCivAudioSources.RemoveAt(num); + } + } + buildingCount++; + if (managedCivAudioSources.Count < 1) + { + ThronefallAudioManager.Instance.onBuildingBuild.RemoveListener(OnNewBuildingBuilt); + } + } +} diff --git a/GameCode/LevelBorder.cs b/GameCode/LevelBorder.cs new file mode 100644 index 0000000..7bc2eff --- /dev/null +++ b/GameCode/LevelBorder.cs @@ -0,0 +1,98 @@ +using System.Collections; +using Shapes; +using UnityEngine; + +public class LevelBorder : MonoBehaviour +{ + public BoxCollider boxCol; + + public float fadeInDistance; + + public Line line; + + private readonly float tickTime = 0.5f; + + private readonly float fadeTime = 0.75f; + + private float timer; + + private bool fadedIn; + + private Transform target; + + private Color defaultColor; + + private Color fadeOutColor; + + private Coroutine currentFade; + + private void Start() + { + target = TagManager.instance.Players[0].transform; + defaultColor = line.Color; + fadeOutColor = defaultColor; + fadeOutColor.a = 0f; + line.Color = fadeOutColor; + } + + private void Update() + { + timer += Time.deltaTime; + if (!(timer >= tickTime)) + { + return; + } + timer = 0f; + float num = Vector3.Distance(target.position, boxCol.ClosestPoint(target.position)); + if (fadedIn && num > fadeInDistance) + { + if (currentFade == null) + { + currentFade = StartCoroutine(FadeOut()); + } + fadedIn = false; + } + else if (!fadedIn && num <= fadeInDistance) + { + if (currentFade == null) + { + currentFade = StartCoroutine(FadeIn()); + } + fadedIn = true; + } + } + + private IEnumerator FadeIn() + { + float timer = 0f; + while (timer <= fadeTime) + { + timer += Time.deltaTime; + line.Color = Color.Lerp(fadeOutColor, defaultColor, timer / fadeTime); + yield return null; + } + line.Color = defaultColor; + currentFade = null; + if (!fadedIn) + { + currentFade = StartCoroutine(FadeOut()); + } + } + + private IEnumerator FadeOut() + { + float timer = 0f; + while (timer <= fadeTime) + { + timer += Time.deltaTime; + line.Color = Color.Lerp(defaultColor, fadeOutColor, timer / fadeTime); + yield return null; + } + line.Color = fadeOutColor; + currentFade = null; + if (fadedIn) + { + currentFade = StartCoroutine(FadeIn()); + } + } +} diff --git a/GameCode/LevelData.cs b/GameCode/LevelData.cs new file mode 100644 index 0000000..2f7caa9 --- /dev/null +++ b/GameCode/LevelData.cs @@ -0,0 +1,46 @@ +using System; +using System.Collections.Generic; + +[Serializable] +public class LevelData +{ + public int questsCompleteWhenLastVisitingMap; + + public bool beaten; + + public int highscore; + + public List dayToDayScore = new List(); + + public List dayToDayNetworth = new List(); + + public bool beatenBest; + + public int highscoreBest; + + public List dayToDayScoreBest = new List(); + + public List dayToDayNetworthBest = new List(); + + public List> levelHasBeenBeatenWith = new List>(); + + public void SaveScoreAndStatsToBestIfBest(bool _endOfMatch) + { + beatenBest = beaten || beatenBest; + if (highscore > highscoreBest) + { + highscoreBest = highscore; + dayToDayScoreBest = new List(dayToDayScore); + dayToDayNetworthBest = new List(dayToDayNetworth); + } + if (_endOfMatch && beaten) + { + levelHasBeenBeatenWith.Add(new List(PerkManager.instance.CurrentlyEquipped)); + } + beaten = false; + highscore = 0; + dayToDayScore = new List(); + dayToDayScore.Add(0); + dayToDayNetworth = new List(); + } +} diff --git a/GameCode/LevelInteractor.cs b/GameCode/LevelInteractor.cs new file mode 100644 index 0000000..efad8df --- /dev/null +++ b/GameCode/LevelInteractor.cs @@ -0,0 +1,280 @@ +using System.Collections; +using System.Collections.Generic; +using I2.Loc; +using TMPro; +using UnityEngine; + +public class LevelInteractor : InteractorBase +{ + public string sceneName; + + public string displayName; + + private LevelSelectManager levelSelectManager; + + private LevelProgressManager levelProgressManager; + + private LevelData myLevelData; + + [Header("Unlock Requirements")] + [SerializeField] + private bool unlockedInDemo; + + public LevelInteractor requirementThisLevelMustBeBeaten; + + [SerializeField] + private string tooltipThisLevelMustBeBeaten = "Beat to unlock this level."; + + [Header("Setup")] + [SerializeField] + private GameObject focusPanel; + + [Header("Setup")] + [SerializeField] + private GameObject cantBePlayedPanel; + + [SerializeField] + private TextMeshProUGUI cantBePlayedCue; + + [SerializeField] + private GameObject lockedLevelVisuals; + + [SerializeField] + private GameObject unlockedLevelVisuals; + + [SerializeField] + private GameObject beatenLevelVisuals; + + [Header("Quests")] + [SerializeField] + private Transform rewardBuildingsParent; + + [SerializeField] + private TMP_Text questsComplete; + + [SerializeField] + private Color allQuestComplete; + + [SerializeField] + private Color notAllQuestComplete; + + [SerializeField] + private List quests = new List(); + + [Header("Loadout")] + public List fixedLoadout = new List(); + + public static LevelInteractor lastActivatedLevelInteractor; + + private string tooltipGetTheFullGame => LocalizationManager.GetTranslation("Menu/Get Full Game"); + + public List Quests => quests; + + public bool HasFixedLoadout => fixedLoadout.Count > 0; + + public bool CanBePlayed + { + get + { + if (DebugController.SaveLoadModeToUse == DebugController.SaveLoadMode.LoadMaxedOutSaveFileOnStartup) + { + return true; + } + if (requirementThisLevelMustBeBeaten != null && !requirementThisLevelMustBeBeaten.Beaten) + { + return false; + } + return true; + } + } + + public string CanNotBePlayedReason + { + get + { + if ((bool)requirementThisLevelMustBeBeaten && !requirementThisLevelMustBeBeaten.Beaten) + { + return tooltipThisLevelMustBeBeaten.Replace("", requirementThisLevelMustBeBeaten.displayName); + } + return ""; + } + } + + public bool Beaten + { + get + { + if (DebugController.SaveLoadModeToUse == DebugController.SaveLoadMode.LoadMaxedOutSaveFileOnStartup) + { + return true; + } + if (myLevelData == null) + { + levelProgressManager = LevelProgressManager.instance; + myLevelData = levelProgressManager.GetLevelDataForScene(sceneName); + } + return myLevelData.beatenBest; + } + } + + public void UpdateVisualsOnStart() + { + if (myLevelData == null) + { + levelProgressManager = LevelProgressManager.instance; + myLevelData = levelProgressManager.GetLevelDataForScene(sceneName); + } + lockedLevelVisuals.SetActive(value: false); + unlockedLevelVisuals.SetActive(value: false); + beatenLevelVisuals.SetActive(value: false); + questsComplete.transform.parent.gameObject.SetActive(value: false); + questsComplete.text = QuestsBeatenString(); + int num = QuestsComplete(); + if (num == QuestsTotal()) + { + AchievementManager.LevelAllQuestsComplete(sceneName); + } + if (myLevelData.beatenBest) + { + AchievementManager.LevelBeaten(sceneName); + } + questsComplete.color = ((num >= QuestsTotal()) ? allQuestComplete : notAllQuestComplete); + float num2 = (float)num / (float)QuestsTotal(); + int enabledBuildings = Mathf.FloorToInt((float)rewardBuildingsParent.childCount * (float)myLevelData.questsCompleteWhenLastVisitingMap); + int num3 = Mathf.FloorToInt((float)rewardBuildingsParent.childCount * num2); + myLevelData.questsCompleteWhenLastVisitingMap = num3; + StartCoroutine(EnableBuildingsCoroutine(enabledBuildings, num3, 0.75f, 0.5f)); + if (!CanBePlayed) + { + lockedLevelVisuals.SetActive(value: true); + return; + } + questsComplete.transform.parent.gameObject.SetActive(value: true); + if (!Beaten) + { + unlockedLevelVisuals.SetActive(value: true); + } + else + { + beatenLevelVisuals.SetActive(value: true); + } + } + + private IEnumerator EnableBuildingsCoroutine(int _enabledBuildings, int _enabledBuildingsUpTo, float _initialDelay, float _interval) + { + if (rewardBuildingsParent.childCount < _enabledBuildingsUpTo) + { + Debug.LogWarning("Not enough children in the rewardBuildingsParent to satisfy enabledBuildingsUpTo"); + yield break; + } + if (rewardBuildingsParent.childCount < _enabledBuildings) + { + Debug.LogWarning("Not enough children in the rewardBuildingsParent to satisfy enabledBuildings"); + yield break; + } + for (int j = 0; j < rewardBuildingsParent.childCount; j++) + { + rewardBuildingsParent.GetChild(j).gameObject.SetActive(value: false); + } + for (int k = 0; k < _enabledBuildings; k++) + { + rewardBuildingsParent.GetChild(k).gameObject.SetActive(value: true); + } + yield return new WaitForSeconds(_initialDelay); + for (int i = _enabledBuildings; i < _enabledBuildingsUpTo; i++) + { + rewardBuildingsParent.GetChild(i).gameObject.SetActive(value: true); + rewardBuildingsParent.GetChild(i).GetChild(0).gameObject.SetActive(value: true); + yield return new WaitForSeconds(_interval); + } + } + + private void Start() + { + levelSelectManager = GetComponentInParent(); + levelProgressManager = LevelProgressManager.instance; + myLevelData = levelProgressManager.GetLevelDataForScene(sceneName); + focusPanel.SetActive(value: false); + cantBePlayedPanel.SetActive(value: false); + UpdateVisualsOnStart(); + } + + public override string ReturnTooltip() + { + if (CanBePlayed) + { + return LocalizationManager.GetTranslation("Menu/Level Interactor Cue"); + } + return ""; + } + + private string GenerateCueText() + { + if (!CanBePlayed) + { + return CanNotBePlayedReason; + } + if (levelSelectManager.PreLevelMenuIsOpen) + { + return ""; + } + return displayName; + } + + public override void InteractionBegin(PlayerInteraction _player) + { + if (CanBePlayed) + { + lastActivatedLevelInteractor = this; + UIFrameManager.TryOpenLevelSelect(); + } + } + + public override void Focus(PlayerInteraction _player) + { + if (CanBePlayed) + { + focusPanel.SetActive(value: true); + cantBePlayedPanel.SetActive(value: false); + } + else + { + cantBePlayedCue.text = GenerateCueText(); + cantBePlayedPanel.SetActive(value: true); + focusPanel.SetActive(value: false); + } + } + + public override void Unfocus(PlayerInteraction _player) + { + focusPanel.SetActive(value: false); + cantBePlayedPanel.SetActive(value: false); + } + + public int QuestsComplete() + { + int num = 0; + if (DebugController.SaveLoadModeToUse == DebugController.SaveLoadMode.LoadMaxedOutSaveFileOnStartup) + { + return quests.Count; + } + for (int i = 0; i < quests.Count; i++) + { + if (quests[i].CheckBeaten(myLevelData)) + { + num++; + } + } + return num; + } + + public int QuestsTotal() + { + return quests.Count; + } + + public string QuestsBeatenString() + { + return QuestsComplete() + "/" + QuestsTotal(); + } +} diff --git a/GameCode/LevelProgressManager.cs b/GameCode/LevelProgressManager.cs new file mode 100644 index 0000000..500bf43 --- /dev/null +++ b/GameCode/LevelProgressManager.cs @@ -0,0 +1,57 @@ +using UnityEngine; +using UnityEngine.SceneManagement; + +public class LevelProgressManager : MonoBehaviour +{ + public static LevelProgressManager instance; + + [SerializeField] + private SceneNameToLevelData sceneNameToLevelData = new SceneNameToLevelData(); + + public SceneNameToLevelData SceneNameToLevelData => sceneNameToLevelData; + + public bool StartsWithUnderscore(string input) + { + if (string.IsNullOrEmpty(input)) + { + return false; + } + return input[0] == '_'; + } + + private void Awake() + { + if ((bool)instance) + { + Object.Destroy(base.gameObject); + return; + } + instance = this; + Object.DontDestroyOnLoad(base.transform.root.gameObject); + } + + public LevelData GetLevelDataForScene(string _sceneName) + { + if (_sceneName == SceneTransitionManager.instance.levelSelectScene) + { + return null; + } + if (StartsWithUnderscore(_sceneName)) + { + return null; + } + if (sceneNameToLevelData.ContainsKey(_sceneName)) + { + return sceneNameToLevelData[_sceneName]; + } + LevelData levelData = new LevelData(); + sceneNameToLevelData.Add(_sceneName, levelData); + return levelData; + } + + public LevelData GetLevelDataForActiveScene() + { + string sceneName = SceneManager.GetActiveScene().name; + return GetLevelDataForScene(sceneName); + } +} diff --git a/GameCode/LevelSelectManager.cs b/GameCode/LevelSelectManager.cs new file mode 100644 index 0000000..5650ffd --- /dev/null +++ b/GameCode/LevelSelectManager.cs @@ -0,0 +1,114 @@ +using TMPro; +using UnityEngine; +using UnityEngine.UI; + +public class LevelSelectManager : MonoBehaviour +{ + public static LevelSelectManager instance; + + private LevelInteractor[] levelInteractors; + + public Vector3 spawnOnLevelOffsetPositon; + + public PlayerMovement playerMovement; + + public TMP_Text levelTitle; + + public TMP_Text levelHighscore; + + public TMP_Text beatenState; + + public string notBeatenYet = "Not beaten yet."; + + public string successfullyBeaten = "Successfully beaten."; + + public string scorePrefix = "Your Best: "; + + public GameObject tooltipObject; + + public Image tooltipImage; + + public TMP_Text tooltipTitle; + + public TMP_Text tooltipDescription; + + private Equippable showingTooltipFor; + + public Canvas levelSelectedCanvas; + + public Camera camMain; + + private LevelInteractor openedLevel; + + private int iFrames; + + private bool fixedLoadout; + + public Equippable ShowingTooltipFor => showingTooltipFor; + + public bool PreLevelMenuIsOpen => openedLevel != null; + + public void ShowTooltip(Equippable _eq) + { + showingTooltipFor = _eq; + tooltipObject.SetActive(_eq != null); + if (!(_eq == null)) + { + tooltipImage.sprite = _eq.icon; + tooltipTitle.text = _eq.displayName; + tooltipDescription.text = _eq.description; + float num = camMain.pixelRect.height / levelSelectedCanvas.pixelRect.height; + tooltipObject.transform.position = Input.mousePosition * num; + } + } + + private void Awake() + { + instance = this; + } + + private void Start() + { + levelInteractors = GetComponentsInChildren(); + ShowTooltip(null); + } + + private void MovePlayerToTheLevelYouCameFrom() + { + SceneTransitionManager sceneTransitionManager = SceneTransitionManager.instance; + if (!sceneTransitionManager || sceneTransitionManager.ComingFromGameplayScene == "") + { + return; + } + for (int i = 0; i < levelInteractors.Length; i++) + { + if (levelInteractors[i].sceneName == sceneTransitionManager.ComingFromGameplayScene) + { + playerMovement.TeleportTo(levelInteractors[i].transform.position + spawnOnLevelOffsetPositon); + break; + } + } + } + + private void Update() + { + if (iFrames <= 1) + { + MovePlayerToTheLevelYouCameFrom(); + } + iFrames++; + } + + public void PlayButtonPressed() + { + if (PreLevelMenuIsOpen) + { + if (openedLevel.fixedLoadout.Count > 0) + { + PerkManager.instance.CurrentlyEquipped.Clear(); + PerkManager.instance.CurrentlyEquipped.AddRange(openedLevel.fixedLoadout); + } + SceneTransitionManager.instance.TransitionFromLevelSelectToLevel(openedLevel.sceneName); + } + } +} diff --git a/GameCode/LevelSelectUIFrameHelper.cs b/GameCode/LevelSelectUIFrameHelper.cs new file mode 100644 index 0000000..4a53e53 --- /dev/null +++ b/GameCode/LevelSelectUIFrameHelper.cs @@ -0,0 +1,17 @@ +using TMPro; +using UnityEngine; + +public class LevelSelectUIFrameHelper : MonoBehaviour +{ + public TextMeshProUGUI levelTitle; + + public void OnShow() + { + levelTitle.text = LevelInteractor.lastActivatedLevelInteractor.displayName; + } + + public void TransitionToSelectedLevel() + { + SceneTransitionManager.instance.TransitionFromLevelSelectToLevel(LevelInteractor.lastActivatedLevelInteractor.sceneName); + } +} diff --git a/GameCode/LevelUpScreenAnimation.cs b/GameCode/LevelUpScreenAnimation.cs new file mode 100644 index 0000000..b0d4476 --- /dev/null +++ b/GameCode/LevelUpScreenAnimation.cs @@ -0,0 +1,29 @@ +using System.Collections; +using UnityEngine; + +public class LevelUpScreenAnimation : MonoBehaviour +{ + public float animationTime = 0.5f; + + public AnimationCurve scaleCurve; + + public Transform target; + + public void Trigger() + { + StopAllCoroutines(); + StartCoroutine(Animation()); + } + + private IEnumerator Animation() + { + float timer = 0f; + while (timer < animationTime) + { + timer += Time.unscaledDeltaTime; + target.localScale = Vector3.one * scaleCurve.Evaluate(Mathf.InverseLerp(0f, animationTime, timer)); + yield return null; + } + target.localScale = Vector3.one; + } +} diff --git a/GameCode/LimitDeltaTime.cs b/GameCode/LimitDeltaTime.cs new file mode 100644 index 0000000..d0a7f54 --- /dev/null +++ b/GameCode/LimitDeltaTime.cs @@ -0,0 +1,11 @@ +using UnityEngine; + +public class LimitDeltaTime : MonoBehaviour +{ + public float maxDeltaTimeInMs = 16f; + + private void Start() + { + Time.maximumDeltaTime = maxDeltaTimeInMs / 1000f; + } +} diff --git a/GameCode/LimitedLifetime.cs b/GameCode/LimitedLifetime.cs new file mode 100644 index 0000000..1d99757 --- /dev/null +++ b/GameCode/LimitedLifetime.cs @@ -0,0 +1,11 @@ +using UnityEngine; + +public class LimitedLifetime : MonoBehaviour +{ + public float liftetime = 5f; + + private void Start() + { + Object.Destroy(base.gameObject, liftetime); + } +} diff --git a/GameCode/LoadSceneOnTop.cs b/GameCode/LoadSceneOnTop.cs new file mode 100644 index 0000000..c514abe --- /dev/null +++ b/GameCode/LoadSceneOnTop.cs @@ -0,0 +1,25 @@ +using UnityEngine; +using UnityEngine.SceneManagement; + +public class LoadSceneOnTop : MonoBehaviour +{ + [SerializeField] + private string sceneNameToLoad; + + private void Start() + { + LoadScene(); + } + + public void LoadScene() + { + if (!string.IsNullOrEmpty(sceneNameToLoad)) + { + SceneManager.LoadScene(sceneNameToLoad, LoadSceneMode.Additive); + } + else + { + Debug.LogError("Scene name is not specified. Please provide a valid scene name."); + } + } +} diff --git a/GameCode/LoadoutUIHelper.cs b/GameCode/LoadoutUIHelper.cs new file mode 100644 index 0000000..7eccf08 --- /dev/null +++ b/GameCode/LoadoutUIHelper.cs @@ -0,0 +1,398 @@ +using System.Collections.Generic; +using I2.Loc; +using TMPro; +using UnityEngine; +using UnityEngine.UI; + +public class LoadoutUIHelper : MonoBehaviour +{ + public UIFrame frame; + + public TextMeshProUGUI perksText; + + public TextMeshProUGUI mutatorBonusText; + + public ThronefallUIElement playButton; + + public GridLayoutGroup weaponsParent; + + public GridLayoutGroup perksParent; + + public GridLayoutGroup mutatorsParent; + + public TFUIEquippable equippableButtonPrefab; + + public GameObject fixedLoadoutWarning; + + public Transform questsParent; + + public QuestEntry questEntryPrefab; + + private List weapons = new List(); + + private List perks = new List(); + + private List mutators = new List(); + + private List equippedWeapons = new List(); + + private List equippedPerks = new List(); + + private List equippedMutators = new List(); + + private readonly int numberOfWeaponsAllowedToEquip = 1; + + private readonly int numberOfMutatiomsAllowedToEquip = 1000; + + private int numberOfPerksAllowedToEquip; + + private LevelData levelData; + + public void OnShow() + { + levelData = LevelProgressManager.instance.GetLevelDataForScene(LevelInteractor.lastActivatedLevelInteractor.sceneName); + weapons.Clear(); + perks.Clear(); + mutators.Clear(); + equippedWeapons.Clear(); + equippedPerks.Clear(); + equippedMutators.Clear(); + foreach (Transform item in weaponsParent.transform) + { + Object.Destroy(item.gameObject); + } + foreach (Transform item2 in perksParent.transform) + { + Object.Destroy(item2.gameObject); + } + foreach (Transform item3 in mutatorsParent.transform) + { + Object.Destroy(item3.gameObject); + } + fixedLoadoutWarning.SetActive(LevelInteractor.lastActivatedLevelInteractor.HasFixedLoadout); + numberOfPerksAllowedToEquip = 0; + foreach (Equippable unlockedEquippable in PerkManager.instance.UnlockedEquippables) + { + if (unlockedEquippable is PerkPoint) + { + numberOfPerksAllowedToEquip++; + } + else if (unlockedEquippable is EquippableWeapon) + { + AddTFUIEquippable(weaponsParent, unlockedEquippable); + } + else if (unlockedEquippable is EquippablePerk) + { + AddTFUIEquippable(perksParent, unlockedEquippable); + } + else if (unlockedEquippable is EquippableMutation) + { + AddTFUIEquippable(mutatorsParent, unlockedEquippable); + } + } + foreach (MetaLevel metaLevel in PerkManager.instance.MetaLevels) + { + Equippable reward = metaLevel.reward; + if (!PerkManager.instance.UnlockedEquippables.Contains(reward)) + { + if (reward is EquippableWeapon) + { + AddTFUIEquippable(weaponsParent, reward); + } + else if (reward is EquippablePerk) + { + AddTFUIEquippable(perksParent, reward); + } + else if (reward is EquippableMutation) + { + AddTFUIEquippable(mutatorsParent, reward); + } + } + } + RecomputeNavigation(); + RewriteQuestTexts(); + UpdatePerksText(); + UpdateMutatorBonusText(); + } + + private void AddTFUIEquippable(GridLayoutGroup parent, Equippable e) + { + TFUIEquippable component = Object.Instantiate(equippableButtonPrefab, parent.transform).GetComponent(); + component.SetData(e); + if (PerkManager.IsEquipped(e)) + { + if (LevelInteractor.lastActivatedLevelInteractor.HasFixedLoadout && !LevelInteractor.lastActivatedLevelInteractor.fixedLoadout.Contains(e)) + { + PerkManager.SetEquipped(e, _equipped: false); + } + else + { + component.Pick(); + if (e is EquippableWeapon) + { + equippedWeapons.Add(component); + } + if (e is EquippablePerk) + { + equippedPerks.Add(component); + } + if (e is EquippableMutation) + { + equippedMutators.Add(component); + } + } + } + else if (LevelInteractor.lastActivatedLevelInteractor.HasFixedLoadout && LevelInteractor.lastActivatedLevelInteractor.fixedLoadout.Contains(e)) + { + PerkManager.SetEquipped(e, _equipped: true); + component.Pick(); + if (e is EquippableWeapon) + { + equippedWeapons.Add(component); + } + if (e is EquippablePerk) + { + equippedPerks.Add(component); + } + if (e is EquippableMutation) + { + equippedMutators.Add(component); + } + } + if (parent == weaponsParent) + { + weapons.Add(component); + } + else if (parent == perksParent) + { + perks.Add(component); + } + else if (parent == mutatorsParent) + { + mutators.Add(component); + } + } + + public void TrySelectEquippableForLoadout() + { + TFUIEquippable tFUIEquippable = frame.LastApplied as TFUIEquippable; + if (tFUIEquippable == null || tFUIEquippable.Locked || LevelInteractor.lastActivatedLevelInteractor.HasFixedLoadout) + { + return; + } + if (tFUIEquippable.Data is EquippableWeapon) + { + for (int num = equippedWeapons.Count - 1; num >= 0; num--) + { + PerkManager.SetEquipped(equippedWeapons[num].Data, _equipped: false); + equippedWeapons[num].UnPick(); + equippedWeapons.Remove(equippedWeapons[num]); + } + tFUIEquippable.Pick(); + PerkManager.SetEquipped(tFUIEquippable.Data, _equipped: true); + equippedWeapons.Add(tFUIEquippable); + } + if (tFUIEquippable.Data is EquippablePerk) + { + List list = new List(); + int num2 = 0; + for (int num3 = equippedPerks.Count - 1; num3 >= 0; num3--) + { + if (equippedPerks[num3] != tFUIEquippable) + { + num2++; + } + if (num2 >= numberOfPerksAllowedToEquip) + { + list.Add(equippedPerks[num3]); + } + } + foreach (TFUIEquippable item in list) + { + PerkManager.SetEquipped(item.Data, _equipped: false); + item.UnPick(); + equippedPerks.Remove(item); + } + if (equippedPerks.Contains(tFUIEquippable)) + { + tFUIEquippable.UnPick(); + PerkManager.SetEquipped(tFUIEquippable.Data, _equipped: false); + equippedPerks.Remove(tFUIEquippable); + } + else + { + tFUIEquippable.Pick(); + PerkManager.SetEquipped(tFUIEquippable.Data, _equipped: true); + equippedPerks.Add(tFUIEquippable); + } + } + if (tFUIEquippable.Data is EquippableMutation) + { + if (equippedMutators.Contains(tFUIEquippable)) + { + tFUIEquippable.UnPick(); + PerkManager.SetEquipped(tFUIEquippable.Data, _equipped: false); + equippedMutators.Remove(tFUIEquippable); + } + else + { + tFUIEquippable.Pick(); + PerkManager.SetEquipped(tFUIEquippable.Data, _equipped: true); + equippedMutators.Add(tFUIEquippable); + } + } + UpdatePerksText(); + UpdateMutatorBonusText(); + } + + private void RecomputeNavigation() + { + int constraintCount = weaponsParent.constraintCount; + AssignNavigationTargets(weapons, playButton, null, null, perks, constraintCount); + AssignNavigationTargets(perks, null, weapons, null, mutators, constraintCount); + AssignNavigationTargets(mutators, null, perks, playButton, null, constraintCount); + playButton.topNav = mutators[mutators.Count - 1]; + playButton.leftNav = mutators[mutators.Count - 1]; + playButton.botNav = weapons[0]; + playButton.rightNav = weapons[0]; + GetComponent().firstSelected = weapons[0]; + } + + private void RewriteQuestTexts() + { + for (int num = questsParent.childCount - 1; num >= 0; num--) + { + Object.Destroy(questsParent.GetChild(num).gameObject); + } + int num2 = 0; + foreach (Quest quest in LevelInteractor.lastActivatedLevelInteractor.Quests) + { + Object.Instantiate(questEntryPrefab, questsParent).Init(quest, num2, quest.CheckBeaten(levelData)); + num2++; + } + } + + private void UpdatePerksText() + { + if (LevelInteractor.lastActivatedLevelInteractor.HasFixedLoadout) + { + perksText.text = LocalizationManager.GetTranslation("Menu/Perks"); + return; + } + perksText.text = LocalizationManager.GetTranslation("Menu/Perks") + " (" + equippedPerks.Count + "/" + numberOfPerksAllowedToEquip + ")"; + } + + private void UpdateMutatorBonusText() + { + if (equippedMutators.Count > 0) + { + mutatorBonusText.gameObject.SetActive(value: true); + float num = 1f; + foreach (TFUIEquippable equippedMutator in equippedMutators) + { + EquippableMutation equippableMutation = equippedMutator.Data as EquippableMutation; + if (!(equippableMutation == null)) + { + num *= equippableMutation.scoreMultiplyerOnWin; + } + } + num -= 1f; + mutatorBonusText.text = LocalizationManager.GetTermTranslation("Menu/Mutator Bonus Preview") + ": +" + (num * 100f).ToString("F0") + "%"; + } + else + { + mutatorBonusText.gameObject.SetActive(value: false); + } + } + + private void AssignNavigationTargets(List targetElements, ThronefallUIElement aboveElement, List aboveList, ThronefallUIElement belowElement, List belowList, int maxColumns) + { + for (int i = 0; i < targetElements.Count; i++) + { + TFUIEquippable tFUIEquippable = targetElements[i]; + int num = i - 1; + int num2 = i + 1; + int num3 = i + maxColumns; + int num4 = i - maxColumns; + if (num < 0) + { + if (aboveElement != null) + { + tFUIEquippable.leftNav = aboveElement; + } + else + { + tFUIEquippable.leftNav = aboveList[aboveList.Count - 1]; + } + } + else + { + tFUIEquippable.leftNav = targetElements[num]; + } + if (num2 >= targetElements.Count) + { + if (belowElement != null) + { + tFUIEquippable.rightNav = belowElement; + } + else + { + tFUIEquippable.rightNav = belowList[0]; + } + } + else + { + tFUIEquippable.rightNav = targetElements[num2]; + } + if (num3 >= targetElements.Count) + { + if (targetElements.Count - i > targetElements.Count % maxColumns) + { + tFUIEquippable.botNav = targetElements[targetElements.Count - 1]; + } + else if (belowElement != null) + { + tFUIEquippable.botNav = belowElement; + } + else + { + int num5 = i % maxColumns; + if (belowList.Count < num5) + { + tFUIEquippable.botNav = belowList[belowList.Count - 1]; + } + else + { + tFUIEquippable.botNav = belowList[num5]; + } + } + } + else + { + tFUIEquippable.botNav = targetElements[num3]; + } + if (num4 < 0) + { + if (aboveElement != null) + { + tFUIEquippable.topNav = aboveElement; + continue; + } + int num6 = i % maxColumns; + int num7 = aboveList.Count % maxColumns; + if (num6 > num7) + { + tFUIEquippable.topNav = aboveList[aboveList.Count - 1]; + continue; + } + int value = aboveList.Count - num7 + num6; + value = Mathf.Clamp(value, 0, aboveList.Count - 1); + tFUIEquippable.topNav = aboveList[value]; + } + else + { + tFUIEquippable.topNav = targetElements[num4]; + } + } + } +} diff --git a/GameCode/LocalGamestate.cs b/GameCode/LocalGamestate.cs new file mode 100644 index 0000000..655c7a2 --- /dev/null +++ b/GameCode/LocalGamestate.cs @@ -0,0 +1,131 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Events; + +public class LocalGamestate : MonoBehaviour +{ + public enum State + { + PreMatch, + InMatch, + AfterMatchVictory, + AfterMatchDefeat + } + + [SerializeField] + private bool autoStartMatch = true; + + [SerializeField] + private State currentState; + + [SerializeField] + private List objectsThatTriggerLoseWhenDestroyed = new List(); + + [HideInInspector] + public UnityEvent OnGameStateChange = new UnityEvent(); + + private static LocalGamestate instance; + + private bool playerFrozen; + + public State CurrentState => currentState; + + public static LocalGamestate Instance => instance; + + public bool PlayerFrozen => playerFrozen; + + private void Awake() + { + if (instance != null) + { + Debug.LogWarning("Multiple LocalGamestate Objects detected. Please make sure there is only on LocalGamestate in the scene. Old instance got destroyed."); + Object.Destroy(instance.gameObject); + } + instance = this; + } + + private void Start() + { + LevelProgressManager.instance.GetLevelDataForActiveScene()?.SaveScoreAndStatsToBestIfBest(_endOfMatch: false); + if (autoStartMatch) + { + SetState(State.InMatch); + } + foreach (Hp item in objectsThatTriggerLoseWhenDestroyed) + { + if ((bool)item && item.OnKillOrKnockout != null) + { + item.OnKillOrKnockout.AddListener(OnVitalObjectKill); + } + } + } + + public void SetState(State nextState, bool forceTransition = false, bool immediate = false) + { + if (currentState == State.AfterMatchVictory || currentState == State.AfterMatchDefeat || (nextState == currentState && !forceTransition)) + { + return; + } + currentState = nextState; + OnGameStateChange.Invoke(); + if (currentState == State.AfterMatchVictory) + { + LevelData levelDataForActiveScene = LevelProgressManager.instance.GetLevelDataForActiveScene(); + if (levelDataForActiveScene != null) + { + levelDataForActiveScene.beaten = true; + } + } + else + { + LevelData levelDataForActiveScene2 = LevelProgressManager.instance.GetLevelDataForActiveScene(); + if (levelDataForActiveScene2 != null) + { + levelDataForActiveScene2.beaten = false; + } + } + if (CurrentState == State.AfterMatchDefeat) + { + MusicManager.instance.PlayMusic(null, 3f); + } + if (currentState == State.AfterMatchVictory || currentState == State.AfterMatchDefeat) + { + StartCoroutine(WaitThenTriggerEndOfMatchScreen(immediate)); + } + } + + private IEnumerator WaitThenTriggerEndOfMatchScreen(bool immediate = false) + { + if (immediate) + { + yield return null; + } + else + { + yield return new WaitForSeconds(1f); + } + if (currentState == State.AfterMatchVictory) + { + SceneTransitionManager.instance.TransitionFromGameplayToEndScreen(ScoreManager.Instance.CurrentScore, ScoreManager.Instance.VictoryGoldBonus, ScoreManager.Instance.VictoryMutatorBonus); + } + else + { + SceneTransitionManager.instance.TransitionFromGameplayToEndScreen(ScoreManager.Instance.CurrentScore, 0, 0); + } + yield return null; + } + + private void OnVitalObjectKill() + { + if (currentState == State.InMatch) + { + SetState(State.AfterMatchDefeat); + } + } + + public void SetPlayerFreezeState(bool frozen) + { + playerFrozen = frozen; + } +} diff --git a/GameCode/LvlSelectTabButton.cs b/GameCode/LvlSelectTabButton.cs new file mode 100644 index 0000000..45f6b60 --- /dev/null +++ b/GameCode/LvlSelectTabButton.cs @@ -0,0 +1,51 @@ +using UnityEngine; +using UnityEngine.EventSystems; +using UnityEngine.UI; + +public class LvlSelectTabButton : MonoBehaviour, IPointerEnterHandler, IEventSystemHandler, IPointerExitHandler +{ + public int tabNumber; + + private bool mouseIsOver; + + private Color colorBasic; + + private Image image; + + [SerializeField] + private Color hoverColor; + + [SerializeField] + private Color selectedColor; + + public bool selected; + + private void Start() + { + image = GetComponent(); + colorBasic = image.color; + } + + public void OnPointerEnter(PointerEventData eventData) + { + mouseIsOver = true; + } + + public void OnPointerExit(PointerEventData eventData) + { + mouseIsOver = false; + } + + private void Update() + { + image.color = (mouseIsOver ? hoverColor : colorBasic); + if (selected) + { + image.color = selectedColor; + } + if (Input.GetMouseButtonDown(0)) + { + _ = mouseIsOver; + } + } +} diff --git a/GameCode/ManualAttack.cs b/GameCode/ManualAttack.cs new file mode 100644 index 0000000..f249343 --- /dev/null +++ b/GameCode/ManualAttack.cs @@ -0,0 +1,247 @@ +using System.Collections.Generic; +using Rewired; +using UnityEngine; +using UnityEngine.Events; + +public class ManualAttack : MonoBehaviour +{ + public float spawnAttackHeight; + + public List targetPriorities = new List(); + + public Weapon weapon; + + public float cooldownTime = 1f; + + public Transform transformForAttackDirection; + + public Transform attackMarkerPosition; + + public Transform preferredTargetMarkerPosition; + + public bool autoAttack = true; + + public ParticleSystem particlesOnAttack; + + public bool playOneShotOnAttack; + + public ThronefallAudioManager.AudioOneShot oneshotOnAttack; + + protected float cooldown; + + protected float inputBuffer = -1f; + + protected bool isAttacking; + + protected Hp hpPlayer; + + private Player input; + + protected TaggedObject myTaggedObj; + + private DayNightCycle dayNightCycle; + + private PlayerUpgradeManager upgradeManager; + + private Vector3 lastTargetPos; + + [HideInInspector] + public UnityEvent onAttack = new UnityEvent(); + + protected AudioSet audioSet; + + private AudioSet.ClipArray caStillOnCooldown; + + private AudioSet.ClipArray caCooldownOver; + + protected ThronefallAudioManager audioManager; + + private bool timedActivationPerfectly; + + protected TaggedObject preferredTarget; + + protected TaggedObject target; + + private float perfectTimingDeniedFor; + + public float AttackDamageMultiplyer => upgradeManager.playerDamageMultiplyer; + + public Vector3 LastTargetPos => lastTargetPos; + + public float CooldownPercentage => Mathf.Clamp01(cooldown / cooldownTime); + + public virtual void Start() + { + upgradeManager = PlayerUpgradeManager.instance; + hpPlayer = GetComponentInParent(); + input = ReInput.players.GetPlayer(0); + myTaggedObj = GetComponentInParent(); + dayNightCycle = DayNightCycle.Instance; + audioSet = ThronefallAudioManager.Instance.audioContent; + audioManager = ThronefallAudioManager.Instance; + caStillOnCooldown = audioSet.PlayerCantUseActiveAbility; + caCooldownOver = audioSet.ActiveAbilityCooldownReadyToUse; + } + + public virtual void Update() + { + if (autoAttack && hpPlayer.HpValue > 0f) + { + Tick(); + } + } + + public void Tick() + { + float num = cooldown; + cooldown -= Time.deltaTime; + if (upgradeManager.assassinsTraining && timedActivationPerfectly) + { + cooldown -= Time.deltaTime * UpgradeAssassinsTraining.instance.additionalCooldownSpeed; + } + if (num > 0f && cooldown <= 0f && !autoAttack && DayNightCycle.Instance.CurrentTimestate == DayNightCycle.Timestate.Night) + { + audioManager.PlaySoundAsOneShot(caCooldownOver, 1f, 1f, audioSet.mixGroupFX, 5); + } + isAttacking = false; + HandleAttackUpdate(); + inputBuffer -= Time.deltaTime; + perfectTimingDeniedFor -= Time.deltaTime; + if ((bool)attackMarkerPosition) + { + if (autoAttack || cooldown <= 0f) + { + target = FindAttackTarget(_choosePreferredTargetIfPossible: true); + if (target == null) + { + attackMarkerPosition.gameObject.SetActive(value: false); + } + else + { + if (autoAttack) + { + inputBuffer = 0.2f; + isAttacking = true; + } + attackMarkerPosition.gameObject.SetActive(value: true); + attackMarkerPosition.position = target.transform.position; + } + } + else + { + attackMarkerPosition.gameObject.SetActive(value: false); + } + } + if (input.GetButtonDown("Lock Target")) + { + TaggedObject taggedObject = FindAttackTarget(); + if (preferredTarget == null) + { + preferredTarget = taggedObject; + if ((bool)taggedObject && upgradeManager.godlyCurse && (bool)preferredTargetMarkerPosition) + { + taggedObject.GetComponent().ScaleHp(1f / upgradeManager.godlyCurseDamageMultiplyer); + } + } + else + { + if (upgradeManager.godlyCurse && (bool)preferredTargetMarkerPosition) + { + taggedObject.GetComponent().ScaleHp(upgradeManager.godlyCurseDamageMultiplyer); + } + preferredTarget = null; + } + } + if ((bool)preferredTargetMarkerPosition) + { + if ((bool)preferredTarget) + { + preferredTargetMarkerPosition.gameObject.SetActive(value: true); + preferredTargetMarkerPosition.position = preferredTarget.transform.position; + } + else + { + preferredTargetMarkerPosition.gameObject.SetActive(value: false); + } + } + } + + public void TryToAttack() + { + if (dayNightCycle.CurrentTimestate == DayNightCycle.Timestate.Day && !autoAttack) + { + return; + } + if (upgradeManager.assassinsTraining && perfectTimingDeniedFor <= 0f) + { + timedActivationPerfectly = Mathf.Abs(cooldown) < UpgradeAssassinsTraining.instance.activationWindow; + if (!timedActivationPerfectly) + { + perfectTimingDeniedFor = 2f; + } + } + inputBuffer = 0.2f; + isAttacking = true; + } + + public void HandleAttackUpdate() + { + if (!(inputBuffer >= 0f)) + { + return; + } + if (cooldown > 0f) + { + if (!autoAttack && cooldown > inputBuffer) + { + audioManager.PlaySoundAsOneShot(caStillOnCooldown, 1f, Random.Range(1.8f, 2.2f), audioSet.mixGroupFX, 5); + inputBuffer = -1f; + } + } + else + { + inputBuffer = -1f; + isAttacking = true; + cooldown = cooldownTime; + Attack(); + } + } + + public virtual void Attack() + { + if ((bool)particlesOnAttack) + { + particlesOnAttack.Play(); + } + if (playOneShotOnAttack) + { + ThronefallAudioManager.Oneshot(oneshotOnAttack); + } + TaggedObject taggedObject = FindAttackTarget(_choosePreferredTargetIfPossible: true); + Hp hp = null; + if ((bool)taggedObject) + { + hp = taggedObject.Hp; + lastTargetPos = taggedObject.transform.position; + weapon.Attack(base.transform.position + spawnAttackHeight * Vector3.up, hp, transformForAttackDirection.forward, myTaggedObj, AttackDamageMultiplyer); + onAttack.Invoke(); + } + } + + protected TaggedObject FindAttackTarget(bool _choosePreferredTargetIfPossible = false) + { + if (_choosePreferredTargetIfPossible && (bool)preferredTarget && TagManager.instance.MeasureDistanceToTaggedObject(preferredTarget, base.transform.position) <= targetPriorities[0].range) + { + return preferredTarget; + } + for (int i = 0; i < targetPriorities.Count; i++) + { + TaggedObject taggedObject = targetPriorities[i].FindClosestTaggedObject(base.transform.position); + if (taggedObject != null) + { + return taggedObject; + } + } + return null; + } +} diff --git a/GameCode/MaterialFlasherFX.cs b/GameCode/MaterialFlasherFX.cs new file mode 100644 index 0000000..ed49ef1 --- /dev/null +++ b/GameCode/MaterialFlasherFX.cs @@ -0,0 +1,77 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +public class MaterialFlasherFX : MonoBehaviour +{ + public class RendererMaterialPair + { + public Renderer renderer; + + public Material originalMaterial; + + public RendererMaterialPair(Renderer targetRenderer) + { + renderer = targetRenderer; + originalMaterial = renderer.sharedMaterial; + } + } + + public List targetRenderers; + + public Material flashMaterial; + + public Material specialFlashMaterial; + + public Material unitSelectedMaterial; + + private bool unitSelected; + + private List targetRendererMaterialPairs = new List(); + + public void SetSelected(bool _selected) + { + unitSelected = _selected; + foreach (RendererMaterialPair targetRendererMaterialPair in targetRendererMaterialPairs) + { + targetRendererMaterialPair.renderer.sharedMaterial = (unitSelected ? unitSelectedMaterial : targetRendererMaterialPair.originalMaterial); + } + } + + private void Start() + { + foreach (Renderer targetRenderer in targetRenderers) + { + if (!(targetRenderer == null)) + { + targetRendererMaterialPairs.Add(new RendererMaterialPair(targetRenderer)); + } + } + } + + private IEnumerator FlashAnimation(float flashTime, Material mat) + { + foreach (RendererMaterialPair targetRendererMaterialPair in targetRendererMaterialPairs) + { + targetRendererMaterialPair.renderer.sharedMaterial = mat; + } + yield return new WaitForSeconds(flashTime); + foreach (RendererMaterialPair targetRendererMaterialPair2 in targetRendererMaterialPairs) + { + targetRendererMaterialPair2.renderer.sharedMaterial = (unitSelected ? unitSelectedMaterial : targetRendererMaterialPair2.originalMaterial); + } + } + + public void TriggerFlash(bool special, float flashTime = 0.25f) + { + StopAllCoroutines(); + if (special) + { + StartCoroutine(FlashAnimation(flashTime, specialFlashMaterial)); + } + else + { + StartCoroutine(FlashAnimation(flashTime, flashMaterial)); + } + } +} diff --git a/GameCode/MetaLevel.cs b/GameCode/MetaLevel.cs new file mode 100644 index 0000000..985a7d4 --- /dev/null +++ b/GameCode/MetaLevel.cs @@ -0,0 +1,9 @@ +using System; + +[Serializable] +public class MetaLevel +{ + public int requiredXp; + + public Equippable reward; +} diff --git a/GameCode/MillRotor.cs b/GameCode/MillRotor.cs new file mode 100644 index 0000000..b2ddb0e --- /dev/null +++ b/GameCode/MillRotor.cs @@ -0,0 +1,44 @@ +using UnityEngine; + +public class MillRotor : MonoBehaviour +{ + public float rotationSpeed = 90f; + + private float acceleration = 10f; + + private float currentSpeed; + + private DayNightCycle daynight; + + private void Start() + { + daynight = DayNightCycle.Instance; + } + + private void Update() + { + if (daynight.CurrentTimestate == DayNightCycle.Timestate.Day) + { + if (currentSpeed < rotationSpeed) + { + currentSpeed += acceleration * Time.deltaTime; + } + if (currentSpeed > rotationSpeed) + { + currentSpeed = rotationSpeed; + } + } + else if (daynight.CurrentTimestate == DayNightCycle.Timestate.Night) + { + if (currentSpeed > 0f) + { + currentSpeed -= acceleration * Time.deltaTime; + } + if (currentSpeed < 0f) + { + currentSpeed = 0f; + } + } + base.transform.Rotate(0f, currentSpeed * Time.deltaTime, 0f, Space.Self); + } +} diff --git a/GameCode/Mill_ImprovedPlow.cs b/GameCode/Mill_ImprovedPlow.cs new file mode 100644 index 0000000..7508fc1 --- /dev/null +++ b/GameCode/Mill_ImprovedPlow.cs @@ -0,0 +1,26 @@ +using UnityEngine; + +public class Mill_ImprovedPlow : MonoBehaviour +{ + [SerializeField] + private BuildSlot buildSlot; + + public Mesh lvl2Mesh; + + public Mesh lvl3Mesh; + + private void OnEnable() + { + buildSlot.upgrades[1].upgradeBranches[0].replacementMesh = lvl2Mesh; + buildSlot.upgrades[2].upgradeBranches[0].replacementMesh = lvl3Mesh; + foreach (BuildSlot.UpgradeBranch upgradeBranch in buildSlot.Upgrades[1].upgradeBranches) + { + upgradeBranch.goldIncomeChange++; + } + foreach (BuildSlot.UpgradeBranch upgradeBranch2 in buildSlot.Upgrades[2].upgradeBranches) + { + upgradeBranch2.goldIncomeChange++; + } + Object.Destroy(base.gameObject); + } +} diff --git a/GameCode/Mill_ImprovementExplosiveTrap.cs b/GameCode/Mill_ImprovementExplosiveTrap.cs new file mode 100644 index 0000000..2b087fd --- /dev/null +++ b/GameCode/Mill_ImprovementExplosiveTrap.cs @@ -0,0 +1,64 @@ +using UnityEngine; + +public class Mill_ImprovementExplosiveTrap : MonoBehaviour, DayNightCycle.IDaytimeSensitive +{ + [SerializeField] + private Weapon weaponLvl1; + + [SerializeField] + private Weapon weaponLvl2; + + [SerializeField] + private Weapon weaponLvl3; + + [SerializeField] + private Hp hpOfBuilding; + + [SerializeField] + private BuildSlot buildSlot; + + public Mesh lvl2Mesh; + + public Mesh lvl3Mesh; + + private void Start() + { + DayNightCycle.Instance.RegisterDaytimeSensitiveObject(this); + } + + public void OnDawn_AfterSunrise() + { + } + + public void OnDawn_BeforeSunrise() + { + } + + public void OnDusk() + { + SetCorrectWeapon(); + } + + private void OnEnable() + { + buildSlot.upgrades[1].upgradeBranches[0].replacementMesh = lvl2Mesh; + buildSlot.upgrades[2].upgradeBranches[0].replacementMesh = lvl3Mesh; + SetCorrectWeapon(); + } + + private void SetCorrectWeapon() + { + if (buildSlot.Level == 1) + { + hpOfBuilding.SpwanAttackOnDeath = weaponLvl1; + } + else if (buildSlot.Level == 2) + { + hpOfBuilding.SpwanAttackOnDeath = weaponLvl2; + } + else if (buildSlot.Level == 3) + { + hpOfBuilding.SpwanAttackOnDeath = weaponLvl3; + } + } +} diff --git a/GameCode/Mill_ImprovementWindSpirits.cs b/GameCode/Mill_ImprovementWindSpirits.cs new file mode 100644 index 0000000..824352e --- /dev/null +++ b/GameCode/Mill_ImprovementWindSpirits.cs @@ -0,0 +1,104 @@ +using System.Collections.Generic; +using UnityEngine; + +public class Mill_ImprovementWindSpirits : MonoBehaviour, DayNightCycle.IDaytimeSensitive +{ + [SerializeField] + private BuildSlot buildSlot; + + [SerializeField] + private float blockIntervalLvl1 = 1f; + + [SerializeField] + private float blockIntervalLvl2 = 0.5f; + + [SerializeField] + private float blockIntervalLvl3 = 0.25f; + + public Mesh lvl2Mesh; + + public Mesh lvl3Mesh; + + private float blockInterval = 1f; + + [SerializeField] + private float range = 30f; + + [SerializeField] + private GameObject fxBlockArrow; + + private float cooldown; + + private TagManager tagManager; + + private List mustHaveTags = new List(); + + private List mayNotHaveTags = new List(); + + private void Start() + { + tagManager = TagManager.instance; + cooldown = Random.value * blockInterval; + mustHaveTags.Add(TagManager.ETag.BlockableEnemyProjectile); + DayNightCycle.Instance.RegisterDaytimeSensitiveObject(this); + } + + private void Update() + { + cooldown -= Time.deltaTime; + while (cooldown <= 0f) + { + BlockAnArrow(); + cooldown += blockInterval; + } + } + + private void BlockAnArrow() + { + TaggedObject taggedObject = tagManager.FindClosestTaggedObjectWithTags(base.transform.position, mustHaveTags, mayNotHaveTags); + if (!(taggedObject == null) && (taggedObject.transform.position - base.transform.position).magnitude < range) + { + if ((bool)fxBlockArrow) + { + Object.Instantiate(fxBlockArrow, taggedObject.transform.position, Quaternion.identity); + } + Object.Destroy(taggedObject.gameObject); + } + } + + private void OnEnable() + { + buildSlot.upgrades[1].upgradeBranches[0].replacementMesh = lvl2Mesh; + buildSlot.upgrades[2].upgradeBranches[0].replacementMesh = lvl3Mesh; + SetCorrectWeapon(); + } + + public void OnDusk() + { + SetCorrectWeapon(); + } + + public void OnDawn_AfterSunrise() + { + } + + public void OnDawn_BeforeSunrise() + { + } + + private void SetCorrectWeapon() + { + if (buildSlot.Level == 1) + { + blockInterval = blockIntervalLvl1; + } + else if (buildSlot.Level == 2) + { + blockInterval = blockIntervalLvl2; + } + else if (buildSlot.Level == 3) + { + blockInterval = blockIntervalLvl3; + } + } +} diff --git a/GameCode/Mill_Improvement_Scarecrows.cs b/GameCode/Mill_Improvement_Scarecrows.cs new file mode 100644 index 0000000..7a7a51e --- /dev/null +++ b/GameCode/Mill_Improvement_Scarecrows.cs @@ -0,0 +1,26 @@ +using UnityEngine; + +public class Mill_Improvement_Scarecrows : MonoBehaviour +{ + [SerializeField] + private BuildSlot buildSlot; + + public Mesh lvl2Mesh; + + public Mesh lvl3Mesh; + + private void OnEnable() + { + buildSlot.upgrades[1].upgradeBranches[0].replacementMesh = lvl2Mesh; + buildSlot.upgrades[2].upgradeBranches[0].replacementMesh = lvl3Mesh; + foreach (BuildSlot item in buildSlot.BuiltSlotsThatRelyOnThisBuilding) + { + Scarecrow[] components = item.GetComponents(); + foreach (Scarecrow scarecrow in components) + { + scarecrow.scareCrow.SetActive(value: true); + item.Upgrades[0].upgradeBranches[0].objectsToActivate.Add(scarecrow.scareCrow); + } + } + } +} diff --git a/GameCode/MineShaft.cs b/GameCode/MineShaft.cs new file mode 100644 index 0000000..6ac6218 --- /dev/null +++ b/GameCode/MineShaft.cs @@ -0,0 +1,141 @@ +using System.Collections.Generic; +using UnityEngine; + +public class MineShaft : IncomeModifyer +{ + public int incomeReductionPerTurn = 1; + + public int minimumIncome = 1; + + private bool firstNightPassed; + + private PlayerManager playerManager; + + public Transform mineEntrance; + + [SerializeField] + private float mineEnterDistance = 3f; + + [SerializeField] + private float mineEnterAngleDotProd = 0.8f; + + [SerializeField] + private float playerEnterTimerMax = 0.75f; + + [SerializeField] + private float cooldownAfterTeleport = 1f; + + private float playerEnterTimer; + + public static List allMineShafts = new List(); + + private BuildSlot myBuildSlot; + + private float cooldown; + + public BuildSlot MyBuildSlot => myBuildSlot; + + public void SetCooldown(float _cooldown) + { + cooldown = _cooldown; + } + + private void Start() + { + playerManager = PlayerManager.Instance; + myBuildSlot = GetComponent(); + playerEnterTimer = playerEnterTimerMax; + if (!allMineShafts.Contains(this)) + { + allMineShafts.Add(this); + } + for (int num = allMineShafts.Count - 1; num >= 0; num--) + { + if (allMineShafts[num] == null) + { + allMineShafts.RemoveAt(num); + } + } + SortAllMineShafts(); + } + + private void SortAllMineShafts() + { + allMineShafts.Sort(delegate(MineShaft mineShaft1, MineShaft mineShaft2) + { + Vector3 position = mineShaft1.gameObject.transform.position; + Vector3 position2 = mineShaft2.gameObject.transform.position; + int num = position.z.CompareTo(position2.z); + if (num != 0) + { + return num; + } + int num2 = position.x.CompareTo(position2.x); + return (num2 != 0) ? num2 : position.y.CompareTo(position2.y); + }); + } + + public static MineShaft FindNextMineShaftAfter(int _i) + { + for (int num = (_i + 1) % allMineShafts.Count; num != _i; num = (num + 1) % allMineShafts.Count) + { + MineShaft mineShaft = allMineShafts[num]; + if (mineShaft.MyBuildSlot.Level > 0 && mineShaft.buildingInteractor.buildingHP.TaggedObj.Tags.Contains(TagManager.ETag.AUTO_Alive)) + { + return mineShaft; + } + } + return null; + } + + private void Update() + { + cooldown -= Time.deltaTime; + if (MyBuildSlot.Level <= 0 || !buildingInteractor.buildingHP.TaggedObj.Tags.Contains(TagManager.ETag.AUTO_Alive) || cooldown > 0f) + { + return; + } + bool flag = false; + PlayerMovement[] registeredPlayers = playerManager.RegisteredPlayers; + foreach (PlayerMovement playerMovement in registeredPlayers) + { + if (!((mineEntrance.position - playerMovement.transform.position).magnitude < mineEnterDistance) || !(Vector3.Dot(mineEntrance.localToWorldMatrix.MultiplyVector(new Vector3(0f, 0f, 1f)).normalized, playerMovement.Velocity.normalized) > mineEnterAngleDotProd)) + { + continue; + } + playerEnterTimer -= Time.deltaTime; + flag = true; + if (playerEnterTimer <= 0f) + { + MineShaft mineShaft = FindNextMineShaftAfter(allMineShafts.IndexOf(this)); + if ((bool)mineShaft) + { + Vector3 position = mineShaft.transform.position; + position += mineShaft.mineEntrance.localToWorldMatrix.MultiplyVector(new Vector3(0f, 0f, -1f)); + playerMovement.TeleportTo(position); + mineShaft.SetCooldown(cooldownAfterTeleport); + SetCooldown(cooldownAfterTeleport); + } + } + } + if (!flag) + { + playerEnterTimer = playerEnterTimerMax; + } + } + + public override void OnDawn() + { + if (myBuildSlot.Level > 0 && !buildingInteractor.KnockedOutTonight) + { + if (!firstNightPassed) + { + firstNightPassed = true; + } + else + { + myBuildSlot.GoldIncome = Mathf.Max(myBuildSlot.GoldIncome - incomeReductionPerTurn, minimumIncome); + } + } + } +} diff --git a/GameCode/MusicManager.cs b/GameCode/MusicManager.cs new file mode 100644 index 0000000..9b779bb --- /dev/null +++ b/GameCode/MusicManager.cs @@ -0,0 +1,163 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +public class MusicManager : MonoBehaviour +{ + [Serializable] + public class OverrideVolume + { + public AudioClip audioClip; + + [Range(0f, 1f)] + public float volume; + + public OverrideVolume(AudioClip clip, float volume) + { + audioClip = clip; + this.volume = volume; + } + } + + public static MusicManager instance; + + [SerializeField] + private AudioSource audioSource; + + private AudioClip currentMusic; + + private Coroutine fadeCoroutine; + + private float currentVolume; + + [SerializeField] + private AudioClip[] resumeableMusicClips; + + private Dictionary resumeableMusicPlaybackPositions = new Dictionary(); + + [SerializeField] + private List overrideVolumes = new List(); + + private float CurrentVolume + { + get + { + return currentVolume; + } + set + { + float num = value; + currentVolume = value; + OverrideVolume overrideVolume = overrideVolumes.Find((OverrideVolume o) => o.audioClip == currentMusic); + if (overrideVolume != null) + { + num *= overrideVolume.volume; + } + audioSource.volume = Mathf.Pow(num, 2f); + } + } + + private void Awake() + { + if (instance != null) + { + UnityEngine.Object.Destroy(base.gameObject); + return; + } + instance = this; + CurrentVolume = 0f; + AudioClip[] array = resumeableMusicClips; + foreach (AudioClip key in array) + { + resumeableMusicPlaybackPositions.Add(key, 0f); + } + } + + public void PlayMusic(AudioClip music, float fadeDuration = 4f) + { + if (currentMusic == music) + { + return; + } + if (music == null && currentMusic != null) + { + StartCoroutine(FadeOutAndStop(fadeDuration)); + return; + } + if (fadeCoroutine != null) + { + StopCoroutine(fadeCoroutine); + } + fadeCoroutine = StartCoroutine(FadeOutChangeMusicFadeIn(music, fadeDuration)); + } + + private IEnumerator FadeOutChangeMusicFadeIn(AudioClip newMusic, float fadeDuration) + { + if (currentMusic != null) + { + if (resumeableMusicPlaybackPositions.ContainsKey(currentMusic)) + { + resumeableMusicPlaybackPositions[currentMusic] = audioSource.time; + } + yield return StartCoroutine(FadeOut(fadeDuration)); + } + CurrentVolume = 0f; + audioSource.clip = newMusic; + currentMusic = newMusic; + if (resumeableMusicPlaybackPositions.ContainsKey(newMusic)) + { + audioSource.time = resumeableMusicPlaybackPositions[newMusic]; + } + else + { + audioSource.time = 0f; + } + audioSource.Play(); + yield return null; + yield return StartCoroutine(FadeIn(fadeDuration)); + } + + private IEnumerator FadeOutAndStop(float fadeDuration) + { + yield return StartCoroutine(FadeOut(fadeDuration)); + if (currentMusic != null && resumeableMusicPlaybackPositions.ContainsKey(currentMusic)) + { + resumeableMusicPlaybackPositions[currentMusic] = audioSource.time; + } + audioSource.Stop(); + currentMusic = null; + } + + private IEnumerator FadeOut(float fadeDuration) + { + if (fadeDuration <= 0f) + { + CurrentVolume = 0f; + yield break; + } + float fadeSpeed = 1f / fadeDuration; + while (CurrentVolume > 0f) + { + CurrentVolume -= fadeSpeed * Time.unscaledDeltaTime; + yield return null; + } + CurrentVolume = 0f; + } + + private IEnumerator FadeIn(float fadeDuration) + { + if (fadeDuration <= 0f) + { + CurrentVolume = 1f; + yield break; + } + float fadeSpeed = 1f / fadeDuration; + while (CurrentVolume < 1f) + { + CurrentVolume += fadeSpeed * Time.unscaledDeltaTime; + yield return null; + } + CurrentVolume = 1f; + } +} diff --git a/GameCode/NightCall.cs b/GameCode/NightCall.cs new file mode 100644 index 0000000..2db1c18 --- /dev/null +++ b/GameCode/NightCall.cs @@ -0,0 +1,140 @@ +using MoreMountains.Feedbacks; +using MPUIKIT; +using Rewired; +using TMPro; +using UnityEngine; + +public class NightCall : MonoBehaviour, DayNightCycle.IDaytimeSensitive +{ + public static NightCall instance; + + public float nightCallTime = 1f; + + public MPImage targetGraphic; + + public MPImage targetFill; + + public MPImage background; + + public TextMeshProUGUI nightCallCueText; + + public TextMeshProUGUI nightCallTimeText; + + public MMF_Player fullFeedback; + + public AnimationCurve textCueScaleCurve; + + public RectTransform scaleParent; + + public AudioSource nightCallAudio; + + private Player input; + + private bool active = true; + + private float currentFill; + + private PlayerInteraction player; + + private Color defaultBackgroundColor; + + private float nightCallTargetVolume; + + private void Awake() + { + instance = this; + } + + private void Start() + { + input = ReInput.players.GetPlayer(0); + DayNightCycle.Instance.RegisterDaytimeSensitiveObject(this); + targetFill.transform.localScale = Vector3.zero; + player = PlayerInteraction.instance; + defaultBackgroundColor = background.color; + nightCallTargetVolume = nightCallAudio.volume; + } + + private void Update() + { + UpdateFill(); + } + + public void UpdateFill() + { + if (active) + { + if (SettingsManager.Instance.UseLargeInGameUI) + { + scaleParent.localScale = Vector3.one * 1.5f; + } + else + { + scaleParent.localScale = Vector3.one; + } + if (input.GetButtonDown("Call Night") && player.IsFreeToCallNight) + { + nightCallAudio.Stop(); + nightCallAudio.PlayOneShot(ThronefallAudioManager.Instance.audioContent.NightCallStart, 0.45f); + } + if (input.GetButton("Call Night") && player.IsFreeToCallNight) + { + currentFill += Time.deltaTime * (1f / nightCallTime); + } + else + { + currentFill -= Time.deltaTime * 2f * (1f / nightCallTime); + } + if (currentFill >= 1f) + { + nightCallAudio.PlayOneShot(ThronefallAudioManager.Instance.audioContent.NightCallComplete, 0.8f); + DayNightCycle.Instance.SwitchToNight(); + fullFeedback.PlayFeedbacks(); + active = false; + } + if (currentFill > 0f) + { + nightCallCueText.gameObject.SetActive(value: true); + nightCallTimeText.text = (nightCallTime * (1f - currentFill)).ToString("F1") + "s"; + nightCallCueText.transform.localScale = Vector3.one * textCueScaleCurve.Evaluate(Mathf.InverseLerp(0f, 0.15f, currentFill)); + nightCallAudio.volume = Mathf.Lerp(0f, nightCallTargetVolume, Mathf.InverseLerp(0f, 0.3f, currentFill)); + } + else + { + nightCallCueText.gameObject.SetActive(value: false); + nightCallCueText.transform.localScale = Vector3.one; + } + defaultBackgroundColor.a = Mathf.InverseLerp(0f, 0.4f, currentFill); + background.color = defaultBackgroundColor; + currentFill = Mathf.Clamp01(currentFill); + targetGraphic.fillAmount = currentFill; + } + else if (currentFill > 0f) + { + currentFill -= Time.deltaTime * 2f; + defaultBackgroundColor.a = Mathf.InverseLerp(0f, 0.4f, currentFill); + background.color = defaultBackgroundColor; + } + } + + public void OnDawn_AfterSunrise() + { + targetFill.transform.localScale = Vector3.zero; + targetGraphic.transform.localScale = Vector3.one; + targetGraphic.fillAmount = 0f; + nightCallCueText.gameObject.SetActive(value: false); + nightCallCueText.transform.localScale = Vector3.one; + defaultBackgroundColor.a = 0f; + background.color = defaultBackgroundColor; + currentFill = 0f; + active = true; + } + + public void OnDawn_BeforeSunrise() + { + } + + public void OnDusk() + { + } +} diff --git a/GameCode/NightLight.cs b/GameCode/NightLight.cs new file mode 100644 index 0000000..affc9b0 --- /dev/null +++ b/GameCode/NightLight.cs @@ -0,0 +1,98 @@ +using System.Collections; +using UnityEngine; + +[RequireComponent(typeof(Light))] +public class NightLight : MonoBehaviour, DayNightCycle.IDaytimeSensitive +{ + public float targetIntensity = 0.75f; + + public float intensityFlickerRange = 0.15f; + + public float distanceFlickerRange = 5f; + + public float flickerSpeed = 1f; + + public float fadeInTime = 2.5f; + + public float fadeOutTime = 1f; + + public ParticleSystem flames; + + private float transitionTime; + + private float targetRange; + + private Light targetLight; + + private bool fullyFadedIn; + + private float currentIntensity => targetIntensity + Mathf.Lerp(0f - intensityFlickerRange, intensityFlickerRange, Mathf.PerlinNoise(Time.time * flickerSpeed, Time.time * flickerSpeed)); + + private float currentRange => targetRange + Mathf.Lerp(0f - distanceFlickerRange, distanceFlickerRange, Mathf.PerlinNoise(Time.time * flickerSpeed, Time.time * flickerSpeed)); + + private void Start() + { + transitionTime = DayNightCycle.Instance.sunriseTime; + DayNightCycle.Instance.RegisterDaytimeSensitiveObject(this); + targetLight = GetComponent(); + targetLight.intensity = 0f; + targetRange = targetLight.range; + base.gameObject.SetActive(value: false); + } + + private void Update() + { + if (fullyFadedIn) + { + targetLight.intensity = currentIntensity; + } + targetLight.range = currentRange; + } + + public void OnDawn_AfterSunrise() + { + } + + public void OnDawn_BeforeSunrise() + { + StopAllCoroutines(); + StartCoroutine(FadeLightOut()); + } + + public void OnDusk() + { + base.gameObject.SetActive(value: true); + StopAllCoroutines(); + StartCoroutine(FadeLightIn()); + } + + private IEnumerator FadeLightIn() + { + fullyFadedIn = false; + float clock = 0f; + yield return new WaitForSeconds(transitionTime * 0.1f); + flames.Play(); + while (clock < fadeInTime) + { + clock += Time.deltaTime; + targetLight.intensity = currentIntensity * Mathf.InverseLerp(0f, fadeInTime, clock); + yield return null; + } + targetLight.intensity = targetIntensity; + fullyFadedIn = true; + } + + private IEnumerator FadeLightOut() + { + float clock = 0f; + flames.Stop(); + while (clock < fadeOutTime) + { + clock += Time.deltaTime; + targetLight.intensity = currentIntensity * Mathf.InverseLerp(fadeOutTime, 0f, clock); + yield return null; + } + targetLight.intensity = 0f; + base.gameObject.SetActive(value: false); + } +} diff --git a/GameCode/Nighthorn.cs b/GameCode/Nighthorn.cs new file mode 100644 index 0000000..f89fcd5 --- /dev/null +++ b/GameCode/Nighthorn.cs @@ -0,0 +1,168 @@ +using MoreMountains.Feedbacks; +using UnityEngine; + +public class Nighthorn : InteractorBase, DayNightCycle.IDaytimeSensitive +{ + public static Nighthorn instance; + + public GameObject nightCue; + + public GameObject harvestCue; + + public string autoCollectGoldTooltip; + + public string startNightTooltip; + + public string startPreFinalNightTooltip; + + public string startFinalNightTooltip; + + public MMF_Player onBlowFeedback; + + private TutorialManager tutorialManager; + + public int CoinCountToBeHarvested + { + get + { + int num = 0; + foreach (BuildingInteractor playerBuildingInteractor in TagManager.instance.playerBuildingInteractors) + { + if ((bool)playerBuildingInteractor.coinSpawner) + { + num += playerBuildingInteractor.coinSpawner.CoinsLeft; + } + if (playerBuildingInteractor.canBeHarvested) + { + num += playerBuildingInteractor.GoldIncome; + } + } + return num; + } + } + + public bool AllCoinsHarvested + { + get + { + bool result = true; + foreach (BuildingInteractor playerBuildingInteractor in TagManager.instance.playerBuildingInteractors) + { + if (playerBuildingInteractor.canBeHarvested) + { + result = false; + break; + } + } + foreach (Coin freeCoin in TagManager.instance.freeCoins) + { + if (freeCoin.IsFree) + { + return false; + } + } + return result; + } + } + + private void Awake() + { + instance = this; + } + + public override string ReturnTooltip() + { + if (!AllCoinsHarvested) + { + return autoCollectGoldTooltip; + } + if (EnemySpawner.instance.PreFinalWaveComingUp) + { + return startPreFinalNightTooltip; + } + if (EnemySpawner.instance.FinalWaveComingUp) + { + return startFinalNightTooltip; + } + return startNightTooltip; + } + + private void Start() + { + DayNightCycle.Instance.RegisterDaytimeSensitiveObject(this); + tutorialManager = TutorialManager.instance; + } + + public override void InteractionBegin(PlayerInteraction player) + { + if ((bool)tutorialManager && !TutorialManager.AllowStartingTheNight) + { + return; + } + if (AllCoinsHarvested) + { + onBlowFeedback.PlayFeedbacks(); + DayNightCycle.Instance.SwitchToNight(); + return; + } + foreach (BuildingInteractor playerBuildingInteractor in TagManager.instance.playerBuildingInteractors) + { + playerBuildingInteractor.Harvest(player); + } + foreach (Coin freeCoin in TagManager.instance.freeCoins) + { + if (freeCoin.IsFree) + { + freeCoin.SetTarget(player); + } + } + ActivateAndRefreshCues(); + } + + public void OnDawn_AfterSunrise() + { + base.gameObject.SetActive(value: true); + } + + public void OnDusk() + { + base.gameObject.SetActive(value: false); + DeactivateCues(); + } + + public override void Focus(PlayerInteraction player) + { + ActivateAndRefreshCues(); + } + + public override void Unfocus(PlayerInteraction player) + { + DeactivateCues(); + EnemySpawner.instance.EnemySpawnersHornUnFocussed(); + } + + public void OnDawn_BeforeSunrise() + { + } + + public void ActivateAndRefreshCues() + { + if (AllCoinsHarvested) + { + nightCue.SetActive(value: true); + harvestCue.SetActive(value: false); + EnemySpawner.instance.EnemySpawnersHornFocussed(); + } + else + { + nightCue.SetActive(value: false); + harvestCue.SetActive(value: true); + } + } + + public void DeactivateCues() + { + nightCue.SetActive(value: false); + harvestCue.SetActive(value: false); + } +} diff --git a/GameCode/NightscoreUI.cs b/GameCode/NightscoreUI.cs new file mode 100644 index 0000000..7150c48 --- /dev/null +++ b/GameCode/NightscoreUI.cs @@ -0,0 +1,295 @@ +using System.Collections; +using I2.Loc; +using MPUIKIT; +using TMPro; +using UnityEngine; + +public class NightscoreUI : MonoBehaviour +{ + public GameObject nightScorePanel; + + public TextMeshProUGUI baseScore; + + public TextMeshProUGUI timeBonus; + + public TextMeshProUGUI protectionPercentage; + + public TextMeshProUGUI protectionScore; + + public TextMeshProUGUI overallScore; + + public AudioSource pointSFXSource; + + [Header("ANIMATION")] + public MPImage backgroundImage; + + public RectTransform content; + + public RectTransform nightSurviveText; + + public RectTransform nightSurviveNumber; + + public RectTransform timeText; + + public RectTransform timeNumber; + + public RectTransform protectionText; + + public RectTransform protectionNumber; + + public RectTransform overallScoreBG; + + public RectTransform overallScoreNumber; + + public AnimationCurve popCurve; + + public AnimationCurve expandCurve; + + public AnimationCurve bumpCurve; + + public AnimationCurve simpleQuad; + + public static NightscoreUI instance; + + private float initialWaitTime = 3f; + + private float completeWaitTime = 3f; + + private float buildUpSFXVol = 0.8f; + + private float clock; + + private bool shown; + + private void Awake() + { + instance = this; + } + + private void Start() + { + nightScorePanel.SetActive(value: false); + ScoreManager.Instance.OnNightScoreAdd.AddListener(ShowNightScore); + UIFrameManager.instance.onFrameOpen.AddListener(StopPointFillSoundOnPause); + } + + private void StopPointFillSoundOnPause() + { + pointSFXSource.Stop(); + } + + public void ShowNightScore(int _baseScore, int _timeBonus, float _protectionPercentage, int _protectionBonus) + { + if (EnemySpawner.instance.Wavenumber < EnemySpawner.instance.waves.Count - 1) + { + shown = true; + StopAllCoroutines(); + clock = 0f; + StartCoroutine(PlayPopUpAnimation(_baseScore, _timeBonus, _protectionPercentage, _protectionBonus)); + } + } + + public void HideNightScore() + { + shown = false; + pointSFXSource.Stop(); + StopAllCoroutines(); + StartCoroutine(PlayHideAnimation()); + } + + private IEnumerator PlayPopUpAnimation(int basescore, int timebonus, float protectionpercent, int protectionbonus) + { + nightScorePanel.SetActive(value: true); + Vector2 contentSizeDelta = content.sizeDelta; + int currentScore = ScoreManager.Instance.CurrentScore - basescore - timebonus - protectionbonus; + int nextScore = currentScore; + baseScore.text = "+" + basescore; + timeBonus.text = "+" + timebonus; + protectionPercentage.text = LocalizationManager.GetTranslation("Menu/Realm") + " " + Mathf.RoundToInt(protectionpercent * 100f) + "% " + LocalizationManager.GetTranslation("Menu/Protected"); + protectionScore.text = "+" + protectionbonus; + overallScore.text = currentScore.ToString(); + contentSizeDelta.y = 0f; + content.sizeDelta = contentSizeDelta; + nightSurviveText.localScale = Vector3.zero; + nightSurviveNumber.localScale = Vector3.zero; + timeText.localScale = Vector3.zero; + timeNumber.localScale = Vector3.zero; + protectionText.localScale = Vector3.zero; + protectionNumber.localScale = Vector3.zero; + overallScoreBG.localScale = Vector3.zero; + overallScoreNumber.localScale = Vector3.zero; + yield return new WaitForSeconds(initialWaitTime); + float animTime2 = 0.5f; + float timer2 = 0f; + while (timer2 < animTime2) + { + timer2 += Time.deltaTime; + overallScoreBG.localScale = Vector3.one * popCurve.Evaluate(Mathf.InverseLerp(0f, animTime2, timer2)); + overallScoreNumber.localScale = Vector3.one * popCurve.Evaluate(Mathf.InverseLerp(0f, animTime2, timer2)); + yield return null; + } + overallScoreBG.localScale = Vector3.one; + overallScoreNumber.localScale = Vector3.one; + yield return new WaitForSeconds(0.25f); + pointSFXSource.PlayOneShot(ThronefallAudioManager.Instance.audioContent.PointScreenBuildB, buildUpSFXVol); + animTime2 = 0.5f; + timer2 = 0f; + while (timer2 < animTime2) + { + timer2 += Time.deltaTime; + content.sizeDelta = contentSizeDelta + Vector2.up * 55f * expandCurve.Evaluate(Mathf.InverseLerp(0f, animTime2, timer2)); + yield return null; + } + content.sizeDelta = contentSizeDelta + Vector2.up * 55f; + contentSizeDelta = content.sizeDelta; + pointSFXSource.PlayOneShot(ThronefallAudioManager.Instance.audioContent.PointScreenBuildC, buildUpSFXVol); + animTime2 = 0.5f; + timer2 = 0f; + while (timer2 < animTime2) + { + timer2 += Time.deltaTime; + nightSurviveText.localScale = Vector3.one * popCurve.Evaluate(Mathf.InverseLerp(0f, animTime2, timer2)); + nightSurviveNumber.localScale = Vector3.one * popCurve.Evaluate(Mathf.InverseLerp(0f, animTime2, timer2)); + yield return null; + } + nightSurviveText.localScale = Vector3.one; + nightSurviveNumber.localScale = Vector3.one; + pointSFXSource.PlayOneShot(ThronefallAudioManager.Instance.audioContent.PointScreenBuildB, buildUpSFXVol); + animTime2 = 0.5f; + timer2 = 0f; + while (timer2 < animTime2) + { + timer2 += Time.deltaTime; + content.sizeDelta = contentSizeDelta + Vector2.up * 30f * expandCurve.Evaluate(Mathf.InverseLerp(0f, animTime2, timer2)); + yield return null; + } + content.sizeDelta = contentSizeDelta + Vector2.up * 30f; + contentSizeDelta = content.sizeDelta; + pointSFXSource.PlayOneShot(ThronefallAudioManager.Instance.audioContent.PointScreenBuildC, buildUpSFXVol); + animTime2 = 0.5f; + timer2 = 0f; + while (timer2 < animTime2) + { + timer2 += Time.deltaTime; + protectionText.localScale = Vector3.one * popCurve.Evaluate(Mathf.InverseLerp(0f, animTime2, timer2)); + protectionNumber.localScale = Vector3.one * popCurve.Evaluate(Mathf.InverseLerp(0f, animTime2, timer2)); + yield return null; + } + protectionText.localScale = Vector3.one; + protectionNumber.localScale = Vector3.one; + pointSFXSource.PlayOneShot(ThronefallAudioManager.Instance.audioContent.PointScreenBuildB, buildUpSFXVol); + animTime2 = 0.5f; + timer2 = 0f; + while (timer2 < animTime2) + { + timer2 += Time.deltaTime; + content.sizeDelta = contentSizeDelta + Vector2.up * 30f * expandCurve.Evaluate(Mathf.InverseLerp(0f, animTime2, timer2)); + yield return null; + } + content.sizeDelta = contentSizeDelta + Vector2.up * 30f; + _ = content.sizeDelta; + pointSFXSource.PlayOneShot(ThronefallAudioManager.Instance.audioContent.PointScreenBuildC, buildUpSFXVol); + animTime2 = 0.5f; + timer2 = 0f; + while (timer2 < animTime2) + { + timer2 += Time.deltaTime; + timeText.localScale = Vector3.one * popCurve.Evaluate(Mathf.InverseLerp(0f, animTime2, timer2)); + timeNumber.localScale = Vector3.one * popCurve.Evaluate(Mathf.InverseLerp(0f, animTime2, timer2)); + yield return null; + } + timeText.localScale = Vector3.one; + timeNumber.localScale = Vector3.one; + pointSFXSource.Play(); + animTime2 = 1.5f; + timer2 = 0f; + nextScore += basescore + protectionbonus + timebonus; + while (timer2 < animTime2) + { + timer2 += Time.deltaTime; + overallScore.text = Mathf.RoundToInt(Mathf.Lerp(currentScore, nextScore, Mathf.InverseLerp(0f, animTime2, timer2))).ToString(); + yield return null; + } + currentScore = nextScore; + overallScore.text = currentScore.ToString(); + pointSFXSource.Stop(); + pointSFXSource.PlayOneShot(ThronefallAudioManager.Instance.audioContent.PointLockInMinor); + animTime2 = 0.5f; + timer2 = 0f; + while (timer2 < animTime2) + { + timer2 += Time.deltaTime; + overallScoreBG.localScale = Vector3.one * bumpCurve.Evaluate(Mathf.InverseLerp(0f, animTime2, timer2)); + yield return null; + } + overallScoreBG.localScale = Vector3.one; + yield return new WaitForSeconds(completeWaitTime); + HideNightScore(); + } + + private IEnumerator PlayHideAnimation() + { + pointSFXSource.PlayOneShot(ThronefallAudioManager.Instance.audioContent.PointScreenBuildB, buildUpSFXVol); + Vector2 contentSizeDelta3 = content.sizeDelta; + nightSurviveText.localScale = Vector3.one; + nightSurviveNumber.localScale = Vector3.one; + timeText.localScale = Vector3.one; + timeNumber.localScale = Vector3.one; + protectionText.localScale = Vector3.one; + protectionNumber.localScale = Vector3.one; + overallScoreBG.localScale = Vector3.one; + overallScoreNumber.localScale = Vector3.one; + timeText.localScale = Vector3.zero; + timeNumber.localScale = Vector3.zero; + float animTime4 = 0.4f; + float timer4 = 0f; + while (timer4 < animTime4) + { + timer4 += Time.deltaTime; + content.sizeDelta = contentSizeDelta3 - Vector2.up * 30f * expandCurve.Evaluate(Mathf.InverseLerp(0f, animTime4, timer4)); + yield return null; + } + content.sizeDelta = contentSizeDelta3 - Vector2.up * 30f; + contentSizeDelta3 = content.sizeDelta; + protectionText.localScale = Vector3.zero; + protectionNumber.localScale = Vector3.zero; + animTime4 = 0.4f; + timer4 = 0f; + while (timer4 < animTime4) + { + timer4 += Time.deltaTime; + content.sizeDelta = contentSizeDelta3 - Vector2.up * 30f * expandCurve.Evaluate(Mathf.InverseLerp(0f, animTime4, timer4)); + yield return null; + } + content.sizeDelta = contentSizeDelta3 - Vector2.up * 30f; + contentSizeDelta3 = content.sizeDelta; + nightSurviveText.localScale = Vector3.zero; + nightSurviveNumber.localScale = Vector3.zero; + animTime4 = 0.4f; + timer4 = 0f; + while (timer4 < animTime4) + { + timer4 += Time.deltaTime; + if (Mathf.InverseLerp(0f, animTime4, timer4) > 0.425f) + { + backgroundImage.enabled = false; + } + content.sizeDelta = contentSizeDelta3 - Vector2.up * 55f * expandCurve.Evaluate(Mathf.InverseLerp(0f, animTime4, timer4)); + yield return null; + } + content.sizeDelta = contentSizeDelta3 - Vector2.up * 55f; + backgroundImage.enabled = true; + animTime4 = 0.2f; + timer4 = 0f; + while (timer4 < animTime4) + { + timer4 += Time.deltaTime; + overallScoreNumber.localScale = Vector3.one * simpleQuad.Evaluate(Mathf.InverseLerp(animTime4, 0f, timer4)); + overallScoreBG.localScale = Vector3.one * simpleQuad.Evaluate(Mathf.InverseLerp(animTime4, 0f, timer4)); + yield return null; + } + overallScoreNumber.localScale = Vector3.zero; + overallScoreBG.localScale = Vector2.zero; + nightScorePanel.SetActive(value: false); + } +} diff --git a/GameCode/OnDamageFeedbackHandler.cs b/GameCode/OnDamageFeedbackHandler.cs new file mode 100644 index 0000000..82aed25 --- /dev/null +++ b/GameCode/OnDamageFeedbackHandler.cs @@ -0,0 +1,28 @@ +using UnityEngine; + +public class OnDamageFeedbackHandler : MonoBehaviour +{ + public Hp target; + + public MaterialFlasherFX flasher; + + public GameObject onDmgByPlayerFX; + + private void Start() + { + target.OnReceiveDamage.AddListener(TakeDamage); + } + + private void TakeDamage(bool causedByPlayer) + { + if (causedByPlayer) + { + Object.Instantiate(onDmgByPlayerFX, target.transform.position + Vector3.up * target.hitFeedbackHeight, onDmgByPlayerFX.transform.rotation); + flasher.TriggerFlash(special: true); + } + else + { + flasher.TriggerFlash(special: false); + } + } +} diff --git a/GameCode/OneShotAnimationBase.cs b/GameCode/OneShotAnimationBase.cs new file mode 100644 index 0000000..7967415 --- /dev/null +++ b/GameCode/OneShotAnimationBase.cs @@ -0,0 +1,6 @@ +using UnityEngine; + +public abstract class OneShotAnimationBase : MonoBehaviour +{ + public abstract void Trigger(); +} diff --git a/GameCode/PathMesher.cs b/GameCode/PathMesher.cs new file mode 100644 index 0000000..244ee39 --- /dev/null +++ b/GameCode/PathMesher.cs @@ -0,0 +1,339 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +[RequireComponent(typeof(MeshRenderer))] +[RequireComponent(typeof(MeshFilter))] +[ExecuteInEditMode] +public class PathMesher : MonoBehaviour +{ + public enum UnwrapMode + { + XZWorldSpace, + River + } + + [Serializable] + public class PathPoint + { + public Vector3 position; + + public float width; + + public PathPoint(Vector3 _position, float _width) + { + position = _position; + width = _width; + } + } + + private MeshFilter meshFilter; + + private MeshCollider meshCollider; + + public int subdivisions = 3; + + public float vertDistance = 0.2f; + + public int endCapSubdivisions = 3; + + public float widthWhobble = 0.5f; + + public float positionWhobble = 0.5f; + + public UnwrapMode uvUnwrapMode; + + public float uvScale = 0.01f; + + public bool topNormalsAlwaysFaceDirectlyUp; + + public Vector3 extrudeDownOffset; + + public bool vertical; + + public bool loop; + + public bool flipNormals; + + private List transformsRemember = new List(); + + private List pathPoints = new List(); + + public void UpdateMesh() + { + pathPoints.Clear(); + for (int i = 0; i < base.transform.childCount; i++) + { + Transform child = base.transform.GetChild(i); + pathPoints.Add(new PathPoint(child.localPosition, child.localScale.x)); + } + if (pathPoints.Count < 2) + { + return; + } + if (loop) + { + Transform child2 = base.transform.GetChild(0); + pathPoints.Add(new PathPoint(child2.localPosition, child2.localScale.x)); + } + meshFilter = GetComponent(); + meshCollider = GetComponent(); + Mesh mesh = new Mesh(); + List list = new List(); + List uvs = new List(); + List list2 = new List(); + List list3 = new List(); + List _pathOriginal = new List(); + InterpolateModifyer(pathPoints, _pathOriginal, subdivisions); + if (vertDistance > 0.1f) + { + ResampleModifyer(ref _pathOriginal, vertDistance, vertDistance / 10f); + } + AddRoundedEndsModifyer(_pathOriginal, endCapSubdivisions); + WhobbleModifyer(_pathOriginal, widthWhobble, positionWhobble); + float num = 0f; + for (int j = 0; j < _pathOriginal.Count; j++) + { + if (_pathOriginal.Count <= 1) + { + break; + } + Vector3 forwards = GetForwards(j, _pathOriginal); + Vector3 vector = Quaternion.Euler(0f, 90f, 0f) * forwards * _pathOriginal[j].width; + Vector3 vector2 = Quaternion.Euler(0f, -90f, 0f) * forwards * _pathOriginal[j].width; + if (vertical) + { + vector = Vector3.up * _pathOriginal[j].width; + vector2 = Vector3.down * _pathOriginal[j].width; + } + AddUnwrappedVertTop(_pathOriginal[j].position + vector, list, uvs, num, 0f - _pathOriginal[j].width); + AddUnwrappedVertTop(_pathOriginal[j].position + vector2, list, uvs, num, _pathOriginal[j].width); + if (j > 0) + { + num += (_pathOriginal[j].position - _pathOriginal[j - 1].position).magnitude; + } + } + int count = list.Count; + if (extrudeDownOffset.y != 0f) + { + num = 0f; + for (int k = 0; k <= 1; k++) + { + int num2 = 0; + for (int l = k; l < count - 2; l += 2) + { + AddUnwrappedVertTop(list[l], list, uvs, num, 0f); + AddUnwrappedVertTop(list[l] + extrudeDownOffset, list, uvs, num, 0f - extrudeDownOffset.magnitude); + num += (_pathOriginal[num2 + 1].position - _pathOriginal[num2].position).magnitude; + num2++; + AddUnwrappedVertTop(list[l + 2], list, uvs, num, 0f); + AddUnwrappedVertTop(list[l + 2] + extrudeDownOffset, list, uvs, num, 0f - extrudeDownOffset.magnitude); + } + } + } + Vector3[] normals = new Vector3[list.Count]; + for (int m = 0; m < _pathOriginal.Count - 1; m++) + { + if (_pathOriginal.Count <= 1) + { + break; + } + int num3 = m * 2; + ConnectTriangle(num3 + 2, num3 + 1, num3, list2, normals, list, topNormalsAlwaysFaceDirectlyUp, vertical); + ConnectTriangle(num3 + 1, num3 + 2, num3 + 3, list2, normals, list, topNormalsAlwaysFaceDirectlyUp, vertical); + } + if (extrudeDownOffset.y != 0f) + { + int num4 = count; + for (int n = 0; n < count - 2; n += 2) + { + ConnectTriangle(num4, num4 + 1, num4 + 2, list3, normals, list, _makeNormalsFaceUp: false, _showFacesFacedDownwards: true); + ConnectTriangle(num4 + 3, num4 + 2, num4 + 1, list3, normals, list, _makeNormalsFaceUp: false, _showFacesFacedDownwards: true); + num4 += 4; + } + int num5 = num4; + for (int num6 = 1; num6 < count - 2; num6 += 2) + { + ConnectTriangle(num4 + 2, num4 + 1, num4, list3, normals, list, _makeNormalsFaceUp: false, _showFacesFacedDownwards: true); + ConnectTriangle(num4 + 1, num4 + 2, num4 + 3, list3, normals, list, _makeNormalsFaceUp: false, _showFacesFacedDownwards: true); + num4 += 4; + } + ConnectTriangle(num5, count + 1, count, list3, normals, list, _makeNormalsFaceUp: false, _showFacesFacedDownwards: true); + ConnectTriangle(count + 1, num5, num5 + 1, list3, normals, list, _makeNormalsFaceUp: false, _showFacesFacedDownwards: true); + ConnectTriangle(num5 - 2, num5 - 1, num4 - 2, list3, normals, list, _makeNormalsFaceUp: false, _showFacesFacedDownwards: true); + ConnectTriangle(num4 - 1, num4 - 2, num5 - 1, list3, normals, list, _makeNormalsFaceUp: false, _showFacesFacedDownwards: true); + } + mesh.subMeshCount = ((extrudeDownOffset.y == 0f) ? 1 : 2); + mesh.SetVertices(list); + mesh.SetTriangles(list2, 0); + if (extrudeDownOffset.y != 0f) + { + mesh.SetTriangles(list3, 1); + } + mesh.SetUVs(0, uvs); + mesh.SetNormals(normals); + mesh.RecalculateBounds(); + if ((bool)meshFilter) + { + meshFilter.sharedMesh = mesh; + } + if ((bool)meshCollider) + { + meshCollider.sharedMesh = mesh; + } + } + + public void ConnectTriangle(int _vertA, int _vertB, int _vertC, List _tris, Vector3[] _normals, List _verts, bool _makeNormalsFaceUp, bool _showFacesFacedDownwards) + { + if (flipNormals) + { + int num = _vertA; + _vertA = _vertC; + _vertC = num; + } + Vector3 normalized = Vector3.Cross(_verts[_vertA] - _verts[_vertB], _verts[_vertC] - _verts[_vertB]).normalized; + if (normalized.y > 0f || _showFacesFacedDownwards) + { + _tris.Add(_vertC); + _tris.Add(_vertB); + _tris.Add(_vertA); + if (_makeNormalsFaceUp) + { + _normals[_vertC] = Vector3.up; + _normals[_vertB] = Vector3.up; + _normals[_vertA] = Vector3.up; + } + else + { + _normals[_vertC] = normalized; + _normals[_vertB] = normalized; + _normals[_vertA] = normalized; + } + } + } + + public void AddUnwrappedVertTop(Vector3 _pos, List _verts, List _uvs, float _distanceTraveled, float _width) + { + _verts.Add(_pos); + if (uvUnwrapMode == UnwrapMode.XZWorldSpace) + { + _pos = base.transform.localToWorldMatrix.MultiplyPoint(_pos); + _uvs.Add(new Vector2(_pos.x * uvScale, _pos.z * uvScale)); + } + else if (uvUnwrapMode == UnwrapMode.River) + { + _uvs.Add(new Vector2(_distanceTraveled * uvScale, _width * uvScale)); + } + } + + public void InterpolateModifyer(List _pathIn, List _pathOut, int _subdivisions) + { + for (int i = 0; i < _pathIn.Count - 1; i++) + { + for (int j = 0; j < _subdivisions; j++) + { + float num = (float)j / (float)_subdivisions; + float magnitude = (_pathIn[i + 1].position - _pathIn[i].position).magnitude; + Vector3 forwards = GetForwards(i, _pathIn); + Vector3 forwards2 = GetForwards(i + 1, _pathIn); + Vector3 a = _pathIn[i].position + num * forwards * magnitude; + Vector3 b = _pathIn[i + 1].position - (1f - num) * forwards2 * magnitude; + Vector3 position = Vector3.Lerp(a, b, Mathf.SmoothStep(0f, 1f, num)); + float width = Mathf.SmoothStep(_pathIn[i].width, _pathIn[i + 1].width, num); + PathPoint item = new PathPoint(position, width); + _pathOut.Add(item); + } + } + _pathOut.Add(_pathIn[_pathIn.Count - 1]); + } + + public void ResampleModifyer(ref List _pathOriginal, float _maxDistance, float _stepSize = 0.1f) + { + if (_pathOriginal.Count < 2) + { + return; + } + List list = new List(); + list.Add(_pathOriginal[0]); + float num = 0f; + for (int i = 0; i < _pathOriginal.Count - 1; i++) + { + int num2 = (int)Mathf.Ceil((_pathOriginal[i].position - _pathOriginal[i + 1].position).magnitude / _stepSize); + for (int j = 0; j < num2; j++) + { + num += _stepSize; + if (num >= _maxDistance) + { + float t = (float)j / (float)num2; + Vector3 position = Vector3.Lerp(_pathOriginal[i].position, _pathOriginal[i + 1].position, t); + float width = Mathf.Lerp(_pathOriginal[i].width, _pathOriginal[i + 1].width, t); + num = 0f; + list.Add(new PathPoint(position, width)); + } + } + } + list.Add(_pathOriginal[_pathOriginal.Count - 1]); + _pathOriginal = list; + } + + public void WhobbleModifyer(List _path, float _widthAmount, float _posAmount) + { + UnityEngine.Random.InitState(_path.Count * 7); + for (int i = 0; i < _path.Count; i++) + { + _path[i].position += new Vector3(UnityEngine.Random.value - 0.5f, 0f, UnityEngine.Random.value - 0.5f) * _posAmount; + _path[i].width *= 1f + (UnityEngine.Random.value - 0.5f) * _widthAmount; + } + } + + public void AddRoundedEndsModifyer(List _pathModify, int _interpolations) + { + Vector3 position = _pathModify[0].position; + Vector3 vector = -GetForwards(0, _pathModify); + float width = _pathModify[0].width; + Vector3 position2 = _pathModify[_pathModify.Count - 1].position; + Vector3 forwards = GetForwards(_pathModify.Count - 1, _pathModify); + float width2 = _pathModify[_pathModify.Count - 1].width; + for (int i = 1; i < _interpolations; i++) + { + float f = (float)i / (float)_interpolations; + f = Mathf.Pow(f, 0.5f); + float width3 = width * (1f - Mathf.Pow(f, 3f)); + float num = width * f; + _pathModify.Insert(0, new PathPoint(position + num * vector, width3)); + } + for (int j = 1; j < _interpolations; j++) + { + float f2 = (float)j / (float)_interpolations; + f2 = Mathf.Pow(f2, 0.5f); + float width4 = width2 * (1f - Mathf.Pow(f2, 3f)); + float num2 = width2 * f2; + _pathModify.Add(new PathPoint(position2 + num2 * forwards, width4)); + } + } + + private Vector3 GetForwards(int i, List path, bool _xzPlaneOnly = true) + { + Vector3 result = ((i == 0) ? (path[i + 1].position - path[i].position).normalized : ((i != path.Count - 1) ? (path[i + 1].position - path[i - 1].position).normalized : (path[i].position - path[i - 1].position).normalized)); + if (_xzPlaneOnly) + { + result = new Vector3(result.x, 0f, result.z).normalized; + } + return result; + } + + public void Nullify() + { + List list = new List(); + for (int i = 0; i < base.transform.childCount; i++) + { + Transform child = base.transform.GetChild(i); + list.Add(child.transform.position); + } + base.transform.position = Vector3.zero; + for (int j = 0; j < base.transform.childCount; j++) + { + base.transform.GetChild(j).transform.position = list[j]; + } + } +} diff --git a/GameCode/PathfindMovement.cs b/GameCode/PathfindMovement.cs new file mode 100644 index 0000000..4a20af2 --- /dev/null +++ b/GameCode/PathfindMovement.cs @@ -0,0 +1,15 @@ +using Pathfinding.RVO; +using UnityEngine; + +public abstract class PathfindMovement : MonoBehaviour +{ + public virtual bool IsSlowed => false; + + public virtual RVOController RVO => null; + + public abstract void ClearCurrentPath(); + + public abstract void Slow(float _duration); + + public abstract void GetAgroFromObject(TaggedObject _agroTarget); +} diff --git a/GameCode/PathfindMovementEnemy.cs b/GameCode/PathfindMovementEnemy.cs new file mode 100644 index 0000000..b80b53d --- /dev/null +++ b/GameCode/PathfindMovementEnemy.cs @@ -0,0 +1,283 @@ +using System.Collections.Generic; +using Pathfinding; +using Pathfinding.RVO; +using UnityEngine; + +[RequireComponent(typeof(Seeker))] +public class PathfindMovementEnemy : PathfindMovement, DayNightCycle.IDaytimeSensitive +{ + public List targetPriorities = new List(); + + public float keepDistanceOf = 2f; + + public float maximumDistanceFromHome = 100000f; + + public float movementSpeed = 2f; + + public float recalculatePathInterval = 1f; + + public string backupMovementGraph = ""; + + public float agroTimeWhenAttackedByPlayer = 5f; + + private TaggedObject agroPlayerTarget; + + private float remainingPlayerAgroTime; + + private Seeker seeker; + + private RVOController rvo; + + private Vector3 seekToTargetPosSnappedtoNavmesh = Vector3.zero; + + private Vector3 seekToTargetPos = Vector3.zero; + + private TaggedObject seekToTaggedObj; + + private List path = new List(); + + private int nextPathPointIndex; + + private float recalculatePathCooldown; + + private Vector3 homePosition; + + private bool currentlyWalkingHome = true; + + private TargetPriority targetPrio; + + private bool currentlyChasingPlayer; + + private NNConstraint nearestConstraint = new NNConstraint(); + + private Vector3 nextPathPoint; + + private Vector3 homeOffset = Vector3.zero; + + private GraphMask graphMaskOriginal; + + private GraphMask graphMaskBackup; + + private float slowedFor; + + private float speedWhenSlowed = 0.33f; + + private Vector3 storeRequestedTargetPos; + + public override RVOController RVO => rvo; + + public Vector3 HomePosition => homePosition; + + public Vector3 NextPathPoint => nextPathPoint; + + public override bool IsSlowed => slowedFor > 0f; + + public override void GetAgroFromObject(TaggedObject _agroTarget) + { + if ((bool)_agroTarget && _agroTarget.Tags.Contains(TagManager.ETag.Player)) + { + agroPlayerTarget = _agroTarget; + remainingPlayerAgroTime = agroTimeWhenAttackedByPlayer; + if (!currentlyChasingPlayer && agroTimeWhenAttackedByPlayer > 0f) + { + OriginalPathRequest(); + } + } + } + + public void OnDusk() + { + } + + public void OnDawn_AfterSunrise() + { + } + + public void OnDawn_BeforeSunrise() + { + } + + private void Start() + { + seeker = GetComponent(); + rvo = GetComponent(); + recalculatePathCooldown = recalculatePathInterval * Random.value; + homePosition = base.transform.position; + nearestConstraint.graphMask = seeker.graphMask; + DayNightCycle.Instance.RegisterDaytimeSensitiveObject(this); + homeOffset = new Vector3(Random.value - 0.5f, 0f, Random.value - 0.5f); + foreach (TargetPriority targetPriority in targetPriorities) + { + targetPriority.mayNotHaveTags.Add(TagManager.ETag.AUTO_Commanded); + } + if (PerkManager.instance.IceMagicActive) + { + speedWhenSlowed *= PerkManager.instance.iceMagic_AdditionalsSlowMutli; + } + graphMaskOriginal = seeker.graphMask; + graphMaskBackup = GraphMask.FromGraphName(backupMovementGraph); + if (GetComponent().Tags.Contains(TagManager.ETag.MeeleFighter) && Random.value < 0.5f) + { + graphMaskOriginal = graphMaskBackup; + } + } + + private void OriginalPathRequest() + { + seekToTargetPos = FindMoveToTarget(); + seekToTargetPosSnappedtoNavmesh = AstarPath.active.GetNearest(seekToTargetPos, nearestConstraint).position; + storeRequestedTargetPos = seekToTargetPosSnappedtoNavmesh; + seeker.StartPath(base.transform.position, seekToTargetPosSnappedtoNavmesh, OriginalOnPathComplete, graphMaskOriginal); + } + + private void OriginalOnPathComplete(Path _p) + { + if (backupMovementGraph != "") + { + if (_p.error) + { + BackupPathRequest(); + return; + } + if ((storeRequestedTargetPos - _p.vectorPath[_p.vectorPath.Count - 1]).magnitude > 0.1f) + { + BackupPathRequest(); + return; + } + } + else if (_p.error) + { + return; + } + path = _p.vectorPath; + nextPathPointIndex = 0; + } + + private void BackupPathRequest() + { + seekToTargetPos = FindMoveToTarget(); + seekToTargetPosSnappedtoNavmesh = AstarPath.active.GetNearest(seekToTargetPos, nearestConstraint).position; + storeRequestedTargetPos = seekToTargetPosSnappedtoNavmesh; + seeker.StartPath(base.transform.position, seekToTargetPosSnappedtoNavmesh, BackupOnPathComplete, graphMaskBackup); + } + + private void BackupOnPathComplete(Path _p) + { + if (!_p.error) + { + path = _p.vectorPath; + nextPathPointIndex = 0; + } + } + + private Vector3 FindMoveToTarget() + { + currentlyWalkingHome = false; + currentlyChasingPlayer = false; + if (remainingPlayerAgroTime > 0f && agroPlayerTarget != null && !agroPlayerTarget.Hp.KnockedOut) + { + seekToTaggedObj = agroPlayerTarget; + currentlyChasingPlayer = true; + return seekToTaggedObj.transform.position; + } + for (int i = 0; i < targetPriorities.Count; i++) + { + targetPrio = targetPriorities[i]; + seekToTaggedObj = targetPrio.FindTaggedObjectCloseToHome(base.transform.position, homePosition, maximumDistanceFromHome, out var _outPosition); + if (!(seekToTaggedObj == null)) + { + if (seekToTaggedObj.Tags.Contains(TagManager.ETag.Player)) + { + currentlyChasingPlayer = true; + } + return _outPosition; + } + } + seekToTaggedObj = null; + targetPrio = null; + currentlyWalkingHome = true; + return homePosition + homeOffset; + } + + private void Update() + { + if (remainingPlayerAgroTime > 0f) + { + remainingPlayerAgroTime -= Time.deltaTime; + } + recalculatePathCooldown -= Time.deltaTime; + if (recalculatePathCooldown <= 0f) + { + recalculatePathCooldown = recalculatePathInterval; + OriginalPathRequest(); + } + if (currentlyChasingPlayer) + { + seekToTargetPosSnappedtoNavmesh = seekToTaggedObj.transform.position; + if (path.Count > 0) + { + path[path.Count - 1] = seekToTargetPosSnappedtoNavmesh; + } + seekToTargetPos = seekToTargetPosSnappedtoNavmesh; + } + FollowPathUpdate(); + } + + public override void Slow(float _duration) + { + slowedFor = Mathf.Max(_duration, slowedFor); + } + + private void FollowPathUpdate() + { + if (path.Count <= nextPathPointIndex) + { + if (!currentlyChasingPlayer || path.Count <= 0) + { + return; + } + nextPathPointIndex = path.Count - 1; + } + nextPathPoint = path[nextPathPointIndex]; + Vector3 vector; + if ((base.transform.position - seekToTargetPos).magnitude < keepDistanceOf && !currentlyWalkingHome) + { + vector = Vector3.zero; + nextPathPoint = base.transform.position; + } + else + { + vector = nextPathPoint - base.transform.position; + if (vector.magnitude <= 1f) + { + nextPathPointIndex++; + nextPathPointIndex = Mathf.Clamp(nextPathPointIndex, 0, path.Count - 1); + nextPathPoint = path[nextPathPointIndex]; + vector = nextPathPoint - base.transform.position; + } + } + rvo.priority = vector.magnitude; + if (slowedFor > 0f) + { + rvo.SetTarget(nextPathPoint, vector.magnitude * 3f, movementSpeed * speedWhenSlowed); + slowedFor -= Time.deltaTime; + } + else + { + rvo.SetTarget(nextPathPoint, vector.magnitude * 3f, movementSpeed); + } + Vector3 position = base.transform.position + rvo.CalculateMovementDelta(Time.deltaTime); + Vector3 position2 = AstarPath.active.GetNearest(position, nearestConstraint).position; + base.transform.position = position2; + } + + public void SnapToNavmesh() + { + base.transform.position = AstarPath.active.GetNearest(base.transform.position, nearestConstraint).position; + } + + public override void ClearCurrentPath() + { + path.Clear(); + } +} diff --git a/GameCode/PathfindMovementPlayerunit.cs b/GameCode/PathfindMovementPlayerunit.cs new file mode 100644 index 0000000..490eb63 --- /dev/null +++ b/GameCode/PathfindMovementPlayerunit.cs @@ -0,0 +1,326 @@ +using System.Collections.Generic; +using Pathfinding; +using Pathfinding.RVO; +using UnityEngine; + +[RequireComponent(typeof(Seeker))] +public class PathfindMovementPlayerunit : PathfindMovement, DayNightCycle.IDaytimeSensitive +{ + public List targetPriorities = new List(); + + public float keepDistanceOf = 2f; + + public float maximumDistanceFromHome = 100000f; + + public float movementSpeed = 2f; + + public float recalculatePathInterval = 1f; + + public string backupMovementGraph = ""; + + public float agroTimeWhenAttackedByPlayer = 5f; + + public float speedBoostDuringDaytime = 1.5f; + + private TaggedObject agroPlayerTarget; + + private Seeker seeker; + + private RVOController rvo; + + private Vector3 seekToTargetPosSnappedtoNavmesh = Vector3.zero; + + private Vector3 seekToTargetPos = Vector3.zero; + + private TaggedObject seekToTaggedObj; + + private List path = new List(); + + private int nextPathPointIndex; + + private float recalculatePathCooldown; + + private Vector3 homePosition; + + private Vector3 homePositionOriginal; + + private bool currentlyWalkingHome = true; + + private TargetPriority targetPrio; + + private NNConstraint nearestConstraint = new NNConstraint(); + + private GraphMask graphMaskOriginal; + + private Vector3 nextPathPoint; + + private SettingsManager settingsManager; + + private bool followingPlayer; + + [SerializeField] + private GameObject holdPositionMarker; + + private Transform holdPositionMarkerTransform; + + private float slowedFor; + + private bool day = true; + + private bool holdPosition; + + private Vector3 storeRequestedTargetPos; + + public override RVOController RVO => rvo; + + public Vector3 HopePositionOriginal => homePositionOriginal; + + public Vector3 HomePosition + { + get + { + return homePosition; + } + set + { + homePosition = value; + } + } + + public Vector3 NextPathPoint => nextPathPoint; + + public override bool IsSlowed => slowedFor > 0f; + + public bool HoldPosition + { + get + { + return holdPosition; + } + set + { + holdPosition = value; + holdPositionMarker.SetActive(value); + if ((bool)holdPositionMarkerTransform) + { + holdPositionMarkerTransform.position = homePosition + 0.05f * Vector3.up; + } + } + } + + public void FollowPlayer(bool _follow) + { + followingPlayer = _follow; + HoldPosition = false; + } + + public override void GetAgroFromObject(TaggedObject _agroTarget) + { + } + + private void OnDisable() + { + if ((bool)holdPositionMarker) + { + holdPositionMarker.SetActive(value: false); + } + } + + private void OnEnable() + { + HoldPosition = HoldPosition; + } + + public void OnDusk() + { + day = false; + } + + public void OnDawn_AfterSunrise() + { + day = true; + } + + public void OnDawn_BeforeSunrise() + { + if (settingsManager.ResetUnitFormationEveryMorning) + { + homePosition = homePositionOriginal; + HoldPosition = false; + } + } + + private void Start() + { + settingsManager = SettingsManager.Instance; + holdPositionMarkerTransform = holdPositionMarker.transform; + holdPositionMarkerTransform.SetParent(null); + HoldPosition = false; + seeker = GetComponent(); + rvo = GetComponent(); + recalculatePathCooldown = recalculatePathInterval * Random.value; + homePosition = base.transform.position; + homePositionOriginal = base.transform.position; + nearestConstraint.graphMask = seeker.graphMask; + graphMaskOriginal = seeker.graphMask; + DayNightCycle.Instance.RegisterDaytimeSensitiveObject(this); + } + + private void OriginalPathRequest() + { + seekToTargetPos = FindMoveToTarget(); + seekToTargetPosSnappedtoNavmesh = AstarPath.active.GetNearest(seekToTargetPos, nearestConstraint).position; + storeRequestedTargetPos = seekToTargetPosSnappedtoNavmesh; + seeker.StartPath(base.transform.position, seekToTargetPosSnappedtoNavmesh, OriginalOnPathComplete, graphMaskOriginal); + } + + private void OriginalOnPathComplete(Path _p) + { + if (backupMovementGraph != "") + { + if (_p.error) + { + BackupPathRequest(); + return; + } + if ((storeRequestedTargetPos - _p.vectorPath[_p.vectorPath.Count - 1]).magnitude > 0.1f) + { + BackupPathRequest(); + return; + } + } + else if (_p.error) + { + return; + } + path = _p.vectorPath; + nextPathPointIndex = 0; + } + + private void BackupPathRequest() + { + seekToTargetPos = FindMoveToTarget(); + seekToTargetPosSnappedtoNavmesh = AstarPath.active.GetNearest(seekToTargetPos, nearestConstraint).position; + storeRequestedTargetPos = seekToTargetPosSnappedtoNavmesh; + seeker.StartPath(base.transform.position, seekToTargetPosSnappedtoNavmesh, BackupOnPathComplete, GraphMask.FromGraphName(backupMovementGraph)); + } + + private void BackupOnPathComplete(Path _p) + { + if (!_p.error) + { + path = _p.vectorPath; + nextPathPointIndex = 0; + } + } + + private Vector3 FindMoveToTarget() + { + if (followingPlayer) + { + seekToTaggedObj = null; + targetPrio = null; + currentlyWalkingHome = true; + return homePosition; + } + if (holdPosition) + { + seekToTaggedObj = null; + targetPrio = null; + currentlyWalkingHome = true; + return homePosition; + } + currentlyWalkingHome = false; + for (int i = 0; i < targetPriorities.Count; i++) + { + targetPrio = targetPriorities[i]; + seekToTaggedObj = targetPrio.FindTaggedObjectCloseToHome(base.transform.position, homePosition, maximumDistanceFromHome, out var _outPosition); + if (!(seekToTaggedObj == null)) + { + return _outPosition; + } + } + seekToTaggedObj = null; + targetPrio = null; + currentlyWalkingHome = true; + return homePosition; + } + + private void Update() + { + recalculatePathCooldown -= Time.deltaTime; + if (recalculatePathCooldown <= 0f) + { + recalculatePathCooldown = recalculatePathInterval; + OriginalPathRequest(); + } + if (followingPlayer) + { + if (path.Count > 0) + { + path[path.Count - 1] = homePosition; + } + seekToTargetPos = homePosition; + } + FollowPathUpdate(); + } + + public override void Slow(float _duration) + { + slowedFor = Mathf.Max(_duration, slowedFor); + } + + private void FollowPathUpdate() + { + if (path.Count <= nextPathPointIndex) + { + if (!followingPlayer || path.Count <= 0) + { + return; + } + nextPathPointIndex = path.Count - 1; + } + nextPathPoint = path[nextPathPointIndex]; + Vector3 vector; + if ((base.transform.position - seekToTargetPos).magnitude < keepDistanceOf && !currentlyWalkingHome) + { + vector = Vector3.zero; + nextPathPoint = base.transform.position; + } + else + { + vector = nextPathPoint - base.transform.position; + if (vector.magnitude <= 1f) + { + nextPathPointIndex++; + nextPathPointIndex = Mathf.Clamp(nextPathPointIndex, 0, path.Count - 1); + nextPathPoint = path[nextPathPointIndex]; + vector = nextPathPoint - base.transform.position; + } + } + rvo.priority = vector.magnitude; + float num = (day ? (movementSpeed * speedBoostDuringDaytime) : movementSpeed); + if (slowedFor > 0f) + { + rvo.SetTarget(nextPathPoint, vector.magnitude * 3f, num * 0.33f); + slowedFor -= Time.deltaTime; + } + else + { + rvo.SetTarget(nextPathPoint, vector.magnitude * 3f, num); + } + Vector3 position = base.transform.position + rvo.CalculateMovementDelta(Time.deltaTime); + Vector3 position2 = AstarPath.active.GetNearest(position, nearestConstraint).position; + base.transform.position = position2; + } + + public void SnapToNavmesh() + { + base.transform.position = AstarPath.active.GetNearest(base.transform.position, nearestConstraint).position; + } + + public override void ClearCurrentPath() + { + path.Clear(); + } +} diff --git a/GameCode/PauseUILoadoutHelper.cs b/GameCode/PauseUILoadoutHelper.cs new file mode 100644 index 0000000..c51180c --- /dev/null +++ b/GameCode/PauseUILoadoutHelper.cs @@ -0,0 +1,161 @@ +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.UI; + +public class PauseUILoadoutHelper : MonoBehaviour +{ + public ThronefallUIElement topmostButton; + + public ThronefallUIElement botmostButton; + + public GridLayoutGroup loadoutGroup; + + public TFUIEquippable equippableButtonPrefab; + + private List grid = new List(); + + private const int maxRows = 4; + + public void Refresh() + { + if (SceneTransitionManager.instance.CurrentSceneState != SceneTransitionManager.SceneState.InGame) + { + return; + } + grid.Clear(); + foreach (Transform item in loadoutGroup.transform) + { + Object.Destroy(item.gameObject); + } + List list = new List(); + List list2 = new List(); + List list3 = new List(); + foreach (Equippable item2 in PerkManager.instance.CurrentlyEquipped) + { + if (item2 is EquippableWeapon) + { + list.Add(item2); + } + else if (item2 is EquippablePerk) + { + list2.Add(item2); + } + else if (item2 is EquippableMutation) + { + list3.Add(item2); + } + } + foreach (Equippable item3 in list) + { + AddTFUIEquippable(loadoutGroup, item3); + } + foreach (Equippable item4 in list2) + { + AddTFUIEquippable(loadoutGroup, item4); + } + foreach (Equippable item5 in list3) + { + AddTFUIEquippable(loadoutGroup, item5); + } + AssignNavigationTargets(); + } + + private void AddTFUIEquippable(GridLayoutGroup parent, Equippable e) + { + TFUIEquippable component = Object.Instantiate(equippableButtonPrefab, parent.transform).GetComponent(); + component.SetDataSimple(e); + grid.Add(component); + } + + private void AssignNavigationTargets() + { + int num = grid.Count / 4; + int num2 = grid.Count % 4; + if (num2 > 0) + { + num++; + } + else + { + num2 = 4; + } + int num3 = 0; + int num4 = 0; + for (int i = 0; i < grid.Count; i++) + { + ThronefallUIElement thronefallUIElement = grid[i]; + if (num3 == 0) + { + thronefallUIElement.topNav = botmostButton; + } + else + { + thronefallUIElement.topNav = grid[i - 1]; + } + if (num3 == 3 || (num == 1 && i == grid.Count - 1)) + { + thronefallUIElement.botNav = topmostButton; + } + else if (num > 1 && i == grid.Count - 1) + { + thronefallUIElement.botNav = grid[4 * num4 - 1]; + } + else + { + thronefallUIElement.botNav = grid[i + 1]; + } + if (num > 1) + { + if (num4 == 0) + { + if (num3 <= num2 - 1) + { + thronefallUIElement.leftNav = grid[grid.Count - (num2 - num3)]; + } + else if (i + 4 <= grid.Count - 1) + { + thronefallUIElement.leftNav = grid[i + 4]; + } + } + else + { + thronefallUIElement.leftNav = grid[i - 4]; + } + if (num4 == num - 1) + { + thronefallUIElement.rightNav = grid[i - 4 * (num - 1)]; + } + else + { + int num5 = i + 4; + if (num5 <= grid.Count - 1) + { + thronefallUIElement.rightNav = grid[num5]; + } + else + { + thronefallUIElement.rightNav = grid[i - 4 * num4]; + } + } + } + num3++; + if (num3 > 3) + { + num3 = 0; + num4++; + } + } + if (grid.Count > 0) + { + botmostButton.botNav = grid[0]; + if (num2 != 4 && num > 1) + { + topmostButton.topNav = grid[4 * (num - 1) - 1]; + } + else + { + topmostButton.topNav = grid[grid.Count - 1]; + } + } + } +} diff --git a/GameCode/PerkCooldownModifyer.cs b/GameCode/PerkCooldownModifyer.cs new file mode 100644 index 0000000..e5b14f0 --- /dev/null +++ b/GameCode/PerkCooldownModifyer.cs @@ -0,0 +1,20 @@ +using UnityEngine; + +public class PerkCooldownModifyer : MonoBehaviour +{ + public Equippable requiredPerk; + + public float hpCooldownMultiplyer; + + public AutoAttack autoAttack; + + private void Start() + { + if (PerkManager.IsEquipped(requiredPerk)) + { + autoAttack.cooldownDuration *= hpCooldownMultiplyer; + autoAttack.recheckTargetInterval *= hpCooldownMultiplyer; + } + Object.Destroy(this); + } +} diff --git a/GameCode/PerkCostModifyer.cs b/GameCode/PerkCostModifyer.cs new file mode 100644 index 0000000..d4e2d62 --- /dev/null +++ b/GameCode/PerkCostModifyer.cs @@ -0,0 +1,21 @@ +using UnityEngine; + +public class PerkCostModifyer : MonoBehaviour +{ + public Equippable requiredPerk; + + public int[] upgradeCostChange; + + private void Start() + { + if (PerkManager.IsEquipped(requiredPerk)) + { + BuildSlot component = GetComponent(); + for (int i = 0; i < component.Upgrades.Count; i++) + { + component.Upgrades[i].cost += upgradeCostChange[i]; + } + } + Object.Destroy(this); + } +} diff --git a/GameCode/PerkDamageModifyerPlayerunitAuto.cs b/GameCode/PerkDamageModifyerPlayerunitAuto.cs new file mode 100644 index 0000000..fe8a9de --- /dev/null +++ b/GameCode/PerkDamageModifyerPlayerunitAuto.cs @@ -0,0 +1,26 @@ +using UnityEngine; + +public class PerkDamageModifyerPlayerunitAuto : MonoBehaviour +{ + private void Start() + { + PerkManager instance = PerkManager.instance; + if (instance.WarriorModeActive) + { + AutoAttack[] componentsInChildren = GetComponentsInChildren(includeInactive: true); + for (int i = 0; i < componentsInChildren.Length; i++) + { + componentsInChildren[i].DamageMultiplyer *= instance.warriorModeAllyDmgMulti; + } + } + if (instance.CommanderModeActive) + { + AutoAttack[] componentsInChildren = GetComponentsInChildren(includeInactive: true); + for (int i = 0; i < componentsInChildren.Length; i++) + { + componentsInChildren[i].DamageMultiplyer *= instance.commanderModeAllyDmgMulti; + } + } + Object.Destroy(this); + } +} diff --git a/GameCode/PerkDestroyGameObjectModifyer.cs b/GameCode/PerkDestroyGameObjectModifyer.cs new file mode 100644 index 0000000..db48c28 --- /dev/null +++ b/GameCode/PerkDestroyGameObjectModifyer.cs @@ -0,0 +1,28 @@ +using UnityEngine; + +public class PerkDestroyGameObjectModifyer : MonoBehaviour +{ + [SerializeField] + private Equippable perk; + + [SerializeField] + private bool destroyIfPerkIsEquipped; + + [SerializeField] + private bool destroyIfPerkIsNotEquipped; + + private void Start() + { + if (PerkManager.IsEquipped(perk)) + { + if (destroyIfPerkIsEquipped) + { + Object.Destroy(base.gameObject); + } + } + else if (destroyIfPerkIsNotEquipped) + { + Object.Destroy(base.gameObject); + } + } +} diff --git a/GameCode/PerkHpModifyer.cs b/GameCode/PerkHpModifyer.cs new file mode 100644 index 0000000..3c7186c --- /dev/null +++ b/GameCode/PerkHpModifyer.cs @@ -0,0 +1,31 @@ +using UnityEngine; + +public class PerkHpModifyer : MonoBehaviour +{ + public Equippable requiredPerk; + + public float hpMultiplyer; + + public Hp hp; + + private void Start() + { + if (PerkManager.IsEquipped(requiredPerk)) + { + BuildSlot componentInParent = GetComponentInParent(); + if ((bool)componentInParent) + { + foreach (BuildSlot.Upgrade upgrade in componentInParent.Upgrades) + { + foreach (BuildSlot.UpgradeBranch upgradeBranch in upgrade.upgradeBranches) + { + upgradeBranch.hpChange = Mathf.RoundToInt((float)upgradeBranch.hpChange * hpMultiplyer); + } + } + } + hp.maxHp *= hpMultiplyer; + hp.Heal(float.MaxValue); + } + Object.Destroy(this); + } +} diff --git a/GameCode/PerkIncomeModifyer.cs b/GameCode/PerkIncomeModifyer.cs new file mode 100644 index 0000000..14de63d --- /dev/null +++ b/GameCode/PerkIncomeModifyer.cs @@ -0,0 +1,24 @@ +using UnityEngine; + +public class PerkIncomeModifyer : MonoBehaviour +{ + public Equippable requiredPerk; + + public int[] upgradeIncomeChange; + + private void Start() + { + if (PerkManager.IsEquipped(requiredPerk)) + { + BuildSlot component = GetComponent(); + for (int i = 0; i < component.Upgrades.Count; i++) + { + foreach (BuildSlot.UpgradeBranch upgradeBranch in component.Upgrades[i].upgradeBranches) + { + upgradeBranch.goldIncomeChange += upgradeIncomeChange[i]; + } + } + } + Object.Destroy(this); + } +} diff --git a/GameCode/PerkIndestructible.cs b/GameCode/PerkIndestructible.cs new file mode 100644 index 0000000..d03713e --- /dev/null +++ b/GameCode/PerkIndestructible.cs @@ -0,0 +1,24 @@ +using UnityEngine; + +public class PerkIndestructible : MonoBehaviour +{ + [SerializeField] + private Equippable indestructiblePerk; + + private void Start() + { + if (PerkManager.IsEquipped(indestructiblePerk)) + { + TaggedObject componentInChildren = GetComponentInChildren(); + if ((bool)componentInChildren) + { + componentInChildren.RemoveTag(TagManager.ETag.PlayerOwned); + } + } + Object.Destroy(this); + } + + private void Update() + { + } +} diff --git a/GameCode/PerkManager.cs b/GameCode/PerkManager.cs new file mode 100644 index 0000000..540b858 --- /dev/null +++ b/GameCode/PerkManager.cs @@ -0,0 +1,193 @@ +using System.Collections.Generic; +using UnityEngine; + +public class PerkManager : MonoBehaviour +{ + public const int MaxLevel = 1000000; + + public static PerkManager instance; + + [Header("Equippables: ")] + [SerializeField] + private List currentlyEquipped; + + [SerializeField] + private List unlockedEquippables; + + [Header("Leveling system: ")] + public int xp; + + public int level = 1; + + [SerializeField] + private List metaLevels; + + public float heavyArmor_HpMultiplyer; + + public float heavyArmor_SpeedMultiplyer; + + public float godsLotion_RegenRateMultiplyer; + + public float godsLotion_RegenDelayMultiplyer; + + public float racingHorse_SpeedMultiplyer; + + public float gladiatorSchool_TrainingSpeedMultiplyer; + + public float elliteWarriors_TrainingSpeedMultiplyer; + + public float tauntTheTiger_damageMultiplyer; + + public Equippable tigerGodPerk; + + public float tauntTheTurtle_hpMultiplyer; + + public Equippable turtleGodPerk; + + public float tauntTheFalcon_speedMultiplyer; + + public float tauntTheFalcon_chasePlayerTimeMultiplyer; + + public Equippable falconGodPerk; + + public Equippable ratGodPerk; + + public Equippable warriorMode; + + public float warriorModeAllyDmgMulti = 0.5f; + + public float warriorModeSelfDmgMultiMax = 2f; + + public Equippable commanderMode; + + public float commanderModeAllyDmgMulti = 1.5f; + + public float commanderModeSelfDmgMulti = 0.5f; + + public Equippable glassCanon; + + public float glassCanon_dmgMulti = 1.5f; + + public Equippable healintSpirits; + + public float healingSpirits_healMulti = 1.5f; + + public Equippable iceMagic; + + public float iceMagic_AdditionalsSlowMutli = 0.75f; + + public float iceMagic_SlowDurationMulti = 2f; + + public Equippable rangedResistence; + + public float rangedResistence_AmountMulti = 1.3f; + + public Equippable meleeResistence; + + public float meleeResistence_AmountMulti = 1.3f; + + public float powerTower_attackSpeedBonus = 2f; + + public Equippable treasureHunter; + + public int treasureHunterGoldAmount = 40; + + public Equippable cheeseGod; + + public Equippable godOfDeath; + + public float godOfDeath_playerRespawnMultiplyer = 2f; + + public Equippable destructionGod; + + public List UnlockedEquippables => unlockedEquippables; + + public List CurrentlyEquipped => currentlyEquipped; + + public List MetaLevels => metaLevels; + + public MetaLevel NextMetaLevel + { + get + { + if (level - 1 >= metaLevels.Count || level >= 1000000) + { + return null; + } + return metaLevels[level - 1]; + } + } + + public bool WarriorModeActive => IsEquipped(warriorMode); + + public bool CommanderModeActive => IsEquipped(commanderMode); + + public bool GlassCanonActive => IsEquipped(glassCanon); + + public bool HealingSpiritsActive => IsEquipped(healintSpirits); + + public bool IceMagicActive => IsEquipped(iceMagic); + + public bool RangedResistenceActive => IsEquipped(rangedResistence); + + public bool MeleeResistenceActive => IsEquipped(meleeResistence); + + public bool TreasureHunterActive => IsEquipped(treasureHunter); + + public bool CheeseGodActive => IsEquipped(cheeseGod); + + public bool GodOfDeathActive => IsEquipped(godOfDeath); + + public bool DestructionGodActive => IsEquipped(destructionGod); + + private void Awake() + { + if ((bool)instance) + { + Object.Destroy(base.gameObject); + return; + } + instance = this; + Object.DontDestroyOnLoad(base.transform.root.gameObject); + } + + public static bool IsEquipped(Equippable _perk) + { + if (!instance) + { + return false; + } + return instance.currentlyEquipped.Contains(_perk); + } + + public static void SetEquipped(Equippable _perk, bool _equipped) + { + if (!instance) + { + return; + } + if (_equipped) + { + if (!instance.currentlyEquipped.Contains(_perk)) + { + instance.currentlyEquipped.Add(_perk); + } + } + else if (instance.currentlyEquipped.Contains(_perk)) + { + instance.currentlyEquipped.Remove(_perk); + } + } + + public void CallAfterLoadToUnlockPerksAndStuff() + { + level = Mathf.Min(level, 1000000); + for (int i = 0; i < Mathf.Min(metaLevels.Count, level - 1); i++) + { + if (!unlockedEquippables.Contains(metaLevels[i].reward) || metaLevels[i].reward.GetType() == typeof(PerkPoint)) + { + unlockedEquippables.Add(metaLevels[i].reward); + } + } + } +} diff --git a/GameCode/PerkPoint.cs b/GameCode/PerkPoint.cs new file mode 100644 index 0000000..b339e08 --- /dev/null +++ b/GameCode/PerkPoint.cs @@ -0,0 +1,6 @@ +using UnityEngine; + +[CreateAssetMenu(fileName = "Data", menuName = "SimpleSiege/Perk Point", order = 1)] +public class PerkPoint : Equippable +{ +} diff --git a/GameCode/PerkRangeModifyer.cs b/GameCode/PerkRangeModifyer.cs new file mode 100644 index 0000000..f515e96 --- /dev/null +++ b/GameCode/PerkRangeModifyer.cs @@ -0,0 +1,28 @@ +using UnityEngine; + +public class PerkRangeModifyer : MonoBehaviour +{ + public Equippable requiredPerk; + + public float rangeMultiplyer; + + public AutoAttack autoAttack; + + public PathfindMovementPlayerunit pathfindMovement; + + private void Start() + { + if (PerkManager.IsEquipped(requiredPerk)) + { + foreach (TargetPriority targetPriority in autoAttack.targetPriorities) + { + targetPriority.range *= rangeMultiplyer; + } + if ((bool)pathfindMovement) + { + pathfindMovement.keepDistanceOf *= rangeMultiplyer; + } + } + Object.Destroy(this); + } +} diff --git a/GameCode/PerkSelectionGroup.cs b/GameCode/PerkSelectionGroup.cs new file mode 100644 index 0000000..06d1131 --- /dev/null +++ b/GameCode/PerkSelectionGroup.cs @@ -0,0 +1,165 @@ +using System.Collections.Generic; +using TMPro; +using UnityEngine; + +public class PerkSelectionGroup : MonoBehaviour +{ + private enum Type + { + Weapons, + Perks, + Mutations, + FixedLoadout + } + + public GameObject perkSelectionItemPrefab; + + public GameObject perkLockedPrefab; + + [SerializeField] + private Type type; + + private PerkManager perkManager; + + private int selectableAmount = 10000; + + private List selectedInMyGroup = new List(); + + [SerializeField] + private TMP_Text headerText; + + [SerializeField] + private string selectNone = "No perks unlocked yet."; + + [SerializeField] + private string selectOne = "Select one perk."; + + [SerializeField] + private string selectMulti = "Select perks."; + + [SerializeField] + private bool canDeselectPerks = true; + + [SerializeField] + private Color textColorNormal = Color.white; + + [SerializeField] + private Color textColorWarning = Color.red; + + private int unlockedPerks; + + private void Start() + { + UpdateVisuals(); + } + + public void UpdateVisuals() + { + perkManager = PerkManager.instance; + int num = 0; + for (int num2 = base.transform.childCount - 1; num2 >= 0; num2--) + { + Object.Destroy(base.transform.GetChild(num2).gameObject); + } + unlockedPerks = 0; + for (int i = 0; i < perkManager.UnlockedEquippables.Count; i++) + { + Equippable equippable = perkManager.UnlockedEquippables[i]; + if (equippable.GetType() == typeof(PerkPoint)) + { + num++; + } + if ((type == Type.Weapons && equippable.GetType() == typeof(EquippableWeapon)) || (type == Type.Perks && equippable.GetType() == typeof(EquippablePerk)) || (type == Type.Mutations && equippable.GetType() == typeof(EquippableMutation))) + { + Object.Instantiate(perkSelectionItemPrefab, base.transform).GetComponent().Initialize(equippable); + unlockedPerks++; + } + } + for (int j = 0; j < perkManager.MetaLevels.Count; j++) + { + Equippable reward = perkManager.MetaLevels[j].reward; + if (((type == Type.Weapons && reward.GetType() == typeof(EquippableWeapon)) || (type == Type.Perks && reward.GetType() == typeof(EquippablePerk)) || (type == Type.Mutations && reward.GetType() == typeof(EquippableMutation))) && !perkManager.UnlockedEquippables.Contains(reward)) + { + Object.Instantiate(perkLockedPrefab, base.transform); + } + } + if (type == Type.FixedLoadout && LevelInteractor.lastActivatedLevelInteractor != null) + { + selectableAmount = 0; + LevelInteractor lastActivatedLevelInteractor = LevelInteractor.lastActivatedLevelInteractor; + for (int k = 0; k < lastActivatedLevelInteractor.fixedLoadout.Count; k++) + { + Equippable equippable2 = lastActivatedLevelInteractor.fixedLoadout[k]; + PerkSelectionItem component = Object.Instantiate(perkSelectionItemPrefab, base.transform).GetComponent(); + component.Selected = true; + component.Initialize(equippable2); + selectableAmount++; + } + } + if (type == Type.Weapons) + { + selectableAmount = 1; + } + if (type == Type.Perks) + { + selectableAmount = num; + } + if (type == Type.Mutations) + { + selectableAmount = 10000; + } + if (selectableAmount <= 0 || unlockedPerks <= 0) + { + headerText.text = selectNone; + } + else if (selectableAmount == 1) + { + headerText.text = selectOne; + } + else + { + headerText.text = selectMulti.Replace("", selectableAmount.ToString()); + } + } + + private void Update() + { + if (selectedInMyGroup.Count < Mathf.Min(unlockedPerks, selectableAmount)) + { + headerText.color = textColorWarning; + } + else + { + headerText.color = textColorNormal; + } + } + + public void SelectPerk(PerkSelectionItem _selectedPerk) + { + if (!canDeselectPerks && _selectedPerk.Selected) + { + return; + } + _selectedPerk.Selected = !_selectedPerk.Selected; + if (_selectedPerk.Selected) + { + selectedInMyGroup.Add(_selectedPerk); + if (!perkManager.CurrentlyEquipped.Contains(_selectedPerk.Equippable)) + { + perkManager.CurrentlyEquipped.Add(_selectedPerk.Equippable); + } + if (selectedInMyGroup.Count > selectableAmount) + { + PerkSelectionItem perkSelectionItem = selectedInMyGroup[0]; + perkSelectionItem.Selected = false; + selectedInMyGroup.Remove(perkSelectionItem); + perkManager.CurrentlyEquipped.Remove(perkSelectionItem.Equippable); + } + } + else + { + selectedInMyGroup.Remove(_selectedPerk); + perkManager.CurrentlyEquipped.Remove(_selectedPerk.Equippable); + } + } +} diff --git a/GameCode/PerkSelectionItem.cs b/GameCode/PerkSelectionItem.cs new file mode 100644 index 0000000..6e43dea --- /dev/null +++ b/GameCode/PerkSelectionItem.cs @@ -0,0 +1,80 @@ +using UnityEngine; +using UnityEngine.EventSystems; +using UnityEngine.UI; + +public class PerkSelectionItem : MonoBehaviour, IPointerEnterHandler, IEventSystemHandler, IPointerExitHandler +{ + private LevelSelectManager levelSelectManager; + + [SerializeField] + private GameObject selectedMarker; + + private PerkSelectionGroup perkSelectionGroup; + + private Color colorBasic; + + private Image image; + + [SerializeField] + private Color hoverColor; + + private bool mouseIsOver; + + private Equippable equippable; + + public Equippable Equippable => equippable; + + public bool Selected + { + get + { + return selectedMarker.activeInHierarchy; + } + set + { + selectedMarker.SetActive(value); + } + } + + public void OnPointerEnter(PointerEventData eventData) + { + mouseIsOver = true; + } + + public void OnPointerExit(PointerEventData eventData) + { + mouseIsOver = false; + if (levelSelectManager.ShowingTooltipFor == equippable) + { + levelSelectManager.ShowTooltip(null); + } + } + + private void Update() + { + image.color = (mouseIsOver ? hoverColor : colorBasic); + if (mouseIsOver) + { + levelSelectManager.ShowTooltip(equippable); + } + if (Input.GetMouseButtonDown(0) && mouseIsOver && (bool)perkSelectionGroup) + { + perkSelectionGroup.SelectPerk(this); + } + } + + public void Initialize(Equippable _equippable) + { + image = GetComponent(); + colorBasic = image.color; + perkSelectionGroup = GetComponentInParent(); + Debug.Log(perkSelectionGroup); + levelSelectManager = LevelSelectManager.instance; + image.sprite = _equippable.icon; + equippable = _equippable; + if (PerkManager.instance.CurrentlyEquipped.Contains(equippable) && (bool)perkSelectionGroup) + { + perkSelectionGroup.SelectPerk(this); + } + } +} diff --git a/GameCode/PerkSelectionTooltipHelper.cs b/GameCode/PerkSelectionTooltipHelper.cs new file mode 100644 index 0000000..9ea47af --- /dev/null +++ b/GameCode/PerkSelectionTooltipHelper.cs @@ -0,0 +1,115 @@ +using I2.Loc; +using MPUIKIT; +using TMPro; +using UnityEngine; +using UnityEngine.UI; + +public class PerkSelectionTooltipHelper : MonoBehaviour +{ + public UIFrame targetFrame; + + public TextMeshProUGUI selectionTitle; + + public TextMeshProUGUI selectionDescription; + + public Image selectionIcon; + + public MPImageBasic background; + + public UIParentResizer sizer; + + public bool disableOnNullSelect; + + public GameObject tooltipParent; + + private TFUIEquippable currentElement; + + public void OnSelection() + { + if (targetFrame.CurrentSelection == null) + { + return; + } + TFUIEquippable tFUIEquippable = targetFrame.CurrentSelection as TFUIEquippable; + if (tFUIEquippable == null) + { + if (disableOnNullSelect) + { + tooltipParent.SetActive(value: false); + } + return; + } + if ((bool)tooltipParent) + { + tooltipParent.SetActive(value: true); + } + currentElement = tFUIEquippable; + UpdateTooltip(); + } + + public void OnFocus() + { + if (targetFrame.CurrentFocus == null) + { + OnSelection(); + return; + } + if ((bool)tooltipParent) + { + tooltipParent.SetActive(value: true); + } + TFUIEquippable tFUIEquippable = targetFrame.CurrentFocus as TFUIEquippable; + if (tFUIEquippable == null) + { + if (disableOnNullSelect) + { + tooltipParent.SetActive(value: false); + } + } + else + { + currentElement = tFUIEquippable; + UpdateTooltip(); + } + } + + public void UpdateTooltip() + { + if (currentElement == null) + { + return; + } + string text = ""; + string text2 = ""; + Equippable data = currentElement.Data; + if (currentElement.Locked) + { + text = LocalizationManager.GetTranslation("Menu/Locked"); + text2 = LocalizationManager.GetTranslation("Menu/Locked Choice Description"); + if (data is EquippableWeapon) + { + text2 = LocalizationManager.GetTranslation("Menu/Locked Weapon Description"); + } + else if (data is EquippablePerk) + { + text2 = LocalizationManager.GetTranslation("Menu/Locked Perk Description"); + } + else if (data is EquippableMutation) + { + text2 = LocalizationManager.GetTranslation("Menu/Locked Mutator Description"); + } + selectionIcon.sprite = currentElement.IconImg.sprite; + } + else + { + text = LocalizationManager.GetTranslation(data.LOCIDENTIFIER_NAME); + text2 = LocalizationManager.GetTranslation(data.LOCIDENTIFIER_DESCRIPTION); + selectionIcon.sprite = data.icon; + } + selectionTitle.text = text; + selectionDescription.text = text2; + background.color = currentElement.GetBackgroundColor; + selectionIcon.color = currentElement.GetIconColor; + sizer.Trigger(); + } +} diff --git a/GameCode/PerkWeaponModifyer.cs b/GameCode/PerkWeaponModifyer.cs new file mode 100644 index 0000000..ab8d4bc --- /dev/null +++ b/GameCode/PerkWeaponModifyer.cs @@ -0,0 +1,19 @@ +using UnityEngine; + +public class PerkWeaponModifyer : MonoBehaviour +{ + public Equippable requiredPerk; + + public Weapon weaponToInsert; + + public AutoAttack autoAttack; + + private void Start() + { + if (PerkManager.IsEquipped(requiredPerk)) + { + autoAttack.weapon = weaponToInsert; + } + Object.Destroy(this); + } +} diff --git a/GameCode/PhysicalCoinAnimator.cs b/GameCode/PhysicalCoinAnimator.cs new file mode 100644 index 0000000..2f44485 --- /dev/null +++ b/GameCode/PhysicalCoinAnimator.cs @@ -0,0 +1,26 @@ +using UnityEngine; + +public class PhysicalCoinAnimator : MonoBehaviour +{ + public float animationTime = 0.5f; + + public AnimationCurve animationCurve; + + private float clock; + + private void Awake() + { + base.transform.localScale = Vector3.zero; + } + + private void Update() + { + clock += Time.deltaTime; + base.transform.localScale = Vector3.one * animationCurve.Evaluate(clock / animationTime); + if (clock >= animationTime) + { + base.transform.localScale = Vector3.one; + Object.Destroy(this); + } + } +} diff --git a/GameCode/PlayLevelButton.cs b/GameCode/PlayLevelButton.cs new file mode 100644 index 0000000..b330372 --- /dev/null +++ b/GameCode/PlayLevelButton.cs @@ -0,0 +1,40 @@ +using UnityEngine; +using UnityEngine.EventSystems; +using UnityEngine.UI; + +public class PlayLevelButton : MonoBehaviour, IPointerEnterHandler, IEventSystemHandler, IPointerExitHandler +{ + private bool mouseIsOver; + + private Color colorBasic; + + private Image image; + + [SerializeField] + private Color hoverColor; + + private void Start() + { + image = GetComponent(); + colorBasic = image.color; + } + + public void OnPointerEnter(PointerEventData eventData) + { + mouseIsOver = true; + } + + public void OnPointerExit(PointerEventData eventData) + { + mouseIsOver = false; + } + + private void Update() + { + image.color = (mouseIsOver ? hoverColor : colorBasic); + if (Input.GetMouseButtonDown(0) && mouseIsOver) + { + LevelSelectManager.instance.PlayButtonPressed(); + } + } +} diff --git a/GameCode/PlayMusicOnStart.cs b/GameCode/PlayMusicOnStart.cs new file mode 100644 index 0000000..ebf6369 --- /dev/null +++ b/GameCode/PlayMusicOnStart.cs @@ -0,0 +1,31 @@ +using UnityEngine; + +public class PlayMusicOnStart : MonoBehaviour +{ + [SerializeField] + private AudioClip audioClip; + + [SerializeField] + private float fadeDuration = 4f; + + [SerializeField] + private bool destroyEntireGameObject = true; + + private void Start() + { + MusicManager instance = MusicManager.instance; + if (instance != null) + { + instance.PlayMusic(audioClip, fadeDuration); + } + else + { + Debug.LogWarning("MusicManager instance not found."); + } + Object.Destroy(this); + if (destroyEntireGameObject) + { + Object.Destroy(base.gameObject); + } + } +} diff --git a/GameCode/PlayOneShotAfterSeconds.cs b/GameCode/PlayOneShotAfterSeconds.cs new file mode 100644 index 0000000..1bf1a43 --- /dev/null +++ b/GameCode/PlayOneShotAfterSeconds.cs @@ -0,0 +1,22 @@ +using UnityEngine; + +public class PlayOneShotAfterSeconds : MonoBehaviour +{ + public float initialDelay = 1f; + + public ThronefallAudioManager.AudioOneShot type; + + private float timer; + + private void Update() + { + if (timer <= initialDelay) + { + timer += Time.deltaTime; + if (timer > initialDelay) + { + ThronefallAudioManager.WorldSpaceOneShot(type, base.transform.position); + } + } + } +} diff --git a/GameCode/PlayerAttack.cs b/GameCode/PlayerAttack.cs new file mode 100644 index 0000000..a3f84ef --- /dev/null +++ b/GameCode/PlayerAttack.cs @@ -0,0 +1,30 @@ +using Rewired; +using UnityEngine; + +public class PlayerAttack : MonoBehaviour +{ + public AttackCooldownAnimation ui; + + private ManualAttack attack; + + private Player input; + + private void Start() + { + input = ReInput.players.GetPlayer(0); + } + + private void Update() + { + if ((bool)attack) + { + attack.Tick(); + ui.SetCurrentCooldownPercentage(attack.CooldownPercentage); + } + } + + public void AssignManualAttack(ManualAttack target) + { + attack = target; + } +} diff --git a/GameCode/PlayerAttackAnimator.cs b/GameCode/PlayerAttackAnimator.cs new file mode 100644 index 0000000..10407a6 --- /dev/null +++ b/GameCode/PlayerAttackAnimator.cs @@ -0,0 +1,27 @@ +using System.Collections.Generic; +using UnityEngine; + +public class PlayerAttackAnimator : MonoBehaviour +{ + public List animations = new List(); + + private ManualAttack playerAttack; + + public void AssignAttack(ManualAttack attack) + { + playerAttack = attack; + playerAttack.onAttack.AddListener(TriggerAnimations); + } + + private void TriggerAnimations() + { + if (!base.gameObject.activeInHierarchy) + { + return; + } + foreach (OneShotAnimationBase animation in animations) + { + animation.Trigger(); + } + } +} diff --git a/GameCode/PlayerAttackTargetFacer.cs b/GameCode/PlayerAttackTargetFacer.cs new file mode 100644 index 0000000..6692d49 --- /dev/null +++ b/GameCode/PlayerAttackTargetFacer.cs @@ -0,0 +1,66 @@ +using UnityEngine; + +public class PlayerAttackTargetFacer : MonoBehaviour +{ + public Transform targetTransform; + + public ManualAttack attack; + + public float maxRotationDelta = 360f; + + public float lookBackTime = 0.4f; + + private Vector3 desiredForwardVector; + + private Quaternion desiredRotation = Quaternion.identity; + + private float lookClock; + + private bool shouldReset; + + public void AssignAttack(ManualAttack _attack) + { + attack = _attack; + attack.onAttack.AddListener(UpdateTarget); + if (attack.cooldownTime <= lookBackTime) + { + lookBackTime = attack.cooldownTime + 0.05f; + } + } + + private void UpdateTarget() + { + if (!(attack.LastTargetPos == Vector3.zero)) + { + desiredForwardVector = attack.LastTargetPos - targetTransform.position; + desiredForwardVector.y = 0f; + desiredForwardVector.Normalize(); + desiredRotation = Quaternion.LookRotation(desiredForwardVector, Vector3.up); + lookClock = lookBackTime; + } + } + + private void Update() + { + if (lookClock >= 0f) + { + lookClock -= Time.deltaTime; + if (!targetTransform.rotation.Equals(desiredRotation)) + { + targetTransform.rotation = Quaternion.RotateTowards(targetTransform.rotation, desiredRotation, maxRotationDelta * Time.deltaTime); + } + if (lookClock <= 0f) + { + shouldReset = true; + } + } + else if (shouldReset) + { + targetTransform.rotation = Quaternion.RotateTowards(targetTransform.rotation, targetTransform.parent.rotation, maxRotationDelta * Time.deltaTime); + if (targetTransform.rotation.Equals(targetTransform.parent.rotation)) + { + shouldReset = false; + } + } + } +} diff --git a/GameCode/PlayerCharacterAudio.cs b/GameCode/PlayerCharacterAudio.cs new file mode 100644 index 0000000..2e951ef --- /dev/null +++ b/GameCode/PlayerCharacterAudio.cs @@ -0,0 +1,94 @@ +using UnityEngine; + +public class PlayerCharacterAudio : MonoBehaviour +{ + public Hp playerHp; + + public AutoRevive playerReviveComponent; + + public AudioSource stepAudioSource; + + public AudioSource fxAudioSource; + + public AudioSource dmgAudioSource; + + public PlayerMovement targetController; + + public float fadeTime = 0.3f; + + public float sprintPitch = 1.1f; + + private PlayerWeaponAudio weaponAudio; + + private float initialVolume; + + private float initialPitch; + + private float fadeSpeed; + + private void Start() + { + initialPitch = stepAudioSource.pitch; + initialVolume = stepAudioSource.volume; + stepAudioSource.volume = 0f; + stepAudioSource.priority = 110; + fadeSpeed = initialVolume / fadeTime; + playerHp.OnKillOrKnockout.AddListener(OnDeath); + playerHp.OnReceiveDamage.AddListener(OnDmg); + playerReviveComponent.onReviveTrigger.AddListener(OnRevive); + } + + public void OnWeaponEquip(ManualAttack weapon) + { + weaponAudio = weapon.GetComponent(); + weaponAudio.autoWeapon.onAttack.AddListener(PlayAttackSound); + } + + private void PlayAttackSound() + { + fxAudioSource.priority = 5; + fxAudioSource.pitch = Random.Range(1f - weaponAudio.pitchRange, 1f + weaponAudio.pitchRange); + fxAudioSource.PlayOneShot(weaponAudio.AttackSound.GetRandomClip(), weaponAudio.volume); + } + + private void OnDeath() + { + dmgAudioSource.priority = 5; + dmgAudioSource.pitch = 1f; + dmgAudioSource.PlayOneShot(ThronefallAudioManager.Instance.audioContent.PlayerDeath.GetRandomClip(), 1f); + } + + private void OnDmg(bool b) + { + dmgAudioSource.priority = 5; + dmgAudioSource.pitch = Random.Range(0.9f, 1.1f); + dmgAudioSource.PlayOneShot(ThronefallAudioManager.Instance.audioContent.PlayerDamage.GetRandomClip(), 0.65f); + } + + private void OnRevive() + { + fxAudioSource.priority = 5; + fxAudioSource.pitch = 1f; + fxAudioSource.PlayOneShot(ThronefallAudioManager.Instance.audioContent.PlayerRevive, 0.8f); + } + + private void Update() + { + if (targetController.Sprinting) + { + stepAudioSource.pitch = sprintPitch; + } + else + { + stepAudioSource.pitch = initialPitch; + } + if (targetController.Moving && (playerHp == null || !playerHp.KnockedOut)) + { + stepAudioSource.volume = Mathf.MoveTowards(stepAudioSource.volume, initialVolume, fadeSpeed * Time.unscaledDeltaTime); + } + else + { + stepAudioSource.volume = Mathf.MoveTowards(stepAudioSource.volume, 0f, fadeSpeed * Time.unscaledDeltaTime); + } + } +} diff --git a/GameCode/PlayerHpRegen.cs b/GameCode/PlayerHpRegen.cs new file mode 100644 index 0000000..d739844 --- /dev/null +++ b/GameCode/PlayerHpRegen.cs @@ -0,0 +1,60 @@ +using UnityEngine; + +[RequireComponent(typeof(Hp))] +public class PlayerHpRegen : MonoBehaviour +{ + private Hp hp; + + public float delayTillRegenerationStarts; + + public float timeToRegenerateFullHealth; + + private float timeSinceLastTakenDamage; + + private float hpRemember; + + private bool heavyArmorEquipped; + + private bool godsLotionEquipped; + + private bool godOfDeseaseActive; + + [SerializeField] + private Equippable heavyArmorPerk; + + [SerializeField] + private Equippable godsLotionPerk; + + private void Start() + { + hp = GetComponent(); + hpRemember = hp.HpValue; + heavyArmorEquipped = PerkManager.IsEquipped(heavyArmorPerk); + godsLotionEquipped = PerkManager.IsEquipped(godsLotionPerk); + if (heavyArmorEquipped) + { + timeToRegenerateFullHealth *= PerkManager.instance.heavyArmor_HpMultiplyer; + hp.maxHp *= PerkManager.instance.heavyArmor_HpMultiplyer; + hp.Heal(float.MaxValue); + } + if (godsLotionEquipped) + { + delayTillRegenerationStarts *= PerkManager.instance.godsLotion_RegenDelayMultiplyer; + timeToRegenerateFullHealth /= PerkManager.instance.godsLotion_RegenRateMultiplyer; + } + } + + private void Update() + { + timeSinceLastTakenDamage += Time.deltaTime; + if (hp.HpValue < hpRemember) + { + timeSinceLastTakenDamage = 0f; + } + hpRemember = hp.HpValue; + if (timeSinceLastTakenDamage >= delayTillRegenerationStarts) + { + hp.Heal(hp.maxHp / timeToRegenerateFullHealth * Time.deltaTime); + } + } +} diff --git a/GameCode/PlayerInteraction.cs b/GameCode/PlayerInteraction.cs new file mode 100644 index 0000000..184045b --- /dev/null +++ b/GameCode/PlayerInteraction.cs @@ -0,0 +1,205 @@ +using Rewired; +using UnityEngine; +using UnityEngine.Events; + +public class PlayerInteraction : MonoBehaviour +{ + private int balance; + + public float coinMagnetRadius = 10f; + + public LayerMask coinLayer; + + public float interactionRadius = 3f; + + public LayerMask interactorLayer; + + private ManualAttack manualAttack; + + private int networth; + + public PlayerCharacterAudio playerAudio; + + public GameObject coinSpendFX; + + public Transform coinSpendFXOrigin; + + private TagManager tagManager; + + [HideInInspector] + public UnityEvent onBalanceGain = new UnityEvent(); + + [HideInInspector] + public UnityEvent onBalanceSpend = new UnityEvent(); + + [HideInInspector] + public UnityEvent onFocusPaymentInteraction = new UnityEvent(); + + [HideInInspector] + public UnityEvent onUnfocusPaymentInteraction = new UnityEvent(); + + public static PlayerInteraction instance; + + private InteractorBase focussedInteractor; + + private Player input; + + public int Networth => networth; + + public ManualAttack EquippedWeapon => manualAttack; + + public bool IsFreeToCallNight + { + get + { + if (!LocalGamestate.Instance.PlayerFrozen && focussedInteractor == null && tagManager.CountObjectsWithTag(TagManager.ETag.CastleCenter) > 0 && TutorialManager.AllowStartingTheNight && !EnemySpawner.instance.MatchOver) + { + return LocalGamestate.Instance.CurrentState == LocalGamestate.State.InMatch; + } + return false; + } + } + + public int Balance => balance; + + public int TrueBalance => balance + TagManager.instance.coins.Count + CoinSpawner.AllCoinsLeftToBeSpawned; + + public InteractorBase FocussedInteractor => focussedInteractor; + + private void Awake() + { + instance = this; + } + + public void EquipWeapon(ManualAttack _manualAttack) + { + manualAttack = _manualAttack; + playerAudio.OnWeaponEquip(manualAttack); + } + + private void Start() + { + input = ReInput.players.GetPlayer(0); + tagManager = TagManager.instance; + } + + private void Update() + { + FetchCoins(); + FetchInteractors(); + RunInteraction(); + } + + private void RunInteraction() + { + if (LocalGamestate.Instance.PlayerFrozen) + { + return; + } + if (input.GetButtonDown("Interact")) + { + if ((bool)focussedInteractor) + { + focussedInteractor.InteractionBegin(this); + } + else if ((bool)manualAttack) + { + manualAttack.TryToAttack(); + } + } + if (input.GetButton("Interact") && (bool)focussedInteractor) + { + focussedInteractor.InteractionHold(this); + } + if (input.GetButtonUp("Interact") && (bool)focussedInteractor) + { + focussedInteractor.InteractionEnd(this); + } + if (input.GetButton("Preview Build Options")) + { + BuildingInteractor.displayAllBuildPreviews = true; + } + else + { + BuildingInteractor.displayAllBuildPreviews = false; + } + } + + private void FetchInteractors() + { + if (input.GetButton("Call Night") || input.GetButton("Interact") || ((bool)focussedInteractor && focussedInteractor is BuildingInteractor && (focussedInteractor as BuildingInteractor).IsWaitingForChoice)) + { + return; + } + Collider[] array = Physics.OverlapSphere(base.transform.position, interactionRadius, interactorLayer); + InteractorBase interactorBase = null; + float num = float.PositiveInfinity; + Collider[] array2 = array; + foreach (Collider collider in array2) + { + InteractorBase component = collider.GetComponent(); + if ((bool)component && component.CanBeInteractedWith) + { + float num2 = Vector3.Distance(base.transform.position, collider.ClosestPoint(base.transform.position)); + if (num2 < num) + { + interactorBase = component; + num = num2; + } + } + } + if ((bool)focussedInteractor && focussedInteractor != interactorBase) + { + if (focussedInteractor is BuildingInteractor) + { + onUnfocusPaymentInteraction.Invoke(); + } + focussedInteractor.Unfocus(this); + focussedInteractor = null; + } + if ((bool)interactorBase && interactorBase != focussedInteractor) + { + if (interactorBase is BuildingInteractor) + { + onFocusPaymentInteraction.Invoke(); + } + interactorBase.Focus(this); + focussedInteractor = interactorBase; + } + } + + private void FetchCoins() + { + Collider[] array = Physics.OverlapSphere(base.transform.position, coinMagnetRadius, coinLayer); + for (int i = 0; i < array.Length; i++) + { + Coin component = array[i].GetComponent(); + if (component != null && component.IsFree) + { + component.SetTarget(this); + } + } + } + + public void AddCoin(int amount = 1) + { + balance += amount; + networth += amount; + onBalanceGain.Invoke(amount); + } + + public void SpendCoins(int amount) + { + balance -= amount; + onBalanceSpend.Invoke(amount); + Object.Instantiate(coinSpendFX, coinSpendFXOrigin.position, coinSpendFXOrigin.rotation, base.transform); + } + + private void OnDrawGizmosSelected() + { + Gizmos.color = Color.blue; + Gizmos.DrawWireSphere(base.transform.position, interactionRadius); + Gizmos.color = Color.yellow; + Gizmos.DrawWireSphere(base.transform.position, coinMagnetRadius); + } +} diff --git a/GameCode/PlayerManager.cs b/GameCode/PlayerManager.cs new file mode 100644 index 0000000..8fe94dd --- /dev/null +++ b/GameCode/PlayerManager.cs @@ -0,0 +1,68 @@ +using System.Collections.Generic; +using UnityEngine; + +public class PlayerManager : MonoBehaviour +{ + private static PlayerManager instance; + + protected List registeredPlayers = new List(); + + public static PlayerManager Instance => instance; + + public PlayerMovement[] RegisteredPlayers => registeredPlayers.ToArray(); + + private void Awake() + { + if (instance != null) + { + Object.Destroy(instance); + Debug.LogWarning("Found more than one player manager in scene. Destroyed old one."); + } + instance = this; + } + + public static void RegisterPlayer(PlayerMovement player) + { + if (!instance) + { + Debug.Log("No PlayerManager exists in scene."); + } + else + { + instance.registeredPlayers.Add(player); + } + } + + public static void UnregisterPlayer(PlayerMovement player) + { + if (!instance) + { + Debug.Log("No PlayerManager exists in scene."); + } + else + { + instance.registeredPlayers.Remove(player); + } + } + + public static PlayerMovement GetClosestPlayer(Vector3 position) + { + if (!instance) + { + Debug.Log("No PlayerManager exists in scene."); + return null; + } + PlayerMovement result = null; + float num = float.PositiveInfinity; + foreach (PlayerMovement registeredPlayer in instance.registeredPlayers) + { + float num2 = Vector3.Distance(position, registeredPlayer.transform.position); + if (num2 < num) + { + num = num2; + result = registeredPlayer; + } + } + return result; + } +} diff --git a/GameCode/PlayerMovement.cs b/GameCode/PlayerMovement.cs new file mode 100644 index 0000000..db7c18a --- /dev/null +++ b/GameCode/PlayerMovement.cs @@ -0,0 +1,152 @@ +using System.Collections; +using Pathfinding.RVO; +using Rewired; +using UnityEngine; + +[RequireComponent(typeof(CharacterController))] +[RequireComponent(typeof(RVOController))] +public class PlayerMovement : MonoBehaviour +{ + public float speed = 4f; + + public float sprintSpeed = 12f; + + public Transform meshParent; + + public float maxMeshRotationSpeed = 360f; + + public Animator meshAnimator; + + private Hp hp; + + private Transform viewTransform; + + private CharacterController controller; + + private Player input; + + private Quaternion desiredMeshRotation; + + private RVOController rvoController; + + private float yVelocity; + + private bool heavyArmorEquipped; + + private bool racingHorseEquipped; + + private bool moving; + + private bool sprinting; + + private bool sprintingToggledOn; + + public static PlayerMovement instance; + + [SerializeField] + private Equippable heavyArmorPerk; + + [SerializeField] + private Equippable warHorsePerk; + + private Vector3 velocity; + + public bool Moving => moving; + + public bool Sprinting => sprinting; + + public Vector3 Velocity => velocity; + + private void Awake() + { + instance = this; + } + + public void TeleportTo(Vector3 _position) + { + controller.enabled = false; + controller.transform.position = _position; + StartCoroutine(EnableControllerNextFrame(controller)); + } + + private void Start() + { + PlayerManager.RegisterPlayer(this); + viewTransform = Camera.main.transform; + controller = GetComponent(); + input = ReInput.players.GetPlayer(0); + rvoController = GetComponent(); + hp = GetComponent(); + heavyArmorEquipped = PerkManager.IsEquipped(heavyArmorPerk); + racingHorseEquipped = PerkManager.IsEquipped(warHorsePerk); + } + + private void Update() + { + Vector2 vector = new Vector2(input.GetAxis("Move Vertical"), input.GetAxis("Move Horizontal")); + if (LocalGamestate.Instance.PlayerFrozen) + { + vector = Vector2.zero; + } + Vector3 normalized = Vector3.ProjectOnPlane(viewTransform.forward, Vector3.up).normalized; + Vector3 normalized2 = Vector3.ProjectOnPlane(viewTransform.right, Vector3.up).normalized; + velocity = Vector3.zero; + velocity += normalized * vector.x; + velocity += normalized2 * vector.y; + velocity = Vector3.ClampMagnitude(velocity, 1f); + if (input.GetButtonDown("Sprint Toggle")) + { + sprintingToggledOn = !sprintingToggledOn; + } + if (sprintingToggledOn && input.GetButton("Sprint")) + { + sprintingToggledOn = false; + } + sprinting = (input.GetButton("Sprint") || sprintingToggledOn) && hp.HpPercentage >= 1f; + velocity *= (sprinting ? sprintSpeed : speed); + if (heavyArmorEquipped && DayNightCycle.Instance.CurrentTimestate == DayNightCycle.Timestate.Night) + { + velocity *= PerkManager.instance.heavyArmor_SpeedMultiplyer; + } + if (racingHorseEquipped) + { + velocity *= PerkManager.instance.racingHorse_SpeedMultiplyer; + } + rvoController.velocity = velocity; + moving = velocity.sqrMagnitude > 0.1f; + if (moving) + { + desiredMeshRotation = Quaternion.LookRotation(velocity.normalized, Vector3.up); + } + if (desiredMeshRotation != meshParent.rotation) + { + meshParent.rotation = Quaternion.RotateTowards(meshParent.rotation, desiredMeshRotation, maxMeshRotationSpeed * Time.deltaTime); + } + meshAnimator.SetBool("Moving", moving); + meshAnimator.SetBool("Sprinting", sprinting); + if (controller.enabled) + { + if (controller.isGrounded) + { + yVelocity = 0f; + } + else + { + yVelocity += -9.81f * Time.deltaTime; + } + velocity += Vector3.up * yVelocity; + controller.Move(velocity * Time.deltaTime); + } + } + + private void OnDisable() + { + meshAnimator.SetBool("Moving", value: false); + } + + private IEnumerator EnableControllerNextFrame(CharacterController controller) + { + yield return new WaitForEndOfFrame(); + controller.enabled = true; + } +} diff --git a/GameCode/PlayerScept.cs b/GameCode/PlayerScept.cs new file mode 100644 index 0000000..6d1fa03 --- /dev/null +++ b/GameCode/PlayerScept.cs @@ -0,0 +1,85 @@ +using System.Collections; +using Rewired; +using UnityEngine; + +public class PlayerScept : MonoBehaviour, DayNightCycle.IDaytimeSensitive +{ + public GameObject loadoutParent; + + public Transform scept; + + public Transform scepterInteractionTarget; + + public AnimationCurve inCurve; + + public AnimationCurve outCurve; + + public float inTime = 0.2f; + + public float outTime = 0.4f; + + private Player input; + + private Vector3 initPos; + + private void Start() + { + DayNightCycle.Instance.RegisterDaytimeSensitiveObject(this); + input = ReInput.players.GetPlayer(0); + initPos = scept.localPosition; + } + + private void Update() + { + if (input.GetButtonDown("Interact")) + { + StopAllCoroutines(); + StartCoroutine(AnimationIn()); + } + if (input.GetButtonUp("Interact")) + { + StopAllCoroutines(); + StartCoroutine(AnimationOut()); + } + } + + private IEnumerator AnimationIn() + { + float timer = 0f; + Vector3 startPos = scept.localPosition; + while (timer < inTime) + { + timer += Time.deltaTime; + scept.localPosition = Vector3.Lerp(startPos, scepterInteractionTarget.localPosition, inCurve.Evaluate(Mathf.InverseLerp(0f, inTime, timer))); + yield return null; + } + scept.localPosition = scepterInteractionTarget.localPosition; + } + + private IEnumerator AnimationOut() + { + float timer = 0f; + _ = scept.localPosition; + while (timer < outTime) + { + timer += Time.deltaTime; + scept.localPosition = Vector3.Lerp(scept.localPosition, initPos, outCurve.Evaluate(Mathf.InverseLerp(0f, outTime, timer))); + yield return null; + } + scept.localPosition = initPos; + } + + public void OnDawn_AfterSunrise() + { + loadoutParent.SetActive(value: true); + } + + public void OnDawn_BeforeSunrise() + { + } + + public void OnDusk() + { + loadoutParent.SetActive(value: false); + } +} diff --git a/GameCode/PlayerUpgradeManager.cs b/GameCode/PlayerUpgradeManager.cs new file mode 100644 index 0000000..5a07815 --- /dev/null +++ b/GameCode/PlayerUpgradeManager.cs @@ -0,0 +1,70 @@ +using UnityEngine; + +public class PlayerUpgradeManager : MonoBehaviour, DayNightCycle.IDaytimeSensitive +{ + public static PlayerUpgradeManager instance; + + public float playerDamageMultiplyer = 1f; + + public bool assassinsTraining; + + public bool godlyCurse; + + public bool magicArmor; + + public bool commander; + + public float godlyCurseDamageMultiplyer = 1.5f; + + private int damageIncreases; + + [SerializeField] + private Equippable glassCanon; + + [SerializeField] + private float glassCanon_dmgMulti = 1.5f; + + private void Awake() + { + instance = this; + } + + private void Start() + { + if ((bool)DayNightCycle.Instance) + { + DayNightCycle.Instance.RegisterDaytimeSensitiveObject(this); + } + if (PerkManager.instance.CommanderModeActive) + { + playerDamageMultiplyer *= PerkManager.instance.commanderModeSelfDmgMulti; + } + if (PerkManager.instance.GlassCanonActive) + { + playerDamageMultiplyer *= PerkManager.instance.glassCanon_dmgMulti; + } + } + + public void OnDusk() + { + GetStrongerIfInWarriorMode(); + } + + public void OnDawn_AfterSunrise() + { + } + + public void OnDawn_BeforeSunrise() + { + GetStrongerIfInWarriorMode(); + } + + public void GetStrongerIfInWarriorMode() + { + while (PerkManager.instance.WarriorModeActive && damageIncreases < EnemySpawner.instance.Wavenumber) + { + damageIncreases++; + playerDamageMultiplyer *= Mathf.Pow(PerkManager.instance.warriorModeSelfDmgMultiMax, 1f / (float)EnemySpawner.instance.WaveCount); + } + } +} diff --git a/GameCode/PlayerWeaponAudio.cs b/GameCode/PlayerWeaponAudio.cs new file mode 100644 index 0000000..90cbfd5 --- /dev/null +++ b/GameCode/PlayerWeaponAudio.cs @@ -0,0 +1,55 @@ +using UnityEngine; + +public class PlayerWeaponAudio : MonoBehaviour +{ + public enum WeaponType + { + Sword, + Spear, + Bow + } + + public ManualAttack autoWeapon; + + public ManualAttack activeAbility; + + public WeaponType weaponType; + + public float pitchRange; + + public float volume = 0.75f; + + [HideInInspector] + private AudioSet.ClipArray attackSound; + + private bool initialized; + + public AudioSet.ClipArray AttackSound + { + get + { + if (!initialized) + { + Initialize(); + } + return attackSound; + } + } + + private void Initialize() + { + switch (weaponType) + { + case WeaponType.Bow: + attackSound = ThronefallAudioManager.Instance.audioContent.PlayerBow; + break; + case WeaponType.Spear: + attackSound = ThronefallAudioManager.Instance.audioContent.PlayerSpear; + break; + case WeaponType.Sword: + attackSound = ThronefallAudioManager.Instance.audioContent.PlayerSword; + break; + } + initialized = true; + } +} diff --git a/GameCode/PlayerWeaponVisuals.cs b/GameCode/PlayerWeaponVisuals.cs new file mode 100644 index 0000000..0e5aa6f --- /dev/null +++ b/GameCode/PlayerWeaponVisuals.cs @@ -0,0 +1,31 @@ +using UnityEngine; + +public class PlayerWeaponVisuals : MonoBehaviour, DayNightCycle.IDaytimeSensitive +{ + private GameObject visuals; + + public void Init(GameObject _visuals, ManualAttack _attack) + { + visuals = _visuals; + DayNightCycle.Instance.RegisterDaytimeSensitiveObject(this); + visuals.GetComponent().AssignAttack(_attack); + if (TutorialManager.instance != null) + { + visuals.SetActive(value: true); + } + } + + public void OnDawn_AfterSunrise() + { + visuals.SetActive(value: false); + } + + public void OnDawn_BeforeSunrise() + { + } + + public void OnDusk() + { + visuals.SetActive(value: true); + } +} diff --git a/GameCode/PositionAnimation.cs b/GameCode/PositionAnimation.cs new file mode 100644 index 0000000..c50408d --- /dev/null +++ b/GameCode/PositionAnimation.cs @@ -0,0 +1,42 @@ +using System.Collections; +using UnityEngine; + +public class PositionAnimation : OneShotAnimationBase +{ + public AnimationCurve curve; + + public float duration = 0.75f; + + public Vector3 targetPosition; + + public Transform transformToAnimate; + + private Vector3 initialPosition; + + private void Start() + { + initialPosition = transformToAnimate.localPosition; + } + + private IEnumerator Animate() + { + transformToAnimate.localPosition = initialPosition; + float timer = 0f; + while (timer < duration) + { + transformToAnimate.localPosition = Vector3.Lerp(initialPosition, targetPosition, curve.Evaluate(timer / duration)); + timer += Time.deltaTime; + yield return null; + } + transformToAnimate.localPosition = Vector3.Lerp(initialPosition, targetPosition, curve.Evaluate(1f)); + } + + public override void Trigger() + { + if (base.gameObject.activeInHierarchy) + { + StopAllCoroutines(); + StartCoroutine(Animate()); + } + } +} diff --git a/GameCode/PowerTowerPerk.cs b/GameCode/PowerTowerPerk.cs new file mode 100644 index 0000000..09466d4 --- /dev/null +++ b/GameCode/PowerTowerPerk.cs @@ -0,0 +1,56 @@ +using System.Collections.Generic; +using UnityEngine; + +public class PowerTowerPerk : MonoBehaviour +{ + [SerializeField] + private Equippable powerTowerPerk; + + [SerializeField] + private List mustHaveTags = new List(); + + [SerializeField] + private List mayNotHaveTags = new List(); + + private TagManager tagManager; + + private float attackSpeedBonus; + + private float nextRefreshIn = 0.2f; + + private TaggedObject closestTower; + + private void Start() + { + if (!PerkManager.IsEquipped(powerTowerPerk)) + { + Object.Destroy(this); + return; + } + tagManager = TagManager.instance; + attackSpeedBonus = PerkManager.instance.powerTower_attackSpeedBonus; + } + + private void Update() + { + nextRefreshIn -= Time.deltaTime; + if (nextRefreshIn <= 0f) + { + closestTower = tagManager.FindClosestTaggedObjectWithTags(base.transform.position, mustHaveTags, mayNotHaveTags); + nextRefreshIn = 0.2f; + } + if (closestTower != null) + { + AutoAttack[] componentsInChildren = closestTower.GetComponentsInChildren(); + for (int i = 0; i < componentsInChildren.Length; i++) + { + componentsInChildren[i].ReduceCooldownBy(attackSpeedBonus * Time.deltaTime); + } + HotOilTower[] componentsInChildren2 = closestTower.GetComponentsInChildren(); + for (int i = 0; i < componentsInChildren2.Length; i++) + { + componentsInChildren2[i].ReduceCooldownBy(attackSpeedBonus * Time.deltaTime); + } + } + } +} diff --git a/GameCode/PracticeTargetCoinDrop.cs b/GameCode/PracticeTargetCoinDrop.cs new file mode 100644 index 0000000..760d9c2 --- /dev/null +++ b/GameCode/PracticeTargetCoinDrop.cs @@ -0,0 +1,33 @@ +using UnityEngine; + +public class PracticeTargetCoinDrop : MonoBehaviour +{ + private Hp hp; + + private TagManager tagManager; + + [SerializeField] + private int totalCoinsToDrop = 3; + + private void Start() + { + hp = GetComponent(); + tagManager = TagManager.instance; + } + + private void Update() + { + if (tagManager.CountAllTaggedObjectsWithTag(TagManager.ETag.PracticeTargets) <= totalCoinsToDrop) + { + hp.coinCount = 1; + } + } + + private void OnDestroy() + { + if ((bool)hp && hp.HpValue <= 0f) + { + AchievementManager.UnlockAchievement(AchievementManager.Achievements.START_TUTORIAL); + } + } +} diff --git a/GameCode/PriorityAudioListener.cs b/GameCode/PriorityAudioListener.cs new file mode 100644 index 0000000..127e5fb --- /dev/null +++ b/GameCode/PriorityAudioListener.cs @@ -0,0 +1,27 @@ +using System.Collections; +using UnityEngine; + +public class PriorityAudioListener : MonoBehaviour +{ + private void OnEnable() + { + StartCoroutine(ExecuteAfterTime()); + } + + private IEnumerator ExecuteAfterTime() + { + while (BackupAudioListener.Instance == null) + { + yield return null; + } + BackupAudioListener.Instance.EnableBackupListener(enable: false); + } + + private void OnDisable() + { + if (BackupAudioListener.Instance != null) + { + BackupAudioListener.Instance.EnableBackupListener(enable: true); + } + } +} diff --git a/GameCode/ProductionBar.cs b/GameCode/ProductionBar.cs new file mode 100644 index 0000000..2f838a1 --- /dev/null +++ b/GameCode/ProductionBar.cs @@ -0,0 +1,23 @@ +using MPUIKIT; +using UnityEngine; + +public class ProductionBar : MonoBehaviour +{ + [SerializeField] + private GameObject canvasParent; + + [SerializeField] + private MPImage fill; + + private float fillAmount = -1f; + + public void UpdateVisual(float _fillAmount) + { + if (fillAmount != _fillAmount) + { + canvasParent.SetActive(_fillAmount > 0f); + fill.fillAmount = _fillAmount; + fillAmount = _fillAmount; + } + } +} diff --git a/GameCode/ProjectileAudio.cs b/GameCode/ProjectileAudio.cs new file mode 100644 index 0000000..7390613 --- /dev/null +++ b/GameCode/ProjectileAudio.cs @@ -0,0 +1,37 @@ +using UnityEngine; + +public class ProjectileAudio : MonoBehaviour +{ + public enum ProjectileType + { + Catapult + } + + public AimbotProjectile target; + + public AudioSource aSource; + + public ProjectileType projectile; + + public float pitchrange = 0.2f; + + private void Start() + { + if (target != null) + { + target.onHit.AddListener(PlayImpact); + } + if (projectile == ProjectileType.Catapult) + { + aSource.clip = ThronefallAudioManager.Instance.audioContent.CatapultImpact.GetRandomClip(); + } + aSource.pitch = Random.Range(1f - pitchrange, 1f + pitchrange); + } + + private void PlayImpact() + { + aSource.Play(); + aSource.transform.parent = null; + Object.Destroy(aSource.gameObject, aSource.clip.length); + } +} diff --git a/GameCode/ProjectileImpactParticles.cs b/GameCode/ProjectileImpactParticles.cs new file mode 100644 index 0000000..6592a9b --- /dev/null +++ b/GameCode/ProjectileImpactParticles.cs @@ -0,0 +1,22 @@ +using UnityEngine; + +public class ProjectileImpactParticles : MonoBehaviour +{ + public AimbotProjectile target; + + public ParticleSystem particles; + + private void Start() + { + if (target != null) + { + target.onHit.AddListener(Play); + } + } + + private void Play() + { + particles.gameObject.transform.parent = null; + particles.Play(); + } +} diff --git a/GameCode/ProjectileSpawnAudio.cs b/GameCode/ProjectileSpawnAudio.cs new file mode 100644 index 0000000..de57603 --- /dev/null +++ b/GameCode/ProjectileSpawnAudio.cs @@ -0,0 +1,11 @@ +using UnityEngine; + +public class ProjectileSpawnAudio : MonoBehaviour +{ + public ThronefallAudioManager.AudioOneShot oneShotType; + + private void Start() + { + ThronefallAudioManager.WorldSpaceOneShot(oneShotType, base.transform.position); + } +} diff --git a/GameCode/Quest.cs b/GameCode/Quest.cs new file mode 100644 index 0000000..2532576 --- /dev/null +++ b/GameCode/Quest.cs @@ -0,0 +1,114 @@ +using System; +using System.Collections.Generic; +using I2.Loc; + +[Serializable] +public class Quest +{ + public enum EType + { + BeatTheLevel = 0, + AchieveScoreOf = 2, + BeatTheLevelWith = 1, + BeatTheLevelWithout = 3 + } + + public EType questType; + + public List beatTheLevelWith = new List(); + + public int achieveScoreOf; + + public List beatTheLevelWithout = new List(); + + private bool IsBeatLevelWith => questType == EType.BeatTheLevelWith; + + private bool IsAchieveScoreOf => questType == EType.AchieveScoreOf; + + private bool IsBeatLevelWithout => questType == EType.BeatTheLevelWithout; + + public bool CheckBeaten(LevelData _myLevelData) + { + switch (questType) + { + case EType.BeatTheLevel: + return _myLevelData.beatenBest; + case EType.AchieveScoreOf: + return _myLevelData.highscoreBest >= achieveScoreOf; + case EType.BeatTheLevelWith: + { + for (int k = 0; k < _myLevelData.levelHasBeenBeatenWith.Count; k++) + { + List list2 = _myLevelData.levelHasBeenBeatenWith[k]; + int num = beatTheLevelWith.Count; + for (int l = 0; l < list2.Count; l++) + { + if (beatTheLevelWith.Contains(list2[l])) + { + num--; + } + if (num <= 0) + { + return true; + } + } + } + return false; + } + case EType.BeatTheLevelWithout: + { + for (int i = 0; i < _myLevelData.levelHasBeenBeatenWith.Count; i++) + { + List list = _myLevelData.levelHasBeenBeatenWith[i]; + bool flag = true; + for (int j = 0; j < list.Count; j++) + { + if (beatTheLevelWithout.Contains(list[j])) + { + flag = false; + break; + } + } + if (flag) + { + return true; + } + } + return false; + } + default: + return false; + } + } + + public string GetMissionStatement() + { + string result = ""; + switch (questType) + { + case EType.AchieveScoreOf: + result = LocalizationManager.GetTranslation("Achieve Score") + " " + achieveScoreOf; + break; + case EType.BeatTheLevel: + result = LocalizationManager.GetTranslation("Achieve Victory"); + break; + case EType.BeatTheLevelWith: + result = LocalizationManager.GetTranslation("Achieve Victory With"); + foreach (Equippable item in beatTheLevelWith) + { + result = result + " " + item.displayName + " +"; + } + result = result.Remove(result.Length - 1, 1); + break; + case EType.BeatTheLevelWithout: + result = LocalizationManager.GetTranslation("Achieve Victory Without"); + foreach (Equippable item2 in beatTheLevelWithout) + { + result = result + " " + item2.displayName + " +"; + } + result = result.Remove(result.Length - 1, 1); + break; + } + return result; + } +} diff --git a/GameCode/QuestConditionEquippable.cs b/GameCode/QuestConditionEquippable.cs new file mode 100644 index 0000000..41c9d94 --- /dev/null +++ b/GameCode/QuestConditionEquippable.cs @@ -0,0 +1,33 @@ +using MPUIKIT; +using UnityEngine; +using UnityEngine.UI; + +public class QuestConditionEquippable : MonoBehaviour +{ + public Color weaponBgColor; + + public Color perkBgColor; + + public Color mutatorBgColor; + + public MPImageBasic background; + + public Image icon; + + public void SetData(Equippable data) + { + icon.sprite = data.icon; + if (data is EquippableWeapon) + { + background.color = weaponBgColor; + } + if (data is EquippablePerk) + { + background.color = perkBgColor; + } + if (data is EquippableMutation) + { + background.color = mutatorBgColor; + } + } +} diff --git a/GameCode/QuestEntry.cs b/GameCode/QuestEntry.cs new file mode 100644 index 0000000..625cbab --- /dev/null +++ b/GameCode/QuestEntry.cs @@ -0,0 +1,87 @@ +using I2.Loc; +using TMPro; +using UnityEngine; + +public class QuestEntry : MonoBehaviour +{ + public TextMeshProUGUI questText; + + public TextMeshProUGUI numericalCondition; + + public GameObject equippableConditionsParent; + + public QuestConditionEquippable equippableConditionPrefab; + + public CanvasGroup canvasGroup; + + public void Init(Quest data, int index, bool completed) + { + string text = ""; + switch (index) + { + case 0: + text += "A."; + break; + case 1: + text += "B."; + break; + case 2: + text += "C."; + break; + case 3: + text += "D."; + break; + case 4: + text += "E."; + break; + case 5: + text += "F."; + break; + case 6: + text += "G."; + break; + case 7: + text += "H."; + break; + } + text += " "; + text += ""; + switch (data.questType) + { + case Quest.EType.AchieveScoreOf: + equippableConditionsParent.SetActive(value: false); + numericalCondition.gameObject.SetActive(value: true); + numericalCondition.text = data.achieveScoreOf.ToString(); + text += LocalizationManager.GetTranslation("Quests/Achieve Score"); + break; + case Quest.EType.BeatTheLevel: + equippableConditionsParent.SetActive(value: false); + numericalCondition.gameObject.SetActive(value: false); + text += LocalizationManager.GetTranslation("Quests/Achieve Victory"); + break; + case Quest.EType.BeatTheLevelWith: + equippableConditionsParent.SetActive(value: true); + numericalCondition.gameObject.SetActive(value: false); + text += LocalizationManager.GetTranslation("Quests/Achieve Victory With"); + foreach (Equippable item in data.beatTheLevelWith) + { + Object.Instantiate(equippableConditionPrefab, equippableConditionsParent.transform).SetData(item); + } + break; + case Quest.EType.BeatTheLevelWithout: + equippableConditionsParent.SetActive(value: true); + numericalCondition.gameObject.SetActive(value: false); + text += LocalizationManager.GetTranslation("Quests/Achieve Victory Without"); + foreach (Equippable item2 in data.beatTheLevelWithout) + { + Object.Instantiate(equippableConditionPrefab, equippableConditionsParent.transform).SetData(item2); + } + break; + } + questText.text = text; + if (completed) + { + canvasGroup.alpha = 0.1f; + } + } +} diff --git a/GameCode/QuestMenu.cs b/GameCode/QuestMenu.cs new file mode 100644 index 0000000..df201d3 --- /dev/null +++ b/GameCode/QuestMenu.cs @@ -0,0 +1,21 @@ +using System.Collections.Generic; +using UnityEngine; + +public class QuestMenu : MonoBehaviour +{ + public void UpdateVisualization(LevelData _levelData, List _quests) + { + for (int i = 0; i < base.transform.childCount; i++) + { + QuestTagUI component = base.transform.GetChild(i).GetComponent(); + if (i < _quests.Count) + { + component.UpdateVisualization(_quests[i], _levelData); + } + else + { + component.UpdateVisualization(null, null); + } + } + } +} diff --git a/GameCode/QuestTagUI.cs b/GameCode/QuestTagUI.cs new file mode 100644 index 0000000..0930a9c --- /dev/null +++ b/GameCode/QuestTagUI.cs @@ -0,0 +1,107 @@ +using TMPro; +using UnityEngine; +using UnityEngine.UI; + +public class QuestTagUI : MonoBehaviour +{ + [Header("Setup")] + public Image completeImage; + + public Color completeColor; + + public Color incompleteColor; + + public TMP_Text description; + + public Image icon1; + + public GameObject crossedOut1; + + public Image icon2; + + public GameObject crossedOut2; + + public Image icon3; + + public GameObject crossedOut3; + + public TMP_Text goalNumber; + + [Header("Quest Texts")] + public string completeLevel = "Achieve a victory."; + + public string achieveScoreOf = "Achieve score:"; + + public string winWith = "Win with:"; + + public string winWithout = "Win without:"; + + public void UpdateVisualization(Quest _quest, LevelData _levelData) + { + if (_quest == null || _levelData == null) + { + base.gameObject.SetActive(value: false); + return; + } + base.gameObject.SetActive(value: true); + bool flag = _quest.CheckBeaten(_levelData); + completeImage.color = (flag ? completeColor : incompleteColor); + crossedOut1.SetActive(value: false); + crossedOut2.SetActive(value: false); + crossedOut3.SetActive(value: false); + icon1.gameObject.SetActive(value: false); + icon2.gameObject.SetActive(value: false); + icon3.gameObject.SetActive(value: false); + goalNumber.gameObject.SetActive(value: false); + switch (_quest.questType) + { + case Quest.EType.BeatTheLevel: + description.text = completeLevel; + break; + case Quest.EType.AchieveScoreOf: + description.text = achieveScoreOf; + goalNumber.gameObject.SetActive(value: true); + goalNumber.text = _quest.achieveScoreOf.ToString(); + break; + case Quest.EType.BeatTheLevelWith: + icon1.gameObject.SetActive(_quest.beatTheLevelWith.Count > 0); + icon2.gameObject.SetActive(_quest.beatTheLevelWith.Count > 1); + icon3.gameObject.SetActive(_quest.beatTheLevelWith.Count > 2); + if (_quest.beatTheLevelWith.Count > 0) + { + icon1.sprite = _quest.beatTheLevelWith[0].icon; + } + if (_quest.beatTheLevelWith.Count > 1) + { + icon2.sprite = _quest.beatTheLevelWith[1].icon; + } + if (_quest.beatTheLevelWith.Count > 2) + { + icon3.sprite = _quest.beatTheLevelWith[2].icon; + } + description.text = winWith; + break; + case Quest.EType.BeatTheLevelWithout: + description.text = winWithout; + crossedOut1.SetActive(value: true); + crossedOut2.SetActive(value: true); + crossedOut3.SetActive(value: true); + icon1.gameObject.SetActive(_quest.beatTheLevelWithout.Count > 0); + icon2.gameObject.SetActive(_quest.beatTheLevelWithout.Count > 1); + icon3.gameObject.SetActive(_quest.beatTheLevelWithout.Count > 2); + if (_quest.beatTheLevelWithout.Count > 0) + { + icon1.sprite = _quest.beatTheLevelWithout[0].icon; + } + if (_quest.beatTheLevelWithout.Count > 1) + { + icon3.sprite = _quest.beatTheLevelWithout[1].icon; + } + if (_quest.beatTheLevelWithout.Count > 2) + { + icon3.sprite = _quest.beatTheLevelWithout[2].icon; + } + break; + } + } +} diff --git a/GameCode/RacerRoll.cs b/GameCode/RacerRoll.cs new file mode 100644 index 0000000..bb85388 --- /dev/null +++ b/GameCode/RacerRoll.cs @@ -0,0 +1,16 @@ +using Pathfinding.RVO; +using UnityEngine; + +public class RacerRoll : MonoBehaviour +{ + public RVOController rvo; + + public float speedMultiplier = 90f; + + public Transform targetTransform; + + private void Update() + { + targetTransform.Rotate(rvo.velocity.sqrMagnitude * speedMultiplier * Time.deltaTime, 0f, 0f, Space.Self); + } +} diff --git a/GameCode/ReduceChildrensBuildRequirementIfPerk.cs b/GameCode/ReduceChildrensBuildRequirementIfPerk.cs new file mode 100644 index 0000000..02df554 --- /dev/null +++ b/GameCode/ReduceChildrensBuildRequirementIfPerk.cs @@ -0,0 +1,24 @@ +using UnityEngine; + +public class ReduceChildrensBuildRequirementIfPerk : MonoBehaviour +{ + [SerializeField] + private Equippable perk; + + private void Update() + { + if (PerkManager.instance.CurrentlyEquipped.Contains(perk)) + { + BuildSlot component = GetComponent(); + Debug.Log("Reduced build requirements of " + component.IsRootOf.Count); + foreach (BuildSlot item in component.IsRootOf) + { + if (item.ActivatorBuilding == component) + { + item.ActivatorLevel = Mathf.Max(0, item.ActivatorLevel - 1); + } + } + } + Object.Destroy(this); + } +} diff --git a/GameCode/ResetAudioSettings.cs b/GameCode/ResetAudioSettings.cs new file mode 100644 index 0000000..23fde41 --- /dev/null +++ b/GameCode/ResetAudioSettings.cs @@ -0,0 +1,13 @@ +using UnityEngine; + +public class ResetAudioSettings : MonoBehaviour +{ + public GameObject objToRefresh; + + public void Trigger() + { + SettingsManager.Instance.ResetAudioSettings(); + objToRefresh.SetActive(value: false); + objToRefresh.SetActive(value: true); + } +} diff --git a/GameCode/ResolutionExtensions.cs b/GameCode/ResolutionExtensions.cs new file mode 100644 index 0000000..989e12e --- /dev/null +++ b/GameCode/ResolutionExtensions.cs @@ -0,0 +1,13 @@ +using UnityEngine; + +public static class ResolutionExtensions +{ + public static bool CompareResolutions(this Resolution resA, Resolution resB) + { + if (resA.width == resB.width) + { + return resA.height == resB.height; + } + return false; + } +} diff --git a/GameCode/RevivePanel.cs b/GameCode/RevivePanel.cs new file mode 100644 index 0000000..d1e6c6e --- /dev/null +++ b/GameCode/RevivePanel.cs @@ -0,0 +1,29 @@ +using MPUIKIT; +using TMPro; +using UnityEngine; + +public class RevivePanel : MonoBehaviour +{ + public GameObject revivePanel; + + public TMP_Text counterText; + + public MPImage fill; + + public AutoRevive playerReviveComponent; + + private void Update() + { + float timeTillRevive = playerReviveComponent.TimeTillRevive; + if (timeTillRevive > 0f && LocalGamestate.Instance.CurrentState == LocalGamestate.State.InMatch) + { + revivePanel.SetActive(value: true); + counterText.text = Mathf.Floor(timeTillRevive).ToString(); + fill.fillAmount = Mathf.InverseLerp(playerReviveComponent.reviveAfterBeingKnockedOutFor, 0f, timeTillRevive); + } + else + { + revivePanel.SetActive(value: false); + } + } +} diff --git a/GameCode/RidingDamager.cs b/GameCode/RidingDamager.cs new file mode 100644 index 0000000..ad8148d --- /dev/null +++ b/GameCode/RidingDamager.cs @@ -0,0 +1,75 @@ +using System.Collections.Generic; +using UnityEngine; + +public class RidingDamager : MonoBehaviour +{ + public Equippable requiredUpgrade; + + public LayerMask lmRecieveDamage; + + public List damage; + + private BoxCollider myCollider; + + private Collider[] tempColliders = new Collider[50]; + + public float cooldownPerObject = 4f; + + private PlayerMovement playerMovement; + + private PlayerUpgradeManager upgradeManager; + + private BlacksmithUpgrades blacksmithUpgrades; + + private List recentlyHit = new List(); + + private List recentlyHitWhen = new List(); + + private float time; + + public float DamageMultiplyer => upgradeManager.playerDamageMultiplyer * blacksmithUpgrades.meleeDamage; + + private void Start() + { + if (!PerkManager.IsEquipped(requiredUpgrade)) + { + Object.Destroy(base.gameObject); + return; + } + myCollider = GetComponent(); + playerMovement = GetComponentInParent(); + upgradeManager = PlayerUpgradeManager.instance; + blacksmithUpgrades = BlacksmithUpgrades.instance; + } + + private void Update() + { + Vector3 center = base.transform.localToWorldMatrix.MultiplyPoint(myCollider.center); + Vector3 halfExtents = base.transform.localToWorldMatrix.MultiplyVector(myCollider.size); + if (playerMovement.Moving && playerMovement.enabled) + { + Physics.OverlapBoxNonAlloc(center, halfExtents, tempColliders, base.transform.rotation, lmRecieveDamage); + for (int i = 0; i < tempColliders.Length && !(tempColliders[i] == null); i++) + { + DealWithColliderHit(tempColliders[i]); + } + } + time += Time.deltaTime; + while (recentlyHitWhen.Count > 0 && time - recentlyHitWhen[0] > cooldownPerObject) + { + recentlyHitWhen.RemoveAt(0); + recentlyHit.RemoveAt(0); + } + } + + private void DealWithColliderHit(Collider other) + { + TaggedObject componentInParent = other.GetComponentInParent(); + if ((bool)componentInParent && !recentlyHit.Contains(componentInParent) && componentInParent.Tags.Contains(TagManager.ETag.EnemyOwned)) + { + componentInParent.Hp.TakeDamage(Weapon.CalculateDamageGeneral(componentInParent, damage, DamageMultiplyer)); + recentlyHit.Add(componentInParent); + recentlyHitWhen.Add(time); + } + } +} diff --git a/GameCode/RiverScroller.cs b/GameCode/RiverScroller.cs new file mode 100644 index 0000000..65f9f3c --- /dev/null +++ b/GameCode/RiverScroller.cs @@ -0,0 +1,18 @@ +using UnityEngine; + +public class RiverScroller : MonoBehaviour +{ + public Material mat; + + public float speed; + + public string propertyName; + + private float xOffset; + + private void Update() + { + xOffset += Time.deltaTime * speed; + mat.SetTextureOffset(propertyName, new Vector2(xOffset, 0f)); + } +} diff --git a/GameCode/RotateForwardToRVOVelocity.cs b/GameCode/RotateForwardToRVOVelocity.cs new file mode 100644 index 0000000..3bbf35f --- /dev/null +++ b/GameCode/RotateForwardToRVOVelocity.cs @@ -0,0 +1,64 @@ +using UnityEngine; + +public class RotateForwardToRVOVelocity : MonoBehaviour +{ + public Transform transformToRotate; + + public PathfindMovement target; + + public AutoAttack attack; + + public float regularSmoothTime = 0.1f; + + public float attackSmoothTime = 0.05f; + + private Vector3 desiredForward; + + private Vector3 angularVelocityRef; + + private float minSqVelocity = 1.5f; + + private bool attackOverride; + + private void Start() + { + if ((bool)attack) + { + attack.onAttackTriggered.AddListener(OnAttack); + } + desiredForward = transformToRotate.forward; + } + + private void Update() + { + if ((bool)target && target.RVO.velocity.sqrMagnitude > minSqVelocity && !attackOverride) + { + desiredForward = target.RVO.velocity; + desiredForward.y = 0f; + desiredForward.Normalize(); + } + if (Vector3.Angle(transformToRotate.forward, desiredForward) > 3f) + { + if (attackOverride) + { + transformToRotate.forward = Vector3.SmoothDamp(transformToRotate.forward, desiredForward, ref angularVelocityRef, attackSmoothTime); + } + else + { + transformToRotate.forward = Vector3.SmoothDamp(transformToRotate.forward, desiredForward, ref angularVelocityRef, regularSmoothTime); + } + } + else + { + attackOverride = false; + } + } + + private void OnAttack() + { + desiredForward = attack.LastTargetPosition - transformToRotate.position; + desiredForward.y = 0f; + desiredForward.Normalize(); + attackOverride = true; + } +} diff --git a/GameCode/SaveLoadManager.cs b/GameCode/SaveLoadManager.cs new file mode 100644 index 0000000..5a51b9e --- /dev/null +++ b/GameCode/SaveLoadManager.cs @@ -0,0 +1,243 @@ +using System.Collections.Generic; +using System.IO; +using UnityEngine; + +public class SaveLoadManager : MonoBehaviour +{ + public static SaveLoadManager instance; + + [SerializeField] + private int saveFileVersionNr = 1; + + [SerializeField] + private string saveFileName = "ThroneSave.sav"; + + private List saveData = new List(); + + private string[] loadData; + + private LevelProgressManager levelProgressManager; + + private PerkManager perkManager; + + [SerializeField] + private List allEquippablesID = new List(); + + private int iln; + + private string line; + + private string FullSaveFilePath => Path.Combine(Application.persistentDataPath, saveFileName); + + private void Awake() + { + if ((bool)instance) + { + Object.Destroy(base.gameObject); + return; + } + Object.DontDestroyOnLoad(base.gameObject); + instance = this; + } + + private void Start() + { + LoadGame(); + if (DebugController.SaveLoadModeToUse != DebugController.SaveLoadMode.LoadMaxedOutSaveFileOnStartup) + { + if (levelProgressManager.GetLevelDataForScene("Neuland(Tutorial)") == null) + { + SceneTransitionManager.instance.TransitionFromLevelSelectToLevel("Neuland(Tutorial)"); + } + else if (!levelProgressManager.GetLevelDataForScene("Neuland(Tutorial)").beatenBest) + { + SceneTransitionManager.instance.TransitionFromLevelSelectToLevel("Neuland(Tutorial)"); + } + } + } + + public void SaveGame() + { + if (!DebugController.SaveTheGame) + { + DebugLogInEditorOnly("Saving is not enabled!"); + return; + } + saveData.Clear(); + levelProgressManager = LevelProgressManager.instance; + perkManager = PerkManager.instance; + SaveSingle("Save File Version", saveFileVersionNr.ToString()); + SaveSingle("Perk Level", perkManager.level.ToString()); + SaveSingle("Perk XP", perkManager.xp.ToString()); + foreach (KeyValuePair sceneNameToLevelDatum in levelProgressManager.SceneNameToLevelData) + { + string key = sceneNameToLevelDatum.Key; + LevelData value = sceneNameToLevelDatum.Value; + if (value.highscoreBest <= 0 && !value.beatenBest) + { + continue; + } + SaveSingle("Level", key); + SaveSingle("QuestsCompleteWhenLastOnMap", value.questsCompleteWhenLastVisitingMap.ToString()); + SaveSingle("Beaten", value.beatenBest ? "1" : "0"); + if (value.beatenBest) + { + AchievementManager.LevelBeaten(key); + } + SaveSingle("HighscoreV2", value.highscoreBest.ToString()); + SaveList("NetworthV2 / Day", value.dayToDayNetworthBest); + SaveList("ScoreV2 / Day", value.dayToDayScoreBest); + foreach (List item in value.levelHasBeenBeatenWith) + { + List list = new List(); + foreach (Equippable item2 in item) + { + if (!(item2 == null)) + { + list.Add(item2.name); + } + } + SaveList("Beaten With", list); + } + } + File.WriteAllLines(FullSaveFilePath, saveData); + DebugLogInEditorOnly("Game Saved to " + FullSaveFilePath); + } + + public void SaveSingle(string _key, string _data) + { + saveData.Add(_key); + saveData.Add(_data); + saveData.Add(""); + } + + public void SaveList(string _key, List _data) + { + saveData.Add(_key); + saveData.Add(_data.Count.ToString()); + for (int i = 0; i < _data.Count; i++) + { + saveData.Add(_data[i].ToString()); + } + saveData.Add(""); + } + + private void LoadGame() + { + levelProgressManager = LevelProgressManager.instance; + perkManager = PerkManager.instance; + if (DebugController.SaveLoadModeToUse == DebugController.SaveLoadMode.LoadEmptySaveFileOnStartup) + { + DebugLogInEditorOnly("Loading is not enabled!"); + return; + } + if (DebugController.SaveLoadModeToUse == DebugController.SaveLoadMode.LoadMaxedOutSaveFileOnStartup) + { + DebugLogInEditorOnly("Loading maxed out save file with everything unlocked!"); + perkManager.level = 10000; + perkManager.CallAfterLoadToUnlockPerksAndStuff(); + return; + } + if (!File.Exists(FullSaveFilePath)) + { + DebugLogInEditorOnly("No save file was found at " + FullSaveFilePath + " so the load process was canceled."); + return; + } + loadData = File.ReadAllLines(FullSaveFilePath); + LevelData levelData = null; + levelProgressManager.SceneNameToLevelData.Clear(); + for (iln = 0; iln < loadData.Length; iln++) + { + line = loadData[iln]; + switch (line) + { + case "Perk Level": + perkManager.level = int.Parse(ReadNextLn()); + break; + case "Perk XP": + perkManager.xp = int.Parse(ReadNextLn()); + break; + case "Level": + levelData = levelProgressManager.GetLevelDataForScene(ReadNextLn()); + break; + case "QuestsCompleteWhenLastOnMap": + if (levelData != null) + { + levelData.questsCompleteWhenLastVisitingMap = int.Parse(ReadNextLn()); + } + break; + case "Beaten": + if (levelData != null) + { + levelData.beatenBest = ReadNextLn() == "1"; + } + break; + case "HighscoreV2": + if (levelData != null) + { + levelData.highscoreBest = int.Parse(ReadNextLn()); + } + break; + case "NetworthV2 / Day": + if (levelData != null) + { + int num = int.Parse(ReadNextLn()); + levelData.dayToDayNetworthBest.Clear(); + for (int l = 0; l < num; l++) + { + levelData.dayToDayNetworthBest.Add(int.Parse(ReadNextLn())); + } + } + break; + case "ScoreV2 / Day": + if (levelData != null) + { + int num = int.Parse(ReadNextLn()); + levelData.dayToDayScoreBest.Clear(); + for (int k = 0; k < num; k++) + { + levelData.dayToDayScoreBest.Add(int.Parse(ReadNextLn())); + } + } + break; + case "Beaten With": + { + if (levelData == null) + { + break; + } + int num = int.Parse(ReadNextLn()); + List list = new List(); + for (int i = 0; i < num; i++) + { + string text = ReadNextLn(); + Equippable item = null; + for (int j = 0; j < allEquippablesID.Count; j++) + { + if (allEquippablesID[j].name == text) + { + item = allEquippablesID[j]; + } + } + list.Add(item); + } + levelData.levelHasBeenBeatenWith.Add(list); + break; + } + } + } + perkManager.CallAfterLoadToUnlockPerksAndStuff(); + DebugLogInEditorOnly("Loaded Game from " + FullSaveFilePath); + } + + private string ReadNextLn() + { + iln++; + line = loadData[iln]; + return line; + } + + private void DebugLogInEditorOnly(string _log) + { + } +} diff --git a/GameCode/ScaleAnimation.cs b/GameCode/ScaleAnimation.cs new file mode 100644 index 0000000..4cd8dd7 --- /dev/null +++ b/GameCode/ScaleAnimation.cs @@ -0,0 +1,42 @@ +using System.Collections; +using UnityEngine; + +public class ScaleAnimation : OneShotAnimationBase +{ + public AnimationCurve curve; + + public float duration = 0.75f; + + public float targetScale; + + public Transform transformToAnimate; + + private float initialScale = 1f; + + private void Start() + { + initialScale = transformToAnimate.localScale.x; + } + + private IEnumerator Animate() + { + transformToAnimate.localScale = Vector3.one * initialScale; + float timer = 0f; + while (timer < duration) + { + transformToAnimate.localScale = Vector3.one * Mathf.Lerp(initialScale, targetScale, curve.Evaluate(timer / duration)); + timer += Time.deltaTime; + yield return null; + } + transformToAnimate.localScale = Vector3.one * Mathf.Lerp(initialScale, targetScale, curve.Evaluate(timer / duration)); + } + + public override void Trigger() + { + if (base.gameObject.activeInHierarchy) + { + StopAllCoroutines(); + StartCoroutine(Animate()); + } + } +} diff --git a/GameCode/ScalePulse.cs b/GameCode/ScalePulse.cs new file mode 100644 index 0000000..16d6934 --- /dev/null +++ b/GameCode/ScalePulse.cs @@ -0,0 +1,18 @@ +using UnityEngine; + +public class ScalePulse : MonoBehaviour +{ + public AnimationCurve scaleCurve; + + public float scaleIncrease = 0.4f; + + public float pulseSpeed = 1f; + + private float clock; + + private void Update() + { + clock += Time.deltaTime * pulseSpeed; + base.transform.localScale = Vector3.one * (1f + scaleIncrease * scaleCurve.Evaluate(clock)); + } +} diff --git a/GameCode/SceneNameToLevelData.cs b/GameCode/SceneNameToLevelData.cs new file mode 100644 index 0000000..7b8f84f --- /dev/null +++ b/GameCode/SceneNameToLevelData.cs @@ -0,0 +1,6 @@ +using System; + +[Serializable] +public class SceneNameToLevelData : UnitySerializedDictionary +{ +} diff --git a/GameCode/SceneTransitionManager.cs b/GameCode/SceneTransitionManager.cs new file mode 100644 index 0000000..0142bc4 --- /dev/null +++ b/GameCode/SceneTransitionManager.cs @@ -0,0 +1,254 @@ +using System.Collections; +using System.Collections.Generic; +using TMPro; +using UnityEngine; +using UnityEngine.Events; +using UnityEngine.SceneManagement; +using UnityEngine.UI; + +public class SceneTransitionManager : MonoBehaviour +{ + public enum SceneState + { + MainMenu, + LevelSelect, + InGame + } + + public static SceneTransitionManager instance; + + public string uiScene = "_UI"; + + public string mainMenuScene = "_StartMenu"; + + public string levelSelectScene; + + public Image placeholderCloudsTransition; + + public TMP_Text loadingText; + + public float cloudFadeInTime = 1f; + + public float cloudFadeOutTime = 2f; + + [HideInInspector] + public UnityEvent onSceneChange = new UnityEvent(); + + private SceneState currentSceneState; + + private SceneState lastSceneState; + + private int ingameScoreFromLastMatch; + + private int goldBonusScoreFromLastMatch; + + private int mutatorBonusScoreFromLastMatch; + + private string comingFromGameplayScene = ""; + + private int totalScoreFromLastMatch; + + private bool totalScoreFromLastMatchIsNewPersonalRecord; + + private LevelData levelDataFromLastMatch; + + private bool sceneTransitionIsRunning; + + private Color cloudsIn; + + private Color cloudsOut; + + private Coroutine currentTransition; + + public SceneState CurrentSceneState => currentSceneState; + + public SceneState LastSceneState => lastSceneState; + + public int IngameScoreFromLastMatch => ingameScoreFromLastMatch; + + public int GoldBonusScoreFromLastMatch => goldBonusScoreFromLastMatch; + + public int MutatorBonusScoreFromLastMatch => mutatorBonusScoreFromLastMatch; + + public int TotalScoreFromLastMatch => totalScoreFromLastMatch; + + public bool TotalScoreFromLastMatchIsNewPersonalRecord => totalScoreFromLastMatchIsNewPersonalRecord; + + public string ComingFromGameplayScene => comingFromGameplayScene; + + public LevelData LevelDataFromLastMatch => levelDataFromLastMatch; + + public bool SceneTransitionIsRunning => sceneTransitionIsRunning; + + private void Awake() + { + if ((bool)instance) + { + Object.Destroy(base.gameObject); + return; + } + instance = this; + Object.DontDestroyOnLoad(base.transform.root.gameObject); + if (!SceneManager.GetSceneByName(uiScene).IsValid()) + { + SceneManager.LoadScene(uiScene, LoadSceneMode.Additive); + } + cloudsIn = placeholderCloudsTransition.color; + cloudsOut = cloudsIn; + cloudsOut.a = 0f; + loadingText.alpha = 0f; + } + + private void Start() + { + } + + public void TransitionFromLevelSelectToLevel(string _levelname) + { + if (currentSceneState != SceneState.LevelSelect) + { + Debug.LogWarning("You should only transition to a specific level from the level selection scene."); + } + else + { + TransitionToScene(_levelname); + } + } + + public void TransitionFromNullToLevel(string _levelname) + { + TransitionToScene(_levelname); + } + + public void RestartCurrentLevel() + { + TransitionToScene(SceneManager.GetActiveScene().name); + } + + public void TransitionFromGameplayToEndScreen(int _score, int _goldBonusScore, int _mutatorBonusScore) + { + comingFromGameplayScene = SceneManager.GetActiveScene().name; + LevelData levelData = (levelDataFromLastMatch = LevelProgressManager.instance.GetLevelDataForScene(comingFromGameplayScene)); + if (currentSceneState != SceneState.InGame) + { + Debug.LogWarning("You should only transition to the end screen from a gameply level."); + return; + } + ingameScoreFromLastMatch = _score; + goldBonusScoreFromLastMatch = _goldBonusScore; + mutatorBonusScoreFromLastMatch = _mutatorBonusScore; + levelData.highscore = _score + _goldBonusScore + _mutatorBonusScore; + totalScoreFromLastMatch = levelData.highscore; + totalScoreFromLastMatchIsNewPersonalRecord = totalScoreFromLastMatch > levelData.highscoreBest; + UIFrameManager.TriggerEndOfMatch(); + } + + public void TransitionFromEndScreenToLevelSelect() + { + TransitionToScene(levelSelectScene); + } + + private void TransitionToScene(string _scenename) + { + if (!sceneTransitionIsRunning) + { + lastSceneState = currentSceneState; + if (_scenename == levelSelectScene) + { + currentSceneState = SceneState.LevelSelect; + } + else if (_scenename == mainMenuScene) + { + currentSceneState = SceneState.MainMenu; + } + else + { + currentSceneState = SceneState.InGame; + } + onSceneChange.Invoke(); + StartCoroutine(SceneTransitionAnimation(_scenename)); + } + } + + private float FadeFormula(float f) + { + return Mathf.Pow(f, 4f); + } + + private IEnumerator SceneTransitionAnimation(string _scenename) + { + sceneTransitionIsRunning = true; + int sceneCount = SceneManager.sceneCount; + placeholderCloudsTransition.gameObject.SetActive(value: true); + float clock2 = 0f; + while (clock2 <= cloudFadeInTime) + { + float num = Mathf.Clamp(Time.unscaledDeltaTime, 0f, 0.1f); + clock2 += num; + placeholderCloudsTransition.color = Color.Lerp(cloudsOut, cloudsIn, 1f - FadeFormula(1f - clock2 / cloudFadeInTime)); + loadingText.alpha = 1f - FadeFormula(1f - clock2 / cloudFadeInTime); + yield return null; + } + placeholderCloudsTransition.color = cloudsIn; + loadingText.alpha = 1f; + List loadOperations = new List(); + if (sceneCount > 0) + { + for (int num2 = sceneCount - 1; num2 >= 0; num2--) + { + Scene sceneAt = SceneManager.GetSceneAt(num2); + if (sceneAt.name != uiScene) + { + loadOperations.Add(SceneManager.UnloadSceneAsync(sceneAt)); + } + } + } + loadOperations.Add(SceneManager.LoadSceneAsync(_scenename, LoadSceneMode.Additive)); + while (loadOperations.Count > 0) + { + for (int num3 = loadOperations.Count - 1; num3 >= 0; num3--) + { + if (loadOperations[num3].isDone) + { + loadOperations.RemoveAt(num3); + } + } + yield return null; + } + SceneManager.SetActiveScene(SceneManager.GetSceneByName(_scenename)); + UIFrameManager.instance.CloseAllFrames(); + if (_scenename == mainMenuScene) + { + UIFrameManager.instance.SwitchToTitleFrame(); + } + clock2 = 0f; + while (clock2 <= cloudFadeOutTime) + { + float num4 = Mathf.Clamp(Time.unscaledDeltaTime, 0f, 0.1f); + clock2 += num4; + placeholderCloudsTransition.color = Color.Lerp(cloudsIn, cloudsOut, FadeFormula(clock2 / cloudFadeOutTime)); + loadingText.alpha = 1f - FadeFormula(1f - clock2 / cloudFadeInTime); + yield return null; + } + placeholderCloudsTransition.color = cloudsOut; + loadingText.alpha = 0f; + placeholderCloudsTransition.gameObject.SetActive(value: false); + sceneTransitionIsRunning = false; + } + + public void TransitionFromNullToLevelSelect() + { + TransitionToScene(levelSelectScene); + } + + public void TransitionFromLevelToLevelSelect() + { + comingFromGameplayScene = SceneManager.GetActiveScene().name; + TransitionToScene(levelSelectScene); + } + + public void TransitionToMainMenu() + { + TransitionToScene(mainMenuScene); + } +} diff --git a/GameCode/ScoreManager.cs b/GameCode/ScoreManager.cs new file mode 100644 index 0000000..daccfb5 --- /dev/null +++ b/GameCode/ScoreManager.cs @@ -0,0 +1,150 @@ +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Events; + +public class ScoreManager : MonoBehaviour, DayNightCycle.IDaytimeSensitive +{ + private static ScoreManager instance; + + private EnemySpawner enemySpawner; + + [Min(0f)] + public int baseScorePerNight = 100; + + [Min(0f)] + public int protectionScorePerNight = 200; + + [Min(0f)] + public int timeScorePerNight = 200; + + [Min(0f)] + public float timebonusMultiplier = 1f; + + [Min(0f)] + public float timeBonusMinTime = 10f; + + [Min(0f)] + public float timeBonusMaxTime = 120f; + + [Min(0f)] + public float protectionScoreMultiplier = 1f; + + [Range(1f, 2f)] + public float scoreExponent = 2f; + + private int currentScore; + + private List buildingTags = new List(new TagManager.ETag[2] + { + TagManager.ETag.Building, + TagManager.ETag.PlayerOwned + }); + + [HideInInspector] + public UnityEvent OnNightScoreAdd = new UnityEvent(); + + private bool tauntTheTiger; + + private bool tauntTheTurtle; + + private bool tauntTheFalcon; + + private bool tauntTheRat; + + private float scoreMultiplyerFromPerks; + + public float victoryGoldBonusMultiplyer = 10f; + + public static ScoreManager Instance => instance; + + public int CurrentScore => currentScore; + + public int VictoryGoldBonus => Mathf.CeilToInt((float)PlayerInteraction.instance.TrueBalance * victoryGoldBonusMultiplyer); + + public int VictoryMutatorBonus + { + get + { + float num = 1f; + foreach (Equippable item in PerkManager.instance.CurrentlyEquipped) + { + if (item.GetType() == typeof(EquippableMutation)) + { + num *= ((EquippableMutation)item).scoreMultiplyerOnWin; + } + } + return Mathf.CeilToInt((float)(currentScore + VictoryGoldBonus) * (num - 1f)); + } + } + + public int MaxScorePerNight => Mathf.RoundToInt((float)(baseScorePerNight + protectionScorePerNight + timeScorePerNight) * scoreMultiplyerFromPerks); + + private void Awake() + { + if (instance != null) + { + Debug.LogWarning("More than one Scoremanger in Scene. Old Scoremanager destroyed."); + Object.Destroy(instance); + } + instance = this; + } + + private void Start() + { + enemySpawner = EnemySpawner.instance; + DayNightCycle.Instance.RegisterDaytimeSensitiveObject(this); + tauntTheTiger = PerkManager.IsEquipped(PerkManager.instance.tigerGodPerk); + tauntTheTurtle = PerkManager.IsEquipped(PerkManager.instance.turtleGodPerk); + tauntTheFalcon = PerkManager.IsEquipped(PerkManager.instance.falconGodPerk); + tauntTheRat = PerkManager.IsEquipped(PerkManager.instance.ratGodPerk); + scoreMultiplyerFromPerks = 1f; + } + + public void CalculateEndOfNightScore() + { + int num = Mathf.RoundToInt((float)baseScorePerNight * scoreMultiplyerFromPerks); + int num2 = num; + float currentNightLength = DayNightCycle.Instance.CurrentNightLength; + float lastSpawnPeriodDuration = enemySpawner.LastSpawnPeriodDuration; + int num3 = Mathf.RoundToInt(Mathf.Pow(Mathf.InverseLerp(timeBonusMaxTime + lastSpawnPeriodDuration, timeBonusMinTime + lastSpawnPeriodDuration, currentNightLength), scoreExponent) * (float)timeScorePerNight * scoreMultiplyerFromPerks); + num2 += num3; + List list = new List(); + TagManager.instance.FindAllTaggedObjectsWithTags(list, buildingTags, null); + int num4 = 0; + foreach (TaggedObject item in list) + { + BuildingInteractor componentInChildren = item.transform.parent.GetComponentInChildren(includeInactive: true); + if ((bool)componentInChildren && componentInChildren.KnockedOutTonight) + { + num4++; + } + } + float f = 1f - Mathf.InverseLerp(0f, list.Count, num4); + f = Mathf.Pow(f, scoreExponent); + int num5 = Mathf.RoundToInt((float)protectionScorePerNight * f * scoreMultiplyerFromPerks); + num2 += num5; + currentScore += num2; + OnNightScoreAdd.Invoke(num, num3, f, num5); + LevelData levelDataForActiveScene = LevelProgressManager.instance.GetLevelDataForActiveScene(); + levelDataForActiveScene.highscore = currentScore; + levelDataForActiveScene.dayToDayScore.Add(currentScore); + } + + public void OnDusk() + { + } + + public void OnDawn_AfterSunrise() + { + } + + public void OnDawn_BeforeSunrise() + { + CalculateEndOfNightScore(); + } + + public void AddDebugPoints(int amount) + { + currentScore += amount; + } +} diff --git a/GameCode/ScoreTag.cs b/GameCode/ScoreTag.cs new file mode 100644 index 0000000..1d78442 --- /dev/null +++ b/GameCode/ScoreTag.cs @@ -0,0 +1,21 @@ +using TMPro; +using UnityEngine; + +public class ScoreTag : MonoBehaviour +{ + public GameObject highlight; + + public TMP_Text rank; + + public TMP_Text username; + + public TMP_Text score; + + public void SetNameAndScore(string _name, int _score, int _rank, bool isPlayer) + { + highlight.SetActive(isPlayer); + rank.text = _rank + "."; + username.text = _name; + score.text = _score.ToString(); + } +} diff --git a/GameCode/ScreenMarker.cs b/GameCode/ScreenMarker.cs new file mode 100644 index 0000000..488c22b --- /dev/null +++ b/GameCode/ScreenMarker.cs @@ -0,0 +1,197 @@ +using MPUIKIT; +using TMPro; +using UnityEngine; + +public class ScreenMarker : MonoBehaviour +{ + [Header("Content")] + [SerializeField] + private Sprite showSprite; + + [SerializeField] + private int showNumber; + + [Header("Setup")] + [SerializeField] + private GameObject screenMarkerPrefab; + + private GameObject myUiMarkerGameObject; + + private EnemyScreenMarkerUIHelper uiMarkerData; + + private RectTransform screenMarkerUI; + + private Camera cam; + + private MPImageBasic enemyIcon; + + private TMP_Text enemyNumber; + + private float myRandomVal; + + private Vector2 unclampedScreenPos; + + private Vector2 clampedScreenPos; + + public bool rotateTowardsTargetWhenOffscreen; + + public bool showWhenOnScreen = true; + + public bool showWhenOffScreen = true; + + public Rect checkOnScreenRect; + + private bool onScreen; + + public float MyRandomVal => myRandomVal; + + public Vector2 UnclampedScreenPos + { + get + { + return unclampedScreenPos; + } + set + { + unclampedScreenPos = value; + } + } + + public Vector2 ClampedScreenPos + { + get + { + return clampedScreenPos; + } + set + { + clampedScreenPos = value; + } + } + + public bool OnScreen + { + get + { + return onScreen; + } + set + { + onScreen = value; + } + } + + public Sprite Sprite => showSprite; + + public int Number => showNumber; + + public Vector2 Position + { + get + { + return screenMarkerUI.localPosition; + } + set + { + screenMarkerUI.localPosition = value; + } + } + + public float ImageRotation + { + get + { + return enemyIcon.transform.rotation.z; + } + set + { + enemyIcon.transform.rotation = Quaternion.Euler(enemyIcon.transform.rotation.x, enemyIcon.transform.rotation.y, value); + } + } + + public Rect Rect => screenMarkerUI.rect; + + private void Start() + { + cam = Camera.main; + myUiMarkerGameObject = Object.Instantiate(screenMarkerPrefab, UIFrameManager.instance.OnScreenMarkerContainer); + uiMarkerData = myUiMarkerGameObject.GetComponent(); + enemyIcon = uiMarkerData.enemyIcon; + enemyNumber = uiMarkerData.enemyNumber; + screenMarkerUI = (RectTransform)myUiMarkerGameObject.transform; + SetSprite(showSprite); + SetNumber(showNumber); + ScreenMarkerManager.instance.RegisterScreenMarker(this); + myRandomVal = Random.value; + SceneTransitionManager.instance.onSceneChange.AddListener(KillOnSceneChange); + } + + public void SetSprite(Sprite _sprite) + { + if (!(_sprite == null)) + { + showSprite = _sprite; + if ((bool)enemyIcon) + { + enemyIcon.sprite = _sprite; + } + } + } + + public void Show(bool _show) + { + if (myUiMarkerGameObject.activeSelf != _show) + { + myUiMarkerGameObject.SetActive(_show); + } + } + + public void SetNumber(int _number) + { + showNumber = _number; + if ((bool)enemyNumber) + { + enemyNumber.text = showNumber.ToString(); + enemyNumber.enabled = showNumber > 0; + } + } + + private void OnEnable() + { + if ((bool)myUiMarkerGameObject) + { + myUiMarkerGameObject.SetActive(value: true); + } + if ((bool)ScreenMarkerManager.instance) + { + ScreenMarkerManager.instance.RegisterScreenMarker(this); + } + } + + private void OnDisable() + { + if ((bool)myUiMarkerGameObject) + { + myUiMarkerGameObject.SetActive(value: false); + } + if ((bool)ScreenMarkerManager.instance) + { + ScreenMarkerManager.instance.UnregisterScreenMarker(this); + } + } + + private void OnDestroy() + { + if ((bool)myUiMarkerGameObject) + { + Object.Destroy(myUiMarkerGameObject); + } + ScreenMarkerManager.instance.UnregisterScreenMarker(this); + } + + private void KillOnSceneChange() + { + Object.Destroy(myUiMarkerGameObject); + Object.Destroy(base.gameObject); + } +} diff --git a/GameCode/ScreenMarkerCanvasHelper.cs b/GameCode/ScreenMarkerCanvasHelper.cs new file mode 100644 index 0000000..5f047c7 --- /dev/null +++ b/GameCode/ScreenMarkerCanvasHelper.cs @@ -0,0 +1,19 @@ +using UnityEngine; + +public class ScreenMarkerCanvasHelper : MonoBehaviour +{ + public static ScreenMarkerCanvasHelper instance; + + [SerializeField] + private RectTransform ownRT; + + public float Height => ownRT.sizeDelta.y; + + private void Awake() + { + if (instance == null) + { + instance = this; + } + } +} diff --git a/GameCode/ScreenMarkerIcon.cs b/GameCode/ScreenMarkerIcon.cs new file mode 100644 index 0000000..82f89af --- /dev/null +++ b/GameCode/ScreenMarkerIcon.cs @@ -0,0 +1,6 @@ +using UnityEngine; + +public class ScreenMarkerIcon : MonoBehaviour +{ + public Sprite sprite; +} diff --git a/GameCode/ScreenMarkerManager.cs b/GameCode/ScreenMarkerManager.cs new file mode 100644 index 0000000..155aae9 --- /dev/null +++ b/GameCode/ScreenMarkerManager.cs @@ -0,0 +1,284 @@ +using System.Collections.Generic; +using UnityEngine; + +public class ScreenMarkerManager : MonoBehaviour +{ + public enum MarkerMode + { + Direction, + ClampedPos + } + + private class ComparePositionX : IComparer + { + public int Compare(ScreenMarker a, ScreenMarker b) + { + if (!object.Equals(a.UnclampedScreenPos.x, b.UnclampedScreenPos.x)) + { + return Comparer.Default.Compare(a.UnclampedScreenPos.x, b.UnclampedScreenPos.x); + } + return Comparer.Default.Compare(a.MyRandomVal - (float)a.Number, b.MyRandomVal - (float)b.Number); + } + } + + private class ComparePositionY : IComparer + { + public int Compare(ScreenMarker a, ScreenMarker b) + { + if (!object.Equals(a.UnclampedScreenPos.y, b.UnclampedScreenPos.y)) + { + return Comparer.Default.Compare(a.UnclampedScreenPos.y, b.UnclampedScreenPos.y); + } + return Comparer.Default.Compare(a.MyRandomVal - (float)a.Number, b.MyRandomVal - (float)b.Number); + } + } + + public static ScreenMarkerManager instance; + + private List screenMarkersActive = new List(); + + private List screenMarkersToShow = new List(); + + private Dictionary screenMarkerInGroup = new Dictionary(); + + private List> screenMarkerGroups = new List>(); + + private Camera cam; + + private float ratio; + + private float clampY; + + private float clampX; + + private int frame; + + [SerializeField] + private MarkerMode markerMode; + + private float FIXED_CANVAS_HEIGHT => ScreenMarkerCanvasHelper.instance.Height; + + private void Awake() + { + instance = this; + } + + private void Start() + { + cam = Camera.main; + UpdateCam(); + } + + private void UpdateCam() + { + ratio = cam.pixelRect.width / cam.pixelRect.height; + clampY = FIXED_CANVAS_HEIGHT / 2f; + clampX = FIXED_CANVAS_HEIGHT / 2f * ratio; + } + + public void RegisterScreenMarker(ScreenMarker _sm) + { + if (!screenMarkersActive.Contains(_sm)) + { + screenMarkersActive.Add(_sm); + } + } + + public void UnregisterScreenMarker(ScreenMarker _sm) + { + if (screenMarkersActive.Contains(_sm)) + { + screenMarkersActive.Remove(_sm); + } + } + + private void Update() + { + frame++; + if (frame < 2) + { + return; + } + UpdateCam(); + screenMarkersToShow.Clear(); + for (int num = screenMarkersActive.Count - 1; num >= 0; num--) + { + UpdateMarkerPosition(screenMarkersActive[num]); + } + for (int i = 0; i < screenMarkerGroups.Count; i++) + { + screenMarkerGroups[i].Clear(); + } + screenMarkerInGroup.Clear(); + while (screenMarkerGroups.Count < screenMarkersToShow.Count) + { + screenMarkerGroups.Add(new List()); + } + for (int j = 0; j < screenMarkersToShow.Count; j++) + { + screenMarkerGroups[j].Add(screenMarkersToShow[j]); + screenMarkerInGroup.Add(screenMarkersToShow[j], j); + } + bool flag = true; + int num2 = 30; + while (flag && num2 > 0) + { + num2--; + bool flag2 = false; + for (int k = 0; k < screenMarkersToShow.Count; k++) + { + ScreenMarker screenMarker = screenMarkersToShow[k]; + for (int l = k + 1; l < screenMarkersToShow.Count; l++) + { + ScreenMarker screenMarker2 = screenMarkersToShow[l]; + if (!CheckOverlap(screenMarker, screenMarker2)) + { + continue; + } + int num3 = screenMarkerInGroup[screenMarker]; + int num4 = screenMarkerInGroup[screenMarker2]; + if (num3 != num4) + { + flag2 = true; + for (int m = 0; m < screenMarkerGroups[num4].Count; m++) + { + ScreenMarker screenMarker3 = screenMarkerGroups[num4][m]; + screenMarkerGroups[num4].Remove(screenMarker3); + screenMarkerGroups[num3].Add(screenMarker3); + screenMarkerInGroup[screenMarker3] = num3; + } + } + } + } + flag = flag2; + if (flag2) + { + for (int n = 0; n < screenMarkerGroups.Count; n++) + { + FormatGroup(screenMarkerGroups[n]); + } + } + } + for (int num5 = 0; num5 < screenMarkersToShow.Count; num5++) + { + ScreenMarker screenMarker4 = screenMarkersToShow[num5]; + if (screenMarker4.rotateTowardsTargetWhenOffscreen) + { + if (screenMarker4.OnScreen) + { + screenMarker4.ImageRotation = 0f; + } + else + { + screenMarker4.ImageRotation = Vector2.SignedAngle(Vector2.down, screenMarker4.UnclampedScreenPos - screenMarker4.Position); + } + } + } + } + + private bool CheckOverlap(ScreenMarker _sm1, ScreenMarker _sm2) + { + if (_sm1.Rect != _sm2.Rect) + { + return false; + } + if (_sm1.UnclampedScreenPos == _sm2.UnclampedScreenPos) + { + return true; + } + Rect rect = _sm1.Rect; + Rect rect2 = _sm2.Rect; + if (Mathf.Abs(_sm1.Position.x - _sm2.Position.x) > Mathf.Abs(rect.width + rect2.width) / 2f) + { + return false; + } + if (Mathf.Abs(_sm1.Position.y - _sm2.Position.y) > Mathf.Abs(rect.height + rect2.height) / 2f) + { + return false; + } + return true; + } + + private void FormatGroup(List _group) + { + if (_group.Count <= 0) + { + return; + } + Vector2 zero = Vector2.zero; + float num = 0f; + float num2 = 0f; + float num3 = 0f; + float num4 = 0f; + for (int i = 0; i < _group.Count; i++) + { + zero += _group[i].ClampedScreenPos; + num3 += _group[i].Rect.width; + num4 += _group[i].Rect.height; + if (i > 0) + { + num -= _group[i].Rect.width / 2f; + num2 -= _group[i].Rect.height / 2f; + } + } + zero /= (float)_group.Count; + if (Mathf.Abs(zero.x / clampX) < Mathf.Abs(zero.y / clampY)) + { + zero = new Vector2(Mathf.Clamp(zero.x, 0f - clampX + num3 / 2f, clampX - num3 / 2f), zero.y); + _group.Sort(new ComparePositionX()); + for (int j = 0; j < _group.Count; j++) + { + _group[j].Position = zero + Vector2.right * (_group[j].Rect.width * (float)j + num); + } + } + else + { + zero = new Vector2(zero.x, Mathf.Clamp(zero.y, 0f - clampY + num4 / 2f, clampY - num4 / 2f)); + _group.Sort(new ComparePositionY()); + for (int k = 0; k < _group.Count; k++) + { + _group[k].Position = zero + Vector2.down * (_group[k].Rect.height * (float)k + num2); + } + } + } + + public void UpdateMarkerPosition(ScreenMarker _sm) + { + float num = cam.pixelRect.height / FIXED_CANVAS_HEIGHT; + Vector3 vector = cam.WorldToScreenPoint(_sm.transform.position); + Vector2 vector3 = (_sm.UnclampedScreenPos = new Vector2(vector.x - cam.pixelRect.width * 0.5f, vector.y - cam.pixelRect.height * 0.5f) / num); + bool flag = true; + if (Mathf.Abs(vector3.y) > clampY - _sm.checkOnScreenRect.height / 2f) + { + flag = false; + } + else if (Mathf.Abs(vector3.x) > clampX - _sm.checkOnScreenRect.width / 2f) + { + flag = false; + } + _sm.OnScreen = flag; + if ((flag && _sm.showWhenOnScreen) || (!flag && _sm.showWhenOffScreen)) + { + screenMarkersToShow.Add(_sm); + _sm.Show(_show: true); + if (markerMode == MarkerMode.Direction) + { + float num2 = (clampX - _sm.Rect.width / 2f) / Mathf.Abs(vector3.x); + float num3 = (clampY - _sm.Rect.height / 2f) / Mathf.Abs(vector3.y); + float num4 = Mathf.Min(num2, num3, 1f); + vector3 = new Vector2(vector3.x, vector3.y) * num4; + } + else + { + Rect rect = _sm.Rect; + vector3 = new Vector2(Mathf.Clamp(vector3.x, 0f - clampX + rect.width / 2f, clampX - rect.width / 2f), Mathf.Clamp(vector3.y, 0f - clampY + rect.height / 2f, clampY - rect.height / 2f)); + } + _sm.Position = vector3; + _sm.ClampedScreenPos = vector3; + } + else + { + _sm.Show(_show: false); + } + } +} diff --git a/GameCode/SelfDestructWhenInRangeOf.cs b/GameCode/SelfDestructWhenInRangeOf.cs new file mode 100644 index 0000000..8ab0e29 --- /dev/null +++ b/GameCode/SelfDestructWhenInRangeOf.cs @@ -0,0 +1,33 @@ +using UnityEngine; + +public class SelfDestructWhenInRangeOf : MonoBehaviour +{ + [SerializeField] + private TargetPriority selfDestructIfInRangeOf; + + [SerializeField] + private float checkInterval = 0.5f; + + private float timeTillNextCheck; + + private Hp hp; + + private void Start() + { + hp = GetComponent(); + timeTillNextCheck = checkInterval; + } + + private void Update() + { + timeTillNextCheck -= Time.deltaTime; + if (timeTillNextCheck <= 0f) + { + timeTillNextCheck = checkInterval; + if (selfDestructIfInRangeOf.FindClosestTaggedObject(base.transform.position) != null && (bool)hp) + { + hp.TakeDamage(1E+09f); + } + } + } +} diff --git a/GameCode/SetStateWhenMacOSX.cs b/GameCode/SetStateWhenMacOSX.cs new file mode 100644 index 0000000..6db5d60 --- /dev/null +++ b/GameCode/SetStateWhenMacOSX.cs @@ -0,0 +1,13 @@ +using UnityEngine; + +public class SetStateWhenMacOSX : MonoBehaviour +{ + public bool activeOnMacOSX; + + public bool activeElsewhere; + + private void Awake() + { + base.gameObject.SetActive(activeElsewhere); + } +} diff --git a/GameCode/SetWidthToTarget.cs b/GameCode/SetWidthToTarget.cs new file mode 100644 index 0000000..fa5c6b6 --- /dev/null +++ b/GameCode/SetWidthToTarget.cs @@ -0,0 +1,29 @@ +using UnityEngine; + +public class SetWidthToTarget : MonoBehaviour +{ + public RectTransform target; + + public float padding; + + public float minWidth = 800f; + + private RectTransform rt; + + private void Awake() + { + rt = GetComponent(); + if (rt.sizeDelta.x < minWidth) + { + rt.sizeDelta = new Vector2(minWidth, rt.sizeDelta.y); + } + } + + private void Update() + { + if (target.sizeDelta.x + padding * 2f > minWidth && !Mathf.Approximately(rt.sizeDelta.x - padding * 2f, target.sizeDelta.x)) + { + rt.sizeDelta = new Vector2(target.sizeDelta.x + padding * 2f, rt.sizeDelta.y); + } + } +} diff --git a/GameCode/SettingsAntiAliasing.cs b/GameCode/SettingsAntiAliasing.cs new file mode 100644 index 0000000..e2a19a6 --- /dev/null +++ b/GameCode/SettingsAntiAliasing.cs @@ -0,0 +1,26 @@ +using UnityEngine; + +public class SettingsAntiAliasing : MonoBehaviour +{ + public EnumSelector selector; + + private void Start() + { + selector.onChange.AddListener(OnChange); + } + + private void OnEnable() + { + selector.options.Clear(); + selector.options.AddRange(new string[4] { "Disabled", "2x", "4x", "8x" }); + if ((bool)SettingsManager.Instance) + { + selector.SetIndex(SettingsManager.AALevelToInt(SettingsManager.Instance.AntiAliasing)); + } + } + + private void OnChange() + { + SettingsManager.Instance.SetAntiAliasing(SettingsManager.IntToAALevel(selector.Index)); + } +} diff --git a/GameCode/SettingsAudioVolume.cs b/GameCode/SettingsAudioVolume.cs new file mode 100644 index 0000000..cadeddb --- /dev/null +++ b/GameCode/SettingsAudioVolume.cs @@ -0,0 +1,26 @@ +using UnityEngine; + +public class SettingsAudioVolume : MonoBehaviour +{ + public TFUISlider target; + + public SettingsManager.MixerChannel channel; + + private void OnEnable() + { + if (SettingsManager.Instance != null) + { + target.SetValue(SettingsManager.Instance.GetAudioVolume(channel)); + } + } + + private void Start() + { + target.onChange.AddListener(OnChange); + } + + private void OnChange() + { + SettingsManager.Instance.SetAudioValue(target.value, channel); + } +} diff --git a/GameCode/SettingsFullscreen.cs b/GameCode/SettingsFullscreen.cs new file mode 100644 index 0000000..4d6ba9f --- /dev/null +++ b/GameCode/SettingsFullscreen.cs @@ -0,0 +1,19 @@ +using UnityEngine; + +public class SettingsFullscreen : MonoBehaviour +{ + public Checkbox checkbox; + + public void OnApply() + { + SettingsManager.Instance.SetFullscreen(checkbox.state); + } + + private void OnEnable() + { + if ((bool)SettingsManager.Instance) + { + checkbox.SetState(SettingsManager.Instance.Fullscreen); + } + } +} diff --git a/GameCode/SettingsLanguage.cs b/GameCode/SettingsLanguage.cs new file mode 100644 index 0000000..57173ee --- /dev/null +++ b/GameCode/SettingsLanguage.cs @@ -0,0 +1,32 @@ +using I2.Loc; +using UnityEngine; + +public class SettingsLanguage : MonoBehaviour +{ + public EnumSelector selector; + + private void Start() + { + selector.onChange.AddListener(OnChange); + } + + private void OnEnable() + { + selector.options.Clear(); + selector.options.AddRange(LocalizationManager.GetAllLanguages()); + string currentLanguage = LocalizationManager.CurrentLanguage; + for (int i = 0; i < selector.options.Count; i++) + { + if (selector.options[i] == currentLanguage) + { + selector.SetIndex(i); + break; + } + } + } + + private void OnChange() + { + LocalizationManager.CurrentLanguage = selector.options[selector.Index]; + } +} diff --git a/GameCode/SettingsLanguageReset.cs b/GameCode/SettingsLanguageReset.cs new file mode 100644 index 0000000..776d9be --- /dev/null +++ b/GameCode/SettingsLanguageReset.cs @@ -0,0 +1,14 @@ +using I2.Loc; +using UnityEngine; + +public class SettingsLanguageReset : MonoBehaviour +{ + public GameObject objToRefresh; + + public void ResetLanguage() + { + LocalizationManager.CurrentLanguage = LocalizationManager.GetCurrentDeviceLanguage(); + objToRefresh.SetActive(value: false); + objToRefresh.SetActive(value: true); + } +} diff --git a/GameCode/SettingsManager.cs b/GameCode/SettingsManager.cs new file mode 100644 index 0000000..287a082 --- /dev/null +++ b/GameCode/SettingsManager.cs @@ -0,0 +1,370 @@ +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Audio; +using UnityEngine.Events; +using UnityEngine.Rendering.Universal; + +public class SettingsManager : MonoBehaviour +{ + public enum MixerChannel + { + Master, + Music, + SFX, + Environment + } + + private static SettingsManager instance; + + public UniversalRenderPipelineAsset renderAsset; + + public AudioMixer mixer; + + [HideInInspector] + public UnityEvent onPPSettingsChange = new UnityEvent(); + + private bool fullscreen = true; + + private Resolution currentResolution; + + private bool postProcessing = true; + + private MsaaQuality antiAliasing = MsaaQuality._4x; + + private float renderscale = 1f; + + private float volumeMaster; + + private float volumeSFX; + + private float volumeEnvironment; + + private float volumeMusic; + + private bool resetUnitFormationEveryMorning; + + private bool useLargeInGameUI; + + private string VIDEO_INITIALIZED = "Video_Initialized"; + + private string VIDEO_RESOLUTION_WIDTH = "Video_ResWidth"; + + private string VIDEO_RESOLUTION_HEIGHT = "Video_ResHeight"; + + private string VIDEO_POSTPROCESSING = "Video_PostProcessing"; + + private string VIDEO_FULLSCREEN = "Video_Fullscreen"; + + private string VIDEO_ANTIALIASING = "Video_AntiAliasing"; + + private string VIDEO_RENDERSCALE = "Video_Renderscale"; + + private string AUDIO_INITIALIZED = "Audio_Initialized_1.1"; + + private string AUDIO_MASTER = "Audio_Master"; + + private string AUDIO_MUSIC = "Audio_Music"; + + private string AUDIO_SFX = "Audio_SFX"; + + private string AUDIO_ENVIRONMENT = "Audio_Environment"; + + private string MIXER_MASTER = "MasterVolume"; + + private string MIXER_MUSIC = "SettingsMusicVolume"; + + private string MIXER_SFX = "SettingsSFXVolume"; + + private string MIXER_ENVIRONMENT = "SettingsEnvironmentVolume"; + + private string GAMEPLAY_INITIALIZED = "Gameplay_Initialized_1.1"; + + private string GAMEPLAY_RESET_UNIS_EVERY_MORNING = "Gameplay_ResetUnitFormationEveryMorning"; + + private string GAMEPLAY_USE_LARGE_UI = "Gameplay_UseLargeInGameUI"; + + public static SettingsManager Instance => instance; + + public bool Fullscreen => fullscreen; + + public Resolution CurrentResolution => currentResolution; + + public bool PostProcessing => postProcessing; + + public MsaaQuality AntiAliasing => antiAliasing; + + public float Renderscale => renderscale; + + public float VolumeMaster => volumeMaster; + + public float VolumeSFX => volumeSFX; + + public float VolumeEnvironment => volumeEnvironment; + + public float VolumeMusic => volumeMusic; + + public bool ResetUnitFormationEveryMorning => resetUnitFormationEveryMorning; + + public bool UseLargeInGameUI => useLargeInGameUI; + + private void Awake() + { + if (instance != null) + { + Object.Destroy(base.gameObject); + } + else + { + instance = this; + } + } + + private void Start() + { + LoadVideoSettingsFromPlayerPrefs(); + LoadAudioSettingsFromPlayerPrefs(); + LoadGameplaySettingsFromPlayerPrefs(); + } + + public void SetResolution(Resolution newRes) + { + List list = new List(Screen.resolutions); + bool flag = false; + foreach (Resolution item in list) + { + if (newRes.CompareResolutions(item)) + { + flag = true; + break; + } + } + if (!flag) + { + newRes = Screen.currentResolution; + } + currentResolution = newRes; + FullScreenMode fullscreenMode = FullScreenMode.FullScreenWindow; + if (!fullscreen) + { + fullscreenMode = FullScreenMode.Windowed; + } + Screen.SetResolution(currentResolution.width, currentResolution.height, fullscreenMode, currentResolution.refreshRateRatio); + PlayerPrefs.SetInt(VIDEO_RESOLUTION_WIDTH, currentResolution.width); + PlayerPrefs.SetInt(VIDEO_RESOLUTION_HEIGHT, currentResolution.height); + } + + public void SetPostProcessing(bool active) + { + postProcessing = active; + onPPSettingsChange.Invoke(); + PlayerPrefs.SetInt(VIDEO_POSTPROCESSING, active ? 1 : 0); + } + + public void SetAntiAliasing(MsaaQuality quality) + { + antiAliasing = quality; + renderAsset.msaaSampleCount = (int)antiAliasing; + PlayerPrefs.SetInt(VIDEO_ANTIALIASING, AALevelToInt(antiAliasing)); + } + + public void SetFullscreen(bool isFullscreen) + { + fullscreen = isFullscreen; + Screen.fullScreen = isFullscreen; + PlayerPrefs.SetInt(VIDEO_FULLSCREEN, isFullscreen ? 1 : 0); + } + + public void SetShadowResolution(int res) + { + } + + public void SetRenderscale(float scale) + { + renderscale = scale; + renderAsset.renderScale = renderscale; + PlayerPrefs.SetFloat(VIDEO_RENDERSCALE, renderscale); + } + + public void SetAudioValue(float value, MixerChannel channel) + { + string text; + switch (channel) + { + case MixerChannel.Environment: + volumeEnvironment = value; + PlayerPrefs.SetFloat(AUDIO_ENVIRONMENT, value); + text = MIXER_ENVIRONMENT; + break; + case MixerChannel.Music: + volumeMusic = value; + PlayerPrefs.SetFloat(AUDIO_MUSIC, value); + text = MIXER_MUSIC; + break; + case MixerChannel.SFX: + volumeSFX = value; + PlayerPrefs.SetFloat(AUDIO_SFX, value); + text = MIXER_SFX; + break; + case MixerChannel.Master: + volumeMaster = value; + PlayerPrefs.SetFloat(AUDIO_MASTER, value); + text = MIXER_MASTER; + break; + default: + text = MIXER_MASTER; + break; + } + mixer.SetFloat(text, PercentageToAudioLogarithmic(value)); + } + + public float GetAudioVolume(MixerChannel channel) + { + return channel switch + { + MixerChannel.Environment => volumeEnvironment, + MixerChannel.Music => volumeMusic, + MixerChannel.SFX => volumeSFX, + MixerChannel.Master => volumeMaster, + _ => volumeMaster, + }; + } + + public static float PercentageToAudioLogarithmic(float value) + { + if ((double)value < 0.0001) + { + value = 0.0001f; + } + if (value > 1f) + { + value = 1f; + } + value = Mathf.Log10(value) * 20f; + return value; + } + + public void SetResetUnitsInTheMorning(bool value) + { + resetUnitFormationEveryMorning = value; + PlayerPrefs.SetInt(GAMEPLAY_RESET_UNIS_EVERY_MORNING, value ? 1 : 0); + } + + public void SetUseLargetInGameUI(bool value) + { + useLargeInGameUI = value; + PlayerPrefs.SetInt(GAMEPLAY_USE_LARGE_UI, value ? 1 : 0); + } + + public static int AALevelToInt(MsaaQuality level) + { + return level switch + { + MsaaQuality.Disabled => 0, + MsaaQuality._2x => 1, + MsaaQuality._4x => 2, + MsaaQuality._8x => 3, + _ => 0, + }; + } + + public static MsaaQuality IntToAALevel(int i) + { + return i switch + { + 0 => MsaaQuality.Disabled, + 1 => MsaaQuality._2x, + 2 => MsaaQuality._4x, + 3 => MsaaQuality._8x, + _ => MsaaQuality.Disabled, + }; + } + + private void InitializeVideoSettingsToPlayerPrefs() + { + Resolution resolution = Screen.resolutions[Screen.resolutions.Length - 1]; + PlayerPrefs.SetInt(VIDEO_RESOLUTION_WIDTH, resolution.width); + PlayerPrefs.SetInt(VIDEO_RESOLUTION_HEIGHT, resolution.height); + PlayerPrefs.SetInt(VIDEO_FULLSCREEN, 1); + PlayerPrefs.SetInt(VIDEO_POSTPROCESSING, 1); + PlayerPrefs.SetInt(VIDEO_ANTIALIASING, AALevelToInt(MsaaQuality._4x)); + PlayerPrefs.SetFloat(VIDEO_RENDERSCALE, 1f); + PlayerPrefs.SetInt(VIDEO_INITIALIZED, 1); + } + + private void LoadVideoSettingsFromPlayerPrefs() + { + if (PlayerPrefs.GetInt(VIDEO_INITIALIZED) == 0) + { + InitializeVideoSettingsToPlayerPrefs(); + } + Resolution resolution = default(Resolution); + resolution.width = PlayerPrefs.GetInt(VIDEO_RESOLUTION_WIDTH); + resolution.height = PlayerPrefs.GetInt(VIDEO_RESOLUTION_HEIGHT); + fullscreen = PlayerPrefs.GetInt(VIDEO_FULLSCREEN) != 0; + renderscale = PlayerPrefs.GetFloat(VIDEO_RENDERSCALE); + SetResolution(resolution); + SetPostProcessing(PlayerPrefs.GetInt(VIDEO_POSTPROCESSING) != 0); + SetAntiAliasing(IntToAALevel(PlayerPrefs.GetInt(VIDEO_ANTIALIASING))); + SetRenderscale(renderscale); + } + + private void InitializeAudioSettingsToPlayerPrefs() + { + PlayerPrefs.SetFloat(AUDIO_MASTER, 1f); + PlayerPrefs.SetFloat(AUDIO_MUSIC, 1f); + PlayerPrefs.SetFloat(AUDIO_SFX, 1f); + PlayerPrefs.SetFloat(AUDIO_ENVIRONMENT, 1f); + PlayerPrefs.SetInt(AUDIO_INITIALIZED, 1); + } + + private void LoadAudioSettingsFromPlayerPrefs() + { + if (PlayerPrefs.GetInt(AUDIO_INITIALIZED) == 0) + { + InitializeAudioSettingsToPlayerPrefs(); + } + volumeMaster = PlayerPrefs.GetFloat(AUDIO_MASTER); + volumeMusic = PlayerPrefs.GetFloat(AUDIO_MUSIC); + volumeSFX = PlayerPrefs.GetFloat(AUDIO_SFX); + volumeEnvironment = PlayerPrefs.GetFloat(AUDIO_ENVIRONMENT); + SetAudioValue(volumeMaster, MixerChannel.Master); + SetAudioValue(volumeMusic, MixerChannel.Music); + SetAudioValue(volumeEnvironment, MixerChannel.Environment); + SetAudioValue(volumeSFX, MixerChannel.SFX); + } + + private void InitializeGameplaySettingsToPlayerPrefs() + { + PlayerPrefs.SetInt(GAMEPLAY_RESET_UNIS_EVERY_MORNING, 1); + PlayerPrefs.SetInt(GAMEPLAY_USE_LARGE_UI, 0); + PlayerPrefs.SetInt(GAMEPLAY_INITIALIZED, 1); + } + + private void LoadGameplaySettingsFromPlayerPrefs() + { + if (PlayerPrefs.GetInt(GAMEPLAY_INITIALIZED) == 0) + { + InitializeGameplaySettingsToPlayerPrefs(); + } + resetUnitFormationEveryMorning = PlayerPrefs.GetInt(GAMEPLAY_RESET_UNIS_EVERY_MORNING) != 0; + useLargeInGameUI = PlayerPrefs.GetInt(GAMEPLAY_USE_LARGE_UI) != 0; + } + + public void ResetVideoSettings() + { + InitializeVideoSettingsToPlayerPrefs(); + LoadVideoSettingsFromPlayerPrefs(); + } + + public void ResetAudioSettings() + { + InitializeAudioSettingsToPlayerPrefs(); + LoadAudioSettingsFromPlayerPrefs(); + } + + public void ResetGameplaySettings() + { + InitializeGameplaySettingsToPlayerPrefs(); + LoadGameplaySettingsFromPlayerPrefs(); + } +} diff --git a/GameCode/SettingsPostProcessing.cs b/GameCode/SettingsPostProcessing.cs new file mode 100644 index 0000000..18c1991 --- /dev/null +++ b/GameCode/SettingsPostProcessing.cs @@ -0,0 +1,19 @@ +using UnityEngine; + +public class SettingsPostProcessing : MonoBehaviour +{ + public Checkbox checkbox; + + public void OnApply() + { + SettingsManager.Instance.SetPostProcessing(checkbox.state); + } + + private void OnEnable() + { + if ((bool)SettingsManager.Instance) + { + checkbox.SetState(SettingsManager.Instance.PostProcessing); + } + } +} diff --git a/GameCode/SettingsPostProcessingHelper.cs b/GameCode/SettingsPostProcessingHelper.cs new file mode 100644 index 0000000..a255c32 --- /dev/null +++ b/GameCode/SettingsPostProcessingHelper.cs @@ -0,0 +1,18 @@ +using UnityEngine; +using UnityEngine.Rendering; + +public class SettingsPostProcessingHelper : MonoBehaviour +{ + public Volume target; + + private void Start() + { + Refresh(); + SettingsManager.Instance.onPPSettingsChange.AddListener(Refresh); + } + + private void Refresh() + { + target.enabled = SettingsManager.Instance.PostProcessing; + } +} diff --git a/GameCode/SettingsRenderScale.cs b/GameCode/SettingsRenderScale.cs new file mode 100644 index 0000000..de1aa86 --- /dev/null +++ b/GameCode/SettingsRenderScale.cs @@ -0,0 +1,24 @@ +using UnityEngine; + +public class SettingsRenderScale : MonoBehaviour +{ + public TFUISlider target; + + private void OnEnable() + { + if (SettingsManager.Instance != null) + { + target.SetValue(SettingsManager.Instance.Renderscale); + } + } + + private void Start() + { + target.onChange.AddListener(OnChange); + } + + private void OnChange() + { + SettingsManager.Instance.SetRenderscale(target.value); + } +} diff --git a/GameCode/SettingsResetUnitsMorning.cs b/GameCode/SettingsResetUnitsMorning.cs new file mode 100644 index 0000000..ea05686 --- /dev/null +++ b/GameCode/SettingsResetUnitsMorning.cs @@ -0,0 +1,19 @@ +using UnityEngine; + +public class SettingsResetUnitsMorning : MonoBehaviour +{ + public Checkbox checkbox; + + public void OnApply() + { + SettingsManager.Instance.SetResetUnitsInTheMorning(checkbox.state); + } + + private void OnEnable() + { + if ((bool)SettingsManager.Instance) + { + checkbox.SetState(SettingsManager.Instance.ResetUnitFormationEveryMorning); + } + } +} diff --git a/GameCode/SettingsResetVideo.cs b/GameCode/SettingsResetVideo.cs new file mode 100644 index 0000000..cd3bc2e --- /dev/null +++ b/GameCode/SettingsResetVideo.cs @@ -0,0 +1,13 @@ +using UnityEngine; + +public class SettingsResetVideo : MonoBehaviour +{ + public GameObject objToRefresh; + + public void ResetVideoSettings() + { + SettingsManager.Instance.ResetVideoSettings(); + objToRefresh.SetActive(value: false); + objToRefresh.SetActive(value: true); + } +} diff --git a/GameCode/SettingsResolution.cs b/GameCode/SettingsResolution.cs new file mode 100644 index 0000000..6a11d56 --- /dev/null +++ b/GameCode/SettingsResolution.cs @@ -0,0 +1,40 @@ +using System.Collections.Generic; +using UnityEngine; + +public class SettingsResolution : MonoBehaviour +{ + public EnumSelector selector; + + private Dictionary availableResolutions = new Dictionary(); + + private void Start() + { + selector.onChange.AddListener(ApplyResolution); + } + + private void OnEnable() + { + selector.options.Clear(); + availableResolutions.Clear(); + int index = 0; + for (int i = 0; i < Screen.resolutions.Length; i++) + { + Resolution resolution = Screen.resolutions[i]; + availableResolutions.Add(i, resolution); + selector.options.Add(resolution.ToString()); + if (resolution.CompareResolutions(SettingsManager.Instance.CurrentResolution)) + { + index = i; + } + } + selector.SetIndex(index); + } + + private void ApplyResolution() + { + if (availableResolutions.TryGetValue(selector.Index, out var value) && !value.CompareResolutions(SettingsManager.Instance.CurrentResolution)) + { + SettingsManager.Instance.SetResolution(value); + } + } +} diff --git a/GameCode/SettingsShadowResolution.cs b/GameCode/SettingsShadowResolution.cs new file mode 100644 index 0000000..d8bb6cb --- /dev/null +++ b/GameCode/SettingsShadowResolution.cs @@ -0,0 +1,26 @@ +using UnityEngine; + +public class SettingsShadowResolution : MonoBehaviour +{ + public EnumSelector selector; + + private void Start() + { + selector.onChange.AddListener(OnChange); + } + + private void OnEnable() + { + selector.options.Clear(); + selector.options.AddRange(new string[5] { "256", "512", "1024", "2048", "4096" }); + if ((bool)SettingsManager.Instance) + { + selector.SetIndex(SettingsManager.AALevelToInt(SettingsManager.Instance.AntiAliasing)); + } + } + + private void OnChange() + { + SettingsManager.Instance.SetAntiAliasing(SettingsManager.IntToAALevel(selector.Index)); + } +} diff --git a/GameCode/SettingsUIHelper.cs b/GameCode/SettingsUIHelper.cs new file mode 100644 index 0000000..1156f53 --- /dev/null +++ b/GameCode/SettingsUIHelper.cs @@ -0,0 +1,114 @@ +using System; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.UI; + +public class SettingsUIHelper : MonoBehaviour +{ + [Serializable] + public class SettingsTab + { + public TFUITextButton parentElement; + + public VerticalLayoutGroup childContainer; + + public void ComputeNavigationForSettingsTab() + { + List list = new List(); + foreach (Transform item in childContainer.transform) + { + list.Add(item.GetComponent()); + } + parentElement.botNav = list[0]; + parentElement.topNav = list[list.Count - 1]; + for (int i = 0; i < list.Count; i++) + { + ThronefallUIElement thronefallUIElement = list[i]; + if (i == 0) + { + thronefallUIElement.topNav = parentElement; + } + else + { + thronefallUIElement.topNav = list[i - 1]; + } + if (i == list.Count - 1) + { + thronefallUIElement.botNav = parentElement; + } + else + { + thronefallUIElement.botNav = list[i + 1]; + } + } + } + } + + public UIFrame targetFrame; + + public SettingsTab videoTab; + + public SettingsTab audioTab; + + public SettingsTab gameplayTab; + + public SettingsTab controlsTab; + + public GameObject dimBG; + + private SettingsTab currentSelectedTab; + + private Dictionary allTabs = new Dictionary(); + + private void Awake() + { + allTabs.Add(videoTab.parentElement, videoTab); + allTabs.Add(audioTab.parentElement, audioTab); + allTabs.Add(gameplayTab.parentElement, gameplayTab); + allTabs.Add(controlsTab.parentElement, controlsTab); + videoTab.childContainer.gameObject.SetActive(value: false); + audioTab.childContainer.gameObject.SetActive(value: false); + gameplayTab.childContainer.gameObject.SetActive(value: false); + controlsTab.childContainer.gameObject.SetActive(value: false); + RecomputeAllNavigation(); + } + + private void RecomputeAllNavigation() + { + videoTab.ComputeNavigationForSettingsTab(); + audioTab.ComputeNavigationForSettingsTab(); + gameplayTab.ComputeNavigationForSettingsTab(); + controlsTab.ComputeNavigationForSettingsTab(); + } + + public void OnShow() + { + if (SceneTransitionManager.instance.CurrentSceneState == SceneTransitionManager.SceneState.MainMenu) + { + dimBG.SetActive(value: false); + } + else + { + dimBG.SetActive(value: true); + } + } + + public void OnSelect() + { + SettingsTab value = null; + if (allTabs.TryGetValue(targetFrame.CurrentSelection, out value)) + { + if (currentSelectedTab != null) + { + currentSelectedTab.childContainer.gameObject.SetActive(value: false); + currentSelectedTab.parentElement.applyOverrideStyle = false; + } + currentSelectedTab = value; + currentSelectedTab.childContainer.gameObject.SetActive(value: true); + } + else if (currentSelectedTab != null) + { + currentSelectedTab.parentElement.applyOverrideStyle = true; + } + } +} diff --git a/GameCode/SettingsUseLargeUI.cs b/GameCode/SettingsUseLargeUI.cs new file mode 100644 index 0000000..c7d4d22 --- /dev/null +++ b/GameCode/SettingsUseLargeUI.cs @@ -0,0 +1,22 @@ +using UnityEngine; + +public class SettingsUseLargeUI : MonoBehaviour +{ + public Checkbox checkbox; + + public UIScaleHandler uiScaleHandler; + + public void OnApply() + { + SettingsManager.Instance.SetUseLargetInGameUI(checkbox.state); + uiScaleHandler.Refresh(); + } + + private void OnEnable() + { + if ((bool)SettingsManager.Instance) + { + checkbox.SetState(SettingsManager.Instance.UseLargeInGameUI); + } + } +} diff --git a/GameCode/SharpCornerMidigator.cs b/GameCode/SharpCornerMidigator.cs new file mode 100644 index 0000000..66500db --- /dev/null +++ b/GameCode/SharpCornerMidigator.cs @@ -0,0 +1,46 @@ +using System.Collections.Generic; +using Pathfinding; +using UnityEngine; + +public class SharpCornerMidigator : MonoModifier +{ + public float extendCorners = 2f; + + private List path; + + private Vector3 pathPointLast; + + private Vector2 toLastPoint; + + private Vector2 toNextPoint; + + private float angle; + + private Vector2 normal2d; + + private float strngth; + + private Vector3 normal; + + public override int Order => 100; + + public override void Apply(Path _p) + { + if (_p.path != null && _p.path.Count != 0 && _p.vectorPath != null && _p.vectorPath.Count != 0) + { + path = _p.vectorPath; + pathPointLast = path[0]; + for (int i = 1; i < path.Count - 1; i++) + { + toLastPoint = new Vector2(pathPointLast.x, pathPointLast.z) - new Vector2(path[i].x, path[i].z); + toNextPoint = new Vector2(path[i + 1].x, path[i + 1].z) - new Vector2(path[i].x, path[i].z); + angle = Vector2.Angle(toLastPoint, toNextPoint); + normal2d = -(toLastPoint.normalized + toNextPoint.normalized).normalized; + strngth = (180f - angle) / 180f; + normal = new Vector3(normal2d.x, 0f, normal2d.y); + pathPointLast = path[i]; + path[i] += normal * strngth * extendCorners; + } + } + } +} diff --git a/GameCode/SimpleRotator.cs b/GameCode/SimpleRotator.cs new file mode 100644 index 0000000..aa2d0b4 --- /dev/null +++ b/GameCode/SimpleRotator.cs @@ -0,0 +1,23 @@ +using UnityEngine; + +public class SimpleRotator : MonoBehaviour +{ + public Vector3 rotationDelta; + + public Space relativeTo; + + public bool randomYRotationOnEnable; + + private void OnEnable() + { + if (randomYRotationOnEnable) + { + base.transform.Rotate(Vector3.up * Random.value * 360f, Space.World); + } + } + + private void Update() + { + base.transform.Rotate(rotationDelta * Time.deltaTime, relativeTo); + } +} diff --git a/GameCode/SimpleUIScaler.cs b/GameCode/SimpleUIScaler.cs new file mode 100644 index 0000000..348433a --- /dev/null +++ b/GameCode/SimpleUIScaler.cs @@ -0,0 +1,43 @@ +using UnityEngine; + +public class SimpleUIScaler : MonoBehaviour +{ + public bool offsetPositionWhenLarge; + + public Vector2 offset; + + private Vector2 ogPosition; + + private bool ogPositionBuffered; + + private RectTransform bufferedRT; + + private void OnEnable() + { + if (offsetPositionWhenLarge) + { + bufferedRT = GetComponent(); + if (!ogPositionBuffered) + { + ogPosition = bufferedRT.anchoredPosition; + ogPositionBuffered = true; + } + } + if (SettingsManager.Instance.UseLargeInGameUI) + { + if (offsetPositionWhenLarge) + { + bufferedRT.anchoredPosition = ogPosition + offset; + } + base.transform.localScale = Vector3.one * 1.5f; + } + else + { + if (offsetPositionWhenLarge) + { + bufferedRT.anchoredPosition = ogPosition; + } + base.transform.localScale = Vector3.one; + } + } +} diff --git a/GameCode/SimpleWalk.cs b/GameCode/SimpleWalk.cs new file mode 100644 index 0000000..b6c7e54 --- /dev/null +++ b/GameCode/SimpleWalk.cs @@ -0,0 +1,55 @@ +using Pathfinding.RVO; +using UnityEngine; +using UnityEngine.Events; + +public class SimpleWalk : MonoBehaviour +{ + public RVOController rvo; + + public Transform animationRoot; + + public float bounceHeight = 0.5f; + + public AnimationCurve bounceCurve; + + public float bounceSpeed = 1f; + + private float bounceClock; + + private float clockDelta; + + private float velocitySqrtDeadzone = 0.15f; + + [HideInInspector] + public UnityEvent onGroundContact = new UnityEvent(); + + private float lastGroundContactTimeStamp; + + private Vector3 initialRootPos; + + private void Start() + { + initialRootPos = animationRoot.localPosition; + bounceClock = Random.value; + } + + private void Update() + { + if (rvo.velocity.sqrMagnitude > velocitySqrtDeadzone) + { + clockDelta = Time.deltaTime * bounceSpeed; + bounceClock += clockDelta; + animationRoot.transform.localPosition = Vector3.Lerp(initialRootPos, initialRootPos + Vector3.up * bounceHeight, bounceCurve.Evaluate(bounceClock)); + if (bounceClock % 1f <= clockDelta && Mathf.Abs(bounceClock - lastGroundContactTimeStamp) > 0.5f) + { + lastGroundContactTimeStamp = bounceClock; + onGroundContact.Invoke(); + } + } + else + { + animationRoot.transform.localPosition = initialRootPos; + bounceClock = 0f; + } + } +} diff --git a/GameCode/SizeRectangleToMeshBounds.cs b/GameCode/SizeRectangleToMeshBounds.cs new file mode 100644 index 0000000..8962f24 --- /dev/null +++ b/GameCode/SizeRectangleToMeshBounds.cs @@ -0,0 +1,20 @@ +using Shapes; +using UnityEngine; + +[RequireComponent(typeof(Rectangle))] +public class SizeRectangleToMeshBounds : MonoBehaviour +{ + public float xMargin = 1f; + + public float yMargin = 1f; + + public MeshFilter meshFilter; + + [ContextMenu("RESIZE")] + private void OnEnable() + { + Rectangle component = GetComponent(); + component.Height = meshFilter.sharedMesh.bounds.size.y + 2f * yMargin; + component.Width = meshFilter.sharedMesh.bounds.size.x + 2f * xMargin; + } +} diff --git a/GameCode/Spawn.cs b/GameCode/Spawn.cs new file mode 100644 index 0000000..f913b71 --- /dev/null +++ b/GameCode/Spawn.cs @@ -0,0 +1,171 @@ +using System; +using UnityEngine; + +[Serializable] +public class Spawn +{ + public float delay; + + public GameObject enemyPrefab; + + public int count; + + public float interval; + + public Transform spawnLine; + + public int goldCoins; + + private int[] goldCoinsPerEnemy; + + private float waitBeforeNextSpawn; + + private int spawnedUnits; + + private bool finished; + + private bool tauntTheTiger; + + private bool tauntTheTurtle; + + private bool tauntTheFalcon; + + private bool tauntTheRat; + + private Hp hpTemp; + + public int SpawnedUnits => spawnedUnits; + + public bool Finished => finished; + + public void Reset(bool _resetGold = true) + { + tauntTheTiger = PerkManager.IsEquipped(PerkManager.instance.tigerGodPerk); + tauntTheTurtle = PerkManager.IsEquipped(PerkManager.instance.turtleGodPerk); + tauntTheFalcon = PerkManager.IsEquipped(PerkManager.instance.falconGodPerk); + tauntTheRat = PerkManager.IsEquipped(PerkManager.instance.ratGodPerk); + waitBeforeNextSpawn = delay; + spawnedUnits = 0; + finished = false; + goldCoinsPerEnemy = new int[count]; + int num = goldCoins; + if (tauntTheRat) + { + num = Mathf.FloorToInt((float)num / 2f); + } + for (int i = 0; i < num; i++) + { + goldCoinsPerEnemy[UnityEngine.Random.Range(0, goldCoinsPerEnemy.Length)] = 0; + } + if (_resetGold) + { + for (int j = 0; j < num; j++) + { + goldCoinsPerEnemy[UnityEngine.Random.Range(0, goldCoinsPerEnemy.Length)]++; + } + } + } + + public void Update() + { + if (finished) + { + return; + } + waitBeforeNextSpawn -= Time.deltaTime; + if (waitBeforeNextSpawn > 0f) + { + return; + } + waitBeforeNextSpawn = interval; + Vector3 randomPointOnSpawnLine = GetRandomPointOnSpawnLine(); + GameObject gameObject; + if (spawnLine == enemyPrefab.transform) + { + gameObject = enemyPrefab; + gameObject.SetActive(value: true); + } + else + { + gameObject = UnityEngine.Object.Instantiate(enemyPrefab, randomPointOnSpawnLine, Quaternion.identity); + EnemySpawnManager instance = EnemySpawnManager.instance; + if ((bool)instance.weaponOnSpawn) + { + instance.weaponOnSpawn.Attack(randomPointOnSpawnLine + Vector3.up * instance.weaponAttackHeight, null, Vector3.forward, gameObject.GetComponent()); + } + } + if (goldCoinsPerEnemy.Length > spawnedUnits) + { + gameObject.GetComponentInChildren().coinCount = goldCoinsPerEnemy[spawnedUnits]; + } + if (tauntTheTurtle) + { + hpTemp = gameObject.GetComponentInChildren(); + hpTemp.maxHp *= PerkManager.instance.tauntTheTurtle_hpMultiplyer; + hpTemp.Heal(float.MaxValue); + } + if (tauntTheTiger) + { + AutoAttack[] componentsInChildren = gameObject.GetComponentsInChildren(); + for (int i = 0; i < componentsInChildren.Length; i++) + { + componentsInChildren[i].DamageMultiplyer *= PerkManager.instance.tauntTheTiger_damageMultiplyer; + } + Hp[] componentsInChildren2 = gameObject.GetComponentsInChildren(); + for (int i = 0; i < componentsInChildren2.Length; i++) + { + componentsInChildren2[i].DamageMultiplyer *= PerkManager.instance.tauntTheTiger_damageMultiplyer; + } + } + if (tauntTheFalcon) + { + PathfindMovementEnemy[] componentsInChildren3 = gameObject.GetComponentsInChildren(); + foreach (PathfindMovementEnemy obj in componentsInChildren3) + { + obj.movementSpeed *= PerkManager.instance.tauntTheFalcon_speedMultiplyer; + obj.agroTimeWhenAttackedByPlayer *= PerkManager.instance.tauntTheFalcon_chasePlayerTimeMultiplyer; + } + } + spawnedUnits++; + if (spawnedUnits >= count) + { + finished = true; + } + } + + public Vector3 GetRandomPointOnSpawnLine() + { + float num = GetTotalSpawnLineLength() * UnityEngine.Random.value; + float num2 = 0f; + for (int i = 0; i < spawnLine.childCount - 1; i++) + { + float magnitude = (spawnLine.GetChild(i).position - spawnLine.GetChild(i + 1).position).magnitude; + if (magnitude != 0f) + { + if (magnitude + num2 >= num) + { + num -= num2; + float t = num / magnitude; + Vector3 position = Vector3.Lerp(spawnLine.GetChild(i).position, spawnLine.GetChild(i + 1).position, t); + return AstarPath.active.GetNearest(position).position; + } + num2 += magnitude; + } + } + if (spawnLine.childCount > 0) + { + return AstarPath.active.GetNearest(spawnLine.GetChild(0).position).position; + } + return AstarPath.active.GetNearest(spawnLine.position).position; + } + + public float GetTotalSpawnLineLength() + { + float num = 0f; + for (int i = 0; i < spawnLine.childCount - 1; i++) + { + num += (spawnLine.GetChild(i).position - spawnLine.GetChild(i + 1).position).magnitude; + } + return num; + } +} diff --git a/GameCode/SpinAnimation.cs b/GameCode/SpinAnimation.cs new file mode 100644 index 0000000..6a4334b --- /dev/null +++ b/GameCode/SpinAnimation.cs @@ -0,0 +1,45 @@ +using System.Collections; +using UnityEngine; + +public class SpinAnimation : OneShotAnimationBase +{ + public AnimationCurve curve; + + public float duration = 0.75f; + + public Vector3 spinRotation; + + public Transform transformToAnimate; + + private Quaternion initialRotation; + + private Quaternion targetRotation; + + private void Start() + { + initialRotation = transformToAnimate.localRotation; + targetRotation = Quaternion.Euler(spinRotation.x, spinRotation.y, spinRotation.z); + } + + private IEnumerator Animate() + { + transformToAnimate.localRotation = initialRotation; + float timer = 0f; + while (timer < duration) + { + transformToAnimate.localRotation = Quaternion.Euler(initialRotation.eulerAngles + spinRotation * (timer / duration)); + timer += Time.deltaTime; + yield return null; + } + transformToAnimate.localRotation = initialRotation; + } + + public override void Trigger() + { + if (base.gameObject.activeInHierarchy) + { + StopAllCoroutines(); + StartCoroutine(Animate()); + } + } +} diff --git a/GameCode/SplashDamageArea.cs b/GameCode/SplashDamageArea.cs new file mode 100644 index 0000000..84a27a9 --- /dev/null +++ b/GameCode/SplashDamageArea.cs @@ -0,0 +1,51 @@ +using System.Collections.Generic; +using UnityEngine; + +public class SplashDamageArea : MonoBehaviour +{ + public enum EShape + { + Sphere, + Box + } + + public EShape shape; + + public Vector3 boxSize; + + public float sphereRadius; + + public LayerMask layerMaskRecieveDamage; + + private static Collider[] collidersTemp = new Collider[200]; + + private void OnDrawGizmosSelected() + { + if (shape == EShape.Box) + { + Gizmos.color = Color.red; + Gizmos.matrix = base.transform.localToWorldMatrix; + Gizmos.DrawWireCube(Vector3.zero, boxSize); + } + else + { + Gizmos.color = Color.red; + Gizmos.matrix = base.transform.localToWorldMatrix; + Gizmos.DrawWireSphere(Vector3.zero, sphereRadius); + } + } + + public void AddReiveDamageHpScriptsInAreaToList(List _listOfHpScripts) + { + int num = 0; + num = ((shape != EShape.Box) ? Physics.OverlapSphereNonAlloc(base.transform.position, sphereRadius, collidersTemp, layerMaskRecieveDamage) : Physics.OverlapBoxNonAlloc(base.transform.position, boxSize, collidersTemp, base.transform.rotation, layerMaskRecieveDamage)); + for (int i = 0; i < num; i++) + { + Hp componentInParent = collidersTemp[i].GetComponentInParent(); + if (!(componentInParent == null) && !_listOfHpScripts.Contains(componentInParent)) + { + _listOfHpScripts.Add(componentInParent); + } + } + } +} diff --git a/GameCode/StabMA.cs b/GameCode/StabMA.cs new file mode 100644 index 0000000..fe34737 --- /dev/null +++ b/GameCode/StabMA.cs @@ -0,0 +1,71 @@ +using UnityEngine; + +public class StabMA : ManualAttack +{ + public float maximumCooldownTime = 15f; + + public float minimumCooldownPercentage = 0.2f; + + private int targetsStabbed; + + private AudioSet.ClipArray caSuccessfulHit; + + private AudioSet.ClipArray caFailedHit; + + public int TargetsStabeed => targetsStabbed; + + public override void Start() + { + base.Start(); + caSuccessfulHit = audioSet.PlayerBowStab; + caFailedHit = audioSet.PlayerBowStabMiss; + } + + public override void Attack() + { + TaggedObject taggedObject = FindAttackTarget(_choosePreferredTargetIfPossible: true); + Hp hp = null; + if ((bool)taggedObject) + { + hp = taggedObject.Hp; + cooldownTime = maximumCooldownTime * (minimumCooldownPercentage + hp.HpPercentage * (1f - minimumCooldownPercentage)); + cooldown = cooldownTime; + } + float num = 0f; + if ((bool)hp) + { + num = hp.HpValue; + } + weapon.Attack(base.transform.position + spawnAttackHeight * Vector3.up, hp, transformForAttackDirection.forward, myTaggedObj, base.AttackDamageMultiplyer); + if ((bool)hp) + { + if (num > hp.HpValue) + { + StabSuccessful(); + } + else + { + StabMissed(); + } + } + else if (num > 0f) + { + StabSuccessful(); + } + else + { + StabMissed(); + } + } + + private void StabSuccessful() + { + audioManager.PlaySoundAsOneShot(caSuccessfulHit, 1f, Random.Range(0.9f, 1.1f), audioSet.mixGroupFX, 5); + targetsStabbed++; + } + + private void StabMissed() + { + audioManager.PlaySoundAsOneShot(caFailedHit, 1f, Random.Range(0.9f, 1.1f), audioSet.mixGroupFX, 5); + } +} diff --git a/GameCode/SteamManager.cs b/GameCode/SteamManager.cs new file mode 100644 index 0000000..fb2f904 --- /dev/null +++ b/GameCode/SteamManager.cs @@ -0,0 +1,209 @@ +using System; +using System.Collections.Generic; +using System.Text; +using AOT; +using Steamworks; +using UnityEngine; +using UnityEngine.Events; + +[DisallowMultipleComponent] +public class SteamManager : MonoBehaviour +{ + public struct LeaderboardEntry + { + public string username; + + public int score; + } + + protected static bool s_EverInitialized = false; + + protected static SteamManager s_instance; + + protected bool m_bInitialized; + + protected SteamAPIWarningMessageHook_t m_SteamAPIWarningMessageHook; + + private static CallResult _findLeaderboardCallback = new CallResult(); + + public static int scoreToUpload = -1; + + private static CallResult _downloadedScoresCallback = new CallResult(); + + public List lastDownloadedLeaderboardEntires = new List(); + + public UnityEvent OnLeaderboardDownloadCallbackComplete = new UnityEvent(); + + public static SteamManager Instance + { + get + { + if (s_instance == null) + { + return new GameObject("SteamManager").AddComponent(); + } + return s_instance; + } + } + + public static bool Initialized => Instance.m_bInitialized; + + [MonoPInvokeCallback(typeof(SteamAPIWarningMessageHook_t))] + protected static void SteamAPIDebugTextHook(int nSeverity, StringBuilder pchDebugText) + { + Debug.LogWarning(pchDebugText); + } + + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)] + private static void InitOnPlayMode() + { + s_EverInitialized = false; + s_instance = null; + } + + protected virtual void Awake() + { + if (s_instance != null) + { + UnityEngine.Object.Destroy(base.gameObject); + return; + } + s_instance = this; + scoreToUpload = -1; + if (s_EverInitialized) + { + throw new Exception("Tried to Initialize the SteamAPI twice in one session!"); + } + UnityEngine.Object.DontDestroyOnLoad(base.transform.root.gameObject); + if (!Packsize.Test()) + { + Debug.LogError("[Steamworks.NET] Packsize Test returned false, the wrong version of Steamworks.NET is being run in this platform.", this); + } + if (!DllCheck.Test()) + { + Debug.LogError("[Steamworks.NET] DllCheck Test returned false, One or more of the Steamworks binaries seems to be the wrong version.", this); + } + try + { + if (SteamAPI.RestartAppIfNecessary(AppId_t.Invalid)) + { + Debug.Log("[Steamworks.NET] Shutting down because RestartAppIfNecessary returned true. Steam will restart the application."); + Application.Quit(); + return; + } + } + catch (DllNotFoundException ex) + { + Debug.Log("[Steamworks.NET] Could not load [lib]steam_api.dll/so/dylib. It's likely not in the correct location. Refer to the README for more details.\n" + ex, this); + Application.Quit(); + return; + } + m_bInitialized = SteamAPI.Init(); + if (!m_bInitialized) + { + Debug.Log("[Steamworks.NET] SteamAPI_Init() failed. This is likely the case because the Steam client is not running.", this); + } + else + { + s_EverInitialized = true; + } + } + + protected virtual void OnEnable() + { + if (s_instance == null) + { + s_instance = this; + } + if (m_bInitialized && m_SteamAPIWarningMessageHook == null) + { + m_SteamAPIWarningMessageHook = SteamAPIDebugTextHook; + SteamClient.SetWarningMessageHook(m_SteamAPIWarningMessageHook); + } + } + + protected virtual void OnDestroy() + { + if (!(s_instance != this)) + { + s_instance = null; + if (m_bInitialized) + { + SteamAPI.Shutdown(); + } + } + } + + protected virtual void Update() + { + if (m_bInitialized) + { + SteamAPI.RunCallbacks(); + } + } + + public void UploadHighscore(int _score, string _leaderboardName) + { + if (Initialized) + { + if (scoreToUpload != -1) + { + Debug.LogError("You can't upload multiple scores symultaneously with the current system."); + return; + } + scoreToUpload = _score; + SteamAPICall_t hAPICall = SteamUserStats.FindOrCreateLeaderboard(_leaderboardName, ELeaderboardSortMethod.k_ELeaderboardSortMethodDescending, ELeaderboardDisplayType.k_ELeaderboardDisplayTypeNumeric); + _findLeaderboardCallback.Set(hAPICall, OnFindLeaderboardForUploadingScore); + } + } + + public void OnFindLeaderboardForUploadingScore(LeaderboardFindResult_t _callback, bool _failure) + { + if (_failure) + { + scoreToUpload = -1; + return; + } + SteamUserStats.UploadLeaderboardScore(_callback.m_hSteamLeaderboard, ELeaderboardUploadScoreMethod.k_ELeaderboardUploadScoreMethodKeepBest, scoreToUpload, new int[0], 0); + scoreToUpload = -1; + } + + public void DownloadFriendsHighscores(string _leaderboardName) + { + lastDownloadedLeaderboardEntires.Clear(); + if (Initialized) + { + SteamAPICall_t hAPICall = SteamUserStats.FindLeaderboard(_leaderboardName); + _findLeaderboardCallback.Set(hAPICall, OnFindLeaderboardFodDownloadingFriendsScore); + } + } + + public void OnFindLeaderboardFodDownloadingFriendsScore(LeaderboardFindResult_t _callback, bool _failure) + { + if (!_failure) + { + SteamAPICall_t hAPICall = SteamUserStats.DownloadLeaderboardEntries(_callback.m_hSteamLeaderboard, ELeaderboardDataRequest.k_ELeaderboardDataRequestFriends, 1, 100); + _downloadedScoresCallback.Set(hAPICall, OnDownloadedScores); + } + } + + public void OnDownloadedScores(LeaderboardScoresDownloaded_t _callback, bool _failure) + { + if (_failure) + { + OnLeaderboardDownloadCallbackComplete.Invoke(); + return; + } + SteamUserStats.GetLeaderboardName(_callback.m_hSteamLeaderboard); + int[] pDetails = new int[0]; + for (int i = 0; i < _callback.m_cEntryCount; i++) + { + SteamUserStats.GetDownloadedLeaderboardEntry(_callback.m_hSteamLeaderboardEntries, i, out var pLeaderboardEntry, pDetails, 0); + LeaderboardEntry item = default(LeaderboardEntry); + item.username = SteamFriends.GetFriendPersonaName(pLeaderboardEntry.m_steamIDUser); + item.score = pLeaderboardEntry.m_nScore; + lastDownloadedLeaderboardEntires.Add(item); + } + OnLeaderboardDownloadCallbackComplete.Invoke(); + } +} diff --git a/GameCode/SuperSimpleOceanAnimation.cs b/GameCode/SuperSimpleOceanAnimation.cs new file mode 100644 index 0000000..f30e181 --- /dev/null +++ b/GameCode/SuperSimpleOceanAnimation.cs @@ -0,0 +1,47 @@ +using System; +using UnityEngine; + +public class SuperSimpleOceanAnimation : MonoBehaviour +{ + private Vector3 startPosition; + + private float time; + + [SerializeField] + private Vector3 waveHeight; + + [SerializeField] + private float waveFrequency = 0.5f; + + [SerializeField] + private Vector3 waveSideways; + + [SerializeField] + private float waveSidewaysFrequency = 0.5f; + + [SerializeField] + private Material targetMaterial; + + [SerializeField] + private float panSpeed = 2f; + + private Vector2 offset; + + private void Start() + { + startPosition = base.transform.position; + } + + private void Update() + { + time += Time.deltaTime; + offset.x = time * panSpeed; + base.transform.position = startPosition; + base.transform.position += waveHeight * Mathf.Sin(time * waveFrequency * MathF.PI); + base.transform.position += waveSideways * Mathf.Sin(time * waveSidewaysFrequency * MathF.PI); + if (targetMaterial != null) + { + targetMaterial.SetTextureOffset("_BaseMap", offset); + } + } +} diff --git a/GameCode/SuspendPlayerCollisionUntilNoOverlap.cs b/GameCode/SuspendPlayerCollisionUntilNoOverlap.cs new file mode 100644 index 0000000..a822b9e --- /dev/null +++ b/GameCode/SuspendPlayerCollisionUntilNoOverlap.cs @@ -0,0 +1,96 @@ +using System.Collections.Generic; +using UnityEngine; + +public class SuspendPlayerCollisionUntilNoOverlap : MonoBehaviour +{ + public bool triggerOnEnable = true; + + public LayerMask scanLayer; + + private List targetColliders = new List(); + + private Collider[] overlaps; + + private bool suspended; + + private CharacterController trackedTarget; + + private void Awake() + { + targetColliders.AddRange(GetComponentsInChildren()); + for (int num = targetColliders.Count - 1; num >= 0; num--) + { + if (targetColliders[num].isTrigger) + { + targetColliders.RemoveAt(num); + } + } + } + + private void OnEnable() + { + if (triggerOnEnable) + { + Trigger(); + } + } + + public void Trigger() + { + if (!PlayerManager.Instance) + { + return; + } + suspended = true; + PlayerMovement closestPlayer = PlayerManager.GetClosestPlayer(base.transform.position); + if ((bool)closestPlayer) + { + trackedTarget = closestPlayer.GetComponent(); + } + foreach (Collider targetCollider in targetColliders) + { + targetCollider.isTrigger = true; + } + } + + private void SwitchBack() + { + suspended = false; + foreach (Collider targetCollider in targetColliders) + { + targetCollider.isTrigger = false; + } + } + + private void Update() + { + if (!suspended) + { + return; + } + if ((bool)trackedTarget) + { + float num = trackedTarget.height / 2f; + Vector3 point = trackedTarget.transform.position + Vector3.down * num; + Vector3 point2 = trackedTarget.transform.position + Vector3.up * num; + overlaps = Physics.OverlapCapsule(point, point2, trackedTarget.radius, scanLayer, QueryTriggerInteraction.Collide); + bool flag = true; + Collider[] array = overlaps; + foreach (Collider item in array) + { + if (targetColliders.Contains(item)) + { + flag = false; + } + } + if (flag) + { + SwitchBack(); + } + } + else + { + SwitchBack(); + } + } +} diff --git a/GameCode/TFUIAudioHelper.cs b/GameCode/TFUIAudioHelper.cs new file mode 100644 index 0000000..39c293e --- /dev/null +++ b/GameCode/TFUIAudioHelper.cs @@ -0,0 +1,53 @@ +using UnityEngine; + +[RequireComponent(typeof(ThronefallUIElement))] +public class TFUIAudioHelper : MonoBehaviour +{ + public bool playOnColdSelect; + + public ThronefallAudioManager.AudioOneShot onSelect = ThronefallAudioManager.AudioOneShot.ButtonSelect; + + public ThronefallAudioManager.AudioOneShot onApply = ThronefallAudioManager.AudioOneShot.ButtonApply; + + private ThronefallUIElement tfui; + + private bool selected + { + get + { + if (tfui.CurrentState == ThronefallUIElement.SelectionState.Selected || tfui.CurrentState == ThronefallUIElement.SelectionState.FocussedAndSelected) + { + if (tfui.PreviousState != ThronefallUIElement.SelectionState.FocussedAndSelected) + { + return tfui.PreviousState != ThronefallUIElement.SelectionState.Selected; + } + return false; + } + return false; + } + } + + private void Start() + { + tfui = GetComponent(); + tfui.onApply.AddListener(PlayApply); + tfui.onSelectionStateChange.AddListener(PlaySelect); + if (selected && playOnColdSelect) + { + PlaySelect(); + } + } + + private void PlayApply() + { + ThronefallAudioManager.Oneshot(onApply); + } + + private void PlaySelect() + { + if (selected) + { + ThronefallAudioManager.Oneshot(onSelect); + } + } +} diff --git a/GameCode/TFUIBlockoutElement.cs b/GameCode/TFUIBlockoutElement.cs new file mode 100644 index 0000000..a0150ad --- /dev/null +++ b/GameCode/TFUIBlockoutElement.cs @@ -0,0 +1,44 @@ +using System; + +public class TFUIBlockoutElement : ThronefallUIElement +{ + public ThronefallUIElement target; + + private void OnEnable() + { + botNav = target.botNav; + topNav = target.topNav; + rightNav = target.rightNav; + leftNav = target.leftNav; + } + + protected override void OnApply() + { + target.Apply(); + } + + protected override void OnClear() + { + target.Clear(); + } + + protected override void OnFocus() + { + target.Focus(); + } + + protected override void OnFocusAndSelect() + { + target.FocusAndSelect(); + } + + protected override void OnHardStateSet(SelectionState selectionState) + { + throw new NotImplementedException(); + } + + protected override void OnSelect() + { + target.Select(); + } +} diff --git a/GameCode/TFUICheckboxMouseCatcher.cs b/GameCode/TFUICheckboxMouseCatcher.cs new file mode 100644 index 0000000..0fe58cb --- /dev/null +++ b/GameCode/TFUICheckboxMouseCatcher.cs @@ -0,0 +1,43 @@ +using MPUIKIT; +using UnityEngine; + +public class TFUICheckboxMouseCatcher : ThronefallUIElement +{ + public Checkbox target; + + public MPImageBasic targetGraphic; + + public Color defaultColor; + + public Color highlightColor; + + protected override void OnApply() + { + target.Toggle(); + targetGraphic.color = highlightColor; + } + + protected override void OnClear() + { + targetGraphic.color = defaultColor; + } + + protected override void OnFocus() + { + targetGraphic.color = highlightColor; + } + + protected override void OnFocusAndSelect() + { + targetGraphic.color = highlightColor; + } + + protected override void OnHardStateSet(SelectionState selectionState) + { + } + + protected override void OnSelect() + { + targetGraphic.color = highlightColor; + } +} diff --git a/GameCode/TFUIEnumMouseCatcher.cs b/GameCode/TFUIEnumMouseCatcher.cs new file mode 100644 index 0000000..e46eb62 --- /dev/null +++ b/GameCode/TFUIEnumMouseCatcher.cs @@ -0,0 +1,51 @@ +using System.Collections.Generic; +using UnityEngine; + +public class TFUIEnumMouseCatcher : ThronefallUIElement +{ + public List focusWhitelist = new List(); + + public GameObject buttons; + + private UIFrame targetFrame; + + protected override void OnApply() + { + } + + protected override void OnClear() + { + } + + protected override void OnFocus() + { + buttons.SetActive(value: true); + targetFrame.onNewFocus.AddListener(ListenForUnfocus); + } + + protected override void OnFocusAndSelect() + { + } + + protected override void OnHardStateSet(SelectionState selectionState) + { + } + + protected override void OnSelect() + { + } + + private void Start() + { + targetFrame = GetComponentInParent(); + } + + private void ListenForUnfocus() + { + if (!(targetFrame.CurrentFocus == this) && !focusWhitelist.Contains(targetFrame.CurrentFocus)) + { + buttons.SetActive(value: false); + targetFrame.onNewFocus.RemoveListener(ListenForUnfocus); + } + } +} diff --git a/GameCode/TFUIEnumSelectorButton.cs b/GameCode/TFUIEnumSelectorButton.cs new file mode 100644 index 0000000..c758c11 --- /dev/null +++ b/GameCode/TFUIEnumSelectorButton.cs @@ -0,0 +1,40 @@ +using MPUIKIT; +using UnityEngine; + +public class TFUIEnumSelectorButton : ThronefallUIElement +{ + public MPImage targetGraphic; + + public Color defaultColor; + + public Color highlightColor; + + protected override void OnApply() + { + targetGraphic.color = highlightColor; + } + + protected override void OnClear() + { + targetGraphic.color = defaultColor; + } + + protected override void OnFocus() + { + targetGraphic.color = highlightColor; + } + + protected override void OnFocusAndSelect() + { + targetGraphic.color = highlightColor; + } + + protected override void OnHardStateSet(SelectionState selectionState) + { + } + + protected override void OnSelect() + { + targetGraphic.color = highlightColor; + } +} diff --git a/GameCode/TFUIEquippable.cs b/GameCode/TFUIEquippable.cs new file mode 100644 index 0000000..bb74692 --- /dev/null +++ b/GameCode/TFUIEquippable.cs @@ -0,0 +1,307 @@ +using System; +using MPUIKIT; +using UnityEngine; +using UnityEngine.UI; + +public class TFUIEquippable : ThronefallUIElement +{ + [Serializable] + public class Style + { + public float scale = 1f; + + public Color outlineColor; + + public AnimationCurve animationCurve = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f); + + public float animationDuration = 0.5f; + + public Style(Color outlineColor, AnimationCurve animationCurve, float animationDuration, float scale) + { + this.scale = scale; + this.outlineColor = outlineColor; + this.animationCurve = animationCurve; + this.animationDuration = animationDuration; + } + } + + public class Animation + { + public TFUIEquippable target; + + public Style startStyle; + + public Style endStyle; + + public float clock; + + public Animation(Style startStyle, Style endStyle, TFUIEquippable target) + { + this.startStyle = startStyle; + this.endStyle = endStyle; + this.target = target; + target.ApplyStyle(startStyle); + target.currentAnimation = this; + } + + public void Tick() + { + clock += Time.unscaledDeltaTime; + float num = Mathf.InverseLerp(0f, endStyle.animationDuration, clock); + float t = endStyle.animationCurve.Evaluate(num); + target.backgroundImg.OutlineColor = Color.Lerp(startStyle.outlineColor, endStyle.outlineColor, t); + target.backgroundImg.transform.localScale = Vector3.one * Mathf.LerpUnclamped(startStyle.scale, endStyle.scale, t); + if (num >= 1f) + { + target.ApplyStyle(endStyle); + target.currentAnimation = null; + } + } + } + + [SerializeField] + private Color weaponBgColor; + + [SerializeField] + private Color perkBgColor; + + [SerializeField] + private Color mutatorBgColor; + + [SerializeField] + private Color lockedBgColor; + + [SerializeField] + private Color lockedOutlineColor; + + [SerializeField] + private Color weaponHighlightColor; + + [SerializeField] + private Color perkHightlightColor; + + [SerializeField] + private Color mutatorHighlightColor; + + [SerializeField] + private Color highlightIconColor; + + [SerializeField] + private MPImageBasic backgroundImg; + + [SerializeField] + private Image iconImg; + + [SerializeField] + private Sprite lockIcon; + + public AnimationCurve defaultAnimationCurve = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f); + + public float defaultAnimationTime = 0.3f; + + public Style focussedStyle; + + public Style selectedStyle; + + public Style focussedAndSelectedStyle; + + private Style defaultStyle; + + private bool defaultStyleInitialized; + + private bool selectedForLoadout; + + private Animation currentAnimation; + + private Equippable equippableData; + + private Color highlightBGColor; + + private Color defaultBGColor; + + private Color defaultIconColor; + + private bool locked; + + public Equippable Data => equippableData; + + private bool isWeapon => equippableData is EquippableWeapon; + + private bool isPerk => equippableData is EquippablePerk; + + private bool isMutator => equippableData is EquippableMutation; + + public bool Locked => locked; + + public Image IconImg => iconImg; + + public Color GetBackgroundColor + { + get + { + if (!selectedForLoadout) + { + return defaultBGColor; + } + return highlightBGColor; + } + } + + public Color GetIconColor + { + get + { + if (!selectedForLoadout) + { + return defaultIconColor; + } + return highlightIconColor; + } + } + + private void Update() + { + if (currentAnimation != null) + { + currentAnimation.Tick(); + } + } + + protected override void OnApply() + { + } + + protected override void OnClear() + { + new Animation(GetStyle(previousState), defaultStyle, this); + } + + protected override void OnFocus() + { + new Animation(GetStyle(previousState), focussedStyle, this); + } + + protected override void OnSelect() + { + new Animation(GetStyle(previousState), selectedStyle, this); + } + + protected override void OnFocusAndSelect() + { + new Animation(GetStyle(previousState), focussedAndSelectedStyle, this); + } + + protected override void OnHardStateSet(SelectionState selectionState) + { + currentAnimation = null; + ApplyStyle(GetStyle(selectionState)); + } + + protected Style GetStyle(SelectionState state) + { + if (!defaultStyleInitialized) + { + InitializeDefaultStyle(); + } + return state switch + { + SelectionState.Default => defaultStyle, + SelectionState.Focussed => focussedStyle, + SelectionState.Selected => selectedStyle, + SelectionState.FocussedAndSelected => focussedAndSelectedStyle, + _ => defaultStyle, + }; + } + + private void ApplyStyle(Style style) + { + backgroundImg.OutlineColor = style.outlineColor; + backgroundImg.transform.localScale = Vector3.one * style.scale; + } + + private void InitializeDefaultStyle() + { + defaultStyle = new Style(backgroundImg.OutlineColor, defaultAnimationCurve, defaultAnimationTime, 1f); + defaultStyleInitialized = true; + } + + public void SetData(Equippable e) + { + equippableData = e; + bool flag = PerkManager.instance.UnlockedEquippables.Contains(e); + bool flag2 = LevelInteractor.lastActivatedLevelInteractor.HasFixedLoadout && !LevelInteractor.lastActivatedLevelInteractor.fixedLoadout.Contains(e); + if (flag && !flag2) + { + iconImg.sprite = e.icon; + if (isWeapon) + { + backgroundImg.color = weaponBgColor; + highlightBGColor = weaponHighlightColor; + } + if (isPerk) + { + backgroundImg.color = perkBgColor; + highlightBGColor = perkHightlightColor; + } + if (isMutator) + { + backgroundImg.color = mutatorBgColor; + highlightBGColor = mutatorHighlightColor; + } + } + else if (flag && flag2) + { + iconImg.sprite = e.icon; + iconImg.color = lockedOutlineColor; + backgroundImg.color = lockedBgColor; + backgroundImg.OutlineColor = lockedOutlineColor; + } + else + { + iconImg.sprite = lockIcon; + iconImg.color = lockedOutlineColor; + backgroundImg.color = lockedBgColor; + backgroundImg.OutlineColor = lockedOutlineColor; + locked = true; + } + defaultBGColor = backgroundImg.color; + defaultIconColor = iconImg.color; + } + + public void SetDataSimple(Equippable e) + { + equippableData = e; + iconImg.sprite = e.icon; + if (isWeapon) + { + backgroundImg.color = weaponBgColor; + highlightBGColor = weaponHighlightColor; + } + if (isPerk) + { + backgroundImg.color = perkBgColor; + highlightBGColor = perkHightlightColor; + } + if (isMutator) + { + backgroundImg.color = mutatorBgColor; + highlightBGColor = mutatorHighlightColor; + } + defaultBGColor = backgroundImg.color; + defaultIconColor = iconImg.color; + } + + public void Pick() + { + backgroundImg.color = highlightBGColor; + iconImg.color = highlightIconColor; + selectedForLoadout = true; + } + + public void UnPick() + { + backgroundImg.color = defaultBGColor; + iconImg.color = defaultIconColor; + selectedForLoadout = false; + } +} diff --git a/GameCode/TFUISlider.cs b/GameCode/TFUISlider.cs new file mode 100644 index 0000000..f48ea9e --- /dev/null +++ b/GameCode/TFUISlider.cs @@ -0,0 +1,141 @@ +using MPUIKIT; +using Rewired; +using TMPro; +using UnityEngine; +using UnityEngine.Events; + +public class TFUISlider : MonoBehaviour +{ + public float minValue; + + public float maxValue = 1f; + + public float value = 1f; + + public float increments = 0.1f; + + public int displayFPPrecision = 1; + + public ThronefallUIElement target; + + public ThronefallUIElement.NavigationDirection increase; + + public ThronefallUIElement.NavigationDirection decrease = ThronefallUIElement.NavigationDirection.Left; + + public TextMeshProUGUI display; + + public GameObject knob; + + public GameObject tooltip; + + public RectTransform backgroundRect; + + public RectTransform fillRect; + + public MPImageBasic fillImg; + + public MPImageBasic knobImg; + + public UnityEvent onChange; + + public UnityEvent onNavigate; + + private Player input; + + private void Start() + { + target.onEmptyNavigate.AddListener(Navigate); + target.onSelectionStateChange.AddListener(ToggleSelectionUI); + input = ReInput.players.GetPlayer(0); + } + + private void OnEnable() + { + ToggleSelectionUI(); + } + + private void UpdateDisplay() + { + fillRect.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, backgroundRect.sizeDelta.x * Mathf.InverseLerp(minValue, maxValue, value)); + display.text = value.ToString("F" + displayFPPrecision); + } + + public void Navigate(ThronefallUIElement.NavigationDirection direction) + { + onNavigate.Invoke(); + if (direction == increase) + { + value += increments; + } + else if (direction == decrease) + { + value -= increments; + } + if (value > maxValue) + { + value = maxValue; + } + if (value < minValue) + { + value = minValue; + } + UpdateDisplay(); + onChange.Invoke(); + } + + public void Increase() + { + Navigate(increase); + } + + public void Decrease() + { + Navigate(decrease); + } + + public void OnTFUIStateChange() + { + } + + public void SetValue(float v) + { + value = v; + if (value > maxValue) + { + value = maxValue; + } + if (value < minValue) + { + value = minValue; + } + UpdateDisplay(); + } + + public void SetValueByScreenPoint(Vector2 point) + { + RectTransformUtility.ScreenPointToLocalPointInRectangle(fillRect, input.controllers.Mouse.screenPosition, null, out point); + if (point.x < 0f) + { + point.x = 0f; + } + if (point.x > backgroundRect.sizeDelta.x) + { + point.x = backgroundRect.sizeDelta.x; + } + float t = Mathf.InverseLerp(0f, backgroundRect.sizeDelta.x, point.x); + int num = Mathf.RoundToInt(Mathf.Lerp(minValue, maxValue, t) / increments); + value = increments * (float)num; + UpdateDisplay(); + onChange.Invoke(); + } + + private void ToggleSelectionUI() + { + bool active = target.CurrentState == ThronefallUIElement.SelectionState.FocussedAndSelected || target.CurrentState == ThronefallUIElement.SelectionState.Selected; + knob.SetActive(active); + if (tooltip != null) + { + tooltip.SetActive(active); + } + } +} diff --git a/GameCode/TFUISliderDragArea.cs b/GameCode/TFUISliderDragArea.cs new file mode 100644 index 0000000..b19b0be --- /dev/null +++ b/GameCode/TFUISliderDragArea.cs @@ -0,0 +1,127 @@ +using MoreMountains.Feedbacks; +using UnityEngine; + +public class TFUISliderDragArea : ThronefallUIElement +{ + public TFUISlider target; + + public Color dragColor; + + public MMF_Player onStartDrag; + + public MMF_Player onEndDrag; + + private Color defaultColor; + + private bool colorInitialized; + + private bool delayedDisable; + + private bool inDrag; + + private float afterDragCounter; + + public override bool dragable => true; + + protected override void OnApply() + { + } + + private void Update() + { + if (!delayedDisable || inDrag) + { + return; + } + afterDragCounter += Time.unscaledDeltaTime; + if (afterDragCounter > 0.35f) + { + delayedDisable = false; + target.knob.SetActive(value: false); + if ((bool)target.tooltip) + { + target.tooltip.SetActive(value: false); + } + } + } + + protected override void OnClear() + { + if (!inDrag) + { + target.knob.SetActive(value: false); + if ((bool)target.tooltip) + { + target.tooltip.SetActive(value: false); + } + } + else + { + delayedDisable = true; + afterDragCounter = 0f; + } + } + + protected override void OnFocus() + { + delayedDisable = false; + target.knob.SetActive(value: true); + if ((bool)target.tooltip) + { + target.tooltip.SetActive(value: true); + } + } + + protected override void OnFocusAndSelect() + { + } + + protected override void OnHardStateSet(SelectionState selectionState) + { + } + + protected override void OnSelect() + { + } + + public override void OnDragStart() + { + inDrag = true; + onStartDrag.PlayFeedbacks(); + if (!colorInitialized) + { + InitColor(); + } + target.fillImg.color = dragColor; + target.knobImg.color = dragColor; + } + + public override void OnDrag(Vector2 mousePosition) + { + target.SetValueByScreenPoint(mousePosition); + } + + public override void OnDragEnd() + { + onEndDrag.PlayFeedbacks(); + target.fillImg.color = defaultColor; + target.knobImg.color = defaultColor; + inDrag = false; + } + + private void InitColor() + { + defaultColor = target.fillImg.color; + colorInitialized = true; + } + + private void OnEnable() + { + if (!colorInitialized) + { + InitColor(); + } + target.fillImg.color = defaultColor; + inDrag = false; + } +} diff --git a/GameCode/TFUITextButton.cs b/GameCode/TFUITextButton.cs new file mode 100644 index 0000000..31205d1 --- /dev/null +++ b/GameCode/TFUITextButton.cs @@ -0,0 +1,195 @@ +using System; +using I2.Loc; +using TMPro; +using UnityEngine; + +[RequireComponent(typeof(TextMeshProUGUI))] +public class TFUITextButton : ThronefallUIElement +{ + [Serializable] + public class Style + { + public Color color = Color.white; + + public float fontSize = 30f; + + public string prefix; + + public string suffix; + + public TMP_FontAsset font; + + public AnimationCurve animationCurve = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f); + + public float animationDuration = 0.5f; + + public Style(Color color, float fontSize, TMP_FontAsset font, AnimationCurve animationCurve, float animationDuration) + { + this.color = color; + this.fontSize = fontSize; + this.font = font; + this.animationCurve = animationCurve; + this.animationDuration = animationDuration; + } + } + + public class Animation + { + public TFUITextButton target; + + public Style startStyle; + + public Style endStyle; + + public float clock; + + public Animation(Style startStyle, Style endStyle, TFUITextButton target) + { + this.startStyle = startStyle; + this.endStyle = endStyle; + this.target = target; + target.ApplyStyle(startStyle); + target.targetText.font = endStyle.font; + target.targetText.text = endStyle.prefix + target.originalString + endStyle.suffix; + target.currentAnimation = this; + } + + public void Tick() + { + clock += Time.unscaledDeltaTime; + float num = Mathf.InverseLerp(0f, endStyle.animationDuration, clock); + float t = endStyle.animationCurve.Evaluate(num); + target.targetText.color = Color.Lerp(startStyle.color, endStyle.color, t); + target.targetText.fontSize = Mathf.LerpUnclamped(startStyle.fontSize, endStyle.fontSize, t); + if (num >= 1f) + { + target.ApplyStyle(endStyle); + target.currentAnimation = null; + } + } + } + + private Style defaultStyle; + + private bool defaultStyleInitialized; + + public AnimationCurve defaultAnimationCurve = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f); + + public float defaultAnimationTime = 0.3f; + + public Style focussedStyle; + + public Style selectedStyle; + + public Style focussedAndSelectedStyle; + + public Style overrideStyle; + + public bool applyOverrideStyle; + + private TextMeshProUGUI targetText; + + private string originalString; + + private Animation currentAnimation; + + private Localize locComponent; + + private void Start() + { + locComponent = GetComponent(); + if (locComponent != null) + { + locComponent.LocalizeEvent.AddListener(UpdateOriginalStringLocalized); + } + } + + private void Update() + { + if (currentAnimation != null) + { + currentAnimation.Tick(); + } + } + + protected Style GetStyle(SelectionState state) + { + if (!defaultStyleInitialized) + { + InitializeDefaultStyle(); + } + return state switch + { + SelectionState.Default => defaultStyle, + SelectionState.Focussed => focussedStyle, + SelectionState.Selected => selectedStyle, + SelectionState.FocussedAndSelected => focussedAndSelectedStyle, + _ => defaultStyle, + }; + } + + protected override void OnApply() + { + } + + protected override void OnClear() + { + new Animation(GetStyle(previousState), applyOverrideStyle ? overrideStyle : defaultStyle, this); + } + + protected override void OnFocus() + { + new Animation(GetStyle(previousState), applyOverrideStyle ? overrideStyle : focussedStyle, this); + } + + protected override void OnSelect() + { + new Animation(GetStyle(previousState), applyOverrideStyle ? overrideStyle : selectedStyle, this); + } + + protected override void OnFocusAndSelect() + { + new Animation(GetStyle(previousState), applyOverrideStyle ? overrideStyle : focussedAndSelectedStyle, this); + } + + protected override void OnHardStateSet(SelectionState selectionState) + { + currentAnimation = null; + ApplyStyle(GetStyle(selectionState)); + } + + private void ApplyStyle(Style style) + { + targetText.color = style.color; + targetText.fontSize = style.fontSize; + targetText.font = style.font; + targetText.text = style.prefix + originalString + style.suffix; + } + + private void InitializeDefaultStyle() + { + if (!defaultStyleInitialized) + { + targetText = GetComponent(); + UpdateOriginalStringLocalized(); + defaultStyle = new Style(targetText.color, targetText.fontSize, targetText.font, defaultAnimationCurve, defaultAnimationTime); + defaultStyleInitialized = true; + } + } + + private void UpdateOriginalStringLocalized() + { + if (locComponent == null) + { + locComponent = GetComponent(); + } + if (locComponent == null) + { + originalString = targetText.text; + } + else + { + originalString = LocalizationManager.GetTranslation(locComponent.Term); + } + } +} diff --git a/GameCode/TFUIUpgradeChoice.cs b/GameCode/TFUIUpgradeChoice.cs new file mode 100644 index 0000000..ac4a246 --- /dev/null +++ b/GameCode/TFUIUpgradeChoice.cs @@ -0,0 +1,203 @@ +using System; +using MPUIKIT; +using UnityEngine; +using UnityEngine.UI; + +public class TFUIUpgradeChoice : ThronefallUIElement +{ + [Serializable] + public class Style + { + public float scale = 1f; + + public Color outlineColor; + + public Color bgColor; + + public AnimationCurve animationCurve = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f); + + public float animationDuration = 0.5f; + + public Style(Color outlineColor, Color bgColor, AnimationCurve animationCurve, float animationDuration, float scale) + { + this.scale = scale; + this.bgColor = bgColor; + this.outlineColor = outlineColor; + this.animationCurve = animationCurve; + this.animationDuration = animationDuration; + } + } + + public class Animation + { + public TFUIUpgradeChoice target; + + public Style startStyle; + + public Style endStyle; + + public float clock; + + public Animation(Style startStyle, Style endStyle, TFUIUpgradeChoice target) + { + this.startStyle = startStyle; + this.endStyle = endStyle; + this.target = target; + target.ApplyStyle(startStyle); + target.currentAnimation = this; + } + + public void Tick() + { + clock += Time.unscaledDeltaTime; + float num = Mathf.InverseLerp(0f, endStyle.animationDuration, clock); + float t = endStyle.animationCurve.Evaluate(num); + target.iconImg.color = Color.Lerp(startStyle.outlineColor, endStyle.outlineColor, t); + target.backgroundImg.color = Color.Lerp(startStyle.bgColor, endStyle.bgColor, t); + target.backgroundImg.OutlineColor = Color.Lerp(startStyle.outlineColor, endStyle.outlineColor, t); + target.backgroundImg.transform.localScale = Vector3.one * Mathf.LerpUnclamped(startStyle.scale, endStyle.scale, t); + if (num >= 1f) + { + target.ApplyStyle(endStyle); + target.currentAnimation = null; + } + } + } + + [SerializeField] + private Color lockedBgColor; + + [SerializeField] + private Color lockedOutlineColor; + + [SerializeField] + private MPImageBasic backgroundImg; + + [SerializeField] + private Image iconImg; + + [SerializeField] + private Sprite lockIcon; + + public AnimationCurve defaultAnimationCurve = AnimationCurve.EaseInOut(0f, 0f, 1f, 1f); + + public float defaultAnimationTime = 0.3f; + + public Style focussedStyle; + + public Style selectedStyle; + + public Style focussedAndSelectedStyle; + + private Style defaultStyle; + + private bool defaultStyleInitialized; + + private Animation currentAnimation; + + private Choice choiceData; + + private Color defaultBgColor; + + private Color defaultIconColor; + + private bool locked; + + public Choice Data => choiceData; + + public bool Locked => locked; + + public Image IconImg => iconImg; + + private void Update() + { + if (currentAnimation != null) + { + currentAnimation.Tick(); + } + } + + protected override void OnApply() + { + } + + protected override void OnClear() + { + new Animation(GetStyle(previousState), defaultStyle, this); + } + + protected override void OnFocus() + { + new Animation(GetStyle(previousState), focussedStyle, this); + } + + protected override void OnSelect() + { + new Animation(GetStyle(previousState), selectedStyle, this); + } + + protected override void OnFocusAndSelect() + { + new Animation(GetStyle(previousState), focussedAndSelectedStyle, this); + } + + protected override void OnHardStateSet(SelectionState selectionState) + { + currentAnimation = null; + ApplyStyle(GetStyle(selectionState)); + } + + protected Style GetStyle(SelectionState state) + { + if (!defaultStyleInitialized) + { + InitializeDefaultStyle(); + } + return state switch + { + SelectionState.Default => defaultStyle, + SelectionState.Focussed => focussedStyle, + SelectionState.Selected => selectedStyle, + SelectionState.FocussedAndSelected => focussedAndSelectedStyle, + _ => defaultStyle, + }; + } + + private void ApplyStyle(Style style) + { + iconImg.color = style.outlineColor; + backgroundImg.color = style.bgColor; + backgroundImg.OutlineColor = style.outlineColor; + backgroundImg.transform.localScale = Vector3.one * style.scale; + } + + private void InitializeDefaultStyle() + { + defaultBgColor = backgroundImg.color; + defaultIconColor = iconImg.color; + defaultStyle = new Style(backgroundImg.OutlineColor, backgroundImg.color, defaultAnimationCurve, defaultAnimationTime, 1f); + defaultStyleInitialized = true; + } + + public void SetData(Choice _choice) + { + choiceData = _choice; + bool flag = true; + if (_choice.requiresUnlocked != null && !PerkManager.instance.UnlockedEquippables.Contains(_choice.requiresUnlocked)) + { + flag = false; + } + if (flag) + { + iconImg.sprite = _choice.icon; + return; + } + iconImg.sprite = lockIcon; + iconImg.color = lockedOutlineColor; + backgroundImg.color = lockedBgColor; + backgroundImg.OutlineColor = lockedOutlineColor; + selectedStyle.bgColor = lockedBgColor; + selectedStyle.outlineColor = lockedOutlineColor; + locked = true; + } +} diff --git a/GameCode/TagManager.cs b/GameCode/TagManager.cs new file mode 100644 index 0000000..2c4c835 --- /dev/null +++ b/GameCode/TagManager.cs @@ -0,0 +1,223 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +public class TagManager : MonoBehaviour +{ + public enum ETag + { + PlayerOwned, + EnemyOwned, + Player, + CastleCenter, + MeeleFighter, + RangedFighter, + Flying, + PlayerUnit, + Building, + SiegeWeapon, + AUTO_Alive, + AUTO_KnockedOutAndHealOnDawn, + Wall, + InfrastructureEconomy, + TakesReducedDamageFromPlayerAttacks, + PracticeTargets, + FastMoving, + ArmoredAgainstRanged, + VulnerableVsRanged, + Monster, + House, + WallOrTower, + AUTO_Commanded, + TakesIncreasedDamageFromTowers, + Tower, + AUTO_NoReviveNextMorning, + PlayerOwnedPriorityTarget, + BlockableEnemyProjectile, + Boss, + UselessWallThatDoesNotBlockPath + } + + public static TagManager instance; + + [SerializeField] + private Dictionary> dictonaryOfListsOfTaggedObjects; + + private List tempTaggedObjectList = new List(); + + private List bufferedPlayerUnits = new List(); + + private List bufferedEnemyUnits = new List(); + + private List bufferedPlayers = new List(); + + public List playerBuildingInteractors = new List(); + + public List freeCoins = new List(); + + public List coins = new List(); + + public IReadOnlyList PlayerUnits => bufferedPlayerUnits.AsReadOnly(); + + public IReadOnlyList EnemyUnits => bufferedEnemyUnits.AsReadOnly(); + + public IReadOnlyList Players => bufferedPlayers.AsReadOnly(); + + private void OnEnable() + { + instance = this; + dictonaryOfListsOfTaggedObjects = new Dictionary>(); + for (int i = 0; i < Enum.GetValues(typeof(ETag)).Length; i++) + { + dictonaryOfListsOfTaggedObjects.Add((ETag)i, new List()); + } + } + + public void AddTaggedObject(TaggedObject _taggedObject) + { + foreach (ETag tag in _taggedObject.Tags) + { + AddTag(_taggedObject, tag); + if (tag == ETag.EnemyOwned) + { + bufferedEnemyUnits.Add(_taggedObject); + } + if (tag == ETag.PlayerUnit) + { + bufferedPlayerUnits.Add(_taggedObject); + } + if (tag == ETag.Player) + { + bufferedPlayers.Add(_taggedObject); + } + } + } + + public void RemoveTaggedObject(TaggedObject _taggedObject) + { + if (bufferedEnemyUnits.Contains(_taggedObject)) + { + bufferedEnemyUnits.Remove(_taggedObject); + } + if (bufferedPlayerUnits.Contains(_taggedObject)) + { + bufferedPlayerUnits.Remove(_taggedObject); + } + foreach (ETag tag in _taggedObject.Tags) + { + RemoveTag(_taggedObject, tag); + } + } + + public void AddTag(TaggedObject _taggedObject, ETag _tag) + { + List list = dictonaryOfListsOfTaggedObjects[_tag]; + if (!list.Contains(_taggedObject)) + { + list.Add(_taggedObject); + } + } + + public void RemoveTag(TaggedObject _taggedObject, ETag _tag) + { + List list = dictonaryOfListsOfTaggedObjects[_tag]; + if (list.Contains(_taggedObject)) + { + list.Remove(_taggedObject); + } + } + + public int CountObjectsWithTag(ETag _tag) + { + return dictonaryOfListsOfTaggedObjects[_tag].Count; + } + + public void FindAllTaggedObjectsWithTags(List _listToPolulate, List _mustHaveTags, List _mayNotHaveTags) + { + _listToPolulate.Clear(); + if (_mustHaveTags.Count <= 0) + { + return; + } + List list = null; + int num = int.MaxValue; + for (int i = 0; i < _mustHaveTags.Count; i++) + { + List list2 = dictonaryOfListsOfTaggedObjects[_mustHaveTags[i]]; + if (list2.Count < num) + { + list = list2; + num = list2.Count; + } + } + if (list.Count == 0) + { + return; + } + for (int j = 0; j < list.Count; j++) + { + TaggedObject taggedObject = list[j]; + List tags = taggedObject.Tags; + bool flag = true; + if (_mustHaveTags != null) + { + for (int k = 0; k < _mustHaveTags.Count; k++) + { + if (!tags.Contains(_mustHaveTags[k])) + { + flag = false; + break; + } + } + } + if (_mayNotHaveTags != null) + { + for (int l = 0; l < _mayNotHaveTags.Count; l++) + { + if (tags.Contains(_mayNotHaveTags[l])) + { + flag = false; + break; + } + } + } + if (flag) + { + _listToPolulate.Add(taggedObject); + } + } + } + + public TaggedObject FindClosestTaggedObjectWithTags(Vector3 _position, List _mustHaveTags, List _mayNotHaveTags) + { + tempTaggedObjectList.Clear(); + FindAllTaggedObjectsWithTags(tempTaggedObjectList, _mustHaveTags, _mayNotHaveTags); + TaggedObject result = null; + float num = float.MaxValue; + for (int i = 0; i < tempTaggedObjectList.Count; i++) + { + TaggedObject taggedObject = tempTaggedObjectList[i]; + float num2 = MeasureDistanceToTaggedObject(taggedObject, _position); + if (num2 < num) + { + num = num2; + result = taggedObject; + } + } + return result; + } + + public float MeasureDistanceToTaggedObject(TaggedObject _taggedObj, Vector3 _pos) + { + if (_taggedObj.colliderForBigOjectsToMeasureDistance != null) + { + return (_taggedObj.colliderForBigOjectsToMeasureDistance.ClosestPoint(_pos) - _pos).magnitude; + } + return (_taggedObj.transform.position - _pos).magnitude; + } + + public int CountAllTaggedObjectsWithTag(ETag _mustHaveTag) + { + return dictonaryOfListsOfTaggedObjects[_mustHaveTag].Count; + } +} diff --git a/GameCode/TaggedObject.cs b/GameCode/TaggedObject.cs new file mode 100644 index 0000000..d6bede0 --- /dev/null +++ b/GameCode/TaggedObject.cs @@ -0,0 +1,59 @@ +using System.Collections.Generic; +using UnityEngine; + +public class TaggedObject : MonoBehaviour +{ + [SerializeField] + private List tags = new List(); + + private TagManager tagManager; + + private Hp hp; + + public Collider colliderForBigOjectsToMeasureDistance; + + public List Tags => tags; + + public Hp Hp => hp; + + private void Start() + { + hp = GetComponent(); + } + + private void OnEnable() + { + if (tagManager == null) + { + tagManager = TagManager.instance; + } + tagManager.AddTaggedObject(this); + } + + private void OnDisable() + { + if (tagManager == null) + { + tagManager = TagManager.instance; + } + tagManager.RemoveTaggedObject(this); + } + + public void AddTag(TagManager.ETag _tag) + { + if (!tags.Contains(_tag)) + { + tags.Add(_tag); + tagManager.AddTag(this, _tag); + } + } + + public void RemoveTag(TagManager.ETag _tag) + { + if (tags.Contains(_tag)) + { + tags.Remove(_tag); + tagManager.RemoveTag(this, _tag); + } + } +} diff --git a/GameCode/TargetPriority.cs b/GameCode/TargetPriority.cs new file mode 100644 index 0000000..55672c0 --- /dev/null +++ b/GameCode/TargetPriority.cs @@ -0,0 +1,127 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +[Serializable] +public class TargetPriority +{ + public List mustHaveTags = new List(); + + public List mayNotHaveTags = new List(); + + public float range; + + private List allTaggedObjects = new List(); + + private TagManager tagManager; + + public TaggedObject FindClosestTaggedObject(Vector3 _position) + { + TaggedObject taggedObject = TagManager.instance.FindClosestTaggedObjectWithTags(_position, mustHaveTags, mayNotHaveTags); + if (taggedObject == null) + { + return null; + } + float num = ((!(taggedObject.colliderForBigOjectsToMeasureDistance != null)) ? (taggedObject.transform.position - _position).magnitude : (taggedObject.colliderForBigOjectsToMeasureDistance.ClosestPoint(_position) - _position).magnitude); + if (num <= range) + { + return taggedObject; + } + return null; + } + + public TaggedObject FindHighestHealthObjectInRange(Vector3 _position) + { + tagManager = TagManager.instance; + allTaggedObjects.Clear(); + tagManager.FindAllTaggedObjectsWithTags(allTaggedObjects, mustHaveTags, mayNotHaveTags); + TaggedObject result = null; + float num = 0f; + for (int i = 0; i < allTaggedObjects.Count; i++) + { + if (!(tagManager.MeasureDistanceToTaggedObject(allTaggedObjects[i], _position) > range)) + { + Hp hp = allTaggedObjects[i].Hp; + if (hp.HpValue > num) + { + num = hp.HpValue; + result = allTaggedObjects[i]; + } + } + } + return result; + } + + public TaggedObject FindLowestHealthObjectInRange(Vector3 _position, bool _excludeFullHealthTargets = true) + { + tagManager = TagManager.instance; + allTaggedObjects.Clear(); + tagManager.FindAllTaggedObjectsWithTags(allTaggedObjects, mustHaveTags, mayNotHaveTags); + TaggedObject result = null; + float num = 100f; + for (int i = 0; i < allTaggedObjects.Count; i++) + { + if (!(tagManager.MeasureDistanceToTaggedObject(allTaggedObjects[i], _position) > range)) + { + Hp hp = allTaggedObjects[i].Hp; + if ((!_excludeFullHealthTargets || !(hp.HpPercentage >= 1f)) && hp.HpPercentage < num) + { + num = hp.HpPercentage; + result = allTaggedObjects[i]; + } + } + } + return result; + } + + public TaggedObject FindTaggedObject(Vector3 _position, out Vector3 _outPosition) + { + _outPosition = Vector3.zero; + TaggedObject taggedObject = TagManager.instance.FindClosestTaggedObjectWithTags(_position, mustHaveTags, mayNotHaveTags); + if (taggedObject == null) + { + return null; + } + float magnitude; + if (taggedObject.colliderForBigOjectsToMeasureDistance != null) + { + _outPosition = taggedObject.colliderForBigOjectsToMeasureDistance.ClosestPoint(_position); + magnitude = (_outPosition - _position).magnitude; + } + else + { + _outPosition = taggedObject.transform.position; + magnitude = (_outPosition - _position).magnitude; + } + if (magnitude <= range) + { + return taggedObject; + } + return null; + } + + public TaggedObject FindTaggedObjectCloseToHome(Vector3 _position, Vector3 _home, float _homeRange, out Vector3 _outPosition) + { + _outPosition = Vector3.zero; + TaggedObject taggedObject = TagManager.instance.FindClosestTaggedObjectWithTags(_position, mustHaveTags, mayNotHaveTags); + if (taggedObject == null) + { + return null; + } + if (taggedObject.colliderForBigOjectsToMeasureDistance != null) + { + _outPosition = taggedObject.colliderForBigOjectsToMeasureDistance.ClosestPoint(_position); + } + else + { + _outPosition = taggedObject.transform.position; + } + float magnitude = (_outPosition - _position).magnitude; + float magnitude2 = (_outPosition - _home).magnitude; + if (magnitude <= range || magnitude2 <= _homeRange) + { + return taggedObject; + } + return null; + } +} diff --git a/GameCode/TextBackgroundFitter.cs b/GameCode/TextBackgroundFitter.cs new file mode 100644 index 0000000..34a9e73 --- /dev/null +++ b/GameCode/TextBackgroundFitter.cs @@ -0,0 +1,24 @@ +using UnityEngine; +using UnityEngine.UI; + +public class TextBackgroundFitter : MonoBehaviour +{ + private RectTransform ownRT; + + public RectTransform target; + + public ContentSizeFitter csf; + + public float horizontalPaddingPerSide; + + public float verticalPaddingPerSide; + + private void OnEnable() + { + ownRT = GetComponent(); + csf.enabled = false; + csf.enabled = true; + LayoutRebuilder.ForceRebuildLayoutImmediate(target); + ownRT.sizeDelta = new Vector2(target.sizeDelta.x + horizontalPaddingPerSide * 2f, target.sizeDelta.y + verticalPaddingPerSide * 2f); + } +} diff --git a/GameCode/Thronefall.csproj b/GameCode/Thronefall.csproj new file mode 100644 index 0000000..b89e7bc --- /dev/null +++ b/GameCode/Thronefall.csproj @@ -0,0 +1,344 @@ + + + Assembly-CSharp + False + netstandard2.1 + + + 11.0 + True + + + + + ..\Game\Thronefall_Data\Managed\AstarPathfindingProject.dll + + + ..\Game\Thronefall_Data\Managed\com.rlabrecque.steamworks.net.dll + + + ..\Game\Thronefall_Data\Managed\Lofelt.NiceVibrations.dll + + + ..\Game\Thronefall_Data\Managed\Lofelt.NiceVibrations.Demo.dll + + + ..\Game\Thronefall_Data\Managed\MoreMountains.Feedbacks.dll + + + ..\Game\Thronefall_Data\Managed\MoreMountains.Feedbacks.Cinemachine.dll + + + ..\Game\Thronefall_Data\Managed\MoreMountains.Feedbacks.HDRP.dll + + + ..\Game\Thronefall_Data\Managed\MoreMountains.Feedbacks.MMTools.dll + + + ..\Game\Thronefall_Data\Managed\MoreMountains.Feedbacks.NiceVibrations.dll + + + ..\Game\Thronefall_Data\Managed\MoreMountains.Feedbacks.PostProcessing.dll + + + ..\Game\Thronefall_Data\Managed\MoreMountains.Feedbacks.TextMeshPro.dll + + + ..\Game\Thronefall_Data\Managed\MoreMountains.Feedbacks.URP.dll + + + ..\Game\Thronefall_Data\Managed\MoreMountains.Tools.dll + + + ..\Game\Thronefall_Data\Managed\MPUIKit.dll + + + ..\Game\Thronefall_Data\Managed\Pathfinding.ClipperLib.dll + + + ..\Game\Thronefall_Data\Managed\Pathfinding.Ionic.Zip.Reduced.dll + + + ..\Game\Thronefall_Data\Managed\Pathfinding.Poly2Tri.dll + + + ..\Game\Thronefall_Data\Managed\Rewired_Core.dll + + + ..\Game\Thronefall_Data\Managed\Rewired_Windows.dll + + + ..\Game\Thronefall_Data\Managed\Rewired_Windows_Functions.dll + + + ..\Game\Thronefall_Data\Managed\ShapesRuntime.dll + + + ..\Game\Thronefall_Data\Managed\Unity.AI.Navigation.dll + + + ..\Game\Thronefall_Data\Managed\Unity.Burst.dll + + + ..\Game\Thronefall_Data\Managed\Unity.Burst.Unsafe.dll + + + ..\Game\Thronefall_Data\Managed\Unity.Collections.dll + + + ..\Game\Thronefall_Data\Managed\Unity.Collections.LowLevel.ILSupport.dll + + + ..\Game\Thronefall_Data\Managed\Unity.Mathematics.dll + + + ..\Game\Thronefall_Data\Managed\Unity.Recorder.dll + + + ..\Game\Thronefall_Data\Managed\Unity.Recorder.Base.dll + + + ..\Game\Thronefall_Data\Managed\Unity.RenderPipeline.Universal.ShaderLibrary.dll + + + ..\Game\Thronefall_Data\Managed\Unity.RenderPipelines.Core.Runtime.dll + + + ..\Game\Thronefall_Data\Managed\Unity.RenderPipelines.Core.ShaderLibrary.dll + + + ..\Game\Thronefall_Data\Managed\Unity.RenderPipelines.ShaderGraph.ShaderGraphLibrary.dll + + + ..\Game\Thronefall_Data\Managed\Unity.RenderPipelines.Universal.Runtime.dll + + + ..\Game\Thronefall_Data\Managed\Unity.RenderPipelines.Universal.Shaders.dll + + + ..\Game\Thronefall_Data\Managed\Unity.TextMeshPro.dll + + + ..\Game\Thronefall_Data\Managed\Unity.Timeline.dll + + + ..\Game\Thronefall_Data\Managed\Unity.VisualScripting.Antlr3.Runtime.dll + + + ..\Game\Thronefall_Data\Managed\Unity.VisualScripting.Core.dll + + + ..\Game\Thronefall_Data\Managed\Unity.VisualScripting.Flow.dll + + + ..\Game\Thronefall_Data\Managed\Unity.VisualScripting.State.dll + + + ..\Game\Thronefall_Data\Managed\UnityEngine.dll + + + ..\Game\Thronefall_Data\Managed\UnityEngine.AccessibilityModule.dll + + + ..\Game\Thronefall_Data\Managed\UnityEngine.AIModule.dll + + + ..\Game\Thronefall_Data\Managed\UnityEngine.AndroidJNIModule.dll + + + ..\Game\Thronefall_Data\Managed\UnityEngine.AnimationModule.dll + + + ..\Game\Thronefall_Data\Managed\UnityEngine.ARModule.dll + + + ..\Game\Thronefall_Data\Managed\UnityEngine.AssetBundleModule.dll + + + ..\Game\Thronefall_Data\Managed\UnityEngine.AudioModule.dll + + + ..\Game\Thronefall_Data\Managed\UnityEngine.ClothModule.dll + + + ..\Game\Thronefall_Data\Managed\UnityEngine.ClusterInputModule.dll + + + ..\Game\Thronefall_Data\Managed\UnityEngine.ClusterRendererModule.dll + + + ..\Game\Thronefall_Data\Managed\UnityEngine.ContentLoadModule.dll + + + ..\Game\Thronefall_Data\Managed\UnityEngine.CoreModule.dll + + + ..\Game\Thronefall_Data\Managed\UnityEngine.CrashReportingModule.dll + + + ..\Game\Thronefall_Data\Managed\UnityEngine.DirectorModule.dll + + + ..\Game\Thronefall_Data\Managed\UnityEngine.DSPGraphModule.dll + + + ..\Game\Thronefall_Data\Managed\UnityEngine.GameCenterModule.dll + + + ..\Game\Thronefall_Data\Managed\UnityEngine.GIModule.dll + + + ..\Game\Thronefall_Data\Managed\UnityEngine.GridModule.dll + + + ..\Game\Thronefall_Data\Managed\UnityEngine.HotReloadModule.dll + + + ..\Game\Thronefall_Data\Managed\UnityEngine.ImageConversionModule.dll + + + ..\Game\Thronefall_Data\Managed\UnityEngine.IMGUIModule.dll + + + ..\Game\Thronefall_Data\Managed\UnityEngine.InputLegacyModule.dll + + + ..\Game\Thronefall_Data\Managed\UnityEngine.InputModule.dll + + + ..\Game\Thronefall_Data\Managed\UnityEngine.JSONSerializeModule.dll + + + ..\Game\Thronefall_Data\Managed\UnityEngine.LocalizationModule.dll + + + ..\Game\Thronefall_Data\Managed\UnityEngine.NVIDIAModule.dll + + + ..\Game\Thronefall_Data\Managed\UnityEngine.ParticleSystemModule.dll + + + ..\Game\Thronefall_Data\Managed\UnityEngine.PerformanceReportingModule.dll + + + ..\Game\Thronefall_Data\Managed\UnityEngine.Physics2DModule.dll + + + ..\Game\Thronefall_Data\Managed\UnityEngine.PhysicsModule.dll + + + ..\Game\Thronefall_Data\Managed\UnityEngine.ProfilerModule.dll + + + ..\Game\Thronefall_Data\Managed\UnityEngine.PropertiesModule.dll + + + ..\Game\Thronefall_Data\Managed\UnityEngine.RuntimeInitializeOnLoadManagerInitializerModule.dll + + + ..\Game\Thronefall_Data\Managed\UnityEngine.ScreenCaptureModule.dll + + + ..\Game\Thronefall_Data\Managed\UnityEngine.SharedInternalsModule.dll + + + ..\Game\Thronefall_Data\Managed\UnityEngine.SpriteMaskModule.dll + + + ..\Game\Thronefall_Data\Managed\UnityEngine.SpriteShapeModule.dll + + + ..\Game\Thronefall_Data\Managed\UnityEngine.StreamingModule.dll + + + ..\Game\Thronefall_Data\Managed\UnityEngine.SubstanceModule.dll + + + ..\Game\Thronefall_Data\Managed\UnityEngine.SubsystemsModule.dll + + + ..\Game\Thronefall_Data\Managed\UnityEngine.TerrainModule.dll + + + ..\Game\Thronefall_Data\Managed\UnityEngine.TerrainPhysicsModule.dll + + + ..\Game\Thronefall_Data\Managed\UnityEngine.TextCoreFontEngineModule.dll + + + ..\Game\Thronefall_Data\Managed\UnityEngine.TextCoreTextEngineModule.dll + + + ..\Game\Thronefall_Data\Managed\UnityEngine.TextRenderingModule.dll + + + ..\Game\Thronefall_Data\Managed\UnityEngine.TilemapModule.dll + + + ..\Game\Thronefall_Data\Managed\UnityEngine.TLSModule.dll + + + ..\Game\Thronefall_Data\Managed\UnityEngine.UI.dll + + + ..\Game\Thronefall_Data\Managed\UnityEngine.UIElementsModule.dll + + + ..\Game\Thronefall_Data\Managed\UnityEngine.UIModule.dll + + + ..\Game\Thronefall_Data\Managed\UnityEngine.UmbraModule.dll + + + ..\Game\Thronefall_Data\Managed\UnityEngine.UnityAnalyticsCommonModule.dll + + + ..\Game\Thronefall_Data\Managed\UnityEngine.UnityAnalyticsModule.dll + + + ..\Game\Thronefall_Data\Managed\UnityEngine.UnityConnectModule.dll + + + ..\Game\Thronefall_Data\Managed\UnityEngine.UnityCurlModule.dll + + + ..\Game\Thronefall_Data\Managed\UnityEngine.UnityTestProtocolModule.dll + + + ..\Game\Thronefall_Data\Managed\UnityEngine.UnityWebRequestAssetBundleModule.dll + + + ..\Game\Thronefall_Data\Managed\UnityEngine.UnityWebRequestAudioModule.dll + + + ..\Game\Thronefall_Data\Managed\UnityEngine.UnityWebRequestModule.dll + + + ..\Game\Thronefall_Data\Managed\UnityEngine.UnityWebRequestTextureModule.dll + + + ..\Game\Thronefall_Data\Managed\UnityEngine.UnityWebRequestWWWModule.dll + + + ..\Game\Thronefall_Data\Managed\UnityEngine.VehiclesModule.dll + + + ..\Game\Thronefall_Data\Managed\UnityEngine.VFXModule.dll + + + ..\Game\Thronefall_Data\Managed\UnityEngine.VideoModule.dll + + + ..\Game\Thronefall_Data\Managed\UnityEngine.VirtualTexturingModule.dll + + + ..\Game\Thronefall_Data\Managed\UnityEngine.VRModule.dll + + + ..\Game\Thronefall_Data\Managed\UnityEngine.WindModule.dll + + + ..\Game\Thronefall_Data\Managed\UnityEngine.XRModule.dll + + + \ No newline at end of file diff --git a/GameCode/Thronefall.sln b/GameCode/Thronefall.sln new file mode 100644 index 0000000..87fce31 --- /dev/null +++ b/GameCode/Thronefall.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.4.33213.308 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Thronefall", "Thronefall.csproj", "{58D17092-0D05-4EB8-B23C-6DE022D1D11F}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {58D17092-0D05-4EB8-B23C-6DE022D1D11F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {58D17092-0D05-4EB8-B23C-6DE022D1D11F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {58D17092-0D05-4EB8-B23C-6DE022D1D11F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {58D17092-0D05-4EB8-B23C-6DE022D1D11F}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {BB7D9AA4-B90C-45B5-8CA6-2B41EAC195EB} + EndGlobalSection +EndGlobal diff --git a/GameCode/ThronefallAudioManager.cs b/GameCode/ThronefallAudioManager.cs new file mode 100644 index 0000000..291c626 --- /dev/null +++ b/GameCode/ThronefallAudioManager.cs @@ -0,0 +1,342 @@ +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.Audio; +using UnityEngine.Events; + +public class ThronefallAudioManager : MonoBehaviour +{ + public class OneshotSource + { + public AudioSource aSource; + + public bool available = true; + + public OneshotSource(AudioSource audioSource) + { + aSource = audioSource; + } + } + + public enum AudioOneShot + { + BuildingBuild, + BuildingUpgrade, + CoinslotFill, + CoinslotInteractionStart, + LastCoinslotFill, + CoinFillCancel, + NightSurvived, + BuildingRepair, + EismolochAppear, + EismolochSpawn, + ButtonSelect, + ButtonApply, + ButtonApplyHero, + CoinCollect, + BuildingStandardProjectile, + BallistaProjectile, + PlayerSwordBigHit, + EnemySpawn, + ShowWaveCount, + CloseWaveCount, + ShowTooltip, + None + } + + private static ThronefallAudioManager instance; + + public readonly float oneshotAudioPoolSize = 15f; + + public readonly float onshotAudioPoolRecycleTick = 0.3f; + + private float oneshotSourceRecycleClock; + + private List oneshotSourcePool = new List(); + + private OneshotSource bufferOneshotSource; + + public AudioSet audioContent; + + public AudioMixerGroup mgMusic; + + public AudioMixerGroup mgSFX; + + public AudioMixerGroup mgEnvironment; + + [HideInInspector] + public UnityEvent onBuildingBuild = new UnityEvent(); + + private bool muted; + + private float coinslotFillPitch = 1f; + + private float coinslotFillPitchIncrease = 0.025f; + + private OneshotSource coinslotFillBackground; + + private float coinslotFillBackgroundClock; + + private float coinslotTotalFillTime = 1f; + + public static ThronefallAudioManager Instance => instance; + + private void Awake() + { + if (instance != null) + { + Object.Destroy(base.gameObject); + return; + } + instance = this; + Object.DontDestroyOnLoad(base.gameObject); + AudioSource audioSource = null; + for (int i = 0; (float)i < oneshotAudioPoolSize; i++) + { + audioSource = new GameObject("Oneshot Source " + i).AddComponent(); + audioSource.transform.SetParent(base.transform); + audioSource.rolloffMode = AudioRolloffMode.Linear; + audioSource.minDistance = 1f; + audioSource.maxDistance = 80f; + audioSource.spatialBlend = 0f; + oneshotSourcePool.Add(new OneshotSource(audioSource)); + } + } + + private void Update() + { + oneshotSourceRecycleClock += Time.unscaledDeltaTime; + if (oneshotSourceRecycleClock > onshotAudioPoolRecycleTick) + { + RecycleOneshotSources(); + } + if (coinslotFillBackground != null) + { + coinslotFillBackgroundClock += Time.deltaTime; + coinslotFillBackground.aSource.pitch = Mathf.Lerp(0.75f, 1f, coinslotFillBackgroundClock / coinslotTotalFillTime); + } + } + + private void ProcessOneShotEvent(AudioOneShot oneshot, bool worldspace = false, Vector3 position = default(Vector3)) + { + if (!muted) + { + switch (oneshot) + { + case AudioOneShot.CoinslotInteractionStart: + coinslotFillPitch = 1f; + PlaySoundAsOneShot(audioContent.CoinslotInteractionStart); + StopCoinfillBackground(); + coinslotFillBackground = PlaySoundAsOneShot(audioContent.PayBackground, 0.2f, 0.75f); + break; + case AudioOneShot.CoinslotFill: + PlaySoundAsOneShot(audioContent.CoinslotFill, 1f, coinslotFillPitch); + coinslotFillPitch += coinslotFillPitchIncrease; + break; + case AudioOneShot.LastCoinslotFill: + PlaySoundAsOneShot(audioContent.LastCoinslotFill); + StopCoinfillBackground(); + break; + case AudioOneShot.CoinFillCancel: + StopCoinfillBackground(); + break; + case AudioOneShot.BuildingBuild: + onBuildingBuild.Invoke(); + PlaySoundAsOneShot(audioContent.BuildingBuild, 1f, Random.RandomRange(0.9f, 1.1f)); + break; + case AudioOneShot.BuildingUpgrade: + PlaySoundAsOneShot(audioContent.BuildingUpgrade); + break; + case AudioOneShot.NightSurvived: + PlaySoundAsOneShot(audioContent.NightSurvived, 0.8f, 1f, null, 0); + break; + case AudioOneShot.BuildingRepair: + PlaySoundAsOneShot(audioContent.BuildingRepair); + break; + case AudioOneShot.EismolochAppear: + PlaySoundAsOneShot(audioContent.EismolochAppear.clips[Random.Range(0, audioContent.EismolochAppear.clips.Length)]); + break; + case AudioOneShot.EismolochSpawn: + PlaySoundAsOneShot(audioContent.EismolochSpawnUnits.clips[Random.Range(0, audioContent.EismolochSpawnUnits.clips.Length)], 1f, 1f, null, 0); + break; + case AudioOneShot.ButtonSelect: + PlaySoundAsOneShot(audioContent.ButtonSelect.GetRandomClip()); + break; + case AudioOneShot.ButtonApply: + PlaySoundAsOneShot(audioContent.ButtonApply.GetRandomClip()); + break; + case AudioOneShot.ButtonApplyHero: + PlaySoundAsOneShot(audioContent.ButtonApplyHero.GetRandomClip()); + break; + case AudioOneShot.CoinCollect: + PlaySoundAsOneShot(audioContent.CoinCollect.GetRandomClip(), 1f, Random.Range(0.9f, 1.1f)); + break; + case AudioOneShot.BuildingStandardProjectile: + PlaySoundAsOneShot(audioContent.TowerShot.GetRandomClip(), 0.5f, Random.Range(0.95f, 1.05f), null, 50, worldspace: true, position); + break; + case AudioOneShot.BallistaProjectile: + PlaySoundAsOneShot(audioContent.BallistaShot.GetRandomClip(), 1f, 1f, null, 30, worldspace: true, position); + break; + case AudioOneShot.PlayerSwordBigHit: + PlaySoundAsOneShot(audioContent.PlayerSwordBigHit); + break; + case AudioOneShot.EnemySpawn: + PlaySoundAsOneShot(audioContent.EnemySpawn, 0.85f, Random.Range(0.95f, 1.05f), null, 140, worldspace: true, position); + break; + case AudioOneShot.ShowWaveCount: + PlaySoundAsOneShot(audioContent.ShowWaveCount, 0.5f); + break; + case AudioOneShot.CloseWaveCount: + PlaySoundAsOneShot(audioContent.CloseWaveCount); + break; + case AudioOneShot.ShowTooltip: + PlaySoundAsOneShot(audioContent.ShowTooltip, 0.3f); + break; + } + } + } + + public OneshotSource PlaySoundAsOneShot(AudioClip clip, float volume = 1f, float pitch = 1f, AudioMixerGroup mixerGroup = null, int priority = 128, bool worldspace = false, Vector3 position = default(Vector3)) + { + if (mixerGroup == null) + { + mixerGroup = mgSFX; + } + bufferOneshotSource = GetFreeOneshotSource(); + if (bufferOneshotSource == null) + { + return null; + } + if (worldspace) + { + bufferOneshotSource.aSource.transform.position = position; + bufferOneshotSource.aSource.spatialBlend = 1f; + } + else + { + bufferOneshotSource.aSource.spatialBlend = 0f; + } + bufferOneshotSource.aSource.volume = volume; + bufferOneshotSource.aSource.pitch = pitch; + bufferOneshotSource.aSource.outputAudioMixerGroup = mixerGroup; + bufferOneshotSource.aSource.priority = priority; + bufferOneshotSource.aSource.PlayOneShot(clip); + bufferOneshotSource.available = false; + return bufferOneshotSource; + } + + public OneshotSource PlaySoundAsOneShot(AudioSet.ClipArray clips, float volume = 1f, float pitch = 1f, AudioMixerGroup mixerGroup = null, int priority = 128, bool worldspace = false, Vector3 position = default(Vector3)) + { + if (clips == null) + { + return null; + } + if (clips.clips.Length == 0) + { + return null; + } + if (mixerGroup == null) + { + mixerGroup = mgSFX; + } + bufferOneshotSource = GetFreeOneshotSource(); + if (bufferOneshotSource == null) + { + return null; + } + if (worldspace) + { + bufferOneshotSource.aSource.transform.position = position; + bufferOneshotSource.aSource.spatialBlend = 1f; + } + else + { + bufferOneshotSource.aSource.spatialBlend = 0f; + } + bufferOneshotSource.aSource.volume = volume; + bufferOneshotSource.aSource.pitch = pitch; + bufferOneshotSource.aSource.outputAudioMixerGroup = mixerGroup; + bufferOneshotSource.aSource.priority = priority; + bufferOneshotSource.aSource.PlayOneShot(clips.clips[Random.Range(0, clips.clips.Length)]); + bufferOneshotSource.available = false; + return bufferOneshotSource; + } + + private OneshotSource GetFreeOneshotSource() + { + foreach (OneshotSource item in oneshotSourcePool) + { + if (item.available) + { + return item; + } + } + return oneshotSourcePool[0]; + } + + private void RecycleOneshotSources() + { + foreach (OneshotSource item in oneshotSourcePool) + { + if (!item.aSource.isPlaying) + { + item.available = true; + } + } + oneshotSourceRecycleClock = 0f; + } + + private void StopCoinfillBackground() + { + if (coinslotFillBackground != null) + { + coinslotFillBackground.available = true; + coinslotFillBackground.aSource.Stop(); + coinslotFillBackground = null; + coinslotFillBackgroundClock = 0f; + } + } + + public void MakeSureCoinFillSoundIsNotPlayingAnymore() + { + StopCoinfillBackground(); + } + + public static void Oneshot(AudioOneShot oneshot) + { + if (instance != null) + { + instance.ProcessOneShotEvent(oneshot); + } + else + { + Debug.LogError("No Audio Manager"); + } + } + + public static void WorldSpaceOneShot(AudioOneShot oneshot, Vector3 position) + { + if (instance != null) + { + instance.ProcessOneShotEvent(oneshot, worldspace: true, position); + } + else + { + Debug.LogError("No Audio Manager"); + } + } + + public static void Mute() + { + instance.muted = true; + } + + public static void Unmute() + { + instance.muted = false; + } + + public static void SetCoinDisplayFillTime(float time) + { + instance.coinslotTotalFillTime = time; + } +} diff --git a/GameCode/ThronefallUIElement.cs b/GameCode/ThronefallUIElement.cs new file mode 100644 index 0000000..e2c9d64 --- /dev/null +++ b/GameCode/ThronefallUIElement.cs @@ -0,0 +1,166 @@ +using UnityEngine; +using UnityEngine.Events; + +public abstract class ThronefallUIElement : MonoBehaviour +{ + public enum NavigationDirection + { + Right, + Left, + Up, + Down + } + + public enum SelectionState + { + Default, + Focussed, + Selected, + FocussedAndSelected + } + + protected SelectionState currentState; + + protected SelectionState previousState; + + public bool ignoreMouse; + + public bool autoSelectOnFocus; + + public bool cannotBeSelected; + + public ThronefallUIElement leftNav; + + public ThronefallUIElement rightNav; + + public ThronefallUIElement topNav; + + public ThronefallUIElement botNav; + + public UnityEvent onSelectionStateChange = new UnityEvent(); + + public UnityEvent onApply = new UnityEvent(); + + public UnityEvent onEmptyNavigate = new UnityEvent(); + + public SelectionState CurrentState => currentState; + + public SelectionState PreviousState => previousState; + + public virtual bool dragable => false; + + public void Apply() + { + if (!SceneTransitionManager.instance.SceneTransitionIsRunning) + { + onApply.Invoke(); + OnApply(); + } + } + + public void Select() + { + SetState(SelectionState.Selected); + } + + public void Focus() + { + SetState(SelectionState.Focussed); + } + + public void FocusAndSelect() + { + SetState(SelectionState.FocussedAndSelected); + } + + public void Clear() + { + SetState(SelectionState.Default); + } + + public void HardStateSet(SelectionState selectionState) + { + currentState = selectionState; + previousState = selectionState; + OnHardStateSet(selectionState); + } + + protected abstract void OnApply(); + + protected abstract void OnClear(); + + protected abstract void OnSelect(); + + protected abstract void OnFocus(); + + protected abstract void OnFocusAndSelect(); + + protected abstract void OnHardStateSet(SelectionState selectionState); + + private void SetState(SelectionState state) + { + if (state != currentState) + { + previousState = currentState; + currentState = state; + switch (currentState) + { + case SelectionState.Default: + OnClear(); + break; + case SelectionState.Focussed: + OnFocus(); + break; + case SelectionState.Selected: + OnSelect(); + break; + case SelectionState.FocussedAndSelected: + OnFocusAndSelect(); + break; + } + onSelectionStateChange.Invoke(); + } + } + + public ThronefallUIElement TryNavigate(NavigationDirection direction) + { + if (SceneTransitionManager.instance.SceneTransitionIsRunning) + { + return this; + } + ThronefallUIElement thronefallUIElement = null; + switch (direction) + { + case NavigationDirection.Down: + thronefallUIElement = botNav; + break; + case NavigationDirection.Up: + thronefallUIElement = topNav; + break; + case NavigationDirection.Left: + thronefallUIElement = leftNav; + break; + case NavigationDirection.Right: + thronefallUIElement = rightNav; + break; + } + if ((bool)thronefallUIElement && !thronefallUIElement.gameObject.activeInHierarchy) + { + return thronefallUIElement.TryNavigate(direction); + } + onEmptyNavigate.Invoke(direction); + return thronefallUIElement; + } + + public virtual void OnDrag(Vector2 mousePosition) + { + } + + public virtual void OnDragEnd() + { + } + + public virtual void OnDragStart() + { + } +} diff --git a/GameCode/TimesensitiveLight.cs b/GameCode/TimesensitiveLight.cs new file mode 100644 index 0000000..158fa2b --- /dev/null +++ b/GameCode/TimesensitiveLight.cs @@ -0,0 +1,68 @@ +using System.Collections; +using UnityEngine; + +[RequireComponent(typeof(Light))] +public class TimesensitiveLight : MonoBehaviour, DayNightCycle.IDaytimeSensitive +{ + public float dayIntensity = 1f; + + public float nightIntensity; + + public float blendTime = 3f; + + private Light target; + + public void OnDawn_AfterSunrise() + { + } + + public void OnDawn_BeforeSunrise() + { + StopAllCoroutines(); + StartCoroutine(BlendToDay(blendTime)); + } + + public void OnDusk() + { + StopAllCoroutines(); + StartCoroutine(BlendToNight(blendTime)); + } + + private void Start() + { + target = GetComponent(); + DayNightCycle.Instance.RegisterDaytimeSensitiveObject(this); + if (DayNightCycle.Instance.CurrentTimestate == DayNightCycle.Timestate.Day) + { + StartCoroutine(BlendToDay(0f)); + } + else + { + StartCoroutine(BlendToNight(0f)); + } + } + + private IEnumerator BlendToNight(float duration) + { + float timer = 0f; + while (timer <= duration) + { + timer += Time.deltaTime; + target.intensity = Mathf.Lerp(dayIntensity, nightIntensity, Mathf.InverseLerp(0f, duration, timer)); + yield return null; + } + target.intensity = nightIntensity; + } + + private IEnumerator BlendToDay(float duration) + { + float timer = 0f; + while (timer <= duration) + { + timer += Time.deltaTime; + target.intensity = Mathf.Lerp(nightIntensity, dayIntensity, Mathf.InverseLerp(0f, duration, timer)); + yield return null; + } + target.intensity = dayIntensity; + } +} diff --git a/GameCode/TitleScreenPopUpHelper.cs b/GameCode/TitleScreenPopUpHelper.cs new file mode 100644 index 0000000..7eb9d23 --- /dev/null +++ b/GameCode/TitleScreenPopUpHelper.cs @@ -0,0 +1,28 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +public class TitleScreenPopUpHelper : MonoBehaviour +{ + private int currentIndex; + + public List popUpOrder = new List(); + + public void PopNext() + { + StartCoroutine(DelayedPopUp()); + } + + private IEnumerator DelayedPopUp() + { + yield return null; + if (currentIndex < popUpOrder.Count) + { + if (popUpOrder[currentIndex].showInFullVersion) + { + UIFrameManager.instance.ChangeActiveFrameKeepOldVisible(popUpOrder[currentIndex].uiFrame); + } + currentIndex++; + } + } +} diff --git a/GameCode/TitleScreenUIHelper.cs b/GameCode/TitleScreenUIHelper.cs new file mode 100644 index 0000000..51e2415 --- /dev/null +++ b/GameCode/TitleScreenUIHelper.cs @@ -0,0 +1,21 @@ +using UnityEngine; + +public class TitleScreenUIHelper : MonoBehaviour +{ + [SerializeField] + private Equippable tutorialWeapon; + + public void ClickPlay() + { + if (LevelProgressManager.instance.GetLevelDataForScene("Neuland(Tutorial)").highscoreBest > 0 || LevelProgressManager.instance.GetLevelDataForScene("Neuland(Tutorial)").beatenBest) + { + Debug.Log("Start game in level select as tutorial has already been played."); + SceneTransitionManager.instance.TransitionFromNullToLevelSelect(); + return; + } + Debug.Log("Start it tutorial!"); + PerkManager.instance.CurrentlyEquipped.Clear(); + PerkManager.instance.CurrentlyEquipped.Add(tutorialWeapon); + SceneTransitionManager.instance.TransitionFromNullToLevel("Neuland(Tutorial)"); + } +} diff --git a/GameCode/Tooltip.cs b/GameCode/Tooltip.cs new file mode 100644 index 0000000..86091f7 --- /dev/null +++ b/GameCode/Tooltip.cs @@ -0,0 +1,63 @@ +using MoreMountains.Feedbacks; +using TMPro; +using UnityEngine; +using UnityEngine.UI; + +public class Tooltip : MonoBehaviour +{ + [SerializeField] + private TextMeshProUGUI content; + + [SerializeField] + private RectTransform targetRect; + + [SerializeField] + private MMF_Player onOpen; + + [SerializeField] + private MMF_Player onClose; + + [SerializeField] + private MMF_Player onUpdate; + + public string currentText => content.text; + + private void Awake() + { + base.transform.localScale = Vector3.zero; + content.text = ""; + } + + public void SetTooltip(string tooltipTxt) + { + if (tooltipTxt == content.text) + { + return; + } + onOpen.StopFeedbacks(); + onClose.StopFeedbacks(); + onUpdate.StopFeedbacks(); + content.text = tooltipTxt; + if (tooltipTxt == "") + { + onClose.PlayFeedbacks(); + return; + } + if (content.text == "") + { + onOpen.PlayFeedbacks(); + } + else + { + onUpdate.PlayFeedbacks(); + } + UpdateSize(); + } + + private void UpdateSize() + { + RectTransform component = GetComponent(); + LayoutRebuilder.ForceRebuildLayoutImmediate(targetRect); + component.sizeDelta = targetRect.sizeDelta; + } +} diff --git a/GameCode/TooltipManager.cs b/GameCode/TooltipManager.cs new file mode 100644 index 0000000..54be2e3 --- /dev/null +++ b/GameCode/TooltipManager.cs @@ -0,0 +1,102 @@ +using UnityEngine; + +public class TooltipManager : MonoBehaviour +{ + public Tooltip targetTooltip; + + private PlayerInteraction playerInteraction; + + private string tutorialOverridePriority = ""; + + private string tutorialOverride = ""; + + private string nextTooltipText = ""; + + private InteractorBase lastFocus; + + private int lastFocusLevel = -9999; + + private bool interactorRefreshFlag; + + public static TooltipManager instance; + + public void SetTutorialOverride(string _text, bool _priorityText = true) + { + if (_priorityText) + { + tutorialOverridePriority = _text; + } + else + { + tutorialOverride = _text; + } + } + + private void Awake() + { + instance = this; + } + + private void Start() + { + playerInteraction = PlayerInteraction.instance; + SceneTransitionManager.instance.onSceneChange.AddListener(ResetAfterSceneLoad); + } + + private void ResetAfterSceneLoad() + { + tutorialOverride = ""; + tutorialOverridePriority = ""; + nextTooltipText = ""; + } + + private void Update() + { + if (playerInteraction != PlayerInteraction.instance) + { + playerInteraction = PlayerInteraction.instance; + } + if (playerInteraction == null) + { + return; + } + if (UIFrameManager.instance.ActiveFrame != null) + { + nextTooltipText = ""; + interactorRefreshFlag = true; + } + else if (tutorialOverridePriority != "") + { + nextTooltipText = tutorialOverridePriority; + interactorRefreshFlag = true; + } + else if ((bool)playerInteraction.FocussedInteractor) + { + if (lastFocus != playerInteraction.FocussedInteractor || interactorRefreshFlag) + { + nextTooltipText = playerInteraction.FocussedInteractor.ReturnTooltip(); + lastFocus = playerInteraction.FocussedInteractor; + interactorRefreshFlag = false; + } + } + else if (tutorialOverride != "") + { + nextTooltipText = tutorialOverride; + interactorRefreshFlag = true; + } + else + { + nextTooltipText = ""; + lastFocus = null; + } + if (nextTooltipText != targetTooltip.currentText) + { + targetTooltip.SetTooltip(nextTooltipText); + } + } + + public void SetInteractorRefreshFlag() + { + interactorRefreshFlag = true; + } +} diff --git a/GameCode/TreasureChestUIHelper.cs b/GameCode/TreasureChestUIHelper.cs new file mode 100644 index 0000000..e0a7b5c --- /dev/null +++ b/GameCode/TreasureChestUIHelper.cs @@ -0,0 +1,39 @@ +using TMPro; +using UnityEngine; + +public class TreasureChestUIHelper : MonoBehaviour +{ + public Transform scaleTarget; + + public TextMeshProUGUI balanceNumber; + + public GameObject toggleParent; + + private DayNightCycle dnc; + + private LocalGamestate lgs; + + private void Update() + { + if (dnc == null) + { + dnc = DayNightCycle.Instance; + } + if (lgs == null) + { + lgs = LocalGamestate.Instance; + } + if (dnc == null || lgs == null) + { + toggleParent.SetActive(value: false); + } + else if (dnc.CurrentTimestate == DayNightCycle.Timestate.Day && lgs.CurrentState == LocalGamestate.State.InMatch) + { + toggleParent.SetActive(value: true); + } + else + { + toggleParent.SetActive(value: false); + } + } +} diff --git a/GameCode/TreasuryUI.cs b/GameCode/TreasuryUI.cs new file mode 100644 index 0000000..e86b87d --- /dev/null +++ b/GameCode/TreasuryUI.cs @@ -0,0 +1,224 @@ +using System.Collections.Generic; +using TMPro; +using UnityEngine; + +public class TreasuryUI : MonoBehaviour, DayNightCycle.IDaytimeSensitive +{ + public enum AnimationState + { + Off, + ScaleIn, + On, + ScaleOut, + WaitToScaleOut + } + + public Transform coinsParent; + + public GameObject renderCamera; + + public GameObject coinPrefab; + + public Transform spawn; + + public float removalInterval; + + public float addInterval = 0.35f; + + public float activationLifetime = 1f; + + public AnimationCurve scaleCurve; + + public float scaleAnimationSpeed; + + private Transform scaleTarget; + + public float waitTimeBeforeScaleOut = 0.3f; + + private TextMeshProUGUI displayText; + + public Animator treasureChestAnimator; + + private List instantiatedCoins = new List(); + + private PlayerInteraction targetPlayer; + + private int coinQeue; + + private float addCounter; + + private float removalCounter; + + private float activationCounter; + + private bool overrideActivation; + + private AnimationState currentState; + + private float scaleAnimationProgress; + + private float scaleOutWaitClock; + + private bool shouldBeActive + { + get + { + if (!(activationCounter > 0f)) + { + return overrideActivation; + } + return true; + } + } + + private void Start() + { + DayNightCycle.Instance.RegisterDaytimeSensitiveObject(this); + scaleTarget = UIFrameManager.instance.TreasureChest.scaleTarget; + displayText = UIFrameManager.instance.TreasureChest.balanceNumber; + targetPlayer = TagManager.instance.Players[0].GetComponent(); + targetPlayer.onBalanceGain.AddListener(AddCoins); + targetPlayer.onBalanceSpend.AddListener(RemoveCoins); + targetPlayer.onFocusPaymentInteraction.AddListener(LockActivation); + targetPlayer.onUnfocusPaymentInteraction.AddListener(UnlockActivation); + AddCoins(targetPlayer.Balance); + SetState(currentState); + } + + private void SetState(AnimationState newState) + { + switch (newState) + { + case AnimationState.Off: + scaleTarget.localScale = Vector3.one * scaleCurve.Evaluate(0f); + scaleAnimationProgress = 0f; + break; + case AnimationState.On: + scaleTarget.localScale = Vector3.one * scaleCurve.Evaluate(1f); + scaleAnimationProgress = 1f; + treasureChestAnimator.SetBool("Open", value: true); + break; + case AnimationState.WaitToScaleOut: + treasureChestAnimator.SetBool("Open", value: false); + scaleOutWaitClock = 0f; + break; + } + currentState = newState; + } + + private void Update() + { + if (addCounter > 0f) + { + addCounter -= Time.deltaTime; + } + if (removalCounter > 0f) + { + removalCounter -= Time.deltaTime; + } + if (activationCounter > 0f) + { + activationCounter -= Time.deltaTime; + } + if (coinQeue > 0 && addCounter <= 0f) + { + GameObject item = Object.Instantiate(coinPrefab, spawn.position, Random.rotation, coinsParent); + instantiatedCoins.Add(item); + coinQeue--; + addCounter = addInterval; + activationCounter = activationLifetime; + } + if (coinQeue < 0 && addCounter <= 0f) + { + GameObject obj = instantiatedCoins[instantiatedCoins.Count - 1]; + instantiatedCoins.RemoveAt(instantiatedCoins.Count - 1); + Object.Destroy(obj); + coinQeue++; + removalCounter = removalInterval; + activationCounter = activationLifetime; + } + switch (currentState) + { + case AnimationState.Off: + if (shouldBeActive) + { + SetState(AnimationState.ScaleIn); + } + break; + case AnimationState.On: + if (!shouldBeActive) + { + SetState(AnimationState.WaitToScaleOut); + } + break; + case AnimationState.WaitToScaleOut: + scaleOutWaitClock += Time.deltaTime; + if (scaleOutWaitClock >= waitTimeBeforeScaleOut) + { + SetState(AnimationState.ScaleOut); + } + break; + case AnimationState.ScaleOut: + scaleAnimationProgress -= Time.deltaTime * scaleAnimationSpeed; + scaleTarget.localScale = Vector3.one * scaleCurve.Evaluate(scaleAnimationProgress); + if (scaleAnimationProgress <= 0f) + { + SetState(AnimationState.Off); + } + else if (shouldBeActive) + { + SetState(AnimationState.ScaleIn); + } + break; + case AnimationState.ScaleIn: + scaleAnimationProgress += Time.deltaTime * scaleAnimationSpeed; + scaleTarget.localScale = Vector3.one * scaleCurve.Evaluate(scaleAnimationProgress); + if (scaleAnimationProgress >= 1f) + { + SetState(AnimationState.On); + } + else if (!shouldBeActive) + { + SetState(AnimationState.ScaleIn); + } + break; + } + } + + private void AddCoins(int amount) + { + coinQeue += amount; + displayText.text = "" + targetPlayer.Balance; + } + + private void RemoveCoins(int amount) + { + coinQeue -= amount; + displayText.text = "" + targetPlayer.Balance; + } + + private void LockActivation() + { + overrideActivation = true; + } + + private void UnlockActivation() + { + overrideActivation = false; + activationCounter = activationLifetime; + } + + public void OnDusk() + { + renderCamera.SetActive(value: false); + } + + public void OnDawn_AfterSunrise() + { + } + + public void OnDawn_BeforeSunrise() + { + renderCamera.SetActive(value: true); + } +} diff --git a/GameCode/TutorialManager.cs b/GameCode/TutorialManager.cs new file mode 100644 index 0000000..681344f --- /dev/null +++ b/GameCode/TutorialManager.cs @@ -0,0 +1,662 @@ +using System.Collections.Generic; +using I2.Loc; +using Pathfinding.RVO; +using UnityEngine; + +public class TutorialManager : MonoBehaviour +{ + public static TutorialManager instance; + + private PlayerInteraction playerInteraction; + + private DayNightCycle dayNightCycle; + + private TooltipManager tooltipManager; + + private TagManager tagManager; + + private EnemySpawner enemySpawner; + + private bool allowStartingTheNight = true; + + private static readonly string LOCIDENTIFIER = "Tutorial/"; + + [SerializeField] + private Transform arrowMarkerTransform; + + [SerializeField] + private ScreenMarker arrowMarker; + + [SerializeField] + private Transform player; + + [Header("When you're dead")] + [SerializeField] + private Hp playerHp; + + [Header("Movement Tutorial")] + [SerializeField] + private RVOController playerRvo; + + [SerializeField] + private float requiredMoveDist; + + private bool playerHasLearnedHowToMove; + + private bool destroyedPracticeTargets; + + private bool playerDidSprint; + + [Header("Build Castle Center")] + [SerializeField] + private BuildingInteractor caslteBuildInteractor; + + private bool castleCenterBuilt; + + private bool mayShowEnemySpawn; + + [Header("Start The Night")] + private bool firstNightStarted; + + [Header("First Night")] + [SerializeField] + private StabMA activeStabAttack; + + [Header("Build Houses")] + [SerializeField] + private List houses; + + private bool housesBuilt; + + [Header("Start The 2nd Night")] + private bool secondNightStarted; + + [Header("2nd Night")] + [Header("Collect Taxes")] + [SerializeField] + private List towers; + + private bool towersBuilt; + + [Header("Start The 3d Night")] + private bool thirdNightStarted; + + [Header("Upgrade Castle Center")] + [SerializeField] + private BuildSlot caslteBuilSlot; + + [SerializeField] + private GameObject royalTraining; + + [SerializeField] + private GameObject buildersGuild; + + private bool castleCenterUpgraded; + + private bool fourthNightStarted; + + [Header("It's up to you!")] + [SerializeField] + private BuildSlot barracks; + + [SerializeField] + private CommandUnits command; + + private bool commandingUnits; + + private bool commandedUnits; + + private bool triedHoldPosition; + + [TextArea(1, 10)] + public string whileDead; + + [TextArea(1, 10)] + public string howToMove; + + [TextArea(1, 10)] + public string howToSprint; + + [TextArea(1, 10)] + public string howToBuild; + + [TextArea(1, 10)] + public string startTheNight; + + [TextArea(1, 10)] + public string howToStartTheNight; + + [TextArea(1, 10)] + public string tooExpensiveToBuild; + + [TextArea(1, 10)] + public string tooExpensiveToUpgrade; + + [TextArea(1, 10)] + public string tooExpensiveToUpgradeCastleCenter; + + [TextArea(1, 10)] + public string firstNight; + + [TextArea(1, 10)] + public string firstNightDone; + + [TextArea(1, 10)] + public string buildHouses; + + [TextArea(1, 10)] + public string startThe2ndNight; + + [TextArea(1, 10)] + public string secondNight; + + [TextArea(1, 10)] + public string buildTowers; + + [TextArea(1, 10)] + public string startThe3ndNight; + + [TextArea(1, 10)] + public string upgradeCastleCenter; + + [TextArea(1, 10)] + public string howToUpgrade; + + [TextArea(1, 10)] + public string chooseAnUpgrade; + + [TextArea(1, 10)] + public string goodChoiceGeneric; + + [TextArea(1, 10)] + public string goodChoiceRoyalTraining; + + [TextArea(1, 10)] + public string goodChoiceBuildersGuild; + + [TextArea(1, 10)] + public string itsUpToYou; + + [TextArea(1, 10)] + public string maybeBuildBarracksSomeTime; + + [TextArea(1, 10)] + public string tryToCommandYourUnits; + + [TextArea(1, 10)] + public string makeThemHoldPosition; + + [TextArea(1, 10)] + public string howToHeal; + + [TextArea(1, 10)] + public string lastDay; + + [TextArea(1, 10)] + public string lastNight; + + private List findTaggedObjects = new List(); + + private List mustHaveTag = new List(); + + private List mayNotHaveTag = new List(); + + public static bool AllowStartingTheNight + { + get + { + if (!instance) + { + return true; + } + return instance.allowStartingTheNight; + } + } + + public bool MayShowEnemySpawn => mayShowEnemySpawn; + + private void SetArrowMarker(bool _enabled, Vector3 _pos, bool _offScreenOnly = false) + { + arrowMarkerTransform.gameObject.SetActive(_enabled); + arrowMarkerTransform.position = _pos + Vector3.up * 10f; + arrowMarker.showWhenOnScreen = !_offScreenOnly; + } + + private void MarkNearestObjectWithTag(TagManager.ETag _tag, bool _offScreenOnly = false) + { + findTaggedObjects.Clear(); + mustHaveTag.Clear(); + mayNotHaveTag.Clear(); + mustHaveTag.Add(_tag); + TagManager.instance.FindAllTaggedObjectsWithTags(findTaggedObjects, mustHaveTag, mayNotHaveTag); + if (findTaggedObjects.Count <= 0) + { + return; + } + TaggedObject taggedObject = null; + float num = float.MaxValue; + for (int i = 0; i < findTaggedObjects.Count; i++) + { + float magnitude = (player.transform.position - findTaggedObjects[i].transform.position).magnitude; + if (magnitude < num) + { + num = magnitude; + taggedObject = findTaggedObjects[i]; + } + } + SetArrowMarker(_enabled: true, taggedObject.transform.position, _offScreenOnly); + } + + private void MarkNearestUnbuiltBuilding(List _buildSlots) + { + List list = new List(_buildSlots); + for (int num = list.Count - 1; num >= 0; num--) + { + if (list[num].State == BuildSlot.BuildingState.Built) + { + list.RemoveAt(num); + } + else if (!list[num].gameObject.activeInHierarchy) + { + list.RemoveAt(num); + } + } + if (list.Count <= 0) + { + return; + } + BuildSlot buildSlot = null; + float num2 = float.MaxValue; + for (int i = 0; i < list.Count; i++) + { + float magnitude = (player.transform.position - list[i].transform.position).magnitude; + if (magnitude < num2) + { + num2 = magnitude; + buildSlot = list[i]; + } + } + SetArrowMarker(_enabled: true, buildSlot.transform.position); + } + + private void MarkNearestGoldCoin() + { + List freeCoins = TagManager.instance.freeCoins; + if (freeCoins.Count <= 0) + { + return; + } + Coin coin = null; + float num = float.MaxValue; + for (int i = 0; i < freeCoins.Count; i++) + { + float magnitude = (player.transform.position - freeCoins[i].transform.position).magnitude; + if (magnitude < num) + { + num = magnitude; + coin = freeCoins[i]; + } + } + SetArrowMarker(_enabled: true, coin.transform.position); + } + + private void Awake() + { + instance = this; + } + + private void OnEnable() + { + LocalizationManager.OnLocalizeEvent += FetchLocalizedTexts; + } + + private void OnDisable() + { + LocalizationManager.OnLocalizeEvent -= FetchLocalizedTexts; + } + + private void Start() + { + dayNightCycle = DayNightCycle.Instance; + tooltipManager = TooltipManager.instance; + tagManager = TagManager.instance; + playerInteraction = PlayerInteraction.instance; + enemySpawner = EnemySpawner.instance; + FetchLocalizedTexts(); + } + + private void Update() + { + if (SceneTransitionManager.instance.SceneTransitionIsRunning) + { + return; + } + SetArrowMarker(_enabled: false, Vector3.zero); + tooltipManager.SetTutorialOverride(""); + tooltipManager.SetTutorialOverride("", _priorityText: false); + if (playerHp.KnockedOut) + { + tooltipManager.SetTutorialOverride(whileDead); + return; + } + if (!playerHasLearnedHowToMove) + { + MarkNearestObjectWithTag(TagManager.ETag.PracticeTargets); + tooltipManager.SetTutorialOverride(howToMove); + requiredMoveDist -= playerRvo.velocity.magnitude * Time.deltaTime; + if (requiredMoveDist < 0f) + { + playerHasLearnedHowToMove = true; + } + return; + } + if (!destroyedPracticeTargets) + { + MarkNearestObjectWithTag(TagManager.ETag.PracticeTargets); + if (tagManager.CountAllTaggedObjectsWithTag(TagManager.ETag.PracticeTargets) <= 0) + { + destroyedPracticeTargets = true; + } + return; + } + if (tagManager.freeCoins.Count > 0 && dayNightCycle.CurrentTimestate == DayNightCycle.Timestate.Day && enemySpawner.Wavenumber == -1 && enemySpawner.Wavenumber <= 3) + { + MarkNearestGoldCoin(); + return; + } + if (!castleCenterBuilt) + { + if (PlayerManager.Instance.RegisteredPlayers[0].Sprinting) + { + playerDidSprint = true; + } + if (playerInteraction.FocussedInteractor == caslteBuildInteractor) + { + tooltipManager.SetTutorialOverride(howToBuild); + } + else + { + tooltipManager.SetTutorialOverride(howToSprint); + if (playerDidSprint) + { + SetArrowMarker(_enabled: true, caslteBuildInteractor.transform.position); + } + } + if (tagManager.CountAllTaggedObjectsWithTag(TagManager.ETag.Building) > 0) + { + castleCenterBuilt = true; + mayShowEnemySpawn = true; + enemySpawner.EnemySpawnersHornUnFocussed(); + } + return; + } + if (playerInteraction.FocussedInteractor != null && playerInteraction.FocussedInteractor.GetType() == typeof(BuildingInteractor)) + { + BuildingInteractor buildingInteractor = (BuildingInteractor)playerInteraction.FocussedInteractor; + if (buildingInteractor.targetBuilding.CanBeUpgraded && playerInteraction.Balance + CostDisplay.currentlyFilledCoinsFromLastActiveDisplay < buildingInteractor.targetBuilding.NextUpgradeOrBuildCost && !buildingInteractor.UpgradeCueVisible) + { + if (buildingInteractor.targetBuilding.State == BuildSlot.BuildingState.Blueprint) + { + tooltipManager.SetTutorialOverride(tooExpensiveToBuild); + } + else if (buildingInteractor.targetBuilding.GetComponentInChildren().Tags.Contains(TagManager.ETag.CastleCenter)) + { + tooltipManager.SetTutorialOverride(tooExpensiveToUpgradeCastleCenter); + } + else + { + tooltipManager.SetTutorialOverride(tooExpensiveToUpgrade); + } + return; + } + } + if (!firstNightStarted) + { + tooltipManager.SetTutorialOverride(startTheNight); + if (dayNightCycle.CurrentTimestate == DayNightCycle.Timestate.Night) + { + firstNightStarted = true; + } + return; + } + if (enemySpawner.Wavenumber == 0 && dayNightCycle.CurrentTimestate == DayNightCycle.Timestate.Night) + { + EnemySpawner.instance.InfinitelySpawning = activeStabAttack.TargetsStabeed < 3; + MarkNearestObjectWithTag(TagManager.ETag.EnemyOwned, _offScreenOnly: true); + allowStartingTheNight = false; + if (activeStabAttack.TargetsStabeed < 3) + { + tooltipManager.SetTutorialOverride(firstNight + " (" + activeStabAttack.TargetsStabeed + "/3)"); + } + else + { + tooltipManager.SetTutorialOverride(firstNightDone); + } + return; + } + if (!housesBuilt && dayNightCycle.CurrentTimestate == DayNightCycle.Timestate.Day) + { + MarkNearestUnbuiltBuilding(houses); + int num = tagManager.CountAllTaggedObjectsWithTag(TagManager.ETag.Building); + int num2 = num - 1; + tooltipManager.SetTutorialOverride(buildHouses + " (" + num2 + "/3)"); + if (playerInteraction.FocussedInteractor != null && playerInteraction.FocussedInteractor.GetType() == typeof(BuildingInteractor)) + { + SetArrowMarker(_enabled: false, Vector3.zero); + if (num2 == 0) + { + tooltipManager.SetTutorialOverride(howToBuild); + } + } + if (num >= 4) + { + housesBuilt = true; + } + return; + } + if (!secondNightStarted && housesBuilt) + { + allowStartingTheNight = true; + tooltipManager.SetTutorialOverride(startThe2ndNight); + if (dayNightCycle.CurrentTimestate == DayNightCycle.Timestate.Night) + { + secondNightStarted = true; + } + return; + } + if (enemySpawner.Wavenumber == 1 && dayNightCycle.CurrentTimestate == DayNightCycle.Timestate.Night) + { + MarkNearestObjectWithTag(TagManager.ETag.EnemyOwned, _offScreenOnly: true); + allowStartingTheNight = false; + tooltipManager.SetTutorialOverride(secondNight); + return; + } + if (!towersBuilt && dayNightCycle.CurrentTimestate == DayNightCycle.Timestate.Day) + { + if (dayNightCycle.AfterSunrise) + { + MarkNearestUnbuiltBuilding(towers); + if (playerInteraction.FocussedInteractor != null && playerInteraction.FocussedInteractor.GetType() == typeof(BuildingInteractor)) + { + SetArrowMarker(_enabled: false, Vector3.zero); + } + int num3 = tagManager.CountAllTaggedObjectsWithTag(TagManager.ETag.Building) - 4; + tooltipManager.SetTutorialOverride(buildTowers + " (" + num3 + "/2)"); + if (num3 >= 2) + { + towersBuilt = true; + } + } + return; + } + if (!thirdNightStarted && towersBuilt) + { + allowStartingTheNight = true; + tooltipManager.SetTutorialOverride(startThe3ndNight); + if (dayNightCycle.CurrentTimestate == DayNightCycle.Timestate.Night) + { + thirdNightStarted = true; + } + return; + } + if (ChoiceManager.instance.ChoiceCoroutineRunning) + { + tooltipManager.SetTutorialOverride(chooseAnUpgrade); + return; + } + if (thirdNightStarted && !castleCenterUpgraded && dayNightCycle.CurrentTimestate == DayNightCycle.Timestate.Day) + { + allowStartingTheNight = false; + if (!dayNightCycle.AfterSunrise) + { + return; + } + if (playerInteraction.FocussedInteractor == caslteBuildInteractor) + { + tooltipManager.SetTutorialOverride(howToUpgrade); + return; + } + SetArrowMarker(_enabled: true, caslteBuildInteractor.transform.position); + tooltipManager.SetTutorialOverride(upgradeCastleCenter); + if (caslteBuilSlot.Level == 2) + { + castleCenterUpgraded = true; + allowStartingTheNight = true; + } + return; + } + if (!fourthNightStarted && castleCenterUpgraded) + { + allowStartingTheNight = true; + if (royalTraining.activeInHierarchy) + { + tooltipManager.SetTutorialOverride(goodChoiceRoyalTraining); + } + else if (buildersGuild.activeInHierarchy) + { + tooltipManager.SetTutorialOverride(goodChoiceBuildersGuild); + } + else + { + tooltipManager.SetTutorialOverride(goodChoiceGeneric); + } + if (dayNightCycle.CurrentTimestate == DayNightCycle.Timestate.Night) + { + fourthNightStarted = true; + } + return; + } + if (enemySpawner.Wavenumber == 3 && dayNightCycle.CurrentTimestate == DayNightCycle.Timestate.Night) + { + allowStartingTheNight = false; + return; + } + if (barracks.State == BuildSlot.BuildingState.Built && dayNightCycle.CurrentTimestate == DayNightCycle.Timestate.Day) + { + if (!dayNightCycle.AfterSunrise) + { + return; + } + if (!commandedUnits) + { + if (command.commanding) + { + commandingUnits = true; + } + if (commandingUnits && !command.commanding) + { + commandedUnits = true; + } + tooltipManager.SetTutorialOverride(tryToCommandYourUnits); + return; + } + if (!triedHoldPosition) + { + foreach (TaggedObject playerUnit in TagManager.instance.PlayerUnits) + { + if (playerUnit.GetComponent().HoldPosition) + { + triedHoldPosition = true; + } + } + tooltipManager.SetTutorialOverride(makeThemHoldPosition); + } + } + if (enemySpawner.Wavenumber == 3 && dayNightCycle.CurrentTimestate == DayNightCycle.Timestate.Day) + { + if (dayNightCycle.AfterSunrise) + { + tooltipManager.SetTutorialOverride(itsUpToYou, _priorityText: false); + allowStartingTheNight = true; + } + } + else if (enemySpawner.Wavenumber == 4 && dayNightCycle.CurrentTimestate == DayNightCycle.Timestate.Night) + { + tooltipManager.SetTutorialOverride(howToHeal); + } + else if (enemySpawner.Wavenumber >= 4 && dayNightCycle.CurrentTimestate == DayNightCycle.Timestate.Day && barracks.State != BuildSlot.BuildingState.Built && playerInteraction.Balance + CostDisplay.currentlyFilledCoinsFromLastActiveDisplay >= 4) + { + if (dayNightCycle.AfterSunrise) + { + tooltipManager.SetTutorialOverride(maybeBuildBarracksSomeTime, _priorityText: false); + if (playerInteraction.FocussedInteractor == null) + { + SetArrowMarker(_enabled: true, barracks.transform.position + Vector3.up * 3f); + } + } + } + else if (enemySpawner.Wavenumber == 5 && dayNightCycle.CurrentTimestate == DayNightCycle.Timestate.Night) + { + tooltipManager.SetTutorialOverride(howToHeal); + } + else if (enemySpawner.Wavenumber == 5 && dayNightCycle.CurrentTimestate == DayNightCycle.Timestate.Day) + { + _ = dayNightCycle.AfterSunrise; + } + else if (enemySpawner.Wavenumber == 6 && dayNightCycle.CurrentTimestate == DayNightCycle.Timestate.Night) + { + tooltipManager.SetTutorialOverride(howToHeal); + } + else if (enemySpawner.Wavenumber == 6 && dayNightCycle.CurrentTimestate == DayNightCycle.Timestate.Day) + { + tooltipManager.SetTutorialOverride(lastDay, _priorityText: false); + } + else if (enemySpawner.Wavenumber == 7 && dayNightCycle.CurrentTimestate == DayNightCycle.Timestate.Night) + { + tooltipManager.SetTutorialOverride(lastNight); + } + } + + private void FetchLocalizedTexts() + { + whileDead = LocalizationManager.GetTranslation(LOCIDENTIFIER + "whileDead"); + howToMove = LocalizationManager.GetTranslation(LOCIDENTIFIER + "howToMove"); + howToSprint = LocalizationManager.GetTranslation(LOCIDENTIFIER + "howToSprint"); + howToBuild = LocalizationManager.GetTranslation(LOCIDENTIFIER + "howToBuild"); + startTheNight = LocalizationManager.GetTranslation(LOCIDENTIFIER + "startTheNight"); + howToStartTheNight = LocalizationManager.GetTranslation(LOCIDENTIFIER + "howToStartTheNight"); + tooExpensiveToBuild = LocalizationManager.GetTranslation(LOCIDENTIFIER + "tooExpensiveToBuild"); + tooExpensiveToUpgrade = LocalizationManager.GetTranslation(LOCIDENTIFIER + "tooExpensiveToUpgrade"); + tooExpensiveToUpgradeCastleCenter = LocalizationManager.GetTranslation(LOCIDENTIFIER + "tooExpensiveToUpgradeCastleCenter"); + firstNight = LocalizationManager.GetTranslation(LOCIDENTIFIER + "firstNight"); + firstNightDone = LocalizationManager.GetTranslation(LOCIDENTIFIER + "firstNightDone"); + buildHouses = LocalizationManager.GetTranslation(LOCIDENTIFIER + "buildHouses"); + startThe2ndNight = LocalizationManager.GetTranslation(LOCIDENTIFIER + "startThe2ndNight"); + secondNight = LocalizationManager.GetTranslation(LOCIDENTIFIER + "secondNight"); + buildTowers = LocalizationManager.GetTranslation(LOCIDENTIFIER + "buildTowers"); + startThe3ndNight = LocalizationManager.GetTranslation(LOCIDENTIFIER + "startThe3ndNight"); + upgradeCastleCenter = LocalizationManager.GetTranslation(LOCIDENTIFIER + "upgradeCastleCenter"); + howToUpgrade = LocalizationManager.GetTranslation(LOCIDENTIFIER + "howToUpgrade"); + chooseAnUpgrade = LocalizationManager.GetTranslation(LOCIDENTIFIER + "chooseAnUpgrade"); + goodChoiceGeneric = LocalizationManager.GetTranslation(LOCIDENTIFIER + "goodChoiceGeneric"); + goodChoiceRoyalTraining = LocalizationManager.GetTranslation(LOCIDENTIFIER + "goodChoiceRoyalTraining"); + goodChoiceBuildersGuild = LocalizationManager.GetTranslation(LOCIDENTIFIER + "goodChoiceBuildersGuild"); + itsUpToYou = LocalizationManager.GetTranslation(LOCIDENTIFIER + "itsUpToYou"); + maybeBuildBarracksSomeTime = LocalizationManager.GetTranslation(LOCIDENTIFIER + "maybeBuildBarracksSomeTime"); + tryToCommandYourUnits = LocalizationManager.GetTranslation(LOCIDENTIFIER + "tryToCommandYourUnits"); + makeThemHoldPosition = LocalizationManager.GetTranslation(LOCIDENTIFIER + "makeThemHoldPosition"); + howToHeal = LocalizationManager.GetTranslation(LOCIDENTIFIER + "howToHeal"); + lastDay = LocalizationManager.GetTranslation(LOCIDENTIFIER + "lastDay"); + lastNight = LocalizationManager.GetTranslation(LOCIDENTIFIER + "lastNight"); + } +} diff --git a/GameCode/UIFrame.cs b/GameCode/UIFrame.cs new file mode 100644 index 0000000..877285f --- /dev/null +++ b/GameCode/UIFrame.cs @@ -0,0 +1,331 @@ +using System.Collections.Generic; +using Rewired; +using UnityEngine; +using UnityEngine.Events; +using UnityEngine.EventSystems; +using UnityEngine.UI; + +public class UIFrame : MonoBehaviour +{ + public ThronefallUIElement firstSelected; + + public bool freezeTime; + + public bool freezePlayer = true; + + public bool canNotBeEscaped; + + public UnityEvent onActivate = new UnityEvent(); + + public UnityEvent onNewFocus = new UnityEvent(); + + public UnityEvent onNewSelection = new UnityEvent(); + + public UnityEvent onApply = new UnityEvent(); + + private List managedElements = new List(); + + private UIFrameManager frameManager; + + private ThronefallUIElement currentSelected; + + private ThronefallUIElement currentFocus; + + private ThronefallUIElement lastSelected; + + private ThronefallUIElement currentDragTarget; + + private Player input; + + private GraphicRaycaster graphicRaycaster; + + private PointerEventData pointerData = new PointerEventData(null); + + private Vector2 lastFramePointerPosition; + + private List pointerRayResults = new List(); + + private List filteredPointerResults = new List(); + + private ThronefallUIElement lastApplied; + + private bool interactable = true; + + private bool mouseSleeping; + + public ThronefallUIElement CurrentSelection => currentSelected; + + public ThronefallUIElement CurrentFocus => currentFocus; + + public ThronefallUIElement LastApplied => lastApplied; + + public bool Interactable => interactable; + + private bool mouseApplyPossible + { + get + { + if (!(currentFocus != null) || currentFocus.ignoreMouse) + { + if (currentSelected != null && currentSelected.autoSelectOnFocus) + { + return !currentSelected.ignoreMouse; + } + return false; + } + return true; + } + } + + private void Awake() + { + frameManager = GetComponentInParent(); + if (frameManager != null) + { + frameManager.RegisterFrame(this); + } + } + + private void Start() + { + input = ReInput.players.GetPlayer(0); + graphicRaycaster = GetComponentInParent(); + } + + private void Update() + { + if ((!(frameManager != null) || !(frameManager.ActiveFrame != this)) && interactable && !SceneTransitionManager.instance.SceneTransitionIsRunning) + { + HandleMouseNavigation(); + HandleButtonNavigation(); + } + } + + private void HandleButtonNavigation() + { + if (input.GetButtonDown("Menu Apply")) + { + Apply(); + } + else if (input.GetButtonRepeating("Menu Right")) + { + ControllerOrKeyboardNavigate(ThronefallUIElement.NavigationDirection.Right); + } + else if (input.GetButtonRepeating("Menu Left")) + { + ControllerOrKeyboardNavigate(ThronefallUIElement.NavigationDirection.Left); + } + else if (input.GetButtonRepeating("Menu Up")) + { + ControllerOrKeyboardNavigate(ThronefallUIElement.NavigationDirection.Up); + } + else if (input.GetButtonRepeating("Menu Down")) + { + ControllerOrKeyboardNavigate(ThronefallUIElement.NavigationDirection.Down); + } + } + + private void HandleMouseNavigation() + { + if (!input.controllers.hasMouse) + { + return; + } + lastFramePointerPosition = pointerData.position; + pointerData.position = input.controllers.Mouse.screenPosition; + if (mouseSleeping && object.Equals(lastFramePointerPosition, pointerData.position)) + { + return; + } + mouseSleeping = false; + pointerRayResults.Clear(); + graphicRaycaster.Raycast(pointerData, pointerRayResults); + filteredPointerResults.Clear(); + foreach (RaycastResult pointerRayResult in pointerRayResults) + { + ThronefallUIElement component = pointerRayResult.gameObject.GetComponent(); + if (component != null && managedElements.Contains(component)) + { + filteredPointerResults.Add(component); + } + } + if (filteredPointerResults.Count > 0 && !filteredPointerResults[0].ignoreMouse) + { + if (filteredPointerResults[0].autoSelectOnFocus) + { + if (filteredPointerResults[0] != currentSelected) + { + Select(filteredPointerResults[0]); + } + Focus(null); + } + else + { + Focus(filteredPointerResults[0]); + } + } + else + { + Focus(null); + } + if (input.controllers.Mouse.GetButtonDown(0) && filteredPointerResults.Count > 0 && mouseApplyPossible) + { + if (CurrentFocus != null) + { + Select(currentFocus); + } + Apply(); + } + if (input.controllers.Mouse.GetButton(0) && currentDragTarget != null) + { + currentDragTarget.OnDrag(input.controllers.Mouse.screenPosition); + } + if (input.controllers.Mouse.GetButtonUp(0) && currentDragTarget != null) + { + currentDragTarget.OnDragEnd(); + currentDragTarget = null; + } + } + + private void ControllerOrKeyboardNavigate(ThronefallUIElement.NavigationDirection direction) + { + if (!(currentSelected == null)) + { + mouseSleeping = true; + ThronefallUIElement thronefallUIElement = currentSelected.TryNavigate(direction); + if (thronefallUIElement != null) + { + Select(thronefallUIElement); + } + } + } + + public void Select(ThronefallUIElement newSelection) + { + if (newSelection == currentSelected || newSelection.cannotBeSelected) + { + return; + } + lastSelected = currentSelected; + currentSelected = newSelection; + onNewSelection.Invoke(); + if (lastSelected != null) + { + if (lastSelected == currentFocus) + { + lastSelected.Focus(); + } + else + { + lastSelected.Clear(); + } + } + if (newSelection != null) + { + if (newSelection == currentFocus) + { + newSelection.FocusAndSelect(); + } + else + { + newSelection.Select(); + } + } + } + + private void Focus(ThronefallUIElement newFocus) + { + if (newFocus == currentFocus) + { + return; + } + if (currentFocus != null) + { + if (currentFocus == currentSelected) + { + currentFocus.Select(); + } + else + { + currentFocus.Clear(); + } + } + if (newFocus != null) + { + if (newFocus == currentSelected) + { + newFocus.FocusAndSelect(); + } + else + { + newFocus.Focus(); + } + } + currentFocus = newFocus; + onNewFocus.Invoke(); + } + + public void Activate() + { + base.gameObject.SetActive(value: true); + interactable = true; + lastApplied = null; + currentFocus = null; + currentSelected = null; + onActivate.Invoke(); + RefetchManagedElements(); + foreach (ThronefallUIElement managedElement in managedElements) + { + managedElement.HardStateSet(ThronefallUIElement.SelectionState.Default); + } + if (firstSelected != null) + { + Select(firstSelected); + } + } + + public void Apply() + { + if (currentFocus != null && currentFocus.cannotBeSelected) + { + currentFocus.Apply(); + lastApplied = currentFocus; + if (currentFocus.dragable) + { + currentDragTarget = CurrentFocus; + currentDragTarget.OnDragStart(); + } + } + else + { + if (!(currentSelected != null)) + { + return; + } + currentSelected.Apply(); + lastApplied = currentSelected; + if (currentSelected.dragable) + { + currentDragTarget = currentSelected; + currentDragTarget.OnDragStart(); + } + } + onApply.Invoke(); + } + + public void Deactivate(bool keepGameObjectActive = false) + { + interactable = false; + base.gameObject.SetActive(keepGameObjectActive); + foreach (ThronefallUIElement managedElement in managedElements) + { + managedElement.Clear(); + } + } + + private void RefetchManagedElements() + { + managedElements.Clear(); + managedElements.AddRange(GetComponentsInChildren(includeInactive: true)); + } +} diff --git a/GameCode/UIFrameManager.cs b/GameCode/UIFrameManager.cs new file mode 100644 index 0000000..80752f8 --- /dev/null +++ b/GameCode/UIFrameManager.cs @@ -0,0 +1,286 @@ +using System.Collections.Generic; +using Rewired; +using UnityEngine; +using UnityEngine.Events; +using UnityEngine.SceneManagement; + +public class UIFrameManager : MonoBehaviour +{ + public static UIFrameManager instance; + + [SerializeField] + private string titleFrameSceneName = "_StartMenu"; + + [SerializeField] + private UIFrame titleFrame; + + [SerializeField] + private UIFrame overworldPauseMenuFrame; + + [SerializeField] + private UIFrame inMatchPauseMenuFrame; + + [SerializeField] + private UIFrame levelSelectFrame; + + [SerializeField] + private UIFrame endOfMatchFrame; + + [SerializeField] + private UIFrame levelUpRewardFrame; + + [SerializeField] + private UIFrame choiceFrame; + + private UIFrame activeFrame; + + private List frames = new List(); + + private Player input; + + private Stack frameStack = new Stack(); + + [SerializeField] + private RectTransform inGameUIContainer; + + [SerializeField] + private RectTransform onScreenMarkerContainer; + + [SerializeField] + private TreasureChestUIHelper treasureChest; + + [HideInInspector] + public UnityEvent onFrameOpen = new UnityEvent(); + + private SceneTransitionManager sceneTransitionManager; + + public UIFrame ActiveFrame => activeFrame; + + public RectTransform InGameUIContainer => inGameUIContainer; + + public RectTransform OnScreenMarkerContainer => onScreenMarkerContainer; + + public TreasureChestUIHelper TreasureChest => treasureChest; + + private void Awake() + { + if (instance != null) + { + Object.Destroy(base.gameObject); + } + else + { + instance = this; + } + } + + private void Start() + { + if (SceneManager.sceneCount <= 1) + { + SceneManager.LoadScene(titleFrameSceneName, LoadSceneMode.Additive); + } + foreach (UIFrame frame in frames) + { + frame.Deactivate(); + } + if (IsSceneLoaded(titleFrameSceneName)) + { + SwitchToTitleFrame(); + } + input = ReInput.players.GetPlayer(0); + sceneTransitionManager = SceneTransitionManager.instance; + sceneTransitionManager.onSceneChange.AddListener(UpdateUIBasedOnCurrentScene); + UpdateUIBasedOnCurrentScene(); + } + + public void SwitchToTitleFrame() + { + ChangeActiveFrame(titleFrame); + } + + public bool IsSceneLoaded(string sceneName) + { + for (int i = 0; i < SceneManager.sceneCount; i++) + { + if (SceneManager.GetSceneAt(i).name == sceneName) + { + return true; + } + } + return false; + } + + private void Update() + { + if (input.GetButtonDown("Pause Menu")) + { + OpenMenu(); + } + else if (input.GetButtonDown("Cancel")) + { + Cancel(); + } + } + + private void Cancel() + { + if (activeFrame != null && activeFrame != titleFrame && !activeFrame.canNotBeEscaped) + { + CloseActiveFrame(); + } + } + + private void OpenMenu() + { + if (activeFrame != null && !activeFrame.canNotBeEscaped) + { + CloseActiveFrame(); + } + else if (activeFrame == null && SceneManager.GetSceneByName(SceneTransitionManager.instance.levelSelectScene).IsValid()) + { + ChangeActiveFrame(overworldPauseMenuFrame); + } + else if (activeFrame == null) + { + ChangeActiveFrame(inMatchPauseMenuFrame); + } + } + + public void RegisterFrame(UIFrame frame) + { + frames.Add(frame); + } + + public void ChangeActiveFrame(UIFrame nextFrame) + { + ProcessFrameChange(nextFrame, writeOldFrameToStack: true); + } + + public void ChangeActiveFrameKeepOldVisible(UIFrame nextFrame) + { + ProcessFrameChange(nextFrame, writeOldFrameToStack: true, keepOldFrameGameObjectActive: true); + } + + private void ProcessFrameChange(UIFrame nextFrame, bool writeOldFrameToStack, bool keepOldFrameGameObjectActive = false) + { + if (nextFrame != null) + { + if (LocalGamestate.Instance != null) + { + LocalGamestate.Instance.SetPlayerFreezeState(nextFrame.freezePlayer); + } + if (nextFrame.freezeTime) + { + Time.timeScale = 0f; + } + else + { + Time.timeScale = 1f; + } + if (activeFrame != null && writeOldFrameToStack) + { + frameStack.Push(activeFrame); + } + onFrameOpen.Invoke(); + } + else + { + if (LocalGamestate.Instance != null) + { + LocalGamestate.Instance.SetPlayerFreezeState(frozen: false); + } + Time.timeScale = 1f; + frameStack.Clear(); + } + if (activeFrame != null) + { + if (activeFrame == choiceFrame && ChoiceManager.instance.ChoiceCoroutineWaiting) + { + ChoiceManager.instance.CancelChoice(); + } + activeFrame.Deactivate(keepOldFrameGameObjectActive); + } + if (nextFrame != null) + { + nextFrame.Activate(); + } + activeFrame = nextFrame; + } + + public void CloseActiveFrame() + { + if (activeFrame != null) + { + if (frameStack.Count > 0) + { + ProcessFrameChange(frameStack.Pop(), writeOldFrameToStack: false); + } + else + { + ChangeActiveFrame(null); + } + } + } + + public void CloseAllFrames() + { + if (activeFrame != null) + { + frameStack.Clear(); + ChangeActiveFrame(null); + } + } + + public void ResetToTileScreen() + { + ProcessFrameChange(titleFrame, writeOldFrameToStack: false); + frameStack.Clear(); + } + + public void QuitToDesktop() + { + Application.Quit(); + } + + public static bool TryOpenLevelSelect() + { + if (instance.activeFrame != null) + { + return false; + } + instance.ChangeActiveFrame(instance.levelSelectFrame); + return true; + } + + public static void TriggerEndOfMatch() + { + instance.ProcessFrameChange(instance.endOfMatchFrame, writeOldFrameToStack: false); + } + + public static void ShowLevelUpReward() + { + instance.ProcessFrameChange(instance.levelUpRewardFrame, writeOldFrameToStack: true, keepOldFrameGameObjectActive: true); + } + + private void UpdateUIBasedOnCurrentScene() + { + switch (sceneTransitionManager.CurrentSceneState) + { + case SceneTransitionManager.SceneState.InGame: + treasureChest.gameObject.SetActive(value: true); + break; + case SceneTransitionManager.SceneState.LevelSelect: + treasureChest.gameObject.SetActive(value: false); + break; + case SceneTransitionManager.SceneState.MainMenu: + treasureChest.gameObject.SetActive(value: false); + break; + } + } + + public void PresentChoiceFrame() + { + ProcessFrameChange(choiceFrame, writeOldFrameToStack: false); + } +} diff --git a/GameCode/UIParentResizer.cs b/GameCode/UIParentResizer.cs new file mode 100644 index 0000000..4044a15 --- /dev/null +++ b/GameCode/UIParentResizer.cs @@ -0,0 +1,40 @@ +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.UI; + +public class UIParentResizer : MonoBehaviour +{ + public enum Mode + { + Vertical + } + + public Mode mode; + + public float minHeight; + + public float padding = 30f; + + public List observedElements; + + private RectTransform ownRT; + + public void Trigger() + { + if (ownRT == null) + { + ownRT = GetComponent(); + } + float num = 0f; + foreach (RectTransform observedElement in observedElements) + { + LayoutRebuilder.ForceRebuildLayoutImmediate(observedElement); + num += observedElement.sizeDelta.y; + } + if (num < minHeight) + { + num = minHeight; + } + ownRT.sizeDelta = new Vector2(ownRT.sizeDelta.x, num + 2f * padding); + } +} diff --git a/GameCode/UIScaleHandler.cs b/GameCode/UIScaleHandler.cs new file mode 100644 index 0000000..0c36253 --- /dev/null +++ b/GameCode/UIScaleHandler.cs @@ -0,0 +1,45 @@ +using UnityEngine; + +public class UIScaleHandler : MonoBehaviour +{ + public static bool useLargeUI; + + public TooltipManager tooltipManager; + + public GameObject defaultTooltipParent; + + public Tooltip defaultTooltip; + + public GameObject largeTooltipParent; + + public Tooltip largeTooltip; + + public RectTransform treasureChestParent; + + public RectTransform coinCountParent; + + private void Start() + { + Refresh(); + } + + public void Refresh() + { + if (SettingsManager.Instance.UseLargeInGameUI) + { + defaultTooltipParent.SetActive(value: false); + largeTooltipParent.SetActive(value: true); + tooltipManager.targetTooltip = largeTooltip; + treasureChestParent.localScale = Vector3.one * 1.25f; + coinCountParent.localScale = Vector3.one * 1.25f; + } + else + { + defaultTooltipParent.SetActive(value: true); + largeTooltipParent.SetActive(value: false); + tooltipManager.targetTooltip = defaultTooltip; + treasureChestParent.localScale = Vector3.one; + coinCountParent.localScale = Vector3.one; + } + } +} diff --git a/GameCode/UnitAttackAnimator.cs b/GameCode/UnitAttackAnimator.cs new file mode 100644 index 0000000..01b95c2 --- /dev/null +++ b/GameCode/UnitAttackAnimator.cs @@ -0,0 +1,31 @@ +using UnityEngine; + +public class UnitAttackAnimator : MonoBehaviour +{ + public AutoAttack unit; + + public OneShotAnimationBase attackAnimation; + + public OneShotAnimationBase[] additionalAttackAnimations; + + private void Start() + { + if ((bool)unit) + { + unit.onAttackTriggered.AddListener(OnAttack); + } + } + + private void OnAttack() + { + if ((bool)attackAnimation) + { + attackAnimation.Trigger(); + } + OneShotAnimationBase[] array = additionalAttackAnimations; + for (int i = 0; i < array.Length; i++) + { + array[i].Trigger(); + } + } +} diff --git a/GameCode/UnitAudio.cs b/GameCode/UnitAudio.cs new file mode 100644 index 0000000..0f25583 --- /dev/null +++ b/GameCode/UnitAudio.cs @@ -0,0 +1,371 @@ +using Pathfinding.RVO; +using UnityEngine; + +public class UnitAudio : MonoBehaviour +{ + public enum LocomotionMode + { + Bounce, + Rolling, + Perpetual + } + + public enum OneshotType + { + TakeDamage, + Attack, + Die + } + + public enum StepType + { + DefaultOnFoot, + Giant, + Fly, + SiegeRoll, + RacerRoll, + SquishyBounce, + ExploderRoll, + MonsterRider, + Slime + } + + public enum DmgType + { + DefaultHumanoidOnFoot, + BigOrganic, + SmallOrganic, + Siege + } + + public enum DeathType + { + DefaultHumanoidOnFoot, + BigOrganic, + Siege, + Exploder + } + + public enum AttackType + { + DefaultSword, + MassiveBlunt, + FlyerSpit, + Flatbow, + Crossbow, + Catapult, + RacerBite, + HunterlingBite, + Ram, + Slime + } + + public LocomotionMode locomotionMode; + + public SimpleWalk walkSource; + + public float maxSpeed = 4f; + + public AudioSource stepSource; + + public AudioSource sfxSource; + + public AutoAttack attackTrigger; + + public Hp hp; + + public RVOController movementTrigger; + + public StepType step; + + [Range(0f, 1f)] + public float stepVolume = 0.5f; + + public float stepPitchVariation = 0.1f; + + public AttackType attack; + + [Range(0f, 1f)] + public float attackVolume = 0.5f; + + public float attackPitchVariation = 0.3f; + + public DeathType death; + + [Range(0f, 1f)] + public float deathVolume = 0.5f; + + public float deathPitchVariation = 0.3f; + + public DmgType dmg; + + [Range(0f, 1f)] + public float dmgVolume = 0.5f; + + public float dmgPitchVariation = 0.3f; + + private int rollPriority = 80; + + private int stepPriority = 110; + + private int damagePriority = 20; + + private int attackPriority = 10; + + private int deathPriority = 3; + + private AudioSet.ClipArray soundOnDmg; + + private AudioSet.ClipArray soundOnAttack; + + private AudioSet.ClipArray soundOnDeath; + + private AudioSet.ClipArray soundOnStep; + + private bool dead; + + private bool isBounceLocomotion => locomotionMode == LocomotionMode.Bounce; + + private bool isPerpetualLocomotion => locomotionMode == LocomotionMode.Perpetual; + + private bool isRollingLocomotion => locomotionMode == LocomotionMode.Rolling; + + private void Start() + { + if (locomotionMode == LocomotionMode.Bounce) + { + stepSource.priority = stepPriority; + } + else + { + stepSource.priority = rollPriority; + } + AudioSet audioContent = ThronefallAudioManager.Instance.audioContent; + switch (step) + { + case StepType.DefaultOnFoot: + soundOnStep = audioContent.DefaultOnFootStep; + break; + case StepType.Giant: + soundOnStep = audioContent.GiantStep; + break; + case StepType.Fly: + soundOnStep = audioContent.FlyingSmall; + break; + case StepType.SiegeRoll: + soundOnStep = audioContent.SiegeRoll; + break; + case StepType.SquishyBounce: + soundOnStep = audioContent.SquishyBounce; + break; + case StepType.RacerRoll: + soundOnStep = audioContent.RacerRoll; + break; + case StepType.ExploderRoll: + soundOnStep = audioContent.ExploderRoll; + break; + case StepType.MonsterRider: + soundOnStep = audioContent.MonsterRiderGallop; + break; + case StepType.Slime: + soundOnStep = audioContent.SlimeStep; + break; + } + switch (attack) + { + case AttackType.DefaultSword: + soundOnAttack = audioContent.DefaultSwordAttack; + break; + case AttackType.MassiveBlunt: + soundOnAttack = audioContent.MassiveBluntAttack; + break; + case AttackType.FlyerSpit: + soundOnAttack = audioContent.FlyerSpit; + break; + case AttackType.Crossbow: + soundOnAttack = audioContent.CrossbowShot; + break; + case AttackType.Flatbow: + soundOnAttack = audioContent.FlatbowShot; + break; + case AttackType.Catapult: + soundOnAttack = audioContent.CatapultShot; + break; + case AttackType.RacerBite: + soundOnAttack = audioContent.RacerBite; + break; + case AttackType.HunterlingBite: + soundOnAttack = audioContent.HunterlingBite; + break; + case AttackType.Ram: + soundOnAttack = audioContent.Ram; + break; + case AttackType.Slime: + soundOnAttack = audioContent.SlimeSpit; + break; + } + switch (dmg) + { + case DmgType.DefaultHumanoidOnFoot: + soundOnDmg = audioContent.DefaultHumanoidOnFootDamage; + break; + case DmgType.BigOrganic: + soundOnDmg = audioContent.BigOrganicDamage; + break; + case DmgType.SmallOrganic: + soundOnDmg = audioContent.SmallOrganicDamage; + break; + case DmgType.Siege: + soundOnDmg = audioContent.SiegeDamage; + break; + } + switch (death) + { + case DeathType.DefaultHumanoidOnFoot: + soundOnDeath = audioContent.DefaultHumanoidOnFootDeath; + break; + case DeathType.BigOrganic: + soundOnDeath = audioContent.BigOrganicDeath; + break; + case DeathType.Siege: + soundOnDeath = audioContent.SiegeDeath; + break; + case DeathType.Exploder: + soundOnDeath = audioContent.ExploderDeath; + break; + } + if ((bool)hp) + { + hp.OnKillOrKnockout.AddListener(PlayDeath); + hp.OnReceiveDamage.AddListener(PlayDMG); + hp.OnRevive.AddListener(Revive); + } + if ((bool)attackTrigger) + { + attackTrigger.onAttackTriggered.AddListener(PlayAttack); + } + switch (locomotionMode) + { + case LocomotionMode.Rolling: + stepSource.clip = soundOnStep.GetRandomClip(); + stepSource.volume = stepVolume; + stepSource.loop = true; + stepSource.pitch = Random.Range(1f - stepPitchVariation, 1f + stepPitchVariation); + break; + case LocomotionMode.Perpetual: + stepSource.clip = soundOnStep.GetRandomClip(); + stepSource.volume = stepVolume; + stepSource.loop = true; + stepSource.pitch = Random.Range(1f - stepPitchVariation, 1f + stepPitchVariation); + stepSource.Play(); + break; + case LocomotionMode.Bounce: + if ((bool)walkSource) + { + walkSource.onGroundContact.AddListener(PlayStep); + } + break; + } + if (isRollingLocomotion) + { + maxSpeed *= maxSpeed; + } + } + + private void Update() + { + if (dead) + { + return; + } + if (Time.timeScale < 0.1f) + { + stepSource.Pause(); + } + else if (locomotionMode == LocomotionMode.Perpetual && !stepSource.isPlaying) + { + stepSource.Play(); + } + else + { + if (locomotionMode != LocomotionMode.Rolling) + { + return; + } + if (movementTrigger.velocity.sqrMagnitude > 0.25f) + { + if (!stepSource.isPlaying) + { + stepSource.Play(); + } + stepSource.volume = Mathf.Lerp(0f, stepVolume, movementTrigger.velocity.sqrMagnitude / maxSpeed); + } + else if (stepSource.isPlaying) + { + stepSource.Pause(); + } + } + } + + public void PlaySound(OneshotType soundType) + { + if (dead) + { + return; + } + switch (soundType) + { + case OneshotType.Attack: + sfxSource.priority = attackPriority; + sfxSource.pitch = Random.Range(1f - attackPitchVariation, 1f + attackPitchVariation); + sfxSource.PlayOneShot(soundOnAttack.GetRandomClip(), attackVolume); + break; + case OneshotType.TakeDamage: + if (!((double)hp.HpValue < 0.01)) + { + sfxSource.priority = damagePriority; + sfxSource.pitch = Random.Range(1f - dmgPitchVariation, 1f + dmgPitchVariation); + sfxSource.PlayOneShot(soundOnDmg.GetRandomClip(), dmgVolume); + } + break; + case OneshotType.Die: + sfxSource.priority = deathPriority; + sfxSource.pitch = Random.Range(1f - deathPitchVariation, 1f + deathPitchVariation); + sfxSource.PlayOneShot(soundOnDeath.GetRandomClip(), deathVolume); + break; + } + } + + private void PlayStep() + { + stepSource.priority = stepPriority; + stepSource.pitch = Random.Range(1f - stepPitchVariation, 1f + stepPitchVariation); + stepSource.PlayOneShot(soundOnStep.GetRandomClip(), stepVolume); + } + + private void PlayAttack() + { + PlaySound(OneshotType.Attack); + } + + private void PlayDMG(bool causedByPlayer) + { + PlaySound(OneshotType.TakeDamage); + } + + private void PlayDeath() + { + PlaySound(OneshotType.Die); + dead = true; + if (!hp.getsKnockedOutInsteadOfDying) + { + sfxSource.transform.parent = null; + Object.Destroy(sfxSource.gameObject, 3f); + } + } + + private void Revive() + { + dead = false; + } +} diff --git a/GameCode/UnitCommandRadiusAnimation.cs b/GameCode/UnitCommandRadiusAnimation.cs new file mode 100644 index 0000000..9549100 --- /dev/null +++ b/GameCode/UnitCommandRadiusAnimation.cs @@ -0,0 +1,69 @@ +using System.Collections; +using UnityEngine; + +public class UnitCommandRadiusAnimation : MonoBehaviour +{ + public AnimationCurve animationCurve; + + public AnimationCurve hideCurve; + + public float animationTime; + + public float hideTime = 0.25f; + + private bool active; + + public bool Active => active; + + private void Start() + { + if (!active) + { + base.gameObject.SetActive(value: false); + } + } + + public void Activate() + { + active = true; + StopAllCoroutines(); + base.gameObject.SetActive(value: true); + StartCoroutine(AnimateShow()); + } + + public void Deactivate() + { + active = false; + if (base.gameObject.activeSelf) + { + StopAllCoroutines(); + StartCoroutine(AnimateHide()); + } + } + + private IEnumerator AnimateShow() + { + float timer = 0f; + while (timer <= animationTime) + { + timer += Time.deltaTime; + base.transform.localScale = Vector3.one * animationCurve.Evaluate(Mathf.InverseLerp(0f, animationTime, timer)); + yield return null; + } + base.transform.localScale = Vector3.one; + } + + private IEnumerator AnimateHide() + { + Debug.Log("START ANIMATION"); + float timer = 0f; + while (timer <= hideTime) + { + timer += Time.deltaTime; + base.transform.localScale = Vector3.one * hideCurve.Evaluate(Mathf.InverseLerp(0f, hideTime, timer)); + yield return null; + } + base.transform.localScale = Vector3.zero; + base.gameObject.SetActive(value: false); + } +} diff --git a/GameCode/UnitRespawnerForBuildings.cs b/GameCode/UnitRespawnerForBuildings.cs new file mode 100644 index 0000000..a405fb5 --- /dev/null +++ b/GameCode/UnitRespawnerForBuildings.cs @@ -0,0 +1,113 @@ +using System.Collections.Generic; +using UnityEngine; + +public class UnitRespawnerForBuildings : MonoBehaviour +{ + public Hp hp; + + public List units; + + public List timeToRespawnAUnitDependingOnLevel = new List(); + + private float timeTillNextRespawn; + + public BuildSlot myBuildSlot; + + public TaggedObject taggedObject; + + public ProductionBar productionBar; + + [Header("Quick arrange units:")] + public Transform copyUnitPositionsFrom; + + private bool gladiatorSchool; + + private bool elliteWarriors; + + private float gladiatorSchoolSpeed; + + private float elliteWarriorSpeed; + + private float totalTrainingSpeed = 1f; + + [SerializeField] + private Equippable gladiatorSchoolPerk; + + [SerializeField] + private Equippable elliteWarriorsPerk; + + private bool godOfDeathActive; + + private float ResetCooldownTime => timeToRespawnAUnitDependingOnLevel[Mathf.Clamp(myBuildSlot.Level, 0, timeToRespawnAUnitDependingOnLevel.Count - 1)]; + + private void Start() + { + godOfDeathActive = PerkManager.instance.GodOfDeathActive; + timeTillNextRespawn = ResetCooldownTime; + productionBar.UpdateVisual(0f); + gladiatorSchool = PerkManager.IsEquipped(gladiatorSchoolPerk); + elliteWarriors = PerkManager.IsEquipped(elliteWarriorsPerk); + gladiatorSchoolSpeed = PerkManager.instance.gladiatorSchool_TrainingSpeedMultiplyer; + elliteWarriorSpeed = PerkManager.instance.elliteWarriors_TrainingSpeedMultiplyer; + totalTrainingSpeed = 1f * (gladiatorSchool ? gladiatorSchoolSpeed : 1f) * (elliteWarriors ? elliteWarriorSpeed : 1f); + } + + private void Update() + { + if (godOfDeathActive) + { + return; + } + if (hp.KnockedOut) + { + productionBar.UpdateVisual(0f); + } + else if (AtLeastOneUnitIsKnockedOut()) + { + timeTillNextRespawn -= Time.deltaTime; + productionBar.UpdateVisual(1f - timeTillNextRespawn / ResetCooldownTime * totalTrainingSpeed); + if (timeTillNextRespawn <= 0f) + { + timeTillNextRespawn += ResetCooldownTime; + timeTillNextRespawn /= totalTrainingSpeed; + RespawnAKnockedOutUnit(); + } + } + else + { + timeTillNextRespawn = ResetCooldownTime; + timeTillNextRespawn /= totalTrainingSpeed; + productionBar.UpdateVisual(0f); + } + } + + private bool AtLeastOneUnitIsKnockedOut() + { + for (int i = 0; i < units.Count; i++) + { + Hp hp = units[i]; + if (hp.gameObject.activeInHierarchy && hp.KnockedOut) + { + return true; + } + } + return false; + } + + private void RespawnAKnockedOutUnit() + { + for (int i = 0; i < units.Count; i++) + { + Hp hp = units[i]; + if (hp.gameObject.activeInHierarchy && hp.KnockedOut) + { + hp.Revive(); + PathfindMovementPlayerunit component = hp.GetComponent(); + Vector3 position = taggedObject.colliderForBigOjectsToMeasureDistance.ClosestPoint(component.HopePositionOriginal); + hp.transform.position = position; + component.SnapToNavmesh(); + break; + } + } + } +} diff --git a/GameCode/UnitSpawnAppear.cs b/GameCode/UnitSpawnAppear.cs new file mode 100644 index 0000000..514dcbb --- /dev/null +++ b/GameCode/UnitSpawnAppear.cs @@ -0,0 +1,36 @@ +using UnityEngine; + +public class UnitSpawnAppear : MonoBehaviour +{ + public AnimationCurve scaleCurve; + + public float animationTime; + + public float initialDelay; + + public Transform target; + + private float timer; + + private float delay; + + private void Awake() + { + target.localScale = Vector3.zero; + } + + private void Update() + { + delay += Time.deltaTime; + if (!(delay < initialDelay)) + { + timer += Time.deltaTime; + target.localScale = Vector3.one * scaleCurve.Evaluate(Mathf.InverseLerp(0f, animationTime, timer)); + if (timer > animationTime) + { + base.transform.localScale = Vector3.one; + base.enabled = false; + } + } + } +} diff --git a/GameCode/UnitySerializedDictionary.cs b/GameCode/UnitySerializedDictionary.cs new file mode 100644 index 0000000..3fc1906 --- /dev/null +++ b/GameCode/UnitySerializedDictionary.cs @@ -0,0 +1,35 @@ +using System.Collections.Generic; +using UnityEngine; + +public abstract class UnitySerializedDictionary : Dictionary, ISerializationCallbackReceiver +{ + [SerializeField] + [HideInInspector] + private List keyData = new List(); + + [SerializeField] + [HideInInspector] + private List valueData = new List(); + + void ISerializationCallbackReceiver.OnAfterDeserialize() + { + Clear(); + for (int i = 0; i < keyData.Count && i < valueData.Count; i++) + { + base[keyData[i]] = valueData[i]; + } + } + + void ISerializationCallbackReceiver.OnBeforeSerialize() + { + keyData.Clear(); + valueData.Clear(); + using Enumerator enumerator = GetEnumerator(); + while (enumerator.MoveNext()) + { + KeyValuePair current = enumerator.Current; + keyData.Add(current.Key); + valueData.Add(current.Value); + } + } +} diff --git a/GameCode/UpgradeAssassinsTraining.cs b/GameCode/UpgradeAssassinsTraining.cs new file mode 100644 index 0000000..52ce5ec --- /dev/null +++ b/GameCode/UpgradeAssassinsTraining.cs @@ -0,0 +1,16 @@ +using UnityEngine; + +public class UpgradeAssassinsTraining : MonoBehaviour +{ + public static UpgradeAssassinsTraining instance; + + public float additionalCooldownSpeed = 1.75f; + + public float activationWindow = 0.2f; + + private void OnEnable() + { + instance = this; + PlayerUpgradeManager.instance.assassinsTraining = true; + } +} diff --git a/GameCode/UpgradeBuildersGuild.cs b/GameCode/UpgradeBuildersGuild.cs new file mode 100644 index 0000000..11e7682 --- /dev/null +++ b/GameCode/UpgradeBuildersGuild.cs @@ -0,0 +1,51 @@ +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using UnityEngine; + +public class UpgradeBuildersGuild : MonoBehaviour, DayNightCycle.IDaytimeSensitive +{ + private List mustHaveTags = new List(); + + private List mayNotHaveTags = new List(); + + private List allHousesTaggedObjs = new List(); + + private List allHousesTaggedObjsSorted = new List(); + + private void OnEnable() + { + mustHaveTags.Add(TagManager.ETag.House); + DayNightCycle.Instance.RegisterDaytimeSensitiveObject(this); + } + + public void OnDusk() + { + } + + public void OnDawn_BeforeSunrise() + { + } + + public void OnDawn_AfterSunrise() + { + StartCoroutine(AfterSunriseDelayed()); + } + + public IEnumerator AfterSunriseDelayed() + { + yield return null; + yield return null; + TagManager.instance.FindAllTaggedObjectsWithTags(allHousesTaggedObjs, mustHaveTags, mayNotHaveTags); + allHousesTaggedObjsSorted = allHousesTaggedObjs.OrderBy((TaggedObject o) => (o.transform.position - base.transform.position).magnitude).ToList(); + for (int i = 0; i < allHousesTaggedObjsSorted.Count; i++) + { + BuildSlot componentInParent = allHousesTaggedObjs[i].GetComponentInParent(); + if (componentInParent.Level == 1) + { + componentInParent.TryToBuildOrUpgradeAndPay(null, _presentChoice: false); + break; + } + } + } +} diff --git a/GameCode/UpgradeCastleUp.cs b/GameCode/UpgradeCastleUp.cs new file mode 100644 index 0000000..802d0f6 --- /dev/null +++ b/GameCode/UpgradeCastleUp.cs @@ -0,0 +1,46 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; + +public class UpgradeCastleUp : MonoBehaviour, DayNightCycle.IDaytimeSensitive +{ + private List mustHaveTags = new List(); + + private List mayNotHaveTags = new List(); + + private List allWallsAndTowers = new List(); + + private void OnEnable() + { + mustHaveTags.Add(TagManager.ETag.WallOrTower); + DayNightCycle.Instance.RegisterDaytimeSensitiveObject(this); + } + + public void OnDusk() + { + } + + public void OnDawn_BeforeSunrise() + { + } + + public void OnDawn_AfterSunrise() + { + StartCoroutine(AfterSunriseDelayed()); + } + + public IEnumerator AfterSunriseDelayed() + { + yield return null; + yield return null; + TagManager.instance.FindAllTaggedObjectsWithTags(allWallsAndTowers, mustHaveTags, mayNotHaveTags); + for (int i = 0; i < allWallsAndTowers.Count; i++) + { + BuildSlot componentInParent = allWallsAndTowers[i].GetComponentInParent(); + if (componentInParent.NextUpgradeOrBuildCost > 1) + { + componentInParent.NextUpgradeOrBuildCost--; + } + } + } +} diff --git a/GameCode/UpgradeCommander.cs b/GameCode/UpgradeCommander.cs new file mode 100644 index 0000000..015f31b --- /dev/null +++ b/GameCode/UpgradeCommander.cs @@ -0,0 +1,47 @@ +using UnityEngine; + +public class UpgradeCommander : MonoBehaviour +{ + public static UpgradeCommander instance; + + public float moveSpeedMultiplicator = 1.5f; + + public float effectRadius = 12f; + + public float healingInterval = 1f; + + public float healingPerSecond = 1f; + + private float cooldown; + + private TagManager tagManager; + + private Transform playerTransform; + + private void OnEnable() + { + tagManager = TagManager.instance; + instance = this; + CommandUnits.instance.PlaceCommandedUnitsAndCalculateTargetPositions(); + CommandUnits.instance.commanding = false; + PlayerUpgradeManager.instance.commander = true; + playerTransform = PlayerUpgradeManager.instance.transform; + } + + private void Update() + { + cooldown -= Time.deltaTime; + if (!(cooldown <= 0f)) + { + return; + } + cooldown += healingInterval; + foreach (TaggedObject playerUnit in tagManager.PlayerUnits) + { + if ((playerTransform.position - playerUnit.transform.position).magnitude < effectRadius) + { + playerUnit.Hp.Heal(healingPerSecond * healingInterval); + } + } + } +} diff --git a/GameCode/UpgradeGodlyCurse.cs b/GameCode/UpgradeGodlyCurse.cs new file mode 100644 index 0000000..e1a6fc8 --- /dev/null +++ b/GameCode/UpgradeGodlyCurse.cs @@ -0,0 +1,9 @@ +using UnityEngine; + +public class UpgradeGodlyCurse : MonoBehaviour +{ + private void OnEnable() + { + PlayerUpgradeManager.instance.godlyCurse = true; + } +} diff --git a/GameCode/UpgradeMagicArmor.cs b/GameCode/UpgradeMagicArmor.cs new file mode 100644 index 0000000..4fb88f5 --- /dev/null +++ b/GameCode/UpgradeMagicArmor.cs @@ -0,0 +1,18 @@ +using UnityEngine; + +public class UpgradeMagicArmor : MonoBehaviour +{ + public static UpgradeMagicArmor instance; + + public float damageMultiplyer = 1f; + + private void Awake() + { + instance = this; + } + + private void OnEnable() + { + PlayerUpgradeManager.instance.magicArmor = true; + } +} diff --git a/GameCode/UpgradePlayerDmg.cs b/GameCode/UpgradePlayerDmg.cs new file mode 100644 index 0000000..965a440 --- /dev/null +++ b/GameCode/UpgradePlayerDmg.cs @@ -0,0 +1,11 @@ +using UnityEngine; + +public class UpgradePlayerDmg : MonoBehaviour +{ + public float damageMultiplyer; + + private void OnEnable() + { + PlayerUpgradeManager.instance.playerDamageMultiplyer *= damageMultiplyer; + } +} diff --git a/GameCode/UpgradePlayerHp.cs b/GameCode/UpgradePlayerHp.cs new file mode 100644 index 0000000..84495d7 --- /dev/null +++ b/GameCode/UpgradePlayerHp.cs @@ -0,0 +1,17 @@ +using UnityEngine; + +public class UpgradePlayerHp : MonoBehaviour +{ + public float healthMultiplyer; + + private void OnEnable() + { + PlayerMovement[] registeredPlayers = PlayerManager.Instance.RegisteredPlayers; + for (int i = 0; i < registeredPlayers.Length; i++) + { + Hp component = registeredPlayers[i].GetComponent(); + component.maxHp *= healthMultiplyer; + component.Heal(float.MaxValue); + } + } +} diff --git a/GameCode/VersionNumberDisplay.cs b/GameCode/VersionNumberDisplay.cs new file mode 100644 index 0000000..90b50f0 --- /dev/null +++ b/GameCode/VersionNumberDisplay.cs @@ -0,0 +1,12 @@ +using TMPro; +using UnityEngine; + +public class VersionNumberDisplay : MonoBehaviour +{ + public TextMeshProUGUI display; + + private void OnEnable() + { + display.text = "version " + Application.version; + } +} diff --git a/GameCode/Wave.cs b/GameCode/Wave.cs new file mode 100644 index 0000000..cbbce3c --- /dev/null +++ b/GameCode/Wave.cs @@ -0,0 +1,45 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +[Serializable] +public class Wave +{ + [TextArea] + public string warningText; + + public List spawns = new List(); + + public void Reset(bool _resetGold = true) + { + for (int i = 0; i < spawns.Count; i++) + { + spawns[i].Reset(_resetGold); + } + } + + public void Update() + { + for (int i = 0; i < spawns.Count; i++) + { + spawns[i].Update(); + } + } + + public bool HasFinished() + { + int num = 0; + for (int i = 0; i < spawns.Count; i++) + { + if (spawns[i].Finished) + { + num++; + } + } + if (num >= spawns.Count) + { + return true; + } + return false; + } +} diff --git a/GameCode/WaveCountPopUp.cs b/GameCode/WaveCountPopUp.cs new file mode 100644 index 0000000..cf4b150 --- /dev/null +++ b/GameCode/WaveCountPopUp.cs @@ -0,0 +1,77 @@ +using System.Collections; +using TMPro; +using UnityEngine; + +public class WaveCountPopUp : MonoBehaviour, DayNightCycle.IDaytimeSensitive +{ + public GameObject popup; + + public AnimationCurve scaleCurve; + + public float animationTime = 0.75f; + + public float initialDelay = 0.5f; + + public float showTime = 3f; + + public TextMeshProUGUI targetText; + + private bool inAnimation; + + private void Start() + { + popup.SetActive(value: false); + DayNightCycle.Instance.RegisterDaytimeSensitiveObject(this); + } + + public void OnDawn_AfterSunrise() + { + } + + public void OnDawn_BeforeSunrise() + { + } + + public void OnDusk() + { + if (!inAnimation) + { + StartCoroutine(PopUpAnimation()); + } + } + + private IEnumerator PopUpAnimation() + { + inAnimation = true; + popup.SetActive(value: true); + popup.transform.localScale = Vector3.zero; + float timer2 = 0f; + yield return new WaitForSeconds(initialDelay); + targetText.text = "" + (EnemySpawner.instance.Wavenumber + 1) + "/" + EnemySpawner.instance.WaveCount; + StartCoroutine(PlaySoundDelayed()); + while (timer2 < animationTime) + { + timer2 += Time.deltaTime; + popup.transform.localScale = Vector3.one * scaleCurve.Evaluate(Mathf.InverseLerp(0f, animationTime, timer2)); + yield return null; + } + popup.transform.localScale = Vector3.one; + yield return new WaitForSeconds(showTime); + timer2 = 0f; + while (timer2 < animationTime) + { + timer2 += Time.deltaTime; + popup.transform.localScale = Vector3.one * scaleCurve.Evaluate(Mathf.InverseLerp(animationTime, 0f, timer2)); + yield return null; + } + popup.transform.localScale = Vector3.zero; + popup.SetActive(value: false); + inAnimation = false; + } + + private IEnumerator PlaySoundDelayed() + { + yield return new WaitForSeconds(0.1f); + ThronefallAudioManager.Oneshot(ThronefallAudioManager.AudioOneShot.ShowWaveCount); + } +} diff --git a/GameCode/WaveDescriptionUI.cs b/GameCode/WaveDescriptionUI.cs new file mode 100644 index 0000000..ef1feb5 --- /dev/null +++ b/GameCode/WaveDescriptionUI.cs @@ -0,0 +1,26 @@ +using UnityEngine; + +public class WaveDescriptionUI : MonoBehaviour, DayNightCycle.IDaytimeSensitive +{ + public GameObject waveDescriptionPanel; + + private void Start() + { + DayNightCycle.Instance.RegisterDaytimeSensitiveObject(this); + waveDescriptionPanel.SetActive(DayNightCycle.Instance.CurrentTimestate == DayNightCycle.Timestate.Day); + } + + public void OnDawn_AfterSunrise() + { + waveDescriptionPanel.SetActive(value: true); + } + + public void OnDusk() + { + waveDescriptionPanel.SetActive(value: false); + } + + public void OnDawn_BeforeSunrise() + { + } +} diff --git a/GameCode/Weapon.cs b/GameCode/Weapon.cs new file mode 100644 index 0000000..bde057a --- /dev/null +++ b/GameCode/Weapon.cs @@ -0,0 +1,225 @@ +using System.Collections.Generic; +using UnityEngine; + +[CreateAssetMenu(fileName = "Weapon", menuName = "SimpleSiege/Weapon")] +public class Weapon : ScriptableObject +{ + public enum EFacingDirection + { + Uniform, + FaceVictim, + FaceAttacker, + Random + } + + public enum EDamageAffectedByBlacksmithUpgrade + { + Null, + MultiplyBy_MeleeDamage, + MultiplyBy_RangedDamage, + DivideBy_MeleeResistance, + DivideBy_RangedResistance + } + + [Header("Blacksmith Upgrades")] + public EDamageAffectedByBlacksmithUpgrade blacksmithEffect; + + [Header("Aimbot Projectile Settings")] + public EFacingDirection projectileFacingDirection; + + public float projectileSpeed; + + public float projectileParabulaFactor; + + public float projectileParabulaOffset; + + public GameObject projectileVisuals; + + public GameObject projectileImpactVisuals; + + public bool performRaycastWhenHittingEmptyPosition; + + public LayerMask emptyPositionRaycastLayerMask; + + public float raycastLength = 1f; + + public bool performRaycastBeforeShooting; + + public LayerMask raycastBeforeShootingLayerMask; + + public float maximumChaseRange = 10000f; + + public float shootWithoutTargetRange = 20f; + + public GameObject spawnOnGroundWhenTargetingGround; + + [Header("Melee Attack Setting")] + public GameObject fxSpawnOnAttacker; + + public bool parentFxToAttacker; + + public GameObject fxSpawnOnVictim; + + [Header("Damage")] + public bool isPlayerWeapon; + + public List directDamage; + + public List splashDamage; + + public float slowsFastEnemiesFor; + + private PlayerUpgradeManager playerUpgradeManager; + + private BlacksmithUpgrades blacksmithUpgrades; + + public void Attack(Vector3 _attackOrigin, Hp _target, Vector3 _attackDirection, TaggedObject _attacker, float _finalDamageMultiplyer = 1f) + { + playerUpgradeManager = PlayerUpgradeManager.instance; + Vector3 vector = _attackOrigin + _attackDirection; + if ((bool)_target) + { + vector = ((!(_target.TaggedObj.colliderForBigOjectsToMeasureDistance != null)) ? (_target.transform.position + _target.hitFeedbackHeight * Vector3.up) : _target.TaggedObj.colliderForBigOjectsToMeasureDistance.ClosestPoint(_attackOrigin)); + } + if (performRaycastBeforeShooting) + { + Physics.Raycast(_attackOrigin, vector - _attackOrigin, out var hitInfo, (vector - _attackOrigin).magnitude, raycastBeforeShootingLayerMask); + if (hitInfo.collider != null) + { + Hp componentInParent = hitInfo.collider.GetComponentInParent(); + if (!(componentInParent != null)) + { + return; + } + _target = componentInParent; + vector = ((!(_target.TaggedObj.colliderForBigOjectsToMeasureDistance != null)) ? (_target.transform.position + _target.hitFeedbackHeight * Vector3.up) : _target.TaggedObj.colliderForBigOjectsToMeasureDistance.ClosestPoint(_attackOrigin)); + } + } + if (projectileSpeed > 0f && projectileVisuals != null) + { + AimbotProjectile component = Object.Instantiate(projectileVisuals, _attackOrigin, Quaternion.identity).GetComponent(); + Vector3 backupTarget = Vector3.zero; + if (_target == null) + { + backupTarget = _attackOrigin + _attackDirection.normalized * shootWithoutTargetRange; + } + component.Fire(this, _target, maximumChaseRange, backupTarget, _attacker, _finalDamageMultiplyer); + return; + } + if (fxSpawnOnAttacker != null) + { + SpawnAttackFx(fxSpawnOnAttacker, _attackOrigin, _attackOrigin, _target, vector, _attacker, _finalDamageMultiplyer, parentFxToAttacker); + } + if (fxSpawnOnVictim != null && _target != null) + { + SpawnAttackFx(fxSpawnOnVictim, vector, _attackOrigin, _target, vector, _attacker, _finalDamageMultiplyer); + } + DealDamage(_target, _finalDamageMultiplyer, _attacker); + } + + private void SpawnAttackFx(GameObject _fxPrefab, Vector3 _spawnPosition, Vector3 _attackOrigin, Hp _target, Vector3 _attackPosition, TaggedObject _attacker, float _finalDamageMultiplyer = 1f, bool parentToAttacker = false) + { + Vector3 vector = _attackPosition - _attackOrigin; + vector = new Vector3(vector.x, 0f, vector.z); + Quaternion rotation = Quaternion.LookRotation(vector, Vector3.up); + Transform parent = null; + if (parentToAttacker) + { + parent = _attacker.transform; + } + GameObject fxWithSplashDamageAreas = Object.Instantiate(_fxPrefab, _spawnPosition, rotation, parent); + DealSplashDamage(fxWithSplashDamageAreas, _attacker, _finalDamageMultiplyer); + } + + public void DealSplashDamage(GameObject _fxWithSplashDamageAreas, TaggedObject _attacker, float _finalDamageMultiplyer) + { + if (splashDamage.Count <= 0) + { + return; + } + SplashDamageArea[] componentsInChildren = _fxWithSplashDamageAreas.GetComponentsInChildren(); + if (componentsInChildren.Length != 0) + { + List list = new List(); + for (int i = 0; i < componentsInChildren.Length; i++) + { + componentsInChildren[i].AddReiveDamageHpScriptsInAreaToList(list); + } + for (int j = 0; j < list.Count; j++) + { + DealDamage(list[j], _finalDamageMultiplyer, _attacker, splashDamage: true); + } + } + } + + public void DealDamage(Hp _target, float _finalDamageMultiplyer, TaggedObject _attacker, bool splashDamage = false) + { + if (!_target || !_target.TaggedObj) + { + return; + } + float num = _finalDamageMultiplyer; + if (blacksmithUpgrades == null) + { + blacksmithUpgrades = BlacksmithUpgrades.instance; + } + switch (blacksmithEffect) + { + case EDamageAffectedByBlacksmithUpgrade.MultiplyBy_MeleeDamage: + num *= blacksmithUpgrades.meleeDamage; + break; + case EDamageAffectedByBlacksmithUpgrade.MultiplyBy_RangedDamage: + num *= blacksmithUpgrades.rangedDamage; + break; + case EDamageAffectedByBlacksmithUpgrade.DivideBy_MeleeResistance: + num /= blacksmithUpgrades.meleeResistance; + break; + case EDamageAffectedByBlacksmithUpgrade.DivideBy_RangedResistance: + num /= blacksmithUpgrades.rangedResistance; + break; + } + float hpValue = _target.HpValue; + if (splashDamage) + { + _target.TakeDamage(CalculateSplashDamageOnTarget(_target.TaggedObj, num), _attacker, isPlayerWeapon); + } + else + { + _target.TakeDamage(CalculateDirectDamageOnTarget(_target.TaggedObj, num), _attacker, isPlayerWeapon); + } + if (_target.TaggedObj.Tags.Contains(TagManager.ETag.Player) && playerUpgradeManager.magicArmor) + { + float num2 = hpValue - _target.HpValue; + if (num2 > 0f && (bool)_attacker) + { + _attacker.Hp.TakeDamage(num2 * UpgradeMagicArmor.instance.damageMultiplyer, _target.TaggedObj, causedByPlayer: true); + } + } + if (slowsFastEnemiesFor >= 0f && _target.TaggedObj.Tags.Contains(TagManager.ETag.FastMoving) && (bool)_target.PathfindMovement) + { + if (PerkManager.instance.IceMagicActive) + { + _target.PathfindMovement.Slow(slowsFastEnemiesFor * PerkManager.instance.iceMagic_SlowDurationMulti); + } + else + { + _target.PathfindMovement.Slow(slowsFastEnemiesFor); + } + } + } + + public float CalculateDirectDamageOnTarget(TaggedObject _taggedObject, float _finalDamageMultiplyer = 1f) + { + return DamageModifyer.CalculateDamageOnTarget(_taggedObject, directDamage, _finalDamageMultiplyer); + } + + public float CalculateSplashDamageOnTarget(TaggedObject _taggedObject, float _finalDamageMultiplyer = 1f) + { + return DamageModifyer.CalculateDamageOnTarget(_taggedObject, splashDamage, _finalDamageMultiplyer); + } + + public static float CalculateDamageGeneral(TaggedObject _taggedObject, List directDamage, float _finalDamageMultiplyer = 1f) + { + return DamageModifyer.CalculateDamageOnTarget(_taggedObject, directDamage, _finalDamageMultiplyer); + } +} diff --git a/GameCode/WeaponEquipper.cs b/GameCode/WeaponEquipper.cs new file mode 100644 index 0000000..d1aac04 --- /dev/null +++ b/GameCode/WeaponEquipper.cs @@ -0,0 +1,29 @@ +using UnityEngine; + +public class WeaponEquipper : MonoBehaviour +{ + public Equippable requiredWeapon; + + public ManualAttack activeWeapon; + + public ManualAttack passiveWeapon; + + public GameObject visuals; + + public PlayerAttackTargetFacer facer; + + private void Start() + { + if (!PerkManager.IsEquipped(requiredWeapon)) + { + Object.Destroy(base.gameObject); + return; + } + GetComponentInParent().EquipWeapon(activeWeapon); + GetComponentInParent(); + GetComponentInParent().AssignManualAttack(activeWeapon); + base.gameObject.AddComponent().Init(visuals, passiveWeapon); + facer.AssignAttack(passiveWeapon); + Object.Destroy(this); + } +} diff --git a/GameCode/Wiggler.cs b/GameCode/Wiggler.cs new file mode 100644 index 0000000..c287088 --- /dev/null +++ b/GameCode/Wiggler.cs @@ -0,0 +1,46 @@ +using UnityEngine; + +public class Wiggler : MonoBehaviour +{ + public Transform parentOverride; + + [SerializeField] + private float acceleration = 50f; + + [SerializeField] + [Range(0f, 1f)] + private float speedDamping = 0.5f; + + [SerializeField] + private float positionDampingMultiplyer = 1f; + + private Vector3 parentOffset; + + public Vector3 velocity { get; set; } + + private void Start() + { + if (parentOverride == null) + { + parentOverride = base.transform.parent; + } + parentOffset = Quaternion.Inverse(parentOverride.rotation) * (base.transform.position - parentOverride.position); + base.transform.SetParent(null); + } + + private void Update() + { + if (!parentOverride) + { + Object.Destroy(base.gameObject); + return; + } + Vector3 vector = parentOverride.position + parentOverride.rotation * parentOffset; + base.transform.position = Vector3.Lerp(vector, base.transform.position, Mathf.Pow(speedDamping, Time.deltaTime * positionDampingMultiplyer)); + Vector3 vector2 = vector - base.transform.position; + float num = Time.deltaTime * acceleration * vector2.magnitude; + velocity += vector2.normalized * num; + velocity *= Mathf.Pow(speedDamping, Time.deltaTime); + base.transform.position += velocity * Time.deltaTime; + } +} diff --git a/GameCode/WigglerAnimatedVelocity.cs b/GameCode/WigglerAnimatedVelocity.cs new file mode 100644 index 0000000..2106d1b --- /dev/null +++ b/GameCode/WigglerAnimatedVelocity.cs @@ -0,0 +1,45 @@ +using UnityEngine; + +public class WigglerAnimatedVelocity : MonoBehaviour +{ + [SerializeField] + private int stateCondition = -1; + + [SerializeField] + private Vector3 direction; + + [SerializeField] + private float timeSpeed = 1f; + + private Wiggler wiggler; + + private float time; + + private WigglerAnimationState wigglerAnimState; + + private void Start() + { + wiggler = GetComponent(); + wigglerAnimState = wiggler.parentOverride.GetComponentInParent(); + time = Random.Range(0f, 1000f); + } + + private void Update() + { + if (stateCondition == -1) + { + PerformUpdate(); + } + else if ((bool)wigglerAnimState && wigglerAnimState.animationState == stateCondition) + { + PerformUpdate(); + } + } + + private void PerformUpdate() + { + time += Time.deltaTime * timeSpeed; + float num = Mathf.Sin(time) * Time.deltaTime; + wiggler.velocity += wiggler.parentOverride.rotation * direction * num; + } +} diff --git a/GameCode/WigglerAnimationState.cs b/GameCode/WigglerAnimationState.cs new file mode 100644 index 0000000..90266a7 --- /dev/null +++ b/GameCode/WigglerAnimationState.cs @@ -0,0 +1,6 @@ +using UnityEngine; + +public class WigglerAnimationState : MonoBehaviour +{ + public int animationState = -1; +} diff --git a/GameCode/WigglerVelocity.cs b/GameCode/WigglerVelocity.cs new file mode 100644 index 0000000..4c9f4a5 --- /dev/null +++ b/GameCode/WigglerVelocity.cs @@ -0,0 +1,40 @@ +using UnityEngine; + +public class WigglerVelocity : MonoBehaviour +{ + [SerializeField] + private int stateCondition = -1; + + [SerializeField] + private Vector3 direction; + + private Wiggler wiggler; + + private float time; + + private WigglerAnimationState wigglerAnimState; + + private void Start() + { + wiggler = GetComponent(); + wigglerAnimState = wiggler.parentOverride.GetComponentInParent(); + time = Random.Range(0f, 1000f); + } + + private void Update() + { + if (stateCondition == -1) + { + PerformUpdate(); + } + else if ((bool)wigglerAnimState && wigglerAnimState.animationState == stateCondition) + { + PerformUpdate(); + } + } + + private void PerformUpdate() + { + wiggler.velocity += wiggler.parentOverride.rotation * direction * Time.deltaTime; + } +} diff --git a/GameCode/WishlistButton.cs b/GameCode/WishlistButton.cs new file mode 100644 index 0000000..b4492ff --- /dev/null +++ b/GameCode/WishlistButton.cs @@ -0,0 +1,9 @@ +using UnityEngine; + +public class WishlistButton : MonoBehaviour +{ + public void Wishlist() + { + Application.OpenURL("steam://openurl/https://store.steampowered.com/app/2239150/Thronefall/"); + } +} diff --git a/Rewired/Rewired.Data/UserDataStore_PlayerPrefs.cs b/Rewired/Rewired.Data/UserDataStore_PlayerPrefs.cs new file mode 100644 index 0000000..b5a933b --- /dev/null +++ b/Rewired/Rewired.Data/UserDataStore_PlayerPrefs.cs @@ -0,0 +1,1358 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Text; +using Rewired.Utils.Libraries.TinyJson; +using UnityEngine; + +namespace Rewired.Data; + +public class UserDataStore_PlayerPrefs : UserDataStore +{ + private class ControllerAssignmentSaveInfo + { + public class PlayerInfo + { + public int id; + + public bool hasKeyboard; + + public bool hasMouse; + + public JoystickInfo[] joysticks; + + public int joystickCount + { + get + { + if (joysticks == null) + { + return 0; + } + return joysticks.Length; + } + } + + public int IndexOfJoystick(int joystickId) + { + for (int i = 0; i < joystickCount; i++) + { + if (joysticks[i] != null && joysticks[i].id == joystickId) + { + return i; + } + } + return -1; + } + + public bool ContainsJoystick(int joystickId) + { + return IndexOfJoystick(joystickId) >= 0; + } + } + + public class JoystickInfo + { + public Guid instanceGuid; + + public string hardwareIdentifier; + + public int id; + } + + public PlayerInfo[] players; + + public int playerCount + { + get + { + if (players == null) + { + return 0; + } + return players.Length; + } + } + + public ControllerAssignmentSaveInfo() + { + } + + public ControllerAssignmentSaveInfo(int playerCount) + { + players = new PlayerInfo[playerCount]; + for (int i = 0; i < playerCount; i++) + { + players[i] = new PlayerInfo(); + } + } + + public int IndexOfPlayer(int playerId) + { + for (int i = 0; i < playerCount; i++) + { + if (players[i] != null && players[i].id == playerId) + { + return i; + } + } + return -1; + } + + public bool ContainsPlayer(int playerId) + { + return IndexOfPlayer(playerId) >= 0; + } + } + + private class JoystickAssignmentHistoryInfo + { + public readonly Joystick joystick; + + public readonly int oldJoystickId; + + public JoystickAssignmentHistoryInfo(Joystick joystick, int oldJoystickId) + { + if (joystick == null) + { + throw new ArgumentNullException("joystick"); + } + this.joystick = joystick; + this.oldJoystickId = oldJoystickId; + } + } + + private const string thisScriptName = "UserDataStore_PlayerPrefs"; + + private const string logPrefix = "Rewired: "; + + private const string editorLoadedMessage = "\n***IMPORTANT:*** Changes made to the Rewired Input Manager configuration after the last time XML data was saved WILL NOT be used because the loaded old saved data has overwritten these values. If you change something in the Rewired Input Manager such as a Joystick Map or Input Behavior settings, you will not see these changes reflected in the current configuration. Clear PlayerPrefs using the inspector option on the UserDataStore_PlayerPrefs component."; + + private const string playerPrefsKeySuffix_controllerAssignments = "ControllerAssignments"; + + private const int controllerMapPPKeyVersion_original = 0; + + private const int controllerMapPPKeyVersion_includeDuplicateJoystickIndex = 1; + + private const int controllerMapPPKeyVersion_supportDisconnectedControllers = 2; + + private const int controllerMapPPKeyVersion_includeFormatVersion = 2; + + private const int controllerMapPPKeyVersion = 2; + + [Tooltip("Should this script be used? If disabled, nothing will be saved or loaded.")] + [SerializeField] + private bool isEnabled = true; + + [Tooltip("Should saved data be loaded on start?")] + [SerializeField] + private bool loadDataOnStart = true; + + [Tooltip("Should Player Joystick assignments be saved and loaded? This is not totally reliable for all Joysticks on all platforms. Some platforms/input sources do not provide enough information to reliably save assignments from session to session and reboot to reboot.")] + [SerializeField] + private bool loadJoystickAssignments = true; + + [Tooltip("Should Player Keyboard assignments be saved and loaded?")] + [SerializeField] + private bool loadKeyboardAssignments = true; + + [Tooltip("Should Player Mouse assignments be saved and loaded?")] + [SerializeField] + private bool loadMouseAssignments = true; + + [Tooltip("The PlayerPrefs key prefix. Change this to change how keys are stored in PlayerPrefs. Changing this will make saved data already stored with the old key no longer accessible.")] + [SerializeField] + private string playerPrefsKeyPrefix = "RewiredSaveData"; + + [NonSerialized] + private bool allowImpreciseJoystickAssignmentMatching = true; + + [NonSerialized] + private bool deferredJoystickAssignmentLoadPending; + + [NonSerialized] + private bool wasJoystickEverDetected; + + [NonSerialized] + private List __allActionIds; + + [NonSerialized] + private string __allActionIdsString; + + public bool IsEnabled + { + get + { + return isEnabled; + } + set + { + isEnabled = value; + } + } + + public bool LoadDataOnStart + { + get + { + return loadDataOnStart; + } + set + { + loadDataOnStart = value; + } + } + + public bool LoadJoystickAssignments + { + get + { + return loadJoystickAssignments; + } + set + { + loadJoystickAssignments = value; + } + } + + public bool LoadKeyboardAssignments + { + get + { + return loadKeyboardAssignments; + } + set + { + loadKeyboardAssignments = value; + } + } + + public bool LoadMouseAssignments + { + get + { + return loadMouseAssignments; + } + set + { + loadMouseAssignments = value; + } + } + + public string PlayerPrefsKeyPrefix + { + get + { + return playerPrefsKeyPrefix; + } + set + { + playerPrefsKeyPrefix = value; + } + } + + private string playerPrefsKey_controllerAssignments => string.Format("{0}_{1}", playerPrefsKeyPrefix, "ControllerAssignments"); + + private bool loadControllerAssignments + { + get + { + if (!loadKeyboardAssignments && !loadMouseAssignments) + { + return loadJoystickAssignments; + } + return true; + } + } + + private List allActionIds + { + get + { + if (__allActionIds != null) + { + return __allActionIds; + } + List list = new List(); + IList actions = ReInput.mapping.Actions; + for (int i = 0; i < actions.Count; i++) + { + list.Add(actions[i].id); + } + __allActionIds = list; + return list; + } + } + + private string allActionIdsString + { + get + { + if (!string.IsNullOrEmpty(__allActionIdsString)) + { + return __allActionIdsString; + } + StringBuilder stringBuilder = new StringBuilder(); + List list = allActionIds; + for (int i = 0; i < list.Count; i++) + { + if (i > 0) + { + stringBuilder.Append(","); + } + stringBuilder.Append(list[i]); + } + __allActionIdsString = stringBuilder.ToString(); + return __allActionIdsString; + } + } + + public override void Save() + { + if (!isEnabled) + { + Debug.LogWarning("Rewired: UserDataStore_PlayerPrefs is disabled and will not save any data.", this); + } + else + { + SaveAll(); + } + } + + public override void SaveControllerData(int playerId, ControllerType controllerType, int controllerId) + { + if (!isEnabled) + { + Debug.LogWarning("Rewired: UserDataStore_PlayerPrefs is disabled and will not save any data.", this); + } + else + { + SaveControllerDataNow(playerId, controllerType, controllerId); + } + } + + public override void SaveControllerData(ControllerType controllerType, int controllerId) + { + if (!isEnabled) + { + Debug.LogWarning("Rewired: UserDataStore_PlayerPrefs is disabled and will not save any data.", this); + } + else + { + SaveControllerDataNow(controllerType, controllerId); + } + } + + public override void SavePlayerData(int playerId) + { + if (!isEnabled) + { + Debug.LogWarning("Rewired: UserDataStore_PlayerPrefs is disabled and will not save any data.", this); + } + else + { + SavePlayerDataNow(playerId); + } + } + + public override void SaveInputBehavior(int playerId, int behaviorId) + { + if (!isEnabled) + { + Debug.LogWarning("Rewired: UserDataStore_PlayerPrefs is disabled and will not save any data.", this); + } + else + { + SaveInputBehaviorNow(playerId, behaviorId); + } + } + + public override void Load() + { + if (!isEnabled) + { + Debug.LogWarning("Rewired: UserDataStore_PlayerPrefs is disabled and will not load any data.", this); + } + else + { + LoadAll(); + } + } + + public override void LoadControllerData(int playerId, ControllerType controllerType, int controllerId) + { + if (!isEnabled) + { + Debug.LogWarning("Rewired: UserDataStore_PlayerPrefs is disabled and will not load any data.", this); + } + else + { + LoadControllerDataNow(playerId, controllerType, controllerId); + } + } + + public override void LoadControllerData(ControllerType controllerType, int controllerId) + { + if (!isEnabled) + { + Debug.LogWarning("Rewired: UserDataStore_PlayerPrefs is disabled and will not load any data.", this); + } + else + { + LoadControllerDataNow(controllerType, controllerId); + } + } + + public override void LoadPlayerData(int playerId) + { + if (!isEnabled) + { + Debug.LogWarning("Rewired: UserDataStore_PlayerPrefs is disabled and will not load any data.", this); + } + else + { + LoadPlayerDataNow(playerId); + } + } + + public override void LoadInputBehavior(int playerId, int behaviorId) + { + if (!isEnabled) + { + Debug.LogWarning("Rewired: UserDataStore_PlayerPrefs is disabled and will not load any data.", this); + } + else + { + LoadInputBehaviorNow(playerId, behaviorId); + } + } + + protected override void OnInitialize() + { + if (loadDataOnStart) + { + Load(); + if (loadControllerAssignments && ReInput.controllers.joystickCount > 0) + { + wasJoystickEverDetected = true; + SaveControllerAssignments(); + } + } + } + + protected override void OnControllerConnected(ControllerStatusChangedEventArgs args) + { + if (isEnabled && args.controllerType == ControllerType.Joystick) + { + LoadJoystickData(args.controllerId); + if (loadDataOnStart && loadJoystickAssignments && !wasJoystickEverDetected) + { + StartCoroutine(LoadJoystickAssignmentsDeferred()); + } + if (loadJoystickAssignments && !deferredJoystickAssignmentLoadPending) + { + SaveControllerAssignments(); + } + wasJoystickEverDetected = true; + } + } + + protected override void OnControllerPreDisconnect(ControllerStatusChangedEventArgs args) + { + if (isEnabled && args.controllerType == ControllerType.Joystick) + { + SaveJoystickData(args.controllerId); + } + } + + protected override void OnControllerDisconnected(ControllerStatusChangedEventArgs args) + { + if (isEnabled && loadControllerAssignments) + { + SaveControllerAssignments(); + } + } + + public override void SaveControllerMap(int playerId, ControllerMap controllerMap) + { + if (controllerMap != null) + { + Player player = ReInput.players.GetPlayer(playerId); + if (player != null) + { + SaveControllerMap(player, controllerMap); + } + } + } + + public override ControllerMap LoadControllerMap(int playerId, ControllerIdentifier controllerIdentifier, int categoryId, int layoutId) + { + Player player = ReInput.players.GetPlayer(playerId); + if (player == null) + { + return null; + } + return LoadControllerMap(player, controllerIdentifier, categoryId, layoutId); + } + + private int LoadAll() + { + int num = 0; + if (loadControllerAssignments && LoadControllerAssignmentsNow()) + { + num++; + } + IList allPlayers = ReInput.players.AllPlayers; + for (int i = 0; i < allPlayers.Count; i++) + { + num += LoadPlayerDataNow(allPlayers[i]); + } + return num + LoadAllJoystickCalibrationData(); + } + + private int LoadPlayerDataNow(int playerId) + { + return LoadPlayerDataNow(ReInput.players.GetPlayer(playerId)); + } + + private int LoadPlayerDataNow(Player player) + { + if (player == null) + { + return 0; + } + int num = 0; + num += LoadInputBehaviors(player.id); + num += LoadControllerMaps(player.id, ControllerType.Keyboard, 0); + num += LoadControllerMaps(player.id, ControllerType.Mouse, 0); + foreach (Joystick joystick in player.controllers.Joysticks) + { + num += LoadControllerMaps(player.id, ControllerType.Joystick, joystick.id); + } + RefreshLayoutManager(player.id); + return num; + } + + private int LoadAllJoystickCalibrationData() + { + int num = 0; + IList joysticks = ReInput.controllers.Joysticks; + for (int i = 0; i < joysticks.Count; i++) + { + num += LoadJoystickCalibrationData(joysticks[i]); + } + return num; + } + + private int LoadJoystickCalibrationData(Joystick joystick) + { + if (joystick == null) + { + return 0; + } + if (!joystick.ImportCalibrationMapFromXmlString(GetJoystickCalibrationMapXml(joystick))) + { + return 0; + } + return 1; + } + + private int LoadJoystickCalibrationData(int joystickId) + { + return LoadJoystickCalibrationData(ReInput.controllers.GetJoystick(joystickId)); + } + + private int LoadJoystickData(int joystickId) + { + int num = 0; + IList allPlayers = ReInput.players.AllPlayers; + for (int i = 0; i < allPlayers.Count; i++) + { + Player player = allPlayers[i]; + if (player.controllers.ContainsController(ControllerType.Joystick, joystickId)) + { + num += LoadControllerMaps(player.id, ControllerType.Joystick, joystickId); + RefreshLayoutManager(player.id); + } + } + return num + LoadJoystickCalibrationData(joystickId); + } + + private int LoadControllerDataNow(int playerId, ControllerType controllerType, int controllerId) + { + int num = 0 + LoadControllerMaps(playerId, controllerType, controllerId); + RefreshLayoutManager(playerId); + return num + LoadControllerDataNow(controllerType, controllerId); + } + + private int LoadControllerDataNow(ControllerType controllerType, int controllerId) + { + int num = 0; + if (controllerType == ControllerType.Joystick) + { + num += LoadJoystickCalibrationData(controllerId); + } + return num; + } + + private int LoadControllerMaps(int playerId, ControllerType controllerType, int controllerId) + { + int num = 0; + Player player = ReInput.players.GetPlayer(playerId); + if (player == null) + { + return num; + } + Controller controller = ReInput.controllers.GetController(controllerType, controllerId); + if (controller == null) + { + return num; + } + IList mapCategories = ReInput.mapping.MapCategories; + for (int i = 0; i < mapCategories.Count; i++) + { + InputMapCategory inputMapCategory = mapCategories[i]; + if (!inputMapCategory.userAssignable) + { + continue; + } + IList list = ReInput.mapping.MapLayouts(controller.type); + for (int j = 0; j < list.Count; j++) + { + InputLayout inputLayout = list[j]; + ControllerMap controllerMap = LoadControllerMap(player, controller.identifier, inputMapCategory.id, inputLayout.id); + if (controllerMap != null) + { + player.controllers.maps.AddMap(controller, controllerMap); + num++; + } + } + } + return num; + } + + private ControllerMap LoadControllerMap(Player player, ControllerIdentifier controllerIdentifier, int categoryId, int layoutId) + { + if (player == null) + { + return null; + } + string controllerMapXml = GetControllerMapXml(player, controllerIdentifier, categoryId, layoutId); + if (string.IsNullOrEmpty(controllerMapXml)) + { + return null; + } + ControllerMap controllerMap = ControllerMap.CreateFromXml(controllerIdentifier.controllerType, controllerMapXml); + if (controllerMap == null) + { + return null; + } + List controllerMapKnownActionIds = GetControllerMapKnownActionIds(player, controllerIdentifier, categoryId, layoutId); + AddDefaultMappingsForNewActions(controllerIdentifier, controllerMap, controllerMapKnownActionIds); + return controllerMap; + } + + private int LoadInputBehaviors(int playerId) + { + Player player = ReInput.players.GetPlayer(playerId); + if (player == null) + { + return 0; + } + int num = 0; + IList inputBehaviors = ReInput.mapping.GetInputBehaviors(player.id); + for (int i = 0; i < inputBehaviors.Count; i++) + { + num += LoadInputBehaviorNow(player, inputBehaviors[i]); + } + return num; + } + + private int LoadInputBehaviorNow(int playerId, int behaviorId) + { + Player player = ReInput.players.GetPlayer(playerId); + if (player == null) + { + return 0; + } + InputBehavior inputBehavior = ReInput.mapping.GetInputBehavior(playerId, behaviorId); + if (inputBehavior == null) + { + return 0; + } + return LoadInputBehaviorNow(player, inputBehavior); + } + + private int LoadInputBehaviorNow(Player player, InputBehavior inputBehavior) + { + if (player == null || inputBehavior == null) + { + return 0; + } + string inputBehaviorXml = GetInputBehaviorXml(player, inputBehavior.id); + if (inputBehaviorXml == null || inputBehaviorXml == string.Empty) + { + return 0; + } + if (!inputBehavior.ImportXmlString(inputBehaviorXml)) + { + return 0; + } + return 1; + } + + private bool LoadControllerAssignmentsNow() + { + try + { + ControllerAssignmentSaveInfo controllerAssignmentSaveInfo = LoadControllerAssignmentData(); + if (controllerAssignmentSaveInfo == null) + { + return false; + } + if (loadKeyboardAssignments || loadMouseAssignments) + { + LoadKeyboardAndMouseAssignmentsNow(controllerAssignmentSaveInfo); + } + if (loadJoystickAssignments) + { + LoadJoystickAssignmentsNow(controllerAssignmentSaveInfo); + } + } + catch + { + } + return true; + } + + private bool LoadKeyboardAndMouseAssignmentsNow(ControllerAssignmentSaveInfo data) + { + try + { + if (data == null && (data = LoadControllerAssignmentData()) == null) + { + return false; + } + foreach (Player allPlayer in ReInput.players.AllPlayers) + { + if (data.ContainsPlayer(allPlayer.id)) + { + ControllerAssignmentSaveInfo.PlayerInfo playerInfo = data.players[data.IndexOfPlayer(allPlayer.id)]; + if (loadKeyboardAssignments) + { + allPlayer.controllers.hasKeyboard = playerInfo.hasKeyboard; + } + if (loadMouseAssignments) + { + allPlayer.controllers.hasMouse = playerInfo.hasMouse; + } + } + } + } + catch + { + } + return true; + } + + private bool LoadJoystickAssignmentsNow(ControllerAssignmentSaveInfo data) + { + try + { + if (ReInput.controllers.joystickCount == 0) + { + return false; + } + if (data == null && (data = LoadControllerAssignmentData()) == null) + { + return false; + } + foreach (Player allPlayer in ReInput.players.AllPlayers) + { + allPlayer.controllers.ClearControllersOfType(ControllerType.Joystick); + } + List list = (loadJoystickAssignments ? new List() : null); + foreach (Player allPlayer2 in ReInput.players.AllPlayers) + { + if (!data.ContainsPlayer(allPlayer2.id)) + { + continue; + } + ControllerAssignmentSaveInfo.PlayerInfo playerInfo = data.players[data.IndexOfPlayer(allPlayer2.id)]; + for (int i = 0; i < playerInfo.joystickCount; i++) + { + ControllerAssignmentSaveInfo.JoystickInfo joystickInfo2 = playerInfo.joysticks[i]; + if (joystickInfo2 == null) + { + continue; + } + Joystick joystick = FindJoystickPrecise(joystickInfo2); + if (joystick != null) + { + if (list.Find((JoystickAssignmentHistoryInfo x) => x.joystick == joystick) == null) + { + list.Add(new JoystickAssignmentHistoryInfo(joystick, joystickInfo2.id)); + } + allPlayer2.controllers.AddController(joystick, removeFromOtherPlayers: false); + } + } + } + if (allowImpreciseJoystickAssignmentMatching) + { + foreach (Player allPlayer3 in ReInput.players.AllPlayers) + { + if (!data.ContainsPlayer(allPlayer3.id)) + { + continue; + } + ControllerAssignmentSaveInfo.PlayerInfo playerInfo2 = data.players[data.IndexOfPlayer(allPlayer3.id)]; + for (int j = 0; j < playerInfo2.joystickCount; j++) + { + ControllerAssignmentSaveInfo.JoystickInfo joystickInfo = playerInfo2.joysticks[j]; + if (joystickInfo == null) + { + continue; + } + Joystick joystick2 = null; + int num = list.FindIndex((JoystickAssignmentHistoryInfo x) => x.oldJoystickId == joystickInfo.id); + if (num >= 0) + { + joystick2 = list[num].joystick; + } + else + { + if (!TryFindJoysticksImprecise(joystickInfo, out var matches)) + { + continue; + } + foreach (Joystick match in matches) + { + if (list.Find((JoystickAssignmentHistoryInfo x) => x.joystick == match) == null) + { + joystick2 = match; + break; + } + } + if (joystick2 == null) + { + continue; + } + list.Add(new JoystickAssignmentHistoryInfo(joystick2, joystickInfo.id)); + } + allPlayer3.controllers.AddController(joystick2, removeFromOtherPlayers: false); + } + } + } + } + catch + { + } + if (ReInput.configuration.autoAssignJoysticks) + { + ReInput.controllers.AutoAssignJoysticks(); + } + return true; + } + + private ControllerAssignmentSaveInfo LoadControllerAssignmentData() + { + try + { + if (!PlayerPrefs.HasKey(playerPrefsKey_controllerAssignments)) + { + return null; + } + string @string = PlayerPrefs.GetString(playerPrefsKey_controllerAssignments); + if (string.IsNullOrEmpty(@string)) + { + return null; + } + ControllerAssignmentSaveInfo controllerAssignmentSaveInfo = JsonParser.FromJson(@string); + if (controllerAssignmentSaveInfo == null || controllerAssignmentSaveInfo.playerCount == 0) + { + return null; + } + return controllerAssignmentSaveInfo; + } + catch + { + return null; + } + } + + private IEnumerator LoadJoystickAssignmentsDeferred() + { + deferredJoystickAssignmentLoadPending = true; + yield return new WaitForEndOfFrame(); + if (ReInput.isReady) + { + LoadJoystickAssignmentsNow(null); + SaveControllerAssignments(); + deferredJoystickAssignmentLoadPending = false; + } + } + + private void SaveAll() + { + IList allPlayers = ReInput.players.AllPlayers; + for (int i = 0; i < allPlayers.Count; i++) + { + SavePlayerDataNow(allPlayers[i]); + } + SaveAllJoystickCalibrationData(); + if (loadControllerAssignments) + { + SaveControllerAssignments(); + } + PlayerPrefs.Save(); + } + + private void SavePlayerDataNow(int playerId) + { + SavePlayerDataNow(ReInput.players.GetPlayer(playerId)); + PlayerPrefs.Save(); + } + + private void SavePlayerDataNow(Player player) + { + if (player != null) + { + PlayerSaveData saveData = player.GetSaveData(userAssignableMapsOnly: true); + SaveInputBehaviors(player, saveData); + SaveControllerMaps(player, saveData); + } + } + + private void SaveAllJoystickCalibrationData() + { + IList joysticks = ReInput.controllers.Joysticks; + for (int i = 0; i < joysticks.Count; i++) + { + SaveJoystickCalibrationData(joysticks[i]); + } + } + + private void SaveJoystickCalibrationData(int joystickId) + { + SaveJoystickCalibrationData(ReInput.controllers.GetJoystick(joystickId)); + } + + private void SaveJoystickCalibrationData(Joystick joystick) + { + if (joystick != null) + { + JoystickCalibrationMapSaveData calibrationMapSaveData = joystick.GetCalibrationMapSaveData(); + PlayerPrefs.SetString(GetJoystickCalibrationMapPlayerPrefsKey(joystick), calibrationMapSaveData.map.ToXmlString()); + } + } + + private void SaveJoystickData(int joystickId) + { + IList allPlayers = ReInput.players.AllPlayers; + for (int i = 0; i < allPlayers.Count; i++) + { + Player player = allPlayers[i]; + if (player.controllers.ContainsController(ControllerType.Joystick, joystickId)) + { + SaveControllerMaps(player.id, ControllerType.Joystick, joystickId); + } + } + SaveJoystickCalibrationData(joystickId); + } + + private void SaveControllerDataNow(int playerId, ControllerType controllerType, int controllerId) + { + SaveControllerMaps(playerId, controllerType, controllerId); + SaveControllerDataNow(controllerType, controllerId); + PlayerPrefs.Save(); + } + + private void SaveControllerDataNow(ControllerType controllerType, int controllerId) + { + if (controllerType == ControllerType.Joystick) + { + SaveJoystickCalibrationData(controllerId); + } + PlayerPrefs.Save(); + } + + private void SaveControllerMaps(Player player, PlayerSaveData playerSaveData) + { + foreach (ControllerMapSaveData allControllerMapSaveDatum in playerSaveData.AllControllerMapSaveData) + { + SaveControllerMap(player, allControllerMapSaveDatum.map); + } + } + + private void SaveControllerMaps(int playerId, ControllerType controllerType, int controllerId) + { + Player player = ReInput.players.GetPlayer(playerId); + if (player == null || !player.controllers.ContainsController(controllerType, controllerId)) + { + return; + } + ControllerMapSaveData[] mapSaveData = player.controllers.maps.GetMapSaveData(controllerType, controllerId, userAssignableMapsOnly: true); + if (mapSaveData != null) + { + for (int i = 0; i < mapSaveData.Length; i++) + { + SaveControllerMap(player, mapSaveData[i].map); + } + } + } + + private void SaveControllerMap(Player player, ControllerMap controllerMap) + { + PlayerPrefs.SetString(GetControllerMapPlayerPrefsKey(player, controllerMap.controller.identifier, controllerMap.categoryId, controllerMap.layoutId, 2), controllerMap.ToXmlString()); + PlayerPrefs.SetString(GetControllerMapKnownActionIdsPlayerPrefsKey(player, controllerMap.controller.identifier, controllerMap.categoryId, controllerMap.layoutId, 2), allActionIdsString); + } + + private void SaveInputBehaviors(Player player, PlayerSaveData playerSaveData) + { + if (player != null) + { + InputBehavior[] inputBehaviors = playerSaveData.inputBehaviors; + for (int i = 0; i < inputBehaviors.Length; i++) + { + SaveInputBehaviorNow(player, inputBehaviors[i]); + } + } + } + + private void SaveInputBehaviorNow(int playerId, int behaviorId) + { + Player player = ReInput.players.GetPlayer(playerId); + if (player != null) + { + InputBehavior inputBehavior = ReInput.mapping.GetInputBehavior(playerId, behaviorId); + if (inputBehavior != null) + { + SaveInputBehaviorNow(player, inputBehavior); + PlayerPrefs.Save(); + } + } + } + + private void SaveInputBehaviorNow(Player player, InputBehavior inputBehavior) + { + if (player != null && inputBehavior != null) + { + PlayerPrefs.SetString(GetInputBehaviorPlayerPrefsKey(player, inputBehavior.id), inputBehavior.ToXmlString()); + } + } + + private bool SaveControllerAssignments() + { + try + { + ControllerAssignmentSaveInfo controllerAssignmentSaveInfo = new ControllerAssignmentSaveInfo(ReInput.players.allPlayerCount); + for (int i = 0; i < ReInput.players.allPlayerCount; i++) + { + Player player = ReInput.players.AllPlayers[i]; + ControllerAssignmentSaveInfo.PlayerInfo playerInfo = new ControllerAssignmentSaveInfo.PlayerInfo(); + controllerAssignmentSaveInfo.players[i] = playerInfo; + playerInfo.id = player.id; + playerInfo.hasKeyboard = player.controllers.hasKeyboard; + playerInfo.hasMouse = player.controllers.hasMouse; + ControllerAssignmentSaveInfo.JoystickInfo[] array = (playerInfo.joysticks = new ControllerAssignmentSaveInfo.JoystickInfo[player.controllers.joystickCount]); + for (int j = 0; j < player.controllers.joystickCount; j++) + { + Joystick joystick = player.controllers.Joysticks[j]; + ControllerAssignmentSaveInfo.JoystickInfo joystickInfo = new ControllerAssignmentSaveInfo.JoystickInfo(); + joystickInfo.instanceGuid = joystick.deviceInstanceGuid; + joystickInfo.id = joystick.id; + joystickInfo.hardwareIdentifier = joystick.hardwareIdentifier; + array[j] = joystickInfo; + } + } + PlayerPrefs.SetString(playerPrefsKey_controllerAssignments, JsonWriter.ToJson(controllerAssignmentSaveInfo)); + PlayerPrefs.Save(); + } + catch + { + } + return true; + } + + private bool ControllerAssignmentSaveDataExists() + { + if (!PlayerPrefs.HasKey(playerPrefsKey_controllerAssignments)) + { + return false; + } + if (string.IsNullOrEmpty(PlayerPrefs.GetString(playerPrefsKey_controllerAssignments))) + { + return false; + } + return true; + } + + private string GetBasePlayerPrefsKey(Player player) + { + return playerPrefsKeyPrefix + "|playerName=" + player.name; + } + + private string GetControllerMapPlayerPrefsKey(Player player, ControllerIdentifier controllerIdentifier, int categoryId, int layoutId, int ppKeyVersion) + { + return string.Concat(GetBasePlayerPrefsKey(player) + "|dataType=ControllerMap", GetControllerMapPlayerPrefsKeyCommonSuffix(player, controllerIdentifier, categoryId, layoutId, ppKeyVersion)); + } + + private string GetControllerMapKnownActionIdsPlayerPrefsKey(Player player, ControllerIdentifier controllerIdentifier, int categoryId, int layoutId, int ppKeyVersion) + { + return string.Concat(GetBasePlayerPrefsKey(player) + "|dataType=ControllerMap_KnownActionIds", GetControllerMapPlayerPrefsKeyCommonSuffix(player, controllerIdentifier, categoryId, layoutId, ppKeyVersion)); + } + + private static string GetControllerMapPlayerPrefsKeyCommonSuffix(Player player, ControllerIdentifier controllerIdentifier, int categoryId, int layoutId, int ppKeyVersion) + { + string text = ""; + if (ppKeyVersion >= 2) + { + text = text + "|kv=" + ppKeyVersion; + } + text = text + "|controllerMapType=" + GetControllerMapType(controllerIdentifier.controllerType).Name; + text = text + "|categoryId=" + categoryId + "|layoutId=" + layoutId; + if (ppKeyVersion >= 2) + { + text = text + "|hardwareGuid=" + controllerIdentifier.hardwareTypeGuid.ToString(); + if (controllerIdentifier.hardwareTypeGuid == Guid.Empty) + { + text = text + "|hardwareIdentifier=" + controllerIdentifier.hardwareIdentifier; + } + if (controllerIdentifier.controllerType == ControllerType.Joystick) + { + text = text + "|duplicate=" + GetDuplicateIndex(player, controllerIdentifier); + } + } + else + { + text = text + "|hardwareIdentifier=" + controllerIdentifier.hardwareIdentifier; + if (controllerIdentifier.controllerType == ControllerType.Joystick) + { + text = text + "|hardwareGuid=" + controllerIdentifier.hardwareTypeGuid.ToString(); + if (ppKeyVersion >= 1) + { + text = text + "|duplicate=" + GetDuplicateIndex(player, controllerIdentifier); + } + } + } + return text; + } + + private string GetJoystickCalibrationMapPlayerPrefsKey(Joystick joystick) + { + return string.Concat(string.Concat(string.Concat(playerPrefsKeyPrefix + "|dataType=CalibrationMap", "|controllerType=", joystick.type.ToString()), "|hardwareIdentifier=", joystick.hardwareIdentifier), "|hardwareGuid=", joystick.hardwareTypeGuid.ToString()); + } + + private string GetInputBehaviorPlayerPrefsKey(Player player, int inputBehaviorId) + { + return string.Concat(GetBasePlayerPrefsKey(player) + "|dataType=InputBehavior", "|id=", inputBehaviorId.ToString()); + } + + private string GetControllerMapXml(Player player, ControllerIdentifier controllerIdentifier, int categoryId, int layoutId) + { + for (int num = 2; num >= 0; num--) + { + string controllerMapPlayerPrefsKey = GetControllerMapPlayerPrefsKey(player, controllerIdentifier, categoryId, layoutId, num); + if (PlayerPrefs.HasKey(controllerMapPlayerPrefsKey)) + { + return PlayerPrefs.GetString(controllerMapPlayerPrefsKey); + } + } + return null; + } + + private List GetControllerMapKnownActionIds(Player player, ControllerIdentifier controllerIdentifier, int categoryId, int layoutId) + { + List list = new List(); + string key = null; + bool flag = false; + for (int num = 2; num >= 0; num--) + { + key = GetControllerMapKnownActionIdsPlayerPrefsKey(player, controllerIdentifier, categoryId, layoutId, num); + if (PlayerPrefs.HasKey(key)) + { + flag = true; + break; + } + } + if (!flag) + { + return list; + } + string @string = PlayerPrefs.GetString(key); + if (string.IsNullOrEmpty(@string)) + { + return list; + } + string[] array = @string.Split(','); + for (int i = 0; i < array.Length; i++) + { + if (!string.IsNullOrEmpty(array[i]) && int.TryParse(array[i], out var result)) + { + list.Add(result); + } + } + return list; + } + + private string GetJoystickCalibrationMapXml(Joystick joystick) + { + string joystickCalibrationMapPlayerPrefsKey = GetJoystickCalibrationMapPlayerPrefsKey(joystick); + if (!PlayerPrefs.HasKey(joystickCalibrationMapPlayerPrefsKey)) + { + return string.Empty; + } + return PlayerPrefs.GetString(joystickCalibrationMapPlayerPrefsKey); + } + + private string GetInputBehaviorXml(Player player, int id) + { + string inputBehaviorPlayerPrefsKey = GetInputBehaviorPlayerPrefsKey(player, id); + if (!PlayerPrefs.HasKey(inputBehaviorPlayerPrefsKey)) + { + return string.Empty; + } + return PlayerPrefs.GetString(inputBehaviorPlayerPrefsKey); + } + + private void AddDefaultMappingsForNewActions(ControllerIdentifier controllerIdentifier, ControllerMap controllerMap, List knownActionIds) + { + if (controllerMap == null || knownActionIds == null || knownActionIds == null || knownActionIds.Count == 0) + { + return; + } + ControllerMap controllerMapInstance = ReInput.mapping.GetControllerMapInstance(controllerIdentifier, controllerMap.categoryId, controllerMap.layoutId); + if (controllerMapInstance == null) + { + return; + } + List list = new List(); + foreach (int allActionId in allActionIds) + { + if (!knownActionIds.Contains(allActionId)) + { + list.Add(allActionId); + } + } + if (list.Count == 0) + { + return; + } + foreach (ActionElementMap allMap in controllerMapInstance.AllMaps) + { + if (list.Contains(allMap.actionId) && !controllerMap.DoesElementAssignmentConflict(allMap)) + { + ElementAssignment elementAssignment = new ElementAssignment(controllerMap.controllerType, allMap.elementType, allMap.elementIdentifierId, allMap.axisRange, allMap.keyCode, allMap.modifierKeyFlags, allMap.actionId, allMap.axisContribution, allMap.invert); + controllerMap.CreateElementMap(elementAssignment); + } + } + } + + private Joystick FindJoystickPrecise(ControllerAssignmentSaveInfo.JoystickInfo joystickInfo) + { + if (joystickInfo == null) + { + return null; + } + if (joystickInfo.instanceGuid == Guid.Empty) + { + return null; + } + IList joysticks = ReInput.controllers.Joysticks; + for (int i = 0; i < joysticks.Count; i++) + { + if (joysticks[i].deviceInstanceGuid == joystickInfo.instanceGuid) + { + return joysticks[i]; + } + } + return null; + } + + private bool TryFindJoysticksImprecise(ControllerAssignmentSaveInfo.JoystickInfo joystickInfo, out List matches) + { + matches = null; + if (joystickInfo == null) + { + return false; + } + if (string.IsNullOrEmpty(joystickInfo.hardwareIdentifier)) + { + return false; + } + IList joysticks = ReInput.controllers.Joysticks; + for (int i = 0; i < joysticks.Count; i++) + { + if (string.Equals(joysticks[i].hardwareIdentifier, joystickInfo.hardwareIdentifier, StringComparison.OrdinalIgnoreCase)) + { + if (matches == null) + { + matches = new List(); + } + matches.Add(joysticks[i]); + } + } + return matches != null; + } + + private static int GetDuplicateIndex(Player player, ControllerIdentifier controllerIdentifier) + { + Controller controller = ReInput.controllers.GetController(controllerIdentifier); + if (controller == null) + { + return 0; + } + int num = 0; + foreach (Controller controller2 in player.controllers.Controllers) + { + if (controller2.type != controller.type) + { + continue; + } + bool flag = false; + if (controller.type == ControllerType.Joystick) + { + if ((controller2 as Joystick).hardwareTypeGuid != controller.hardwareTypeGuid) + { + continue; + } + if (controller.hardwareTypeGuid != Guid.Empty) + { + flag = true; + } + } + if (flag || !(controller2.hardwareIdentifier != controller.hardwareIdentifier)) + { + if (controller2 == controller) + { + return num; + } + num++; + } + } + return num; + } + + private void RefreshLayoutManager(int playerId) + { + ReInput.players.GetPlayer(playerId)?.controllers.maps.layoutManager.Apply(); + } + + private static Type GetControllerMapType(ControllerType controllerType) + { + switch (controllerType) + { + case ControllerType.Custom: + return typeof(CustomControllerMap); + case ControllerType.Joystick: + return typeof(JoystickMap); + case ControllerType.Keyboard: + return typeof(KeyboardMap); + case ControllerType.Mouse: + return typeof(MouseMap); + default: + Debug.LogWarning("Rewired: Unknown ControllerType " + controllerType); + return null; + } + } +} diff --git a/Rewired/Rewired.Demos.GamepadTemplateUI/ControllerUIEffect.cs b/Rewired/Rewired.Demos.GamepadTemplateUI/ControllerUIEffect.cs new file mode 100644 index 0000000..695aa76 --- /dev/null +++ b/Rewired/Rewired.Demos.GamepadTemplateUI/ControllerUIEffect.cs @@ -0,0 +1,57 @@ +using UnityEngine; +using UnityEngine.UI; + +namespace Rewired.Demos.GamepadTemplateUI; + +[RequireComponent(typeof(Image))] +public class ControllerUIEffect : MonoBehaviour +{ + [SerializeField] + private Color _highlightColor = Color.white; + + private Image _image; + + private Color _color; + + private Color _origColor; + + private bool _isActive; + + private float _highlightAmount; + + private void Awake() + { + _image = GetComponent(); + _origColor = _image.color; + _color = _origColor; + } + + public void Activate(float amount) + { + amount = Mathf.Clamp01(amount); + if (!_isActive || amount != _highlightAmount) + { + _highlightAmount = amount; + _color = Color.Lerp(_origColor, _highlightColor, _highlightAmount); + _isActive = true; + RedrawImage(); + } + } + + public void Deactivate() + { + if (_isActive) + { + _color = _origColor; + _highlightAmount = 0f; + _isActive = false; + RedrawImage(); + } + } + + private void RedrawImage() + { + _image.color = _color; + _image.enabled = _isActive; + } +} diff --git a/Rewired/Rewired.Demos.GamepadTemplateUI/ControllerUIElement.cs b/Rewired/Rewired.Demos.GamepadTemplateUI/ControllerUIElement.cs new file mode 100644 index 0000000..b59e6f8 --- /dev/null +++ b/Rewired/Rewired.Demos.GamepadTemplateUI/ControllerUIElement.cs @@ -0,0 +1,186 @@ +using UnityEngine; +using UnityEngine.UI; + +namespace Rewired.Demos.GamepadTemplateUI; + +[RequireComponent(typeof(Image))] +public class ControllerUIElement : MonoBehaviour +{ + [SerializeField] + private Color _highlightColor = Color.white; + + [SerializeField] + private ControllerUIEffect _positiveUIEffect; + + [SerializeField] + private ControllerUIEffect _negativeUIEffect; + + [SerializeField] + private Text _label; + + [SerializeField] + private Text _positiveLabel; + + [SerializeField] + private Text _negativeLabel; + + [SerializeField] + private ControllerUIElement[] _childElements = new ControllerUIElement[0]; + + private Image _image; + + private Color _color; + + private Color _origColor; + + private bool _isActive; + + private float _highlightAmount; + + private bool hasEffects + { + get + { + if (!(_positiveUIEffect != null)) + { + return _negativeUIEffect != null; + } + return true; + } + } + + private void Awake() + { + _image = GetComponent(); + _origColor = _image.color; + _color = _origColor; + ClearLabels(); + } + + public void Activate(float amount) + { + amount = Mathf.Clamp(amount, -1f, 1f); + if (hasEffects) + { + if (amount < 0f && _negativeUIEffect != null) + { + _negativeUIEffect.Activate(Mathf.Abs(amount)); + } + if (amount > 0f && _positiveUIEffect != null) + { + _positiveUIEffect.Activate(Mathf.Abs(amount)); + } + } + else + { + if (_isActive && amount == _highlightAmount) + { + return; + } + _highlightAmount = amount; + _color = Color.Lerp(_origColor, _highlightColor, _highlightAmount); + } + _isActive = true; + RedrawImage(); + if (_childElements.Length == 0) + { + return; + } + for (int i = 0; i < _childElements.Length; i++) + { + if (!(_childElements[i] == null)) + { + _childElements[i].Activate(amount); + } + } + } + + public void Deactivate() + { + if (!_isActive) + { + return; + } + _color = _origColor; + _highlightAmount = 0f; + if (_positiveUIEffect != null) + { + _positiveUIEffect.Deactivate(); + } + if (_negativeUIEffect != null) + { + _negativeUIEffect.Deactivate(); + } + _isActive = false; + RedrawImage(); + if (_childElements.Length == 0) + { + return; + } + for (int i = 0; i < _childElements.Length; i++) + { + if (!(_childElements[i] == null)) + { + _childElements[i].Deactivate(); + } + } + } + + public void SetLabel(string text, AxisRange labelType) + { + Text text2 = labelType switch + { + AxisRange.Full => _label, + AxisRange.Positive => _positiveLabel, + AxisRange.Negative => _negativeLabel, + _ => null, + }; + if (text2 != null) + { + text2.text = text; + } + if (_childElements.Length == 0) + { + return; + } + for (int i = 0; i < _childElements.Length; i++) + { + if (!(_childElements[i] == null)) + { + _childElements[i].SetLabel(text, labelType); + } + } + } + + public void ClearLabels() + { + if (_label != null) + { + _label.text = string.Empty; + } + if (_positiveLabel != null) + { + _positiveLabel.text = string.Empty; + } + if (_negativeLabel != null) + { + _negativeLabel.text = string.Empty; + } + if (_childElements.Length == 0) + { + return; + } + for (int i = 0; i < _childElements.Length; i++) + { + if (!(_childElements[i] == null)) + { + _childElements[i].ClearLabels(); + } + } + } + + private void RedrawImage() + { + _image.color = _color; + } +} diff --git a/Rewired/Rewired.Demos.GamepadTemplateUI/GamepadTemplateUI.cs b/Rewired/Rewired.Demos.GamepadTemplateUI/GamepadTemplateUI.cs new file mode 100644 index 0000000..e56617c --- /dev/null +++ b/Rewired/Rewired.Demos.GamepadTemplateUI/GamepadTemplateUI.cs @@ -0,0 +1,417 @@ +using System.Collections.Generic; +using UnityEngine; + +namespace Rewired.Demos.GamepadTemplateUI; + +public class GamepadTemplateUI : MonoBehaviour +{ + private class Stick + { + private RectTransform _transform; + + private Vector2 _origPosition; + + private int _xAxisElementId = -1; + + private int _yAxisElementId = -1; + + public Vector2 position + { + get + { + if (!(_transform != null)) + { + return Vector2.zero; + } + return _transform.anchoredPosition - _origPosition; + } + set + { + if (!(_transform == null)) + { + _transform.anchoredPosition = _origPosition + value; + } + } + } + + public Stick(RectTransform transform, int xAxisElementId, int yAxisElementId) + { + if (!(transform == null)) + { + _transform = transform; + _origPosition = _transform.anchoredPosition; + _xAxisElementId = xAxisElementId; + _yAxisElementId = yAxisElementId; + } + } + + public void Reset() + { + if (!(_transform == null)) + { + _transform.anchoredPosition = _origPosition; + } + } + + public bool ContainsElement(int elementId) + { + if (_transform == null) + { + return false; + } + if (elementId != _xAxisElementId) + { + return elementId == _yAxisElementId; + } + return true; + } + + public void SetAxisPosition(int elementId, float value) + { + if (!(_transform == null)) + { + Vector2 vector = position; + if (elementId == _xAxisElementId) + { + vector.x = value; + } + else if (elementId == _yAxisElementId) + { + vector.y = value; + } + position = vector; + } + } + } + + private class UIElement + { + public int id; + + public ControllerUIElement element; + + public UIElement(int id, ControllerUIElement element) + { + this.id = id; + this.element = element; + } + } + + private const float stickRadius = 20f; + + public int playerId; + + [SerializeField] + private RectTransform leftStick; + + [SerializeField] + private RectTransform rightStick; + + [SerializeField] + private ControllerUIElement leftStickX; + + [SerializeField] + private ControllerUIElement leftStickY; + + [SerializeField] + private ControllerUIElement leftStickButton; + + [SerializeField] + private ControllerUIElement rightStickX; + + [SerializeField] + private ControllerUIElement rightStickY; + + [SerializeField] + private ControllerUIElement rightStickButton; + + [SerializeField] + private ControllerUIElement actionBottomRow1; + + [SerializeField] + private ControllerUIElement actionBottomRow2; + + [SerializeField] + private ControllerUIElement actionBottomRow3; + + [SerializeField] + private ControllerUIElement actionTopRow1; + + [SerializeField] + private ControllerUIElement actionTopRow2; + + [SerializeField] + private ControllerUIElement actionTopRow3; + + [SerializeField] + private ControllerUIElement leftShoulder; + + [SerializeField] + private ControllerUIElement leftTrigger; + + [SerializeField] + private ControllerUIElement rightShoulder; + + [SerializeField] + private ControllerUIElement rightTrigger; + + [SerializeField] + private ControllerUIElement center1; + + [SerializeField] + private ControllerUIElement center2; + + [SerializeField] + private ControllerUIElement center3; + + [SerializeField] + private ControllerUIElement dPadUp; + + [SerializeField] + private ControllerUIElement dPadRight; + + [SerializeField] + private ControllerUIElement dPadDown; + + [SerializeField] + private ControllerUIElement dPadLeft; + + private UIElement[] _uiElementsArray; + + private Dictionary _uiElements = new Dictionary(); + + private IList _tempTargetList = new List(2); + + private Stick[] _sticks; + + private Player player => ReInput.players.GetPlayer(playerId); + + private void Awake() + { + _uiElementsArray = new UIElement[23] + { + new UIElement(0, leftStickX), + new UIElement(1, leftStickY), + new UIElement(17, leftStickButton), + new UIElement(2, rightStickX), + new UIElement(3, rightStickY), + new UIElement(18, rightStickButton), + new UIElement(4, actionBottomRow1), + new UIElement(5, actionBottomRow2), + new UIElement(6, actionBottomRow3), + new UIElement(7, actionTopRow1), + new UIElement(8, actionTopRow2), + new UIElement(9, actionTopRow3), + new UIElement(14, center1), + new UIElement(15, center2), + new UIElement(16, center3), + new UIElement(19, dPadUp), + new UIElement(20, dPadRight), + new UIElement(21, dPadDown), + new UIElement(22, dPadLeft), + new UIElement(10, leftShoulder), + new UIElement(11, leftTrigger), + new UIElement(12, rightShoulder), + new UIElement(13, rightTrigger) + }; + for (int i = 0; i < _uiElementsArray.Length; i++) + { + _uiElements.Add(_uiElementsArray[i].id, _uiElementsArray[i].element); + } + _sticks = new Stick[2] + { + new Stick(leftStick, 0, 1), + new Stick(rightStick, 2, 3) + }; + ReInput.ControllerConnectedEvent += OnControllerConnected; + ReInput.ControllerDisconnectedEvent += OnControllerDisconnected; + } + + private void Start() + { + if (ReInput.isReady) + { + DrawLabels(); + } + } + + private void OnDestroy() + { + ReInput.ControllerConnectedEvent -= OnControllerConnected; + ReInput.ControllerDisconnectedEvent -= OnControllerDisconnected; + } + + private void Update() + { + if (ReInput.isReady) + { + DrawActiveElements(); + } + } + + private void DrawActiveElements() + { + for (int i = 0; i < _uiElementsArray.Length; i++) + { + _uiElementsArray[i].element.Deactivate(); + } + for (int j = 0; j < _sticks.Length; j++) + { + _sticks[j].Reset(); + } + IList actions = ReInput.mapping.Actions; + for (int k = 0; k < actions.Count; k++) + { + ActivateElements(player, actions[k].id); + } + } + + private void ActivateElements(Player player, int actionId) + { + float axis = player.GetAxis(actionId); + if (axis == 0f) + { + return; + } + IList currentInputSources = player.GetCurrentInputSources(actionId); + for (int i = 0; i < currentInputSources.Count; i++) + { + InputActionSourceData inputActionSourceData = currentInputSources[i]; + IGamepadTemplate template = inputActionSourceData.controller.GetTemplate(); + if (template == null) + { + continue; + } + template.GetElementTargets(inputActionSourceData.actionElementMap, _tempTargetList); + for (int j = 0; j < _tempTargetList.Count; j++) + { + ControllerTemplateElementTarget controllerTemplateElementTarget = _tempTargetList[j]; + int id = controllerTemplateElementTarget.element.id; + ControllerUIElement controllerUIElement = _uiElements[id]; + if (controllerTemplateElementTarget.elementType == ControllerTemplateElementType.Axis) + { + controllerUIElement.Activate(axis); + } + else if (controllerTemplateElementTarget.elementType == ControllerTemplateElementType.Button && (player.GetButton(actionId) || player.GetNegativeButton(actionId))) + { + controllerUIElement.Activate(1f); + } + GetStick(id)?.SetAxisPosition(id, axis * 20f); + } + } + } + + private void DrawLabels() + { + for (int i = 0; i < _uiElementsArray.Length; i++) + { + _uiElementsArray[i].element.ClearLabels(); + } + IList actions = ReInput.mapping.Actions; + for (int j = 0; j < actions.Count; j++) + { + DrawLabels(player, actions[j]); + } + } + + private void DrawLabels(Player player, InputAction action) + { + Controller firstControllerWithTemplate = player.controllers.GetFirstControllerWithTemplate(); + if (firstControllerWithTemplate == null) + { + return; + } + IGamepadTemplate template = firstControllerWithTemplate.GetTemplate(); + ControllerMap map = player.controllers.maps.GetMap(firstControllerWithTemplate, "Default", "Default"); + if (map != null) + { + for (int i = 0; i < _uiElementsArray.Length; i++) + { + ControllerUIElement element = _uiElementsArray[i].element; + int id = _uiElementsArray[i].id; + IControllerTemplateElement element2 = template.GetElement(id); + DrawLabel(element, action, map, template, element2); + } + } + } + + private void DrawLabel(ControllerUIElement uiElement, InputAction action, ControllerMap controllerMap, IControllerTemplate template, IControllerTemplateElement element) + { + if (element.source == null) + { + return; + } + if (element.source.type == ControllerTemplateElementSourceType.Axis) + { + IControllerTemplateAxisSource controllerTemplateAxisSource = element.source as IControllerTemplateAxisSource; + ActionElementMap firstElementMapWithElementTarget; + if (controllerTemplateAxisSource.splitAxis) + { + firstElementMapWithElementTarget = controllerMap.GetFirstElementMapWithElementTarget(controllerTemplateAxisSource.positiveTarget, action.id, skipDisabledMaps: true); + if (firstElementMapWithElementTarget != null) + { + uiElement.SetLabel(firstElementMapWithElementTarget.actionDescriptiveName, AxisRange.Positive); + } + firstElementMapWithElementTarget = controllerMap.GetFirstElementMapWithElementTarget(controllerTemplateAxisSource.negativeTarget, action.id, skipDisabledMaps: true); + if (firstElementMapWithElementTarget != null) + { + uiElement.SetLabel(firstElementMapWithElementTarget.actionDescriptiveName, AxisRange.Negative); + } + return; + } + firstElementMapWithElementTarget = controllerMap.GetFirstElementMapWithElementTarget(controllerTemplateAxisSource.fullTarget, action.id, skipDisabledMaps: true); + if (firstElementMapWithElementTarget != null) + { + uiElement.SetLabel(firstElementMapWithElementTarget.actionDescriptiveName, AxisRange.Full); + return; + } + firstElementMapWithElementTarget = controllerMap.GetFirstElementMapWithElementTarget(new ControllerElementTarget(controllerTemplateAxisSource.fullTarget) + { + axisRange = AxisRange.Positive + }, action.id, skipDisabledMaps: true); + if (firstElementMapWithElementTarget != null) + { + uiElement.SetLabel(firstElementMapWithElementTarget.actionDescriptiveName, AxisRange.Positive); + } + firstElementMapWithElementTarget = controllerMap.GetFirstElementMapWithElementTarget(new ControllerElementTarget(controllerTemplateAxisSource.fullTarget) + { + axisRange = AxisRange.Negative + }, action.id, skipDisabledMaps: true); + if (firstElementMapWithElementTarget != null) + { + uiElement.SetLabel(firstElementMapWithElementTarget.actionDescriptiveName, AxisRange.Negative); + } + } + else if (element.source.type == ControllerTemplateElementSourceType.Button) + { + IControllerTemplateButtonSource controllerTemplateButtonSource = element.source as IControllerTemplateButtonSource; + ActionElementMap firstElementMapWithElementTarget = controllerMap.GetFirstElementMapWithElementTarget(controllerTemplateButtonSource.target, action.id, skipDisabledMaps: true); + if (firstElementMapWithElementTarget != null) + { + uiElement.SetLabel(firstElementMapWithElementTarget.actionDescriptiveName, AxisRange.Full); + } + } + } + + private Stick GetStick(int elementId) + { + for (int i = 0; i < _sticks.Length; i++) + { + if (_sticks[i].ContainsElement(elementId)) + { + return _sticks[i]; + } + } + return null; + } + + private void OnControllerConnected(ControllerStatusChangedEventArgs args) + { + DrawLabels(); + } + + private void OnControllerDisconnected(ControllerStatusChangedEventArgs args) + { + DrawLabels(); + } +} diff --git a/Rewired/Rewired.Demos/Bullet.cs b/Rewired/Rewired.Demos/Bullet.cs new file mode 100644 index 0000000..bb521c8 --- /dev/null +++ b/Rewired/Rewired.Demos/Bullet.cs @@ -0,0 +1,30 @@ +using UnityEngine; + +namespace Rewired.Demos; + +[AddComponentMenu("")] +public class Bullet : MonoBehaviour +{ + public float lifeTime = 3f; + + private bool die; + + private float deathTime; + + private void Start() + { + if (lifeTime > 0f) + { + deathTime = Time.time + lifeTime; + die = true; + } + } + + private void Update() + { + if (die && Time.time >= deathTime) + { + Object.Destroy(base.gameObject); + } + } +} diff --git a/Rewired/Rewired.Demos/ControlRemappingDemo1.cs b/Rewired/Rewired.Demos/ControlRemappingDemo1.cs new file mode 100644 index 0000000..b0e4f51 --- /dev/null +++ b/Rewired/Rewired.Demos/ControlRemappingDemo1.cs @@ -0,0 +1,1797 @@ +using System; +using System.Collections.Generic; +using UnityEngine; + +namespace Rewired.Demos; + +[AddComponentMenu("")] +public class ControlRemappingDemo1 : MonoBehaviour +{ + private class ControllerSelection + { + private int _id; + + private int _idPrev; + + private ControllerType _type; + + private ControllerType _typePrev; + + public int id + { + get + { + return _id; + } + set + { + _idPrev = _id; + _id = value; + } + } + + public ControllerType type + { + get + { + return _type; + } + set + { + _typePrev = _type; + _type = value; + } + } + + public int idPrev => _idPrev; + + public ControllerType typePrev => _typePrev; + + public bool hasSelection => _id >= 0; + + public ControllerSelection() + { + Clear(); + } + + public void Set(int id, ControllerType type) + { + this.id = id; + this.type = type; + } + + public void Clear() + { + _id = -1; + _idPrev = -1; + _type = ControllerType.Joystick; + _typePrev = ControllerType.Joystick; + } + } + + private class DialogHelper + { + public enum DialogType + { + None = 0, + JoystickConflict = 1, + ElementConflict = 2, + KeyConflict = 3, + DeleteAssignmentConfirmation = 10, + AssignElement = 11 + } + + private const float openBusyDelay = 0.25f; + + private const float closeBusyDelay = 0.1f; + + private DialogType _type; + + private bool _enabled; + + private float _busyTime; + + private bool _busyTimerRunning; + + private Action drawWindowDelegate; + + private GUI.WindowFunction drawWindowFunction; + + private WindowProperties windowProperties; + + private int currentActionId; + + private Action resultCallback; + + private float busyTimer + { + get + { + if (!_busyTimerRunning) + { + return 0f; + } + return _busyTime - Time.realtimeSinceStartup; + } + } + + public bool enabled + { + get + { + return _enabled; + } + set + { + if (value) + { + if (_type != 0) + { + StateChanged(0.25f); + } + } + else + { + _enabled = value; + _type = DialogType.None; + StateChanged(0.1f); + } + } + } + + public DialogType type + { + get + { + if (!_enabled) + { + return DialogType.None; + } + return _type; + } + set + { + if (value == DialogType.None) + { + _enabled = false; + StateChanged(0.1f); + } + else + { + _enabled = true; + StateChanged(0.25f); + } + _type = value; + } + } + + public bool busy => _busyTimerRunning; + + public DialogHelper() + { + drawWindowDelegate = DrawWindow; + drawWindowFunction = drawWindowDelegate.Invoke; + } + + public void StartModal(int queueActionId, DialogType type, WindowProperties windowProperties, Action resultCallback) + { + StartModal(queueActionId, type, windowProperties, resultCallback, -1f); + } + + public void StartModal(int queueActionId, DialogType type, WindowProperties windowProperties, Action resultCallback, float openBusyDelay) + { + currentActionId = queueActionId; + this.windowProperties = windowProperties; + this.type = type; + this.resultCallback = resultCallback; + if (openBusyDelay >= 0f) + { + StateChanged(openBusyDelay); + } + } + + public void Update() + { + Draw(); + UpdateTimers(); + } + + public void Draw() + { + if (_enabled) + { + bool flag = GUI.enabled; + GUI.enabled = true; + GUILayout.Window(windowProperties.windowId, windowProperties.rect, drawWindowFunction, windowProperties.title); + GUI.FocusWindow(windowProperties.windowId); + if (GUI.enabled != flag) + { + GUI.enabled = flag; + } + } + } + + public void DrawConfirmButton() + { + DrawConfirmButton("Confirm"); + } + + public void DrawConfirmButton(string title) + { + bool flag = GUI.enabled; + if (busy) + { + GUI.enabled = false; + } + if (GUILayout.Button(title)) + { + Confirm(UserResponse.Confirm); + } + if (GUI.enabled != flag) + { + GUI.enabled = flag; + } + } + + public void DrawConfirmButton(UserResponse response) + { + DrawConfirmButton(response, "Confirm"); + } + + public void DrawConfirmButton(UserResponse response, string title) + { + bool flag = GUI.enabled; + if (busy) + { + GUI.enabled = false; + } + if (GUILayout.Button(title)) + { + Confirm(response); + } + if (GUI.enabled != flag) + { + GUI.enabled = flag; + } + } + + public void DrawCancelButton() + { + DrawCancelButton("Cancel"); + } + + public void DrawCancelButton(string title) + { + bool flag = GUI.enabled; + if (busy) + { + GUI.enabled = false; + } + if (GUILayout.Button(title)) + { + Cancel(); + } + if (GUI.enabled != flag) + { + GUI.enabled = flag; + } + } + + public void Confirm() + { + Confirm(UserResponse.Confirm); + } + + public void Confirm(UserResponse response) + { + resultCallback(currentActionId, response); + Close(); + } + + public void Cancel() + { + resultCallback(currentActionId, UserResponse.Cancel); + Close(); + } + + private void DrawWindow(int windowId) + { + windowProperties.windowDrawDelegate(windowProperties.title, windowProperties.message); + } + + private void UpdateTimers() + { + if (_busyTimerRunning && busyTimer <= 0f) + { + _busyTimerRunning = false; + } + } + + private void StartBusyTimer(float time) + { + _busyTime = time + Time.realtimeSinceStartup; + _busyTimerRunning = true; + } + + private void Close() + { + Reset(); + StateChanged(0.1f); + } + + private void StateChanged(float delay) + { + StartBusyTimer(delay); + } + + private void Reset() + { + _enabled = false; + _type = DialogType.None; + currentActionId = -1; + resultCallback = null; + } + + private void ResetTimers() + { + _busyTimerRunning = false; + } + + public void FullReset() + { + Reset(); + ResetTimers(); + } + } + + private abstract class QueueEntry + { + public enum State + { + Waiting, + Confirmed, + Canceled + } + + private static int uidCounter; + + public int id { get; protected set; } + + public QueueActionType queueActionType { get; protected set; } + + public State state { get; protected set; } + + public UserResponse response { get; protected set; } + + protected static int nextId + { + get + { + int result = uidCounter; + uidCounter++; + return result; + } + } + + public QueueEntry(QueueActionType queueActionType) + { + id = nextId; + this.queueActionType = queueActionType; + } + + public void Confirm(UserResponse response) + { + state = State.Confirmed; + this.response = response; + } + + public void Cancel() + { + state = State.Canceled; + } + } + + private class JoystickAssignmentChange : QueueEntry + { + public int playerId { get; private set; } + + public int joystickId { get; private set; } + + public bool assign { get; private set; } + + public JoystickAssignmentChange(int newPlayerId, int joystickId, bool assign) + : base(QueueActionType.JoystickAssignment) + { + playerId = newPlayerId; + this.joystickId = joystickId; + this.assign = assign; + } + } + + private class ElementAssignmentChange : QueueEntry + { + public ElementAssignmentChangeType changeType { get; set; } + + public InputMapper.Context context { get; private set; } + + public ElementAssignmentChange(ElementAssignmentChangeType changeType, InputMapper.Context context) + : base(QueueActionType.ElementAssignment) + { + this.changeType = changeType; + this.context = context; + } + + public ElementAssignmentChange(ElementAssignmentChange other) + : this(other.changeType, other.context.Clone()) + { + } + } + + private class FallbackJoystickIdentification : QueueEntry + { + public int joystickId { get; private set; } + + public string joystickName { get; private set; } + + public FallbackJoystickIdentification(int joystickId, string joystickName) + : base(QueueActionType.FallbackJoystickIdentification) + { + this.joystickId = joystickId; + this.joystickName = joystickName; + } + } + + private class Calibration : QueueEntry + { + public int selectedElementIdentifierId; + + public bool recording; + + public Player player { get; private set; } + + public ControllerType controllerType { get; private set; } + + public Joystick joystick { get; private set; } + + public CalibrationMap calibrationMap { get; private set; } + + public Calibration(Player player, Joystick joystick, CalibrationMap calibrationMap) + : base(QueueActionType.Calibrate) + { + this.player = player; + this.joystick = joystick; + this.calibrationMap = calibrationMap; + selectedElementIdentifierId = -1; + } + } + + private struct WindowProperties + { + public int windowId; + + public Rect rect; + + public Action windowDrawDelegate; + + public string title; + + public string message; + } + + private enum QueueActionType + { + None, + JoystickAssignment, + ElementAssignment, + FallbackJoystickIdentification, + Calibrate + } + + private enum ElementAssignmentChangeType + { + Add, + Replace, + Remove, + ReassignOrRemove, + ConflictCheck + } + + public enum UserResponse + { + Confirm, + Cancel, + Custom1, + Custom2 + } + + private const float defaultModalWidth = 250f; + + private const float defaultModalHeight = 200f; + + private const float assignmentTimeout = 5f; + + private DialogHelper dialog; + + private InputMapper inputMapper = new InputMapper(); + + private InputMapper.ConflictFoundEventData conflictFoundEventData; + + private bool guiState; + + private bool busy; + + private bool pageGUIState; + + private Player selectedPlayer; + + private int selectedMapCategoryId; + + private ControllerSelection selectedController; + + private ControllerMap selectedMap; + + private bool showMenu; + + private bool startListening; + + private Vector2 actionScrollPos; + + private Vector2 calibrateScrollPos; + + private Queue actionQueue; + + private bool setupFinished; + + [NonSerialized] + private bool initialized; + + private bool isCompiling; + + private GUIStyle style_wordWrap; + + private GUIStyle style_centeredBox; + + private void Awake() + { + inputMapper.options.timeout = 5f; + inputMapper.options.ignoreMouseXAxis = true; + inputMapper.options.ignoreMouseYAxis = true; + Initialize(); + } + + private void OnEnable() + { + Subscribe(); + } + + private void OnDisable() + { + Unsubscribe(); + } + + private void Initialize() + { + dialog = new DialogHelper(); + actionQueue = new Queue(); + selectedController = new ControllerSelection(); + ReInput.ControllerConnectedEvent += JoystickConnected; + ReInput.ControllerPreDisconnectEvent += JoystickPreDisconnect; + ReInput.ControllerDisconnectedEvent += JoystickDisconnected; + ResetAll(); + initialized = true; + ReInput.userDataStore.Load(); + if (ReInput.unityJoystickIdentificationRequired) + { + IdentifyAllJoysticks(); + } + } + + private void Setup() + { + if (!setupFinished) + { + style_wordWrap = new GUIStyle(GUI.skin.label); + style_wordWrap.wordWrap = true; + style_centeredBox = new GUIStyle(GUI.skin.box); + style_centeredBox.alignment = TextAnchor.MiddleCenter; + setupFinished = true; + } + } + + private void Subscribe() + { + Unsubscribe(); + inputMapper.ConflictFoundEvent += OnConflictFound; + inputMapper.StoppedEvent += OnStopped; + } + + private void Unsubscribe() + { + inputMapper.RemoveAllEventListeners(); + } + + public void OnGUI() + { + if (initialized) + { + Setup(); + HandleMenuControl(); + if (!showMenu) + { + DrawInitialScreen(); + return; + } + SetGUIStateStart(); + ProcessQueue(); + DrawPage(); + ShowDialog(); + SetGUIStateEnd(); + busy = false; + } + } + + private void HandleMenuControl() + { + if (!dialog.enabled && Event.current.type == EventType.Layout && ReInput.players.GetSystemPlayer().GetButtonDown("Menu")) + { + if (showMenu) + { + ReInput.userDataStore.Save(); + Close(); + } + else + { + Open(); + } + } + } + + private void Close() + { + ClearWorkingVars(); + showMenu = false; + } + + private void Open() + { + showMenu = true; + } + + private void DrawInitialScreen() + { + ActionElementMap firstElementMapWithAction = ReInput.players.GetSystemPlayer().controllers.maps.GetFirstElementMapWithAction("Menu", skipDisabledMaps: true); + GUIContent content = ((firstElementMapWithAction == null) ? new GUIContent("There is no element assigned to open the menu!") : new GUIContent("Press " + firstElementMapWithAction.elementIdentifierName + " to open the menu.")); + GUILayout.BeginArea(GetScreenCenteredRect(300f, 50f)); + GUILayout.Box(content, style_centeredBox, GUILayout.ExpandHeight(expand: true), GUILayout.ExpandWidth(expand: true)); + GUILayout.EndArea(); + } + + private void DrawPage() + { + if (GUI.enabled != pageGUIState) + { + GUI.enabled = pageGUIState; + } + GUILayout.BeginArea(new Rect(((float)Screen.width - (float)Screen.width * 0.9f) * 0.5f, ((float)Screen.height - (float)Screen.height * 0.9f) * 0.5f, (float)Screen.width * 0.9f, (float)Screen.height * 0.9f)); + DrawPlayerSelector(); + DrawJoystickSelector(); + DrawMouseAssignment(); + DrawControllerSelector(); + DrawCalibrateButton(); + DrawMapCategories(); + actionScrollPos = GUILayout.BeginScrollView(actionScrollPos); + DrawCategoryActions(); + GUILayout.EndScrollView(); + GUILayout.EndArea(); + } + + private void DrawPlayerSelector() + { + if (ReInput.players.allPlayerCount == 0) + { + GUILayout.Label("There are no players."); + return; + } + GUILayout.Space(15f); + GUILayout.Label("Players:"); + GUILayout.BeginHorizontal(); + foreach (Player player in ReInput.players.GetPlayers(includeSystemPlayer: true)) + { + if (selectedPlayer == null) + { + selectedPlayer = player; + } + bool flag = ((player == selectedPlayer) ? true : false); + bool flag2 = GUILayout.Toggle(flag, (player.descriptiveName != string.Empty) ? player.descriptiveName : player.name, "Button", GUILayout.ExpandWidth(expand: false)); + if (flag2 != flag && flag2) + { + selectedPlayer = player; + selectedController.Clear(); + selectedMapCategoryId = -1; + } + } + GUILayout.EndHorizontal(); + } + + private void DrawMouseAssignment() + { + bool flag = GUI.enabled; + if (selectedPlayer == null) + { + GUI.enabled = false; + } + GUILayout.Space(15f); + GUILayout.Label("Assign Mouse:"); + GUILayout.BeginHorizontal(); + bool flag2 = ((selectedPlayer != null && selectedPlayer.controllers.hasMouse) ? true : false); + bool flag3 = GUILayout.Toggle(flag2, "Assign Mouse", "Button", GUILayout.ExpandWidth(expand: false)); + if (flag3 != flag2) + { + if (flag3) + { + selectedPlayer.controllers.hasMouse = true; + foreach (Player player in ReInput.players.Players) + { + if (player != selectedPlayer) + { + player.controllers.hasMouse = false; + } + } + } + else + { + selectedPlayer.controllers.hasMouse = false; + } + } + GUILayout.EndHorizontal(); + if (GUI.enabled != flag) + { + GUI.enabled = flag; + } + } + + private void DrawJoystickSelector() + { + bool flag = GUI.enabled; + if (selectedPlayer == null) + { + GUI.enabled = false; + } + GUILayout.Space(15f); + GUILayout.Label("Assign Joysticks:"); + GUILayout.BeginHorizontal(); + bool flag2 = ((selectedPlayer == null || selectedPlayer.controllers.joystickCount == 0) ? true : false); + bool flag3 = GUILayout.Toggle(flag2, "None", "Button", GUILayout.ExpandWidth(expand: false)); + if (flag3 != flag2) + { + selectedPlayer.controllers.ClearControllersOfType(ControllerType.Joystick); + ControllerSelectionChanged(); + } + if (selectedPlayer != null) + { + foreach (Joystick joystick in ReInput.controllers.Joysticks) + { + flag2 = selectedPlayer.controllers.ContainsController(joystick); + flag3 = GUILayout.Toggle(flag2, joystick.name, "Button", GUILayout.ExpandWidth(expand: false)); + if (flag3 != flag2) + { + EnqueueAction(new JoystickAssignmentChange(selectedPlayer.id, joystick.id, flag3)); + } + } + } + GUILayout.EndHorizontal(); + if (GUI.enabled != flag) + { + GUI.enabled = flag; + } + } + + private void DrawControllerSelector() + { + if (selectedPlayer == null) + { + return; + } + bool flag = GUI.enabled; + GUILayout.Space(15f); + GUILayout.Label("Controller to Map:"); + GUILayout.BeginHorizontal(); + if (!selectedController.hasSelection) + { + selectedController.Set(0, ControllerType.Keyboard); + ControllerSelectionChanged(); + } + bool flag2 = selectedController.type == ControllerType.Keyboard; + if (GUILayout.Toggle(flag2, "Keyboard", "Button", GUILayout.ExpandWidth(expand: false)) != flag2) + { + selectedController.Set(0, ControllerType.Keyboard); + ControllerSelectionChanged(); + } + if (!selectedPlayer.controllers.hasMouse) + { + GUI.enabled = false; + } + flag2 = selectedController.type == ControllerType.Mouse; + if (GUILayout.Toggle(flag2, "Mouse", "Button", GUILayout.ExpandWidth(expand: false)) != flag2) + { + selectedController.Set(0, ControllerType.Mouse); + ControllerSelectionChanged(); + } + if (GUI.enabled != flag) + { + GUI.enabled = flag; + } + foreach (Joystick joystick in selectedPlayer.controllers.Joysticks) + { + flag2 = selectedController.type == ControllerType.Joystick && selectedController.id == joystick.id; + if (GUILayout.Toggle(flag2, joystick.name, "Button", GUILayout.ExpandWidth(expand: false)) != flag2) + { + selectedController.Set(joystick.id, ControllerType.Joystick); + ControllerSelectionChanged(); + } + } + GUILayout.EndHorizontal(); + if (GUI.enabled != flag) + { + GUI.enabled = flag; + } + } + + private void DrawCalibrateButton() + { + if (selectedPlayer == null) + { + return; + } + bool flag = GUI.enabled; + GUILayout.Space(10f); + Controller controller = (selectedController.hasSelection ? selectedPlayer.controllers.GetController(selectedController.type, selectedController.id) : null); + if (controller == null || selectedController.type != ControllerType.Joystick) + { + GUI.enabled = false; + GUILayout.Button("Select a controller to calibrate", GUILayout.ExpandWidth(expand: false)); + if (GUI.enabled != flag) + { + GUI.enabled = flag; + } + } + else if (GUILayout.Button("Calibrate " + controller.name, GUILayout.ExpandWidth(expand: false)) && controller is Joystick joystick) + { + CalibrationMap calibrationMap = joystick.calibrationMap; + if (calibrationMap != null) + { + EnqueueAction(new Calibration(selectedPlayer, joystick, calibrationMap)); + } + } + if (GUI.enabled != flag) + { + GUI.enabled = flag; + } + } + + private void DrawMapCategories() + { + if (selectedPlayer == null || !selectedController.hasSelection) + { + return; + } + bool flag = GUI.enabled; + GUILayout.Space(15f); + GUILayout.Label("Categories:"); + GUILayout.BeginHorizontal(); + foreach (InputMapCategory userAssignableMapCategory in ReInput.mapping.UserAssignableMapCategories) + { + if (!selectedPlayer.controllers.maps.ContainsMapInCategory(selectedController.type, userAssignableMapCategory.id)) + { + GUI.enabled = false; + } + else if (selectedMapCategoryId < 0) + { + selectedMapCategoryId = userAssignableMapCategory.id; + selectedMap = selectedPlayer.controllers.maps.GetFirstMapInCategory(selectedController.type, selectedController.id, userAssignableMapCategory.id); + } + bool flag2 = ((userAssignableMapCategory.id == selectedMapCategoryId) ? true : false); + if (GUILayout.Toggle(flag2, (userAssignableMapCategory.descriptiveName != string.Empty) ? userAssignableMapCategory.descriptiveName : userAssignableMapCategory.name, "Button", GUILayout.ExpandWidth(expand: false)) != flag2) + { + selectedMapCategoryId = userAssignableMapCategory.id; + selectedMap = selectedPlayer.controllers.maps.GetFirstMapInCategory(selectedController.type, selectedController.id, userAssignableMapCategory.id); + } + if (GUI.enabled != flag) + { + GUI.enabled = flag; + } + } + GUILayout.EndHorizontal(); + if (GUI.enabled != flag) + { + GUI.enabled = flag; + } + } + + private void DrawCategoryActions() + { + if (selectedPlayer == null || selectedMapCategoryId < 0) + { + return; + } + bool flag = GUI.enabled; + if (selectedMap == null) + { + return; + } + GUILayout.Space(15f); + GUILayout.Label("Actions:"); + InputMapCategory mapCategory = ReInput.mapping.GetMapCategory(selectedMapCategoryId); + if (mapCategory == null) + { + return; + } + InputCategory actionCategory = ReInput.mapping.GetActionCategory(mapCategory.name); + if (actionCategory == null) + { + return; + } + float width = 150f; + foreach (InputAction item in ReInput.mapping.ActionsInCategory(actionCategory.id)) + { + string text = ((item.descriptiveName != string.Empty) ? item.descriptiveName : item.name); + if (item.type == InputActionType.Button) + { + GUILayout.BeginHorizontal(); + GUILayout.Label(text, GUILayout.Width(width)); + DrawAddActionMapButton(selectedPlayer.id, item, AxisRange.Positive, selectedController, selectedMap); + foreach (ActionElementMap allMap in selectedMap.AllMaps) + { + if (allMap.actionId == item.id) + { + DrawActionAssignmentButton(selectedPlayer.id, item, AxisRange.Positive, selectedController, selectedMap, allMap); + } + } + GUILayout.EndHorizontal(); + } + else + { + if (item.type != 0) + { + continue; + } + if (selectedController.type != 0) + { + GUILayout.BeginHorizontal(); + GUILayout.Label(text, GUILayout.Width(width)); + DrawAddActionMapButton(selectedPlayer.id, item, AxisRange.Full, selectedController, selectedMap); + foreach (ActionElementMap allMap2 in selectedMap.AllMaps) + { + if (allMap2.actionId == item.id && allMap2.elementType != ControllerElementType.Button && allMap2.axisType != AxisType.Split) + { + DrawActionAssignmentButton(selectedPlayer.id, item, AxisRange.Full, selectedController, selectedMap, allMap2); + DrawInvertButton(selectedPlayer.id, item, Pole.Positive, selectedController, selectedMap, allMap2); + } + } + GUILayout.EndHorizontal(); + } + string text2 = ((item.positiveDescriptiveName != string.Empty) ? item.positiveDescriptiveName : (item.descriptiveName + " +")); + GUILayout.BeginHorizontal(); + GUILayout.Label(text2, GUILayout.Width(width)); + DrawAddActionMapButton(selectedPlayer.id, item, AxisRange.Positive, selectedController, selectedMap); + foreach (ActionElementMap allMap3 in selectedMap.AllMaps) + { + if (allMap3.actionId == item.id && allMap3.axisContribution == Pole.Positive && allMap3.axisType != AxisType.Normal) + { + DrawActionAssignmentButton(selectedPlayer.id, item, AxisRange.Positive, selectedController, selectedMap, allMap3); + } + } + GUILayout.EndHorizontal(); + string text3 = ((item.negativeDescriptiveName != string.Empty) ? item.negativeDescriptiveName : (item.descriptiveName + " -")); + GUILayout.BeginHorizontal(); + GUILayout.Label(text3, GUILayout.Width(width)); + DrawAddActionMapButton(selectedPlayer.id, item, AxisRange.Negative, selectedController, selectedMap); + foreach (ActionElementMap allMap4 in selectedMap.AllMaps) + { + if (allMap4.actionId == item.id && allMap4.axisContribution == Pole.Negative && allMap4.axisType != AxisType.Normal) + { + DrawActionAssignmentButton(selectedPlayer.id, item, AxisRange.Negative, selectedController, selectedMap, allMap4); + } + } + GUILayout.EndHorizontal(); + } + } + if (GUI.enabled != flag) + { + GUI.enabled = flag; + } + } + + private void DrawActionAssignmentButton(int playerId, InputAction action, AxisRange actionRange, ControllerSelection controller, ControllerMap controllerMap, ActionElementMap elementMap) + { + if (GUILayout.Button(elementMap.elementIdentifierName, GUILayout.ExpandWidth(expand: false), GUILayout.MinWidth(30f))) + { + InputMapper.Context context = new InputMapper.Context + { + actionId = action.id, + actionRange = actionRange, + controllerMap = controllerMap, + actionElementMapToReplace = elementMap + }; + EnqueueAction(new ElementAssignmentChange(ElementAssignmentChangeType.ReassignOrRemove, context)); + startListening = true; + } + GUILayout.Space(4f); + } + + private void DrawInvertButton(int playerId, InputAction action, Pole actionAxisContribution, ControllerSelection controller, ControllerMap controllerMap, ActionElementMap elementMap) + { + bool invert = elementMap.invert; + bool flag = GUILayout.Toggle(invert, "Invert", GUILayout.ExpandWidth(expand: false)); + if (flag != invert) + { + elementMap.invert = flag; + } + GUILayout.Space(10f); + } + + private void DrawAddActionMapButton(int playerId, InputAction action, AxisRange actionRange, ControllerSelection controller, ControllerMap controllerMap) + { + if (GUILayout.Button("Add...", GUILayout.ExpandWidth(expand: false))) + { + InputMapper.Context context = new InputMapper.Context + { + actionId = action.id, + actionRange = actionRange, + controllerMap = controllerMap + }; + EnqueueAction(new ElementAssignmentChange(ElementAssignmentChangeType.Add, context)); + startListening = true; + } + GUILayout.Space(10f); + } + + private void ShowDialog() + { + dialog.Update(); + } + + private void DrawModalWindow(string title, string message) + { + if (dialog.enabled) + { + GUILayout.Space(5f); + GUILayout.Label(message, style_wordWrap); + GUILayout.FlexibleSpace(); + GUILayout.BeginHorizontal(); + dialog.DrawConfirmButton("Okay"); + GUILayout.FlexibleSpace(); + dialog.DrawCancelButton(); + GUILayout.EndHorizontal(); + } + } + + private void DrawModalWindow_OkayOnly(string title, string message) + { + if (dialog.enabled) + { + GUILayout.Space(5f); + GUILayout.Label(message, style_wordWrap); + GUILayout.FlexibleSpace(); + GUILayout.BeginHorizontal(); + dialog.DrawConfirmButton("Okay"); + GUILayout.EndHorizontal(); + } + } + + private void DrawElementAssignmentWindow(string title, string message) + { + if (!dialog.enabled) + { + return; + } + GUILayout.Space(5f); + GUILayout.Label(message, style_wordWrap); + GUILayout.FlexibleSpace(); + if (!(actionQueue.Peek() is ElementAssignmentChange elementAssignmentChange)) + { + dialog.Cancel(); + return; + } + float num; + if (!dialog.busy) + { + if (startListening && inputMapper.status == InputMapper.Status.Idle) + { + inputMapper.Start(elementAssignmentChange.context); + startListening = false; + } + if (conflictFoundEventData != null) + { + dialog.Confirm(); + return; + } + num = inputMapper.timeRemaining; + if (num == 0f) + { + dialog.Cancel(); + return; + } + } + else + { + num = inputMapper.options.timeout; + } + GUILayout.Label("Assignment will be canceled in " + (int)Mathf.Ceil(num) + "...", style_wordWrap); + } + + private void DrawElementAssignmentProtectedConflictWindow(string title, string message) + { + if (dialog.enabled) + { + GUILayout.Space(5f); + GUILayout.Label(message, style_wordWrap); + GUILayout.FlexibleSpace(); + if (!(actionQueue.Peek() is ElementAssignmentChange)) + { + dialog.Cancel(); + return; + } + GUILayout.BeginHorizontal(); + dialog.DrawConfirmButton(UserResponse.Custom1, "Add"); + GUILayout.FlexibleSpace(); + dialog.DrawCancelButton(); + GUILayout.EndHorizontal(); + } + } + + private void DrawElementAssignmentNormalConflictWindow(string title, string message) + { + if (dialog.enabled) + { + GUILayout.Space(5f); + GUILayout.Label(message, style_wordWrap); + GUILayout.FlexibleSpace(); + if (!(actionQueue.Peek() is ElementAssignmentChange)) + { + dialog.Cancel(); + return; + } + GUILayout.BeginHorizontal(); + dialog.DrawConfirmButton(UserResponse.Confirm, "Replace"); + GUILayout.FlexibleSpace(); + dialog.DrawConfirmButton(UserResponse.Custom1, "Add"); + GUILayout.FlexibleSpace(); + dialog.DrawCancelButton(); + GUILayout.EndHorizontal(); + } + } + + private void DrawReassignOrRemoveElementAssignmentWindow(string title, string message) + { + if (dialog.enabled) + { + GUILayout.Space(5f); + GUILayout.Label(message, style_wordWrap); + GUILayout.FlexibleSpace(); + GUILayout.BeginHorizontal(); + dialog.DrawConfirmButton("Reassign"); + GUILayout.FlexibleSpace(); + dialog.DrawCancelButton("Remove"); + GUILayout.EndHorizontal(); + } + } + + private void DrawFallbackJoystickIdentificationWindow(string title, string message) + { + if (!dialog.enabled) + { + return; + } + if (!(actionQueue.Peek() is FallbackJoystickIdentification fallbackJoystickIdentification)) + { + dialog.Cancel(); + return; + } + GUILayout.Space(5f); + GUILayout.Label(message, style_wordWrap); + GUILayout.Label("Press any button or axis on \"" + fallbackJoystickIdentification.joystickName + "\" now.", style_wordWrap); + GUILayout.FlexibleSpace(); + if (GUILayout.Button("Skip")) + { + dialog.Cancel(); + } + else if (!dialog.busy && ReInput.controllers.SetUnityJoystickIdFromAnyButtonOrAxisPress(fallbackJoystickIdentification.joystickId, 0.8f, positiveAxesOnly: false)) + { + dialog.Confirm(); + } + } + + private void DrawCalibrationWindow(string title, string message) + { + if (!dialog.enabled) + { + return; + } + if (!(actionQueue.Peek() is Calibration calibration)) + { + dialog.Cancel(); + return; + } + GUILayout.Space(5f); + GUILayout.Label(message, style_wordWrap); + GUILayout.Space(20f); + GUILayout.BeginHorizontal(); + bool flag = GUI.enabled; + GUILayout.BeginVertical(GUILayout.Width(200f)); + calibrateScrollPos = GUILayout.BeginScrollView(calibrateScrollPos); + if (calibration.recording) + { + GUI.enabled = false; + } + IList axisElementIdentifiers = calibration.joystick.AxisElementIdentifiers; + for (int i = 0; i < axisElementIdentifiers.Count; i++) + { + ControllerElementIdentifier controllerElementIdentifier = axisElementIdentifiers[i]; + bool flag2 = calibration.selectedElementIdentifierId == controllerElementIdentifier.id; + bool flag3 = GUILayout.Toggle(flag2, controllerElementIdentifier.name, "Button", GUILayout.ExpandWidth(expand: false)); + if (flag2 != flag3) + { + calibration.selectedElementIdentifierId = controllerElementIdentifier.id; + } + } + if (GUI.enabled != flag) + { + GUI.enabled = flag; + } + GUILayout.EndScrollView(); + GUILayout.EndVertical(); + GUILayout.BeginVertical(GUILayout.Width(200f)); + if (calibration.selectedElementIdentifierId >= 0) + { + float axisRawById = calibration.joystick.GetAxisRawById(calibration.selectedElementIdentifierId); + GUILayout.Label("Raw Value: " + axisRawById); + int axisIndexById = calibration.joystick.GetAxisIndexById(calibration.selectedElementIdentifierId); + AxisCalibration axis = calibration.calibrationMap.GetAxis(axisIndexById); + GUILayout.Label("Calibrated Value: " + calibration.joystick.GetAxisById(calibration.selectedElementIdentifierId)); + GUILayout.Label("Zero: " + axis.calibratedZero); + GUILayout.Label("Min: " + axis.calibratedMin); + GUILayout.Label("Max: " + axis.calibratedMax); + GUILayout.Label("Dead Zone: " + axis.deadZone); + GUILayout.Space(15f); + bool flag4 = GUILayout.Toggle(axis.enabled, "Enabled", "Button", GUILayout.ExpandWidth(expand: false)); + if (axis.enabled != flag4) + { + axis.enabled = flag4; + } + GUILayout.Space(10f); + bool flag5 = GUILayout.Toggle(calibration.recording, "Record Min/Max", "Button", GUILayout.ExpandWidth(expand: false)); + if (flag5 != calibration.recording) + { + if (flag5) + { + axis.calibratedMax = 0f; + axis.calibratedMin = 0f; + } + calibration.recording = flag5; + } + if (calibration.recording) + { + axis.calibratedMin = Mathf.Min(axis.calibratedMin, axisRawById, axis.calibratedMin); + axis.calibratedMax = Mathf.Max(axis.calibratedMax, axisRawById, axis.calibratedMax); + GUI.enabled = false; + } + if (GUILayout.Button("Set Zero", GUILayout.ExpandWidth(expand: false))) + { + axis.calibratedZero = axisRawById; + } + if (GUILayout.Button("Set Dead Zone", GUILayout.ExpandWidth(expand: false))) + { + axis.deadZone = axisRawById; + } + bool flag6 = GUILayout.Toggle(axis.invert, "Invert", "Button", GUILayout.ExpandWidth(expand: false)); + if (axis.invert != flag6) + { + axis.invert = flag6; + } + GUILayout.Space(10f); + if (GUILayout.Button("Reset", GUILayout.ExpandWidth(expand: false))) + { + axis.Reset(); + } + if (GUI.enabled != flag) + { + GUI.enabled = flag; + } + } + else + { + GUILayout.Label("Select an axis to begin."); + } + GUILayout.EndVertical(); + GUILayout.EndHorizontal(); + GUILayout.FlexibleSpace(); + if (calibration.recording) + { + GUI.enabled = false; + } + if (GUILayout.Button("Close")) + { + calibrateScrollPos = default(Vector2); + dialog.Confirm(); + } + if (GUI.enabled != flag) + { + GUI.enabled = flag; + } + } + + private void DialogResultCallback(int queueActionId, UserResponse response) + { + foreach (QueueEntry item in actionQueue) + { + if (item.id == queueActionId) + { + if (response != UserResponse.Cancel) + { + item.Confirm(response); + } + else + { + item.Cancel(); + } + break; + } + } + } + + private Rect GetScreenCenteredRect(float width, float height) + { + return new Rect((float)Screen.width * 0.5f - width * 0.5f, (float)((double)Screen.height * 0.5 - (double)(height * 0.5f)), width, height); + } + + private void EnqueueAction(QueueEntry entry) + { + if (entry != null) + { + busy = true; + GUI.enabled = false; + actionQueue.Enqueue(entry); + } + } + + private void ProcessQueue() + { + if (dialog.enabled || busy || actionQueue.Count == 0) + { + return; + } + while (actionQueue.Count > 0) + { + QueueEntry queueEntry = actionQueue.Peek(); + bool flag = false; + switch (queueEntry.queueActionType) + { + case QueueActionType.JoystickAssignment: + flag = ProcessJoystickAssignmentChange((JoystickAssignmentChange)queueEntry); + break; + case QueueActionType.ElementAssignment: + flag = ProcessElementAssignmentChange((ElementAssignmentChange)queueEntry); + break; + case QueueActionType.FallbackJoystickIdentification: + flag = ProcessFallbackJoystickIdentification((FallbackJoystickIdentification)queueEntry); + break; + case QueueActionType.Calibrate: + flag = ProcessCalibration((Calibration)queueEntry); + break; + } + if (flag) + { + actionQueue.Dequeue(); + continue; + } + break; + } + } + + private bool ProcessJoystickAssignmentChange(JoystickAssignmentChange entry) + { + if (entry.state == QueueEntry.State.Canceled) + { + return true; + } + Player player = ReInput.players.GetPlayer(entry.playerId); + if (player == null) + { + return true; + } + if (!entry.assign) + { + player.controllers.RemoveController(ControllerType.Joystick, entry.joystickId); + ControllerSelectionChanged(); + return true; + } + if (player.controllers.ContainsController(ControllerType.Joystick, entry.joystickId)) + { + return true; + } + if (!ReInput.controllers.IsJoystickAssigned(entry.joystickId) || entry.state == QueueEntry.State.Confirmed) + { + player.controllers.AddController(ControllerType.Joystick, entry.joystickId, removeFromOtherPlayers: true); + ControllerSelectionChanged(); + return true; + } + dialog.StartModal(entry.id, DialogHelper.DialogType.JoystickConflict, new WindowProperties + { + title = "Joystick Reassignment", + message = "This joystick is already assigned to another player. Do you want to reassign this joystick to " + player.descriptiveName + "?", + rect = GetScreenCenteredRect(250f, 200f), + windowDrawDelegate = DrawModalWindow + }, DialogResultCallback); + return false; + } + + private bool ProcessElementAssignmentChange(ElementAssignmentChange entry) + { + switch (entry.changeType) + { + case ElementAssignmentChangeType.ReassignOrRemove: + return ProcessRemoveOrReassignElementAssignment(entry); + case ElementAssignmentChangeType.Remove: + return ProcessRemoveElementAssignment(entry); + case ElementAssignmentChangeType.Add: + case ElementAssignmentChangeType.Replace: + return ProcessAddOrReplaceElementAssignment(entry); + case ElementAssignmentChangeType.ConflictCheck: + return ProcessElementAssignmentConflictCheck(entry); + default: + throw new NotImplementedException(); + } + } + + private bool ProcessRemoveOrReassignElementAssignment(ElementAssignmentChange entry) + { + if (entry.context.controllerMap == null) + { + return true; + } + if (entry.state == QueueEntry.State.Canceled) + { + ElementAssignmentChange elementAssignmentChange = new ElementAssignmentChange(entry); + elementAssignmentChange.changeType = ElementAssignmentChangeType.Remove; + actionQueue.Enqueue(elementAssignmentChange); + return true; + } + if (entry.state == QueueEntry.State.Confirmed) + { + ElementAssignmentChange elementAssignmentChange2 = new ElementAssignmentChange(entry); + elementAssignmentChange2.changeType = ElementAssignmentChangeType.Replace; + actionQueue.Enqueue(elementAssignmentChange2); + return true; + } + dialog.StartModal(entry.id, DialogHelper.DialogType.AssignElement, new WindowProperties + { + title = "Reassign or Remove", + message = "Do you want to reassign or remove this assignment?", + rect = GetScreenCenteredRect(250f, 200f), + windowDrawDelegate = DrawReassignOrRemoveElementAssignmentWindow + }, DialogResultCallback); + return false; + } + + private bool ProcessRemoveElementAssignment(ElementAssignmentChange entry) + { + if (entry.context.controllerMap == null) + { + return true; + } + if (entry.state == QueueEntry.State.Canceled) + { + return true; + } + if (entry.state == QueueEntry.State.Confirmed) + { + entry.context.controllerMap.DeleteElementMap(entry.context.actionElementMapToReplace.id); + return true; + } + dialog.StartModal(entry.id, DialogHelper.DialogType.DeleteAssignmentConfirmation, new WindowProperties + { + title = "Remove Assignment", + message = "Are you sure you want to remove this assignment?", + rect = GetScreenCenteredRect(250f, 200f), + windowDrawDelegate = DrawModalWindow + }, DialogResultCallback); + return false; + } + + private bool ProcessAddOrReplaceElementAssignment(ElementAssignmentChange entry) + { + if (entry.state == QueueEntry.State.Canceled) + { + inputMapper.Stop(); + return true; + } + if (entry.state == QueueEntry.State.Confirmed) + { + if (Event.current.type != EventType.Layout) + { + return false; + } + if (conflictFoundEventData != null) + { + ElementAssignmentChange elementAssignmentChange = new ElementAssignmentChange(entry); + elementAssignmentChange.changeType = ElementAssignmentChangeType.ConflictCheck; + actionQueue.Enqueue(elementAssignmentChange); + } + return true; + } + string text; + if (entry.context.controllerMap.controllerType != 0) + { + text = ((entry.context.controllerMap.controllerType != ControllerType.Mouse) ? "Press any button or axis to assign it to this action." : "Press any mouse button or axis to assign it to this action.\n\nTo assign mouse movement axes, move the mouse quickly in the direction you want mapped to the action. Slow movements will be ignored."); + } + else + { + text = ((Application.platform != 0 && Application.platform != RuntimePlatform.OSXPlayer) ? "Press any key to assign it to this action. You may also use the modifier keys Control, Alt, and Shift. If you wish to assign a modifier key itself to this action, press and hold the key for 1 second." : "Press any key to assign it to this action. You may also use the modifier keys Command, Control, Alt, and Shift. If you wish to assign a modifier key itself to this action, press and hold the key for 1 second."); + if (Application.isEditor) + { + text += "\n\nNOTE: Some modifier key combinations will not work in the Unity Editor, but they will work in a game build."; + } + } + dialog.StartModal(entry.id, DialogHelper.DialogType.AssignElement, new WindowProperties + { + title = "Assign", + message = text, + rect = GetScreenCenteredRect(250f, 200f), + windowDrawDelegate = DrawElementAssignmentWindow + }, DialogResultCallback); + return false; + } + + private bool ProcessElementAssignmentConflictCheck(ElementAssignmentChange entry) + { + if (entry.context.controllerMap == null) + { + return true; + } + if (entry.state == QueueEntry.State.Canceled) + { + inputMapper.Stop(); + return true; + } + if (conflictFoundEventData == null) + { + return true; + } + if (entry.state == QueueEntry.State.Confirmed) + { + if (entry.response == UserResponse.Confirm) + { + conflictFoundEventData.responseCallback(InputMapper.ConflictResponse.Replace); + } + else + { + if (entry.response != UserResponse.Custom1) + { + throw new NotImplementedException(); + } + conflictFoundEventData.responseCallback(InputMapper.ConflictResponse.Add); + } + return true; + } + if (conflictFoundEventData.isProtected) + { + string message = conflictFoundEventData.assignment.elementDisplayName + " is already in use and is protected from reassignment. You cannot remove the protected assignment, but you can still assign the action to this element. If you do so, the element will trigger multiple actions when activated."; + dialog.StartModal(entry.id, DialogHelper.DialogType.AssignElement, new WindowProperties + { + title = "Assignment Conflict", + message = message, + rect = GetScreenCenteredRect(250f, 200f), + windowDrawDelegate = DrawElementAssignmentProtectedConflictWindow + }, DialogResultCallback); + } + else + { + string message2 = conflictFoundEventData.assignment.elementDisplayName + " is already in use. You may replace the other conflicting assignments, add this assignment anyway which will leave multiple actions assigned to this element, or cancel this assignment."; + dialog.StartModal(entry.id, DialogHelper.DialogType.AssignElement, new WindowProperties + { + title = "Assignment Conflict", + message = message2, + rect = GetScreenCenteredRect(250f, 200f), + windowDrawDelegate = DrawElementAssignmentNormalConflictWindow + }, DialogResultCallback); + } + return false; + } + + private bool ProcessFallbackJoystickIdentification(FallbackJoystickIdentification entry) + { + if (entry.state == QueueEntry.State.Canceled) + { + return true; + } + if (entry.state == QueueEntry.State.Confirmed) + { + return true; + } + dialog.StartModal(entry.id, DialogHelper.DialogType.JoystickConflict, new WindowProperties + { + title = "Joystick Identification Required", + message = "A joystick has been attached or removed. You will need to identify each joystick by pressing a button on the controller listed below:", + rect = GetScreenCenteredRect(250f, 200f), + windowDrawDelegate = DrawFallbackJoystickIdentificationWindow + }, DialogResultCallback, 1f); + return false; + } + + private bool ProcessCalibration(Calibration entry) + { + if (entry.state == QueueEntry.State.Canceled) + { + return true; + } + if (entry.state == QueueEntry.State.Confirmed) + { + return true; + } + dialog.StartModal(entry.id, DialogHelper.DialogType.JoystickConflict, new WindowProperties + { + title = "Calibrate Controller", + message = "Select an axis to calibrate on the " + entry.joystick.name + ".", + rect = GetScreenCenteredRect(450f, 480f), + windowDrawDelegate = DrawCalibrationWindow + }, DialogResultCallback); + return false; + } + + private void PlayerSelectionChanged() + { + ClearControllerSelection(); + } + + private void ControllerSelectionChanged() + { + ClearMapSelection(); + } + + private void ClearControllerSelection() + { + selectedController.Clear(); + ClearMapSelection(); + } + + private void ClearMapSelection() + { + selectedMapCategoryId = -1; + selectedMap = null; + } + + private void ResetAll() + { + ClearWorkingVars(); + initialized = false; + showMenu = false; + } + + private void ClearWorkingVars() + { + selectedPlayer = null; + ClearMapSelection(); + selectedController.Clear(); + actionScrollPos = default(Vector2); + dialog.FullReset(); + actionQueue.Clear(); + busy = false; + startListening = false; + conflictFoundEventData = null; + inputMapper.Stop(); + } + + private void SetGUIStateStart() + { + guiState = true; + if (busy) + { + guiState = false; + } + pageGUIState = guiState && !busy && !dialog.enabled && !dialog.busy; + if (GUI.enabled != guiState) + { + GUI.enabled = guiState; + } + } + + private void SetGUIStateEnd() + { + guiState = true; + if (!GUI.enabled) + { + GUI.enabled = guiState; + } + } + + private void JoystickConnected(ControllerStatusChangedEventArgs args) + { + if (ReInput.controllers.IsControllerAssigned(args.controllerType, args.controllerId)) + { + foreach (Player allPlayer in ReInput.players.AllPlayers) + { + if (allPlayer.controllers.ContainsController(args.controllerType, args.controllerId)) + { + ReInput.userDataStore.LoadControllerData(allPlayer.id, args.controllerType, args.controllerId); + } + } + } + else + { + ReInput.userDataStore.LoadControllerData(args.controllerType, args.controllerId); + } + if (ReInput.unityJoystickIdentificationRequired) + { + IdentifyAllJoysticks(); + } + } + + private void JoystickPreDisconnect(ControllerStatusChangedEventArgs args) + { + if (selectedController.hasSelection && args.controllerType == selectedController.type && args.controllerId == selectedController.id) + { + ClearControllerSelection(); + } + if (!showMenu) + { + return; + } + if (ReInput.controllers.IsControllerAssigned(args.controllerType, args.controllerId)) + { + foreach (Player allPlayer in ReInput.players.AllPlayers) + { + if (allPlayer.controllers.ContainsController(args.controllerType, args.controllerId)) + { + ReInput.userDataStore.SaveControllerData(allPlayer.id, args.controllerType, args.controllerId); + } + } + return; + } + ReInput.userDataStore.SaveControllerData(args.controllerType, args.controllerId); + } + + private void JoystickDisconnected(ControllerStatusChangedEventArgs args) + { + if (showMenu) + { + ClearWorkingVars(); + } + if (ReInput.unityJoystickIdentificationRequired) + { + IdentifyAllJoysticks(); + } + } + + private void OnConflictFound(InputMapper.ConflictFoundEventData data) + { + conflictFoundEventData = data; + } + + private void OnStopped(InputMapper.StoppedEventData data) + { + conflictFoundEventData = null; + } + + public void IdentifyAllJoysticks() + { + if (ReInput.controllers.joystickCount == 0) + { + return; + } + ClearWorkingVars(); + Open(); + foreach (Joystick joystick in ReInput.controllers.Joysticks) + { + actionQueue.Enqueue(new FallbackJoystickIdentification(joystick.id, joystick.name)); + } + } + + protected void CheckRecompile() + { + } + + private void RecompileWindow(int windowId) + { + } +} diff --git a/Rewired/Rewired.Demos/CustomControllerDemo.cs b/Rewired/Rewired.Demos/CustomControllerDemo.cs new file mode 100644 index 0000000..2c67e86 --- /dev/null +++ b/Rewired/Rewired.Demos/CustomControllerDemo.cs @@ -0,0 +1,144 @@ +using System; +using UnityEngine; + +namespace Rewired.Demos; + +[AddComponentMenu("")] +public class CustomControllerDemo : MonoBehaviour +{ + public int playerId; + + public string controllerTag; + + public bool useUpdateCallbacks; + + private int buttonCount; + + private int axisCount; + + private float[] axisValues; + + private bool[] buttonValues; + + private TouchJoystickExample[] joysticks; + + private TouchButtonExample[] buttons; + + private CustomController controller; + + [NonSerialized] + private bool initialized; + + private void Awake() + { + ScreenOrientation screenOrientation = ScreenOrientation.LandscapeLeft; + if (SystemInfo.deviceType == DeviceType.Handheld && Screen.orientation != screenOrientation) + { + Screen.orientation = screenOrientation; + } + Initialize(); + } + + private void Initialize() + { + ReInput.InputSourceUpdateEvent += OnInputSourceUpdate; + joysticks = GetComponentsInChildren(); + buttons = GetComponentsInChildren(); + axisCount = joysticks.Length * 2; + buttonCount = buttons.Length; + axisValues = new float[axisCount]; + buttonValues = new bool[buttonCount]; + Player player = ReInput.players.GetPlayer(playerId); + controller = player.controllers.GetControllerWithTag(controllerTag); + if (controller == null) + { + Debug.LogError("A matching controller was not found for tag \"" + controllerTag + "\""); + } + if (controller.buttonCount != buttonValues.Length || controller.axisCount != axisValues.Length) + { + Debug.LogError("Controller has wrong number of elements!"); + } + if (useUpdateCallbacks && controller != null) + { + controller.SetAxisUpdateCallback(GetAxisValueCallback); + controller.SetButtonUpdateCallback(GetButtonValueCallback); + } + initialized = true; + } + + private void Update() + { + if (ReInput.isReady && !initialized) + { + Initialize(); + } + } + + private void OnInputSourceUpdate() + { + GetSourceAxisValues(); + GetSourceButtonValues(); + if (!useUpdateCallbacks) + { + SetControllerAxisValues(); + SetControllerButtonValues(); + } + } + + private void GetSourceAxisValues() + { + for (int i = 0; i < axisValues.Length; i++) + { + if (i % 2 != 0) + { + axisValues[i] = joysticks[i / 2].position.y; + } + else + { + axisValues[i] = joysticks[i / 2].position.x; + } + } + } + + private void GetSourceButtonValues() + { + for (int i = 0; i < buttonValues.Length; i++) + { + buttonValues[i] = buttons[i].isPressed; + } + } + + private void SetControllerAxisValues() + { + for (int i = 0; i < axisValues.Length; i++) + { + controller.SetAxisValue(i, axisValues[i]); + } + } + + private void SetControllerButtonValues() + { + for (int i = 0; i < buttonValues.Length; i++) + { + controller.SetButtonValue(i, buttonValues[i]); + } + } + + private float GetAxisValueCallback(int index) + { + if (index >= axisValues.Length) + { + return 0f; + } + return axisValues[index]; + } + + private bool GetButtonValueCallback(int index) + { + if (index >= buttonValues.Length) + { + return false; + } + return buttonValues[index]; + } +} diff --git a/Rewired/Rewired.Demos/CustomControllerDemo_Player.cs b/Rewired/Rewired.Demos/CustomControllerDemo_Player.cs new file mode 100644 index 0000000..7c4346a --- /dev/null +++ b/Rewired/Rewired.Demos/CustomControllerDemo_Player.cs @@ -0,0 +1,58 @@ +using UnityEngine; + +namespace Rewired.Demos; + +[AddComponentMenu("")] +[RequireComponent(typeof(CharacterController))] +public class CustomControllerDemo_Player : MonoBehaviour +{ + public int playerId; + + public float speed = 1f; + + public float bulletSpeed = 20f; + + public GameObject bulletPrefab; + + private Player _player; + + private CharacterController cc; + + private Player player + { + get + { + if (_player == null) + { + _player = ReInput.players.GetPlayer(playerId); + } + return _player; + } + } + + private void Awake() + { + cc = GetComponent(); + } + + private void Update() + { + if (ReInput.isReady) + { + Vector2 vector = new Vector2(player.GetAxis("Move Horizontal"), player.GetAxis("Move Vertical")); + cc.Move(vector * speed * Time.deltaTime); + if (player.GetButtonDown("Fire")) + { + Vector3 vector2 = Vector3.Scale(new Vector3(1f, 0f, 0f), base.transform.right); + Object.Instantiate(bulletPrefab, base.transform.position + vector2, Quaternion.identity).GetComponent().velocity = new Vector3(bulletSpeed * base.transform.right.x, 0f, 0f); + } + if (player.GetButtonDown("Change Color")) + { + Renderer component = GetComponent(); + Material material = component.material; + material.color = new Color(Random.Range(0f, 1f), Random.Range(0f, 1f), Random.Range(0f, 1f), 1f); + component.material = material; + } + } + } +} diff --git a/Rewired/Rewired.Demos/CustomControllersTiltDemo.cs b/Rewired/Rewired.Demos/CustomControllersTiltDemo.cs new file mode 100644 index 0000000..d24caf2 --- /dev/null +++ b/Rewired/Rewired.Demos/CustomControllersTiltDemo.cs @@ -0,0 +1,47 @@ +using UnityEngine; + +namespace Rewired.Demos; + +[AddComponentMenu("")] +public class CustomControllersTiltDemo : MonoBehaviour +{ + public Transform target; + + public float speed = 10f; + + private CustomController controller; + + private Player player; + + private void Awake() + { + Screen.orientation = ScreenOrientation.LandscapeLeft; + player = ReInput.players.GetPlayer(0); + ReInput.InputSourceUpdateEvent += OnInputUpdate; + controller = (CustomController)player.controllers.GetControllerWithTag(ControllerType.Custom, "TiltController"); + } + + private void Update() + { + if (!(target == null)) + { + Vector3 zero = Vector3.zero; + zero.y = player.GetAxis("Tilt Vertical"); + zero.x = player.GetAxis("Tilt Horizontal"); + if (zero.sqrMagnitude > 1f) + { + zero.Normalize(); + } + zero *= Time.deltaTime; + target.Translate(zero * speed); + } + } + + private void OnInputUpdate() + { + Vector3 acceleration = Input.acceleration; + controller.SetAxisValue(0, acceleration.x); + controller.SetAxisValue(1, acceleration.y); + controller.SetAxisValue(2, acceleration.z); + } +} diff --git a/Rewired/Rewired.Demos/DualShock4SpecialFeaturesExample.cs b/Rewired/Rewired.Demos/DualShock4SpecialFeaturesExample.cs new file mode 100644 index 0000000..838b779 --- /dev/null +++ b/Rewired/Rewired.Demos/DualShock4SpecialFeaturesExample.cs @@ -0,0 +1,219 @@ +using System.Collections.Generic; +using Rewired.ControllerExtensions; +using UnityEngine; + +namespace Rewired.Demos; + +[AddComponentMenu("")] +public class DualShock4SpecialFeaturesExample : MonoBehaviour +{ + private class Touch + { + public GameObject go; + + public int touchId = -1; + } + + private const int maxTouches = 2; + + public int playerId; + + public Transform touchpadTransform; + + public GameObject lightObject; + + public Transform accelerometerTransform; + + private List touches; + + private Queue unusedTouches; + + private bool isFlashing; + + private GUIStyle textStyle; + + private Player player => ReInput.players.GetPlayer(playerId); + + private void Awake() + { + InitializeTouchObjects(); + } + + private void Update() + { + if (!ReInput.isReady) + { + return; + } + IDualShock4Extension firstDS = GetFirstDS4(player); + if (firstDS != null) + { + base.transform.rotation = firstDS.GetOrientation(); + HandleTouchpad(firstDS); + Vector3 accelerometerValue = firstDS.GetAccelerometerValue(); + accelerometerTransform.LookAt(accelerometerTransform.position + accelerometerValue); + } + if (player.GetButtonDown("CycleLight")) + { + SetRandomLightColor(); + } + if (player.GetButtonDown("ResetOrientation")) + { + ResetOrientation(); + } + if (player.GetButtonDown("ToggleLightFlash")) + { + if (isFlashing) + { + StopLightFlash(); + } + else + { + StartLightFlash(); + } + isFlashing = !isFlashing; + } + if (player.GetButtonDown("VibrateLeft")) + { + firstDS.SetVibration(0, 1f, 1f); + } + if (player.GetButtonDown("VibrateRight")) + { + firstDS.SetVibration(1, 1f, 1f); + } + } + + private void OnGUI() + { + if (textStyle == null) + { + textStyle = new GUIStyle(GUI.skin.label); + textStyle.fontSize = 20; + textStyle.wordWrap = true; + } + if (GetFirstDS4(player) != null) + { + GUILayout.BeginArea(new Rect(200f, 100f, (float)Screen.width - 400f, (float)Screen.height - 200f)); + GUILayout.Label("Rotate the Dual Shock 4 to see the model rotate in sync.", textStyle); + GUILayout.Label("Touch the touchpad to see them appear on the model.", textStyle); + ActionElementMap firstElementMapWithAction = player.controllers.maps.GetFirstElementMapWithAction(ControllerType.Joystick, "ResetOrientation", skipDisabledMaps: true); + if (firstElementMapWithAction != null) + { + GUILayout.Label("Press " + firstElementMapWithAction.elementIdentifierName + " to reset the orientation. Hold the gamepad facing the screen with sticks pointing up and press the button.", textStyle); + } + firstElementMapWithAction = player.controllers.maps.GetFirstElementMapWithAction(ControllerType.Joystick, "CycleLight", skipDisabledMaps: true); + if (firstElementMapWithAction != null) + { + GUILayout.Label("Press " + firstElementMapWithAction.elementIdentifierName + " to change the light color.", textStyle); + } + firstElementMapWithAction = player.controllers.maps.GetFirstElementMapWithAction(ControllerType.Joystick, "ToggleLightFlash", skipDisabledMaps: true); + if (firstElementMapWithAction != null) + { + GUILayout.Label("Press " + firstElementMapWithAction.elementIdentifierName + " to start or stop the light flashing.", textStyle); + } + firstElementMapWithAction = player.controllers.maps.GetFirstElementMapWithAction(ControllerType.Joystick, "VibrateLeft", skipDisabledMaps: true); + if (firstElementMapWithAction != null) + { + GUILayout.Label("Press " + firstElementMapWithAction.elementIdentifierName + " vibrate the left motor.", textStyle); + } + firstElementMapWithAction = player.controllers.maps.GetFirstElementMapWithAction(ControllerType.Joystick, "VibrateRight", skipDisabledMaps: true); + if (firstElementMapWithAction != null) + { + GUILayout.Label("Press " + firstElementMapWithAction.elementIdentifierName + " vibrate the right motor.", textStyle); + } + GUILayout.EndArea(); + } + } + + private void ResetOrientation() + { + GetFirstDS4(player)?.ResetOrientation(); + } + + private void SetRandomLightColor() + { + IDualShock4Extension firstDS = GetFirstDS4(player); + if (firstDS != null) + { + Color color = new Color(Random.Range(0f, 1f), Random.Range(0f, 1f), Random.Range(0f, 1f), 1f); + firstDS.SetLightColor(color); + lightObject.GetComponent().material.color = color; + } + } + + private void StartLightFlash() + { + if (GetFirstDS4(player) is DualShock4Extension dualShock4Extension) + { + dualShock4Extension.SetLightFlash(0.5f, 0.5f); + } + } + + private void StopLightFlash() + { + if (GetFirstDS4(player) is DualShock4Extension dualShock4Extension) + { + dualShock4Extension.StopLightFlash(); + } + } + + private IDualShock4Extension GetFirstDS4(Player player) + { + foreach (Joystick joystick in player.controllers.Joysticks) + { + IDualShock4Extension extension = joystick.GetExtension(); + if (extension != null) + { + return extension; + } + } + return null; + } + + private void InitializeTouchObjects() + { + touches = new List(2); + unusedTouches = new Queue(2); + for (int i = 0; i < 2; i++) + { + Touch touch = new Touch(); + touch.go = GameObject.CreatePrimitive(PrimitiveType.Sphere); + touch.go.transform.localScale = new Vector3(0.1f, 0.1f, 0.1f); + touch.go.transform.SetParent(touchpadTransform, worldPositionStays: true); + touch.go.GetComponent().material.color = ((i == 0) ? Color.red : Color.green); + touch.go.SetActive(value: false); + unusedTouches.Enqueue(touch); + } + } + + private void HandleTouchpad(IDualShock4Extension ds4) + { + for (int num = touches.Count - 1; num >= 0; num--) + { + Touch touch = touches[num]; + if (!ds4.IsTouchingByTouchId(touch.touchId)) + { + touch.go.SetActive(value: false); + unusedTouches.Enqueue(touch); + touches.RemoveAt(num); + } + } + for (int i = 0; i < ds4.maxTouches; i++) + { + if (ds4.IsTouching(i)) + { + int touchId = ds4.GetTouchId(i); + Touch touch2 = touches.Find((Touch x) => x.touchId == touchId); + if (touch2 == null) + { + touch2 = unusedTouches.Dequeue(); + touches.Add(touch2); + } + touch2.touchId = touchId; + touch2.go.SetActive(value: true); + ds4.GetTouchPosition(i, out var position); + touch2.go.transform.localPosition = new Vector3(position.x - 0.5f, 0.5f + touch2.go.transform.localScale.y * 0.5f, position.y - 0.5f); + } + } + } +} diff --git a/Rewired/Rewired.Demos/EightPlayersExample_Player.cs b/Rewired/Rewired.Demos/EightPlayersExample_Player.cs new file mode 100644 index 0000000..0ce56e1 --- /dev/null +++ b/Rewired/Rewired.Demos/EightPlayersExample_Player.cs @@ -0,0 +1,71 @@ +using System; +using UnityEngine; + +namespace Rewired.Demos; + +[AddComponentMenu("")] +[RequireComponent(typeof(CharacterController))] +public class EightPlayersExample_Player : MonoBehaviour +{ + public int playerId; + + public float moveSpeed = 3f; + + public float bulletSpeed = 15f; + + public GameObject bulletPrefab; + + private Player player; + + private CharacterController cc; + + private Vector3 moveVector; + + private bool fire; + + [NonSerialized] + private bool initialized; + + private void Awake() + { + cc = GetComponent(); + } + + private void Initialize() + { + player = ReInput.players.GetPlayer(playerId); + initialized = true; + } + + private void Update() + { + if (ReInput.isReady) + { + if (!initialized) + { + Initialize(); + } + GetInput(); + ProcessInput(); + } + } + + private void GetInput() + { + moveVector.x = player.GetAxis("Move Horizontal"); + moveVector.y = player.GetAxis("Move Vertical"); + fire = player.GetButtonDown("Fire"); + } + + private void ProcessInput() + { + if (moveVector.x != 0f || moveVector.y != 0f) + { + cc.Move(moveVector * moveSpeed * Time.deltaTime); + } + if (fire) + { + UnityEngine.Object.Instantiate(bulletPrefab, base.transform.position + base.transform.right, base.transform.rotation).GetComponent().AddForce(base.transform.right * bulletSpeed, ForceMode.VelocityChange); + } + } +} diff --git a/Rewired/Rewired.Demos/FallbackJoystickIdentificationDemo.cs b/Rewired/Rewired.Demos/FallbackJoystickIdentificationDemo.cs new file mode 100644 index 0000000..3213b71 --- /dev/null +++ b/Rewired/Rewired.Demos/FallbackJoystickIdentificationDemo.cs @@ -0,0 +1,114 @@ +using System.Collections.Generic; +using UnityEngine; + +namespace Rewired.Demos; + +[AddComponentMenu("")] +public class FallbackJoystickIdentificationDemo : MonoBehaviour +{ + private const float windowWidth = 250f; + + private const float windowHeight = 250f; + + private const float inputDelay = 1f; + + private bool identifyRequired; + + private Queue joysticksToIdentify; + + private float nextInputAllowedTime; + + private GUIStyle style; + + private void Awake() + { + if (ReInput.unityJoystickIdentificationRequired) + { + ReInput.ControllerConnectedEvent += JoystickConnected; + ReInput.ControllerDisconnectedEvent += JoystickDisconnected; + IdentifyAllJoysticks(); + } + } + + private void JoystickConnected(ControllerStatusChangedEventArgs args) + { + IdentifyAllJoysticks(); + } + + private void JoystickDisconnected(ControllerStatusChangedEventArgs args) + { + IdentifyAllJoysticks(); + } + + public void IdentifyAllJoysticks() + { + Reset(); + if (ReInput.controllers.joystickCount != 0) + { + Joystick[] joysticks = ReInput.controllers.GetJoysticks(); + if (joysticks != null) + { + identifyRequired = true; + joysticksToIdentify = new Queue(joysticks); + SetInputDelay(); + } + } + } + + private void SetInputDelay() + { + nextInputAllowedTime = Time.time + 1f; + } + + private void OnGUI() + { + if (!identifyRequired) + { + return; + } + if (joysticksToIdentify == null || joysticksToIdentify.Count == 0) + { + Reset(); + return; + } + Rect screenRect = new Rect((float)Screen.width * 0.5f - 125f, (float)Screen.height * 0.5f - 125f, 250f, 250f); + GUILayout.Window(0, screenRect, DrawDialogWindow, "Joystick Identification Required"); + GUI.FocusWindow(0); + if (!(Time.time < nextInputAllowedTime) && ReInput.controllers.SetUnityJoystickIdFromAnyButtonOrAxisPress(joysticksToIdentify.Peek().id, 0.8f, positiveAxesOnly: false)) + { + joysticksToIdentify.Dequeue(); + SetInputDelay(); + if (joysticksToIdentify.Count == 0) + { + Reset(); + } + } + } + + private void DrawDialogWindow(int windowId) + { + if (identifyRequired) + { + if (style == null) + { + style = new GUIStyle(GUI.skin.label); + style.wordWrap = true; + } + GUILayout.Space(15f); + GUILayout.Label("A joystick has been attached or removed. You will need to identify each joystick by pressing a button on the controller listed below:", style); + Joystick joystick = joysticksToIdentify.Peek(); + GUILayout.Label("Press any button on \"" + joystick.name + "\" now.", style); + GUILayout.FlexibleSpace(); + if (GUILayout.Button("Skip")) + { + joysticksToIdentify.Dequeue(); + } + } + } + + private void Reset() + { + joysticksToIdentify = null; + identifyRequired = false; + } +} diff --git a/Rewired/Rewired.Demos/PlayerMouseSpriteExample.cs b/Rewired/Rewired.Demos/PlayerMouseSpriteExample.cs new file mode 100644 index 0000000..194fb5d --- /dev/null +++ b/Rewired/Rewired.Demos/PlayerMouseSpriteExample.cs @@ -0,0 +1,116 @@ +using System; +using UnityEngine; + +namespace Rewired.Demos; + +[AddComponentMenu("")] +public class PlayerMouseSpriteExample : MonoBehaviour +{ + [Tooltip("The Player that will control the mouse")] + public int playerId; + + [Tooltip("The Rewired Action used for the mouse horizontal axis.")] + public string horizontalAction = "MouseX"; + + [Tooltip("The Rewired Action used for the mouse vertical axis.")] + public string verticalAction = "MouseY"; + + [Tooltip("The Rewired Action used for the mouse wheel axis.")] + public string wheelAction = "MouseWheel"; + + [Tooltip("The Rewired Action used for the mouse left button.")] + public string leftButtonAction = "MouseLeftButton"; + + [Tooltip("The Rewired Action used for the mouse right button.")] + public string rightButtonAction = "MouseRightButton"; + + [Tooltip("The Rewired Action used for the mouse middle button.")] + public string middleButtonAction = "MouseMiddleButton"; + + [Tooltip("The distance from the camera that the pointer will be drawn.")] + public float distanceFromCamera = 1f; + + [Tooltip("The scale of the sprite pointer.")] + public float spriteScale = 0.05f; + + [Tooltip("The pointer prefab.")] + public GameObject pointerPrefab; + + [Tooltip("The click effect prefab.")] + public GameObject clickEffectPrefab; + + [Tooltip("Should the hardware pointer be hidden?")] + public bool hideHardwarePointer = true; + + [NonSerialized] + private GameObject pointer; + + [NonSerialized] + private PlayerMouse mouse; + + private void Awake() + { + pointer = UnityEngine.Object.Instantiate(pointerPrefab); + pointer.transform.localScale = new Vector3(spriteScale, spriteScale, spriteScale); + if (hideHardwarePointer) + { + Cursor.visible = false; + } + mouse = PlayerMouse.Factory.Create(); + mouse.playerId = playerId; + mouse.xAxis.actionName = horizontalAction; + mouse.yAxis.actionName = verticalAction; + mouse.wheel.yAxis.actionName = wheelAction; + mouse.leftButton.actionName = leftButtonAction; + mouse.rightButton.actionName = rightButtonAction; + mouse.middleButton.actionName = middleButtonAction; + mouse.pointerSpeed = 1f; + mouse.wheel.yAxis.repeatRate = 5f; + mouse.screenPosition = new Vector2((float)Screen.width * 0.5f, (float)Screen.height * 0.5f); + mouse.ScreenPositionChangedEvent += OnScreenPositionChanged; + OnScreenPositionChanged(mouse.screenPosition); + } + + private void Update() + { + if (ReInput.isReady) + { + pointer.transform.Rotate(Vector3.forward, mouse.wheel.yAxis.value * 20f); + if (mouse.leftButton.justPressed) + { + CreateClickEffect(new Color(0f, 1f, 0f, 1f)); + } + if (mouse.rightButton.justPressed) + { + CreateClickEffect(new Color(1f, 0f, 0f, 1f)); + } + if (mouse.middleButton.justPressed) + { + CreateClickEffect(new Color(1f, 1f, 0f, 1f)); + } + } + } + + private void OnDestroy() + { + if (ReInput.isReady) + { + mouse.ScreenPositionChangedEvent -= OnScreenPositionChanged; + } + } + + private void CreateClickEffect(Color color) + { + GameObject obj = UnityEngine.Object.Instantiate(clickEffectPrefab); + obj.transform.localScale = new Vector3(spriteScale, spriteScale, spriteScale); + obj.transform.position = Camera.main.ScreenToWorldPoint(new Vector3(mouse.screenPosition.x, mouse.screenPosition.y, distanceFromCamera)); + obj.GetComponentInChildren().color = color; + UnityEngine.Object.Destroy(obj, 0.5f); + } + + private void OnScreenPositionChanged(Vector2 position) + { + Vector3 position2 = Camera.main.ScreenToWorldPoint(new Vector3(position.x, position.y, distanceFromCamera)); + pointer.transform.position = position2; + } +} diff --git a/Rewired/Rewired.Demos/PlayerPointerEventHandlerExample.cs b/Rewired/Rewired.Demos/PlayerPointerEventHandlerExample.cs new file mode 100644 index 0000000..dde8871 --- /dev/null +++ b/Rewired/Rewired.Demos/PlayerPointerEventHandlerExample.cs @@ -0,0 +1,138 @@ +using System.Collections.Generic; +using System.Text; +using Rewired.Integration.UnityUI; +using UnityEngine; +using UnityEngine.EventSystems; +using UnityEngine.UI; + +namespace Rewired.Demos; + +[AddComponentMenu("")] +public sealed class PlayerPointerEventHandlerExample : MonoBehaviour, IPointerEnterHandler, IEventSystemHandler, IPointerExitHandler, IPointerUpHandler, IPointerDownHandler, IPointerClickHandler, IScrollHandler, IBeginDragHandler, IDragHandler, IEndDragHandler +{ + public Text text; + + private const int logLength = 10; + + private List log = new List(); + + private void Log(string o) + { + log.Add(o); + if (log.Count > 10) + { + log.RemoveAt(0); + } + } + + private void Update() + { + if (!(text != null)) + { + return; + } + StringBuilder stringBuilder = new StringBuilder(); + foreach (string item in log) + { + stringBuilder.AppendLine(item); + } + text.text = stringBuilder.ToString(); + } + + public void OnPointerEnter(PointerEventData eventData) + { + if (eventData is PlayerPointerEventData) + { + PlayerPointerEventData playerPointerEventData = (PlayerPointerEventData)eventData; + Log("OnPointerEnter: Player = " + playerPointerEventData.playerId + ", Pointer Index = " + playerPointerEventData.inputSourceIndex + ", Source = " + GetSourceName(playerPointerEventData)); + } + } + + public void OnPointerExit(PointerEventData eventData) + { + if (eventData is PlayerPointerEventData) + { + PlayerPointerEventData playerPointerEventData = (PlayerPointerEventData)eventData; + Log("OnPointerExit: Player = " + playerPointerEventData.playerId + ", Pointer Index = " + playerPointerEventData.inputSourceIndex + ", Source = " + GetSourceName(playerPointerEventData)); + } + } + + public void OnPointerUp(PointerEventData eventData) + { + if (eventData is PlayerPointerEventData) + { + PlayerPointerEventData playerPointerEventData = (PlayerPointerEventData)eventData; + Log("OnPointerUp: Player = " + playerPointerEventData.playerId + ", Pointer Index = " + playerPointerEventData.inputSourceIndex + ", Source = " + GetSourceName(playerPointerEventData) + ", Button Index = " + playerPointerEventData.buttonIndex); + } + } + + public void OnPointerDown(PointerEventData eventData) + { + if (eventData is PlayerPointerEventData) + { + PlayerPointerEventData playerPointerEventData = (PlayerPointerEventData)eventData; + Log("OnPointerDown: Player = " + playerPointerEventData.playerId + ", Pointer Index = " + playerPointerEventData.inputSourceIndex + ", Source = " + GetSourceName(playerPointerEventData) + ", Button Index = " + playerPointerEventData.buttonIndex); + } + } + + public void OnPointerClick(PointerEventData eventData) + { + if (eventData is PlayerPointerEventData) + { + PlayerPointerEventData playerPointerEventData = (PlayerPointerEventData)eventData; + Log("OnPointerClick: Player = " + playerPointerEventData.playerId + ", Pointer Index = " + playerPointerEventData.inputSourceIndex + ", Source = " + GetSourceName(playerPointerEventData) + ", Button Index = " + playerPointerEventData.buttonIndex); + } + } + + public void OnScroll(PointerEventData eventData) + { + if (eventData is PlayerPointerEventData) + { + PlayerPointerEventData playerPointerEventData = (PlayerPointerEventData)eventData; + Log("OnScroll: Player = " + playerPointerEventData.playerId + ", Pointer Index = " + playerPointerEventData.inputSourceIndex + ", Source = " + GetSourceName(playerPointerEventData)); + } + } + + public void OnBeginDrag(PointerEventData eventData) + { + if (eventData is PlayerPointerEventData) + { + PlayerPointerEventData playerPointerEventData = (PlayerPointerEventData)eventData; + Log("OnBeginDrag: Player = " + playerPointerEventData.playerId + ", Pointer Index = " + playerPointerEventData.inputSourceIndex + ", Source = " + GetSourceName(playerPointerEventData) + ", Button Index = " + playerPointerEventData.buttonIndex); + } + } + + public void OnDrag(PointerEventData eventData) + { + if (eventData is PlayerPointerEventData) + { + PlayerPointerEventData playerPointerEventData = (PlayerPointerEventData)eventData; + Log("OnDrag: Player = " + playerPointerEventData.playerId + ", Pointer Index = " + playerPointerEventData.inputSourceIndex + ", Source = " + GetSourceName(playerPointerEventData) + ", Button Index = " + playerPointerEventData.buttonIndex); + } + } + + public void OnEndDrag(PointerEventData eventData) + { + if (eventData is PlayerPointerEventData) + { + PlayerPointerEventData playerPointerEventData = (PlayerPointerEventData)eventData; + Log("OnEndDrag: Player = " + playerPointerEventData.playerId + ", Pointer Index = " + playerPointerEventData.inputSourceIndex + ", Source = " + GetSourceName(playerPointerEventData) + ", Button Index = " + playerPointerEventData.buttonIndex); + } + } + + private static string GetSourceName(PlayerPointerEventData playerEventData) + { + if (playerEventData.sourceType == PointerEventType.Mouse) + { + if (playerEventData.mouseSource is Behaviour) + { + return (playerEventData.mouseSource as Behaviour).name; + } + } + else if (playerEventData.sourceType == PointerEventType.Touch && playerEventData.touchSource is Behaviour) + { + return (playerEventData.touchSource as Behaviour).name; + } + return null; + } +} diff --git a/Rewired/Rewired.Demos/PressAnyButtonToJoinExample_Assigner.cs b/Rewired/Rewired.Demos/PressAnyButtonToJoinExample_Assigner.cs new file mode 100644 index 0000000..83c25e8 --- /dev/null +++ b/Rewired/Rewired.Demos/PressAnyButtonToJoinExample_Assigner.cs @@ -0,0 +1,57 @@ +using System.Collections.Generic; +using UnityEngine; + +namespace Rewired.Demos; + +[AddComponentMenu("")] +public class PressAnyButtonToJoinExample_Assigner : MonoBehaviour +{ + private void Update() + { + if (ReInput.isReady) + { + AssignJoysticksToPlayers(); + } + } + + private void AssignJoysticksToPlayers() + { + IList joysticks = ReInput.controllers.Joysticks; + for (int i = 0; i < joysticks.Count; i++) + { + Joystick joystick = joysticks[i]; + if (!ReInput.controllers.IsControllerAssigned(joystick.type, joystick.id) && joystick.GetAnyButtonDown()) + { + Player player = FindPlayerWithoutJoystick(); + if (player == null) + { + return; + } + player.controllers.AddController(joystick, removeFromOtherPlayers: false); + } + } + if (DoAllPlayersHaveJoysticks()) + { + ReInput.configuration.autoAssignJoysticks = true; + base.enabled = false; + } + } + + private Player FindPlayerWithoutJoystick() + { + IList players = ReInput.players.Players; + for (int i = 0; i < players.Count; i++) + { + if (players[i].controllers.joystickCount <= 0) + { + return players[i]; + } + } + return null; + } + + private bool DoAllPlayersHaveJoysticks() + { + return FindPlayerWithoutJoystick() == null; + } +} diff --git a/Rewired/Rewired.Demos/PressAnyButtonToJoinExample_GamePlayer.cs b/Rewired/Rewired.Demos/PressAnyButtonToJoinExample_GamePlayer.cs new file mode 100644 index 0000000..a0466ce --- /dev/null +++ b/Rewired/Rewired.Demos/PressAnyButtonToJoinExample_GamePlayer.cs @@ -0,0 +1,67 @@ +using UnityEngine; + +namespace Rewired.Demos; + +[AddComponentMenu("")] +[RequireComponent(typeof(CharacterController))] +public class PressAnyButtonToJoinExample_GamePlayer : MonoBehaviour +{ + public int playerId; + + public float moveSpeed = 3f; + + public float bulletSpeed = 15f; + + public GameObject bulletPrefab; + + private CharacterController cc; + + private Vector3 moveVector; + + private bool fire; + + private Player player + { + get + { + if (!ReInput.isReady) + { + return null; + } + return ReInput.players.GetPlayer(playerId); + } + } + + private void OnEnable() + { + cc = GetComponent(); + } + + private void Update() + { + if (ReInput.isReady && player != null) + { + GetInput(); + ProcessInput(); + } + } + + private void GetInput() + { + moveVector.x = player.GetAxis("Move Horizontal"); + moveVector.y = player.GetAxis("Move Vertical"); + fire = player.GetButtonDown("Fire"); + } + + private void ProcessInput() + { + if (moveVector.x != 0f || moveVector.y != 0f) + { + cc.Move(moveVector * moveSpeed * Time.deltaTime); + } + if (fire) + { + Object.Instantiate(bulletPrefab, base.transform.position + base.transform.right, base.transform.rotation).GetComponent().AddForce(base.transform.right * bulletSpeed, ForceMode.VelocityChange); + } + } +} diff --git a/Rewired/Rewired.Demos/PressStartToJoinExample_Assigner.cs b/Rewired/Rewired.Demos/PressStartToJoinExample_Assigner.cs new file mode 100644 index 0000000..6b23589 --- /dev/null +++ b/Rewired/Rewired.Demos/PressStartToJoinExample_Assigner.cs @@ -0,0 +1,87 @@ +using System.Collections.Generic; +using UnityEngine; + +namespace Rewired.Demos; + +[AddComponentMenu("")] +public class PressStartToJoinExample_Assigner : MonoBehaviour +{ + private class PlayerMap + { + public int rewiredPlayerId; + + public int gamePlayerId; + + public PlayerMap(int rewiredPlayerId, int gamePlayerId) + { + this.rewiredPlayerId = rewiredPlayerId; + this.gamePlayerId = gamePlayerId; + } + } + + private static PressStartToJoinExample_Assigner instance; + + public int maxPlayers = 4; + + private List playerMap; + + private int gamePlayerIdCounter; + + public static Player GetRewiredPlayer(int gamePlayerId) + { + if (!ReInput.isReady) + { + return null; + } + if (instance == null) + { + Debug.LogError("Not initialized. Do you have a PressStartToJoinPlayerSelector in your scehe?"); + return null; + } + for (int i = 0; i < instance.playerMap.Count; i++) + { + if (instance.playerMap[i].gamePlayerId == gamePlayerId) + { + return ReInput.players.GetPlayer(instance.playerMap[i].rewiredPlayerId); + } + } + return null; + } + + private void Awake() + { + playerMap = new List(); + instance = this; + } + + private void Update() + { + for (int i = 0; i < ReInput.players.playerCount; i++) + { + if (ReInput.players.GetPlayer(i).GetButtonDown("JoinGame")) + { + AssignNextPlayer(i); + } + } + } + + private void AssignNextPlayer(int rewiredPlayerId) + { + if (playerMap.Count >= maxPlayers) + { + Debug.LogError("Max player limit already reached!"); + return; + } + int nextGamePlayerId = GetNextGamePlayerId(); + playerMap.Add(new PlayerMap(rewiredPlayerId, nextGamePlayerId)); + Player player = ReInput.players.GetPlayer(rewiredPlayerId); + player.controllers.maps.SetMapsEnabled(state: false, "Assignment"); + player.controllers.maps.SetMapsEnabled(state: true, "Default"); + Debug.Log("Added Rewired Player id " + rewiredPlayerId + " to game player " + nextGamePlayerId); + } + + private int GetNextGamePlayerId() + { + return gamePlayerIdCounter++; + } +} diff --git a/Rewired/Rewired.Demos/PressStartToJoinExample_GamePlayer.cs b/Rewired/Rewired.Demos/PressStartToJoinExample_GamePlayer.cs new file mode 100644 index 0000000..04ee6c4 --- /dev/null +++ b/Rewired/Rewired.Demos/PressStartToJoinExample_GamePlayer.cs @@ -0,0 +1,57 @@ +using UnityEngine; + +namespace Rewired.Demos; + +[AddComponentMenu("")] +[RequireComponent(typeof(CharacterController))] +public class PressStartToJoinExample_GamePlayer : MonoBehaviour +{ + public int gamePlayerId; + + public float moveSpeed = 3f; + + public float bulletSpeed = 15f; + + public GameObject bulletPrefab; + + private CharacterController cc; + + private Vector3 moveVector; + + private bool fire; + + private Player player => PressStartToJoinExample_Assigner.GetRewiredPlayer(gamePlayerId); + + private void OnEnable() + { + cc = GetComponent(); + } + + private void Update() + { + if (ReInput.isReady && player != null) + { + GetInput(); + ProcessInput(); + } + } + + private void GetInput() + { + moveVector.x = player.GetAxis("Move Horizontal"); + moveVector.y = player.GetAxis("Move Vertical"); + fire = player.GetButtonDown("Fire"); + } + + private void ProcessInput() + { + if (moveVector.x != 0f || moveVector.y != 0f) + { + cc.Move(moveVector * moveSpeed * Time.deltaTime); + } + if (fire) + { + Object.Instantiate(bulletPrefab, base.transform.position + base.transform.right, base.transform.rotation).GetComponent().AddForce(base.transform.right * bulletSpeed, ForceMode.VelocityChange); + } + } +} diff --git a/Rewired/Rewired.Demos/SimpleCombinedKeyboardMouseRemapping.cs b/Rewired/Rewired.Demos/SimpleCombinedKeyboardMouseRemapping.cs new file mode 100644 index 0000000..3a2544b --- /dev/null +++ b/Rewired/Rewired.Demos/SimpleCombinedKeyboardMouseRemapping.cs @@ -0,0 +1,225 @@ +using System.Collections; +using System.Collections.Generic; +using UnityEngine; +using UnityEngine.UI; + +namespace Rewired.Demos; + +[AddComponentMenu("")] +public class SimpleCombinedKeyboardMouseRemapping : MonoBehaviour +{ + private class Row + { + public InputAction action; + + public AxisRange actionRange; + + public Button button; + + public Text text; + } + + private struct TargetMapping + { + public ControllerMap controllerMap; + + public int actionElementMapId; + } + + private const string category = "Default"; + + private const string layout = "Default"; + + private const string uiCategory = "UI"; + + private InputMapper inputMapper_keyboard = new InputMapper(); + + private InputMapper inputMapper_mouse = new InputMapper(); + + public GameObject buttonPrefab; + + public GameObject textPrefab; + + public RectTransform fieldGroupTransform; + + public RectTransform actionGroupTransform; + + public Text controllerNameUIText; + + public Text statusUIText; + + private List rows = new List(); + + private TargetMapping _replaceTargetMapping; + + private Player player => ReInput.players.GetPlayer(0); + + private void OnEnable() + { + if (ReInput.isReady) + { + inputMapper_keyboard.options.timeout = 5f; + inputMapper_mouse.options.timeout = 5f; + inputMapper_mouse.options.ignoreMouseXAxis = true; + inputMapper_mouse.options.ignoreMouseYAxis = true; + inputMapper_keyboard.options.allowButtonsOnFullAxisAssignment = false; + inputMapper_mouse.options.allowButtonsOnFullAxisAssignment = false; + inputMapper_keyboard.InputMappedEvent += OnInputMapped; + inputMapper_keyboard.StoppedEvent += OnStopped; + inputMapper_mouse.InputMappedEvent += OnInputMapped; + inputMapper_mouse.StoppedEvent += OnStopped; + InitializeUI(); + } + } + + private void OnDisable() + { + inputMapper_keyboard.Stop(); + inputMapper_mouse.Stop(); + inputMapper_keyboard.RemoveAllEventListeners(); + inputMapper_mouse.RemoveAllEventListeners(); + } + + private void RedrawUI() + { + controllerNameUIText.text = "Keyboard/Mouse"; + for (int i = 0; i < rows.Count; i++) + { + Row row = rows[i]; + InputAction action = rows[i].action; + string text = string.Empty; + int actionElementMapId = -1; + for (int j = 0; j < 2; j++) + { + ControllerType controllerType = ((j != 0) ? ControllerType.Mouse : ControllerType.Keyboard); + foreach (ActionElementMap item in player.controllers.maps.GetMap(controllerType, 0, "Default", "Default").ElementMapsWithAction(action.id)) + { + if (item.ShowInField(row.actionRange)) + { + text = item.elementIdentifierName; + actionElementMapId = item.id; + break; + } + } + if (actionElementMapId >= 0) + { + break; + } + } + row.text.text = text; + row.button.onClick.RemoveAllListeners(); + int index = i; + row.button.onClick.AddListener(delegate + { + OnInputFieldClicked(index, actionElementMapId); + }); + } + } + + private void ClearUI() + { + controllerNameUIText.text = string.Empty; + for (int i = 0; i < rows.Count; i++) + { + rows[i].text.text = string.Empty; + } + } + + private void InitializeUI() + { + foreach (Transform item in actionGroupTransform) + { + Object.Destroy(item.gameObject); + } + foreach (Transform item2 in fieldGroupTransform) + { + Object.Destroy(item2.gameObject); + } + foreach (InputAction item3 in ReInput.mapping.ActionsInCategory("Default")) + { + if (item3.type == InputActionType.Axis) + { + CreateUIRow(item3, AxisRange.Full, item3.descriptiveName); + CreateUIRow(item3, AxisRange.Positive, (!string.IsNullOrEmpty(item3.positiveDescriptiveName)) ? item3.positiveDescriptiveName : (item3.descriptiveName + " +")); + CreateUIRow(item3, AxisRange.Negative, (!string.IsNullOrEmpty(item3.negativeDescriptiveName)) ? item3.negativeDescriptiveName : (item3.descriptiveName + " -")); + } + else if (item3.type == InputActionType.Button) + { + CreateUIRow(item3, AxisRange.Positive, item3.descriptiveName); + } + } + RedrawUI(); + } + + private void CreateUIRow(InputAction action, AxisRange actionRange, string label) + { + GameObject obj = Object.Instantiate(textPrefab); + obj.transform.SetParent(actionGroupTransform); + obj.transform.SetAsLastSibling(); + obj.GetComponent().text = label; + GameObject gameObject = Object.Instantiate(buttonPrefab); + gameObject.transform.SetParent(fieldGroupTransform); + gameObject.transform.SetAsLastSibling(); + rows.Add(new Row + { + action = action, + actionRange = actionRange, + button = gameObject.GetComponent