/// <summary> /// Selects a touch spell from this enemy's list and returns true if it can be cast. /// </summary> bool CanCastTouchSpell() { if (entity.CurrentMagicka <= 0) { return(false); } EffectBundleSettings[] spells = entity.GetSpells(); List <EffectBundleSettings> rangeSpells = new List <EffectBundleSettings>(); int count = 0; foreach (EffectBundleSettings spell in spells) { // Classic AI considers ByTouch and CasterOnly here if (!DaggerfallUnity.Settings.EnhancedCombatAI) { if (spell.TargetType == TargetTypes.ByTouch || spell.TargetType == TargetTypes.CasterOnly) { rangeSpells.Add(spell); count++; } } else // Enhanced AI considers ByTouch and AreaAroundCaster. TODO: CasterOnly logic { if (spell.TargetType == TargetTypes.ByTouch || spell.TargetType == TargetTypes.AreaAroundCaster) { rangeSpells.Add(spell); count++; } } } if (count == 0) { return(false); } EffectBundleSettings selectedSpellSettings = rangeSpells[Random.Range(0, count)]; selectedSpell = new EntityEffectBundle(selectedSpellSettings, entityBehaviour); int totalGoldCostUnused; int readySpellCastingCost; Formulas.FormulaHelper.CalculateTotalEffectCosts(selectedSpell.Settings.Effects, selectedSpell.Settings.TargetType, out totalGoldCostUnused, out readySpellCastingCost); if (entity.CurrentMagicka < readySpellCastingCost) { return(false); } if (EffectsAlreadyOnTarget(selectedSpell)) { return(false); } return(true); }
public override PayloadCallbackResults?EnchantmentPayloadCallback(EnchantmentPayloadFlags context, EnchantmentParam?param = null, DaggerfallEntityBehaviour sourceEntity = null, DaggerfallEntityBehaviour targetEntity = null, DaggerfallUnityItem sourceItem = null, int sourceDamage = 0) { base.EnchantmentPayloadCallback(context, param, sourceEntity, targetEntity, sourceItem); // Validate if (context != EnchantmentPayloadFlags.Used || sourceEntity == null || param == null) { return(null); } // Get caster effect manager EntityEffectManager effectManager = sourceEntity.GetComponent <EntityEffectManager>(); if (!effectManager) { return(null); } // Cast when used enchantment prepares a new ready spell if (!string.IsNullOrEmpty(param.Value.CustomParam)) { // TODO: Ready a custom spell bundle } else { // Ready a classic spell bundle SpellRecord.SpellRecordData spell; EffectBundleSettings bundleSettings; EntityEffectBundle bundle; if (GameManager.Instance.EntityEffectBroker.GetClassicSpellRecord(param.Value.ClassicParam, out spell)) { if (GameManager.Instance.EntityEffectBroker.ClassicSpellRecordDataToEffectBundleSettings(spell, BundleTypes.Spell, out bundleSettings)) { // Self-cast spells are all assigned directly to self, "click to cast" spells are loaded to ready spell // TODO: Support multiple ready spells so all loaded spells are launched on click bundle = new EntityEffectBundle(bundleSettings, sourceEntity); bundle.CastByItem = sourceItem; if (bundle.Settings.TargetType == TargetTypes.CasterOnly) { effectManager.AssignBundle(bundle, AssignBundleFlags.BypassSavingThrows | AssignBundleFlags.BypassChance); } else { effectManager.SetReadySpell(bundle, true); } } } } return(new PayloadCallbackResults() { durabilityLoss = durabilityLossOnUse }); }
public override void Update(Task caller) { // Inflict disease on player if (diseaseType != Diseases.None) { EntityEffectBundle bundle = GameManager.Instance.PlayerEffectManager.CreateDisease(diseaseType); GameManager.Instance.PlayerEffectManager.AssignBundle(bundle, AssignBundleFlags.BypassSavingThrows); } SetComplete(); }
public override PayloadCallbackResults?EnchantmentPayloadCallback(EnchantmentPayloadFlags context, EnchantmentParam?param = null, DaggerfallEntityBehaviour sourceEntity = null, DaggerfallEntityBehaviour targetEntity = null, DaggerfallUnityItem sourceItem = null, int sourceDamage = 0) { base.EnchantmentPayloadCallback(context, param, sourceEntity, targetEntity, sourceItem, sourceDamage); // Validate if (context != EnchantmentPayloadFlags.Equipped || param == null || sourceEntity == null || sourceItem == null) { return(null); } // Get caster effect manager EntityEffectManager casterManager = sourceEntity.GetComponent <EntityEffectManager>(); if (!casterManager) { return(null); } // Cast when held enchantment invokes a spell bundle that is permanent until item is removed if (!string.IsNullOrEmpty(param.Value.CustomParam)) { // TODO: Instantiate a custom spell bundle } else { // Instantiate a classic spell bundle SpellRecord.SpellRecordData spell; if (GameManager.Instance.EntityEffectBroker.GetClassicSpellRecord(param.Value.ClassicParam, out spell)) { UnityEngine.Debug.LogFormat("CastWhenHeld callback found enchantment '{0}'", spell.spellName); // Create effect bundle settings from classic spell EffectBundleSettings bundleSettings; if (GameManager.Instance.EntityEffectBroker.ClassicSpellRecordDataToEffectBundleSettings(spell, BundleTypes.HeldMagicItem, out bundleSettings)) { // Assign bundle EntityEffectBundle bundle = new EntityEffectBundle(bundleSettings, sourceEntity); bundle.FromEquippedItem = sourceItem; casterManager.AssignBundle(bundle, AssignBundleFlags.BypassSavingThrows); // Play cast sound on equip for player only if (casterManager.IsPlayerEntity) { casterManager.PlayCastSound(sourceEntity, casterManager.GetCastSoundID(bundle.Settings.ElementType)); } // TODO: Apply durability loss to equipped item on equip and over time // http://en.uesp.net/wiki/Daggerfall:Magical_Items#Durability_of_Magical_Items } } } return(null); }
private void DeployFullBlownVampirism() { const int deathIsNotEternalTextID = 401; // Cancel rest window if sleeping if (DaggerfallUI.Instance.UserInterfaceManager.TopWindow is DaggerfallRestWindow) { (DaggerfallUI.Instance.UserInterfaceManager.TopWindow as DaggerfallRestWindow).CloseWindow(); } // Halt random enemy spawns for next playerEntity update so player isn't bombarded by spawned enemies after transform time GameManager.Instance.PlayerEntity.PreventEnemySpawns = true; // Reset legal reputation for all regions and strip player of guild memberships ResetLegalRepAndGuildMembership(); // Raise game time to an evening two weeks later float raiseTime = (2 * DaggerfallDateTime.SecondsPerWeek) + (DaggerfallDateTime.DuskHour + 1 - DaggerfallUnity.Instance.WorldTime.DaggerfallDateTime.Hour) * 3600; DaggerfallUnity.Instance.WorldTime.DaggerfallDateTime.RaiseTime(raiseTime); // Transfer player to a random cemetery // Always using a small cemetery, nothing spoils that first vampire moment like being lost the guts of a massive dungeon // Intentionally not spawning enemies, for this time the PLAYER is the monster lurking inside the crypt DFLocation location = GetRandomCemetery(); DFPosition mapPixel = MapsFile.LongitudeLatitudeToMapPixel(location.MapTableData.Longitude, location.MapTableData.Latitude); DFPosition worldPos = MapsFile.MapPixelToWorldCoord(mapPixel.X, mapPixel.Y); GameManager.Instance.PlayerEnterExit.RespawnPlayer( worldPos.X, worldPos.Y, true, false); // Assign vampire spells to spellbook GameManager.Instance.PlayerEntity.AssignPlayerVampireSpells(InfectionVampireClan); // Fade in from black DaggerfallUI.Instance.FadeBehaviour.FadeHUDFromBlack(1.0f); // Start permanent vampirism effect stage two EntityEffectBundle bundle = GameManager.Instance.PlayerEffectManager.CreateVampirismCurse(); GameManager.Instance.PlayerEffectManager.AssignBundle(bundle, AssignBundleFlags.BypassSavingThrows); // Display popup DaggerfallMessageBox mb = DaggerfallUI.MessageBox(deathIsNotEternalTextID); mb.Show(); // Terminate custom disease lifecycle EndDisease(); }
protected override void DeployFullBlownLycanthropy() { // Start permanent wereboar lycanthropy effect stage two EntityEffectBundle bundle = GameManager.Instance.PlayerEffectManager.CreateLycanthropyCurse(); GameManager.Instance.PlayerEffectManager.AssignBundle(bundle, AssignBundleFlags.BypassSavingThrows); LycanthropyEffect lycanthropyEffect = (LycanthropyEffect)GameManager.Instance.PlayerEffectManager.FindIncumbentEffect <LycanthropyEffect>(); if (lycanthropyEffect != null) { lycanthropyEffect.InfectionType = LycanthropyTypes.Wereboar; } }
/// <summary> /// Selects a ranged spell from this enemy's list and returns true if it can be cast. /// </summary> bool CanCastRangedSpell() { if (entity.CurrentMagicka <= 0) { return(false); } EffectBundleSettings[] spells = entity.GetSpells(); List <EffectBundleSettings> rangeSpells = new List <EffectBundleSettings>(); int count = 0; foreach (EffectBundleSettings spell in spells) { if (spell.TargetType == TargetTypes.SingleTargetAtRange || spell.TargetType == TargetTypes.AreaAtRange) { rangeSpells.Add(spell); count++; } } if (count == 0) { return(false); } EffectBundleSettings selectedSpellSettings = rangeSpells[Random.Range(0, count)]; selectedSpell = new EntityEffectBundle(selectedSpellSettings, entityBehaviour); int totalGoldCostUnused; int readySpellCastingCost; Formulas.FormulaHelper.CalculateTotalEffectCosts(selectedSpell.Settings.Effects, selectedSpell.Settings.TargetType, out totalGoldCostUnused, out readySpellCastingCost); if (entity.CurrentMagicka < readySpellCastingCost) { return(false); } if (EffectsAlreadyOnTarget(selectedSpell)) { return(false); } return(true); }
protected virtual void InstantiateSpellBundle(EnchantmentParam param, DaggerfallEntityBehaviour sourceEntity, DaggerfallUnityItem sourceItem, EntityEffectManager casterManager, bool recast = false) { if (!string.IsNullOrEmpty(param.CustomParam)) { // TODO: Instantiate a custom spell bundle } else { // Instantiate a classic spell bundle SpellRecord.SpellRecordData spell; if (GameManager.Instance.EntityEffectBroker.GetClassicSpellRecord(param.ClassicParam, out spell)) { UnityEngine.Debug.LogFormat("CastWhenHeld callback found enchantment '{0}'", spell.spellName); // Create effect bundle settings from classic spell EffectBundleSettings bundleSettings; if (GameManager.Instance.EntityEffectBroker.ClassicSpellRecordDataToEffectBundleSettings(spell, BundleTypes.HeldMagicItem, out bundleSettings)) { // Assign bundle EntityEffectBundle bundle = new EntityEffectBundle(bundleSettings, sourceEntity); bundle.FromEquippedItem = sourceItem; bundle.AddRuntimeFlags(BundleRuntimeFlags.ItemRecastEnabled); casterManager.AssignBundle(bundle, AssignBundleFlags.BypassSavingThrows); // Play cast sound on equip for player only if (casterManager.IsPlayerEntity) { casterManager.PlayCastSound(sourceEntity, casterManager.GetCastSoundID(bundle.Settings.ElementType), true); } // Classic uses an item last "cast when held" effect spell cost to determine its durability loss on equip // Here, all effects are considered, as it seems more coherent to do so if (!recast) { int amount = FormulaHelper.CalculateCastingCost(spell, false); sourceItem.LowerCondition(amount, sourceEntity.Entity, sourceEntity.Entity.Items); //UnityEngine.Debug.LogFormat("CastWhenHeld degraded '{0}' by {1} durability points on equip. {2}/{3} remaining.", sourceItem.LongName, amount, sourceItem.currentCondition, sourceItem.maxCondition); } } // Store equip time as last reroll time sourceItem.timeEffectsLastRerolled = DaggerfallUnity.Instance.WorldTime.DaggerfallDateTime.ToClassicDaggerfallTime(); } } }
public override PayloadCallbackResults?EnchantmentPayloadCallback(EnchantmentPayloadFlags context, EnchantmentParam?param = null, DaggerfallEntityBehaviour sourceEntity = null, DaggerfallEntityBehaviour targetEntity = null, DaggerfallUnityItem sourceItem = null, int sourceDamage = 0) { base.EnchantmentPayloadCallback(context, param, sourceEntity, targetEntity, sourceItem, sourceDamage); // Validate if (context != EnchantmentPayloadFlags.Strikes || targetEntity == null || param == null || sourceDamage == 0) { return(null); } // Get target effect manager EntityEffectManager effectManager = targetEntity.GetComponent <EntityEffectManager>(); if (!effectManager) { return(null); } // Cast when strikes enchantment prepares a new ready spell if (!string.IsNullOrEmpty(param.Value.CustomParam)) { // TODO: Ready a custom spell bundle } else { // Ready a classic spell bundle SpellRecord.SpellRecordData spell; EffectBundleSettings bundleSettings; EntityEffectBundle bundle; if (GameManager.Instance.EntityEffectBroker.GetClassicSpellRecord(param.Value.ClassicParam, out spell)) { if (GameManager.Instance.EntityEffectBroker.ClassicSpellRecordDataToEffectBundleSettings(spell, BundleTypes.Spell, out bundleSettings)) { bundle = new EntityEffectBundle(bundleSettings, sourceEntity); effectManager.AssignBundle(bundle, AssignBundleFlags.ShowNonPlayerFailures); } } } return(new PayloadCallbackResults() { durabilityLoss = durabilityLossOnStrike }); }
public override void Update(Task caller) { // Validate if (string.IsNullOrEmpty(effectKey) || taskSymbol == null || lastReadySpell == null) { lastReadySpell = null; return; } // Compare readied spell for target effect for (int i = 0; i < lastReadySpell.Settings.Effects.Length; i++) { if (lastReadySpell.Settings.Effects[i].Key == effectKey) { ParentQuest.StartTask(taskSymbol); SetComplete(); break; } } }
public override void Update(Task caller) { // Validate if (spellID == -1 || classicEffects == null || classicEffects.Length == 0 || taskSymbol == null || lastReadySpell == null) { lastReadySpell = null; return; } // Compare readied effect properties to spell record int foundEffects = 0; for (int i = 0; i < classicEffects.Length; i++) { // Effect slot must be populated if (classicEffects[i].type == -1) { continue; } // Bundle must have contain native effects matching this classic effect foundEffects++; if (!lastReadySpell.HasMatchForClassicEffect(classicEffects[i])) { lastReadySpell = null; return; } } // Do nothing if no effects found in spell if (foundEffects == 0) { SetComplete(); return; } // Only reached here if action is running and matching spell is cast ParentQuest.StartTask(taskSymbol); SetComplete(); }
void InstantiateSpellBundle(EnchantmentParam param, DaggerfallEntityBehaviour sourceEntity, DaggerfallUnityItem sourceItem, EntityEffectManager casterManager) { if (!string.IsNullOrEmpty(param.CustomParam)) { // TODO: Instantiate a custom spell bundle } else { // Instantiate a classic spell bundle SpellRecord.SpellRecordData spell; if (GameManager.Instance.EntityEffectBroker.GetClassicSpellRecord(param.ClassicParam, out spell)) { UnityEngine.Debug.LogFormat("CastWhenHeld callback found enchantment '{0}'", spell.spellName); // Create effect bundle settings from classic spell EffectBundleSettings bundleSettings; if (GameManager.Instance.EntityEffectBroker.ClassicSpellRecordDataToEffectBundleSettings(spell, BundleTypes.HeldMagicItem, out bundleSettings)) { // Assign bundle EntityEffectBundle bundle = new EntityEffectBundle(bundleSettings, sourceEntity); bundle.FromEquippedItem = sourceItem; bundle.AddRuntimeFlags(BundleRuntimeFlags.ItemRecastEnabled); casterManager.AssignBundle(bundle, AssignBundleFlags.BypassSavingThrows); // Play cast sound on equip for player only if (casterManager.IsPlayerEntity) { casterManager.PlayCastSound(sourceEntity, casterManager.GetCastSoundID(bundle.Settings.ElementType), true); } // TODO: Apply durability loss to equipped item on equip // http://en.uesp.net/wiki/Daggerfall:Magical_Items#Durability_of_Magical_Items } // Store equip time as last reroll time sourceItem.timeEffectsLastRerolled = DaggerfallUnity.Instance.WorldTime.DaggerfallDateTime.ToClassicDaggerfallTime(); } } }
private void PlayerEffectManager_OnNewReadySpell(EntityEffectBundle spell) { // Store last ready spell to evaluate on next tick lastReadySpell = spell; }
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); playerEntity.SetCurrentLevelUpSkillSum(); // 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 classic items and spells to player entity playerEntity.AssignItemsAndSpells(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); // Ship ownership Banking.DaggerfallBankManager.AssignShipToPlayer(saveVars.PlayerOwnedShip); // 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; // 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); // Restore old class specials RestoreOldClassSpecials(saveTree, characterDocument.classicTransformedRace); // Restore vampirism if classic character was a vampire if (characterDocument.classicTransformedRace == Races.Vampire) { // Restore effect Debug.Log("Restoring vampirism to classic character."); EntityEffectBundle bundle = GameManager.Instance.PlayerEffectManager.CreateVampirismCurse(); GameManager.Instance.PlayerEffectManager.AssignBundle(bundle, AssignBundleFlags.BypassSavingThrows); // Assign correct clan from classic save VampirismEffect vampireEffect = (VampirismEffect)GameManager.Instance.PlayerEffectManager.FindIncumbentEffect <VampirismEffect>(); if (vampireEffect != null) { Debug.LogFormat("Setting vampire clan to {0}", (VampireClans)characterDocument.vampireClan); vampireEffect.VampireClan = (VampireClans)characterDocument.vampireClan; } } // TODO: Restore lycanthropy if classic character was a werewolf/wereboar // 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); } }
private void PlayerEffectManager_OnCastReadySpell(EntityEffectBundle spell) { // Clear last ready spell so player can't queue it up before entering location lastReadySpell = null; }
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; }
/// <summary> /// Selects a ranged spell from this enemy's list and returns true if it can be cast. /// </summary> bool CanCastRangedSpell() { if (entity.CurrentMagicka <= 0) { return(false); } EffectBundleSettings[] spells = entity.GetSpells(); List <EffectBundleSettings> rangeSpells = new List <EffectBundleSettings>(); int count = 0; foreach (EffectBundleSettings spell in spells) { if (spell.TargetType == TargetTypes.SingleTargetAtRange || spell.TargetType == TargetTypes.AreaAtRange) { rangeSpells.Add(spell); count++; } } if (count == 0) { return(false); } EffectBundleSettings selectedSpellSettings = rangeSpells[Random.Range(0, count)]; selectedSpell = new EntityEffectBundle(selectedSpellSettings, entityBehaviour); int totalGoldCostUnused; int readySpellCastingCost; Formulas.FormulaHelper.CalculateTotalEffectCosts(selectedSpell.Settings.Effects, selectedSpell.Settings.TargetType, out totalGoldCostUnused, out readySpellCastingCost); if (entity.CurrentMagicka < readySpellCastingCost) { return(false); } if (EffectsAlreadyOnTarget(selectedSpell)) { return(false); } // Check that there is a clear path to shoot a spell float spellMovementSpeed = 15; // All range spells are currently 15 speed Vector3 sphereCastDir = senses.PredictNextTargetPos(spellMovementSpeed); if (sphereCastDir == EnemySenses.ResetPlayerPos) { return(false); } float sphereCastDist = (sphereCastDir - transform.position).magnitude; sphereCastDir = (sphereCastDir - transform.position).normalized; RaycastHit hit; if (Physics.SphereCast(transform.position, 0.45f, sphereCastDir, out hit, sphereCastDist)) { DaggerfallEntityBehaviour hitTarget = hit.transform.GetComponent <DaggerfallEntityBehaviour>(); // Clear path to target if (hitTarget == senses.Target) { return(true); } // Something in the way return(false); } // Clear path to predicted target position return(true); }