Example #1
0
	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)
Example #2
0
    def _PlanSimulationInternal(self,
                                simulation: ReproductionShared.Simulation,
                                reproductiveTimeMultiplier: float) -> None:
        quickMode = Settings.QuickMode.Get()  # type: bool

        if not self.Fertilized:
            decayTick = ReproductionShared.ReproductiveMinutesToTicks(
                self.TimeRemaining, reproductiveTimeMultiplier)  # type: int

            if decayTick <= 0:
                decayTick = 1

            if simulation.RemainingTicks >= decayTick:
                simulation.Schedule.AddPoint(decayTick)
        else:
            if quickMode:
                if simulation.RemainingTicks >= 1:
                    simulation.Schedule.AddPoint(1)
            else:
                implantationTick = ReproductionShared.ReproductiveMinutesToTicks(
                    self.TimeUntilImplantation,
                    reproductiveTimeMultiplier)  # type: int

                if simulation.RemainingTicks >= implantationTick:
                    simulation.Schedule.AddPoint(implantationTick)
Example #3
0
	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
Example #4
0
	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
Example #5
0
	def _PlanSimulation (self, simulation: ReproductionShared.Simulation) -> None:
		super()._PlanSimulation(simulation)

		reproductiveTimeMultiplier = self.ReproductiveTimeMultiplier  # type: typing.Union[float, int]

		simulationMemory = CycleTrackerSimulationMemory()  # type: CycleTrackerSimulationMemory

		if self.CurrentCycle is None:
			cycleStartTesting = self.DoCycleStartTesting()  # type: CycleEvents.CycleStartTestingArguments

			if cycleStartTesting.GetCanStart():
				timeUntilCycleStart = 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 simulation.RemainingTicks >= ticksUntilCycleStart:
					simulation.Schedule.AddPoint(ticksUntilCycleStart)

			simulationMemory.CycleStartTesting = cycleStartTesting
		else:
			self.CurrentCycle.PlanSimulation(simulation, reproductiveTimeMultiplier)

		simulation.Memory[self.SimulationMemoryKey] = simulationMemory
Example #6
0
	def _PlanSimulationInternal (self, simulation: ReproductionShared.Simulation, reproductiveTimeMultiplier: typing.Union[float, int]) -> None:
		decayTick = ReproductionShared.ReproductiveMinutesToTicks(self.TimeRemaining, reproductiveTimeMultiplier)  # type: int

		if decayTick <= 0:
			decayTick = 1

		if simulation.RemainingTicks >= decayTick:
			simulation.Schedule.AddPoint(decayTick)
Example #7
0
	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)
