annotate skaapsteker/sprites/base.py @ 206:e2acf4663065

Move fox properties to the world
author Neil Muller <drnlmuller@gmail.com>
date Wed, 06 Apr 2011 23:19:08 +0200
parents 0a793c4ac341
children c72d9bf911fb
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
18
81974842b38e Add skeleton for physics and sprites.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
1 """Basic sprite classes."""
81974842b38e Add skeleton for physics and sprites.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
2
35
38d2f7c43d86 Sprite-based tiles. \o/
Jeremy Thurgood <firxen@gmail.com>
parents: 28
diff changeset
3 from pygame import Rect
38d2f7c43d86 Sprite-based tiles. \o/
Jeremy Thurgood <firxen@gmail.com>
parents: 28
diff changeset
4
22
b815471d4b95 Move sprite base class into physics since they're tightly coupled.
Simon Cross <hodgestar@gmail.com>
parents: 18
diff changeset
5 from skaapsteker.physics import Sprite
59
1be1ca704346 Add Layers constants. Set Monsters to player's layer by default
Neil Muller <drnlmuller@gmail.com>
parents: 47
diff changeset
6 from skaapsteker.constants import Layers
47
215e2e74c244 Better dummy monster.
Jeremy Thurgood <firxen@gmail.com>
parents: 35
diff changeset
7 from skaapsteker import data
189
9d08f99b5ddf Add npcs to gamestate. Update gamestate. Pass world around a bit. Some other stuff.
Simon Cross <hodgestar@gmail.com>
parents: 186
diff changeset
8 from skaapsteker import dialogue
18
81974842b38e Add skeleton for physics and sprites.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
9
81974842b38e Add skeleton for physics and sprites.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
10
35
38d2f7c43d86 Sprite-based tiles. \o/
Jeremy Thurgood <firxen@gmail.com>
parents: 28
diff changeset
11 TILE_SIZE = (64, 64)
38d2f7c43d86 Sprite-based tiles. \o/
Jeremy Thurgood <firxen@gmail.com>
parents: 28
diff changeset
12
97
a1d95c6152a0 Shiny new collision detection. Read code for usage information.
Simon Cross <hodgestar@gmail.com>
parents: 88
diff changeset
13 # Collision Layers (values are ids not numbers)
a1d95c6152a0 Shiny new collision detection. Read code for usage information.
Simon Cross <hodgestar@gmail.com>
parents: 88
diff changeset
14 PC_LAYER = 0
a1d95c6152a0 Shiny new collision detection. Read code for usage information.
Simon Cross <hodgestar@gmail.com>
parents: 88
diff changeset
15 MONSTER_LAYER = 1
189
9d08f99b5ddf Add npcs to gamestate. Update gamestate. Pass world around a bit. Some other stuff.
Simon Cross <hodgestar@gmail.com>
parents: 186
diff changeset
16 NPC_LAYER = 2
97
a1d95c6152a0 Shiny new collision detection. Read code for usage information.
Simon Cross <hodgestar@gmail.com>
parents: 88
diff changeset
17
35
38d2f7c43d86 Sprite-based tiles. \o/
Jeremy Thurgood <firxen@gmail.com>
parents: 28
diff changeset
18
202
a11325bc5ff0 Sprite refactoring stuff.
Jeremy Thurgood <firxen@gmail.com>
parents: 193
diff changeset
19
a11325bc5ff0 Sprite refactoring stuff.
Jeremy Thurgood <firxen@gmail.com>
parents: 193
diff changeset
20 class GameSprite(Sprite):
a11325bc5ff0 Sprite refactoring stuff.
Jeremy Thurgood <firxen@gmail.com>
parents: 193
diff changeset
21 image_dir = 'sprites/'
a11325bc5ff0 Sprite refactoring stuff.
Jeremy Thurgood <firxen@gmail.com>
parents: 193
diff changeset
22 image_file = None
97
a1d95c6152a0 Shiny new collision detection. Read code for usage information.
Simon Cross <hodgestar@gmail.com>
parents: 88
diff changeset
23
202
a11325bc5ff0 Sprite refactoring stuff.
Jeremy Thurgood <firxen@gmail.com>
parents: 193
diff changeset
24 def __init__(self, pos, **opts):
a11325bc5ff0 Sprite refactoring stuff.
Jeremy Thurgood <firxen@gmail.com>
parents: 193
diff changeset
25 Sprite.__init__(self)
a11325bc5ff0 Sprite refactoring stuff.
Jeremy Thurgood <firxen@gmail.com>
parents: 193
diff changeset
26 self.image = data.load_image(self.image_dir + self.image_file)
a11325bc5ff0 Sprite refactoring stuff.
Jeremy Thurgood <firxen@gmail.com>
parents: 193
diff changeset
27 self.starting_tile_pos = pos
a11325bc5ff0 Sprite refactoring stuff.
Jeremy Thurgood <firxen@gmail.com>
parents: 193
diff changeset
28 self.rect = self.image.get_rect(midbottom=(pos[0]*TILE_SIZE[0]+TILE_SIZE[0]/2, (pos[1]+1)*TILE_SIZE[1]))
a11325bc5ff0 Sprite refactoring stuff.
Jeremy Thurgood <firxen@gmail.com>
parents: 193
diff changeset
29 self.collide_rect = self.rect.move(0, 0)
a11325bc5ff0 Sprite refactoring stuff.
Jeremy Thurgood <firxen@gmail.com>
parents: 193
diff changeset
30 self.setup(**opts)
a11325bc5ff0 Sprite refactoring stuff.
Jeremy Thurgood <firxen@gmail.com>
parents: 193
diff changeset
31
a11325bc5ff0 Sprite refactoring stuff.
Jeremy Thurgood <firxen@gmail.com>
parents: 193
diff changeset
32
a11325bc5ff0 Sprite refactoring stuff.
Jeremy Thurgood <firxen@gmail.com>
parents: 193
diff changeset
33
a11325bc5ff0 Sprite refactoring stuff.
Jeremy Thurgood <firxen@gmail.com>
parents: 193
diff changeset
34 class Monster(GameSprite):
a11325bc5ff0 Sprite refactoring stuff.
Jeremy Thurgood <firxen@gmail.com>
parents: 193
diff changeset
35
97
a1d95c6152a0 Shiny new collision detection. Read code for usage information.
Simon Cross <hodgestar@gmail.com>
parents: 88
diff changeset
36 collision_layer = MONSTER_LAYER
a1d95c6152a0 Shiny new collision detection. Read code for usage information.
Simon Cross <hodgestar@gmail.com>
parents: 88
diff changeset
37 collides_with = set([PC_LAYER])
47
215e2e74c244 Better dummy monster.
Jeremy Thurgood <firxen@gmail.com>
parents: 35
diff changeset
38
117
b361d9e17c26 Angry fruit salad debug boxes.
Jeremy Thurgood <firxen@gmail.com>
parents: 97
diff changeset
39 debug_color = (240, 120, 120)
b361d9e17c26 Angry fruit salad debug boxes.
Jeremy Thurgood <firxen@gmail.com>
parents: 97
diff changeset
40
152
60138b935bc0 Make enemies block by default, so we can jump off them
Neil Muller <drnlmuller@gmail.com>
parents: 144
diff changeset
41 block = True
60138b935bc0 Make enemies block by default, so we can jump off them
Neil Muller <drnlmuller@gmail.com>
parents: 144
diff changeset
42
25
fe87d828d093 Very basic enemy support.
Jeremy Thurgood <firxen@gmail.com>
parents: 22
diff changeset
43 def __init__(self, pos, **opts):
202
a11325bc5ff0 Sprite refactoring stuff.
Jeremy Thurgood <firxen@gmail.com>
parents: 193
diff changeset
44 GameSprite.__init__(self, pos, **opts)
186
72e92893ccb8 Use layers for floor check
Neil Muller <drnlmuller@gmail.com>
parents: 174
diff changeset
45 self.floor_rect = Rect(self.collide_rect.topleft, (self.collide_rect.width, 2))
59
1be1ca704346 Add Layers constants. Set Monsters to player's layer by default
Neil Muller <drnlmuller@gmail.com>
parents: 47
diff changeset
46 self._layer = Layers.PLAYER
206
e2acf4663065 Move fox properties to the world
Neil Muller <drnlmuller@gmail.com>
parents: 203
diff changeset
47 self.health = 10
203
0a793c4ac341 Add default health values
Neil Muller <drnlmuller@gmail.com>
parents: 202
diff changeset
48 self.setup(**opts)
25
fe87d828d093 Very basic enemy support.
Jeremy Thurgood <firxen@gmail.com>
parents: 22
diff changeset
49
fe87d828d093 Very basic enemy support.
Jeremy Thurgood <firxen@gmail.com>
parents: 22
diff changeset
50
202
a11325bc5ff0 Sprite refactoring stuff.
Jeremy Thurgood <firxen@gmail.com>
parents: 193
diff changeset
51 def collided_player(self):
a11325bc5ff0 Sprite refactoring stuff.
Jeremy Thurgood <firxen@gmail.com>
parents: 193
diff changeset
52 print "%s collided with player" % self
18
81974842b38e Add skeleton for physics and sprites.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
53
81974842b38e Add skeleton for physics and sprites.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
54
202
a11325bc5ff0 Sprite refactoring stuff.
Jeremy Thurgood <firxen@gmail.com>
parents: 193
diff changeset
55 class NPC(GameSprite):
189
9d08f99b5ddf Add npcs to gamestate. Update gamestate. Pass world around a bit. Some other stuff.
Simon Cross <hodgestar@gmail.com>
parents: 186
diff changeset
56
9d08f99b5ddf Add npcs to gamestate. Update gamestate. Pass world around a bit. Some other stuff.
Simon Cross <hodgestar@gmail.com>
parents: 186
diff changeset
57 image_file = None
9d08f99b5ddf Add npcs to gamestate. Update gamestate. Pass world around a bit. Some other stuff.
Simon Cross <hodgestar@gmail.com>
parents: 186
diff changeset
58 collision_layer = NPC_LAYER
9d08f99b5ddf Add npcs to gamestate. Update gamestate. Pass world around a bit. Some other stuff.
Simon Cross <hodgestar@gmail.com>
parents: 186
diff changeset
59 collides_with = set([PC_LAYER])
9d08f99b5ddf Add npcs to gamestate. Update gamestate. Pass world around a bit. Some other stuff.
Simon Cross <hodgestar@gmail.com>
parents: 186
diff changeset
60
9d08f99b5ddf Add npcs to gamestate. Update gamestate. Pass world around a bit. Some other stuff.
Simon Cross <hodgestar@gmail.com>
parents: 186
diff changeset
61 debug_color = (240, 240, 240)
9d08f99b5ddf Add npcs to gamestate. Update gamestate. Pass world around a bit. Some other stuff.
Simon Cross <hodgestar@gmail.com>
parents: 186
diff changeset
62
202
a11325bc5ff0 Sprite refactoring stuff.
Jeremy Thurgood <firxen@gmail.com>
parents: 193
diff changeset
63 block = False
189
9d08f99b5ddf Add npcs to gamestate. Update gamestate. Pass world around a bit. Some other stuff.
Simon Cross <hodgestar@gmail.com>
parents: 186
diff changeset
64
9d08f99b5ddf Add npcs to gamestate. Update gamestate. Pass world around a bit. Some other stuff.
Simon Cross <hodgestar@gmail.com>
parents: 186
diff changeset
65 def __init__(self, pos, **opts):
202
a11325bc5ff0 Sprite refactoring stuff.
Jeremy Thurgood <firxen@gmail.com>
parents: 193
diff changeset
66 GameSprite.__init__(self, pos, **opts)
189
9d08f99b5ddf Add npcs to gamestate. Update gamestate. Pass world around a bit. Some other stuff.
Simon Cross <hodgestar@gmail.com>
parents: 186
diff changeset
67 self._layer = Layers.PLAYER
202
a11325bc5ff0 Sprite refactoring stuff.
Jeremy Thurgood <firxen@gmail.com>
parents: 193
diff changeset
68
189
9d08f99b5ddf Add npcs to gamestate. Update gamestate. Pass world around a bit. Some other stuff.
Simon Cross <hodgestar@gmail.com>
parents: 186
diff changeset
69
193
897eec397cbb Fix state checks for hattori, ichiro, kaneda and kumiko. In the process provide easier access to other npcs.
Simon Cross <hodgestar@gmail.com>
parents: 191
diff changeset
70 def setup(self, name, world, dsm):
897eec397cbb Fix state checks for hattori, ichiro, kaneda and kumiko. In the process provide easier access to other npcs.
Simon Cross <hodgestar@gmail.com>
parents: 191
diff changeset
71 self.dsm = dialogue.DSM(name, world, dsm)
18
81974842b38e Add skeleton for physics and sprites.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
72
81974842b38e Add skeleton for physics and sprites.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
73
202
a11325bc5ff0 Sprite refactoring stuff.
Jeremy Thurgood <firxen@gmail.com>
parents: 193
diff changeset
74 class Projectile(GameSprite):
18
81974842b38e Add skeleton for physics and sprites.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
75 gravitates = False
81974842b38e Add skeleton for physics and sprites.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
76
81974842b38e Add skeleton for physics and sprites.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
77
202
a11325bc5ff0 Sprite refactoring stuff.
Jeremy Thurgood <firxen@gmail.com>
parents: 193
diff changeset
78 class Item(GameSprite):
18
81974842b38e Add skeleton for physics and sprites.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
79 mobile = False
81974842b38e Add skeleton for physics and sprites.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
80 gravitates = False
81974842b38e Add skeleton for physics and sprites.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
81
127
e1dd3b785269 Initial game state stuff.
Jeremy Thurgood <firxen@gmail.com>
parents: 122
diff changeset
82 collision_layer = MONSTER_LAYER
e1dd3b785269 Initial game state stuff.
Jeremy Thurgood <firxen@gmail.com>
parents: 122
diff changeset
83 collides_with = set([PC_LAYER])
e1dd3b785269 Initial game state stuff.
Jeremy Thurgood <firxen@gmail.com>
parents: 122
diff changeset
84
191
993f4f55eb93 Minor item changes.
Jeremy Thurgood <firxen@gmail.com>
parents: 189
diff changeset
85 portable = True
127
e1dd3b785269 Initial game state stuff.
Jeremy Thurgood <firxen@gmail.com>
parents: 122
diff changeset
86
e1dd3b785269 Initial game state stuff.
Jeremy Thurgood <firxen@gmail.com>
parents: 122
diff changeset
87 def __init__(self, pos, **opts):
202
a11325bc5ff0 Sprite refactoring stuff.
Jeremy Thurgood <firxen@gmail.com>
parents: 193
diff changeset
88 GameSprite.__init__(self, pos, **opts)
127
e1dd3b785269 Initial game state stuff.
Jeremy Thurgood <firxen@gmail.com>
parents: 122
diff changeset
89 self._layer = Layers.PLAYER
e1dd3b785269 Initial game state stuff.
Jeremy Thurgood <firxen@gmail.com>
parents: 122
diff changeset
90
e1dd3b785269 Initial game state stuff.
Jeremy Thurgood <firxen@gmail.com>
parents: 122
diff changeset
91
193
897eec397cbb Fix state checks for hattori, ichiro, kaneda and kumiko. In the process provide easier access to other npcs.
Simon Cross <hodgestar@gmail.com>
parents: 191
diff changeset
92 def setup(self, name, world):
127
e1dd3b785269 Initial game state stuff.
Jeremy Thurgood <firxen@gmail.com>
parents: 122
diff changeset
93 pass
e1dd3b785269 Initial game state stuff.
Jeremy Thurgood <firxen@gmail.com>
parents: 122
diff changeset
94
18
81974842b38e Add skeleton for physics and sprites.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
95
191
993f4f55eb93 Minor item changes.
Jeremy Thurgood <firxen@gmail.com>
parents: 189
diff changeset
96 def get_debug_color(self):
993f4f55eb93 Minor item changes.
Jeremy Thurgood <firxen@gmail.com>
parents: 189
diff changeset
97 if self.portable:
993f4f55eb93 Minor item changes.
Jeremy Thurgood <firxen@gmail.com>
parents: 189
diff changeset
98 return (240, 0, 240)
993f4f55eb93 Minor item changes.
Jeremy Thurgood <firxen@gmail.com>
parents: 189
diff changeset
99 return (0, 0, 240)
993f4f55eb93 Minor item changes.
Jeremy Thurgood <firxen@gmail.com>
parents: 189
diff changeset
100
993f4f55eb93 Minor item changes.
Jeremy Thurgood <firxen@gmail.com>
parents: 189
diff changeset
101
202
a11325bc5ff0 Sprite refactoring stuff.
Jeremy Thurgood <firxen@gmail.com>
parents: 193
diff changeset
102 def collided_player(self):
a11325bc5ff0 Sprite refactoring stuff.
Jeremy Thurgood <firxen@gmail.com>
parents: 193
diff changeset
103 print "Player touched %s" % self
a11325bc5ff0 Sprite refactoring stuff.
Jeremy Thurgood <firxen@gmail.com>
parents: 193
diff changeset
104
a11325bc5ff0 Sprite refactoring stuff.
Jeremy Thurgood <firxen@gmail.com>
parents: 193
diff changeset
105
18
81974842b38e Add skeleton for physics and sprites.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
106 class Geography(Sprite):
81974842b38e Add skeleton for physics and sprites.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
107 mobile = False
81974842b38e Add skeleton for physics and sprites.
Simon Cross <hodgestar@gmail.com>
parents:
diff changeset
108 gravitates = False
189
9d08f99b5ddf Add npcs to gamestate. Update gamestate. Pass world around a bit. Some other stuff.
Simon Cross <hodgestar@gmail.com>
parents: 186
diff changeset
109 collides_with = set([PC_LAYER, MONSTER_LAYER, NPC_LAYER])
144
6b488e1351a5 Buggy ground implementation. Make the world less bouncy
Neil Muller <drnlmuller@gmail.com>
parents: 127
diff changeset
110 is_ground = True
6b488e1351a5 Buggy ground implementation. Make the world less bouncy
Neil Muller <drnlmuller@gmail.com>
parents: 127
diff changeset
111 bounce_factor = (0.0, 0.0)
28
94d5ebaa912f Example for global sprite importing.
Simon Cross <hodgestar@gmail.com>
parents: 25
diff changeset
112
35
38d2f7c43d86 Sprite-based tiles. \o/
Jeremy Thurgood <firxen@gmail.com>
parents: 28
diff changeset
113 def __init__(self, pos, image):
38d2f7c43d86 Sprite-based tiles. \o/
Jeremy Thurgood <firxen@gmail.com>
parents: 28
diff changeset
114 Sprite.__init__(self)
38d2f7c43d86 Sprite-based tiles. \o/
Jeremy Thurgood <firxen@gmail.com>
parents: 28
diff changeset
115 self.tile_pos = pos
38d2f7c43d86 Sprite-based tiles. \o/
Jeremy Thurgood <firxen@gmail.com>
parents: 28
diff changeset
116 self.image = image
122
51bcc909873d Saner, buggier collision rectangles
Neil Muller <drnlmuller@gmail.com>
parents: 117
diff changeset
117 self.collide_rect = self.image.get_bounding_rect(1)
186
72e92893ccb8 Use layers for floor check
Neil Muller <drnlmuller@gmail.com>
parents: 174
diff changeset
118 self.floor_rect = Rect(self.collide_rect.topleft, (self.collide_rect.width, 2))
122
51bcc909873d Saner, buggier collision rectangles
Neil Muller <drnlmuller@gmail.com>
parents: 117
diff changeset
119 self.rect = self.image.get_rect()
51bcc909873d Saner, buggier collision rectangles
Neil Muller <drnlmuller@gmail.com>
parents: 117
diff changeset
120 self.rect_offset = self.collide_rect.left - self.rect.left, self.rect.top - self.rect.top
51bcc909873d Saner, buggier collision rectangles
Neil Muller <drnlmuller@gmail.com>
parents: 117
diff changeset
121 self.collide_rect.topleft = pos[0] * TILE_SIZE[0] + self.rect_offset[0], pos[1] * TILE_SIZE[1] + self.rect_offset[1]
186
72e92893ccb8 Use layers for floor check
Neil Muller <drnlmuller@gmail.com>
parents: 174
diff changeset
122 self.floor_rect.topleft = pos[0] * TILE_SIZE[0] + self.rect_offset[0], pos[1] * TILE_SIZE[1] + self.rect_offset[1]
122
51bcc909873d Saner, buggier collision rectangles
Neil Muller <drnlmuller@gmail.com>
parents: 117
diff changeset
123 self.rect.topleft = pos[0] * TILE_SIZE[0], pos[1] * TILE_SIZE[1]
35
38d2f7c43d86 Sprite-based tiles. \o/
Jeremy Thurgood <firxen@gmail.com>
parents: 28
diff changeset
124
117
b361d9e17c26 Angry fruit salad debug boxes.
Jeremy Thurgood <firxen@gmail.com>
parents: 97
diff changeset
125 def get_debug_color(self):
b361d9e17c26 Angry fruit salad debug boxes.
Jeremy Thurgood <firxen@gmail.com>
parents: 97
diff changeset
126 if self.floor or self.block:
b361d9e17c26 Angry fruit salad debug boxes.
Jeremy Thurgood <firxen@gmail.com>
parents: 97
diff changeset
127 return (240, 240, 0)
b361d9e17c26 Angry fruit salad debug boxes.
Jeremy Thurgood <firxen@gmail.com>
parents: 97
diff changeset
128 return (0, 240, 0)
b361d9e17c26 Angry fruit salad debug boxes.
Jeremy Thurgood <firxen@gmail.com>
parents: 97
diff changeset
129
35
38d2f7c43d86 Sprite-based tiles. \o/
Jeremy Thurgood <firxen@gmail.com>
parents: 28
diff changeset
130
127
e1dd3b785269 Initial game state stuff.
Jeremy Thurgood <firxen@gmail.com>
parents: 122
diff changeset
131 def find_sprite(descr, mod_name=None):
28
94d5ebaa912f Example for global sprite importing.
Simon Cross <hodgestar@gmail.com>
parents: 25
diff changeset
132 """Create a sprite object from a dictionary describing it."""
94d5ebaa912f Example for global sprite importing.
Simon Cross <hodgestar@gmail.com>
parents: 25
diff changeset
133 descr = descr.copy()
127
e1dd3b785269 Initial game state stuff.
Jeremy Thurgood <firxen@gmail.com>
parents: 122
diff changeset
134 cls_name = descr.pop("type")
e1dd3b785269 Initial game state stuff.
Jeremy Thurgood <firxen@gmail.com>
parents: 122
diff changeset
135 if mod_name is None:
e1dd3b785269 Initial game state stuff.
Jeremy Thurgood <firxen@gmail.com>
parents: 122
diff changeset
136 mod_name, cls_name = cls_name.rsplit(".", 1)
28
94d5ebaa912f Example for global sprite importing.
Simon Cross <hodgestar@gmail.com>
parents: 25
diff changeset
137 mod_name = ".".join(["skaapsteker.sprites", mod_name])
94d5ebaa912f Example for global sprite importing.
Simon Cross <hodgestar@gmail.com>
parents: 25
diff changeset
138 mod = __import__(mod_name, fromlist=[cls_name])
94d5ebaa912f Example for global sprite importing.
Simon Cross <hodgestar@gmail.com>
parents: 25
diff changeset
139 cls = getattr(mod, cls_name)
94d5ebaa912f Example for global sprite importing.
Simon Cross <hodgestar@gmail.com>
parents: 25
diff changeset
140 return cls(**descr)
35
38d2f7c43d86 Sprite-based tiles. \o/
Jeremy Thurgood <firxen@gmail.com>
parents: 28
diff changeset
141