Exemple #1
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)
Exemple #2
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)
Exemple #3
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
Exemple #4
0
    def _PrepareForSimulation(
            self, simulation: ReproductionShared.Simulation) -> None:
        super()._PrepareForSimulation(simulation)

        simulation.RegisterPhase(
            ReproductionShared.SimulationPhase(
                30, self._PregnancyCachedTestSimulationPhase))

        simulation.RegisterPhase(
            ReproductionShared.SimulationPhase(
                -30, self._PregnancyVisualsSimulationPhase))
Exemple #5
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
Exemple #6
0
    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
Exemple #7
0
def GetSpermTrackerReproductiveTimeMultiplier() -> float:
    multiplier = ReproductionShared.GetGeneralReproductiveTimeMultiplier()

    if multiplier < SpermQuickModeMinimumTimeMultiplier:
        multiplier = SpermQuickModeMinimumTimeMultiplier

    return multiplier
Exemple #8
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
Exemple #9
0
    def _PrepareForSimulation(
            self, simulation: ReproductionShared.Simulation) -> None:
        super()._PrepareForSimulation(simulation)

        simulation.RegisterPhase(
            ReproductionShared.SimulationPhase(-15,
                                               self._HandlerSimulationPhase))
Exemple #10
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)
Exemple #11
0
    def _PlanSimulation(self,
                        simulation: ReproductionShared.Simulation) -> None:
        if self._cachedPregnancyTestGameMinutesRemaining is not None:
            ticksUntilPregnancyTestCacheReset = ReproductionShared.GameMinutesToTicks(
                self._cachedPregnancyTestGameMinutesRemaining)

            if simulation.RemainingTicks >= ticksUntilPregnancyTestCacheReset:
                simulation.Schedule.AddPoint(ticksUntilPregnancyTestCacheReset)
Exemple #12
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)
Exemple #13
0
    def _PregnancyCachedTestSimulationPhase(
            self, simulation: ReproductionShared.Simulation,
            ticks: int) -> None:
        simulatingGameMinutes = ReproductionShared.TicksToGameMinutes(
            ticks)  # type: float

        if self._cachedPregnancyTestGameMinutesRemaining is not None:
            self._cachedPregnancyTestGameMinutesRemaining -= simulatingGameMinutes

            if self._cachedPregnancyTestGameMinutesRemaining <= 0:
                self._ResetCachedPregnancyTestResults()
Exemple #14
0
    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
Exemple #15
0
def InitiateReproductiveSystem(
        simInfo: sim_info.SimInfo) -> ReproductionShared.ReproductiveSystem:
    """
	Create a blank reproductive system for this sim. If one already exists the existing one will be returned as opposed of creating a new one.
	:param simInfo: The target sim's info.
	:type simInfo: sim_info.SimInfo
	"""

    if not isinstance(simInfo, sim_info.SimInfo):
        raise Exceptions.IncorrectTypeException(simInfo, "simInfo",
                                                (sim_info.SimInfo, ))

    if SimHasSystem(simInfo):
        return GetSimSystem(simInfo)

    simReproductiveSystem = ReproductionShared.ReproductiveSystem(simInfo)
    RegisterReproductiveSystem(simReproductiveSystem)

    return simReproductiveSystem
Exemple #16
0
	def _SimulateInternal (self, simulation: ReproductionShared.Simulation, ticks: int, reproductiveTimeMultiplier: float) -> None:
		simulatingGameMinutes = ReproductionShared.TicksToGameMinutes(ticks)  # type: float

		if self.BuffCoolDown is not None:
			self.BuffCoolDown -= simulatingGameMinutes

			if self.BuffCoolDown <= 0:
				self.BuffCoolDown = None

		if self.BuffCoolDown is not None and self.BuffCoolDown > 0:
			return

		if not self.AffectingSystem.SimInfo.is_instanced():
			return  # The game doesn't appear to allow us to add the buffs to non-instanced sims.

		if not simulation.LastTickStep:
			return

		cycleTracker = self.AffectingSystem.GetTracker(FemalesShared.CycleTrackerIdentifier)  # type: typing.Optional[CycleTracker.CycleTracker]

		if cycleTracker is None:
			return

		currentCycle = cycleTracker.CurrentCycle  # type: typing.Optional[CycleMenstrual.MenstrualCycle]

		if currentCycle is None:
			return

		if currentCycle.TypeIdentifier != CycleShared.MenstrualCycleTypeIdentifier:
			return

		buffSelectionTesting = self.DoBuffSelectionTesting()  # type: CycleEvents.MenstrualEffectBuffSelectionTestingArguments
		selectedBuffType, hadValidSelections = buffSelectionTesting.SelectAppropriateBuff(currentCycle)  # type: typing.Optional[typing.Type[BuffsMenstrual.MenstrualBuffBase]], bool

		if not hadValidSelections:
			return

		if selectedBuffType is None:
			self.ApplyBuffAbstainedEffects()
			return

		self.AffectingSystem.SimInfo.Buffs.add_buff_from_op(selectedBuffType, BuffsShared.ReproductiveSystemBuffReason.GetLocalizationString())
    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
