public CalculCriticalHitRate ( int &cHitRate ) : void | ||
cHitRate | int | |
return | void |
/// <summary> /// /// </summary> /// <param name="fighter"></param> /// <param name="cellId"></param> public void TryUseWeapon(AbstractFighter fighter, int cellId, int actionTime = 5000) { AddMessage(() => { if (LoopState == FightLoopStateEnum.STATE_WAIT_END || LoopState == FightLoopStateEnum.STATE_ENDED) { fighter.Dispatch(WorldMessage.BASIC_NO_OPERATION()); return; } if(State != FightStateEnum.STATE_FIGHTING) { Logger.Debug("Fight::TryUseWeapon fight is not in fighting state : " + fighter.Name); fighter.Dispatch(WorldMessage.BASIC_NO_OPERATION()); return; } if (m_currentApCost != -1) { Logger.Debug("Fight::TryUseWeapon fight already processing spell launch and not finished : " + fighter.Name); fighter.Dispatch(WorldMessage.BASIC_NO_OPERATION()); return; } var weapon = fighter.Inventory.Items.Find(item => item.Slot == ItemSlotEnum.SLOT_WEAPON); if(weapon == null) { TryLaunchSpell(fighter, 0, cellId); return; } if(!CanUseWeapon(fighter, weapon, cellId)) { Logger.Debug("Fight::TryUseWeapon unable to use weapon : " + fighter.Name); fighter.Dispatch(WorldMessage.BASIC_NO_OPERATION()); return; } var weaponTemplate = weapon.Template; CurrentFighter.Team.CheckWeapon(fighter, weaponTemplate); var isMelee = Pathfinding.GoalDistance(Map, fighter.Cell.Id, cellId) == 1; fighter.UsedAP += weaponTemplate.APCost; Dispatch(WorldMessage.FIGHT_ACTION_START(CurrentFighter.Id)); var failure = false; if (weaponTemplate.CFRate != 0) { var criticalFailureRate = weaponTemplate.CFRate - fighter.Statistics.GetTotal(EffectEnum.AddEchecCritic); if (criticalFailureRate < 2) criticalFailureRate = 2; if (Util.Next(0, criticalFailureRate) == 0) failure = true; } if(failure) { CachedBuffer = true; Dispatch(WorldMessage.GAME_ACTION(GameActionTypeEnum.FIGHT_WEAPON_FAILURE, fighter.Id, weaponTemplate.Id.ToString())); Dispatch(WorldMessage.GAME_ACTION(GameActionTypeEnum.FIGHT_PA_LOST, fighter.Id, fighter.Id + ",-" + weaponTemplate.APCost)); Dispatch(WorldMessage.FIGHT_ACTION_FINISHED(CurrentFighter.Id)); CachedBuffer = false; CurrentFighter.TurnPass = true; return; } var criticalHit = false; if (weaponTemplate.CSRate != 0) { var criticalHitRate = weaponTemplate.CSRate - fighter.Statistics.GetTotal(EffectEnum.AddDamageCritic); fighter.CalculCriticalHitRate(ref criticalHitRate); if (criticalHitRate < 2) criticalHitRate = 2; if (Util.Next(0, criticalHitRate) == 0) criticalHit = true; } if(criticalHit) Dispatch(WorldMessage.GAME_ACTION(GameActionTypeEnum.FIGHT_CRITICAL_HIT, fighter.Id, "0")); var effects = weapon.Statistics.WeaponEffects; var targetLists = new List<Tuple<GenericEffect, List<AbstractFighter>>>(); foreach (var effect in effects) { var targetList = new List<AbstractFighter>(); foreach (var currentCellId in CellZone.GetCells(Map, cellId, fighter.Cell.Id, weaponTemplate.RangeType)) { var fightCell = GetCell(currentCellId); if (fightCell != null) { foreach(var fighterObject in fightCell.FightObjects.OfType<AbstractFighter>()) { if (fighter == fighterObject) continue; targetList.Add(fighterObject); } } } targetLists.Add(Tuple.Create(effect.Value, targetList)); } LoopState = FightLoopStateEnum.STATE_WAIT_ACTION; fighter.UseWeapon(cellId, actionTime, () => { if (LoopState == FightLoopStateEnum.STATE_WAIT_END || LoopState == FightLoopStateEnum.STATE_ENDED) { fighter.Dispatch(WorldMessage.BASIC_NO_OPERATION()); return; } foreach (var targetsByEffect in targetLists) { targetsByEffect.Item2.RemoveAll(affectedTarget => affectedTarget.IsFighterDead); if (targetsByEffect.Item2.Count == 0) { AddProcessingTarget( new CastInfos( targetsByEffect.Item1.EffectType, -1, cellId, criticalHit && CastInfos.IsDamageEffect(targetsByEffect.Item1.EffectType) ? targetsByEffect.Item1.Value1 + weaponTemplate.CSBonus : targetsByEffect.Item1.Value1, criticalHit && CastInfos.IsDamageEffect(targetsByEffect.Item1.EffectType) ? targetsByEffect.Item1.Value2 + weaponTemplate.CSBonus : targetsByEffect.Item1.Value2, -1, -1, 0, fighter, null, weaponTemplate.RangeType, 0, -1, isMelee) ); } else { foreach (var target in targetsByEffect.Item2) { AddProcessingTarget(new CastInfos( targetsByEffect.Item1.EffectType, -1, cellId, criticalHit && CastInfos.IsDamageEffect(targetsByEffect.Item1.EffectType) ? targetsByEffect.Item1.Value1 + weaponTemplate.CSBonus : targetsByEffect.Item1.Value1, criticalHit && CastInfos.IsDamageEffect(targetsByEffect.Item1.EffectType) ? targetsByEffect.Item1.Value2 + weaponTemplate.CSBonus : targetsByEffect.Item1.Value2, -1, -1, 0, fighter, target, weaponTemplate.RangeType, target.Cell.Id, -1, isMelee)); } } } m_currentApCost = weaponTemplate.APCost; }); }); }
/// <summary> /// /// </summary> /// <param name="fighter"></param> /// <param name="spellId"></param> /// <param name="castCellId"></param> public void TryLaunchSpell(AbstractFighter fighter, int spellId, int castCellId, int actionTime = 5000) { AddMessage(() => { if (LoopState == FightLoopStateEnum.STATE_WAIT_END || LoopState == FightLoopStateEnum.STATE_ENDED) { fighter.Dispatch(WorldMessage.BASIC_NO_OPERATION()); return; } if (State != FightStateEnum.STATE_FIGHTING) { Logger.Debug("Fight::TryLaunchSpell fight is not in fighting state : " + fighter.Name); fighter.Dispatch(WorldMessage.BASIC_NO_OPERATION()); return; } if (m_currentApCost != -1) { Logger.Debug("Fight::TryLaunchSpell fight already processing spell launch and not finished : " + fighter.Name); fighter.Dispatch(WorldMessage.BASIC_NO_OPERATION()); return; } if (fighter.SpellBook == null) { Logger.Debug("Fight::TryLaunchSpell empty spellbook : " + fighter.Name); fighter.Dispatch(WorldMessage.BASIC_NO_OPERATION()); return; } var spellLevel = fighter.SpellBook.GetSpellLevel(spellId); if (spellLevel == null) { Logger.Debug("Fight::TryLaunchSpell unnknow spellId : " + fighter.Name); fighter.Dispatch(WorldMessage.BASIC_NO_OPERATION()); return; } var launchResult = CanLaunchSpell(fighter, spellLevel, spellId, fighter.Cell.Id, castCellId); if (launchResult != FightSpellLaunchResultEnum.RESULT_OK) { Logger.Debug("Fight::TryLaunchSpell unable to launch spell : " + fighter.Name + " reason=" + launchResult); fighter.Dispatch(WorldMessage.BASIC_NO_OPERATION()); return; } var isMelee = Pathfinding.GoalDistance(Map, fighter.Cell.Id, castCellId) == 1; fighter.UsedAP += spellLevel.APCost; base.Dispatch(WorldMessage.FIGHT_ACTION_START(CurrentFighter.Id)); var isEchec = false; if (spellLevel.ECSRate != 0) { var echecRate = spellLevel.ECSRate - fighter.Statistics.GetTotal(EffectEnum.AddEchecCritic); if (echecRate < 2) echecRate = 2; if (Util.Next(0, echecRate) == 0) isEchec = true; if (isEchec) { CachedBuffer = true; Dispatch(WorldMessage.GAME_ACTION(GameActionTypeEnum.FIGHT_CRITICAL_FAILURE, fighter.Id, spellId.ToString())); Dispatch(WorldMessage.GAME_ACTION(GameActionTypeEnum.FIGHT_PA_LOST, fighter.Id, fighter.Id + ",-" + spellLevel.APCost)); Dispatch(WorldMessage.FIGHT_ACTION_FINISHED(CurrentFighter.Id)); CachedBuffer = false; if (spellLevel.IsECSEndTurn == 1) { CurrentFighter.TurnPass = true; } return; } } var target = GetFighterOnCell(castCellId); if (target != null) { fighter.SpellManager.Actualize(spellLevel, spellId, target.Id); } var isCritic = false; if (spellLevel.CSRate != 0 && spellLevel.CriticalEffects.Count > 0) { var criticalHitRate = spellLevel.CSRate - fighter.Statistics.GetTotal(EffectEnum.AddDamageCritic); fighter.CalculCriticalHitRate(ref criticalHitRate); if (criticalHitRate < 2) criticalHitRate = 2; if (Util.Next(0, criticalHitRate) == 0) isCritic = true; } if (isCritic) Dispatch(WorldMessage.GAME_ACTION(GameActionTypeEnum.FIGHT_CRITICAL_HIT, fighter.Id, spellId.ToString())); var effects = isCritic ? spellLevel.CriticalEffects : spellLevel.Effects; var targetLists = new Dictionary<SpellEffect, List<AbstractFighter>>(); var effectIndex = 0; foreach (var effect in effects) { targetLists.Add(effect, new List<AbstractFighter>()); var targetType = spellLevel.Template.Targets != null ? spellLevel.Template.Targets.Count > effectIndex ? spellLevel.Template.Targets[effectIndex] : -1 : -1; if (effect.TypeEnum != EffectEnum.UseGlyph && effect.TypeEnum != EffectEnum.UseTrap) { foreach (var currentCellId in CellZone.GetCells(Map, castCellId, fighter.Cell.Id, spellLevel.RangeType)) { var fightCell = GetCell(currentCellId); if (fightCell != null) { foreach (var fighterObject in fightCell.FightObjects.OfType<AbstractFighter>()) { if (targetType != -1) { // affect caster : 32 if (((((targetType >> 5) & 1) == 1) && (fighter.Id != fighterObject.Id))) { if (!targetLists[effect].Contains(fighter)) targetLists[effect].Add(fighter); continue; } // doesnt affect team mates : 1 if (((targetType & 1) == 1) && fighter.Team == fighterObject.Team) continue; // doesnt affect the caster : 2 if ((((targetType >> 1) & 1) == 1) && fighter.Id == fighterObject.Id) continue; // doesnt affect ennemies : 4 if ((((targetType >> 2) & 1) == 1) && fighter.Team != fighterObject.Team) continue; // only invocation : 8 if (((((targetType >> 3) & 1) == 1) && (fighterObject.Invocator == null))) continue; // doesnt affect invocs : 16 if (((((targetType >> 4) & 1) == 1) && (fighterObject.Invocator != null))) continue; } if (!targetLists[effect].Contains(fighterObject)) targetLists[effect].Add(fighterObject); } } } } effectIndex++; } LoopState = FightLoopStateEnum.STATE_WAIT_ACTION; var template = SpellManager.Instance.GetTemplate(spellId); fighter.LaunchSpell(castCellId, spellId, spellLevel.Level, template.Sprite.ToString(), template.SpriteInfos, actionTime, () => { if (LoopState == FightLoopStateEnum.STATE_WAIT_END || LoopState == FightLoopStateEnum.STATE_ENDED) { fighter.Dispatch(WorldMessage.BASIC_NO_OPERATION()); return; } var actualChance = 0; foreach (var effect in effects) { if (effect.Chance > 0) { if (Util.Next(0, 100) > (effect.Chance + actualChance)) { actualChance += effect.Chance; continue; } actualChance -= 100; } targetLists[effect].RemoveAll(affectedTarget => affectedTarget.IsFighterDead); if (targetLists[effect].Count == 0) { var castInfos = new CastInfos( effect.TypeEnum, spellId, castCellId, effect.Value1, effect.Value2, effect.Value3, effect.Chance, effect.Duration, fighter, null, spellLevel.RangeType, 0, spellLevel.Level, isMelee); AddProcessingTarget(castInfos); CurrentFighter.Team.CheckSpell(CurrentFighter, castInfos); } else { foreach (var effectTarget in targetLists[effect]) { var castInfos = new CastInfos( effect.TypeEnum, spellId, castCellId, effect.Value1, effect.Value2, effect.Value3, effect.Chance, effect.Duration, fighter, effectTarget, spellLevel.RangeType, effectTarget.Cell.Id, spellLevel.Level, isMelee); AddProcessingTarget(castInfos); CurrentFighter.Team.CheckSpell(CurrentFighter, castInfos); } } } m_currentApCost = spellLevel.APCost; }); }); }