all repos — Legends-RPG @ a5b828ace1209769c68ffed3ad2178da480599a4

A fantasy mini-RPG built with Python and Pygame.

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