void Update() { // Don't process game manager input messages when game not running if (!IsPlayingGame()) { return; } // Post message to open options dialog on escape during gameplay if (InputManager.Instance.ActionComplete(InputManager.Actions.Escape)) { DaggerfallUI.PostMessage(DaggerfallUIMessages.dfuiOpenPauseOptionsDialog); } // Handle in-game windows if (InputManager.Instance.ActionComplete(InputManager.Actions.CharacterSheet)) { DaggerfallUI.PostMessage(DaggerfallUIMessages.dfuiOpenCharacterSheetWindow); } else if (InputManager.Instance.ActionComplete(InputManager.Actions.Inventory)) { DaggerfallUI.PostMessage(DaggerfallUIMessages.dfuiOpenInventoryWindow); } else if (InputManager.Instance.ActionComplete(InputManager.Actions.TravelMap)) { DaggerfallUI.PostMessage(DaggerfallUIMessages.dfuiOpenTravelMapWindow); } else if (InputManager.Instance.ActionComplete(InputManager.Actions.Rest)) { DaggerfallUI.PostMessage(DaggerfallUIMessages.dfuiOpenRestWindow); } else if (InputManager.Instance.ActionComplete(InputManager.Actions.Transport)) { DaggerfallUI.PostMessage(DaggerfallUIMessages.dfuiOpenTransportWindow); } else if (InputManager.Instance.ActionComplete(InputManager.Actions.LogBook)) { DaggerfallUI.PostMessage(DaggerfallUIMessages.dfuiOpenQuestJournalWindow); } else if (InputManager.Instance.ActionComplete(InputManager.Actions.NoteBook)) { DaggerfallUI.PostMessage(DaggerfallUIMessages.dfuiOpenNotebookWindow); } else if (InputManager.Instance.ActionComplete(InputManager.Actions.CastSpell)) { DaggerfallUI.PostMessage(DaggerfallUIMessages.dfuiOpenSpellBookWindow); } else if (InputManager.Instance.ActionComplete(InputManager.Actions.UseMagicItem)) { DaggerfallUI.PostMessage(DaggerfallUIMessages.dfuiOpenUseMagicItemWindow); } if (InputManager.Instance.ActionComplete(InputManager.Actions.Status)) { DaggerfallUI.PostMessage(DaggerfallUIMessages.dfuiStatusInfo); } if (InputManager.Instance.ActionComplete(InputManager.Actions.AutoMap)) { DaggerfallUI.PostMessage(DaggerfallUIMessages.dfuiOpenAutomap); } // Handle quick save and load if (InputManager.Instance.ActionStarted(InputManager.Actions.QuickSave)) { if (SaveLoadManager.IsSavingPrevented) { DaggerfallUI.MessageBox(TextManager.Instance.GetLocalizedText("cannotSaveNow")); } else { SaveLoadManager.Instance.QuickSave(); } } else if (InputManager.Instance.ActionStarted(InputManager.Actions.QuickLoad)) { if (SaveLoadManager.Instance.HasQuickSave(GameManager.Instance.PlayerEntity.Name)) { GameManager.Instance.SaveLoadManager.PromptQuickLoadGame(GameManager.Instance.PlayerEntity.Name, () => { SaveLoadManager.Instance.QuickLoad(); }); } } }
void Update() { if (!dfUnity.IsReady || !playerEnterExit || !PlayerTorch || playerEntity == null || GameManager.IsGamePaused) { return; } bool enableTorch = false; if (DaggerfallUnity.Settings.PlayerTorchFromItems) { DaggerfallUnityItem lightSource = playerEntity.LightSource; if (lightSource != null) { enableTorch = true; torchLight.range = lightSource.ItemTemplate.capacityOrTarget; // Consume durability / fuel if (Time.realtimeSinceStartup > lastTickTime + tickTimeInterval) { lastTickTime = Time.realtimeSinceStartup; if (lightSource.currentCondition > 0) { lightSource.currentCondition--; } if (lightSource.currentCondition == 0 && DaggerfallUnityItem.CompareItems(playerEntity.LightSource, lightSource)) { DaggerfallUI.MessageBox(TextManager.Instance.GetText(textDatabase, "lightDies"), false, lightSource); enableTorch = false; playerEntity.LightSource = null; if (!lightSource.IsOfTemplate(ItemGroups.UselessItems2, (int)UselessItems2.Lantern)) { playerEntity.Items.RemoveItem(lightSource); } } } if (lightSource.currentCondition < 3) { // Give warning signs if running low of fuel intensityMod = 0.6f + (Mathf.Cos(guttering) * 0.2f); guttering += Random.Range(-0.02f, 0.06f); } else { intensityMod = 1; guttering = 0; } } } else { enableTorch = (!playerEnterExit.IsPlayerInside && dfUnity.WorldTime.Now.IsCityLightsOn) || playerEnterExit.IsPlayerInsideDungeon; } if (torchLight) { torchLight.intensity = torchIntensity * DaggerfallUnity.Settings.PlayerTorchLightScale * intensityMod; } PlayerTorch.SetActive(enableTorch); }
void Update() { if (mainCamera == null) { return; } // Change activate mode if (InputManager.Instance.ActionStarted(InputManager.Actions.StealMode)) { ChangeInteractionMode(PlayerActivateModes.Steal); } else if (InputManager.Instance.ActionStarted(InputManager.Actions.GrabMode)) { ChangeInteractionMode(PlayerActivateModes.Grab); } else if (InputManager.Instance.ActionStarted(InputManager.Actions.InfoMode)) { ChangeInteractionMode(PlayerActivateModes.Info); } else if (InputManager.Instance.ActionStarted(InputManager.Actions.TalkMode)) { ChangeInteractionMode(PlayerActivateModes.Talk); } // Fire ray into scene if (InputManager.Instance.ActionStarted(InputManager.Actions.ActivateCenterObject)) { // TODO: Clean all this up // Ray origin is slightly below camera height to ensure it originates inside player's own collider // This prevents ray from intersecting with player's own collider and blocking looting or low triggers Ray ray = new Ray(transform.position + Vector3.up * 0.7f, mainCamera.transform.forward); RaycastHit hit; RayDistance = 75f; // Approximates classic at full view distance (default setting). Classic seems to do raycasts for as far as it can render objects. bool hitSomething = Physics.Raycast(ray, out hit, RayDistance); if (hitSomething) { bool hitBuilding = false; bool buildingUnlocked = false; DFLocation.BuildingTypes buildingType = DFLocation.BuildingTypes.AllValid; StaticBuilding building = new StaticBuilding(); #region Hit Checks // Trigger quest resource behaviour click on anything but NPCs QuestResourceBehaviour questResourceBehaviour; if (QuestResourceBehaviourCheck(hit, out questResourceBehaviour)) { if (!(questResourceBehaviour.TargetResource is Person)) { if (hit.distance > (DefaultActivationDistance * MeshReader.GlobalScale)) { DaggerfallUI.SetMidScreenText(HardStrings.youAreTooFarAway); return; } // Only trigger click when not in info mode if (currentMode != PlayerActivateModes.Info) { TriggerQuestResourceBehaviourClick(questResourceBehaviour); } } } // Check for a static building hit Transform buildingOwner; DaggerfallStaticBuildings buildings = GetBuildings(hit.transform, out buildingOwner); if (buildings) { if (buildings.HasHit(hit.point, out building)) { hitBuilding = true; // Get building directory for location BuildingDirectory buildingDirectory = GameManager.Instance.StreamingWorld.GetCurrentBuildingDirectory(); if (!buildingDirectory) { return; } // Get detailed building data from directory BuildingSummary buildingSummary; if (!buildingDirectory.GetBuildingSummary(building.buildingKey, out buildingSummary)) { return; } // Check if door is unlocked buildingUnlocked = BuildingIsUnlocked(buildingSummary); // Store building type buildingType = buildingSummary.BuildingType; if (currentMode == PlayerActivateModes.Info) { // Discover building GameManager.Instance.PlayerGPS.DiscoverBuilding(building.buildingKey); // Get discovered building PlayerGPS.DiscoveredBuilding db; if (GameManager.Instance.PlayerGPS.GetDiscoveredBuilding(building.buildingKey, out db)) { // TODO: Check against quest system for an overriding quest-assigned display name for this building DaggerfallUI.AddHUDText(db.displayName); if (!buildingUnlocked && buildingType < DFLocation.BuildingTypes.Temple && buildingType != DFLocation.BuildingTypes.HouseForSale) { string storeClosedMessage = HardStrings.storeClosed; storeClosedMessage = storeClosedMessage.Replace("%d1", openHours[(int)buildingType].ToString()); storeClosedMessage = storeClosedMessage.Replace("%d2", closeHours[(int)buildingType].ToString()); DaggerfallUI.Instance.PopupMessage(storeClosedMessage); } } } } } // Check for a static door hit Transform doorOwner; DaggerfallStaticDoors doors = GetDoors(hit.transform, out doorOwner); if (doors && playerEnterExit) { StaticDoor door; if (doors.HasHit(hit.point, out door)) { // Check if close enough to activate if (hit.distance > (DoorActivationDistance * MeshReader.GlobalScale)) { DaggerfallUI.SetMidScreenText(HardStrings.youAreTooFarAway); return; } if (door.doorType == DoorTypes.Building && !playerEnterExit.IsPlayerInside) { // Discover building GameManager.Instance.PlayerGPS.DiscoverBuilding(building.buildingKey); // TODO: Implement lockpicking and door bashing for exterior doors // For now, any locked building door can be entered by using steal mode if (!buildingUnlocked) { if (currentMode != PlayerActivateModes.Steal) { string Locked = "Locked."; DaggerfallUI.Instance.PopupMessage(Locked); return; } else // Breaking into building { PlayerEntity player = GameManager.Instance.PlayerEntity; //player.TallyCrimeGuildRequirements(true, 1); } } // If entering a shop let player know the quality level // If entering an open home, show greeting if (hitBuilding) { const int houseGreetingsTextId = 256; DaggerfallMessageBox mb; if (buildingUnlocked && buildingType >= DFLocation.BuildingTypes.House1 && buildingType <= DFLocation.BuildingTypes.House4) { string greetingText = DaggerfallUnity.Instance.TextProvider.GetRandomText(houseGreetingsTextId); mb = DaggerfallUI.MessageBox(greetingText); } else { mb = PresentShopQuality(building); } if (mb != null) { // Defer transition to interior to after user closes messagebox deferredInteriorDoorOwner = doorOwner; deferredInteriorDoor = door; mb.OnClose += Popup_OnClose; return; } } // Hit door while outside, transition inside TransitionInterior(doorOwner, door, true); return; } else if (door.doorType == DoorTypes.Building && playerEnterExit.IsPlayerInside) { // Hit door while inside, transition outside playerEnterExit.TransitionExterior(true); return; } else if (door.doorType == DoorTypes.DungeonEntrance && !playerEnterExit.IsPlayerInside) { if (playerGPS) { // Hit dungeon door while outside, transition inside playerEnterExit.TransitionDungeonInterior(doorOwner, door, playerGPS.CurrentLocation, true); return; } } else if (door.doorType == DoorTypes.DungeonExit && playerEnterExit.IsPlayerInside) { // Hit dungeon exit while inside, ask if access wagon or transition outside if (GameManager.Instance.PlayerEntity.Items.Contains(ItemGroups.Transportation, (int)Transportation.Small_cart)) { DaggerfallMessageBox messageBox = new DaggerfallMessageBox(DaggerfallUI.UIManager, DaggerfallMessageBox.CommonMessageBoxButtons.YesNo, 38, DaggerfallUI.UIManager.TopWindow); messageBox.OnButtonClick += DungeonWagonAccess_OnButtonClick; DaggerfallUI.UIManager.PushWindow(messageBox); return; } else { playerEnterExit.TransitionDungeonExterior(true); } } } } // Check for an action door hit DaggerfallActionDoor actionDoor; if (ActionDoorCheck(hit, out actionDoor)) { // Check if close enough to activate if (hit.distance > (DoorActivationDistance * MeshReader.GlobalScale)) { DaggerfallUI.SetMidScreenText(HardStrings.youAreTooFarAway); return; } if (currentMode == PlayerActivateModes.Steal && actionDoor.IsLocked && !actionDoor.IsOpen) { actionDoor.AttemptLockpicking(); } else { actionDoor.ToggleDoor(true); } } // Check for action record hit DaggerfallAction action; if (ActionCheck(hit, out action)) { if (hit.distance <= (DefaultActivationDistance * MeshReader.GlobalScale)) { action.Receive(this.gameObject, DaggerfallAction.TriggerTypes.Direct); } } // Check for lootable object hit DaggerfallLoot loot; if (LootCheck(hit, out loot)) { switch (currentMode) { case PlayerActivateModes.Info: if (loot.ContainerType == LootContainerTypes.CorpseMarker && !string.IsNullOrEmpty(loot.entityName)) { string message = string.Empty; if (loot.isEnemyClass) { message = HardStrings.youSeeADeadPerson; } else { message = HardStrings.youSeeADead; message = message.Replace("%s", loot.entityName); } DaggerfallUI.Instance.PopupMessage(message); } break; case PlayerActivateModes.Grab: case PlayerActivateModes.Talk: case PlayerActivateModes.Steal: // Check if close enough to activate if (loot.ContainerType == LootContainerTypes.CorpseMarker) { if (hit.distance > CorpseActivationDistance * MeshReader.GlobalScale) { DaggerfallUI.SetMidScreenText(HardStrings.youAreTooFarAway); break; } } else if (hit.distance > TreasureActivationDistance * MeshReader.GlobalScale) { DaggerfallUI.SetMidScreenText(HardStrings.youAreTooFarAway); break; } // For bodies, check has treasure first if (loot.ContainerType == LootContainerTypes.CorpseMarker && loot.Items.Count == 0) { DaggerfallUI.AddHUDText(HardStrings.theBodyHasNoTreasure); break; } // Open inventory window with loot as remote target DaggerfallUI.Instance.InventoryWindow.LootTarget = loot; DaggerfallUI.PostMessage(DaggerfallUIMessages.dfuiOpenInventoryWindow); break; } } // Check for static NPC hit StaticNPC npc; if (NPCCheck(hit, out npc)) { switch (currentMode) { case PlayerActivateModes.Info: PresentNPCInfo(npc); break; case PlayerActivateModes.Grab: case PlayerActivateModes.Talk: case PlayerActivateModes.Steal: if (hit.distance > (StaticNPCActivationDistance * MeshReader.GlobalScale)) { DaggerfallUI.SetMidScreenText(HardStrings.youAreTooFarAway); break; } StaticNPCClick(npc); break; } } // Check for mobile NPC hit MobilePersonNPC mobileNpc = null; if (MobilePersonMotorCheck(hit, out mobileNpc)) { switch (currentMode) { case PlayerActivateModes.Info: case PlayerActivateModes.Grab: case PlayerActivateModes.Talk: if (hit.distance > (MobileNPCActivationDistance * MeshReader.GlobalScale)) { DaggerfallUI.SetMidScreenText(HardStrings.youAreTooFarAway); break; } GameManager.Instance.TalkManager.TalkToMobileNPC(mobileNpc); break; case PlayerActivateModes.Steal: if (!mobileNpc.PickpocketByPlayerAttempted) { if (hit.distance > (PickpocketDistance * MeshReader.GlobalScale)) { DaggerfallUI.SetMidScreenText(HardStrings.youAreTooFarAway); break; } mobileNpc.PickpocketByPlayerAttempted = true; Pickpocket(); } break; } } // Check for mobile enemy hit DaggerfallEntityBehaviour mobileEnemyBehaviour; if (MobileEnemyCheck(hit, out mobileEnemyBehaviour)) { EnemyEntity enemyEntity = mobileEnemyBehaviour.Entity as EnemyEntity; switch (currentMode) { case PlayerActivateModes.Info: case PlayerActivateModes.Grab: case PlayerActivateModes.Talk: if (enemyEntity != null) { MobileEnemy mobileEnemy = enemyEntity.MobileEnemy; bool startsWithVowel = "aeiouAEIOU".Contains(mobileEnemy.Name[0].ToString()); string message; if (startsWithVowel) { message = HardStrings.youSeeAn; } else { message = HardStrings.youSeeA; } message = message.Replace("%s", mobileEnemy.Name); DaggerfallUI.Instance.PopupMessage(message); } break; case PlayerActivateModes.Steal: // Classic allows pickpocketing of NPC mobiles and enemy mobiles. // In early versions the only enemy mobiles that can be pickpocketed are classes, // but patch 1.07.212 allows pickpocketing of creatures. // For now, the only enemy mobiles being allowed by DF Unity are classes. if (mobileEnemyBehaviour && (mobileEnemyBehaviour.EntityType != EntityTypes.EnemyClass)) { break; } // Classic doesn't set any flag when pickpocketing enemy mobiles, so infinite attempts are possible if (enemyEntity != null && !enemyEntity.PickpocketByPlayerAttempted) { if (hit.distance > (PickpocketDistance * MeshReader.GlobalScale)) { DaggerfallUI.SetMidScreenText(HardStrings.youAreTooFarAway); break; } enemyEntity.PickpocketByPlayerAttempted = true; Pickpocket(mobileEnemyBehaviour); } break; } } // Trigger ladder hit DaggerfallLadder ladder = hit.transform.GetComponent <DaggerfallLadder>(); if (ladder) { if (hit.distance > (DefaultActivationDistance * MeshReader.GlobalScale)) { DaggerfallUI.SetMidScreenText(HardStrings.youAreTooFarAway); return; } ladder.ClimbLadder(); } #endregion } } }
// Display a shop quality level private DaggerfallMessageBox PresentShopQuality(StaticBuilding building) { const int qualityLevel1TextId = 266; // "Incense and soft music soothe your nerves" const int qualityLevel2TextId = 267; // "The shop is better appointed than many" const int qualityLevel3TextId = 268; // "The shop is laid out in a practical" const int qualityLevel4TextId = 269; // "Sturdy shelves, cobbled together" const int qualityLevel5TextId = 270; // "Rusty relics lie wherever they were last tossed" // Get building directory for location BuildingDirectory buildingDirectory = GameManager.Instance.StreamingWorld.GetCurrentBuildingDirectory(); if (!buildingDirectory) { return(null); } // Get detailed building data from directory BuildingSummary buildingSummary; if (!buildingDirectory.GetBuildingSummary(building.buildingKey, out buildingSummary)) { return(null); } // Do nothing if not a shop if (!RMBLayout.IsShop(buildingSummary.BuildingType)) { return(null); } // Set quality level text ID from quality value 01-20 // UESP states this is building quality / 4 but Daggerfall uses manual thresholds int qualityTextId; if (buildingSummary.Quality <= 3) { qualityTextId = qualityLevel5TextId; // 01 - 03 } else if (buildingSummary.Quality <= 7) { qualityTextId = qualityLevel4TextId; // 04 - 07 } else if (buildingSummary.Quality <= 13) { qualityTextId = qualityLevel3TextId; // 08 - 13 } else if (buildingSummary.Quality <= 17) { qualityTextId = qualityLevel2TextId; // 14 - 17 } else { qualityTextId = qualityLevel1TextId; // 18 - 20 } // Log quality of building entered for debugging //Debug.Log("Entered store with quality of " + buildingData.Quality); // Output quality text based on settings switch (DaggerfallUnity.Settings.ShopQualityPresentation) { case 0: // Display popup as per classic return(DaggerfallUI.MessageBox(qualityTextId)); case 1: // Display HUD text only with variable delay TextFile.Token[] tokens = DaggerfallUnity.Instance.TextProvider.GetRSCTokens(qualityTextId); for (int i = 0; i < tokens.Length; i++) { if (tokens[i].formatting == TextFile.Formatting.Text) { DaggerfallUI.AddHUDText(tokens[i].text, DaggerfallUnity.Settings.ShopQualityHUDDelay); } } break; case 2: // Display nothing about shop quality default: return(null); } return(null); }
// Player has clicked on a pickpocket target in steal mode void Pickpocket(DaggerfallEntityBehaviour target = null) { const int foundNothingValuableTextId = 8999; PlayerEntity player = GameManager.Instance.PlayerEntity; EnemyEntity enemyEntity = null; if (target != null) { enemyEntity = target.Entity as EnemyEntity; } player.TallySkill(DFCareer.Skills.Pickpocket, 1); int chance = Formulas.FormulaHelper.CalculatePickpocketingChance(player, enemyEntity); if (UnityEngine.Random.Range(0, 101) <= chance) { if (UnityEngine.Random.Range(0, 101) >= 33) { int pinchedGoldPieces = UnityEngine.Random.Range(0, 6) + 1; player.GoldPieces += pinchedGoldPieces; string gotGold; if (pinchedGoldPieces == 1) { // Classic doesn't have this string, it only has the plural one gotGold = HardStrings.youPinchedGoldPiece; } else { gotGold = HardStrings.youPinchedGoldPieces; gotGold = gotGold.Replace("%d", pinchedGoldPieces.ToString()); } DaggerfallUI.MessageBox(gotGold); //player.TallyCrimeGuildRequirements(true, 1); } else { string noGoldFound = DaggerfallUnity.Instance.TextProvider.GetRandomText(foundNothingValuableTextId); DaggerfallUI.MessageBox(noGoldFound, true); } } else { string notSuccessfulMessage = HardStrings.youAreNotSuccessful; DaggerfallUI.Instance.PopupMessage(notSuccessfulMessage); // Make enemies in an area aggressive if player failed to pickpocket a non-hostile one. EnemyMotor enemyMotor = null; if (target != null) { enemyMotor = target.GetComponent <EnemyMotor>(); } if (enemyMotor) { if (!enemyMotor.IsHostile) { GameManager.Instance.MakeEnemiesHostile(); } enemyMotor.MakeEnemyHostileToPlayer(gameObject); } } }