private void AttemptAvoid() { int playerSkillRunning = playerEntity.Skills.GetLiveSkillValue(DFCareer.Skills.Running); int playerSkillStealth = playerEntity.Skills.GetLiveSkillValue(DFCareer.Skills.Stealth); int successChance = Mathf.Max(playerSkillRunning, playerSkillStealth); successChance = successChance * maxSuccessChance / 100; DaggerfallMessageBox mb = new DaggerfallMessageBox(DaggerfallUI.Instance.UserInterfaceManager); mb.SetText("You approach a hostile encounter. Attempt to avoid it?"); mb.AddButton(DaggerfallMessageBox.MessageBoxButtons.Yes, true); mb.AddButton(DaggerfallMessageBox.MessageBoxButtons.No); mb.ParentPanel.BackgroundColor = Color.clear; mb.OnButtonClick += (_sender, button) => { _sender.CloseWindow(); if (button == DaggerfallMessageBox.MessageBoxButtons.Yes) { if (Dice100.SuccessRoll(successChance)) { delayCombat = true; delayCombatTime = DaggerfallUnity.Instance.WorldTime.Now.ToClassicDaggerfallTime() + 10; StartFastTravel(destinationSummary); } else { DaggerfallUI.MessageBox("You failed to avoid the encounter!"); } } }; mb.Show(); }
private static void PercentManaRegenRealtime() { if (FixedUpdateCounter >= 80) // 50 FixedUpdates is approximately equal to 1 second since each FixedUpdate happens every 0.02 seconds, that's what Unity docs say at least. { FixedUpdateCounter = 0; float playerWillMod = (Mathf.Pow(1.019f, player.Stats.LiveWillpower) - 1) * RegenAmountModifier; //float playerWillMod = player.Stats.LiveWillpower * 0.05f * RegenAmountModifier; if (GameManager.Instance.PlayerEffectManager.HasVampirism() && !(GameManager.Instance.PlayerEffectManager.GetRacialOverrideEffect() as VampirismEffect).IsSatiated()) // If player is a vampire and currently does NOT have their thirst sated, they will regen magic much slower. { playerWillMod *= 0.2f; // Vampires with unsated thirst will only regen mana at 20% of their normal amount. } if (GameManager.Instance.PlayerEffectManager.HasReadySpell || player.CurrentMagicka >= player.MaxMagicka) // Don't allow regen "tick" to occur while player has spell ready to fire, nor if they currently have full mana. { return; } ManaCounter += playerWillMod; if (Dice100.SuccessRoll((int)Mathf.Floor(player.Stats.LiveLuck / 2))) { ManaCounter *= 1.3f; } if (ManaCounter >= 1) { int quotient = (int)Math.Truncate(ManaCounter); player.IncreaseMagicka(Mathf.Max((int)Mathf.Round(player.MaxMagicka * (quotient / 100f)), 1)); //Debug.LogFormat("Basic Magic Regen, Just Increased Your Mana By {0} Points. Remainder Is {1}", Mathf.Max((int)Mathf.Round(player.MaxMagicka * (quotient / 100f)), 1), ManaCounter - quotient); ManaCounter -= quotient; } } }
/// <summary> /// Randomly add a potion /// </summary> public static void RandomlyAddPotion(int chance, ItemCollection collection) { if (Dice100.SuccessRoll(chance)) { collection.AddItem(ItemBuilder.CreateRandomPotion()); } }
void AttemptAvoidEncounter() { int successChance = Mathf.Min(GameManager.Instance.PlayerEntity.Stats.LiveLuck + GameManager.Instance.PlayerEntity.Skills.GetLiveSkillValue(DFCareer.Skills.Stealth) - 50, maxAvoidChance); if (Dice100.SuccessRoll(successChance)) { Debug.LogWarning("Avoided enemies enountered during travel, chance: " + successChance); ignoreEncounters = true; ignoreEncountersTime = (uint)Time.unscaledTime + 15; if (DestinationName != null) { BeginTravel(); } else { FollowPath(); } travelControlUI.ShowMessage(MsgAvoidSuccess); } else { Debug.Log("Failed to avoid enemies enountered during travel, chance: " + successChance); DaggerfallUI.MessageBox(MsgAvoidFail); } }
public void AttemptBash(bool byPlayer) { if (!IsOpen) { // Play bash sound if flagged and ready if (PlaySounds && BashSound > 0 && audioSource) { DaggerfallAudioSource dfAudioSource = GetComponent <DaggerfallAudioSource>(); if (dfAudioSource != null) { dfAudioSource.PlayOneShot(BashSound); } } // Cannot bash magically held doors if (!IsMagicallyHeld) { // Roll for chance to open int chance = 20 - CurrentLockValue; if (Dice100.SuccessRoll(chance)) { CurrentLockValue = 0; ToggleDoor(true); } } if (byPlayer && Game.GameManager.Instance.PlayerEnterExit.IsPlayerInsideDungeonCastle) { Game.GameManager.Instance.MakeEnemiesHostile(); } } }
private static void KillAll(bool all = true) { DaggerfallEntityBehaviour[] entityBehaviours = FindObjectsOfType <DaggerfallEntityBehaviour>(); int length = entityBehaviours.Length; int killed = 0; int mobs = 0; int luck = playerEntity.Stats.LiveLuck / 4; for (int i = 0; i < length; i++) { DaggerfallEntityBehaviour entityBehaviour = entityBehaviours[i]; if (entityBehaviour.EntityType == EntityTypes.EnemyMonster || entityBehaviour.EntityType == EntityTypes.EnemyClass) { mobs++; if (all) { killed++; entityBehaviour.Entity.SetHealth(0); } else if (Dice100.SuccessRoll(luck)) { killed++; entityBehaviour.Entity.SetHealth(0); } } } horrorWakeup = true; playerEntity.CurrentHealth = playerEntity.MaxHealth; playerEntity.CurrentFatigue = playerEntity.MaxFatigue; playerEntity.CurrentMagicka = playerEntity.MaxMagicka; DaggerfallUI.Instance.FadeBehaviour.FadeHUDFromBlack(); }
private void DonationMsgBox_OnGotUserInput(DaggerfallInputMessageBox sender, string input) { int amount = 0; if (int.TryParse(input, out amount)) { if (playerEntity.GetGoldAmount() > amount) { // Deduct gold, and apply blessing playerEntity.DeductGoldAmount(amount); int factionId = (int)Temple.GetDivine(buildingFactionId); // Change reputation int rep = Math.Abs(playerEntity.FactionData.GetReputation(factionId)); if (Dice100.SuccessRoll(2 * amount / rep + 1)) { playerEntity.FactionData.ChangeReputation(factionId, 1); // Does not propagate in classic } // Show thanks message DaggerfallMessageBox messageBox = new DaggerfallMessageBox(uiManager, uiManager.TopWindow); messageBox.SetTextTokens(DaggerfallUnity.Instance.TextProvider.GetRandomTokens(DonationThanksId), this); messageBox.ClickAnywhereToClose = true; messageBox.Show(); } else { DaggerfallMessageBox messageBox = new DaggerfallMessageBox(uiManager, uiManager.TopWindow); messageBox.SetTextTokens(DaggerfallUnity.Instance.TextProvider.GetRandomTokens(TooGenerousId), this); messageBox.ClickAnywhereToClose = true; messageBox.Show(); } } }
/// <summary> /// Randomly add a map /// </summary> public static void RandomlyAddMap(int chance, ItemCollection collection) { if (Dice100.SuccessRoll(chance)) { DaggerfallUnityItem map = new DaggerfallUnityItem(ItemGroups.MiscItems, 8); collection.AddItem(map); } }
static void RandomIngredient(float chance, ItemGroups ingredientGroup, List <DaggerfallUnityItem> targetItems) { while (Dice100.SuccessRoll((int)chance)) { targetItems.Add(ItemBuilder.CreateRandomIngredient(ingredientGroup)); chance *= 0.5f; } }
/// <summary> /// Randomly add a potion recipe /// </summary> public static void RandomlyAddPotionRecipe(int chance, ItemCollection collection) { if (Dice100.SuccessRoll(chance)) { DaggerfallUnityItem potionRecipe = new DaggerfallUnityItem(ItemGroups.MiscItems, 4); byte recipe = (byte)Random.Range(0, 20); potionRecipe.typeDependentData = recipe; collection.AddItem(potionRecipe); } }
static Weapons RandomBigWeapon() { Weapons weapon = (Weapons)UnityEngine.Random.Range((int)Weapons.Claymore, (int)Weapons.War_Axe + 1); if (weapon == Weapons.Dai_Katana && Dice100.SuccessRoll(95)) { weapon = Weapons.Claymore; // Dai-katana's are really rare. } return(weapon); }
static Weapons RandomShortblade() { if (Dice100.SuccessRoll(95)) { return(CoinFlip() ? Weapons.Dagger : Weapons.Shortsword); } else { return((Weapons)UnityEngine.Random.Range((int)Weapons.Dagger, (int)Weapons.Wakazashi + 1)); } }
/// <summary> /// Randomly add a potion /// </summary> public static void RandomlyAddPotionRecipe(int chance, ItemCollection collection) { if (Dice100.SuccessRoll(chance)) { List <int> recipeKeys = GameManager.Instance.EntityEffectBroker.GetPotionRecipeKeys(); int recipeIdx = UnityEngine.Random.Range(0, recipeKeys.Count); DaggerfallUnityItem potionRecipe = new DaggerfallUnityItem(ItemGroups.MiscItems, 4) { PotionRecipeKey = recipeKeys[recipeIdx] }; collection.AddItem(potionRecipe); } }
/// <summary> /// Randomly add a potion recipe /// </summary> public static void RandomlyAddPotionRecipe(int chance, ItemCollection collection) { if (Dice100.SuccessRoll(chance)) { int recipeIdx = Random.Range(0, PotionRecipe.classicRecipeKeys.Length); int recipeKey = PotionRecipe.classicRecipeKeys[recipeIdx]; DaggerfallUnityItem potionRecipe = new DaggerfallUnityItem(ItemGroups.MiscItems, 4) { PotionRecipeKey = recipeKey }; collection.AddItem(potionRecipe); } }
// Capture this message so we can play pain voice public void RemoveHealth(int amount) { if (dfAudioSource && DaggerfallUnity.Settings.CombatVoices && Dice100.SuccessRoll(40)) { Entity.PlayerEntity playerEntity = GameManager.Instance.PlayerEntity; bool heavyDamage = amount >= playerEntity.MaxHealth / 4; SoundClips sound = Entity.DaggerfallEntity.GetRaceGenderPainSound(playerEntity.Race, playerEntity.Gender, heavyDamage); float pitch = dfAudioSource.AudioSource.pitch; dfAudioSource.AudioSource.pitch = pitch + Random.Range(0, 0.3f); dfAudioSource.PlayOneShot((int)sound, 0, 1f); dfAudioSource.AudioSource.pitch = pitch; } }
/// <summary> /// Performs a chance roll for this effect based on chance settings. /// </summary> /// <returns>True if chance roll succeeded.</returns> public virtual bool RollChance() { if (!Properties.SupportChance) { return(false); } bool outcome = Dice100.SuccessRoll(ChanceValue()); //Debug.LogFormat("Effect '{0}' has a {1}% chance of succeeding and rolled {2} for a {3}", Key, ChanceValue(), roll, (outcome) ? "success" : "fail"); return(outcome); }
public override void OnWeaponHitEntity(PlayerEntity playerEntity, DaggerfallEntity targetEntity = null) { const int chanceOfAttackSound = 10; const int chanceOfBarkSound = 20; // Check if we killed an innocent and update satiation - do not need to be transformed if (KilledInnocent(targetEntity)) { UpdateSatiation(); } // Do nothing further if not transformed if (!isTransformed) { return; } // Lycanthrope characters emit both attack and bark sounds while attacking SoundClips customSound = SoundClips.None; if (infectionType == LycanthropyTypes.Werewolf) { if (Dice100.SuccessRoll(chanceOfAttackSound)) { customSound = SoundClips.EnemyWerewolfAttack; } else if (Dice100.SuccessRoll(chanceOfBarkSound)) { customSound = SoundClips.EnemyWerewolfBark; } } else if (infectionType == LycanthropyTypes.Wereboar) { if (Dice100.SuccessRoll(chanceOfAttackSound)) { customSound = SoundClips.EnemyWereboarAttack; } else if (Dice100.SuccessRoll(chanceOfBarkSound)) { customSound = SoundClips.EnemyWereboarBark; } } // Play sound through weapon FPSWeapon screenWeapon = GameManager.Instance.WeaponManager.ScreenWeapon; if (screenWeapon && customSound != SoundClips.None) { screenWeapon.PlayAttackVoice(customSound); } }
private static WeaponMaterialTypes randomMat() { WeaponMaterialTypes weaponMaterial = WeaponMaterialTypes.Iron; if (GameManager.Instance.PlayerEnterExit.IsPlayerInsideDungeon) { matRoll = (matRoll - 15) + dungeonQuality(); } else { matRoll -= UnityEngine.Random.Range(10, 20); } //increased chance of orcish when in orsinium or an orc stronghold if (Dice100.SuccessRoll(luckMod * 2)) { if ((region == (int)DaggerfallRegions.OrsiniumArea || dungeon == (int)DFRegion.DungeonTypes.OrcStronghold) && Dice100.SuccessRoll(luckMod)) { return(WeaponMaterialTypes.Orcish); } else { matRoll += luckMod * 4; } } if (matRoll > 90) { if (Dice100.SuccessRoll(luckMod * 3)) { weaponMaterial = RandomHighTier(); } else { weaponMaterial = WeaponMaterialTypes.Dwarven; } } else if (matRoll > 83) { weaponMaterial = WeaponMaterialTypes.Elven; } else if (matRoll > 75) { weaponMaterial = WeaponMaterialTypes.Silver; } else if (matRoll > 35) { weaponMaterial = WeaponMaterialTypes.Steel; } return(weaponMaterial); }
public void AttemptBash(bool byPlayer, PlayerEntity player = null, EnemyEntity enemy = null) { // Play bash sound if flagged and ready if (PlaySounds && BashSound > 0 && audioSource) { DaggerfallAudioSource dfAudioSource = GetComponent <DaggerfallAudioSource>(); if (dfAudioSource != null) { dfAudioSource.PlayOneShot(BashSound); } } if (IsOpen) { // Bash-close the door ToggleDoor(true); } // Cannot bash magically held doors else if (!IsMagicallyHeld) { int chance = 0; if (player != null) { chance = Mathf.Clamp(15 + (int)Mathf.Ceil((player.Stats.LiveStrength - 50) / 2.5f) - CurrentLockValue, 1, 100); } else if (enemy != null) { chance = Mathf.Clamp(15 + (int)Mathf.Ceil((enemy.Stats.LiveStrength - 50) / 2.5f) - CurrentLockValue, 1, 100); } else { chance = 20 - CurrentLockValue; } // Roll for chance to open if (Dice100.SuccessRoll(chance)) { CurrentLockValue = 0; ToggleDoor(true); } } if (byPlayer && Game.GameManager.Instance.PlayerEnterExit.IsPlayerInsideDungeonCastle) { Game.GameManager.Instance.MakeEnemiesHostile(); } }
public override void OnWeaponHitEnemy(PlayerEntity playerEntity, EnemyEntity enemyEntity) { const int chanceOfAttackSound = 10; const int chanceOfBarkSound = 20; // Do nothing if not transformed if (!isTransformed) { return; } // Lycanthrope characters emit both attack and bark sounds while attacking SoundClips customSound = SoundClips.None; if (infectionType == LycanthropyTypes.Werewolf) { if (Dice100.SuccessRoll(chanceOfAttackSound)) { customSound = SoundClips.EnemyWerewolfAttack; } else if (Dice100.SuccessRoll(chanceOfBarkSound)) { customSound = SoundClips.EnemyWerewolfBark; } } else if (infectionType == LycanthropyTypes.Wereboar) { if (Dice100.SuccessRoll(chanceOfAttackSound)) { customSound = SoundClips.EnemyWereboarAttack; } else if (Dice100.SuccessRoll(chanceOfBarkSound)) { customSound = SoundClips.EnemyWereboarBark; } } // Play sound through weapon FPSWeapon screenWeapon = GameManager.Instance.WeaponManager.ScreenWeapon; if (screenWeapon && customSound != SoundClips.None) { screenWeapon.PlayAttackVoice(customSound); } }
public static void TheftItems_OnLootSpawned(object sender, ContainerLootSpawnedEventArgs e) { if (e.ContainerType == LootContainerTypes.HouseContainers) { int liveLuck = playerEntity.Stats.LiveLuck; int itemNumber = (liveLuck / 10) - UnityEngine.Random.Range(1, 40); while (itemNumber > 0) { DaggerfallUnityItem item = BurglaryLoot(); e.Loot.AddItem(item); itemNumber--; itemNumber--; } if (Dice100.SuccessRoll(liveLuck / 10)) { DaggerfallUnityItem item = ItemBuilder.CreateItem(ItemGroups.Currency, (int)Currency.Gold_pieces); item.stackCount = UnityEngine.Random.Range(Mathf.Max(1, liveLuck / 10), liveLuck * 10); e.Loot.AddItem(item); } if (Dice100.SuccessRoll(liveLuck / 10)) { DaggerfallUnityItem map = ItemBuilder.CreateItem(ItemGroups.MiscItems, (int)MiscItems.Map); } if (Dice100.SuccessRoll(liveLuck / 10)) { int typeRoll = UnityEngine.Random.Range(0, 100); DaggerfallUnityItem itemWpnArm; int level = UnityEngine.Random.Range(1, playerEnterExit.Interior.BuildingData.Quality); if (typeRoll > 50) { itemWpnArm = ItemBuilder.CreateRandomWeapon(level); } else { itemWpnArm = ItemBuilder.CreateRandomArmor(level, playerEntity.Gender, playerEntity.Race); } itemWpnArm.currentCondition = (int)(UnityEngine.Random.Range(0.3f, 0.75f) * itemWpnArm.maxCondition); e.Loot.AddItem(itemWpnArm); } } }
/// <summary> /// Our work is done here. /// </summary> private void Juggle() { // Juggle current things DaggerfallUI.AddHUDText(string.Format("Juggling {0} {1}...", thingsRemaining, thingName)); // We might drop something! if (Dice100.SuccessRoll(dropPercent)) { thingsRemaining--; DaggerfallUI.AddHUDText("Oops, I dropped one!"); } // Give up if we've dropped everything if (thingsRemaining == 0) { DaggerfallUI.AddHUDText(string.Format("Dropped all the {0}. I give up!", thingName)); return; } }
private void MakeAvoidAttempt(int successChance) { if (Dice100.SuccessRoll(successChance)) { delayCombat = true; delayCombatTime = DaggerfallUnity.Instance.WorldTime.Now.ToClassicDaggerfallTime() + 10; StartFastTravel(destinationSummary); } else { if (avoidEncounters == AvoidEncounterChoice.ALWAYS) { DaggerfallUI.MessageBox("You failed to avoid an encounter!"); } else { DaggerfallUI.MessageBox("You failed to avoid the encounter!"); } } }
/// <summary> /// Randomly add a potion recipe /// </summary> public static void RandomlyAddPotionRecipe(int chance, ItemCollection collection) { if (Dice100.SuccessRoll(chance)) { List <int> recipeKeys = GameManager.Instance.EntityEffectBroker.GetPotionRecipeKeys(); int recipeIdx = UnityEngine.Random.Range(0, recipeKeys.Count); DaggerfallUnityItem potionRecipe = new DaggerfallUnityItem(ItemGroups.MiscItems, 4) { PotionRecipeKey = recipeKeys[recipeIdx] }; collection.AddItem(potionRecipe); /*for (int i = 0; i < recipeKeys.Count; i++) // This is simply here for a quick easy testing loop to see the potions and their prices in the Unity Debug window. * { * DaggerfallUnityItem printThis = new DaggerfallUnityItem(ItemGroups.MiscItems, 4) { PotionRecipeKey = recipeKeys[i] }; * * Debug.LogFormat("Potion Recipe ID: {0}, ||| Potion Name: {1}, ||| Potion Weight: {2}, ||| Potion Value: {3}", recipeKeys[i], printThis.LongName, printThis.weightInKg, printThis.value); * }*/ } }
/// Applies condition damage to an item based on physical hit damage. private static void ApplyConditionDamageThroughWeaponDamage(DaggerfallUnityItem item, DaggerfallEntity owner, int damage, bool bluntWep, bool shtbladeWep, bool missileWep, int wepEqualize) // Possibly add on so that magic damage also damages worn equipment. { //Debug.LogFormat("Item Group Index is {0}", item.GroupIndex); //Debug.LogFormat("Item Template Index is {0}", item.TemplateIndex); if (item.ItemGroup == ItemGroups.Armor) // Target gets their armor/shield condition damaged. { int amount = item.IsShield ? damage * 2: damage * 4; item.LowerCondition(amount, owner); /*int percentChange = 100 * amount / item.maxCondition; * if (owner == GameManager.Instance.PlayerEntity){ * Debug.LogFormat("Target Had {0} Damaged by {1}, cond={2}", item.LongName, amount, item.currentCondition); * Debug.LogFormat("Had {0} Damaged by {1}%, of Total Maximum. There Remains {2}% of Max Cond.", item.LongName, percentChange, item.ConditionPercentage);} // Percentage Change */ } else // Attacker gets their weapon damaged, if they are using one, otherwise this method is not called. { int amount = (10 * damage) / 50; if ((amount == 0) && Dice100.SuccessRoll(40)) { amount = 1; } if (missileWep) { amount = SpecificWeaponConditionDamage(item, amount, wepEqualize); } item.LowerCondition(amount, owner); /*int percentChange = 100 * amount / item.maxCondition; * if (owner == GameManager.Instance.PlayerEntity){ * Debug.LogFormat("Attacker Damaged {0} by {1}, cond={2}", item.LongName, amount, item.currentCondition); * Debug.LogFormat("Had {0} Damaged by {1}%, of Total Maximum. There Remains {2}% of Max Cond.", item.LongName, percentChange, item.ConditionPercentage);} // Percentage Change */ } }
// Returns true if hit an enemy entity public bool WeaponDamage(DaggerfallUnityItem strikingWeapon, bool arrowHit, bool arrowSummoned, Transform hitTransform, Vector3 impactPosition, Vector3 direction) { DaggerfallEntityBehaviour entityBehaviour = hitTransform.GetComponent <DaggerfallEntityBehaviour>(); var entityMobileUnit = hitTransform.GetComponentInChildren <MobileUnit>(); EnemyMotor enemyMotor = hitTransform.GetComponent <EnemyMotor>(); EnemySounds enemySounds = hitTransform.GetComponent <EnemySounds>(); // Check if hit a mobile NPC MobilePersonNPC mobileNpc = hitTransform.GetComponent <MobilePersonNPC>(); if (mobileNpc) { if (!mobileNpc.IsGuard) { EnemyBlood blood = hitTransform.GetComponent <EnemyBlood>(); if (blood) { blood.ShowBloodSplash(0, impactPosition); } mobileNpc.Motor.gameObject.SetActive(false); playerEntity.TallyCrimeGuildRequirements(false, 5); playerEntity.CrimeCommitted = PlayerEntity.Crimes.Murder; playerEntity.SpawnCityGuards(true); // Allow custom race handling of weapon hit against mobile NPCs, e.g. vampire feeding or lycanthrope killing if (entityBehaviour) { entityBehaviour.Entity.SetHealth(0); RacialOverrideEffect racialOverride = GameManager.Instance.PlayerEffectManager.GetRacialOverrideEffect(); if (racialOverride != null) { racialOverride.OnWeaponHitEntity(GameManager.Instance.PlayerEntity, entityBehaviour.Entity); } } } else { playerEntity.CrimeCommitted = PlayerEntity.Crimes.Assault; GameObject guard = playerEntity.SpawnCityGuard(mobileNpc.transform.position, mobileNpc.transform.forward); entityBehaviour = guard.GetComponent <DaggerfallEntityBehaviour>(); entityMobileUnit = guard.GetComponentInChildren <MobileUnit>(); enemyMotor = guard.GetComponent <EnemyMotor>(); enemySounds = guard.GetComponent <EnemySounds>(); } mobileNpc.Motor.gameObject.SetActive(false); } // Check if hit an entity and remove health if (entityBehaviour) { if (entityBehaviour.EntityType == EntityTypes.EnemyMonster || entityBehaviour.EntityType == EntityTypes.EnemyClass) { EnemyEntity enemyEntity = entityBehaviour.Entity as EnemyEntity; // Calculate damage int animTime = (int)(ScreenWeapon.GetAnimTime() * 1000); // Get animation time, converted to ms. bool isEnemyFacingAwayFromPlayer = entityMobileUnit.IsBackFacing && entityMobileUnit.EnemyState != MobileStates.SeducerTransform1 && entityMobileUnit.EnemyState != MobileStates.SeducerTransform2; int damage = FormulaHelper.CalculateAttackDamage(playerEntity, enemyEntity, isEnemyFacingAwayFromPlayer, animTime, strikingWeapon); // Break any "normal power" concealment effects on player if (playerEntity.IsMagicallyConcealedNormalPower && damage > 0) { EntityEffectManager.BreakNormalPowerConcealmentEffects(GameManager.Instance.PlayerEntityBehaviour); } // Add arrow to target's inventory if (arrowHit && !arrowSummoned) { DaggerfallUnityItem arrow = ItemBuilder.CreateItem(ItemGroups.Weapons, (int)Weapons.Arrow); enemyEntity.Items.AddItem(arrow); } // Play hit sound and trigger blood splash at hit point if (damage > 0) { if (usingRightHand) { enemySounds.PlayHitSound(currentRightHandWeapon); } else { enemySounds.PlayHitSound(currentLeftHandWeapon); } EnemyBlood blood = hitTransform.GetComponent <EnemyBlood>(); if (blood) { blood.ShowBloodSplash(enemyEntity.MobileEnemy.BloodIndex, impactPosition); } // Knock back enemy based on damage and enemy weight if (enemyMotor) { if (enemyMotor.KnockbackSpeed <= (5 / (PlayerSpeedChanger.classicToUnitySpeedUnitRatio / 10)) && entityBehaviour.EntityType == EntityTypes.EnemyClass || enemyEntity.MobileEnemy.Weight > 0) { float enemyWeight = enemyEntity.GetWeightInClassicUnits(); float tenTimesDamage = damage * 10; float twoTimesDamage = damage * 2; float knockBackAmount = ((tenTimesDamage - enemyWeight) * 256) / (enemyWeight + tenTimesDamage) * twoTimesDamage; float KnockbackSpeed = (tenTimesDamage / enemyWeight) * (twoTimesDamage - (knockBackAmount / 256)); KnockbackSpeed /= (PlayerSpeedChanger.classicToUnitySpeedUnitRatio / 10); if (KnockbackSpeed < (15 / (PlayerSpeedChanger.classicToUnitySpeedUnitRatio / 10))) { KnockbackSpeed = (15 / (PlayerSpeedChanger.classicToUnitySpeedUnitRatio / 10)); } enemyMotor.KnockbackSpeed = KnockbackSpeed; enemyMotor.KnockbackDirection = direction; } } if (DaggerfallUnity.Settings.CombatVoices && entityBehaviour.EntityType == EntityTypes.EnemyClass && Dice100.SuccessRoll(40)) { Genders gender; if (entityMobileUnit.Enemy.Gender == MobileGender.Male || enemyEntity.MobileEnemy.ID == (int)MobileTypes.Knight_CityWatch) { gender = Genders.Male; } else { gender = Genders.Female; } bool heavyDamage = damage >= enemyEntity.MaxHealth / 4; enemySounds.PlayCombatVoice(gender, false, heavyDamage); } } else { if ((!arrowHit && !enemyEntity.MobileEnemy.ParrySounds) || strikingWeapon == null) { ScreenWeapon.PlaySwingSound(); } else if (enemyEntity.MobileEnemy.ParrySounds) { enemySounds.PlayParrySound(); } } // Handle weapon striking enchantments - this could change damage amount if (strikingWeapon != null && strikingWeapon.IsEnchanted) { EntityEffectManager effectManager = GetComponent <EntityEffectManager>(); if (effectManager) { damage = effectManager.DoItemEnchantmentPayloads(EnchantmentPayloadFlags.Strikes, strikingWeapon, GameManager.Instance.PlayerEntity.Items, enemyEntity.EntityBehaviour, damage); } strikingWeapon.RaiseOnWeaponStrikeEvent(entityBehaviour, damage); } // Remove health enemyEntity.DecreaseHealth(damage); // Handle attack from player enemyEntity.EntityBehaviour.HandleAttackFromSource(GameManager.Instance.PlayerEntityBehaviour); // Allow custom race handling of weapon hit against enemies, e.g. vampire feeding or lycanthrope killing RacialOverrideEffect racialOverride = GameManager.Instance.PlayerEffectManager.GetRacialOverrideEffect(); if (racialOverride != null) { racialOverride.OnWeaponHitEntity(GameManager.Instance.PlayerEntity, entityBehaviour.Entity); } return(true); } } return(false); }
void Update() { // Automatically update weapons from inventory when PlayerEntity available if (playerEntity != null) { UpdateHands(); } else { playerEntity = GameManager.Instance.PlayerEntity; } // Reset variables if there isn't an attack ongoing if (!IsWeaponAttacking()) { // If an attack with a bow just finished, set cooldown if (ScreenWeapon.WeaponType == WeaponTypes.Bow && isAttacking) { cooldownTime = Time.time + FormulaHelper.GetBowCooldownTime(playerEntity); } isAttacking = false; isDamageFinished = false; isBowSoundFinished = false; } // Do nothing while weapon cooldown. Used for bow. if (Time.time < cooldownTime) { return; } // Do nothing if player paralyzed or is climbing if (GameManager.Instance.PlayerEntity.IsParalyzed || GameManager.Instance.ClimbingMotor.IsClimbing) { ShowWeapons(false); return; } bool doToggleSheath = false; // Hide weapons and do nothing if spell is ready or cast animation in progress if (GameManager.Instance.PlayerEffectManager) { if (GameManager.Instance.PlayerEffectManager.HasReadySpell || GameManager.Instance.PlayerSpellCasting.IsPlayingAnim) { if (!isAttacking && InputManager.Instance.ActionStarted(InputManager.Actions.ReadyWeapon)) { GameManager.Instance.PlayerEffectManager.AbortReadySpell(); //if currently unsheathed, then sheath it, so we can give the effect of unsheathing it again if (!Sheathed) { ToggleSheath(); } doToggleSheath = true; } else { ShowWeapons(false); return; } } } // Toggle weapon sheath if (doToggleSheath || (!isAttacking && InputManager.Instance.ActionStarted(InputManager.Actions.ReadyWeapon))) { ToggleSheath(); } // Toggle weapon hand if (!isAttacking && InputManager.Instance.ActionComplete(InputManager.Actions.SwitchHand)) { ToggleHand(); } // Do nothing if weapon isn't done equipping if ((usingRightHand && EquipCountdownRightHand != 0) || (!usingRightHand && EquipCountdownLeftHand != 0)) { ShowWeapons(false); return; } // Do nothing if weapons sheathed if (Sheathed) { ShowWeapons(false); return; } else { ShowWeapons(true); } // Do nothing if player has cursor active over large HUD (player is clicking on HUD not clicking to attack) if (GameManager.Instance.PlayerMouseLook.cursorActive && DaggerfallUI.Instance.DaggerfallHUD != null && DaggerfallUI.Instance.DaggerfallHUD.LargeHUD.ActiveMouseOverLargeHUD) { return; } // Get if bow is equipped bool bowEquipped = (ScreenWeapon && ScreenWeapon.WeaponType == WeaponTypes.Bow); // Handle beginning a new attack if (!isAttacking) { if (!DaggerfallUnity.Settings.ClickToAttack || bowEquipped) { // Reset tracking if user not holding down 'SwingWeapon' button and no attack in progress if (!InputManager.Instance.HasAction(InputManager.Actions.SwingWeapon)) { lastAttackHand = Hand.None; _gesture.Clear(); return; } } else { // Player must click to attack if (InputManager.Instance.ActionStarted(InputManager.Actions.SwingWeapon)) { isClickAttack = true; } else { _gesture.Clear(); return; } } } var attackDirection = MouseDirections.None; if (!isAttacking) { if (bowEquipped) { // Ensure attack button was released before starting the next attack if (lastAttackHand == Hand.None) { attackDirection = DaggerfallUnity.Settings.BowDrawback ? MouseDirections.Up : MouseDirections.Down; // Force attack without tracking a swing for Bow } } else if (isClickAttack) { attackDirection = (MouseDirections)UnityEngine.Random.Range((int)MouseDirections.UpRight, (int)MouseDirections.DownRight + 1); isClickAttack = false; } else { attackDirection = TrackMouseAttack(); // Track swing direction for other weapons } } if (isAttacking && bowEquipped && DaggerfallUnity.Settings.BowDrawback && ScreenWeapon.GetCurrentFrame() == 3) { if (InputManager.Instance.HasAction(InputManager.Actions.ActivateCenterObject) || ScreenWeapon.GetAnimTime() > MaxBowHeldDrawnSeconds) { // Un-draw the bow without releasing an arrow. ScreenWeapon.ChangeWeaponState(WeaponStates.Idle); } else if (!InputManager.Instance.HasAction(InputManager.Actions.SwingWeapon)) { // Release arrow. Debug.Log("Release arrow!"); attackDirection = MouseDirections.Down; } } // Start attack if one has been initiated if (attackDirection != MouseDirections.None) { ExecuteAttacks(attackDirection); isAttacking = true; } // Stop here if no attack is happening if (!isAttacking) { return; } if (!isBowSoundFinished && ScreenWeapon.WeaponType == WeaponTypes.Bow && ScreenWeapon.GetCurrentFrame() == 4) { ScreenWeapon.PlaySwingSound(); isBowSoundFinished = true; } else if (!isDamageFinished && ScreenWeapon.GetCurrentFrame() == ScreenWeapon.GetHitFrame()) { // Racial override can suppress optional attack voice RacialOverrideEffect racialOverride = GameManager.Instance.PlayerEffectManager.GetRacialOverrideEffect(); bool suppressCombatVoices = racialOverride != null && racialOverride.SuppressOptionalCombatVoices; // Chance to play attack voice if (DaggerfallUnity.Settings.CombatVoices && !suppressCombatVoices && ScreenWeapon.WeaponType != WeaponTypes.Bow && Dice100.SuccessRoll(20)) { ScreenWeapon.PlayAttackVoice(); } // Transfer damage. bool hitEnemy = false; // Non-bow weapons if (ScreenWeapon.WeaponType != WeaponTypes.Bow) { MeleeDamage(ScreenWeapon, out hitEnemy); } // Bow weapons else { DaggerfallMissile missile = Instantiate(ArrowMissilePrefab); if (missile) { // Remove arrow ItemCollection playerItems = playerEntity.Items; DaggerfallUnityItem arrow = playerItems.GetItem(ItemGroups.Weapons, (int)Weapons.Arrow, allowQuestItem: false, priorityToConjured: true); bool isArrowSummoned = arrow.IsSummoned; playerItems.RemoveOne(arrow); missile.Caster = GameManager.Instance.PlayerEntityBehaviour; missile.TargetType = TargetTypes.SingleTargetAtRange; missile.ElementType = ElementTypes.None; missile.IsArrow = true; missile.IsArrowSummoned = isArrowSummoned; lastBowUsed = usingRightHand ? currentRightHandWeapon : currentLeftHandWeapon;; } } // Fatigue loss playerEntity.DecreaseFatigue(swingWeaponFatigueLoss); // Play swing sound if attack didn't hit an enemy. if (!hitEnemy && ScreenWeapon.WeaponType != WeaponTypes.Bow) { ScreenWeapon.PlaySwingSound(); } else { // Tally skills if (ScreenWeapon.WeaponType == WeaponTypes.Melee || ScreenWeapon.WeaponType == WeaponTypes.Werecreature) { playerEntity.TallySkill(DFCareer.Skills.HandToHand, 1); } else if (usingRightHand && (currentRightHandWeapon != null)) { playerEntity.TallySkill(currentRightHandWeapon.GetWeaponSkillID(), 1); } else if (currentLeftHandWeapon != null) { playerEntity.TallySkill(currentLeftHandWeapon.GetWeaponSkillID(), 1); } playerEntity.TallySkill(DFCareer.Skills.CriticalStrike, 1); } isDamageFinished = true; } }
/// <summary> /// Generates an array of items based on loot chance matrix. /// </summary> /// <param name="matrix">Loot chance matrix.</param> /// <param name="playerEntity">Player entity.</param> /// <returns>DaggerfallUnityItem array.</returns> public static DaggerfallUnityItem[] GenerateRandomLoot(LootChanceMatrix matrix, PlayerEntity playerEntity) { // Notes: The first part of the DF Chronicles explanation of how loot is generated does not match the released game. // It says the chance for each item category is the matrix amount * the level of the NPC. Actual behavior in the // released game is (matrix amount * PC level) for the first 4 item categories (temperate plants, warm plants, // miscellaneous monster, warm monster), and just matrix amount for the categories after that. // The second part of the DF Chronicles explanation (roll repeatedly for items from a category, each time at halved // chance), matches the game. // In classic, since a 0-99 roll is compared to whether it is less or greater than item chance, // even a 0% chance category has a 1/100 chance to appear, and the chance values are effectively // 1 higher than what the loot tables show. float chance; List <DaggerfallUnityItem> items = new List <DaggerfallUnityItem>(); // Reseed random Random.InitState(items.GetHashCode()); // Random gold int goldCount = Random.Range(matrix.MinGold, matrix.MaxGold + 1) * playerEntity.Level; if (goldCount > 0) { items.Add(ItemBuilder.CreateGoldPieces(goldCount)); } // Random weapon chance = matrix.WP; while (Dice100.SuccessRoll((int)chance)) { items.Add(ItemBuilder.CreateRandomWeapon(playerEntity.Level)); chance *= 0.5f; } // Random armor chance = matrix.AM; while (Dice100.SuccessRoll((int)chance)) { items.Add(ItemBuilder.CreateRandomArmor(playerEntity.Level, playerEntity.Gender, playerEntity.Race)); chance *= 0.5f; } // Random ingredients RandomIngredient(matrix.C1 * playerEntity.Level, ItemGroups.CreatureIngredients1, items); RandomIngredient(matrix.C2 * playerEntity.Level, ItemGroups.CreatureIngredients2, items); RandomIngredient(matrix.C3, ItemGroups.CreatureIngredients3, items); RandomIngredient(matrix.P1 * playerEntity.Level, ItemGroups.PlantIngredients1, items); RandomIngredient(matrix.P2 * playerEntity.Level, ItemGroups.PlantIngredients2, items); RandomIngredient(matrix.M1, ItemGroups.MiscellaneousIngredients1, items); RandomIngredient(matrix.M2, ItemGroups.MiscellaneousIngredients2, items); // Random magic item chance = matrix.MI; while (Dice100.SuccessRoll((int)chance)) { items.Add(ItemBuilder.CreateRandomMagicItem(playerEntity.Level, playerEntity.Gender, playerEntity.Race)); chance *= 0.5f; } // Random clothes chance = matrix.CL; while (Dice100.SuccessRoll((int)chance)) { items.Add(ItemBuilder.CreateRandomClothing(playerEntity.Gender, playerEntity.Race)); chance *= 0.5f; } // Random books chance = matrix.BK; while (Dice100.SuccessRoll((int)chance)) { items.Add(ItemBuilder.CreateRandomBook()); chance *= 0.5f; } // Random religious item chance = matrix.RL; while (Dice100.SuccessRoll((int)chance)) { items.Add(ItemBuilder.CreateRandomReligiousItem()); chance *= 0.5f; } return(items.ToArray()); }
private int ApplyDamageToNonPlayer(Items.DaggerfallUnityItem weapon, Vector3 direction, bool bowAttack = false) { if (senses.Target == null) { return(0); } // TODO: Merge with hit code in WeaponManager to eliminate duplicate code EnemyEntity entity = entityBehaviour.Entity as EnemyEntity; EnemyEntity targetEntity = senses.Target.Entity as EnemyEntity; EnemySounds targetSounds = senses.Target.GetComponent <EnemySounds>(); EnemyMotor targetMotor = senses.Target.transform.GetComponent <EnemyMotor>(); // Calculate damage damage = FormulaHelper.CalculateAttackDamage(entity, targetEntity, false, 0, weapon); // Break any "normal power" concealment effects on enemy if (entity.IsMagicallyConcealedNormalPower && damage > 0) { EntityEffectManager.BreakNormalPowerConcealmentEffects(entityBehaviour); } // Play hit sound and trigger blood splash at hit point if (damage > 0) { targetSounds.PlayHitSound(weapon); EnemyBlood blood = senses.Target.transform.GetComponent <EnemyBlood>(); CharacterController targetController = senses.Target.transform.GetComponent <CharacterController>(); Vector3 bloodPos = senses.Target.transform.position + targetController.center; bloodPos.y += targetController.height / 8; if (blood) { blood.ShowBloodSplash(targetEntity.MobileEnemy.BloodIndex, bloodPos); } // Knock back enemy based on damage and enemy weight if (targetMotor && (targetMotor.KnockbackSpeed <= (5 / (PlayerSpeedChanger.classicToUnitySpeedUnitRatio / 10)) && (entityBehaviour.EntityType == EntityTypes.EnemyClass || targetEntity.MobileEnemy.Weight > 0))) { float enemyWeight = targetEntity.GetWeightInClassicUnits(); float tenTimesDamage = damage * 10; float twoTimesDamage = damage * 2; float knockBackAmount = ((tenTimesDamage - enemyWeight) * 256) / (enemyWeight + tenTimesDamage) * twoTimesDamage; float KnockbackSpeed = (tenTimesDamage / enemyWeight) * (twoTimesDamage - (knockBackAmount / 256)); KnockbackSpeed /= (PlayerSpeedChanger.classicToUnitySpeedUnitRatio / 10); if (KnockbackSpeed < (15 / (PlayerSpeedChanger.classicToUnitySpeedUnitRatio / 10))) { KnockbackSpeed = (15 / (PlayerSpeedChanger.classicToUnitySpeedUnitRatio / 10)); } targetMotor.KnockbackSpeed = KnockbackSpeed; targetMotor.KnockbackDirection = direction; } if (DaggerfallUnity.Settings.CombatVoices && senses.Target.EntityType == EntityTypes.EnemyClass && Dice100.SuccessRoll(40)) { DaggerfallMobileUnit targetMobileUnit = senses.Target.GetComponentInChildren <DaggerfallMobileUnit>(); Genders gender; if (targetMobileUnit.Summary.Enemy.Gender == MobileGender.Male || targetEntity.MobileEnemy.ID == (int)MobileTypes.Knight_CityWatch) { gender = Genders.Male; } else { gender = Genders.Female; } targetSounds.PlayCombatVoice(gender, false, damage >= targetEntity.MaxHealth / 4); } } else { WeaponTypes weaponType = WeaponTypes.Melee; if (weapon != null) { weaponType = DaggerfallUnity.Instance.ItemHelper.ConvertItemToAPIWeaponType(weapon); } if ((!bowAttack && !targetEntity.MobileEnemy.ParrySounds) || weaponType == WeaponTypes.Melee) { sounds.PlayMissSound(weapon); } else if (targetEntity.MobileEnemy.ParrySounds) { targetSounds.PlayParrySound(); } } // Handle Strikes payload from enemy to non-player target - this could change damage amount if (weapon != null && weapon.IsEnchanted) { EntityEffectManager effectManager = GetComponent <EntityEffectManager>(); if (effectManager) { damage = effectManager.DoItemEnchantmentPayloads(EnchantmentPayloadFlags.Strikes, weapon, entity.Items, targetEntity.EntityBehaviour, damage); } } targetEntity.DecreaseHealth(damage); if (targetMotor) { targetMotor.MakeEnemyHostileToAttacker(entityBehaviour); } return(damage); }
private void MeleeDamage() { if (entityBehaviour) { EnemyEntity entity = entityBehaviour.Entity as EnemyEntity; EnemyEntity targetEntity = null; if (senses.Target != null && senses.Target != GameManager.Instance.PlayerEntityBehaviour) { targetEntity = senses.Target.Entity as EnemyEntity; } // Switch to hand-to-hand if enemy is immune to weapon Items.DaggerfallUnityItem weapon = entity.ItemEquipTable.GetItem(Items.EquipSlots.RightHand); if (weapon != null && targetEntity != null && targetEntity.MobileEnemy.MinMetalToHit > (Items.WeaponMaterialTypes)weapon.NativeMaterialValue) { weapon = null; } damage = 0; // Melee hit detection, matched to classic if (senses.Target != null && senses.TargetInSight && (senses.DistanceToTarget <= 0.25f || (senses.DistanceToTarget <= MeleeDistance && senses.TargetIsWithinYawAngle(35.156f, senses.Target.transform.position)))) { if (senses.Target == GameManager.Instance.PlayerEntityBehaviour) { damage = ApplyDamageToPlayer(weapon); } else { damage = ApplyDamageToNonPlayer(weapon, transform.forward); } } // Handle bashing door else if (motor.Bashing && senses.LastKnownDoor != null && senses.DistanceToDoor <= MeleeDistance && !senses.LastKnownDoor.IsOpen) { senses.LastKnownDoor.AttemptBash(false); } else { sounds.PlayMissSound(weapon); } if (DaggerfallUnity.Settings.CombatVoices && entity.EntityType == EntityTypes.EnemyClass && Dice100.SuccessRoll(20)) { Genders gender; if (mobile.Summary.Enemy.Gender == MobileGender.Male || entity.MobileEnemy.ID == (int)MobileTypes.Knight_CityWatch) { gender = Genders.Male; } else { gender = Genders.Female; } sounds.PlayCombatVoice(gender, true); } } }