def _SimulateInternal (self, ticks: int) -> None: if ticks <= 0: return if self.TimeSinceCycleStart is None: return cycleReproductiveTimeMultiplier = _GetCycleReproductiveTimeMultiplier() # type: float lastTimeSinceCycleStart = self.TimeSinceCycleStart # type: float lastTickSinceCycleStart = ReproductionShared.ReproductiveMinutesToTicks(lastTimeSinceCycleStart, cycleReproductiveTimeMultiplier) # type: int nextTickSinceCycleStart = lastTickSinceCycleStart + ticks # type: int nextTimeSinceCycleStart = ReproductionShared.TicksToReproductiveMinutes(nextTickSinceCycleStart, cycleReproductiveTimeMultiplier) # type: float if self.ShowFertilityNotifications and self.Enabled: currentCycleState = self._GetCycle(lastTimeSinceCycleStart) # type: DotCycle currentTicksUntilOvulationStarts = ReproductionShared.GameMinutesToTicks(currentCycleState.GetTimeUntilPhaseStarts(CycleShared.MenstrualCyclePhases.Ovulation)) # type: int ticksBeforeOvulationToNotify = ReproductionShared.GameMinutesToTicks(_GetSpermHalfLifeTime()) # type: int if ticksBeforeOvulationToNotify < self.MinimumTicksBeforeOvulationToNotify: ticksBeforeOvulationToNotify = self.MinimumTicksBeforeOvulationToNotify if currentTicksUntilOvulationStarts > 0 and ticksBeforeOvulationToNotify < currentTicksUntilOvulationStarts: nextCycleState = self._GetCycle(nextTimeSinceCycleStart) # type: DotCycle nextTicksUntilOvulationStarts = ReproductionShared.GameMinutesToTicks(nextCycleState.GetTimeUntilPhaseStarts(CycleShared.MenstrualCyclePhases.Ovulation)) # type: int if ticksBeforeOvulationToNotify > nextTicksUntilOvulationStarts: UIDot.ShowFertilityNotification(self.TargetSimInfo) self.TimeSinceCycleStart = nextTimeSinceCycleStart
def _SimulateInternal (self, simulation: ReproductionShared.Simulation, ticks: int, reproductiveTimeMultiplier: typing.Union[float, int]) -> None: ageTicks = ReproductionShared.ReproductiveMinutesToTicks(self.Age, reproductiveTimeMultiplier) # type: typing.Union[float, int] decayTick = ReproductionShared.ReproductiveMinutesToTicks(self.Lifetime, reproductiveTimeMultiplier) # type: typing.Union[float, int] decaying = False # type: bool decayed = False # type: bool if ageTicks < decayTick <= (ageTicks + ticks): decaying = True if decayTick <= (ageTicks + ticks): decayed = True if not decayed: decayingAmount = self.DecayingTicks(ticks, reproductiveTimeMultiplier) # type: int else: decayingAmount = self.SpermCount # type: int self.Age = ReproductionShared.TicksToReproductiveMinutes(ageTicks + ticks, reproductiveTimeMultiplier) self.SpermCount -= decayingAmount if decaying: if self.DecayedCallback is None: Debug.Log("Missing callback to be triggered on sperm decay.", This.Mod.Namespace, Debug.LogLevels.Warning, group = This.Mod.Namespace, owner = __name__, lockIdentifier = __name__ + ":" + str(Python.GetLineNumber())) else: self.DecayedCallback(self)
def DecayingTicks (self, ticks: int, reproductiveTimeMultiplier: typing.Union[float, int]) -> int: """ Get the amount of sperm cells that will decay within this many ticks. """ if not isinstance(ticks, (int,)): raise Exceptions.IncorrectTypeException(ticks, "ticks", (int,)) if not isinstance(reproductiveTimeMultiplier, (float, int)): raise Exceptions.IncorrectTypeException(reproductiveTimeMultiplier, "reproductiveTimeMultiplier", (float, int)) if ticks < 0: raise ValueError("The parameter 'ticks' cannot be less than 0.") if reproductiveTimeMultiplier <= 0: raise ValueError("The parameter 'reproductiveTimeMultiplier' cannot be less than or equal to 0.") if self.SpermCount == 0: return 0 if ticks == 0: return 0 currentAgeTicks = ReproductionShared.ReproductiveMinutesToTicks(self.Age, reproductiveTimeMultiplier) # type: int currentAge = ReproductionShared.TicksToReproductiveMinutes(currentAgeTicks, reproductiveTimeMultiplier) # type: typing.Union[float, int] # This is slightly faster than getting using the GetClosestPreciseReproductiveMinute function. nextAgeTicks = currentAgeTicks + ticks # type: typing.Union[float, int] nextAge = ReproductionShared.TicksToReproductiveMinutes(nextAgeTicks, reproductiveTimeMultiplier) # type: typing.Union[float, int] lifeTimeTick = ReproductionShared.ReproductiveMinutesToTicks(self.Lifetime, reproductiveTimeMultiplier) if nextAgeTicks >= lifeTimeTick: return self.SpermCount currentPercentageRemaining = 1.0 - self.LifetimeDistribution.CumulativeDistribution(currentAge) # type: typing.Union[float, int] nextPercentageRemaining = 1.0 - self.LifetimeDistribution.CumulativeDistribution(nextAge) # type: typing.Union[float, int] percentageRemainingChange = currentPercentageRemaining - nextPercentageRemaining # type: typing.Union[float, int] originalSpermCount = int(self.SpermCount / currentPercentageRemaining) # type: int decayingSpermCount = int(originalSpermCount * percentageRemainingChange) # type: int if decayingSpermCount < 0: Debug.Log("Calculated a decaying sperm count of less than zero (%s)." % decayingSpermCount, This.Mod.Namespace, Debug.LogLevels.Warning, group = This.Mod.Namespace, owner = __name__, lockIdentifier = __name__ + ":" + str(Python.GetLineNumber())) return int(originalSpermCount * percentageRemainingChange)
def _CycleSimulationPhase (self, simulation: ReproductionShared.Simulation, ticks: int) -> None: reproductiveTimeMultiplier = self.ReproductiveTimeMultiplier # type: typing.Union[float, int] simulatingMinutes = ReproductionShared.TicksToReproductiveMinutes(ticks, reproductiveTimeMultiplier) # type: typing.Union[float, int] simulationMemoryKey = self.SimulationMemoryKey simulationMemoryExists = simulationMemoryKey in simulation.Memory # type: bool simulationMemory = simulation.Memory.get(simulationMemoryKey, CycleTrackerSimulationMemory()) # type: CycleTrackerSimulationMemory if self.TimeSinceLastCycle is not None: self.TimeSinceLastCycle += simulatingMinutes if self.CurrentCycle is not None: cycleTicksRemaining = ReproductionShared.ReproductiveMinutesToTicks(self.CurrentCycle.TimeRemaining, reproductiveTimeMultiplier) # type: typing.Union[float, int] if cycleTicksRemaining < ticks: Debug.Log("Simulation stepped over the end of a cycle by %s ticks, this may cause lost time for the tracking sim.\n%s" % (str(ticks - cycleTicksRemaining), self.DebugInformation), This.Mod.Namespace, Debug.LogLevels.Warning, group = This.Mod.Namespace, owner = __name__, lockIdentifier = __name__ + ":" + str(Python.GetLineNumber()), lockReference = self.TrackingSystem) self.CurrentCycle.Simulate(simulation, ticks, reproductiveTimeMultiplier) else: if simulationMemory.CycleStartTesting is None: Debug.Log("Expected the 'CycleStartTesting' to be in the simulation memory, but all we found was None.\n" + self.DebugInformation, This.Mod.Namespace, Debug.LogLevels.Warning, group = This.Mod.Namespace, owner = __name__, lockIdentifier = __name__ + ":" + str(Python.GetLineNumber()), lockReference = self.TrackingSystem) simulationMemory.CycleStartTesting = self.DoCycleStartTesting() elif not simulationMemoryExists: simulationMemory.CycleStartTesting = self.DoCycleStartTesting() if simulationMemory.CycleStartTesting.GetCanStart(): timeUntilCycleStart = simulationMemory.CycleStartTesting.GetTimeUntilStart() # type: typing.Optional[float] cycleStartPlanned = timeUntilCycleStart is not None # type: bool if cycleStartPlanned: ticksUntilCycleStart = ReproductionShared.ReproductiveMinutesToTicks(timeUntilCycleStart, reproductiveTimeMultiplier) # type: int else: ticksUntilCycleStart = 1 # type: int if ticksUntilCycleStart <= ticks: if cycleStartPlanned and ticksUntilCycleStart < ticks: Debug.Log("Simulation stepped over the start of a cycle by %s ticks, this may cause lost time for the tracking sim.\n%s" % (str(ticks - ticksUntilCycleStart), self.DebugInformation), This.Mod.Namespace, Debug.LogLevels.Warning, group = This.Mod.Namespace, owner = __name__, lockIdentifier = __name__ + ":" + str(Python.GetLineNumber()), lockReference = self.TrackingSystem) cycleTypeIdentifier = simulationMemory.CycleStartTesting.GetCycleTypeIdentifier() # type: str cycle = self.GenerateCycle(cycleTypeIdentifier) self.CycleStartTestingSeed = None simulationMemory.CycleStartTesting = None self.CurrentCycle = cycle else: simulationMemory.CycleStartTesting.IncreaseTimeSinceTest(simulatingMinutes) if not simulationMemoryExists: simulation.Memory[simulationMemoryKey] = simulationMemory
def _SimulateInternal(self, simulation: ReproductionShared.Simulation, ticks: int, reproductiveTimeMultiplier: float) -> None: simulatingMinutes = ReproductionShared.TicksToReproductiveMinutes( ticks, reproductiveTimeMultiplier) # type: float gameMinutes = ReproductionShared.TicksToGameMinutes( ticks) # type: float effectGuide = self.BirthControlPillsEffectGuide # type: CycleGuides.BirthControlPillsEffectGuide currentNeed = self.Need # type: float nextNeed = self.Need # type: float if effectGuide.NeedPerGameMinute != 0: if effectGuide.NeedPerGameMinute > 0: if currentNeed != 1: nextNeed += gameMinutes * effectGuide.NeedPerGameMinute else: if currentNeed != 0: nextNeed += gameMinutes * effectGuide.NeedPerGameMinute nextNeed = min(max(nextNeed, 0), 1) currentEntrenchmentRate = effectGuide.EntrenchmentPerReproductiveMinute.Evaluate( currentNeed) # type: float nextEntrenchmentRate = effectGuide.EntrenchmentPerReproductiveMinute.Evaluate( nextNeed) # type: float averageEntrenchmentRate = ( currentEntrenchmentRate + nextEntrenchmentRate ) / 2 # type: float # This is probably only right if the curve is linear. currentEntrenchment = self.Entrenchment nextEntrenchment = self.Entrenchment if averageEntrenchmentRate != 0: if averageEntrenchmentRate > 0: if currentEntrenchment != 1: nextEntrenchment += simulatingMinutes * averageEntrenchmentRate else: if currentEntrenchment != 0: nextEntrenchment += simulatingMinutes * averageEntrenchmentRate nextEntrenchment = min(max(nextEntrenchment, 0), 1) gameMinutesSinceLastPill = self.GameMinutesSinceLastPill # type: float self.Need = nextNeed self.Entrenchment = nextEntrenchment if gameMinutesSinceLastPill is not None: self.GameMinutesSinceLastPill = gameMinutesSinceLastPill + gameMinutes
def _SimulateInternal(self, simulation: ReproductionShared.Simulation, ticks: int, reproductiveTimeMultiplier: float) -> None: simulatingMinutes = ReproductionShared.TicksToReproductiveMinutes( ticks, reproductiveTimeMultiplier) # type: float quickMode = Settings.QuickMode.Get() # type: bool if not self.Fertilized: decaying = False # type: bool if self.Age < self.TimeRemaining <= (self.Age + simulatingMinutes): decaying = True if decaying: #TODO set age first? if self.DecayedCallback is None: Debug.Log( "Missing callback to be triggered on ovum decay.", This.Mod.Namespace, Debug.LogLevels.Warning, group=This.Mod.Namespace, owner=__name__, lockIdentifier=__name__ + ":" + str(Python.GetLineNumber())) else: self.DecayedCallback(self) else: if quickMode: implanting = True # type: bool self.Age = self.ImplantationTime else: implanting = False # type: bool if self.Age < self.TimeUntilImplantation <= ( self.Age + simulatingMinutes): implanting = True if implanting: if self.AttemptImplantationCallback is None: Debug.Log( "Missing callback to be triggered on ovum implantation attempt.", This.Mod.Namespace, Debug.LogLevels.Warning, group=This.Mod.Namespace, owner=__name__, lockIdentifier=__name__ + ":" + str(Python.GetLineNumber())) else: self.AttemptImplantationCallback(self) self.Age += simulatingMinutes
def _SimulateInternal(self, simulation: ReproductionShared.Simulation, ticks: int, reproductiveTimeMultiplier: float) -> None: simulatingMinutes = ReproductionShared.TicksToReproductiveMinutes( ticks, reproductiveTimeMultiplier) # type: float effectGuide = self.EmergencyContraceptivePillEffectGuide # type: CycleGuides.EmergencyContraceptivePillEffectGuide currentStrength = self.Strength # type: float nextStrength = self.Strength # type: float if effectGuide.StrengthPerReproductiveMinute != 0: if effectGuide.StrengthPerReproductiveMinute > 0: if currentStrength != 1: nextStrength += simulatingMinutes * effectGuide.StrengthPerReproductiveMinute else: if currentStrength != 0: nextStrength += simulatingMinutes * effectGuide.StrengthPerReproductiveMinute nextStrength = min(max(nextStrength, 0), 1) self.Strength = nextStrength