sonolus.py 0.1.2__tar.gz → 0.1.3__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 sonolus.py might be problematic. Click here for more details.
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/PKG-INFO +1 -2
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/pyproject.toml +1 -1
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/sonolus/backend/visitor.py +2 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/sonolus/build/engine.py +55 -5
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/sonolus/script/callbacks.py +12 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/sonolus/script/engine.py +37 -1
- sonolus_py-0.1.3/sonolus/script/instruction.py +151 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/sonolus/script/iterator.py +3 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/sonolus/script/runtime.py +43 -6
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/sonolus/script/vec.py +7 -1
- sonolus_py-0.1.2/sonolus/build/defaults.py +0 -32
- sonolus_py-0.1.2/sonolus/script/icon.py +0 -73
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/.gitignore +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/.python-version +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/LICENSE +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/README.md +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/scripts/generate.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/scripts/runtimes/Engine/Tutorial/Blocks.json +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/scripts/runtimes/Functions.json +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/scripts/runtimes/Level/Play/Blocks.json +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/scripts/runtimes/Level/Preview/Blocks.json +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/scripts/runtimes/Level/Watch/Blocks.json +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/sonolus/__init__.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/sonolus/backend/__init__.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/sonolus/backend/allocate.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/sonolus/backend/blocks.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/sonolus/backend/excepthook.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/sonolus/backend/finalize.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/sonolus/backend/flow.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/sonolus/backend/interpret.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/sonolus/backend/ir.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/sonolus/backend/mode.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/sonolus/backend/node.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/sonolus/backend/ops.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/sonolus/backend/optimize.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/sonolus/backend/passes.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/sonolus/backend/place.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/sonolus/backend/simplify.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/sonolus/backend/utils.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/sonolus/build/__init__.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/sonolus/build/cli.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/sonolus/build/collection.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/sonolus/build/compile.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/sonolus/build/level.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/sonolus/build/node.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/sonolus/build/project.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/sonolus/py.typed +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/sonolus/script/__init__.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/sonolus/script/archetype.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/sonolus/script/array.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/sonolus/script/bucket.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/sonolus/script/comptime.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/sonolus/script/containers.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/sonolus/script/debug.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/sonolus/script/effect.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/sonolus/script/globals.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/sonolus/script/graphics.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/sonolus/script/internal/__init__.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/sonolus/script/internal/builtin_impls.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/sonolus/script/internal/context.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/sonolus/script/internal/descriptor.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/sonolus/script/internal/error.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/sonolus/script/internal/generic.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/sonolus/script/internal/impl.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/sonolus/script/internal/introspection.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/sonolus/script/internal/native.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/sonolus/script/internal/value.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/sonolus/script/interval.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/sonolus/script/level.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/sonolus/script/math.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/sonolus/script/num.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/sonolus/script/options.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/sonolus/script/particle.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/sonolus/script/pointer.py +0 -0
- /sonolus_py-0.1.2/sonolus/script/preview.py → /sonolus_py-0.1.3/sonolus/script/print.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/sonolus/script/project.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/sonolus/script/range.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/sonolus/script/record.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/sonolus/script/sprite.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/sonolus/script/text.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/sonolus/script/timing.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/sonolus/script/transform.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/sonolus/script/ui.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/sonolus/script/values.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/tests/__init__.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/tests/script/__init__.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/tests/script/conftest.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/tests/script/test_array.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/tests/script/test_array_map.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/tests/script/test_assert.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/tests/script/test_helpers.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/tests/script/test_interval.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/tests/script/test_num.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/tests/script/test_range.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/tests/script/test_record.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/tests/script/test_var_array.py +0 -0
- {sonolus_py-0.1.2 → sonolus_py-0.1.3}/uv.lock +0 -0
|
@@ -7,12 +7,15 @@ from pathlib import Path
|
|
|
7
7
|
|
|
8
8
|
from sonolus.backend.mode import Mode
|
|
9
9
|
from sonolus.build.compile import compile_mode
|
|
10
|
-
from sonolus.build.defaults import EMPTY_ENGINE_TUTORIAL_DATA
|
|
11
10
|
from sonolus.script.archetype import BaseArchetype
|
|
12
11
|
from sonolus.script.bucket import Buckets
|
|
13
|
-
from sonolus.script.callbacks import update_spawn_callback
|
|
12
|
+
from sonolus.script.callbacks import navigate_callback, preprocess_callback, update_callback, update_spawn_callback
|
|
14
13
|
from sonolus.script.effect import Effects
|
|
15
14
|
from sonolus.script.engine import EngineData
|
|
15
|
+
from sonolus.script.instruction import (
|
|
16
|
+
TutorialInstructionIcons,
|
|
17
|
+
TutorialInstructions,
|
|
18
|
+
)
|
|
16
19
|
from sonolus.script.internal.context import ReadOnlyMemory
|
|
17
20
|
from sonolus.script.options import Options
|
|
18
21
|
from sonolus.script.particle import Particles
|
|
@@ -61,17 +64,28 @@ def package_engine(engine: EngineData):
|
|
|
61
64
|
rom=rom,
|
|
62
65
|
update_spawn=engine.watch.update_spawn,
|
|
63
66
|
)
|
|
64
|
-
|
|
67
|
+
preview_data = build_preview_mode(
|
|
65
68
|
archetypes=engine.preview.archetypes,
|
|
66
69
|
skin=engine.preview.skin,
|
|
67
70
|
rom=rom,
|
|
68
71
|
)
|
|
72
|
+
tutorial_data = build_tutorial_mode(
|
|
73
|
+
skin=engine.tutorial.skin,
|
|
74
|
+
effects=engine.tutorial.effects,
|
|
75
|
+
particles=engine.tutorial.particles,
|
|
76
|
+
instructions=engine.tutorial.instructions,
|
|
77
|
+
instruction_icons=engine.tutorial.instruction_icons,
|
|
78
|
+
preprocess=engine.tutorial.preprocess,
|
|
79
|
+
navigate=engine.tutorial.navigate,
|
|
80
|
+
update=engine.tutorial.update,
|
|
81
|
+
rom=rom,
|
|
82
|
+
)
|
|
69
83
|
return PackagedEngine(
|
|
70
84
|
configuration=package_output(configuration),
|
|
71
85
|
play_data=package_output(play_data),
|
|
72
86
|
watch_data=package_output(watch_data),
|
|
73
|
-
preview_data=package_output(
|
|
74
|
-
tutorial_data=package_output(
|
|
87
|
+
preview_data=package_output(preview_data),
|
|
88
|
+
tutorial_data=package_output(tutorial_data),
|
|
75
89
|
rom=package_rom(rom),
|
|
76
90
|
)
|
|
77
91
|
|
|
@@ -134,6 +148,35 @@ def build_preview_mode(
|
|
|
134
148
|
}
|
|
135
149
|
|
|
136
150
|
|
|
151
|
+
def build_tutorial_mode(
|
|
152
|
+
skin: Skin,
|
|
153
|
+
effects: Effects,
|
|
154
|
+
particles: Particles,
|
|
155
|
+
instructions: TutorialInstructions,
|
|
156
|
+
instruction_icons: TutorialInstructionIcons,
|
|
157
|
+
preprocess: Callable[[], None],
|
|
158
|
+
navigate: Callable[[int], None],
|
|
159
|
+
update: Callable[[], None],
|
|
160
|
+
rom: ReadOnlyMemory,
|
|
161
|
+
):
|
|
162
|
+
return {
|
|
163
|
+
**compile_mode(
|
|
164
|
+
mode=Mode.TUTORIAL,
|
|
165
|
+
rom=rom,
|
|
166
|
+
archetypes=[],
|
|
167
|
+
global_callbacks=[
|
|
168
|
+
(preprocess_callback, preprocess),
|
|
169
|
+
(navigate_callback, navigate),
|
|
170
|
+
(update_callback, update),
|
|
171
|
+
],
|
|
172
|
+
),
|
|
173
|
+
"skin": build_skin(skin),
|
|
174
|
+
"effect": build_effects(effects),
|
|
175
|
+
"particle": build_particles(particles),
|
|
176
|
+
"instruction": build_instructions(instructions, instruction_icons),
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
|
|
137
180
|
def build_skin(skin: Skin) -> JsonValue:
|
|
138
181
|
return {"sprites": [{"name": name, "id": i} for i, name in enumerate(skin._sprites_)]}
|
|
139
182
|
|
|
@@ -150,6 +193,13 @@ def build_buckets(buckets: Buckets) -> JsonValue:
|
|
|
150
193
|
return [bucket.to_dict() for bucket in buckets._buckets_]
|
|
151
194
|
|
|
152
195
|
|
|
196
|
+
def build_instructions(instructions: TutorialInstructions, instruction_icons: TutorialInstructionIcons) -> JsonValue:
|
|
197
|
+
return {
|
|
198
|
+
"texts": [{"name": name, "id": i} for i, name in enumerate(instructions._instructions_)],
|
|
199
|
+
"icons": [{"name": name, "id": i} for i, name in enumerate(instruction_icons._instruction_icons_)],
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
|
|
153
203
|
def package_rom(rom: ReadOnlyMemory) -> bytes:
|
|
154
204
|
values = rom.values or [0]
|
|
155
205
|
output = bytearray()
|
|
@@ -81,6 +81,18 @@ render_callback = CallbackInfo(
|
|
|
81
81
|
supports_order=False,
|
|
82
82
|
returns_value=False,
|
|
83
83
|
)
|
|
84
|
+
navigate_callback = CallbackInfo(
|
|
85
|
+
name="navigate",
|
|
86
|
+
py_name="navigate",
|
|
87
|
+
supports_order=False,
|
|
88
|
+
returns_value=False,
|
|
89
|
+
)
|
|
90
|
+
update_callback = CallbackInfo(
|
|
91
|
+
name="update",
|
|
92
|
+
py_name="update",
|
|
93
|
+
supports_order=False,
|
|
94
|
+
returns_value=False,
|
|
95
|
+
)
|
|
84
96
|
|
|
85
97
|
|
|
86
98
|
def _by_name(*callbacks: CallbackInfo) -> dict[str, CallbackInfo]:
|
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
from collections.abc import Callable
|
|
4
|
+
from typing import Any
|
|
4
5
|
|
|
5
6
|
from sonolus.build.collection import Asset
|
|
6
7
|
from sonolus.script.archetype import BaseArchetype, PlayArchetype, PreviewArchetype, WatchArchetype
|
|
7
8
|
from sonolus.script.bucket import Buckets, EmptyBuckets
|
|
8
9
|
from sonolus.script.effect import Effects, EmptyEffects
|
|
10
|
+
from sonolus.script.instruction import (
|
|
11
|
+
EmptyInstructionIcons,
|
|
12
|
+
EmptyInstructions,
|
|
13
|
+
TutorialInstructionIcons,
|
|
14
|
+
TutorialInstructions,
|
|
15
|
+
)
|
|
9
16
|
from sonolus.script.options import EmptyOptions, Options
|
|
10
17
|
from sonolus.script.particle import EmptyParticles, Particles
|
|
11
18
|
from sonolus.script.sprite import EmptySkin, Skin
|
|
@@ -41,7 +48,7 @@ class Engine:
|
|
|
41
48
|
self.data = data
|
|
42
49
|
|
|
43
50
|
|
|
44
|
-
def default_callback() ->
|
|
51
|
+
def default_callback() -> Any:
|
|
45
52
|
return 0.0
|
|
46
53
|
|
|
47
54
|
|
|
@@ -104,6 +111,29 @@ class PreviewMode:
|
|
|
104
111
|
raise ValueError(f"archetype {archetype} is not a BaseArchetype")
|
|
105
112
|
|
|
106
113
|
|
|
114
|
+
class TutorialMode:
|
|
115
|
+
def __init__(
|
|
116
|
+
self,
|
|
117
|
+
*,
|
|
118
|
+
skin: Skin = EmptySkin,
|
|
119
|
+
effects: Effects = EmptyEffects,
|
|
120
|
+
particles: Particles = EmptyParticles,
|
|
121
|
+
instructions: TutorialInstructions = EmptyInstructions,
|
|
122
|
+
instruction_icons: TutorialInstructionIcons = EmptyInstructionIcons,
|
|
123
|
+
preprocess: Callable[[], None],
|
|
124
|
+
navigate: Callable[[], None],
|
|
125
|
+
update: Callable[[], None],
|
|
126
|
+
) -> None:
|
|
127
|
+
self.skin = skin
|
|
128
|
+
self.effects = effects
|
|
129
|
+
self.particles = particles
|
|
130
|
+
self.instructions = instructions
|
|
131
|
+
self.instruction_icons = instruction_icons
|
|
132
|
+
self.preprocess = preprocess
|
|
133
|
+
self.navigate = navigate
|
|
134
|
+
self.update = update
|
|
135
|
+
|
|
136
|
+
|
|
107
137
|
class EngineData:
|
|
108
138
|
def __init__(
|
|
109
139
|
self,
|
|
@@ -113,9 +143,15 @@ class EngineData:
|
|
|
113
143
|
play: PlayMode | None = None,
|
|
114
144
|
watch: WatchMode | None = None,
|
|
115
145
|
preview: PreviewMode | None = None,
|
|
146
|
+
tutorial: TutorialMode | None = None,
|
|
116
147
|
) -> None:
|
|
117
148
|
self.ui = ui or UiConfig()
|
|
118
149
|
self.options = options
|
|
119
150
|
self.play = play or PlayMode()
|
|
120
151
|
self.watch = watch or WatchMode(update_spawn=default_callback)
|
|
121
152
|
self.preview = preview or PreviewMode()
|
|
153
|
+
self.tutorial = tutorial or TutorialMode(
|
|
154
|
+
preprocess=default_callback,
|
|
155
|
+
navigate=default_callback,
|
|
156
|
+
update=default_callback,
|
|
157
|
+
)
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
from dataclasses import dataclass
|
|
2
|
+
from typing import Annotated, Any, NewType, dataclass_transform, get_origin
|
|
3
|
+
|
|
4
|
+
from sonolus.backend.ops import Op
|
|
5
|
+
from sonolus.script.internal.introspection import get_field_specifiers
|
|
6
|
+
from sonolus.script.internal.native import native_function
|
|
7
|
+
from sonolus.script.record import Record
|
|
8
|
+
from sonolus.script.runtime import _TutorialInstruction
|
|
9
|
+
from sonolus.script.text import StandardText
|
|
10
|
+
from sonolus.script.vec import Vec2
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class InstructionText(Record):
|
|
14
|
+
id: int
|
|
15
|
+
|
|
16
|
+
def show(self):
|
|
17
|
+
show_instruction(self)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class InstructionIcon(Record):
|
|
21
|
+
id: int
|
|
22
|
+
|
|
23
|
+
def paint(self, position: Vec2, size: float, rotation: float, z: float, a: float):
|
|
24
|
+
_paint(self.id, position.x, position.y, size, rotation, z, a)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
@dataclass
|
|
28
|
+
class InstructionTextInfo:
|
|
29
|
+
name: str
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
@dataclass
|
|
33
|
+
class InstructionIconInfo:
|
|
34
|
+
name: str
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def instruction(name: str) -> Any:
|
|
38
|
+
return InstructionTextInfo(name=name)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def instruction_icon(name: str) -> Any:
|
|
42
|
+
return InstructionIconInfo(name=name)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
type TutorialInstructions = NewType("TutorialInstructions", Any)
|
|
46
|
+
type TutorialInstructionIcons = NewType("TutorialInstructionIcons", Any)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
@dataclass_transform()
|
|
50
|
+
def instructions[T](cls: type[T]) -> T | TutorialInstructions:
|
|
51
|
+
if len(cls.__bases__) != 1:
|
|
52
|
+
raise ValueError("Instructions class must not inherit from any class (except object)")
|
|
53
|
+
instance = cls()
|
|
54
|
+
names = []
|
|
55
|
+
for i, (name, annotation) in enumerate(get_field_specifiers(cls).items()):
|
|
56
|
+
if get_origin(annotation) is not Annotated:
|
|
57
|
+
raise TypeError(f"Invalid annotation for instruction: {annotation}")
|
|
58
|
+
annotation_type = annotation.__args__[0]
|
|
59
|
+
annotation_values = annotation.__metadata__
|
|
60
|
+
if annotation_type is not InstructionText:
|
|
61
|
+
raise TypeError(
|
|
62
|
+
f"Invalid annotation for instruction: {annotation}, expected annotation of type InstructionText"
|
|
63
|
+
)
|
|
64
|
+
if len(annotation_values) != 1 or not isinstance(annotation_values[0], InstructionTextInfo):
|
|
65
|
+
raise TypeError(f"Invalid annotation for instruction: {annotation}, expected a single annotation value")
|
|
66
|
+
instruction_name = annotation_values[0].name
|
|
67
|
+
names.append(instruction_name)
|
|
68
|
+
setattr(instance, name, InstructionText(i))
|
|
69
|
+
instance._instructions_ = names
|
|
70
|
+
instance._is_comptime_value_ = True
|
|
71
|
+
return instance
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
@dataclass_transform()
|
|
75
|
+
def instruction_icons[T](cls: type[T]) -> T | TutorialInstructionIcons:
|
|
76
|
+
if len(cls.__bases__) != 1:
|
|
77
|
+
raise ValueError("Instruction icons class must not inherit from any class (except object)")
|
|
78
|
+
instance = cls()
|
|
79
|
+
names = []
|
|
80
|
+
for i, (name, annotation) in enumerate(get_field_specifiers(cls).items()):
|
|
81
|
+
if get_origin(annotation) is not Annotated:
|
|
82
|
+
raise TypeError(f"Invalid annotation for instruction icon: {annotation}")
|
|
83
|
+
annotation_type = annotation.__args__[0]
|
|
84
|
+
annotation_values = annotation.__metadata__
|
|
85
|
+
if annotation_type is not InstructionIcon:
|
|
86
|
+
raise TypeError(
|
|
87
|
+
f"Invalid annotation for instruction icon: {annotation}, expected annotation of type InstructionIcon"
|
|
88
|
+
)
|
|
89
|
+
if len(annotation_values) != 1 or not isinstance(annotation_values[0], InstructionIconInfo):
|
|
90
|
+
raise TypeError(
|
|
91
|
+
f"Invalid annotation for instruction icon: {annotation}, expected a single annotation value"
|
|
92
|
+
)
|
|
93
|
+
icon_name = annotation_values[0].name
|
|
94
|
+
names.append(icon_name)
|
|
95
|
+
setattr(instance, name, InstructionIcon(i))
|
|
96
|
+
instance._instruction_icons_ = names
|
|
97
|
+
instance._is_comptime_value_ = True
|
|
98
|
+
return instance
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
class StandardInstruction:
|
|
102
|
+
TAP = Annotated[InstructionText, instruction(StandardText.TAP)]
|
|
103
|
+
TAP_HOLD = Annotated[InstructionText, instruction(StandardText.TAP_HOLD)]
|
|
104
|
+
TAP_RELEASE = Annotated[InstructionText, instruction(StandardText.TAP_RELEASE)]
|
|
105
|
+
TAP_FLICK = Annotated[InstructionText, instruction(StandardText.TAP_FLICK)]
|
|
106
|
+
TAP_SLIDE = Annotated[InstructionText, instruction(StandardText.TAP_SLIDE)]
|
|
107
|
+
HOLD = Annotated[InstructionText, instruction(StandardText.HOLD)]
|
|
108
|
+
HOLD_SLIDE = Annotated[InstructionText, instruction(StandardText.HOLD_SLIDE)]
|
|
109
|
+
HOLD_FOLLOW = Annotated[InstructionText, instruction(StandardText.HOLD_FOLLOW)]
|
|
110
|
+
RELEASE = Annotated[InstructionText, instruction(StandardText.RELEASE)]
|
|
111
|
+
FLICK = Annotated[InstructionText, instruction(StandardText.FLICK)]
|
|
112
|
+
SLIDE = Annotated[InstructionText, instruction(StandardText.SLIDE)]
|
|
113
|
+
SLIDE_FLICK = Annotated[InstructionText, instruction(StandardText.SLIDE_FLICK)]
|
|
114
|
+
AVOID = Annotated[InstructionText, instruction(StandardText.AVOID)]
|
|
115
|
+
JIGGLE = Annotated[InstructionText, instruction(StandardText.JIGGLE)]
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
class StandardInstructionIcon:
|
|
119
|
+
HAND = Annotated[InstructionIcon, instruction_icon("#HAND")]
|
|
120
|
+
ARROW = Annotated[InstructionIcon, instruction_icon("#ARROW")]
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
@instructions
|
|
124
|
+
class EmptyInstructions:
|
|
125
|
+
pass
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
@instruction_icons
|
|
129
|
+
class EmptyInstructionIcons:
|
|
130
|
+
pass
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
@native_function(Op.Paint)
|
|
134
|
+
def _paint(
|
|
135
|
+
icon_id: int,
|
|
136
|
+
x: float,
|
|
137
|
+
y: float,
|
|
138
|
+
size: float,
|
|
139
|
+
rotation: float,
|
|
140
|
+
z: float,
|
|
141
|
+
a: float,
|
|
142
|
+
):
|
|
143
|
+
raise NotImplementedError()
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
def show_instruction(inst: InstructionText, /):
|
|
147
|
+
_TutorialInstruction.text_id = inst.id
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def clear_instruction():
|
|
151
|
+
_TutorialInstruction.text_id = -1
|
|
@@ -180,6 +180,9 @@ class ArrayReverser[V: ArrayLike](Record, ArrayLike):
|
|
|
180
180
|
def __setitem__(self, index: Num, value: V):
|
|
181
181
|
self.array[self.size() - 1 - index] = value
|
|
182
182
|
|
|
183
|
+
def reversed(self) -> ArrayLike[V]:
|
|
184
|
+
return self.array
|
|
185
|
+
|
|
183
186
|
|
|
184
187
|
class Enumerator[V: SonolusIterator](Record, SonolusIterator):
|
|
185
188
|
i: int
|
|
@@ -18,6 +18,7 @@ from sonolus.script.globals import (
|
|
|
18
18
|
_runtime_particle_transform,
|
|
19
19
|
_runtime_skin_transform,
|
|
20
20
|
_runtime_touch_array,
|
|
21
|
+
_tutorial_instruction,
|
|
21
22
|
_tutorial_runtime_environment,
|
|
22
23
|
_tutorial_runtime_ui,
|
|
23
24
|
_tutorial_runtime_ui_configuration,
|
|
@@ -181,6 +182,37 @@ class RuntimeUiLayout(Record):
|
|
|
181
182
|
self.background = background
|
|
182
183
|
|
|
183
184
|
|
|
185
|
+
class BasicRuntimeUiLayout(Record):
|
|
186
|
+
anchor: Vec2
|
|
187
|
+
pivot: Vec2
|
|
188
|
+
dimensions: Vec2
|
|
189
|
+
rotation: float
|
|
190
|
+
alpha: float
|
|
191
|
+
background: bool
|
|
192
|
+
|
|
193
|
+
def update(
|
|
194
|
+
self,
|
|
195
|
+
anchor: Vec2 | None = None,
|
|
196
|
+
pivot: Vec2 | None = None,
|
|
197
|
+
dimensions: Vec2 | None = None,
|
|
198
|
+
rotation: float | None = None,
|
|
199
|
+
alpha: float | None = None,
|
|
200
|
+
background: bool | None = None,
|
|
201
|
+
):
|
|
202
|
+
if anchor is not None:
|
|
203
|
+
self.anchor = anchor
|
|
204
|
+
if pivot is not None:
|
|
205
|
+
self.pivot = pivot
|
|
206
|
+
if dimensions is not None:
|
|
207
|
+
self.dimensions = dimensions
|
|
208
|
+
if rotation is not None:
|
|
209
|
+
self.rotation = rotation
|
|
210
|
+
if alpha is not None:
|
|
211
|
+
self.alpha = alpha
|
|
212
|
+
if background is not None:
|
|
213
|
+
self.background = background
|
|
214
|
+
|
|
215
|
+
|
|
184
216
|
@_play_runtime_ui
|
|
185
217
|
class _PlayRuntimeUi:
|
|
186
218
|
menu: RuntimeUiLayout
|
|
@@ -208,16 +240,16 @@ class _WatchRuntimeUi:
|
|
|
208
240
|
|
|
209
241
|
@_preview_runtime_ui
|
|
210
242
|
class _PreviewRuntimeUi:
|
|
211
|
-
menu:
|
|
212
|
-
progress:
|
|
243
|
+
menu: BasicRuntimeUiLayout
|
|
244
|
+
progress: BasicRuntimeUiLayout
|
|
213
245
|
|
|
214
246
|
|
|
215
247
|
@_tutorial_runtime_ui
|
|
216
248
|
class _TutorialRuntimeUi:
|
|
217
|
-
menu:
|
|
218
|
-
previous:
|
|
219
|
-
next:
|
|
220
|
-
instruction:
|
|
249
|
+
menu: BasicRuntimeUiLayout
|
|
250
|
+
previous: BasicRuntimeUiLayout
|
|
251
|
+
next: BasicRuntimeUiLayout
|
|
252
|
+
instruction: BasicRuntimeUiLayout
|
|
221
253
|
|
|
222
254
|
|
|
223
255
|
class Touch(Record):
|
|
@@ -392,6 +424,11 @@ class _LevelLife:
|
|
|
392
424
|
self.consecutive_good_step = consecutive_good_step
|
|
393
425
|
|
|
394
426
|
|
|
427
|
+
@_tutorial_instruction
|
|
428
|
+
class _TutorialInstruction:
|
|
429
|
+
text_id: int
|
|
430
|
+
|
|
431
|
+
|
|
395
432
|
@meta_fn
|
|
396
433
|
def is_debug() -> bool:
|
|
397
434
|
if not ctx():
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from typing import Self
|
|
2
2
|
|
|
3
|
-
from sonolus.script.math import atan2
|
|
3
|
+
from sonolus.script.math import atan2, cos, sin
|
|
4
4
|
from sonolus.script.num import Num
|
|
5
5
|
from sonolus.script.record import Record
|
|
6
6
|
|
|
@@ -44,6 +44,12 @@ class Vec2(Record):
|
|
|
44
44
|
def dot(self, other: Self) -> Num:
|
|
45
45
|
return self.x * other.x + self.y * other.y
|
|
46
46
|
|
|
47
|
+
def rotate(self, angle: Num) -> Self:
|
|
48
|
+
return Vec2(
|
|
49
|
+
x=self.x * cos(angle) - self.y * sin(angle),
|
|
50
|
+
y=self.x * sin(angle) + self.y * cos(angle),
|
|
51
|
+
)
|
|
52
|
+
|
|
47
53
|
@property
|
|
48
54
|
def tuple(self) -> tuple[float, float]:
|
|
49
55
|
return self.x, self.y
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
EMPTY_ENGINE_PLAY_DATA = {
|
|
2
|
-
"skin": {"sprites": []},
|
|
3
|
-
"effect": {"clips": []},
|
|
4
|
-
"particle": {"effects": []},
|
|
5
|
-
"buckets": [],
|
|
6
|
-
"archetypes": [],
|
|
7
|
-
"nodes": [{"value": 0}],
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
EMPTY_ENGINE_WATCH_DATA = {
|
|
11
|
-
"skin": {"sprites": []},
|
|
12
|
-
"effect": {"clips": []},
|
|
13
|
-
"particle": {"effects": []},
|
|
14
|
-
"buckets": [],
|
|
15
|
-
"archetypes": [],
|
|
16
|
-
"updateSpawn": 0,
|
|
17
|
-
"nodes": [{"value": 0}],
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
EMPTY_ENGINE_PREVIEW_DATA = {
|
|
21
|
-
"skin": {"sprites": []},
|
|
22
|
-
"archetypes": [],
|
|
23
|
-
"nodes": [{"value": 0}],
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
EMPTY_ENGINE_TUTORIAL_DATA = {
|
|
27
|
-
"skin": {"sprites": []},
|
|
28
|
-
"effect": {"clips": []},
|
|
29
|
-
"particle": {"effects": []},
|
|
30
|
-
"instruction": {"texts": [], "icons": []},
|
|
31
|
-
"nodes": [{"value": 0}],
|
|
32
|
-
}
|
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
from enum import StrEnum
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
class StandardIcon(StrEnum):
|
|
5
|
-
ADVANCED = "advanced"
|
|
6
|
-
ANGLE_DOWN = "angleDown"
|
|
7
|
-
ANGLE_LEFT = "angleLeft"
|
|
8
|
-
ANGLE_RIGHT = "angleRight"
|
|
9
|
-
ANGLES_DOWN = "anglesDown"
|
|
10
|
-
ANGLES_LEFT = "anglesLeft"
|
|
11
|
-
ANGLES_RIGHT = "anglesRight"
|
|
12
|
-
ANGLES_UP = "anglesUp"
|
|
13
|
-
ANGLE_UP = "angleUp"
|
|
14
|
-
ARROW_DOWN = "arrowDown"
|
|
15
|
-
ARROW_LEFT = "arrowLeft"
|
|
16
|
-
ARROW_RIGHT = "arrowRight"
|
|
17
|
-
ARROW_UP = "arrowUp"
|
|
18
|
-
AWARD = "award"
|
|
19
|
-
BACKGROUND = "background"
|
|
20
|
-
BELL = "bell"
|
|
21
|
-
BELL_SLASH = "bellSlash"
|
|
22
|
-
BOOKMARK = "bookmark"
|
|
23
|
-
BOOKMARK_HOLLOW = "bookmarkHollow"
|
|
24
|
-
CHECK = "check"
|
|
25
|
-
CLOCK = "clock"
|
|
26
|
-
COMMENT = "comment"
|
|
27
|
-
CROWN = "crown"
|
|
28
|
-
DELETE = "delete"
|
|
29
|
-
EDIT = "edit"
|
|
30
|
-
EFFECT = "effect"
|
|
31
|
-
ENGINE = "engine"
|
|
32
|
-
ENVELOPE = "envelope"
|
|
33
|
-
ENVELOPE_OPEN = "envelopeOpen"
|
|
34
|
-
GLOBE = "globe"
|
|
35
|
-
HEART = "heart"
|
|
36
|
-
HEART_HOLLOW = "heartHollow"
|
|
37
|
-
HIDE = "hide"
|
|
38
|
-
INFORMATION = "information"
|
|
39
|
-
LEVEL = "level"
|
|
40
|
-
LOCK = "lock"
|
|
41
|
-
MEDAL = "medal"
|
|
42
|
-
MESSAGE = "message"
|
|
43
|
-
MINUS = "minus"
|
|
44
|
-
OPTIONS = "options"
|
|
45
|
-
PARTICLE = "particle"
|
|
46
|
-
PIN = "pin"
|
|
47
|
-
PLAYER = "player"
|
|
48
|
-
PLAYLIST = "playlist"
|
|
49
|
-
PLUS = "plus"
|
|
50
|
-
POST = "post"
|
|
51
|
-
QUESTION = "question"
|
|
52
|
-
RANKING = "ranking"
|
|
53
|
-
REPLAY = "replay"
|
|
54
|
-
REPLY = "reply"
|
|
55
|
-
RESTORE = "restore"
|
|
56
|
-
ROOM = "room"
|
|
57
|
-
SEARCH = "search"
|
|
58
|
-
SETTINGS = "settings"
|
|
59
|
-
SHOW = "show"
|
|
60
|
-
SHUFFLE = "shuffle"
|
|
61
|
-
SKIN = "skin"
|
|
62
|
-
STAR = "star"
|
|
63
|
-
STAR_HALF = "starHalf"
|
|
64
|
-
STAR_HOLLOW = "starHollow"
|
|
65
|
-
STOPWATCH = "stopwatch"
|
|
66
|
-
TAG = "tag"
|
|
67
|
-
THUMBS_DOWN = "thumbsDown"
|
|
68
|
-
THUMBS_DOWN_HOLLOW = "thumbsDownHollow"
|
|
69
|
-
THUMBS_UP = "thumbsUp"
|
|
70
|
-
THUMBS_UP_HOLLOW = "thumbsUpHollow"
|
|
71
|
-
TROPHY = "trophy"
|
|
72
|
-
UNLOCK = "unlock"
|
|
73
|
-
X_MARK = "xMark"
|
|
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
|
|
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
|