Exemplo n.º 1
0
        public override void Update(Task caller)
        {
            base.Update(caller);

            // When an amount is specified
            if (amount > 0)
            {
                // Does player have enough gold?
                if (GameManager.Instance.PlayerEntity.GetGoldAmount() >= amount)
                {
                    // Then deduct gold
                    GameManager.Instance.PlayerEntity.DeductGoldAmount(amount);
                    ParentQuest.StartTask(paidTaskSymbol);
                }
                else
                {
                    // Otherwise trigger secondary task and exit
                    ParentQuest.StartTask(notTaskSymbol);
                }
            }

            SetComplete();
        }
Exemplo n.º 2
0
        /// <summary>
        /// Places NPC to home. This can happen automatically when player enters building or when
        /// quest script uses "create npc" action to automatically assign Person to home.
        /// </summary>
        public bool PlaceAtHome()
        {
            // Does not attempt to place a questor as they should be statically place or moved manually
            Place homePlace = ParentQuest.GetPlace(homePlaceSymbol);

            if (homePlace == null || isQuestor)
            {
                return(false);
            }

            // Create SiteLink if not already present
            if (!QuestMachine.HasSiteLink(ParentQuest, homePlaceSymbol))
            {
                QuestMachine.CreateSiteLink(ParentQuest, homePlaceSymbol);
            }

            // Assign to home place
            homePlace.AssignQuestResource(Symbol);
            SetAssignedPlaceSymbol(homePlace.Symbol);
            assignedToHome = true;

            return(true);
        }
Exemplo n.º 3
0
        void CreatePendingFoeSpawn()
        {
            // Get the Foe resource
            Foe foe = ParentQuest.GetFoe(foeSymbol);

            if (foe == null)
            {
                throw new Exception(string.Format("create foe could not find Foe with symbol name {0}", Symbol.Name));
            }

            // Get foe GameObjects
            pendingFoeGameObjects = foe.CreateFoeGameObjects(Vector3.zero);
            if (pendingFoeGameObjects == null || pendingFoeGameObjects.Length != foe.SpawnCount)
            {
                throw new Exception(string.Format("create foe attempted to create {0}x{1} GameObjects and failed.", foe.SpawnCount, Symbol.Name));
            }

            // Initiate deployment process
            // Usually the foe will spawn immediately but can take longer depending on available placement space
            // This process ensures these foes have all been deployed before starting next cycle
            spawnInProgress    = true;
            pendingFoesSpawned = 0;
        }
Exemplo n.º 4
0
        private void MessageBox_OnButtonClick(DaggerfallMessageBox sender, DaggerfallMessageBox.MessageBoxButtons messageBoxButton)
        {
            // Start selected task
            if (messageBoxButton == (DaggerfallMessageBox.MessageBoxButtons)opt1button)
            {
                ParentQuest.StartTask(opt1TaskSymbol);
            }
            else if (messageBoxButton == (DaggerfallMessageBox.MessageBoxButtons)opt2button)
            {
                ParentQuest.StartTask(opt2TaskSymbol);
            }
            else if (messageBoxButton == (DaggerfallMessageBox.MessageBoxButtons)opt3button)
            {
                ParentQuest.StartTask(opt3TaskSymbol);
            }
            else if (messageBoxButton == (DaggerfallMessageBox.MessageBoxButtons)opt4button)
            {
                ParentQuest.StartTask(opt4TaskSymbol);
            }

            // Close prompt
            sender.CloseWindow();
        }
Exemplo n.º 5
0
        /// <summary>
        /// Checks if player in same world cell as Place this Person was assigned to.
        /// Does not care about specific building/dungeon or interior/exterior, just matching location mapID.
        /// Does not care if player actually inside bounds, just if inside same world cell.
        /// </summary>
        /// <returns>True if player in same world cell as location.</returns>
        public bool IsPlayerInSameLocationWorldCell()
        {
            // Get Place resource
            Place place = ParentQuest.GetPlace(lastAssignedPlaceSymbol);

            if (place == null)
            {
                return(false);
            }

            // Compare mapID of player location and Place
            DFLocation location = GameManager.Instance.PlayerGPS.CurrentLocation;

            if (location.Loaded)
            {
                if (location.MapTableData.MapId == place.SiteDetails.mapId)
                {
                    return(true);
                }
            }

            return(false);
        }
