mima-engine 0.4.0__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.
Files changed (153) hide show
  1. mima/__init__.py +4 -0
  2. mima/backend/__init__.py +1 -0
  3. mima/backend/pygame_assets.py +401 -0
  4. mima/backend/pygame_audio.py +78 -0
  5. mima/backend/pygame_backend.py +603 -0
  6. mima/backend/pygame_camera.py +63 -0
  7. mima/backend/pygame_events.py +695 -0
  8. mima/backend/touch_control_scheme_a.py +126 -0
  9. mima/backend/touch_control_scheme_b.py +132 -0
  10. mima/core/__init__.py +0 -0
  11. mima/core/collision.py +325 -0
  12. mima/core/database.py +58 -0
  13. mima/core/engine.py +367 -0
  14. mima/core/mode_engine.py +81 -0
  15. mima/core/scene_engine.py +81 -0
  16. mima/integrated/__init__.py +0 -0
  17. mima/integrated/entity.py +183 -0
  18. mima/integrated/layered_map.py +351 -0
  19. mima/integrated/sprite.py +156 -0
  20. mima/layered/__init__.py +0 -0
  21. mima/layered/assets.py +56 -0
  22. mima/layered/scene.py +415 -0
  23. mima/layered/shape.py +99 -0
  24. mima/layered/shaped_sprite.py +78 -0
  25. mima/layered/virtual_input.py +302 -0
  26. mima/maps/__init__.py +0 -0
  27. mima/maps/template.py +71 -0
  28. mima/maps/tile.py +20 -0
  29. mima/maps/tile_animation.py +7 -0
  30. mima/maps/tile_info.py +10 -0
  31. mima/maps/tile_layer.py +52 -0
  32. mima/maps/tiled/__init__.py +0 -0
  33. mima/maps/tiled/tiled_layer.py +48 -0
  34. mima/maps/tiled/tiled_map.py +95 -0
  35. mima/maps/tiled/tiled_object.py +79 -0
  36. mima/maps/tiled/tiled_objectgroup.py +25 -0
  37. mima/maps/tiled/tiled_template.py +49 -0
  38. mima/maps/tiled/tiled_tile.py +90 -0
  39. mima/maps/tiled/tiled_tileset.py +51 -0
  40. mima/maps/tilemap.py +216 -0
  41. mima/maps/tileset.py +39 -0
  42. mima/maps/tileset_info.py +9 -0
  43. mima/maps/transition_map.py +146 -0
  44. mima/objects/__init__.py +0 -0
  45. mima/objects/animated_sprite.py +217 -0
  46. mima/objects/attribute_effect.py +26 -0
  47. mima/objects/attributes.py +126 -0
  48. mima/objects/creature.py +384 -0
  49. mima/objects/dynamic.py +206 -0
  50. mima/objects/effects/__init__.py +0 -0
  51. mima/objects/effects/colorize_screen.py +60 -0
  52. mima/objects/effects/debug_box.py +133 -0
  53. mima/objects/effects/light.py +103 -0
  54. mima/objects/effects/show_sprite.py +50 -0
  55. mima/objects/effects/walking_on_grass.py +70 -0
  56. mima/objects/effects/walking_on_water.py +57 -0
  57. mima/objects/loader.py +111 -0
  58. mima/objects/projectile.py +111 -0
  59. mima/objects/sprite.py +116 -0
  60. mima/objects/world/__init__.py +0 -0
  61. mima/objects/world/color_gate.py +67 -0
  62. mima/objects/world/color_switch.py +101 -0
  63. mima/objects/world/container.py +175 -0
  64. mima/objects/world/floor_switch.py +109 -0
  65. mima/objects/world/gate.py +178 -0
  66. mima/objects/world/light_source.py +121 -0
  67. mima/objects/world/logic_gate.py +157 -0
  68. mima/objects/world/movable.py +399 -0
  69. mima/objects/world/oneway.py +195 -0
  70. mima/objects/world/pickup.py +157 -0
  71. mima/objects/world/switch.py +179 -0
  72. mima/objects/world/teleport.py +308 -0
  73. mima/py.typed +0 -0
  74. mima/scripts/__init__.py +2 -0
  75. mima/scripts/command.py +38 -0
  76. mima/scripts/commands/__init__.py +0 -0
  77. mima/scripts/commands/add_quest.py +19 -0
  78. mima/scripts/commands/change_map.py +34 -0
  79. mima/scripts/commands/close_dialog.py +9 -0
  80. mima/scripts/commands/equip_weapon.py +23 -0
  81. mima/scripts/commands/give_item.py +26 -0
  82. mima/scripts/commands/give_resource.py +51 -0
  83. mima/scripts/commands/move_map.py +152 -0
  84. mima/scripts/commands/move_to.py +49 -0
  85. mima/scripts/commands/oneway_move.py +58 -0
  86. mima/scripts/commands/parallel.py +66 -0
  87. mima/scripts/commands/play_sound.py +13 -0
  88. mima/scripts/commands/present_item.py +53 -0
  89. mima/scripts/commands/progress_quest.py +12 -0
  90. mima/scripts/commands/quit_game.py +8 -0
  91. mima/scripts/commands/save_game.py +14 -0
  92. mima/scripts/commands/screen_fade.py +83 -0
  93. mima/scripts/commands/serial.py +69 -0
  94. mima/scripts/commands/set_facing_direction.py +21 -0
  95. mima/scripts/commands/set_spawn_map.py +17 -0
  96. mima/scripts/commands/show_choices.py +52 -0
  97. mima/scripts/commands/show_dialog.py +118 -0
  98. mima/scripts/commands/take_coins.py +23 -0
  99. mima/scripts/script_processor.py +61 -0
  100. mima/standalone/__init__.py +0 -0
  101. mima/standalone/camera.py +153 -0
  102. mima/standalone/geometry.py +1318 -0
  103. mima/standalone/multicolumn_list.py +54 -0
  104. mima/standalone/pixel_font.py +84 -0
  105. mima/standalone/scripting.py +145 -0
  106. mima/standalone/spatial.py +186 -0
  107. mima/standalone/sprite.py +158 -0
  108. mima/standalone/tiled_map.py +1247 -0
  109. mima/standalone/transformed_view.py +433 -0
  110. mima/standalone/user_input.py +563 -0
  111. mima/states/__init__.py +0 -0
  112. mima/states/game_state.py +189 -0
  113. mima/states/memory.py +28 -0
  114. mima/states/quest.py +71 -0
  115. mima/types/__init__.py +0 -0
  116. mima/types/alignment.py +7 -0
  117. mima/types/blend.py +8 -0
  118. mima/types/damage.py +42 -0
  119. mima/types/direction.py +44 -0
  120. mima/types/gate_color.py +7 -0
  121. mima/types/graphic_state.py +23 -0
  122. mima/types/keys.py +64 -0
  123. mima/types/mode.py +9 -0
  124. mima/types/nature.py +12 -0
  125. mima/types/object.py +22 -0
  126. mima/types/player.py +9 -0
  127. mima/types/position.py +13 -0
  128. mima/types/start.py +7 -0
  129. mima/types/terrain.py +9 -0
  130. mima/types/tile_collision.py +11 -0
  131. mima/types/weapon_slot.py +6 -0
  132. mima/types/window.py +44 -0
  133. mima/usables/__init__.py +0 -0
  134. mima/usables/item.py +51 -0
  135. mima/usables/weapon.py +68 -0
  136. mima/util/__init__.py +1 -0
  137. mima/util/colors.py +50 -0
  138. mima/util/constants.py +55 -0
  139. mima/util/functions.py +38 -0
  140. mima/util/input_defaults.py +170 -0
  141. mima/util/logging.py +51 -0
  142. mima/util/property.py +8 -0
  143. mima/util/runtime_config.py +327 -0
  144. mima/util/trading_item.py +23 -0
  145. mima/view/__init__.py +0 -0
  146. mima/view/camera.py +192 -0
  147. mima/view/mima_mode.py +618 -0
  148. mima/view/mima_scene.py +231 -0
  149. mima/view/mima_view.py +12 -0
  150. mima/view/mima_window.py +244 -0
  151. mima_engine-0.4.0.dist-info/METADATA +47 -0
  152. mima_engine-0.4.0.dist-info/RECORD +153 -0
  153. mima_engine-0.4.0.dist-info/WHEEL +4 -0
