diff --git a/ants_vs_some_bees.py b/ants_vs_some_bees.py index 5713af3823f73fee895f9d2a6c2e2b11943c50a2..7b68dbec335f06e4e63535d80f5684ca7b1f048a 100644 --- a/ants_vs_some_bees.py +++ b/ants_vs_some_bees.py @@ -136,7 +136,7 @@ class UnitType(Enum): possible for fundamentally different Insects to have the same UnitType. Any changes to this Enum should be accompanied by corresponding changes to - the frontend in main.py. + the frontend in main.py and tower.kv. """ BEE = 'BEE' HARVESTER = 'HARVESTER' @@ -259,19 +259,6 @@ class Harvester(Ant): self.production = production -class Wall(Ant): - """ - A Wall is an Ant with no attack, but lots of health for holding off - attacking Bees. - """ - - def __init__(self, unit_type): - """ - Create a Wall with the given type. - """ - super(Wall, self).__init__(unit_type, 4, 4) - - class Thrower(Ant): """ A Thrower throws a leaf each turn at the nearest Bee in its range. @@ -400,7 +387,7 @@ class GameState(object): Construct a world from the given places, designating one place as the Bee's target, offer the player the given archetypes, and provide the player with the given amount of starting food. The places may be (and - usually are) prepopulated with insects. + usually should be) prepopulated with insects. """ self.ant_archetypes = ant_archetypes self.places = places @@ -473,7 +460,7 @@ STANDARD_ANT_ARCHETYPES = ( Thrower(UnitType.THROWER, food_cost=7, health=1, damage=1), Thrower(UnitType.LONG_THROWER, food_cost=3, health=1, damage=1, minimum_range=4), - Wall(UnitType.WALL), + Ant(UnitType.WALL, food_cost=4, health=4), ) @@ -497,36 +484,50 @@ def make_standard_hive(center_x, center_y, radius, wave_count=4, wave_size=2, return hive -def make_standard_game(row_count=3, column_count=8, wave_count=4, wave_size=2, +def make_standard_game(minimum_row_count=2, maximum_row_count=4, + column_count=9, wave_count=4, wave_size=2, wave_growth=1, wave_interval=5, bee_health=4, bee_damage=1, ant_archetypes=STANDARD_ANT_ARCHETYPES, food=4): """ Construct the GameState for the beginning of a standard game, which has the - ant queen and the Bee's hive separated by several equal-length rows of - ColonyPlaces and Bee's attacking in waves of increasing size. Most of the - specifics of this setup can be varied by specifying non-default arguments. + ant queen and the Bee's hive separated by tunnels of ColonyPlaces and Bee's + attacking in waves of increasing size. Most of the specifics of this setup + can be varied by specifying non-default arguments. """ + assert minimum_row_count > 0, 'Cannot create a game with no rows' + assert maximum_row_count >= minimum_row_count, \ + 'The maximum row count must be at least the minimum row count' + assert column_count > 0, 'Cannot create a game with no columns' - center_y = (row_count + 1) / 2 + center_y = (maximum_row_count + 1) / 2 queen_place = Place(1, center_y) - hive_center_x = column_count + 6 + multiplier = maximum_row_count - minimum_row_count + 1 + heights = [int(minimum_row_count + multiplier * column / column_count) + for column in range(column_count)] + + hive_center_x = 6 + column_count + heights[-1] - minimum_row_count hive = make_standard_hive(hive_center_x, center_y, 2, wave_count, wave_size, wave_growth, wave_interval, bee_health, bee_damage) - places = [queen_place] + hive - for row in range(row_count): - destination = queen_place - for column in range(column_count): - place = Respite(column + 3, row + 1) \ - if (column + 2 * row) % 5 == 1 else \ - ColonyPlace(column + 3, row + 1) - place.connect_to(destination) - destination = place - places.append(place) - for hive_place in hive: - hive_place.connect_to(destination) - - return GameState(places, queen_place, ant_archetypes, food) + tunnels = {} + for column in range(column_count): + height = heights[column] + x = 3 + column + height - minimum_row_count + for row in range(height): + y = center_y + row - (height - 1) / 2 + place = Respite(x, y) if (column + 2 * row) % 5 == 1 else ColonyPlace(x, y) + if column == 0: + place.connect_to(queen_place) + elif height == heights[column - 1]: + place.connect_to(tunnels[column - 1, row]) + else: + for other_row in range(heights[column - 1]): + place.connect_to(tunnels[column - 1, other_row]) + if column == column_count - 1: + for hive_place in hive: + hive_place.connect_to(place) + tunnels[column, row] = place + return GameState([queen_place] + hive + list(tunnels.values()), queen_place, ant_archetypes, food) diff --git a/main.py b/main.py index dbf572f295b777e2c125b426d426a54e7ac8b2e6..1038f92a75923fe2fa8a5bde69961c79b1d1ee5b 100644 --- a/main.py +++ b/main.py @@ -388,6 +388,6 @@ class TowerApp(App): self.end_game() -if __name__ == "__main__": +if __name__ == '__main__': app = TowerApp() app.run() diff --git a/tower.kv b/tower.kv index 75d789a15833d38766971e80456f1235a0c1a790..e9caec3c3500357bb10f6a175595b9829d20f65a 100644 --- a/tower.kv +++ b/tower.kv @@ -1,9 +1,7 @@ -#:import ants_vs_some_bees ants_vs_some_bees - -#:set SPRITE_WIDTH 93 -#:set SPRITE_HEIGHT 98 -#:set UNIT_NAMES {'HARVESTER': 'Harvester Ant', 'SHORT_THROWER': 'Short-Range Leaf Thrower', 'THROWER': 'All-Range Leaf Thrower', 'LONG_THROWER': 'Long-Range Leaf Thrower', 'WALL': 'Wall Ant'} - +#:import Game main.Game +#:import UnitType ants_vs_some_bees.UnitType +#:set SPRITE_SIZE (Game.SPRITE_WIDTH, Game.SPRITE_HEIGHT) +#:set UNIT_NAMES {UnitType.HARVESTER: 'Harvester Ant', UnitType.SHORT_THROWER: 'Short-Range Leaf Thrower', UnitType.THROWER: 'All-Range Leaf Thrower', UnitType.LONG_THROWER: 'Long-Range Leaf Thrower', UnitType.WALL: 'Wall Ant'} ScreenManager: Screen: @@ -132,7 +130,7 @@ ScreenManager: id: harvester_image source: 'assets/ant_harvester.gif' size_hint: (None, 1) - size: (SPRITE_WIDTH, SPRITE_HEIGHT) + size: SPRITE_SIZE Label: text: 'A harvester ant costs 3 food units to deploy, but produces 2 food units per turn.' text_size: (self.width, None) @@ -149,7 +147,7 @@ ScreenManager: id: short_thrower_image source: 'assets/ant_short_thrower.gif' size_hint: (None, 1) - size: (SPRITE_WIDTH, SPRITE_HEIGHT) + size: SPRITE_SIZE Label: text: 'A short-range leaf thrower costs 3 food units to deploy and can throw leaves at bees it sees up to two spaces away.' text_size: (self.width, None) @@ -166,7 +164,7 @@ ScreenManager: id: thrower_image source: 'assets/ant_thrower.gif' size_hint: (None, 1) - size: (SPRITE_WIDTH, SPRITE_HEIGHT) + size: SPRITE_SIZE Label: text: 'An all-range thrower costs 7 food units to deploy and can throw leaves at any range.' text_size: (self.width, None) @@ -183,7 +181,7 @@ ScreenManager: id: long_thrower_image source: 'assets/ant_long_thrower.gif' size_hint: (None, 1) - size: (SPRITE_WIDTH, SPRITE_HEIGHT) + size: SPRITE_SIZE Label: text: 'A long-range thrower costs 3 food units to deploy and can throw leaves at bees it sees from at least four spaces away.' text_size: (self.width, None) @@ -200,7 +198,7 @@ ScreenManager: id: wall_image source: 'assets/ant_wall.gif' size_hint: (None, 1) - size: (SPRITE_WIDTH, SPRITE_HEIGHT) + size: SPRITE_SIZE Label: text: 'A wall ant costs 4 food units to deploy and has no attack, but it can withstand 4 stings before dying.' text_size: (self.width, None) @@ -233,7 +231,7 @@ ScreenManager: id: wall_image source: 'assets/bee.gif' size_hint: (None, 1) - size: (SPRITE_WIDTH, SPRITE_HEIGHT) + size: SPRITE_SIZE Label: text: 'A bee can either fly forward or sting each turn. It normally takes 4 leaves to kill a bee.' text_size: (self.width, None) @@ -264,7 +262,7 @@ ScreenManager: size: self.size source: 'assets/tunnel.gif' size_hint: (None, 1) - size: (SPRITE_WIDTH, SPRITE_HEIGHT) + size: SPRITE_SIZE Label: text: 'Every time a bee reaches a red-shaded space in the tunnel, its health increases by one point.' text_size: (self.width, None) @@ -318,7 +316,7 @@ ScreenManager: height: 24 Label: id: selection - text: '{unit} ({food_cost} food)'.format(unit=UNIT_NAMES[root.selection.unit_type.value], food_cost=getattr(root.selection, 'food_cost', 0)) if root.selection is not None else 'Sacrifice Ant' + text: '{unit} ({food_cost} food)'.format(unit=UNIT_NAMES[root.selection.unit_type], food_cost=getattr(root.selection, 'food_cost', 0)) if root.selection is not None else 'Sacrifice Ant' size_hint: (1, None) height: 24 Label: @@ -363,7 +361,7 @@ ScreenManager: pos: self.pos size: self.size size_hint: (None, None) - size: (SPRITE_WIDTH, SPRITE_HEIGHT) + size: SPRITE_SIZE <Sprite>: @@ -373,6 +371,6 @@ ScreenManager: Rectangle: pos: self.pos size: self.size - pos: (SPRITE_WIDTH * self.world_x, SPRITE_HEIGHT * self.world_y) + pos: (Game.SPRITE_WIDTH * self.world_x, Game.SPRITE_HEIGHT * self.world_y) size_hint: (None, None) - size: (SPRITE_WIDTH, SPRITE_HEIGHT) + size: SPRITE_SIZE