Exemple #18
0
	def _PlanUpdateCallback (self, owner, eventArguments: CycleEvents.PlanUpdateArguments) -> None:
		if not self.AffectingSystem.SimInfo.is_instanced():
			return  # The game doesn't appear to allow us to add the buffs to non-instanced sims.

		cycleTracker = self.AffectingSystem.GetTracker(FemalesShared.CycleTrackerIdentifier)  # type: typing.Optional[CycleTracker.CycleTracker]

		if cycleTracker is None:
			return

		if cycleTracker.CurrentCycle is None:
			return

		currentCycle = cycleTracker.CurrentCycle  # type: typing.Optional[CycleMenstrual.MenstrualCycle]

		if currentCycle.TypeIdentifier != CycleShared.MenstrualCycleTypeIdentifier:
			return

		if self.BuffCoolDown is not None and self.BuffCoolDown > 0:
			eventArguments.RequestTick(ReproductionShared.GameMinutesToTicks(self.BuffCoolDown))
			return

		soonestBuffValidTick = None  # type: typing.Optional[int]

		for menstrualBuff in BuffsMenstrual.GetAllMenstrualBuffs():  # type: BuffsMenstrual.MenstrualBuffBase
			ticksUntilBuffValid = menstrualBuff.CyclePhaseTest.TicksUntilValidPhase(currentCycle, cycleTracker.ReproductiveTimeMultiplier)  # type: int

			if ticksUntilBuffValid is None:
				continue

			if soonestBuffValidTick is None or soonestBuffValidTick > ticksUntilBuffValid:
				soonestBuffValidTick = ticksUntilBuffValid

		if soonestBuffValidTick is None or soonestBuffValidTick <= 0:
			return

		eventArguments.RequestTick(soonestBuffValidTick)
def _GetPregnancyRate() -> float:
    reproductiveTimeMultiplier = Settings.PregnancySpeed.Get()  # type: float

    pregnancyGuide = CycleGuides.HumanPregnancyGuide.Guide  # type: CycleGuides.PregnancyGuide

    pregnancyTime = pregnancyGuide.PregnancyTime  # type: float
    pregnancyGameTime = ReproductionShared.ReproductiveMinutesToGameMinutes(
        pregnancyTime, reproductiveTimeMultiplier)  # type: float

    if pregnancyGameTime != 0:
        pregnancyRate = 100 / pregnancyGameTime  # type: float
    else:
        Debug.Log(
            "Calculated a pregnancy game time to be 0 minutes, this is probably not intentional.",
            This.Mod.Namespace,
            Debug.LogLevels.Warning,
            group=This.Mod.Namespace,
            owner=__name__,
            lockIdentifier=__name__ + ":" + str(Python.GetLineNumber()),
            lockThreshold=1)

        pregnancyRate = 0

    return pregnancyRate
Exemple #20
0
def GetSpermProductionTrackerReproductiveTimeMultiplier() -> float:
    return ReproductionShared.GetGeneralReproductiveTimeMultiplier()
Exemple #21
0
def GetHandlerTrackerReproductiveTimeMultiplier() -> float:
    return ReproductionShared.GetGeneralReproductiveTimeMultiplier()
