data/tools.py (view raw)
1__author__ = 'justinarmstrong'
2
3import os, random
4import pygame as pg
5from . import constants as c
6
7class Control(object):
8 """
9 Control class for entire project. Contains the game loop, and contains
10 the event_loop which passes events to States as needed. Logic for flipping
11 states is also found here.
12 """
13 def __init__(self, caption):
14 self.screen = pg.display.get_surface()
15 self.done = False
16 self.clock = pg.time.Clock()
17 self.caption = caption
18 self.fps = 60
19 self.show_fps = False
20 self.current_time = 0.0
21 self.keys = pg.key.get_pressed()
22 self.state_dict = {}
23 self.state_name = None
24 self.state = None
25
26 def setup_states(self, state_dict, start_state):
27 self.state_dict = state_dict
28 self.state_name = start_state
29 self.state = self.state_dict[self.state_name]
30
31 def update(self):
32 self.current_time = pg.time.get_ticks()
33 if self.state.quit:
34 self.done = True
35 elif self.state.done:
36 self.flip_state()
37 self.state.update(self.screen, self.keys, self.current_time)
38
39 def flip_state(self):
40 previous, self.state_name = self.state_name, self.state.next
41 persist = self.state.cleanup()
42 self.state = self.state_dict[self.state_name]
43 self.state.previous = previous
44 self.state.startup(self.current_time, persist)
45 self.set_music()
46
47 def set_music(self):
48 """
49 Set music for the new state.
50 """
51 if self.state.music:
52 pg.mixer.music.load(self.state.music)
53 pg.mixer.music.set_volume(self.state.volume)
54 pg.mixer.music.play(-1)
55
56 def event_loop(self):
57 self.events = pg.event.get()
58
59 for event in self.events:
60 if event.type == pg.QUIT:
61 self.done = True
62 elif event.type == pg.KEYDOWN:
63 if event.key == pg.K_ESCAPE:
64 self.done = True
65 self.keys = pg.key.get_pressed()
66 self.toggle_show_fps(event.key)
67 self.state.get_event(event)
68 elif event.type == pg.KEYUP:
69 self.keys = pg.key.get_pressed()
70 self.state.get_event(event)
71
72 def toggle_show_fps(self, key):
73 if key == pg.K_F5:
74 self.show_fps = not self.show_fps
75 if not self.show_fps:
76 pg.display.set_caption(self.caption)
77
78 def main(self):
79 """Main loop for entire program"""
80 while not self.done:
81 self.event_loop()
82 self.update()
83 pg.display.update()
84 self.clock.tick(self.fps)
85 if self.show_fps:
86 fps = self.clock.get_fps()
87 with_fps = "{} - {:.2f} FPS".format(self.caption, fps)
88 pg.display.set_caption(with_fps)
89
90
91class _State(object):
92 """Base class for all game states"""
93 def __init__(self):
94 self.start_time = 0.0
95 self.current_time = 0.0
96 self.done = False
97 self.quit = False
98 self.next = None
99 self.previous = None
100 self.game_data = {}
101 self.music = None
102
103 def get_event(self, event):
104 pass
105
106 def startup(self, current_time, game_data):
107 self.game_data = game_data
108 self.start_time = current_time
109
110 def cleanup(self):
111 self.done = False
112 return self.game_data
113
114 def update(self, surface, keys, current_time):
115 pass
116
117
118def load_all_gfx(directory, colorkey=(255,0,255), accept=('.png', 'jpg', 'bmp')):
119 graphics = {}
120 for pic in os.listdir(directory):
121 name, ext = os.path.splitext(pic)
122 if ext.lower() in accept:
123 img = pg.image.load(os.path.join(directory, pic))
124 if img.get_alpha():
125 img = img.convert_alpha()
126 else:
127 img = img.convert()
128 img.set_colorkey(colorkey)
129 graphics[name] = img
130 return graphics
131
132
133def load_all_music(directory, accept=('.wav', '.mp3', '.ogg', '.mdi')):
134 songs = {}
135 for song in os.listdir(directory):
136 name, ext = os.path.splitext(song)
137 if ext.lower() in accept:
138 songs[name] = os.path.join(directory, song)
139 return songs
140
141
142def load_all_fonts(directory, accept=('.ttf')):
143 return load_all_music(directory, accept)
144
145
146def load_all_tmx(directory, accept=('.tmx')):
147 return load_all_music(directory, accept)
148
149
150def load_all_sfx(directory, accept=('.wav','.mp3','.ogg','.mdi')):
151 effects = {}
152 for fx in os.listdir(directory):
153 name, ext = os.path.splitext(fx)
154 if ext.lower() in accept:
155 effects[name] = pg.mixer.Sound(os.path.join(directory, fx))
156 return effects
157
158
159def get_image(x, y, width, height, sprite_sheet):
160 """Extracts image from sprite sheet"""
161 image = pg.Surface([width, height])
162 rect = image.get_rect()
163
164 image.blit(sprite_sheet, (0, 0), (x, y, width, height))
165 image.set_colorkey(c.BLACK)
166
167 return image
168
169def get_tile(x, y, tileset, width=16, height=16, scale=1):
170 """Gets the surface and rect for a tile"""
171 surface = get_image(x, y, width, height, tileset)
172 surface = pg.transform.scale(surface, (int(width*scale), int(height*scale)))
173 rect = surface.get_rect()
174
175 tile_dict = {'surface': surface,
176 'rect': rect}
177
178 return tile_dict
179
180def notify_observers(self, event):
181 """
182 Notify all observers of events.
183 """
184 for each_observer in self.observers:
185 each_observer.on_notify(event)
186
187def create_game_data_dict():
188 """Create a dictionary of persistant values the player
189 carries between states"""
190
191 player_items = {'GOLD': dict([('quantity',200),
192 ('value',0)]),
193 'Healing Potion': dict([('quantity',2),
194 ('value',15)]),
195 'Ether Potion': dict([('quantity',1),
196 ('value', 15)]),
197 'Rapier': dict([('quantity', 1),
198 ('value', 50),
199 ('power', 5)]),
200 'equipped weapon': 'Rapier',
201 'equipped armor': []}
202
203 player_health = {'current': 70,
204 'maximum': 70}
205
206 player_magic = {'current': 70,
207 'maximum': 70}
208
209 player_stats = {'health': player_health,
210 'Level': 1,
211 'experience to next level': 30,
212 'magic': player_magic,
213 'attack points': 10,
214 'Defense Points': 10}
215
216
217 data_dict = {'last location': None,
218 'last state': None,
219 'last direction': 'down',
220 'king item': 'GOLD',
221 'old man item': {'ELIXIR': dict([('value',1000),
222 ('quantity',1)])},
223 'player inventory': player_items,
224 'player stats': player_stats,
225 'battle counter': random.randint(50, 255),
226 'treasure1': True,
227 'treasure2': True,
228 'treasure3': True,
229 'treasure4': True,
230 'treasure5': True,
231 'talked to king': False,
232 'brother quest complete': False,
233 'talked to sick brother': False,
234 'has brother elixir': False,
235 'elixir received': False,
236 'old man gift': '',
237 'battle type': '',
238 'crown quest': False,
239 'delivered crown': False,
240 'brother item': 'ELIXIR'
241 }
242
243 return data_dict
244
245
246
247
248
249
250