Game

class gamelib.Game.Game(name='Game', boards={}, menu={}, current_level=None, enable_partial_display=False, partial_display_viewport=None)

Bases: object

A class that serve as a game engine.

This object is the central system that allow the management of a game. It holds boards (see gamelib.Board.Board), associate it to level, takes care of level changing, etc.

Parameters:
  • name (str) – The Game name.
  • boards (dict) – A dictionnary of boards with the level number as key and a board reference as value.
  • menu (dict) – A dictionnary of menus with a category (str) as key and another dictionnary (key: a shortcut, value: a description) as value.
  • current_level (int) – The current level.
  • enable_partial_display (bool) – A boolean to tell the Game object to enable or not partial display of boards. Default: False.
  • partial_display_viewport (list) – A 2 int elements array that gives the radius of the partial display in number of row and column. Please see display_around().

Note

The game object has an object_library member that is always an empty array except just after loading a board. In this case, if the board have a “library” field, it is going to be used to populate object_library. This library is accessible through the Game object mainly so people have access to it across different Boards during level design in the editor. That architecture decision is debatable.

Note

The constructor of Game takes care of initializing the terminal to properly render the colors on Windows.

Important

The Game object automatically assumes ownership over the Player.

actuate_npcs(level_number)

Actuate all NPCs on a given level

This method actuate all NPCs on a board associated with a level. At the moment it means moving the NPCs but as the Actuators become more capable this method will evolve to allow more choice (like attack use objects, etc.)

Parameters:level_number – The number of the level to actuate NPCs in.

Example:

mygame.actuate_npcs(1)

Note

This method only move NPCs when their actuator state is RUNNING. If it is PAUSED or STOPPED, theNPC is not moved.

actuate_projectiles(level_number)

Actuate all Projectiles on a given level

This method actuate all Projectiles on a board associated with a level. This method differs from actuate_npcs() as some logic is involved with projectiles that NPC do not have. This method decrease the available range by projectile.step each time it’s called. It also detects potential collisions. If the available range falls to 0 or a collision is detected the projectile hit_callback is called.

Parameters:level_number – The number of the level to actuate Projectiles in.

Example:

mygame.actuate_projectiles(1)

Note

This method only move Projectiles when their actuator state is RUNNING. If it is PAUSED or STOPPED, the Projectile is not moved.

add_board(level_number, board)

Add a board for the level number.

This method associate a Board (gamelib.Board.Board) to a level number.

Example:

game.add_board(1,myboard)
Parameters:
  • level_number (int) – the level number to associate the board to.
  • board (gamelib.Board.Board) – a Board object corresponding to the level number.
Raises:

HacInvalidTypeException – If either of these parameters are not of the correct type.

add_menu_entry(category, shortcut, message, data=None)

Add a new entry to the menu.

Add another shortcut and message to the specified category.

Categories help organize the different sections of a menu or dialogues.

Parameters:
  • category (str) – The category to which the entry should be added.
  • shortcut (str) – A shortcut (usually one key) to display.
  • message (various) – a message that explains what the shortcut does.
  • data – a data that you can get from the menu object.

The shortcut and data is optional.

Example:

game.add_menu_entry('main_menu','d','Go right',Constants.RIGHT)
game.add_menu_entry('main_menu',None,'-----------------')
game.add_menu_entry('main_menu','v','Change game speed')
add_npc(level_number, npc, row=None, column=None)

Add a NPC to the game. It will be placed on the board corresponding to the level_number. If row and column are not None, the NPC is placed at these coordinates. Else, it’s randomly placed in an empty cell.

Example:

game.add_npc(1,my_evil_npc,5,2)
Parameters:
  • level_number (int) – the level number of the board.
  • npc (gamelib.Characters.NPC) – the NPC to place.
  • row (int) – the row coordinate to place the NPC at.
  • column (int) – the column coordinate to place the NPC at.

If either of these parameters are not of the correct type, a HacInvalidTypeException exception is raised.

Important

If the NPC does not have an actuator, this method is going to affect a gamelib.Actuators.SimpleActuators.RandomActuator() to npc.actuator. And if npc.step == None, this method sets it to 1

add_projectile(level_number, projectile, row=None, column=None)

Add a Projectile to the game. It will be placed on the board corresponding to level_number. Neither row nor column can be None.

Example:

