frontengine 1.0.6__tar.gz → 1.0.8__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (136) hide show
  1. {frontengine-1.0.6 → frontengine-1.0.8}/PKG-INFO +1 -1
  2. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/show/pet/desktop_pet.py +89 -11
  3. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/user_setting/user_setting_file.py +3 -0
  4. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/utils/multi_language/english.py +3 -1
  5. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/utils/multi_language/traditional_chinese.py +3 -1
  6. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine.egg-info/PKG-INFO +1 -1
  7. {frontengine-1.0.6 → frontengine-1.0.8}/pyproject.toml +1 -1
  8. {frontengine-1.0.6 → frontengine-1.0.8}/LICENSE +0 -0
  9. {frontengine-1.0.6 → frontengine-1.0.8}/README.md +0 -0
  10. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/__init__.py +0 -0
  11. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/__main__.py +0 -0
  12. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/show/__init__.py +0 -0
  13. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/show/base_widget.py +0 -0
  14. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/show/gif/__init__.py +0 -0
  15. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/show/gif/paint_gif.py +0 -0
  16. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/show/image/__init__.py +0 -0
  17. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/show/image/paint_image.py +0 -0
  18. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/show/load/__init__.py +0 -0
  19. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/show/load/load_someone_make_ui.py +0 -0
  20. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/show/overlay_factory.py +0 -0
  21. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/show/particle/__init__.py +0 -0
  22. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/show/particle/particle_ui.py +0 -0
  23. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/show/pet/__init__.py +0 -0
  24. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/show/scene/__init__.py +0 -0
  25. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/show/scene/extend_graphic_scene.py +0 -0
  26. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/show/scene/extend_graphic_view.py +0 -0
  27. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/show/scene/scene.py +0 -0
  28. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/show/sound_player/__init__.py +0 -0
  29. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/show/sound_player/sound_effect.py +0 -0
  30. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/show/sound_player/sound_player.py +0 -0
  31. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/show/text/__init__.py +0 -0
  32. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/show/text/draw_text.py +0 -0
  33. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/show/video/__init__.py +0 -0
  34. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/show/video/video_player.py +0 -0
  35. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/show/web/__init__.py +0 -0
  36. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/show/web/webview.py +0 -0
  37. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/show/window_helpers.py +0 -0
  38. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/system_tray/__init__.py +0 -0
  39. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/system_tray/extend_system_tray.py +0 -0
  40. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/ui/__init__.py +0 -0
  41. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/ui/color/__init__.py +0 -0
  42. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/ui/color/global_color.py +0 -0
  43. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/ui/dialog/__init__.py +0 -0
  44. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/ui/dialog/choose_file_dialog.py +0 -0
  45. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/ui/dialog/hotkey_settings_dialog.py +0 -0
  46. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/ui/dialog/save_file_dialog.py +0 -0
  47. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/ui/main_ui.py +0 -0
  48. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/ui/menu/__init__.py +0 -0
  49. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/ui/menu/help_menu.py +0 -0
  50. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/ui/menu/how_to_menu.py +0 -0
  51. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/ui/menu/language_menu.py +0 -0
  52. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/ui/menu/preset_menu.py +0 -0
  53. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/ui/menu/settings_menu.py +0 -0
  54. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/ui/page/__init__.py +0 -0
  55. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/ui/page/control_center/__init__.py +0 -0
  56. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/ui/page/control_center/control_center_ui.py +0 -0
  57. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/ui/page/gif/__init__.py +0 -0
  58. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/ui/page/gif/gif_setting_ui.py +0 -0
  59. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/ui/page/image/__init__.py +0 -0
  60. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/ui/page/image/image_setting_ui.py +0 -0
  61. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/ui/page/particle/__init__.py +0 -0
  62. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/ui/page/particle/particle_setting_ui.py +0 -0
  63. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/ui/page/pet/__init__.py +0 -0
  64. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/ui/page/pet/pet_setting_ui.py +0 -0
  65. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/ui/page/scene_setting/__init__.py +0 -0
  66. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/ui/page/scene_setting/scene_manager.py +0 -0
  67. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/ui/page/scene_setting/scene_page/__init__.py +0 -0
  68. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/ui/page/scene_setting/scene_page/base_scene_page.py +0 -0
  69. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/ui/page/scene_setting/scene_page/gif.py +0 -0
  70. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/ui/page/scene_setting/scene_page/image.py +0 -0
  71. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/ui/page/scene_setting/scene_page/registry.py +0 -0
  72. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/ui/page/scene_setting/scene_page/sound.py +0 -0
  73. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/ui/page/scene_setting/scene_page/text.py +0 -0
  74. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/ui/page/scene_setting/scene_page/video.py +0 -0
  75. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/ui/page/scene_setting/scene_page/web.py +0 -0
  76. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/ui/page/scene_setting/scene_setting_ui.py +0 -0
  77. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/ui/page/sound_player/__init__.py +0 -0
  78. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/ui/page/sound_player/sound_player_setting_ui.py +0 -0
  79. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/ui/page/text/__init__.py +0 -0
  80. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/ui/page/text/text_setting_ui.py +0 -0
  81. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/ui/page/utils.py +0 -0
  82. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/ui/page/video/__init__.py +0 -0
  83. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/ui/page/video/video_setting_ui.py +0 -0
  84. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/ui/page/web/__init__.py +0 -0
  85. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/ui/page/web/web_setting_ui.py +0 -0
  86. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/user_setting/__init__.py +0 -0
  87. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/user_setting/preset_repository.py +0 -0
  88. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/user_setting/scene_setting.py +0 -0
  89. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/utils/__init__.py +0 -0
  90. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/utils/browser/__init__.py +0 -0
  91. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/utils/browser/browser.py +0 -0
  92. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/utils/critical_exit/__init__.py +0 -0
  93. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/utils/critical_exit/check_key_is_press.py +0 -0
  94. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/utils/critical_exit/critical_exit.py +0 -0
  95. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/utils/critical_exit/win32_vk.py +0 -0
  96. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/utils/exception/__init__.py +0 -0
  97. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/utils/exception/exception_tags.py +0 -0
  98. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/utils/exception/exceptions.py +0 -0
  99. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/utils/file/__init__.py +0 -0
  100. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/utils/file/open/__init__.py +0 -0
  101. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/utils/file/open/open_file.py +0 -0
  102. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/utils/file/save/__init__.py +0 -0
  103. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/utils/file/save/save_file.py +0 -0
  104. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/utils/hotkey/__init__.py +0 -0
  105. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/utils/hotkey/hotkey_service.py +0 -0
  106. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/utils/json/__init__.py +0 -0
  107. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/utils/json/json_file.py +0 -0
  108. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/utils/json/json_repository.py +0 -0
  109. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/utils/json_format/__init__.py +0 -0
  110. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/utils/json_format/json_process.py +0 -0
  111. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/utils/logging/__init__.py +0 -0
  112. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/utils/logging/loggin_instance.py +0 -0
  113. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/utils/multi_language/__init__.py +0 -0
  114. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/utils/multi_language/france.py +0 -0
  115. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/utils/multi_language/germany.py +0 -0
  116. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/utils/multi_language/italy.py +0 -0
  117. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/utils/multi_language/language_wrapper.py +0 -0
  118. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/utils/multi_language/russian.py +0 -0
  119. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/utils/multi_language/simplified_chinese.py +0 -0
  120. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/utils/preset_schedule/__init__.py +0 -0
  121. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/utils/preset_schedule/preset_schedule_service.py +0 -0
  122. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/utils/redirect_manager/__init__.py +0 -0
  123. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/utils/redirect_manager/redirect_manager_class.py +0 -0
  124. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/utils/smart_pause/__init__.py +0 -0
  125. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/utils/smart_pause/smart_pause_service.py +0 -0
  126. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/utils/theme_schedule/__init__.py +0 -0
  127. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/utils/theme_schedule/theme_schedule_service.py +0 -0
  128. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/utils/web_url.py +0 -0
  129. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/worker/__init__.py +0 -0
  130. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine/worker/qthread_worker.py +0 -0
  131. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine.egg-info/SOURCES.txt +0 -0
  132. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine.egg-info/dependency_links.txt +0 -0
  133. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine.egg-info/entry_points.txt +0 -0
  134. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine.egg-info/requires.txt +0 -0
  135. {frontengine-1.0.6 → frontengine-1.0.8}/frontengine.egg-info/top_level.txt +0 -0
  136. {frontengine-1.0.6 → frontengine-1.0.8}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: frontengine