Exemplo n.º 6
0
        public override void Update(Task caller)
        {
            base.Update(caller);

            // Get related Person resource
            Person person = ParentQuest.GetPerson(personSymbol);

            if (person == null)
            {
                return;
            }

            // Add face to HUD
            DaggerfallUI.Instance.DaggerfallHUD.EscortingFaces.AddFace(person);

            // Popup saying message
            if (sayingID != 0)
            {
                ParentQuest.ShowMessagePopup(sayingID);
            }

            SetComplete();
        }
Exemplo n.º 7
0
        public override void Tick(Quest caller)
        {
            base.Tick(caller);

            // Auto-assign NPC to home Place if available and player enters
            // This only happens for very specific NPC types
            // Equivalent to calling "place anNPC at aPlace" from script
            // Will not be called again as assignment is permanent for duration of quest
            if (homePlaceSymbol != null && !assignedToHome)
            {
                Place home = ParentQuest.GetPlace(homePlaceSymbol);
                if (home == null)
                {
                    return;
                }

                // Hot-place NPC at this location when player enters
                if (home.IsPlayerHere())
                {
                    PlaceAtHome();
                }
            }
        }
Exemplo n.º 8
0
        void SpawnFoe()
        {
            // Roll for spawn chance
            float chance = spawnChance / 100f;

            if (UnityEngine.Random.Range(0f, 1f) < chance)
            {
                return;
            }

            // Get the Foe resource
            Foe foe = ParentQuest.GetFoe(foeSymbol);

            if (foe == null)
            {
                throw new Exception(string.Format("create foe could not find Foe with symbol name {0}", Symbol.Name));
            }

            // Get game objects
            GameObject[] gameObjects = foe.CreateFoeGameObjects(Vector3.zero);
            if (gameObjects == null || gameObjects.Length != foe.SpawnCount)
            {
                throw new Exception(string.Format("create foe attempted to spawn {0}x{1} and failed.", foe.SpawnCount, Symbol.Name));
            }

            // For simple initial testing just place enemies 2m behind player
            // Will eventually need to spawn enemy within a certain radius of player
            // and ensure not dropped into the void for dungeons and building interiors
            GameObject player   = GameManager.Instance.PlayerObject;
            Vector3    position = player.transform.position + (-player.transform.forward * 2);

            for (int i = 0; i < gameObjects.Length; i++)
            {
                gameObjects[i].transform.position = position;
                gameObjects[i].SetActive(true);
            }
        }
Exemplo n.º 9
0
        public override void Update(Task caller)
        {
            base.Update(caller);

            // Drop related Person or Foe resource
            if (personSymbol != null && !string.IsNullOrEmpty(personSymbol.Name))
            {
                Person person = ParentQuest.GetPerson(personSymbol);
                if (person != null)
                {
                    DaggerfallUI.Instance.DaggerfallHUD.EscortingFaces.DropFace(person);
                }
            }
            else if (foeSymbol != null && !string.IsNullOrEmpty(foeSymbol.Name))
            {
                Foe foe = ParentQuest.GetFoe(foeSymbol);
                if (foe != null)
                {
                    DaggerfallUI.Instance.DaggerfallHUD.EscortingFaces.DropFace(foe);
                }
            }

            SetComplete();
        }
Exemplo n.º 10
0
        /// <summary>
        /// Places NPC to home. This can happen automatically when player enters building or when
        /// quest script uses "create npc" action to automatically assign Person to home.
        /// </summary>
        public bool PlaceAtHome()
        {
            // Does not attempt to place a questor as they should be statically placed or moved manually
            // Individual NPCs are also excluded as they are either automatically at home or moved elsewhere by quest
            Place homePlace = ParentQuest.GetPlace(homePlaceSymbol);

            if (homePlace == null || isQuestor || isIndividualNPC)
            {
                return(false);
            }

            // Create SiteLink if not already present
            if (!QuestMachine.HasSiteLink(ParentQuest, homePlaceSymbol))
            {
                QuestMachine.CreateSiteLink(ParentQuest, homePlaceSymbol);
            }

            // Assign to home place
            homePlace.AssignQuestResource(Symbol);
            SetAssignedPlaceSymbol(homePlace.Symbol);
            assignedToHome = true;

            return(true);
        }
Exemplo n.º 11
0
        public override bool CheckTrigger(Task caller)
        {
            // Get related Foe resource
            Foe foe = ParentQuest.GetFoe(foeSymbol);

            if (foe == null)
            {
                return(false);
            }

            // Check total kills recorded on this Foe
            if (foe.KillCount >= killsRequired)
            {
                // Popup saying message
                if (sayingID != 0)
                {
                    ParentQuest.ShowMessagePopup(sayingID);
                }

                return(true);
            }

            return(false);
        }