game.add_projectile(1, fireball, 5, 2)
Parameters:
  • level_number (int) – the level number of the board.
  • projectile (Projectile) – the Projectile to place.
  • row (int) – the row coordinate to place the Projectile at.
  • column (int) – the column coordinate to place the Projectile at.

If either of these parameters are not of the correct type, a HacInvalidTypeException exception is raised.

Important

If the Projectile does not have an actuator, this method is going to affect gamelib.Actuators.SimpleActuators.RandomActuator(moveset=[RIGHT]) to projectile.actuator. And if projectile.step == None, this method sets it to 1.

animate_items(level_number)

That method goes through all the BoardItems of a given map and call Animation.next_frame() :param level_number: The number of the level to animate items in. :type level_number: int

Raise:gamelib.HacExceptions.HacInvalidLevelException class:gamelib.HacExceptions.HacInvalidTypeException

Example:

mygame.animate_items(1)
change_level(level_number)

Change the current level, load the board and place the player to the right place.

Example:

game.change_level(1)
Parameters:level_number (int) – the level number to change to.
Raises:HacInvalidTypeException – If parameter is not an int.
clear_screen()

Clear the whole screen (i.e: remove everything written in terminal)

config(section='main')

Get the content of a previously loaded configuration section.

Parameters:section (str) – The name of the section.

Example:

if mygame.config('main')['hgl-version-required'] < 10100:
    print('The hac-game-lib version 1.1.0 or greater is required.')
    exit()
create_config(section)

Initialize a new config section.

The new section is a dictionary.

Parameters:section (str) – The name of the new section.

Example:

if mygame.config('high_scores') is None:
    mygame.create_config('high_scores')
mygame.config('high_scores')['first_place'] = mygame.player.name
current_board()

This method return the board object corresponding to the current_level.

Example:

game.current_board().display()

If current_level is set to a value with no corresponding board a HacException exception is raised with an invalid_level error.

delete_menu_category(category=None)

Delete an entire category from the menu.

That function removes the entire list of messages that are attached to the category.

Parameters:category (str) – The category to delete.
Raises:HacInvalidTypeException – If the category is not a string

Important

If the entry have no shortcut it’s advised not to try to update unless you have only one NoneType as a shortcut.

Example:

game.add_menu_entry('main_menu','d','Go right')
game.update_menu_entry('main_menu','d','Go LEFT',Constants.LEFT)
display_board()

Display the current board.

The behavior of that function is dependant on how you configured this object. If you set enable_partial_display to True AND partial_display_viewport is set to a correct value, it will call Game.current_board().display_around() with the correct parameters. The partial display will be centered on the player (Game.player). Otherwise it will just call Game.current_board().display().

Example:

mygame.enable_partial_display = True
# Number of rows, number of column (on each side, total viewport
# will be 20x20 in that case).
mygame.partial_display_viewport = [10, 10]
# This will call Game.current_board().display_around()
mygame.display()
mygame.enable_partial_display = False
# This will call Game.current_board().display()
mygame.display()
display_menu(category, orientation=10010000, paginate=10)

Display the menu.

This method display the whole menu for a given category.

Parameters:
  • category (str) – The category to display. Mandatory parameter.
  • orientation (gamelib.Constants.Constants) – The shortcut of the entry you want to get.
  • paginate (int) – pagination parameter (how many items to display before changing line or page).

Example:

game.display_menu('main_menu')
game.display_menu('main_menu', Constants.ORIENTATION_HORIZONTAL, 5)
display_player_stats(life_model='\x1b[41m \x1b[0m', void_model='\x1b[40m \x1b[0m')

Display the player name and health.

This method print the Player name, a health bar (20 blocks of life_model). When life is missing the complement (20-life missing) is printed using void_model. It also display the inventory value as “Score”.

Parameters:
  • life_model (str) – The character(s) that should be used to represent the remaining life.
  • void_model (str) – The character(s) that should be used to represent the lost life.

Note

This method might change in the future. Particularly it could take a template of what to display.

get_board(level_number)

This method returns the board associated with a level number. :param level_number: The number of the level. :type level_number: int

Raises:HacInvalidTypeException – if the level_number is not an int.

Example:

level1_board = mygame.get_board(1)
get_menu_entry(category, shortcut)

Get an entry of the menu.

This method return a dictionnary with 3 entries :
  • shortcut
  • message
  • data
Parameters:
  • category (str) – The category in which the entry is located.
  • shortcut (str) – The shortcut of the entry you want to get.
Returns:

The menu entry or None if none was found

