private StaticBuilding AddBuildingPrerequisites(StaticBuilding building, string upgradesFrom, string upgradesTo, string buildingChain) { building.UpgradesFrom = upgradesFrom; building.UpgradesTo = upgradesTo; building.BuildingChain = buildingChain; //building.Prerequisites = prerequisites.ToList(); return(building); }
private StaticBuilding AddBuilding(string name, string tagName, StaticBuildingType buildingType, RequiredEnum requiredEnum, float goldCost, float maintance, int buildTime) { StaticBuilding building = new StaticBuilding(); building.Name = name; building.TagName = tagName; building.DataType = DataType.Building; building.BuildingType = buildingType; building.RequiredEnum = requiredEnum; building.DefaultGoldCost = goldCost; building.DefaultMaintenance = maintance; building.DefaultBuildTime = buildTime; return(building); }
// Output building info to HUD private void PresentBuildingInfo(StaticBuilding building) { // 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)) { int layoutX, layoutY, recordIndex; BuildingDirectory.ReverseBuildingKey(building.buildingKey, out layoutX, out layoutY, out recordIndex); Debug.LogFormat("Unable to find expected building key {0} in {1}.{2}", building.buildingKey, buildingDirectory.LocationData.RegionName, buildingDirectory.LocationData.Name); Debug.LogFormat("LayoutX={0}, LayoutY={1}, RecordIndex={2}", layoutX, layoutY, recordIndex); throw new Exception("Error finding building key in directory."); } // Resolve name by building type string buildingName; if (RMBLayout.IsResidence(buildingSummary.BuildingType)) { // Residence // TODO: Link to quest system active sites buildingName = HardStrings.residence; } else { // Fixed building name buildingName = BuildingNames.GetName( buildingSummary.NameSeed, buildingSummary.BuildingType, buildingSummary.FactionId, buildingDirectory.LocationData.Name, buildingDirectory.LocationData.RegionName); } // Output building name to HUD DaggerfallUI.AddHUDText(buildingName); }
private static void AddModels( DaggerfallUnity dfUnity, int layoutX, int layoutY, ref DFBlock blockData, out List <StaticDoor> doorsOut, out List <StaticBuilding> buildingsOut, ModelCombiner combiner = null, Transform parent = null) { doorsOut = new List <StaticDoor>(); buildingsOut = new List <StaticBuilding>(); // Iterate through all subrecords int recordCount = 0; foreach (DFBlock.RmbSubRecord subRecord in blockData.RmbBlock.SubRecords) { // Get subrecord transform Vector3 subRecordPosition = new Vector3(subRecord.XPos, 0, BlocksFile.RMBDimension - subRecord.ZPos) * MeshReader.GlobalScale; Vector3 subRecordRotation = new Vector3(0, -subRecord.YRotation / BlocksFile.RotationDivisor, 0); Matrix4x4 subRecordMatrix = Matrix4x4.TRS(subRecordPosition, Quaternion.Euler(subRecordRotation), Vector3.one); // Iterate through models in this subrecord bool firstModel = true; foreach (DFBlock.RmbBlock3dObjectRecord obj in subRecord.Exterior.Block3dObjectRecords) { // Get model transform Vector3 modelPosition = new Vector3(obj.XPos, -obj.YPos, obj.ZPos) * MeshReader.GlobalScale; Vector3 modelRotation = new Vector3(-obj.XRotation / BlocksFile.RotationDivisor, -obj.YRotation / BlocksFile.RotationDivisor, -obj.ZRotation / BlocksFile.RotationDivisor); Vector3 modelScale = GetModelScaleVector(obj); Matrix4x4 modelMatrix = subRecordMatrix * Matrix4x4.TRS(modelPosition, Quaternion.Euler(modelRotation), modelScale); // Get model data ModelData modelData; dfUnity.MeshReader.GetModelData(obj.ModelIdNum, out modelData); // Does this model have doors? StaticDoor[] staticDoors = null; if (modelData.Doors != null) { staticDoors = GameObjectHelper.GetStaticDoors(ref modelData, blockData.Index, recordCount, modelMatrix); } // Store building information for first model of record // First model is main record structure, others are attachments like posts // Only main structure is needed to resolve building after hit-test int buildingKey = 0; if (firstModel) { // Create building key for this record - considered experimental for now buildingKey = BuildingDirectory.MakeBuildingKey((byte)layoutX, (byte)layoutY, (byte)recordCount); StaticBuilding staticBuilding = new StaticBuilding(); staticBuilding.modelMatrix = modelMatrix; staticBuilding.recordIndex = recordCount; staticBuilding.centre = new Vector3(modelData.DFMesh.Centre.X, modelData.DFMesh.Centre.Y, modelData.DFMesh.Centre.Z) * MeshReader.GlobalScale; staticBuilding.size = new Vector3(modelData.DFMesh.Size.X, modelData.DFMesh.Size.Y, modelData.DFMesh.Size.Z) * MeshReader.GlobalScale; buildingsOut.Add(staticBuilding); firstModel = false; } bool dontCreateStaticDoors = false; // Import custom GameObject or use Daggerfall Model GameObject go; if (go = MeshReplacement.ImportCustomGameobject(obj.ModelIdNum, parent, modelMatrix)) { // Find doors if (staticDoors != null && staticDoors.Length > 0) { CustomDoor.InitDoors(go, staticDoors, buildingKey, out dontCreateStaticDoors); } } else if (combiner == null || IsCityGate(obj.ModelIdNum) || IsBulletinBoard(obj.ModelIdNum) || PlayerActivate.HasCustomActivation(obj.ModelIdNum)) { AddStandaloneModel(dfUnity, ref modelData, modelMatrix, parent); } else { combiner.Add(ref modelData, modelMatrix); } if (modelData.Doors != null && !dontCreateStaticDoors) { doorsOut.AddRange(staticDoors); } } // Increment record count recordCount++; } }
/// <summary> /// Instantiate base RMB block by DFBlock data. /// </summary> /// <param name="blockData">Block data.</param> /// <param name="layoutX">X coordinate in parent map layout.</param> /// /// <param name="layoutY">Y coordinate in parent map layout.</param> /// <param name="cloneFrom">Prefab to clone from.</param> /// <returns>Block GameObject.</returns> public static GameObject CreateBaseGameObject(ref DFBlock blockData, int layoutX, int layoutY, DaggerfallRMBBlock cloneFrom = null) { DaggerfallUnity dfUnity = DaggerfallUnity.Instance; if (!dfUnity.IsReady) { return(null); } // Create gameobject GameObject go; string name = string.Format("DaggerfallBlock [{0}]", blockData.Name); if (cloneFrom != null) { go = GameObjectHelper.InstantiatePrefab(cloneFrom.gameObject, name, null, Vector3.zero); } else { go = new GameObject(name); } // Setup combiner ModelCombiner combiner = null; if (dfUnity.Option_CombineRMB) { combiner = new ModelCombiner(); } // Lists to receive any doors found in this block List <StaticDoor> modelDoors; List <StaticDoor> propDoors; List <StaticBuilding> modelBuildings; // Add models and static props GameObject modelsNode = new GameObject("Models"); modelsNode.transform.parent = go.transform; AddModels(dfUnity, layoutX, layoutY, ref blockData, out modelDoors, out modelBuildings, combiner, modelsNode.transform); AddProps(dfUnity, ref blockData, out propDoors, combiner, modelsNode.transform); // Combine list of doors found in models and props List <StaticDoor> allDoors = new List <StaticDoor>(); if (modelDoors.Count > 0) { allDoors.AddRange(modelDoors); } if (propDoors.Count > 0) { allDoors.AddRange(propDoors); } // Assign building key to each door for (int i = 0; i < allDoors.Count; i++) { StaticDoor door = allDoors[i]; door.buildingKey = BuildingDirectory.MakeBuildingKey((byte)layoutX, (byte)layoutY, (byte)door.recordIndex); allDoors[i] = door; } // Assign building key to each building for (int i = 0; i < modelBuildings.Count; i++) { StaticBuilding building = modelBuildings[i]; building.buildingKey = BuildingDirectory.MakeBuildingKey((byte)layoutX, (byte)layoutY, (byte)building.recordIndex); modelBuildings[i] = building; } // Add static doors component if (allDoors.Count > 0) { AddStaticDoors(allDoors.ToArray(), go); } // Add static buildings component if (modelBuildings.Count > 0) { AddStaticBuildings(modelBuildings.ToArray(), go); } // Apply combiner if (combiner != null) { if (combiner.VertexCount > 0) { combiner.Apply(); GameObjectHelper.CreateCombinedMeshGameObject( combiner, "CombinedModels", modelsNode.transform, dfUnity.Option_SetStaticFlags); } } return(go); }
public GameBuilding(StaticBuilding building) : base(building) { }
private static void AddModels( DaggerfallUnity dfUnity, ref DFBlock blockData, out List <StaticDoor> doorsOut, out List <StaticBuilding> buildingsOut, ModelCombiner combiner = null, Transform parent = null) { doorsOut = new List <StaticDoor>(); buildingsOut = new List <StaticBuilding>(); // Iterate through all subrecords int recordCount = 0; foreach (DFBlock.RmbSubRecord subRecord in blockData.RmbBlock.SubRecords) { // Get subrecord transform Vector3 subRecordPosition = new Vector3(subRecord.XPos, 0, BlocksFile.RMBDimension - subRecord.ZPos) * MeshReader.GlobalScale; Vector3 subRecordRotation = new Vector3(0, -subRecord.YRotation / BlocksFile.RotationDivisor, 0); Matrix4x4 subRecordMatrix = Matrix4x4.TRS(subRecordPosition, Quaternion.Euler(subRecordRotation), Vector3.one); // Iterate through models in this subrecord bool firstModel = true; foreach (DFBlock.RmbBlock3dObjectRecord obj in subRecord.Exterior.Block3dObjectRecords) { // Get model transform Vector3 modelPosition = new Vector3(obj.XPos, -obj.YPos, obj.ZPos) * MeshReader.GlobalScale; Vector3 modelRotation = new Vector3(0, -obj.YRotation / BlocksFile.RotationDivisor, 0); Matrix4x4 modelMatrix = subRecordMatrix * Matrix4x4.TRS(modelPosition, Quaternion.Euler(modelRotation), Vector3.one); // Get model data ModelData modelData; dfUnity.MeshReader.GetModelData(obj.ModelIdNum, out modelData); // Does this model have doors? if (modelData.Doors != null) { doorsOut.AddRange(GameObjectHelper.GetStaticDoors(ref modelData, blockData.Index, recordCount, modelMatrix)); } // Store building information for first model of record // First model is main record structure, others are attachments like posts // Only main structure is needed to resolve building after hit-test if (firstModel) { StaticBuilding staticBuilding = new StaticBuilding(); staticBuilding.modelMatrix = modelMatrix; staticBuilding.recordIndex = recordCount; staticBuilding.centre = new Vector3(modelData.DFMesh.Centre.X, modelData.DFMesh.Centre.Y, modelData.DFMesh.Centre.Z) * MeshReader.GlobalScale; staticBuilding.size = new Vector3(modelData.DFMesh.Size.X, modelData.DFMesh.Size.Y, modelData.DFMesh.Size.Z) * MeshReader.GlobalScale; buildingsOut.Add(staticBuilding); firstModel = false; } // Import custom GameObject if (MeshReplacement.ImportCustomGameobject(obj.ModelIdNum, parent, modelMatrix) != null) { continue; } // Use Daggerfall Model // Add or combine if (combiner == null || IsCityGate(obj.ModelIdNum)) { AddStandaloneModel(dfUnity, ref modelData, modelMatrix, parent); } else { combiner.Add(ref modelData, modelMatrix); } } // Increment record count recordCount++; } }
// 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); }
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 } } }
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 and support mobile enemy info-clicks // Using RaycastAll as hits can be blocked by decorations or other models // When this happens activation feels unresponsive to player // Also processing hit detection in order of priority Ray ray = new Ray(mainCamera.transform.position, mainCamera.transform.forward); RaycastHit[] hits; hits = Physics.RaycastAll(ray, RayDistance); if (hits != null) { // Check each hit in range for action, exit on first valid action processed bool hitBuilding = false; StaticBuilding building = new StaticBuilding(); for (int i = 0; i < hits.Length; i++) { #region Hit Checks // Check for a static building hit Transform buildingOwner; DaggerfallStaticBuildings buildings = GetBuildings(hits[i].transform, out buildingOwner); if (buildings) { if (buildings.HasHit(hits[i].point, out building)) { hitBuilding = true; // Show building info if (currentMode == PlayerActivateModes.Info) { PresentBuildingInfo(building); } } } // Check for a static door hit Transform doorOwner; DaggerfallStaticDoors doors = GetDoors(hits[i].transform, out doorOwner); if (doors && playerEnterExit) { StaticDoor door; if (doors.HasHit(hits[i].point, out door)) { if (door.doorType == DoorTypes.Building && !playerEnterExit.IsPlayerInside) { // If entering a shop let player know the quality level if (hitBuilding) { DaggerfallMessageBox mb = PresentShopQuality(building); if (mb != null) { // Defer transition to interior to after user closes messagebox deferredInteriorDoorOwner = doorOwner; deferredInteriorDoor = door; mb.OnClose += ShopQualityPopup_OnClose; return; } } // Hit door while outside, transition inside playerEnterExit.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, transition outside playerEnterExit.TransitionDungeonExterior(true); return; } } } // Check for an action door hit DaggerfallActionDoor actionDoor; if (ActionDoorCheck(hits[i], out actionDoor)) { if (currentMode == PlayerActivateModes.Steal && actionDoor.IsLocked) { if (actionDoor.IsNoLongerPickable) { return; } else { actionDoor.AttemptLockpicking(); } } else { actionDoor.ToggleDoor(); } } // Check for action record hit DaggerfallAction action; if (ActionCheck(hits[i], out action)) { action.Receive(this.gameObject, DaggerfallAction.TriggerTypes.Direct); } // Check for lootable object hit DaggerfallLoot loot; if (LootCheck(hits[i], out loot)) { // For bodies, check has treasure first if (loot.ContainerType == LootContainerTypes.CorpseMarker && loot.Items.Count == 0) { DaggerfallUI.AddHUDText(HardStrings.theBodyHasNoTreasure); return; } // Open inventory window with loot as remote target DaggerfallUI.Instance.InventoryWindow.LootTarget = loot; DaggerfallUI.PostMessage(DaggerfallUIMessages.dfuiOpenInventoryWindow); } // Check for static NPC hit StaticNPC npc; if (NPCCheck(hits[i], out npc)) { switch (currentMode) { case PlayerActivateModes.Info: PresentNPCInfo(npc); break; case PlayerActivateModes.Grab: case PlayerActivateModes.Talk: SpecialNPCClick(npc); QuestorCheck(npc); break; } } // Trigger general quest resource behaviour click // Note: This will cause a second click on special NPCs, look into a way to unify this handling QuestResourceBehaviour questResourceBehaviour; if (QuestResourceBehaviourCheck(hits[i], out questResourceBehaviour)) { TriggerQuestResourceBehaviourClick(questResourceBehaviour); } #endregion } } } }