/// <summary> /// Check if the current attack is a chance to knockback the defender. /// </summary> /// <param name="attackerAttackFlags">Attacker attack flags</param> /// <returns></returns> public bool IsKnockback(AttackFlags attackerAttackFlags) { bool knockbackChance = RandomHelper.Random(0, 100) < 15; if (this._defender.Type == WorldEntityType.Player) { return(false); } if (this._attacker is IPlayerEntity player) { var weapon = player.Inventory[InventorySystem.RightWeaponSlot]; if (weapon == null) { weapon = InventorySystem.Hand; } if (weapon.Data.WeaponType == WeaponType.MELEE_YOYO || attackerAttackFlags.HasFlag(AttackFlags.AF_FORCE)) { return(false); } } bool canFly = false; // TODO: if is flying, return false if ((this._defender.Object.MovingFlags & ObjectState.OBJSTA_DMG_FLY_ALL) == 0 && this._defender is IMonsterEntity monster) { canFly = monster.Data.Class != MoverClassType.RANK_SUPER && monster.Data.Class != MoverClassType.RANK_MATERIAL && monster.Data.Class != MoverClassType.RANK_MIDBOSS; } return(canFly && knockbackChance); }
/// <summary> /// Check if the current attack is a chance to knockback the defender. /// </summary> /// <param name="attackerAttackFlags">Attacker attack flags</param> /// <returns></returns> public bool IsKnockback(AttackFlags attackerAttackFlags) { var knockbackChance = RandomHelper.Random(0, 100) < 15; if (Defender.Type == WorldEntityType.Player) { return(false); } if (Attacker is IPlayerEntity player) { Item weapon = player.Inventory.GetEquipedItem(ItemPartType.RightWeapon) ?? player.Hand; if (weapon.Data.WeaponType == WeaponType.MELEE_YOYO || attackerAttackFlags.HasFlag(AttackFlags.AF_FORCE)) { return(false); } } var canFly = false; // TODO: if is flying, return false if ((Defender.Object.MovingFlags & ObjectState.OBJSTA_DMG_FLY_ALL) == 0 && Defender is IMonsterEntity monster) { canFly = monster.Data.Class != MoverClassType.RANK_SUPER && monster.Data.Class != MoverClassType.RANK_MATERIAL && monster.Data.Class != MoverClassType.RANK_MIDBOSS; } return(canFly && knockbackChance); }
public override int GetDefense(Mover attacker, AttackFlags flags) { int defense = 0; if (attacker is Player) { if (flags.HasFlag(AttackFlags.AF_MAGIC)) { defense = (int)((this.Attributes[DefineAttributes.INT] * 9.04f) + (this.Level * 35.98f)); } else { // TODO: Generic hit PVP } } else { defense = (int)(((this.GetEquipedDefense() / 4 /*+ GetParam(DST_ADJDEF, 0)*/) + (this.Level + (this.Attributes[DefineAttributes.STA] / 2) + this.Attributes[DefineAttributes.DEX]) / 2.8f) - 4 + this.Level * 2); } if (defense < 0) { defense = 0; } return(defense); }
public static AttackFlags GetAttackFlags() { AttackFlags attackFlags = 0; // determine if its a critical hit, knockback, miss hit, etc... return(attackFlags); }
public bool HasFlag(AttackFlags flag) { // Checks if it has the flag if ((flags & flag) == flag) { return(true); } return(false); }
public override int GetDefense(Mover attacker, AttackFlags flags) { float armor = this.Data.NaturalArmor; if (flags.HasFlag(AttackFlags.AF_MAGIC)) { armor = this.Data.ResistMagic; } return((int)(armor / 7f + 1f)); }
void IUpdateable.Update(TimeSpan elapsedInFrame) { if (!initialized) { Initialize(); } //if(Actor.IsOnGround.Active) //{ // if(JumpForward != null) // JumpForwardMotion.Active = false; //} if (IsAttacking.JustStarted()) { Actor.Face(Actor.Scene.Player); } if (IsAttacking && AttackFlags.HasFlag(AttackFlags.StopWhileAttacking)) { Actor.Motion.Stop(Axis.X); } if (AttackFlags.HasFlag(AttackFlags.ThrowFireball)) { if (IsAttacking.JustEnded()) { var bullet = new EnemyBullet(); bullet.Direction = Actor.Direction; bullet.PositionRelativeTo(Actor, 0, 0); bullet.MoveInDirection(bullet.Direction, new ConfigValue <int>("enemy bullet speed").Value); } } if (TileChecker.IsOnLedge) { ReactToObstacle(TileChecker.CurrentLedge, Reactions.WalkingOffLedge); } if (TileChecker.IsAtWall) { if (TileChecker.CurrentWall.ActorCouldJumpOver(Actor)) { ReactToObstacle(TileChecker.CurrentWall, Reactions.WalkingIntoShortWall); } else { ReactToObstacle(TileChecker.CurrentWall, Reactions.WalkingIntoWall); } } }
private static int GetDefense(Mover attacker, Mover defender, AttackFlags flags) { if (flags.HasFlag(AttackFlags.AF_MAGICSKILL)) { // return Magic resist return 0; } if ((attacker is Player && defender is Player) || flags.HasFlag(AttackFlags.AF_GENERIC)) { } return defender.GetDefense(attacker, flags); }
/// <inheritdoc /> public void SendAddDamage(ILivingEntity defender, ILivingEntity attacker, AttackFlags attackFlags, int damage) { using var packet = new FFPacket(); packet.StartNewMergedPacket(defender.Id, SnapshotType.DAMAGE); packet.Write(attacker.Id); packet.Write(damage); packet.Write((int)attackFlags); if (attackFlags.HasFlag(AttackFlags.AF_FLYING)) { packet.Write(defender.Moves.DestinationPosition.X); packet.Write(defender.Moves.DestinationPosition.Y); packet.Write(defender.Moves.DestinationPosition.Z); packet.Write(defender.Object.Angle); } SendToVisible(packet, defender, sendToPlayer: true); }
internal void SendDamagesTo(Mover defender, int damages, AttackFlags flags, Vector3 position = null, float angle = 0f) { using (var packet = new FFPacket()) { packet.StartNewMergedPacket(defender.ObjectId, SnapshotType.DAMAGE); packet.Write(this.ObjectId); packet.Write(damages); packet.Write((int)flags); if (flags.HasFlag(AttackFlags.AF_FLYING)) { packet.Write(position.X); packet.Write(position.Y); packet.Write(position.Z); packet.Write(angle * 10f); } this.SendToVisible(packet); } }
/// <summary> /// Check if the attacker's melee attack is a critical hit. /// </summary> /// <param name="attacker">Attacker</param> /// <param name="currentAttackFlags">Attack flags</param> /// <returns></returns> public bool IsCriticalAttack(ILivingEntity attacker, AttackFlags currentAttackFlags) { if (currentAttackFlags.HasFlag(AttackFlags.AF_MELEESKILL) || currentAttackFlags.HasFlag(AttackFlags.AF_MAGICSKILL)) { return(false); } var criticalJobFactor = attacker is IPlayerEntity player ? player.PlayerData.JobData.Critical : 1f; var criticalProbability = (int)(attacker.Attributes[DefineAttributes.DEX] / 10 * criticalJobFactor); // TODO: add DST_CHR_CHANCECRITICAL to criticalProbability if (criticalProbability < 0) { criticalProbability = 0; } // TODO: check if player is in party and if it has the MVRF_CRITICAL flag return(RandomHelper.Random(0, 100) < criticalProbability); }
/// <summary> /// Calculates the player's defense. /// </summary> /// <param name="defenderPlayer">Current defender player.</param> /// <param name="flags">Attack flags.</param> /// <returns>Player's defense.</returns> private int GetPlayerDefense(IPlayerEntity defenderPlayer, AttackFlags flags) { var defense = 0; if (Attacker.Type == WorldEntityType.Player) { if (flags.HasFlag(AttackFlags.AF_MAGIC)) { defense = (int)(defenderPlayer.Attributes[DefineAttributes.INT] * 9.04f + defenderPlayer.Object.Level * 35.98f); } else { // TODO: GetDefenseByItem() } } else { // TODO: GetDefenseByItem() } return(Math.Max(0, defense)); }
public static AttackFlags GetAttackFlags(Mover attacker, Mover defender) { AttackFlags flags = 0; if (IsMissedHit(attacker, defender)) return AttackFlags.AF_MISS; else flags |= AttackFlags.AF_GENERIC; if (IsCriticalHit(attacker, defender)) { flags |= AttackFlags.AF_CRITICAL; float chance = RandomHelper.Random(0, 100); if (chance < 30) flags |= AttackFlags.AF_FLYING; } if (IsBlockingHit(attacker, defender)) flags |= AttackFlags.AF_BLOCKING; return flags; }
// melee attacks and throwing only public bool BeginAttack( AttackType attacktype, AttackFlags flags, bool playerInitiated ) { if ( attacktype == AttackType.Invalid ) return false; bool flashyFollowup = ( (flags&AttackFlags.FlashyFollowup) != AttackFlags.None ); bool disregardDelay = ( (flags&AttackFlags.DisregardDelay) != AttackFlags.None ); bool feint = false; bool flashy = false; Mobile attacker = AttachedTo as Mobile; IKhaerosMobile km = attacker as IKhaerosMobile; BaseWeapon weapon = attacker.Weapon as BaseWeapon; BaseShield shield = attacker.FindItemOnLayer( Layer.TwoHanded ) as BaseShield; if( attacker is PlayerMobile ) { PlayerMobile m = attacker as PlayerMobile; if( !m.EnableOffHand ) m.OffHandWeapon = null; else { m.EnableOffHand = false; if( !Commands.OffHandThrow.EnableOffHand( m ) ) return false; } } m_OffHand = ( attacker is PlayerMobile && ( (PlayerMobile)attacker ).OffHandThrowing ) && attacktype == AttackType.Throw; if ( !CanBeginCombatAction( ) || !CanBeginAttack( flags ) ) return false; if ( attacktype == AttackType.Throw ) { if( m_OffHand ) weapon = ((PlayerMobile)attacker).OffHandWeapon; if ( !CanThrow() ) return false; if ( weapon is AzhuranBoomerang ) // requires still time { if ( !((BaseRanged)weapon).IsStill( attacker ) ) { if ( playerInitiated ) { m_ErrorMessage = ""; DisplayQueueResultMessage( QueueRanged() ); } return false; } } } else if ( !CanBeginMeleeAttack() ) return false; else if ( attacktype == AttackType.ShieldBash && shield == null ) { m_ErrorMessage = "A shield is needed in order to perform a shield bash!"; return false; } if ( attacker.Mounted ) { if ( attacktype == AttackType.Swing || attacktype == AttackType.Circular ) { m_ErrorMessage = "Cannot perform swing attacks while mounted."; return false; } else if ( attacktype == AttackType.Thrust && !(CanThrustOnMount()) ) return false; else if ( attacktype == AttackType.ShieldBash ) { m_ErrorMessage = "This attack cannot be performed while mounted."; return false; } } StopAllActions( false ); if ( attacktype == AttackType.Circular ) // it is important that all of these are part of the same if/elseif chain { // as some feats are actually additional attacks, but that does not mean they can be used together with maneuvers. PlayerMobile pm = attacker as PlayerMobile; if ( km.Feats.GetFeatLevel(FeatList.CircularAttack) <= 0 ) { m_ErrorMessage = "You do not have the required feat."; return false; } else if ( pm == null || weapon.Layer != Layer.TwoHanded || weapon is BaseRanged ) { m_ErrorMessage = "You can only perform this attack with two-handed melee weapons."; return false; } else if ( weapon.NameType != pm.WeaponSpecialization && weapon.NameType != pm.SecondSpecialization ) { m_ErrorMessage = "You can only perform this attack with a weapon you have specialized in."; return false; } else if ( !BaseWeapon.CheckStam( attacker, km.Feats.GetFeatLevel(FeatList.CircularAttack), false, false ) ) { m_ErrorMessage = ""; // will be displayed by the checkstam thingy return false; } } else if ( attacktype == AttackType.ShieldBash ) { if ( km.Feats.GetFeatLevel(FeatList.ShieldBash) <= 0 ) { m_ErrorMessage = "You do not have the required feat."; return false; } else if ( !BaseWeapon.CheckStam( attacker, km.Feats.GetFeatLevel(FeatList.ShieldBash), false, false ) ) { m_ErrorMessage = ""; // will be displayed by the checkstam thingy return false; } km.CombatManeuver = new ShieldBash( km.Feats.GetFeatLevel(FeatList.ShieldBash) ); km.OffensiveFeat = FeatList.ShieldBash; } else if ( km.OffensiveFeat == FeatList.Feint ) { if ( BaseWeapon.CheckStam( attacker, km.Feats.GetFeatLevel(FeatList.Feint), false, false ) ) feint = true; weapon.EndManeuver( attacker ); } else if ( km.OffensiveFeat == FeatList.FlashyAttack ) { if ( BaseWeapon.CheckStam( attacker, km.Feats.GetFeatLevel(FeatList.FlashyAttack), false, false ) ) flashy = true; weapon.EndManeuver( attacker ); } // standard delay is 1 second double delay = ComputeAnimationDelay(); if ( attacktype == AttackType.ShieldBash ) delay = 4.0 - (3.0*((attacker.Skills[SkillName.Parry].Base)/100.0)); if ( feint ) delay *= 2.5-(((double)km.Feats.GetFeatLevel(FeatList.Feint))*0.5); // lvl 1 -> 2x slower, lvl 2 -> 1.5x slower, lvl 3 -> same as normal if ( attacktype == AttackType.Throw ) { if ( !(weapon is AzhuranBoomerang) ) // otherwise the duration is already calculated delay = 0.5; } int animspeed = (int)(delay*2); IKhaerosMobile kmob = attacker as IKhaerosMobile; AttackTimer newTimer = null; if ( attacktype != AttackType.Circular ) { newTimer = new AttackTimer( attacker, attacktype, TimeSpan.FromSeconds( delay ) ); newTimer.Flashy = flashy; newTimer.Feint = feint; newTimer.FlashyFollowup = flashyFollowup; } if ( attacktype == AttackType.Throw ) // throws cannot have a rotationtimer anyway { SpellHelper.Turn( attacker, m_Opponent ); m_AttackTimer = newTimer; } if ( attacktype != AttackType.Circular ) // not if we're spinning { m_AttackTimer = newTimer; if ( m_Opponent != null ) { // checking of AoO is necessary so we don't force Turn, which causes jerky movement m_NextAttackAction = DateTime.Now + ComputeNextSwingTime() + TimeSpan.FromSeconds( delay ); if ( !CheckForFreeAttack( m_Opponent, true ) ) // attack of opportunity { m_AttackTimer = null; SpellHelper.Turn( attacker, m_Opponent ); m_AttackTimer = newTimer; } else // we DID get an AoO, so we're done here { if ( BandageContext.GetContext( attacker ) != null ) { BandageContext.GetContext( attacker ).StopHeal(); if ( attacker is IKhaerosMobile ) { if ( ((IKhaerosMobile)attacker).HealingTimer != null ) { ((IKhaerosMobile)attacker).HealingTimer.Stop(); ((IKhaerosMobile)attacker).HealingTimer = null; } } } return true; } } } int zMod = 0; if ( attacker is BaseCreature ) zMod = ((BaseCreature)attacker).Height; if ( !feint ) { if ( attacktype == AttackType.ShieldBash ) m_NextAttackAction = DateTime.Now + TimeSpan.FromSeconds( 1.0 ); else m_NextAttackAction = DateTime.Now + ComputeNextSwingTime() + TimeSpan.FromSeconds( delay ); } switch ( (int)attacktype ) { case (int)AttackType.ShieldBash: { if ( attacker.Body.Type == BodyType.Human ) Animate( 30, 7, 1, true, false, animspeed ); else { int[] anim = BAData.GetAnimation( attacker, AttackType.ShieldBash ); if ( anim != null ) Animate( anim[0], anim[1], 1, true, false, animspeed ); } break; } case (int)AttackType.Throw: { if ( attacker.Body.Type == BodyType.Human ) { if ( !attacker.Mounted ) { if( weapon.Layer == Layer.OneHanded || m_OffHand ) Animate( 11, 7, 1, true, false, animspeed ); else Animate( 12, 7, 1, true, false, animspeed ); } else { if( weapon.Layer == Layer.OneHanded || m_OffHand ) Animate( 26, 8, 1, true, false, animspeed ); else Animate( 29, 7, 1, true, false, animspeed ); } } else { int[] anim = BAData.GetAnimation( attacker, AttackType.Throw ); if ( anim == null ) anim = BAData.GetAnimation( attacker, AttackType.Thrust ); if ( anim == null ) anim = BAData.GetAnimation( attacker, AttackType.Overhead ); if ( anim == null ) anim = BAData.GetAnimation( attacker, AttackType.Swing ); if ( anim != null ) Animate( anim[0], anim[1], 1, true, false, animspeed ); } break; } case (int)AttackType.Circular: goto case (int)AttackType.Swing; case (int)AttackType.Swing: { IEntity from = new Entity( Server.Serial.Zero, new Point3D( attacker.X, attacker.Y, attacker.Z + zMod ), attacker.Map ); IEntity to = new Entity( Server.Serial.Zero, new Point3D( attacker.X, attacker.Y, attacker.Z + 25 + zMod*2 ), attacker.Map ); SendCombatAlerts( from, to, 9556, 3, 0, true, false, 3, 2, 9501, 1, 0, EffectLayer.Head, 0x100 ); if ( attacker.Body.Type == BodyType.Human ) { if ( weapon is Fists ) { if ( kmob.Stance is VenomousWay ) Animate( 9, 7, 1, true, false, animspeed ); // karate chop else Animate( 31, 7, 1, true, false, animspeed ); // regular wrestling } else { if ( weapon.Layer == Layer.TwoHanded ) Animate( 13, 7, 1, true, false, animspeed ); else Animate( 9, 7, 1, true, false, animspeed ); } } else { int[] anim = BAData.GetAnimation( attacker, AttackType.Swing ); if ( anim == null ) anim = BAData.GetAnimation( attacker, AttackType.Thrust ); if ( anim == null ) anim = BAData.GetAnimation( attacker, AttackType.Overhead ); if ( anim != null ) Animate( anim[0], anim[1], 1, true, false, animspeed ); } break; } case (int)AttackType.Thrust: { IEntity from = new Entity( Server.Serial.Zero, new Point3D( attacker.X, attacker.Y, attacker.Z + zMod ), attacker.Map ); IEntity to = new Entity( Server.Serial.Zero, new Point3D( attacker.X, attacker.Y, attacker.Z + 25 + zMod*2 ), attacker.Map ); SendCombatAlerts( from, to, 9556, 3, 0, true, false, 62, 2, 9501, 1, 0, EffectLayer.Head, 0x100 ); if ( attacker.Body.Type == BodyType.Human ) { if ( attacker.Mounted ) Animate( 28, 7, 1, false, false, animspeed ); else { if ( weapon.Layer == Layer.TwoHanded ) Animate( 14, 7, 1, true, false, animspeed ); else { if ( weapon is Fists && kmob.Stance is SearingBreath ) Animate( 32, 5, 1, false, false, animspeed+2 ); // headbutt! Nah. People could abuse bow to do this. else if ( weapon is Fists && kmob.Stance is TempestuousSea ) // this is fine, though, heartstopper punch! Animate( 16, 7, 1, true, false, animspeed ); else Animate( 10, 7, 1, true, false, animspeed ); } } } else { int[] anim = BAData.GetAnimation( attacker, AttackType.Thrust ); if ( anim == null ) anim = BAData.GetAnimation( attacker, AttackType.Overhead ); if ( anim == null ) anim = BAData.GetAnimation( attacker, AttackType.Swing ); if ( anim != null ) Animate( anim[0], anim[1], 1, true, false, animspeed ); } break; } case (int)AttackType.Overhead: { IEntity from = new Entity( Server.Serial.Zero, new Point3D( attacker.X, attacker.Y, attacker.Z + zMod ), attacker.Map ); IEntity to = new Entity( Server.Serial.Zero, new Point3D( attacker.X, attacker.Y, attacker.Z + 25 + zMod*2 ), attacker.Map ); SendCombatAlerts( from, to, 9556, 3, 0, true, false, 37, 2, 9501, 1, 0, EffectLayer.Head, 0x100 ); if ( attacker.Body.Type == BodyType.Human ) { if ( attacker.Mounted ) { if ( weapon.Layer == Layer.TwoHanded ) Animate( 29, 7, 1, true, false, animspeed ); else Animate( 26, 7, 1, true, false, animspeed ); } else { if ( weapon.Layer == Layer.TwoHanded ) Animate( 12, 7, 1, true, false, animspeed ); else Animate( 11, 7, 1, true, false, animspeed ); } } else { int[] anim = BAData.GetAnimation( attacker, AttackType.Overhead ); if ( anim == null ) anim = BAData.GetAnimation( attacker, AttackType.Thrust ); if ( anim == null ) anim = BAData.GetAnimation( attacker, AttackType.Swing ); if ( anim != null ) Animate( anim[0], anim[1], 1, true, false, animspeed ); } break; } } if (attacktype == AttackType.Circular) { m_RotationTimer = new RotationTimer(attacker, TimeSpan.FromSeconds(delay)); m_RotationTimer.Start(); } else { if (m_AttackTimer == null) { attacker.SendMessage("There was an error in the CombatSystemAttachment @ line 2226."); return false; } else m_AttackTimer.Start(); } // this delays as if we were parried, but if we actually won't be, then the delay will shorten // what if we get interrupted, though? it should count as a hit on our part, no extra delay. if ( BandageContext.GetContext( attacker ) != null ) { BandageContext.GetContext( attacker ).StopHeal(); if ( attacker is IKhaerosMobile ) { if ( ((IKhaerosMobile)attacker).HealingTimer != null ) { ((IKhaerosMobile)attacker).HealingTimer.Stop(); ((IKhaerosMobile)attacker).HealingTimer = null; } } } if ( m_Opponent != null ) { GetCSA( m_Opponent ).UpdateACBrainExternal(); } return true; }
public static void SendMeleeAttack(ILivingEntity attacker, ObjectMessageType motion, uint targetId, int unknwonParam, AttackFlags attackFlags) { using (var packet = new FFPacket()) { packet.StartNewMergedPacket(attacker.Id, SnapshotType.MELEE_ATTACK); packet.Write((int)motion); packet.Write(targetId); packet.Write(unknwonParam); packet.Write((int)attackFlags); SendToVisible(packet, attacker); } }
public bool CanBeginAttack( AttackFlags flags ) { Mobile attacker = AttachedTo as Mobile; BaseWeapon weapon = attacker.Weapon as BaseWeapon; bool sbash = ( ((IKhaerosMobile)attacker).OffensiveFeat == FeatList.ShieldBash ); bool disregardDelay = ((flags&AttackFlags.DisregardDelay) != AttackFlags.None); if ( m_PerformingSequence ) { m_ErrorMessage = "You cannot do that right now."; return false; } else if ( ( m_AttackTimer != null && !m_AttackTimer.Feint ) || m_RotationTimer != null ) { m_ErrorMessage = "You are too busy attacking."; return false; } else if ( weapon.CannotUseOnFoot && !attacker.Mounted && !sbash ) { m_ErrorMessage = "That weapon cannot be used on foot."; return false; } else if ( weapon.ChargeOnly && !sbash ) { m_ErrorMessage = "That weapon can only be charged with."; return false; } else if ( attacker.Mounted && sbash ) { m_ErrorMessage = "That attack cannot be used while mounted."; return false; } else if( weapon.CannotUseOnMount && attacker.Mounted ) { m_ErrorMessage = "That weapon cannot be used while mounted."; return false; } else if ( !disregardDelay && m_NextAttackAction > DateTime.Now ) { m_ErrorMessage = "You must wait before performing another offensive action."; return false; } return true; }
public virtual int GetDefense(Mover attacker, AttackFlags flags) { return(0); }
public bool BeginAttack( AttackType attacktype, AttackFlags flags ) { return BeginAttack( attacktype, flags, false ); }
public static void Process(Mover attacker, Mover defender) { AttackFlags flags = GetAttackFlags(attacker, defender); int damages = CalculateMeleeDamages(attacker, defender); if (flags.HasFlag(AttackFlags.AF_BLOCKING)) { float blockFactor = GetBlockFactor(attacker, defender); if (blockFactor < 1f) damages = (int)(damages * blockFactor); Log.Debug("=> {0} blocking {1}", defender.Name, attacker.Name); } if (flags.HasFlag(AttackFlags.AF_CRITICAL)) { damages *= 2; // TODO: GetCriticalHitFactor Log.Debug("=> {0} inflicts a critical hit to {1}", attacker.Name, defender.Name); } damages -= GetDefense(attacker, defender, flags); if (flags == AttackFlags.AF_MISS) { Log.Debug("{0} misses {1}", attacker.Name, defender.Name); damages = 0; } if (damages < 0) damages = 0; Log.Debug("{0} inflicted {1} damages to {2}", attacker.Name, damages, defender.Name); // Send damages if (flags.HasFlag(AttackFlags.AF_FLYING)) // KnockBack SendDamagesFly(attacker, defender, damages, flags); else attacker.SendDamagesTo(defender, damages, flags); defender.Attributes[DefineAttributes.HP] -= damages; if (defender.Attributes[DefineAttributes.HP] <= 0) defender.Die(); if (defender.IsDead) { if (defender is Monster && attacker is Player) { var monster = defender as Monster; var player = attacker as Player; int experience = player.CalculateExperience(monster.Data.ExpValue); // TODO: give experience for party if (player.GiveExperience(experience)) { player.SendSetLevel(); player.SendStatPoints(); } player.SendExperience(); } if (defender is Player && attacker is Monster) { } } }
private static void SendDamagesFly(Mover attacker, Mover defender, int damages, AttackFlags flags) { var delta = new Vector3(); float angle = MathHelper.ToRadian(defender.Angle); float angleY = MathHelper.ToRadian(145f); delta.Y = (float)(-Math.Cos(angleY) * 0.18f); float dist = (float)(Math.Sin(angleY) * 0.18f); delta.X = (float)(Math.Sin(angle) * dist); delta.Z = (float)(-Math.Cos(angle) * dist); defender.DestinationPosition.X += delta.X; defender.DestinationPosition.Z += delta.Z; attacker.SendDamagesTo(defender, damages, flags, defender.Position, angle); }
void AddBehaviorsBasedOnFlags() { var player = Actor.Scene.Player; Actor.RecoilsWhenHit = Flags.HasFlag(EnemyBehaviorFlags.HasGravity); //if(AttackFlags.HasFlag(AttackFlags.AttackWhenClose)) //{ // beginAttackCondition = beginAttackCondition.Or(Actor.IsCloseTo(player, 64)); //todo - config //} if (AttackFlags.HasFlag(AttackFlags.AttackPeriodically)) { isStartingAttack = new Timer(Actor).OnceEvery(QuickGameConfig.NormalAttackFrequency).And(Actor.IsOnGround); } IsAttacking = isStartingAttack.ContinueWhile(Actor.Animations.IsAnimationPlaying(AnimationKeys.Attack)); ////todo - config //if (AttackFlags.HasFlag(AttackFlags.ThrowFireball)) // throwFireballCondition = beginAttackCondition.And( // WaitUntil(new PlayingAnimationCondition(Actor.Animations, AnimationKeys.Attack).Negate()); //if (Flags.HasFlag(EnemyBehaviorFlags.Shoots)) //{ // beginAttackCondition = new OnceEvery(new Timer(TimeSpan.FromSeconds(5), Actor), Condition.True); // attackDurationCondition = beginAttackCondition.ContinueWhileAnimationPlaying(Actor.Animations, AnimationKeys.Attack); //} // new AnimationController<TEnemy>(Actor, attackDurationCondition, null); //if (Flags.HasFlag(EnemyBehaviorFlags.FollowsPlayer)) //{ // Actor.Face(player); // Actor.AlwaysFace(player, new OnceEvery(new Timer(TimeSpan.FromSeconds(2), Actor))); //} //else //{ // Actor.Direction = Direction.Left; //} if (Flags.HasFlag(EnemyBehaviorFlags.MovesFast)) { Actor.Motion.AddAdjuster(new GroundMotion <TEnemy>(Actor, Config.ReadValue <AxisMotionConfig>("fast motion"))); } else if (Flags.HasFlag(EnemyBehaviorFlags.MovesMore)) { Actor.Motion.AddAdjuster(new GroundMotion <TEnemy>(Actor, Config.ReadValue <AxisMotionConfig>("medium motion"))); } else if (Flags.HasFlag(EnemyBehaviorFlags.Moves)) { Actor.Motion.AddAdjuster(new GroundMotion <TEnemy>(Actor, Config.ReadValue <AxisMotionConfig>("slow motion"))); } if (Flags.HasFlag(EnemyBehaviorFlags.HasGravity)) { Actor.AddGravity(); } // //todo - make work better with FacePlayer // //if(!Flags.HasFlag(EnemyBehaviorFlags.FallsOfLedges)) // //{ // // new LambdaAction<Actor>(Actor, UpdatePriority.Behavior, Actor.Scene, TileChecker.IsAtWall.Or(TileChecker.IsOnLedge), // // (a, t) => // // { // // //if (a.Position.GetEdgeDistanceTo(TileChecker.NextWallTile.Position, Axis.X) <= 1) // // a.Direction = a.DirectionAwayFrom(TileChecker.NextWallTile, Axis.X); // // }); // //} // if(Flags.HasFlag(EnemyBehaviorFlags.CanJump)) // { // throw new NotImplementedException(); // //var jumpMotion = new AxisMotion("enemy jump", Actor).Set(deactivateAfterStart: true); // //JumpForwardMotion = new AxisMotion("enemy jump X", Actor).Set(flipWhen: Direction.Left, deactivateWhenTargetReached:false); // //Actor.Motion.Forces.Add(jumpMotion); // //new LambdaAction<Actor>(Actor, UpdatePriority.Behavior, Actor.Scene, TileChecker.IsAtWall.Or(TileChecker.IsOnLedge), // // (a, t) => // // { // // if (TileChecker.IsAtWall.IsActive || // // Flags.HasFlag(EnemyBehaviorFlags.FallsOfLedges) && TileChecker.IsOnDangerousLedge.IsActive) // // { // // jumpMotion.Active = true; // // JumpForwardMotion.Active = true; // // } // // }); // } //} }
/// <summary> /// Calculates the given monster defense. /// </summary> /// <param name="defenderMonster">Monster entity defending an attack.</param> /// <param name="attackFlags">Attack flags.</param> /// <returns>Monster's defense.</returns> private int GetMonsterDefense(IMonsterEntity defenderMonster, AttackFlags attackFlags) { var monsterDefenseArmor = attackFlags.HasFlag(AttackFlags.AF_MAGIC) ? defenderMonster.Data.MagicResitance : defenderMonster.Data.NaturalArmor; return((int)(monsterDefenseArmor / 7f + 1)); }