void UpdateHeadTexture() { ImageData head; // Check for racial override head RacialOverrideEffect racialOverride = GameManager.Instance.PlayerEffectManager.GetRacialOverrideEffect(); if (racialOverride != null && racialOverride.GetCustomHeadImageData(playerEntity, out head)) { HeadTexture = head.texture; return; } // Otherwise just get standard head based on gender and race switch (playerEntity.Gender) { default: case Genders.Male: head = ImageReader.GetImageData(playerEntity.RaceTemplate.PaperDollHeadsMale, playerEntity.FaceIndex, 0, true); break; case Genders.Female: head = ImageReader.GetImageData(playerEntity.RaceTemplate.PaperDollHeadsFemale, playerEntity.FaceIndex, 0, true); break; } HeadTexture = head.texture; }
// Update player background panel void RefreshBackground(PlayerEntity entity) { // Allow racial override background (vampire / transformed were-creature) // If racial override is not present or returns null then standard racial background will be used // The racial override has full control over which texture is displayed, such as when were-creature transformed or not Texture2D customBackground; RacialOverrideEffect racialOverride = GameManager.Instance.PlayerEffectManager.GetRacialOverrideEffect(); if (racialOverride != null && racialOverride.GetCustomPaperDollBackgroundTexture(entity, out customBackground)) { backgroundPanel.BackgroundTexture = customBackground; backgroundPanel.Size = new Vector2(paperDollWidth, paperDollHeight); lastBackgroundName = string.Empty; return; } // Use standard racial background string backgroundName = GetPaperDollBackground(entity); if (lastBackgroundName != backgroundName) { Texture2D texture = ImageReader.GetTexture(backgroundName, 0, 0, false); backgroundPanel.BackgroundTexture = ImageReader.GetSubTexture(texture, backgroundSubRect, backgroundFullSize); backgroundPanel.Size = new Vector2(paperDollWidth, paperDollHeight); lastBackgroundName = backgroundName; } }
/// <summary> /// Redraws paper doll image and selection mask. /// Call this after changing equipment, loading a new game, etc. /// Only call when required as constructing paper doll image is expensive. /// </summary> /// <param name="playerEntity"></param> public void Refresh(PlayerEntity playerEntity = null) { // Get current player entity if one not provided if (playerEntity == null) { playerEntity = GameManager.Instance.PlayerEntity; } // Racial override can suppress body and items bool suppressBody = false; RacialOverrideEffect racialOverride = GameManager.Instance.PlayerEffectManager.GetRacialOverrideEffect(); if (racialOverride != null) { suppressBody = racialOverride.SuppressPaperDollBodyAndItems; } // Update background RefreshBackground(playerEntity); // Display paper doll render DaggerfallUI.Instance.PaperDollRenderer.Refresh(PaperDollRenderer.LayerFlags.All, playerEntity); characterPanel.BackgroundTexture = DaggerfallUI.Instance.PaperDollRenderer.PaperDollTexture; // Update armour values RefreshArmourValues(playerEntity, suppressBody); }
/// <summary> /// Renders a new paper doll image for the specified player entity. /// </summary> /// <param name="layers">Flags controlling which layers of paper doll to draw.</param> /// <param name="playerEntity">Player entity to use for paper doll construction. Use null for live player entity.</param> public void Refresh(LayerFlags layers = LayerFlags.All, PlayerEntity playerEntity = null) { // Clear current item layout itemLayout.Clear(); // Get current player entity if one not provided if (playerEntity == null) { playerEntity = GameManager.Instance.PlayerEntity; } // Racial override can suppress body and items bool suppressBody = false; RacialOverrideEffect racialOverride = GameManager.Instance.PlayerEffectManager.GetRacialOverrideEffect(); if (racialOverride != null) { suppressBody = racialOverride.SuppressPaperDollBodyAndItems; } // Start rendering to paper doll target RenderTexture oldRT = RenderTexture.active; RenderTexture.active = target; GL.PushMatrix(); GL.LoadPixelMatrix(0, target.width, target.height, 0); // Clear render target GL.Clear(true, true, Color.clear); if (!suppressBody) { // Cloak interior if ((layers & LayerFlags.CloakInterior) == LayerFlags.CloakInterior) { BlitCloakInterior(playerEntity); } // Body if ((layers & LayerFlags.Body) == LayerFlags.Body) { BlitBody(playerEntity); } // Items if ((layers & LayerFlags.Items) == LayerFlags.Items) { BlitItems(playerEntity); } } // Copy render to new output paperDollTexture.ReadPixels(new Rect(0, 0, target.width, target.height), 0, 0); paperDollTexture.Apply(); // Switch back to previous render target GL.PopMatrix(); RenderTexture.active = oldRT; }
// Capture this message so we can play pain voice public void RemoveHealth(int amount) { // Racial override can suppress optional attack voice RacialOverrideEffect racialOverride = GameManager.Instance.PlayerEffectManager.GetRacialOverrideEffect(); bool suppressCombatVoices = racialOverride != null && racialOverride.SuppressOptionalCombatVoices; if (dfAudioSource && DaggerfallUnity.Settings.CombatVoices && !suppressCombatVoices && 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> /// Redraws paper doll image and selection mask. /// Call this after changing equipment, loading a new game, etc. /// Only call when required as constructing paper doll image is expensive. /// </summary> /// <param name="playerEntity"></param> public void Refresh(PlayerEntity playerEntity = null) { // Get current player entity if one not provided if (playerEntity == null) { playerEntity = GameManager.Instance.PlayerEntity; } // Racial override can suppress body and items bool suppressBody = false; RacialOverrideEffect racialOverride = GameManager.Instance.PlayerEffectManager.GetRacialOverrideEffect(); if (racialOverride != null) { suppressBody = racialOverride.SuppressPaperDollBodyAndItems; } // Update paper doll ClearPaperDoll(); RefreshBackground(playerEntity); if (!suppressBody) { BlitCloakInterior(playerEntity); BlitBody(playerEntity); BlitItems(playerEntity); } // Destroy old paper doll texture characterPanel.BackgroundTexture = null; GameObject.Destroy(paperDollTexture); paperDollTexture = null; // Update paper doll texture paperDollTexture = ImageReader.GetTexture(paperDollColors, paperDollWidth, paperDollHeight); characterPanel.BackgroundTexture = paperDollTexture; // Display using new paper doll renderer //DaggerfallUI.Instance.PaperDollRenderer.Refresh(PaperDollRenderer.LayerFlags.All, playerEntity); //characterPanel.BackgroundTexture = DaggerfallUI.Instance.PaperDollRenderer.PaperDollTexture; //TextureReader.SaveTextureToPNG(DaggerfallUI.Instance.PaperDollRenderer.PaperDollTexture, "c:\\test\\testrender.png"); // Update armour values RefreshArmourValues(playerEntity, suppressBody); }
ImageData GetHeadImageData(PlayerEntity entity) { // Check for racial override head ImageData customHead; RacialOverrideEffect racialOverride = GameManager.Instance.PlayerEffectManager.GetRacialOverrideEffect(); if (racialOverride != null && racialOverride.GetCustomHeadImageData(entity, out customHead)) { return(customHead); } // Otherwise just get standard head based on gender and race switch (entity.Gender) { default: case Genders.Male: return(ImageReader.GetImageData(entity.RaceTemplate.PaperDollHeadsMale, entity.FaceIndex, 0, true)); case Genders.Female: return(ImageReader.GetImageData(entity.RaceTemplate.PaperDollHeadsFemale, entity.FaceIndex, 0, true)); } }
void ApplyWeapon() { if (!ScreenWeapon) { return; } RacialOverrideEffect racialOverride = GameManager.Instance.PlayerEffectManager.GetRacialOverrideEffect(); if (racialOverride != null && racialOverride.SetFPSWeapon(ScreenWeapon)) { return; } else if (usingRightHand) { if (currentRightHandWeapon == null) { SetMelee(ScreenWeapon); } else { SetWeapon(ScreenWeapon, currentRightHandWeapon); } } else { if (currentLeftHandWeapon == null) { SetMelee(ScreenWeapon); } else { SetWeapon(ScreenWeapon, currentLeftHandWeapon); } } ScreenWeapon.Reach = defaultWeaponReach; }
// Returns true if hit an enemy entity public bool WeaponDamage(RaycastHit hit, Vector3 direction, bool arrowHit = false) { DaggerfallUnityItem strikingWeapon = null; // Check if hit has an DaggerfallAction component DaggerfallAction action = hit.transform.gameObject.GetComponent <DaggerfallAction>(); if (action) { action.Receive(player, DaggerfallAction.TriggerTypes.Attack); } // Check if hit has an DaggerfallActionDoor component DaggerfallActionDoor actionDoor = hit.transform.gameObject.GetComponent <DaggerfallActionDoor>(); if (actionDoor) { actionDoor.AttemptBash(true); return(false); } // Check if player hit a static exterior door if (GameManager.Instance.PlayerActivate.AttemptExteriorDoorBash(hit)) { return(false); } // Set up for use below DaggerfallEntityBehaviour entityBehaviour = hit.transform.GetComponent <DaggerfallEntityBehaviour>(); DaggerfallMobileUnit entityMobileUnit = hit.transform.GetComponentInChildren <DaggerfallMobileUnit>(); EnemyMotor enemyMotor = hit.transform.GetComponent <EnemyMotor>(); EnemySounds enemySounds = hit.transform.GetComponent <EnemySounds>(); // Check if hit a mobile NPC MobilePersonNPC mobileNpc = hit.transform.GetComponent <MobilePersonNPC>(); if (mobileNpc) { if (!mobileNpc.Billboard.IsUsingGuardTexture) { EnemyBlood blood = hit.transform.GetComponent <EnemyBlood>(); if (blood) { blood.ShowBloodSplash(0, hit.point); } mobileNpc.Motor.gameObject.SetActive(false); playerEntity.TallyCrimeGuildRequirements(false, 5); playerEntity.CrimeCommitted = PlayerEntity.Crimes.Murder; playerEntity.SpawnCityGuards(true); } else { playerEntity.CrimeCommitted = PlayerEntity.Crimes.Assault; GameObject guard = playerEntity.SpawnCityGuard(mobileNpc.transform.position, mobileNpc.transform.forward); entityBehaviour = guard.GetComponent <DaggerfallEntityBehaviour>(); entityMobileUnit = guard.GetComponentInChildren <DaggerfallMobileUnit>(); 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 damage; if (!arrowHit) { if (usingRightHand) { strikingWeapon = currentRightHandWeapon; } else { strikingWeapon = currentLeftHandWeapon; } } else { strikingWeapon = lastBowUsed; } damage = FormulaHelper.CalculateAttackDamage(playerEntity, enemyEntity, strikingWeapon, entityMobileUnit.Summary.AnimStateRecord); // Break any "normal power" concealment effects on player if (playerEntity.IsMagicallyConcealedNormalPower && damage > 0) { EntityEffectManager.BreakNormalPowerConcealmentEffects(GameManager.Instance.PlayerEntityBehaviour); } // Play arrow sound and add arrow to target's inventory if (arrowHit) { 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 = hit.transform.GetComponent <EnemyBlood>(); if (blood) { blood.ShowBloodSplash(enemyEntity.MobileEnemy.BloodIndex, hit.point); } // 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 && UnityEngine.Random.Range(1, 101) <= 40) { Genders gender; if (entityMobileUnit.Summary.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(); } } // Remove health enemyEntity.DecreaseHealth(damage); // Assign "cast when strikes" to target entity and raise special strike handling event if (strikingWeapon != null && strikingWeapon.IsEnchanted) { EntityEffectManager enemyEffectManager = enemyEntity.EntityBehaviour.GetComponent <EntityEffectManager>(); if (enemyEffectManager) { enemyEffectManager.StrikeWithItem(strikingWeapon, GameManager.Instance.PlayerEntityBehaviour); } strikingWeapon.RaiseOnWeaponStrikeEvent(entityBehaviour, damage); } // Make foe attack their aggressor // Currently this is just player, but should be expanded later // for a wider variety of behaviours if (enemyMotor) { // Make enemies in an area aggressive if player attacked a non-hostile one. if (!enemyMotor.IsHostile) { GameManager.Instance.MakeEnemiesHostile(); } enemyMotor.MakeEnemyHostileToAttacker(GameManager.Instance.PlayerEntityBehaviour); } if (enemyEntity.MobileEnemy.ID == (int)MobileTypes.Knight_CityWatch && enemyEntity.CurrentHealth <= 0) { playerEntity.TallyCrimeGuildRequirements(false, 1); playerEntity.CrimeCommitted = PlayerEntity.Crimes.Murder; } // Allow custom race handling of weapon hit, e.g. vampire feeding RacialOverrideEffect racialOverride = GameManager.Instance.PlayerEffectManager.GetRacialOverrideEffect(); if (racialOverride != null) { racialOverride.OnWeaponHitEnemy(GameManager.Instance.PlayerEntity, enemyEntity); } return(true); } } return(false); }
// 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; } }
// Gets factionID of a faction type NPC int GetFactionTypeFactionID(string factionTypeName) { // Only allowing a small range of random faction types for now FactionFile.FactionTypes[] randomFactionTypes = new FactionFile.FactionTypes[] { FactionFile.FactionTypes.Courts, FactionFile.FactionTypes.Province, FactionFile.FactionTypes.People, FactionFile.FactionTypes.Temple, }; // P3 is faction type int factionType; Table factionsTable = QuestMachine.Instance.FactionsTable; if (factionsTable.HasValue(factionTypeName)) { factionType = Parser.ParseInt(factionsTable.GetValue("p3", factionTypeName)); } else { Debug.LogErrorFormat("Could not find factionTypeName {0}", factionTypeName); return(-1); } // Handle random faction type // This selects from a restricted pool to ensure vital NPCs don't get randomly selected if (factionType == -1) { factionType = (int)UnityEngine.Random.Range(0, randomFactionTypes.Length); } // Assign factionID based on factionType // This value is 0-15 and maps to "type:" in faction.txt // Daggerfall seems to largely select from selected pool of factionType objects at random // But some factionTypes do not exist in file and suspect special handling for others // Treating on a case-by-case basis for now switch ((FactionFile.FactionTypes)factionType) { // These faction types do not generally have a specific region associated with them // Select from pool of all objects this faction type case FactionFile.FactionTypes.Daedra: case FactionFile.FactionTypes.Group: case FactionFile.FactionTypes.Subgroup: case FactionFile.FactionTypes.Official: case FactionFile.FactionTypes.Temple: return(GetRandomFactionOfType(factionType)); // Faction type of God is never used in quests // Many of these factions do not have an NPC flat // Recommend never using - not sure how to redirect to working state yet case FactionFile.FactionTypes.God: return(GetRandomFactionOfType(factionType)); // The individual type is not used by any canonical quests // It is more or less equivalent to reserving an individual NPC // Not recommended to use this in quests // Just returning a random person to ensure NPC is created case FactionFile.FactionTypes.Individual: return(GetRandomFactionOfType(factionType)); // Classic is bugged there as it always selects a random vampire clan. // Here we fix it by using player vampire clan for vampire and cure vampirism quests // and by using the vampire clan affiliated to the current region otherwise. case FactionFile.FactionTypes.VampireClan: if (ParentQuest.QuestName.StartsWith("P0") || ParentQuest.QuestName.StartsWith("$CUREVAM")) { RacialOverrideEffect racialEffect = GameManager.Instance.PlayerEffectManager.GetRacialOverrideEffect(); return((int)(racialEffect as VampirismEffect).VampireClan); } else { return(GameManager.Instance.PlayerGPS.GetCurrentRegionVampireClan()); } // Assign an NPC from current player region case FactionFile.FactionTypes.Province: return(GameManager.Instance.PlayerGPS.GetCurrentRegionFaction()); // Not all regions have a witches coven associated // Just select a random coven for now case FactionFile.FactionTypes.WitchesCoven: return(GetRandomFactionOfType(factionType)); // Type 10 Knightly_Guard does not exist in FACTION.TXT but IS used in some quests // Redirecting this to "Generic Knightly Order" #844 to ensure NPC is created case FactionFile.FactionTypes.KnightlyGuard: return(844); // Type 11 Magic_User does not exist in FACTION.TXT and is not used in any quests // Redirecting this to "Mages Guild" #40 to ensure NPC is created case FactionFile.FactionTypes.MagicUser: return(40); // Type 12 Generic_Group does not exist in FACTION.TXT and is not used in any quests // Redirecting this to a random choice between "Generic Temple" #450 and "Generic Knightly Order" #844 to ensure NPC is created case FactionFile.FactionTypes.Generic: return((UnityEngine.Random.Range(0f, 1f) < 0.5f) ? 450 : 844); // Type 13 Thieves_Den does not exist in FACTION.TXT and is not used in any quests // Redirecting this to "Thieves Guild" #42 to ensure NPC is created case FactionFile.FactionTypes.Thieves: return(42); // Get "court of" current region case FactionFile.FactionTypes.Courts: return(GameManager.Instance.PlayerGPS.GetCourtOfCurrentRegion()); // Get "people of" current region case FactionFile.FactionTypes.People: return(GameManager.Instance.PlayerGPS.GetPeopleOfCurrentRegion()); // Give up default: return(-1); } }
public static SoundClips GetRaceGenderAttackSound(Races race, Genders gender, bool isPlayerAttack = false) { // Check for racial override attack sound for player only if (isPlayerAttack) { SoundClips customSound; RacialOverrideEffect racialOverride = GameManager.Instance.PlayerEffectManager.GetRacialOverrideEffect(); if (racialOverride != null && racialOverride.GetCustomRaceGenderAttackSoundData(GameManager.Instance.PlayerEntity, out customSound)) { return(customSound); } } if (gender == Genders.Male) { switch (race) { case Races.Breton: return(SoundClips.BretonMalePain1); case Races.Redguard: return(SoundClips.RedguardMalePain1); case Races.Nord: return(SoundClips.NordMalePain1); case Races.DarkElf: return(SoundClips.DarkElfMalePain1); case Races.HighElf: return(SoundClips.HighElfMalePain1); case Races.WoodElf: return(SoundClips.WoodElfMalePain1); case Races.Khajiit: return(SoundClips.KhajiitMalePain1); case Races.Argonian: return(SoundClips.ArgonianMalePain1); default: return(SoundClips.None); } } else { switch (race) { case Races.Breton: case Races.Redguard: case Races.Nord: int random = UnityEngine.Random.Range(0, 3); if (random == 0) { return(SoundClips.BretonFemalePain1); } else if (random == 1) { return(SoundClips.BretonFemalePain2); } else { return(SoundClips.DarkElfFemalePain2); } case Races.DarkElf: case Races.HighElf: case Races.WoodElf: random = UnityEngine.Random.Range(0, 2); if (random == 0) { return(SoundClips.HighElfFemalePain1); } else { return(SoundClips.HighElfFemalePain2); } case Races.Khajiit: random = UnityEngine.Random.Range(0, 2); if (random == 0) { return(SoundClips.KhajiitFemalePain1); } else { return(SoundClips.KhajiitFemalePain2); } case Races.Argonian: random = UnityEngine.Random.Range(0, 2); if (random == 0) { return(SoundClips.ArgonianFemalePain1); } else { return(SoundClips.ArgonianFemalePain2); } default: return(SoundClips.None); } } }
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) { float cooldown = 10 * (100 - playerEntity.Stats.LiveSpeed) + 800; cooldownTime = Time.time + (cooldown / 980); // Approximates classic frame update } isAttacking = false; isDamageFinished = false; isBowSoundFinished = false; } // Do nothing while weapon cooldown. Used for bow. if (Time.time < cooldownTime) { return; } // Do nothing if weapon isn't done equipping if ((usingRightHand && EquipCountdownRightHand != 0) || (!usingRightHand && EquipCountdownLeftHand != 0)) { ShowWeapons(false); return; } // 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) { ShowWeapons(false); return; } } // Do nothing if player paralyzed if (GameManager.Instance.PlayerEntity.IsParalyzed) { ShowWeapons(false); return; } // Toggle weapon sheath if (!isAttacking && InputManager.Instance.ActionStarted(InputManager.Actions.ReadyWeapon)) { ToggleSheath(); } // Toggle weapon hand if (!isAttacking && InputManager.Instance.ActionComplete(InputManager.Actions.SwitchHand)) { ToggleHand(); } // Do nothing if weapons sheathed if (Sheathed) { ShowWeapons(false); return; } else { ShowWeapons(true); } // 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 = MouseDirections.Down; // Force attack without tracking a swing for Bow } } else if (isClickAttack) { attackDirection = (MouseDirections)UnityEngine.Random.Range((int)MouseDirections.Left, (int)MouseDirections.DownRight + 1); isClickAttack = false; } else { attackDirection = TrackMouseAttack(); // Track swing direction for other weapons } } // 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() == 3) { ScreenWeapon.PlaySwingSound(); isBowSoundFinished = true; // Remove arrow ItemCollection playerItems = playerEntity.Items; DaggerfallUnityItem arrow = playerItems.GetItem(ItemGroups.Weapons, (int)Weapons.Arrow); playerItems.RemoveOne(arrow); } 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) { missile.Caster = GameManager.Instance.PlayerEntityBehaviour; missile.TargetType = TargetTypes.SingleTargetAtRange; missile.ElementType = ElementTypes.None; missile.IsArrow = true; lastBowUsed = currentRightHandWeapon; } } // 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; } }