public static void ReadNativeBankData(SaveTreeBaseRecord records) { SetupAccounts(); if (records == null || records.RecordType != RecordTypes.BankAccount) { return; } MemoryStream stream = new MemoryStream(records.RecordData); BinaryReader reader = new BinaryReader(stream); int count = 0; while (reader.BaseStream.Position + 13 < records.RecordLength) { BankRecordData_v1 record = new BankRecordData_v1(); record.accountGold = reader.ReadInt32(); record.loanTotal = reader.ReadInt32(); record.loanDueDate = reader.ReadUInt32(); record.hasDefaulted = reader.ReadBoolean(); record.regionIndex = count; if (record.regionIndex >= BankAccounts.Length) { Debug.LogError("error reading bank data from classic save"); break; } BankAccounts[record.regionIndex] = record; count++; } reader.Close(); }
void DisplaySaveTree(SaveTreeBaseRecord parent) { for (int i = 0; i < parent.Children.Count; i++) { RecordTypes recordType = parent.Children[i].RecordType; if (recordType == RecordTypes.Door || recordType == RecordTypes.Goods) { continue; } string textLabel = recordType.ToString(); if (recordType == RecordTypes.Item || recordType == RecordTypes.Spell) { textLabel += string.Format(" [{0}]", GetItemOrSpellName(parent.Children[i])); } // Check if item equipped if (recordType == RecordTypes.Item) { //ItemRecord itemRecord = (ItemRecord)parent.Children[i]; //textLabel += string.Format(" [id={0}]", itemRecord.RecordRoot.RecordID); int equippedIndex = GetEquippedIndex(parent.Children[i] as ItemRecord); if (equippedIndex != -1) { //textLabel = string.Format("(*={0:00}) {1}", equippedIndex, textLabel); } } // Tag container types if (recordType == RecordTypes.Container && parent.RecordType == RecordTypes.Character) { string[] tags = { " [Weapons & Armor]", " [Magic Items]", " [Clothing & Misc]", " [Ingredients]", " [Wagon]", " [House]", " [Ship]", " [Tavern Rooms]", " [Item Repairers]" }; ContainerRecord containerRecord = (ContainerRecord)parent.Children[i]; textLabel += tags[containerRecord.RecordRoot.SpriteIndex]; } EditorGUILayout.LabelField(textLabel); GUILayoutHelper.Indent(() => { DisplaySaveTree(parent.Children[i]); }); } }
void DisplaySaveTree(SaveTreeBaseRecord parent) { for (int i = 0; i < parent.Children.Count; i++) { RecordTypes recordType = parent.Children[i].RecordType; if (recordType == RecordTypes.Door || recordType == RecordTypes.UnknownItemRecord) { continue; } string textLabel = recordType.ToString(); if (recordType == RecordTypes.Item || recordType == RecordTypes.Spell) { textLabel += string.Format(" [{0}]", GetItemOrSpellName(parent.Children[i])); } // Check if item equipped if (recordType == RecordTypes.Item) { //ItemRecord itemRecord = (ItemRecord)parent.Children[i]; //textLabel += string.Format(" [id={0}]", itemRecord.RecordRoot.RecordID); int equippedIndex = GetEquippedIndex(parent.Children[i] as ItemRecord); if (equippedIndex != -1) { //textLabel = string.Format("(*={0:00}) {1}", equippedIndex, textLabel); } } // Tag wagon container if (recordType == RecordTypes.Container && parent.RecordType == RecordTypes.Character) { ContainerRecord containerRecord = (ContainerRecord)parent.Children[i]; if (containerRecord.IsWagon) { textLabel += " [Wagon]"; } } EditorGUILayout.LabelField(textLabel); GUILayoutHelper.Indent(() => { DisplaySaveTree(parent.Children[i]); }); } }
void RestoreOldClassSpecials(SaveTree saveTree, Races classicTransformedRace) { try { // Get old class record SaveTreeBaseRecord oldClassRecord = saveTree.FindRecord(RecordTypes.OldClass); if (oldClassRecord == null) { return; } // Read old class data System.IO.MemoryStream stream = new System.IO.MemoryStream(oldClassRecord.RecordData); System.IO.BinaryReader reader = new System.IO.BinaryReader(stream); ClassFile classFile = new ClassFile(); classFile.Load(reader); reader.Close(); // Restore any specials set by transformed race if (classicTransformedRace == Races.Vampire) { // Restore pre-vampire specials characterDocument.career.DamageFromSunlight = classFile.Career.DamageFromSunlight; characterDocument.career.DamageFromHolyPlaces = classFile.Career.DamageFromHolyPlaces; characterDocument.career.Paralysis = classFile.Career.Paralysis; characterDocument.career.Disease = classFile.Career.Disease; } else if (classicTransformedRace == Races.Werewolf) { // TODO: Restore pre-werewolf specials } else if (classicTransformedRace == Races.Wereboar) { // TODO: Restore pre-wereboar specials } } catch (Exception ex) { Debug.LogErrorFormat("Could not restore old class specials for vamp/were import. Error: '{0}'", ex.Message); } }
string GetItemOrSpellName(SaveTreeBaseRecord record) { string result = string.Empty; byte[] recordData = record.RecordData; MemoryStream stream = new MemoryStream(recordData); BinaryReader reader = new BinaryReader(stream); if (record.RecordType == RecordTypes.Item) { result = FileProxy.ReadCString(reader); // Name starts at offset 0 } else if (record.RecordType == RecordTypes.Spell) { reader.BaseStream.Position += 47; // Name starts at offset 47 result = FileProxy.ReadCString(reader); } reader.Close(); return(result); }
void DisplaySaveTree(SaveTreeBaseRecord parent) { for (int i = 0; i < parent.Children.Count; i++) { RecordTypes recordType = parent.Children[i].RecordType; if (recordType == RecordTypes.UnknownTownLink || recordType == RecordTypes.UnknownItemRecord) { continue; } string textLabel = recordType.ToString(); if (recordType == RecordTypes.Item || recordType == RecordTypes.Spell) { textLabel += string.Format(" [{0}]", GetItemOrSpellName(parent.Children[i])); } EditorGUILayout.LabelField(textLabel); GUILayoutHelper.Indent(() => { DisplaySaveTree(parent.Children[i]); }); } }
void StartFromClassicSave() { DaggerfallUnity.ResetUID(); QuestMachine.Instance.ClearState(); RaiseOnNewGameEvent(); ResetWeaponManager(); // Save index must be in range if (classicSaveIndex < 0 || classicSaveIndex >= 6) { throw new IndexOutOfRangeException("classicSaveIndex out of range."); } // Open saves in parent path of Arena2 folder string path = SaveLoadManager.Instance.DaggerfallSavePath; SaveGames saveGames = new SaveGames(path); if (!saveGames.IsPathOpen) { throw new Exception(string.Format("Could not open Daggerfall saves path {0}", path)); } // Open save index if (!saveGames.TryOpenSave(classicSaveIndex)) { string error = string.Format("Could not open classic save index {0}.", classicSaveIndex); DaggerfallUI.MessageBox(error); DaggerfallUnity.LogMessage(string.Format(error), true); return; } // Get required save data SaveTree saveTree = saveGames.SaveTree; SaveVars saveVars = saveGames.SaveVars; SaveTreeBaseRecord positionRecord = saveTree.FindRecord(RecordTypes.CharacterPositionRecord); if (NoWorld) { playerEnterExit.DisableAllParents(); } else { // Set player to world position playerEnterExit.EnableExteriorParent(); StreamingWorld streamingWorld = FindStreamingWorld(); int worldX = positionRecord.RecordRoot.Position.WorldX; int worldZ = positionRecord.RecordRoot.Position.WorldZ; streamingWorld.TeleportToWorldCoordinates(worldX, worldZ); streamingWorld.suppressWorld = false; } GameObject cameraObject = GameObject.FindGameObjectWithTag("MainCamera"); PlayerMouseLook mouseLook = cameraObject.GetComponent <PlayerMouseLook>(); if (mouseLook) { // Classic save value ranges from -256 (looking up) to 256 (looking down). // The maximum up and down range of view in classic is similar to 45 degrees up and down in DF Unity. float pitch = positionRecord.RecordRoot.Pitch; if (pitch != 0) { pitch = (pitch * 45 / 256); } mouseLook.Pitch = pitch; float yaw = positionRecord.RecordRoot.Yaw; // In classic saves 2048 units of yaw is 360 degrees. if (yaw != 0) { yaw = (yaw * 360 / 2048); } mouseLook.Yaw = yaw; } // Set whether the player's weapon is drawn WeaponManager weaponManager = GameManager.Instance.WeaponManager; weaponManager.Sheathed = (!saveVars.WeaponDrawn); // Set game time DaggerfallUnity.Instance.WorldTime.Now.FromClassicDaggerfallTime(saveVars.GameTime); // Get character record List <SaveTreeBaseRecord> records = saveTree.FindRecords(RecordTypes.Character); if (records.Count != 1) { throw new Exception("SaveTree CharacterRecord not found."); } // Get prototypical character document data CharacterRecord characterRecord = (CharacterRecord)records[0]; characterDocument = characterRecord.ToCharacterDocument(); // Assign data to player entity PlayerEntity playerEntity = FindPlayerEntity(); playerEntity.AssignCharacter(characterDocument, characterRecord.ParsedData.level, characterRecord.ParsedData.maxHealth, false); // Assign biography modifiers playerEntity.BiographyResistDiseaseMod = saveVars.BiographyResistDiseaseMod; playerEntity.BiographyResistMagicMod = saveVars.BiographyResistMagicMod; playerEntity.BiographyAvoidHitMod = saveVars.BiographyAvoidHitMod; playerEntity.BiographyResistPoisonMod = saveVars.BiographyResistPoisonMod; playerEntity.BiographyFatigueMod = saveVars.BiographyFatigueMod; // Assign faction data playerEntity.FactionData.ImportClassicReputation(saveVars); // Assign global variables playerEntity.GlobalVars.ImportClassicGlobalVars(saveVars); // Set time of last check for raising skills playerEntity.TimeOfLastSkillIncreaseCheck = saveVars.LastSkillCheckTime; // Assign items to player entity playerEntity.AssignItems(saveTree); // Assign guild memberships playerEntity.AssignGuildMemberships(saveTree); // Assign diseases and poisons to player entity playerEntity.AssignDiseasesAndPoisons(saveTree); // Assign gold pieces playerEntity.GoldPieces = (int)characterRecord.ParsedData.physicalGold; // Assign weapon hand being used weaponManager.UsingRightHand = !saveVars.UsingLeftHandWeapon; // GodMode setting playerEntity.GodMode = saveVars.GodMode; // Setup bank accounts var bankRecords = saveTree.FindRecord(RecordTypes.BankAccount); Banking.DaggerfallBankManager.ReadNativeBankData(bankRecords); // Get regional data. playerEntity.RegionData = saveVars.RegionData; // Set time tracked by playerEntity for game minute-based updates playerEntity.LastGameMinutes = saveVars.GameTime; // Get breath remaining if player was submerged (0 if they were not in the water) playerEntity.CurrentBreath = saveVars.BreathRemaining; // TODO: Import classic spellbook playerEntity.DeserializeSpellbook(null); // Get last type of crime committed playerEntity.CrimeCommitted = (PlayerEntity.Crimes)saveVars.CrimeCommitted; // Get weather byte[] climateWeathers = saveVars.ClimateWeathers; // Enums for thunder and snow are reversed in classic and Unity, so they are converted here. for (int i = 0; i < climateWeathers.Length; i++) { // TODO: 0x80 flag can be set for snow or rain, to add fog to these weathers. This isn't in DF Unity yet, so // temporarily removing the flag. climateWeathers[i] &= 0x7f; if (climateWeathers[i] == 5) { climateWeathers[i] = 6; } else if (climateWeathers[i] == 6) { climateWeathers[i] = 5; } } GameManager.Instance.WeatherManager.PlayerWeather.ClimateWeathers = climateWeathers; // Load character biography text playerEntity.BackStory = saveGames.BioFile.Lines; // Validate spellbook item DaggerfallUnity.Instance.ItemHelper.ValidateSpellbookItem(playerEntity); // Start game DaggerfallUI.Instance.PopToHUD(); GameManager.Instance.PauseGame(false); DaggerfallUI.Instance.FadeBehaviour.FadeHUDFromBlack(); DaggerfallUI.PostMessage(PostStartMessage); lastStartMethod = StartMethods.LoadClassicSave; SaveIndex = -1; if (OnStartGame != null) { OnStartGame(this, null); } }
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)); //}); }
void StartFromClassicSave() { DaggerfallUnity.ResetUID(); QuestMachine.Instance.ClearState(); RaiseOnNewGameEvent(); ResetWeaponManager(); // Save index must be in range if (classicSaveIndex < 0 || classicSaveIndex >= 6) { throw new IndexOutOfRangeException("classicSaveIndex out of range."); } // Open saves in parent path of Arena2 folder string path = SaveLoadManager.Instance.DaggerfallSavePath; SaveGames saveGames = new SaveGames(path); if (!saveGames.IsPathOpen) { throw new Exception(string.Format("Could not open Daggerfall saves path {0}", path)); } // Open save index if (!saveGames.TryOpenSave(classicSaveIndex)) { string error = string.Format("Could not open classic save index {0}.", classicSaveIndex); DaggerfallUI.MessageBox(error); DaggerfallUnity.LogMessage(string.Format(error), true); return; } // Get required save data SaveTree saveTree = saveGames.SaveTree; SaveVars saveVars = saveGames.SaveVars; SaveTreeBaseRecord positionRecord = saveTree.FindRecord(RecordTypes.CharacterPositionRecord); if (NoWorld) { playerEnterExit.DisableAllParents(); } else { // Set player to world position playerEnterExit.EnableExteriorParent(); StreamingWorld streamingWorld = FindStreamingWorld(); int worldX = positionRecord.RecordRoot.Position.WorldX; int worldZ = positionRecord.RecordRoot.Position.WorldZ; streamingWorld.TeleportToWorldCoordinates(worldX, worldZ); streamingWorld.suppressWorld = false; } GameObject cameraObject = GameObject.FindGameObjectWithTag("MainCamera"); PlayerMouseLook mouseLook = cameraObject.GetComponent <PlayerMouseLook>(); if (mouseLook) { // Classic save value ranges from -256 (looking up) to 256 (looking down). // The maximum up and down range of view in classic is similar to 45 degrees up and down in DF Unity. float pitch = positionRecord.RecordRoot.Pitch; if (pitch != 0) { pitch = (pitch * 45 / 256); } mouseLook.Pitch = pitch; float yaw = positionRecord.RecordRoot.Yaw; // In classic saves 2048 units of yaw is 360 degrees. if (yaw != 0) { yaw = (yaw * 360 / 2048); } mouseLook.Yaw = yaw; } // Set whether the player's weapon is drawn GameManager.Instance.WeaponManager.Sheathed = (!saveVars.WeaponDrawn); // Set game time DaggerfallUnity.Instance.WorldTime.Now.FromClassicDaggerfallTime(saveVars.GameTime); // Get character record List <SaveTreeBaseRecord> records = saveTree.FindRecords(RecordTypes.Character); if (records.Count != 1) { throw new Exception("SaveTree CharacterRecord not found."); } // Get prototypical character document data CharacterRecord characterRecord = (CharacterRecord)records[0]; characterDocument = characterRecord.ToCharacterDocument(); // Assign data to player entity PlayerEntity playerEntity = FindPlayerEntity(); playerEntity.AssignCharacter(characterDocument, characterRecord.ParsedData.level, characterRecord.ParsedData.maxHealth, false); // Assign biography modifiers playerEntity.BiographyResistDiseaseMod = saveVars.BiographyResistDiseaseMod; playerEntity.BiographyResistMagicMod = saveVars.BiographyResistMagicMod; playerEntity.BiographyAvoidHitMod = saveVars.BiographyAvoidHitMod; playerEntity.BiographyResistPoisonMod = saveVars.BiographyResistPoisonMod; playerEntity.BiographyFatigueMod = saveVars.BiographyFatigueMod; // Assign faction data playerEntity.FactionData.ImportClassicReputation(saveVars); // Assign global variables playerEntity.GlobalVars.ImportClassicGlobalVars(saveVars); // Set time of last check for raising skills playerEntity.TimeOfLastSkillIncreaseCheck = saveVars.LastSkillCheckTime; // Assign items to player entity playerEntity.AssignItems(saveTree); // Assign gold pieces playerEntity.GoldPieces = (int)characterRecord.ParsedData.physicalGold; // GodMode setting playerEntity.GodMode = saveVars.GodMode; // Setup bank accounts var bankRecords = saveTree.FindRecord(RecordTypes.BankAccount); Banking.DaggerfallBankManager.ReadNativeBankData(bankRecords); // Get regional data. playerEntity.RegionData = saveVars.RegionData; // Set time tracked by playerEntity for game minute-based updates playerEntity.LastGameMinutes = saveVars.GameTime; // Start game DaggerfallUI.Instance.PopToHUD(); GameManager.Instance.PauseGame(false); DaggerfallUI.Instance.FadeHUDFromBlack(); DaggerfallUI.PostMessage(PostStartMessage); lastStartMethod = StartMethods.LoadClassicSave; SaveIndex = -1; if (OnStartGame != null) { OnStartGame(this, null); } }