BTP main module - game.py

About

This is main game executable file which contains main logics of the game and manipulates other modules and classes (basically, screens module).

At first, we set game.CAPTION and game.SIZE constants, which is responsible for main window title and size respectively.

CAPTION = 'Big Typernatural Project'
SIZE = (1000, 700)  #: Should be at least the size of images in Images folder

Note

Size of the window must be smaller or at least the same as any image used as background, otherwise the image won’t cover all screen and there will be black areas.

Then we create new pygame window using those constants.

if __name__ == '__main__':
    pg.display.set_caption(CAPTION)
    screen = pg.display.set_mode(SIZE)
    Game().loop(screen)
    pg.quit()

Last two lines are basically creation of main game class game.Game and a proper pygame quit. The game.Game class is looping through whole lots of game logics while True, so it’s okay that we’re quiting our game right after game.Game creation.

Note

The __name__ == '__main__' thing is basically checking whether we’re running our game standalone way (form console, as executable, etc.) or we’re importing it. Even though I’m not intended to import it and you’re should not too, it’s proper way to protect your project from undesired execution.

Imports

screens For wrapping screens around (see Interfaces wrapper - screens.py)
os Determine whether file exists or not
pickle For saving/loading Pers() object (savegame)
random For executing battle only if the chance is right
pygame As a core of the whole game it is imported in each module

Classes

Game

This is the main logics class which rules the game while true through screens module.

class game.Game[source]
loop(surface)[source]

Main function loop of the game

We have only one method here and nothing else - game.Game.loop(). So, basically, we don’t need a class - we can easily make it a function or even write all the code within __name__ == '__main__' condition, but I like OOP concepts and I like extensibility of classes and object. So for now it will stand a class, but when the stable 1.0 version is out - we’ll see.

Todo

Make something about attr -> param linking support

Our game.Game.loop() method have only one attribute - game.Game.loop.surface which is the screen area for drawing all the stuff.

At first, we set some variables:

        pers = Pers()
        started = False # Prevent multiple game loads + game quit to menu trigger
  • game.Game.loop.pers - our game.Pers object to work with. All the data about your character is stored within it. Your hitpoints, your current location and etc.
  • game.Game.loop.started - boolean which tells us whether game is already loaded or is it should yet be loaded/created.

Then goes main cycle which loops while True.

        while True:
            # Create menu
            while pers.name == '':
                login = screens.Menu().main(surface)
                # Create loginscreen
                if login:
                    pers.name = screens.Login().main(surface)

            # Load game of save new game, then started=True
            if not started:
                if os.path.isfile('Saves/' + pers.name):
                    pers.load()
                else:
                    pers.save()
                    screens.Introduction().main(surface, pers.name)
                started = True
            (pers.place, mobs) = screens.World().main(surface, pers.place)
            if random.randrange(0, 100) < mobs['Chance']:
                pers = screens.Battle().main(surface, mobs, pers, Mob())
            # Save each loop
            pers.save()

Here we create menu using class screens.Menu and it’s method screens.Menu.main(). When ‘New game / load game’ option is selected, menu returns something (not important what) into the local login variable which, if not empty, will load screens.Login.main() method from screens.Login.

Well, the login screen will return a name when it is entered to login screen and Enter is pressed. The name will be stored in game.Pers.name variable and then whole cycle will stop working. Because game.Pers.name won’t be empty anymore.

The next step is to save game and start intro or to load game if user entered the name which already exists in Saves folder. Here we’re using os module to check whether savegame exists or not.

If it exists, we use game.Pers.load() method which loads whole object data by means of pickle. If it isn’t, firstly we’re saving whole object data to the file and then we’re executing screens.World.main() method form screens.World class, which is intended to tell user some pre-history of game world and give hime base knowledge of what he’ll be waiting within the game.

After that, the variable game.Game.loop.started sets to True and this part of code never repeats too.

Next step is finally the world loading. Class screens.World is showing world until any action was performed. When an action was performed, screens.World returns next place to game.Pers.place and mobs record for new place to local variable mobs.

There’s our random module comes in handy: we’re using it to calculate chances that we’re in trouble and monsters are attacking.

Then we’re saving a game (after successful battle) and all begins again

Note

There will be lots more logics added to calculate, it’s early development stage of the game. In the future, you’ll be able to ‘cleanse’ locations so that mobs you’ve killed won’t attack you again or even will respawn after some time. Now, however, if you’ll kill any monsters (hah, battle is not yet ready) and you’ll try to load the game - they can attack you again.

Mob

There’s not much done yet about this class. It’s here just for an example of what will be done soon.

class game.Mob(maxhp)[source]

Creates new monster who is to fight you

maxhp = 20

Standard mob hitpoints

Source code:

    maxhp = 20  #: Standard mob hitpoints
    hp = maxhp

    def __init__(self, maxhp):
        self.maxhp = maxhp

Pers

Handles all Player data.

class game.Pers[source]
load()[source]

Load self Pers() object from file

name = ''

Player name stored internally for easy self save/load

place = 'OldManHouse'

Standard first place of a game (changeable through the game)

save()[source]

Saves self Pers() object to file

Source code:

    name = ''               #: Player name stored internally for easy self save/load
    place = 'OldManHouse'   #: Standard first place of a game (changeable through the game)
    maxhp = 20
    hp = maxhp

    def save(self):
        """Saves self Pers() object to file"""
        with open('Saves/' + self.name, 'wb') as f:
            pickle.dump(self, f)
            print('Game saved as ' + self.name)

    def load(self):
        """Load self Pers() object from file"""
        with open('Saves/' + self.name, 'rb') as f:
            self = pickle.load(f)
            print('Game loaded as ' + self.name)

Quest

This class will contain lots of tasks, jounral, other things to handle all the quests system and other logic. Yet it is far not done.

class game.Quest[source]

Source code:

    print('Class for quests and tasks and notes')