Exemplo n.º 12
0
        public override bool CheckTrigger(Task caller)
        {
            // Get related Foe resource
            Foe foe = ParentQuest.GetFoe(foeSymbol);

            if (foe == null)
            {
                return(false);
            }

            // Check injured flag
            if (foe.InjuredTrigger)
            {
                // Optionally show message
                if (textID != 0)
                {
                    ParentQuest.ShowMessagePopup(textID);
                }

                return(true);
            }

            return(false);
        }
Exemplo n.º 13
0
        void AssignHomeTown(string scopeString)
        {
            const string houseString = "house";

            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;
                }
            }

            // If this is an individual NPC who is not at home, don't place for now
            // as this has to be done by the "place _person_ at" command
            if (IsIndividualNPC)
            {
                return;
            }

            // For other NPCs use the given scope if any
            if (string.IsNullOrEmpty(scopeString))
            {
                // Else generate it at random only if there are local buildings
                if (GameManager.Instance.PlayerGPS.HasCurrentLocation &&
                    GameManager.Instance.PlayerGPS.CurrentLocation.Exterior.BuildingCount > 0)
                {
                    scopeString = UnityEngine.Random.Range(0.0f, 1.0f) < 0.5f ? "local" : "remote";
                }
                else
                {
                    scopeString = "remote";
                }
            }

            // Adjust building type based on faction hints
            string buildingTypeString = houseString;
            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));
                if (p1 == 0 && p2 >= 0 && p2 <= 20 && p3 == 0)
                {
                    // Set to a specific building type
                    buildingTypeString = QuestMachine.Instance.PlacesTable.GetKeyForValue("p2", p2.ToString());
                }
            }

            // Create the home location - this will try to match NPC group (e.g. a Noble will select a Palace)
            try
            {
                // Try preferred location type
                string source = string.Format("Place {0} {1} {2}", symbolName, scopeString, buildingTypeString);
                homePlace = new Place(ParentQuest, source);
            }
            catch
            {
                // Otherwise try to use a generic house
                // If this doesn't work for some reason then next exception will prevent quest from starting
                string source = string.Format("Place {0} {1} {2}", symbolName, scopeString, houseString);
                homePlace = new Place(ParentQuest, source);
            }

            // Complete assigning home place
            homePlaceSymbol = homePlace.Symbol.Clone();
            ParentQuest.AddResource(homePlace);
            LogHomePlace(homePlace);
        }
Exemplo n.º 14
0
        public List <TextFile.Token[]> GetMessage(int messageId)
        {
            Message message = ParentQuest.GetMessage(messageId);

            return(message == null ? null : TokenizeMessage(message));
        }
        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 = "house2";

            // 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);
            //    }
            //}
        }
Exemplo n.º 16
0
        public void Update()
        {
            // Iterate conditions and actions for this task
            foreach (IQuestAction action in actions)
            {
                // Completed actions are never executed again
                // The action itself should decide if/when to be complete
                // At a higher level, turning off the task will also disable actions
                // The exception being triggers which always run even when task disabled
                if (action.IsComplete)
                {
                    continue;
                }

                // Always check trigger conditions
                // These can turn task on when any trigger evaluates true
                // They are no longer checked once task is triggered (unless set to always be on)
                // But can fire again if owning task is unset/rearmed later
                if (action.IsTriggerCondition && !IsTriggered || action.IsAlwaysOnTriggerCondition)
                {
                    if (action.CheckTrigger(this))
                    {
                        IsTriggered = true;
                    }
                    else
                    {
                        IsTriggered = false;
                    }
                }

                // Tick other actions only when active
                if (IsTriggered && !action.IsTriggerCondition)
                {
                    // Initialise action if task was previously untriggered
                    if (!prevTriggered)
                    {
                        action.InitialiseOnSet();
                    }

                    // Update action and handle quest break
                    action.Update(this);
                    if (ParentQuest.QuestBreak)
                    {
                        return;
                    }
                }
            }

            // If this is a PersistUntil task we need to check target condition for unset state.
            // Experimentation seems to indicate these monitoring tasks get at least one tick.
            // For example, starting player outside of PH in classic using Z.CFG cheat will
            // cause main quest to start as normal before _exitstarter_ flag has a chance to
            // terminate "until _exitstarter_ performed" task.
            // Performing termination check AFTER executing task at least once to ensure behaviour matches classic.
            if (type == TaskType.PersistUntil)
            {
                Task targetTask = ParentQuest.GetTask(targetSymbol);
                if (targetTask.IsTriggered)
                {
                    // Target now set, terminate persistent task
                    Clear();
                }
                else
                {
                    // Rearm actions so they can repeat next run
                    // This behaviour obvserved in S0000011 in "until _S.12_ performed" to continuously clear Barenziah click
                    RearmActions();
                }
            }

            // Store trigger state this update
            prevTriggered = IsTriggered;
        }