3
- Version: 1.0.6
3
+ Version: 1.0.8
4
4
  Summary: FrontEngine is use-define frontview or only use like screen saver
5
5
  Author-email: JE-Chen <jechenmailman@gmail.com>
6
6
  Project-URL: Homepage, https://github.com/Intergration-Automation-Testing/FrontEngine
@@ -9,6 +9,7 @@ from PySide6.QtWidgets import QMenu, QMessageBox, QWidget
9
9
 
10
10
  from frontengine.show.base_widget import BaseWidget
11
11
  from frontengine.show.window_helpers import apply_overlay_window_flags
12
+ from frontengine.user_setting.user_setting_file import user_setting_dict
12
13
  from frontengine.utils.logging.loggin_instance import front_engine_logger
13
14
  from frontengine.utils.multi_language.language_wrapper import language_wrapper
14
15
 
@@ -26,6 +27,7 @@ SURFACE_RIGHT = "right"
26
27
  # 視覺狀態(決定顯示哪張精靈)/ Visual states (which sprite to show)
27
28
  STATE_WALK = "walk"
28
29
  STATE_IDLE = "idle"
30
+ STATE_SLEEP = "sleep"
29
31
  STATE_CLIMB = "climb"
30
32
  STATE_FALL = "fall"
31
33
  STATE_DRAG = "drag"
