frontengine 1.0.27__tar.gz → 1.0.29__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.
Potentially problematic release.
This version of frontengine might be problematic. Click here for more details.
- {frontengine-1.0.27 → frontengine-1.0.29}/PKG-INFO +7 -2
- {frontengine-1.0.27 → frontengine-1.0.29}/README.md +6 -1
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/show/pet/desktop_pet.py +230 -10
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/ui/page/pet/pet_setting_ui.py +66 -10
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/utils/multi_language/english.py +6 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/utils/multi_language/traditional_chinese.py +6 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine.egg-info/PKG-INFO +7 -2
- {frontengine-1.0.27 → frontengine-1.0.29}/pyproject.toml +1 -1
- {frontengine-1.0.27 → frontengine-1.0.29}/LICENSE +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/__init__.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/__main__.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/show/__init__.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/show/base_widget.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/show/gif/__init__.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/show/gif/paint_gif.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/show/image/__init__.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/show/image/paint_image.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/show/load/__init__.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/show/load/load_someone_make_ui.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/show/overlay_factory.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/show/particle/__init__.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/show/particle/particle_ui.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/show/pet/__init__.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/show/scene/__init__.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/show/scene/extend_graphic_scene.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/show/scene/extend_graphic_view.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/show/scene/scene.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/show/sound_player/__init__.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/show/sound_player/sound_effect.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/show/sound_player/sound_player.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/show/text/__init__.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/show/text/draw_text.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/show/video/__init__.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/show/video/video_player.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/show/web/__init__.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/show/web/webview.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/show/window_helpers.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/system_tray/__init__.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/system_tray/extend_system_tray.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/ui/__init__.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/ui/color/__init__.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/ui/color/global_color.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/ui/dialog/__init__.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/ui/dialog/choose_file_dialog.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/ui/dialog/hotkey_settings_dialog.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/ui/dialog/save_file_dialog.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/ui/main_ui.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/ui/menu/__init__.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/ui/menu/help_menu.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/ui/menu/how_to_menu.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/ui/menu/language_menu.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/ui/menu/preset_menu.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/ui/menu/settings_menu.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/ui/page/__init__.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/ui/page/control_center/__init__.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/ui/page/control_center/control_center_ui.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/ui/page/gif/__init__.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/ui/page/gif/gif_setting_ui.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/ui/page/image/__init__.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/ui/page/image/image_setting_ui.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/ui/page/particle/__init__.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/ui/page/particle/particle_setting_ui.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/ui/page/pet/__init__.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/ui/page/scene_setting/__init__.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/ui/page/scene_setting/scene_manager.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/ui/page/scene_setting/scene_page/__init__.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/ui/page/scene_setting/scene_page/base_scene_page.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/ui/page/scene_setting/scene_page/gif.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/ui/page/scene_setting/scene_page/image.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/ui/page/scene_setting/scene_page/registry.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/ui/page/scene_setting/scene_page/sound.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/ui/page/scene_setting/scene_page/text.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/ui/page/scene_setting/scene_page/video.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/ui/page/scene_setting/scene_page/web.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/ui/page/scene_setting/scene_setting_ui.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/ui/page/sound_player/__init__.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/ui/page/sound_player/sound_player_setting_ui.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/ui/page/text/__init__.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/ui/page/text/text_setting_ui.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/ui/page/utils.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/ui/page/video/__init__.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/ui/page/video/video_setting_ui.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/ui/page/web/__init__.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/ui/page/web/web_setting_ui.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/user_setting/__init__.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/user_setting/preset_repository.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/user_setting/scene_setting.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/user_setting/user_setting_file.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/utils/__init__.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/utils/audio_meter/__init__.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/utils/audio_meter/audio_envelope.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/utils/audio_meter/screen_audio.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/utils/audio_meter/system_audio_meter.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/utils/browser/__init__.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/utils/browser/browser.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/utils/critical_exit/__init__.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/utils/critical_exit/check_key_is_press.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/utils/critical_exit/critical_exit.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/utils/critical_exit/win32_vk.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/utils/exception/__init__.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/utils/exception/exception_tags.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/utils/exception/exceptions.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/utils/file/__init__.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/utils/file/open/__init__.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/utils/file/open/open_file.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/utils/file/save/__init__.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/utils/file/save/save_file.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/utils/hotkey/__init__.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/utils/hotkey/hotkey_service.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/utils/json/__init__.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/utils/json/json_file.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/utils/json/json_repository.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/utils/json_format/__init__.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/utils/json_format/json_process.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/utils/logging/__init__.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/utils/logging/loggin_instance.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/utils/multi_language/__init__.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/utils/multi_language/france.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/utils/multi_language/germany.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/utils/multi_language/italy.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/utils/multi_language/language_wrapper.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/utils/multi_language/russian.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/utils/multi_language/simplified_chinese.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/utils/preset_schedule/__init__.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/utils/preset_schedule/preset_schedule_service.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/utils/redirect_manager/__init__.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/utils/redirect_manager/redirect_manager_class.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/utils/smart_pause/__init__.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/utils/smart_pause/smart_pause_service.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/utils/theme_schedule/__init__.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/utils/theme_schedule/theme_schedule_service.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/utils/web_url.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/worker/__init__.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine/worker/qthread_worker.py +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine.egg-info/SOURCES.txt +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine.egg-info/dependency_links.txt +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine.egg-info/entry_points.txt +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine.egg-info/requires.txt +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/frontengine.egg-info/top_level.txt +0 -0
- {frontengine-1.0.27 → frontengine-1.0.29}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: frontengine
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.29
|
|
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
|
|
@@ -68,7 +68,12 @@ Spawn an animated sprite that lives on your desktop, from the **Pet** tab.
|
|
|
68
68
|
away, and warns you about a low battery.
|
|
69
69
|
- **Interaction** — drag it around, right-click to clone/feed/set a reminder,
|
|
70
70
|
and **drop a file onto it**: an image or pet pack becomes its new look,
|
|
71
|
-
anything else is eaten
|
|
71
|
+
anything else is eaten. What it eats matters — an archive is a feast, music
|
|
72
|
+
cheers it up more than it fills, a document is a modest meal, and a binary is
|
|
73
|
+
too hard to chew.
|
|
74
|
+
- **Tag** — with two or more pets on screen, tick *Play tag with each other* and
|
|
75
|
+
one becomes "it": it walks toward its nearest neighbour while the others run
|
|
76
|
+
the other way, and catching someone passes the tag on.
|
|
72
77
|
- **React to audio** — the pet pulses to your speakers' output level. It reads
|
|
73
78
|
only the Windows output *meter* (WASAPI `IAudioMeterInformation`); no audio
|
|
74
79
|
is captured or recorded. Peaks are smoothed with an RMS window and a
|
|
@@ -44,7 +44,12 @@ Spawn an animated sprite that lives on your desktop, from the **Pet** tab.
|
|
|
44
44
|
away, and warns you about a low battery.
|
|
45
45
|
- **Interaction** — drag it around, right-click to clone/feed/set a reminder,
|
|
46
46
|
and **drop a file onto it**: an image or pet pack becomes its new look,
|
|
47
|
-
anything else is eaten
|
|
47
|
+
anything else is eaten. What it eats matters — an archive is a feast, music
|
|
48
|
+
cheers it up more than it fills, a document is a modest meal, and a binary is
|
|
49
|
+
too hard to chew.
|
|
50
|
+
- **Tag** — with two or more pets on screen, tick *Play tag with each other* and
|
|
51
|
+
one becomes "it": it walks toward its nearest neighbour while the others run
|
|
52
|
+
the other way, and catching someone passes the tag on.
|
|
48
53
|
- **React to audio** — the pet pulses to your speakers' output level. It reads
|
|
49
54
|
only the Windows output *meter* (WASAPI `IAudioMeterInformation`); no audio
|
|
50
55
|
is captured or recorded. Peaks are smoothed with an RMS window and a
|
|
@@ -105,6 +105,43 @@ def classify_drop(path) -> Optional[str]:
|
|
|
105
105
|
return DROP_SPRITE if target.suffix.lower() in _PACK_EXTS else DROP_FOOD
|
|
106
106
|
|
|
107
107
|
|
|
108
|
+
# 食物種類(依副檔名猜)與各自的效果 / Food kinds guessed from the suffix
|
|
109
|
+
FOOD_SNACK = "snack" # 一般點心 / an ordinary snack
|
|
110
|
+
FOOD_FEAST = "feast" # 壓縮檔=大餐 / an archive is a hearty meal
|
|
111
|
+
FOOD_MUSIC = "music" # 音樂檔=聽了很開心 / music cheers it up more than it fills
|
|
112
|
+
FOOD_BOOK = "book" # 文件檔=細嚼慢嚥 / a document is chewed slowly
|
|
113
|
+
FOOD_HARD = "hard" # 可執行檔=咬不動 / a binary is too hard to chew
|
|
114
|
+
|
|
115
|
+
_FOOD_SUFFIXES = {
|
|
116
|
+
FOOD_FEAST: (".zip", ".7z", ".rar", ".tar", ".gz", ".iso"),
|
|
117
|
+
FOOD_MUSIC: (".mp3", ".wav", ".ogg", ".flac", ".m4a", ".aac"),
|
|
118
|
+
FOOD_BOOK: (".txt", ".md", ".pdf", ".doc", ".docx", ".rtf", ".epub"),
|
|
119
|
+
FOOD_HARD: (".exe", ".dll", ".msi", ".sys", ".bat"),
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
# 每種食物的飽足/心情/親密度變化(心情為負代表不喜歡)
|
|
123
|
+
# Fullness / mood / affection change per food kind (negative mood = dislikes it).
|
|
124
|
+
FOOD_EFFECTS = {
|
|
125
|
+
FOOD_SNACK: {"fullness": 30, "mood": 12, "affection": 5},
|
|
126
|
+
FOOD_FEAST: {"fullness": 45, "mood": 8, "affection": 6},
|
|
127
|
+
FOOD_MUSIC: {"fullness": 15, "mood": 20, "affection": 5},
|
|
128
|
+
FOOD_BOOK: {"fullness": 20, "mood": 6, "affection": 4},
|
|
129
|
+
FOOD_HARD: {"fullness": 2, "mood": -6, "affection": 1},
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def classify_food(path) -> str:
|
|
134
|
+
"""依副檔名判斷食物種類;認不出來就當一般點心 / Guess the food kind from the suffix."""
|
|
135
|
+
try:
|
|
136
|
+
suffix = Path(path).suffix.lower()
|
|
137
|
+
except (OSError, TypeError, ValueError):
|
|
138
|
+
return FOOD_SNACK
|
|
139
|
+
for kind, suffixes in _FOOD_SUFFIXES.items():
|
|
140
|
+
if suffix in suffixes:
|
|
141
|
+
return kind
|
|
142
|
+
return FOOD_SNACK
|
|
143
|
+
|
|
144
|
+
|
|
108
145
|
def derive_visual_state(dragging: bool, airborne: bool, surface: str, motion_state: str) -> str:
|
|
109
146
|
"""依目前情形推導應顯示的視覺狀態 / Derive which sprite state to show."""
|
|
110
147
|
if dragging:
|
|
@@ -291,6 +328,106 @@ def nearest_peer(center, peers):
|
|
|
291
328
|
return best, best_distance
|
|
292
329
|
|
|
293
330
|
|
|
331
|
+
# 鬼抓人角色 / Roles in the tag game
|
|
332
|
+
TAG_CHASE = "chase"
|
|
333
|
+
TAG_FLEE = "flee"
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
class PetTagGame:
|
|
337
|
+
"""
|
|
338
|
+
多隻寵物的鬼抓人:一隻當鬼追最近的同伴,其他往反方向逃;抓到就換人當鬼,
|
|
339
|
+
並有短暫冷卻避免立刻抓回去。純邏輯、不依賴 Qt,由外部每一拍餵入座標。
|
|
340
|
+
|
|
341
|
+
Tag between pets: one is "it" and chases its nearest peer while the others
|
|
342
|
+
run the other way; catching someone passes "it" on, with a short cooldown so
|
|
343
|
+
the tag cannot bounce straight back. Pure logic — positions are fed in each
|
|
344
|
+
tick from outside.
|
|
345
|
+
"""
|
|
346
|
+
|
|
347
|
+
CATCH_DISTANCE = 60.0
|
|
348
|
+
FLEE_DISTANCE = 220.0
|
|
349
|
+
COOLDOWN_TICKS = 20
|
|
350
|
+
|
|
351
|
+
def __init__(self, catch_distance: float = CATCH_DISTANCE, flee_distance: float = FLEE_DISTANCE,
|
|
352
|
+
cooldown_ticks: int = COOLDOWN_TICKS) -> None:
|
|
353
|
+
self.catch_distance = float(catch_distance)
|
|
354
|
+
self.flee_distance = float(flee_distance)
|
|
355
|
+
self.cooldown_ticks = max(0, int(cooldown_ticks))
|
|
356
|
+
self.it = None
|
|
357
|
+
self.just_tagged = None
|
|
358
|
+
self._cooldown = 0
|
|
359
|
+
|
|
360
|
+
def reset(self) -> None:
|
|
361
|
+
"""重置遊戲(參與者換人或停玩時呼叫)。"""
|
|
362
|
+
self.it = None
|
|
363
|
+
self.just_tagged = None
|
|
364
|
+
self._cooldown = 0
|
|
365
|
+
|
|
366
|
+
@staticmethod
|
|
367
|
+
def _nearest(positions: dict, source):
|
|
368
|
+
"""回傳離 source 最近的其他參與者 (id, 距離);只有一人時回傳 (None, inf)。"""
|
|
369
|
+
source_x, source_y = positions[source]
|
|
370
|
+
best, best_distance = None, float("inf")
|
|
371
|
+
for participant, (x, y) in positions.items():
|
|
372
|
+
if participant == source:
|
|
373
|
+
continue
|
|
374
|
+
distance = ((x - source_x) ** 2 + (y - source_y) ** 2) ** 0.5
|
|
375
|
+
if distance < best_distance:
|
|
376
|
+
best, best_distance = participant, distance
|
|
377
|
+
return best, best_distance
|
|
378
|
+
|
|
379
|
+
def update(self, positions: dict) -> dict:
|
|
380
|
+
"""
|
|
381
|
+
餵入 {參與者: (x, y)},回傳 {參與者: (角色, 目標 x)}。少於兩人時不開局。
|
|
382
|
+
Feed in {participant: (x, y)} and get {participant: (role, target_x)}.
|
|
383
|
+
"""
|
|
384
|
+
self.just_tagged = None
|
|
385
|
+
if not positions or len(positions) < 2:
|
|
386
|
+
self.reset()
|
|
387
|
+
return {}
|
|
388
|
+
if self.it not in positions:
|
|
389
|
+
self.it = sorted(positions)[0]
|
|
390
|
+
self._cooldown = self.cooldown_ticks
|
|
391
|
+
# 冷卻期間只是跑給對方追,不換鬼;先判斷再遞減,冷卻 N 拍就真的保護 N 拍。
|
|
392
|
+
# While cooling down nobody can be tagged; check before decrementing so a
|
|
393
|
+
# cooldown of N protects exactly N updates.
|
|
394
|
+
can_tag = self._cooldown <= 0
|
|
395
|
+
if self._cooldown > 0:
|
|
396
|
+
self._cooldown -= 1
|
|
397
|
+
prey, distance = self._nearest(positions, self.it)
|
|
398
|
+
if prey is not None and can_tag and distance <= self.catch_distance:
|
|
399
|
+
self.it = prey
|
|
400
|
+
self.just_tagged = prey
|
|
401
|
+
self._cooldown = self.cooldown_ticks
|
|
402
|
+
prey, _distance = self._nearest(positions, self.it)
|
|
403
|
+
return self._roles(positions, prey)
|
|
404
|
+
|
|
405
|
+
def _roles(self, positions: dict, prey) -> dict:
|
|
406
|
+
"""
|
|
407
|
+
依目前的鬼與獵物組出每個人的 (角色, 目標 x, 目標 y)。逃跑方向取兩點連線的反向,
|
|
408
|
+
讓地板模式(只用 x)與飄移/追游標模式(用整個點)都有合理目標。
|
|
409
|
+
Build each participant's (role, target_x, target_y). Runners head along
|
|
410
|
+
the line away from "it", which suits floor pets (x only) and wander or
|
|
411
|
+
chase pets (the whole point) alike.
|
|
412
|
+
"""
|
|
413
|
+
it_x, it_y = positions[self.it]
|
|
414
|
+
prey_position = positions[prey] if prey is not None else (it_x, it_y)
|
|
415
|
+
roles = {self.it: (TAG_CHASE, float(prey_position[0]), float(prey_position[1]))}
|
|
416
|
+
for participant, (x, y) in positions.items():
|
|
417
|
+
if participant == self.it:
|
|
418
|
+
continue
|
|
419
|
+
dx, dy = x - it_x, y - it_y
|
|
420
|
+
length = (dx * dx + dy * dy) ** 0.5
|
|
421
|
+
if length < 1e-9: # standing on each other: just pick a direction
|
|
422
|
+
dx, dy, length = 1.0, 0.0, 1.0
|
|
423
|
+
roles[participant] = (
|
|
424
|
+
TAG_FLEE,
|
|
425
|
+
x + self.flee_distance * dx / length,
|
|
426
|
+
y + self.flee_distance * dy / length,
|
|
427
|
+
)
|
|
428
|
+
return roles
|
|
429
|
+
|
|
430
|
+
|
|
294
431
|
def message_bucket(hour: int) -> str:
|
|
295
432
|
"""依小時回傳時段 / Time-of-day bucket for the given hour."""
|
|
296
433
|
hour = int(hour) % 24
|
|
@@ -543,6 +680,10 @@ class PetMotion:
|
|
|
543
680
|
self.ground_feet = 0.0
|
|
544
681
|
# 追向某個 x(用於朝同伴走過去玩耍)/ Horizontal target to walk toward (play).
|
|
545
682
|
self.follow_target_x: Optional[float] = None
|
|
683
|
+
# 引導目標 (x, y):三種行為模式都會朝它移動(鬼抓人用),優先於各自的預設動線。
|
|
684
|
+
# Guidance point (x, y) honoured by every behaviour (used by the tag
|
|
685
|
+
# game); it takes precedence over each mode's own default movement.
|
|
686
|
+
self.guidance: Optional[Tuple[float, float]] = None
|
|
546
687
|
|
|
547
688
|
@property
|
|
548
689
|
def facing_left(self) -> bool:
|
|
@@ -590,6 +731,43 @@ class PetMotion:
|
|
|
590
731
|
def set_target(self, x: float, y: float) -> None:
|
|
591
732
|
self.target = (float(x), float(y))
|
|
592
733
|
|
|
734
|
+
def set_guidance(self, x: float, y: Optional[float] = None) -> None:
|
|
735
|
+
"""
|
|
736
|
+
設定引導目標;地板模式走向該 x,飄移/追游標模式則朝該點移動。
|
|
737
|
+
Set the guidance point: floor pets walk toward its x, wander and chase
|
|
738
|
+
pets steer toward the point itself.
|
|
739
|
+
"""
|
|
740
|
+
centre_y = self.y + self.height / 2.0
|
|
741
|
+
self.guidance = (float(x), centre_y if y is None else float(y))
|
|
742
|
+
if self.behaviour == BEHAVIOUR_FLOOR:
|
|
743
|
+
self.follow_target_x = self.guidance[0]
|
|
744
|
+
|
|
745
|
+
def clear_guidance(self) -> None:
|
|
746
|
+
"""取消引導,回到該模式原本的動線 / Drop the guidance and resume normal movement."""
|
|
747
|
+
self.guidance = None
|
|
748
|
+
self.follow_target_x = None
|
|
749
|
+
|
|
750
|
+
STEER_BLEND = 0.4
|
|
751
|
+
|
|
752
|
+
def _steer_toward(self, point: Tuple[float, float]) -> None:
|
|
753
|
+
"""把速度往目標點轉一些(保持速率),轉彎自然而不是瞬間轉向。"""
|
|
754
|
+
target_x, target_y = point
|
|
755
|
+
dx = target_x - (self.x + self.width / 2.0)
|
|
756
|
+
dy = target_y - (self.y + self.height / 2.0)
|
|
757
|
+
distance = (dx * dx + dy * dy) ** 0.5
|
|
758
|
+
if distance < 1e-9:
|
|
759
|
+
return
|
|
760
|
+
desired_x = self.speed * dx / distance
|
|
761
|
+
desired_y = self.speed * dy / distance
|
|
762
|
+
blended_x = self.vx + self.STEER_BLEND * (desired_x - self.vx)
|
|
763
|
+
blended_y = self.vy + self.STEER_BLEND * (desired_y - self.vy)
|
|
764
|
+
magnitude = (blended_x * blended_x + blended_y * blended_y) ** 0.5
|
|
765
|
+
if magnitude < 1e-9:
|
|
766
|
+
self.vx, self.vy = desired_x, desired_y
|
|
767
|
+
return
|
|
768
|
+
self.vx = self.speed * blended_x / magnitude
|
|
769
|
+
self.vy = self.speed * blended_y / magnitude
|
|
770
|
+
|
|
593
771
|
def throw(self, vx: float, vy: float) -> None:
|
|
594
772
|
"""拖曳放開後以動量丟出(只在重力模式有意義)。"""
|
|
595
773
|
self.vx = float(vx)
|
|
@@ -822,6 +1000,8 @@ class PetMotion:
|
|
|
822
1000
|
def _step_wander(self, left, top, right, bottom) -> Tuple[int, int]:
|
|
823
1001
|
if abs(self.vy) < 1e-9:
|
|
824
1002
|
self.vy = float(self.speed)
|
|
1003
|
+
if self.guidance is not None:
|
|
1004
|
+
self._steer_toward(self.guidance)
|
|
825
1005
|
self.x += self.vx
|
|
826
1006
|
self.y += self.vy
|
|
827
1007
|
if self.x <= left:
|
|
@@ -840,14 +1020,19 @@ class PetMotion:
|
|
|
840
1020
|
|
|
841
1021
|
# --- chase cursor ---
|
|
842
1022
|
def _step_chase(self, left, top, right, bottom) -> Tuple[int, int]:
|
|
843
|
-
|
|
1023
|
+
# 被引導時(鬼抓人)以引導目標為準,而不是游標
|
|
1024
|
+
# While guided (tag game) the guidance point wins over the cursor.
|
|
1025
|
+
chase_target = self.guidance if self.guidance is not None else self.target
|
|
1026
|
+
if chase_target is None:
|
|
844
1027
|
return int(self.x), int(self.y)
|
|
845
|
-
target_x, target_y =
|
|
1028
|
+
target_x, target_y = chase_target
|
|
846
1029
|
dx = target_x - (self.x + self.width / 2)
|
|
847
1030
|
dy = target_y - (self.y + self.height / 2)
|
|
848
1031
|
distance = (dx * dx + dy * dy) ** 0.5
|
|
849
1032
|
if distance <= self.CHASE_STOP_DISTANCE:
|
|
850
|
-
|
|
1033
|
+
# 追到游標會睡著;玩鬼抓人時只是站在對方身上,不睡。
|
|
1034
|
+
# Catching the cursor means a nap; catching a playmate does not.
|
|
1035
|
+
self.asleep = self.guidance is None
|
|
851
1036
|
return int(self.x), int(self.y)
|
|
852
1037
|
self.asleep = False
|
|
853
1038
|
step = float(self.speed) * self.CHASE_SPEED_FACTOR
|
|
@@ -932,6 +1117,8 @@ class DesktopPetWidget(BaseWidget):
|
|
|
932
1117
|
self._peers_provider = None
|
|
933
1118
|
self._peer_greeted = False
|
|
934
1119
|
self._peer_tick = 0
|
|
1120
|
+
# 鬼抓人角色(由外部的 PetTagGame 指派)/ Tag role assigned by a PetTagGame
|
|
1121
|
+
self._tag_role = None
|
|
935
1122
|
# 電量提醒 / Low-battery reaction
|
|
936
1123
|
self._battery_provider = read_battery
|
|
937
1124
|
self._battery_warned = False
|
|
@@ -984,8 +1171,31 @@ class DesktopPetWidget(BaseWidget):
|
|
|
984
1171
|
"""設定回傳其他寵物中心座標清單的函式 / Provider of other pets' centres."""
|
|
985
1172
|
self._peers_provider = provider
|
|
986
1173
|
|
|
1174
|
+
def apply_tag_role(self, role) -> None:
|
|
1175
|
+
"""
|
|
1176
|
+
套用鬼抓人角色 (角色, 目標 x, 目標 y);None 代表沒在玩,恢復平常的同伴互動。
|
|
1177
|
+
Apply a tag role; None means the game is off and normal peer play resumes.
|
|
1178
|
+
"""
|
|
1179
|
+
if role is None:
|
|
1180
|
+
if self._tag_role is not None:
|
|
1181
|
+
self._tag_role = None
|
|
1182
|
+
self.motion.clear_guidance()
|
|
1183
|
+
return
|
|
1184
|
+
self._tag_role, target_x, target_y = role
|
|
1185
|
+
self.motion.wake()
|
|
1186
|
+
self.motion.set_guidance(target_x, target_y)
|
|
1187
|
+
|
|
1188
|
+
def on_tagged(self) -> None:
|
|
1189
|
+
"""換自己當鬼時喊一句 / Shout when the tag lands on this pet."""
|
|
1190
|
+
self._gain_affection(1)
|
|
1191
|
+
pool = self._messages.get("tag") or []
|
|
1192
|
+
if pool:
|
|
1193
|
+
self.say(pool[self._chatter_rng.randrange(len(pool))])
|
|
1194
|
+
|
|
987
1195
|
def _check_peers(self) -> None:
|
|
988
1196
|
"""靠近其他寵物時走過去玩耍、抵達後轉向打招呼(帶遲滯,避免重複)。"""
|
|
1197
|
+
if self._tag_role is not None:
|
|
1198
|
+
return # the tag game owns where this pet is heading
|
|
989
1199
|
if self._peers_provider is None:
|
|
990
1200
|
return
|
|
991
1201
|
try:
|
|
@@ -1164,9 +1374,14 @@ class DesktopPetWidget(BaseWidget):
|
|
|
1164
1374
|
"battery": lines("pet_chatter_battery", "Battery's low - plug me in?|Low power!|Find a charger?"),
|
|
1165
1375
|
"hungry": lines("pet_chatter_hungry", "I'm hungry...|Got a snack?|Feed me?"),
|
|
1166
1376
|
"fed": lines("pet_chatter_fed", "Yum!|Thank you!|Delicious!"),
|
|
1377
|
+
"fed_feast": lines("pet_chatter_fed_feast", "What a feast!|So full!|That was huge!"),
|
|
1378
|
+
"fed_music": lines("pet_chatter_fed_music", "Tasty tune!|That one sings!|Encore!"),
|
|
1379
|
+
"fed_book": lines("pet_chatter_fed_book", "Food for thought.|Chewy words!|Mmm, a story."),
|
|
1380
|
+
"fed_hard": lines("pet_chatter_fed_hard", "Too hard to chew!|Ouch, my teeth!|Not food!"),
|
|
1167
1381
|
"away": lines("pet_chatter_away", "Still there?|I'll nap till you're back~|Zzz..."),
|
|
1168
1382
|
"levelup": lines("pet_chatter_levelup", "Level up!|I'm growing!|We're getting closer!"),
|
|
1169
1383
|
"costume": lines("pet_chatter_costume", "New look!|How do I look?|Nice fit!"),
|
|
1384
|
+
"tag": lines("pet_chatter_tag", "You're it!|Caught you!|My turn to chase!"),
|
|
1170
1385
|
"any": lines("pet_chatter_any", "Hi there!|(^_^)|Keep going!"),
|
|
1171
1386
|
}
|
|
1172
1387
|
|
|
@@ -1333,14 +1548,19 @@ class DesktopPetWidget(BaseWidget):
|
|
|
1333
1548
|
def _persist_hunger(self) -> None:
|
|
1334
1549
|
user_setting_dict["pet_hunger"] = self._hunger.value
|
|
1335
1550
|
|
|
1336
|
-
def feed(self) -> None:
|
|
1337
|
-
"""
|
|
1338
|
-
|
|
1339
|
-
self.
|
|
1551
|
+
def feed(self, kind: str = FOOD_SNACK) -> None:
|
|
1552
|
+
"""餵食:依食物種類調整飽足與心情,並說一句對應的話。"""
|
|
1553
|
+
effect = FOOD_EFFECTS.get(kind, FOOD_EFFECTS[FOOD_SNACK])
|
|
1554
|
+
self._hunger.feed(effect["fullness"])
|
|
1555
|
+
mood_change = effect["mood"]
|
|
1556
|
+
if mood_change >= 0:
|
|
1557
|
+
self._mood.pet(mood_change)
|
|
1558
|
+
else:
|
|
1559
|
+
self._mood.decay(-mood_change)
|
|
1340
1560
|
self._persist_hunger()
|
|
1341
1561
|
self._persist_mood()
|
|
1342
|
-
self._gain_affection(
|
|
1343
|
-
pool = self._messages.get("fed") or []
|
|
1562
|
+
self._gain_affection(effect["affection"])
|
|
1563
|
+
pool = self._messages.get(f"fed_{kind}") or self._messages.get("fed") or []
|
|
1344
1564
|
if pool:
|
|
1345
1565
|
self.say(pool[self._chatter_rng.randrange(len(pool))])
|
|
1346
1566
|
|
|
@@ -1484,7 +1704,7 @@ class DesktopPetWidget(BaseWidget):
|
|
|
1484
1704
|
if classify_drop(path) == DROP_SPRITE:
|
|
1485
1705
|
self.change_sprite(path)
|
|
1486
1706
|
else:
|
|
1487
|
-
self.feed()
|
|
1707
|
+
self.feed(classify_food(path))
|
|
1488
1708
|
event.acceptProposedAction()
|
|
1489
1709
|
|
|
1490
1710
|
def contextMenuEvent(self, event) -> None:
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
from typing import Optional
|
|
2
2
|
|
|
3
|
+
from PySide6.QtCore import QTimer
|
|
3
4
|
from PySide6.QtGui import QGuiApplication
|
|
4
5
|
from PySide6.QtWidgets import (
|
|
5
6
|
QWidget, QGridLayout, QLabel, QPushButton, QMessageBox, QComboBox, QCheckBox, QFileDialog,
|
|
6
7
|
)
|
|
7
8
|
|
|
8
9
|
from frontengine.show.pet.desktop_pet import (
|
|
9
|
-
DesktopPetWidget, BEHAVIOUR_FLOOR, BEHAVIOUR_WANDER, BEHAVIOUR_CHASE, scan_pet_pack,
|
|
10
|
+
DesktopPetWidget, BEHAVIOUR_FLOOR, BEHAVIOUR_WANDER, BEHAVIOUR_CHASE, PetTagGame, scan_pet_pack,
|
|
10
11
|
)
|
|
11
12
|
from frontengine.ui.dialog.choose_file_dialog import choose_pet, choose_wav_sound
|
|
12
13
|
from frontengine.ui.page.utils import (
|
|
@@ -36,6 +37,11 @@ class PetSettingUI(QWidget):
|
|
|
36
37
|
self.ready_to_play = False
|
|
37
38
|
self.pet_image_path: Optional[str] = None
|
|
38
39
|
self.pet_sound_path: Optional[str] = None
|
|
40
|
+
# 鬼抓人:由本頁統一驅動,寵物只負責套用被指派的角色
|
|
41
|
+
# Tag game: driven from this page, pets only apply the role they are given.
|
|
42
|
+
self.tag_game = PetTagGame()
|
|
43
|
+
self.tag_timer = QTimer(self)
|
|
44
|
+
self.tag_timer.timeout.connect(self._tick_tag_game)
|
|
39
45
|
|
|
40
46
|
# Choose file
|
|
41
47
|
self.choose_file_button = QPushButton(
|
|
@@ -81,6 +87,9 @@ class PetSettingUI(QWidget):
|
|
|
81
87
|
self.talk_checkbox.setChecked(True)
|
|
82
88
|
self.sit_checkbox = QCheckBox(language_wrapper.language_word_dict.get("pet_sit_label", "Sit on windows"))
|
|
83
89
|
self.sit_checkbox.setChecked(True)
|
|
90
|
+
self.tag_checkbox = QCheckBox(
|
|
91
|
+
language_wrapper.language_word_dict.get("pet_tag_label", "Play tag with each other"))
|
|
92
|
+
self.tag_checkbox.toggled.connect(self._on_tag_toggled)
|
|
84
93
|
|
|
85
94
|
# Target monitor + sound volume
|
|
86
95
|
self.target_monitor_label = QLabel(
|
|
@@ -134,6 +143,7 @@ class PetSettingUI(QWidget):
|
|
|
134
143
|
self.grid_layout.addWidget(self.volume_label, 6, 2)
|
|
135
144
|
self.grid_layout.addWidget(self.volume_combobox, 7, 2)
|
|
136
145
|
self.grid_layout.addWidget(self.audio_react_checkbox, 7, 0)
|
|
146
|
+
self.grid_layout.addWidget(self.tag_checkbox, 7, 1)
|
|
137
147
|
self.grid_layout.addWidget(self.drop_hint_label, 8, 0, 1, 3)
|
|
138
148
|
|
|
139
149
|
def _spawn_pet(self) -> None:
|
|
@@ -163,6 +173,7 @@ class PetSettingUI(QWidget):
|
|
|
163
173
|
pet.set_pet_window_flag()
|
|
164
174
|
self.pet_list.append(pet)
|
|
165
175
|
pet.show()
|
|
176
|
+
self._start_tag_game()
|
|
166
177
|
if geometry is not None:
|
|
167
178
|
pet.setScreen(geometry[1])
|
|
168
179
|
bounds = geometry[0]
|
|
@@ -180,17 +191,59 @@ class PetSettingUI(QWidget):
|
|
|
180
191
|
return None
|
|
181
192
|
return (screen.availableGeometry(), screen)
|
|
182
193
|
|
|
183
|
-
def
|
|
184
|
-
"""
|
|
185
|
-
|
|
186
|
-
for
|
|
187
|
-
if other is me:
|
|
188
|
-
continue
|
|
194
|
+
def _alive_pets(self) -> list:
|
|
195
|
+
"""回傳仍存活的寵物,並把已被銷毀者從清單移除。"""
|
|
196
|
+
alive = []
|
|
197
|
+
for pet in list(self.pet_list):
|
|
189
198
|
try:
|
|
190
|
-
|
|
199
|
+
pet.center()
|
|
191
200
|
except RuntimeError:
|
|
192
|
-
|
|
193
|
-
|
|
201
|
+
self.pet_list.remove(pet) # underlying C++ object already deleted
|
|
202
|
+
continue
|
|
203
|
+
alive.append(pet)
|
|
204
|
+
return alive
|
|
205
|
+
|
|
206
|
+
def _peer_centers(self, me) -> list:
|
|
207
|
+
"""回傳其他仍存活寵物的中心座標(略過已被銷毀者)。"""
|
|
208
|
+
return [pet.center() for pet in self._alive_pets() if pet is not me]
|
|
209
|
+
|
|
210
|
+
TAG_INTERVAL_MS = 100
|
|
211
|
+
|
|
212
|
+
def _on_tag_toggled(self, checked: bool) -> None:
|
|
213
|
+
"""切換鬼抓人:關掉時停錶並把所有寵物放回平常的行為。"""
|
|
214
|
+
front_engine_logger.info(f"[PetSettingUI] tag game | enabled={checked}")
|
|
215
|
+
if checked:
|
|
216
|
+
self._start_tag_game()
|
|
217
|
+
return
|
|
218
|
+
self.tag_timer.stop()
|
|
219
|
+
self.tag_game.reset()
|
|
220
|
+
for pet in self._alive_pets():
|
|
221
|
+
pet.apply_tag_role(None)
|
|
222
|
+
|
|
223
|
+
def _start_tag_game(self) -> None:
|
|
224
|
+
"""有兩隻以上寵物且已勾選時才需要開錶 / Only run the game with 2+ pets."""
|
|
225
|
+
if self.tag_checkbox.isChecked() and len(self._alive_pets()) >= 2:
|
|
226
|
+
if not self.tag_timer.isActive():
|
|
227
|
+
self.tag_timer.start(self.TAG_INTERVAL_MS)
|
|
228
|
+
|
|
229
|
+
def _tick_tag_game(self) -> None:
|
|
230
|
+
"""每一拍把座標餵給遊戲,再把角色發回各隻寵物。"""
|
|
231
|
+
pets = self._alive_pets()
|
|
232
|
+
if len(pets) < 2:
|
|
233
|
+
self.tag_timer.stop()
|
|
234
|
+
self.tag_game.reset()
|
|
235
|
+
for pet in pets:
|
|
236
|
+
pet.apply_tag_role(None)
|
|
237
|
+
return
|
|
238
|
+
# 用每隻寵物的物件識別碼當鍵,避免有寵物關閉後索引位移導致「鬼」換人
|
|
239
|
+
# Key by object identity so closing a pet cannot shift who is "it".
|
|
240
|
+
by_key = {id(pet): pet for pet in pets}
|
|
241
|
+
roles = self.tag_game.update({key: pet.center() for key, pet in by_key.items()})
|
|
242
|
+
tagged = self.tag_game.just_tagged
|
|
243
|
+
for key, pet in by_key.items():
|
|
244
|
+
pet.apply_tag_role(roles.get(key))
|
|
245
|
+
if key == tagged:
|
|
246
|
+
pet.on_tagged()
|
|
194
247
|
|
|
195
248
|
def start_play_pet(self) -> None:
|
|
196
249
|
front_engine_logger.info("[PetSettingUI] start_play_pet")
|
|
@@ -271,6 +324,7 @@ class PetSettingUI(QWidget):
|
|
|
271
324
|
"target_monitor": self.target_monitor_combobox.currentText(),
|
|
272
325
|
"volume": self.volume_combobox.currentText(),
|
|
273
326
|
"audio_react": self.audio_react_checkbox.isChecked(),
|
|
327
|
+
"tag": self.tag_checkbox.isChecked(),
|
|
274
328
|
}
|
|
275
329
|
|
|
276
330
|
def set_state(self, state: dict) -> None:
|
|
@@ -308,3 +362,5 @@ class PetSettingUI(QWidget):
|
|
|
308
362
|
self.volume_combobox.setCurrentIndex(index)
|
|
309
363
|
if "audio_react" in state:
|
|
310
364
|
self.audio_react_checkbox.setChecked(bool(state["audio_react"]))
|
|
365
|
+
if "tag" in state:
|
|
366
|
+
self.tag_checkbox.setChecked(bool(state["tag"]))
|
|
@@ -236,9 +236,15 @@ english_word_dict = {
|
|
|
236
236
|
"pet_hunger_hungry": "hungry",
|
|
237
237
|
"pet_chatter_hungry": "I'm hungry...|Got a snack?|Feed me, please?|My tummy's rumbling~",
|
|
238
238
|
"pet_chatter_fed": "Yum!|Thank you!|Delicious!|Nom nom (^o^)",
|
|
239
|
+
"pet_chatter_fed_feast": "What a feast!|So full!|That was a big one!|I could nap now...",
|
|
240
|
+
"pet_chatter_fed_music": "Tasty tune!|That one sings!|Encore!|My favourite flavour ♪",
|
|
241
|
+
"pet_chatter_fed_book": "Food for thought.|Chewy words!|Mmm, a story.|I read every bite.",
|
|
242
|
+
"pet_chatter_fed_hard": "Too hard to chew!|Ouch, my teeth!|That is not food!|Yuck (>_<)",
|
|
239
243
|
"pet_chatter_away": "Still there?|I'll nap till you're back~|Zzz...|Take your time!",
|
|
240
244
|
"pet_chatter_levelup": "Level up!|I'm growing!|We're getting closer!|Yay, thank you!",
|
|
241
245
|
"pet_chatter_costume": "New look!|How do I look?|Nice fit!|I like this one!",
|
|
246
|
+
"pet_chatter_tag": "You're it!|Caught you!|My turn to chase!|Hey, no fair!",
|
|
247
|
+
"pet_tag_label": "Play tag with each other",
|
|
242
248
|
"pet_drop_hint": "Tip: drop an image or pet pack onto the pet to change its look, "
|
|
243
249
|
"or any other file to feed it.",
|
|
244
250
|
"pet_set_reminder": "Set reminder...",
|
{frontengine-1.0.27 → frontengine-1.0.29}/frontengine/utils/multi_language/traditional_chinese.py
RENAMED
|
@@ -237,9 +237,15 @@ traditional_chinese_word_dict = {
|
|
|
237
237
|
"pet_hunger_hungry": "肚子餓",
|
|
238
238
|
"pet_chatter_hungry": "我餓了…|有點心嗎?|餵餵我好嗎?|肚子咕咕叫~",
|
|
239
239
|
"pet_chatter_fed": "好吃!|謝謝你!|真美味!|嗯嗯 (^o^)",
|
|
240
|
+
"pet_chatter_fed_feast": "好大一餐!|吃得好飽!|這份量夠了!|想睡午覺了…",
|
|
241
|
+
"pet_chatter_fed_music": "這口有旋律!|好聽又好吃!|再來一首!|我最愛這個味道 ♪",
|
|
242
|
+
"pet_chatter_fed_book": "很有味道的一段。|字字都要嚼。|嗯,有故事的味道。|我一口一句讀完了。",
|
|
243
|
+
"pet_chatter_fed_hard": "太硬了咬不動!|我的牙齒啊!|這不是食物吧!|嘔 (>_<)",
|
|
240
244
|
"pet_chatter_away": "還在嗎?|我先打個盹等你回來~|Zzz…|慢慢來沒關係!",
|
|
241
245
|
"pet_chatter_levelup": "升級了!|我長大了!|我們更親近了!|耶,謝謝你!",
|
|
242
246
|
"pet_chatter_costume": "換新裝!|好看嗎?|很合身耶!|我喜歡這套!",
|
|
247
|
+
"pet_chatter_tag": "換你當鬼!|抓到你了!|輪到我追了!|喂,不公平啦!",
|
|
248
|
+
"pet_tag_label": "寵物玩鬼抓人",
|
|
243
249
|
"pet_drop_hint": "小提示:把圖片或動作包拖到寵物身上可以換裝,拖其他檔案則是餵牠吃東西。",
|
|
244
250
|
"pet_set_reminder": "設定提醒...",
|
|
245
251
|
"pet_reminder_prompt": "提醒我:",
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: frontengine
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.29
|
|
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
|
|
@@ -68,7 +68,12 @@ Spawn an animated sprite that lives on your desktop, from the **Pet** tab.
|
|
|
68
68
|
away, and warns you about a low battery.
|
|
69
69
|
- **Interaction** — drag it around, right-click to clone/feed/set a reminder,
|
|
70
70
|
and **drop a file onto it**: an image or pet pack becomes its new look,
|
|
71
|
-
anything else is eaten
|
|
71
|
+
anything else is eaten. What it eats matters — an archive is a feast, music
|
|
72
|
+
cheers it up more than it fills, a document is a modest meal, and a binary is
|
|
73
|
+
too hard to chew.
|
|
74
|
+
- **Tag** — with two or more pets on screen, tick *Play tag with each other* and
|
|
75
|
+
one becomes "it": it walks toward its nearest neighbour while the others run
|
|
76
|
+
the other way, and catching someone passes the tag on.
|
|
72
77
|
- **React to audio** — the pet pulses to your speakers' output level. It reads
|
|
73
78
|
only the Windows output *meter* (WASAPI `IAudioMeterInformation`); no audio
|
|
74
79
|
is captured or recorded. Peaks are smoothed with an RMS window and a
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{frontengine-1.0.27 → frontengine-1.0.29}/frontengine/ui/page/control_center/control_center_ui.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{frontengine-1.0.27 → frontengine-1.0.29}/frontengine/ui/page/particle/particle_setting_ui.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{frontengine-1.0.27 → frontengine-1.0.29}/frontengine/ui/page/scene_setting/scene_manager.py
RENAMED
|
File without changes
|
{frontengine-1.0.27 → frontengine-1.0.29}/frontengine/ui/page/scene_setting/scene_page/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{frontengine-1.0.27 → frontengine-1.0.29}/frontengine/ui/page/scene_setting/scene_page/gif.py
RENAMED
|
File without changes
|
{frontengine-1.0.27 → frontengine-1.0.29}/frontengine/ui/page/scene_setting/scene_page/image.py
RENAMED
|
File without changes
|
{frontengine-1.0.27 → frontengine-1.0.29}/frontengine/ui/page/scene_setting/scene_page/registry.py
RENAMED
|
File without changes
|
{frontengine-1.0.27 → frontengine-1.0.29}/frontengine/ui/page/scene_setting/scene_page/sound.py
RENAMED
|
File without changes
|
{frontengine-1.0.27 → frontengine-1.0.29}/frontengine/ui/page/scene_setting/scene_page/text.py
RENAMED
|
File without changes
|
{frontengine-1.0.27 → frontengine-1.0.29}/frontengine/ui/page/scene_setting/scene_page/video.py
RENAMED
|
File without changes
|
{frontengine-1.0.27 → frontengine-1.0.29}/frontengine/ui/page/scene_setting/scene_page/web.py
RENAMED
|
File without changes
|
{frontengine-1.0.27 → frontengine-1.0.29}/frontengine/ui/page/scene_setting/scene_setting_ui.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{frontengine-1.0.27 → frontengine-1.0.29}/frontengine/utils/audio_meter/system_audio_meter.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{frontengine-1.0.27 → frontengine-1.0.29}/frontengine/utils/critical_exit/check_key_is_press.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{frontengine-1.0.27 → frontengine-1.0.29}/frontengine/utils/multi_language/language_wrapper.py
RENAMED
|
File without changes
|
|
File without changes
|
{frontengine-1.0.27 → frontengine-1.0.29}/frontengine/utils/multi_language/simplified_chinese.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{frontengine-1.0.27 → frontengine-1.0.29}/frontengine/utils/smart_pause/smart_pause_service.py
RENAMED
|
File without changes
|
|
File without changes
|
{frontengine-1.0.27 → frontengine-1.0.29}/frontengine/utils/theme_schedule/theme_schedule_service.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|