Exemplo n.º 17
0
 void DirectToPlayerWithNotify(Item item)
 {
     // Give player item and show notify message
     GameManager.Instance.PlayerEntity.Items.AddItem(item.DaggerfallUnityItem, Items.ItemCollection.AddPosition.Front);
     ParentQuest.ShowMessagePopup(textId);
 }
Exemplo n.º 18
0
 public override void Update(Task caller)
 {
     ParentQuest.AddLogStep(stepID, messageID);
     SetComplete();
 }
Exemplo n.º 19
0
        /// <summary>
        /// Assigns a quest resource to this Place site.
        /// Supports Persons, Foes, Items from within same quest as Place.
        /// Quest must have previously created SiteLink for layout builders to discover assigned resources.
        /// </summary>
        /// <param name="targetSymbol">Resource symbol of Person, Item, or Foe to assign.</param>
        public void AssignQuestResource(Symbol targetSymbol)
        {
            // Site must have at least one marker of each type
            if (!ValidateQuestMarkers(siteDetails.questSpawnMarkers, siteDetails.questItemMarkers))
            {
                throw new Exception(string.Format("Tried to assign resource {0} to Place without at least 1x spawn and 1x item marker.", targetSymbol.Name));
            }

            // Attempt to get resource from symbol
            QuestResource resource = ParentQuest.GetResource(targetSymbol);

            if (resource == null)
            {
                throw new Exception(string.Format("Could not locate quest resource with symbol {0}", targetSymbol.Name));
            }

            // Must be a supported resource type
            MarkerTypes requiredMarkerType = MarkerTypes.None;

            if (resource is Person || resource is Foe)
            {
                requiredMarkerType = MarkerTypes.QuestSpawn;
            }
            else if (resource is Item)
            {
                requiredMarkerType = MarkerTypes.QuestItem;
            }
            else
            {
                throw new Exception(string.Format("Tried to assign incompatible resource symbol {0} to Place", targetSymbol.Name));
            }

            // Assign target resource to marker selected for this quest
            if (requiredMarkerType == MarkerTypes.QuestSpawn)
            {
                AssignResourceToMarker(targetSymbol, ref siteDetails.questSpawnMarkers[siteDetails.selectedQuestSpawnMarker]);
            }
            else if (requiredMarkerType == MarkerTypes.QuestItem)
            {
                AssignResourceToMarker(targetSymbol, ref siteDetails.questItemMarkers[siteDetails.selectedQuestItemMarker]);
            }
            else
            {
                throw new Exception(string.Format("Tried to assign resource symbol _{0}_ to Place {1} but it has an unknown MarkerType {2}", targetSymbol.Name, Symbol.Name, requiredMarkerType.ToString()));
            }

            // Output debug information
            if (resource is Person)
            {
                if (siteDetails.siteType == SiteTypes.Building)
                {
                    if (requiredMarkerType == MarkerTypes.QuestSpawn)
                    {
                        Debug.LogFormat("Assigned Person {0} to Building {1}", (resource as Person).DisplayName, SiteDetails.buildingName);
                    }
                }
                else if (siteDetails.siteType == SiteTypes.Dungeon)
                {
                    if (requiredMarkerType == MarkerTypes.QuestSpawn)
                    {
                        Debug.LogFormat("Assigned Person {0} to Dungeon {1}", (resource as Person).DisplayName, SiteDetails.locationName);
                    }
                }
            }
            else if (resource is Foe)
            {
                if (siteDetails.siteType == SiteTypes.Building)
                {
                    if (requiredMarkerType == MarkerTypes.QuestSpawn)
                    {
                        Debug.LogFormat("Assigned Foe _{0}_ to Building {1}", resource.Symbol.Name, SiteDetails.buildingName);
                    }
                }
                else if (siteDetails.siteType == SiteTypes.Dungeon)
                {
                    if (requiredMarkerType == MarkerTypes.QuestSpawn)
                    {
                        Debug.LogFormat("Assigned Foe _{0}_ to Dungeon {1}", resource.Symbol.Name, SiteDetails.locationName);
                    }
                }
            }
            else if (resource is Item)
            {
                if (siteDetails.siteType == SiteTypes.Building)
                {
                    if (requiredMarkerType == MarkerTypes.QuestItem)
                    {
                        Debug.LogFormat("Assigned Item _{0}_ to Building {1}", resource.Symbol.Name, SiteDetails.buildingName);
                    }
                }
                else if (siteDetails.siteType == SiteTypes.Dungeon)
                {
                    if (requiredMarkerType == MarkerTypes.QuestItem)
                    {
                        Debug.LogFormat("Assigned Item _{0}_ to Dungeon {1}", resource.Symbol.Name, SiteDetails.locationName);
                    }
                }
            }
        }
