frontengine 1.0.10__tar.gz → 1.0.12__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.10 → frontengine-1.0.12}/PKG-INFO +1 -1
  2. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/show/pet/desktop_pet.py +102 -0
  3. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/ui/page/pet/pet_setting_ui.py +13 -0
  4. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/utils/multi_language/english.py +1 -0
  5. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/utils/multi_language/traditional_chinese.py +1 -0
  6. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine.egg-info/PKG-INFO +1 -1
  7. {frontengine-1.0.10 → frontengine-1.0.12}/pyproject.toml +1 -1
  8. {frontengine-1.0.10 → frontengine-1.0.12}/LICENSE +0 -0
  9. {frontengine-1.0.10 → frontengine-1.0.12}/README.md +0 -0
  10. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/__init__.py +0 -0
  11. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/__main__.py +0 -0
  12. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/show/__init__.py +0 -0
  13. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/show/base_widget.py +0 -0
  14. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/show/gif/__init__.py +0 -0
  15. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/show/gif/paint_gif.py +0 -0
  16. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/show/image/__init__.py +0 -0
  17. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/show/image/paint_image.py +0 -0
  18. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/show/load/__init__.py +0 -0
  19. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/show/load/load_someone_make_ui.py +0 -0
  20. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/show/overlay_factory.py +0 -0
  21. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/show/particle/__init__.py +0 -0
  22. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/show/particle/particle_ui.py +0 -0
  23. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/show/pet/__init__.py +0 -0
  24. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/show/scene/__init__.py +0 -0
  25. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/show/scene/extend_graphic_scene.py +0 -0
  26. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/show/scene/extend_graphic_view.py +0 -0
  27. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/show/scene/scene.py +0 -0
  28. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/show/sound_player/__init__.py +0 -0
  29. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/show/sound_player/sound_effect.py +0 -0
  30. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/show/sound_player/sound_player.py +0 -0
  31. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/show/text/__init__.py +0 -0
  32. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/show/text/draw_text.py +0 -0
  33. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/show/video/__init__.py +0 -0
  34. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/show/video/video_player.py +0 -0
  35. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/show/web/__init__.py +0 -0
  36. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/show/web/webview.py +0 -0
  37. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/show/window_helpers.py +0 -0
  38. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/system_tray/__init__.py +0 -0
  39. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/system_tray/extend_system_tray.py +0 -0
  40. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/ui/__init__.py +0 -0
  41. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/ui/color/__init__.py +0 -0
  42. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/ui/color/global_color.py +0 -0
  43. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/ui/dialog/__init__.py +0 -0
  44. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/ui/dialog/choose_file_dialog.py +0 -0
  45. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/ui/dialog/hotkey_settings_dialog.py +0 -0
  46. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/ui/dialog/save_file_dialog.py +0 -0
  47. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/ui/main_ui.py +0 -0
  48. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/ui/menu/__init__.py +0 -0
  49. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/ui/menu/help_menu.py +0 -0
  50. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/ui/menu/how_to_menu.py +0 -0
  51. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/ui/menu/language_menu.py +0 -0
  52. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/ui/menu/preset_menu.py +0 -0
  53. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/ui/menu/settings_menu.py +0 -0
  54. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/ui/page/__init__.py +0 -0
  55. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/ui/page/control_center/__init__.py +0 -0
  56. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/ui/page/control_center/control_center_ui.py +0 -0
  57. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/ui/page/gif/__init__.py +0 -0
  58. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/ui/page/gif/gif_setting_ui.py +0 -0
  59. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/ui/page/image/__init__.py +0 -0
  60. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/ui/page/image/image_setting_ui.py +0 -0
  61. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/ui/page/particle/__init__.py +0 -0
  62. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/ui/page/particle/particle_setting_ui.py +0 -0
  63. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/ui/page/pet/__init__.py +0 -0
  64. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/ui/page/scene_setting/__init__.py +0 -0
  65. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/ui/page/scene_setting/scene_manager.py +0 -0
  66. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/ui/page/scene_setting/scene_page/__init__.py +0 -0
  67. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/ui/page/scene_setting/scene_page/base_scene_page.py +0 -0
  68. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/ui/page/scene_setting/scene_page/gif.py +0 -0
  69. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/ui/page/scene_setting/scene_page/image.py +0 -0
  70. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/ui/page/scene_setting/scene_page/registry.py +0 -0
  71. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/ui/page/scene_setting/scene_page/sound.py +0 -0
  72. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/ui/page/scene_setting/scene_page/text.py +0 -0
  73. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/ui/page/scene_setting/scene_page/video.py +0 -0
  74. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/ui/page/scene_setting/scene_page/web.py +0 -0
  75. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/ui/page/scene_setting/scene_setting_ui.py +0 -0
  76. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/ui/page/sound_player/__init__.py +0 -0
  77. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/ui/page/sound_player/sound_player_setting_ui.py +0 -0
  78. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/ui/page/text/__init__.py +0 -0
  79. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/ui/page/text/text_setting_ui.py +0 -0
  80. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/ui/page/utils.py +0 -0
  81. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/ui/page/video/__init__.py +0 -0
  82. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/ui/page/video/video_setting_ui.py +0 -0
  83. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/ui/page/web/__init__.py +0 -0
  84. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/ui/page/web/web_setting_ui.py +0 -0
  85. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/user_setting/__init__.py +0 -0
  86. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/user_setting/preset_repository.py +0 -0
  87. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/user_setting/scene_setting.py +0 -0
  88. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/user_setting/user_setting_file.py +0 -0
  89. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/utils/__init__.py +0 -0
  90. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/utils/browser/__init__.py +0 -0
  91. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/utils/browser/browser.py +0 -0
  92. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/utils/critical_exit/__init__.py +0 -0
  93. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/utils/critical_exit/check_key_is_press.py +0 -0
  94. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/utils/critical_exit/critical_exit.py +0 -0
  95. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/utils/critical_exit/win32_vk.py +0 -0
  96. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/utils/exception/__init__.py +0 -0
  97. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/utils/exception/exception_tags.py +0 -0
  98. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/utils/exception/exceptions.py +0 -0
  99. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/utils/file/__init__.py +0 -0
  100. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/utils/file/open/__init__.py +0 -0
  101. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/utils/file/open/open_file.py +0 -0
  102. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/utils/file/save/__init__.py +0 -0
  103. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/utils/file/save/save_file.py +0 -0
  104. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/utils/hotkey/__init__.py +0 -0
  105. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/utils/hotkey/hotkey_service.py +0 -0
  106. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/utils/json/__init__.py +0 -0
  107. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/utils/json/json_file.py +0 -0
  108. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/utils/json/json_repository.py +0 -0
  109. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/utils/json_format/__init__.py +0 -0
  110. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/utils/json_format/json_process.py +0 -0
  111. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/utils/logging/__init__.py +0 -0
  112. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/utils/logging/loggin_instance.py +0 -0
  113. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/utils/multi_language/__init__.py +0 -0
  114. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/utils/multi_language/france.py +0 -0
  115. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/utils/multi_language/germany.py +0 -0
  116. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/utils/multi_language/italy.py +0 -0
  117. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/utils/multi_language/language_wrapper.py +0 -0
  118. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/utils/multi_language/russian.py +0 -0
  119. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/utils/multi_language/simplified_chinese.py +0 -0
  120. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/utils/preset_schedule/__init__.py +0 -0
  121. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/utils/preset_schedule/preset_schedule_service.py +0 -0
  122. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/utils/redirect_manager/__init__.py +0 -0
  123. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/utils/redirect_manager/redirect_manager_class.py +0 -0
  124. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/utils/smart_pause/__init__.py +0 -0
  125. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/utils/smart_pause/smart_pause_service.py +0 -0
  126. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/utils/theme_schedule/__init__.py +0 -0
  127. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/utils/theme_schedule/theme_schedule_service.py +0 -0
  128. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/utils/web_url.py +0 -0
  129. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/worker/__init__.py +0 -0
  130. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine/worker/qthread_worker.py +0 -0
  131. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine.egg-info/SOURCES.txt +0 -0
  132. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine.egg-info/dependency_links.txt +0 -0
  133. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine.egg-info/entry_points.txt +0 -0
  134. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine.egg-info/requires.txt +0 -0
  135. {frontengine-1.0.10 → frontengine-1.0.12}/frontengine.egg-info/top_level.txt +0 -0
  136. {frontengine-1.0.10 → frontengine-1.0.12}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: frontengine
