public async Task <ImmutableDictionary <BodyPartIndex, Wound> > HitCalculateAsync( Immutable <IEntity> attacker, Immutable <IEntity> defender, Immutable <IEntity> injurant, HitMethod hitMethod) { switch (hitMethod) { case HitMethod.Fist: case HitMethod.Foot: { if (injurant.Value == null) { return(await HitCalculateWithoutInjurantAsync(attacker.Value, defender.Value, hitMethod)); } throw new NotSupportedException(); } case HitMethod.Melee: case HitMethod.Magic: case HitMethod.Projectile: case HitMethod.Temperature: case HitMethod.Trap: throw new NotSupportedException(); default: throw new ArgumentOutOfRangeException(nameof(hitMethod), hitMethod, null); } }
public async Task <AttackResult> Attack(IEntity target, IEntity injurant, HitMethod hitMethod) { // TODO check distance var attackResult = await _hitStrategy.HitCalculateAsync( GrainFactory.GetEntity(this).AsImmutable(), target.AsImmutable(), injurant.AsImmutable(), hitMethod); return(attackResult.IsEmpty ? AttackResult.Miss() : AttackResult.Hit(attackResult)); }
private async Task <ImmutableDictionary <BodyPartIndex, Wound> > HitCalculateWithoutInjurantAsync( IEntity attacker, IEntity defender, HitMethod hitMethod) { UnitState attackerState = await GrainFactory.Get <IUnit>(attacker).GetData(); UnitState defenderState = await GrainFactory.Get <IUnit>(defender).GetData(); UnitProperty hitRate; UnitProperty dodgeRate = defenderState.DodgeRate; UnitProperty attackEfficiency; switch (hitMethod) { case HitMethod.Fist: hitRate = attackerState.UpperAttackHitRate; attackEfficiency = attackerState.UpperAttackEfficiency; break; case HitMethod.Foot: hitRate = attackerState.LowerAttackHitRate; attackEfficiency = attackerState.LowerAttackEfficiency; break; default: throw new ArgumentOutOfRangeException(nameof(hitMethod), hitMethod, null); } double hitP = 1 - Math.Exp(hitRate / dodgeRate); if (Rand.NextDouble() > hitP) { return(ImmutableDictionary <BodyPartIndex, Wound> .Empty); } var attackResult = new Dictionary <BodyPartIndex, Wound>(); for (var i = 0; i < (int)BodyPartIndex.BodyPartCount; i++) { if (Options.BodyHitBaseProbability[i] > Rand.NextDouble()) { attackResult.Add((BodyPartIndex)i, new Wound((uint)attackEfficiency, WoundType.Bruise)); } } return(attackResult.ToImmutableDictionary()); }