Exemplo n.º 20
0
        public void Update()
        {
            // "Always on" triggers can both start and stop a task
            // An example is S0000977 _S.03_ task which uses a single "when" trigger to start/stop spawns and play vengeance sound in Daggerfall city
            // But this becomes an issue if task has multiple "always on" triggers, as trigger A might start the task then trigger B will stop it again
            // One example of this behaviour is W0C00Y00 _pcgetsgold_ task where either "when" trigger can start reward task but subsequent triggers should not stop it again
            // This implementation considers the first "always on" trigger as the "primary" - able to both start & stop parent task
            // Subsequent "always on" triggers within the same task are "secondary" - only able to start a parent task but not stop it again
            bool ranPrimaryAlwaysOnTrigger = false;

            // Iterate conditions and actions for this task
            foreach (IQuestAction action in actions)
            {
                // Completed actions are never executed again
                // The action itself should decide if/when to be complete
                // At a higher level, turning off the task will also disable actions
                // The exception being triggers which always run even when task disabled
                if (action.IsComplete)
                {
                    continue;
                }

                // Always check trigger conditions
                // These can turn task on when any trigger evaluates true
                // They are no longer checked once task is triggered (unless set to always be on)
                // But can fire again if owning task is unset/rearmed later
                if (action.IsTriggerCondition && !IsTriggered || action.IsAlwaysOnTriggerCondition)
                {
                    // Handle primary/secondary "always on" triggers
                    if (action.IsAlwaysOnTriggerCondition && !ranPrimaryAlwaysOnTrigger)
                    {
                        // Primary "always on" trigger can start/stop parent task
                        // Flag is raised at first "always on" trigger so that subsequent triggers know the primary has run
                        IsTriggered = action.CheckTrigger(this);
                        ranPrimaryAlwaysOnTrigger = true;
                    }
                    else if (action.IsAlwaysOnTriggerCondition && ranPrimaryAlwaysOnTrigger)
                    {
                        // Secondary "always on" triggers can only start parent task, they cannot stop it again
                        if (action.CheckTrigger(this))
                        {
                            IsTriggered = true;
                        }
                    }
                    else
                    {
                        // All other triggers
                        IsTriggered = action.CheckTrigger(this);
                    }
                }

                // Tick other actions only when active
                if (IsTriggered && !action.IsTriggerCondition)
                {
                    // Initialise action if task was previously untriggered
                    if (!prevTriggered)
                    {
                        action.InitialiseOnSet();
                    }

                    // Update action and handle quest break
                    action.Update(this);
                    if (ParentQuest.QuestBreak)
                    {
                        return;
                    }
                }
            }

            // If this is a PersistUntil task we need to check target condition for unset state.
            // Experimentation seems to indicate these monitoring tasks get at least one tick.
            // For example, starting player outside of PH in classic using Z.CFG cheat will
            // cause main quest to start as normal before _exitstarter_ flag has a chance to
            // terminate "until _exitstarter_ performed" task.
            // Performing termination check AFTER executing task at least once to ensure behaviour matches classic.
            if (type == TaskType.PersistUntil)
            {
                Task targetTask = ParentQuest.GetTask(targetSymbol);
                if (targetTask.IsTriggered)
                {
                    // Target now set, terminate persistent task
                    Clear();
                }
                else
                {
                    // Rearm actions so they can repeat next run
                    // This behaviour obvserved in S0000011 in "until _S.12_ performed" to continuously clear Barenziah click
                    RearmActions();
                }
            }

            // Store trigger state this update
            prevTriggered = IsTriggered;
        }