Example #8
0
    def TicksUntilValidPhase(
            self, testingCycle: CycleMenstrual.MenstrualCycle,
            reproductiveTimeMultiplier: float) -> typing.Optional[int]:
        """
		Get the number of game ticks until the input cycle reaches a valid phase. This will return none if the cycle will never enter a valid phase.
		:param testingCycle: The menstrual cycle to find valid phases for.
		:type testingCycle: CycleMenstrual.MenstrualCycle
		:param reproductiveTimeMultiplier: The reproductive time multiplier used to simulate the testing cycle
		:type reproductiveTimeMultiplier: float
		"""

        if not isinstance(testingCycle, CycleMenstrual.MenstrualCycle):
            raise Exceptions.IncorrectTypeException(
                testingCycle, "testingCycle",
                (CycleMenstrual.MenstrualCycle, ))

        if len(self.PhaseStates) == 0:
            return 0

        hasWhitelistedPhase = False  # type: bool

        whitelistedTimes = list(
        )  # type: typing.List[typing.Tuple[float, float]]
        blacklistedTimes = list(
        )  # type: typing.List[typing.Tuple[float, float]]

        for phaseState in self.PhaseStates:
            if phaseState.MatchType == CyclePhaseTest.PhaseState.MatchTypes.Whitelist:
                hasWhitelistedPhase = True

            if testingCycle.GetPhaseCompleted(phaseState.Phase):
                continue

            timeUntilPhaseStart = testingCycle.GetTimeUntilPhaseStarts(
                phaseState.Phase)  # type: float
            timeUntilPhaseEnd = testingCycle.GetTimeUntilPhaseEnds(
                phaseState.Phase)  # type: float

            if timeUntilPhaseEnd < 0:
                Debug.Log(
                    "A menstrual cycle indicated a phase was not complete, but its end time was %s minutes ago. Phase: %s"
                    % (str(timeUntilPhaseEnd), str(phaseState.Phase)),
                    This.Mod.Namespace,
                    Debug.LogLevels.Warning,
                    group=This.Mod.Namespace,
                    owner=__name__,
                    lockIdentifier=__name__ + ":" +
                    str(Python.GetLineNumber()))
                continue

            phaseLength = timeUntilPhaseEnd - timeUntilPhaseStart  # type: float

            if phaseLength <= 0:
                Debug.Log(
                    "Calculated a menstrual cycle phase length as less than or equal to 0. Phase: %s"
                    % str(phaseState.Phase),
                    This.Mod.Namespace,
                    Debug.LogLevels.Warning,
                    group=This.Mod.Namespace,
                    owner=__name__,
                    lockIdentifier=__name__ + ":" +
                    str(Python.GetLineNumber()))
                continue

            if phaseState.StartCompletion is None:
                listedStartTime = timeUntilPhaseStart
            else:
                listedStartTime = timeUntilPhaseStart + phaseLength * phaseState.StartCompletion

            if phaseState.EndCompletion is None:
                listedEndTime = timeUntilPhaseEnd
            else:
                listedEndTime = timeUntilPhaseStart + phaseLength * phaseState.EndCompletion

            if phaseState.MatchType == CyclePhaseTest.PhaseState.MatchTypes.Whitelist:
                whitelistedTimes.append((listedStartTime, listedEndTime))
            elif phaseState.MatchType == CyclePhaseTest.PhaseState.MatchTypes.Blacklist:
                blacklistedTimes.append((listedStartTime, listedEndTime))

        soonestValidTime = None  # type: typing.Optional[float]

        def setTimeIfSooner(testingValidTime: float) -> None:
            nonlocal soonestValidTime

            if soonestValidTime is None:
                soonestValidTime = testingValidTime

            if soonestValidTime < testingValidTime:
                soonestValidTime = testingValidTime

        if hasWhitelistedPhase:
            for whitelistedStartTime, whitelistedEndTime in whitelistedTimes:  # type: float, float
                if soonestValidTime is not None and whitelistedStartTime >= soonestValidTime:
                    continue

                validTime = whitelistedStartTime  # type: float

                intervalBlacklisted = False  # type: bool
                for blackListedStartTime, blackListedEndTime in blacklistedTimes:  # type: float, float
                    if blackListedStartTime <= validTime and blackListedEndTime >= whitelistedEndTime:
                        intervalBlacklisted = True
                        break

                    if blackListedStartTime <= validTime:
                        validTime = blackListedEndTime

                if not intervalBlacklisted:
                    setTimeIfSooner(max(validTime, 0.0))

                if soonestValidTime == 0:
                    break
        else:
            for blackListedStartTime, blackListedEndTime in blacklistedTimes:  # type: float, float
                if soonestValidTime is not None and blackListedEndTime >= soonestValidTime:
                    continue

                blacklistContinues = False  # type: bool
                for otherBlackListedStartTime, otherBlackListedEndTime in blacklistedTimes:  # type: float, float
                    if otherBlackListedStartTime <= blackListedEndTime < otherBlackListedEndTime:
                        blacklistContinues = True
                        pass

                if not blacklistContinues:
                    setTimeIfSooner(max(blackListedEndTime, 0.0))

                if soonestValidTime == 0:
                    break

        if soonestValidTime is None:
            return None
        else:
            return ReproductionShared.ReproductiveMinutesToTicks(
                soonestValidTime, reproductiveTimeMultiplier)
Example #9
0
	def TicksSinceLastCycle (self) -> typing.Union[float, int, None]:
		"""
		The amount of game ticks since the last cycle ended. This will be None if the sim has not had a cycle yet.
		"""

		return ReproductionShared.ReproductiveMinutesToTicks(self.TimeSinceLastCycle, self.ReproductiveTimeMultiplier)