@@ -0,0 +1,327 @@
1
+ import configparser
2
+ import os
3
+ from copy import deepcopy
4
+ from typing import Any, Dict, List, Optional, Tuple
5
+
6
+ from ..types.keys import Key as K
7
+ from ..types.player import Player
8
+ from .colors import (
9
+ BLACK,
10
+ BLUE,
11
+ DARK_GREY,
12
+ DARK_RED,
13
+ GREEN,
14
+ RED,
15
+ VERY_LIGHT_GREY,
16
+ WHITE,
17
+ Color,
18
+ )
19
+ from .constants import (
20
+ BIG_FONT_HEIGHT,
21
+ BIG_FONT_NAME,
22
+ BIG_FONT_WIDTH,
23
+ SMALL_FONT_HEIGHT,
24
+ SMALL_FONT_NAME,
25
+ SMALL_FONT_WIDTH,
26
+ TILE_HEIGHT,
27
+ TILE_WIDTH,
28
+ )
29
+ from .functions import strtobool
30
+
31
+ DEFAULT_CONFIG = {
32
+ "keyboard_map_p1": {
33
+ "UP": "w",
34
+ "DOWN": "s",
35
+ "LEFT": "a",
36
+ "RIGHT": "d",
37
+ "A": "e",
38
+ "B": "q",
39
+ "X": "x",
40
+ "Y": "y",
41
+ "L": "1",
42
+ "R": "2",
43
+ "START": "r",
44
+ "SELECT": "c",
45
+ },
46
+ "keyboard_map_p2": {
47
+ "UP": "up",
48
+ "DOWN": "down",
49
+ "LEFT": "left",
50
+ "RIGHT": "right",
51
+ "A": "6",
52
+ "B": "2",
53
+ "X": "8",
54
+ "Y": "4",
55
+ "L": "7",
56
+ "R": "9",
57
+ "START": "5",
58
+ "SELECT": "0",
59
+ },
60
+ "joysticks": {"p1": 0, "p2": 1},
61
+ "joystick_map_p1": {
62
+ "UP": "up",
63
+ "DOWN": "down",
64
+ "LEFT": "left",
65
+ "RIGHT": "right",
66
+ "A": "0",
67
+ "B": "1",
68
+ "X": "2",
69
+ "Y": "3",
70
+ "L": "7",
71
+ "R": "8",
72
+ "START": "5",
73
+ "SELECT": "6",
74
+ },
75
+ "joystick_map_p2": {
76
+ "UP": "up",
77
+ "DOWN": "down",
78
+ "LEFT": "left",
79
+ "RIGHT": "right",
80
+ "A": "0",
81
+ "B": "1",
82
+ "X": "2",
83
+ "Y": "3",
84
+ "L": "7",
85
+ "R": "8",
86
+ "START": "5",
87
+ "SELECT": "6",
88
+ },
89
+ "colors": {},
90
+ "color_remaps": {},
91
+ "flags": {},
92
+ }
93
+
94
+
95
+ class RuntimeConfig:
96
+ def __init__(
97
+ self,
98
+ config_path: str = "",
99
+ default_config: Optional[Dict[str, Any]] = None,
100
+ ):
101
+ if default_config is None:
102
+ default_config = DEFAULT_CONFIG
103
+
104
+ self._loaded: Dict[str, Any] = deepcopy(default_config)
105
+
106
+ self._converted: Dict[str, Any] = {}
107
+
108
+ if not config_path:
109
+ config_path = os.path.abspath(os.path.join(os.getcwd(), "mima.ini"))
110
+
111
+ self._config_path = config_path
112
+ config = configparser.ConfigParser()
113
+
114
+ if os.path.exists(config_path):
115
+ config.read(config_path)
116
+
117
+ if config.sections():
118
+ self._read_config(config)
119
+ else:
120
+ self._write_config(config)
121
+ else:
122
+ self._write_config(config)
123
+
124
+ # Per-game constants
125
+ ## Colors
126
+ self.color_black = BLACK
127
+ self.color_white = WHITE
128
+ self.color_red = RED
129
+ self.color_blue = BLUE
130
+ self.color_green = GREEN
131
+ self.color_dark_red = DARK_RED
132
+ self.color_dark_grey = DARK_GREY
133
+ self.color_very_light_grey = VERY_LIGHT_GREY
134
+
135
+ self.tile_width = TILE_WIDTH
136
+ self.tile_height = TILE_HEIGHT
137
+
138
+ ## Font
139
+ self.big_font_name = BIG_FONT_NAME
140
+ self.big_font_width = BIG_FONT_WIDTH
141
+ self.big_font_height = BIG_FONT_HEIGHT
142
+ self.small_font_name = SMALL_FONT_NAME
143
+ self.small_font_width = SMALL_FONT_WIDTH
144
+ self.small_font_height = SMALL_FONT_HEIGHT
145
+
146
+ ## Locale
147
+ self.locale = "en"
148
+
149
+ def _read_config(self, config: configparser.ConfigParser):
150
+ mappings = [
151
+ "keyboard_map_p1",
152
+ "keyboard_map_p2",
153
+ "joystick_map_p1",
154
+ "joystick_map_p2",
155
+ ]
156
+ for m in mappings:
157
+ for key, mapping in config[m].items():
158
+ vals = mapping.strip().split(",")
159
+ self._loaded[m][key.upper()] = vals
160
+ self._loaded["joysticks"] = {
161
+ "p1": int(config["joysticks"].get("p1", 0)),
162
+ "p2": int(config["joysticks"].get("p2", 1)),
163
+ }
164
+
165
+ default_colors = {}
166
+ for color_name, color in self._loaded["colors"].items():
167
+ default_colors[f"{color_name}_default"] = color
168
+ self._loaded["colors"][color_name] = config["colors"][color_name]
169
+ self._loaded["colors"].update(default_colors)
170
+
171
+ for flag in self._loaded["flags"]:
172
+ self._loaded["flags"][flag] = config["flags"][flag]
173
+
174
+ def save_config(self):
175
+ config = configparser.ConfigParser()
176
+ self._write_config(config)
177
+
178
+ def _write_config(self, config: configparser.ConfigParser):
179
+ mappings = [
180
+ "keyboard_map_p1",
181
+ "keyboard_map_p2",
182
+ "joystick_map_p1",
183
+ "joystick_map_p2",
184
+ ]
185
+ for m in mappings:
186
+ config[m] = {}
187
+ for key, mapping in self._loaded[m].items():
188
+ config[m][key.lower()] = ",".join(mapping)
189
+ # config["keyboard_map_p1"] = {}
190
+ # config["keyboard_map_p2"] = {}
191
+ config["joysticks"] = {
192
+ "p1": self._loaded["joysticks"].get("p1", 0),
193
+ "p2": self._loaded["joysticks"].get("p2", 1),
194
+ }
195
+ # config["joystick_map_p1"] = {}
196
+ # config["joystick_p2"] =
197
+ # config["joystick_map_p2"] = {}
198
+ config["colors"] = {}
199
+ config["flags"] = {}
200
+
201
+ # for key, mapping in self._loaded["keyboard_map_p1"].items():
202
+
203
+ for color_name, color in self._loaded["colors"].items():
204
+ if color_name.endswith("_default"):
205
+ continue
206
+ config["colors"][color_name] = color
207
+
208
+ for flag_name, flag in self._loaded["flags"].items():
209
+ config["flags"][flag_name] = flag
210
+
211
+ with open(self._config_path, "w") as cfg_file:
212
+ config.write(cfg_file)
213
+
214
+ def update_keyboard_map(self, kbmap: Dict[K, List[str]]):
215
+ mappings = [
216
+ "keyboard_map_p1",
217
+ "keyboard_map_p2",
218
+ # "joystick_map_p3",
219
+ # "keyboard_map_p4",
220
+ ]
221
+ mip = 1
222
+ for idx, (key, mapping) in enumerate(kbmap.items()):
223
+ mip = idx // 12
224
+ if mip < 1 or mip > 2:
225
+ continue
226
+ key_name = key.name.split("_")[1]
227
+ self._loaded[mappings[mip - 1]][key_name] = mapping
228
+
229
+ def update_joystick_map(self, jsmap: Dict[K, List[str]]):
230
+ mappings = [
231
+ # "keyboard_map_p1",
232
+ # "keyboard_map_p2",
233
+ "joystick_map_p1",
234
+ "keyboard_map_p2",
235
+ ]
236
+ mip = 1
237
+ for idx, (key, mapping) in enumerate(jsmap.items()):
238
+ mip = idx // 12
239
+ if mip < 1 or mip > 2:
240
+ continue
241
+ key_name = key.name.split("_")[1]
242
+ self._loaded[mappings[mip - 1]][key_name] = mapping
243
+
244
+ def update_joysticks(self, reassign: List[Tuple[int, Player]]):
245
+ self._loaded["joysticks"] = {}
246
+ for item in reassign:
247
+ self._loaded["joysticks"][item[1].name.lower()] = item[0]
248
+
249
+ def get_keyboard_map(self) -> Dict[K, List[str]]:
250
+ kbmap = {}
251
+ for but in K:
252
+ if but.value < 12:
253
+ kbmap[but] = []
254
+ elif but.value < 24:
255
+ kbmap[but] = self._loaded["keyboard_map_p1"][but.name.split("_")[1]]
256
+
257
+ elif but.value < 36:
258
+ kbmap[but] = self._loaded["keyboard_map_p2"][but.name.split("_")[1]]
259
+
260
+ else:
261
+ kbmap[but] = []
262
+ return kbmap
263
+
264
+ def get_joystick_map(self) -> Dict[K, List[str]]:
265
+ jsmap = {}
266
+
267
+ for but in K:
268
+ if but.value < 12:
269
+ jsmap[but] = []
270
+ elif but.value < 24:
271
+ jsmap[but] = self._loaded["joystick_map_p1"][but.name.split("_")[1]]
272
+
273
+ elif but.value < 36:
274
+ jsmap[but] = self._loaded["joystick_map_p2"][but.name.split("_")[1]]
275
+
276
+ else:
277
+ jsmap[but] = []
278
+ return jsmap
279
+
280
+ def get_joy_to_player(self) -> Dict[int, Player]:
281
+ joy2p = {}
282
+ for p, j in self._loaded["joysticks"].items():
283
+ joy2p[j] = Player[p.upper()]
284
+ return joy2p
285
+
286
+ def get_player_to_joy(self) -> Dict[Player, int]:
287
+ p2joy = {}
288
+ for p, j in self._loaded["joysticks"].items():
289
+ p2joy[Player[p.upper()]] = j
290
+ return p2joy
291
+
292
+ # @property
293
+ # def keymap(self):
294
+ # if "keymap" in self._converted:
295
+ # return self._converted["keymap"]
296
+ # else:
297
+ # self._converted["keymap"] = {}
298
+ # for but in K:
299
+ # self._converted["keymap"][but] = self._loaded["keymap"][
300
+ # but.name
301
+ # ]
302
+
303
+ # return self._converted["keymap"]
304
+
305
+ @property
306
+ def colors(self) -> Dict[str, Color]:
307
+ if "colors" in self._converted:
308
+ return self._converted["colors"]
309
+ else:
310
+ self._converted["colors"] = {}
311
+ for key, val in self._loaded["colors"].items():
312
+ self._converted["colors"][key] = Color(
313
+ *[int(p) for p in val.strip().split(",")]
314
+ )
315
+
316
+ return self._converted["colors"]
317
+
318
+ @property
319
+ def flags(self) -> Dict[str, bool]:
320
+ if "flags" in self._converted:
321
+ return self._converted["flags"]
322
+ else:
323
+ self._converted["flags"] = {}
324
+ for flag, value in self._loaded["flags"].items():
325
+ self._converted["flags"][flag] = strtobool(value)
326
+
327
+ return self._converted["flags"]
@@ -0,0 +1,23 @@
1
+ from __future__ import annotations
2
+
3
+ from dataclasses import dataclass
4
+ from typing import TYPE_CHECKING
5
+
6
+ if TYPE_CHECKING:
7
+ from ..usables.item import Item
8
+
9
+
10
+ @dataclass
11
+ class TradingItem:
12
+ item: Item
13
+ count: int = 1
14
+ factor: float = 1.0
15
+ available: int = 1
16
+ tid: int = 0
17
+ price: int = 0
18
+ trading_price: int = 0
19
+ stackable: bool = False
20
+ stackable_merchant: bool = False
21
+
22
+ def __eq__(self, other):
23
+ return self.tid == other.tid
mima/view/__init__.py ADDED
File without changes
mima/view/camera.py ADDED
@@ -0,0 +1,192 @@
1
+ from __future__ import annotations
2
+
3
+ from typing import TYPE_CHECKING, Optional
4
+
5
+ from ..backend.pygame_camera import PygameCamera
6
+ from ..util.colors import Color
7
+
8
+ if TYPE_CHECKING:
9
+ from ..engine import MimaEngine
10
+ from ..maps.tilemap import Tilemap
11
+ from ..objects.dynamic import Dynamic
12
+
13
+
14
+ class Camera:
15
+ engine: MimaEngine
16
+
17
+ def __init__(
18
+ self,
19
+ name: str,
20
+ width: float,
21
+ height: float,
22
+ visible_tiles_sx: int = 0,
23
+ visible_tiles_sy: int = 0,
24
+ visible_tiles_ex: Optional[int] = None,
25
+ visible_tiles_ey: Optional[int] = None,
26
+ ):
27
+ self.pwidth = int(width * self.engine.rtc.tile_width)
28
+ self.pheight = int(height * self.engine.rtc.tile_height)
29
+ self._ui_pwidth = self.pwidth
30
+ self._ui_pheight = self.pheight
31
+ self.ui_pwidth = self.pwidth
32
+ self.ui_pheight = self.pheight
33
+
34
+ self.engine.backend.new_camera(name, self.pwidth, self.pheight)
35
+
36
+ self.name = name
37
+
38
+ if visible_tiles_ex is None:
39
+ visible_tiles_ex = width
40
+ if visible_tiles_ey is None:
41
+ visible_tiles_ey = height
42
+
43
+ self._visible_tiles_sx: int = int(visible_tiles_sx)
44
+ self._visible_tiles_sy: int = int(visible_tiles_sy)
45
+ self._visible_tiles_ex: int = int(visible_tiles_ex)
46
+ self._visible_tiles_ey: int = int(visible_tiles_ey)
47
+ self.visible_tiles_sx: float = visible_tiles_sx
48
+ self.visible_tiles_sy: float = visible_tiles_sy
49
+ self.visible_tiles_ex: float = visible_tiles_ex
50
+ self.visible_tiles_ey: float = visible_tiles_ey
51
+
52
+ self._zoom: float = 1.0
53
+ self._zoom_changed: bool = False
54
+ self.camera_scale: float = 1.0
55
+ self._ui_zoom: float = 1.0
56
+ self._ui_zoom_changed: bool = False
57
+
58
+ if self.visible_tiles_ex is None:
59
+ self.visible_tiles_ex = (
60
+ self.engine.backend.render_width / self.engine.rtc.tile_width
61
+ - self.visible_tiles_sx
62
+ )
63
+
64
+ if self.visible_tiles_ey is None:
65
+ self.visible_tiles_ey = (
66
+ self.engine.backend.render_height / self.engine.rtc.tile_height
67
+ - self.visible_tiles_sy
68
+ )
69
+ self.border_left: bool = False
70
+ self.border_right: bool = False
71
+ self.border_top: bool = False
72
+ self.border_bottom: bool = False
73
+ self.border_width: int = 1
74
+ self.border_color: Color = self.engine.rtc.color_white
75
+
76
+ def update(
77
+ self,
78
+ target: Optional[Dynamic] = None,
79
+ map_width: int = 0,
80
+ map_height: int = 0,
81
+ ):
82
+ self.visible_tiles_sx = self._visible_tiles_sx * 1 / self.zoom
83
+ self.visible_tiles_sy = self._visible_tiles_sy * 1 / self.zoom
84
+ self.visible_tiles_ex = self._visible_tiles_ex * 1 / self.zoom
85
+ self.visible_tiles_ey = self._visible_tiles_ey * 1 / self.zoom
86
+ self.camera_scale = self.engine.backend.render_width / (
87
+ self.visible_tiles_ex * self.engine.rtc.tile_width
88
+ )
89
+
90
+ if target is not None:
91
+ # Calculate x offset
92
+ self.ox = target.px - self.visible_tiles_ex / 2.0
93
+
94
+ # Calculate y offset
95
+ self.oy = target.py - self.visible_tiles_ey / 2.0
96
+
97
+ if map_width > 0:
98
+ # Adjust x offset to map
99
+ self.ox = min(map_width - self.visible_tiles_ex, max(0, self.ox))
100
+ if map_width < self.visible_tiles_ex:
101
+ self.ox += (self.visible_tiles_ex - map_width) / 2.0
102
+ if map_height > 0:
103
+ # Adjust y offset to map
104
+ self.oy = min(map_height - self.visible_tiles_ey, max(0, self.oy))
105
+ if map_height < self.visible_tiles_ey:
106
+ self.oy += (self.visible_tiles_ey - map_height) / 2.0
107
+
108
+ self.ox -= self.visible_tiles_sx
109
+ self.oy -= self.visible_tiles_sy
110
+
111
+ if self._zoom_changed:
112
+ self.engine.backend.get_camera(self.name).change_zoom(
113
+ int(self.visible_tiles_ex * self.engine.rtc.tile_width),
114
+ int(self.visible_tiles_ey * self.engine.rtc.tile_height),
115
+ )
116
+ self.engine.backend.get_camera(
117
+ self.name
118
+ ).camera_scale = self.camera_scale
119
+
120
+ self._zoom_changed = False
121
+ if self._ui_zoom_changed:
122
+ # print(
123
+ # int(self.ui_pwidth * self._ui_zoom),
124
+ # int(self.ui_pheight * self._ui_zoom),
125
+ # )
126
+ self.ui_pwidth = int(self._ui_pwidth * 1 / self._ui_zoom)
127
+ self.ui_pheight = int(self._ui_pheight * 1 / self._ui_zoom)
128
+
129
+ self.engine.backend.get_camera(self.name).change_ui_zoom(
130
+ self.ui_pwidth, self.ui_pheight
131
+ )
132
+ self._ui_zoom_changed = False
133
+
134
+ def draw(self, *sprites):
135
+ for sprite in sprites:
136
+ sprite.draw_self(self.ox, self.oy)
137
+
138
+ def draw_borders(self):
139
+ if self.border_left:
140
+ self.engine.backend.draw_line(
141
+ 0,
142
+ 0,
143
+ 0,
144
+ self.pheight - 1,
145
+ self.border_color,
146
+ camera_name=self.name,
147
+ width=self.border_width,
148
+ )
149
+ if self.border_right:
150
+ self.engine.backend.draw_line(
151
+ self.pwidth - 1,
152
+ 0,
153
+ self.pwidth - 1,
154
+ self.pheight - 1,
155
+ self.border_color,
156
+ camera_name=self.name,
157
+ width=self.border_width,
158
+ )
159
+
160
+ @property
161
+ def zoom(self):
162
+ return self._zoom
163
+
164
+ @zoom.setter
165
+ def zoom(self, val):
166
+ self._zoom = val
167
+ self._zoom_changed = True
168
+
169
+ @property
170
+ def ui_zoom(self):
171
+ return self._ui_zoom
172
+
173
+ @ui_zoom.setter
174
+ def ui_zoom(self, val):
175
+ self._ui_zoom = val
176
+ self._ui_zoom_changed = True
177
+
178
+ @property
179
+ def px(self):
180
+ return self.engine.backend.get_camera(self.name).px
181
+
182
+ @property
183
+ def py(self):
184
+ return self.engine.backend.get_camera(self.name).py
185
+
186
+ @px.setter
187
+ def px(self, val):
188
+ self.engine.backend.get_camera(self.name).px = val
189
+
190
+ @py.setter
191
+ def py(self, val):
192
+ self.engine.backend.get_camera(self.name).py = val