-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathaction.py
144 lines (116 loc) · 5.04 KB
/
action.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
from typing import TYPE_CHECKING
from abc import ABCMeta, abstractmethod
from core import RELEASE_DELAY, HAND_RADIUS_MAX
if TYPE_CHECKING:
from core import Pad
from simai import SimaiNote
from slides import SlidePath
class Action(metaclass=ABCMeta):
def __init__(self, source: "SimaiNote", moment: float, two_hands: bool):
"""
Base class of all hand actions.
@param source: the original note producing this action
@param moment: the music timestamp when action is performed, in ticks
"""
self.source = source
self.moment = moment
self.require_two_hands = two_hands
@abstractmethod
def update(self, now: float) -> None | tuple[complex, float, complex]:
"""
Update action routine.
@param now: current music timestamp in ticks
@return: None if no action is performed, or the touch circle in (center, radius, tangent), tangent is normalized
"""
raise NotImplementedError
@abstractmethod
def finish(self, now: float) -> bool:
"""
whether the action is finished
@param now: current music timestamp in ticks
"""
raise NotImplementedError
def merge_key(self) -> None | str:
return None
def __repr__(self):
return "<Action \"{2}\" L{0}, C{1}>".format(*self.source.cursor)
class ActionPress(Action):
def __init__(
self, source: "SimaiNote", moment: float, duration: float,
position: complex, radius: float, tailless: bool = False
):
"""
Press actions, press a position for some time interval.
@param source: the original note producing this action
@param moment: the music timestamp when action is performed (press down), in ticks
@param duration: the duration of the press action in ticks
@param position: where to press, vector expressed in complex, 0 is at the center of the screen
@param radius: the radius of the hand in pixels
@param tailless: no delay release
"""
super().__init__(source, moment, radius > HAND_RADIUS_MAX)
self.position = position
self.duration = duration
self.radius = radius
self.end_moment = moment + duration
if not tailless:
self.end_moment += RELEASE_DELAY
def update(self, now: float) -> None | tuple[complex, float, complex]:
if self.moment <= now < self.end_moment:
pass
return self.position, self.radius, 0
return None
def finish(self, now: float) -> bool:
return now >= self.end_moment
class ActionSlide(Action):
def __init__(
self, source: "SimaiNote", moment: float, duration: float,
path: "SlidePath", radius: float, tailless: bool = False, is_wifi = False
):
"""
Slide actions, press a position and move along a path in some time interval.
@param source: the original note producing this action
@param moment: the music timestamp when action is performed (press down), in ticks
@param duration: the duration of the slide action in ticks
@param path: slide path
@param radius: the radius of the hand in pixels
@param tailless: no delay release
"""
super().__init__(source, moment, False)
self.duration = duration
self.radius = radius
self.path = path
self.end_moment = moment + duration
if not tailless:
self.end_moment += RELEASE_DELAY
self.is_wifi = is_wifi
def update(self, now: float) -> None | tuple[complex, float, complex]:
if self.moment <= now < self.end_moment:
t = (now - self.moment) / self.duration
if t >= 1:
t = 1
tan = self.path.tangent(t)
return self.path.point(t), self.radius, tan / abs(tan)
return None
def finish(self, now: float) -> bool:
return now >= self.end_moment
def merge_key(self) -> None | str:
return "wifi" if self.is_wifi else "normal"
class ActionExtraPadDown(Action):
def __init__(self, source: "SimaiNote", moment: float, pad: "Pad", delay: float):
"""
Dummy action for tap-slide. Won't perform anything by itself.
When using outer buttons to play tap-slide, pad A is touched about 50 ms later.
This action is to record that extra touch, but it won't perform that touch by itself.
Instead, judging manager will check if an action is an instance of this class and create extra pad down event.
模拟外屏拍星星进入A区时的额外判定
@param source: the original note producing this action
@param moment: the music timestamp when action is performed (press down), in ticks
@param pad: the pad which should be pressed
"""
super().__init__(source, moment + delay, False)
self.pad = pad
def update(self, now: float) -> None | tuple[complex, float, complex]:
return None
def finish(self, now: float) -> bool:
return now > self.moment