public void TakeDamage(ActorHitInfo data) { if (MetaState.Instance.SessionFlags.Contains("GodMode") || GameState.Instance.PlayerFlags.Contains(PlayerFlags.Invulnerable) || IsDying) { return; } if (!data.HarmFriendly) { string hitFaction = data.OriginatorFaction; if (!string.IsNullOrEmpty(hitFaction)) { FactionRelationStatus relation = FactionModel.GetRelation(hitFaction, PredefinedFaction.Player.ToString()); //this looks backwards but it's because we're checking if the Bullet is-friendly-to the Actor if (relation == FactionRelationStatus.Friendly) { return; //no friendly fire } } } if (DamageHandler != null) { var hitOut = DamageHandler(data); if (hitOut.HasValue) { data = hitOut.Value; } else { return; } } CharacterModel playerModel = GameState.Instance.PlayerRpgState; var(damageToShields, damageToArmor, damageToCharacter) = RpgValues.DamageRatio(data.Damage, data.DamagePierce, playerModel); float oldShields = playerModel.Shields; playerModel.Shields -= damageToShields; if (oldShields > 0 && playerModel.Shields <= 0) { MessageInterface.PushToBus(new QdmsFlagMessage("PlayerShieldsLost")); ShieldComponent.Ref()?.SignalLostShields(); } var(dt, dr) = playerModel.GetDamageThresholdAndResistance(data.DamageType); float damageTaken = RpgValues.DamageTaken(damageToArmor, damageToCharacter, dt, dr); if (data.HitLocation == (int)ActorBodyPart.Head) { damageTaken *= 2.0f; } else if (data.HitLocation == (int)ActorBodyPart.LeftArm || data.HitLocation == (int)ActorBodyPart.LeftLeg || data.HitLocation == (int)ActorBodyPart.RightArm || data.HitLocation == (int)ActorBodyPart.RightLeg) { damageTaken *= 0.75f; } playerModel.Health -= damageTaken; if (damageTaken > PainSoundThreshold) { if (PainSound != null && !PainSound.isPlaying) { PainSound.Play(); } } if (damageToShields > 0 || damageTaken > 0) { ShieldComponent.Ref()?.SignalTookDamage(damageToShields, damageTaken); var damageValues = new Dictionary <string, object>() { { "DamageTaken", damageTaken }, { "DamageToShields", damageToShields }, { "DamageToArmor", damageToArmor }, { "DamageToCharacter", damageToCharacter } }; MessageInterface.PushToBus(new QdmsKeyValueMessage(damageValues, "PlayerTookDamage")); } }
private void SelectTarget() { var gameplayConfig = ConfigState.Instance.GetGameplayConfig(); if (TotalTickCount % SearchInterval * (1f / gameplayConfig.Difficulty.ActorAggression) != 0) { return; } var detectionDifficultyFactor = 1f / gameplayConfig.Difficulty.ActorPerception; //check player first since it's (relatively) cheap if (FactionModel.GetRelation(Faction, "Player") == FactionRelationStatus.Hostile && !MetaState.Instance.SessionFlags.Contains("NoTarget") && !GameState.Instance.PlayerFlags.Contains(PlayerFlags.NoTarget)) { var playerObj = WorldUtils.GetPlayerObject(); if (playerObj != null && RpgWorldUtils.TargetIsAlive(playerObj.transform)) { PlayerController pc = playerObj.GetComponent <PlayerController>(); if ((playerObj.transform.position - transform.position).magnitude <= SearchRadius && UnityEngine.Random.Range(0f, 1f * detectionDifficultyFactor) <= RpgValues.DetectionChance(GameState.Instance.PlayerRpgState, pc.MovementComponent.IsCrouching, pc.MovementComponent.IsRunning)) { if (UseLineOfSight) { //additional check RaycastHit hitinfo; if (Physics.Raycast(transform.position + new Vector3(0, 1.0f, 0), (playerObj.transform.position - transform.position), out hitinfo)) { if (hitinfo.collider.gameObject == playerObj) { Target = playerObj.transform; return; } } } else { //otherwise, close enough Target = playerObj.transform; return; } } } } //if(TargetNpc) { //var sw = System.Diagnostics.Stopwatch.StartNew(); //new code should be faster if n is large but it may not bear out in practice, and it probably allocs more dedotated wam var colliders = Physics.OverlapSphere(transform.position, SearchRadius, LayerMask.GetMask("Default", "ActorHitbox")); HashSet <ActorController> potentialTargets = new HashSet <ActorController>(); foreach (var collider in colliders) { var actorController = collider.GetComponent <ActorController>(); if (actorController != null) { potentialTargets.Add(actorController); break; } var hitboxComponent = collider.GetComponent <IHitboxComponent>(); if (hitboxComponent != null && hitboxComponent.ParentController is ActorController hitboxAC) { potentialTargets.Add(hitboxAC); break; } } //old stupid code: should work well enough as long as n is small and your computer is fast enough //IEnumerable<ActorController> potentialTargets = transform.root.GetComponentsInChildren<ActorController>(); foreach (var potentialTarget in potentialTargets) { if (RpgWorldUtils.TargetIsAlive(potentialTarget.transform) && (potentialTarget.transform.position - transform.position).magnitude <= SearchRadius && FactionModel.GetRelation(Faction, potentialTarget.Faction) == FactionRelationStatus.Hostile && !(potentialTarget == this)) { //roll some dice if (potentialTarget.Detectability < 1 && UnityEngine.Random.Range(0f, 1f * detectionDifficultyFactor) > potentialTarget.Detectability) //probably correct { continue; } if (UseLineOfSight) { //additional check RaycastHit hitinfo; if (Physics.Raycast(transform.position + new Vector3(0, 1.0f, 0), (potentialTarget.transform.position - transform.position), out hitinfo)) { if (hitinfo.collider.gameObject == potentialTarget.gameObject) { Target = potentialTarget.transform; break; } } } else { //otherwise, close enough Target = potentialTarget.transform; break; } } } //sw.Stop(); //Debug.Log($"Target lookup: {sw.Elapsed.TotalMilliseconds:F4} ms"); } if (!RpgWorldUtils.TargetIsAlive(Target)) { Target = null; } }
public void TakeDamage(ActorHitInfo data) { //damage model is very stupid right now, we will make it better later float dt = data.DamageType < DamageThreshold.Length ? DamageThreshold[(int)data.DamageType] : 0f; float dr = data.DamageType < DamageThreshold.Length ? DamageResistance[(int)data.DamageType] : 0f; float damageTaken = RpgValues.DamageTaken(data.Damage, data.DamagePierce, dt, dr); if (data.HitLocation == (int)ActorBodyPart.Head) { damageTaken *= 2.0f; } else if (data.HitLocation == (int)ActorBodyPart.LeftArm || data.HitLocation == (int)ActorBodyPart.LeftLeg || data.HitLocation == (int)ActorBodyPart.RightArm || data.HitLocation == (int)ActorBodyPart.RightLeg) { damageTaken *= 0.75f; } damageTaken *= (1f / ConfigState.Instance.GetGameplayConfig().Difficulty.ActorStrength); if (!Invincible) { Health -= damageTaken; } /* * if(!string.IsNullOrEmpty(data.HitPuff)) * { * Debug.Log($"Spawning hitpuff \"{data.HitPuff}\" at {data.HitCoords}"); * Vector3 hitCoords = data.HitCoords.HasValue ? data.HitCoords.Value : transform.position; * WorldUtils.SpawnEffect(data.HitPuff, hitCoords, transform.eulerAngles, null); * } * else if(!string.IsNullOrEmpty(DefaultHitPuff)) * { * Vector3 hitCoords = data.HitCoords.HasValue ? data.HitCoords.Value : transform.position; * WorldUtils.SpawnEffect(DefaultHitPuff, hitCoords, transform.eulerAngles, null); * } */ //we no longer spawn hitpuffs here if (CurrentAiState == ActorAiState.Dead) //abort if we're already dead { return; } bool didTakePain = UnityEngine.Random.Range(0f, 1f) < PainChance; if (Defensive && data.Originator != null && data.Originator != this) { FactionRelationStatus relation = FactionRelationStatus.Neutral; if (data.Originator is PlayerController) { relation = FactionModel.GetRelation(Faction, "Player"); } else if (data.Originator is ActorController) { relation = FactionModel.GetRelation(Faction, ((ActorController)data.Originator).Faction); } if (relation != FactionRelationStatus.Friendly || Infighting) { Target = data.Originator.transform; BeenHit = true; if (DisableInteractionOnHit && InteractionComponent != null) { InteractionComponent.InteractionDisabledByHit = true; } if (FeelPain && didTakePain) { EnterState(ActorAiState.Hurting); } else { EnterState(ActorAiState.Chasing); } } else { EnterState(ActorAiState.Hurting); } } else if (FeelPain && didTakePain) { EnterState(ActorAiState.Hurting); } }
public void TakeDamage(ActorHitInfo data) { if (!data.HarmFriendly) { string hitFaction = data.OriginatorFaction; if (!string.IsNullOrEmpty(hitFaction)) { FactionRelationStatus relation = FactionModel.GetRelation(hitFaction, Faction); //this looks backwards but it's because we're checking if the Bullet is-friendly-to the Actor if (relation == FactionRelationStatus.Friendly) { return; //no friendly fire } } } //damage model is very stupid right now, we will make it better later float dt = data.DamageType < DamageThreshold.Length ? DamageThreshold[(int)data.DamageType] : 0f; float dr = data.DamageType < DamageThreshold.Length ? DamageResistance[(int)data.DamageType] : 0f; float damageTaken = RpgValues.DamageTaken(data.Damage, data.DamagePierce, dt, dr); if (data.HitLocation == (int)ActorBodyPart.Head) { damageTaken *= 2.0f; } else if (data.HitLocation == (int)ActorBodyPart.LeftArm || data.HitLocation == (int)ActorBodyPart.LeftLeg || data.HitLocation == (int)ActorBodyPart.RightArm || data.HitLocation == (int)ActorBodyPart.RightLeg) { damageTaken *= 0.75f; } damageTaken *= (1f / ConfigState.Instance.GetGameplayConfig().Difficulty.ActorStrength); if (!Invincible) { Health -= damageTaken; } if (CurrentAiState == ActorAiState.Dead) //abort if we're already dead { return; } bool didTakePain = UnityEngine.Random.Range(0f, 1f) < PainChance; //shouldn't this be weighted by damage? if (Defensive && data.Originator != null && data.Originator != this) { FactionRelationStatus relation = FactionRelationStatus.Neutral; if (data.Originator is PlayerController) { relation = FactionModel.GetRelation(Faction, "Player"); } else if (data.Originator is ActorController) { relation = FactionModel.GetRelation(Faction, ((ActorController)data.Originator).Faction); } if (relation != FactionRelationStatus.Friendly || Infighting) { Target = data.Originator.transform; BeenHit = true; if (DisableInteractionOnHit && InteractionComponent != null) { InteractionComponent.InteractionDisabledByHit = true; } if (FeelPain && didTakePain) { if (CurrentAiState != ActorAiState.Hurting) { EnterState(ActorAiState.Hurting); } else { EnterState(ActorAiState.Chasing); } } } else if (CurrentAiState != ActorAiState.Hurting) { EnterState(ActorAiState.Hurting); } } else if (FeelPain && didTakePain && CurrentAiState != ActorAiState.Hurting) { EnterState(ActorAiState.Hurting); } }