diff --git a/Manual_ctf.pdf b/Manual_ctf.pdf
new file mode 100644
index 0000000000000000000000000000000000000000..601854daa42e1fae7ed66c5202999b5a1ff72103
Binary files /dev/null and b/Manual_ctf.pdf differ
diff --git a/__pycache__/ai.cpython-37.pyc b/__pycache__/ai.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..a823f57355cee0728e07418968676be6cb0ece67
Binary files /dev/null and b/__pycache__/ai.cpython-37.pyc differ
diff --git a/__pycache__/ctf.cpython-37.pyc b/__pycache__/ctf.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..dd7f19c7622934d1bd77fc232bf63a93e64be4d7
Binary files /dev/null and b/__pycache__/ctf.cpython-37.pyc differ
diff --git a/__pycache__/gameobjects.cpython-37.pyc b/__pycache__/gameobjects.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..39bcf4ea4230be5a4eeaa3ea4f609743c36555ed
Binary files /dev/null and b/__pycache__/gameobjects.cpython-37.pyc differ
diff --git a/__pycache__/images.cpython-311.pyc b/__pycache__/images.cpython-311.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..9e08ecc31bc01976803c0092099ad68a44d101c2
Binary files /dev/null and b/__pycache__/images.cpython-311.pyc differ
diff --git a/__pycache__/images.cpython-37.pyc b/__pycache__/images.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..df14fe77d23d6471915b508213fae4960fe2b034
Binary files /dev/null and b/__pycache__/images.cpython-37.pyc differ
diff --git a/__pycache__/init_objects.cpython-37.pyc b/__pycache__/init_objects.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..1be0cdcb96130a4b12cf0cc7146abfa4ff48ab7d
Binary files /dev/null and b/__pycache__/init_objects.cpython-37.pyc differ
diff --git a/__pycache__/maps.cpython-37.pyc b/__pycache__/maps.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..9af117ad23c19a21a9617d71234f66f8fa7956d1
Binary files /dev/null and b/__pycache__/maps.cpython-37.pyc differ
diff --git a/__pycache__/menu.cpython-37.pyc b/__pycache__/menu.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..4044cccd6315b27f771cbb34aafd1d788ff5d798
Binary files /dev/null and b/__pycache__/menu.cpython-37.pyc differ
diff --git a/__pycache__/print_functions.cpython-37.pyc b/__pycache__/print_functions.cpython-37.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..b131ce0efdfbde62d86ef2276d81c9390d3853ef
Binary files /dev/null and b/__pycache__/print_functions.cpython-37.pyc differ
diff --git a/ai.py b/ai.py
new file mode 100644
index 0000000000000000000000000000000000000000..3d80ac36eb0f154d1ea76f37db1200ebe12af150
--- /dev/null
+++ b/ai.py
@@ -0,0 +1,236 @@
+import math
+import pymunk
+from pymunk import Vec2d
+import gameobjects
+from collections import defaultdict, deque
+import images
+import pygame
+
+# NOTE: use only 'map0' during development!
+
+MIN_ANGLE_DIF = math.radians(6) # input degrees
+
+def angle_between_vectors(vec1, vec2):
+    """ Since Vec2d operates in a cartesian coordinate space we have to
+        convert the resulting vector to get the correct angle for our space.
+    """
+    vec = vec1 - vec2
+    vec = vec.perpendicular()
+    return vec.angle
+
+def periodic_difference_of_angles(angle1, angle2):
+    """ Return the periodic difference between two angles. """
+    
+    return (angle1 - angle2)%(2*math.pi)
+
+class Ai:
+    """ A simple ai that finds the shortest path to the target using
+    a breadth first search. Also capable of shooting other tanks and or wooden
+    boxes. """
+
+    def __init__(self, tank,game_objects_list, tanks_list,space,currentmap):
+        """ Ai constructor """
+        self.tank               = tank
+        self.game_objects_list  = game_objects_list
+        self.tanks_list         = tanks_list
+        self.space              = space
+        self.currentmap         = currentmap
+        self.flag = None
+        self.MAX_X = currentmap.width - 1
+        self.MAX_Y = currentmap.height - 1
+
+        self.metal_path = False
+        self.path = deque()
+        self.move_cycle = self.move_cycle_gen()
+        self.update_grid_pos()
+        self.last_shot = pygame.time.get_ticks()
+
+    def ray_cast(self):
+        """Function for detecting ray cast for ai shoot function"""
+
+        angle = self.tank.body.angle + math.pi/2 # adapt to cartesian angles
+        x_bullet = self.tank.body.position[0]+0.5*math.cos(angle)
+        y_bullet = self.tank.body.position[1]+0.5*math.sin(angle)
+        ray_beg = (x_bullet, y_bullet) # same as bullet start
+        ray_max1 = x_bullet + 100 * math.cos(angle)
+        ray_max2 = y_bullet + 100 * math.sin(angle)
+        ray_max = (ray_max1, ray_max2) # projectile line for bullet
+        return self.space.segment_query_first(ray_beg, ray_max, 0, \
+                                              pymunk.ShapeFilter())
+
+    def update_grid_pos(self):
+        """ This should only be called in the beginning,
+            or at the end of a move_cycle. """
+        
+        self.grid_pos = self.get_tile_of_position(self.tank.body.position)
+
+    def maybe_shoot(self):
+        """ Makes a raycast query in front of the tank. If another tank
+            or a wooden box is found, then we shoot. """
+        
+        res = self.ray_cast()
+        if hasattr(res, "shape"):
+            # check for the collision types
+            if isinstance(res.shape.collision_type, int): 
+                col_type = res.shape.collision_type
+                if col_type == 1 or (col_type == 3 and \
+                    res.shape.parent.destructable) or col_type == 2:
+                    ai_bullet = self.tank.shoot()
+                    if ai_bullet != None:
+                        ##unfair Ai (times 1.3)
+                        ai_bullet.body.velocity = ai_bullet.body.velocity*1.3 
+                        self.game_objects_list.append(ai_bullet)
+
+
+    def decide(self):
+        """ Main decision function that gets called on every tick of the game.
+        """
+        self.maybe_shoot()
+        next(self.move_cycle)    
+    
+    
+    def find_shortest_path(self):
+        """ A simple Breadth First Search using integer coordinates as our
+            nodes. Edges are calculated as we go, using an external
+            function. """
+        
+        source_node = self.grid_pos.int_tuple
+        queue = deque() # neighbors (new nodes)
+        visited = set()
+        shortest_path = []
+        queue.append((source_node, shortest_path))
+        
+        while queue: # all tiles in worst case...
+            queue = self.astar_heu(queue) # rearrange according to heu!
+            curr_tile, curr_shortest = queue.popleft()
+            if self.get_target_tile() == curr_tile:
+                curr_shortest.append(curr_tile)
+                shortest_path = curr_shortest
+                return deque(shortest_path[1:])
+            neighbours = self.get_tile_neighbors(curr_tile)
+            for neighbor in neighbours:
+                neighbor = neighbor.int_tuple
+                if neighbor not in visited:
+                    queue.append((neighbor,curr_shortest + [curr_tile])) 
+                    visited.add(neighbor)
+
+
+    def astar_heu(self, input_queue):
+        """ Heurstic function for calculating a path the
+            flag using the shortest distance. """
+        queue = deque(input_queue)
+        astar_queue = deque()
+        curr_min_dist = 1+Vec2d(self.tank.body.position\
+                                ).get_distance(self.get_target_tile())
+        while queue:
+            curr_path =queue.popleft()
+            temp_dist =Vec2d(curr_path[0]).get_distance(self.get_target_tile())
+            if temp_dist < curr_min_dist:
+                astar_queue.appendleft(curr_path)
+                curr_min_dist = temp_dist
+            else:
+                astar_queue.append(curr_path)
+        return astar_queue
+
+    def move_cycle_gen(self):
+        """ A generator that iteratively goes through all the required steps
+            to move to our goal. """
+        while True:
+            path = self.find_shortest_path()
+            if path == None:
+                self.metal_path = True
+                yield
+                continue 
+            if len(path) == 0:
+                yield
+                continue 
+            next_coord = path.popleft()+Vec2d(0.5, 0.5)
+            yield
+
+           # turn()
+            angle_diff = angle_between_vectors(self.tank.body.position,\
+                                               next_coord)
+            angle_next = periodic_difference_of_angles(\
+                                self.tank.body.angle,angle_diff)
+            self.tank.stop_moving()
+            self.tank.body.angle = self.tank.body.angle % (2*math.pi)
+            # Must check when tank is tilted downwords!
+            if (angle_next < -math.pi) or (math.pi > angle_next > 0): 
+                self.tank.turn_left()
+            else:
+                self.tank.turn_right()
+                
+            # correct_angle()
+            while abs(angle_next) > MIN_ANGLE_DIF:
+                angle_next = periodic_difference_of_angles(\
+                                        self.tank.body.angle,angle_diff)
+                yield
+            self.tank.stop_turning()
+            self.tank.accelerate()
+            yield
+
+            # correct_pos()
+            current_dist = self.tank.body.position.get_distance(next_coord)
+            temp_next_dist = current_dist
+            while (current_dist >= temp_next_dist):
+                self.update_grid_pos()
+                # set new next tile when we reach the target!
+                temp_next_dist = current_dist + 1 
+                yield
+            move_cycle = self.move_cycle_gen()
+
+    def get_target_tile(self):
+        """ Returns position of the flag if we don't have it. If we do
+            have the flag, return the position of our home base. """
+        if self.tank.flag is not None:
+            x, y = self.tank.start_position
+        else:
+            self.get_flag() # Ensure that we have initialized it.
+            x, y = self.flag.x, self.flag.y
+        return Vec2d(int(x), int(y))
+
+    def get_flag(self):
+        """ This has to be called to get the flag, since we don't know
+            where it is when the Ai object is initialized. """
+        if self.flag is None:
+        # Find the flag in the game objects list
+            for obj in self.game_objects_list:
+                if isinstance(obj, gameobjects.Flag):
+                    self.flag = obj
+                    break
+        return self.flag
+
+    def get_tile_of_position(self, position_vector):
+        """ Converts and returns the float position of our tank to
+            an integer position."""
+        
+        x, y = position_vector
+        return Vec2d(int(x), int(y))
+
+    def get_tile_neighbors(self, coord_vec):
+        """ Returns all bordering grid squares of the input coordinate.
+            A bordering square is only considered accessible if it is grass
+            or a wooden box. """
+        
+        curr_tile = self.get_tile_of_position(coord_vec)
+        tile1 = Vec2d(curr_tile[0]+1, curr_tile[1])
+        tile2 = Vec2d(curr_tile[0]-1, curr_tile[1])
+        tile3 = Vec2d(curr_tile[0], curr_tile[1]+1)
+        tile4 = Vec2d(curr_tile[0], curr_tile[1]-1)
+        neighbors = [tile1, tile2, tile3, tile4]        
+        return filter(self.filter_tile_neighbors, neighbors)
+      
+
+    def filter_tile_neighbors (self, coord):
+        """ Checks wether a tank can move to the specific tile type"""
+        
+        x = coord[0]
+        y = coord[1]
+        if (x >= 0 and x <= self.MAX_X) and (y >= 0 and y <= self.MAX_Y):
+            box = self.currentmap.boxAt(x,y)
+            if box == 0 or box == 2 or self.metal_path == True and box == 3:
+                return True
+        return False
+
+
+
diff --git a/classes.py b/classes.py
new file mode 100644
index 0000000000000000000000000000000000000000..da5db561f644fe0d6216bd1fdedffbd7ca161890
--- /dev/null
+++ b/classes.py
@@ -0,0 +1,34 @@
+class VideoGame:
+    def __init__(self, title, price, developer, platform):
+        self.title = title 
+        self.price = price
+        self.developer = developer
+        self.platform = platform
+
+    def print_description(self):
+        print()
+        print(f'{self.title} - Now only ${self.price}!!')
+        print(f'Developed by {self.developer} for {self.platform}')
+
+
+
+class PC_Game(VideoGame):
+    def __init__(self, title, price, developer, platform, requirements):
+        super().__init__(title, price, developer, platform)
+        self.requirements = requirements 
+        
+    def print_description(self):
+        super().print_description()
+        print(f'Written by the renowned author {self.requirements}')
+        
+
+
+
+
+videogames = [
+    PC_Game('Crysis 3', 500, 'Crytek', 'PC','Intel HD Graphics 4000 is not the right option')
+    ]
+  
+
+#for videogame in videogames:
+ #   videogame.print_description()
diff --git a/ctf.py b/ctf.py
new file mode 100644
index 0000000000000000000000000000000000000000..9494dee6d42dee26cd7dfe47e31d2e7c30788e07
--- /dev/null
+++ b/ctf.py
@@ -0,0 +1,335 @@
+import pygame
+import sys
+import time
+from pygame.locals import *
+from pygame.color import *
+import pymunk
+pygame.init()
+pygame.display.set_mode()
+#-- Initialise the clock
+clock = pygame.time.Clock()
+#-- Initialise the physics engine
+space = pymunk.Space()
+space.gravity = (0.0,  0.0)
+space.damping = 0.1# Adds friction to the ground for all objects
+#-- Import from the ctf framework
+import ai
+import images
+import gameobjects
+import maps
+import menu
+import print_functions
+import init_objects
+
+
+#######  Collision functions #################
+        
+def collision_bullet_wall(arb, space, data):
+     """Handle the collision between bullet and wall."""
+     
+     bullet = arb.shapes[0].parent
+     game_objects_list.remove(bullet)
+     space.remove(arb.shapes[0], arb.shapes[0].body)
+     return False
+
+def collision_bullet_box(arb, space, data):
+    """Handle the collision between bullet and box."""
+    
+    bullet = arb.shapes[0].parent
+    space.remove(arb.shapes[0], arb.shapes[0].body)
+    if bullet in game_objects_list:
+        game_objects_list.remove(bullet)
+    box = arb.shapes[1].parent
+    if box.destructable:
+        if box.hitpoints > 1:
+            box.hitpoints = box.hitpoints-1
+        else:
+            if box in game_objects_list:
+                game_objects_list.remove(box)
+            space.remove(arb.shapes[1], arb.shapes[1])
+    return False
+
+def collision_bullet_tank(arb, space, data):
+    """Handle the collision between bullet and tank."""
+    
+    bullet = arb.shapes[0].parent
+    tank = arb.shapes[1].parent
+    if bullet in game_objects_list:
+        game_objects_list.remove(bullet)
+    space.remove(arb.shapes[0], arb.shapes[0].body)
+    flag.is_on_tank = False
+    tank.on_death()
+    return False
+
+            
+def collision_bullet_bullet(arb, space, data):
+    """Handle the collision between bullet and bullet."""
+    
+    bullet1= arb.shapes[1].parent
+    bullet2 = arb.shapes[0].parent
+    if bullet1 in game_objects_list:
+        game_objects_list.remove(bullet1)
+    space.remove(arb.shapes[0], arb.shapes[0].body)
+    if bullet2 in game_objects_list:
+        game_objects_list.remove(bullet2)
+    space.remove(arb.shapes[1], arb.shapes[1].body)
+    return False
+
+def create_collision_handlers():
+    """Creates the handling of collisions
+       between different objects."""
+    
+    handler = space.add_collision_handler(1, 3)
+    handler.pre_solve = collision_bullet_box
+    handler = space.add_collision_handler(1, 10)
+    handler.pre_solve = collision_bullet_wall
+    handler = space.add_collision_handler(1, 2)
+    handler.pre_solve = collision_bullet_tank
+    handler = space.add_collision_handler(1, 1)
+    handler.pre_solve = collision_bullet_bullet
+
+def create_objects():
+    """Creates objects in the game."""
+    
+    init_objects.create_borders(space,current_map)
+    init_objects.create_background(current_map,background)
+    init_objects.create_boxes(game_objects_list, current_map, space)
+    init_objects.create_tanks(tanks_list,game_objects_list , \
+                              current_map, space, multi, ai_list)
+    init_objects.create_bases(game_objects_list , current_map)
+
+
+############## Main loop ######################
+def shoot_bullet(i):
+    """Shoots a bullet from the tank
+       and adds it to the game objects list."""
+    
+    bullet = tanks_list[i].shoot()
+    if bullet != None:
+        game_objects_list.append(bullet)
+        
+
+def keyhandler():
+    """Handles key events for the game."""
+    
+    dic_keydown = {
+            K_UP: tanks_list[0].accelerate,
+            K_DOWN: tanks_list[0].decelerate,
+            K_RIGHT: tanks_list[0].turn_right,
+            K_LEFT: tanks_list[0].turn_left,
+            K_ESCAPE: pygame.quit}
+
+    dic_keyup = {
+                 K_UP: tanks_list[0].stop_moving,
+                 K_DOWN: tanks_list[0].stop_moving,
+                 K_LEFT: tanks_list[0].stop_turning,
+                 K_RIGHT: tanks_list[0].stop_turning }
+    if multi:
+        dic_keydown_multi = {
+            K_w: tanks_list[1].accelerate,
+            K_s: tanks_list[1].decelerate,
+            K_d: tanks_list[1].turn_right,
+            K_a: tanks_list[1].turn_left}
+
+        dic_keyup_multi = {
+
+                 K_w: tanks_list[1].stop_moving,
+                 K_s: tanks_list[1].stop_moving,
+                 K_d: tanks_list[1].stop_turning,
+                 K_a: tanks_list[1].stop_turning}
+        
+        dic_keydown.update(dic_keydown_multi)
+        dic_keyup.update(dic_keyup_multi)
+    return dic_keydown, dic_keyup 
+    
+    
+def tank_win(tank, max_round, max_time):
+    """Handles the scenario when a tank wins the game."""
+    
+    player = 1
+    flag.x, flag.y = flag_start
+    flag.is_on_tank = False
+    tank.flag = None
+    tank.points = tank.points +1
+    for i in tanks_list:
+        i.stop_moving() # make sure no speed when respawn
+        i.body.position = i.start_position
+        print("Player",player,":",i.points)
+        player = player+1
+    print_functions.print_score_result(screen,tanks_list)
+    print("============")
+    
+    if tank.points == 2 or max_round == 10  or max_time>1800*5: # 1800 == 1 min
+        return False
+    return True
+
+
+def fog_of_war():
+    """Implements the fog of war effect for the game."""
+    
+    tank_pixle_pos = 40
+    tile_pixle_size = 100
+    fog_pixle_radius = 90
+    color_black = (255,255,255)
+    color_white = (0,0,0)
+    
+    map_pixle_size = ((current_map.width+1)*tile_pixle_size,\
+                      (current_map.height+1)*tile_pixle_size)
+    x = tanks_list[0].body.position[0]*tank_pixle_pos
+    y = tanks_list[0].body.position[1]*tank_pixle_pos
+    surface1 = pygame.Surface(map_pixle_size)
+    pygame.draw.circle(surface1, color_black, (x,y), \
+                       fog_pixle_radius,pygame.SRCALPHA)
+
+    # add the extra fog vision in case of multiplayer 
+    if multi:
+        x_multi = tanks_list[1].body.position[0]*tank_pixle_pos
+        y_multi = tanks_list[1].body.position[1]*tank_pixle_pos
+        pygame.draw.circle(surface1, color_black,(x_multi,y_multi),
+                           fog_pixle_radius,pygame.SRCALPHA)
+        
+    pygame.draw.rect(surface1, color_white,(map_pixle_size[0], \
+                                            map_pixle_size[1],0,0))
+    surface1.set_colorkey(color_black)  
+    screen.blit(surface1, (0,0))
+    
+def main_loop():
+    """The main loop of the game where events are handled,
+       game objects are updated and displayed on the screen."""
+    
+    
+    # init key inputs!
+    dic_keydown, dic_keyup = keyhandler()
+    
+    running = True
+    skip_update = 0
+
+    # Create the tank, images.tanks contains the image representing the tank
+    count_rounds = 1
+    count_time = 0
+    
+    while running:
+        count_time = count_time +1
+
+        for event in pygame.event.get():
+            if event.type == KEYDOWN:
+                if event.key in dic_keydown:
+                    dic_keydown[event.key]()
+                elif event.key == K_RETURN:
+                    shoot_bullet(0)
+                elif event.key == K_SPACE:
+                    shoot_bullet(1)
+            
+            elif event.type == KEYUP:
+                if event.key in dic_keyup:
+                    dic_keyup[event.key]()
+            
+#-- Update physics
+
+        if skip_update == 0:
+
+            for obj in game_objects_list:
+                obj.update()
+            skip_update = 2
+        else:
+            skip_update -= 1
+            
+        space.step(1 / FRAMERATE)
+
+    #<INSERT DISPLAY BACKGROUND>
+
+# Display the background on the screen
+        screen.blit(background, (0, 0))
+
+    #<INSERT DISPLAY OBJECTS>
+        
+    # Update the display of the game objects on the screen
+        for i in tanks_list:
+            if i.has_won():
+                count_rounds = count_rounds +1
+                running = tank_win(i,count_rounds, count_time)
+            i.post_update(flag)
+            
+                
+        for i in ai_list:
+            i.decide()
+            
+        for obj in game_objects_list:
+            obj.update_screen(screen)
+            obj.update()
+
+        if FOG:
+            fog_of_war()
+            
+        if game_mode == 1:
+            print_functions.print_stats_score(screen,\
+                                              tanks_list, current_map)
+            
+        elif game_mode == 2:
+            print_functions.print_stats_time(screen, \
+                                             count_time, current_map)
+            
+        elif game_mode == 3:
+            print_functions.print_stats_round(screen,\
+                                              count_rounds , current_map)
+      
+    #   Redisplay the entire screen (see double buffer technique)  
+        pygame.display.flip()
+
+    #   Control the game framerate
+        clock.tick(FRAMERATE)
+
+    #   Redisplay the entire screen (see double buffer technique)
+        pygame.display.flip()
+
+    #   Control the game framerate
+        clock.tick(FRAMERATE)
+
+# main
+try:
+    if str(sys.argv[1]) == "--singleplayer":
+        multi = False
+    if str(sys.argv[1]) == "--hot-multiplayer":
+        multi = True
+        FOG = False
+        current_map = maps.map0
+        game_mode = 1
+
+except IndexError:
+    main_tuple = menu.main_menu()
+    multi = main_tuple[0]
+    current_map = main_tuple[1]
+    FOG = main_tuple[2]
+    game_mode = main_tuple[3]
+
+#----- Initialisation -----#
+
+#-- Initialise the display
+
+#-- Constants
+FRAMERATE = 100
+
+#-- Variables
+
+#   Define the current level
+
+flag_start  = current_map.flag_position[0], current_map.flag_position[1]
+#   List of all game objects
+
+game_objects_list   = []
+tanks_list          = []
+ai_list             = []
+
+#-- Resize the screen to the size of the current level
+screen = pygame.display.set_mode((current_map.rect().size[0]+100,\
+                                  current_map.rect().size[1]))
+
+#<INSERT GENERATE BACKGROUND>
+
+#-- Generate the background
+background = pygame.Surface(screen.get_size())
+
+flag = init_objects.create_flag(game_objects_list,flag_start)
+create_objects()
+create_collision_handlers()
+main_loop()
diff --git a/data/base.kra b/data/base.kra
new file mode 100644
index 0000000000000000000000000000000000000000..805a569aa3d6b4d8f2f0b33b2887f6af4bf182c7
Binary files /dev/null and b/data/base.kra differ
diff --git a/data/base_blue.png b/data/base_blue.png
new file mode 100644
index 0000000000000000000000000000000000000000..b4acc006aad20c3d3275d754b6af87e15f0ae7e7
Binary files /dev/null and b/data/base_blue.png differ
diff --git a/data/base_gray.png b/data/base_gray.png
new file mode 100644
index 0000000000000000000000000000000000000000..daaaae97663e9bcfbf35fdaaa98b68492028f000
Binary files /dev/null and b/data/base_gray.png differ
diff --git a/data/base_orange.png b/data/base_orange.png
new file mode 100644
index 0000000000000000000000000000000000000000..d6e697c1986ff3d00165431db37c60314588567b
Binary files /dev/null and b/data/base_orange.png differ
diff --git a/data/base_red.png b/data/base_red.png
new file mode 100644
index 0000000000000000000000000000000000000000..bae530ca3ed2ca726164a20a9ae786ce380e85b1
Binary files /dev/null and b/data/base_red.png differ
diff --git a/data/base_white.png b/data/base_white.png
new file mode 100644
index 0000000000000000000000000000000000000000..9b196090ebd51adf85a633eaf2351f22d6f608e2
Binary files /dev/null and b/data/base_white.png differ
diff --git a/data/base_yellow.png b/data/base_yellow.png
new file mode 100644
index 0000000000000000000000000000000000000000..8d2fc0fb6144684083b2d2e7a3215a706cba96dc
Binary files /dev/null and b/data/base_yellow.png differ
diff --git a/data/bullet.png b/data/bullet.png
new file mode 100644
index 0000000000000000000000000000000000000000..77e8445e48e708a51e73d9ab8625b68f5547af80
Binary files /dev/null and b/data/bullet.png differ
diff --git a/data/explosion.kra b/data/explosion.kra
new file mode 100644
index 0000000000000000000000000000000000000000..1be3221f6dab027f4df3b28836e09c5fdde63039
Binary files /dev/null and b/data/explosion.kra differ
diff --git a/data/explosion.png b/data/explosion.png
new file mode 100644
index 0000000000000000000000000000000000000000..dbfc20f8d84e577a2d0fa2e9ffa8ddd50201abe7
Binary files /dev/null and b/data/explosion.png differ
diff --git a/data/flag.png b/data/flag.png
new file mode 100644
index 0000000000000000000000000000000000000000..60d5708bbe5abf8564e459d397458e9bca15ff8a
Binary files /dev/null and b/data/flag.png differ
diff --git a/data/grass.png b/data/grass.png
new file mode 100644
index 0000000000000000000000000000000000000000..d9f37de36d7cfed9d5a1bf4021ac3d839c50a5a9
Binary files /dev/null and b/data/grass.png differ
diff --git a/data/metalbox.png b/data/metalbox.png
new file mode 100644
index 0000000000000000000000000000000000000000..1e4edec084ca62e5ecdd34fa7051cd76a03d89ba
Binary files /dev/null and b/data/metalbox.png differ
diff --git a/data/rockbox.png b/data/rockbox.png
new file mode 100644
index 0000000000000000000000000000000000000000..b53b509abcc65762f888a3bf0aff92032de6f4a1
Binary files /dev/null and b/data/rockbox.png differ
diff --git a/data/tank.kra b/data/tank.kra
new file mode 100644
index 0000000000000000000000000000000000000000..ede20213172114be2307b62e86e7b7c0ec48ff3a
Binary files /dev/null and b/data/tank.kra differ
diff --git a/data/tank_blue.png b/data/tank_blue.png
new file mode 100644
index 0000000000000000000000000000000000000000..9235417dee08f19e67fbc97bf0f03506ec64bf39
Binary files /dev/null and b/data/tank_blue.png differ
diff --git a/data/tank_gray.png b/data/tank_gray.png
new file mode 100644
index 0000000000000000000000000000000000000000..4084b15c926ae93d5d23a5d77f37025e478924be
Binary files /dev/null and b/data/tank_gray.png differ
diff --git a/data/tank_orange.png b/data/tank_orange.png
new file mode 100644
index 0000000000000000000000000000000000000000..84f940ba2c93504982ccf24c3fcb857e7839c122
Binary files /dev/null and b/data/tank_orange.png differ
diff --git a/data/tank_red.png b/data/tank_red.png
new file mode 100644
index 0000000000000000000000000000000000000000..7c8a5c1691621823b768ac638971fe2664782dc6
Binary files /dev/null and b/data/tank_red.png differ
diff --git a/data/tank_white.png b/data/tank_white.png
new file mode 100644
index 0000000000000000000000000000000000000000..a8e5367925987cce09edaff60a30288ad9bdb0d1
Binary files /dev/null and b/data/tank_white.png differ
diff --git a/data/tank_yellow.png b/data/tank_yellow.png
new file mode 100644
index 0000000000000000000000000000000000000000..a5ba8c999b53d0f48dd4953731fafd07f6df8a7b
Binary files /dev/null and b/data/tank_yellow.png differ
diff --git a/data/woodbox.png b/data/woodbox.png
new file mode 100644
index 0000000000000000000000000000000000000000..15ee620943723cb134446c937c510dd2ab316fb8
Binary files /dev/null and b/data/woodbox.png differ
diff --git a/gameobjects.py b/gameobjects.py
new file mode 100644
index 0000000000000000000000000000000000000000..fbc4127cef470a5ba5192cfbbba8866f9c2c84a7
--- /dev/null
+++ b/gameobjects.py
@@ -0,0 +1,345 @@
+import images
+import pygame
+import pymunk
+import math
+
+DEBUG = False # Change this to set it in debug mode
+
+
+def physics_to_display(x):
+    """ This function is used to convert coordinates
+        in the physic engine into the display coordinates """
+    
+    return x * images.TILE_SIZE
+
+
+class GameObject:
+    """ Mostly handles visual aspects (pygame) of an object.
+        Subclasses need to implement two functions:
+        -screen_position that will return the position of the object
+        -screen_orientation that will return how much the object
+         is rotated on the screen (in degrees). """
+
+    def __init__(self, sprite):
+        """ Game object constructor """
+        self.sprite         = sprite
+
+
+    def update(self):
+        """ Placeholder, supposed to be implemented in a subclass.
+            Should update the current state (after a tick) of the object."""
+        return
+
+    def post_update(self):
+        """ Should be implemented in a subclass. Make updates that depend on
+            other objects than itself."""
+        return
+
+
+    def update_screen(self, screen):
+        """ Updates the visual part of the game. Should NOT need to be changed
+            by a subclass."""
+        sprite = self.sprite
+        
+        # Get the position of the object (pygame coordinates)
+        p = self.screen_position()
+        
+        # Rotate the sprite using the rotation of the object
+        sprite = pygame.transform.rotate(sprite, self.screen_orientation()) 
+
+        # The position of the screen correspond to the center of the object,
+        # but the function screen.blit expect to receive the top left corner
+        # as argument, so we need to adjust the position p with an offset
+        # which is the vector between the center of the sprite and the top left
+        # corner of the sprite
+        offset = pymunk.Vec2d(sprite.get_size()) / 2.
+        p = p - offset
+        screen.blit(sprite, p) # Copy the sprite on the screen
+
+
+class GamePhysicsObject(GameObject):
+    """ This class extends GameObject and it is used for objects which have a
+        physical shape(such as tanks and boxes). This class handle the physical
+        interaction of the objects.
+    """
+
+    def __init__(self, x, y, orientation, sprite, space, movable):
+        """ Takes as parameters the starting coordinate (x,y), the orientation,
+            the sprite (aka the image representing the object), the physic
+            engine object(space) and whether the object can be moved (movable).
+        """
+        super().__init__(sprite)
+        # Half dimensions of the object converted
+        # from screen coordinates to physic coordinates.
+        half_width          = 0.5 * self.sprite.get_width() / images.TILE_SIZE
+        half_height         = 0.5 * self.sprite.get_height() / images.TILE_SIZE
+
+        # Physical objects have a rectangular shape, the points
+        # correspond to the corners of that shape.
+        points              = [[-half_width, -half_height],
+                            [-half_width, half_height],
+                            [half_width, half_height],
+                            [half_width, -half_height]]
+        self.points = points
+        
+        # Create a body (which is the physical representation
+        # of this game object in the physic engine)
+        if(movable):
+            # Create a movable object with some mass and moments
+            # (considering the game is a top view game, with no gravity,
+            # the mass is set to the same value for all objects)."""
+            mass = 10
+            moment = pymunk.moment_for_poly(mass, points)
+            self.body         = pymunk.Body(mass, moment)
+        else:
+            # Create a non movable (static) object
+            self.body         = pymunk.Body(body_type=pymunk.Body.STATIC) 
+        
+        self.body.position  = x, y
+        # orientation is provided in degress, but pymunk expects radians.
+        self.body.angle     = math.radians(orientation)
+        # Create a polygon shape using the corner of the rectangle
+        self.shape          = pymunk.Poly(self.body, points)  
+        self.shape.parent = self
+
+        # Add the object to the physic engine
+        if(movable):
+            space.add(self.body, self.shape)
+        else:
+            space.add(self.shape)
+
+
+    def screen_position(self):
+        """ Converts the body's position in the physics engine to
+            screen coordinates. """
+        return physics_to_display(self.body.position)
+
+    def screen_orientation(self):
+        """ Angles are reversed from the engine to the display. """
+        return -math.degrees(self.body.angle)
+
+    def update_screen(self, screen):
+        """ Function for repaint the screen in its current state."""
+        super().update_screen(screen)
+        # debug draw
+        if DEBUG:
+            ps = [self.body.position+p for p in self.points]
+
+            ps = [physics_to_display(p) for p in ps]
+            ps += [ps[0]]
+            pygame.draw.lines(screen,pygame.color.THECOLORS["red"],False, ps,1)
+
+
+
+
+def clamp(min_max, value):
+    """ Convenient helper function to bound a value to a specific interval. """
+    return min(max(-min_max, value), min_max)
+
+
+class Tank(GamePhysicsObject):
+    """ Extends GamePhysicsObject and handles aspects which are specific
+        to our tanks. """
+
+    ACCELERATION = 0.8
+    NORMAL_MAX_SPEED = 4.0
+    FLAG_MAX_SPEED = NORMAL_MAX_SPEED * 0.5
+
+    def __init__(self, x, y, orientation, sprite, space):
+        """ Tank constructor """
+        super().__init__(x, y, orientation, sprite, space, True)
+        # Define variable used to apply motion to the tanks
+        self.shape.collision_type = 2
+        self.acceleration = 0 # 1 forward, 0 for stand still, -1 for backwards
+        self.rotation = 0 # 1 clockwise, 0 for no rotation, -1 counter clockwise
+        self.timer = 0
+        self.spawn_cooldown = 0
+        self.cooldown = 0
+        self.points = 0
+        self.hitpoints = 2
+        self.space = space
+        self.flag                 = None                      
+        self.max_speed        = Tank.NORMAL_MAX_SPEED  
+        self.start_position       = pymunk.Vec2d(x, y)
+
+
+    def accelerate(self):
+        """ Call this function to make the tank move forward. """
+        self.acceleration = 1
+
+    def stop_moving(self):
+        """ Call this function to make the tank stop moving. """
+        self.acceleration  = 0
+        self.body.velocity = pymunk.Vec2d.zero()
+
+    def decelerate(self):
+        """ Call this function to make the tank move backward. """
+        self.acceleration = -1
+
+    def turn_left(self):
+        """ Makes the tank turn left (counter clock-wise). """
+        self.rotation = -1
+
+    def turn_right(self):
+        """ Makes the tank turn right (clock-wise). """
+        self.rotation = 1
+
+    def stop_turning(self):
+        """ Call this function to make the tank stop turning. """
+        self.rotation = 0
+        self.body.angular_velocity = 0
+
+    def update(self):
+        """ A function to update the objects coordinates.
+            Gets called at every tick of the game. """
+
+        # Creates a vector in the direction we want accelerate / decelerate
+        acceleration_vector = pymunk.Vec2d\
+                              (0,self.ACCELERATION*\
+                               self.acceleration).rotated(self.body.angle)
+        # Applies the vector to our velocity
+        self.body.velocity += acceleration_vector
+
+        # Makes sure that we dont exceed our speed limit
+        velocity = clamp(self.max_speed, self.body.velocity.length)
+        self.body.velocity = pymunk.Vec2d(velocity, \
+                                          0).rotated(self.body.velocity.angle)
+
+        # Updates the rotation
+        self.body.angular_velocity += self.rotation * self.ACCELERATION
+        self.body.angular_velocity = clamp(self.max_speed, \
+                                           self.body.angular_velocity)
+
+
+    def post_update(self,flag):
+        # If the tank carries the flag, then update the positon of the flag
+        if(self.flag != None):
+            self.flag.x           = self.body.position[0]
+            self.flag.y           = self.body.position[1]
+            self.flag.orientation = -math.degrees(self.body.angle)
+        # Else ensure that the tank has its normal max speed
+        else:
+            self.max_speed = Tank.NORMAL_MAX_SPEED
+            
+        self.try_grab_flag(flag)
+    
+        self.timer += 1
+        self.spawn_cooldown += 1
+        self.cooldown -= 1
+    
+        if self.cooldown > 0:
+            self.body.position = self.start_position
+            self.stop_moving()
+        
+        
+
+    def try_grab_flag(self, flag):
+        """ Call this function to try to grab the flag, if the
+            flag is not on other tank and it is close to the current tank,
+            then the current tank will grab the flag.
+        """
+        
+        # Check that the flag is not on other tank
+        if(not flag.is_on_tank):
+            # Check if the tank is close to the flag
+            flag_pos = pymunk.Vec2d(flag.x, flag.y)
+            if((flag_pos - self.body.position).length < 0.5): 
+                # Grab the flag !
+                self.flag           = flag
+                flag.is_on_tank     = True
+                self.max_speed  = Tank.FLAG_MAX_SPEED
+
+    def has_won(self):
+        """ Check if the current tank has won (if it is has the
+            flag and it is close to its start position). """
+        
+        return self.flag != None and \
+               (self.start_position - self.body.position).length < 0.2
+
+
+    
+    def shoot(self):
+        """ Call this function to shoot a missile"""
+        
+        if self.timer > 60:
+            self.timer = 0
+            x = self.body.position[0]+ 0.3*math.cos(math.pi/2+self.body.angle)
+            y = self.body.position[1]+0.3*math.sin(math.pi/2+self.body.angle)
+            return Bullet(x, y, self.body.angle, images.bullet, self.space)
+        
+    def on_death(self):
+        """ Reset the tank's position and set the cooldown when a tank is
+            destroyed. """
+        self.flag = None
+        
+        if self.spawn_cooldown > 100:
+            if self.hitpoints > 1:
+                self.hitpoints = self.hitpoints-1
+            else:
+                self.body.position = self.start_position
+                self.cooldown = 120
+                self.max_speed = 0
+                self.spawn_cooldown = 0
+
+class Box(GamePhysicsObject):
+    """ This class extends the GamePhysicsObject to handle box objects. """
+
+    def __init__(self, x, y, sprite, movable, space, destructable):
+        """ It takes as arguments the coordinate of the starting position
+            of the box (x,y) and the box model (boxmodel). """
+        super().__init__(x, y, 0, sprite, space, movable)
+        self.shape.collision_type = 3
+        self.destructable = destructable
+        self.hitpoints = 2
+      
+
+def get_box_with_type(x, y, type, space):
+    """ Return the box onject corresponding to the input type"""
+    (x, y) = (x + 0.5, y + 0.5) # set offsets in center of the tile
+    if type == 1: # Creates a non-movable non-destructable rockbox
+        return Box(x, y, images.rockbox, False, space, False)
+    if type == 2: # Creates a movable destructable woodbox
+        return Box(x, y, images.woodbox, True, space, True)
+    if type == 3: # Creates a movable non-destructable metalbox
+        return Box(x, y, images.metalbox, True, space, False)
+
+
+
+class GameVisibleObject(GameObject):
+    """ This class extends GameObject for object that are visible on
+        screen but have no physical representation (bases and flag) """
+
+    def __init__(self, x, y, sprite):
+        """ It takes argument the coordinates (x,y) and the sprite. """
+        self.x            = x
+        self.y            = y
+        self.orientation  = 0
+        super().__init__(sprite)
+        
+    def screen_position(self):
+        return physics_to_display(pymunk.Vec2d(self.x, self.y))
+
+    def screen_orientation(self):
+        return self.orientation
+
+
+class Flag(GameVisibleObject):
+    """ This class extends GameVisibleObject for representing flags."""
+
+    def __init__(self, x, y):
+        self.is_on_tank   = False
+        super().__init__(x, y,  images.flag)
+        
+        
+class Bullet(GamePhysicsObject):
+    """ Class for the bullet objects in the game."""
+    def __init__(self, x, y, sprite, orientation, space):
+        """Bullet constructor, take information from the tank that
+           shoots as input"""
+        super().__init__(x,y, sprite, orientation, space, True)
+        self.orientation = math.degrees(self.body.angle)
+        self.shape.collision_type = 1
+        self.velocity             = 15
+        self.body.velocity = pymunk.Vec2d(\
+            (0,self.velocity)).rotated(self.orientation)
+
diff --git a/images.py b/images.py
new file mode 100644
index 0000000000000000000000000000000000000000..6ec9605c3263cb3516d344434c8c3808627adb94
--- /dev/null
+++ b/images.py
@@ -0,0 +1,46 @@
+import pygame
+import os
+
+main_dir = os.path.split(os.path.abspath(__file__))[0]
+
+def load_image(file):
+    """ Load an image from the data directory. """
+    
+    file = os.path.join(main_dir, 'data', file)
+    try:
+        surface = pygame.image.load(file)
+    except pygame.error:
+        raise SystemExit('Could not load image "%s" %s'%\
+                         (file, pygame.get_error()))
+    return surface.convert_alpha()
+
+
+TILE_SIZE = 40 # Define the default size of tiles
+ 
+explosion = load_image('explosion.png') # Image of an explosion
+ 
+grass     = load_image('grass.png') # Image of a grass tile
+
+rockbox   = load_image('rockbox.png') # Image of a rock box (wall)
+
+metalbox  = load_image('metalbox.png') # Image of a metal box
+
+woodbox   = load_image('woodbox.png') # Image of a wood box
+
+flag      = load_image('flag.png') # Image of flag
+
+bullet = load_image('bullet.png')
+bullet = pygame.transform.scale(bullet, (10, 10))
+bullet = pygame.transform.rotate(bullet, -90)
+
+# List of image of tanks of different colors
+tanks     = [load_image('tank_orange.png'), load_image('tank_blue.png'),\
+             load_image('tank_white.png'),
+             load_image('tank_yellow.png'), load_image('tank_red.png'),\
+             load_image('tank_gray.png')]
+
+# List of image of bases corresponding to the color of each tank
+bases     = [load_image('base_orange.png'), load_image('base_blue.png'),\
+             load_image('base_white.png'),
+             load_image('base_yellow.png'), load_image('base_red.png'), \
+             load_image('base_gray.png')]
diff --git a/init_objects.py b/init_objects.py
new file mode 100644
index 0000000000000000000000000000000000000000..74e7e09431ef10fad3e9a9f58eacac5fac10b645
--- /dev/null
+++ b/init_objects.py
@@ -0,0 +1,89 @@
+import gameobjects
+from pygame.locals import *
+from pygame.color import *
+import pymunk
+import images
+import ai
+def create_flag(game_objects_list,flag_start):
+    """Create a flag object and add it to the list of game objects."""
+
+    flag = gameobjects.Flag(flag_start[0], flag_start[1])
+    game_objects_list.append(flag)
+    flag.is_on_tank   = False
+    flag.x, flag.y = flag_start
+    return flag
+
+def create_borders(space,current_map):
+    """ Create borders for the game map. """
+    
+    static_body = space.static_body
+
+    static_lines = [
+            pymunk.Segment(static_body,
+                           (-0.5, current_map.height), (-0.5, 0), 0.5
+                            ), # left
+            pymunk.Segment(static_body, (0, current_map.height+0.5),
+                           (current_map.width, current_map.height+0.5),
+                            0.5), # lower
+            pymunk.Segment(static_body,
+                           (current_map.width+0.5, 0), (current_map.width+0.5,
+                            current_map.height),
+                           0.5), # right
+            pymunk.Segment(static_body, (0, -0.5), (current_map.width, -0.5),
+                            0.5) # upper
+        ]
+    static_lines[0].collision_type = 10
+    static_lines[1].collision_type = 10
+    static_lines[2].collision_type = 10
+    static_lines[3].collision_type = 10
+    space.add(*static_lines)
+    
+    
+def create_background(current_map,background):
+    """Create a background image for the game map."""
+    for x in range(0, current_map.width):
+        for y in range(0,  current_map.height):
+            background.blit(images.grass,(x*images.TILE_SIZE, \
+                                          y*images.TILE_SIZE))
+            
+            
+def create_boxes(game_objects_list , current_map, space):
+    """Create boxes for the game map."""
+    
+    for x in range(0, current_map.width):
+        for y in range(0,  current_map.height):
+        # Get the type of boxes
+            box_type  = current_map.boxAt(x, y)
+            if(box_type != 0):
+                box = gameobjects.get_box_with_type(x, y, box_type, space)
+                game_objects_list.append(box)
+
+def create_tanks(tanks_list,game_objects_list,current_map,space,multi,ai_list):
+    """  create and manage tanks in the game. """
+    
+    for i in range(0, len(current_map.start_positions)):
+    # Get the starting position of the tank "i"
+        pos = current_map.start_positions[i]
+    # Create the tank, images.tanks contains the image representing the tank
+        tank = gameobjects.Tank(pos[0], pos[1], pos[2], images.tanks[i], space)
+    # Add the tank to the list of objects to display
+        game_objects_list.append(tank)
+    # Add the tank to the list of tanks
+        tanks_list.append(tank)
+        if not multi:
+            for i in range(len(tanks_list)-1):
+                ai_list.append(ai.Ai(tanks_list[i+1], game_objects_list,\
+                                     tanks_list, space, current_map))
+        else:
+            for i in range(1,len(tanks_list)-1):
+                ai_list.append(ai.Ai(tanks_list[i+1], game_objects_list,\
+                                     tanks_list, space, current_map))   
+               
+
+def create_bases(game_objects_list,current_map):
+    """ create all needed bases in the game. """
+    
+    for i in range(0, len(current_map.start_positions)):
+        pos = current_map.start_positions[i]
+        base = gameobjects.GameVisibleObject(pos[0],pos[1],images.bases[i])
+        game_objects_list.append(base)
diff --git a/maps.py b/maps.py
new file mode 100644
index 0000000000000000000000000000000000000000..c0841d6181076af3db479feb2c01d1b3c71483ea
--- /dev/null
+++ b/maps.py
@@ -0,0 +1,68 @@
+import images
+import pygame
+
+
+class Map:
+  """ An instance of Map is a blueprint for how the game map will look. """
+
+  def __init__(self,  width,  height,  boxes,  start_positions, flag_position):
+    """ Takes as argument the size of the map (width, height),
+        an array with the boxes type, the start position of tanks
+        (start_positions) and the position of the flag (flag_position).
+    """
+    self.width              = width
+    self.height             = height
+    self.boxes              = boxes
+    self.start_positions    = start_positions
+    self.flag_position      = flag_position
+
+  def rect(self):
+    """ Creates a rectangle for a specifc image. """
+    
+    return pygame.Rect(0, 0, images.TILE_SIZE*self.width, \
+                       images.TILE_SIZE*self.height)
+  
+  def boxAt(self, x, y):
+    """ Return the type of the box at coordinates (x, y). """
+    
+    return self.boxes[y][x]
+
+
+map0 = Map(9, 9, 
+               [ [0, 1, 0, 0, 0, 0, 0, 1, 0], 
+                 [0, 1, 0, 2, 0, 2, 0, 1, 0], 
+                 [0, 2, 0, 1, 0, 1, 0, 2, 0], 
+                 [0, 0, 0, 1, 0, 1, 0, 0, 0], 
+                 [1, 1, 0, 3, 0, 3, 0, 1, 1], 
+                 [0, 0, 0, 1, 0, 1, 0, 0, 0], 
+                 [0, 2, 0, 1, 0, 1, 0, 2, 0], 
+                 [0, 1, 0, 2, 0, 2, 0, 1, 0], 
+                 [0, 1, 0, 0, 0, 0, 0, 1, 0] ],
+               [[0.5, 0.5, 0], [8.5, 0.5, 0],
+                
+                [0.5, 8.5, 180], [8.5, 8.5, 180]], [4.5, 4.5])
+
+map1 = Map(15, 11, 
+           [ [ 0, 2, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 2, 0],
+             [ 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0], 
+             [ 0, 1, 0, 3, 1, 1, 0, 0, 0, 1, 1, 3, 0, 1, 0], 
+             [ 0, 2, 0, 0, 3, 0, 0, 2, 0, 0, 3, 0, 0, 2, 0], 
+             [ 2, 1, 0, 1, 1, 0, 1, 3, 1, 0, 1, 1, 0, 1, 2], 
+             [ 1, 1, 3, 0, 3, 2, 3, 0, 3, 2, 3, 0, 3, 1, 1], 
+             [ 2, 1, 0, 1, 1, 0, 1, 3, 1, 0, 1, 1, 0, 1, 2], 
+             [ 0, 2, 0, 0, 3, 0, 0, 2, 0, 0, 3, 0, 0, 2, 0], 
+             [ 0, 1, 0, 3, 1, 1, 0, 0, 0, 1, 1, 3, 0, 1, 0], 
+             [ 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0], 
+             [ 0, 2, 0, 0, 0, 2, 0, 0, 0, 2, 0, 0, 0, 2, 0] ], 
+           [[0.5, 0.5, 0], [14.5, 0.5, 0], [0.5, 10.5, 180],
+
+            [14.5, 10.5, 180], [7.5, 0.5,  0], [7.5, 10.5, 180]], [7.5, 5.5])
+
+map2 = Map(10, 5, 
+           [ [ 0, 2, 0, 2, 0, 0, 2, 0, 2, 0 ],
+             [ 0, 3, 0, 1, 3, 3, 1, 0, 3, 0 ],
+             [ 0, 1, 0, 1, 0, 0, 1, 0, 1, 0 ], 
+             [ 0, 3, 0, 1, 3, 3, 1, 0, 3, 0 ], 
+             [ 0, 2, 0, 2, 0, 0, 2, 0, 2, 0 ] ],
+           
+           [[0.5, 2.5, 270], [9.5, 2.5, 90]], [5, 2.5] )
diff --git a/menu.py b/menu.py
new file mode 100644
index 0000000000000000000000000000000000000000..a8c24c24016c953311c974f573815628bfea0837
--- /dev/null
+++ b/menu.py
@@ -0,0 +1,106 @@
+import pygame
+import images
+from pygame.locals import *
+import maps
+
+
+def main_menu():
+    """
+    Displays the main menu screen, allowing the user to select options for
+    game play (singleplayer or multiplayer), map, fog, and game mode
+    (score limit, time limit, or round limit). """
+    
+    multiplayer = 1
+    mapp        = 2
+    fog         = 3
+    game_mode   = 4
+    return_    = 5
+        
+    def get_text(var):
+        """ Returns the text to be displayed for each option in the main menu.
+        """
+        
+        white = (255,255,255)
+        font = pygame.font.SysFont('Corbel',35)
+      
+        if var == multiplayer :
+            text1 = font.render('play:' , True , white)
+            text2 = font.render('Capture the Flag!' , True , white)
+            text3 = font.render('singleplayer: press 1!' , True , white)
+            text4 = font.render('multiplayer:  press 2!' , True , white)
+        elif var == mapp :
+            text1 = font.render('Choose a map:' , True , white)
+            text2 = font.render('Capture the Flag!' , True , white)
+            text3 = font.render('Map1, Map2 or Map3' , True , white)
+            text4 = font.render('press: 1 , 2 or 3 ' , True , white)
+        elif var == fog :
+            text1 = font.render('Choose fog:' , True , white)
+            text2 = font.render('Capture the Flag!' , True , white)
+            text3 = font.render('With fog:    press 1' , True , white)
+            text4 = font.render('Without fog: press 2' , True , white)
+        elif var == game_mode :
+            text1 = font.render('Choose a game mode:' , True , white)
+            text2 = font.render('Capture the Flag!' , True , white)
+            text3 = font.render('Score limit, Time limit or Round limit' ,\
+                                True , white)
+            text4 = font.render('press: 1, 2 or 3 ' , True , white)
+        
+        return text1,text2,text3,text4
+
+    def print_on_screen(lst):
+        """ prints the text on the screen """
+        
+        green = (80,200,80)
+        width = 600
+        height = 600
+        screen = pygame.display.set_mode((width,height))
+        screen.fill(green)
+        screen.blit(lst[0], (width/6,height/3))
+        screen.blit(lst[1], (width/6,height/6))
+        screen.blit(lst[2], (width/6,height/3+30))
+        screen.blit(lst[3], (width/6,height/3+70))
+        pygame.display.update()
+
+    return_list = []
+    state = 1
+    while True:
+        
+        print_on_screen(get_text(state))
+        
+        for ev in pygame.event.get():
+            if ev.type == KEYDOWN:
+                temp = None
+                if ev.key == K_ESCAPE:
+                    pygame.quit()
+                if ev.key == K_1:
+                    if state == multiplayer :
+                        temp = False
+                    elif state == mapp :
+                        temp = maps.map0
+                    elif state == fog :
+                        temp = True
+                    elif state == game_mode :
+                        temp = 1
+                    
+                elif ev.key == K_2:
+                    if state == multiplayer :
+                        temp = True
+                    elif state == mapp :
+                        temp = maps.map1
+                    elif state == fog :
+                        temp = False
+                    elif state == game_mode :
+                        temp = 2
+                    
+                elif ev.key == K_3:
+                    if state == mapp :
+                        temp = maps.map2
+                    elif state == game_mode :
+                        temp = 3
+                        
+                if temp != None:
+                    return_list.append(temp)
+                    state = state + 1
+            
+            if state == return_ :
+                return return_list
diff --git a/print_functions.py b/print_functions.py
new file mode 100644
index 0000000000000000000000000000000000000000..489bb0243efe4b129adcc0d79aa47631da5c5110
--- /dev/null
+++ b/print_functions.py
@@ -0,0 +1,70 @@
+import pygame
+import pymunk
+from pygame.locals import *
+from pygame.color import *
+import images
+
+font1 = pygame.font.SysFont('Corbel',20)
+font2 = pygame.font.SysFont('Corbel',35)
+white = (255,255,255)
+
+
+def print_stats_time(screen,var, current_map):
+    """ Print the current time left on the game screen. """
+    
+    text1 = font1.render("Time left:"+str(((1800*5-var)//60)) , True , white)
+    screen.blit(text1, (current_map.width*40+18,current_map.height*18))
+    
+    
+def print_counting_score_console(tanks_list):
+    """ Print the score of retrived flags in the console"""
+    
+    player = 1
+    for i in tanks_list:
+        print('Player',player,": ",i.points)
+        player = player+1
+
+def print_score_result(screen, tanks_list):
+    """ Print the current score of retrived flags for all tanks over the whole
+        screen before a new round is started """
+    
+    width = 300
+    height = 300
+    # create all labels!
+    while True:
+        for ev in pygame.event.get():
+            if ev.type == KEYDOWN:
+                if ev.key == K_1:        
+                    return
+        text2 = font2.render('Press 1 to countinue ' , True , white)
+        player = 1
+        screen.blit(images.grass,(200, 200))
+        for i in tanks_list:
+            text1 = font2.render("Player"+str(player)+":"+str(i.points), \
+                                 True , white)
+            screen.blit(text1, (width/2-120,height/6+player*50))
+            player = player +1
+        screen.blit(text2, (width/2-120,height/6-40)) 
+        text3 = font2.render('Result:' , True , white)
+        screen.blit(text3, (width/2-120,height/6))
+        pygame.display.update()
+        
+        
+def print_stats_score(screen, tanks_list , current_map):
+    """ Print the current score of each tank on the game screen """
+
+    player = 1
+    for i in tanks_list:
+        text1 = font1.render(('Player'+str(player)+": "+str(i.points)) , \
+                             True , white)
+        screen.blit(text1,(current_map.width*40+18,\
+                           current_map.height*15+player*15))
+        player = player+1
+
+
+    
+def print_stats_round(screen, var , current_map):
+    """ Print the round number on the game screen. """
+    
+    text1 = font1.render("round nr:"+str(var) , True , white)
+    screen.blit(text1, (current_map.width*40+18,current_map.height*18))