3
- Version: 1.0.10
3
+ Version: 1.0.12
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
@@ -144,6 +144,23 @@ def windows_platforms(exclude_hwnds=()) -> list:
144
144
  return []
145
145
 
146
146
 
147
+ def nearest_peer(center, peers):
148
+ """
149
+ 回傳離 center 最近的同伴座標與距離;無同伴回傳 (None, inf)。
150
+ Return the nearest peer center and its distance to `center`, or
151
+ (None, inf) when there are no peers.
152
+ """
153
+ best = None
154
+ best_distance = float("inf")
155
+ cx, cy = center
156
+ for peer_x, peer_y in peers:
157
+ distance = ((peer_x - cx) ** 2 + (peer_y - cy) ** 2) ** 0.5
158
+ if distance < best_distance:
159
+ best_distance = distance
160
+ best = (peer_x, peer_y)
161
+ return best, best_distance
162
+
163
+
147
164
  def message_bucket(hour: int) -> str:
148
165
  """依小時回傳時段 / Time-of-day bucket for the given hour."""
149
166
  hour = int(hour) % 24
@@ -306,6 +323,8 @@ class PetMotion:
306
323
  self.on_platform = False
307
324
  self.platform_span: Optional[Tuple[float, float]] = None
308
325
  self.ground_feet = 0.0