Exemplo n.º 21
0
        public override void Update(Task caller)
        {
            base.Update(caller);

            // Attempt to get Item resource
            Item item = ParentQuest.GetItem(itemSymbol);

            if (item == null)
            {
                SetComplete();
                throw new Exception(string.Format("Could not find Item resource symbol {0}", itemSymbol));
            }

            // Attempt to get target resource
            QuestResource target = ParentQuest.GetResource(targetSymbol);

            if (target == null)
            {
                SetComplete();
                throw new Exception(string.Format("Could not find target resource symbol {0}", targetSymbol));
            }

            // Add item to Foe resource or generic entity
            // In practice GiveItem will always be to a Foe resource - NPCs are handled by "get item"
            // Keeping generic GiveItem behaviour as entity catch-all and reference
            if (target is Foe)
            {
                // Add to Foe item queue
                (target as Foe).QueueItem(item.DaggerfallUnityItem);

                // Dequeue items on entity immediately if target already exists in the world
                // Will also handle placing items to dead enemy loot container
                if (target.QuestResourceBehaviour)
                {
                    DaggerfallEntityBehaviour entityBehaviour = target.QuestResourceBehaviour.GetComponent <DaggerfallEntityBehaviour>();
                    if (entityBehaviour)
                    {
                        target.QuestResourceBehaviour.AddItemQueue(target as Foe, entityBehaviour);
                    }
                }
            }
            else
            {
                // Target must exist in the world
                if (!target.QuestResourceBehaviour)
                {
                    return;
                }

                // Must have an Entity to receive item
                DaggerfallEntityBehaviour entityBehaviour = target.QuestResourceBehaviour.GetComponent <DaggerfallEntityBehaviour>();
                if (!entityBehaviour)
                {
                    SetComplete();
                    throw new Exception(string.Format("GiveItem target {0} is not an Entity with DaggerfallEntityBehaviour", targetSymbol));
                }

                // Assign item for player to find
                //  * Some quests assign item to Foe at create time, others on injured event
                //  * It's possible for target enemy to be one-shot or to be killed by other means (such as "killall")
                //  * This assignment will direct quest loot item either to live enemy or corpse loot container
                if (entityBehaviour.CorpseLootContainer)
                {
                    // If enemy is already dead then place item in corpse loot container
                    entityBehaviour.CorpseLootContainer.Items.AddItem(item.DaggerfallUnityItem);
                }
                else
                {
                    // Otherwise add quest Item to Entity item collection
                    // It will be transferred to corpse marker loot container when dropped
                    entityBehaviour.Entity.Items.AddItem(item.DaggerfallUnityItem);
                }
            }

            // Remove item from player inventory if they are holding it
            if (GameManager.Instance.PlayerEntity.Items.Contains(item.DaggerfallUnityItem))
            {
                GameManager.Instance.PlayerEntity.Items.RemoveItem(item.DaggerfallUnityItem);
            }

            SetComplete();
        }
Exemplo n.º 22
0
        // Uses raycasts to find next spawn position just outside of player's field of view
        void PlaceFoeFreely(GameObject[] gameObjects, Transform parent, float minDistance = 5f, float maxDistance = 20f)
        {
            const float overlapSphereRadius = 0.65f;
            const float separationDistance  = 1.25f;
            const float maxFloorDistance    = 4f;

            // Must have received a valid array
            if (gameObjects == null || gameObjects.Length == 0)
            {
                return;
            }

            // Set parent - otherwise caller must set a parent
            if (parent)
            {
                gameObjects[pendingFoesSpawned].transform.parent = parent;
            }

            // Select a left or right direction outside of camera FOV
            Quaternion rotation;
            float      directionAngle = GameManager.Instance.MainCamera.fieldOfView;

            directionAngle += UnityEngine.Random.Range(0f, 4f);
            if (UnityEngine.Random.Range(0f, 1f) > 0.5f)
            {
                rotation = Quaternion.Euler(0, -directionAngle, 0);
            }
            else
            {
                rotation = Quaternion.Euler(0, directionAngle, 0);
            }

            // Get direction vector and create a new ray
            Vector3 angle          = (rotation * Vector3.forward).normalized;
            Vector3 spawnDirection = GameManager.Instance.PlayerObject.transform.TransformDirection(angle).normalized;
            Ray     ray            = new Ray(GameManager.Instance.PlayerObject.transform.position, spawnDirection);

            // Check for a hit
            Vector3    currentPoint;
            RaycastHit initialHit;

            if (Physics.Raycast(ray, out initialHit, maxDistance))
            {
                // Separate out from hit point
                float extraDistance = UnityEngine.Random.Range(0f, 2f);
                currentPoint = initialHit.point + initialHit.normal.normalized * (separationDistance + extraDistance);

                // Must be greater than minDistance
                if (initialHit.distance < minDistance)
                {
                    return;
                }
            }
            else
            {
                // Player might be in an open area (e.g. outdoors) pick a random point along spawn direction
                currentPoint = GameManager.Instance.PlayerObject.transform.position + spawnDirection * UnityEngine.Random.Range(minDistance, maxDistance);
            }

            // Must be able to find a surface below
            RaycastHit floorHit;

            ray = new Ray(currentPoint, Vector3.down);
            if (!Physics.Raycast(ray, out floorHit, maxFloorDistance))
            {
                return;
            }

            // Ensure this is open space
            Vector3 testPoint = floorHit.point + Vector3.up * separationDistance;

            Collider[] colliders = Physics.OverlapSphere(testPoint, overlapSphereRadius);
            if (colliders.Length > 0)
            {
                return;
            }

            // This looks like a good spawn position
            pendingFoeGameObjects[pendingFoesSpawned].transform.position = testPoint;
            FinalizeFoe(pendingFoeGameObjects[pendingFoesSpawned]);
            gameObjects[pendingFoesSpawned].transform.LookAt(GameManager.Instance.PlayerObject.transform.position);

            // Send msg message on first spawn only
            if (msgMessageID != -1)
            {
                ParentQuest.ShowMessagePopup(msgMessageID);
                msgMessageID = -1;
            }

            // Increment count
            pendingFoesSpawned++;
        }