Return type:

dict

Example:

ent = game.get_menu_entry('main_menu','d')
game.move_player(int(ent['data']),1)
load_board(filename, lvl_number=0)

Load a saved board

Load a Board saved on the disk as a JSON file. This method creates a new Board object, populate it with all the elements (except a Player) and then return it.

If the filename argument is not an existing file, the open function is going to raise an exception.

This method, load the board from the JSON file, populate it with all BoardItem included, check for sanity, init the board with BoardItemVoid and then associate the freshly created board to a lvl_number. It then create the NPCs and add them to the board.

Parameters:
  • filename (str) – The file to load
  • lvl_number (int) – The level number to associate the board to. Default is 0.
Returns:

a newly created board (see gamelib.Board.Board)

Example:

mynewboard = game.load_board( 'awesome_level.json', 1 )
game.change_level( 1 )
load_config(filename, section='main')

Load a configuration file from the disk. The configuration file must respect the INI syntax. The goal of these methods is to simplify configuration files management.

Parameters:
  • filename (str) – The filename to load. does not check for existence.
  • section (str) – The section to put the read config file into. This allow for multiple files for multiple purpose. Section is a human readable unique identifier.
Raises:
  • FileNotFoundError – If filename is not found on the disk.
  • json.decoder.JSONDecodeError – If filename could not be decoded as JSON.
Returns:

The parsed data.

Return type:

dict

Warning

breaking changes: before v1.1.0 that method use to load file using the configparser module. This have been dumped in favor of json files. Since that methods was apparently not used, there is no backward compatibility.

Example:

mygame.load_config('game_controls.json','game_control')
move_player(direction, step)

Easy wrapper for Board.move().

Example:

mygame.move_player(Constants.RIGHT,1)
neighbors(radius=1, object=None)

Get a list of neighbors (non void item) around an object.

This method returns a list of objects that are all around an object between the position of an object and all the cells at radius.

Parameters:
  • radius (int) – The radius in which non void item should be included
  • object (gamelib.BoardItem.BoardItem) – The central object. The neighbors are calculated for that object. If None, the player is the object.
Returns:

A list of BoardItem. No BoardItemVoid is included.

Raises:

HacInvalidTypeException – If radius is not an int.

Example:

for item in game.neighbors(2):
    print(f'{item.name} is around player at coordinates '
        '({item.pos[0]},{item.pos[1]})')
pause()

Set the game engine state to PAUSE.

Example:

mygame.pause()
remove_npc(level_number, npc)

This methods remove the NPC from the level in parameter.

Parameters:
  • level (int) – The number of the level from where the NPC is to be removed.
  • npc (NPC) – The NPC object to remove.

Example:

mygame.remove_npc(1, dead_npc)
save_board(lvl_number, filename)

Save a board to a JSON file

This method saves a Board and everything in it but the BoardItemVoid.

Not check are done on the filename, if anything happen you get the exceptions from open().

Parameters:
  • lvl_number (int) – The level number to get the board from.
  • filename (str) – The path to the file to save the data to.
Raises:

Example:

game.save_board( 1, 'hac-maps/level1.json')

If Game.object_library is not an empty array, it will be saved also.

save_config(section=None, filename=None, append=False)

Save a configuration section.

Parameters:
  • section (str) – The name of the section to save on disk.
  • filename (str) – The file to write in. If not provided it will write in the file that was used to load the given section. If section was not loaded from a file, save will raise an exception.
  • append (bool) – Do we need to append to the file or replace the content (True = append, False = replace)

Example:

mygame.save_config('game_controls', 'data/game_controls.json')
start()

Set the game engine state to RUNNING.

The game has to be RUNNING for actuate_npcs() and move_player() to do anything.

Example:

mygame.start()
stop()

Set the game engine state to STOPPED.

Example:

mygame.stop()
update_menu_entry(category, shortcut, message, data=None)

Update an entry of the menu.

Update the message associated to a category and a shortcut.

Parameters:
  • category (str) – The category in which the entry is located.
  • shortcut (str) – The shortcut of the entry you want to update.
  • message (various) – a message that explains what the shortcut does.
  • data – a data that you can get from the menu object.

Important

If the entry have no shortcut it’s advised not to try to update unless you have only one NoneType as a shortcut.

Example:

game.add_menu_entry('main_menu','d','Go right')
game.update_menu_entry('main_menu','d','Go LEFT',Constants.LEFT)