Exemple #22
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)
Exemple #23
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)
Exemple #24
0
class DotInformation(Savable.SavableExtension):
	HostNamespace = This.Mod.Namespace

	MinimumTicksBeforeOvulationToNotify = ReproductionShared.GameMinutesToTicks(date_and_time.MINUTES_PER_HOUR * 8)

	def __init__ (self, targetSimInfoOrID: typing.Union[sim_info.SimInfo, int, None]):
		"""
		An object to save information for and handle interactions with the dot menstrual cycle tracker app.
		"""

		if not isinstance(targetSimInfoOrID, (sim_info.SimInfo, int)) and targetSimInfoOrID is not None:
			raise Exceptions.IncorrectTypeException(targetSimInfoOrID, "targetSimInfoOrID", (sim_info.SimInfo, int, None))

		super().__init__()

		self._targetSimPointer = SimPointer.SimPointer()
		self._targetSimPointer.ChangePointer(targetSimInfoOrID)

		self._simulating = False  # type: bool

		self.Enabled = False
		self.TrackingMode = TrackingMode.Cycle
		self.ShowFertilityNotifications = False

		self.TimeSinceCycleStart = None

		self.LastSimulatedTick = services.time_service().sim_now.absolute_ticks()

		encodeEnum = lambda value: value.name if value is not None else None
		decodeTrackingMode = lambda valueString: Parse.ParsePythonEnum(valueString, TrackingMode)

		self.RegisterSavableAttribute(Savable.StandardAttributeHandler("Enabled", "Enabled", self.Enabled))
		self.RegisterSavableAttribute(Savable.StandardAttributeHandler("TrackingMode", "TrackingMode", self.TrackingMode, encoder = encodeEnum, decoder = decodeTrackingMode))
		self.RegisterSavableAttribute(Savable.StandardAttributeHandler("ShowFertilityNotifications", "ShowFertilityNotifications", self.ShowFertilityNotifications))
		self.RegisterSavableAttribute(Savable.StandardAttributeHandler("TimeSinceCycleStart", "TimeSinceCycleStart", self.TimeSinceCycleStart))

	@property
	def SavableOperationInformation (self) -> str:
		return self.DebugInformation

	@property
	def DebugInformation (self) -> str:
		return "%s | Section Key: %s | Sim ID: %s | Sim: %s" % \
			   (self.__class__.__name__,
				DotSavingKey,
				self.TargetSimInfo.id,
				ToolsSims.GetFullName(self.TargetSimInfo))

	@property
	def TargetSimInfo (self) -> typing.Optional[sim_info.SimInfo]:
		"""
		The sim that this dot object is handling.
		"""

		return self._targetSimPointer.GetSim()

	@property
	def TargetSimID (self) -> typing.Optional[int]:
		"""
		The id of the sim that this dot object is handling.
		"""

		return self._targetSimPointer.SimID

	@property
	def Enabled (self) -> bool:
		"""
		Whether or not the dot app is installed on the target sim's phone.
		"""

		return self._enabled

	@Enabled.setter
	def Enabled (self, value: bool) -> None:
		if not isinstance(value, bool):
			raise Exceptions.IncorrectTypeException(value, "Enabled", (bool,))

		self._enabled = value

	@property
	def TrackingMode (self) -> TrackingMode:
		"""
		Whether the app is currently tracking the target sim's menstrual cycle or pregnancy.
		"""

		return self._trackingMode

	@TrackingMode.setter
	def TrackingMode (self, value: TrackingMode) -> None:
		if not isinstance(value, TrackingMode):
			raise Exceptions.IncorrectTypeException(value, "TrackingMode", (TrackingMode,))

		self._trackingMode = value

	@property
	def ShowFertilityNotifications (self) -> bool:
		"""
		Whether or not the app should notify the player when the target sim is about to become fertile.
		"""

		return self._showFertilityNotifications

	@ShowFertilityNotifications.setter
	def ShowFertilityNotifications (self, value: bool) -> None:
		if not isinstance(value, bool):
			raise Exceptions.IncorrectTypeException(value, "ShowFertilityNotifications", (bool,))

		self._showFertilityNotifications = value

	@property
	def TimeSinceCycleStart (self) -> typing.Optional[float]:
		"""
		The time in reproductive minutes since the target sim's last known cycle start.
		"""

		return self._timeSinceCycleStart

	@TimeSinceCycleStart.setter
	def TimeSinceCycleStart (self, value: typing.Optional[float]) -> None:
		if not isinstance(value, (float, int)) and value is not None:
			raise Exceptions.IncorrectTypeException(value, "TimeSinceCycleStart", (float, int, None))

		self._timeSinceCycleStart = value

	@property
	def LastSimulatedTick (self) -> int:
		"""
		The tick this dot information was last simulated to. This value isn't saved, when the dot information is first creating it is assumed the it was
		simulated up to now. All dot information objects should be updated before being saved to prevent missed time.
		"""

		return self._lastSimulatedTick

	@LastSimulatedTick.setter
	def LastSimulatedTick (self, value: int) -> None:
		if not isinstance(value, int):
			raise Exceptions.IncorrectTypeException(value, "LastSimulatedTick", (int,))

		self._lastSimulatedTick = value

	@property
	def TicksBehind (self) -> int:
		"""
		The number of game ticks the information object is behind the current game tick.
		"""

		timeService = services.time_service()  # type: time_service.TimeService
		return max(timeService.sim_now.absolute_ticks() - self.LastSimulatedTick, 0)

	@property
	def Simulating (self) -> bool:
		"""
		Whether or not this reproductive system is currently in the process of simulating time.
		"""

		return self._simulating

	@property
	def Outdated (self) -> bool:
		"""
		Whether or not this dot information has been updated all the way to the latest tick. If the game's time service is not available this will return False.
		"""

		if game_services.service_manager is None:
			return False

		timeService = services.time_service()  # type: time_service.TimeService

		return self.LastSimulatedTick < timeService.sim_now.absolute_ticks()

	@property
	def ShouldUpdate (self) -> bool:
		"""
		Whether or not this reproductive system should be updated. This value will be True if this object is outdated and is not already simulating.
		"""

		return self.Outdated and not self.Simulating

	def Load (self, simsSection: SectionBranched.SectionBranched) -> bool:
		"""
		Load the reproductive system's data from this saving section. An exception will be raised if no valid sim has been set for this dot object.
		"""

		if self.TargetSimID is None or self.TargetSimInfo is None:
			raise Exception("Cannot load a dot information object with no target sim.")

		if not isinstance(simsSection, SectionBranched.SectionBranched):
			raise Exceptions.IncorrectTypeException(simsSection, "simsSection", (SectionBranched.SectionBranched,))

		operationInformation = self.SavableOperationInformation  # type: str
		operationSuccessful = True  # type: bool

		try:
			targetSimSavingKey = Saving.GetSimSimsSectionBranchKey(self.TargetSimInfo)  # type: str

			dotInformationData = simsSection.GetValue(targetSimSavingKey, DotSavingKey, default = None)

			if dotInformationData is None:
				Debug.Log("'%s' has had a dot information object created for the first time, or at least, they had no saved data in the loaded save file.\n%s" % (ToolsSims.GetFullName(self.TargetSimInfo), operationInformation), self.HostNamespace, Debug.LogLevels.Info, group = self.HostNamespace, owner = __name__)
				dotInformationData = dict()

			if not isinstance(dotInformationData, dict):
				Debug.Log("Incorrect type in dot information data with the section key.\n" + operationInformation + "\n" + Exceptions.GetIncorrectTypeExceptionText(dotInformationData, "DotInformationData", (dict,)), self.HostNamespace, Debug.LogLevels.Warning, group = self.HostNamespace, owner = __name__)
				dotInformationData = dict()
				operationSuccessful = False

			if simsSection.SavingObject.DataHostVersion is not None:
				lastVersion = Version.Version(simsSection.SavingObject.DataHostVersion)  # type: typing.Optional[Version.Version]
			else:
				lastVersion = None  # type: typing.Optional[Version.Version]

			loadSuccessful = self.LoadFromDictionary(dotInformationData, lastVersion = lastVersion)
		except:
			Debug.Log("Load operation in a dot information object aborted.\n" + operationInformation, self.HostNamespace, Debug.LogLevels.Exception, group = self.HostNamespace, owner = __name__)
			self.Reset()
			return False

		if not loadSuccessful:
			return False

		return operationSuccessful

	def Save (self, simsSection: SectionBranched.SectionBranched) -> bool:
		"""
		Save the reproductive system's data to this saving section. An exception will be raised if no valid sim has been set for this dot object.
		"""

		if self.TargetSimID is None or self.TargetSimInfo is None:
			raise Exception("Cannot save a dot information object with no target sim.")

		if not isinstance(simsSection, SectionBranched.SectionBranched):
			raise Exceptions.IncorrectTypeException(simsSection, "simsSection", (SectionBranched.SectionBranched,))

		if self.Outdated:
			self.Update()

		operationInformation = self.SavableOperationInformation  # type: str
		operationSuccessful = True  # type: bool

		try:
			targetSimSavingKey = Saving.GetSimSimsSectionBranchKey(self.TargetSimInfo)  # type: str

			saveSuccessful, dotInformationData = self.SaveToDictionary()  # type: bool, dict
			simsSection.Set(targetSimSavingKey, DotSavingKey, dotInformationData)
		except:
			Debug.Log("Save operation in a dot information object aborted.\n" + operationInformation, self.HostNamespace, Debug.LogLevels.Exception, group = self.HostNamespace, owner = __name__)
			return False

		if not saveSuccessful:
			return False

		return operationSuccessful

	def Update (self) -> None:
		"""
		Update this dot app information to the most recent tick.
		"""

		if game_services.service_manager is None:
			return

		if not self.Outdated:
			return

		ticksBehind = self.TicksBehind

		if ticksBehind <= 0:
			return

		self.Simulate(ticksBehind)

	def Simulate (self, ticks: int) -> None:
		"""
		Simulate this many ticks for this dot app information. This method could allow you to simulate time that hasn't actually passed. The dot app information
		should be simulated every time the target sim's reproductive system simulates.
		:param ticks: The number of ticks to simulate.
		:type ticks: int
		"""

		if not isinstance(ticks, int):
			raise Exceptions.IncorrectTypeException(ticks, "ticks", (int,))

		self._simulating = True
		self._SimulateInternal(ticks)
		self._simulating = False

		timeService = services.time_service()  # type: time_service.TimeService
		currentTick = timeService.sim_now.absolute_ticks()  # type: int

		self.LastSimulatedTick = min(self.LastSimulatedTick + ticks, currentTick)

	def GetCurrentCycle (self) -> typing.Optional[DotCycle]:
		"""
		Get information about the current cycle, according to the dot app. This will be none if the app is not tracking the cycle, the target sim does not exist,
		the target sim cannot menstruate, or we don't know when the last menstrual cycle occurred.
		"""

		if self.TrackingMode != TrackingMode.Cycle:
			return None

		if self.TimeSinceCycleStart is None:
			return None

		return self._GetCycle(self.TimeSinceCycleStart)

	def GetCurrentCycleAge (self) -> typing.Optional[float]:
		"""
		Get the age of the target sim's current cycle in game minutes, according to the dot app. This will be none if the app is not tracking the cycle,
		the target sim does not exist, the target sim cannot menstruate, or we don't know when the last menstrual cycle occurred.
		"""

		if self.TrackingMode != TrackingMode.Cycle:
			return None

		if self.TimeSinceCycleStart is None:
			return None

		return self._GetCycleAge(self.TimeSinceCycleStart)

	def SetCycleStart (self, minutesSince: float) -> None:
		"""
		Set the suspected start of the target's cycle.
		:param minutesSince: The number of reproductive minutes since the cycle started.
		:type minutesSince: float
		"""

		if not isinstance(minutesSince, (float, int)):
			raise Exceptions.IncorrectTypeException(minutesSince, "minutesSince", (float, int))

		self.TimeSinceCycleStart = minutesSince

	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 _GetCycle (self, reproductiveTimeSinceCycleStart: float) -> DotCycle:
		cycleInformation = DotCycle()
		currentCycleAge = self._GetCycleAge(reproductiveTimeSinceCycleStart)  # type: typing.Optional[float]

		assert currentCycleAge is not None

		cycleInformation.Age = currentCycleAge
		return cycleInformation

	def _GetCycleAge (self, reproductiveTimeSinceCycleStart: float) -> float: # Time in game minutes
		gameTimeSinceCycleStart = ReproductionShared.ReproductiveMinutesToGameMinutes(reproductiveTimeSinceCycleStart, _GetCycleReproductiveTimeMultiplier())  # type: float
		return gameTimeSinceCycleStart % _GetMenstrualCycleLifetime()
