/// <summary> /// Gets the dominant race in player's current region. /// This seems to be based on subclimate rather than FACTION.TXT. /// The faction data has very little diversity and does not match observed race in many regions. /// </summary> public Races GetRaceOfCurrentRegion() { // Racial distribution in Daggerfall: // * Desert, Desert2, Rainforest = Redguard // * Mountain, MountainWoods = Nord // * Swamp, Subtropical, Woodlands, Default = Breton DFLocation.ClimateSettings settings = MapsFile.GetWorldClimateSettings(climateSettings.WorldClimate); switch (settings.People) { case FactionFile.FactionRaces.Redguard: return(Races.Redguard); case FactionFile.FactionRaces.Nord: return(Races.Nord); case FactionFile.FactionRaces.Breton: default: return(Races.Breton); } }
/// <summary> /// Updates discovered building data in current location. /// </summary> /// <param name="discoveredBuilding">Updated data to write back to live discovery database.</param> void UpdateDiscoveredBuilding(DiscoveredBuilding discoveredBuildingIn) { // Must have discovered building if (!HasDiscoveredBuilding(discoveredBuildingIn.buildingKey)) { return; } // Get the location discovery for this mapID int mapPixelID = MapsFile.GetMapPixelIDFromLongitudeLatitude((int)CurrentLocation.MapTableData.Longitude, CurrentLocation.MapTableData.Latitude); DiscoveredLocation dl = discoveredLocations[mapPixelID]; if (dl.discoveredBuildings == null) { return; } // Replace discovery data for building dl.discoveredBuildings.Remove(discoveredBuildingIn.buildingKey); dl.discoveredBuildings.Add(discoveredBuildingIn.buildingKey, discoveredBuildingIn); }
/// <summary> /// Creates a new block node. /// </summary> /// <param name="name">Block name.</param> /// <param name="climate">Climate settings.</param> /// <param name="clearGroundTextures">Clear ground plane texture dictionary.</param> /// <returns>BlockNode.</returns> public BlockNode CreateBlockNode(string name, DFLocation.ClimateSettings?climate, bool clearGroundTextures) { // Load block DFBlock block; if (!LoadDaggerfallBlock(name, out block)) { return(null); } // Set default world climate if (climate == null) { climate = MapsFile.GetWorldClimateSettings(defaultWorldClimate); } // Reset ground plane texture cache if (clearGroundTextures) { textureManager.ClearGroundTextures(); } // Build node BlockNode node = null; switch (block.Type) { case DFBlock.BlockTypes.Rmb: textureManager.ClimateType = climate.Value.ClimateType; node = BuildRMBNode(ref block, climate.Value); break; case DFBlock.BlockTypes.Rdb: textureManager.ClimateType = DFLocation.ClimateBaseType.None; node = BuildRDBNode(ref block); break; } return(node); }
/// <summary> /// Constructor. Accepts pre-created TextureManager, ModelManager, /// BlocksFile, and MapsFile objects. /// These content managers cannot be NULL and must /// be configured ready for use. /// </summary> /// <param name="textureManager">TextureManager.</param> /// <param name="modelManager">ModelManager</param> /// <param name="blocksFile">BlocksFile.</param> /// <param name="mapsFile">MapsFile.</param> public SceneBuilder( TextureManager textureManager, ModelManager modelManager, BlocksFile blocksFile, MapsFile mapsFile) { // Check managers non-null if (textureManager == null || modelManager == null || blocksFile == null || mapsFile == null) { throw new Exception( "One or more content managers are NULL."); } // Store this.textureManager = textureManager; this.modelManager = modelManager; this.blocksFile = blocksFile; this.mapsFile = mapsFile; }
/// <summary> /// Setup API file readers. /// </summary> private void SetupReaders() { // Try to setup Arena2-dependent content readers if (blockFileReader == null) { blockFileReader = new BlocksFile(Path.Combine(arena2Path, BlocksFile.Filename), FileUsage.UseMemory, true); } if (mapFileReader == null) { mapFileReader = new MapsFile(Path.Combine(arena2Path, MapsFile.Filename), FileUsage.UseMemory, true); } if (monsterFileReader == null) { monsterFileReader = new MonsterFile(Path.Combine(arena2Path, MonsterFile.Filename), FileUsage.UseMemory, true); } if (woodsFileReader == null) { woodsFileReader = new WoodsFile(Path.Combine(arena2Path, WoodsFile.Filename), FileUsage.UseMemory, true); } if (factionFileReader == null) { factionFileReader = new FactionFile(Path.Combine(arena2Path, FactionFile.Filename), FileUsage.UseMemory, true); } if (flatsFileReader == null) { flatsFileReader = new FlatsFile(Path.Combine(arena2Path, FlatsFile.Filename), FileUsage.UseMemory, true); } //if (spellIconCollection == null) // spellIconCollection = new SpellIconCollection(); // Build map lookup dictionary if (mapDict == null && mapFileReader != null) { EnumerateMaps(); } // Raise ready flag isReady = true; }
/// <summary> /// Convert a scene position back into virtual world space. /// This is specific to the peered location due to floating origin. /// </summary> /// <param name="scenePosition">Scene position to convert to nearest point in world space.</param> /// <returns>World DFPosition.</returns> public DFPosition SceneToWorldPosition(Vector3 scenePosition) { // Validate DaggerfallLocation if (!dfLocation || dfLocation.Summary.MapID == 0) { throw new Exception(noLocationError); } // Get location origin in both scene and world // The SW origin of location in scene spaces aligns with SW terrain tile origin in world space Vector3 locationOrigin = dfLocation.transform.position; DFPosition worldOrigin = MapsFile.MapPixelToWorldCoord(dfLocation.Summary.MapPixelX, dfLocation.Summary.MapPixelY); // Get difference between origin and target position in scene space Vector3 difference = scenePosition - locationOrigin; // Convert difference into Daggerfall units and apply to origin in world space DFPosition result = new DFPosition( (int)(difference.x * StreamingWorld.SceneMapRatio) + worldOrigin.X, (int)(difference.z * StreamingWorld.SceneMapRatio) + worldOrigin.Y); return(result); }
/// <summary> /// Gets discovered building data for current location. /// </summary> /// <param name="buildingKey">Building key in current location.</param> /// <param name="discoveredBuildingOut">Building discovery data out.</param> /// <returns>True if building discovered, false if building not discovered.</returns> public bool GetDiscoveredBuilding(int buildingKey, out DiscoveredBuilding discoveredBuildingOut) { discoveredBuildingOut = new DiscoveredBuilding(); // Must have discovered building if (!HasDiscoveredBuilding(buildingKey)) { return(false); } // Get the location discovery for this mapID int mapPixelID = MapsFile.GetMapPixelIDFromLongitudeLatitude((int)CurrentLocation.MapTableData.Longitude, CurrentLocation.MapTableData.Latitude); DiscoveredLocation dl = discoveredLocations[mapPixelID]; if (dl.discoveredBuildings == null) { return(false); } // Get discovery data for building bool discovered = GetBuildingDiscoveryData(buildingKey, out discoveredBuildingOut); return(true); }
public override void Update(Task caller) { base.Update(caller); // Do nothing while player respawning if (GameManager.Instance.PlayerEnterExit.IsRespawning) { return; } // Handle resume on next tick of action after respawn process complete if (resumePending) { GameObject player = GameManager.Instance.PlayerObject; player.transform.position = resumePosition; resumePending = false; SetComplete(); return; } // Create SiteLink if not already present if (!QuestMachine.HasSiteLink(ParentQuest, targetPlace)) { QuestMachine.CreateSiteLink(ParentQuest, targetPlace); } // Attempt to get Place resource Place place = ParentQuest.GetPlace(targetPlace); if (place == null) { return; } // Get selected spawn QuestMarker for this Place bool usingMarker = false; QuestMarker marker = new QuestMarker(); if (targetMarker >= 0 && targetMarker < place.SiteDetails.questSpawnMarkers.Length) { marker = place.SiteDetails.questSpawnMarkers[targetMarker]; usingMarker = true; } // Attempt to get location data - using GetLocation(regionName, locationName) as it can support all locations DFLocation location; if (!DaggerfallUnity.Instance.ContentReader.GetLocation(place.SiteDetails.regionName, place.SiteDetails.locationName, out location)) { return; } // Spawn inside dungeon at this world position DFPosition mapPixel = MapsFile.LongitudeLatitudeToMapPixel((int)location.MapTableData.Longitude, location.MapTableData.Latitude); DFPosition worldPos = MapsFile.MapPixelToWorldCoord(mapPixel.X, mapPixel.Y); GameManager.Instance.PlayerEnterExit.RespawnPlayer( worldPos.X, worldPos.Y, true, true); // Determine start position if (usingMarker) { // Use specified quest marker Vector3 dungeonBlockPosition = new Vector3(marker.dungeonX * RDBLayout.RDBSide, 0, marker.dungeonZ * RDBLayout.RDBSide); resumePosition = dungeonBlockPosition + marker.flatPosition; } else { // Use first quest marker marker = place.SiteDetails.questSpawnMarkers[0]; Vector3 dungeonBlockPosition = new Vector3(marker.dungeonX * RDBLayout.RDBSide, 0, marker.dungeonZ * RDBLayout.RDBSide); resumePosition = dungeonBlockPosition + marker.flatPosition; } resumePending = true; }
private void UpdateMode(TransportModes transportMode) { // Update the transport mode and stop any riding sounds playing. mode = transportMode; if (ridingAudioSource.isPlaying) { ridingAudioSource.Stop(); } if (mode == TransportModes.Horse || mode == TransportModes.Cart) { // Tell player motor we're riding. playerMotor.IsRiding = true; // Setup appropriate riding sounds. SoundClips sound = (mode == TransportModes.Horse) ? horseRidingSound2 : cartRidingSound; ridingAudioSource.clip = dfAudioSource.GetAudioClip((int)sound); // Setup appropriate riding textures. string textureName = (mode == TransportModes.Horse) ? horseTextureName : cartTextureName; for (int i = 0; i < 4; i++) { ridingTexures[i] = ImageReader.GetImageData(textureName, 0, i, true, true); } ridingTexture = ridingTexures[0]; // Initialise neighing timer. neighTime = Time.time + Random.Range(1, 5); } else { // Tell player motor we're not riding. playerMotor.IsRiding = false; } if (mode == TransportModes.Ship) { GameManager.Instance.PlayerMotor.CancelMovement = true; SerializablePlayer serializablePlayer = GetComponent <SerializablePlayer>(); DaggerfallUI.Instance.FadeBehaviour.SmashHUDToBlack(); StreamingWorld world = GameManager.Instance.StreamingWorld; DFPosition shipCoords = DaggerfallBankManager.GetShipCoords(); // Is there recorded position before boarding and is player on the ship? if (IsOnShip()) { // Check for terrain sampler changes. (so don't fall through floor) StreamingWorld.RepositionMethods reposition = StreamingWorld.RepositionMethods.None; if (boardShipPosition.terrainSamplerName != DaggerfallUnity.Instance.TerrainSampler.ToString() || boardShipPosition.terrainSamplerVersion != DaggerfallUnity.Instance.TerrainSampler.Version) { reposition = StreamingWorld.RepositionMethods.RandomStartMarker; if (DaggerfallUI.Instance.DaggerfallHUD != null) { DaggerfallUI.Instance.DaggerfallHUD.PopupText.AddText("Terrain sampler changed. Repositioning player."); } } // Restore player position from before boarding ship, caching ship scene first. SaveLoadManager.CacheScene(world.SceneName); // TODO: Should this should move into teleport to support other teleports? Issue only if inside. (e.g. recall) DFPosition mapPixel = MapsFile.WorldCoordToMapPixel(boardShipPosition.worldPosX, boardShipPosition.worldPosZ); world.TeleportToCoordinates(mapPixel.X, mapPixel.Y, reposition); serializablePlayer.RestorePosition(boardShipPosition); boardShipPosition = null; // Restore cached scene (ship is special case, cache will not be cleared) SaveLoadManager.RestoreCachedScene(world.SceneName); } else { // Record current player position before boarding ship, and cache scene. (ship is special case, cache will not be cleared) boardShipPosition = serializablePlayer.GetPlayerPositionData(); SaveLoadManager.CacheScene(world.SceneName); // Teleport to the players ship, restoring cached scene. world.TeleportToCoordinates(shipCoords.X, shipCoords.Y, StreamingWorld.RepositionMethods.RandomStartMarker); SaveLoadManager.RestoreCachedScene(world.SceneName); } DaggerfallUI.Instance.FadeBehaviour.FadeHUDFromBlack(); mode = TransportModes.Foot; } }
// Drops nature flats based on random chance scaled by simple rules public static void LayoutNatureBillboards(DaggerfallTerrain dfTerrain, DaggerfallBillboardBatch dfBillboardBatch, float terrainScale, int terrainDist) { const float maxSteepness = 50f; // 50 const float slopeSinkRatio = 70f; // Sink flats slightly into ground as slope increases to prevent floaty trees. const float baseChanceOnDirt = 0.2f; // 0.2 const float baseChanceOnGrass = 0.9f; // 0.4 const float baseChanceOnStone = 0.05f; // 0.05 // Location Rect is expanded slightly to give extra clearance around locations const int natureClearance = 4; Rect rect = dfTerrain.MapData.locationRect; if (rect.x > 0 && rect.y > 0) { rect.xMin -= natureClearance; rect.xMax += natureClearance; rect.yMin -= natureClearance; rect.yMax += natureClearance; } // Chance scaled based on map pixel height // This tends to produce sparser lowlands and denser highlands // Adjust or remove clamp range to influence nature generation float elevationScale = (dfTerrain.MapData.worldHeight / 128f); elevationScale = Mathf.Clamp(elevationScale, 0.4f, 1.0f); // Chance scaled by base climate type float climateScale = 1.0f; DFLocation.ClimateSettings climate = MapsFile.GetWorldClimateSettings(dfTerrain.MapData.worldClimate); switch (climate.ClimateType) { case DFLocation.ClimateBaseType.Desert: // Just lower desert for now climateScale = 0.25f; break; } float chanceOnDirt = baseChanceOnDirt * elevationScale * climateScale; float chanceOnGrass = baseChanceOnGrass * elevationScale * climateScale; float chanceOnStone = baseChanceOnStone * elevationScale * climateScale; // Get terrain Terrain terrain = dfTerrain.gameObject.GetComponent <Terrain>(); if (!terrain) { return; } // Get terrain data TerrainData terrainData = terrain.terrainData; if (!terrainData) { return; } // Remove exiting billboards dfBillboardBatch.Clear(); MeshReplacement.ClearNatureGameObjects(terrain); // Seed random with terrain key Random.InitState(MakeTerrainKey(dfTerrain.MapPixelX, dfTerrain.MapPixelY)); // Just layout some random flats spread evenly across entire map pixel area // Flats are aligned with tiles, max 16129 billboards per batch Vector2 tilePos = Vector2.zero; int tDim = MapsFile.WorldMapTileDim; int hDim = DaggerfallUnity.Instance.TerrainSampler.HeightmapDimension; float scale = terrainData.heightmapScale.x * (float)hDim / (float)tDim; float maxTerrainHeight = DaggerfallUnity.Instance.TerrainSampler.MaxTerrainHeight; float beachLine = DaggerfallUnity.Instance.TerrainSampler.BeachElevation; for (int y = 0; y < tDim; y++) { for (int x = 0; x < tDim; x++) { // Reject based on steepness float steepness = terrainData.GetSteepness((float)x / tDim, (float)y / tDim); if (steepness > maxSteepness) { continue; } // Reject if inside location rect (expanded slightly to give extra clearance around locations) tilePos.x = x; tilePos.y = y; if (rect.x > 0 && rect.y > 0 && rect.Contains(tilePos)) { continue; } // Chance also determined by tile type int tile = dfTerrain.MapData.tilemapSamples[x, y] & 0x3F; if (tile == 1) { // Dirt if (Random.Range(0f, 1f) > chanceOnDirt) { continue; } } else if (tile == 2) { // Grass if (Random.Range(0f, 1f) > chanceOnGrass) { continue; } } else if (tile == 3) { // Stone if (Random.Range(0f, 1f) > chanceOnStone) { continue; } } else { // Anything else continue; } int hx = (int)Mathf.Clamp(hDim * ((float)x / (float)tDim), 0, hDim - 1); int hy = (int)Mathf.Clamp(hDim * ((float)y / (float)tDim), 0, hDim - 1); float height = dfTerrain.MapData.heightmapSamples[hy, hx] * maxTerrainHeight; // x & y swapped in heightmap for TerrainData.SetHeights() // Reject if too close to water if (height < beachLine) { continue; } // Sample height and position billboard Vector3 pos = new Vector3(x * scale, 0, y * scale); float height2 = terrain.SampleHeight(pos + terrain.transform.position); pos.y = height2 - (steepness / slopeSinkRatio); // Add to batch unless a mesh replacement is found int record = Random.Range(1, 32); if (terrainDist > 1 || !MeshReplacement.ImportNatureGameObject(dfBillboardBatch.TextureArchive, record, terrain, x, y)) { dfBillboardBatch.AddItem(record, pos); } else if (!NatureMeshUsed) { NatureMeshUsed = true; // Signal that nature mesh has been used to initiate extra terrain updates } } } // Apply new batch dfBillboardBatch.Apply(); }
IEnumerator Respawner(int worldX, int worldZ, bool insideDungeon, bool insideBuilding, bool forceReposition) { // Wait for end of frame so existing world data can be removed yield return(new WaitForEndOfFrame()); // Reset dungeon block on new spawn lastPlayerDungeonBlockIndex = -1; playerDungeonBlockData = new DFLocation.DungeonBlock(); // Reset inside state isPlayerInside = false; isPlayerInsideDungeon = false; isPlayerInsideDungeonPalace = false; // Set player GPS coordinates playerGPS.WorldX = worldX; playerGPS.WorldZ = worldZ; // Set streaming world coordinates DFPosition pos = MapsFile.WorldCoordToMapPixel(worldX, worldZ); world.MapPixelX = pos.X; world.MapPixelY = pos.Y; // Get location at this position ContentReader.MapSummary summary; bool hasLocation = dfUnity.ContentReader.HasLocation(pos.X, pos.Y, out summary); if (!insideDungeon && !insideBuilding) { // Start outside EnableExteriorParent(); if (!forceReposition) { // Teleport to explicit world coordinates world.TeleportToWorldCoordinates(worldX, worldZ); } else { // Force reposition to closest start marker if available world.TeleportToCoordinates(pos.X, pos.Y, StreamingWorld.RepositionMethods.RandomStartMarker); } // Wait until world is ready while (world.IsInit) { yield return(new WaitForEndOfFrame()); } } else if (hasLocation && insideDungeon) { // Start in dungeon DFLocation location; world.TeleportToCoordinates(pos.X, pos.Y, StreamingWorld.RepositionMethods.None); dfUnity.ContentReader.GetLocation(summary.RegionIndex, summary.MapIndex, out location); StartDungeonInterior(location, true); world.suppressWorld = true; } else if (hasLocation && insideBuilding && exteriorDoors != null) { // Start in building DFLocation location; world.TeleportToCoordinates(pos.X, pos.Y, StreamingWorld.RepositionMethods.None); dfUnity.ContentReader.GetLocation(summary.RegionIndex, summary.MapIndex, out location); StartBuildingInterior(location, exteriorDoors[0]); world.suppressWorld = true; } else { // All else fails teleport to map pixel DaggerfallUnity.LogMessage("Something went wrong! Teleporting to origin of nearest map pixel."); EnableExteriorParent(); world.TeleportToCoordinates(pos.X, pos.Y); } // Lower respawn flag isRespawning = false; }
public override string LocationDirection() { Vector2 positionPlayer; Vector2 positionLocation = Vector2.zero; Place questLastPlaceReferenced = parent.LastPlaceReferenced; if (questLastPlaceReferenced == null) { QuestMachine.Log(parent, "Trying to get direction to quest location when no location has been referenced in the quest."); return(TextManager.Instance.GetText("ConversationText", "resolvingError")); } DFPosition position = new DFPosition(); PlayerGPS playerGPS = GameManager.Instance.PlayerGPS; if (playerGPS) { position = playerGPS.CurrentMapPixel; } positionPlayer = new Vector2(position.X, position.Y); int region = DaggerfallUnity.Instance.ContentReader.MapFileReader.GetPoliticIndex(position.X, position.Y) - 128; if (region < 0 || region >= DaggerfallUnity.Instance.ContentReader.MapFileReader.RegionCount) { region = -1; } DFRegion.RegionMapTable locationInfo = new DFRegion.RegionMapTable(); DFRegion currentDFRegion = DaggerfallUnity.Instance.ContentReader.MapFileReader.GetRegion(region); string name = questLastPlaceReferenced.SiteDetails.locationName.ToLower(); string[] locations = currentDFRegion.MapNames; for (int i = 0; i < locations.Length; i++) { if (locations[i].ToLower() == name) // Valid location found with exact name { if (currentDFRegion.MapNameLookup.ContainsKey(locations[i])) { int index = currentDFRegion.MapNameLookup[locations[i]]; locationInfo = currentDFRegion.MapTable[index]; position = MapsFile.LongitudeLatitudeToMapPixel((int)locationInfo.Longitude, (int)locationInfo.Latitude); positionLocation = new Vector2(position.X, position.Y); } } } if (positionLocation != Vector2.zero) { Vector2 vecDirectionToTarget = positionLocation - positionPlayer; vecDirectionToTarget.y = -vecDirectionToTarget.y; // invert y axis return(GameManager.Instance.TalkManager.DirectionVector2DirectionHintString(vecDirectionToTarget)); } else { return("... never mind ..."); } }
/// <summary> /// Creates a path from player's current location to destination and /// returns minutes taken to travel. /// </summary> /// <param name="endPos">Endpoint in map pixel coordinates.</param> public int CalculateTravelTime(DFPosition endPos, bool speedCautious = false, bool sleepModeInn = false, bool travelShip = false, bool hasHorse = false, bool hasCart = false) { int transportModifier = 0; if (hasHorse) { transportModifier = 128; } else if (hasCart) { transportModifier = 192; } else { transportModifier = 256; } int playerXMapPixel = GameManager.Instance.PlayerGPS.CurrentMapPixel.X; int playerYMapPixel = GameManager.Instance.PlayerGPS.CurrentMapPixel.Y; int distanceXMapPixels = endPos.X - playerXMapPixel; int distanceYMapPixels = endPos.Y - playerYMapPixel; int distanceXMapPixelsAbs = Mathf.Abs(distanceXMapPixels); int distanceYMapPixelsAbs = Mathf.Abs(distanceYMapPixels); int furthestOfXandYDistance = 0; if (distanceXMapPixelsAbs <= distanceYMapPixelsAbs) { furthestOfXandYDistance = distanceYMapPixelsAbs; } else { furthestOfXandYDistance = distanceXMapPixelsAbs; } int xPixelMovementDirection; int yPixelMovementDirection; if (distanceXMapPixels >= 0) { xPixelMovementDirection = 1; } else { xPixelMovementDirection = -1; } if (distanceYMapPixels >= 0) { yPixelMovementDirection = 1; } else { yPixelMovementDirection = -1; } int numberOfMovements = 0; int shorterOfXandYDistanceIncrementer = 0; int minutesTakenThisMove = 0; int minutesTakenTotal = 0; MapsFile mapsFile = DaggerfallUnity.Instance.ContentReader.MapFileReader; pixelsTraveledOnOcean = 0; while (numberOfMovements < furthestOfXandYDistance) { if (furthestOfXandYDistance == distanceXMapPixelsAbs) { playerXMapPixel += xPixelMovementDirection; shorterOfXandYDistanceIncrementer += distanceYMapPixelsAbs; if (shorterOfXandYDistanceIncrementer > distanceXMapPixelsAbs) { shorterOfXandYDistanceIncrementer -= distanceXMapPixelsAbs; playerYMapPixel += yPixelMovementDirection; } } else { playerYMapPixel += yPixelMovementDirection; shorterOfXandYDistanceIncrementer += distanceXMapPixelsAbs; if (shorterOfXandYDistanceIncrementer > distanceYMapPixelsAbs) { shorterOfXandYDistanceIncrementer -= distanceYMapPixelsAbs; playerXMapPixel += xPixelMovementDirection; } } int terrainMovementIndex = 0; int terrain = mapsFile.GetClimateIndex(playerXMapPixel, playerYMapPixel); if (terrain == (int)MapsFile.Climates.Ocean) { ++pixelsTraveledOnOcean; if (travelShip) { minutesTakenThisMove = 51; } else { minutesTakenThisMove = 255; } } else { terrainMovementIndex = climateIndices[terrain - (int)MapsFile.Climates.Ocean]; minutesTakenThisMove = (((102 * transportModifier) >> 8) * (256 - terrainMovementModifiers[terrainMovementIndex] + 256)) >> 8; } if (!sleepModeInn) { minutesTakenThisMove = (300 * minutesTakenThisMove) >> 8; } minutesTakenTotal += minutesTakenThisMove; ++numberOfMovements; } if (!speedCautious) { minutesTakenTotal = minutesTakenTotal >> 1; } return(minutesTakenTotal); }
private void UpdateMode(TransportModes transportMode) { // Update the transport mode and stop any riding sounds playing. mode = transportMode; if (ridingAudioSource.isPlaying) { ridingAudioSource.Stop(); } if (mode == TransportModes.Horse || mode == TransportModes.Cart) { // Tell player motor we're riding. TODO: Change to event system so other classes can listen for transport changes. playerMotor.IsRiding = true; // Setup appropriate riding sounds. SoundClips sound = (mode == TransportModes.Horse) ? horseRidingSound2 : cartRidingSound; ridingAudioSource.clip = dfAudioSource.GetAudioClip((int)sound); // Setup appropriate riding textures. string textureName = (mode == TransportModes.Horse) ? horseTextureName : cartTextureName; for (int i = 0; i < 4; i++) { ridingTexures[i] = ImageReader.GetImageData(textureName, 0, i, true, true); } ridingTexure = ridingTexures[0]; // Initialise neighing timer. neighTime = Time.time + Random.Range(1, 5); } else { // Tell player motor we're not riding. playerMotor.IsRiding = false; } if (mode == TransportModes.Ship) { GameManager.Instance.PlayerMotor.CancelMovement = true; SerializablePlayer serializablePlayer = GetComponent <SerializablePlayer>(); DaggerfallUI.Instance.SmashHUDToBlack(); // Is player on board ship? if (boardShipPosition != null) { // Check for terrain sampler changes. (so don't fall through floor) StreamingWorld.RepositionMethods reposition = StreamingWorld.RepositionMethods.None; if (boardShipPosition.terrainSamplerName != DaggerfallUnity.Instance.TerrainSampler.ToString() || boardShipPosition.terrainSamplerVersion != DaggerfallUnity.Instance.TerrainSampler.Version) { reposition = StreamingWorld.RepositionMethods.RandomStartMarker; if (DaggerfallUI.Instance.DaggerfallHUD != null) { DaggerfallUI.Instance.DaggerfallHUD.PopupText.AddText("Terrain sampler changed. Repositioning player."); } } // Restore player position from before boarding ship. DFPosition mapPixel = MapsFile.WorldCoordToMapPixel(boardShipPosition.worldPosX, boardShipPosition.worldPosZ); GameManager.Instance.StreamingWorld.TeleportToCoordinates(mapPixel.X, mapPixel.Y, reposition); serializablePlayer.RestorePosition(boardShipPosition); boardShipPosition = null; } else { // Record current player position before boarding ship. boardShipPosition = serializablePlayer.GetPlayerPositionData(); // Teleport to ship GameManager.Instance.StreamingWorld.TeleportToCoordinates(2, 2, StreamingWorld.RepositionMethods.RandomStartMarker); } DaggerfallUI.Instance.FadeHUDFromBlack(); mode = TransportModes.Foot; } }
bool parseCommand(string[] args) { bool handled = false; Logger l = Logger.GetInstance(); switch (args[0]) { case (SPAWN_ENEMY_CMD): if (args.Length == 2) { int mobileType = System.Convert.ToInt32(args[1]); if (mobileType > -1 && mobileType < 147) { l.log("Spawning enemy of type " + (MobileTypes)mobileType + ".\n"); GameObject.FindGameObjectWithTag("EnemySpawner").SendMessage("SpawnEnemy", mobileType); handled = true; } } break; case (TRAVEL_CMD): if (args.Length >= 2) { DFLocation location; string nameWithPossibleSpaces = string.Join(" ", args); nameWithPossibleSpaces = nameWithPossibleSpaces.Substring(TRAVEL_CMD.Length + 1); if (!GameObjectHelper.FindMultiNameLocation(nameWithPossibleSpaces, out location)) { l.log("Unable to find location " + nameWithPossibleSpaces + ".\n"); } else { l.log("Found location in " + location.RegionName + "!\n"); DFPosition mapPos = MapsFile.LongitudeLatitudeToMapPixel((int)location.MapTableData.Longitude, (int)location.MapTableData.Latitude); if (mapPos.X >= TerrainHelper.minMapPixelX || mapPos.X < TerrainHelper.maxMapPixelX || mapPos.Y >= TerrainHelper.minMapPixelY || mapPos.Y < TerrainHelper.maxMapPixelY) { streamingWorldOwner.TeleportToCoordinates(mapPos.X, mapPos.Y); } else { l.log("Requested location is out of bounds!\n"); } } } break; case (SNOW_COMMAND): if (weatherManager.IsSnowing) { weatherManager.StopSnowing(); } else { weatherManager.StartSnowing(); } break; case (XML_DEBUG): QuestManager.Instance.doDebugQuest(); break; case (QUEST_DEBUG): l.log("Dumping all quests:"); QuestManager.Instance.dumpAllQuests(); break; case (TIME_DEBUG): l.log("The time is: " + dfUnity.WorldTime.Now.LongDateTimeString()); ulong timeInSeconds = dfUnity.WorldTime.Now.ToSeconds(); l.log("The time in seconds is: " + timeInSeconds.ToString()); timeInSeconds -= 60 * 60 * 24; l.log("Setting the time 1 day in the past: " + timeInSeconds.ToString()); dfUnity.WorldTime.Now.FromSeconds(timeInSeconds); l.log("The time is now: " + dfUnity.WorldTime.Now.LongDateTimeString()); l.log("The time in seconds is now: " + dfUnity.WorldTime.Now.ToSeconds().ToString()); break; case (DISPLAY_SCROLL): if (args.Length == 2) { scrollManager.displayScroll(args[1]); } break; default: break; } return(handled); }
private void UpdateWorldInfo(int x, int y) { // Requires DaggerfallUnity to be ready if (!ReadyCheck()) { return; } // Requires MAPS.BSA connection if (dfUnity.ContentReader.MapFileReader == null) { return; } // Get climate and politic data currentClimateIndex = dfUnity.ContentReader.MapFileReader.GetClimateIndex(x, y); currentPoliticIndex = dfUnity.ContentReader.MapFileReader.GetPoliticIndex(x, y); climateSettings = MapsFile.GetWorldClimateSettings(currentClimateIndex); if (currentPoliticIndex >= 128) { regionName = dfUnity.ContentReader.MapFileReader.GetRegionName(currentPoliticIndex - 128); } else if (currentPoliticIndex == 64) { regionName = "Ocean"; } else { regionName = "Unknown"; } // Get region data currentRegion = dfUnity.ContentReader.MapFileReader.GetRegion(CurrentRegionIndex); // Get location data ContentReader.MapSummary mapSummary; if (dfUnity.ContentReader.HasLocation(x, y, out mapSummary)) { currentLocation = dfUnity.ContentReader.MapFileReader.GetLocation(mapSummary.RegionIndex, mapSummary.MapIndex); hasCurrentLocation = true; CalculateWorldLocationRect(); } else { currentLocation = new DFLocation(); hasCurrentLocation = false; ClearWorldLocationRect(); } // Get location type if (hasCurrentLocation) { if (currentRegion.MapTable == null) { DaggerfallUnity.LogMessage(string.Format("PlayerGPS: Location {0} in region{1} has a null MapTable.", currentLocation.Name, currentLocation.RegionName)); } else { currentLocationType = currentRegion.MapTable[mapSummary.MapIndex].LocationType; } } }
void DisplaySaveStatsGUI() { if (currentSaveTree == null) { return; } SaveTreeBaseRecord positionRecord = currentSaveTree.FindRecord(RecordTypes.CharacterPositionRecord); EditorGUILayout.Space(); GUILayoutHelper.Horizontal(() => { EditorGUILayout.LabelField(new GUIContent("Version"), GUILayout.Width(EditorGUIUtility.labelWidth - 4)); EditorGUILayout.SelectableLabel(currentSaveTree.Header.Version.ToString(), EditorStyles.textField, GUILayout.Height(EditorGUIUtility.singleLineHeight)); }); GUILayoutHelper.Horizontal(() => { string positionText = string.Format("X={0}, Y={1}, Z={2}", positionRecord.RecordRoot.Position.WorldX, positionRecord.RecordRoot.Position.WorldY, positionRecord.RecordRoot.Position.WorldZ); EditorGUILayout.LabelField(new GUIContent("Player Position", "Position of player in the world."), GUILayout.Width(EditorGUIUtility.labelWidth - 4)); EditorGUILayout.SelectableLabel(positionText, EditorStyles.textField, GUILayout.Height(EditorGUIUtility.singleLineHeight)); }); GUILayoutHelper.Horizontal(() => { DFPosition mapPixel = MapsFile.WorldCoordToMapPixel(positionRecord.RecordRoot.Position.WorldX, positionRecord.RecordRoot.Position.WorldZ); string mapPixelText = string.Format("X={0}, Y={1}", mapPixel.X, mapPixel.Y); EditorGUILayout.LabelField(new GUIContent("Player Map Pixel", "Position of player on small map."), GUILayout.Width(EditorGUIUtility.labelWidth - 4)); EditorGUILayout.SelectableLabel(mapPixelText, EditorStyles.textField, GUILayout.Height(EditorGUIUtility.singleLineHeight)); }); GUILayoutHelper.Horizontal(() => { DaggerfallDateTime time = new DaggerfallDateTime(); time.FromClassicDaggerfallTime(currentSaveVars.GameTime); EditorGUILayout.LabelField(new GUIContent("Player Time", "World time of this save."), GUILayout.Width(EditorGUIUtility.labelWidth - 4)); EditorGUILayout.SelectableLabel(time.LongDateTimeString(), EditorStyles.textField, GUILayout.Height(EditorGUIUtility.singleLineHeight)); }); GUILayoutHelper.Horizontal(() => { EditorGUILayout.LabelField(new GUIContent("Player Environment"), GUILayout.Width(EditorGUIUtility.labelWidth - 4)); EditorGUILayout.SelectableLabel(((Environments)currentSaveTree.Header.Environment).ToString(), EditorStyles.textField, GUILayout.Height(EditorGUIUtility.singleLineHeight)); }); GUILayoutHelper.Horizontal(() => { EditorGUILayout.LabelField(new GUIContent("RecordElement records"), GUILayout.Width(EditorGUIUtility.labelWidth - 4)); EditorGUILayout.SelectableLabel(currentSaveTree.RecordDictionary.Count.ToString(), EditorStyles.textField, GUILayout.Height(EditorGUIUtility.singleLineHeight)); }); //GUILayoutHelper.Horizontal(() => //{ // EditorGUILayout.LabelField(new GUIContent("Header.Unknown"), GUILayout.Width(EditorGUIUtility.labelWidth - 4)); // EditorGUILayout.SelectableLabel(currentSaveTree.Header.Unknown.ToString(), EditorStyles.textField, GUILayout.Height(EditorGUIUtility.singleLineHeight)); //}); //GUILayoutHelper.Horizontal(() => //{ // EditorGUILayout.LabelField(new GUIContent("CharacterPosition.Unknown"), GUILayout.Width(EditorGUIUtility.labelWidth - 4)); // EditorGUILayout.SelectableLabel(currentSaveTree.Header.CharacterPosition.Unknown.ToString(), EditorStyles.textField, GUILayout.Height(EditorGUIUtility.singleLineHeight)); //}); }
// Drops nature flats based on random chance scaled by simple rules public static void LayoutNatureBillboards(DaggerfallTerrain dfTerrain, DaggerfallBillboardBatch dfBillboardBatch, float terrainScale) { const float maxSteepness = 50f; // 50 const float chanceOnDirt = 0.2f; // 0.2 const float chanceOnGrass = 0.9f; // 0.4 const float chanceOnStone = 0.05f; // 0.05 // Get terrain Terrain terrain = dfTerrain.gameObject.GetComponent <Terrain>(); if (!terrain) { return; } // Get terrain data TerrainData terrainData = terrain.terrainData; if (!terrainData) { return; } // Remove exiting billboards dfBillboardBatch.Clear(); // Seed random with terrain key UnityEngine.Random.seed = MakeTerrainKey(dfTerrain.MapPixelX, dfTerrain.MapPixelY); // Just layout some random flats spread evenly across entire map pixel area // Flats are aligned with tiles, max 127x127 in billboard batch Vector2 tilePos = Vector2.zero; float scale = terrainData.heightmapScale.x; int dim = TerrainHelper.terrainTileDim - 1; for (int y = 0; y < dim; y++) { for (int x = 0; x < dim; x++) { // Reject based on steepness float steepness = terrainData.GetSteepness((float)x / dim, (float)y / dim); if (steepness > maxSteepness) { continue; } // Reject if inside location rect // Rect is expanded slightly to give extra clearance around locations tilePos.x = x; tilePos.y = y; const int natureClearance = 4; Rect rect = dfTerrain.MapData.locationRect; if (rect.x > 0 && rect.y > 0) { rect.xMin -= natureClearance; rect.xMin += natureClearance; rect.yMin -= natureClearance; rect.yMax += natureClearance; if (rect.Contains(tilePos)) { continue; } } // Chance scaled based on map pixel height // This tends to produce sparser lowlands and denser highlands // Adjust or remove clamp range to influence nature generation float elevationScale = (dfTerrain.MapData.worldHeight / 128f); elevationScale = Mathf.Clamp(elevationScale, 0.4f, 1.0f); // Chance scaled by base climate type float climateScale = 1.0f; DFLocation.ClimateSettings climate = MapsFile.GetWorldClimateSettings(dfTerrain.MapData.worldClimate); switch (climate.ClimateType) { case DFLocation.ClimateBaseType.Desert: // Just lower desert for now climateScale = 0.25f; break; } // Chance also determined by tile type WorldSample sample = TerrainHelper.GetSample(ref dfTerrain.MapData.samples, x, y); if (sample.record == 1) { // Dirt if (UnityEngine.Random.Range(0f, 1f) > chanceOnDirt * elevationScale * climateScale) { continue; } } else if (sample.record == 2) { // Grass if (UnityEngine.Random.Range(0f, 1f) > chanceOnGrass * elevationScale * climateScale) { continue; } } else if (sample.record == 3) { // Stone if (UnityEngine.Random.Range(0f, 1f) > chanceOnStone * elevationScale * climateScale) { continue; } } else { // Anything else continue; } // Sample height and position billboard Vector3 pos = new Vector3(x * scale, 0, y * scale); float height = terrain.SampleHeight(pos + terrain.transform.position); pos.y = height; // Reject if too close to water float beachLine = DaggerfallUnity.Instance.TerrainSampler.BeachElevation * terrainScale; if (height < beachLine) { continue; } // Add to batch int record = UnityEngine.Random.Range(1, 32); dfBillboardBatch.AddItem(record, pos); } } // Apply new batch dfBillboardBatch.Apply(); }