void ParseQBN(Quest quest, List <string> lines) { bool foundHeadlessTask = false; for (int i = 0; i < lines.Count; i++) { // Skip empty lines while scanning for next QBN item if (string.IsNullOrEmpty(lines[i].Trim())) { continue; } // Simple way to identify certain lines // This is just to get started on some basics for now if (lines[i].StartsWith("clock", StringComparison.InvariantCultureIgnoreCase)) { Clock clock = new Clock(quest, lines[i]); quest.AddResource(clock); } else if (lines[i].StartsWith("item", StringComparison.InvariantCultureIgnoreCase)) { Item item = new Item(quest, lines[i]); quest.AddResource(item); } else if (lines[i].StartsWith("person", StringComparison.InvariantCultureIgnoreCase)) { // This is a person declaration Person person = new Person(quest, lines[i]); quest.AddResource(person); } else if (lines[i].StartsWith("foe", StringComparison.InvariantCultureIgnoreCase)) { // This is an enemy declaration Foe foe = new Foe(quest, lines[i]); quest.AddResource(foe); } else if (lines[i].StartsWith("place", StringComparison.InvariantCultureIgnoreCase)) { // This is a place declaration Place place = new Place(quest, lines[i]); quest.AddResource(place); } else if (lines[i].StartsWith("variable", StringComparison.InvariantCultureIgnoreCase)) { // This is a single-line variable declaration task string[] variableLines = new string[1]; variableLines[0] = lines[i]; Task task = new Task(quest, variableLines); quest.AddTask(task); } else if (lines[i].Contains("task:") || (lines[i].StartsWith("until", StringComparison.InvariantCultureIgnoreCase) && lines[i].Contains("performed:"))) { // This is a standard or repeating task declaration List <string> taskLines = ReadBlock(lines, ref i); Task task = new Task(quest, taskLines.ToArray()); quest.AddTask(task); } else if (IsGlobalReference(lines[i])) { // Check if following line is another task or a line break bool hasBody = false; if (i + 1 != lines.Count) { hasBody = !IsNewTaskOrLineBreak(lines[i + 1]); } // This is a global variable link task Task task; int globalVar = GetGlobalReference(lines[i]); if (hasBody) { List <string> taskLines = ReadBlock(lines, ref i); task = new Task(quest, taskLines.ToArray(), globalVar); } else { string[] variableLines = new string[1]; variableLines[0] = lines[i]; task = new Task(quest, variableLines, globalVar); } quest.AddTask(task); } else if (foundHeadlessTask == false) { // The first QBN line found that is not a resource declaration should be our headless entry point // Currently only a single headless task is expected for startup task // May be expanded later to allow multiple headless tasks List <string> taskLines = ReadBlock(lines, ref i); Task task = new Task(quest, taskLines.ToArray()); quest.AddTask(task); foundHeadlessTask = true; } else { // Something went wrong throw new Exception(string.Format("Unknown line signature encounted '{0}'.", lines[i])); } } }
void AssignHomeTown() { Place homePlace; string symbolName = string.Format("_{0}_home_", Symbol.Name); // If this is a Questor or individual NPC then use current location of player using a special helper if (isQuestor || (IsIndividualNPC && isIndividualAtHome)) { homePlace = new Place(ParentQuest); if (GameManager.Instance.PlayerGPS.HasCurrentLocation) { if (!homePlace.ConfigureFromPlayerLocation(symbolName)) { throw new Exception("AssignHomeTown() could not configure questor/individual home from current player location."); } homePlaceSymbol = homePlace.Symbol; ParentQuest.AddResource(homePlace); LogHomePlace(homePlace); return; } } // For other NPCs use default scope and building type Place.Scopes scope = Place.Scopes.Remote; string buildingTypeString = "house"; // Adjust scope and building type based on faction hints int p1 = 0, p2 = 0, p3 = 0; if (!string.IsNullOrEmpty(factionTableKey)) { // Get faction parameters p1 = Parser.ParseInt(QuestMachine.Instance.FactionsTable.GetValue("p1", factionTableKey)); p2 = Parser.ParseInt(QuestMachine.Instance.FactionsTable.GetValue("p2", factionTableKey)); p3 = Parser.ParseInt(QuestMachine.Instance.FactionsTable.GetValue("p3", factionTableKey)); // Set based on parameters if (p1 == 0 && p2 == -3 || p1 == 0 && p2 == -4) { // For local types set to local place // This will support Local_3.0 - Local_4.10k // Referencing quest Sx009 where player must locate and click an NPC with only a home location to go by scope = Place.Scopes.Local; } else if (p1 == 0 && p2 >= 0 && p2 <= 20 && p3 == 0) { // Set to a specific building type buildingTypeString = QuestMachine.Instance.PlacesTable.GetKeyForValue("p2", p2.ToString()); } } // Get scope string - must be "local" or "remote" string scopeString = string.Empty; if (scope == Place.Scopes.Local) { scopeString = "local"; } else if (scope == Place.Scopes.Remote) { scopeString = "remote"; } else { throw new Exception("AssignHomeTown() scope must be either 'local' or 'remote'."); } // Create the home location string source = string.Format("Place {0} {1} {2}", symbolName, scopeString, buildingTypeString); homePlace = new Place(ParentQuest, source); homePlaceSymbol = homePlace.Symbol.Clone(); ParentQuest.AddResource(homePlace); LogHomePlace(homePlace); // // NOTE: Keeping the below for reference only at this time // //const string blank = "BLANK"; //// If this is a Questor or individual NPC then use current location name //// Person is being instantiated where player currently is //if (isQuestor || (IsIndividualNPC && isIndividualAtHome)) //{ // if (GameManager.Instance.PlayerGPS.HasCurrentLocation) // { // homeTownName = GameManager.Instance.PlayerGPS.CurrentLocation.Name; // homeRegionName = GameManager.Instance.PlayerGPS.CurrentLocation.RegionName; // homeBuildingName = blank; // return; // } //} //// Handle specific home Place assigned at create time //if (homePlaceSymbol != null) //{ // Place home = ParentQuest.GetPlace(homePlaceSymbol); // if (home != null) // { // homeTownName = home.SiteDetails.locationName; // homeRegionName = home.SiteDetails.regionName; // homeBuildingName = home.SiteDetails.buildingName; // } //} //else //{ // // Find a random location name from town types for flavour text // // This might take a few attempts but will very quickly find a random town name // int index; // bool found = false; // int regionIndex = GameManager.Instance.PlayerGPS.CurrentRegionIndex; // DFRegion regionData = DaggerfallUnity.Instance.ContentReader.MapFileReader.GetRegion(regionIndex); // while (!found) // { // index = UnityEngine.Random.Range(0, regionData.MapTable.Length); // DFRegion.LocationTypes locationType = regionData.MapTable[index].LocationType; // if (locationType == DFRegion.LocationTypes.TownCity || // locationType == DFRegion.LocationTypes.TownHamlet || // locationType == DFRegion.LocationTypes.TownVillage) // { // homeTownName = regionData.MapNames[index]; // homeRegionName = regionData.Name; // homeBuildingName = blank; // found = true; // } // } //} //// Handle Local_3.x group NPCs (limited) //// These appear to be a special case of assigning a residential person who is automatically instantiated to home Place //// Creating a full target Place for this person automatically and storing in Quest //// NOTE: Understanding is still being developed here, likely will need to rework this later //if (QuestMachine.Instance.FactionsTable.HasValue(careerAllianceName)) //{ // // Get params for this case // int p1 = Parser.ParseInt(QuestMachine.Instance.FactionsTable.GetValue("p1", careerAllianceName)); // int p2 = Parser.ParseInt(QuestMachine.Instance.FactionsTable.GetValue("p2", careerAllianceName)); // //int p3 = Parser.ParseInt(QuestMachine.Instance.FactionsTable.GetValue("p3", careerAllianceName)); // // Only supporting specific cases for now - can expand later based on testing and iteration of support // // This will support Local_3.0 - Local_3.3 // // Referencing quest Sx009 here where player must locate and click an NPC with only a home location to go by // if (p1 == 0 && p2 == -3) // { // // Just using "house2" here as actual meaning of p3 unknown // string homeSymbol = string.Format("_{0}_home_", Symbol.Name); // string source = string.Format("Place {0} remote house2", homeSymbol); // Place home = new Place(ParentQuest, source); // homePlaceSymbol = home.Symbol.Clone(); // ParentQuest.AddResource(home); // } // else if (p1 == 0 && p2 >= 0) // { // // Handle standard building types // string buildingSymbol = string.Format("_{0}_building_", Symbol.Name); // string buildingType = QuestMachine.Instance.PlacesTable.GetKeyForValue("p2", p2.ToString()); // string source = string.Format("Place {0} remote {1}", buildingSymbol, buildingType); // Place building = new Place(ParentQuest, source); // homePlaceSymbol = building.Symbol.Clone(); // ParentQuest.AddResource(building); // } //} }
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; }
// Creates a career-based NPC like a Shopkeeper or Banker void SetupCareerAllianceNPC(string careerAllianceName) { // Special handling for Questor class // Will revisit this later when guilds are more integrated if (careerAllianceName.Equals("Questor", StringComparison.InvariantCultureIgnoreCase)) { if (SetupQuestorNPC()) { return; } } // Handle Local_3.x group NPCs (limited) // These appear to be a special case of assigning a residential person who is automatically instantiated to home Place // Creating a full target Place for this person automatically and storing in Quest // NOTE: Understanding is still being developed here, likely will need to rework this later if (QuestMachine.Instance.FactionsTable.HasValue(careerAllianceName)) { // Get params for this case int p1 = Parser.ParseInt(QuestMachine.Instance.FactionsTable.GetValue("p1", careerAllianceName)); int p2 = Parser.ParseInt(QuestMachine.Instance.FactionsTable.GetValue("p2", careerAllianceName)); //int p3 = Parser.ParseInt(QuestMachine.Instance.FactionsTable.GetValue("p3", careerAllianceName)); // Only supporting specific cases for now - can expand later based on testing and iteration of support // This will support Local_3.0 - Local_3.3 // Referencing quest Sx009 here where player must locate and click an NPC with only a home location to go by if (p1 == 0 && p2 == -3) { // Just using "house2" here as actual meaning of p3 unknown string homeSymbol = string.Format("_{0}_home_", Symbol.Name); string source = string.Format("Place {0} remote house2", homeSymbol); Place home = new Place(ParentQuest, source); homePlaceSymbol = home.Symbol.Clone(); ParentQuest.AddResource(home); } else if (p1 == 0 && p2 >= 0) { // Handle standard building types string buildingSymbol = string.Format("_{0}_building_", Symbol.Name); string buildingType = QuestMachine.Instance.PlacesTable.GetKeyForValue("p2", p2.ToString()); string source = string.Format("Place {0} remote {1}", buildingSymbol, buildingType); Place building = new Place(ParentQuest, source); homePlaceSymbol = building.Symbol.Clone(); ParentQuest.AddResource(building); } } // Get faction data int factionID = GetCareerFactionID(careerAllianceName); if (factionID != -1) { FactionFile.FactionData factionData = GetFactionData(factionID); // Setup Person resource this.factionData = factionData; } else { Debug.LogErrorFormat("SetupCareerAllianceNPC() failed to setup {0}", careerAllianceName); } }