Exemple #25
0
def _GetSpermHalfLifeTime () -> float:
	reproductiveTimeMultiplier = _GetSpermReproductiveTimeMultiplier()  # type: float
	spermGuide = _GetSpermGuide()  # type: CycleGuides.SpermGuide
	return ReproductionShared.ReproductiveMinutesToGameMinutes(spermGuide.LifetimeDistributionMean.Mean, reproductiveTimeMultiplier)
Exemple #26
0
def _GetMenstrualCycleMenstruationLength () -> float:
	reproductiveTimeMultiplier = _GetCycleReproductiveTimeMultiplier()  # type: float
	menstrualCycleGuide = _GetMenstrualCycleGuide()  # type: CycleGuides.CycleMenstrualGuide
	return ReproductionShared.ReproductiveMinutesToGameMinutes(menstrualCycleGuide.MenstruationLength.Mean, reproductiveTimeMultiplier)
Exemple #27
0
	def _GetCycleAge (self, reproductiveTimeSinceCycleStart: float) -> float: # Time in game minutes
		gameTimeSinceCycleStart = ReproductionShared.ReproductiveMinutesToGameMinutes(reproductiveTimeSinceCycleStart, _GetCycleReproductiveTimeMultiplier())  # type: float
		return gameTimeSinceCycleStart % _GetMenstrualCycleLifetime()