Exemplo n.º 23
0
 public override void Update(Task caller)
 {
     ParentQuest.ShowMessagePopup(id);
     SetComplete();
 }
Exemplo n.º 24
0
        public void Update()
        {
            // Iterate conditions and actions for this task
            foreach (IQuestAction action in actions)
            {
                // Completed actions are never executed again
                // The action itself should decide if/when to be complete
                // At a higher level, turning off the task will also disable actions
                // The exception being triggers which always run even when task disabled
                if (action.IsComplete)
                {
                    continue;
                }

                // Always check trigger conditions
                // These can turn task on when any trigger evaluates true
                // They are no longer checked once task is triggered
                // But can fire again if task is unset/rearmed later
                if (action.IsTriggerCondition && !triggered)
                {
                    if (action.CheckTrigger(this))
                    {
                        triggered = true;
                    }
                    else
                    {
                        triggered = false;
                    }
                }

                // Tick other actions only when active
                if (triggered && !action.IsTriggerCondition)
                {
                    // Initialise action if task was previously untriggered
                    if (!prevTriggered)
                    {
                        action.InitialiseOnSet();
                    }

                    // Update action and handle quest break
                    action.Update(this);
                    if (ParentQuest.QuestBreak)
                    {
                        return;
                    }
                }
            }

            // If this is a PersistUntil task we need to check target condition for unset state.
            // Experimentation seems to indicate these monitoring tasks get at least one tick.
            // For example, starting player outside of PH in classic using Z.CFG cheat will
            // cause main quest to start as normal before _exitstarter_ flag has a chance to
            // terminate "until _exitstarter_ performed" task.
            // Performing termination check AFTER executing task at least once to ensure behaviour matches classic.
            if (type == TaskType.PersistUntil)
            {
                // Unset this task when target symbol is also unset
                Task targetTask = ParentQuest.GetTask(targetSymbol);
                if (targetTask != null)
                {
                    if (!targetTask.IsSet)
                    {
                        Unset();
                    }
                    // Should these tasks be able to rearm?
                    // Would need strong evidence before allowing this
                }
            }

            // Store trigger state this update
            prevTriggered = triggered;
        }
Exemplo n.º 25
0
        public override void Update(Task caller)
        {
            ulong gameSeconds = DaggerfallUnity.Instance.WorldTime.DaggerfallDateTime.ToSeconds();

            // Init spawn timer on first update
            if (lastSpawnTime == 0)
            {
                lastSpawnTime = gameSeconds + (uint)UnityEngine.Random.Range(0, spawnInterval + 1);
            }

            // Do nothing if max foes already spawned
            // This can be cleared on next set/rearm
            if (spawnCounter >= spawnMaxTimes && spawnMaxTimes != -1)
            {
                return;
            }

            // Clear pending foes if all have been spawned
            if (spawnInProgress && pendingFoesSpawned >= pendingFoeGameObjects.Length)
            {
                spawnInProgress = false;
                spawnCounter++;
                return;
            }

            // Check for a new spawn event - only one spawn event can be running at a time
            if (gameSeconds > lastSpawnTime + spawnInterval && !spawnInProgress)
            {
                // Update last spawn time
                lastSpawnTime = gameSeconds;

                // Roll for spawn chance
                float chance = spawnChance / 100f;
                if (UnityEngine.Random.Range(0f, 1f) > chance)
                {
                    return;
                }

                // Get the Foe resource
                Foe foe = ParentQuest.GetFoe(foeSymbol);
                if (foe == null)
                {
                    SetComplete();
                    throw new Exception(string.Format("create foe could not find Foe with symbol name {0}", Symbol.Name));
                }

                // Do not spawn if foe is hidden
                if (foe.IsHidden)
                {
                    return;
                }

                // Start deploying GameObjects
                CreatePendingFoeSpawn(foe);
            }

            // Try to deploy a pending spawns
            if (spawnInProgress)
            {
                TryPlacement();
                GameManager.Instance.RaiseOnEncounterEvent();
            }
        }
