private static void AddStaticBuildings(StaticBuilding[] buildings, GameObject target) { DaggerfallStaticBuildings c = target.GetComponent <DaggerfallStaticBuildings>(); if (c == null) { c = target.AddComponent <DaggerfallStaticBuildings>(); } if (buildings != null && target != null) { c.Buildings = buildings; } }
// Look for building array on object, then on direct parent private DaggerfallStaticBuildings GetBuildings(Transform transform, out Transform owner) { owner = null; DaggerfallStaticBuildings buildings = transform.GetComponent <DaggerfallStaticBuildings>(); if (!buildings) { buildings = transform.GetComponentInParent <DaggerfallStaticBuildings>(); if (buildings) { owner = buildings.transform; } } else { owner = buildings.transform; } return(buildings); }
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 } } } }
public void UpdateMarkers(bool RemoveMarkersOnly = false) { foreach (GameObject marker in buildingInfoCollection) { if (marker.GetComponent <BuildingMarker>() != null) { BuildingMarker markerInstance = marker.GetComponent <BuildingMarker>(); Destroy(markerInstance.marker.attachedDoorIcon); Destroy(markerInstance.marker.attachedLabel); Destroy(markerInstance.marker.attachedMesh); Destroy(markerInstance.marker.attachedQuestIcon); Destroy(markerInstance.marker.attachedIcon); Destroy(markerInstance); } if (marker != null) { Destroy(marker); } } buildingInfoCollection.Clear(); buildingInfoCollection = new List <GameObject>(); if (RemoveMarkersOnly) { return; } generatingMarkers = true; //Vector3 position = currentCityNav.WorldToScenePosition(new DFPosition(Minimap.currentLocation.Summary.MapPixelX, Minimap.currentLocation.Summary.MapPixelX), true); List <BuildingSummary> housesForSaleList = buildingDirectory.GetHousesForSale(); foreach (DaggerfallRMBBlock block in blockArray) { Vector3 blockPosition = block.transform.position; //setup a new static buildings object to hold the rmb blocks static buildings object. DaggerfallStaticBuildings staticBuildingContainer = block.GetComponentInChildren <DaggerfallStaticBuildings>(); //if there are not any buildings in this block, stop code from crashing script and return. if (staticBuildingContainer == null) { continue; } //resize static building array based on the number of static building pbjects in the container. StaticBuildingArray = new StaticBuilding[staticBuildingContainer.transform.childCount]; //load blocks static building array into the empty array for looping through. StaticBuildingArray = staticBuildingContainer.Buildings; // Find the doors for the buildings and drop into a list for referencing below when setting up individual building information. StaticDoor[] doors = DaggerfallStaticDoors.FindDoorsInCollections(GameManager.Instance.StreamingWorld.CurrentPlayerLocationObject.StaticDoorCollections, DoorTypes.Building); List <CombineInstance> houseMeshList = new List <CombineInstance>(); //runs through building array. foreach (StaticBuilding building in StaticBuildingArray) { //sets up and grabes the current buildings material, summary object/info, placing/final position, game model. BuildingSummary SavedBuilding = new BuildingSummary(); buildingDirectory.GetBuildingSummary(building.buildingKey, out SavedBuilding); if (SavedBuilding.BuildingType == DFLocation.BuildingTypes.AllValid) { continue; } Vector3 markerPosition = new Vector3(0, 0, 0); if (building.size.z > tallestSpot) { tallestSpot = building.size.z; } //create gameobject for building marker. GameObject buildingMarkerObject = GameObjectHelper.CreateDaggerfallMeshGameObject(SavedBuilding.ModelID, null, false, null, true, false); buildingMarkerObject.GetComponent <Renderer>().enabled = false; buildingMarkerObject.transform.position = new Vector3(blockPosition.x + SavedBuilding.Position.x, blockPosition.y + tallestSpot + 10f, blockPosition.z + SavedBuilding.Position.z); //buildingMarkerObject.SetActive(false); BuildingMarker buildingsInfo = buildingMarkerObject.AddComponent <BuildingMarker>(); MeshRenderer buildingMesh = buildingMarkerObject.GetComponent <MeshRenderer>(); buildingsInfo.marker.attachedMesh = buildingMarkerObject; buildingMarkerObject.transform.position = buildingMarkerObject.transform.position; buildingMarkerObject.transform.Rotate(SavedBuilding.Rotation); buildingMarkerObject.layer = Minimap.layerMinimap; buildingMarkerObject.transform.localScale = new Vector3(1, 0.01f, 1); buildingMarkerObject.name = string.Concat(SavedBuilding.BuildingType.ToString(), " Marker ", SavedBuilding.buildingKey); buildingMesh.shadowCastingMode = 0; buildingMesh.lightProbeUsage = UnityEngine.Rendering.LightProbeUsage.Off; buildingMesh.motionVectorGenerationMode = MotionVectorGenerationMode.ForceNoMotion; //Destroy(buildingMarkerObject.GetComponent<MeshCollider>()); //grab and store all building info into the building marker object. buildingsInfo.marker.staticBuilding = building; buildingsInfo.marker.buildingSummary = SavedBuilding; buildingsInfo.marker.buildingKey = SavedBuilding.buildingKey; foreach (BuildingSummary buildingInfo in housesForSaleList) { if (buildingInfo.BuildingType == DFLocation.BuildingTypes.HouseForSale) { buildingsInfo.marker.buildingType = DFLocation.BuildingTypes.HouseForSale; } else { buildingsInfo.marker.buildingType = SavedBuilding.BuildingType; } } buildingsInfo.marker.buildingLocation = GameManager.Instance.PlayerGPS.CurrentLocation; //buildingPositionList.Add(new Vector3(block.transform.position.x + SavedBuilding.Position.x, SavedBuilding.Position.y, block.transform.position.z + SavedBuilding.Position.z)); buildingsInfo.marker.position = buildingMarkerObject.transform.position; foreach (StaticDoor buildingsDoor in doors) { if (building.buildingKey == buildingsDoor.buildingKey) { buildingsInfo.marker.doorPosition = DaggerfallStaticDoors.GetDoorPosition(buildingsDoor); } } //setup ref properties for quest resource locator below. bool pcLearnedAboutExistence = false; bool receivedDirectionalHints = false; bool locationWasMarkedOnMapByNPC = false; string overrideBuildingName = string.Empty; //check if the building contains a quest using quest resouces. If found to contain a quest, mark it so. if (GameManager.Instance.TalkManager.IsBuildingQuestResource(GameManager.Instance.PlayerGPS.CurrentMapID, buildingsInfo.marker.buildingKey, ref overrideBuildingName, ref pcLearnedAboutExistence, ref receivedDirectionalHints, ref locationWasMarkedOnMapByNPC)) { Minimap.lastQuestMarkerPosition = buildingsInfo.marker.position; buildingsInfo.marker.questActive = true; } //save building to building collection. This is more for other modders to use how they wish, since it contains all the building info for every building in a city. buildingInfoCollection.Add(buildingMarkerObject); } } markersGenerated = true; }