Mercurial > skaapsteker
annotate skaapsteker/level.py @ 279:8d2e4b2a65bf
fixed level editor
author | Adrianna Pińska <adrianna.pinska@gmail.com> |
---|---|
date | Fri, 08 Apr 2011 19:59:05 +0200 |
parents | afd9256ad682 |
children | e157119d5e84 |
rev | line source |
---|---|
8 | 1 import json |
2 | |
243
4050e77dade6
Add support for background music tracks
Neil Muller <drnlmuller@gmail.com>
parents:
127
diff
changeset
|
3 from pygame import Rect, Surface, Color, mixer |
75
95cb0b575e05
Enemies in level editor, tile layers.
Jeremy Thurgood <firxen@gmail.com>
parents:
69
diff
changeset
|
4 from pygame.sprite import LayeredUpdates |
13
b83f2db218e6
Draw level background with scaled offset.
Jeremy Thurgood <firxen@gmail.com>
parents:
10
diff
changeset
|
5 |
101
b502e732f821
Add ? object-placement-help tiles
Stefano Rivera <stefano@rivera.za.net>
parents:
97
diff
changeset
|
6 from . import data |
b502e732f821
Add ? object-placement-help tiles
Stefano Rivera <stefano@rivera.za.net>
parents:
97
diff
changeset
|
7 from .constants import Layers |
b502e732f821
Add ? object-placement-help tiles
Stefano Rivera <stefano@rivera.za.net>
parents:
97
diff
changeset
|
8 from .sprites.base import TILE_SIZE, find_sprite, Geography |
b502e732f821
Add ? object-placement-help tiles
Stefano Rivera <stefano@rivera.za.net>
parents:
97
diff
changeset
|
9 from .widgets.text import Text |
8 | 10 |
11 | |
12 | |
13 class TileSet(object): | |
14 def __init__(self, dirname): | |
15 self.dirname = 'tiles/' + dirname | |
65 | 16 self.tile_factories = { |
17 '.': lambda pos: None, | |
101
b502e732f821
Add ? object-placement-help tiles
Stefano Rivera <stefano@rivera.za.net>
parents:
97
diff
changeset
|
18 '?': lambda pos: None, # Object placement helper |
65 | 19 '-': self.tile_factory('floor.png', True), |
107
a770ac0c3385
created xcf with tile shapes and Olli's backgrounds; wrote xcf2png script to generate tiles; switched levels to real tilesets
Adrianna Pińska <adrianna.pinska@gmail.com>
parents:
101
diff
changeset
|
20 'X': self.tile_factory('wall.png', True, True), |
a770ac0c3385
created xcf with tile shapes and Olli's backgrounds; wrote xcf2png script to generate tiles; switched levels to real tilesets
Adrianna Pińska <adrianna.pinska@gmail.com>
parents:
101
diff
changeset
|
21 '<': self.tile_factory('floor-end-l.png', True), |
a770ac0c3385
created xcf with tile shapes and Olli's backgrounds; wrote xcf2png script to generate tiles; switched levels to real tilesets
Adrianna Pińska <adrianna.pinska@gmail.com>
parents:
101
diff
changeset
|
22 '>': self.tile_factory('floor-end-r.png', True), |
118
081f78470dcf
Fix misclassified tiles.
Jeremy Thurgood <firxen@gmail.com>
parents:
107
diff
changeset
|
23 '=': self.tile_factory('floor-start-l.png', True), |
081f78470dcf
Fix misclassified tiles.
Jeremy Thurgood <firxen@gmail.com>
parents:
107
diff
changeset
|
24 '+': self.tile_factory('floor-start-r.png', True), |
107
a770ac0c3385
created xcf with tile shapes and Olli's backgrounds; wrote xcf2png script to generate tiles; switched levels to real tilesets
Adrianna Pińska <adrianna.pinska@gmail.com>
parents:
101
diff
changeset
|
25 '(': self.tile_factory('wall-end-l.png', True, True), |
a770ac0c3385
created xcf with tile shapes and Olli's backgrounds; wrote xcf2png script to generate tiles; switched levels to real tilesets
Adrianna Pińska <adrianna.pinska@gmail.com>
parents:
101
diff
changeset
|
26 ')': self.tile_factory('wall-end-r.png', True, True), |
a770ac0c3385
created xcf with tile shapes and Olli's backgrounds; wrote xcf2png script to generate tiles; switched levels to real tilesets
Adrianna Pińska <adrianna.pinska@gmail.com>
parents:
101
diff
changeset
|
27 'q': self.tile_factory('wall-end-tr.png', True, True), |
a770ac0c3385
created xcf with tile shapes and Olli's backgrounds; wrote xcf2png script to generate tiles; switched levels to real tilesets
Adrianna Pińska <adrianna.pinska@gmail.com>
parents:
101
diff
changeset
|
28 'd': self.tile_factory('wall-end-br.png', True, True), |
a770ac0c3385
created xcf with tile shapes and Olli's backgrounds; wrote xcf2png script to generate tiles; switched levels to real tilesets
Adrianna Pińska <adrianna.pinska@gmail.com>
parents:
101
diff
changeset
|
29 'p': self.tile_factory('wall-end-tl.png', True, True), |
a770ac0c3385
created xcf with tile shapes and Olli's backgrounds; wrote xcf2png script to generate tiles; switched levels to real tilesets
Adrianna Pińska <adrianna.pinska@gmail.com>
parents:
101
diff
changeset
|
30 'b': self.tile_factory('wall-end-bl.png', True, True), |
a770ac0c3385
created xcf with tile shapes and Olli's backgrounds; wrote xcf2png script to generate tiles; switched levels to real tilesets
Adrianna Pińska <adrianna.pinska@gmail.com>
parents:
101
diff
changeset
|
31 '{': self.tile_factory('arch-l.png'), |
a770ac0c3385
created xcf with tile shapes and Olli's backgrounds; wrote xcf2png script to generate tiles; switched levels to real tilesets
Adrianna Pińska <adrianna.pinska@gmail.com>
parents:
101
diff
changeset
|
32 '}': self.tile_factory('arch-r.png'), |
a770ac0c3385
created xcf with tile shapes and Olli's backgrounds; wrote xcf2png script to generate tiles; switched levels to real tilesets
Adrianna Pińska <adrianna.pinska@gmail.com>
parents:
101
diff
changeset
|
33 '1': self.tile_factory('decor-1.png', layer=Layers.FOREGROUND), |
65 | 34 } |
8 | 35 |
36 | |
35 | 37 def get_tile(self, tilechar, pos): |
65 | 38 return self.tile_factories[tilechar](pos) |
8 | 39 |
40 | |
69
e4089417766e
FPS counter and tile sprite layering.
Jeremy Thurgood <firxen@gmail.com>
parents:
65
diff
changeset
|
41 def tile_factory(self, image_name, floor=False, block=False, layer=Layers.BACKGROUND): |
65 | 42 image = data.load_image(self.dirname + '/' + image_name) |
43 def _tilefac(pos): | |
44 tile = Geography(pos, image) | |
45 tile.block = block | |
46 tile.floor = floor | |
69
e4089417766e
FPS counter and tile sprite layering.
Jeremy Thurgood <firxen@gmail.com>
parents:
65
diff
changeset
|
47 tile._layer = layer |
97
a1d95c6152a0
Shiny new collision detection. Read code for usage information.
Simon Cross <hodgestar@gmail.com>
parents:
94
diff
changeset
|
48 if not (tile.block or tile.floor): |
a1d95c6152a0
Shiny new collision detection. Read code for usage information.
Simon Cross <hodgestar@gmail.com>
parents:
94
diff
changeset
|
49 tile.collides_with = set() |
65 | 50 return tile |
51 return _tilefac | |
8 | 52 |
53 | |
54 | |
55 class Level(object): | |
264
afd9256ad682
Move between doorways. (Still with hacky collision limiting.)
Jeremy Thurgood <firxen@gmail.com>
parents:
262
diff
changeset
|
56 def __init__(self, leveldef, soundsystem): |
127
e1dd3b785269
Initial game state stuff.
Jeremy Thurgood <firxen@gmail.com>
parents:
119
diff
changeset
|
57 self.name = leveldef |
20
f81e073fb8f5
Remove .json suffix from level defs.
Jeremy Thurgood <firxen@gmail.com>
parents:
13
diff
changeset
|
58 self.level_data = json.loads(data.load('levels/' + leveldef + '.json').read()) |
75
95cb0b575e05
Enemies in level editor, tile layers.
Jeremy Thurgood <firxen@gmail.com>
parents:
69
diff
changeset
|
59 self.sprites = LayeredUpdates() |
262 | 60 self._soundsystem = soundsystem |
52
a18bf35519f3
Multiple layered backgrounds.
Jeremy Thurgood <firxen@gmail.com>
parents:
50
diff
changeset
|
61 self.build_backgrounds() |
8 | 62 self.build_tiles() |
25
fe87d828d093
Very basic enemy support.
Jeremy Thurgood <firxen@gmail.com>
parents:
24
diff
changeset
|
63 self.setup_enemies() |
249 | 64 self.setup_doorways() |
243
4050e77dade6
Add support for background music tracks
Neil Muller <drnlmuller@gmail.com>
parents:
127
diff
changeset
|
65 self._background_music = None |
262 | 66 if 'music' in self.level_data: |
67 # soundsystem will call data.filepath | |
68 self._background_music = 'music/' + self.level_data['music'] | |
8 | 69 |
52
a18bf35519f3
Multiple layered backgrounds.
Jeremy Thurgood <firxen@gmail.com>
parents:
50
diff
changeset
|
70 def build_backgrounds(self): |
a18bf35519f3
Multiple layered backgrounds.
Jeremy Thurgood <firxen@gmail.com>
parents:
50
diff
changeset
|
71 self.backgrounds = [] |
a18bf35519f3
Multiple layered backgrounds.
Jeremy Thurgood <firxen@gmail.com>
parents:
50
diff
changeset
|
72 for background in self.level_data['backgrounds']: |
a18bf35519f3
Multiple layered backgrounds.
Jeremy Thurgood <firxen@gmail.com>
parents:
50
diff
changeset
|
73 self.backgrounds.append(data.load_image('backgrounds/' + background)) |
13
b83f2db218e6
Draw level background with scaled offset.
Jeremy Thurgood <firxen@gmail.com>
parents:
10
diff
changeset
|
74 |
262 | 75 def enter(self): |
76 if self._background_music: | |
77 self._soundsystem.play_background_music(self._background_music) | |
13
b83f2db218e6
Draw level background with scaled offset.
Jeremy Thurgood <firxen@gmail.com>
parents:
10
diff
changeset
|
78 |
243
4050e77dade6
Add support for background music tracks
Neil Muller <drnlmuller@gmail.com>
parents:
127
diff
changeset
|
79 def leave(self): |
262 | 80 pass |
243
4050e77dade6
Add support for background music tracks
Neil Muller <drnlmuller@gmail.com>
parents:
127
diff
changeset
|
81 |
8 | 82 def build_tiles(self): |
13
b83f2db218e6
Draw level background with scaled offset.
Jeremy Thurgood <firxen@gmail.com>
parents:
10
diff
changeset
|
83 self.tileset = TileSet(self.level_data['tileset']) |
75
95cb0b575e05
Enemies in level editor, tile layers.
Jeremy Thurgood <firxen@gmail.com>
parents:
69
diff
changeset
|
84 self.tiles = LayeredUpdates() |
35 | 85 tile_data = self.level_data['tiles'] |
86 self.tile_size = (len(tile_data[0]), len(tile_data)) | |
87 self.pixel_size = (self.tile_size[0] * TILE_SIZE[0], self.tile_size[1] * TILE_SIZE[1]) | |
88 for y, row in enumerate(tile_data): | |
89 for x, char in enumerate(row): | |
90 tile = self.tileset.get_tile(char, (x, y)) | |
91 if tile: | |
40
fa1bb94cfa76
Re-factor drawing to blit to a clip rect in the One True Level Surface before blitting that to the screen.
Simon Cross <hodgestar@gmail.com>
parents:
35
diff
changeset
|
92 self.tiles.add(tile) |
47 | 93 self.sprites.add(tile) |
8 | 94 |
95 | |
25
fe87d828d093
Very basic enemy support.
Jeremy Thurgood <firxen@gmail.com>
parents:
24
diff
changeset
|
96 def setup_enemies(self): |
75
95cb0b575e05
Enemies in level editor, tile layers.
Jeremy Thurgood <firxen@gmail.com>
parents:
69
diff
changeset
|
97 self.enemies = LayeredUpdates() |
47 | 98 for enemy_def in self.level_data['enemies']: |
127
e1dd3b785269
Initial game state stuff.
Jeremy Thurgood <firxen@gmail.com>
parents:
119
diff
changeset
|
99 enemy = find_sprite(enemy_def, 'enemies') |
47 | 100 self.enemies.add(enemy) |
101 self.sprites.add(enemy) | |
102 | |
127
e1dd3b785269
Initial game state stuff.
Jeremy Thurgood <firxen@gmail.com>
parents:
119
diff
changeset
|
103 |
249 | 104 def setup_doorways(self): |
264
afd9256ad682
Move between doorways. (Still with hacky collision limiting.)
Jeremy Thurgood <firxen@gmail.com>
parents:
262
diff
changeset
|
105 self.doorways = {} |
afd9256ad682
Move between doorways. (Still with hacky collision limiting.)
Jeremy Thurgood <firxen@gmail.com>
parents:
262
diff
changeset
|
106 for door_name, door_def in self.level_data['doorways'].items(): |
249 | 107 doorway = find_sprite(door_def, 'base') |
264
afd9256ad682
Move between doorways. (Still with hacky collision limiting.)
Jeremy Thurgood <firxen@gmail.com>
parents:
262
diff
changeset
|
108 self.doorways[door_name] = doorway |
249 | 109 self.sprites.add(doorway) |
110 | |
111 | |
40
fa1bb94cfa76
Re-factor drawing to blit to a clip rect in the One True Level Surface before blitting that to the screen.
Simon Cross <hodgestar@gmail.com>
parents:
35
diff
changeset
|
112 def get_surface(self): |
64
13b9031febeb
remove SRCALPHA flag for performance reasons
Neil Muller <drnlmuller@gmail.com>
parents:
63
diff
changeset
|
113 return Surface(self.pixel_size) |
40
fa1bb94cfa76
Re-factor drawing to blit to a clip rect in the One True Level Surface before blitting that to the screen.
Simon Cross <hodgestar@gmail.com>
parents:
35
diff
changeset
|
114 |
8 | 115 |
52
a18bf35519f3
Multiple layered backgrounds.
Jeremy Thurgood <firxen@gmail.com>
parents:
50
diff
changeset
|
116 def get_background_pos(self, background, viewport): |
a18bf35519f3
Multiple layered backgrounds.
Jeremy Thurgood <firxen@gmail.com>
parents:
50
diff
changeset
|
117 vp_x, vp_y = viewport.size |
a18bf35519f3
Multiple layered backgrounds.
Jeremy Thurgood <firxen@gmail.com>
parents:
50
diff
changeset
|
118 bg_scalable = background.get_rect().inflate(-vp_x, -vp_y).size |
a18bf35519f3
Multiple layered backgrounds.
Jeremy Thurgood <firxen@gmail.com>
parents:
50
diff
changeset
|
119 lev_scalable = Rect((0, 0), self.pixel_size).inflate(-vp_x, -vp_y).size |
a18bf35519f3
Multiple layered backgrounds.
Jeremy Thurgood <firxen@gmail.com>
parents:
50
diff
changeset
|
120 return ((viewport.left * bg_scalable[0]) / lev_scalable[0], |
a18bf35519f3
Multiple layered backgrounds.
Jeremy Thurgood <firxen@gmail.com>
parents:
50
diff
changeset
|
121 (viewport.top * bg_scalable[1]) / lev_scalable[1]) |
13
b83f2db218e6
Draw level background with scaled offset.
Jeremy Thurgood <firxen@gmail.com>
parents:
10
diff
changeset
|
122 |
b83f2db218e6
Draw level background with scaled offset.
Jeremy Thurgood <firxen@gmail.com>
parents:
10
diff
changeset
|
123 |
40
fa1bb94cfa76
Re-factor drawing to blit to a clip rect in the One True Level Surface before blitting that to the screen.
Simon Cross <hodgestar@gmail.com>
parents:
35
diff
changeset
|
124 def draw_background(self, surface): |
fa1bb94cfa76
Re-factor drawing to blit to a clip rect in the One True Level Surface before blitting that to the screen.
Simon Cross <hodgestar@gmail.com>
parents:
35
diff
changeset
|
125 clip_rect = surface.get_clip() |
52
a18bf35519f3
Multiple layered backgrounds.
Jeremy Thurgood <firxen@gmail.com>
parents:
50
diff
changeset
|
126 for background in self.backgrounds: |
a18bf35519f3
Multiple layered backgrounds.
Jeremy Thurgood <firxen@gmail.com>
parents:
50
diff
changeset
|
127 bg_pos = self.get_background_pos(background, clip_rect) |
a18bf35519f3
Multiple layered backgrounds.
Jeremy Thurgood <firxen@gmail.com>
parents:
50
diff
changeset
|
128 surface.blit(background, clip_rect.topleft, Rect(bg_pos, clip_rect.size)) |
13
b83f2db218e6
Draw level background with scaled offset.
Jeremy Thurgood <firxen@gmail.com>
parents:
10
diff
changeset
|
129 |
b83f2db218e6
Draw level background with scaled offset.
Jeremy Thurgood <firxen@gmail.com>
parents:
10
diff
changeset
|
130 |
40
fa1bb94cfa76
Re-factor drawing to blit to a clip rect in the One True Level Surface before blitting that to the screen.
Simon Cross <hodgestar@gmail.com>
parents:
35
diff
changeset
|
131 def draw_tiles(self, surface): |
fa1bb94cfa76
Re-factor drawing to blit to a clip rect in the One True Level Surface before blitting that to the screen.
Simon Cross <hodgestar@gmail.com>
parents:
35
diff
changeset
|
132 self.tiles.draw(surface) |
13
b83f2db218e6
Draw level background with scaled offset.
Jeremy Thurgood <firxen@gmail.com>
parents:
10
diff
changeset
|
133 |
b83f2db218e6
Draw level background with scaled offset.
Jeremy Thurgood <firxen@gmail.com>
parents:
10
diff
changeset
|
134 |
40
fa1bb94cfa76
Re-factor drawing to blit to a clip rect in the One True Level Surface before blitting that to the screen.
Simon Cross <hodgestar@gmail.com>
parents:
35
diff
changeset
|
135 def draw(self, surface): |
fa1bb94cfa76
Re-factor drawing to blit to a clip rect in the One True Level Surface before blitting that to the screen.
Simon Cross <hodgestar@gmail.com>
parents:
35
diff
changeset
|
136 self.draw_background(surface) |
101
b502e732f821
Add ? object-placement-help tiles
Stefano Rivera <stefano@rivera.za.net>
parents:
97
diff
changeset
|
137 |
b502e732f821
Add ? object-placement-help tiles
Stefano Rivera <stefano@rivera.za.net>
parents:
97
diff
changeset
|
138 |
b502e732f821
Add ? object-placement-help tiles
Stefano Rivera <stefano@rivera.za.net>
parents:
97
diff
changeset
|
139 |
b502e732f821
Add ? object-placement-help tiles
Stefano Rivera <stefano@rivera.za.net>
parents:
97
diff
changeset
|
140 class DebugLevel(Level): |
b502e732f821
Add ? object-placement-help tiles
Stefano Rivera <stefano@rivera.za.net>
parents:
97
diff
changeset
|
141 """Used by level-editor""" |
b502e732f821
Add ? object-placement-help tiles
Stefano Rivera <stefano@rivera.za.net>
parents:
97
diff
changeset
|
142 def build_tiles(self): |
b502e732f821
Add ? object-placement-help tiles
Stefano Rivera <stefano@rivera.za.net>
parents:
97
diff
changeset
|
143 super(DebugLevel, self).build_tiles() |
b502e732f821
Add ? object-placement-help tiles
Stefano Rivera <stefano@rivera.za.net>
parents:
97
diff
changeset
|
144 tile_data = self.level_data['tiles'] |
b502e732f821
Add ? object-placement-help tiles
Stefano Rivera <stefano@rivera.za.net>
parents:
97
diff
changeset
|
145 for y, row in enumerate(tile_data): |
b502e732f821
Add ? object-placement-help tiles
Stefano Rivera <stefano@rivera.za.net>
parents:
97
diff
changeset
|
146 for x, char in enumerate(row): |
b502e732f821
Add ? object-placement-help tiles
Stefano Rivera <stefano@rivera.za.net>
parents:
97
diff
changeset
|
147 if char == '?': |
b502e732f821
Add ? object-placement-help tiles
Stefano Rivera <stefano@rivera.za.net>
parents:
97
diff
changeset
|
148 self.check_debug_tile(x, y) |
b502e732f821
Add ? object-placement-help tiles
Stefano Rivera <stefano@rivera.za.net>
parents:
97
diff
changeset
|
149 |
b502e732f821
Add ? object-placement-help tiles
Stefano Rivera <stefano@rivera.za.net>
parents:
97
diff
changeset
|
150 |
b502e732f821
Add ? object-placement-help tiles
Stefano Rivera <stefano@rivera.za.net>
parents:
97
diff
changeset
|
151 def check_debug_tile(self, x, y): |
b502e732f821
Add ? object-placement-help tiles
Stefano Rivera <stefano@rivera.za.net>
parents:
97
diff
changeset
|
152 objects = [] |
b502e732f821
Add ? object-placement-help tiles
Stefano Rivera <stefano@rivera.za.net>
parents:
97
diff
changeset
|
153 objects += self.level_data.get('enemies', []) |
b502e732f821
Add ? object-placement-help tiles
Stefano Rivera <stefano@rivera.za.net>
parents:
97
diff
changeset
|
154 objects += self.level_data.get('sprites', []) |
b502e732f821
Add ? object-placement-help tiles
Stefano Rivera <stefano@rivera.za.net>
parents:
97
diff
changeset
|
155 |
b502e732f821
Add ? object-placement-help tiles
Stefano Rivera <stefano@rivera.za.net>
parents:
97
diff
changeset
|
156 for object_ in objects: |
b502e732f821
Add ? object-placement-help tiles
Stefano Rivera <stefano@rivera.za.net>
parents:
97
diff
changeset
|
157 if [x, y] == object_['pos']: |
b502e732f821
Add ? object-placement-help tiles
Stefano Rivera <stefano@rivera.za.net>
parents:
97
diff
changeset
|
158 break |
b502e732f821
Add ? object-placement-help tiles
Stefano Rivera <stefano@rivera.za.net>
parents:
97
diff
changeset
|
159 else: |
b502e732f821
Add ? object-placement-help tiles
Stefano Rivera <stefano@rivera.za.net>
parents:
97
diff
changeset
|
160 tile = self.get_debug_tile(x, y) |
b502e732f821
Add ? object-placement-help tiles
Stefano Rivera <stefano@rivera.za.net>
parents:
97
diff
changeset
|
161 print "Debug tile at (%i, %i)" % (x, y) |
b502e732f821
Add ? object-placement-help tiles
Stefano Rivera <stefano@rivera.za.net>
parents:
97
diff
changeset
|
162 self.tiles.add(tile) |
b502e732f821
Add ? object-placement-help tiles
Stefano Rivera <stefano@rivera.za.net>
parents:
97
diff
changeset
|
163 self.sprites.add(tile) |
b502e732f821
Add ? object-placement-help tiles
Stefano Rivera <stefano@rivera.za.net>
parents:
97
diff
changeset
|
164 |
b502e732f821
Add ? object-placement-help tiles
Stefano Rivera <stefano@rivera.za.net>
parents:
97
diff
changeset
|
165 |
b502e732f821
Add ? object-placement-help tiles
Stefano Rivera <stefano@rivera.za.net>
parents:
97
diff
changeset
|
166 def get_debug_tile(self, x, y): |
b502e732f821
Add ? object-placement-help tiles
Stefano Rivera <stefano@rivera.za.net>
parents:
97
diff
changeset
|
167 surface = Surface((64, 64)) |
b502e732f821
Add ? object-placement-help tiles
Stefano Rivera <stefano@rivera.za.net>
parents:
97
diff
changeset
|
168 surface.fill(Color('black')) |
b502e732f821
Add ? object-placement-help tiles
Stefano Rivera <stefano@rivera.za.net>
parents:
97
diff
changeset
|
169 text = Text("? Tile at\n(%i, %i)" % (x, y), (2, 2), size=14, color='white') |
b502e732f821
Add ? object-placement-help tiles
Stefano Rivera <stefano@rivera.za.net>
parents:
97
diff
changeset
|
170 text.draw(surface) |
b502e732f821
Add ? object-placement-help tiles
Stefano Rivera <stefano@rivera.za.net>
parents:
97
diff
changeset
|
171 return Geography((x, y), surface.convert_alpha()) |