all repos — Legends-RPG @ c0a1a80585351c8001637d8bf163dd13b033aaa7

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