@@ -34,13 +36,23 @@ STATE_DRAG = "drag"
34
36
  # Accepted file stems per state inside a pet pack folder (first match wins).
35
37
  _PACK_STATE_ALIASES = {
36
38
  STATE_WALK: ("walk", "run", "move"),
37
- STATE_IDLE: ("idle", "sit", "stand", "sleep"),
39
+ STATE_IDLE: ("idle", "sit", "stand"),
40
+ STATE_SLEEP: ("sleep", "zzz", "rest"),
38
41
  STATE_CLIMB: ("climb", "grab", "wall"),
39
42
  STATE_FALL: ("fall", "jump"),
40
43
  STATE_DRAG: ("drag", "pinch", "grabbed", "held"),
41
44
  }
42
45
  _PACK_EXTS = (".gif", ".webp", ".png", ".jpg", ".jpeg")
43
46
 
47
+ # 缺該狀態精靈時的退回順序 / Fallback order when a state's sprite is missing
48
+ _STATE_FALLBACKS = {
49
+ STATE_SLEEP: (STATE_IDLE, STATE_WALK),
50
+ STATE_IDLE: (STATE_WALK,),
51
+ STATE_CLIMB: (STATE_WALK,),
52
+ STATE_FALL: (STATE_WALK,),
53
+ STATE_DRAG: (STATE_WALK,),
54
+ }
55
+
44
56
 
45
57
  def scan_pet_pack(folder: str) -> dict:
46
58
  """
@@ -76,6 +88,8 @@ def derive_visual_state(dragging: bool, airborne: bool, surface: str, motion_sta
76
88
  return STATE_FALL
77
89
  if surface in (SURFACE_LEFT, SURFACE_RIGHT, SURFACE_CEILING):
78
90
  return STATE_CLIMB
91
+ if surface == SURFACE_FLOOR and motion_state == STATE_SLEEP:
92
+ return STATE_SLEEP
79
93
  if surface == SURFACE_FLOOR and motion_state == "idle":
80
94
  return STATE_IDLE
81
95
  return STATE_WALK
@@ -93,18 +107,56 @@ def message_bucket(hour: int) -> str:
93
107
  return "night"
94
108
 
95
109
 
96
- def pick_message(hour: int, rng, messages: dict) -> str:
110
+ def pick_message(hour: int, rng, messages: dict, mood: Optional[str] = None) -> str:
97
111
  """