326
+ # 追向某個 x(用於朝同伴走過去玩耍)/ Horizontal target to walk toward (play).
327
+ self.follow_target_x: Optional[float] = None
309
328
 
310
329
  @property
311
330
  def facing_left(self) -> bool:
@@ -318,6 +337,13 @@ class PetMotion:
318
337
  """設定可站立的視窗上緣平台 / Set standable window top-edge platforms."""
319
338
  self.platforms = list(platforms)
320
339
 
340
+ def set_follow(self, target_x) -> None:
341
+ """設定要走向的 x 座標(朝同伴玩耍)/ Set a horizontal target to walk toward."""
342
+ self.follow_target_x = float(target_x)
343
+
344
+ def clear_follow(self) -> None:
345
+ self.follow_target_x = None
346
+
321
347
  def set_target(self, x: float, y: float) -> None:
322
348
  self.target = (float(x), float(y))
323
349
 
@@ -330,6 +356,7 @@ class PetMotion:
330
356
  self.surface = SURFACE_FLOOR
331
357
  self.on_platform = False
332
358
  self.platform_span = None
359
+ self.follow_target_x = None
333
360
 
334
361
  def step(self) -> Tuple[int, int]:
335
362
  left, top, right, bottom = self.bounds
@@ -347,6 +374,8 @@ class PetMotion:
347
374
  )
348
375
  if airborne:
349
376
  return self._step_fall(left, top, right, bottom, floor_y)
377
+ if self.follow_target_x is not None:
378
+ return self._step_follow(left, top, right, bottom, floor_y)
350
379
  if self.on_platform:
351
380
  return self._step_platform(left, top, right, bottom, floor_y)
352
381
  if self.surface != SURFACE_FLOOR:
@@ -420,6 +449,25 @@ class PetMotion:
420
449
  self._new_state(force_walk=True)
421
450
  return int(self.x), int(self.y)
422
451
 
452
+ def _step_follow(self, left, top, right, bottom, floor_y) -> Tuple[int, int]:
453
+ """朝 follow_target_x 走過去;抵達附近即清除並恢復隨機行為。"""
454
+ center_x = self.x + self.width / 2.0
455
+ if abs(center_x - self.follow_target_x) <= self.speed + 2.0:
456
+ self.follow_target_x = None
457
+ self._new_state()
458
+ return int(self.x), int(self.y)
459
+ self.state = "walk"
460
+ self.vx = float(self.speed) if self.follow_target_x >= center_x else float(-self.speed)
461
+ self.x += self.vx
462
+ if self.on_platform and self.platform_span is not None:
463
+ span_left, span_right = self.platform_span
464
+ self.x = min(max(self.x, span_left), span_right - self.width)
465
+ self.y = float(self.ground_feet - self.height)
466
+ else:
467
+ self.x = min(max(self.x, float(left)), float(right - self.width))
468
+ self.y = float(floor_y)
469
+ return int(self.x), int(self.y)
470
+
423
471
  def _platform_under(self) -> Optional[Tuple[float, float]]:
