batframework 1.1.0__py3-none-any.whl → 2.0.0a1__py3-none-any.whl
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.
- batFramework/__init__.py +84 -52
- batFramework/action.py +280 -252
- batFramework/actionContainer.py +105 -38
- batFramework/animatedSprite.py +81 -117
- batFramework/animation.py +91 -0
- batFramework/audioManager.py +156 -85
- batFramework/baseScene.py +249 -0
- batFramework/camera.py +245 -123
- batFramework/constants.py +57 -75
- batFramework/cutscene.py +239 -119
- batFramework/cutsceneManager.py +34 -0
- batFramework/drawable.py +107 -0
- batFramework/dynamicEntity.py +30 -23
- batFramework/easingController.py +58 -0
- batFramework/entity.py +130 -123
- batFramework/enums.py +171 -0
- batFramework/fontManager.py +65 -0
- batFramework/gui/__init__.py +28 -14
- batFramework/gui/animatedLabel.py +90 -0
- batFramework/gui/button.py +18 -84
- batFramework/gui/clickableWidget.py +244 -0
- batFramework/gui/collapseContainer.py +98 -0
- batFramework/gui/constraints/__init__.py +1 -0
- batFramework/gui/constraints/constraints.py +1066 -0
- batFramework/gui/container.py +220 -49
- batFramework/gui/debugger.py +140 -47
- batFramework/gui/draggableWidget.py +63 -0
- batFramework/gui/image.py +61 -23
- batFramework/gui/indicator.py +116 -40
- batFramework/gui/interactiveWidget.py +243 -22
- batFramework/gui/label.py +147 -110
- batFramework/gui/layout.py +442 -81
- batFramework/gui/meter.py +155 -0
- batFramework/gui/radioButton.py +43 -0
- batFramework/gui/root.py +228 -60
- batFramework/gui/scrollingContainer.py +282 -0
- batFramework/gui/selector.py +232 -0
- batFramework/gui/shape.py +286 -86
- batFramework/gui/slider.py +353 -0
- batFramework/gui/style.py +10 -0
- batFramework/gui/styleManager.py +49 -0
- batFramework/gui/syncedVar.py +43 -0
- batFramework/gui/textInput.py +331 -0
- batFramework/gui/textWidget.py +308 -0
- batFramework/gui/toggle.py +140 -62
- batFramework/gui/tooltip.py +35 -0
- batFramework/gui/widget.py +546 -307
- batFramework/manager.py +131 -50
- batFramework/particle.py +118 -0
- batFramework/propertyEaser.py +79 -0
- batFramework/renderGroup.py +34 -0
- batFramework/resourceManager.py +130 -0
- batFramework/scene.py +31 -226
- batFramework/sceneLayer.py +134 -0
- batFramework/sceneManager.py +200 -165
- batFramework/scrollingSprite.py +115 -0
- batFramework/sprite.py +46 -0
- batFramework/stateMachine.py +49 -51
- batFramework/templates/__init__.py +2 -0
- batFramework/templates/character.py +15 -0
- batFramework/templates/controller.py +158 -0
- batFramework/templates/stateMachine.py +39 -0
- batFramework/tileset.py +46 -0
- batFramework/timeManager.py +213 -0
- batFramework/transition.py +162 -157
- batFramework/triggerZone.py +22 -22
- batFramework/utils.py +306 -184
- {batframework-1.1.0.dist-info → batframework-2.0.0a1.dist-info}/LICENSE +20 -20
- {batframework-1.1.0.dist-info → batframework-2.0.0a1.dist-info}/METADATA +7 -2
- batframework-2.0.0a1.dist-info/RECORD +72 -0
- batFramework/cutsceneBlocks.py +0 -176
- batFramework/debugger.py +0 -48
- batFramework/easing.py +0 -71
- batFramework/gui/constraints.py +0 -204
- batFramework/gui/frame.py +0 -19
- batFramework/particles.py +0 -77
- batFramework/time.py +0 -75
- batFramework/transitionManager.py +0 -0
- batframework-1.1.0.dist-info/RECORD +0 -43
- {batframework-1.1.0.dist-info → batframework-2.0.0a1.dist-info}/WHEEL +0 -0
- {batframework-1.1.0.dist-info → batframework-2.0.0a1.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,158 @@
|
|
1
|
+
import batFramework as bf
|
2
|
+
import pygame
|
3
|
+
from .stateMachine import *
|
4
|
+
|
5
|
+
|
6
|
+
|
7
|
+
class PlatformController(bf.DynamicEntity):
|
8
|
+
def __init__(self,*args,**kwargs):
|
9
|
+
super().__init__(*args,**kwargs)
|
10
|
+
self.control = bf.ActionContainer()
|
11
|
+
self.speed = 500
|
12
|
+
self.acceleration = 100
|
13
|
+
self.jump_force = -500
|
14
|
+
self.gravity = 1200
|
15
|
+
self.terminal_velocity = 1000
|
16
|
+
self.on_ground = False
|
17
|
+
self.friction = 0.7
|
18
|
+
|
19
|
+
def reset_actions(self):
|
20
|
+
self.control.reset()
|
21
|
+
|
22
|
+
def process_actions(self, event):
|
23
|
+
self.control.process_event(event)
|
24
|
+
|
25
|
+
def check_collision_y(self):
|
26
|
+
pass
|
27
|
+
|
28
|
+
def check_collision_x(self):
|
29
|
+
pass
|
30
|
+
|
31
|
+
def update(self, dt):
|
32
|
+
super().update(dt)
|
33
|
+
if (not self.control.is_active("right")) and (not self.control.is_active("left")):
|
34
|
+
self.velocity.x *= self.friction
|
35
|
+
if abs(self.velocity.x) <= 0.01:
|
36
|
+
self.velocity.x = 0
|
37
|
+
if not self.on_ground:
|
38
|
+
self.velocity.y += self.gravity * dt
|
39
|
+
if self.velocity.y > self.terminal_velocity:
|
40
|
+
self.velocity.y = self.terminal_velocity
|
41
|
+
if self.control.is_active("left"):
|
42
|
+
self.velocity.x -= self.acceleration
|
43
|
+
if self.control.is_active("right"):
|
44
|
+
self.velocity.x += self.acceleration
|
45
|
+
if self.on_ground and self.control.is_active("jump") :
|
46
|
+
self.velocity.y = self.jump_force
|
47
|
+
self.on_ground = False
|
48
|
+
|
49
|
+
self.velocity.x = pygame.math.clamp(self.velocity.x,-self.speed,self.speed)
|
50
|
+
self.rect.y += self.velocity.y * dt
|
51
|
+
self.check_collision_y()
|
52
|
+
self.rect.x += self.velocity.x * dt
|
53
|
+
self.check_collision_x()
|
54
|
+
|
55
|
+
|
56
|
+
|
57
|
+
class TopDownController(bf.DynamicEntity):
|
58
|
+
def __init__(self,*args,**kwargs):
|
59
|
+
super().__init__(*args,**kwargs)
|
60
|
+
self.control = bf.ActionContainer()
|
61
|
+
self.input_velocity = pygame.Vector2()
|
62
|
+
self.speed = 500
|
63
|
+
self.acceleration = 100
|
64
|
+
self.friction = 0
|
65
|
+
|
66
|
+
def reset_actions(self):
|
67
|
+
self.control.reset()
|
68
|
+
|
69
|
+
def process_actions(self, event):
|
70
|
+
self.control.process_event(event)
|
71
|
+
|
72
|
+
def check_collision_y(self):
|
73
|
+
pass
|
74
|
+
|
75
|
+
def check_collision_x(self):
|
76
|
+
pass
|
77
|
+
|
78
|
+
def update(self, dt):
|
79
|
+
super().update(dt)
|
80
|
+
self.input_velocity.update(0,0)
|
81
|
+
self.velocity *= self.friction
|
82
|
+
|
83
|
+
if abs(self.velocity.x) <= 0.01:
|
84
|
+
self.velocity.x = 0
|
85
|
+
if self.control.is_active("left"):
|
86
|
+
self.input_velocity[0] = -self.acceleration
|
87
|
+
if self.control.is_active("right"):
|
88
|
+
self.input_velocity[0] = self.acceleration
|
89
|
+
if self.control.is_active("up"):
|
90
|
+
self.input_velocity[1] = -self.acceleration
|
91
|
+
if self.control.is_active("down"):
|
92
|
+
self.input_velocity[1] = self.acceleration
|
93
|
+
|
94
|
+
if self.input_velocity:
|
95
|
+
self.input_velocity.normalize_ip()
|
96
|
+
|
97
|
+
self.velocity += self.input_velocity * self.acceleration
|
98
|
+
self.velocity.clamp_magnitude_ip(self.speed)
|
99
|
+
|
100
|
+
|
101
|
+
self.rect.x += self.velocity.x * dt
|
102
|
+
self.check_collision_x()
|
103
|
+
self.rect.y += self.velocity.y * dt
|
104
|
+
self.check_collision_y()
|
105
|
+
|
106
|
+
|
107
|
+
|
108
|
+
|
109
|
+
class CameraController(bf.Entity):
|
110
|
+
def __init__(self, *args, **kwargs):
|
111
|
+
super().__init__(*args, **kwargs)
|
112
|
+
self.origin = None # Previous frame's world mouse pos
|
113
|
+
self.mouse_actions = bf.ActionContainer(
|
114
|
+
bf.Action("control").add_key_control(pygame.K_LCTRL).set_holding(),
|
115
|
+
bf.Action("drag").add_mouse_control(1).set_holding().set_consume_event(True),
|
116
|
+
bf.Action("zoom_in").add_mouse_control(4).set_consume_event(True),
|
117
|
+
bf.Action("zoom_out").add_mouse_control(5).set_consume_event(True),
|
118
|
+
)
|
119
|
+
|
120
|
+
def reset_actions(self):
|
121
|
+
self.mouse_actions.reset()
|
122
|
+
|
123
|
+
def process_actions(self, event):
|
124
|
+
self.mouse_actions.process_event(event)
|
125
|
+
if self.mouse_actions["drag"] and event.type == pygame.MOUSEMOTION:
|
126
|
+
event.consumed = True
|
127
|
+
|
128
|
+
def do_update(self, dt):
|
129
|
+
cam = self.parent_layer.camera
|
130
|
+
if self.mouse_actions["zoom_in"]:
|
131
|
+
if self.mouse_actions["control"]:
|
132
|
+
cam.rotate_by(10)
|
133
|
+
else:
|
134
|
+
cam.zoom(cam.zoom_factor * 1.1)
|
135
|
+
|
136
|
+
elif self.mouse_actions["zoom_out"]:
|
137
|
+
if self.mouse_actions["control"]:
|
138
|
+
cam.rotate_by(-10)
|
139
|
+
else:
|
140
|
+
cam.zoom(cam.zoom_factor / 1.1)
|
141
|
+
|
142
|
+
if self.mouse_actions["drag"]:
|
143
|
+
mouse_world = cam.get_mouse_pos()
|
144
|
+
cam_pos = cam.world_rect.topleft
|
145
|
+
|
146
|
+
if self.origin is None:
|
147
|
+
self.origin = (mouse_world[0] - cam_pos[0], mouse_world[1] - cam_pos[1])
|
148
|
+
else:
|
149
|
+
offset = (mouse_world[0] - cam_pos[0], mouse_world[1] - cam_pos[1])
|
150
|
+
dx = offset[0] - self.origin[0]
|
151
|
+
dy = offset[1] - self.origin[1]
|
152
|
+
|
153
|
+
cam.move_by(-dx, -dy)
|
154
|
+
self.origin = (mouse_world[0] - cam_pos[0], mouse_world[1] - cam_pos[1])
|
155
|
+
|
156
|
+
|
157
|
+
else:
|
158
|
+
self.origin = None
|
@@ -0,0 +1,39 @@
|
|
1
|
+
import batFramework as bf
|
2
|
+
import pygame
|
3
|
+
from batFramework.stateMachine import State,StateMachine
|
4
|
+
from ..animation import Animation
|
5
|
+
from ..animatedSprite import AnimatedSprite
|
6
|
+
|
7
|
+
class AnimatedState(State):
|
8
|
+
|
9
|
+
def __init__(self, animation:str):
|
10
|
+
super().__init__(animation)
|
11
|
+
self._transition : dict[str,str] = {}
|
12
|
+
self.animation = animation
|
13
|
+
|
14
|
+
def add_transition(self,dest:str,transition_animation:str):
|
15
|
+
self._transition[dest] = transition_animation
|
16
|
+
|
17
|
+
|
18
|
+
class AnimatedStateMachine(StateMachine):
|
19
|
+
def __init__(self, parent:AnimatedSprite):
|
20
|
+
self.states: dict[str, AnimatedState] = {}
|
21
|
+
self.parent:AnimatedSprite = parent
|
22
|
+
self.current_state = None
|
23
|
+
|
24
|
+
def set_state(self, state_name: str,reset_counter:bool = True):
|
25
|
+
|
26
|
+
if state_name not in self.states:
|
27
|
+
return
|
28
|
+
|
29
|
+
if self.current_state:
|
30
|
+
self.current_state.on_exit()
|
31
|
+
|
32
|
+
if self.current_state and state_name in self.current_state._transition:
|
33
|
+
self.parent.set_animation(self.current_state._transition[state_name],reset_counter,0,self.states[state_name].animation)
|
34
|
+
else:
|
35
|
+
self.parent.set_animation(self.states[state_name].animation,reset_counter)
|
36
|
+
|
37
|
+
self.current_state = self.states[state_name]
|
38
|
+
self.current_state.on_enter()
|
39
|
+
|
batFramework/tileset.py
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
import pygame
|
2
|
+
from .resourceManager import ResourceManager
|
3
|
+
import batFramework as bf
|
4
|
+
|
5
|
+
|
6
|
+
class Tileset:
|
7
|
+
def __init__(self, source: pygame.Surface, tilesize: tuple[int, int]) -> None:
|
8
|
+
self.surface = source
|
9
|
+
self.tile_size = tilesize
|
10
|
+
self.tile_width = source.get_width() // tilesize[0]
|
11
|
+
self.tile_height = source.get_height() // tilesize[1]
|
12
|
+
# Create flipped versions of the tileset surface
|
13
|
+
self.flipped_surfaces = {
|
14
|
+
(False, False): self.surface,
|
15
|
+
(False, True): pygame.transform.flip(self.surface, False, True),
|
16
|
+
(True, False): pygame.transform.flip(self.surface, True, False),
|
17
|
+
(True, True): pygame.transform.flip(self.surface, True, True),
|
18
|
+
}
|
19
|
+
|
20
|
+
# Split each of the surfaces into tiles
|
21
|
+
self.tile_dict = {}
|
22
|
+
for flip_state, surf in self.flipped_surfaces.items():
|
23
|
+
tiles = bf.utils.split_surface(surf, self.tile_size)
|
24
|
+
for coord, tile in tiles.items():
|
25
|
+
if coord not in self.tile_dict:
|
26
|
+
self.tile_dict[coord] = {}
|
27
|
+
self.tile_dict[coord][flip_state] = tile
|
28
|
+
|
29
|
+
def __str__(self) -> str:
|
30
|
+
num_tiles = 0
|
31
|
+
if self.tile_dict:
|
32
|
+
num_tiles = len(self.tile_dict.values())
|
33
|
+
return f"{num_tiles} tiles | Tile size : {self.tile_size}"
|
34
|
+
|
35
|
+
def get_tile(
|
36
|
+
self, x: int, y: int, flipX=False, flipY=False
|
37
|
+
) -> pygame.Surface | None:
|
38
|
+
if flipX:
|
39
|
+
x = self.tile_width - 1 - x
|
40
|
+
if flipY:
|
41
|
+
y = self.tile_height - 1 - y
|
42
|
+
tile_data = self.tile_dict.get((x, y), None)
|
43
|
+
if tile_data is None:
|
44
|
+
return None
|
45
|
+
|
46
|
+
return tile_data.get((flipX, flipY), None)
|
@@ -0,0 +1,213 @@
|
|
1
|
+
import batFramework as bf
|
2
|
+
from typing import Callable, Union, Self,Any
|
3
|
+
|
4
|
+
class Timer:
|
5
|
+
_count: int = 0
|
6
|
+
_available_ids: set[int] = set()
|
7
|
+
|
8
|
+
def __init__(self, duration: float, end_callback: Callable[[], Any], loop: int = 0, register: str = "global") -> None:
|
9
|
+
if Timer._available_ids:
|
10
|
+
self.uid = Timer._available_ids.pop()
|
11
|
+
else:
|
12
|
+
self.uid = Timer._count
|
13
|
+
Timer._count += 1
|
14
|
+
|
15
|
+
self.register = register
|
16
|
+
self.duration: float = duration
|
17
|
+
self.end_callback = end_callback
|
18
|
+
|
19
|
+
self.elapsed_time: float = 0
|
20
|
+
self.is_over: bool = False
|
21
|
+
self.loop: int = loop # Number of loops (-1 for infinite)
|
22
|
+
self.is_paused: bool = False
|
23
|
+
self.do_delete: bool = False
|
24
|
+
self.is_stopped: bool = True
|
25
|
+
|
26
|
+
def __bool__(self) -> bool:
|
27
|
+
return self.elapsed_time != -1 and self.is_over
|
28
|
+
|
29
|
+
def __str__(self) -> str:
|
30
|
+
loop_info = "infinite" if self.loop == -1 else f"{self.loop} loops left"
|
31
|
+
return f"Timer ({self.uid}) {self.elapsed_time}/{self.duration} | {loop_info} {'(D) ' if self.do_delete else ''}"
|
32
|
+
|
33
|
+
def stop(self) -> Self:
|
34
|
+
"""
|
35
|
+
Cancels all progression and stops the timer.
|
36
|
+
Does not mark it for deletion and does not call the end_callback.
|
37
|
+
Prevents automatic restart if looping.
|
38
|
+
"""
|
39
|
+
self.is_stopped = True
|
40
|
+
self.is_paused = False
|
41
|
+
self.is_over = False
|
42
|
+
self.elapsed_time = 0
|
43
|
+
return self
|
44
|
+
|
45
|
+
def start(self, force: bool = False) -> Self:
|
46
|
+
"""
|
47
|
+
Starts the timer only if not already started (unless force is used, which resets it).
|
48
|
+
"""
|
49
|
+
if self.elapsed_time > 0 and not force:
|
50
|
+
return self
|
51
|
+
if not bf.TimeManager().add_timer(self, self.register):
|
52
|
+
return self
|
53
|
+
self.elapsed_time = 0
|
54
|
+
self.is_paused = False
|
55
|
+
self.is_over = False
|
56
|
+
self.is_stopped = False
|
57
|
+
return self
|
58
|
+
|
59
|
+
def pause(self) -> Self:
|
60
|
+
"""
|
61
|
+
Momentarily stops the timer until resume is called.
|
62
|
+
"""
|
63
|
+
self.is_paused = True
|
64
|
+
return self
|
65
|
+
|
66
|
+
def resume(self) -> Self:
|
67
|
+
"""
|
68
|
+
Resumes from a paused state.
|
69
|
+
"""
|
70
|
+
self.is_paused = False
|
71
|
+
return self
|
72
|
+
|
73
|
+
def delete(self) -> Self:
|
74
|
+
"""
|
75
|
+
Marks the timer for deletion.
|
76
|
+
"""
|
77
|
+
self.do_delete = True
|
78
|
+
return self
|
79
|
+
|
80
|
+
def has_started(self) -> bool:
|
81
|
+
"""
|
82
|
+
Returns True if the timer has started.
|
83
|
+
"""
|
84
|
+
return not self.is_stopped
|
85
|
+
|
86
|
+
def get_progression(self) -> float:
|
87
|
+
"""
|
88
|
+
Returns the progression of the timer (0 to 1) as a float.
|
89
|
+
"""
|
90
|
+
if self.is_stopped:
|
91
|
+
return 0
|
92
|
+
if self.elapsed_time >= self.duration:
|
93
|
+
return 1
|
94
|
+
return self.elapsed_time / self.duration
|
95
|
+
|
96
|
+
def update(self, dt) -> None:
|
97
|
+
if self.is_stopped or self.is_paused or self.is_over:
|
98
|
+
return
|
99
|
+
self.elapsed_time += dt
|
100
|
+
if self.get_progression() == 1:
|
101
|
+
self.end()
|
102
|
+
|
103
|
+
def end(self):
|
104
|
+
"""
|
105
|
+
Ends the timer progression (calls the end_callback function).
|
106
|
+
Is called automatically once the timer is over.
|
107
|
+
Will not mark the timer for deletion.
|
108
|
+
If it is looping, it will restart the timer **only if it wasn't stopped**.
|
109
|
+
"""
|
110
|
+
self.is_over = True
|
111
|
+
if self.end_callback:
|
112
|
+
self.end_callback()
|
113
|
+
|
114
|
+
# Handle looping
|
115
|
+
if self.loop == -1: # Infinite looping
|
116
|
+
self.elapsed_time = 0
|
117
|
+
self.start()
|
118
|
+
return
|
119
|
+
elif self.loop > 0: # Decrease loop count and restart
|
120
|
+
self.loop -= 1
|
121
|
+
self.elapsed_time = 0
|
122
|
+
self.start()
|
123
|
+
return
|
124
|
+
|
125
|
+
# Stop the timer if no loops are left
|
126
|
+
self.is_stopped = True
|
127
|
+
|
128
|
+
def should_delete(self) -> bool:
|
129
|
+
"""
|
130
|
+
Method that returns if the timer is to be deleted.
|
131
|
+
Required for timer management.
|
132
|
+
"""
|
133
|
+
return self.is_over or self.do_delete
|
134
|
+
|
135
|
+
def _release_id(self):
|
136
|
+
Timer._available_ids.add(self.uid)
|
137
|
+
|
138
|
+
class SceneTimer(Timer):
|
139
|
+
"""
|
140
|
+
A timer that is only updated while the given scene is active (being updated)
|
141
|
+
"""
|
142
|
+
def __init__(self, duration: float | int, end_callback, loop: int = 0, scene_name:str = "global") -> None:
|
143
|
+
super().__init__(duration, end_callback, loop, scene_name)
|
144
|
+
|
145
|
+
class TimeManager(metaclass=bf.Singleton):
|
146
|
+
class TimerRegister:
|
147
|
+
def __init__(self, active=True):
|
148
|
+
self.active = active
|
149
|
+
self.timers: dict[int | str, Timer] = {}
|
150
|
+
|
151
|
+
def __iter__(self):
|
152
|
+
return iter(self.timers.values())
|
153
|
+
|
154
|
+
def add_timer(self, timer: Timer):
|
155
|
+
self.timers[timer.uid] = timer
|
156
|
+
|
157
|
+
def update(self, dt):
|
158
|
+
expired_timers = []
|
159
|
+
for timer in list(self.timers.values()):
|
160
|
+
if not timer.is_paused:
|
161
|
+
timer.update(dt)
|
162
|
+
if timer.should_delete():
|
163
|
+
expired_timers.append(timer.uid)
|
164
|
+
for uid in expired_timers:
|
165
|
+
self.timers[uid]._release_id()
|
166
|
+
del self.timers[uid]
|
167
|
+
|
168
|
+
def __init__(self):
|
169
|
+
self.registers = {"global": TimeManager.TimerRegister()}
|
170
|
+
|
171
|
+
def add_register(self, name, active=True):
|
172
|
+
if name not in self.registers:
|
173
|
+
self.registers[name] = TimeManager.TimerRegister(active)
|
174
|
+
|
175
|
+
def remove_register(self, name):
|
176
|
+
if name not in self.registers:
|
177
|
+
return
|
178
|
+
|
179
|
+
self.registers.pop(name)
|
180
|
+
|
181
|
+
|
182
|
+
def add_timer(self, timer, register="global") -> bool:
|
183
|
+
if register in self.registers:
|
184
|
+
self.registers[register].add_timer(timer)
|
185
|
+
return True
|
186
|
+
print(f"Register '{register}' does not exist.")
|
187
|
+
return False
|
188
|
+
|
189
|
+
def get_active_registers(self) -> list[TimerRegister]:
|
190
|
+
return [t for t in self.registers.values() if t.active]
|
191
|
+
|
192
|
+
def update(self, dt):
|
193
|
+
for register in self.registers.values():
|
194
|
+
if register.active:
|
195
|
+
register.update(dt)
|
196
|
+
|
197
|
+
def activate_register(self, name, active=True):
|
198
|
+
if name in self.registers:
|
199
|
+
self.registers[name].active = active
|
200
|
+
else:
|
201
|
+
print(f"Register '{name}' does not exist.")
|
202
|
+
|
203
|
+
def deactivate_register(self, name):
|
204
|
+
self.activate_register(name, active=False)
|
205
|
+
|
206
|
+
def __str__(self)->str:
|
207
|
+
res = ""
|
208
|
+
for name,reg in self.registers.items():
|
209
|
+
if not reg.timers:continue
|
210
|
+
res +=name+"\n"
|
211
|
+
for t in reg.timers.values():
|
212
|
+
res +="\t"+str(t)+"\n"
|
213
|
+
return res
|