private void Update() { // Ensure target resource has this behaviour assigned // Coupling is otherwise lost when reloading a game if (targetResource != null) { if (!targetResource.QuestResourceBehaviour) { targetResource.QuestResourceBehaviour = this; } } // Handle enemy checks if (enemyEntityBehaviour) { // Get foe resource Foe foe = (Foe)targetResource; if (foe == null) { return; } // If foe is hidden then remove self from game if (foe.IsHidden) { Destroy(gameObject); return; } // Handle restrained check // This might need some tuning in relation to injured and death checks if (foe.IsRestrained) { // Make enemy non-hostile EnemyMotor enemyMotor = transform.GetComponent <EnemyMotor>(); if (enemyMotor) { enemyMotor.IsHostile = false; } // Lower flag now this has been handled foe.ClearRestrained(); } // Handle injured check // This has to happen before death or script actions attached to injured event will not trigger if (enemyEntityBehaviour.Entity.CurrentHealth < enemyEntityBehaviour.Entity.MaxHealth && !foe.InjuredTrigger) { foe.SetInjured(); return; } // Handle death check if (enemyEntityBehaviour.Entity.CurrentHealth <= 0 && !isFoeDead) { foe.IncrementKills(); isFoeDead = true; } } }
public override void Update(Task caller) { base.Update(caller); // Get related Foe resource Foe foe = ParentQuest.GetFoe(npcSymbol); if (foe == null) { return; } foreach (DaggerfallEnemy enemy in UnityEngine.Object.FindObjectsOfType <DaggerfallEnemy>()) { if (enemy.QuestSpawn) { QuestResourceBehaviour qrb = enemy.GetComponent <QuestResourceBehaviour>(); if (qrb && qrb.TargetSymbol == foe.Symbol) { qrb.IsAttackableByAI = isAttackableByAI; SetComplete(); } } } return; }
public void AddItemQueue(Foe foe, DaggerfallEntityBehaviour enemyEntityBehaviour) { // Validate if (!enemyEntityBehaviour || foe == null || foe.ItemQueueCount == 0 || foeItemQueuePosition == foe.ItemQueueCount) { return; } // Get item queue as cloned items with new UIDs DaggerfallUnityItem[] clonedItems = foe.GetClonedItemQueue(); // Assign all items 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 (enemyEntityBehaviour.CorpseLootContainer) { // If enemy is already dead then place item in corpse loot container enemyEntityBehaviour.CorpseLootContainer.Items.AddItems(clonedItems); } else { // Otherwise add quest Item to Entity item collection // It will be transferred to corpse marker loot container when dropped enemyEntityBehaviour.Entity.Items.AddItems(clonedItems); } // Set index position to end of queue foeItemQueuePosition = foe.ItemQueueCount; }
public override void Update(Task caller) { base.Update(caller); // Get related Foe resource Foe foe = ParentQuest.GetFoe(npcSymbol); if (foe == null) { return; } foreach (DaggerfallEnemy enemy in UnityEngine.Object.FindObjectsOfType <DaggerfallEnemy>()) { if (enemy.QuestSpawn) { QuestResourceBehaviour qrb = enemy.GetComponent <QuestResourceBehaviour>(); if (qrb && qrb.TargetSymbol == foe.Symbol) { DaggerfallEntityBehaviour deb = enemy.GetComponent <DaggerfallEntityBehaviour>(); if (deb) { EnemyEntity enemyEntity = deb.Entity as EnemyEntity; //Debug.Log("Changed team from " + enemyEntity.Team + " to " + (MobileTeams)teamNumber); enemyEntity.Team = (MobileTeams)teamNumber; SetComplete(); } } } } }
void CreatePendingFoeSpawn() { // 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)); } // Get foe GameObjects pendingFoeGameObjects = GameObjectHelper.CreateFoeGameObjects(Vector3.zero, foe.FoeType, foe.SpawnCount, MobileReactions.Hostile, foe); if (pendingFoeGameObjects == null || pendingFoeGameObjects.Length != foe.SpawnCount) { SetComplete(); 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; }
public override bool CheckTrigger(Task caller) { // Always return true once owning Task is triggered // Another action will need to rearm/unset this task if another click is required if (caller.IsTriggered) { return(true); } // Get related Foe resource Foe foe = ParentQuest.GetFoe(npcSymbol); if (foe == null) { return(false); } // Check player clicked flag if (foe.HasPlayerClicked) { // When a gold amount and task is specified, the player must have that amount of gold or another task is called if (goldAmount > 0 && taskSymbol != null && !string.IsNullOrEmpty(taskSymbol.Name)) { // Does player have enough gold? if (GameManager.Instance.PlayerEntity.GoldPieces >= goldAmount) { // Then deduct gold and fire trigger GameManager.Instance.PlayerEntity.GoldPieces -= goldAmount; } else { // Otherwise trigger secondary task and exit without firing trigger ParentQuest.StartTask(taskSymbol); return(false); } } if (id != 0) { ParentQuest.ShowMessagePopup(id); } // Rearm foe click after current task ParentQuest.ScheduleClickRearm(foe); return(true); } return(false); }
public override void Update(Task caller) { // Get related Foe resource Foe foe = ParentQuest.GetFoe(foeSymbol); if (foe == null) { return; } // Raise the restrained flag foe.ClearRestrained(); SetComplete(); }
public override void Update(Task caller) { // Get the Foe resource Foe foe = ParentQuest.GetFoe(foeSymbol); if (foe == null) { SetComplete(); throw new Exception(string.Format("CastSpellOnFoe could not find Foe with symbol name {0}", Symbol.Name)); } // Add spell to Foe resource queue foe.QueueSpell(spell); SetComplete(); }
private void Update() { // Handle enemy checks if (enemyEntityBehaviour) { // Handle injured check // This has to happen before death or script actions attached to injured event will not trigger Foe foe = (Foe)targetResource; if (enemyEntityBehaviour.Entity.CurrentHealth < enemyEntityBehaviour.Entity.MaxHealth && !foe.InjuredTrigger) { foe.SetInjured(); return; } // Handle death check if (enemyEntityBehaviour.Entity.CurrentHealth <= 0 && !isFoeDead) { foe.IncrementKills(); isFoeDead = true; } } }
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); } }
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(); } }
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])); } } }
private void Update() { // Ensure target resource has this behaviour assigned // Coupling is otherwise lost when reloading a game if (targetResource != null) { if (!targetResource.QuestResourceBehaviour) { targetResource.QuestResourceBehaviour = this; } } // Handle NPC checks if (targetResource is Person && targetResource.QuestResourceBehaviour) { // Disable person resource if hidden or destroyed // Normally this is done via QuestResource.Tick() but this stops receiving ticks when quest terminates // Sometimes a quest person is hidden at same time quest is ended, e.g. $CUREWER when spawning lycanthrope foe // Also disabling here to handle this situation Person targetPerson = (Person)targetResource; if (targetPerson.IsHidden || targetPerson.IsDestroyed) { targetPerson.QuestResourceBehaviour.gameObject.SetActive(false); } } // Handle enemy checks if (enemyEntityBehaviour) { // Get foe resource Foe foe = (Foe)targetResource; if (foe == null) { return; } // If foe is hidden then remove self from game if (foe.IsHidden) { Destroy(gameObject); return; } // Handle restrained check // This might need some tuning in relation to injured and death checks if (foe.IsRestrained) { // Make enemy non-hostile EnemyMotor enemyMotor = transform.GetComponent <EnemyMotor>(); if (enemyMotor) { enemyMotor.IsHostile = false; } // Lower flag now this has been handled foe.ClearRestrained(); } // Handle injured check // This has to happen before death or script actions attached to injured event will not trigger if (enemyEntityBehaviour.Entity.CurrentHealth < enemyEntityBehaviour.Entity.MaxHealth && !foe.InjuredTrigger) { foe.SetInjured(); return; } // Handle death check if (enemyEntityBehaviour.Entity.CurrentHealth <= 0 && !isFoeDead) { foe.IncrementKills(); isFoeDead = true; } } }
public void CastSpellQueue(Foe foe, DaggerfallEntityBehaviour enemyEntityBehaviour) { // Validate if (!enemyEntityBehaviour || foe == null || foe.SpellQueue == null || foeSpellQueuePosition == foe.SpellQueue.Count) { return; } // Target entity must be alive if (enemyEntityBehaviour.Entity.CurrentHealth == 0) { return; } // Get effect manager on enemy EntityEffectManager enemyEffectManager = enemyEntityBehaviour.GetComponent <EntityEffectManager>(); if (!enemyEffectManager) { return; } // Cast queued spells on foe from current position for (int i = foeSpellQueuePosition; i < foe.SpellQueue.Count; i++) { SpellReference spell = foe.SpellQueue[i]; EntityEffectBundle spellBundle = null; // Create classic or custom spell bundle if (string.IsNullOrEmpty(spell.CustomKey)) { // Get classic spell data SpellRecord.SpellRecordData spellData; if (!GameManager.Instance.EntityEffectBroker.GetClassicSpellRecord(spell.ClassicID, out spellData)) { continue; } // Create classic spell bundle settings EffectBundleSettings bundleSettings; if (!GameManager.Instance.EntityEffectBroker.ClassicSpellRecordDataToEffectBundleSettings(spellData, BundleTypes.Spell, out bundleSettings)) { continue; } // Create classic spell bundle spellBundle = new EntityEffectBundle(bundleSettings, enemyEntityBehaviour); } else { // Create custom spell bundle - must be previously registered to broker try { EntityEffectBroker.CustomSpellBundleOffer offer = GameManager.Instance.EntityEffectBroker.GetCustomSpellBundleOffer(spell.CustomKey); spellBundle = new EntityEffectBundle(offer.BundleSetttings, enemyEntityBehaviour); } catch (Exception ex) { Debug.LogErrorFormat("QuestResourceBehaviour.CastSpellQueue() could not find custom spell offer with key: {0}, exception: {1}", spell.CustomKey, ex.Message); } } // Assign spell bundle to enemy if (spellBundle != null) { enemyEffectManager.AssignBundle(spellBundle, AssignBundleFlags.BypassSavingThrows); } } // Set index positon to end of queue foeSpellQueuePosition = foe.SpellQueue.Count; }