424
472
  """回傳目前站立平台的水平範圍;平台已消失(視窗移走/關閉)則回傳 None。"""
425
473
  body_left = self.x
@@ -616,6 +664,10 @@ class DesktopPetWidget(BaseWidget):
616
664
  self._init_sound(sound_path)
617
665
  self._sit_on_windows = bool(sit_on_windows)
618
666
  self._platform_tick = 0
667
+ # 多寵物互動 / Multi-pet interaction
668
+ self._peers_provider = None
669
+ self._peer_greeted = False
670
+ self._peer_tick = 0
619
671
  self._bubble = SpeechBubble()
620
672
  self._chatter_timer = QTimer(self)
621
673
  self._chatter_timer.setSingleShot(True)
@@ -629,10 +681,54 @@ class DesktopPetWidget(BaseWidget):
629
681
  self.close_action.triggered.connect(self.close)
630
682
  self.menu.addAction(self.close_action)
631
683
 
684
+ MEET_DISTANCE = 90.0
685
+ PLAY_RANGE = 320.0
686
+ PLAY_CHANCE = 0.25
687
+
632
688
  def set_pet_window_flag(self) -> None:
633
689
  """寵物需接收滑鼠以便拖曳,故 allow_input=True 並置頂。"""
634
690
  apply_overlay_window_flags(self, show_on_bottom=False, allow_input=True)
635
691
 
692
+ def center(self) -> Tuple[int, int]:
693
+ return (self.x() + self.width() // 2, self.y() + self.height() // 2)
694
+
695
+ def set_peers_provider(self, provider) -> None:
696
+ """設定回傳其他寵物中心座標清單的函式 / Provider of other pets' centres."""
697
+ self._peers_provider = provider
698
+
699
+ def _check_peers(self) -> None:
700
+ """靠近其他寵物時走過去玩耍、抵達後轉向打招呼(帶遲滯,避免重複)。"""
701
+ if self._peers_provider is None:
702
+ return
703
+ try:
704
+ peers = self._peers_provider()
705
+ except Exception: # pragma: no cover - defensive
706
+ return
707
+ my_center = self.center()
708
+ peer, distance = nearest_peer(my_center, peers)
709
+ if peer is None:
710
+ self._peer_greeted = False
711
+ self.motion.clear_follow()
712
+ return
713
+ # play: a floor pet may walk over to a near-ish peer
714
+ if self.motion.behaviour == BEHAVIOUR_FLOOR:
715
+ if self.MEET_DISTANCE < distance <= self.PLAY_RANGE:
716
+ if self.motion.follow_target_x is not None or self._chatter_rng.random() < self.PLAY_CHANCE:
717
+ self.motion.set_follow(peer[0])
718
+ elif distance > self.PLAY_RANGE:
719
+ self.motion.clear_follow()
720
+ # greet: face and say a meet line once per approach
721
+ if distance <= self.MEET_DISTANCE:
722
+ self.motion.clear_follow()
723
+ if self._talk and not self._peer_greeted:
724
+ self._peer_greeted = True
725
+ self.motion.vx = abs(self.motion.vx) if peer[0] >= my_center[0] else -abs(self.motion.vx)
726
+ pool = self._messages.get("meet") or []
727
+ if pool:
728
+ self.say(pool[self._chatter_rng.randrange(len(pool))])
729
+ elif distance > self.MEET_DISTANCE * 1.6:
730
+ self._peer_greeted = False
731
+
636
732
  def _load_sprite(self, path: str):
637
733
  if Path(path).suffix.lower() in (".gif", ".webp"):
638
734
  movie = QMovie(str(path))
@@ -712,6 +808,7 @@ class DesktopPetWidget(BaseWidget):
712
808
  "night": lines("pet_chatter_night", "It's late - get some rest!|Still up?"),
713
809
  "happy": lines("pet_chatter_happy", "I'm so happy!|You're the best!|(^o^)"),
714
810
  "sad": lines("pet_chatter_sad", "Feeling a bit lonely...|Pet me?|(._.)"),
811
+ "meet": lines("pet_chatter_meet", "Hi friend!|Hello!|Let's play!"),
715
812
  "any": lines("pet_chatter_any", "Hi there!|(^_^)|Keep going!"),
716
813
  }