98
- 依時段從對應句庫(加上通用句庫)隨機挑一句台詞;句庫皆空回傳空字串。
99
- Pick a chatter line from the time bucket plus the generic pool. rng needs
100
- a ``randrange`` method (injectable for tests).
112
+ 挑一句台詞:先放心情句庫(若有),再放時段句庫、通用句庫。皆空回傳空字串。
113
+ Pick a chatter line: mood pool (if any) first, then the time-of-day pool,
114
+ then the generic pool. rng needs ``randrange``.
101
115
  """
102
- pool = list(messages.get(message_bucket(hour), [])) + list(messages.get("any", []))
116
+ pool = []
117
+ if mood and mood in messages:
118
+ pool += list(messages[mood])
119
+ pool += list(messages.get(message_bucket(hour), []))
120
+ pool += list(messages.get("any", []))
103
121
  if not pool:
104
122
  return ""
105
123
  return pool[rng.randrange(len(pool))]
106
124
 
107
125
 
126
+ class PetMood:
127
+ """
128
+ 寵物心情值 0~100:互動會上升、被忽略會慢慢下降;level() 回傳 happy/content/sad。
129
+ Pet happiness 0..100: petting raises it, neglect decays it; level() buckets it.
130
+ """
131
+
132
+ HAPPY = "happy"
133
+ CONTENT = "content"
134
+ SAD = "sad"
135
+
136
+ def __init__(self, value: int = 60) -> None:
137
+ self.value = self._clamp(value)
138
+
139
+ @staticmethod
140
+ def _clamp(value) -> int:
141
+ try:
142
+ return max(0, min(100, int(value)))
143
+ except (TypeError, ValueError):
144
+ return 60
145
+
146
+ def pet(self, amount: int = 12) -> None:
147
+ self.value = self._clamp(self.value + amount)
148
+
149
+ def decay(self, amount: int = 1) -> None:
150
+ self.value = self._clamp(self.value - amount)
151
+
152
+ def level(self) -> str:
153
+ if self.value >= 70:
154
+ return self.HAPPY
155
+ if self.value <= 30:
156
+ return self.SAD
157
+ return self.CONTENT
158
+
159
+
108
160
  class SpeechBubble(QWidget):
109
161
  """寵物頭上的小對話泡泡,數秒後自動消失 / A small speech bubble that auto-hides."""
110
162
 
@@ -192,8 +244,9 @@ class PetMotion:
192
244
  self.vx = float(self.speed)
193
245
  self.vy = 0.0 if behaviour != BEHAVIOUR_WANDER else float(self.speed)
194
246
  self._airborne = False
195
- self.state = "walk" # walk | idle
247
+ self.state = "walk" # walk | idle | sleep
196
248
  self._state_ticks = 0
249
+ self._idle_count = 0
197
250
  self.target: Optional[Tuple[float, float]] = None
198
251
  self.asleep = False
199
252
  self.climb = bool(climb)
@@ -329,13 +382,25 @@ class PetMotion:
329
382
  def _new_state(self, force_walk: bool = False) -> None:
330
383
  if force_walk or self._rng.random() < 0.65:
331
384
  self.state = "walk"
385
+ self._idle_count = 0
332
386
  if not force_walk:
333
387
  self.vx = float(self.speed) if self._rng.random() < 0.5 else float(-self.speed)
334
388
  self._state_ticks = self._rng.randint(30, 120)
389
+ elif self._idle_count >= 2:
390
+ # been idling a while -> doze off
391
+ self.state = STATE_SLEEP
392
+ self._idle_count = 0
393
+ self._state_ticks = self._rng.randint(120, 300)
335
394
  else:
336
395
  self.state = "idle"
396
+ self._idle_count += 1
337
397
  self._state_ticks = self._rng.randint(20, 80)
338
398
 
399
+ def wake(self) -> None:
400
+ """喚醒寵物並恢復走動(互動時呼叫)/ Wake the pet and resume walking."""
401
+ self._idle_count = 0
402
+ self._new_state(force_walk=True)
403
+
339
404
  # --- free wander ---
340
405
  def _step_wander(self, left, top, right, bottom) -> Tuple[int, int]:
341
406
  if abs(self.vy) < 1e-9:
@@ -419,10 +484,11 @@ class DesktopPetWidget(BaseWidget):
419
484
  self._timer = QTimer(self)
420
485
  self._timer.timeout.connect(self._on_tick)
421
486
 
422
- # Speech bubbles / chatter
487
+ # Speech bubbles / chatter / mood
423
488
  self._talk = bool(talk)
424
489
  self._moved = False
425
490
  self._chatter_rng = _random_module.SystemRandom()
491
+ self._mood = PetMood(user_setting_dict.get("pet_mood", 60))
426
492
  self._messages = self._load_messages()
427
493
  self._bubble = SpeechBubble()
428
494
  self._chatter_timer = QTimer(self)
@@ -461,7 +527,7 @@ class DesktopPetWidget(BaseWidget):
461
527
  return self._sprites["default"]
462
528
  if state in self._sprites:
463
529
  return self._sprites[state]
464
- for fallback in (STATE_WALK, STATE_IDLE):
530
+ for fallback in _STATE_FALLBACKS.get(state, (STATE_WALK,)):
465
531
  if fallback in self._sprites:
466
532
  return self._sprites[fallback]
467
533
  return next(iter(self._sprites.values()), None)
@@ -518,23 +584,32 @@ class DesktopPetWidget(BaseWidget):
518
584
  "afternoon": lines("pet_chatter_afternoon", "Good afternoon!|Taking a break?"),
519
585
  "evening": lines("pet_chatter_evening", "Good evening!|How was your day?"),
520
586
  "night": lines("pet_chatter_night", "It's late - get some rest!|Still up?"),
587
+ "happy": lines("pet_chatter_happy", "I'm so happy!|You're the best!|(^o^)"),
588
+ "sad": lines("pet_chatter_sad", "Feeling a bit lonely...|Pet me?|(._.)"),
521
589
  "any": lines("pet_chatter_any", "Hi there!|(^_^)|Keep going!"),
522
590
  }
523
591
 
592
+ def _persist_mood(self) -> None:
593
+ user_setting_dict["pet_mood"] = self._mood.value
594
+
524
595
  def _schedule_chatter(self) -> None:
525
596
  if self._talk:
526
597
  self._chatter_timer.start(self._chatter_rng.randint(15000, 35000))
527
598
 
528
599
  def _on_chatter(self) -> None:
600
+ self._mood.decay() # a little neglect over time
601
+ self._persist_mood()
529
602
  self.say()
530
603
  self._schedule_chatter()
531
604
 
532
605
  def say(self, text: Optional[str] = None) -> None:
533
- """顯示一句台詞(text 為 None 時依時段隨機挑)。"""
606
+ """顯示一句台詞(text 為 None 時依心情/時段隨機挑)。"""
534
607
  if not self._talk:
535
608
  return
536
609
  if text is None:
537
- text = pick_message(datetime.now().hour, self._chatter_rng, self._messages)
610
+ level = self._mood.level()
611
+ mood = level if level in (PetMood.HAPPY, PetMood.SAD) else None
612
+ text = pick_message(datetime.now().hour, self._chatter_rng, self._messages, mood=mood)
538
613
  if text:
539
614
  self._bubble.show_message(text, self)
540
615
 
@@ -558,6 +633,9 @@ class DesktopPetWidget(BaseWidget):
558
633
  self._moved = False
559
634
  self._last_move_delta = (0, 0)
560
635
  self._drag_offset = event.globalPosition().toPoint() - self.frameGeometry().topLeft()
636
+ self.motion.wake() # interacting wakes a sleeping pet
637
+ self._mood.pet() # petting cheers it up
638
+ self._persist_mood()
561
639
  self._set_active_sprite(STATE_DRAG)
562
640
  super().mousePressEvent(event)
563
641
 
@@ -33,6 +33,9 @@ user_setting_dict: Dict[str, Any] = {
33
33
  # 每天在指定時間自動套用預設集
34
34
  # Auto-apply a preset at a configured time each day
35
35
  "preset_schedule": dict(DEFAULT_PRESET_SCHEDULE),
36
+ # 桌面寵物心情值(0~100),跨工作階段保存
37
+ # Desktop pet mood (0..100), persisted across sessions
38
+ "pet_mood": 60,
36
39
  }
37
40
 
38
41
 
@@ -226,13 +226,15 @@ english_word_dict = {
226
226
  "pet_climb_label": "Climb walls",
227
227
  "pet_clone": "Clone",
228
228
  "pet_choose_pack": "Choose pet pack...",
229
- "pet_pack_empty": "No sprites (walk/idle/climb/fall/drag) found in that folder.",
229
+ "pet_pack_empty": "No sprites (walk/idle/sleep/climb/fall/drag) found in that folder.",
230
230
  "pet_talk_label": "Speech bubbles",
231
231
  "pet_chatter_morning": "Good morning!|Rise and shine!|Ready for the day?",
232
232
  "pet_chatter_afternoon": "Good afternoon!|Taking a break?|Keep it up!",
233
233
  "pet_chatter_evening": "Good evening!|How was your day?|Almost done?",
234
234
  "pet_chatter_night": "It's late - get some rest!|Still up?|Sweet dreams soon~",
235
235
  "pet_chatter_any": "Hi there!|(^_^)|Keep going!|You've got this!",
236
+ "pet_chatter_happy": "I'm so happy!|You're the best!|(^o^)/|Best day ever!",
237
+ "pet_chatter_sad": "Feeling a bit lonely...|Pet me?|(._.)|Don't forget about me~",
236
238
  "pet_start": "Spawn pet",
237
239
  "pet_message_box_text": "Pet image not found",
238
240
  }
@@ -227,13 +227,15 @@ traditional_chinese_word_dict = {
227
227
  "pet_climb_label": "攀爬牆壁",
228
228
  "pet_clone": "複製",
229
229
  "pet_choose_pack": "選擇動作包資料夾...",
230
- "pet_pack_empty": "該資料夾找不到精靈檔(walk/idle/climb/fall/drag)。",
230
+ "pet_pack_empty": "該資料夾找不到精靈檔(walk/idle/sleep/climb/fall/drag)。",
231
231
  "pet_talk_label": "對話泡泡",
232
232
  "pet_chatter_morning": "早安!|新的一天開始囉!|準備好了嗎?",
233
233
  "pet_chatter_afternoon": "午安!|要不要休息一下?|繼續加油!",
234
234
  "pet_chatter_evening": "晚上好!|今天過得如何?|快完成了嗎?",
235
235
  "pet_chatter_night": "很晚了,早點休息!|還沒睡嗎?|祝好夢~",
236
236
  "pet_chatter_any": "嗨!|(^_^)|加油!|你可以的!",
237
+ "pet_chatter_happy": "我好開心!|你最棒了!|(^o^)/|今天真美好!",
238
+ "pet_chatter_sad": "有點寂寞…|摸摸我好嗎?|(._.)|別忘了我~",
237
239
  "pet_start": "召喚寵物",
238
240
  "pet_message_box_text": "找不到寵物圖片",
239
241
  }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: frontengine
3
- Version: 1.0.6
3
+ Version: 1.0.8
4
4
  Summary: FrontEngine is use-define frontview or only use like screen saver
5
5
  Author-email: JE-Chen <jechenmailman@gmail.com>
6
6
  Project-URL: Homepage, https://github.com/Intergration-Automation-Testing/FrontEngine
@@ -6,7 +6,7 @@ build-backend = "setuptools.build_meta"
6
6
 
7
7
  [project]
8
8
  name = "frontengine"
9
- version = "1.0.6"
9
+ version = "1.0.8"
10
10
  authors = [
11
11
  { name = "JE-Chen", email = "jechenmailman@gmail.com" },
12
12
  ]
File without changes
File without changes
File without changes