/// <summary> /// Update NPC presence for shops and guilds after resting/idling. /// </summary> public void UpdateNpcPresence() { PlayerEnterExit playerEnterExit = GameManager.Instance.PlayerEnterExit; DFLocation.BuildingTypes buildingType = playerEnterExit.BuildingType; if ((RMBLayout.IsShop(buildingType) && !playerEnterExit.IsPlayerInsideOpenShop) || (!RMBLayout.IsShop(buildingType) && buildingType <= DFLocation.BuildingTypes.Palace && buildingType != DFLocation.BuildingTypes.HouseForSale)) { Transform npcTransforms = transform.Find(peopleFlats); if (PlayerActivate.IsBuildingOpen(buildingType)) { foreach (Transform npcTransform in npcTransforms) { npcTransform.gameObject.SetActive(true); } Debug.Log("Updated npcs to be present."); } } }
/// <summary> /// Checks if building is a shop with quality text. /// </summary> public static bool IsShop(DFLocation.BuildingTypes buildingType) { switch (buildingType) { case DFLocation.BuildingTypes.Alchemist: case DFLocation.BuildingTypes.Armorer: case DFLocation.BuildingTypes.Bookseller: case DFLocation.BuildingTypes.ClothingStore: case DFLocation.BuildingTypes.FurnitureStore: case DFLocation.BuildingTypes.GemStore: case DFLocation.BuildingTypes.GeneralStore: case DFLocation.BuildingTypes.PawnShop: case DFLocation.BuildingTypes.WeaponSmith: return(true); default: return(false); } }
// Check if non-house building is unlocked and enterable private bool BuildingIsUnlocked(BuildingSummary buildingSummary) { bool unlocked = false; DFLocation.BuildingTypes type = buildingSummary.BuildingType; // TODO: Guild structures can become unlocked 24hr depending on player rank // Handle House1 through House4 // TODO: Figure out the rest of house door calculations. if (type >= DFLocation.BuildingTypes.House1 && type <= DFLocation.BuildingTypes.House4 && DaggerfallUnity.Instance.WorldTime.Now.IsDay) { unlocked = true; } // Handle other structures (stores, temples, taverns, palaces) else if (type <= DFLocation.BuildingTypes.Palace) { unlocked = (openHours[(int)type] <= DaggerfallUnity.Instance.WorldTime.Now.Hour && closeHours[(int)type] > DaggerfallUnity.Instance.WorldTime.Now.Hour); } return(unlocked); }
private bool checkBuildingTypeInSkipList(DFLocation.BuildingTypes buildingType) { if (buildingType == DFLocation.BuildingTypes.AllValid || buildingType == DFLocation.BuildingTypes.FurnitureStore || buildingType == DFLocation.BuildingTypes.House1 || buildingType == DFLocation.BuildingTypes.House2 || buildingType == DFLocation.BuildingTypes.House3 || buildingType == DFLocation.BuildingTypes.House4 || buildingType == DFLocation.BuildingTypes.House5 || buildingType == DFLocation.BuildingTypes.House6 || buildingType == DFLocation.BuildingTypes.HouseForSale || buildingType == DFLocation.BuildingTypes.Palace || buildingType == DFLocation.BuildingTypes.Ship || buildingType == DFLocation.BuildingTypes.Special1 || buildingType == DFLocation.BuildingTypes.Special2 || buildingType == DFLocation.BuildingTypes.Special3 || buildingType == DFLocation.BuildingTypes.Special4 || buildingType == DFLocation.BuildingTypes.Town23 || buildingType == DFLocation.BuildingTypes.Town4) { return(true); } return(false); }
/// <summary> /// Transition player through an exterior door into building interior. /// </summary> /// <param name="doorOwner">Parent transform owning door array..</param> /// <param name="door">Exterior door player clicked on.</param> public void TransitionInterior(Transform doorOwner, StaticDoor door, bool doFade = false) { // Ensure we have component references if (!ReferenceComponents()) { return; } // Copy owner position to door // This ensures the door itself is all we need to reposition interior // Useful when loading a save and doorOwner is null (as outside world does not exist) if (doorOwner) { door.ownerPosition = doorOwner.position; door.ownerRotation = doorOwner.rotation; } // Raise event RaiseOnPreTransitionEvent(TransitionType.ToBuildingInterior, door); // Get climate ClimateBases climateBase = ClimateBases.Temperate; if (OverrideLocation) { climateBase = OverrideLocation.Summary.Climate; } else if (playerGPS) { climateBase = ClimateSwaps.FromAPIClimateBase(playerGPS.ClimateSettings.ClimateType); } // Layout interior // This needs to be done first so we know where the enter markers are GameObject newInterior = new GameObject(string.Format("DaggerfallInterior [Block={0}, Record={1}]", door.blockIndex, door.recordIndex)); newInterior.hideFlags = defaultHideFlags; interior = newInterior.AddComponent <DaggerfallInterior>(); // Try to layout interior // If we fail for any reason, use that old chestnut "this house has nothing of value" try { interior.DoLayout(doorOwner, door, climateBase); } catch { DaggerfallUI.AddHUDText(UserInterfaceWindows.HardStrings.thisHouseHasNothingOfValue); Destroy(newInterior); return; } // Position interior directly inside of exterior // This helps with finding closest enter/exit point relative to player position interior.transform.position = door.ownerPosition + (Vector3)door.buildingMatrix.GetColumn(3); interior.transform.rotation = GameObjectHelper.QuaternionFromMatrix(door.buildingMatrix); // Position player above closest enter marker Vector3 marker; if (!interior.FindClosestEnterMarker(transform.position, out marker)) { // Could not find an enter marker, probably not a valid interior Destroy(newInterior); return; } // Enumerate all exterior doors belonging to this building DaggerfallStaticDoors exteriorStaticDoors = interior.ExteriorDoors; if (exteriorStaticDoors && doorOwner) { List <StaticDoor> buildingDoors = new List <StaticDoor>(); for (int i = 0; i < exteriorStaticDoors.Doors.Length; i++) { if (exteriorStaticDoors.Doors[i].recordIndex == door.recordIndex) { StaticDoor newDoor = exteriorStaticDoors.Doors[i]; newDoor.ownerPosition = doorOwner.position; newDoor.ownerRotation = doorOwner.rotation; buildingDoors.Add(newDoor); } } SetExteriorDoors(buildingDoors.ToArray()); } // Assign new interior to parent if (InteriorParent != null) { newInterior.transform.parent = InteriorParent.transform; } // Cache some information about this interior buildingType = interior.BuildingData.BuildingType; // Set player to marker position // TODO: Find closest door for player facing transform.position = marker + Vector3.up * (controller.height * 0.6f); SetStanding(); EnableInteriorParent(); // Raise event RaiseOnTransitionInteriorEvent(door, interior); // Fade in from black if (doFade) { DaggerfallUI.Instance.FadeHUDFromBlack(); } }
public void StockHouseContainer(PlayerGPS.DiscoveredBuilding buildingData) { stockedDate = CreateStockedDate(DaggerfallUnity.Instance.WorldTime.Now); items.Clear(); DFLocation.BuildingTypes buildingType = buildingData.buildingType; uint modelIndex = (uint)TextureRecord; //int buildingQuality = buildingData.quality; byte[] privatePropertyList = null; DaggerfallUnityItem item = null; Game.Entity.PlayerEntity playerEntity = GameManager.Instance.PlayerEntity; if (buildingType < DFLocation.BuildingTypes.House5) { if (modelIndex >= 2) { if (modelIndex >= 4) { if (modelIndex >= 11) { if (modelIndex >= 15) { privatePropertyList = DaggerfallLootDataTables.privatePropertyItemsModels15AndUp[(int)buildingType]; } else { privatePropertyList = DaggerfallLootDataTables.privatePropertyItemsModels11to14[(int)buildingType]; } } else { privatePropertyList = DaggerfallLootDataTables.privatePropertyItemsModels4to10[(int)buildingType]; } } else { privatePropertyList = DaggerfallLootDataTables.privatePropertyItemsModels2to3[(int)buildingType]; } } else { privatePropertyList = DaggerfallLootDataTables.privatePropertyItemsModels0to1[(int)buildingType]; } if (privatePropertyList == null) { return; } int randomChoice = Random.Range(0, privatePropertyList.Length); ItemGroups itemGroup = (ItemGroups)privatePropertyList[randomChoice]; int continueChance = 100; bool keepGoing = true; while (keepGoing) { if (itemGroup != ItemGroups.MensClothing && itemGroup != ItemGroups.WomensClothing) { if (itemGroup == ItemGroups.MagicItems) { item = ItemBuilder.CreateRandomMagicItem(playerEntity.Level, playerEntity.Gender, playerEntity.Race); } else if (itemGroup == ItemGroups.Books) { item = ItemBuilder.CreateRandomBook(); } else { if (itemGroup == ItemGroups.Weapons) { item = ItemBuilder.CreateRandomWeapon(playerEntity.Level); } else if (itemGroup == ItemGroups.Armor) { item = ItemBuilder.CreateRandomArmor(playerEntity.Level, playerEntity.Gender, playerEntity.Race); } else { System.Array enumArray = DaggerfallUnity.Instance.ItemHelper.GetEnumArray(itemGroup); item = new DaggerfallUnityItem(itemGroup, Random.Range(0, enumArray.Length)); } } } else { item = ItemBuilder.CreateRandomClothing(playerEntity.Gender, playerEntity.Race); } continueChance >>= 1; if (DFRandom.rand() % 100 > continueChance) { keepGoing = false; } items.AddItem(item); } } }
public void StockShopShelf(PlayerGPS.DiscoveredBuilding buildingData) { stockedDate = CreateStockedDate(DaggerfallUnity.Instance.WorldTime.Now); items.Clear(); DFLocation.BuildingTypes buildingType = buildingData.buildingType; int shopQuality = buildingData.quality; Game.Entity.PlayerEntity playerEntity = GameManager.Instance.PlayerEntity; ItemHelper itemHelper = DaggerfallUnity.Instance.ItemHelper; byte[] itemGroups = { 0 }; switch (buildingType) { case DFLocation.BuildingTypes.Alchemist: itemGroups = DaggerfallLootDataTables.itemGroupsAlchemist; RandomlyAddPotionRecipe(25, items); break; case DFLocation.BuildingTypes.Armorer: itemGroups = DaggerfallLootDataTables.itemGroupsArmorer; break; case DFLocation.BuildingTypes.Bookseller: itemGroups = DaggerfallLootDataTables.itemGroupsBookseller; break; case DFLocation.BuildingTypes.ClothingStore: itemGroups = DaggerfallLootDataTables.itemGroupsClothingStore; break; case DFLocation.BuildingTypes.GemStore: itemGroups = DaggerfallLootDataTables.itemGroupsGemStore; break; case DFLocation.BuildingTypes.GeneralStore: itemGroups = DaggerfallLootDataTables.itemGroupsGeneralStore; items.AddItem(ItemBuilder.CreateItem(ItemGroups.Transportation, (int)Transportation.Horse)); items.AddItem(ItemBuilder.CreateItem(ItemGroups.Transportation, (int)Transportation.Small_cart)); break; case DFLocation.BuildingTypes.PawnShop: itemGroups = DaggerfallLootDataTables.itemGroupsPawnShop; break; case DFLocation.BuildingTypes.WeaponSmith: itemGroups = DaggerfallLootDataTables.itemGroupsWeaponSmith; break; } for (int i = 0; i < itemGroups.Length; i += 2) { ItemGroups itemGroup = (ItemGroups)itemGroups[i]; int chanceMod = itemGroups[i + 1]; if (itemGroup == ItemGroups.MensClothing && playerEntity.Gender == Game.Entity.Genders.Female) { itemGroup = ItemGroups.WomensClothing; } if (itemGroup == ItemGroups.WomensClothing && playerEntity.Gender == Game.Entity.Genders.Male) { itemGroup = ItemGroups.MensClothing; } if (itemGroup != ItemGroups.Furniture && itemGroup != ItemGroups.UselessItems1) { if (itemGroup == ItemGroups.Books) { int qualityMod = (shopQuality + 3) / 5; if (qualityMod >= 4) { --qualityMod; } qualityMod++; for (int j = 0; j <= qualityMod; ++j) { items.AddItem(ItemBuilder.CreateRandomBook()); } } else { System.Array enumArray = itemHelper.GetEnumArray(itemGroup); for (int j = 0; j < enumArray.Length; ++j) { ItemTemplate itemTemplate = itemHelper.GetItemTemplate(itemGroup, j); if (itemTemplate.rarity <= shopQuality) { int stockChance = chanceMod * 5 * (21 - itemTemplate.rarity) / 100; if (Dice100.SuccessRoll(stockChance)) { DaggerfallUnityItem item = null; if (itemGroup == ItemGroups.Weapons) { item = ItemBuilder.CreateWeapon(j + Weapons.Dagger, FormulaHelper.RandomMaterial(playerEntity.Level)); } else if (itemGroup == ItemGroups.Armor) { item = ItemBuilder.CreateArmor(playerEntity.Gender, playerEntity.Race, j + Armor.Cuirass, FormulaHelper.RandomArmorMaterial(playerEntity.Level)); } else if (itemGroup == ItemGroups.MensClothing) { item = ItemBuilder.CreateMensClothing(j + MensClothing.Straps, playerEntity.Race); item.dyeColor = ItemBuilder.RandomClothingDye(); } else if (itemGroup == ItemGroups.WomensClothing) { item = ItemBuilder.CreateWomensClothing(j + WomensClothing.Brassier, playerEntity.Race); item.dyeColor = ItemBuilder.RandomClothingDye(); } else if (itemGroup == ItemGroups.MagicItems) { item = ItemBuilder.CreateRandomMagicItem(playerEntity.Level, playerEntity.Gender, playerEntity.Race); } else { item = new DaggerfallUnityItem(itemGroup, j); if (DaggerfallUnity.Settings.PlayerTorchFromItems && item.IsOfTemplate(ItemGroups.UselessItems2, (int)UselessItems2.Oil)) { item.stackCount = Random.Range(5, 20 + 1); // Shops stock 5-20 bottles } } items.AddItem(item); } } } // Add any modded items registered in applicable groups int[] customItemTemplates = itemHelper.GetCustomItemsForGroup(itemGroup); for (int j = 0; j < customItemTemplates.Length; j++) { ItemTemplate itemTemplate = itemHelper.GetItemTemplate(itemGroup, customItemTemplates[j]); if (itemTemplate.rarity <= shopQuality) { int stockChance = chanceMod * 5 * (21 - itemTemplate.rarity) / 100; if (Dice100.SuccessRoll(stockChance)) { DaggerfallUnityItem item = ItemBuilder.CreateItem(itemGroup, customItemTemplates[j]); // Setup specific group stats if (itemGroup == ItemGroups.Weapons) { WeaponMaterialTypes material = FormulaHelper.RandomMaterial(playerEntity.Level); ItemBuilder.ApplyWeaponMaterial(item, material); } else if (itemGroup == ItemGroups.Armor) { ArmorMaterialTypes material = FormulaHelper.RandomArmorMaterial(playerEntity.Level); ItemBuilder.ApplyArmorSettings(item, playerEntity.Gender, playerEntity.Race, material); } items.AddItem(item); } } } } } } }
/// <summary> /// Transition player through an exterior door into building interior. /// </summary> /// <param name="doorOwner">Parent transform owning door array.</param> /// <param name="door">Exterior door player clicked on.</param> public void TransitionInterior(Transform doorOwner, StaticDoor door) { // Ensure we have component references if (!ReferenceComponents()) { return; } // Get current climate ClimateBases climateBase = ClimateBases.Temperate; if (playerGPS) { climateBase = ClimateSwaps.FromAPIClimateBase(playerGPS.ClimateSettings.ClimateType); } // Layout interior // This needs to be done first so we know where the enter markers are GameObject newInterior = new GameObject(string.Format("DaggerfallInterior [Block={0}, Record={1}]", door.blockIndex, door.recordIndex)); newInterior.hideFlags = HideFlags.HideAndDontSave; interior = newInterior.AddComponent <DaggerfallInterior>(); interior.DoLayout(doorOwner, door, climateBase); // Position interior directly inside of exterior // This helps with finding closest enter/exit point relative to player position interior.transform.position = doorOwner.position + (Vector3)door.buildingMatrix.GetColumn(3); interior.transform.rotation = GameObjectHelper.QuaternionFromMatrix(door.buildingMatrix); // Position player above closest enter marker Vector3 marker; if (!interior.FindClosestEnterMarker(transform.position, out marker)) { // Could not find an enter marker, probably not a valid interior Destroy(newInterior); return; } // Assign new interior to parent if (InteriorParent != null) { newInterior.transform.parent = InteriorParent.transform; } // Disable exterior parent if (ExteriorParent != null) { ExteriorParent.SetActive(false); } // Enable interior parent if (InteriorParent != null) { InteriorParent.SetActive(true); } // Cache some information about this interior buildingType = interior.BuildingData.BuildingType; // Set player to marker position // Not sure how to set facing here as player transitions to a marker, not a door // Could always find closest door and use that transform.position = marker + Vector3.up * (controller.height * 0.6f); SetStanding(); // Player is now inside building isPlayerInside = true; }
/// <summary> /// Draws and consume building from pool. /// Checking if buildings are ordered by special type. /// </summary> static bool GetNextBuildingFromPool(List <BuildingPoolItem> namedBuildingPool, DFLocation.BuildingTypes buildingType, out BuildingPoolItem itemOut) { itemOut = new BuildingPoolItem(); for (int i = 0; i < namedBuildingPool.Count; i++) { if (!namedBuildingPool[i].used && namedBuildingPool[i].buildingData.BuildingType == buildingType) { itemOut = namedBuildingPool[i]; itemOut.used = true; return(true); } } return(false); }
/// <summary> /// Transition player through an exterior door into building interior. /// </summary> /// <param name="doorOwner">Parent transform owning door array.</param> /// <param name="door">Exterior door player clicked on.</param> public void TransitionInterior(Transform doorOwner, StaticDoor door) { // Ensure we have component references if (!ReferenceComponents()) return; // Raise event RaiseOnPreTransitionEvent(TransitionType.ToBuildingInterior, door); // Get climate ClimateBases climateBase = ClimateBases.Temperate; if (OverrideLocation) { climateBase = OverrideLocation.Summary.Climate; } else if (playerGPS) { climateBase = ClimateSwaps.FromAPIClimateBase(playerGPS.ClimateSettings.ClimateType); } // Layout interior // This needs to be done first so we know where the enter markers are GameObject newInterior = new GameObject(string.Format("DaggerfallInterior [Block={0}, Record={1}]", door.blockIndex, door.recordIndex)); newInterior.hideFlags = HideFlags.HideAndDontSave; interior = newInterior.AddComponent<DaggerfallInterior>(); interior.DoLayout(doorOwner, door, climateBase); // Position interior directly inside of exterior // This helps with finding closest enter/exit point relative to player position interior.transform.position = doorOwner.position + (Vector3)door.buildingMatrix.GetColumn(3); interior.transform.rotation = GameObjectHelper.QuaternionFromMatrix(door.buildingMatrix); // Position player above closest enter marker Vector3 marker; if (!interior.FindClosestEnterMarker(transform.position, out marker)) { // Could not find an enter marker, probably not a valid interior Destroy(newInterior); return; } // Assign new interior to parent if (InteriorParent != null) newInterior.transform.parent = InteriorParent.transform; // Disable exterior parent if (ExteriorParent != null) ExteriorParent.SetActive(false); // Enable interior parent if (InteriorParent != null) InteriorParent.SetActive(true); // Cache some information about this interior buildingType = interior.BuildingData.BuildingType; // Set player to marker position // Not sure how to set facing here as player transitions to a marker, not a door // Could always find closest door and use that transform.position = marker + Vector3.up * (controller.height * 0.6f); SetStanding(); // Player is now inside building isPlayerInside = true; // Raise event RaiseOnTransitionInteriorEvent(door, interior); }
/// <summary> /// Transition player through an exterior door into building interior. /// </summary> /// <param name="doorOwner">Parent transform owning door array..</param> /// <param name="door">Exterior door player clicked on.</param> public void TransitionInterior(Transform doorOwner, StaticDoor door, bool doFade = false, bool start = true) { // Ensure we have component references if (!ReferenceComponents()) { return; } // Copy owner position to door // This ensures the door itself is all we need to reposition interior // Useful when loading a save and doorOwner is null (as outside world does not exist) if (doorOwner) { door.ownerPosition = doorOwner.position; door.ownerRotation = doorOwner.rotation; } if (!start) { // Update scene cache from serializable state for exterior->interior transition SaveLoadManager.CacheScene(world.SceneName); // Explicitly deregister all stateful objects since exterior isn't destroyed SaveLoadManager.DeregisterAllSerializableGameObjects(true); // Clear all stateful objects from world loose object tracking world.ClearStatefulLooseObjects(); } // Raise event RaiseOnPreTransitionEvent(TransitionType.ToBuildingInterior, door); // Ensure expired rooms are removed GameManager.Instance.PlayerEntity.RemoveExpiredRentedRooms(); // Get climate ClimateBases climateBase = ClimateBases.Temperate; if (OverrideLocation) { climateBase = OverrideLocation.Summary.Climate; } else if (playerGPS) { climateBase = ClimateSwaps.FromAPIClimateBase(playerGPS.ClimateSettings.ClimateType); } // Layout interior // This needs to be done first so we know where the enter markers are GameObject newInterior = new GameObject(DaggerfallInterior.GetSceneName(playerGPS.CurrentLocation, door)); newInterior.hideFlags = defaultHideFlags; interior = newInterior.AddComponent <DaggerfallInterior>(); // Try to layout interior // If we fail for any reason, use that old chestnut "this house has nothing of value" try { interior.DoLayout(doorOwner, door, climateBase, buildingDiscoveryData); } catch { DaggerfallUI.AddHUDText(HardStrings.thisHouseHasNothingOfValue); Destroy(newInterior); return; } // Position interior directly inside of exterior // This helps with finding closest enter/exit point relative to player position interior.transform.position = door.ownerPosition + (Vector3)door.buildingMatrix.GetColumn(3); interior.transform.rotation = GameObjectHelper.QuaternionFromMatrix(door.buildingMatrix); // Position player above closest enter marker Vector3 marker; if (!interior.FindClosestEnterMarker(transform.position, out marker)) { // Could not find an enter marker, probably not a valid interior Destroy(newInterior); return; } // Enumerate all exterior doors belonging to this building DaggerfallStaticDoors exteriorStaticDoors = interior.ExteriorDoors; if (exteriorStaticDoors && doorOwner) { List <StaticDoor> buildingDoors = new List <StaticDoor>(); for (int i = 0; i < exteriorStaticDoors.Doors.Length; i++) { if (exteriorStaticDoors.Doors[i].recordIndex == door.recordIndex) { StaticDoor newDoor = exteriorStaticDoors.Doors[i]; newDoor.ownerPosition = doorOwner.position; newDoor.ownerRotation = doorOwner.rotation; buildingDoors.Add(newDoor); } } SetExteriorDoors(buildingDoors.ToArray()); } // Assign new interior to parent if (InteriorParent != null) { newInterior.transform.parent = InteriorParent.transform; } // Cache some information about this interior buildingType = interior.BuildingData.BuildingType; factionID = interior.BuildingData.FactionId; // Set player to marker position // TODO: Find closest door for player facing transform.position = marker + Vector3.up * (controller.height * 0.6f); SetStanding(); EnableInteriorParent(); // Add quest resources GameObjectHelper.AddQuestResourceObjects(SiteTypes.Building, interior.transform, interior.EntryDoor.buildingKey); // Update serializable state from scene cache for exterior->interior transition (unless new/load game) if (!start) { SaveLoadManager.RestoreCachedScene(interior.name); } // Raise event RaiseOnTransitionInteriorEvent(door, interior); // Fade in from black if (doFade) { DaggerfallUI.Instance.FadeHUDFromBlack(); } }
public void StockShopShelf(PlayerGPS.DiscoveredBuilding buildingData) { stockedDate = CreateStockedDate(DaggerfallUnity.Instance.WorldTime.Now); items.Clear(); DFLocation.BuildingTypes buildingType = buildingData.buildingType; int shopQuality = buildingData.quality; Game.Entity.PlayerEntity playerEntity = GameManager.Instance.PlayerEntity; int playerLuck = playerEntity.Stats.LiveLuck; ItemHelper itemHelper = DaggerfallUnity.Instance.ItemHelper; byte[] itemGroups = { 0 }; int[] discrimItems = new int[] { }; switch (buildingType) { case DFLocation.BuildingTypes.Alchemist: float alchChance = 60; float alchChanceMod = 0.75f; while (Dice100.SuccessRoll((int)alchChance)) { RandomlyAddPotion(100, items); alchChance *= alchChanceMod; } alchChance = 40; while (Dice100.SuccessRoll((int)alchChance)) { RandomlyAddPotionRecipe(100, items); alchChance *= alchChanceMod; } itemGroups = DaggerfallLootDataTables.itemGroupsAlchemist; break; case DFLocation.BuildingTypes.Armorer: itemGroups = DaggerfallLootDataTables.itemGroupsArmorer; discrimItems = new int[] { (int)Repair_Tools.Charging_Powder, (int)Repair_Tools.Epoxy_Glue, (int)Repair_Tools.Whetstone }; break; case DFLocation.BuildingTypes.Bookseller: itemGroups = DaggerfallLootDataTables.itemGroupsBookseller; break; case DFLocation.BuildingTypes.ClothingStore: itemGroups = DaggerfallLootDataTables.itemGroupsClothingStore; break; case DFLocation.BuildingTypes.GemStore: itemGroups = DaggerfallLootDataTables.itemGroupsGemStore; break; case DFLocation.BuildingTypes.GeneralStore: if (Dice100.SuccessRoll(20)) { items.AddItem(ItemBuilder.CreateItem(ItemGroups.Transportation, (int)Transportation.Horse)); } if (Dice100.SuccessRoll(30)) { items.AddItem(ItemBuilder.CreateItem(ItemGroups.Transportation, (int)Transportation.Small_cart)); } itemGroups = DaggerfallLootDataTables.itemGroupsGeneralStore; discrimItems = new int[] { (int)Containers.Barrel, (int)Containers.Lockbox, (int)Liquid_Containers.Gem_Encrusted_Gold_Goblet, (int)Liquid_Containers.Gem_Encrusted_Silver_Goblet, (int)Liquid_Containers.Gold_Goblet, (int)Liquid_Containers.Silver_Goblet }; break; case DFLocation.BuildingTypes.PawnShop: itemGroups = DaggerfallLootDataTables.itemGroupsPawnShop; discrimItems = new int[] { (int)Containers.Barrel, (int)Containers.Bucket, (int)Containers.Urn, (int)Containers.Urn, (int)Containers.Snuff_Box, (int)Containers.Quiver, (int)Liquid_Containers.Empty_Bottle, (int)Liquid_Containers.Wooden_Cup, (int)Liquid_Containers.Tin_Goblet }; break; case DFLocation.BuildingTypes.WeaponSmith: itemGroups = DaggerfallLootDataTables.itemGroupsWeaponSmith; discrimItems = new int[] { (int)Repair_Tools.Charging_Powder, (int)Repair_Tools.Armorers_Hammer, (int)Repair_Tools.Jewelers_Pliers, (int)Repair_Tools.Sewing_Kit }; break; } for (int i = 0; i < itemGroups.Length; i += 2) // Alright, that makes more sense to me now at least, from what it seems at least. Odd values are the itemGroup, Even are the chance for that itemGroup, makes much more sense. { ItemGroups itemGroup = (ItemGroups)itemGroups[i]; float chance = itemGroups[i + 1]; float chanceMod = 0.45f; if (itemGroup != ItemGroups.Furniture && itemGroup != ItemGroups.UselessItems1) { while (Dice100.SuccessRoll((int)chance)) // I think order will be, roll if item of group is generated, then actually pick the item of said group randomly and then continue from there until loop roll fails. { DaggerfallUnityItem item = null; // Don't forget to have weapons and armor and such have variable condition values depending on the quality of the store they were bought/generated in. chanceMod = Mathf.Clamp(chanceMod + 0.05f, 0.10f, 0.85f); // Will likely have to tweak this around and see how the results are. Possibly have shop quality modify these chance values as well. if (itemGroup == ItemGroups.Weapons) { item = ItemBuilder.CreateWeapon((Weapons)Random.Range((int)Weapons.Dagger, (int)Weapons.Arrow + 1), FormulaHelper.RandomMaterial(-1, shopQuality, playerLuck)); // May rework and give weapons different rarity values later. } else if (itemGroup == ItemGroups.Armor) { item = ItemBuilder.CreateArmor(playerEntity.Gender, playerEntity.Race, (Armor)Random.Range((int)Armor.Cuirass, (int)Armor.Tower_Shield + 1), FormulaHelper.RandomArmorMaterial(-1, shopQuality, playerLuck)); } else if (itemGroup == ItemGroups.MensClothing) { item = ItemBuilder.CreateMensClothing((MensClothing)Random.Range((int)MensClothing.Straps, (int)MensClothing.Champion_straps + 1), playerEntity.Race); item.dyeColor = ItemBuilder.RandomClothingDye(); } else if (itemGroup == ItemGroups.WomensClothing) { item = ItemBuilder.CreateWomensClothing((WomensClothing)Random.Range((int)WomensClothing.Brassier, (int)WomensClothing.Vest + 1), playerEntity.Race); item.dyeColor = ItemBuilder.RandomClothingDye(); } else if (itemGroup == ItemGroups.Books) { item = ItemBuilder.CreateRandomBookOfRandomSubject(-1, shopQuality, playerLuck); } else if (itemGroup == ItemGroups.MagicItems) { item = ItemBuilder.CreateRandomMagicItem(playerEntity.Gender, playerEntity.Race, -1, shopQuality, playerLuck); } else if ((int)itemGroup == (int)ItemGroups.Jewellery || ((int)itemGroup >= (int)ItemGroups.Tiara_Jewelry && (int)itemGroup <= (int)ItemGroups.Bracelet_Jewelry)) { item = ItemBuilder.CreateRandomJewelryOfRandomSlot(-1, shopQuality, playerLuck, discrimItems); } else { item = ItemBuilder.CreateRandomItemOfItemgroup(itemGroup, -1, shopQuality, playerLuck, discrimItems); // For filter could make a method to populate the discrimItem para values and just change them based on shop types, maybe. if (item != null && DaggerfallUnity.Settings.PlayerTorchFromItems && item.IsOfTemplate(ItemGroups.UselessItems2, (int)UselessItems2.Oil)) { item.stackCount = Random.Range(5, 20 + 1); // Shops stock 5-20 bottles } } items.AddItem(item); chance *= chanceMod; // Likely determine chanceMod by the itemGroup being currently ran. } // Add any modded items registered in applicable groups int[] customItemTemplates = itemHelper.GetCustomItemsForGroup(itemGroup); for (int j = 0; j < customItemTemplates.Length; j++) { ItemTemplate itemTemplate = itemHelper.GetItemTemplate(itemGroup, customItemTemplates[j]); if (itemTemplate.rarity <= shopQuality) { int stockChance = (int)Mathf.Round(chance * 5 * (21 - itemTemplate.rarity) / 100); if (Dice100.SuccessRoll(stockChance)) { DaggerfallUnityItem item = ItemBuilder.CreateItem(itemGroup, customItemTemplates[j]); // Setup specific group stats if (itemGroup == ItemGroups.Weapons) { WeaponMaterialTypes material = FormulaHelper.RandomMaterial(-1, shopQuality, playerLuck); ItemBuilder.ApplyWeaponMaterial(item, material); } else if (itemGroup == ItemGroups.Armor) { ArmorMaterialTypes material = FormulaHelper.RandomArmorMaterial(-1, shopQuality, playerLuck); ItemBuilder.ApplyArmorSettings(item, playerEntity.Gender, playerEntity.Race, material); } else if (item.TemplateIndex == 810) { WeaponMaterialTypes material = FormulaHelper.RandomMaterial(-1, shopQuality, playerLuck); ItemBuilder.ApplyIngotMaterial(item, material); } items.AddItem(item); } } } } } }
/// <summary> /// Generate a list of potential sites based on building type. /// This uses actual map layout and block data rather than the (often inaccurate) list of building in map data. /// Specify BuildingTypes.AllValid to find all valid building types /// </summary> SiteDetails[] CollectQuestSitesOfBuildingType(DFLocation location, DFLocation.BuildingTypes buildingType) { // Valid building types for valid search int[] validBuildingTypes = { 0, 2, 3, 5, 6, 8, 9, 11, 12, 13, 14, 15, 17, 18, 19, 20 }; List <SiteDetails> foundSites = new List <SiteDetails>(); // Iterate through all blocks DFBlock[] blocks; RMBLayout.GetLocationBuildingData(location, out blocks); int width = location.Exterior.ExteriorData.Width; int height = location.Exterior.ExteriorData.Height; for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { // Iterate through all buildings in this block int index = y * width + x; BuildingSummary[] buildingSummary = RMBLayout.GetBuildingData(blocks[index], x, y); for (int i = 0; i < buildingSummary.Length; i++) { // When enumAllValid is specified accept all valid building types bool forceAccept = false; if (buildingType == DFLocation.BuildingTypes.AllValid) { for (int j = 0; j < validBuildingTypes.Length; j++) { if (validBuildingTypes[j] == (int)buildingSummary[i].BuildingType) { forceAccept = true; break; } } } // Match building against required type if (buildingSummary[i].BuildingType == buildingType || forceAccept) { // Building must be a valid quest site QuestMarker[] questSpawnMarkers, questItemMarkers; EnumerateBuildingQuestMarkers(blocks[index], i, out questSpawnMarkers, out questItemMarkers); if (!ValidateQuestMarkers(questSpawnMarkers, questItemMarkers)) { continue; } // Get building name based on type string buildingName; if (RMBLayout.IsResidence(buildingType)) { // Generate a random surname for this residence DFRandom.srand(Time.renderedFrameCount); string surname = DaggerfallUnity.Instance.NameHelper.Surname(Utility.NameHelper.BankTypes.Breton); buildingName = HardStrings.theNamedResidence.Replace("%s", surname); } else { // Use fixed name buildingName = BuildingNames.GetName( buildingSummary[i].NameSeed, buildingSummary[i].BuildingType, buildingSummary[i].FactionId, location.Name, location.RegionName); } // Configure new site details SiteDetails site = new SiteDetails(); site.questUID = ParentQuest.UID; site.siteType = SiteTypes.Building; site.mapId = location.MapTableData.MapId; site.locationId = location.Exterior.ExteriorData.LocationId; site.regionName = location.RegionName; site.locationName = location.Name; site.buildingKey = buildingSummary[i].buildingKey; site.buildingName = buildingName; site.questSpawnMarkers = questSpawnMarkers; site.questItemMarkers = questItemMarkers; // Asssign markers only if available if (questSpawnMarkers != null) { siteDetails.selectedQuestSpawnMarker = UnityEngine.Random.Range(0, questSpawnMarkers.Length); } if (questItemMarkers != null) { siteDetails.selectedQuestItemMarker = UnityEngine.Random.Range(0, questItemMarkers.Length); } foundSites.Add(site); } } } } return(foundSites.ToArray()); }
/// <summary> /// Find a town for remote site containing building type. /// Daggerfall's locations are so generic that we usually find a match within a few random attempts /// compared to indexing several hundred locations and only selecting from known-good candidates. /// In short, there are so many possible candidates it's not worth narrowing them down. Throw darts instead. /// Basic checks are still done to reject unsuitable locations very quickly. /// </summary> bool SelectRemoteTownSite(DFLocation.BuildingTypes requiredBuildingType) { // Get player region int regionIndex = GameManager.Instance.PlayerGPS.CurrentRegionIndex; DFRegion regionData = DaggerfallUnity.Instance.ContentReader.MapFileReader.GetRegion(regionIndex); // Cannot use a region with no locations // This should not happen in normal play if (regionData.LocationCount == 0) { return(false); } // Find random town containing building int attempts = 0; bool found = false; while (!found) { // Increment attempts attempts++; // Get a random location index int locationIndex = UnityEngine.Random.Range(0, (int)regionData.LocationCount); // Discard all dungeon location types if (IsDungeonType(regionData.MapTable[locationIndex].LocationType)) { continue; } // Get location data for town DFLocation location = DaggerfallUnity.Instance.ContentReader.MapFileReader.GetLocation(regionIndex, locationIndex); if (!location.Loaded) { continue; } // Get list of valid sites SiteDetails[] foundSites = null; if (p2 == -1) { // Collect random building sites foundSites = CollectQuestSitesOfBuildingType(location, DFLocation.BuildingTypes.AllValid); } else { // Check if town contains specified building type in MAPS.BSA directory if (!HasBuildingType(location, requiredBuildingType)) { continue; } // Get an array of potential quest sites with specified building type // This ensures building site actually exists inside town, as MAPS.BSA directory can be incorrect foundSites = CollectQuestSitesOfBuildingType(location, (DFLocation.BuildingTypes)p2); } // Must have found at least one site if (foundSites == null || foundSites.Length == 0) { continue; } // Select a random site from available list int selectedIndex = UnityEngine.Random.Range(0, foundSites.Length); siteDetails = foundSites[selectedIndex]; // All conditions have been satisfied found = true; } //Debug.LogFormat("Found remote candidate site in {0} attempts", attempts); return(true); }
public static string GetName(int seed, DFLocation.BuildingTypes type, int factionID, string locationName, string regionName) { const string firstNameTitleVar = "%ef"; const string cityNameTitleVar = "%cn"; const string royalTitleVar = "%rt"; string a = string.Empty, b = string.Empty; string result = string.Empty; bool singleton = false; FactionFile.FactionData factionData; DFRandom.srand(seed); switch (type) { case DFLocation.BuildingTypes.HouseForSale: return("House for sale"); case DFLocation.BuildingTypes.Tavern: b = TavernsB[DFRandom.random_range(0, TavernsB.Length)]; a = TavernsA[DFRandom.random_range(0, TavernsA.Length)]; break; case DFLocation.BuildingTypes.GeneralStore: b = GeneralStoresB[DFRandom.random_range(0, GeneralStoresB.Length)]; a = StoresA[DFRandom.random_range(0, StoresA.Length)]; break; case DFLocation.BuildingTypes.WeaponSmith: b = WeaponStoresB[DFRandom.random_range(0, WeaponStoresB.Length)]; a = StoresA[DFRandom.random_range(0, StoresA.Length)]; break; case DFLocation.BuildingTypes.Armorer: b = ArmorStoresB[DFRandom.random_range(0, ArmorStoresB.Length)]; a = StoresA[DFRandom.random_range(0, StoresA.Length)]; break; case DFLocation.BuildingTypes.Bookseller: b = BookStoresB[DFRandom.random_range(0, BookStoresB.Length)]; a = StoresA[DFRandom.random_range(0, StoresA.Length)]; break; case DFLocation.BuildingTypes.ClothingStore: b = ClothingStoresB[DFRandom.random_range(0, ClothingStoresB.Length)]; a = StoresA[DFRandom.random_range(0, StoresA.Length)]; break; case DFLocation.BuildingTypes.Alchemist: b = AlchemyStoresB[DFRandom.random_range(0, AlchemyStoresB.Length)]; a = StoresA[DFRandom.random_range(0, StoresA.Length)]; break; case DFLocation.BuildingTypes.GemStore: b = GemStoresB[DFRandom.random_range(0, GemStoresB.Length)]; a = StoresA[DFRandom.random_range(0, StoresA.Length)]; break; case DFLocation.BuildingTypes.PawnShop: b = PawnStoresB[DFRandom.random_range(0, PawnStoresB.Length)]; a = StoresA[DFRandom.random_range(0, StoresA.Length)]; break; case DFLocation.BuildingTypes.FurnitureStore: b = FurnitureStoresB[DFRandom.random_range(0, FurnitureStoresB.Length)]; a = StoresA[DFRandom.random_range(0, StoresA.Length)]; break; case DFLocation.BuildingTypes.Library: b = LibraryStoresB[DFRandom.random_range(0, LibraryStoresB.Length)]; a = StoresA[DFRandom.random_range(0, StoresA.Length)]; break; case DFLocation.BuildingTypes.Bank: // Banks always appear to be named "The Bank of RegionName" b = regionName; a = "The Bank of"; break; case DFLocation.BuildingTypes.GuildHall: // Guild halls get the name from faction data if (DaggerfallUnity.Instance.ContentReader.FactionFileReader.GetFactionData(factionID, out factionData)) { a = factionData.name; singleton = true; } break; case DFLocation.BuildingTypes.Temple: // Temples get name from faction data - always seem to be first child of factionID if (DaggerfallUnity.Instance.ContentReader.FactionFileReader.GetFactionData(factionID, out factionData)) { if (factionData.children.Count > 0) { FactionFile.FactionData firstChild; if (DaggerfallUnity.Instance.ContentReader.FactionFileReader.GetFactionData(factionData.children[0], out firstChild)) { a = firstChild.name; singleton = true; } } } break; case DFLocation.BuildingTypes.Palace: // Main palace names come from TEXT.RSC (e.g. "Castle Daggerfall") // Other palaces are just named "Palace" (still need to confirm behaviour) int textId = 0; if (locationName == "Daggerfall") { textId = 475; } else if (locationName == "Wayrest") { textId = 476; } else if (locationName == "Sentinel") { textId = 477; } if (textId > 0) { TextFile.Token[] nameTokens = DaggerfallUnity.Instance.TextProvider.GetRSCTokens(textId); foreach (TextFile.Token token in nameTokens) { if (token.formatting == TextFile.Formatting.Text) { a = token.text; break; } } a = a.TrimEnd('.'); // remove character '.' from castle text record entry if it is last character } else { a = "Palace"; } singleton = true; break; default: // Do nothing for unknown/unsupported building type // Houses can actually change names based on active quests return(string.Empty); } // Replace %cn a = a.Replace(cityNameTitleVar, locationName); // Replace %ef if (a.Contains(firstNameTitleVar)) { // Need to burn a rand() for %ef roll to be correct. // Classic is always doing this when expanding a macro. DFRandom.rand(); // In classic, the function expanding the %ef macro uses a global variable containing the current // region race. However, this variable is never updated when the character travels // and remains at 0. This explains why the Breton name bank is always used for shops. // This global variable is probably a leftover from Daggerfall early development as, // with the exception of %lp, which presents a similar issue and always returns // "High Rock", all naming functions use a global array of 62 fixed race values, one for each region. // As with %lp, we choose to fix the original bug in DFU and use this array, meaning that // all shops in Hammerfell now use Redguard names. NameHelper.BankTypes nameBank = (NameHelper.BankTypes)MapsFile.RegionRaces[GameManager.Instance.PlayerGPS.CurrentRegionIndex]; string firstName = DaggerfallUnity.Instance.NameHelper.FirstName(nameBank, Game.Entity.Genders.Male); a = a.Replace(firstNameTitleVar, firstName); } // Replace %rt based on faction ruler if (a.Contains(royalTitleVar)) { a = a.Replace(royalTitleVar, MacroHelper.RegentTitle(null)); } // Final text is "{a} {b}" for two-part names or just "{a}" for singleton names if (!singleton) { result = string.Format("{0} {1}", a, b); } else { result = a; } return(result); }
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 } } }
public static string GetName(int seed, DFLocation.BuildingTypes type, int factionID, string locationName, string regionName) { const string firstNameTitleVar = "%ef"; const string cityNameTitleVar = "%cn"; const string royalTitleVar = "%rt"; string a = string.Empty, b = string.Empty; string result = string.Empty; bool singleton = false; FactionFile.FactionData factionData; DFRandom.srand(seed); switch (type) { case DFLocation.BuildingTypes.HouseForSale: return("House for sale"); case DFLocation.BuildingTypes.Tavern: b = TavernsB[DFRandom.random_range(0, TavernsB.Length)]; a = TavernsA[DFRandom.random_range(0, TavernsA.Length)]; break; case DFLocation.BuildingTypes.GeneralStore: b = GeneralStoresB[DFRandom.random_range(0, GeneralStoresB.Length)]; a = StoresA[DFRandom.random_range(0, StoresA.Length)]; break; case DFLocation.BuildingTypes.WeaponSmith: b = WeaponStoresB[DFRandom.random_range(0, WeaponStoresB.Length)]; a = StoresA[DFRandom.random_range(0, StoresA.Length)]; break; case DFLocation.BuildingTypes.Armorer: b = ArmorStoresB[DFRandom.random_range(0, ArmorStoresB.Length)]; a = StoresA[DFRandom.random_range(0, StoresA.Length)]; break; case DFLocation.BuildingTypes.Bookseller: b = BookStoresB[DFRandom.random_range(0, BookStoresB.Length)]; a = StoresA[DFRandom.random_range(0, StoresA.Length)]; break; case DFLocation.BuildingTypes.ClothingStore: b = ClothingStoresB[DFRandom.random_range(0, ClothingStoresB.Length)]; a = StoresA[DFRandom.random_range(0, StoresA.Length)]; break; case DFLocation.BuildingTypes.Alchemist: b = AlchemyStoresB[DFRandom.random_range(0, AlchemyStoresB.Length)]; a = StoresA[DFRandom.random_range(0, StoresA.Length)]; break; case DFLocation.BuildingTypes.GemStore: b = GemStoresB[DFRandom.random_range(0, GemStoresB.Length)]; a = StoresA[DFRandom.random_range(0, StoresA.Length)]; break; case DFLocation.BuildingTypes.PawnShop: b = PawnStoresB[DFRandom.random_range(0, PawnStoresB.Length)]; a = StoresA[DFRandom.random_range(0, StoresA.Length)]; break; case DFLocation.BuildingTypes.FurnitureStore: b = FurnitureStoresB[DFRandom.random_range(0, FurnitureStoresB.Length)]; a = StoresA[DFRandom.random_range(0, StoresA.Length)]; break; case DFLocation.BuildingTypes.Library: b = LibraryStoresB[DFRandom.random_range(0, LibraryStoresB.Length)]; a = StoresA[DFRandom.random_range(0, StoresA.Length)]; break; case DFLocation.BuildingTypes.Bank: // Banks always appear to be named "The Bank of RegionName" b = regionName; a = "The Bank of"; break; case DFLocation.BuildingTypes.GuildHall: // Guild halls get the name from faction data if (DaggerfallUnity.Instance.ContentReader.FactionFileReader.GetFactionData(factionID, out factionData)) { a = factionData.name; singleton = true; } break; case DFLocation.BuildingTypes.Temple: // Temples get name from faction data - always seem to be first child of factionID if (DaggerfallUnity.Instance.ContentReader.FactionFileReader.GetFactionData(factionID, out factionData)) { if (factionData.children.Count > 0) { FactionFile.FactionData firstChild; if (DaggerfallUnity.Instance.ContentReader.FactionFileReader.GetFactionData(factionData.children[0], out firstChild)) { a = firstChild.name; singleton = true; } } } break; case DFLocation.BuildingTypes.Palace: // Main palace names (e.g. "Castle Daggerfall" appear to be hardcoded in FALL.EXE // Other palaces are just named "Palace" // Need to confirm behaviour before implementing // Just calling everything "Palace" for now. a = "Palace"; singleton = true; break; default: // Do nothing for unknown/unsupported building type // Houses can actually change names based on active quests return(string.Empty); } // Replace %cn a = a.Replace(cityNameTitleVar, locationName); // Replace %ef if (a.Contains(firstNameTitleVar)) { // Need to burn a rand() for %ef roll to be correct // What is Daggerfall rolling here? DFRandom.rand(); // Observation finds nameplates only seem to use male Breton namebank string firstName = DaggerfallUnity.Instance.NameHelper.FirstName(NameHelper.BankTypes.Breton, Game.Entity.Genders.Male); a = a.Replace(firstNameTitleVar, firstName); } // Replace %rt based on faction ruler if (a.Contains(royalTitleVar)) { // Get factionID of this region FactionFile factionFile = DaggerfallUnity.Instance.ContentReader.FactionFileReader; int regionalFactionID = factionFile.GetFactionID(regionName); if (regionalFactionID != -1) { // Get faction data if (factionFile.GetFactionData(factionID, out factionData)) { // Get ruler title for this region string royalTile = RoyalTitles[factionData.ruler]; a = a.Replace(royalTitleVar, royalTile); } } } // Final text is "{a} {b}" for two-part names or just "{a}" for singleton names if (!singleton) { result = string.Format("{0} {1}", a, b); } else { result = a; } return(result); }
/// <summary> /// Transition player through an exterior door into building interior. /// </summary> /// <param name="doorOwner">Parent transform owning door array..</param> /// <param name="door">Exterior door player clicked on.</param> public void TransitionInterior(Transform doorOwner, StaticDoor door, bool doFade = false) { // Ensure we have component references if (!ReferenceComponents()) return; // Copy owner position to door // This ensures the door itself is all we need to reposition interior // Useful when loading a save and doorOwner is null (as outside world does not exist) if (doorOwner) { door.ownerPosition = doorOwner.position; door.ownerRotation = doorOwner.rotation; } // Raise event RaiseOnPreTransitionEvent(TransitionType.ToBuildingInterior, door); // Get climate ClimateBases climateBase = ClimateBases.Temperate; if (OverrideLocation) climateBase = OverrideLocation.Summary.Climate; else if (playerGPS) climateBase = ClimateSwaps.FromAPIClimateBase(playerGPS.ClimateSettings.ClimateType); // Layout interior // This needs to be done first so we know where the enter markers are GameObject newInterior = new GameObject(string.Format("DaggerfallInterior [Block={0}, Record={1}]", door.blockIndex, door.recordIndex)); newInterior.hideFlags = defaultHideFlags; interior = newInterior.AddComponent<DaggerfallInterior>(); // Try to layout interior // If we fail for any reason, use that old chestnut "this house has nothing of value" try { interior.DoLayout(doorOwner, door, climateBase); } catch { DaggerfallUI.AddHUDText(UserInterfaceWindows.HardStrings.thisHouseHasNothingOfValue); Destroy(newInterior); return; } // Position interior directly inside of exterior // This helps with finding closest enter/exit point relative to player position interior.transform.position = door.ownerPosition + (Vector3)door.buildingMatrix.GetColumn(3); interior.transform.rotation = GameObjectHelper.QuaternionFromMatrix(door.buildingMatrix); // Position player above closest enter marker Vector3 marker; if (!interior.FindClosestEnterMarker(transform.position, out marker)) { // Could not find an enter marker, probably not a valid interior Destroy(newInterior); return; } // Enumerate all exterior doors belonging to this building DaggerfallStaticDoors exteriorStaticDoors = interior.ExteriorDoors; if (exteriorStaticDoors && doorOwner) { List<StaticDoor> buildingDoors = new List<StaticDoor>(); for (int i = 0; i < exteriorStaticDoors.Doors.Length; i++) { if (exteriorStaticDoors.Doors[i].recordIndex == door.recordIndex) { StaticDoor newDoor = exteriorStaticDoors.Doors[i]; newDoor.ownerPosition = doorOwner.position; newDoor.ownerRotation = doorOwner.rotation; buildingDoors.Add(newDoor); } } exteriorDoors = buildingDoors.ToArray(); } // Assign new interior to parent if (InteriorParent != null) newInterior.transform.parent = InteriorParent.transform; // Cache some information about this interior buildingType = interior.BuildingData.BuildingType; // Set player to marker position // TODO: Find closest door for player facing transform.position = marker + Vector3.up * (controller.height * 0.6f); SetStanding(); EnableInteriorParent(); // Raise event RaiseOnTransitionInteriorEvent(door, interior); // Fade in from black if (doFade) DaggerfallUI.Instance.FadeHUDFromBlack(); }
/// <summary> /// Checks if building is a tavern. /// </summary> public static bool IsTavern(DFLocation.BuildingTypes buildingType) => buildingType == DFLocation.BuildingTypes.Tavern;
public void StockShopShelf(PlayerGPS.DiscoveredBuilding buildingData) { stockedDate = CreateStockedDate(DaggerfallUnity.Instance.WorldTime.Now); items.Clear(); DFLocation.BuildingTypes buildingType = buildingData.buildingType; int shopQuality = buildingData.quality; Game.Entity.PlayerEntity playerEntity = GameManager.Instance.PlayerEntity; byte[] itemGroups = { 0 }; switch (buildingType) { case DFLocation.BuildingTypes.Alchemist: itemGroups = DaggerfallLootDataTables.itemGroupsAlchemist; RandomlyAddPotionRecipe(25, items); break; case DFLocation.BuildingTypes.Armorer: itemGroups = DaggerfallLootDataTables.itemGroupsArmorer; break; case DFLocation.BuildingTypes.Bookseller: itemGroups = DaggerfallLootDataTables.itemGroupsBookseller; break; case DFLocation.BuildingTypes.ClothingStore: itemGroups = DaggerfallLootDataTables.itemGroupsClothingStore; break; case DFLocation.BuildingTypes.GemStore: itemGroups = DaggerfallLootDataTables.itemGroupsGemStore; break; case DFLocation.BuildingTypes.GeneralStore: itemGroups = DaggerfallLootDataTables.itemGroupsGeneralStore; items.AddItem(ItemBuilder.CreateItem(ItemGroups.Transportation, (int)Transportation.Horse)); items.AddItem(ItemBuilder.CreateItem(ItemGroups.Transportation, (int)Transportation.Small_cart)); break; case DFLocation.BuildingTypes.PawnShop: itemGroups = DaggerfallLootDataTables.itemGroupsPawnShop; break; case DFLocation.BuildingTypes.WeaponSmith: itemGroups = DaggerfallLootDataTables.itemGroupsWeaponSmith; break; } for (int i = 0; i < itemGroups.Length; i += 2) { ItemGroups itemGroup = (ItemGroups)itemGroups[i]; int chanceMod = itemGroups[i + 1]; if (itemGroup == ItemGroups.MensClothing && playerEntity.Gender == Game.Entity.Genders.Female) { itemGroup = ItemGroups.WomensClothing; } if (itemGroup == ItemGroups.WomensClothing && playerEntity.Gender == Game.Entity.Genders.Male) { itemGroup = ItemGroups.MensClothing; } if (itemGroup != ItemGroups.Furniture && itemGroup != ItemGroups.UselessItems1) { if (itemGroup == ItemGroups.Books) { int qualityMod = (shopQuality + 3) / 5; if (qualityMod >= 4) { --qualityMod; } qualityMod++; for (int j = 0; j <= qualityMod; ++j) { items.AddItem(ItemBuilder.CreateRandomBook()); } } else { System.Array enumArray = DaggerfallUnity.Instance.ItemHelper.GetEnumArray(itemGroup); for (int j = 0; j < enumArray.Length; ++j) { DaggerfallConnect.FallExe.ItemTemplate itemTemplate = DaggerfallUnity.Instance.ItemHelper.GetItemTemplate(itemGroup, j); if (itemTemplate.rarity <= shopQuality) { int stockChance = chanceMod * 5 * (21 - itemTemplate.rarity) / 100; if (Random.Range(1, 101) <= stockChance) { DaggerfallUnityItem item = null; if (itemGroup == ItemGroups.Weapons) { item = ItemBuilder.CreateWeapon(j + Weapons.Dagger, ItemBuilder.RandomMaterial(playerEntity.Level)); } else if (itemGroup == ItemGroups.Armor) { item = ItemBuilder.CreateArmor(playerEntity.Gender, playerEntity.Race, j + Armor.Cuirass, ItemBuilder.RandomArmorMaterial(playerEntity.Level)); } else if (itemGroup == ItemGroups.MensClothing) { item = ItemBuilder.CreateMensClothing(j + MensClothing.Straps, playerEntity.Race); item.dyeColor = ItemBuilder.RandomClothingDye(); } else if (itemGroup == ItemGroups.WomensClothing) { item = ItemBuilder.CreateWomensClothing(j + WomensClothing.Brassier, playerEntity.Race); item.dyeColor = ItemBuilder.RandomClothingDye(); } else { item = new DaggerfallUnityItem(itemGroup, j); } items.AddItem(item); } } } } } } }
public static string GetName(int seed, DFLocation.BuildingTypes type, int factionID, string locationName, string regionName) { const string firstNameTitleVar = "%ef"; const string cityNameTitleVar = "%cn"; const string royalTitleVar = "%rt"; string a = string.Empty, b = string.Empty; string result = string.Empty; bool singleton = false; FactionFile.FactionData factionData; DFRandom.srand(seed); switch (type) { case DFLocation.BuildingTypes.HouseForSale: return("House for sale"); case DFLocation.BuildingTypes.Tavern: b = TavernsB[DFRandom.random_range(0, TavernsB.Length)]; a = TavernsA[DFRandom.random_range(0, TavernsA.Length)]; break; case DFLocation.BuildingTypes.GeneralStore: b = GeneralStoresB[DFRandom.random_range(0, GeneralStoresB.Length)]; a = StoresA[DFRandom.random_range(0, StoresA.Length)]; break; case DFLocation.BuildingTypes.WeaponSmith: b = WeaponStoresB[DFRandom.random_range(0, WeaponStoresB.Length)]; a = StoresA[DFRandom.random_range(0, StoresA.Length)]; break; case DFLocation.BuildingTypes.Armorer: b = ArmorStoresB[DFRandom.random_range(0, ArmorStoresB.Length)]; a = StoresA[DFRandom.random_range(0, StoresA.Length)]; break; case DFLocation.BuildingTypes.Bookseller: b = BookStoresB[DFRandom.random_range(0, BookStoresB.Length)]; a = StoresA[DFRandom.random_range(0, StoresA.Length)]; break; case DFLocation.BuildingTypes.ClothingStore: b = ClothingStoresB[DFRandom.random_range(0, ClothingStoresB.Length)]; a = StoresA[DFRandom.random_range(0, StoresA.Length)]; break; case DFLocation.BuildingTypes.Alchemist: b = AlchemyStoresB[DFRandom.random_range(0, AlchemyStoresB.Length)]; a = StoresA[DFRandom.random_range(0, StoresA.Length)]; break; case DFLocation.BuildingTypes.GemStore: b = GemStoresB[DFRandom.random_range(0, GemStoresB.Length)]; a = StoresA[DFRandom.random_range(0, StoresA.Length)]; break; case DFLocation.BuildingTypes.PawnShop: b = PawnStoresB[DFRandom.random_range(0, PawnStoresB.Length)]; a = StoresA[DFRandom.random_range(0, StoresA.Length)]; break; case DFLocation.BuildingTypes.FurnitureStore: b = FurnitureStoresB[DFRandom.random_range(0, FurnitureStoresB.Length)]; a = StoresA[DFRandom.random_range(0, StoresA.Length)]; break; case DFLocation.BuildingTypes.Library: b = LibraryStoresB[DFRandom.random_range(0, LibraryStoresB.Length)]; a = StoresA[DFRandom.random_range(0, StoresA.Length)]; break; case DFLocation.BuildingTypes.Bank: // Banks always appear to be named "The Bank of RegionName" b = regionName; a = "The Bank of"; break; case DFLocation.BuildingTypes.GuildHall: // Guild halls get the name from faction data if (DaggerfallUnity.Instance.ContentReader.FactionFileReader.GetFactionData(factionID, out factionData)) { a = factionData.name; singleton = true; } break; case DFLocation.BuildingTypes.Temple: // Temples get name from faction data - always seem to be first child of factionID if (DaggerfallUnity.Instance.ContentReader.FactionFileReader.GetFactionData(factionID, out factionData)) { if (factionData.children.Count > 0) { FactionFile.FactionData firstChild; if (DaggerfallUnity.Instance.ContentReader.FactionFileReader.GetFactionData(factionData.children[0], out firstChild)) { a = firstChild.name; singleton = true; } } } break; case DFLocation.BuildingTypes.Palace: // Main palace names come from TEXT.RSC (e.g. "Castle Daggerfall") // Other palaces are just named "Palace" (still need to confirm behaviour) int textId = 0; if (locationName == "Daggerfall") { textId = 475; } else if (locationName == "Wayrest") { textId = 476; } else if (locationName == "Sentinel") { textId = 477; } if (textId > 0) { TextFile.Token[] nameTokens = DaggerfallUnity.Instance.TextProvider.GetRSCTokens(textId); foreach (TextFile.Token token in nameTokens) { if (token.formatting == TextFile.Formatting.Text) { a = token.text; break; } } a = a.TrimEnd('.'); // remove character '.' from castle text record entry if it is last character } else { a = "Palace"; } singleton = true; break; default: // Do nothing for unknown/unsupported building type // Houses can actually change names based on active quests return(string.Empty); } // Replace %cn a = a.Replace(cityNameTitleVar, locationName); // Replace %ef if (a.Contains(firstNameTitleVar)) { // Need to burn a rand() for %ef roll to be correct // What is Daggerfall rolling here? DFRandom.rand(); // Observation finds nameplates only seem to use male Breton namebank string firstName = DaggerfallUnity.Instance.NameHelper.FirstName(NameHelper.BankTypes.Breton, Game.Entity.Genders.Male); a = a.Replace(firstNameTitleVar, firstName); } // Replace %rt based on faction ruler if (a.Contains(royalTitleVar)) { a = a.Replace(royalTitleVar, MacroHelper.RegentTitle(null)); } // Final text is "{a} {b}" for two-part names or just "{a}" for singleton names if (!singleton) { result = string.Format("{0} {1}", a, b); } else { result = a; } return(result); }
/// <summary> /// Add interior people flats. /// </summary> private void AddPeople(PlayerGPS.DiscoveredBuilding buildingData) { GameObject node = new GameObject(peopleFlats); node.transform.parent = this.transform; IGuild guild = GameManager.Instance.GuildManager.GetGuild(buildingData.factionID); bool isMemberOfBuildingGuild = guild.IsMember(); // Add block flats foreach (DFBlock.RmbBlockPeopleRecord obj in recordData.Interior.BlockPeopleRecords) { // Calculate position Vector3 billboardPosition = new Vector3(obj.XPos, -obj.YPos, obj.ZPos) * MeshReader.GlobalScale; // Make person gameobject GameObject go = MeshReplacement.ImportCustomFlatGameobject(obj.TextureArchive, obj.TextureRecord, billboardPosition, node.transform); if (!go) { // Spawn billboard gameobject go = GameObjectHelper.CreateDaggerfallBillboardGameObject(obj.TextureArchive, obj.TextureRecord, node.transform); // Handle non-classic textures, which may not have had their collision component added if (!go.GetComponent <Collider>()) { Collider col = go.AddComponent <BoxCollider>(); col.isTrigger = true; } // Set position Billboard dfBillboard = go.GetComponent <Billboard>(); go.transform.position = billboardPosition; go.transform.position += new Vector3(0, dfBillboard.Summary.Size.y / 2, 0); // Add RMB data to billboard dfBillboard.SetRMBPeopleData(obj); } else { Billboard dfBillboard = go.GetComponent <Billboard>(); if (dfBillboard) { dfBillboard.SetRMBPeopleData(obj); } } // Add StaticNPC behaviour StaticNPC npc = go.AddComponent <StaticNPC>(); npc.SetLayoutData(obj, entryDoor.buildingKey); // Disable people if shop or building is closed DFLocation.BuildingTypes buildingType = buildingData.buildingType; if ((RMBLayout.IsShop(buildingType) && !GameManager.Instance.PlayerEnterExit.IsPlayerInsideOpenShop) || (buildingType <= DFLocation.BuildingTypes.Palace && !RMBLayout.IsShop(buildingType) && !(PlayerActivate.IsBuildingOpen(buildingType) || buildingType == DFLocation.BuildingTypes.GuildHall && guild.HallAccessAnytime()))) { go.SetActive(false); } // Disable people if player owns this house else if (DaggerfallBankManager.IsHouseOwned(buildingData.buildingKey)) { go.SetActive(false); } // Disable people if this is TG/DB house and player is not a member else if (buildingData.buildingType == DFLocation.BuildingTypes.House2 && buildingData.factionID != 0 && !isMemberOfBuildingGuild) { go.SetActive(false); } } }