717
814
 
@@ -775,6 +872,10 @@ class DesktopPetWidget(BaseWidget):
775
872
  x, y = self.motion.step()
776
873
  self.move(x, y)
777
874
  self._set_active_sprite(self._visual_state())
875
+ self._peer_tick += 1
876
+ if self._peer_tick >= 5:
877
+ self._peer_tick = 0
878
+ self._check_peers()
778
879
  if self._bubble.isVisible():
779
880
  self._bubble.reposition(self)
780
881
 
@@ -786,6 +887,7 @@ class DesktopPetWidget(BaseWidget):
786
887
  self._last_move_delta = (0, 0)
787
888
  self._drag_offset = event.globalPosition().toPoint() - self.frameGeometry().topLeft()
788
889
  self.motion.wake() # interacting wakes a sleeping pet
890
+ self.motion.clear_follow()
789
891
  self._mood.pet() # petting cheers it up
790
892
  self._persist_mood()
791
893
  self._play_sound()
@@ -124,6 +124,7 @@ class PetSettingUI(QWidget):
124
124
  sit_on_windows=self.sit_checkbox.isChecked(),
125
125
  )
126
126
  pet.clone_requested.connect(self._spawn_pet)
127
+ pet.set_peers_provider(lambda me=pet: self._peer_centers(me))
127
128
  pet.set_pet_window_flag()
128
129
  self.pet_list.append(pet)
129
130
  screen = QGuiApplication.primaryScreen()
@@ -132,6 +133,18 @@ class PetSettingUI(QWidget):
132
133
  if geometry is not None:
133
134
  pet.start_moving((geometry.left(), geometry.top(), geometry.right(), geometry.bottom()))
134
135
 
136
+ def _peer_centers(self, me) -> list:
137
+ """回傳其他仍存活寵物的中心座標(略過已被銷毀者)。"""
138
+ centers = []
139
+ for other in list(self.pet_list):
140
+ if other is me:
141
+ continue
142
+ try:
143
+ centers.append(other.center())
144
+ except RuntimeError:
145
+ pass # underlying C++ object already deleted
146
+ return centers
147
+
135
148
  def start_play_pet(self) -> None:
136
149
  front_engine_logger.info("[PetSettingUI] start_play_pet")
137
150
  if not self.pet_image_path or not self.ready_to_play:
@@ -237,6 +237,7 @@ english_word_dict = {
237
237
  "pet_chatter_any": "Hi there!|(^_^)|Keep going!|You've got this!",
238
238
  "pet_chatter_happy": "I'm so happy!|You're the best!|(^o^)/|Best day ever!",
239
239
  "pet_chatter_sad": "Feeling a bit lonely...|Pet me?|(._.)|Don't forget about me~",
240
+ "pet_chatter_meet": "Hi friend!|Hello there!|Let's play!|Fancy meeting you here!",
240
241
  "pet_start": "Spawn pet",
241
242
  "pet_message_box_text": "Pet image not found",
242
243
  }
@@ -238,6 +238,7 @@ traditional_chinese_word_dict = {
238
238
  "pet_chatter_any": "嗨!|(^_^)|加油!|你可以的!",
239
239
  "pet_chatter_happy": "我好開心!|你最棒了!|(^o^)/|今天真美好!",
240
240
  "pet_chatter_sad": "有點寂寞…|摸摸我好嗎?|(._.)|別忘了我~",
241
+ "pet_chatter_meet": "嗨朋友!|你好呀!|一起玩吧!|在這遇到你真巧!",
241
242
  "pet_start": "召喚寵物",
242
243
  "pet_message_box_text": "找不到寵物圖片",
243
244
  }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: frontengine
3
- Version: 1.0.10
3
+ Version: 1.0.12
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.10"
9
+ version = "1.0.12"
10
10
  authors = [
11
11
  { name = "JE-Chen", email = "jechenmailman@gmail.com" },
12
12
  ]
File without changes
File without changes
File without changes