Exemplo n.º 26
0
        void AssignHomeTown()
        {
            const string houseString = "house";

            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 = houseString;

            // 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 < -2 && p2 != -6)
                {
                    // From usage in the quests it appears -3 and lower are local.
                    // Referencing quest Sx009 where player must locate and click an NPC with only a home location to go by
                    // and K0C00Y04 where two Group_7 npcs are local.
                    // Interkarma Note: -6 is used by Thieves Guild introduction quest O0A0AL00 and should be a remote NPC. Treating -6 as remote.
                    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 - this will try to match NPC group (e.g. a Noble will select a Palace)
            try
            {
                // Try preferred location type
                string source = string.Format("Place {0} {1} {2}", symbolName, scopeString, buildingTypeString);
                homePlace = new Place(ParentQuest, source);
            }
            catch
            {
                // Otherwise try to use a generic house
                // If this doesn't work for some reason then next exception will prevent quest from starting
                string source = string.Format("Place {0} {1} {2}", symbolName, scopeString, houseString);
                homePlace = new Place(ParentQuest, source);
            }

            // Complete assigning home place
            homePlaceSymbol = homePlace.Symbol.Clone();
            ParentQuest.AddResource(homePlace);
            LogHomePlace(homePlace);
        }
Exemplo n.º 27
0
        public override void Update(Task caller)
        {
            const int minHour  = 7;
            const int maxHour  = 18;
            const int minDelay = 40;
            const int maxDelay = 500;

            base.Update(caller);

            // "give pc anItem notify 1234" and "give pc anItem silently" require player
            // to be within a town, outdoors, and during set hours for action to fire
            if ((textId != 0 || silently) && !offerImmediately)
            {
                // Fail if conditions not met, but take note we are waiting
                DaggerfallDateTime now = DaggerfallUnity.Instance.WorldTime.Now;
                if (!GameManager.Instance.PlayerGPS.IsPlayerInTown(true, true) || now.Hour < minHour || now.Hour > maxHour)
                {
                    waitingForTown = true;
                    ticksUntilFire = 0;
                    return;
                }

                // If we were waiting then add a small random delay so messages don't all arrive at once
                if (waitingForTown)
                {
                    ticksUntilFire = UnityEngine.Random.Range(minDelay, maxDelay + 1);
                    waitingForTown = false;
                    RaiseOnOfferPendingEvent(this);
                }
            }

            // Reduce random delay until nothing is left
            // This is in questmachine ticks which is currently 10 ticks per second while game is running
            // Does not tick while game paused or resting - player must be actively in town walking around
            if (ticksUntilFire > 0)
            {
                ticksUntilFire--;
                return;
            }

            // Handle giving player nothing
            // This also shows QuestComplete message but does not give player loot
            if (isNothing)
            {
                OfferToPlayerWithQuestComplete(null);
                SetComplete();
                return;
            }

            // Attempt to get Item resource
            Item item = ParentQuest.GetItem(itemSymbol);

            if (item == null)
            {
                Debug.LogErrorFormat("Could not find Item resource symbol {0}", itemSymbol);
                return;
            }

            // Give quest item to player based on command format
            if (textId != 0)
            {
                DirectToPlayerWithNotify(item);
            }
            else
            {
                if (silently)
                {
                    DirectToPlayerWithoutNotify(item);
                }
                else
                {
                    OfferToPlayerWithQuestComplete(item);
                }
            }

            offerImmediately = false;
            SetComplete();
        }
Exemplo n.º 28
0
 public override void Update(Task caller)
 {
     ParentQuest.SetTask(taskSymbol);
     SetComplete();
 }
Exemplo n.º 29
0
        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;
        }
Exemplo n.º 30
0
 public override void Update(Task caller)
 {
     ParentQuest.RemoveLogStep(stepID);
     SetComplete();
 }