/// <summary> /// コンストラクタ /// </summary> /// <param name="gameMemberAbility">メンバ能力</param> /// <param name="runnerNumber">もともと何塁ランナーか</param> /// <param name="remainingTimeToNextBase">次の塁までの残り時間</param> /// <param name="overBaseCount">通過したベース数</param> /// <param name="backRun">帰塁中か</param> /// <param name="isSteal">盗塁(スクイズ・エンドラン含む)するランナーか</param> public RunnerStatus(GameMemberAbility gameMemberAbility, int runnerNumber, int remainingTimeToNextBase, int overBaseCount, bool backRun, bool isSteal) { MemberAbility = gameMemberAbility; RunnerNumber = runnerNumber; RemainingTimeToNextBase = remainingTimeToNextBase; OverBaseCount = overBaseCount; BackRun = backRun; IsSteal = isSteal; m_FinalTargetBase = TargetBase; }
/// <summary> /// 一二三塁のランナー状態を作成する(打者ランナーは対象外) /// </summary> /// <param name="baseNumber">元の塁の番号(1~3)</param> /// <param name="memberAbility">メンバ能力</param> /// <param name="isSteal">盗塁するランナーか</param> /// <returns>ランナー状態</returns> private RunnerStatus CreateBaseRunnerStatus(int baseNumber, GameMemberAbility memberAbility, bool isSteal) { // リード距離の算出 double leadDistance = RunnerTactics.GetLeadDistance(baseNumber, isSteal, GameData, GameData.LatestPitchingBollResult.PitchingBallData); // 一三塁で一塁ランナーのみの盗塁時、三塁ランナーはリードが大きすぎると帰塁できずに刺される可能性があるため // リード距離を最小値に補正する if (baseNumber == 3 && isSteal == false && IsStealMode == true) { leadDistance = Constants.MinRunnerLeadDistance; } // ランナー状態の作成 RunnerStatus runnerStatus = CreateRunnerStatus(baseNumber, memberAbility, Constants.BaseDistance - leadDistance, isSteal); // 現在位置の設定 if (baseNumber == 1) { runnerStatus.Point = Constants.PointFirstBase + new Vector(leadDistance * Math.Sin(-45 * Math.PI / 180), leadDistance * Math.Cos(-45 * Math.PI / 180)); } else if (baseNumber == 2) { runnerStatus.Point = Constants.PointSecondBase + new Vector(leadDistance * Math.Sin(-135 * Math.PI / 180), leadDistance * Math.Cos(-135 * Math.PI / 180)); } else if (baseNumber == 3) { runnerStatus.Point = Constants.PointThirdBase + new Vector(leadDistance * Math.Sin(135 * Math.PI / 180), leadDistance * Math.Cos(135 * Math.PI / 180)); } else { throw new Exception("Invalid basenumber"); } // ランナー状態を返す return runnerStatus; }
/// <summary> /// 指定時間後の守備メンバがボールを捕球できるか /// </summary> /// <param name="memberAbility">対象メンバ</param> /// <param name="bollPoint">指定時間後のボール位置</param> /// <param name="fitureSecond">指定時間</param> /// <returns>捕球できるか</returns> private bool CatchedBoll(GameMemberAbility memberAbility, MPoint bollPoint, int fitureSecond) { // エラー発生後の再判定時、ベースカバーの野手は捕球できない if (IsError && IsBaseCover(memberAbility.GameMember.DefensePosition)) { return false; } // 残り硬直時間を取得 int stiffSecond = GetStiffSecond(memberAbility); if (fitureSecond < stiffSecond) { // 硬直時間中はボールを捕球できない return false; } // メンバとボールの距離 double defenseToBollDistanse = (GameData.GetDefensePoint(memberAbility.DefensePosition) - bollPoint).Length; // 指定時間後の守備メンバの移動距離を取得 double moveDistance = GetDefenseMoveDistance(memberAbility, fitureSecond); // 捕球範囲を取得 double catchArea = GetCatchArea(memberAbility); // 捕球できるかを返す return moveDistance + catchArea >= defenseToBollDistanse; }
/// <summary> /// 捕球範囲の取得 /// </summary> /// <param name="memberAbility">メンバ能力</param> /// <returns>捕球範囲</returns> private static double GetCatchArea(GameMemberAbility memberAbility) { if (memberAbility.Defense < Constants.MaxAbilityValue) { // 守備範囲を守備力依存とする // 守備力が低すぎてアウトにできないことを考慮して一定以上の場合のみの補正とする double addArea = GameMemberAbility.GetHigherValueOverBaseline(memberAbility.Defense, Constants.MaxCatchArea); return Constants.MinCatchArea + addArea; } else { // 守備力Sに限り、特殊キャラの個性を強めるために守備範囲が異常に広くなる // 守備力15から5増えるごとに1メートル守備力が増加する // (守備力30(基礎値含めて35)で合計4メートル) double addArea = (memberAbility.Defense - Constants.MaxAbilityValue) * 0.2; return Constants.MinCatchArea + addArea; } }
/// <summary> /// 送球準備時間を取得する /// </summary> /// <param name="memberAbility">メンバ能力</param> /// <returns>送球準備時間</returns> public static int GetThrowPrepareTime(GameMemberAbility memberAbility) { // 残り硬直時間を取得 // 送球までの硬直時間=(固定値)+(最大硬直時間)*{(最大値 - 守備力)/ 最大値} int prepareTime = 0; if (DefensePositionHelper.IsInFielder(memberAbility.DefensePosition)) { // 内野(投手、捕手含む)の場合 prepareTime += Constants.MinThrowPrepareTime; prepareTime += (int)GameMemberAbility.GetLowerValue(memberAbility.Throw, Constants.MaxThrowPrepareTime); } else { // 外野の場合、外野ゴロのアウトを減らすために(足の遅い強打者がアウトにならないように) // 送球準備完了に時間がかかる prepareTime += Constants.MinThrowPrepareTimeForOutFielder; prepareTime += (int)GameMemberAbility.GetLowerValue(memberAbility.Throw, Constants.MaxThrowPrepareTimeForOutFielder); } return prepareTime; }
/// <summary> /// 送球開始から完了までの時間を取得 /// </summary> /// <param name="targetBase">送球先ベース</param> /// <param name="memberAbility">送球メンバ能力</param> /// <param name="startPoint">送球開始位置</param> /// <param name="runTargetBase">送球先に自分が走ってベースカバーに行くか</param> /// <returns>送球が届くまでの時間</returns> public static int GetThrowBollReachTime(int targetBase, GameMemberAbility memberAbility, MPoint startPoint, bool runTargetBase) { // 送球速度 double bollSpeed; if (!runTargetBase) { // 通常の送球速度の設定 bollSpeed = memberAbility.Throw * Constants.ThrowBollSpeedOffSet; if (DefensePositionHelper.IsOutFielder(memberAbility.DefensePosition)) { // 外野の場合は送球速度低下 bollSpeed *= Constants.ThrowBollSpeedOffSetByOutFileder; } } else { // ベースカバーが遅れており、自分でベースを踏む場合は自分の走力が送球速度になる bollSpeed = memberAbility.RunSpeed; } // 送球が届くまでの時間(0割を防ぐ意味でも必ず1秒以上かかる) MPoint targetPoint = GameData.GetBasePoint(targetBase); double distance = (targetPoint - startPoint).Length; return Math.Max((int)(Math.Ceiling(distance / bollSpeed)), 1); }
/// <summary> /// 対象のランナーが盗塁するか /// </summary> /// <param name="baseNumber">ランナー番号</param> /// <param name="gameData">試合のデータ</param> /// <param name="stealJudgeType">盗塁判断タイプ</param> /// <returns>盗塁するか</returns> private static bool TryStealPerRunner(int baseNumber, GameData gameData, out StealJudgeType stealJudgeType) { // 盗塁阻止にかかる時間を取得 GameMemberAbility catcherAbility = new GameMemberAbility(gameData.CurrentDefenseTeam.GetMember(DefensePosition.Catcher), gameData); int throwTime = GetThrowTimeForSteal(baseNumber + 1, catcherAbility); // 盗塁にかかる時間を取得 int stealTimeByFastBall = GetStealTimeByFastBall(baseNumber, gameData); int stealTimeByBreakingBall = GetStealTimeByBreakingBall(baseNumber, gameData); int stealTimeByPitchOut = GetStealTimeByPitchOut(baseNumber, gameData); // メンバ能力の取得 GameMemberAbility memberAbility = GetRunnerAbility(baseNumber, gameData); // 状況によって積極盗塁と慎重盗塁を分ける // 慎重盗塁(ウエストでもいけるなら100%で実行、直球でもいけるなら確率で実行) { // 盗塁できないと誤判断する時間 int judgeTime = (int)GameMemberAbility.GetLowerValue(memberAbility.Wisdom, Constants.MaxWrongJudgeTimeForStealNotEnable); #region 盗塁判断タイプの設定 if (stealTimeByPitchOut + judgeTime < throwTime) { stealJudgeType = StealJudgeType.Success; } else if (stealTimeByFastBall + judgeTime < throwTime) { stealJudgeType = StealJudgeType.SuccessIfFastBoll; } else if (stealTimeByBreakingBall + judgeTime < throwTime) { stealJudgeType = StealJudgeType.SuccessIfBreakingBoll; } else { stealJudgeType = StealJudgeType.Impossible; } #endregion // ウエスト時に盗塁可能か if (stealTimeByPitchOut + judgeTime < throwTime) { // ウエスト時に盗塁可能と判断した場合、100%で盗塁する return true; } // 直球で盗塁可能か if (stealTimeByFastBall + judgeTime < throwTime) { // 盗塁可能であれば、アウトカウントごとに確率で判定 int value; if (gameData.OutCount == 0) { // 0アウトの場合 value = 30; } else if (gameData.OutCount == 1) { // 1アウトの場合 value = 50; } else { // 2アウトの場合 value = 70; } // 三盗は慎重に行うべきのため、半分の確率とする if (baseNumber == 2) { value /= 2; } return RandomCreater.GetPercentValue() < value; } } // 積極盗塁(2アウトの一塁ランナーの場合のみ) if (gameData.OutCount == 2 && baseNumber == 1 && gameData.AllRunnerMembers.Count == 1) { // 9回以降で2点以上負けている場合は盗塁しない if (gameData.CurrentInning >= 9 && gameData.RunScoreDeltaForAttackTeam <= -2) { return false; } // 試合中にすでに盗塁失敗している場合は実行確率低下 int downValue = gameData.CurrentAttackTeam.StealOutCount * 10; // 盗塁できると誤判断する時間 int judgeTime = (int)GameMemberAbility.GetLowerValue(memberAbility.Wisdom, Constants.MaxWrongJudgeTimeForStealForEnable); // ウエスト時に盗塁可能か if (stealTimeByPitchOut - judgeTime < throwTime) { // ウエスト時に盗塁可能と判断した場合、高確率で盗塁する // (誤判断で盗塁できない可能性があるため100%としない) return RandomCreater.GetPercentValue() < (80 - downValue); } // 直球で盗塁可能か if (stealTimeByFastBall - judgeTime < throwTime) { return RandomCreater.GetPercentValue() < (50 - downValue); } // 変化球で盗塁可能か if (stealTimeByBreakingBall - judgeTime < throwTime) { if (gameData.CurrentPitcherAbirity.Fastball - gameData.CurrentPitcherAbirity.Breakingball > 4) { // 直球の方が大幅に強い場合は、直球中心で投げる可能性が高いため盗塁はあまり狙わない return RandomCreater.GetPercentValue() < (10 - downValue); } else { // そうでなければ、変化球を投げることを願って盗塁する return RandomCreater.GetPercentValue() < (30 - downValue); } } } // いずれの条件にも該当しなければ盗塁しない return false; }
/// <summary> /// 送球開始の回転からタッチアウトまでにかかる時間を取得 /// (ベースカバーが遅れて自分でベースまで走る場合も考慮) /// </summary> /// <param name="targetBase">送球先ベース</param> /// <param name="throwPosition">送球ポジション</param> /// <param name="startPoint">送球開始位置</param> /// <param name="memberAbility">送球メンバ能力</param> /// <param name="passedTime">送球開始までに現在時刻からさらに経過している時間(捕球前の予測で使用)</param> /// <returns>かかる時間時間</returns> private int GetThrowTimeFromTurnToTouch(int targetBase, DefensePosition throwPosition, MPoint startPoint, GameMemberAbility memberAbility, int passedTime) { // 送球前の回転から送球完了までの時間の算出 int throwTime = GetThrowBollReachTimeFromTurn(targetBase, throwPosition, startPoint, memberAbility); // ベースカバー完了までの時間を算出(送球開始までにさらに経過している時間は減算) int baseCoverTime = BaseCoverRemainingTime[targetBase] - passedTime; if (baseCoverTime > throwTime) { // ベースカバー完了の方が遅ければ、それが送球完了時間となる // (送球完了時にベースカバー完了するタイミングまで送球開始を待つため) throwTime = baseCoverTime; // 自分でベースまで走った場合と比較してどちらが速いか検証する int throwTimeByRun = GetThrowBollReachTime(targetBase, throwPosition, startPoint, true); if (throwTimeByRun < throwTime) { // 自分でベースまで走った方が早ければ、その時間を送球時間とする throwTime = throwTimeByRun; } } // フォースアウトでも帰塁ランナーのアウトでもなければ // タッチアウト体制への準備時間を加算する if (!IsForceOut(targetBase) && GetBackRunRunner(targetBase) == null) { throwTime += Constants.ReadyingTouchSecond; } // かかる時間を返す return throwTime; }
/// <summary> /// ランナーが次の塁に進むか正しく判断するか /// </summary> /// <param name="memberAbility"></param> /// <param name="marginTime"></param> /// <returns></returns> private bool JudgeCorrectRun(GameMemberAbility memberAbility, int marginTime) { // 打球が外野まで行った場合、100ターン以上かかることが多く、200ターン以上かかることもある // その場合に、最大数十ターンの誤判断は小さすぎるため、捕球時間をもとに誤判断時間を長くする double maxWrongJudgeTime = Math.Max((double)CatchTime * 3 / 10, Constants.MaxWrongJudgeTimeForForwardRun); // 正しく判断可能な余裕時間を算出する(この値より大きい余裕時間であれば、正しい判断ができる) int correctJudgeTime = (int)GameMemberAbility.GetLowerValue(memberAbility.Wisdom, maxWrongJudgeTime); if (Math.Abs(marginTime) >= correctJudgeTime) { // 正しく判断する return true; } else { // 誤判断する return false; } }
/// <summary> /// 残り硬直時間を取得 /// </summary> /// <param name="memberAbility">メンバ能力</param> /// <returns>硬直時間</returns> private int GetStiffSecond(GameMemberAbility memberAbility) { int stiffSecond = 0; { // 守備の硬直時間=(最短捕球開始時間)+(守備位置ごとの補正)-(バントシフト補正) // (固定で硬直時間を付加しないと、守備が良い場合にゴロで安打がでない) if (DefensePositionHelper.IsInFielder(memberAbility.DefensePosition)) { // 内野(投手、捕手を含む)の場合 // (硬直時間は守備力に依存しない。 // 1差による打率への影響が大きく、硬直時間では最大5差しか付けられないため捕球範囲で差を付ける // また、捕球範囲で差をつけた方がユーザがアクションで守備力を把握しやすい) stiffSecond += Constants.MinDefenseCatchSecond; // 投手の場合は余分にかかる(ピッチャー強襲のゴロを捕球してしまわないようにするため) if (memberAbility.DefensePosition == DefensePosition.Pitcher) { stiffSecond += Constants.MinDefenseCatchSecondForPitcher; } // バントの場合、セーフティバントを防止するために投手と捕手以外の内野はダッシュする // (硬直時間を削減することで表現する) if (GameData.CurrentBattingBunt) { // 内野全員、一定の硬直時間を削減 stiffSecond -= Constants.BuntShiftDashTimeForInFielder; // 投手と捕手以外の内野は、さらに硬直時間を削減 if (memberAbility.DefensePosition != DefensePosition.Pitcher && memberAbility.DefensePosition != DefensePosition.Catcher) { // 前進守備による削減 if (GameData.InFielderDrawIn) { stiffSecond -= Constants.BuntShiftDashTimeByDrawIn; } // ダッシュによる削減 if (GameData.AllRunnerMembers.Count == 0) { // ランナーなし(一塁手と三塁手ダッシュ可能) stiffSecond -= Constants.BuntShiftDashTimeByDash; } else if (GameData.AllRunnerMembers.Count == 1 && GameData.FirstRunnerMember != null) { // ランナー:一塁(一塁手ダッシュ不可) if (memberAbility.DefensePosition != DefensePosition.First) { stiffSecond -= Constants.BuntShiftDashTimeByDash; } } else if (GameData.AllRunnerMembers.Count == 2 && GameData.FirstRunnerMember != null && GameData.ThirdRunnerMember != null) { // ランナー:一三塁(両方ダッシュ不可) if (memberAbility.DefensePosition != DefensePosition.First && memberAbility.DefensePosition != DefensePosition.Third) { stiffSecond -= Constants.BuntShiftDashTimeByDash; } } else { // それ以外 // ランナー:二塁 or 一二塁(三塁手ダッシュ不可、三塁手が取っても進塁防げないため) // ランナー:三塁 or 二三塁 or 満塁(三塁手ダッシュ不可、三塁ランナーの牽制のため) if (memberAbility.DefensePosition != DefensePosition.Third) { stiffSecond -= Constants.BuntShiftDashTimeByDash; } } } // 将来、定数を変更してマイナスになっても0以上になるように補正する stiffSecond = Math.Max(0, stiffSecond); } } else { // 外野の場合、捕球範囲の広さだけでは守備力の効果が小さ過ぎるため、 // 硬直時間を守備依存にして、余分に硬直させる stiffSecond += Constants.MinDefenseCatchSecond; stiffSecond += (int)GameMemberAbility.GetLowerValueOverBaseline(memberAbility.Defense, Constants.MaxDefenseStiffTimeForOutFielder); } // すでに経過している時間を硬直時間から減算 // (ベースカバーの場合は守備動作種別が変更されているため、全経過時間から算出) stiffSecond = Math.Max(0, stiffSecond - GameData.AllDefensePassedSecond); // エラーした場合、エラーした野手は一定時間捕球できない if (IsError && memberAbility.DefensePosition == ErrorPosition) { stiffSecond = Constants.ErrorStiffSecond; stiffSecond = Math.Max(0, stiffSecond + ErrorTime - GameData.AllDefensePassedSecond); } } return stiffSecond; }
/// <summary> /// 送球のための回転開始から送球完了までの時間を取得 /// </summary> /// <param name="targetBase">送球先ベース</param> /// <param name="throwPosition">送球ポジション</param> /// <param name="startPoint">送球開始位置</param> /// <param name="memberAbility">送球メンバ能力</param> /// <returns>かかる時間時間</returns> private int GetThrowBollReachTimeFromTurn(int targetBase, DefensePosition throwPosition, MPoint startPoint, GameMemberAbility memberAbility) { // 送球開始から完了までの時間を取得 int throwTime = GetThrowBollReachTime(targetBase, throwPosition, startPoint); // 送球前の回転が必要な場合は余分に時間を加算 if (NeedTurnForThrow(memberAbility, targetBase, startPoint)) { throwTime += Constants.TurnForThrowTime; } return throwTime; }
/// <summary> /// 指定時間後の守備メンバの位置を返す /// </summary> /// <param name="memberAbility">対象メンバ</param> /// <param name="goalPoint">目標位置位置</param> /// <param name="fitureSecond">指定時間</param> /// <returns>指定時間後の守備メンバの位置</returns> private MPoint GetDefenseMovePoint(GameMemberAbility memberAbility, MPoint goalPoint, int fitureSecond) { // 指定時間後の守備メンバの移動距離を取得 double moveDistance = GetDefenseMoveDistance(memberAbility, fitureSecond); // 指定秒数後のメンバ位置を取得 MPoint fitureMemberPoint; { MPoint memberPoint = GameData.GetDefensePoint(memberAbility.DefensePosition); // 目的位置とメンバの位置関係から進行方向のベクトルを取得 Vector memberToGoalVector = (goalPoint - memberPoint); if (memberToGoalVector.Length > moveDistance) { // ベクトルを正規化 double normalizing = memberToGoalVector.Length > 0 ? memberToGoalVector.Length : 1; memberToGoalVector = new Vector(memberToGoalVector.X / normalizing, memberToGoalVector.Y / normalizing); // 正規化したベクトルと移動距離から移動ベクトルを算出 Vector moveVector = new Vector(moveDistance * memberToGoalVector.X, moveDistance * memberToGoalVector.Y); // フェンスによる位置の補正 fitureMemberPoint = ChangePointByFense(memberPoint, moveVector); } else { // 目標位置までの距離が移動可能距離より小さい場合は、目標位置がそのまま最終位置になる fitureMemberPoint = goalPoint; } } return fitureMemberPoint; }
/// <summary> /// 指定時間後の守備メンバの移動距離を取得 /// </summary> /// <param name="memberAbility">メンバ能力</param> /// <param name="fitureSecond">指定時間</param> /// <returns>移動距離</returns> private double GetDefenseMoveDistance(GameMemberAbility memberAbility, int fitureSecond) { // 残り硬直時間を取得 int stiffSecond = GetStiffSecond(memberAbility); // 守備移動距離 double moveDistance; if (fitureSecond < stiffSecond) { // 硬直時間の方が長ければ移動なし moveDistance = 0; } else { // 移動距離を算出 double speed = memberAbility.RunSpeed; moveDistance = speed * (fitureSecond - stiffSecond); } return moveDistance; }
/// <summary> /// ランナー状態の作成 /// </summary> /// <param name="baseNumber">元の塁の番号(0~3)</param> /// <param name="memberAbility">メンバの能力</param> /// <param name="distance">次の塁への残り距離</param> /// <param name="isSteal">盗塁(スクイズ・エンドラン含む)するランナーか</param> /// <returns>ランナー状態</returns> private RunnerStatus CreateRunnerStatus(int baseNumber, GameMemberAbility memberAbility, double distance, bool isSteal) { // 初期状態は必ず進塁しベース間距離からリード距離を引いた距離を進む int remainingTimeToNextBase = GetRemainingTimeToNextBase(memberAbility.Run, distance); return new RunnerStatus(memberAbility, baseNumber, remainingTimeToNextBase, baseNumber, false, isSteal); }
/// <summary> /// 盗塁可能かどうかの盗塁判断タイプを智力依存でなく事実を取得する /// </summary> /// <param name="gameData">試合のデータ</param> /// <returns>盗塁判断タイプ</returns> public static StealJudgeType GetRealStealJudgeType(GameData gameData) { StealJudgeType stealJudgeType = StealJudgeType.Invalid; // ランナーがいないか満塁の場合は何もしない if (gameData.AllRunnerMembers.Count == 0 || gameData.AllRunnerMembers.Count == 3) { return stealJudgeType; } // 盗塁対象外ならそれを返す int baseNumber = gameData.StealTargetRunnerNumber; if (baseNumber == 0) { return stealJudgeType; } // 盗塁阻止にかかる時間を取得 GameMemberAbility catcherAbility = new GameMemberAbility(gameData.CurrentDefenseTeam.GetMember(DefensePosition.Catcher), gameData); int throwTime = GetThrowTimeForSteal(baseNumber + 1, catcherAbility); // 盗塁にかかる時間を取得 int stealTimeByFastBall = GetStealTimeByFastBall(baseNumber, gameData); int stealTimeByBreakingBall = GetStealTimeByBreakingBall(baseNumber, gameData); int stealTimeByPitchOut = GetStealTimeByPitchOut(baseNumber, gameData); if (stealTimeByPitchOut < throwTime) { stealJudgeType = StealJudgeType.Success; } else if (stealTimeByFastBall < throwTime) { stealJudgeType = StealJudgeType.SuccessIfFastBoll; } else if (stealTimeByBreakingBall < throwTime) { stealJudgeType = StealJudgeType.SuccessIfBreakingBoll; } else { stealJudgeType = StealJudgeType.Impossible; } return stealJudgeType; }
/// <summary> /// 送球でランナーをアウトにできるかを正しく判断するか /// </summary> /// <param name="memberAbility">メンバ能力</param> /// <param name="marginTime">正しくアウトにできる時間からの誤差時間(マイナスならアウトにできる)</param> /// <returns>正しく判断するか</returns> private bool JudgeThrowForOut(GameMemberAbility memberAbility, int marginTime) { // 智力に依存して、ランナーをアウトにできるか判定する // 賢いほど、ぎりぎり間にあう状態で積極的にアウトにする // (アホだと、アウトにできるのに諦め、アウトにしやすい所に送球する) // 打球が外野まで行った場合、100ターン以上かかることが多く、200ターン以上かかることもある // その場合に、最大数十ターンの誤判断は小さすぎるため、捕球時間をもとに誤判断時間を長くする double maxWrongJudgeTime = Math.Max((double)CatchTime * 4 / 10, Constants.MaxWrongJudgeTimeForThrow); // 正しく判断可能な余裕時間を算出する(この値より大きい余裕時間であれば、正しい判断ができる) int correctJudgeTime = (int)GameMemberAbility.GetLowerValue(memberAbility.Wisdom, maxWrongJudgeTime); if (Math.Abs(marginTime) >= correctJudgeTime) { // 正しく判断する return true; } else { // 誤判断する return false; } }
/// <summary> /// 盗塁阻止にかかる時間を取得する /// </summary> /// <param name="targetBase">送球先のベース</param> /// <param name="memberAbility">捕手のメンバ能力</param> /// <returns>盗塁阻止にかかる時間</returns> public static int GetThrowTimeForSteal(int targetBase, GameMemberAbility memberAbility) { // 準備時間の取得 int prepareTime = DefenseActionManger.GetThrowPrepareTime(memberAbility); // 送球開始から届くまでの時間の取得 MPoint startPoint = Constants.Defense2PointDefault; int throwBollReachTime = DefenseActionManger.GetThrowBollReachTime(targetBase, memberAbility, startPoint, false); // 上記の時間+タッチするためにかかる時間を加算して返す return prepareTime + throwBollReachTime + Constants.ReadyingTouchSecond; }
/// <summary> /// 送球前の回転が必要か判定 /// </summary> /// <param name="throwMemberAbility">送球メンバ能力</param> /// <param name="targetBase">送球先</param> /// <param name="throwStartPoint">送球開始位置</param> /// <returns>余分に時間がかかるか</returns> private bool NeedTurnForThrow(GameMemberAbility throwMemberAbility, int targetBase, MPoint throwStartPoint) { // 回転が必要ない野手であれば不要を返す // (投手と内野のみが対象で、捕手は反対を向いているため回転不要) if (throwMemberAbility.DefensePosition != DefensePosition.Pitcher && throwMemberAbility.DefensePosition != DefensePosition.First && throwMemberAbility.DefensePosition != DefensePosition.Second && throwMemberAbility.DefensePosition != DefensePosition.Third && throwMemberAbility.DefensePosition != DefensePosition.Short) { return false; } // 左投げで一塁送球時に回転が必要 if (throwMemberAbility.GameMember.Player.IsLeftThrow && targetBase == 1) { return true; } // 前にダッシュして後ろ(二塁)に送球する場合は回転が必要 // (二塁へのバントを成功させやすくするための処置のため、バントで二塁送球時に必ず発生する) if (GameData.CurrentBattingBunt && targetBase == 2) { return true; } // 右投げで三塁送球時に回転が必要 // (二塁手/遊撃手/三塁手をむやみに回転させたくないため、投手と一塁手のみ発生する) if (throwMemberAbility.GameMember.Player.IsLeftThrow == false && targetBase == 3 && (throwMemberAbility.DefensePosition == DefensePosition.Pitcher || throwMemberAbility.DefensePosition == DefensePosition.First)) { return true; } // 上記の条件を満たさなければ回転不要 return false; }
/// <summary> /// 盗塁実行ボタン /// </summary> /// <param name="sender"></param> /// <param name="e"></param> private void m_StealButton_Click(object sender, EventArgs e) { // ランナー無しで実行した場合は、一塁ランナーのみ存在させる if (!m_FirstRunner.Checked && !m_SecondRunner.Checked && !m_ThirdRunner.Checked) { m_FirstRunner.Checked = true; m_SecondRunner.Checked = false; m_ThirdRunner.Checked = false; } // チーム設定以外のパラメータ設定 int baseAbilityValue = int.Parse(m_BaseAbilityValue.Text); // 試合管理クラスの取得 GameManager gameManager = GetGameManager(baseAbilityValue); // 盗塁ランナーの設定 int stealRunnerNumber; if (m_SecondRunner.Checked) { // 二塁ランナーが存在すれば、そのランナーが盗塁 stealRunnerNumber = 2; } else { // いなければ一塁ランナーが盗塁(一塁か二塁に必ずランナーがいる想定) stealRunnerNumber = 1; } // 盗塁阻止にかかる時間を取得 GameMemberAbility memberAbility = new GameMemberAbility(gameManager.GameData.CurrentDefenseTeam.GetMember(DefensePosition.Catcher), gameManager.GameData); int throwTime = RunnerTactics.GetThrowTimeForSteal(stealRunnerNumber + 1, memberAbility); // 送球時間を出力 StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine(string.Format("送球時間:{0}", throwTime)); // 盗塁時間をN球分出力 for (int throwCount = 1; throwCount <= 4; throwCount++) { // 1球投げた状態に更新(実際も計算も先に球数を加算してから盗塁時間を算出する) gameManager.GameData.ThrowBallCountForCurretBatter++; gameManager.GameData.ThrowBallCountForSteal = gameManager.GameData.ThrowBallCountForCurretBatter; // 盗塁時間の算出 int stealTimeByFastBall = RunnerTactics.GetStealTimeByFastBall(stealRunnerNumber, gameManager.GameData); int stealTimeByBreakingBall = RunnerTactics.GetStealTimeByBreakingBall(stealRunnerNumber, gameManager.GameData); int stealTimeByPitchOut = RunnerTactics.GetStealTimeByPitchOut(stealRunnerNumber, gameManager.GameData); // 出力 stringBuilder.AppendLine(string.Format("盗塁時間({0}球目)", throwCount)); stringBuilder.AppendLine(string.Format(" 変化球:{0} {1}", stealTimeByBreakingBall, stealTimeByBreakingBall < throwTime)); stringBuilder.AppendLine(string.Format(" 直球 :{0} {1}", stealTimeByFastBall, stealTimeByFastBall < throwTime)); stringBuilder.AppendLine(string.Format(" ウエスト :{0} {1}", stealTimeByPitchOut, stealTimeByPitchOut < throwTime)); } // UIに表示 m_ResultText.Text = stringBuilder.ToString(); }
/// <summary> /// 投手交代 /// </summary> private void ChangePitcher() { // デバッグモードでなくメンバー変更画面表示が必要な場合は勝手に交代しない if (!EVManager.Instance.DebugMode && !GameData.UserTeamOffenseOrDefense && NeedMemberSelectView) { return; } // スタミナが切れた場合か、代打・代走により投手でないメンバが投手の場合に交代 // (起用が「交代しない」は代打・代走で交代しないという意味であるため、スタミナ切れは交代する) if (GameData.CurrentPitcher.RemainingStaminaRasio < Constants.ChangePitcherStamina || !GameData.CurrentPitcher.IsPitcher) { if (!HighSpeedGameMode && !GameData.UserTeamOffenseOrDefense) { // ユーザが操作画面でユーザの守備中の場合は勝手に交代しない } else { // 控え投手と交代するか判定 GameMember oldPitcher = GameData.CurrentPitcher; GameMember newPitcher = GameData.CurrentDefenseTeam.GetSubPitcher(); if (newPitcher != null) { // 現在投手と控え投手をスタミナを考慮した上で比較し、控えの方が強ければ交代する // (スタミナ0でも控えの方が弱ければ交代しない) GameMemberAbility oldAbility = new GameMemberAbility(oldPitcher, GameData); GameMemberAbility newAbility = new GameMemberAbility(newPitcher, GameData); if (oldAbility.PitcherTotalConsideringStamina < newAbility.PitcherTotalConsideringStamina) { GameData.CurrentDefenseTeam.ChangeMemberForPitcher(newPitcher, GameData.CurrentInning); } } } } }