CoverTransitionModel.cs
1 using GUNRPG.Core.Operators; 2 3 namespace GUNRPG.Core.Combat; 4 5 /// <summary> 6 /// Models cover transition delays and exposure windows. 7 /// Cover transitions are not instantaneous - they create vulnerability windows. 8 /// </summary> 9 public static class CoverTransitionModel 10 { 11 // Transition delay constants (in milliseconds) 12 // These represent realistic times for moving into/out of cover positions 13 14 /// <summary> 15 /// Delay for transitioning from no cover to partial cover (80-150ms). 16 /// Moving to a peeking position from exposed. 17 /// </summary> 18 public const int NoneToPartialDelayMs = 100; 19 20 /// <summary> 21 /// Delay for transitioning from partial cover to full cover (80-150ms). 22 /// Fully concealing oneself from a peeking position. 23 /// </summary> 24 public const int PartialToFullDelayMs = 100; 25 26 /// <summary> 27 /// Delay for transitioning from full cover to partial cover (100-200ms). 28 /// Exposing to peek from complete concealment - takes slightly longer. 29 /// </summary> 30 public const int FullToPartialDelayMs = 150; 31 32 /// <summary> 33 /// Delay for transitioning from partial cover to no cover (80-150ms). 34 /// Leaving cover entirely from a peeking position. 35 /// </summary> 36 public const int PartialToNoneDelayMs = 100; 37 38 /// <summary> 39 /// Direct transition from full cover to no cover goes through partial first. 40 /// Total delay = FullToPartialDelayMs + PartialToNoneDelayMs 41 /// </summary> 42 public const int FullToNoneDelayMs = FullToPartialDelayMs + PartialToNoneDelayMs; 43 44 /// <summary> 45 /// Direct transition from no cover to full cover goes through partial first. 46 /// Total delay = NoneToPartialDelayMs + PartialToFullDelayMs 47 /// </summary> 48 public const int NoneToFullDelayMs = NoneToPartialDelayMs + PartialToFullDelayMs; 49 50 /// <summary> 51 /// Gets the base transition delay between two cover states. 52 /// </summary> 53 /// <param name="fromCover">Starting cover state</param> 54 /// <param name="toCover">Target cover state</param> 55 /// <returns>Base transition delay in milliseconds, or 0 if no change</returns> 56 public static int GetTransitionDelayMs(CoverState fromCover, CoverState toCover) 57 { 58 if (fromCover == toCover) 59 return 0; 60 61 return (fromCover, toCover) switch 62 { 63 // Direct adjacent transitions 64 (CoverState.None, CoverState.Partial) => NoneToPartialDelayMs, 65 (CoverState.Partial, CoverState.Full) => PartialToFullDelayMs, 66 (CoverState.Full, CoverState.Partial) => FullToPartialDelayMs, 67 (CoverState.Partial, CoverState.None) => PartialToNoneDelayMs, 68 69 // Multi-step transitions (going through intermediate state) 70 (CoverState.None, CoverState.Full) => NoneToFullDelayMs, 71 (CoverState.Full, CoverState.None) => FullToNoneDelayMs, 72 73 _ => 0 74 }; 75 } 76 77 /// <summary> 78 /// Gets the effective transition delay between two cover states, scaled by response proficiency. 79 /// Higher response proficiency results in faster transitions. 80 /// </summary> 81 /// <param name="fromCover">Starting cover state</param> 82 /// <param name="toCover">Target cover state</param> 83 /// <param name="responseProficiency">Operator's response proficiency (0.0-1.0)</param> 84 /// <returns>Effective transition delay in milliseconds</returns> 85 public static int GetEffectiveTransitionDelayMs(CoverState fromCover, CoverState toCover, float responseProficiency) 86 { 87 int baseDelay = GetTransitionDelayMs(fromCover, toCover); 88 if (baseDelay == 0) 89 return 0; 90 91 float effectiveDelay = ResponseProficiencyModel.CalculateEffectiveDelay(baseDelay, responseProficiency); 92 return (int)Math.Round(effectiveDelay); 93 } 94 95 /// <summary> 96 /// Gets the effective transition delay with multiplier info for logging/timeline display. 97 /// </summary> 98 /// <param name="fromCover">Starting cover state</param> 99 /// <param name="toCover">Target cover state</param> 100 /// <param name="responseProficiency">Operator's response proficiency (0.0-1.0)</param> 101 /// <returns>Tuple of (effectiveDelayMs, baseDelayMs, multiplier)</returns> 102 public static (int effectiveDelayMs, int baseDelayMs, float multiplier) GetEffectiveTransitionDelayWithInfo( 103 CoverState fromCover, 104 CoverState toCover, 105 float responseProficiency) 106 { 107 int baseDelay = GetTransitionDelayMs(fromCover, toCover); 108 if (baseDelay == 0) 109 return (0, 0, 1.0f); 110 111 var (effectiveDelay, multiplier) = ResponseProficiencyModel.CalculateEffectiveDelayWithMultiplier( 112 baseDelay, responseProficiency); 113 return ((int)Math.Round(effectiveDelay), baseDelay, multiplier); 114 } 115 }