/// <summary> /// Возвращает тип обороны, которая может быть использована для отражения указанного наступления. /// </summary> /// <param name="offenceType"> Тип наступления. </param> /// <returns> Возвращает экземпляр типа обороны. </returns> public static DefenceType GetDefence(OffenseType offenceType) { var rawValue = (int)offenceType; var defenceType = (DefenceType)rawValue; return(defenceType); }
public void UseOn_ArmorSavePassed_ActEfficientDecrease() { // ARRANGE const OffenseType offenceType = OffenseType.Tactical; const int fakeToHitDiceRoll = 2; // успех в ToHit 2+ const int fakeArmorSaveDiceRoll = 6; // успех в ArmorSave 4+ при раных рангах const int fakeActEfficientRoll = 3; // эффективность пробрасывается D3, максимальный бросок const int expectedActEfficient = fakeActEfficientRoll - 1; // -1 даёт текущая броня var actUsageRandomSourceMock = new Mock <ITacticalActUsageRandomSource>(); actUsageRandomSourceMock.Setup(x => x.RollToHit()).Returns(fakeToHitDiceRoll); actUsageRandomSourceMock.Setup(x => x.RollArmorSave()).Returns(fakeArmorSaveDiceRoll); actUsageRandomSourceMock.Setup(x => x.RollEfficient(It.IsAny <Roll>())).Returns(fakeActEfficientRoll); var actUsageRandomSource = actUsageRandomSourceMock.Object; var actUsageService = new TacticalActUsageService( actUsageRandomSource, _perkResolver, _sectorManager); var actorMock = new Mock <IActor>(); actorMock.SetupGet(x => x.Node).Returns(new HexNode(0, 0)); var actor = actorMock.Object; var armors = new[] { new PersonArmorItem(ImpactType.Kinetic, PersonRuleLevel.Lesser, 10) }; var monsterMock = CreateMonsterMock(armors: armors); var monster = monsterMock.Object; // Настройка дествия var actScheme = new TestTacticalActStatsSubScheme { Offence = new TestTacticalActOffenceSubScheme { Type = offenceType, ApRank = 10, Impact = ImpactType.Kinetic } }; var actMock = new Mock <ITacticalAct>(); actMock.SetupGet(x => x.Stats).Returns(actScheme); var act = actMock.Object; // ACT var usedActs = new UsedTacticalActs(new[] { act }); actUsageService.UseOn(actor, monster, usedActs); // ASSERT actUsageRandomSourceMock.Verify(x => x.RollArmorSave(), Times.Once); monsterMock.Verify(x => x.TakeDamage(It.Is <int>(damage => damage == expectedActEfficient)), Times.Once); }
public void UseOn_ArmorSavePassed_ActEfficientDecrease() { // ARRANGE const OffenseType OFFENCETYPE = OffenseType.Tactical; const int FAKE_TOHIT_DICE_ROLL = 2; // успех в ToHit 2+ const int FAKE_ARMORSAVE_DICE_ROLL = 6; // успех в ArmorSave 4+ при раных рангах const int FAKE_ACTEFFICIENT_ROLL = 3; // эффективность пробрасывается D3, максимальный бросок const int EXPECTED_ACTEFFICIENT = FAKE_ACTEFFICIENT_ROLL - 1; // -1 даёт текущая броня var actUsageRandomSourceMock = new Mock <ITacticalActUsageRandomSource>(); actUsageRandomSourceMock.Setup(x => x.RollToHit(It.IsAny <Roll>())).Returns(FAKE_TOHIT_DICE_ROLL); actUsageRandomSourceMock.Setup(x => x.RollArmorSave()).Returns(FAKE_ARMORSAVE_DICE_ROLL); actUsageRandomSourceMock.Setup(x => x.RollEfficient(It.IsAny <Roll>())).Returns(FAKE_ACTEFFICIENT_ROLL); var actUsageRandomSource = actUsageRandomSourceMock.Object; var perkResolverMock = new Mock <IPerkResolver>(); var perkResolver = perkResolverMock.Object; var actUsageService = new ActorActUsageHandler(perkResolver, actUsageRandomSource); var actorMock = new Mock <IActor>(); actorMock.SetupGet(x => x.Node).Returns(new HexNode(0, 0)); var actor = actorMock.Object; var armors = new[] { new PersonArmorItem(ImpactType.Kinetic, PersonRuleLevel.Lesser, 10) }; var monsterMock = CreateMonsterMock(armors: armors); var monster = monsterMock.Object; // Настройка дествия var actScheme = new TestTacticalActStatsSubScheme { Offence = new TestTacticalActOffenceSubScheme { Type = OFFENCETYPE, ApRank = 10, Impact = ImpactType.Kinetic } }; var actMock = new Mock <ICombatAct>(); actMock.SetupGet(x => x.Stats).Returns(actScheme); var act = actMock.Object; var map = Mock.Of <ISectorMap>(); // ACT var usedActs = new CombatActRoll(act, FAKE_ACTEFFICIENT_ROLL); actUsageService.ProcessActUsage(actor, monster, usedActs, map); // ASSERT actUsageRandomSourceMock.Verify(x => x.RollArmorSave(), Times.Once); monsterMock.Verify(x => x.TakeDamage(It.Is <int>(damage => damage == EXPECTED_ACTEFFICIENT)), Times.Once); }
/// <summary> /// Извлечение всех оборон актёра, способных противостоять указанному типу урона. /// Включая DivineDefence, противодействующий всем типам урона. /// </summary> /// <param name="targetActor"> Целевой актёр. </param> /// <param name="offenceType"> Тип урона. </param> /// <returns> Возвращает набор оборон. </returns> private static IEnumerable <PersonDefenceItem> GetCurrentDefences(IActor targetActor, OffenseType offenceType) { var defenceType = HitHelper.GetDefence(offenceType); return(targetActor.Person.CombatStats.DefenceStats.Defences .Where(x => x.Type == defenceType || x.Type == DefenceType.DivineDefence)); }
/**比赛中取有效技能 根据当前command*/ public SkillInstance GetValidSkillInMatch(Command curCommand, bool isAI = false, System.Predicate <SkillInstance> filter = null) { if (curCommand == Command.None) { return(null); } PlayerState curPlayerState = m_player.m_StateMachine.m_curState; if (curPlayerState != null && !curPlayerState.IsCommandValid(curCommand)) { return(null); } List <SkillInstance> skills = m_cachedSkillList; GameMatch curMatch = GameSystem.Instance.mClient.mCurMatch; PlayerState curState = m_player.m_StateMachine.m_curState; bool bIsSkillState = curState is PlayerState_Skill; List <SkillInstance> matchedSkills = new List <SkillInstance>(); List <SkillInstance> toMatchSkills = new List <SkillInstance>(); foreach (SkillInstance skillInstance in skills) { if (isAI && (Command)skillInstance.skill.action_type != curCommand) { continue; } if (!_MatchArea(curMatch, skillInstance)) { continue; } if (!_MatchActionCondition(skillInstance)) { continue; } if (!_MatchSkillSpecParam(skillInstance)) { continue; } //has power & has vigour if (!_MatchStamina(skillInstance)) { if (curMatch.mainRole == m_player) { curMatch.ShowTips((Vector3)m_player.position + Vector3.up, CommonFunction.GetConstString("MATCH_TIPS_NOT_ENOUGH_STAMINA"), GlobalConst.MATCH_TIP_COLOR_RED); if (isAI) { Debug.Log(string.Format("SkillSystem, no enough stamina for skill: {0} {1}", skillInstance.skill.id, skillInstance.skill.name)); } } continue; } if (isAI && filter != null && !filter(skillInstance)) { continue; } toMatchSkills.Add(skillInstance); //precise matching if (!isAI && !_MatchAction(curCommand, skillInstance, false)) { continue; } matchedSkills.Add(skillInstance); } if (!isAI && matchedSkills.Count == 0) { foreach (SkillInstance skillInstance in toMatchSkills) { //unprecise matching if (!_MatchAction(curCommand, skillInstance, true)) { continue; } matchedSkills.Add(skillInstance); } } //filter out shoot dunk layup and offense type if (!isAI && curCommand == Command.Shoot) { List <OffenseType> offenses = new List <OffenseType>(); foreach (SkillInstance skillInstance in matchedSkills) { if (skillInstance.skill.action_type == 1 && !offenses.Contains(OffenseType.eShot)) { offenses.Add(OffenseType.eShot); } else if (skillInstance.skill.action_type == 2 && !offenses.Contains(OffenseType.eLayup)) { offenses.Add(OffenseType.eLayup); } else if (skillInstance.skill.action_type == 3 && !offenses.Contains(OffenseType.eDunk)) { offenses.Add(OffenseType.eDunk); } } if (offenses.Count > 0) { OffenseType type = _CalcOffenseType(m_player, offenses); if (type != OffenseType.eNone) { //Debug.Log("OffenseType : " + type ); for (int i = matchedSkills.Count - 1; i >= 0; i--) { SkillInstance skillInstance = matchedSkills[i]; if (skillInstance.skill.action_type != (uint)type) { //Debug.Log("Remove action_type : " + skillInstance.skill.action_type + " Type value: " + (uint)skillInstance.skill.action_type); matchedSkills.Remove(skillInstance); } } } } } /* * if( matchedSkills.Count != 0 ) * { * Debug.Log("====matched skill==="); * foreach( SkillInstance instance in matchedSkills ) * Debug.Log("matched skill: " + instance.curAction.action_id); * Debug.Log("===================="); * } */ //choose highest weight. SkillInstance finalSkill = null; finalSkill = MatchSkillByWeight(matchedSkills); //if( finalSkill != null ) // Debug.Log("final skill: " + finalSkill.curAction.action_id); //choose a default skill if (finalSkill == null && !bIsSkillState && curCommand != Command.CutIn) //TODO: 临时针对空切特殊处理,以后修改 { foreach (SkillInstance skillInstance in m_basicMatchedSkills) { if ((Command)skillInstance.skill.action_type != curCommand) { continue; } if (!_MatchArea(curMatch, skillInstance)) { continue; } if (!_MatchActionCondition(skillInstance)) { continue; } //has power & has vigour if (!_MatchStamina(skillInstance)) { continue; } finalSkill = skillInstance; //Debug.Log("Get basic skill: "); break; } } return(finalSkill); }
OffenseType _CalcOffenseType(Player player, List <OffenseType> offenses) { GameMatch match = GameSystem.Instance.mClient.mCurMatch; UBasket basket = match.mCurScene.mBasket; if (basket == null) { return(OffenseType.eNone); } Dictionary <string, uint> data = player.m_finalAttrs; if (data == null) { Debug.LogError("Can not build player: " + player.m_name + " ,can not fight state by id: " + player.m_id); return(OffenseType.eNone); } PlayGround playGround = match.mCurScene.mGround; Debugger.Instance.m_steamer.message = "Attr of offense type: "; Dictionary <OffenseType, IM.Number> lstOffenseRates = new Dictionary <OffenseType, IM.Number>(); foreach (OffenseType type in offenses) { Area area = Area.eInvalid; IM.Number offenseRate = IM.Number.zero; if (type == OffenseType.eLayup) { area = playGround.GetLayupArea(player); } else if (type == OffenseType.eDunk) { area = playGround.GetDunkArea(player); } else if (type == OffenseType.eShot) { area = playGround.GetArea(player); } if (area == Area.eNear) { if (type == OffenseType.eLayup) { offenseRate = new IM.Number((int)data["layup_near"]); } else if (type == OffenseType.eDunk) { offenseRate = new IM.Number((int)data["dunk_near"]); } else if (type == OffenseType.eShot) { offenseRate = new IM.Number((int)data["shoot_near"]); } } else if (area == Area.eMiddle) { if (type == OffenseType.eShot) { offenseRate = new IM.Number((int)data["shoot_middle"]); } else if (type == OffenseType.eDunk) { offenseRate = new IM.Number((int)data["dunk_middle"]); } else if (type == OffenseType.eLayup) { offenseRate = new IM.Number((int)data["layup_middle"]); } } else if (area == Area.eFar) { if (type == OffenseType.eShot) { offenseRate = new IM.Number((int)data["shoot_far"]); } } lstOffenseRates.Add(type, offenseRate); Debugger.Instance.m_steamer.message += type + " " + offenseRate + " "; } IM.Number totalValue = IM.Number.zero; foreach (KeyValuePair <OffenseType, IM.Number> keyvalue in lstOffenseRates) { totalValue += keyvalue.Value; } IM.Number rateAdjust = IM.Number.zero; if (lstOffenseRates.Count > 1 && lstOffenseRates.ContainsKey(OffenseType.eDunk)) { rateAdjust = GameSystem.Instance.DunkRateConfig.GetRate(m_player.m_position); } Debugger.Instance.m_steamer.message += "\nDunk adjustment: " + rateAdjust; List <OffenseType> keys = new List <OffenseType>(lstOffenseRates.Keys); foreach (OffenseType key in keys) { IM.Number rate = lstOffenseRates[key] / totalValue; if (lstOffenseRates.Count > 1) { if (key == OffenseType.eDunk) { rate += rateAdjust; } else { rate -= rateAdjust / (lstOffenseRates.Count - 1); } } lstOffenseRates[key] = rate; Debugger.Instance.m_steamer.message += " " + key + ": " + rate; } IM.Number value = IM.Random.value; Debugger.Instance.m_steamer.message += " Random: " + value + "\n"; OffenseType validType = OffenseType.eShot; IM.Number curValue = IM.Number.zero; foreach (KeyValuePair <OffenseType, IM.Number> keyvalue in lstOffenseRates) { IM.Number rate = keyvalue.Value; curValue += rate; if (value > curValue) { continue; } validType = keyvalue.Key; break; } return(validType); }