class AHNagCooldown(Skill):
"""warns when the same input repeats back to back, and if the nagging continues,
removes the logic lobe's regular skills (except defcon skills, which include
this one) for a cooldown period, then restores them (without duplicates) and
resets the repeat counter.
defcon skills are those whose skillNotes("type") returns "defcon"
"""
def __init__(self, brain: Brain, cooldown_minutes=3, warn_at=3, hibernate_at=6):
super().__init__()
self.brain = brain
self.tg: TimeGate = TimeGate(cooldown_minutes)
self.warn_at = max(2, warn_at) # clamp
self.hibernate_at = max(self.warn_at + 1, hibernate_at) # always after the warning
self.hibernating = False
self._removed: list[Skill] = [] # skills taken out during the cooldown
self._last_ear = ""
self._repeat_count = 0
def _normalize(self, ear: str) -> str:
# "Nag!", "nag " and "NAG" all count as the same input
cleaned = "".join(c for c in ear.lower() if c.isalnum() or c.isspace())
return " ".join(cleaned.split())
def _count_repeats(self, ear: str) -> int:
# consecutive repeats of the same input, empty input is ignored
if not isinstance(ear, str):
return self._repeat_count
text = self._normalize(ear)
if text == "":
return self._repeat_count
if text == self._last_ear:
self._repeat_count += 1
else:
self._last_ear = text
self._repeat_count = 1
return self._repeat_count
def _reset_counter(self):
self._last_ear = ""
self._repeat_count = 0
def input(self, ear: str, skin: str, eye: str):
if not self.hibernating:
count = self._count_repeats(ear)
if count >= self.hibernate_at:
# ===================== HIBERNATION STARTS HERE =====================
# snapshot the logic lobe's regular skills, minus defcon skills (incl. me)
self._removed = [s for s in list(self.brain.logicLobe.dClasses)
if s.skillNotes("type") != "defcon"]
self.hibernating = True
self._reset_counter()
self.tg.openForPauseMinutes()
# announce first, then remove the skills
self.algPartsFusion(4,
APVerbatim("I'm hibernating now, talk to you later"),
APSkillsRemover(self.brain, *self._removed))
# ===================================================================
elif count == self.warn_at:
# tier 1: warning, fires once at the threshold, nothing is removed
self.setSimpleAlg("stop repeating yourself")
else:
if self.tg.isClosed():
# ===================== HIBERNATION ENDS HERE =======================
self.hibernating = False
self._reset_counter() # back to square one
# clear throat, then put the skills back (skipping ones already present)
self.algPartsFusion(4,
APVerbatim("ahem"),
APAddUniqueSkills(self.brain, *self._removed))
self._removed = []
# ===================================================================
def skillNotes(self, param: str) -> str:
if param == "type":
return "defcon"
elif param == "notes":
return "warns on repeated input, then hibernates other skills for a cooldown"
elif param == "triggers":
return "repeat the same input back to back"
return "note unavailable"