From 6b93340473365231e635e4ba0823baed34102e5c Mon Sep 17 00:00:00 2001 From: dmccoystephenson Date: Mon, 6 Feb 2023 20:04:33 -0700 Subject: [PATCH 01/18] Changed version to 0.8.0-SNAPSHOT for development towards next release. --- version.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.txt b/version.txt index bcaffe1..8c49440 100644 --- a/version.txt +++ b/version.txt @@ -1 +1 @@ -0.7.0 \ No newline at end of file +0.8.0-SNAPSHOT \ No newline at end of file From 8ed5362575391ec12fe89854f75d99a115d36279 Mon Sep 17 00:00:00 2001 From: dmccoystephenson Date: Wed, 8 Feb 2023 21:35:57 -0700 Subject: [PATCH 02/18] Added unit tests for 'src/entity' package. --- .gitignore | 3 +- pytest.ini | 4 ++ src/__init__.py | 0 src/entity/living/__init__.py | 0 src/entity/living/livingEntity.py | 3 ++ test.sh | 4 ++ tests/entity/living/test_bear.py | 9 ++++ tests/entity/living/test_chicken.py | 12 +++++ tests/entity/living/test_livingEntity.py | 56 ++++++++++++++++++++++++ tests/entity/test_apple.py | 8 ++++ tests/entity/test_banana.py | 8 ++++ tests/entity/test_coalOre.py | 8 ++++ tests/entity/test_drawableEntity.py | 7 +++ tests/entity/test_food.py | 8 ++++ tests/entity/test_grass.py | 8 ++++ tests/entity/test_ironOre.py | 8 ++++ tests/entity/test_jungleWood.py | 8 ++++ tests/entity/test_leaves.py | 8 ++++ tests/entity/test_oakWood.py | 8 ++++ tests/entity/test_stone.py | 8 ++++ 20 files changed, 177 insertions(+), 1 deletion(-) create mode 100644 pytest.ini create mode 100644 src/__init__.py create mode 100644 src/entity/living/__init__.py create mode 100644 test.sh create mode 100644 tests/entity/living/test_bear.py create mode 100644 tests/entity/living/test_chicken.py create mode 100644 tests/entity/living/test_livingEntity.py create mode 100644 tests/entity/test_apple.py create mode 100644 tests/entity/test_banana.py create mode 100644 tests/entity/test_coalOre.py create mode 100644 tests/entity/test_drawableEntity.py create mode 100644 tests/entity/test_food.py create mode 100644 tests/entity/test_grass.py create mode 100644 tests/entity/test_ironOre.py create mode 100644 tests/entity/test_jungleWood.py create mode 100644 tests/entity/test_leaves.py create mode 100644 tests/entity/test_oakWood.py create mode 100644 tests/entity/test_stone.py diff --git a/.gitignore b/.gitignore index 8bc9c0f..766d959 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,5 @@ saves/*/*.json saves/*/rooms/*.json saves/*/roompngs/*.png saves/*/mapImage.png -output.txt \ No newline at end of file +output.txt +.coverage \ No newline at end of file diff --git a/pytest.ini b/pytest.ini new file mode 100644 index 0000000..04b92dc --- /dev/null +++ b/pytest.ini @@ -0,0 +1,4 @@ +[pytest] +pythonpath = . + src + src/entity \ No newline at end of file diff --git a/src/__init__.py b/src/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/entity/living/__init__.py b/src/entity/living/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/entity/living/livingEntity.py b/src/entity/living/livingEntity.py index 3875962..3267375 100644 --- a/src/entity/living/livingEntity.py +++ b/src/entity/living/livingEntity.py @@ -41,6 +41,9 @@ def needsEnergy(self): def getTargetEnergy(self): return self.targetEnergy + def setTargetEnergy(self, targetEnergy): + self.targetEnergy = targetEnergy + def canEat(self, entity): for entityType in self.edibleEntityTypes: if type(entity) is entityType: diff --git a/test.sh b/test.sh new file mode 100644 index 0000000..92268f2 --- /dev/null +++ b/test.sh @@ -0,0 +1,4 @@ +# run pytest with coverage and generate html report +# Usage: ./test.sh + +coverage report -m pytest --verbose -vv \ No newline at end of file diff --git a/tests/entity/living/test_bear.py b/tests/entity/living/test_bear.py new file mode 100644 index 0000000..c54dd82 --- /dev/null +++ b/tests/entity/living/test_bear.py @@ -0,0 +1,9 @@ +from src.entity.living.bear import Bear + +def test_initialization(): + bear = Bear(0) + + assert(bear.name == "Bear") + assert(bear.getTickCreated() == 0) + assert(bear.getImagePath() == "assets/bear.png") + assert(bear.isSolid() == False) \ No newline at end of file diff --git a/tests/entity/living/test_chicken.py b/tests/entity/living/test_chicken.py new file mode 100644 index 0000000..1d72aab --- /dev/null +++ b/tests/entity/living/test_chicken.py @@ -0,0 +1,12 @@ +from src.entity.living.chicken import Chicken + +def test_initialization(): + chicken = Chicken(0) + + assert(chicken.name == "Chicken") + assert(chicken.getTickCreated() == 0) + assert(chicken.getImagePath() == "assets/chicken.png") + +def test_can_eat(): + chicken = Chicken(0) + assert(chicken.canEat("test") == False) \ No newline at end of file diff --git a/tests/entity/living/test_livingEntity.py b/tests/entity/living/test_livingEntity.py new file mode 100644 index 0000000..5f1bbda --- /dev/null +++ b/tests/entity/living/test_livingEntity.py @@ -0,0 +1,56 @@ +import pytest +from src.entity.living.livingEntity import LivingEntity + +def test_initialization(): + livingEntity = LivingEntity("test", "myimagepath.png", 50, [], 0) + + assert(livingEntity.name == "test") + assert(livingEntity.getEnergy() == 50) + assert(livingEntity.getTargetEnergy() == 50) + assert(livingEntity.getTickCreated() == 0) + +def test_set_energy(): + livingEntity = LivingEntity("test", "myimagepath.png", 50, [], 0) + livingEntity.setEnergy(100) + + assert(livingEntity.getEnergy() == 100) + + +def test_set_target_energy(): + livingEntity = LivingEntity("test", "myimagepath.png", 50, [], 0) + livingEntity.setTargetEnergy(100) + + assert(livingEntity.getTargetEnergy() == 100) + +def test_add_energy(): + livingEntity = LivingEntity("test", "myimagepath.png", 50, [], 0) + livingEntity.addEnergy(50) + + assert(livingEntity.getEnergy() == 100) + +def test_remove_energy(): + livingEntity = LivingEntity("test", "myimagepath.png", 50, [], 0) + livingEntity.removeEnergy(50) + + assert(livingEntity.getEnergy() == 0) + +def test_needs_energy(): + livingEntity = LivingEntity("test", "myimagepath.png", 50, [], 0) + assert(livingEntity.needsEnergy() == False) + + livingEntity.setEnergy(livingEntity.getTargetEnergy() / 2 - 1) + assert(livingEntity.needsEnergy() == True) + +def test_get_age(): + livingEntity = LivingEntity("test", "myimagepath.png", 50, [], 0) + assert(livingEntity.getAge(100) == 100) + +def test_kill(): + livingEntity = LivingEntity("test", "myimagepath.png", 50, [], 0) + livingEntity.kill() + + assert(livingEntity.getEnergy() == 0) + +def test_can_eat(): + livingEntity = LivingEntity("test", "myimagepath.png", 50, [], 0) + assert(livingEntity.canEat("test") == False) \ No newline at end of file diff --git a/tests/entity/test_apple.py b/tests/entity/test_apple.py new file mode 100644 index 0000000..958694f --- /dev/null +++ b/tests/entity/test_apple.py @@ -0,0 +1,8 @@ +from src.entity.apple import Apple + +def test_initialization(): + apple = Apple() + + assert(apple.name == "Apple") + assert(apple.getImagePath() == "assets/apple.png") + assert(apple.isSolid() == False) \ No newline at end of file diff --git a/tests/entity/test_banana.py b/tests/entity/test_banana.py new file mode 100644 index 0000000..d671eaa --- /dev/null +++ b/tests/entity/test_banana.py @@ -0,0 +1,8 @@ +from src.entity.banana import Banana + +def test_initialization(): + banana = Banana() + + assert(banana.name == "Banana") + assert(banana.getImagePath() == "assets/banana.png") + assert(banana.isSolid() == False) \ No newline at end of file diff --git a/tests/entity/test_coalOre.py b/tests/entity/test_coalOre.py new file mode 100644 index 0000000..de1b64a --- /dev/null +++ b/tests/entity/test_coalOre.py @@ -0,0 +1,8 @@ +from src.entity.coalOre import CoalOre + +def test_initialization(): + coalore = CoalOre() + + assert(coalore.name == "Coal Ore") + assert(coalore.getImagePath() == "assets/coalOre.png") + assert(coalore.isSolid() == True) \ No newline at end of file diff --git a/tests/entity/test_drawableEntity.py b/tests/entity/test_drawableEntity.py new file mode 100644 index 0000000..6411fd7 --- /dev/null +++ b/tests/entity/test_drawableEntity.py @@ -0,0 +1,7 @@ +from src.entity.drawableEntity import DrawableEntity + +def test_initialization(): + drawableEntity = DrawableEntity("test", "myimagepath.png") + + assert(drawableEntity.getName() == "test") + assert(drawableEntity.getImagePath() == "myimagepath.png") \ No newline at end of file diff --git a/tests/entity/test_food.py b/tests/entity/test_food.py new file mode 100644 index 0000000..23e92de --- /dev/null +++ b/tests/entity/test_food.py @@ -0,0 +1,8 @@ +from src.entity.food import Food + +def test_initialization(): + food = Food("test", "myimagepath.png", 20) + + assert(food.getName() == "test") + assert(food.getImagePath() == "myimagepath.png") + assert(food.getEnergy() == 20) \ No newline at end of file diff --git a/tests/entity/test_grass.py b/tests/entity/test_grass.py new file mode 100644 index 0000000..78728ed --- /dev/null +++ b/tests/entity/test_grass.py @@ -0,0 +1,8 @@ +from src.entity.grass import Grass + +def test_initialization(): + grass = Grass() + + assert(grass.name == "Grass") + assert(grass.getImagePath() == "assets/grass.png") + assert(grass.isSolid() == False) \ No newline at end of file diff --git a/tests/entity/test_ironOre.py b/tests/entity/test_ironOre.py new file mode 100644 index 0000000..6662e25 --- /dev/null +++ b/tests/entity/test_ironOre.py @@ -0,0 +1,8 @@ +from src.entity.ironOre import IronOre + +def test_initialization(): + ironore = IronOre() + + assert(ironore.name == "Iron Ore") + assert(ironore.getImagePath() == "assets/ironOre.png") + assert(ironore.isSolid() == True) \ No newline at end of file diff --git a/tests/entity/test_jungleWood.py b/tests/entity/test_jungleWood.py new file mode 100644 index 0000000..73cb538 --- /dev/null +++ b/tests/entity/test_jungleWood.py @@ -0,0 +1,8 @@ +from src.entity.jungleWood import JungleWood + +def test_initialization(): + junglewood = JungleWood() + + assert(junglewood.name == "Jungle Wood") + assert(junglewood.getImagePath() == "assets/jungleWood.png") + assert(junglewood.isSolid() == True) \ No newline at end of file diff --git a/tests/entity/test_leaves.py b/tests/entity/test_leaves.py new file mode 100644 index 0000000..e2b02de --- /dev/null +++ b/tests/entity/test_leaves.py @@ -0,0 +1,8 @@ +from src.entity.leaves import Leaves + +def test_initialization(): + leaves = Leaves() + + assert(leaves.name == "Leaves") + assert(leaves.getImagePath() == "assets/leaves.png") + assert(leaves.isSolid() == False) \ No newline at end of file diff --git a/tests/entity/test_oakWood.py b/tests/entity/test_oakWood.py new file mode 100644 index 0000000..8069b16 --- /dev/null +++ b/tests/entity/test_oakWood.py @@ -0,0 +1,8 @@ +from src.entity.oakWood import OakWood + +def test_initialization(): + oakwood = OakWood() + + assert(oakwood.name == "Oak Wood") + assert(oakwood.getImagePath() == "assets/oakWood.png") + assert(oakwood.isSolid() == True) \ No newline at end of file diff --git a/tests/entity/test_stone.py b/tests/entity/test_stone.py new file mode 100644 index 0000000..322ed34 --- /dev/null +++ b/tests/entity/test_stone.py @@ -0,0 +1,8 @@ +from src.entity.stone import Stone + +def test_initialization(): + stone = Stone() + + assert(stone.name == "Stone") + assert(stone.getImagePath() == "assets/stone.png") + assert(stone.isSolid() == True) \ No newline at end of file From 4c506c12236340f1a575865d4d31c28c4d842c5f Mon Sep 17 00:00:00 2001 From: dmccoystephenson Date: Wed, 8 Feb 2023 21:40:22 -0700 Subject: [PATCH 03/18] Modified test.sh --- test.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test.sh b/test.sh index 92268f2..0b46800 100644 --- a/test.sh +++ b/test.sh @@ -1,4 +1,4 @@ -# run pytest with coverage and generate html report +# /bin/bash # Usage: ./test.sh -coverage report -m pytest --verbose -vv \ No newline at end of file +pytest --verbose -vv \ No newline at end of file From 9fcaedc16c94d585e7711c53a69dff3a8fb4b016 Mon Sep 17 00:00:00 2001 From: dmccoystephenson Date: Wed, 8 Feb 2023 21:43:08 -0700 Subject: [PATCH 04/18] Added solid check to test_chicken.py --- tests/entity/living/test_chicken.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/entity/living/test_chicken.py b/tests/entity/living/test_chicken.py index 1d72aab..18b2cbc 100644 --- a/tests/entity/living/test_chicken.py +++ b/tests/entity/living/test_chicken.py @@ -6,6 +6,7 @@ def test_initialization(): assert(chicken.name == "Chicken") assert(chicken.getTickCreated() == 0) assert(chicken.getImagePath() == "assets/chicken.png") + assert(chicken.isSolid() == False) def test_can_eat(): chicken = Chicken(0) From 47333c3b45022edf49fa96db52fca3fb643d3ae3 Mon Sep 17 00:00:00 2001 From: dmccoystephenson Date: Wed, 8 Feb 2023 21:44:08 -0700 Subject: [PATCH 05/18] Cleaned up test_livingEntity.py a bit. --- tests/entity/living/test_livingEntity.py | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/tests/entity/living/test_livingEntity.py b/tests/entity/living/test_livingEntity.py index 5f1bbda..092827b 100644 --- a/tests/entity/living/test_livingEntity.py +++ b/tests/entity/living/test_livingEntity.py @@ -1,8 +1,11 @@ import pytest from src.entity.living.livingEntity import LivingEntity +def createLivingEntity(): + return LivingEntity("test", "myimagepath.png", 50, [], 0) + def test_initialization(): - livingEntity = LivingEntity("test", "myimagepath.png", 50, [], 0) + livingEntity = createLivingEntity() assert(livingEntity.name == "test") assert(livingEntity.getEnergy() == 50) @@ -10,47 +13,47 @@ def test_initialization(): assert(livingEntity.getTickCreated() == 0) def test_set_energy(): - livingEntity = LivingEntity("test", "myimagepath.png", 50, [], 0) + livingEntity = createLivingEntity() livingEntity.setEnergy(100) assert(livingEntity.getEnergy() == 100) def test_set_target_energy(): - livingEntity = LivingEntity("test", "myimagepath.png", 50, [], 0) + livingEntity = createLivingEntity() livingEntity.setTargetEnergy(100) assert(livingEntity.getTargetEnergy() == 100) def test_add_energy(): - livingEntity = LivingEntity("test", "myimagepath.png", 50, [], 0) + livingEntity = createLivingEntity() livingEntity.addEnergy(50) assert(livingEntity.getEnergy() == 100) def test_remove_energy(): - livingEntity = LivingEntity("test", "myimagepath.png", 50, [], 0) + livingEntity = createLivingEntity() livingEntity.removeEnergy(50) assert(livingEntity.getEnergy() == 0) def test_needs_energy(): - livingEntity = LivingEntity("test", "myimagepath.png", 50, [], 0) + livingEntity = createLivingEntity() assert(livingEntity.needsEnergy() == False) livingEntity.setEnergy(livingEntity.getTargetEnergy() / 2 - 1) assert(livingEntity.needsEnergy() == True) def test_get_age(): - livingEntity = LivingEntity("test", "myimagepath.png", 50, [], 0) + livingEntity = createLivingEntity() assert(livingEntity.getAge(100) == 100) def test_kill(): - livingEntity = LivingEntity("test", "myimagepath.png", 50, [], 0) + livingEntity = createLivingEntity() livingEntity.kill() assert(livingEntity.getEnergy() == 0) def test_can_eat(): - livingEntity = LivingEntity("test", "myimagepath.png", 50, [], 0) + livingEntity = createLivingEntity() assert(livingEntity.canEat("test") == False) \ No newline at end of file From e3de4ba8b58cd7d92cfc5523cbb073c736e0ebe1 Mon Sep 17 00:00:00 2001 From: dmccoystephenson Date: Wed, 8 Feb 2023 22:43:13 -0700 Subject: [PATCH 06/18] Added unit tests for Stats class. --- .gitignore | 3 +- tests/stats/test_stats.py | 132 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 134 insertions(+), 1 deletion(-) create mode 100644 tests/stats/test_stats.py diff --git a/.gitignore b/.gitignore index 766d959..51d74ae 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,5 @@ saves/*/rooms/*.json saves/*/roompngs/*.png saves/*/mapImage.png output.txt -.coverage \ No newline at end of file +.coverage +tests/stats/*.json \ No newline at end of file diff --git a/tests/stats/test_stats.py b/tests/stats/test_stats.py new file mode 100644 index 0000000..7d443d4 --- /dev/null +++ b/tests/stats/test_stats.py @@ -0,0 +1,132 @@ +from unittest.mock import MagicMock +from src.stats.stats import Stats +from src.config.config import Config + +def createStatsInstance(): + config = MagicMock() + config.pathToSaveDirectory = "tests/stats" + return Stats(config) + +def test_initialization(): + # call + stats = createStatsInstance() + + # check + assert(stats.getScore() == 0) + assert(stats.getRoomsExplored() == 0) + assert(stats.getFoodEaten() == 0) + assert(stats.getNumberOfDeaths() == 0) + +def test_setScore(): + # prepare + stats = createStatsInstance() + + # call + stats.setScore(5) + + # check + assert(stats.getScore() == 5) + +def test_setRoomsExplored(): + # prepare + stats = createStatsInstance() + + # call + stats.setRoomsExplored(5) + + # check + assert(stats.getRoomsExplored() == 5) + +def test_setFoodEaten(): + # prepare + stats = createStatsInstance() + + # call + stats.setFoodEaten(5) + + # check + assert(stats.getFoodEaten() == 5) + +def test_setNumberOfDeaths(): + # prepare + stats = createStatsInstance() + + # call + stats.setNumberOfDeaths(5) + + # check + assert(stats.getNumberOfDeaths() == 5) + +def test_incrementScore(): + # prepare + stats = createStatsInstance() + + # call + stats.incrementScore() + + # check + assert(stats.getScore() == 1) + +def test_incrementRoomsExplored(): + # prepare + stats = createStatsInstance() + + # call + stats.incrementRoomsExplored() + + # check + assert(stats.getRoomsExplored() == 1) + +def test_incrementFoodEaten(): + # prepare + stats = createStatsInstance() + + # call + stats.incrementFoodEaten() + + # check + assert(stats.getFoodEaten() == 1) + +def test_incrementNumberOfDeaths(): + # prepare + stats = createStatsInstance() + + # call + stats.incrementNumberOfDeaths() + + # check + assert(stats.getNumberOfDeaths() == 1) + +def test_save(): + # prepare + stats = createStatsInstance() + stats.incrementScore() + stats.incrementRoomsExplored() + stats.incrementFoodEaten() + stats.incrementNumberOfDeaths() + + # call + stats.save() + + # check + assert(stats.getScore() == 1) + assert(stats.getRoomsExplored() == 1) + assert(stats.getFoodEaten() == 1) + assert(stats.getNumberOfDeaths() == 1) + +def test_load(): + # prepare + stats = createStatsInstance() + stats.incrementScore() + stats.incrementRoomsExplored() + stats.incrementFoodEaten() + stats.incrementNumberOfDeaths() + + # call + stats.load() + + # check + assert(stats.getScore() == 1) + assert(stats.getRoomsExplored() == 1) + assert(stats.getFoodEaten() == 1) + assert(stats.getNumberOfDeaths() == 1) \ No newline at end of file From 2f4b23136a84c46e989dc1789b0633b3f06ff3dc Mon Sep 17 00:00:00 2001 From: dmccoystephenson Date: Wed, 8 Feb 2023 22:54:28 -0700 Subject: [PATCH 07/18] Added unit tests for Player class. --- tests/player/test_player.py | 174 ++++++++++++++++++++++++++++++++++++ 1 file changed, 174 insertions(+) create mode 100644 tests/player/test_player.py diff --git a/tests/player/test_player.py b/tests/player/test_player.py new file mode 100644 index 0000000..8358a7b --- /dev/null +++ b/tests/player/test_player.py @@ -0,0 +1,174 @@ +from unittest.mock import MagicMock +from src.player import player + +def createPlayerInstance(): + player.Inventory = MagicMock() + return player.Player(0) + +def test_initialization(): + # call + playerInstance = createPlayerInstance() + + # check + assert(playerInstance.getDirection() == -1) + assert(playerInstance.getLastDirection() == -1) + assert(playerInstance.isGathering() == False) + assert(playerInstance.isPlacing() == False) + assert(playerInstance.isDead() == False) + assert(playerInstance.getTickLastMoved() == -1) + assert(playerInstance.getMovementSpeed() == 30) + assert(playerInstance.getGatherSpeed() == 30) + assert(playerInstance.getPlaceSpeed() == 30) + assert(playerInstance.isCrouching() == False) + assert(playerInstance.isSolid() == False) + + player.Inventory.assert_called_once() + +def test_set_direction_up(): + # prepare + playerInstance = createPlayerInstance() + + # call + playerInstance.setDirection(0) + + # check + assert(playerInstance.getDirection() == 0) + assert(playerInstance.getLastDirection() == -1) + assert(playerInstance.imagePath == "assets/player_up.png") + +def test_set_direction_left(): + # prepare + playerInstance = createPlayerInstance() + + # call + playerInstance.setDirection(1) + + # check + assert(playerInstance.getDirection() == 1) + assert(playerInstance.getLastDirection() == -1) + assert(playerInstance.imagePath == "assets/player_left.png") + +def test_set_direction_down(): + # prepare + playerInstance = createPlayerInstance() + + # call + playerInstance.setDirection(2) + + # check + assert(playerInstance.getDirection() == 2) + assert(playerInstance.getLastDirection() == -1) + assert(playerInstance.imagePath == "assets/player_down.png") + +def test_set_direction_right(): + # prepare + playerInstance = createPlayerInstance() + + # call + playerInstance.setDirection(3) + + # check + assert(playerInstance.getDirection() == 3) + assert(playerInstance.getLastDirection() == -1) + assert(playerInstance.imagePath == "assets/player_right.png") + +def test_set_gathering(): + # prepare + playerInstance = createPlayerInstance() + + # call + playerInstance.setGathering(True) + + # check + assert(playerInstance.isGathering() == True) + +def test_set_placing(): + # prepare + playerInstance = createPlayerInstance() + + # call + playerInstance.setPlacing(True) + + # check + assert(playerInstance.isPlacing() == True) + +def test_set_tick_last_moved(): + # prepare + playerInstance = createPlayerInstance() + + # call + playerInstance.setTickLastMoved(10) + + # check + assert(playerInstance.getTickLastMoved() == 10) + +def test_set_inventory(): + # prepare + playerInstance = createPlayerInstance() + inventory = MagicMock() + + # call + playerInstance.setInventory(inventory) + + # check + assert(playerInstance.getInventory() == inventory) + +def test_set_movement_speed(): + # prepare + playerInstance = createPlayerInstance() + + # call + playerInstance.setMovementSpeed(10) + + # check + assert(playerInstance.movementSpeed == 10) + +def test_set_gather_speed(): + # prepare + playerInstance = createPlayerInstance() + + # call + playerInstance.setGatherSpeed(10) + + # check + assert(playerInstance.gatherSpeed == 10) + +def test_set_place_speed(): + # prepare + playerInstance = createPlayerInstance() + + # call + playerInstance.setPlaceSpeed(10) + + # check + assert(playerInstance.placeSpeed == 10) + +def test_set_crouching(): + # prepare + playerInstance = createPlayerInstance() + + # call + playerInstance.setCrouching(True) + + # check + assert(playerInstance.crouching == True) + +def test_is_moving(): + # prepare + playerInstance = createPlayerInstance() + + # call + playerInstance.setDirection(0) + + # check + assert(playerInstance.isMoving() == True) + +def is_moving_false(): + # prepare + playerInstance = createPlayerInstance() + + # call + playerInstance.setDirection(-1) + + # check + assert(playerInstance.isMoving() == False) \ No newline at end of file From e4f0320978f87442c22e3f1a48f6b78a6a362ce4 Mon Sep 17 00:00:00 2001 From: dmccoystephenson Date: Fri, 10 Feb 2023 20:48:24 -0700 Subject: [PATCH 08/18] Made test.sh generate coverage file and display coverage in console. --- .devcontainer/devcontainer.json | 19 +++++++++++++++++++ .gitignore | 3 ++- requirements.txt | Bin 644 -> 680 bytes test.sh | 3 ++- 4 files changed, 23 insertions(+), 2 deletions(-) create mode 100644 .devcontainer/devcontainer.json diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..009a80f --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,19 @@ +// For format details, see https://aka.ms/devcontainer.json. For config options, see the +// README at: https://github.com/devcontainers/templates/tree/main/src/debian +{ + "name": "Debian", + // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile + "image": "mcr.microsoft.com/devcontainers/base:bullseye" + + // Features to add to the dev container. More info: https://containers.dev/features. + // "features": {}, + + // Use 'forwardPorts' to make a list of ports inside the container available locally. + // "forwardPorts": [], + + // Configure tool-specific properties. + // "customizations": {}, + + // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. + // "remoteUser": "root" +} diff --git a/.gitignore b/.gitignore index 51d74ae..f64939a 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,5 @@ saves/*/roompngs/*.png saves/*/mapImage.png output.txt .coverage -tests/stats/*.json \ No newline at end of file +tests/stats/*.json +cov.xml \ No newline at end of file diff --git a/requirements.txt b/requirements.txt index eccc1513e0eaa5aa392b0b6bdf9ed279f933524e..d38d08712c88876026d62b1cf7649910acc125a9 100644 GIT binary patch delta 75 zcmZo+UBNmbNj8}wpP`H)m7$0sks%#O+XA6EgC2t+5F1R4UC$UWnV0eQ^X=2MN#)8TEjJGEnFjY)^q5=S8TL{en diff --git a/test.sh b/test.sh index 0b46800..d9f0a07 100644 --- a/test.sh +++ b/test.sh @@ -1,4 +1,5 @@ # /bin/bash # Usage: ./test.sh -pytest --verbose -vv \ No newline at end of file +# generate coverage file named "cov.xml" +python -m pytest --verbose -vv --cov=src --cov-report=term-missing --cov-report=xml:cov.xml \ No newline at end of file From 8938e5639004c7ce52fc5339470f35044d2c1080 Mon Sep 17 00:00:00 2001 From: dmccoystephenson Date: Fri, 10 Feb 2023 20:55:43 -0700 Subject: [PATCH 09/18] Added python and pip checks to run.sh script. --- run.sh | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/run.sh b/run.sh index 2d7c444..2665ed1 100644 --- a/run.sh +++ b/run.sh @@ -10,6 +10,16 @@ echo "Current version: $(cat version.txt)" # check that dependencies are installed echo "Checking dependencies" +if ! command -v python &> /dev/null +then + echo "Python could not be found. Download it from https://www.python.org/downloads/" + exit +fi +if ! command -v pip &> /dev/null +then + echo "Pip could not be found. Download it from https://pip.pypa.io/en/stable/installation/ or run 'python -m ensurepip' in a terminal" + exit +fi pip install pygame --pre --quiet pip install -r requirements.txt --quiet From b357045e4d88555b023de1721a24fd533ec64c6d Mon Sep 17 00:00:00 2001 From: dmccoystephenson Date: Fri, 10 Feb 2023 20:58:38 -0700 Subject: [PATCH 10/18] Cleaned up run.sh script. --- run.sh | 68 +++++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 44 insertions(+), 24 deletions(-) diff --git a/run.sh b/run.sh index 2665ed1..f272121 100644 --- a/run.sh +++ b/run.sh @@ -1,28 +1,48 @@ -# get the latest version of the code -echo "Pulling latest version of code from GitHub" -git pull +# /bin/bash +# Usage: ./run.sh -# print branch status -echo "Current branch: $(git branch --show-current)" +getLatest() { + # get the latest version of the code + echo "Pulling latest version of code from GitHub" + git pull +} -# read in and print version -echo "Current version: $(cat version.txt)" +printBranchStatus() { + # print the current branch + echo "Current branch: $(git branch --show-current)" +} -# check that dependencies are installed -echo "Checking dependencies" -if ! command -v python &> /dev/null -then - echo "Python could not be found. Download it from https://www.python.org/downloads/" - exit -fi -if ! command -v pip &> /dev/null -then - echo "Pip could not be found. Download it from https://pip.pypa.io/en/stable/installation/ or run 'python -m ensurepip' in a terminal" - exit -fi -pip install pygame --pre --quiet -pip install -r requirements.txt --quiet +printVersion() { + # print the current version + echo "Current version: $(cat version.txt)" +} -# start program -echo "Starting program" -python src/roam.py > output.txt \ No newline at end of file +checkDependencies() { + # check that dependencies are installed + echo "Checking dependencies" + if ! command -v python &> /dev/null + then + echo "Python could not be found. Download it from https://www.python.org/downloads/" + exit + fi + if ! command -v pip &> /dev/null + then + echo "Pip could not be found. Download it from https://pip.pypa.io/en/stable/installation/ or run 'python -m ensurepip' in a terminal" + exit + fi + pip install pygame --pre --quiet + pip install -r requirements.txt --quiet +} + +startProgram() { + # start program + echo "Starting program" + python src/roam.py > output.txt +} + +# main +getLatest +printBranchStatus +printVersion +checkDependencies +startProgram \ No newline at end of file From 643bc52067ae4385ad0f023e965330aaf4c8438a Mon Sep 17 00:00:00 2001 From: dmccoystephenson Date: Fri, 10 Feb 2023 21:04:12 -0700 Subject: [PATCH 11/18] Called tests in run.sh script. --- .devcontainer/devcontainer.json | 19 ------------------- run.sh | 12 ++++++++++++ 2 files changed, 12 insertions(+), 19 deletions(-) delete mode 100644 .devcontainer/devcontainer.json diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json deleted file mode 100644 index 009a80f..0000000 --- a/.devcontainer/devcontainer.json +++ /dev/null @@ -1,19 +0,0 @@ -// For format details, see https://aka.ms/devcontainer.json. For config options, see the -// README at: https://github.com/devcontainers/templates/tree/main/src/debian -{ - "name": "Debian", - // Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile - "image": "mcr.microsoft.com/devcontainers/base:bullseye" - - // Features to add to the dev container. More info: https://containers.dev/features. - // "features": {}, - - // Use 'forwardPorts' to make a list of ports inside the container available locally. - // "forwardPorts": [], - - // Configure tool-specific properties. - // "customizations": {}, - - // Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root. - // "remoteUser": "root" -} diff --git a/run.sh b/run.sh index f272121..8576c73 100644 --- a/run.sh +++ b/run.sh @@ -5,16 +5,19 @@ getLatest() { # get the latest version of the code echo "Pulling latest version of code from GitHub" git pull + echo "" } printBranchStatus() { # print the current branch echo "Current branch: $(git branch --show-current)" + echo "" } printVersion() { # print the current version echo "Current version: $(cat version.txt)" + echo "" } checkDependencies() { @@ -32,6 +35,14 @@ checkDependencies() { fi pip install pygame --pre --quiet pip install -r requirements.txt --quiet + echo "" +} + +runTests() { + # run tests + echo "Running tests" + python -m pytest + echo "" } startProgram() { @@ -45,4 +56,5 @@ getLatest printBranchStatus printVersion checkDependencies +runTests startProgram \ No newline at end of file From 64bce82cd0a32333dc34624baec3a7e935d33335 Mon Sep 17 00:00:00 2001 From: dmccoystephenson Date: Sun, 12 Feb 2023 21:54:23 -0700 Subject: [PATCH 12/18] Added showMiniMap config option toggleable with 'M' --- src/config/config.py | 3 +- src/screen/configScreen.py | 7 +++ src/screen/worldScreen.py | 89 ++++++++++++++++++++++++++++---------- 3 files changed, 75 insertions(+), 24 deletions(-) diff --git a/src/config/config.py b/src/config/config.py index ba1c116..223b496 100644 --- a/src/config/config.py +++ b/src/config/config.py @@ -25,4 +25,5 @@ def __init__(self): self.fullscreen = False self.autoEatFoodInInventory = True self.generateMapImage = True - self.removeDeadEntities = True \ No newline at end of file + self.removeDeadEntities = True + self.showMiniMap = True \ No newline at end of file diff --git a/src/screen/configScreen.py b/src/screen/configScreen.py index a010a9c..8a79110 100644 --- a/src/screen/configScreen.py +++ b/src/screen/configScreen.py @@ -46,6 +46,10 @@ def toggleGenerateMapImage(self): def toggleRemoveDeadEntities(self): self.config.removeDeadEntities = not self.config.removeDeadEntities sleep(0.1) + + def toggleShowMiniMap(self): + self.config.showMiniMap = not self.config.showMiniMap + sleep(0.1) def drawMenuButtons(self): # draw buttons in red or green depending on config option value @@ -71,6 +75,9 @@ def drawMenuButtons(self): ypos = ypos + height + margin color = (0,255,0) if self.config.removeDeadEntities else (255,0,0) self.graphik.drawButton(xpos, ypos, width, height, (255,255,255), color, 30, "remove dead entities", self.toggleRemoveDeadEntities) + ypos = ypos + height + margin + color = (0,255,0) if self.config.showMiniMap else (255,0,0) + self.graphik.drawButton(xpos, ypos, width, height, (255,255,255), color, 30, "show minimap", self.toggleShowMiniMap) self.drawBackButton() diff --git a/src/screen/worldScreen.py b/src/screen/worldScreen.py index 595e1cd..ba201d4 100644 --- a/src/screen/worldScreen.py +++ b/src/screen/worldScreen.py @@ -53,6 +53,9 @@ def __init__(self, graphik: Graphik, config: Config, status: Status, tickCounter self.changeScreen = False self.roomJsonReaderWriter = RoomJsonReaderWriter(self.config.gridSize, self.graphik, self.tickCounter, self.config) self.mapImageUpdater = MapImageUpdater(self.tickCounter, self.config) + self.minimapScaleFactor = 0.10 + self.minimapX = 5 + self.minimapY = 5 def initialize(self): self.map = Map(self.config.gridSize, self.graphik, self.tickCounter, self.config) @@ -217,8 +220,6 @@ def changeRooms(self): playerLocation = self.getLocationOfPlayer() self.currentRoom.removeEntity(self.player) - - self.saveCurrentRoomToFile() room = self.map.getRoom(x, y) if room == -1: @@ -305,6 +306,7 @@ def movePlayer(self, direction: int): if newLocation == -1: # we're at a border self.changeRooms() + self.save() return if self.locationContainsSolidEntity(newLocation): @@ -522,6 +524,17 @@ def handleKeyDownEvent(self, key): elif key == pygame.K_F3: # toggle debug mode self.config.debug = not self.config.debug + elif key == pygame.K_m: + # toggle minimap + self.config.showMiniMap = not self.config.showMiniMap + elif key == pygame.K_EQUALS: + # increase minimap scale factor + if self.minimapScaleFactor < 1.0: + self.minimapScaleFactor += 0.1 + elif key == pygame.K_MINUS: + # decrease minimap scale factor + if self.minimapScaleFactor > 0: + self.minimapScaleFactor -= 0.1 def handleKeyUpEvent(self, key): if (key == pygame.K_w or key == pygame.K_UP) and self.player.getDirection() == 0: @@ -563,7 +576,7 @@ def respawnPlayer(self): self.currentRoom.removeEntity(self.player) self.map.getRoom(0, 0).addEntity(self.player) - self.saveCurrentRoomToFile() + self.save() self.currentRoom = self.map.getRoom(0, 0) self.player.energy = self.player.targetEnergy @@ -629,23 +642,41 @@ def isCurrentRoomSavedAsPNG(self): def saveCurrentRoomAsPNG(self): if not os.path.exists(self.config.pathToSaveDirectory + "/roompngs"): os.makedirs(self.config.pathToSaveDirectory + "/roompngs") + + # remove player + locationOfPlayer = self.currentRoom.getGrid().getLocation(self.player.getLocationID()) + self.currentRoom.removeEntity(self.player) + self.currentRoom.draw(self.locationWidth, self.locationHeight) + path = self.config.pathToSaveDirectory + "/roompngs/" + str(self.currentRoom.getX()) + "_" + str(self.currentRoom.getY()) + ".png" self.captureScreen(path, (0, 0), (self.graphik.getGameDisplay().get_width(), self.graphik.getGameDisplay().get_height())) + # add player back + self.currentRoom.addEntityToLocation(self.player, locationOfPlayer) + + def drawMiniMap(self): + # if map image doesn't exist, return + if not os.path.isfile(self.config.pathToSaveDirectory + "/mapImage.png"): + return + + # get mapImage.png for current save + mapImage = pygame.image.load(self.config.pathToSaveDirectory + "/mapImage.png") + + # scale with respect to size of display + mapImage = pygame.transform.scale(mapImage, (self.graphik.getGameDisplay().get_width() * self.minimapScaleFactor, self.graphik.getGameDisplay().get_height() * self.minimapScaleFactor)) + + # draw rectangle + backgroundColor = (200, 200, 200) + self.graphik.drawRectangle(self.minimapX, self.minimapY, mapImage.get_width() + 20, mapImage.get_height() + 20, backgroundColor) + + # blit in top left corner with 10px padding + self.graphik.getGameDisplay().blit(mapImage, (self.minimapX + 10, self.minimapY + 10)) + def draw(self): self.graphik.getGameDisplay().fill(self.currentRoom.getBackgroundColor()) if self.config.generateMapImage and not self.isCurrentRoomSavedAsPNG(): - # remove player - locationOfPlayer = self.currentRoom.getGrid().getLocation(self.player.getLocationID()) - self.currentRoom.removeEntity(self.player) - self.currentRoom.draw(self.locationWidth, self.locationHeight) - - # save room as png self.saveCurrentRoomAsPNG() - - # add player back - self.currentRoom.addEntityToLocation(self.player, locationOfPlayer) self.currentRoom.draw(self.locationWidth, self.locationHeight) self.status.draw() @@ -706,7 +737,14 @@ def draw(self): # draw room coordinates in top left corner coordinatesText = "(" + str(self.currentRoom.getX()) + ", " + str(self.currentRoom.getY() * -1) + ")" - self.graphik.drawText(coordinatesText, 30, 20, 20, (255,255,255)) + ypos = 20 + if self.config.showMiniMap: + # move to bottom left + ypos = self.graphik.getGameDisplay().get_height() - 40 + self.graphik.drawText(coordinatesText, 30, ypos, 20, (255,255,255)) + + if self.config.generateMapImage and self.config.showMiniMap and self.minimapScaleFactor > 0: + self.drawMiniMap() pygame.display.update() @@ -876,6 +914,19 @@ def checkForLivingEntityDeaths(self): if self.config.debug: print("Removed " + livingEntity.getName() + " from room " + self.currentRoom.getName() + " because it had 0 energy") + def save(self): + self.saveCurrentRoomToFile() + self.savePlayerLocationToFile() + self.savePlayerAttributesToFile() + self.savePlayerInventoryToFile() + self.stats.save() + self.tickCounter.save() + + if self.config.generateMapImage: + if not self.isCurrentRoomSavedAsPNG(): + self.saveCurrentRoomAsPNG() + self.mapImageUpdater.updateMapImage() + def run(self): while not self.changeScreen: for event in pygame.event.get(): @@ -912,7 +963,7 @@ def run(self): newRoom = self.map.getRoom(newRoomX, newRoomY) if newRoom == -1: # attempt to load room if file exists, otherwise generate new room - nextRoomPath = self.config.pathToSaveDirectory + "/rooms/room_" + str(x) + "_" + str(y) + ".json" + nextRoomPath = self.config.pathToSaveDirectory + "/rooms/room_" + str(newRoomX) + "_" + str(newRoomY) + ".json" if os.path.exists(nextRoomPath): roomJsonReaderWriter = RoomJsonReaderWriter(self.config.gridSize, self.graphik, self.tickCounter) newRoom = roomJsonReaderWriter.loadRoom(nextRoomPath) @@ -977,15 +1028,7 @@ def run(self): if not os.path.exists(self.config.pathToSaveDirectory): os.makedirs(self.config.pathToSaveDirectory) - self.saveCurrentRoomToFile() - self.savePlayerLocationToFile() - self.savePlayerAttributesToFile() - self.savePlayerInventoryToFile() - self.stats.save() - self.tickCounter.save() - - if self.config.generateMapImage: - self.mapImageUpdater.updateMapImage() + self.save() self.changeScreen = False return self.nextScreen \ No newline at end of file From 02c39ebf14a5c72a268bfc2c108bca26a8324c5b Mon Sep 17 00:00:00 2001 From: dmccoystephenson Date: Sat, 18 Feb 2023 17:41:41 -0700 Subject: [PATCH 13/18] Moved image assets to 'assets/images' --- assets/{ => images}/apple.png | Bin assets/{ => images}/banana.png | Bin assets/{ => images}/bear.png | Bin assets/{ => images}/bearOnReproductionCooldown.png | Bin assets/{ => images}/chicken.png | Bin .../{ => images}/chickenOnReproductionCooldown.png | Bin assets/{ => images}/coalOre.png | Bin assets/{ => images}/grass.png | Bin assets/{ => images}/ironOre.png | Bin assets/{ => images}/jungleWood.png | Bin assets/{ => images}/leaves.png | Bin assets/{ => images}/oakWood.png | Bin assets/{ => images}/player_down.png | Bin assets/{ => images}/player_left.png | Bin assets/{ => images}/player_right.png | Bin assets/{ => images}/player_up.png | Bin assets/{ => images}/stone.png | Bin src/entity/apple.py | 2 +- src/entity/banana.py | 2 +- src/entity/coalOre.py | 2 +- src/entity/grass.py | 2 +- src/entity/ironOre.py | 2 +- src/entity/jungleWood.py | 2 +- src/entity/leaves.py | 2 +- src/entity/living/bear.py | 2 +- src/entity/living/chicken.py | 2 +- src/entity/oakWood.py | 2 +- src/entity/stone.py | 2 +- src/player/player.py | 10 +++++----- src/roam.py | 2 +- src/world/room.py | 12 ++++++------ 31 files changed, 23 insertions(+), 23 deletions(-) rename assets/{ => images}/apple.png (100%) rename assets/{ => images}/banana.png (100%) rename assets/{ => images}/bear.png (100%) rename assets/{ => images}/bearOnReproductionCooldown.png (100%) rename assets/{ => images}/chicken.png (100%) rename assets/{ => images}/chickenOnReproductionCooldown.png (100%) rename assets/{ => images}/coalOre.png (100%) rename assets/{ => images}/grass.png (100%) rename assets/{ => images}/ironOre.png (100%) rename assets/{ => images}/jungleWood.png (100%) rename assets/{ => images}/leaves.png (100%) rename assets/{ => images}/oakWood.png (100%) rename assets/{ => images}/player_down.png (100%) rename assets/{ => images}/player_left.png (100%) rename assets/{ => images}/player_right.png (100%) rename assets/{ => images}/player_up.png (100%) rename assets/{ => images}/stone.png (100%) diff --git a/assets/apple.png b/assets/images/apple.png similarity index 100% rename from assets/apple.png rename to assets/images/apple.png diff --git a/assets/banana.png b/assets/images/banana.png similarity index 100% rename from assets/banana.png rename to assets/images/banana.png diff --git a/assets/bear.png b/assets/images/bear.png similarity index 100% rename from assets/bear.png rename to assets/images/bear.png diff --git a/assets/bearOnReproductionCooldown.png b/assets/images/bearOnReproductionCooldown.png similarity index 100% rename from assets/bearOnReproductionCooldown.png rename to assets/images/bearOnReproductionCooldown.png diff --git a/assets/chicken.png b/assets/images/chicken.png similarity index 100% rename from assets/chicken.png rename to assets/images/chicken.png diff --git a/assets/chickenOnReproductionCooldown.png b/assets/images/chickenOnReproductionCooldown.png similarity index 100% rename from assets/chickenOnReproductionCooldown.png rename to assets/images/chickenOnReproductionCooldown.png diff --git a/assets/coalOre.png b/assets/images/coalOre.png similarity index 100% rename from assets/coalOre.png rename to assets/images/coalOre.png diff --git a/assets/grass.png b/assets/images/grass.png similarity index 100% rename from assets/grass.png rename to assets/images/grass.png diff --git a/assets/ironOre.png b/assets/images/ironOre.png similarity index 100% rename from assets/ironOre.png rename to assets/images/ironOre.png diff --git a/assets/jungleWood.png b/assets/images/jungleWood.png similarity index 100% rename from assets/jungleWood.png rename to assets/images/jungleWood.png diff --git a/assets/leaves.png b/assets/images/leaves.png similarity index 100% rename from assets/leaves.png rename to assets/images/leaves.png diff --git a/assets/oakWood.png b/assets/images/oakWood.png similarity index 100% rename from assets/oakWood.png rename to assets/images/oakWood.png diff --git a/assets/player_down.png b/assets/images/player_down.png similarity index 100% rename from assets/player_down.png rename to assets/images/player_down.png diff --git a/assets/player_left.png b/assets/images/player_left.png similarity index 100% rename from assets/player_left.png rename to assets/images/player_left.png diff --git a/assets/player_right.png b/assets/images/player_right.png similarity index 100% rename from assets/player_right.png rename to assets/images/player_right.png diff --git a/assets/player_up.png b/assets/images/player_up.png similarity index 100% rename from assets/player_up.png rename to assets/images/player_up.png diff --git a/assets/stone.png b/assets/images/stone.png similarity index 100% rename from assets/stone.png rename to assets/images/stone.png diff --git a/src/entity/apple.py b/src/entity/apple.py index 0741df8..c74bf2c 100644 --- a/src/entity/apple.py +++ b/src/entity/apple.py @@ -6,7 +6,7 @@ # @since August 8th, 2022 class Apple(Food): def __init__(self): - Food.__init__(self, "Apple", "assets/apple.png", random.randrange(5, 11)) + Food.__init__(self, "Apple", "assets/images/apple.png", random.randrange(5, 11)) self.solid = False def isSolid(self): diff --git a/src/entity/banana.py b/src/entity/banana.py index 0529088..07b759d 100644 --- a/src/entity/banana.py +++ b/src/entity/banana.py @@ -6,7 +6,7 @@ # @since January 28th, 2023 class Banana(Food): def __init__(self): - Food.__init__(self, "Banana", "assets/banana.png", random.randrange(10, 20)) + Food.__init__(self, "Banana", "assets/images/banana.png", random.randrange(10, 20)) self.solid = False def isSolid(self): diff --git a/src/entity/coalOre.py b/src/entity/coalOre.py index 485d724..7a2620f 100644 --- a/src/entity/coalOre.py +++ b/src/entity/coalOre.py @@ -6,7 +6,7 @@ # @since August 18th, 2022 class CoalOre(DrawableEntity): def __init__(self): - DrawableEntity.__init__(self, "Coal Ore", "assets/coalOre.png") + DrawableEntity.__init__(self, "Coal Ore", "assets/images/coalOre.png") self.solid = True def isSolid(self): diff --git a/src/entity/grass.py b/src/entity/grass.py index 0b2a0cb..f2d5beb 100644 --- a/src/entity/grass.py +++ b/src/entity/grass.py @@ -5,7 +5,7 @@ # @since August 8th, 2022 class Grass(DrawableEntity): def __init__(self): - DrawableEntity.__init__(self, "Grass", "assets/grass.png") + DrawableEntity.__init__(self, "Grass", "assets/images/grass.png") self.solid = False def isSolid(self): diff --git a/src/entity/ironOre.py b/src/entity/ironOre.py index e29a021..5aaf6a7 100644 --- a/src/entity/ironOre.py +++ b/src/entity/ironOre.py @@ -6,7 +6,7 @@ # @since August 18th, 2022 class IronOre(DrawableEntity): def __init__(self): - DrawableEntity.__init__(self, "Iron Ore", "assets/ironOre.png") + DrawableEntity.__init__(self, "Iron Ore", "assets/images/ironOre.png") self.solid = True def isSolid(self): diff --git a/src/entity/jungleWood.py b/src/entity/jungleWood.py index b120dce..27255d8 100644 --- a/src/entity/jungleWood.py +++ b/src/entity/jungleWood.py @@ -5,7 +5,7 @@ # @since August 8th, 2022 class JungleWood(DrawableEntity): def __init__(self): - DrawableEntity.__init__(self, "Jungle Wood", "assets/jungleWood.png") + DrawableEntity.__init__(self, "Jungle Wood", "assets/images/jungleWood.png") self.solid = True def isSolid(self): diff --git a/src/entity/leaves.py b/src/entity/leaves.py index 3db6eb5..bf08fde 100644 --- a/src/entity/leaves.py +++ b/src/entity/leaves.py @@ -5,7 +5,7 @@ # @since August 8th, 2022 class Leaves(DrawableEntity): def __init__(self): - DrawableEntity.__init__(self, "Leaves", "assets/leaves.png") + DrawableEntity.__init__(self, "Leaves", "assets/images/leaves.png") self.solid = False def isSolid(self): diff --git a/src/entity/living/bear.py b/src/entity/living/bear.py index 17a04e0..ea85cf5 100644 --- a/src/entity/living/bear.py +++ b/src/entity/living/bear.py @@ -8,7 +8,7 @@ # @since December 24th, 2022 class Bear(LivingEntity): def __init__(self, tickCreated): - LivingEntity.__init__(self, "Bear", "assets/bear.png", random.randrange(20, 30), [Chicken, Player], tickCreated) + LivingEntity.__init__(self, "Bear", "assets/images/bear.png", random.randrange(20, 30), [Chicken, Player], tickCreated) self.solid = False def isSolid(self): diff --git a/src/entity/living/chicken.py b/src/entity/living/chicken.py index 6cc6a4f..67e91f5 100644 --- a/src/entity/living/chicken.py +++ b/src/entity/living/chicken.py @@ -7,7 +7,7 @@ # @since July 7th, 2022 class Chicken(LivingEntity): def __init__(self, tickCreated): - LivingEntity.__init__(self, "Chicken", "assets/chicken.png", random.randrange(20, 30), [Grass], tickCreated) + LivingEntity.__init__(self, "Chicken", "assets/images/chicken.png", random.randrange(20, 30), [Grass], tickCreated) self.solid = False def isSolid(self): diff --git a/src/entity/oakWood.py b/src/entity/oakWood.py index d2f8003..f7d79ec 100644 --- a/src/entity/oakWood.py +++ b/src/entity/oakWood.py @@ -5,7 +5,7 @@ # @since August 8th, 2022 class OakWood(DrawableEntity): def __init__(self): - DrawableEntity.__init__(self, "Oak Wood", "assets/oakWood.png") + DrawableEntity.__init__(self, "Oak Wood", "assets/images/oakWood.png") self.solid = True def isSolid(self): diff --git a/src/entity/stone.py b/src/entity/stone.py index e3a0490..650721f 100644 --- a/src/entity/stone.py +++ b/src/entity/stone.py @@ -6,7 +6,7 @@ # @since August 18th, 2022 class Stone(DrawableEntity): def __init__(self): - DrawableEntity.__init__(self, "Stone", "assets/stone.png") + DrawableEntity.__init__(self, "Stone", "assets/images/stone.png") self.solid = True def isSolid(self): diff --git a/src/player/player.py b/src/player/player.py index ae2cb22..389ec22 100644 --- a/src/player/player.py +++ b/src/player/player.py @@ -9,7 +9,7 @@ # @since August 8th, 2022 class Player(LivingEntity): def __init__(self, tickCreated): - LivingEntity.__init__(self, "Player", "assets/player_down.png", 100, [Apple, Banana, Chicken], tickCreated) + LivingEntity.__init__(self, "Player", "assets/images/player_down.png", 100, [Apple, Banana, Chicken], tickCreated) self.direction = -1 # -1 when not moving self.lastDirection = -1 self.inventory = Inventory() @@ -32,13 +32,13 @@ def setDirection(self, direction): self.direction = direction if self.direction == 0: - self.imagePath = "assets/player_up.png" + self.imagePath = "assets/images/player_up.png" elif self.direction == 1: - self.imagePath = "assets/player_left.png" + self.imagePath = "assets/images/player_left.png" elif self.direction == 2: - self.imagePath = "assets/player_down.png" + self.imagePath = "assets/images/player_down.png" elif self.direction == 3: - self.imagePath = "assets/player_right.png" + self.imagePath = "assets/images/player_right.png" def getLastDirection(self): return self.lastDirection diff --git a/src/roam.py b/src/roam.py index 670a55a..3514026 100644 --- a/src/roam.py +++ b/src/roam.py @@ -19,7 +19,7 @@ class Roam: def __init__(self, config: Config): pygame.init() - pygame.display.set_icon(pygame.image.load("assets/player_down.png")) + pygame.display.set_icon(pygame.image.load("assets/images/player_down.png")) self.running = True self.config = config pygame.display.set_caption("Roam" + " (" + config.pathToSaveDirectory + ")") diff --git a/src/world/room.py b/src/world/room.py index 8486d38..dfd236c 100644 --- a/src/world/room.py +++ b/src/world/room.py @@ -159,9 +159,9 @@ def reproduceLivingEntities(self, tick): # reset image if isinstance(entity, Chicken): - entity.setImagePath("assets/chicken.png") + entity.setImagePath("assets/images/chicken.png") elif isinstance(entity, Bear): - entity.setImagePath("assets/bear.png") + entity.setImagePath("assets/images/bear.png") # throw dice if random.randrange(1, 101) > 1: # 1% chance @@ -182,11 +182,11 @@ def reproduceLivingEntities(self, tick): entity.setTickLastReproduced(tick) targetEntity.setTickLastReproduced(tick) if isinstance(entity, Chicken): - entity.setImagePath("assets/chickenOnReproductionCooldown.png") - targetEntity.setImagePath("assets/chickenOnReproductionCooldown.png") + entity.setImagePath("assets/images/chickenOnReproductionCooldown.png") + targetEntity.setImagePath("assets/images/chickenOnReproductionCooldown.png") if isinstance(entity, Bear): - entity.setImagePath("assets/bearOnReproductionCooldown.png") - targetEntity.setImagePath("assets/bearOnReproductionCooldown.png") + entity.setImagePath("assets/images/bearOnReproductionCooldown.png") + targetEntity.setImagePath("assets/images/bearOnReproductionCooldown.png") # set new entity's energy to 10% of average of parent's energy newEntity.setEnergy((entity.getEnergy() + targetEntity.getEnergy())/2 * 0.1) From f586c064532b042bf1365baec2ee277fc8158167 Mon Sep 17 00:00:00 2001 From: dmccoystephenson Date: Sat, 18 Feb 2023 19:58:23 -0700 Subject: [PATCH 14/18] Removed generateMapImage config option and printed a warning if ticks take too long to complete. --- src/config/config.py | 1 - src/mapimage/mapImageGenerator.py | 14 +++++++++----- src/screen/configScreen.py | 7 ------- src/screen/worldScreen.py | 8 ++++---- src/world/tickCounter.py | 4 ++++ 5 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/config/config.py b/src/config/config.py index 223b496..55ab678 100644 --- a/src/config/config.py +++ b/src/config/config.py @@ -24,6 +24,5 @@ def __init__(self): self.debug = True self.fullscreen = False self.autoEatFoodInInventory = True - self.generateMapImage = True self.removeDeadEntities = True self.showMiniMap = True \ No newline at end of file diff --git a/src/mapimage/mapImageGenerator.py b/src/mapimage/mapImageGenerator.py index a32b4e5..ee0f4c4 100644 --- a/src/mapimage/mapImageGenerator.py +++ b/src/mapimage/mapImageGenerator.py @@ -8,6 +8,7 @@ class MapImageGenerator: def __init__(self, config): self.config = config + self.numRoomsInEachDirection = 5 self.roomSizeInPixels = 100 self.mapImageSizeInPixels = (self.numRoomsInEachDirection * 2 + 1) * self.roomSizeInPixels @@ -37,11 +38,13 @@ def mapImageExists(self): return os.path.exists(self.mapImagePath) def getExistingMapImage(self): - print("Loading existing map image") + if (self.config.debug): + print("Loading existing map image") return Image.open(self.mapImagePath) def createNewMapImage(self): - print("Creating new map image") + if (self.config.debug): + print("Creating new map image") return Image.new("RGB", (self.mapImageSizeInPixels, self.mapImageSizeInPixels), "white") def getRoomImages(self): @@ -76,6 +79,7 @@ def pasteRoomImagesAtCorrectCoordinates(self, roomImages): else: numOutOfBounds += 1 - print("Images pasted: " + str(numPasted)) - print("Images out of bounds: " + str(numOutOfBounds)) - print("Percent of map updated: " + str(int(numPasted / (self.numRoomsInEachDirection * 2 + 1) ** 2 * 100)) + "%") \ No newline at end of file + if (self.config.debug): + print("Images pasted: " + str(numPasted)) + print("Images out of bounds: " + str(numOutOfBounds)) + print("Percent of map updated: " + str(int(numPasted / (self.numRoomsInEachDirection * 2 + 1) ** 2 * 100)) + "%") \ No newline at end of file diff --git a/src/screen/configScreen.py b/src/screen/configScreen.py index 8a79110..9716b48 100644 --- a/src/screen/configScreen.py +++ b/src/screen/configScreen.py @@ -39,10 +39,6 @@ def toggleAutoEatFoodInInventory(self): self.config.autoEatFoodInInventory = not self.config.autoEatFoodInInventory sleep(0.1) - def toggleGenerateMapImage(self): - self.config.generateMapImage = not self.config.generateMapImage - sleep(0.1) - def toggleRemoveDeadEntities(self): self.config.removeDeadEntities = not self.config.removeDeadEntities sleep(0.1) @@ -70,9 +66,6 @@ def drawMenuButtons(self): color = (0,255,0) if self.config.autoEatFoodInInventory else (255,0,0) self.graphik.drawButton(xpos, ypos, width, height, (255,255,255), color, 30, "auto eat in inventory", self.toggleAutoEatFoodInInventory) ypos = ypos + height + margin - color = (0,255,0) if self.config.generateMapImage else (255,0,0) - self.graphik.drawButton(xpos, ypos, width, height, (255,255,255), color, 30, "generate map image", self.toggleGenerateMapImage) - ypos = ypos + height + margin color = (0,255,0) if self.config.removeDeadEntities else (255,0,0) self.graphik.drawButton(xpos, ypos, width, height, (255,255,255), color, 30, "remove dead entities", self.toggleRemoveDeadEntities) ypos = ypos + height + margin diff --git a/src/screen/worldScreen.py b/src/screen/worldScreen.py index ba201d4..afa8c7a 100644 --- a/src/screen/worldScreen.py +++ b/src/screen/worldScreen.py @@ -675,7 +675,7 @@ def drawMiniMap(self): def draw(self): self.graphik.getGameDisplay().fill(self.currentRoom.getBackgroundColor()) - if self.config.generateMapImage and not self.isCurrentRoomSavedAsPNG(): + if self.config.showMiniMap and not self.isCurrentRoomSavedAsPNG(): self.saveCurrentRoomAsPNG() self.currentRoom.draw(self.locationWidth, self.locationHeight) @@ -743,7 +743,7 @@ def draw(self): ypos = self.graphik.getGameDisplay().get_height() - 40 self.graphik.drawText(coordinatesText, 30, ypos, 20, (255,255,255)) - if self.config.generateMapImage and self.config.showMiniMap and self.minimapScaleFactor > 0: + if self.config.showMiniMap and self.minimapScaleFactor > 0: self.drawMiniMap() pygame.display.update() @@ -922,7 +922,7 @@ def save(self): self.stats.save() self.tickCounter.save() - if self.config.generateMapImage: + if self.config.showMiniMap: if not self.isCurrentRoomSavedAsPNG(): self.saveCurrentRoomAsPNG() self.mapImageUpdater.updateMapImage() @@ -1021,7 +1021,7 @@ def run(self): time.sleep(3) self.respawnPlayer() - if self.config.generateMapImage: + if self.config.showMiniMap: self.mapImageUpdater.updateIfCooldownOver() # create save directory if it doesn't exist diff --git a/src/world/tickCounter.py b/src/world/tickCounter.py index 1cfa58f..1a7f791 100644 --- a/src/world/tickCounter.py +++ b/src/world/tickCounter.py @@ -20,6 +20,10 @@ def incrementTick(self): self.updateMeasuredTicksPerSecond() def updateMeasuredTicksPerSecond(self): + millisecondsSinceLastTick = (time.time() - self.lastTimestamp) * 1000 + warningThreshold = 500 + if millisecondsSinceLastTick > warningThreshold: + print("WARNING: Tick took " + str(int(millisecondsSinceLastTick)) + " milliseconds to complete. (tick=" + str(self.tick) + ")") currentTimestamp = time.time() timeElapsed = currentTimestamp - self.lastTimestamp self.lastTimestamp = currentTimestamp From 1c2d31610e57503b2b0215ae9737cc1eb3febb3b Mon Sep 17 00:00:00 2001 From: dmccoystephenson Date: Sun, 19 Feb 2023 18:46:19 -0700 Subject: [PATCH 15/18] Fixed tests not passing due to assets directory reorganization. --- tests/entity/living/test_bear.py | 2 +- tests/entity/living/test_chicken.py | 2 +- tests/entity/test_apple.py | 2 +- tests/entity/test_banana.py | 2 +- tests/entity/test_coalOre.py | 2 +- tests/entity/test_grass.py | 2 +- tests/entity/test_ironOre.py | 2 +- tests/entity/test_jungleWood.py | 2 +- tests/entity/test_leaves.py | 2 +- tests/entity/test_oakWood.py | 2 +- tests/entity/test_stone.py | 2 +- tests/player/test_player.py | 8 ++++---- 12 files changed, 15 insertions(+), 15 deletions(-) diff --git a/tests/entity/living/test_bear.py b/tests/entity/living/test_bear.py index c54dd82..84bd71c 100644 --- a/tests/entity/living/test_bear.py +++ b/tests/entity/living/test_bear.py @@ -5,5 +5,5 @@ def test_initialization(): assert(bear.name == "Bear") assert(bear.getTickCreated() == 0) - assert(bear.getImagePath() == "assets/bear.png") + assert(bear.getImagePath() == "assets/images/bear.png") assert(bear.isSolid() == False) \ No newline at end of file diff --git a/tests/entity/living/test_chicken.py b/tests/entity/living/test_chicken.py index 18b2cbc..fd7a921 100644 --- a/tests/entity/living/test_chicken.py +++ b/tests/entity/living/test_chicken.py @@ -5,7 +5,7 @@ def test_initialization(): assert(chicken.name == "Chicken") assert(chicken.getTickCreated() == 0) - assert(chicken.getImagePath() == "assets/chicken.png") + assert(chicken.getImagePath() == "assets/images/chicken.png") assert(chicken.isSolid() == False) def test_can_eat(): diff --git a/tests/entity/test_apple.py b/tests/entity/test_apple.py index 958694f..a226ffe 100644 --- a/tests/entity/test_apple.py +++ b/tests/entity/test_apple.py @@ -4,5 +4,5 @@ def test_initialization(): apple = Apple() assert(apple.name == "Apple") - assert(apple.getImagePath() == "assets/apple.png") + assert(apple.getImagePath() == "assets/images/apple.png") assert(apple.isSolid() == False) \ No newline at end of file diff --git a/tests/entity/test_banana.py b/tests/entity/test_banana.py index d671eaa..4122662 100644 --- a/tests/entity/test_banana.py +++ b/tests/entity/test_banana.py @@ -4,5 +4,5 @@ def test_initialization(): banana = Banana() assert(banana.name == "Banana") - assert(banana.getImagePath() == "assets/banana.png") + assert(banana.getImagePath() == "assets/images/banana.png") assert(banana.isSolid() == False) \ No newline at end of file diff --git a/tests/entity/test_coalOre.py b/tests/entity/test_coalOre.py index de1b64a..d3e9acd 100644 --- a/tests/entity/test_coalOre.py +++ b/tests/entity/test_coalOre.py @@ -4,5 +4,5 @@ def test_initialization(): coalore = CoalOre() assert(coalore.name == "Coal Ore") - assert(coalore.getImagePath() == "assets/coalOre.png") + assert(coalore.getImagePath() == "assets/images/coalOre.png") assert(coalore.isSolid() == True) \ No newline at end of file diff --git a/tests/entity/test_grass.py b/tests/entity/test_grass.py index 78728ed..6852cc7 100644 --- a/tests/entity/test_grass.py +++ b/tests/entity/test_grass.py @@ -4,5 +4,5 @@ def test_initialization(): grass = Grass() assert(grass.name == "Grass") - assert(grass.getImagePath() == "assets/grass.png") + assert(grass.getImagePath() == "assets/images/grass.png") assert(grass.isSolid() == False) \ No newline at end of file diff --git a/tests/entity/test_ironOre.py b/tests/entity/test_ironOre.py index 6662e25..5cc912e 100644 --- a/tests/entity/test_ironOre.py +++ b/tests/entity/test_ironOre.py @@ -4,5 +4,5 @@ def test_initialization(): ironore = IronOre() assert(ironore.name == "Iron Ore") - assert(ironore.getImagePath() == "assets/ironOre.png") + assert(ironore.getImagePath() == "assets/images/ironOre.png") assert(ironore.isSolid() == True) \ No newline at end of file diff --git a/tests/entity/test_jungleWood.py b/tests/entity/test_jungleWood.py index 73cb538..40d28e5 100644 --- a/tests/entity/test_jungleWood.py +++ b/tests/entity/test_jungleWood.py @@ -4,5 +4,5 @@ def test_initialization(): junglewood = JungleWood() assert(junglewood.name == "Jungle Wood") - assert(junglewood.getImagePath() == "assets/jungleWood.png") + assert(junglewood.getImagePath() == "assets/images/jungleWood.png") assert(junglewood.isSolid() == True) \ No newline at end of file diff --git a/tests/entity/test_leaves.py b/tests/entity/test_leaves.py index e2b02de..974652f 100644 --- a/tests/entity/test_leaves.py +++ b/tests/entity/test_leaves.py @@ -4,5 +4,5 @@ def test_initialization(): leaves = Leaves() assert(leaves.name == "Leaves") - assert(leaves.getImagePath() == "assets/leaves.png") + assert(leaves.getImagePath() == "assets/images/leaves.png") assert(leaves.isSolid() == False) \ No newline at end of file diff --git a/tests/entity/test_oakWood.py b/tests/entity/test_oakWood.py index 8069b16..9419bf1 100644 --- a/tests/entity/test_oakWood.py +++ b/tests/entity/test_oakWood.py @@ -4,5 +4,5 @@ def test_initialization(): oakwood = OakWood() assert(oakwood.name == "Oak Wood") - assert(oakwood.getImagePath() == "assets/oakWood.png") + assert(oakwood.getImagePath() == "assets/images/oakWood.png") assert(oakwood.isSolid() == True) \ No newline at end of file diff --git a/tests/entity/test_stone.py b/tests/entity/test_stone.py index 322ed34..c5b06fd 100644 --- a/tests/entity/test_stone.py +++ b/tests/entity/test_stone.py @@ -4,5 +4,5 @@ def test_initialization(): stone = Stone() assert(stone.name == "Stone") - assert(stone.getImagePath() == "assets/stone.png") + assert(stone.getImagePath() == "assets/images/stone.png") assert(stone.isSolid() == True) \ No newline at end of file diff --git a/tests/player/test_player.py b/tests/player/test_player.py index 8358a7b..7cd3be1 100644 --- a/tests/player/test_player.py +++ b/tests/player/test_player.py @@ -34,7 +34,7 @@ def test_set_direction_up(): # check assert(playerInstance.getDirection() == 0) assert(playerInstance.getLastDirection() == -1) - assert(playerInstance.imagePath == "assets/player_up.png") + assert(playerInstance.imagePath == "assets/images/player_up.png") def test_set_direction_left(): # prepare @@ -46,7 +46,7 @@ def test_set_direction_left(): # check assert(playerInstance.getDirection() == 1) assert(playerInstance.getLastDirection() == -1) - assert(playerInstance.imagePath == "assets/player_left.png") + assert(playerInstance.imagePath == "assets/images/player_left.png") def test_set_direction_down(): # prepare @@ -58,7 +58,7 @@ def test_set_direction_down(): # check assert(playerInstance.getDirection() == 2) assert(playerInstance.getLastDirection() == -1) - assert(playerInstance.imagePath == "assets/player_down.png") + assert(playerInstance.imagePath == "assets/images/player_down.png") def test_set_direction_right(): # prepare @@ -70,7 +70,7 @@ def test_set_direction_right(): # check assert(playerInstance.getDirection() == 3) assert(playerInstance.getLastDirection() == -1) - assert(playerInstance.imagePath == "assets/player_right.png") + assert(playerInstance.imagePath == "assets/images/player_right.png") def test_set_gathering(): # prepare From 33f039e28ed28623d029c189c89c5985e4db3196 Mon Sep 17 00:00:00 2001 From: dmccoystephenson Date: Sun, 26 Feb 2023 20:31:48 -0700 Subject: [PATCH 16/18] Added format script & reformatted project files. --- format.sh | 4 + src/config/config.py | 10 +- src/entity/apple.py | 8 +- src/entity/banana.py | 10 +- src/entity/coalOre.py | 5 +- src/entity/drawableEntity.py | 6 +- src/entity/food.py | 4 +- src/entity/grass.py | 2 +- src/entity/ironOre.py | 5 +- src/entity/jungleWood.py | 4 +- src/entity/leaves.py | 4 +- src/entity/living/bear.py | 11 +- src/entity/living/chicken.py | 11 +- src/entity/living/livingEntity.py | 20 +- src/entity/oakWood.py | 4 +- src/entity/stone.py | 5 +- src/inventory/inventory.py | 35 +- src/inventory/inventoryJsonReaderWriter.py | 93 +-- src/inventory/inventorySlot.py | 18 +- src/lib/graphik/src/graphik.py | 28 +- src/lib/pyenvlib/entity.py | 12 +- src/lib/pyenvlib/environment.py | 14 +- src/lib/pyenvlib/grid.py | 40 +- src/lib/pyenvlib/location.py | 32 +- src/mapimage/mapImageGenerator.py | 47 +- src/mapimage/mapImageUpdater.py | 9 +- src/player/player.py | 61 +- src/roam.py | 36 +- src/screen/configScreen.py | 122 +++- src/screen/inventoryScreen.py | 167 ++++-- src/screen/mainMenuScreen.py | 77 ++- src/screen/optionsScreen.py | 86 ++- src/screen/screenType.py | 2 +- src/screen/statsScreen.py | 77 ++- src/screen/worldScreen.py | 623 ++++++++++++++------- src/stats/stats.py | 40 +- src/ui/energyBar.py | 24 +- src/ui/status.py | 28 +- src/world/map.py | 37 +- src/world/room.py | 104 ++-- src/world/roomFactory.py | 103 ++-- src/world/roomJsonReaderWriter.py | 86 +-- src/world/roomType.py | 1 - src/world/tickCounter.py | 32 +- tests/entity/living/test_bear.py | 11 +- tests/entity/living/test_chicken.py | 14 +- tests/entity/living/test_livingEntity.py | 52 +- tests/entity/test_apple.py | 9 +- tests/entity/test_banana.py | 9 +- tests/entity/test_coalOre.py | 9 +- tests/entity/test_drawableEntity.py | 7 +- tests/entity/test_food.py | 9 +- tests/entity/test_grass.py | 9 +- tests/entity/test_ironOre.py | 9 +- tests/entity/test_jungleWood.py | 9 +- tests/entity/test_leaves.py | 9 +- tests/entity/test_oakWood.py | 9 +- tests/entity/test_stone.py | 9 +- tests/player/test_player.py | 142 ++--- tests/stats/test_stats.py | 101 ++-- 60 files changed, 1620 insertions(+), 944 deletions(-) create mode 100644 format.sh diff --git a/format.sh b/format.sh new file mode 100644 index 0000000..aa1f648 --- /dev/null +++ b/format.sh @@ -0,0 +1,4 @@ +black src +black tests +autoflake --in-place --remove-all-unused-imports --remove-unused-variables -r src +autoflake --in-place --remove-all-unused-imports --remove-unused-variables -r tests \ No newline at end of file diff --git a/src/config/config.py b/src/config/config.py index 55ab678..7bd7695 100644 --- a/src/config/config.py +++ b/src/config/config.py @@ -8,16 +8,16 @@ def __init__(self): # static (cannot be changed in game) self.displayWidth = pygame.display.Info().current_h * 0.90 self.displayHeight = pygame.display.Info().current_h * 0.90 - self.black = (0,0,0) - self.white = (255,255,255) + self.black = (0, 0, 0) + self.white = (255, 255, 255) self.playerMovementEnergyCost = 0.2 - self.playerInteractionEnergyCost= 0.05 + self.playerInteractionEnergyCost = 0.05 self.runSpeedFactor = 2 self.energyDepletionRate = 0.01 self.playerInteractionDistanceLimit = 5 self.ticksPerSecond = 30 self.gridSize = 17 - self.worldBorder = 0 # 0 = no border + self.worldBorder = 0 # 0 = no border self.pathToSaveDirectory = "saves/defaultsavefile" # dynamic (can be changed in game) @@ -25,4 +25,4 @@ def __init__(self): self.fullscreen = False self.autoEatFoodInInventory = True self.removeDeadEntities = True - self.showMiniMap = True \ No newline at end of file + self.showMiniMap = True diff --git a/src/entity/apple.py b/src/entity/apple.py index c74bf2c..c244582 100644 --- a/src/entity/apple.py +++ b/src/entity/apple.py @@ -6,8 +6,8 @@ # @since August 8th, 2022 class Apple(Food): def __init__(self): - Food.__init__(self, "Apple", "assets/images/apple.png", random.randrange(5, 11)) - self.solid = False - + Food.__init__(self, "Apple", "assets/images/apple.png", random.randrange(5, 11)) + self.solid = False + def isSolid(self): - return self.solid \ No newline at end of file + return self.solid diff --git a/src/entity/banana.py b/src/entity/banana.py index 07b759d..8115b47 100644 --- a/src/entity/banana.py +++ b/src/entity/banana.py @@ -6,8 +6,10 @@ # @since January 28th, 2023 class Banana(Food): def __init__(self): - Food.__init__(self, "Banana", "assets/images/banana.png", random.randrange(10, 20)) - self.solid = False - + Food.__init__( + self, "Banana", "assets/images/banana.png", random.randrange(10, 20) + ) + self.solid = False + def isSolid(self): - return self.solid \ No newline at end of file + return self.solid diff --git a/src/entity/coalOre.py b/src/entity/coalOre.py index 7a2620f..3ee0b3a 100644 --- a/src/entity/coalOre.py +++ b/src/entity/coalOre.py @@ -1,4 +1,3 @@ -import random from entity.drawableEntity import DrawableEntity @@ -8,6 +7,6 @@ class CoalOre(DrawableEntity): def __init__(self): DrawableEntity.__init__(self, "Coal Ore", "assets/images/coalOre.png") self.solid = True - + def isSolid(self): - return self.solid \ No newline at end of file + return self.solid diff --git a/src/entity/drawableEntity.py b/src/entity/drawableEntity.py index f917f09..01b0d6a 100644 --- a/src/entity/drawableEntity.py +++ b/src/entity/drawableEntity.py @@ -8,12 +8,12 @@ class DrawableEntity(Entity): def __init__(self, name, imagePath): Entity.__init__(self, name) self.imagePath = imagePath - + def getImage(self): return pygame.image.load(self.imagePath) def getImagePath(self): return self.imagePath - + def setImagePath(self, imagePath): - self.imagePath = imagePath \ No newline at end of file + self.imagePath = imagePath diff --git a/src/entity/food.py b/src/entity/food.py index 1d859d3..c52c51d 100644 --- a/src/entity/food.py +++ b/src/entity/food.py @@ -7,6 +7,6 @@ class Food(DrawableEntity): def __init__(self, name, color, energy): DrawableEntity.__init__(self, name, color) self.energy = energy - + def getEnergy(self): - return self.energy \ No newline at end of file + return self.energy diff --git a/src/entity/grass.py b/src/entity/grass.py index f2d5beb..007aae3 100644 --- a/src/entity/grass.py +++ b/src/entity/grass.py @@ -9,4 +9,4 @@ def __init__(self): self.solid = False def isSolid(self): - return self.solid \ No newline at end of file + return self.solid diff --git a/src/entity/ironOre.py b/src/entity/ironOre.py index 5aaf6a7..63eb35c 100644 --- a/src/entity/ironOre.py +++ b/src/entity/ironOre.py @@ -1,4 +1,3 @@ -import random from entity.drawableEntity import DrawableEntity @@ -8,6 +7,6 @@ class IronOre(DrawableEntity): def __init__(self): DrawableEntity.__init__(self, "Iron Ore", "assets/images/ironOre.png") self.solid = True - + def isSolid(self): - return self.solid \ No newline at end of file + return self.solid diff --git a/src/entity/jungleWood.py b/src/entity/jungleWood.py index 27255d8..7d7bd55 100644 --- a/src/entity/jungleWood.py +++ b/src/entity/jungleWood.py @@ -7,6 +7,6 @@ class JungleWood(DrawableEntity): def __init__(self): DrawableEntity.__init__(self, "Jungle Wood", "assets/images/jungleWood.png") self.solid = True - + def isSolid(self): - return self.solid \ No newline at end of file + return self.solid diff --git a/src/entity/leaves.py b/src/entity/leaves.py index bf08fde..e7253e0 100644 --- a/src/entity/leaves.py +++ b/src/entity/leaves.py @@ -7,6 +7,6 @@ class Leaves(DrawableEntity): def __init__(self): DrawableEntity.__init__(self, "Leaves", "assets/images/leaves.png") self.solid = False - + def isSolid(self): - return self.solid \ No newline at end of file + return self.solid diff --git a/src/entity/living/bear.py b/src/entity/living/bear.py index ea85cf5..6ffbba9 100644 --- a/src/entity/living/bear.py +++ b/src/entity/living/bear.py @@ -8,8 +8,15 @@ # @since December 24th, 2022 class Bear(LivingEntity): def __init__(self, tickCreated): - LivingEntity.__init__(self, "Bear", "assets/images/bear.png", random.randrange(20, 30), [Chicken, Player], tickCreated) + LivingEntity.__init__( + self, + "Bear", + "assets/images/bear.png", + random.randrange(20, 30), + [Chicken, Player], + tickCreated, + ) self.solid = False def isSolid(self): - return self.solid \ No newline at end of file + return self.solid diff --git a/src/entity/living/chicken.py b/src/entity/living/chicken.py index 67e91f5..89a9b42 100644 --- a/src/entity/living/chicken.py +++ b/src/entity/living/chicken.py @@ -7,8 +7,15 @@ # @since July 7th, 2022 class Chicken(LivingEntity): def __init__(self, tickCreated): - LivingEntity.__init__(self, "Chicken", "assets/images/chicken.png", random.randrange(20, 30), [Grass], tickCreated) + LivingEntity.__init__( + self, + "Chicken", + "assets/images/chicken.png", + random.randrange(20, 30), + [Grass], + tickCreated, + ) self.solid = False def isSolid(self): - return self.solid \ No newline at end of file + return self.solid diff --git a/src/entity/living/livingEntity.py b/src/entity/living/livingEntity.py index 3267375..fe062e2 100644 --- a/src/entity/living/livingEntity.py +++ b/src/entity/living/livingEntity.py @@ -11,7 +11,7 @@ def __init__(self, name, color, energy, edibleEntityTypes, tickCreated): self.targetEnergy = energy self.tickCreated = tickCreated self.tickLastReproduced = None - + def getEnergy(self): return self.energy @@ -28,7 +28,7 @@ def addEnergy(self, amount): self.energy = 100 else: self.energy += amount - + def removeEnergy(self, amount): if self.energy - amount < 0: self.energy = 0 @@ -37,7 +37,7 @@ def removeEnergy(self, amount): def needsEnergy(self): return self.energy < self.targetEnergy * 0.50 - + def getTargetEnergy(self): return self.targetEnergy @@ -49,21 +49,21 @@ def canEat(self, entity): if type(entity) is entityType: return True return False - + def kill(self): self.energy = 0 - + def getTickCreated(self): return self.tickCreated - + def setTickCreated(self, tick): self.tickCreated = tick - + def getAge(self, tick): return tick - self.tickCreated - + def getTickLastReproduced(self): return self.tickLastReproduced - + def setTickLastReproduced(self, tick): - self.tickLastReproduced = tick \ No newline at end of file + self.tickLastReproduced = tick diff --git a/src/entity/oakWood.py b/src/entity/oakWood.py index f7d79ec..958276a 100644 --- a/src/entity/oakWood.py +++ b/src/entity/oakWood.py @@ -7,6 +7,6 @@ class OakWood(DrawableEntity): def __init__(self): DrawableEntity.__init__(self, "Oak Wood", "assets/images/oakWood.png") self.solid = True - + def isSolid(self): - return self.solid \ No newline at end of file + return self.solid diff --git a/src/entity/stone.py b/src/entity/stone.py index 650721f..86d161b 100644 --- a/src/entity/stone.py +++ b/src/entity/stone.py @@ -1,4 +1,3 @@ -import random from entity.drawableEntity import DrawableEntity @@ -8,6 +7,6 @@ class Stone(DrawableEntity): def __init__(self): DrawableEntity.__init__(self, "Stone", "assets/images/stone.png") self.solid = True - + def isSolid(self): - return self.solid \ No newline at end of file + return self.solid diff --git a/src/inventory/inventory.py b/src/inventory/inventory.py index 100ae4b..b85f100 100644 --- a/src/inventory/inventory.py +++ b/src/inventory/inventory.py @@ -8,25 +8,28 @@ def __init__(self): for i in range(self.size): self.inventorySlots.append(InventorySlot()) self.selectedInventorySlotIndex = 0 - + def getInventorySlots(self): return self.inventorySlots - + def getNumInventorySlots(self): return len(self.inventorySlots) - + def placeIntoFirstAvailableInventorySlot(self, item): for inventorySlot in self.inventorySlots: if inventorySlot.isEmpty(): # set the item inventorySlot.add(item) return True - elif inventorySlot.getContents()[0].getName() == item.getName() and inventorySlot.getNumItems() < inventorySlot.getMaxStackSize(): + elif ( + inventorySlot.getContents()[0].getName() == item.getName() + and inventorySlot.getNumItems() < inventorySlot.getMaxStackSize() + ): # increment the amount inventorySlot.add(item) return True return False - + def removeByItem(self, item): for inventorySlot in self.inventorySlots: if inventorySlot.isEmpty(): @@ -38,25 +41,25 @@ def removeByItem(self, item): inventorySlot.clear() return True return False - + def clear(self): for inventorySlot in self.inventorySlots: inventorySlot.clear() - + def getNumFreeInventorySlots(self): count = 0 for inventorySlot in self.inventorySlots: if inventorySlot.getItem() == None: count += 1 return count - + def getNumTakenInventorySlots(self): count = 0 for inventorySlot in self.inventorySlots: if inventorySlot.isEmpty() == False: count += 1 return count - + def getNumItems(self): count = 0 for inventorySlot in self.inventorySlots: @@ -64,7 +67,7 @@ def getNumItems(self): continue count += inventorySlot.getNumItems() return count - + def getNumItemsByType(self, type): count = 0 for inventorySlot in self.inventorySlots: @@ -74,22 +77,22 @@ def getNumItemsByType(self, type): if isinstance(item, type): count += inventorySlot.getNumItems() return count - + def getSelectedInventorySlotIndex(self): return self.selectedInventorySlotIndex - + def setSelectedInventorySlotIndex(self, index): self.selectedInventorySlotIndex = index - + def getItemByIndex(self, index): return self.inventorySlots[index].getItem() - + def getSelectedInventorySlot(self): return self.inventorySlots[self.selectedInventorySlotIndex] - + def removeSelectedItem(self): return self.inventorySlots[self.selectedInventorySlotIndex].pop() - + def getFirstTenInventorySlots(self): if len(self.inventorySlots) > 10: return self.inventorySlots[:10] diff --git a/src/inventory/inventoryJsonReaderWriter.py b/src/inventory/inventoryJsonReaderWriter.py index 743f218..8cdaef4 100644 --- a/src/inventory/inventoryJsonReaderWriter.py +++ b/src/inventory/inventoryJsonReaderWriter.py @@ -26,34 +26,33 @@ def __init__(self, config): def saveInventory(self, inventory: Inventory, path): print("Saving inventory to " + path) toReturn = {} - toReturn['inventorySlots'] = [] + toReturn["inventorySlots"] = [] slotIndex = 0 for slot in inventory.getInventorySlots(): slotContents = [] for entity in slot.getContents(): toAppend = {} toAppend = { - 'entityId': str(entity.getID()), - 'entityClass': entity.__class__.__name__, - 'name': entity.getName(), - 'assetPath': entity.getImagePath() + "entityId": str(entity.getID()), + "entityClass": entity.__class__.__name__, + "name": entity.getName(), + "assetPath": entity.getImagePath(), } - if (isinstance(entity, Food)): - toAppend['energy'] = entity.getEnergy() - if (isinstance(entity, LivingEntity)): - toAppend['energy'] = entity.getEnergy() - toAppend['tickCreated'] = entity.getTickCreated() - toAppend['tickLastReproduced'] = entity.getTickLastReproduced() - toAppend['imagePath'] = entity.getImagePath() + if isinstance(entity, Food): + toAppend["energy"] = entity.getEnergy() + if isinstance(entity, LivingEntity): + toAppend["energy"] = entity.getEnergy() + toAppend["tickCreated"] = entity.getTickCreated() + toAppend["tickLastReproduced"] = entity.getTickLastReproduced() + toAppend["imagePath"] = entity.getImagePath() slotContents.append(toAppend) - toReturn['inventorySlots'].append({ - 'slotIndex': slotIndex, - 'slotContents': slotContents - }) + toReturn["inventorySlots"].append( + {"slotIndex": slotIndex, "slotContents": slotContents} + ) slotIndex += 1 - + # Validate the JSON - with open('schemas/inventory.json') as f: + with open("schemas/inventory.json") as f: inventorySchema = json.load(f) try: jsonschema.validate(toReturn, inventorySchema) @@ -65,7 +64,7 @@ def saveInventory(self, inventory: Inventory, path): os.makedirs(self.config.pathToSaveDirectory) # print the JSON to file - with open(path, 'w') as f: + with open(path, "w") as f: json.dump(toReturn, f, indent=4) def loadInventory(self, path): @@ -75,59 +74,61 @@ def loadInventory(self, path): return inventory with open(path) as f: inventoryJson = json.load(f) - for slot in inventoryJson['inventorySlots']: - for entityJson in slot['slotContents']: - entityClass = entityJson['entityClass'] + for slot in inventoryJson["inventorySlots"]: + for entityJson in slot["slotContents"]: + entityClass = entityJson["entityClass"] if entityClass == "Apple": apple = Apple() - apple.setID(UUID(entityJson['entityId'])) + apple.setID(UUID(entityJson["entityId"])) inventory.placeIntoFirstAvailableInventorySlot(apple) elif entityClass == "CoalOre": coalOre = CoalOre() - coalOre.setID(UUID(entityJson['entityId'])) + coalOre.setID(UUID(entityJson["entityId"])) inventory.placeIntoFirstAvailableInventorySlot(coalOre) - elif entityClass == 'Grass': + elif entityClass == "Grass": grass = Grass() - grass.setID(UUID(entityJson['entityId'])) + grass.setID(UUID(entityJson["entityId"])) inventory.placeIntoFirstAvailableInventorySlot(grass) elif entityClass == "IronOre": ironOre = IronOre() - ironOre.setID(UUID(entityJson['entityId'])) + ironOre.setID(UUID(entityJson["entityId"])) inventory.placeIntoFirstAvailableInventorySlot(ironOre) - elif entityClass == 'JungleWood': + elif entityClass == "JungleWood": jungleWood = JungleWood() - jungleWood.setID(UUID(entityJson['entityId'])) + jungleWood.setID(UUID(entityJson["entityId"])) inventory.placeIntoFirstAvailableInventorySlot(jungleWood) elif entityClass == "Leaves": leaves = Leaves() - leaves.setID(UUID(entityJson['entityId'])) + leaves.setID(UUID(entityJson["entityId"])) inventory.placeIntoFirstAvailableInventorySlot(leaves) - elif entityClass == 'OakWood': + elif entityClass == "OakWood": oakWood = OakWood() - oakWood.setID(UUID(entityJson['entityId'])) + oakWood.setID(UUID(entityJson["entityId"])) inventory.placeIntoFirstAvailableInventorySlot(oakWood) elif entityClass == "Stone": stone = Stone() - stone.setID(UUID(entityJson['entityId'])) + stone.setID(UUID(entityJson["entityId"])) inventory.placeIntoFirstAvailableInventorySlot(stone) elif entityClass == "Bear": - bear = Bear(entityJson['tickCreated']) - bear.setID(UUID(entityJson['entityId'])) + bear = Bear(entityJson["tickCreated"]) + bear.setID(UUID(entityJson["entityId"])) inventory.placeIntoFirstAvailableInventorySlot(bear) - bear.setEnergy(entityJson['energy']) - bear.setTickLastReproduced(entityJson['tickLastReproduced']) - bear.setImagePath(entityJson['imagePath']) + bear.setEnergy(entityJson["energy"]) + bear.setTickLastReproduced(entityJson["tickLastReproduced"]) + bear.setImagePath(entityJson["imagePath"]) elif entityClass == "Chicken": - chicken = Chicken(entityJson['tickCreated']) - chicken.setID(UUID(entityJson['entityId'])) - chicken.setEnergy(entityJson['energy']) - chicken.setTickLastReproduced(entityJson['tickLastReproduced']) - chicken.setImagePath(entityJson['imagePath']) + chicken = Chicken(entityJson["tickCreated"]) + chicken.setID(UUID(entityJson["entityId"])) + chicken.setEnergy(entityJson["energy"]) + chicken.setTickLastReproduced(entityJson["tickLastReproduced"]) + chicken.setImagePath(entityJson["imagePath"]) inventory.placeIntoFirstAvailableInventorySlot(chicken) elif entityClass == "Banana": banana = Banana() - banana.setID(UUID(entityJson['entityId'])) + banana.setID(UUID(entityJson["entityId"])) inventory.placeIntoFirstAvailableInventorySlot(banana) else: - raise Exception("Unknown entity class: " + entityJson['entityClass']) - return inventory \ No newline at end of file + raise Exception( + "Unknown entity class: " + entityJson["entityClass"] + ) + return inventory diff --git a/src/inventory/inventorySlot.py b/src/inventory/inventorySlot.py index b70317e..2116c4d 100644 --- a/src/inventory/inventorySlot.py +++ b/src/inventory/inventorySlot.py @@ -2,30 +2,30 @@ class InventorySlot: def __init__(self): self.contents = [] - + def getContents(self): return self.contents def setContents(self, contents): self.contents = contents - + def getNumItems(self): return len(self.contents) - + def add(self, item): self.contents.append(item) - + def remove(self, item): self.contents.remove(item) - + def pop(self): return self.contents.pop(0) - + def clear(self): self.contents = [] - + def isEmpty(self): return len(self.contents) == 0 - + def getMaxStackSize(self): - return 20 \ No newline at end of file + return 20 diff --git a/src/lib/graphik/src/graphik.py b/src/lib/graphik/src/graphik.py index 331cc91..6b2eec0 100644 --- a/src/lib/graphik/src/graphik.py +++ b/src/lib/graphik/src/graphik.py @@ -9,11 +9,11 @@ def __init__(self): displayHeight = 600 self.gameDisplay = pygame.display.set_mode((displayWidth, displayHeight)) - self.black = (0,0,0) - self.white = (255,255,255) - self.red = (200,0,0) - self.green = (0,200,0) - self.blue = (0,0,200) + self.black = (0, 0, 0) + self.white = (255, 255, 255) + self.red = (200, 0, 0) + self.green = (0, 200, 0) + self.blue = (0, 0, 200) def __init__(self, gameDisplay): self.gameDisplay = gameDisplay @@ -28,19 +28,23 @@ def drawRectangle(self, xpos, ypos, width, height, color): pygame.draw.rect(self.gameDisplay, color, [xpos, ypos, width, height]) def drawText(self, text, xpos, ypos, size, color): - myFont = pygame.font.Font('freesansbold.ttf', size) + myFont = pygame.font.Font("freesansbold.ttf", size) textSurface = myFont.render(text, True, color) textRectangle = textSurface.get_rect() - textRectangle.center = ((xpos, ypos)) + textRectangle.center = (xpos, ypos) self.gameDisplay.blit(textSurface, textRectangle) - def drawButton(self, xpos, ypos, width, height, colorBox, colorText, sizeText, text, function): + def drawButton( + self, xpos, ypos, width, height, colorBox, colorText, sizeText, text, function + ): self.drawRectangle(xpos, ypos, width, height, colorBox) - self.drawText(text, xpos + (width//2), ypos + (height//2), sizeText, colorText) - + self.drawText( + text, xpos + (width // 2), ypos + (height // 2), sizeText, colorText + ) + # if clicked then do function mouse = pygame.mouse.get_pos() - if (xpos + width > mouse[0] > xpos and ypos + height > mouse[1] > ypos): + if xpos + width > mouse[0] > xpos and ypos + height > mouse[1] > ypos: click = pygame.mouse.get_pressed() if click[0] == 1: - function() \ No newline at end of file + function() diff --git a/src/lib/pyenvlib/entity.py b/src/lib/pyenvlib/entity.py index 393c5de..9e20129 100644 --- a/src/lib/pyenvlib/entity.py +++ b/src/lib/pyenvlib/entity.py @@ -16,11 +16,11 @@ def __init__(self, name): self.environmentID = -1 self.gridID = -1 self.locationID = -1 - + # Returns the ID of this entity. def getID(self): return self.id - + # Returns the name of this entity. def getName(self): return self.name @@ -40,7 +40,7 @@ def getGridID(self): # Returns the ID of the location that this entity is in. def getLocationID(self): return self.locationID - + # Sets the ID of this entity. def setID(self, id): self.id = id @@ -52,7 +52,7 @@ def setName(self, name): # Sets the environment ID for this entity. def setEnvironmentID(self, environmentID): self.environmentID = environmentID - + # Sets the creation timestamp for this entity. def setCreationDate(self, creationDate): self.creationDate = creationDate @@ -64,7 +64,7 @@ def setGridID(self, gridID): # Sets the location ID for this entity. def setLocationID(self, locationID): self.locationID = locationID - + # Prints information about this entity to the console. def printInfo(self): print("--------------") @@ -75,4 +75,4 @@ def printInfo(self): print("Environment ID: ", self.getEnvironmentID()) print("Grid ID: ", self.getGridID()) print("Location ID: ", self.getLocationID()) - print("\n") \ No newline at end of file + print("\n") diff --git a/src/lib/pyenvlib/environment.py b/src/lib/pyenvlib/environment.py index 06feac6..1350be4 100644 --- a/src/lib/pyenvlib/environment.py +++ b/src/lib/pyenvlib/environment.py @@ -16,11 +16,11 @@ def __init__(self, name, size): self.name = name self.grid = Grid(size, size) self.creationDate = datetime.datetime.now() - + # Returns the ID of this environment. def getID(self): return self.id - + # Returns the name of this environment. def getName(self): return self.name @@ -49,16 +49,16 @@ def setGrid(self, grid): def addEntity(self, entity: Entity): entity.setEnvironmentID(self.getID()) self.grid.addEntity(entity) - + # Adds an entity to a particular location in the underlying grid of this environment. def addEntityToLocation(self, entity: Entity, location): entity.setEnvironmentID(self.getID()) self.grid.addEntityToLocation(entity, location) - + # Removes an entity from the underlying grid. def removeEntity(self, entity: Entity): self.grid.removeEntity(entity) - + # Checks if an entity is present anywhere in the underlying grid. def isEntityPresent(self, entity: Entity): return self.grid.isEntityPresent(entity) @@ -78,7 +78,7 @@ def printInfo(self): print("ID: ", self.getID()) print("Grid ID: ", self.getGrid().getID()) print("\n") - + # Returns the entity in this environment with the given ID. def getEntity(self, id): - return self.grid.getEntity(id) \ No newline at end of file + return self.grid.getEntity(id) diff --git a/src/lib/pyenvlib/grid.py b/src/lib/pyenvlib/grid.py index 983f867..532861d 100644 --- a/src/lib/pyenvlib/grid.py +++ b/src/lib/pyenvlib/grid.py @@ -41,7 +41,7 @@ def getFirstLocation(self): # Returns the number of locations in this grid. def getSize(self): return len(self.locations) - + # Returns the number of entities in this grid. def getNumEntities(self): count = 0 @@ -49,42 +49,42 @@ def getNumEntities(self): location = self.locations[locationId] count += location.getNumEntities() return count - + # Sets the ID of this grid. def setID(self, id): self.id = id - + # Sets the number of columns of this grid. def setColumns(self, columns): self.columns = columns - + # Sets the number of rows of this grid. def setRows(self, rows): self.rows = rows - + # Sets the locations for this grid. def setLocations(self, locations): self.locations = locations - - # Adds a location to this grid. + + # Adds a location to this grid. def addLocation(self, location: Location): self.locations[location.getID()] = location - + # Removes a location from this grid. def removeLocation(self, location: Location): self.locations.remove(location) - + # Adds an entity to a random location in this grid. def addEntity(self, entity: Entity): entity.setGridID(self.getID()) self.getRandomLocation().addEntity(entity) - + # Adds an entity to a specified location in this grid. def addEntityToLocation(self, entity: Entity, location): entity.setGridID(self.getID()) - + self.locations[location.getID()].addEntity(entity) - + # Removes an entity from this grid. def removeEntity(self, entity: Entity): for locationId in self.getLocations(): @@ -92,7 +92,7 @@ def removeEntity(self, entity: Entity): if location.isEntityPresent(entity): location.removeEntity(entity) return - + # Checks if an entity is present in this grid. def isEntityPresent(self, entity: Entity): for locationId in self.grid.getLocations(): @@ -106,17 +106,17 @@ def generateLocations(self): for y in range(self.getRows()): location = Location(x, y) self.locations[location.getID()] = location - + # Returns a location with the specified ID. def getLocation(self, id): return self.locations[id] - + # Returns a random location. def getRandomLocation(self): index = random.randrange(0, len(self.locations)) id = list(self.locations.keys())[index] return self.locations[id] - + # Returns a location at the specified coordinates. def getLocationByCoordinates(self, x, y): for locationId in self.locations: @@ -130,19 +130,19 @@ def getUp(self, location: Location): if location == -1: return -1 return self.getLocationByCoordinates(location.getX(), location.getY() - 1) - + # Returns the location to the right of the specified location. def getRight(self, location: Location): if location == -1: return -1 return self.getLocationByCoordinates(location.getX() + 1, location.getY()) - + # Returns the location underneath the specified location. def getDown(self, location: Location): if location == -1: return -1 return self.getLocationByCoordinates(location.getX(), location.getY() + 1) - + # Returns the location to the left of the specified location. def getLeft(self, location: Location): if location == -1: @@ -156,4 +156,4 @@ def getEntity(self, id): entity = location.getEntity(id) if entity != None: return entity - return None \ No newline at end of file + return None diff --git a/src/lib/pyenvlib/location.py b/src/lib/pyenvlib/location.py index d983350..e30c501 100644 --- a/src/lib/pyenvlib/location.py +++ b/src/lib/pyenvlib/location.py @@ -14,15 +14,15 @@ def __init__(self, x, y): self.x = x self.y = y self.entities = dict() - + # Returns the ID of this location. def getID(self): return self.id - + # Returns the X coordinate of this location. def getX(self): return self.x - + # Returns the Y coordinate of this location. def getY(self): return self.y @@ -30,42 +30,46 @@ def getY(self): # Returns the number of entities in this location. def getNumEntities(self): return len(self.entities) - + # Adds an entity to this location. def addEntity(self, entity: Entity): if not self.isEntityPresent(entity): self.entities[entity.getID()] = entity entity.setLocationID(self.getID()) else: - print("Warning: An entity was already present when attempting to add it to a location.") - + print( + "Warning: An entity was already present when attempting to add it to a location." + ) + # Removes an entity from this location. def removeEntity(self, entity: Entity): if self.isEntityPresent(entity): del self.entities[entity.getID()] else: - print("Warning: An entity was not present when attempting to remove it from a location.") - + print( + "Warning: An entity was not present when attempting to remove it from a location." + ) + # Checks if an entity is present in this location. def isEntityPresent(self, entity: Entity): return entity.getID() in self.entities - + # Returns the dictionary of entities in this location. def getEntities(self): return self.entities - + # Returns an entity in this location matching the given ID. def getEntity(self, id): if not id in self.entities: # print("Warning: An entity was not present when attempting to retrieve it from a location.") return None return self.entities[id] - + def setID(self, id): self.id = id - + def setCreationDate(self, creationDate): self.creationDate = creationDate - + def setEntities(self, entities): - self.entities = entities \ No newline at end of file + self.entities = entities diff --git a/src/mapimage/mapImageGenerator.py b/src/mapimage/mapImageGenerator.py index ee0f4c4..a9f70e0 100644 --- a/src/mapimage/mapImageGenerator.py +++ b/src/mapimage/mapImageGenerator.py @@ -8,10 +8,12 @@ class MapImageGenerator: def __init__(self, config): self.config = config - + self.numRoomsInEachDirection = 5 self.roomSizeInPixels = 100 - self.mapImageSizeInPixels = (self.numRoomsInEachDirection * 2 + 1) * self.roomSizeInPixels + self.mapImageSizeInPixels = ( + self.numRoomsInEachDirection * 2 + 1 + ) * self.roomSizeInPixels self.roomImagesDirectoryPath = self.config.pathToSaveDirectory + "/roompngs" self.mapImagePath = self.config.pathToSaveDirectory + "/mapImage.png" @@ -20,32 +22,34 @@ def __init__(self, config): self.mapImage = self.getExistingMapImage() else: self.mapImage = self.createNewMapImage() - + # public methods def generate(self): roomImages = self.getRoomImages() self.pasteRoomImagesAtCorrectCoordinates(roomImages) return self.mapImage - + def clearRoomImages(self): for file in os.listdir(self.roomImagesDirectoryPath): os.remove(self.roomImagesDirectoryPath + "/" + file) - + # private methods - + def mapImageExists(self): return os.path.exists(self.mapImagePath) def getExistingMapImage(self): - if (self.config.debug): + if self.config.debug: print("Loading existing map image") return Image.open(self.mapImagePath) def createNewMapImage(self): - if (self.config.debug): + if self.config.debug: print("Creating new map image") - return Image.new("RGB", (self.mapImageSizeInPixels, self.mapImageSizeInPixels), "white") + return Image.new( + "RGB", (self.mapImageSizeInPixels, self.mapImageSizeInPixels), "white" + ) def getRoomImages(self): return os.listdir(self.roomImagesDirectoryPath) @@ -69,17 +73,28 @@ def pasteRoomImagesAtCorrectCoordinates(self, roomImages): # Get the x and y coordinates of the room x = int(room_number[0]) y = int(room_number[1]) - + # Paste the room image onto the new image at the correct coordinates - picX = int(self.mapImageSizeInPixels/2) + x * roomSize - int(roomSize/2) - picY = int(self.mapImageSizeInPixels/2) + y * roomSize - int(roomSize/2) - if picX >= 0 and picY >= 0 and picX < self.mapImageSizeInPixels and picY < self.mapImageSizeInPixels: + picX = int(self.mapImageSizeInPixels / 2) + x * roomSize - int(roomSize / 2) + picY = int(self.mapImageSizeInPixels / 2) + y * roomSize - int(roomSize / 2) + if ( + picX >= 0 + and picY >= 0 + and picX < self.mapImageSizeInPixels + and picY < self.mapImageSizeInPixels + ): self.mapImage.paste(image, (picX, picY)) numPasted += 1 else: numOutOfBounds += 1 - - if (self.config.debug): + + if self.config.debug: print("Images pasted: " + str(numPasted)) print("Images out of bounds: " + str(numOutOfBounds)) - print("Percent of map updated: " + str(int(numPasted / (self.numRoomsInEachDirection * 2 + 1) ** 2 * 100)) + "%") \ No newline at end of file + print( + "Percent of map updated: " + + str( + int(numPasted / (self.numRoomsInEachDirection * 2 + 1) ** 2 * 100) + ) + + "%" + ) diff --git a/src/mapimage/mapImageUpdater.py b/src/mapimage/mapImageUpdater.py index 4dd3827..9ad3262 100644 --- a/src/mapimage/mapImageUpdater.py +++ b/src/mapimage/mapImageUpdater.py @@ -11,13 +11,16 @@ def __init__(self, tickCounter: TickCounter, config): self.mapImageGenerator = MapImageGenerator(self.config) self.tickLastUpdated = self.tickCounter.getTick() self.updateCooldownInTicks = 300 - + def updateIfCooldownOver(self): - if self.tickCounter.getTick() - self.tickLastUpdated > self.updateCooldownInTicks: + if ( + self.tickCounter.getTick() - self.tickLastUpdated + > self.updateCooldownInTicks + ): self.updateMapImage() def updateMapImage(self): image = self.mapImageGenerator.generate() image.save(self.mapImageGenerator.mapImagePath) self.mapImageGenerator.clearRoomImages() - self.tickLastUpdated = self.tickCounter.getTick() \ No newline at end of file + self.tickLastUpdated = self.tickCounter.getTick() diff --git a/src/player/player.py b/src/player/player.py index 389ec22..e980bdc 100644 --- a/src/player/player.py +++ b/src/player/player.py @@ -9,8 +9,15 @@ # @since August 8th, 2022 class Player(LivingEntity): def __init__(self, tickCreated): - LivingEntity.__init__(self, "Player", "assets/images/player_down.png", 100, [Apple, Banana, Chicken], tickCreated) - self.direction = -1 # -1 when not moving + LivingEntity.__init__( + self, + "Player", + "assets/images/player_down.png", + 100, + [Apple, Banana, Chicken], + tickCreated, + ) + self.direction = -1 # -1 when not moving self.lastDirection = -1 self.inventory = Inventory() self.gathering = False @@ -23,10 +30,10 @@ def __init__(self, tickCreated): self.placeSpeed = 30 self.crouching = False self.solid = False - + def getDirection(self): return self.direction - + def setDirection(self, direction): self.lastDirection = self.direction self.direction = direction @@ -39,87 +46,87 @@ def setDirection(self, direction): self.imagePath = "assets/images/player_down.png" elif self.direction == 3: self.imagePath = "assets/images/player_right.png" - + def getLastDirection(self): return self.lastDirection - + def getInventory(self): return self.inventory def setInventory(self, inventory): self.inventory = inventory - + def isGathering(self): return self.gathering def setGathering(self, bool): self.gathering = bool - + def isPlacing(self): return self.placing - + def setPlacing(self, bool): self.placing = bool - + def isDead(self): return self.energy < 1 def getTickLastMoved(self): return self.tickLastMoved - + def setTickLastMoved(self, tick): self.tickLastMoved = tick - + def getMovementSpeed(self): return self.movementSpeed - + def setMovementSpeed(self, newSpeed): self.movementSpeed = newSpeed def getTickLastGathered(self): return self.tickLastGathered - + def setTickLastGathered(self, tick): self.tickLastGathered = tick - + def getGatherSpeed(self): return self.gatherSpeed - + def setGatherSpeed(self, newSpeed): self.gatherSpeed = newSpeed def getTickLastPlaced(self): return self.tickLastPlaced - + def setTickLastPlaced(self, tick): self.tickLastPlaced = tick - + def getPlaceSpeed(self): return self.placeSpeed - + def setPlaceSpeed(self, newSpeed): self.placeSpeed = newSpeed - + def isCrouching(self): return self.crouching - + def setCrouching(self, bool): self.crouching = bool - + def getTickLastGathered(self): return self.tickLastGathered - + def setTickLastGathered(self, tick): self.tickLastGathered = tick def getTickLastPlaced(self): return self.tickLastPlaced - + def setTickLastPlaced(self, tick): self.tickLastPlaced = tick - + def isMoving(self): return self.direction != -1 - + def isSolid(self): - return self.solid \ No newline at end of file + return self.solid diff --git a/src/roam.py b/src/roam.py index 3514026..b5b4285 100644 --- a/src/roam.py +++ b/src/roam.py @@ -29,27 +29,44 @@ def __init__(self, config: Config): self.status = Status(self.graphik, self.tickCounter) self.stats = Stats(self.config) self.player = Player(self.tickCounter.getTick()) - self.worldScreen = WorldScreen(self.graphik, self.config, self.status, self.tickCounter, self.stats, self.player) + self.worldScreen = WorldScreen( + self.graphik, + self.config, + self.status, + self.tickCounter, + self.stats, + self.player, + ) self.optionsScreen = OptionsScreen(self.graphik, self.config, self.status) - self.mainMenuScreen = MainMenuScreen(self.graphik, self.config, self.initializeWorldScreen) - self.statsScreen = StatsScreen(self.graphik, self.config, self.status, self.stats) - self.inventoryScreen = InventoryScreen(self.graphik, self.config, self.status, self.player.getInventory()) + self.mainMenuScreen = MainMenuScreen( + self.graphik, self.config, self.initializeWorldScreen + ) + self.statsScreen = StatsScreen( + self.graphik, self.config, self.status, self.stats + ) + self.inventoryScreen = InventoryScreen( + self.graphik, self.config, self.status, self.player.getInventory() + ) self.configScreen = ConfigScreen(self.graphik, self.config, self.status) self.currentScreen = self.mainMenuScreen def initializeGameDisplay(self): if self.config.fullscreen: - return pygame.display.set_mode((self.config.displayWidth, self.config.displayHeight), pygame.FULLSCREEN) + return pygame.display.set_mode( + (self.config.displayWidth, self.config.displayHeight), pygame.FULLSCREEN + ) else: - return pygame.display.set_mode((self.config.displayWidth, self.config.displayHeight), pygame.RESIZABLE) - + return pygame.display.set_mode( + (self.config.displayWidth, self.config.displayHeight), pygame.RESIZABLE + ) + def initializeWorldScreen(self): self.worldScreen.initialize() def quitApplication(self): pygame.quit() quit() - + def run(self): while True: result = self.currentScreen.run() @@ -72,6 +89,7 @@ def run(self): print("unrecognized screen: " + result) self.quitApplication() + pygame.init() config = Config() roam = Roam(config) @@ -79,4 +97,4 @@ def run(self): result = roam.run() if result != "restart": break - roam = Roam(config) \ No newline at end of file + roam = Roam(config) diff --git a/src/screen/configScreen.py b/src/screen/configScreen.py index 9716b48..493c50c 100644 --- a/src/screen/configScreen.py +++ b/src/screen/configScreen.py @@ -14,11 +14,11 @@ def __init__(self, graphik: Graphik, config: Config, status: Status): self.running = True self.nextScreen = ScreenType.MAIN_MENU_SCREEN self.changeScreen = False - + def handleKeyDownEvent(self, key): if key == pygame.K_ESCAPE: self.switchToMainMenuScreen() - + def switchToMainMenuScreen(self): self.nextScreen = ScreenType.MAIN_MENU_SCREEN self.changeScreen = True @@ -26,19 +26,19 @@ def switchToMainMenuScreen(self): def quitApplication(self): self.nextScreen = ScreenType.NONE self.changeScreen = True - + def toggleDebug(self): self.config.debug = not self.config.debug sleep(0.1) - + def toggleFullscreen(self): self.config.fullscreen = not self.config.fullscreen sleep(0.1) - + def toggleAutoEatFoodInInventory(self): self.config.autoEatFoodInInventory = not self.config.autoEatFoodInInventory sleep(0.1) - + def toggleRemoveDeadEntities(self): self.config.removeDeadEntities = not self.config.removeDeadEntities sleep(0.1) @@ -46,54 +46,114 @@ def toggleRemoveDeadEntities(self): def toggleShowMiniMap(self): self.config.showMiniMap = not self.config.showMiniMap sleep(0.1) - + def drawMenuButtons(self): # draw buttons in red or green depending on config option value # config options to include: debug, fullscreen, autoEatInInventory x, y = self.graphik.getGameDisplay().get_size() - width = x/2 - height = y/10 + width = x / 2 + height = y / 10 # start at top of screen - xpos = x/2 - width/2 - ypos = 0 + height/2 + xpos = x / 2 - width / 2 + ypos = 0 + height / 2 margin = 10 - color = (0,255,0) if self.config.debug else (255,0,0) - self.graphik.drawButton(xpos, ypos, width, height, (255,255,255), color, 30, "debug", self.toggleDebug) + color = (0, 255, 0) if self.config.debug else (255, 0, 0) + self.graphik.drawButton( + xpos, + ypos, + width, + height, + (255, 255, 255), + color, + 30, + "debug", + self.toggleDebug, + ) ypos = ypos + height + margin - color = (0,255,0) if self.config.fullscreen else (255,0,0) - self.graphik.drawButton(xpos, ypos, width, height, (255,255,255), color, 30, "fullscreen", self.toggleFullscreen) + color = (0, 255, 0) if self.config.fullscreen else (255, 0, 0) + self.graphik.drawButton( + xpos, + ypos, + width, + height, + (255, 255, 255), + color, + 30, + "fullscreen", + self.toggleFullscreen, + ) ypos = ypos + height + margin - color = (0,255,0) if self.config.autoEatFoodInInventory else (255,0,0) - self.graphik.drawButton(xpos, ypos, width, height, (255,255,255), color, 30, "auto eat in inventory", self.toggleAutoEatFoodInInventory) + color = (0, 255, 0) if self.config.autoEatFoodInInventory else (255, 0, 0) + self.graphik.drawButton( + xpos, + ypos, + width, + height, + (255, 255, 255), + color, + 30, + "auto eat in inventory", + self.toggleAutoEatFoodInInventory, + ) ypos = ypos + height + margin - color = (0,255,0) if self.config.removeDeadEntities else (255,0,0) - self.graphik.drawButton(xpos, ypos, width, height, (255,255,255), color, 30, "remove dead entities", self.toggleRemoveDeadEntities) + color = (0, 255, 0) if self.config.removeDeadEntities else (255, 0, 0) + self.graphik.drawButton( + xpos, + ypos, + width, + height, + (255, 255, 255), + color, + 30, + "remove dead entities", + self.toggleRemoveDeadEntities, + ) ypos = ypos + height + margin - color = (0,255,0) if self.config.showMiniMap else (255,0,0) - self.graphik.drawButton(xpos, ypos, width, height, (255,255,255), color, 30, "show minimap", self.toggleShowMiniMap) + color = (0, 255, 0) if self.config.showMiniMap else (255, 0, 0) + self.graphik.drawButton( + xpos, + ypos, + width, + height, + (255, 255, 255), + color, + 30, + "show minimap", + self.toggleShowMiniMap, + ) self.drawBackButton() def drawBackButton(self): # draw in bottom right corner x, y = self.graphik.getGameDisplay().get_size() - width = x/3 - height = y/10 - xpos = x/2 - width/2 - ypos = y/2 - height/2 + width - self.graphik.drawButton(xpos, ypos, width, height, (255,255,255), (0,0,0), 30, "back", self.switchToMainMenuScreen) + width = x / 3 + height = y / 10 + xpos = x / 2 - width / 2 + ypos = y / 2 - height / 2 + width + self.graphik.drawButton( + xpos, + ypos, + width, + height, + (255, 255, 255), + (0, 0, 0), + 30, + "back", + self.switchToMainMenuScreen, + ) - def run(self): + def run(self): while not self.changeScreen: for event in pygame.event.get(): if event.type == pygame.QUIT: return ScreenType.NONE elif event.type == pygame.KEYDOWN: - self.handleKeyDownEvent(event.key) - + self.handleKeyDownEvent(event.key) + self.graphik.getGameDisplay().fill((0, 0, 0)) self.drawMenuButtons() pygame.display.update() - + self.changeScreen = False - return self.nextScreen \ No newline at end of file + return self.nextScreen diff --git a/src/screen/inventoryScreen.py b/src/screen/inventoryScreen.py index 60d689b..0710263 100644 --- a/src/screen/inventoryScreen.py +++ b/src/screen/inventoryScreen.py @@ -10,7 +10,9 @@ # @author Daniel McCoy Stephenson class InventoryScreen: - def __init__(self, graphik: Graphik, config: Config, status: Status, inventory: Inventory): + def __init__( + self, graphik: Graphik, config: Config, status: Status, inventory: Inventory + ): self.graphik = graphik self.config = config self.status = status @@ -18,20 +20,26 @@ def __init__(self, graphik: Graphik, config: Config, status: Status, inventory: self.nextScreen = ScreenType.WORLD_SCREEN self.changeScreen = False self.cursorSlot = InventorySlot() - + # @source https://stackoverflow.com/questions/63342477/how-to-take-screenshot-of-entire-display-pygame - def captureScreen(self, name, pos, size): # (pygame Surface, String, tuple, tuple) + def captureScreen(self, name, pos, size): # (pygame Surface, String, tuple, tuple) image = pygame.Surface(size) # Create image surface - image.blit(self.graphik.getGameDisplay(), (0,0), (pos, size)) # Blit portion of the display to the image + image.blit( + self.graphik.getGameDisplay(), (0, 0), (pos, size) + ) # Blit portion of the display to the image pygame.image.save(image, name) # Save the image to the disk** - + def swapCursorSlotWithInventorySlotByIndex(self, index): if self.cursorSlot.isEmpty(): - self.cursorSlot.setContents(self.inventory.getInventorySlots()[index].getContents()) + self.cursorSlot.setContents( + self.inventory.getInventorySlots()[index].getContents() + ) self.inventory.getInventorySlots()[index].setContents([]) else: temp = self.inventory.getInventorySlots()[index].getContents() - self.inventory.getInventorySlots()[index].setContents(self.cursorSlot.getContents()) + self.inventory.getInventorySlots()[index].setContents( + self.cursorSlot.getContents() + ) self.cursorSlot.setContents(temp) def handleKeyDownEvent(self, key): @@ -42,7 +50,14 @@ def handleKeyDownEvent(self, key): if not os.path.exists(screenshotsFolder): os.makedirs(screenshotsFolder) x, y = self.graphik.getGameDisplay().get_size() - self.captureScreen(screenshotsFolder + "/screenshot-" + str(datetime.datetime.now()).replace(" ", "-").replace(":", ".") +".png", (0,0), (x,y)) + self.captureScreen( + screenshotsFolder + + "/screenshot-" + + str(datetime.datetime.now()).replace(" ", "-").replace(":", ".") + + ".png", + (0, 0), + (x, y), + ) elif key == pygame.K_1: self.swapCursorSlotWithInventorySlotByIndex(0) elif key == pygame.K_2: @@ -63,7 +78,7 @@ def handleKeyDownEvent(self, key): self.swapCursorSlotWithInventorySlotByIndex(8) elif key == pygame.K_0: self.swapCursorSlotWithInventorySlotByIndex(9) - + def switchToWorldScreen(self): self.nextScreen = ScreenType.WORLD_SCREEN self.changeScreen = True @@ -74,53 +89,87 @@ def quitApplication(self): def drawPlayerInventory(self): # draw inventory background that is 50% size of screen and centered - backgroundX = self.graphik.getGameDisplay().get_width()/4 - backgroundY = self.graphik.getGameDisplay().get_height()/4 - backgroundWidth = self.graphik.getGameDisplay().get_width()/2 - backgroundHeight = self.graphik.getGameDisplay().get_height()/2 - self.graphik.drawRectangle(backgroundX, backgroundY, backgroundWidth, backgroundHeight, (0,0,0)) - + backgroundX = self.graphik.getGameDisplay().get_width() / 4 + backgroundY = self.graphik.getGameDisplay().get_height() / 4 + backgroundWidth = self.graphik.getGameDisplay().get_width() / 2 + backgroundHeight = self.graphik.getGameDisplay().get_height() / 2 + self.graphik.drawRectangle( + backgroundX, backgroundY, backgroundWidth, backgroundHeight, (0, 0, 0) + ) + # draw contents inside inventory background itemsPerRow = 5 row = 0 column = 0 margin = 5 for inventorySlot in self.inventory.getInventorySlots(): - itemX = backgroundX + column*backgroundWidth/itemsPerRow + margin - itemY = backgroundY + row*backgroundHeight/itemsPerRow + margin - itemWidth = backgroundWidth/itemsPerRow - 2*margin - itemHeight = backgroundHeight/itemsPerRow - 2*margin + itemX = backgroundX + column * backgroundWidth / itemsPerRow + margin + itemY = backgroundY + row * backgroundHeight / itemsPerRow + margin + itemWidth = backgroundWidth / itemsPerRow - 2 * margin + itemHeight = backgroundHeight / itemsPerRow - 2 * margin if inventorySlot.isEmpty(): - self.graphik.drawRectangle(itemX, itemY, itemWidth, itemHeight, (255,255,255)) - if row*itemsPerRow + column == self.inventory.getSelectedInventorySlotIndex(): + self.graphik.drawRectangle( + itemX, itemY, itemWidth, itemHeight, (255, 255, 255) + ) + if ( + row * itemsPerRow + column + == self.inventory.getSelectedInventorySlotIndex() + ): # draw yellow square in the middle of the selected inventory slot (may be on any row) - self.graphik.drawRectangle(itemX + itemWidth/2 - 5, itemY + itemHeight/2 - 5, 10, 10, (255,255,0)) + self.graphik.drawRectangle( + itemX + itemWidth / 2 - 5, + itemY + itemHeight / 2 - 5, + 10, + 10, + (255, 255, 0), + ) column += 1 if column == itemsPerRow: column = 0 row += 1 continue - + item = inventorySlot.getContents()[0] image = item.getImage() scaledImage = pygame.transform.scale(image, (itemWidth, itemHeight)) self.graphik.gameDisplay.blit(scaledImage, (itemX, itemY)) - - if row*itemsPerRow + column == self.inventory.getSelectedInventorySlotIndex(): + + if ( + row * itemsPerRow + column + == self.inventory.getSelectedInventorySlotIndex() + ): # draw yellow square in the middle of the selected inventory slot - self.graphik.drawRectangle(itemX + itemWidth/2 - 5, itemY + itemHeight/2 - 5, 10, 10, (255,255,0)) - + self.graphik.drawRectangle( + itemX + itemWidth / 2 - 5, + itemY + itemHeight / 2 - 5, + 10, + 10, + (255, 255, 0), + ) + # draw item amount in bottom right corner of inventory slot - self.graphik.drawText(str(inventorySlot.getNumItems()), itemX + itemWidth - 20, itemY + itemHeight - 20, 20, (255,255,255)) - + self.graphik.drawText( + str(inventorySlot.getNumItems()), + itemX + itemWidth - 20, + itemY + itemHeight - 20, + 20, + (255, 255, 255), + ) + column += 1 if column == itemsPerRow: column = 0 row += 1 - + # draw '(press I to close)' text below inventory - self.graphik.drawText("(press I to close)", backgroundX, backgroundY + backgroundHeight + 20, 20, (255,255,255)) + self.graphik.drawText( + "(press I to close)", + backgroundX, + backgroundY + backgroundHeight + 20, + 20, + (255, 255, 255), + ) def drawBackButton(self): x, y = self.graphik.getGameDisplay().get_size() @@ -128,28 +177,43 @@ def drawBackButton(self): height = 50 xpos = x - width - 10 ypos = y - height - 10 - self.graphik.drawButton(xpos, ypos, width, height, (255,255,255), (0,0,0), 30, "back", self.switchToWorldScreen) + self.graphik.drawButton( + xpos, + ypos, + width, + height, + (255, 255, 255), + (0, 0, 0), + 30, + "back", + self.switchToWorldScreen, + ) def handleMouseClickEvent(self, pos): # get inventory slot that was clicked - backgroundX = self.graphik.getGameDisplay().get_width()/4 - backgroundY = self.graphik.getGameDisplay().get_height()/4 - backgroundWidth = self.graphik.getGameDisplay().get_width()/2 - backgroundHeight = self.graphik.getGameDisplay().get_height()/2 + backgroundX = self.graphik.getGameDisplay().get_width() / 4 + backgroundY = self.graphik.getGameDisplay().get_height() / 4 + backgroundWidth = self.graphik.getGameDisplay().get_width() / 2 + backgroundHeight = self.graphik.getGameDisplay().get_height() / 2 itemsPerRow = 5 row = 0 column = 0 margin = 5 for inventorySlot in self.inventory.getInventorySlots(): - itemX = backgroundX + column*backgroundWidth/itemsPerRow + margin - itemY = backgroundY + row*backgroundHeight/itemsPerRow + margin - itemWidth = backgroundWidth/itemsPerRow - 2*margin - itemHeight = backgroundHeight/itemsPerRow - 2*margin + itemX = backgroundX + column * backgroundWidth / itemsPerRow + margin + itemY = backgroundY + row * backgroundHeight / itemsPerRow + margin + itemWidth = backgroundWidth / itemsPerRow - 2 * margin + itemHeight = backgroundHeight / itemsPerRow - 2 * margin # if mouse click was inside inventory slot - if pos[0] > itemX and pos[0] < itemX + itemWidth and pos[1] > itemY and pos[1] < itemY + itemHeight: - index = row*itemsPerRow + column - + if ( + pos[0] > itemX + and pos[0] < itemX + itemWidth + and pos[1] > itemY + and pos[1] < itemY + itemHeight + ): + index = row * itemsPerRow + column + # select that inventory slot if right mouse button was clicked if pygame.mouse.get_pressed()[2]: self.inventory.setSelectedInventorySlotIndex(index) @@ -160,17 +224,16 @@ def handleMouseClickEvent(self, pos): cursorSlotContents = self.cursorSlot.getContents() inventorySlot.setContents(cursorSlotContents) self.cursorSlot.setContents(inventorySlotContents) - - + column += 1 if column == itemsPerRow: column = 0 row += 1 - + def drawCursorSlot(self): if self.cursorSlot.isEmpty(): return - + item = self.cursorSlot.getContents()[0] image = item.getImage() scaledImage = pygame.transform.scale(image, (50, 50)) @@ -186,21 +249,21 @@ def run(self): self.handleKeyDownEvent(event.key) elif event.type == pygame.MOUSEBUTTONDOWN: self.handleMouseClickEvent(event.pos) - + self.graphik.getGameDisplay().fill((0, 0, 0)) self.drawPlayerInventory() self.drawBackButton() self.drawCursorSlot() pygame.display.update() - + # empty cursor slot when exiting inventory screen if not self.cursorSlot.isEmpty(): for item in self.cursorSlot.getContents(): self.inventory.placeIntoFirstAvailableInventorySlot(item) self.cursorSlot.setContents([]) - + self.changeScreen = False return self.nextScreen - + def setInventory(self, inventory): - self.inventory = inventory \ No newline at end of file + self.inventory = inventory diff --git a/src/screen/mainMenuScreen.py b/src/screen/mainMenuScreen.py index d32f6b5..b8ed4bb 100644 --- a/src/screen/mainMenuScreen.py +++ b/src/screen/mainMenuScreen.py @@ -14,11 +14,11 @@ def __init__(self, graphik: Graphik, config: Config, initializeWorldScreen): self.initializeWorldScreen = initializeWorldScreen self.nextScreen = ScreenType.WORLD_SCREEN self.changeScreen = False - + def switchToWorldScreen(self): self.nextScreen = ScreenType.WORLD_SCREEN self.changeScreen = True - + def switchToConfigScreen(self): self.nextScreen = ScreenType.CONFIG_SCREEN self.changeScreen = True @@ -26,37 +26,74 @@ def switchToConfigScreen(self): def quitApplication(self): pygame.quit() quit() - + def drawText(self): x, y = self.graphik.getGameDisplay().get_size() - xpos = x/2 - ypos = y/10 + xpos = x / 2 + ypos = y / 10 self.graphik.drawText("Roam", xpos, ypos, 64, (255, 255, 255)) - ypos = y/3 - self.graphik.drawText("press any key to start!", xpos, ypos, 32, (255, 255, 255)) - + ypos = y / 3 + self.graphik.drawText( + "press any key to start!", xpos, ypos, 32, (255, 255, 255) + ) + def drawMenuButtons(self): x, y = self.graphik.getGameDisplay().get_size() - width = x/5 - height = y/10 - xpos = x/2 - width/2 - ypos = y/2 - height/2 + width = x / 5 + height = y / 10 + xpos = x / 2 - width / 2 + ypos = y / 2 - height / 2 margin = 10 backgroundColor = (255, 255, 255) - self.graphik.drawButton(xpos, ypos, width, height, backgroundColor, (0,0,0), 30, "play", self.switchToWorldScreen) + self.graphik.drawButton( + xpos, + ypos, + width, + height, + backgroundColor, + (0, 0, 0), + 30, + "play", + self.switchToWorldScreen, + ) ypos = ypos + height + margin - self.graphik.drawButton(xpos, ypos, width, height, backgroundColor, (0,0,0), 30, "config", self.switchToConfigScreen) + self.graphik.drawButton( + xpos, + ypos, + width, + height, + backgroundColor, + (0, 0, 0), + 30, + "config", + self.switchToConfigScreen, + ) ypos = ypos + height + margin - self.graphik.drawButton(xpos, ypos, width, height, backgroundColor, (0,0,0), 30, "quit", self.quitApplication) + self.graphik.drawButton( + xpos, + ypos, + width, + height, + backgroundColor, + (0, 0, 0), + 30, + "quit", + self.quitApplication, + ) def drawVersion(self): if os.path.isfile("version.txt"): with open("version.txt", "r") as file: version = file.read() - + # display centered at bottom of screen - self.graphik.drawText(version, self.graphik.getGameDisplay().get_size()[0]/2, self.graphik.getGameDisplay().get_size()[1] - 10, 16, (255, 255, 255)) - + self.graphik.drawText( + version, + self.graphik.getGameDisplay().get_size()[0] / 2, + self.graphik.getGameDisplay().get_size()[1] - 10, + 16, + (255, 255, 255), + ) def handleKeyDownEvent(self, key): self.switchToWorldScreen() @@ -70,7 +107,7 @@ def run(self): break elif event.type == pygame.KEYDOWN: self.handleKeyDownEvent(event.key) - + self.graphik.getGameDisplay().fill((0, 0, 0)) self.drawText() self.drawMenuButtons() @@ -78,4 +115,4 @@ def run(self): pygame.display.update() self.initializeWorldScreen() self.changeScreen = False - return self.nextScreen \ No newline at end of file + return self.nextScreen diff --git a/src/screen/optionsScreen.py b/src/screen/optionsScreen.py index 4ab2e9b..6925b1f 100644 --- a/src/screen/optionsScreen.py +++ b/src/screen/optionsScreen.py @@ -13,27 +13,27 @@ def __init__(self, graphik: Graphik, config: Config, status: Status): self.running = True self.nextScreen = ScreenType.WORLD_SCREEN self.changeScreen = False - + def handleKeyDownEvent(self, key): if key == pygame.K_ESCAPE: self.switchToWorldScreen() - + def switchToWorldScreen(self): self.nextScreen = ScreenType.WORLD_SCREEN self.changeScreen = True - + def switchToStatsScreen(self): self.nextScreen = ScreenType.STATS_SCREEN self.changeScreen = True - + def switchToInventoryScreen(self): self.nextScreen = ScreenType.INVENTORY_SCREEN self.changeScreen = True - + def switchToMainMenuScreen(self): self.nextScreen = ScreenType.MAIN_MENU_SCREEN self.changeScreen = True - + def switchToConfigScreen(self): self.nextScreen = ScreenType.CONFIG_SCREEN self.changeScreen = True @@ -41,30 +41,70 @@ def switchToConfigScreen(self): def quitApplication(self): self.nextScreen = ScreenType.NONE self.changeScreen = True - + def drawMenuButtons(self): x, y = self.graphik.getGameDisplay().get_size() - width = x/3 - height = y/10 + width = x / 3 + height = y / 10 # start at top of screen - xpos = x/2 - width/2 - ypos = 0 + height/2 + xpos = x / 2 - width / 2 + ypos = 0 + height / 2 margin = 10 - self.graphik.drawButton(xpos, ypos, width, height, (255,255,255), (0,0,0), 30, "main menu", self.switchToMainMenuScreen) + self.graphik.drawButton( + xpos, + ypos, + width, + height, + (255, 255, 255), + (0, 0, 0), + 30, + "main menu", + self.switchToMainMenuScreen, + ) ypos = ypos + height + margin - self.graphik.drawButton(xpos, ypos, width, height, (255,255,255), (0,0,0), 30, "stats", self.switchToStatsScreen) + self.graphik.drawButton( + xpos, + ypos, + width, + height, + (255, 255, 255), + (0, 0, 0), + 30, + "stats", + self.switchToStatsScreen, + ) ypos = ypos + height + margin - self.graphik.drawButton(xpos, ypos, width, height, (255,255,255), (0,0,0), 30, "inventory", self.switchToInventoryScreen) + self.graphik.drawButton( + xpos, + ypos, + width, + height, + (255, 255, 255), + (0, 0, 0), + 30, + "inventory", + self.switchToInventoryScreen, + ) self.drawBackButton() def drawBackButton(self): # draw in bottom right corner x, y = self.graphik.getGameDisplay().get_size() - width = x/3 - height = y/10 - xpos = x/2 - width/2 - ypos = y/2 - height/2 + width - self.graphik.drawButton(xpos, ypos, width, height, (255,255,255), (0,0,0), 30, "back", self.switchToWorldScreen) + width = x / 3 + height = y / 10 + xpos = x / 2 - width / 2 + ypos = y / 2 - height / 2 + width + self.graphik.drawButton( + xpos, + ypos, + width, + height, + (255, 255, 255), + (0, 0, 0), + 30, + "back", + self.switchToWorldScreen, + ) def run(self): while not self.changeScreen: @@ -72,11 +112,11 @@ def run(self): if event.type == pygame.QUIT: return ScreenType.NONE elif event.type == pygame.KEYDOWN: - self.handleKeyDownEvent(event.key) - + self.handleKeyDownEvent(event.key) + self.graphik.getGameDisplay().fill((0, 0, 0)) self.drawMenuButtons() pygame.display.update() - + self.changeScreen = False - return self.nextScreen \ No newline at end of file + return self.nextScreen diff --git a/src/screen/screenType.py b/src/screen/screenType.py index 6123f55..4aec270 100644 --- a/src/screen/screenType.py +++ b/src/screen/screenType.py @@ -6,4 +6,4 @@ class ScreenType: STATS_SCREEN = "stats_screen" INVENTORY_SCREEN = "inventory_screen" CONFIG_SCREEN = "config_screen" - NONE = "none_screen" \ No newline at end of file + NONE = "none_screen" diff --git a/src/screen/statsScreen.py b/src/screen/statsScreen.py index 28c8a71..073f7f8 100644 --- a/src/screen/statsScreen.py +++ b/src/screen/statsScreen.py @@ -16,13 +16,15 @@ def __init__(self, graphik: Graphik, config: Config, status: Status, stats: Stat self.stats = stats self.nextScreen = ScreenType.OPTIONS_SCREEN self.changeScreen = False - + # @source https://stackoverflow.com/questions/63342477/how-to-take-screenshot-of-entire-display-pygame - def captureScreen(self, name, pos, size): # (pygame Surface, String, tuple, tuple) + def captureScreen(self, name, pos, size): # (pygame Surface, String, tuple, tuple) image = pygame.Surface(size) # Create image surface - image.blit(self.graphik.getGameDisplay(), (0,0), (pos, size)) # Blit portion of the display to the image + image.blit( + self.graphik.getGameDisplay(), (0, 0), (pos, size) + ) # Blit portion of the display to the image pygame.image.save(image, name) # Save the image to the disk** - + def handleKeyDownEvent(self, key): if key == pygame.K_ESCAPE: self.switchToOptionsScreen() @@ -31,8 +33,15 @@ def handleKeyDownEvent(self, key): if not os.path.exists(screenshotsFolder): os.makedirs(screenshotsFolder) x, y = self.graphik.getGameDisplay().get_size() - self.captureScreen(screenshotsFolder + "/screenshot-" + str(datetime.datetime.now()).replace(" ", "-").replace(":", ".") +".png", (0,0), (x,y)) - + self.captureScreen( + screenshotsFolder + + "/screenshot-" + + str(datetime.datetime.now()).replace(" ", "-").replace(":", ".") + + ".png", + (0, 0), + (x, y), + ) + def switchToOptionsScreen(self): self.nextScreen = ScreenType.OPTIONS_SCREEN self.changeScreen = True @@ -43,42 +52,52 @@ def quitApplication(self): def drawStats(self): x, y = self.graphik.getGameDisplay().get_size() - + # aim for center of screen - width = x/5 - height = y/10 - xpos = x/2 - ypos = 0 + height/2 - + x / 5 + height = y / 10 + xpos = x / 2 + ypos = 0 + height / 2 + # draw score text = "score: " + str(self.stats.getScore()) - self.graphik.drawText(text, xpos, ypos, 30, (255,255,255)) - + self.graphik.drawText(text, xpos, ypos, 30, (255, 255, 255)) + # draw rooms explored self.xpos = xpos self.ypos = ypos + height text = "rooms explored: " + str(self.stats.getRoomsExplored()) - self.graphik.drawText(text, xpos, ypos + height, 30, (255,255,255)) - + self.graphik.drawText(text, xpos, ypos + height, 30, (255, 255, 255)) + # draw apples eaten self.xpos = xpos - self.ypos = ypos + height*2 + self.ypos = ypos + height * 2 text = "food eaten: " + str(self.stats.getFoodEaten()) - self.graphik.drawText(text, xpos, ypos + height*2, 30, (255,255,255)) - + self.graphik.drawText(text, xpos, ypos + height * 2, 30, (255, 255, 255)) + # draw number of deaths self.xpos = xpos - self.ypos = ypos + height*3 + self.ypos = ypos + height * 3 text = "number of deaths: " + str(self.stats.getNumberOfDeaths()) - self.graphik.drawText(text, xpos, ypos + height*3, 30, (255,255,255)) + self.graphik.drawText(text, xpos, ypos + height * 3, 30, (255, 255, 255)) def drawBackButton(self): x, y = self.graphik.getGameDisplay().get_size() - width = x/5 - height = y/10 - xpos = x/2 - width/2 - ypos = y/2 - height/2 + width - self.graphik.drawButton(xpos, ypos, width, height, (255,255,255), (0,0,0), 30, "back", self.switchToOptionsScreen) + width = x / 5 + height = y / 10 + xpos = x / 2 - width / 2 + ypos = y / 2 - height / 2 + width + self.graphik.drawButton( + xpos, + ypos, + width, + height, + (255, 255, 255), + (0, 0, 0), + 30, + "back", + self.switchToOptionsScreen, + ) def run(self): while not self.changeScreen: @@ -88,11 +107,11 @@ def run(self): self.changeScreen = True elif event.type == pygame.KEYDOWN: self.handleKeyDownEvent(event.key) - + self.graphik.getGameDisplay().fill((0, 0, 0)) self.drawStats() self.drawBackButton() pygame.display.update() - + self.changeScreen = False - return self.nextScreen \ No newline at end of file + return self.nextScreen diff --git a/src/screen/worldScreen.py b/src/screen/worldScreen.py index afa8c7a..6b04f03 100644 --- a/src/screen/worldScreen.py +++ b/src/screen/worldScreen.py @@ -2,9 +2,7 @@ import json from math import ceil import os -import random import time -from uuid import UUID import jsonschema import pygame from entity.apple import Apple @@ -21,7 +19,6 @@ from screen.screenType import ScreenType from stats.stats import Stats from ui.energyBar import EnergyBar -from entity.food import Food from lib.graphik.src.graphik import Graphik from entity.grass import Grass from lib.pyenvlib.grid import Grid @@ -29,7 +26,6 @@ from entity.leaves import Leaves from lib.pyenvlib.location import Location from world.room import Room -from world.roomFactory import RoomFactory from world.roomJsonReaderWriter import RoomJsonReaderWriter from world.tickCounter import TickCounter from world.map import Map @@ -40,7 +36,15 @@ # @author Daniel McCoy Stephenson # @since August 16th, 2022 class WorldScreen: - def __init__(self, graphik: Graphik, config: Config, status: Status, tickCounter: TickCounter, stats: Stats, player: Player): + def __init__( + self, + graphik: Graphik, + config: Config, + status: Status, + tickCounter: TickCounter, + stats: Stats, + player: Player, + ): self.graphik = graphik self.config = config self.status = status @@ -51,17 +55,21 @@ def __init__(self, graphik: Graphik, config: Config, status: Status, tickCounter self.showInventory = False self.nextScreen = ScreenType.OPTIONS_SCREEN self.changeScreen = False - self.roomJsonReaderWriter = RoomJsonReaderWriter(self.config.gridSize, self.graphik, self.tickCounter, self.config) + self.roomJsonReaderWriter = RoomJsonReaderWriter( + self.config.gridSize, self.graphik, self.tickCounter, self.config + ) self.mapImageUpdater = MapImageUpdater(self.tickCounter, self.config) self.minimapScaleFactor = 0.10 self.minimapX = 5 self.minimapY = 5 - + def initialize(self): - self.map = Map(self.config.gridSize, self.graphik, self.tickCounter, self.config) - + self.map = Map( + self.config.gridSize, self.graphik, self.tickCounter, self.config + ) + # load player location if possible - if (os.path.exists(self.config.pathToSaveDirectory + "/playerLocation.json")): + if os.path.exists(self.config.pathToSaveDirectory + "/playerLocation.json"): self.loadPlayerLocationFromFile() else: self.currentRoom = self.map.getRoom(0, 0) @@ -69,32 +77,32 @@ def initialize(self): self.currentRoom = self.map.generateNewRoom(0, 0) self.currentRoom.addEntity(self.player) self.stats.incrementRoomsExplored() - + # load player attributes if possible - if (os.path.exists(self.config.pathToSaveDirectory + "/playerAttributes.json")): + if os.path.exists(self.config.pathToSaveDirectory + "/playerAttributes.json"): self.loadPlayerAttributesFromFile() - + # load stats if possible - if (os.path.exists(self.config.pathToSaveDirectory + "/stats.json")): + if os.path.exists(self.config.pathToSaveDirectory + "/stats.json"): self.stats.load() - + # load tick if possible - if (os.path.exists(self.config.pathToSaveDirectory + "/tick.json")): + if os.path.exists(self.config.pathToSaveDirectory + "/tick.json"): self.tickCounter.load() - + # load player inventory if possible - if (os.path.exists(self.config.pathToSaveDirectory + "/playerInventory.json")): + if os.path.exists(self.config.pathToSaveDirectory + "/playerInventory.json"): self.loadPlayerInventoryFromFile() - + self.initializeLocationWidthAndHeight() - + self.status.set("entered the world") self.energyBar = EnergyBar(self.graphik, self.player) def initializeLocationWidthAndHeight(self): x, y = self.graphik.getGameDisplay().get_size() - self.locationWidth = x/self.currentRoom.getGrid().getRows() - self.locationHeight = y/self.currentRoom.getGrid().getColumns() + self.locationWidth = x / self.currentRoom.getGrid().getRows() + self.locationHeight = y / self.currentRoom.getGrid().getColumns() def printStatsToConsole(self): print("=== Stats ===") @@ -103,7 +111,7 @@ def printStatsToConsole(self): print("Number of deaths: " + str(self.stats.getNumberOfDeaths())) print("") print("Score: " + str(self.stats.getScore())) - print("----------") + print("----------") def getLocationOfPlayer(self): return self.map.getLocationOfEntity(self.player, self.currentRoom) @@ -119,7 +127,7 @@ def getLocationDirection(self, direction: int, grid: Grid, location: Location): return grid.getRight(location) elif direction == -1: return -1 - + def getCoordinatesForNewRoomBasedOnPlayerLocationAndDirection(self): location = self.getLocationOfPlayer() x = self.currentRoom.getX() @@ -152,7 +160,10 @@ def getCoordinatesForNewRoomBasedOnPlayerLocationAndDirection(self): elif direction == 1: x -= 1 # if bottom right corner - elif location.getX() == self.config.gridSize - 1 and location.getY() == self.config.gridSize - 1: + elif ( + location.getX() == self.config.gridSize - 1 + and location.getY() == self.config.gridSize - 1 + ): # if facing down if direction == 2: y += 1 @@ -173,14 +184,14 @@ def getCoordinatesForNewRoomBasedOnPlayerLocationAndDirection(self): # we are at the top of this room y -= 1 return x, y - + def getCoordinatesForNewRoomBasedOnLivingEntityLocation(self, livingEntity): # get location of living entity in current room locationId = livingEntity.getLocationID() location = self.currentRoom.getGrid().getLocation(locationId) - locationX = location.getX() - locationY = location.getY() - + location.getX() + location.getY() + # get coordinates of new room based on location of living entity x = self.currentRoom.getX() y = self.currentRoom.getY() @@ -200,33 +211,59 @@ def getCoordinatesForNewRoomBasedOnLivingEntityLocation(self, livingEntity): # we are at the top of this room y -= 1 return x, y - + def ifCorner(self, location: Location): - return (location.getX() == 0 and location.getY() == 0) or (location.getX() == self.config.gridSize - 1 and location.getY() == 0) or (location.getX() == 0 and location.getY() == self.config.gridSize - 1) or (location.getX() == self.config.gridSize - 1 and location.getY() == self.config.gridSize - 1) - + return ( + (location.getX() == 0 and location.getY() == 0) + or (location.getX() == self.config.gridSize - 1 and location.getY() == 0) + or (location.getX() == 0 and location.getY() == self.config.gridSize - 1) + or ( + location.getX() == self.config.gridSize - 1 + and location.getY() == self.config.gridSize - 1 + ) + ) + def saveCurrentRoomToFile(self): self.saveRoomToFile(self.currentRoom) - + def saveRoomToFile(self, room: Room): - roomPath = self.config.pathToSaveDirectory + "/rooms/room_" + str(room.getX()) + "_" + str(room.getY()) + ".json" + roomPath = ( + self.config.pathToSaveDirectory + + "/rooms/room_" + + str(room.getX()) + + "_" + + str(room.getY()) + + ".json" + ) self.roomJsonReaderWriter.saveRoom(room, roomPath) - + def changeRooms(self): x, y = self.getCoordinatesForNewRoomBasedOnPlayerLocationAndDirection() - if self.config.worldBorder != 0 and (abs(x) > self.config.worldBorder or abs(y) > self.config.worldBorder): + if self.config.worldBorder != 0 and ( + abs(x) > self.config.worldBorder or abs(y) > self.config.worldBorder + ): self.status.set("reached world border") return playerLocation = self.getLocationOfPlayer() self.currentRoom.removeEntity(self.player) - + room = self.map.getRoom(x, y) if room == -1: # attempt to load room if file exists, otherwise generate new room - nextRoomPath = self.config.pathToSaveDirectory + "/rooms/room_" + str(x) + "_" + str(y) + ".json" + nextRoomPath = ( + self.config.pathToSaveDirectory + + "/rooms/room_" + + str(x) + + "_" + + str(y) + + ".json" + ) if os.path.exists(nextRoomPath): - roomJsonReaderWriter = RoomJsonReaderWriter(self.config.gridSize, self.graphik, self.tickCounter) + roomJsonReaderWriter = RoomJsonReaderWriter( + self.config.gridSize, self.graphik, self.tickCounter + ) room = roomJsonReaderWriter.loadRoom(nextRoomPath) self.map.addRoom(room) self.currentRoom = room @@ -245,7 +282,7 @@ def changeRooms(self): min = 0 max = self.config.gridSize - 1 - + # if in corner if self.ifCorner(playerLocation): playerDirection = self.player.getDirection() @@ -292,16 +329,20 @@ def changeRooms(self): elif playerLocation.getY() == max: targetY = min - targetLocation = self.currentRoom.getGrid().getLocationByCoordinates(targetX, targetY) + targetLocation = self.currentRoom.getGrid().getLocationByCoordinates( + targetX, targetY + ) self.currentRoom.addEntityToLocation(self.player, targetLocation) self.initializeLocationWidthAndHeight() - - def movePlayer(self, direction: int): + + def movePlayer(self, direction: int): if self.player.isCrouching(): return location = self.getLocationOfPlayer() - newLocation = self.getLocationDirection(direction, self.currentRoom.getGrid(), location) + newLocation = self.getLocationDirection( + direction, self.currentRoom.getGrid(), location + ) if newLocation == -1: # we're at a border @@ -311,14 +352,14 @@ def movePlayer(self, direction: int): if self.locationContainsSolidEntity(newLocation): return - + # if bear is in the new location, kill the player for entityId in list(newLocation.getEntities().keys()): entity = newLocation.getEntity(entityId) if isinstance(entity, Bear): self.player.kill() return - + if self.player.needsEnergy(): # search for food to eat for entityId in list(newLocation.getEntities().keys()): @@ -326,45 +367,60 @@ def movePlayer(self, direction: int): if self.player.canEat(entity): newLocation.removeEntity(entity) self.player.addEnergy(entity.getEnergy()) - + self.stats.incrementFoodEaten() - + self.status.set("ate '" + entity.getName() + "'") - + self.stats.incrementScore() # move player location.removeEntity(self.player) newLocation.addEntity(self.player) - + # decrease energy self.player.removeEnergy(self.config.playerMovementEnergyCost) self.player.setTickLastMoved(self.tickCounter.getTick()) - + def canBePickedUp(self, entity): - itemTypes = [OakWood, JungleWood, Leaves, Grass, Apple, Stone, CoalOre, IronOre, Chicken, Bear, Banana] + itemTypes = [ + OakWood, + JungleWood, + Leaves, + Grass, + Apple, + Stone, + CoalOre, + IronOre, + Chicken, + Bear, + Banana, + ] for itemType in itemTypes: if isinstance(entity, itemType): return True return False - + def getLocationAtMousePosition(self): x, y = pygame.mouse.get_pos() x = int(x / self.locationWidth) y = int(y / self.locationHeight) return self.currentRoom.getGrid().getLocationByCoordinates(x, y) - + def executeGatherAction(self): targetLocation = self.getLocationAtMousePosition() - + if targetLocation == -1: self.status.set("no location available") return - + # if location too far away distanceLimit = self.config.playerInteractionDistanceLimit playerLocation = self.getLocationOfPlayer() - if abs(targetLocation.getX() - playerLocation.getX()) > distanceLimit or abs(targetLocation.getY() - playerLocation.getY()) > distanceLimit: + if ( + abs(targetLocation.getX() - playerLocation.getX()) > distanceLimit + or abs(targetLocation.getY() - playerLocation.getY()) > distanceLimit + ): self.status.set("too far away") return @@ -378,8 +434,10 @@ def executeGatherAction(self): if toRemove == -1: return - - result = self.player.getInventory().placeIntoFirstAvailableInventorySlot(toRemove) + + result = self.player.getInventory().placeIntoFirstAvailableInventorySlot( + toRemove + ) if result == False: self.status.set("no available inventory slots") return @@ -389,7 +447,7 @@ def executeGatherAction(self): self.status.set("picked up '" + entity.getName() + "'") self.player.removeEnergy(self.config.playerInteractionEnergyCost) self.player.setTickLastGathered(self.tickCounter.getTick()) - + def getLocationInFrontOfPlayer(self): lastDirectionPlayerWasFacing = self.player.getLastDirection() directionPlayerIsFacing = self.player.getDirection() @@ -398,15 +456,17 @@ def getLocationInFrontOfPlayer(self): # player was standing still direction = directionPlayerIsFacing playerLocation = self.getLocationOfPlayer() - return self.getLocationDirection(direction, self.currentRoom.grid, playerLocation) - + return self.getLocationDirection( + direction, self.currentRoom.grid, playerLocation + ) + def locationContainsSolidEntity(self, location): for entityId in list(location.getEntities().keys()): entity = location.getEntity(entityId) if entity.isSolid(): return True return False - + def executePlaceAction(self): if self.player.getInventory().getNumTakenInventorySlots() == 0: self.status.set("no items") @@ -422,14 +482,17 @@ def executePlaceAction(self): if self.locationContainsSolidEntity(targetLocation): self.status.set("location blocked") return - + # if location too far away distanceLimit = self.config.playerInteractionDistanceLimit playerLocation = self.getLocationOfPlayer() - if abs(targetLocation.getX() - playerLocation.getX()) > distanceLimit or abs(targetLocation.getY() - playerLocation.getY()) > distanceLimit: + if ( + abs(targetLocation.getX() - playerLocation.getX()) > distanceLimit + or abs(targetLocation.getY() - playerLocation.getY()) > distanceLimit + ): self.status.set("too far away") return - + # if living entity is in the location, don't place for entityId in list(targetLocation.getEntities().keys()): entity = targetLocation.getEntity(entityId) @@ -443,17 +506,17 @@ def executePlaceAction(self): if inventorySlot.isEmpty(): self.status.set("no item selected") return - toPlace = self.player.getInventory().removeSelectedItem() + toPlace = self.player.getInventory().removeSelectedItem() if toPlace == -1: return - + self.currentRoom.addEntityToLocation(toPlace, targetLocation) if isinstance(toPlace, LivingEntity): self.currentRoom.addLivingEntity(toPlace) self.status.set("placed '" + toPlace.getName() + "'") self.player.setTickLastPlaced(self.tickCounter.getTick()) - + def changeSelectedInventorySlot(self, index): self.player.getInventory().setSelectedInventorySlotIndex(index) inventorySlot = self.player.getInventory().getSelectedInventorySlot() @@ -489,10 +552,19 @@ def handleKeyDownEvent(self, key): if not os.path.exists(screenshotsFolder): os.makedirs(screenshotsFolder) x, y = self.graphik.getGameDisplay().get_size() - self.captureScreen(screenshotsFolder + "/screenshot-" + str(datetime.datetime.now()).replace(" ", "-").replace(":", ".") +".png", (0,0), (x,y)) + self.captureScreen( + screenshotsFolder + + "/screenshot-" + + str(datetime.datetime.now()).replace(" ", "-").replace(":", ".") + + ".png", + (0, 0), + (x, y), + ) self.status.set("screenshot saved") elif key == pygame.K_LSHIFT: - self.player.setMovementSpeed(self.player.getMovementSpeed()*self.config.runSpeedFactor) + self.player.setMovementSpeed( + self.player.getMovementSpeed() * self.config.runSpeedFactor + ) elif key == pygame.K_LCTRL: self.player.setCrouching(True) elif key == pygame.K_i: @@ -537,29 +609,41 @@ def handleKeyDownEvent(self, key): self.minimapScaleFactor -= 0.1 def handleKeyUpEvent(self, key): - if (key == pygame.K_w or key == pygame.K_UP) and self.player.getDirection() == 0: + if ( + key == pygame.K_w or key == pygame.K_UP + ) and self.player.getDirection() == 0: self.player.setDirection(-1) - elif (key == pygame.K_a or key == pygame.K_LEFT) and self.player.getDirection() == 1: + elif ( + key == pygame.K_a or key == pygame.K_LEFT + ) and self.player.getDirection() == 1: self.player.setDirection(-1) - elif (key == pygame.K_s or key == pygame.K_DOWN) and self.player.getDirection() == 2: + elif ( + key == pygame.K_s or key == pygame.K_DOWN + ) and self.player.getDirection() == 2: self.player.setDirection(-1) - elif (key == pygame.K_d or key == pygame.K_RIGHT) and self.player.getDirection() == 3: + elif ( + key == pygame.K_d or key == pygame.K_RIGHT + ) and self.player.getDirection() == 3: self.player.setDirection(-1) elif key == pygame.K_e: self.player.setGathering(False) elif key == pygame.K_q: self.player.setPlacing(False) elif key == pygame.K_LSHIFT: - self.player.setMovementSpeed(self.player.getMovementSpeed()/self.config.runSpeedFactor) + self.player.setMovementSpeed( + self.player.getMovementSpeed() / self.config.runSpeedFactor + ) elif key == pygame.K_LCTRL: self.player.setCrouching(False) # @source https://stackoverflow.com/questions/63342477/how-to-take-screenshot-of-entire-display-pygame - def captureScreen(self, name, pos, size): # (pygame Surface, String, tuple, tuple) + def captureScreen(self, name, pos, size): # (pygame Surface, String, tuple, tuple) image = pygame.Surface(size) # Create image surface - image.blit(self.graphik.getGameDisplay(), (0,0), (pos, size)) # Blit portion of the display to the image + image.blit( + self.graphik.getGameDisplay(), (0, 0), (pos, size) + ) # Blit portion of the display to the image pygame.image.save(image, name) # Save the image to the disk** - + def respawnPlayer(self): # drop all items and clear inventory playerLocationId = self.player.getLocationID() @@ -575,26 +659,35 @@ def respawnPlayer(self): self.currentRoom.removeEntity(self.player) self.map.getRoom(0, 0).addEntity(self.player) - + self.save() - + self.currentRoom = self.map.getRoom(0, 0) self.player.energy = self.player.targetEnergy self.status.set("respawned") self.player.setTickCreated(self.tickCounter.getTick()) - + def checkPlayerMovementCooldown(self, tickToCheck): ticksPerSecond = self.config.ticksPerSecond - return tickToCheck + ticksPerSecond/self.player.getMovementSpeed() < self.tickCounter.getTick() - + return ( + tickToCheck + ticksPerSecond / self.player.getMovementSpeed() + < self.tickCounter.getTick() + ) + def checkPlayerGatherCooldown(self, tickToCheck): ticksPerSecond = self.config.ticksPerSecond - return tickToCheck + ticksPerSecond/self.player.getGatherSpeed() < self.tickCounter.getTick() - + return ( + tickToCheck + ticksPerSecond / self.player.getGatherSpeed() + < self.tickCounter.getTick() + ) + def checkPlayerPlaceCooldown(self, tickToCheck): ticksPerSecond = self.config.ticksPerSecond - return tickToCheck + ticksPerSecond/self.player.getPlaceSpeed() < self.tickCounter.getTick() - + return ( + tickToCheck + ticksPerSecond / self.player.getPlaceSpeed() + < self.tickCounter.getTick() + ) + def eatFoodInInventory(self): for itemSlot in self.player.getInventory().getInventorySlots(): if itemSlot.isEmpty(): @@ -604,24 +697,30 @@ def eatFoodInInventory(self): self.player.addEnergy(item.getEnergy()) self.player.getInventory().removeByItem(item) self.stats.incrementFoodEaten() - + self.status.set("ate " + item.getName() + " from inventory") - + self.stats.incrementScore() return - + def handlePlayerActions(self): - if self.player.isMoving() and self.checkPlayerMovementCooldown(self.player.getTickLastMoved()): + if self.player.isMoving() and self.checkPlayerMovementCooldown( + self.player.getTickLastMoved() + ): self.movePlayer(self.player.direction) - if self.player.isGathering() and self.checkPlayerGatherCooldown(self.player.getTickLastGathered()): + if self.player.isGathering() and self.checkPlayerGatherCooldown( + self.player.getTickLastGathered() + ): self.executeGatherAction() - elif self.player.isPlacing() and self.checkPlayerPlaceCooldown(self.player.getTickLastPlaced()): + elif self.player.isPlacing() and self.checkPlayerPlaceCooldown( + self.player.getTickLastPlaced() + ): self.executePlaceAction() - + if self.player.needsEnergy() and self.config.autoEatFoodInInventory: self.eatFoodInInventory() - + def removeEnergyAndCheckForPlayerDeath(self): self.player.removeEnergy(self.config.energyDepletionRate) if self.player.getEnergy() < self.player.getTargetEnergy() * 0.10: @@ -630,26 +729,49 @@ def removeEnergyAndCheckForPlayerDeath(self): self.status.set("you died") self.stats.setScore(ceil(self.stats.getScore() * 0.9)) self.stats.incrementNumberOfDeaths() - + def switchToInventoryScreen(self): self.nextScreen = ScreenType.INVENTORY_SCREEN self.changeScreen = True - + def isCurrentRoomSavedAsPNG(self): - path = self.config.pathToSaveDirectory + "/roompngs/" + str(self.currentRoom.getX()) + "_" + str(self.currentRoom.getY()) + ".png" + path = ( + self.config.pathToSaveDirectory + + "/roompngs/" + + str(self.currentRoom.getX()) + + "_" + + str(self.currentRoom.getY()) + + ".png" + ) return os.path.isfile(path) - + def saveCurrentRoomAsPNG(self): if not os.path.exists(self.config.pathToSaveDirectory + "/roompngs"): os.makedirs(self.config.pathToSaveDirectory + "/roompngs") - + # remove player - locationOfPlayer = self.currentRoom.getGrid().getLocation(self.player.getLocationID()) + locationOfPlayer = self.currentRoom.getGrid().getLocation( + self.player.getLocationID() + ) self.currentRoom.removeEntity(self.player) self.currentRoom.draw(self.locationWidth, self.locationHeight) - path = self.config.pathToSaveDirectory + "/roompngs/" + str(self.currentRoom.getX()) + "_" + str(self.currentRoom.getY()) + ".png" - self.captureScreen(path, (0, 0), (self.graphik.getGameDisplay().get_width(), self.graphik.getGameDisplay().get_height())) + path = ( + self.config.pathToSaveDirectory + + "/roompngs/" + + str(self.currentRoom.getX()) + + "_" + + str(self.currentRoom.getY()) + + ".png" + ) + self.captureScreen( + path, + (0, 0), + ( + self.graphik.getGameDisplay().get_width(), + self.graphik.getGameDisplay().get_height(), + ), + ) # add player back self.currentRoom.addEntityToLocation(self.player, locationOfPlayer) @@ -658,94 +780,154 @@ def drawMiniMap(self): # if map image doesn't exist, return if not os.path.isfile(self.config.pathToSaveDirectory + "/mapImage.png"): return - + # get mapImage.png for current save mapImage = pygame.image.load(self.config.pathToSaveDirectory + "/mapImage.png") # scale with respect to size of display - mapImage = pygame.transform.scale(mapImage, (self.graphik.getGameDisplay().get_width() * self.minimapScaleFactor, self.graphik.getGameDisplay().get_height() * self.minimapScaleFactor)) + mapImage = pygame.transform.scale( + mapImage, + ( + self.graphik.getGameDisplay().get_width() * self.minimapScaleFactor, + self.graphik.getGameDisplay().get_height() * self.minimapScaleFactor, + ), + ) # draw rectangle backgroundColor = (200, 200, 200) - self.graphik.drawRectangle(self.minimapX, self.minimapY, mapImage.get_width() + 20, mapImage.get_height() + 20, backgroundColor) + self.graphik.drawRectangle( + self.minimapX, + self.minimapY, + mapImage.get_width() + 20, + mapImage.get_height() + 20, + backgroundColor, + ) # blit in top left corner with 10px padding - self.graphik.getGameDisplay().blit(mapImage, (self.minimapX + 10, self.minimapY + 10)) + self.graphik.getGameDisplay().blit( + mapImage, (self.minimapX + 10, self.minimapY + 10) + ) def draw(self): self.graphik.getGameDisplay().fill(self.currentRoom.getBackgroundColor()) if self.config.showMiniMap and not self.isCurrentRoomSavedAsPNG(): self.saveCurrentRoomAsPNG() - + self.currentRoom.draw(self.locationWidth, self.locationHeight) self.status.draw() self.energyBar.draw() - - itemPreviewXPos = self.graphik.getGameDisplay().get_width()/2 - 50*5 - 50/2 - itemPreviewYPos = self.graphik.getGameDisplay().get_height() - 50*3 + + itemPreviewXPos = ( + self.graphik.getGameDisplay().get_width() / 2 - 50 * 5 - 50 / 2 + ) + itemPreviewYPos = self.graphik.getGameDisplay().get_height() - 50 * 3 itemPreviewWidth = 50 itemPreviewHeight = 50 - + barXPos = itemPreviewXPos - 5 barYPos = itemPreviewYPos - 5 - barWidth = itemPreviewWidth*11 + 5 + barWidth = itemPreviewWidth * 11 + 5 barHeight = itemPreviewHeight + 10 - + # draw rectangle slightly bigger than item images - self.graphik.drawRectangle(barXPos, barYPos, barWidth, barHeight, (0,0,0)) - + self.graphik.drawRectangle(barXPos, barYPos, barWidth, barHeight, (0, 0, 0)) + # draw first 10 items in player inventory in bottom center firstTenInventorySlots = self.player.getInventory().getFirstTenInventorySlots() for i in range(len(firstTenInventorySlots)): inventorySlot = firstTenInventorySlots[i] if inventorySlot.isEmpty(): # draw white square if item slot is empty - self.graphik.drawRectangle(itemPreviewXPos, itemPreviewYPos, itemPreviewWidth, itemPreviewHeight, (255,255,255)) + self.graphik.drawRectangle( + itemPreviewXPos, + itemPreviewYPos, + itemPreviewWidth, + itemPreviewHeight, + (255, 255, 255), + ) if i == self.player.getInventory().getSelectedInventorySlotIndex(): # draw yellow square in the middle of the selected inventory slot - self.graphik.drawRectangle(itemPreviewXPos + itemPreviewWidth/2 - 5, itemPreviewYPos + itemPreviewHeight/2 - 5, 10, 10, (255,255,0)) + self.graphik.drawRectangle( + itemPreviewXPos + itemPreviewWidth / 2 - 5, + itemPreviewYPos + itemPreviewHeight / 2 - 5, + 10, + 10, + (255, 255, 0), + ) itemPreviewXPos += 50 + 5 continue item = inventorySlot.getContents()[0] image = item.getImage() scaledImage = pygame.transform.scale(image, (50, 50)) - self.graphik.gameDisplay.blit(scaledImage, (itemPreviewXPos, itemPreviewYPos)) - + self.graphik.gameDisplay.blit( + scaledImage, (itemPreviewXPos, itemPreviewYPos) + ) + if i == self.player.getInventory().getSelectedInventorySlotIndex(): # draw yellow square in the middle of the selected inventory slot - self.graphik.drawRectangle(itemPreviewXPos + itemPreviewWidth/2 - 5, itemPreviewYPos + itemPreviewHeight/2 - 5, 10, 10, (255,255,0)) - + self.graphik.drawRectangle( + itemPreviewXPos + itemPreviewWidth / 2 - 5, + itemPreviewYPos + itemPreviewHeight / 2 - 5, + 10, + 10, + (255, 255, 0), + ) + # draw item amount in bottom right corner of inventory slot - self.graphik.drawText(str(inventorySlot.getNumItems()), itemPreviewXPos + itemPreviewWidth - 20, itemPreviewYPos + itemPreviewHeight - 20, 20, (255,255,255)) - + self.graphik.drawText( + str(inventorySlot.getNumItems()), + itemPreviewXPos + itemPreviewWidth - 20, + itemPreviewYPos + itemPreviewHeight - 20, + 20, + (255, 255, 255), + ) + itemPreviewXPos += 50 + 5 - + if self.config.debug: # display tick count in top right corner tickValue = self.tickCounter.getTick() measuredTicksPerSecond = self.tickCounter.getMeasuredTicksPerSecond() xpos = self.graphik.getGameDisplay().get_width() - 100 ypos = 20 - self.graphik.drawText("tick: " + str(tickValue) + " (" + str(int(measuredTicksPerSecond)) + " mtps)", xpos, ypos, 20, (255,255,255)) + self.graphik.drawText( + "tick: " + + str(tickValue) + + " (" + + str(int(measuredTicksPerSecond)) + + " mtps)", + xpos, + ypos, + 20, + (255, 255, 255), + ) # display max measured ticks per second in top right corner highestmtps = self.tickCounter.getHighestMeasuredTicksPerSecond() xpos = self.graphik.getGameDisplay().get_width() - 100 ypos = 40 - self.graphik.drawText("max mtps: " + str(int(highestmtps)), xpos, ypos, 20, (255,255,255)) + self.graphik.drawText( + "max mtps: " + str(int(highestmtps)), xpos, ypos, 20, (255, 255, 255) + ) # draw room coordinates in top left corner - coordinatesText = "(" + str(self.currentRoom.getX()) + ", " + str(self.currentRoom.getY() * -1) + ")" + coordinatesText = ( + "(" + + str(self.currentRoom.getX()) + + ", " + + str(self.currentRoom.getY() * -1) + + ")" + ) ypos = 20 if self.config.showMiniMap: # move to bottom left ypos = self.graphik.getGameDisplay().get_height() - 40 - self.graphik.drawText(coordinatesText, 30, ypos, 20, (255,255,255)) - + self.graphik.drawText(coordinatesText, 30, ypos, 20, (255, 255, 255)) + if self.config.showMiniMap and self.minimapScaleFactor > 0: self.drawMiniMap() - + pygame.display.update() def handleMouseDownEvent(self): @@ -753,9 +935,9 @@ def handleMouseDownEvent(self): # disallow player to interact with the world while inventory is open self.status.set("close inventory to interact with the world") return - if pygame.mouse.get_pressed()[0]: # left click + if pygame.mouse.get_pressed()[0]: # left click self.player.setGathering(True) - elif pygame.mouse.get_pressed()[2]: # right click + elif pygame.mouse.get_pressed()[2]: # right click self.player.setPlacing(True) def handleMouseUpEvent(self): @@ -763,21 +945,29 @@ def handleMouseUpEvent(self): self.player.setGathering(False) if not pygame.mouse.get_pressed()[2]: self.player.setPlacing(False) - + def handleMouseWheelEvent(self, event): if event.y > 0: - currentSelectedInventorySlotIndex = self.player.getInventory().getSelectedInventorySlotIndex() + currentSelectedInventorySlotIndex = ( + self.player.getInventory().getSelectedInventorySlotIndex() + ) newSelectedInventorySlotIndex = currentSelectedInventorySlotIndex - 1 if newSelectedInventorySlotIndex < 0: newSelectedInventorySlotIndex = 9 - self.player.getInventory().setSelectedInventorySlotIndex(newSelectedInventorySlotIndex) + self.player.getInventory().setSelectedInventorySlotIndex( + newSelectedInventorySlotIndex + ) elif event.y < 0: - currentSelectedInventorySlotIndex = self.player.getInventory().getSelectedInventorySlotIndex() + currentSelectedInventorySlotIndex = ( + self.player.getInventory().getSelectedInventorySlotIndex() + ) newSelectedInventorySlotIndex = currentSelectedInventorySlotIndex + 1 if newSelectedInventorySlotIndex > 9: newSelectedInventorySlotIndex = 0 - self.player.getInventory().setSelectedInventorySlotIndex(newSelectedInventorySlotIndex) - + self.player.getInventory().setSelectedInventorySlotIndex( + newSelectedInventorySlotIndex + ) + def handleMouseOver(self): location = self.getLocationAtMousePosition() if location == -1: @@ -788,27 +978,35 @@ def handleMouseOver(self): if isinstance(entity, LivingEntity): statusString = entity.getName() if self.config.debug: - # include energy and age - statusString += " (e=" + str(entity.getEnergy()) + "/" + str(entity.getTargetEnergy()) + ", a=" + str(entity.getAge(self.tickCounter.getTick())) + ")" + # include energy and age + statusString += ( + " (e=" + + str(entity.getEnergy()) + + "/" + + str(entity.getTargetEnergy()) + + ", a=" + + str(entity.getAge(self.tickCounter.getTick())) + + ")" + ) self.status.set(statusString) def savePlayerLocationToFile(self): jsonPlayerLocation = {} - + jsonPlayerLocation["roomX"] = self.currentRoom.getX() jsonPlayerLocation["roomY"] = self.currentRoom.getY() - + playerLocationId = self.player.getLocationID() jsonPlayerLocation["locationId"] = str(playerLocationId) - + # validate playerLocationSchema = json.load(open("schemas/playerLocation.json")) jsonschema.validate(jsonPlayerLocation, playerLocationSchema) - + path = self.config.pathToSaveDirectory + "/playerLocation.json" print("Saving player location to " + path) json.dump(jsonPlayerLocation, open(path, "w"), indent=4) - + def loadPlayerLocationFromFile(self): path = self.config.pathToSaveDirectory + "/playerLocation.json" if not os.path.exists(path): @@ -816,31 +1014,31 @@ def loadPlayerLocationFromFile(self): print("Loading player location from " + path) jsonPlayerLocation = json.load(open(path)) - + # validate playerLocationSchema = json.load(open("schemas/playerLocation.json")) jsonschema.validate(jsonPlayerLocation, playerLocationSchema) - + roomX = jsonPlayerLocation["roomX"] - roomY = jsonPlayerLocation["roomY"] + roomY = jsonPlayerLocation["roomY"] self.currentRoom = self.map.getRoom(roomX, roomY) - + locationId = jsonPlayerLocation["locationId"] location = self.currentRoom.getGrid().getLocation(locationId) self.currentRoom.addEntityToLocation(self.player, location) - + def savePlayerAttributesToFile(self): jsonPlayerAttributes = {} jsonPlayerAttributes["energy"] = ceil(self.player.getEnergy()) - + # validate playerAttributesSchema = json.load(open("schemas/playerAttributes.json")) jsonschema.validate(jsonPlayerAttributes, playerAttributesSchema) - + path = self.config.pathToSaveDirectory + "/playerAttributes.json" print("Saving player attributes to " + path) json.dump(jsonPlayerAttributes, open(path, "w"), indent=4) - + def loadPlayerAttributesFromFile(self): path = self.config.pathToSaveDirectory + "/playerAttributes.json" if not os.path.exists(path): @@ -848,32 +1046,37 @@ def loadPlayerAttributesFromFile(self): print("Loading player attributes from " + path) jsonPlayerAttributes = json.load(open(path)) - + # validate playerAttributesSchema = json.load(open("schemas/playerAttributes.json")) jsonschema.validate(jsonPlayerAttributes, playerAttributesSchema) - + energy = jsonPlayerAttributes["energy"] self.player.setEnergy(energy) - + def savePlayerInventoryToFile(self): inventoryJsonReaderWriter = InventoryJsonReaderWriter(self.config) - inventoryJsonReaderWriter.saveInventory(self.player.getInventory(), self.config.pathToSaveDirectory + "/playerInventory.json") + inventoryJsonReaderWriter.saveInventory( + self.player.getInventory(), + self.config.pathToSaveDirectory + "/playerInventory.json", + ) def loadPlayerInventoryFromFile(self): inventoryJsonReaderWriter = InventoryJsonReaderWriter(self.config) - inventory = inventoryJsonReaderWriter.loadInventory(self.config.pathToSaveDirectory + "/playerInventory.json") + inventory = inventoryJsonReaderWriter.loadInventory( + self.config.pathToSaveDirectory + "/playerInventory.json" + ) if inventory is not None: self.player.setInventory(inventory) - + def getNewLocationCoordinatesForLivingEntityBasedOnLocation(self, currentLocation): newLocationX = None newLocationY = None - + # get current location coordinates currentLocationX = currentLocation.getX() currentLocationY = currentLocation.getY() - + # if corner if self.ifCorner(currentLocation): raise Exception("corner movement not supported yet") @@ -899,20 +1102,26 @@ def getNewLocationCoordinatesForLivingEntityBasedOnLocation(self, currentLocatio # throw error raise Exception("Living entity is not on the edge of the room") return newLocationX, newLocationY - + def checkForLivingEntityDeaths(self): toRemove = [] for livingEntityId in self.currentRoom.getLivingEntities(): livingEntity = self.currentRoom.getEntity(livingEntityId) if livingEntity.getEnergy() == 0: toRemove.append(livingEntityId) - + for livingEntityId in toRemove: livingEntity = self.currentRoom.getEntity(livingEntityId) self.currentRoom.removeEntity(livingEntity) self.currentRoom.removeLivingEntity(livingEntity) if self.config.debug: - print("Removed " + livingEntity.getName() + " from room " + self.currentRoom.getName() + " because it had 0 energy") + print( + "Removed " + + livingEntity.getName() + + " from room " + + self.currentRoom.getName() + + " because it had 0 energy" + ) def save(self): self.saveCurrentRoomToFile() @@ -948,14 +1157,21 @@ def run(self): self.handleMouseUpEvent() elif event.type == pygame.MOUSEWHEEL: self.handleMouseWheelEvent(event) - + # move living entities - entitiesToMoveToNewRooms = self.currentRoom.moveLivingEntities(self.tickCounter.getTick()) + entitiesToMoveToNewRooms = self.currentRoom.moveLivingEntities( + self.tickCounter.getTick() + ) if len(entitiesToMoveToNewRooms) > 0: for entityToMove in entitiesToMoveToNewRooms: # get new room try: - newRoomX, newRoomY = self.getCoordinatesForNewRoomBasedOnLivingEntityLocation(entityToMove) + ( + newRoomX, + newRoomY, + ) = self.getCoordinatesForNewRoomBasedOnLivingEntityLocation( + entityToMove + ) except Exception as e: if self.config.debug: print("Error: " + str(e)) @@ -963,46 +1179,71 @@ def run(self): newRoom = self.map.getRoom(newRoomX, newRoomY) if newRoom == -1: # attempt to load room if file exists, otherwise generate new room - nextRoomPath = self.config.pathToSaveDirectory + "/rooms/room_" + str(newRoomX) + "_" + str(newRoomY) + ".json" + nextRoomPath = ( + self.config.pathToSaveDirectory + + "/rooms/room_" + + str(newRoomX) + + "_" + + str(newRoomY) + + ".json" + ) if os.path.exists(nextRoomPath): - roomJsonReaderWriter = RoomJsonReaderWriter(self.config.gridSize, self.graphik, self.tickCounter) + roomJsonReaderWriter = RoomJsonReaderWriter( + self.config.gridSize, self.graphik, self.tickCounter + ) newRoom = roomJsonReaderWriter.loadRoom(nextRoomPath) self.map.addRoom(newRoom) self.status.set("area loaded") else: - x, y = self.getCoordinatesForNewRoomBasedOnPlayerLocationAndDirection() + ( + x, + y, + ) = ( + self.getCoordinatesForNewRoomBasedOnPlayerLocationAndDirection() + ) newRoom = self.map.generateNewRoom(x, y) self.status.set("new area discovered") self.stats.incrementScore() self.stats.incrementRoomsExplored() - + # get new location currentLocationId = entityToMove.getLocationID() - currentLocation = self.currentRoom.getGrid().getLocation(currentLocationId) + currentLocation = self.currentRoom.getGrid().getLocation( + currentLocationId + ) try: - newLocationX, newLocationY = self.getNewLocationCoordinatesForLivingEntityBasedOnLocation(currentLocation) + ( + newLocationX, + newLocationY, + ) = self.getNewLocationCoordinatesForLivingEntityBasedOnLocation( + currentLocation + ) except Exception as e: if self.config.debug: print("Error: " + str(e)) continue - newLocation = newRoom.getGrid().getLocationByCoordinates(newLocationX, newLocationY) - + newLocation = newRoom.getGrid().getLocationByCoordinates( + newLocationX, newLocationY + ) + if newLocation == -1: - print("Error: could not find new location for entity " + entityToMove.getName()) + print( + "Error: could not find new location for entity " + + entityToMove.getName() + ) continue - + # remove entity from current room self.currentRoom.removeEntity(entityToMove) self.currentRoom.removeLivingEntity(entityToMove) - + # add entity to new room - newRoom.addEntityToLocation(entityToMove, newLocation) + newRoom.addEntityToLocation(entityToMove, newLocation) newRoom.addLivingEntity(entityToMove) - + # save new room self.saveRoomToFile(newRoom) - - + self.currentRoom.reproduceLivingEntities(self.tickCounter.getTick()) self.handleMouseOver() @@ -1013,22 +1254,22 @@ def run(self): self.checkForLivingEntityDeaths() self.status.checkForExpiration(self.tickCounter.getTick()) self.draw() - + pygame.display.update() - self.tickCounter.incrementTick() # TODO: implement vsync - + self.tickCounter.incrementTick() # TODO: implement vsync + if self.player.isDead(): time.sleep(3) self.respawnPlayer() - + if self.config.showMiniMap: self.mapImageUpdater.updateIfCooldownOver() # create save directory if it doesn't exist if not os.path.exists(self.config.pathToSaveDirectory): os.makedirs(self.config.pathToSaveDirectory) - + self.save() - + self.changeScreen = False - return self.nextScreen \ No newline at end of file + return self.nextScreen diff --git a/src/stats/stats.py b/src/stats/stats.py index d756e54..cc5f0d6 100644 --- a/src/stats/stats.py +++ b/src/stats/stats.py @@ -11,69 +11,69 @@ def __init__(self, config): self.roomsExplored = 0 self.foodEaten = 0 self.numberOfDeaths = 0 - + def getScore(self): return self.score - + def setScore(self, score): self.score = score - + def incrementScore(self): self.score += 1 - + def getRoomsExplored(self): return self.roomsExplored - + def setRoomsExplored(self, roomsExplored): self.roomsExplored = roomsExplored - + def incrementRoomsExplored(self): self.roomsExplored += 1 - + def getFoodEaten(self): return self.foodEaten - + def setFoodEaten(self, applesEaten): self.foodEaten = applesEaten - + def incrementFoodEaten(self): self.foodEaten += 1 - + def getNumberOfDeaths(self): return self.numberOfDeaths - + def setNumberOfDeaths(self, numberOfDeaths): self.numberOfDeaths = numberOfDeaths - + def incrementNumberOfDeaths(self): self.numberOfDeaths += 1 - + def save(self): jsonStats = {} - + jsonStats["score"] = str(self.getScore()) jsonStats["roomsExplored"] = str(self.getRoomsExplored()) jsonStats["foodEaten"] = str(self.getFoodEaten()) jsonStats["numberOfDeaths"] = str(self.getNumberOfDeaths()) - + # validate statsSchema = json.load(open("schemas/stats.json")) jsonschema.validate(jsonStats, statsSchema) - + path = self.config.pathToSaveDirectory + "/stats.json" json.dump(jsonStats, open(path, "w"), indent=4) - + def load(self): path = self.config.pathToSaveDirectory + "/stats.json" if not os.path.exists(path): return jsonStats = json.load(open(path)) - + # validate statsSchema = json.load(open("schemas/stats.json")) jsonschema.validate(jsonStats, statsSchema) - + self.setScore(int(jsonStats["score"])) self.setRoomsExplored(int(jsonStats["roomsExplored"])) self.setFoodEaten(int(jsonStats["foodEaten"])) - self.setNumberOfDeaths(int(jsonStats["numberOfDeaths"])) \ No newline at end of file + self.setNumberOfDeaths(int(jsonStats["numberOfDeaths"])) diff --git a/src/ui/energyBar.py b/src/ui/energyBar.py index f149755..52c8d07 100644 --- a/src/ui/energyBar.py +++ b/src/ui/energyBar.py @@ -8,24 +8,32 @@ class EnergyBar: def __init__(self, graphik: Graphik, player: Player): self.graphik = graphik self.player = player - + def draw(self): x, y = self.graphik.getGameDisplay().get_size() xpos = 0 - ypos = y - y/64 - width = x * (self.player.getEnergy()/self.player.getTargetEnergy()) - height = y/64 + ypos = y - y / 64 + width = x * (self.player.getEnergy() / self.player.getTargetEnergy()) + height = y / 64 color = (255, 215, 73) - + # draw black bar self.graphik.drawRectangle(xpos, ypos, x, height, (0, 0, 0)) # draw white interior - self.graphik.drawRectangle(xpos + 1, ypos + 1, x - 2, height - 2, (255, 255, 255)) + self.graphik.drawRectangle( + xpos + 1, ypos + 1, x - 2, height - 2, (255, 255, 255) + ) # fill interior with energy self.graphik.drawRectangle(xpos + 1, ypos + 1, width - 2, height - 2, color) # draw text in center of bar - text = str(ceil(self.player.getEnergy())) + "/" + str(self.player.getTargetEnergy()) - self.graphik.drawText(text, x/2, ypos + height/2, ceil(height) - 1, (0, 0, 0)) \ No newline at end of file + text = ( + str(ceil(self.player.getEnergy())) + + "/" + + str(self.player.getTargetEnergy()) + ) + self.graphik.drawText( + text, x / 2, ypos + height / 2, ceil(height) - 1, (0, 0, 0) + ) diff --git a/src/ui/status.py b/src/ui/status.py index 1d286e9..d4771d3 100644 --- a/src/ui/status.py +++ b/src/ui/status.py @@ -13,28 +13,38 @@ def __init__(self, graphik: Graphik, tickCounter: TickCounter): self.tickLastSet = -1 self.durationInTicks = 20 self.tickCounter = tickCounter - + def set(self, text): self.text = text self.tickLastSet = self.tickCounter.getTick() - + def clear(self): self.text = -1 - + def draw(self): if self.text == -1: return x, y = self.graphik.getGameDisplay().get_size() width = len(self.text) * 10 height = self.textSize * 2 - xpos = x/2 - width/2 - ypos = y - y/12 - height/2 - self.graphik.drawButton(xpos, ypos, width, height, (255,255,255), self.textColor, self.textSize, self.text, self.clear) - + xpos = x / 2 - width / 2 + ypos = y - y / 12 - height / 2 + self.graphik.drawButton( + xpos, + ypos, + width, + height, + (255, 255, 255), + self.textColor, + self.textSize, + self.text, + self.clear, + ) + def getTickLastSet(self): return self.tickLastSet - + def checkForExpiration(self, currentTick): expiryTick = self.tickLastSet + self.durationInTicks if currentTick > expiryTick: - self.clear() \ No newline at end of file + self.clear() diff --git a/src/world/map.py b/src/world/map.py index b841e25..cea99e4 100644 --- a/src/world/map.py +++ b/src/world/map.py @@ -1,15 +1,7 @@ -from math import ceil import os import random -from entity.apple import Apple -from entity.living.bear import Bear -from entity.living.chicken import Chicken from lib.graphik.src.graphik import Graphik -from entity.stone import Stone -from entity.oakWood import OakWood from lib.pyenvlib.entity import Entity -from entity.grass import Grass -from entity.leaves import Leaves from world.roomFactory import RoomFactory from world.roomJsonReaderWriter import RoomJsonReaderWriter from world.tickCounter import TickCounter @@ -26,23 +18,32 @@ def __init__(self, gridSize, graphik: Graphik, tickCounter: TickCounter, config) self.tickCounter = tickCounter self.config = config self.roomFactory = RoomFactory(self.gridSize, self.graphik, self.tickCounter) - + def getRooms(self): return self.rooms - + def getRoom(self, x, y): for room in self.getRooms(): if room.getX() == x and room.getY() == y: return room - + # attempt to load room if file exists, otherwise generate new room - nextRoomPath = self.config.pathToSaveDirectory + "/rooms/room_" + str(x) + "_" + str(y) + ".json" + nextRoomPath = ( + self.config.pathToSaveDirectory + + "/rooms/room_" + + str(x) + + "_" + + str(y) + + ".json" + ) if os.path.exists(nextRoomPath): - roomJsonReaderWriter = RoomJsonReaderWriter(self.gridSize, self.graphik, self.tickCounter, self.config) + roomJsonReaderWriter = RoomJsonReaderWriter( + self.gridSize, self.graphik, self.tickCounter, self.config + ) room = roomJsonReaderWriter.loadRoom(nextRoomPath) self.addRoom(room) return room - + return -1 def getLocationOfEntity(self, entity: Entity, room: Room): @@ -54,12 +55,14 @@ def generateNewRoom(self, x, y): # 50% chance to generate last room type newRoom = None if random.randrange(1, 101) > 50: - newRoom = self.roomFactory.createRoom(self.roomFactory.lastRoomTypeCreated, x, y) + newRoom = self.roomFactory.createRoom( + self.roomFactory.lastRoomTypeCreated, x, y + ) else: newRoom = self.roomFactory.createRandomRoom(x, y) self.rooms.append(newRoom) return newRoom - + def addRoom(self, room): - self.rooms.append(room) \ No newline at end of file + self.rooms.append(room) diff --git a/src/world/room.py b/src/world/room.py index dfd236c..5490d35 100644 --- a/src/world/room.py +++ b/src/world/room.py @@ -18,20 +18,26 @@ def __init__(self, name, gridSize, backgroundColor, x, y, graphik: Graphik): self.y = y self.graphik = graphik self.livingEntities = dict() - + def getBackgroundColor(self): return self.backgroundColor - + def getX(self): return self.x - + def getY(self): return self.y - + def draw(self, locationWidth, locationHeight): for locationId in self.grid.getLocations(): location = self.grid.getLocation(locationId) - self.drawLocation(location, location.getX() * locationWidth - 1, location.getY() * locationHeight - 1, locationWidth + 2, locationHeight + 2) + self.drawLocation( + location, + location.getX() * locationWidth - 1, + location.getY() * locationHeight - 1, + locationWidth + 2, + locationHeight + 2, + ) # Draws a location at a specified position. def drawLocation(self, location, xPos, yPos, width, height): @@ -45,31 +51,34 @@ def drawLocation(self, location, xPos, yPos, width, height): else: # draw background color self.graphik.drawRectangle(xPos, yPos, width, height, self.backgroundColor) - + def addLivingEntity(self, entity): self.livingEntities[entity.getID()] = entity - + def removeLivingEntity(self, entity): if entity.getID() not in self.livingEntities: - print("Entity was not found in living entities list when trying to remove it. Entity ID: " + str(entity.getID())) + print( + "Entity was not found in living entities list when trying to remove it. Entity ID: " + + str(entity.getID()) + ) return del self.livingEntities[entity.getID()] - + def getRandomAdjacentLocation(self, location): num = random.randrange(0, 4) if num == 0: return self.getGrid().getUp(location) elif num == 1: return self.getGrid().getRight(location) - elif num == 2: + elif num == 2: return self.getGrid().getDown(location) elif num == 3: return self.getGrid().getLeft(location) - + def checkEntityMovementCooldown(self, tickToCheck, entity): ticksPerSecond = self.config.ticksPerSecond - return tickToCheck + ticksPerSecond/entity.getSpeed() < self.tick - + return tickToCheck + ticksPerSecond / entity.getSpeed() < self.tick + def moveLivingEntities(self, tick) -> list: entitiesToMoveToNewRoom = [] for entityId in self.livingEntities: @@ -84,17 +93,22 @@ def moveLivingEntities(self, tick) -> list: try: location = self.getGrid().getLocation(locationId) except: - print("ERROR: Location not found when trying to move entity. Entity ID: " + str(entity.getID()) + ", Location ID: " + str(locationId)) + print( + "ERROR: Location not found when trying to move entity. Entity ID: " + + str(entity.getID()) + + ", Location ID: " + + str(locationId) + ) continue newLocation = self.getRandomAdjacentLocation(location) if newLocation == -1: entitiesToMoveToNewRoom.append(entity) continue - + if self.locationContainsSolidEntity(newLocation): continue - + # move entity location.removeEntity(entity) newLocation.addEntity(entity) @@ -111,7 +125,10 @@ def moveLivingEntities(self, tick) -> list: continue targetEntity = newLocation.getEntity(targetEntityId) if entity.canEat(targetEntity): - if isinstance(targetEntity, LivingEntity) and targetEntity.getEnergy() > 0: + if ( + isinstance(targetEntity, LivingEntity) + and targetEntity.getEnergy() > 0 + ): targetEntity.kill() entity.addEnergy(targetEntity.getEnergy()) else: @@ -119,11 +136,11 @@ def moveLivingEntities(self, tick) -> list: entity.addEnergy(10) break return entitiesToMoveToNewRoom - + def reproduceLivingEntities(self, tick): entityLocationMappings = [] - minAgeToReproduce = 30 * 60 * 5 # 5 minutes (at 30/ticks per second) - reproductionCooldown = minAgeToReproduce/2 # 2.5 minutes + minAgeToReproduce = 30 * 60 * 5 # 5 minutes (at 30/ticks per second) + reproductionCooldown = minAgeToReproduce / 2 # 2.5 minutes for entityId in self.livingEntities: entity = self.livingEntities[entityId] if entity.getAge(tick) < minAgeToReproduce: @@ -134,7 +151,12 @@ def reproduceLivingEntities(self, tick): try: location = self.getGrid().getLocation(locationId) except: - print("ERROR: Location not found when trying to reproduce entity. Entity ID: " + str(entity.getID()) + ", Location ID: " + str(locationId)) + print( + "ERROR: Location not found when trying to reproduce entity. Entity ID: " + + str(entity.getID()) + + ", Location ID: " + + str(locationId) + ) continue for targetEntityId in list(location.getEntities().keys()): targetEntity = location.getEntity(targetEntityId) @@ -154,7 +176,10 @@ def reproduceLivingEntities(self, tick): if targetEntity.getAge(tick) < minAgeToReproduce: continue # check reproduction cooldown - if entity.getTickLastReproduced() != None and entity.getTickLastReproduced() + reproductionCooldown > tick: + if ( + entity.getTickLastReproduced() != None + and entity.getTickLastReproduced() + reproductionCooldown > tick + ): continue # reset image @@ -164,12 +189,12 @@ def reproduceLivingEntities(self, tick): entity.setImagePath("assets/images/bear.png") # throw dice - if random.randrange(1, 101) > 1: # 1% chance + if random.randrange(1, 101) > 1: # 1% chance continue # decrease energy by half - entity.removeEnergy(entity.getEnergy()/2) - targetEntity.removeEnergy(targetEntity.getEnergy()/2) + entity.removeEnergy(entity.getEnergy() / 2) + targetEntity.removeEnergy(targetEntity.getEnergy() / 2) newEntity = None if isinstance(entity, Bear): @@ -182,21 +207,30 @@ def reproduceLivingEntities(self, tick): entity.setTickLastReproduced(tick) targetEntity.setTickLastReproduced(tick) if isinstance(entity, Chicken): - entity.setImagePath("assets/images/chickenOnReproductionCooldown.png") - targetEntity.setImagePath("assets/images/chickenOnReproductionCooldown.png") + entity.setImagePath( + "assets/images/chickenOnReproductionCooldown.png" + ) + targetEntity.setImagePath( + "assets/images/chickenOnReproductionCooldown.png" + ) if isinstance(entity, Bear): - entity.setImagePath("assets/images/bearOnReproductionCooldown.png") - targetEntity.setImagePath("assets/images/bearOnReproductionCooldown.png") - + entity.setImagePath( + "assets/images/bearOnReproductionCooldown.png" + ) + targetEntity.setImagePath( + "assets/images/bearOnReproductionCooldown.png" + ) + # set new entity's energy to 10% of average of parent's energy - newEntity.setEnergy((entity.getEnergy() + targetEntity.getEnergy())/2 * 0.1) - + newEntity.setEnergy( + (entity.getEnergy() + targetEntity.getEnergy()) / 2 * 0.1 + ) + for entityLocationMapping in entityLocationMappings: entity = entityLocationMapping[0] location = entityLocationMapping[1] self.addEntityToLocation(entity, location) self.addLivingEntity(entity) - def locationContainsSolidEntity(self, location): for entityId in list(location.getEntities().keys()): @@ -204,9 +238,9 @@ def locationContainsSolidEntity(self, location): if entity.isSolid(): return True return False - + def getLivingEntities(self): return self.livingEntities def setLivingEntities(self, livingEntities): - self.livingEntities = livingEntities \ No newline at end of file + self.livingEntities = livingEntities diff --git a/src/world/roomFactory.py b/src/world/roomFactory.py index 60d8afc..31faf2f 100644 --- a/src/world/roomFactory.py +++ b/src/world/roomFactory.py @@ -17,13 +17,13 @@ from world.roomType import RoomType -class RoomFactory(): +class RoomFactory: def __init__(self, gridSize, graphik, tickCounter): self.gridSize = gridSize self.graphik = graphik self.tickCounter = tickCounter self.lastRoomTypeCreated = RoomType.GRASSLAND - + def createRoom(self, roomType, x, y): if roomType == RoomType.EMPTY: self.lastRoomTypeCreated = RoomType.EMPTY @@ -40,7 +40,7 @@ def createRoom(self, roomType, x, y): elif roomType == RoomType.MOUNTAIN: self.lastRoomTypeCreated = RoomType.MOUNTAIN return self.createMountainRoom(x, y) - + def createRandomRoom(self, x, y): # get random int number = random.randrange(0, 4) @@ -55,14 +55,25 @@ def createRandomRoom(self, x, y): else: newRoom = self.createRoom(RoomType.EMPTY, x, y) return newRoom - + # create methods def createEmptyRoom(self, color, x, y): - newRoom = Room(("(" + str(x) + ", " + str(y) + ")"), self.gridSize, color, x, y, self.graphik) + newRoom = Room( + ("(" + str(x) + ", " + str(y) + ")"), + self.gridSize, + color, + x, + y, + self.graphik, + ) return newRoom - + def createGrassRoom(self, x, y): - newRoomColor = ((random.randrange(200, 210), random.randrange(130, 140), random.randrange(60, 70))) + newRoomColor = ( + random.randrange(200, 210), + random.randrange(130, 140), + random.randrange(60, 70), + ) newRoom = self.createEmptyRoom(newRoomColor, x, y) # generate grass @@ -73,66 +84,74 @@ def createGrassRoom(self, x, y): # generate chickens self.spawnChickens(newRoom) - + return newRoom def createForestRoom(self, x, y): newRoom = self.createGrassRoom(x, y) # generate food - maxTrees = ceil(self.gridSize/3) + maxTrees = ceil(self.gridSize / 3) for i in range(0, maxTrees): self.spawnOakTree(newRoom) # generate bears self.spawnBears(newRoom) return newRoom - + def createJungleRoom(self, x, y): newRoom = self.createGrassRoom(x, y) - + # generate leaves self.spawnLeaves(newRoom) # generate lots of food - maxTrees = ceil(self.gridSize/3) - for i in range(0, maxTrees*4): + maxTrees = ceil(self.gridSize / 3) + for i in range(0, maxTrees * 4): self.spawnJungleTree(newRoom) return newRoom def createMountainRoom(self, x, y): - newRoom = self.createEmptyRoom((random.randrange(100, 110), random.randrange(100, 110), random.randrange(100, 110)), x, y) - + newRoom = self.createEmptyRoom( + ( + random.randrange(100, 110), + random.randrange(100, 110), + random.randrange(100, 110), + ), + x, + y, + ) + # generate ore self.spawnSomeOre(newRoom) - + # generate rocks self.fillWithRocks(newRoom) - + return newRoom # spawn methods def spawnGrass(self, room: Room): for locationId in room.getGrid().getLocations(): location = room.getGrid().getLocation(locationId) - if random.randrange(1, 101) > 5: # 95% chance + if random.randrange(1, 101) > 5: # 95% chance room.addEntityToLocation(Grass(), location) - + def spawnSomeRocks(self, room: Room): for locationId in room.getGrid().getLocations(): location = room.getGrid().getLocation(locationId) - if random.randrange(1, 101) == 1: # 1% chance + if random.randrange(1, 101) == 1: # 1% chance room.addEntityToLocation(Stone(), location) def fillWithRocks(self, room: Room): for locationId in room.getGrid().getLocations(): location = room.getGrid().getLocation(locationId) room.addEntityToLocation(Stone(), location) - + def spawnSomeOre(self, room: Room): for locationId in room.getGrid().getLocations(): location = room.getGrid().getLocation(locationId) - if random.randrange(1, 101) == 1: # 5% chance + if random.randrange(1, 101) == 1: # 5% chance # 50% chance for coal, 50% chance for iron if random.randrange(1, 101) > 50: room.addEntityToLocation(CoalOre(), location) @@ -150,61 +169,67 @@ def spawnOakTree(self, room: Room): locationsToSpawnApples.append(room.grid.getLeft(location)) locationsToSpawnApples.append(room.grid.getDown(location)) locationsToSpawnApples.append(room.grid.getRight(location)) - + # spawn leaves and apples around the tree for appleSpawnLocation in locationsToSpawnApples: - if appleSpawnLocation == -1 or self.locationContainsEntityType(appleSpawnLocation, OakWood): + if appleSpawnLocation == -1 or self.locationContainsEntityType( + appleSpawnLocation, OakWood + ): continue room.addEntityToLocation(Leaves(), appleSpawnLocation) if random.randrange(0, 2) == 0: room.addEntityToLocation(Apple(), appleSpawnLocation) - + def spawnJungleTree(self, room: Room): wood = JungleWood() room.addEntity(wood) - + location = self.getLocationOfEntity(wood, room) - + locationsToSpawnLeaves = [] locationsToSpawnLeaves.append(room.grid.getUp(location)) locationsToSpawnLeaves.append(room.grid.getLeft(location)) locationsToSpawnLeaves.append(room.grid.getDown(location)) locationsToSpawnLeaves.append(room.grid.getRight(location)) - + # spawn abundance of leaves around the tree for leavesSpawnLocation in locationsToSpawnLeaves: - if leavesSpawnLocation == -1 or self.locationContainsEntityType(leavesSpawnLocation, JungleWood): + if leavesSpawnLocation == -1 or self.locationContainsEntityType( + leavesSpawnLocation, JungleWood + ): continue room.addEntityToLocation(Leaves(), leavesSpawnLocation) room.addEntityToLocation(Leaves(), leavesSpawnLocation) - + # spawn bananas around the tree for bananaSpawnLocation in locationsToSpawnLeaves: - if bananaSpawnLocation == -1 or self.locationContainsEntityType(bananaSpawnLocation, JungleWood): + if bananaSpawnLocation == -1 or self.locationContainsEntityType( + bananaSpawnLocation, JungleWood + ): continue if random.randrange(0, 2) == 0: room.addEntityToLocation(Banana(), bananaSpawnLocation) - + def spawnChickens(self, room: Room): for i in range(0, 5): - if random.randrange(1, 101) > 75: # 25% chance + if random.randrange(1, 101) > 75: # 25% chance newChicken = Chicken(self.tickCounter.getTick()) room.addEntity(newChicken) room.addLivingEntity(newChicken) - + def spawnBears(self, room: Room): for i in range(0, 2): - if random.randrange(1, 101) > 90: # 10% chance + if random.randrange(1, 101) > 90: # 10% chance newBear = Bear(self.tickCounter.getTick()) room.addEntity(newBear) room.addLivingEntity(newBear) - + def spawnLeaves(self, room: Room): for locationId in room.getGrid().getLocations(): location = room.getGrid().getLocation(locationId) - if random.randrange(1, 101) > 5: # 95% chance + if random.randrange(1, 101) > 5: # 95% chance room.addEntityToLocation(Leaves(), location) - + # helper methods def getLocationOfEntity(self, entity: Entity, room: Room): locationID = entity.getLocationID() @@ -216,4 +241,4 @@ def locationContainsEntityType(self, location, entityType): entity = location.getEntity(entityId) if isinstance(entity, entityType): return True - return False \ No newline at end of file + return False diff --git a/src/world/roomJsonReaderWriter.py b/src/world/roomJsonReaderWriter.py index 17d3b8a..c6f5ea4 100644 --- a/src/world/roomJsonReaderWriter.py +++ b/src/world/roomJsonReaderWriter.py @@ -15,19 +15,20 @@ from entity.living.bear import Bear from entity.living.chicken import Chicken from entity.living.livingEntity import LivingEntity -from player.player import Player from entity.oakWood import OakWood from entity.stone import Stone from lib.graphik.src.graphik import Graphik -from lib.pyenvlib.entity import Entity from lib.pyenvlib.grid import Grid from lib.pyenvlib.location import Location from world.room import Room from world.tickCounter import TickCounter + class RoomJsonReaderWriter: - def __init__(self, gridSize, graphik: Graphik, tickCounter: TickCounter, config: Config): + def __init__( + self, gridSize, graphik: Graphik, tickCounter: TickCounter, config: Config + ): self.gridSize = gridSize self.graphik = graphik self.tickCounter = tickCounter @@ -41,7 +42,7 @@ def saveRoom(self, room, path): roomJson = self.generateJsonForRoom(room) if not os.path.exists(self.config.pathToSaveDirectory + "/rooms"): os.makedirs(self.config.pathToSaveDirectory + "/rooms") - with open(path, 'w') as outfile: + with open(path, "w") as outfile: json.dump(roomJson, outfile, indent=4) def loadRoom(self, path): @@ -58,14 +59,16 @@ def generateJsonForRoom(self, room): roomJson["y"] = room.getY() roomJson["name"] = room.getName() roomJson["id"] = str(room.getID()) - roomJson["livingEntityIds"] = [str(entityId) for entityId in room.getLivingEntities().keys()] + roomJson["livingEntityIds"] = [ + str(entityId) for entityId in room.getLivingEntities().keys() + ] roomJson["grid"] = self.generateJsonForGrid(room.getGrid()) roomJson["creationDate"] = str(room.getCreationDate()) # validate json with schema jsonschema.validate(roomJson, self.roomSchema) return roomJson - + def generateJsonForGrid(self, grid): gridJson = {} gridJson["id"] = str(grid.getID()) @@ -73,7 +76,7 @@ def generateJsonForGrid(self, grid): gridJson["rows"] = grid.getRows() gridJson["locations"] = self.generateJsonForLocations(grid.getLocations()) return gridJson - + def generateJsonForLocations(self, locations): locationsJson = [] for locationId in locations: @@ -113,14 +116,21 @@ def generateJsonForEntity(self, entity): entityJson["tickLastReproduced"] = entity.getTickLastReproduced() entityJson["imagePath"] = entity.getImagePath() return entityJson - + # generate room methods def generateRoomFromJson(self, roomJson): rgb = roomJson["backgroundColor"].replace("(", "").replace(")", "").split(",") r = int(rgb[0]) g = int(rgb[1]) b = int(rgb[2]) - room = Room(roomJson["name"], self.gridSize, (r, g, b), roomJson["x"], roomJson["y"], self.graphik) + room = Room( + roomJson["name"], + self.gridSize, + (r, g, b), + roomJson["x"], + roomJson["y"], + self.graphik, + ) room.setID(roomJson["id"]) # room.setCreationDate(roomJson["creationDate"]) room.setGrid(self.generateGridFromJson(roomJson["grid"])) @@ -155,7 +165,7 @@ def generateEntitiesFromJson(self, entitiesJson): entities = {} for entityJson in entitiesJson: entity = self.generateEntityFromJson(entityJson) - if (entity == None): + if entity == None: continue entities[entity.getID()] = entity @@ -164,55 +174,55 @@ def generateEntitiesFromJson(self, entitiesJson): return entities def generateEntityFromJson(self, entityJson): - entityClass = entityJson['entityClass'] + entityClass = entityJson["entityClass"] entity = None if entityClass == "Apple": entity = Apple() - entity.setID(UUID(entityJson['id'])) + entity.setID(UUID(entityJson["id"])) elif entityClass == "CoalOre": entity = CoalOre() - entity.setID(UUID(entityJson['id'])) - elif entityClass == 'Grass': + entity.setID(UUID(entityJson["id"])) + elif entityClass == "Grass": entity = Grass() - entity.setID(UUID(entityJson['id'])) + entity.setID(UUID(entityJson["id"])) elif entityClass == "IronOre": entity = IronOre() - entity.setID(UUID(entityJson['id'])) - elif entityClass == 'JungleWood': + entity.setID(UUID(entityJson["id"])) + elif entityClass == "JungleWood": entity = JungleWood() - entity.setID(UUID(entityJson['id'])) + entity.setID(UUID(entityJson["id"])) elif entityClass == "Leaves": entity = Leaves() - entity.setID(UUID(entityJson['id'])) - elif entityClass == 'OakWood': + entity.setID(UUID(entityJson["id"])) + elif entityClass == "OakWood": entity = OakWood() - entity.setID(UUID(entityJson['id'])) + entity.setID(UUID(entityJson["id"])) elif entityClass == "Stone": entity = Stone() - entity.setID(UUID(entityJson['id'])) + entity.setID(UUID(entityJson["id"])) elif entityClass == "Bear": - entity = Bear(entityJson['tickCreated']) - entity.setID(UUID(entityJson['id'])) + entity = Bear(entityJson["tickCreated"]) + entity.setID(UUID(entityJson["id"])) elif entityClass == "Chicken": - entity = Chicken(entityJson['tickCreated']) - entity.setID(UUID(entityJson['id'])) + entity = Chicken(entityJson["tickCreated"]) + entity.setID(UUID(entityJson["id"])) elif entityClass == "Banana": entity = Banana() - entity.setID(UUID(entityJson['id'])) + entity.setID(UUID(entityJson["id"])) elif entityClass == "Player": return None else: - raise Exception("Unknown entity class: " + entityJson['entityClass']) + raise Exception("Unknown entity class: " + entityJson["entityClass"]) if isinstance(entity, LivingEntity): - entity.setEnergy(entityJson['energy']) - entity.setTickCreated(entityJson['tickCreated']) - entity.setTickLastReproduced(entityJson['tickLastReproduced']) - entity.setImagePath(entityJson['imagePath']) - - entity.setEnvironmentID(UUID(entityJson['environmentId'])) - entity.setGridID(UUID(entityJson['gridId'])) - entity.setLocationID(entityJson['locationId']) - entity.setName(entityJson['name']) + entity.setEnergy(entityJson["energy"]) + entity.setTickCreated(entityJson["tickCreated"]) + entity.setTickLastReproduced(entityJson["tickLastReproduced"]) + entity.setImagePath(entityJson["imagePath"]) + + entity.setEnvironmentID(UUID(entityJson["environmentId"])) + entity.setGridID(UUID(entityJson["gridId"])) + entity.setLocationID(entityJson["locationId"]) + entity.setName(entityJson["name"]) # entity.setCreationDate(entityJson['creationDate']) - return entity \ No newline at end of file + return entity diff --git a/src/world/roomType.py b/src/world/roomType.py index aca5ad5..57e776d 100644 --- a/src/world/roomType.py +++ b/src/world/roomType.py @@ -5,4 +5,3 @@ class RoomType: FOREST = "forest" JUNGLE = "jungle" MOUNTAIN = "mountain" - \ No newline at end of file diff --git a/src/world/tickCounter.py b/src/world/tickCounter.py index 1a7f791..56c6585 100644 --- a/src/world/tickCounter.py +++ b/src/world/tickCounter.py @@ -11,19 +11,25 @@ def __init__(self, config): self.measuredTicksPerSecond = 0 self.lastTimestamp = time.time() self.highestMeasuredTicksPerSecond = 0 - + def getTick(self): return self.tick - + def incrementTick(self): self.tick += 1 self.updateMeasuredTicksPerSecond() - + def updateMeasuredTicksPerSecond(self): millisecondsSinceLastTick = (time.time() - self.lastTimestamp) * 1000 warningThreshold = 500 if millisecondsSinceLastTick > warningThreshold: - print("WARNING: Tick took " + str(int(millisecondsSinceLastTick)) + " milliseconds to complete. (tick=" + str(self.tick) + ")") + print( + "WARNING: Tick took " + + str(int(millisecondsSinceLastTick)) + + " milliseconds to complete. (tick=" + + str(self.tick) + + ")" + ) currentTimestamp = time.time() timeElapsed = currentTimestamp - self.lastTimestamp self.lastTimestamp = currentTimestamp @@ -31,30 +37,30 @@ def updateMeasuredTicksPerSecond(self): if self.measuredTicksPerSecond > self.highestMeasuredTicksPerSecond: self.highestMeasuredTicksPerSecond = self.measuredTicksPerSecond - + def getMeasuredTicksPerSecond(self): return self.measuredTicksPerSecond - + def getHighestMeasuredTicksPerSecond(self): return self.highestMeasuredTicksPerSecond - + def save(self): jsonTick = {} jsonTick["tick"] = self.getTick() - + # validate tickSchema = json.load(open("schemas/tick.json")) jsonschema.validate(jsonTick, tickSchema) - + path = self.config.pathToSaveDirectory + "/tick.json" json.dump(jsonTick, open(path, "w"), indent=4) - + def load(self): path = self.config.pathToSaveDirectory + "/tick.json" jsonTick = json.load(open(path)) - + # validate tickSchema = json.load(open("schemas/tick.json")) jsonschema.validate(jsonTick, tickSchema) - - self.tick = int(jsonTick["tick"]) \ No newline at end of file + + self.tick = int(jsonTick["tick"]) diff --git a/tests/entity/living/test_bear.py b/tests/entity/living/test_bear.py index 84bd71c..8a80774 100644 --- a/tests/entity/living/test_bear.py +++ b/tests/entity/living/test_bear.py @@ -1,9 +1,10 @@ from src.entity.living.bear import Bear + def test_initialization(): bear = Bear(0) - - assert(bear.name == "Bear") - assert(bear.getTickCreated() == 0) - assert(bear.getImagePath() == "assets/images/bear.png") - assert(bear.isSolid() == False) \ No newline at end of file + + assert bear.name == "Bear" + assert bear.getTickCreated() == 0 + assert bear.getImagePath() == "assets/images/bear.png" + assert bear.isSolid() == False diff --git a/tests/entity/living/test_chicken.py b/tests/entity/living/test_chicken.py index fd7a921..52b28ce 100644 --- a/tests/entity/living/test_chicken.py +++ b/tests/entity/living/test_chicken.py @@ -1,13 +1,15 @@ from src.entity.living.chicken import Chicken + def test_initialization(): chicken = Chicken(0) - - assert(chicken.name == "Chicken") - assert(chicken.getTickCreated() == 0) - assert(chicken.getImagePath() == "assets/images/chicken.png") - assert(chicken.isSolid() == False) + + assert chicken.name == "Chicken" + assert chicken.getTickCreated() == 0 + assert chicken.getImagePath() == "assets/images/chicken.png" + assert chicken.isSolid() == False + def test_can_eat(): chicken = Chicken(0) - assert(chicken.canEat("test") == False) \ No newline at end of file + assert chicken.canEat("test") == False diff --git a/tests/entity/living/test_livingEntity.py b/tests/entity/living/test_livingEntity.py index 092827b..d1fe28d 100644 --- a/tests/entity/living/test_livingEntity.py +++ b/tests/entity/living/test_livingEntity.py @@ -1,59 +1,67 @@ -import pytest from src.entity.living.livingEntity import LivingEntity + def createLivingEntity(): return LivingEntity("test", "myimagepath.png", 50, [], 0) + def test_initialization(): livingEntity = createLivingEntity() - - assert(livingEntity.name == "test") - assert(livingEntity.getEnergy() == 50) - assert(livingEntity.getTargetEnergy() == 50) - assert(livingEntity.getTickCreated() == 0) + + assert livingEntity.name == "test" + assert livingEntity.getEnergy() == 50 + assert livingEntity.getTargetEnergy() == 50 + assert livingEntity.getTickCreated() == 0 + def test_set_energy(): livingEntity = createLivingEntity() livingEntity.setEnergy(100) - - assert(livingEntity.getEnergy() == 100) - + + assert livingEntity.getEnergy() == 100 + def test_set_target_energy(): livingEntity = createLivingEntity() livingEntity.setTargetEnergy(100) - - assert(livingEntity.getTargetEnergy() == 100) + + assert livingEntity.getTargetEnergy() == 100 + def test_add_energy(): livingEntity = createLivingEntity() livingEntity.addEnergy(50) - - assert(livingEntity.getEnergy() == 100) + + assert livingEntity.getEnergy() == 100 + def test_remove_energy(): livingEntity = createLivingEntity() livingEntity.removeEnergy(50) - - assert(livingEntity.getEnergy() == 0) + + assert livingEntity.getEnergy() == 0 + def test_needs_energy(): livingEntity = createLivingEntity() - assert(livingEntity.needsEnergy() == False) - + assert livingEntity.needsEnergy() == False + livingEntity.setEnergy(livingEntity.getTargetEnergy() / 2 - 1) - assert(livingEntity.needsEnergy() == True) + assert livingEntity.needsEnergy() == True + def test_get_age(): livingEntity = createLivingEntity() - assert(livingEntity.getAge(100) == 100) + assert livingEntity.getAge(100) == 100 + def test_kill(): livingEntity = createLivingEntity() livingEntity.kill() - - assert(livingEntity.getEnergy() == 0) + + assert livingEntity.getEnergy() == 0 + def test_can_eat(): livingEntity = createLivingEntity() - assert(livingEntity.canEat("test") == False) \ No newline at end of file + assert livingEntity.canEat("test") == False diff --git a/tests/entity/test_apple.py b/tests/entity/test_apple.py index a226ffe..29631a1 100644 --- a/tests/entity/test_apple.py +++ b/tests/entity/test_apple.py @@ -1,8 +1,9 @@ from src.entity.apple import Apple + def test_initialization(): apple = Apple() - - assert(apple.name == "Apple") - assert(apple.getImagePath() == "assets/images/apple.png") - assert(apple.isSolid() == False) \ No newline at end of file + + assert apple.name == "Apple" + assert apple.getImagePath() == "assets/images/apple.png" + assert apple.isSolid() == False diff --git a/tests/entity/test_banana.py b/tests/entity/test_banana.py index 4122662..e8d1097 100644 --- a/tests/entity/test_banana.py +++ b/tests/entity/test_banana.py @@ -1,8 +1,9 @@ from src.entity.banana import Banana + def test_initialization(): banana = Banana() - - assert(banana.name == "Banana") - assert(banana.getImagePath() == "assets/images/banana.png") - assert(banana.isSolid() == False) \ No newline at end of file + + assert banana.name == "Banana" + assert banana.getImagePath() == "assets/images/banana.png" + assert banana.isSolid() == False diff --git a/tests/entity/test_coalOre.py b/tests/entity/test_coalOre.py index d3e9acd..b547be8 100644 --- a/tests/entity/test_coalOre.py +++ b/tests/entity/test_coalOre.py @@ -1,8 +1,9 @@ from src.entity.coalOre import CoalOre + def test_initialization(): coalore = CoalOre() - - assert(coalore.name == "Coal Ore") - assert(coalore.getImagePath() == "assets/images/coalOre.png") - assert(coalore.isSolid() == True) \ No newline at end of file + + assert coalore.name == "Coal Ore" + assert coalore.getImagePath() == "assets/images/coalOre.png" + assert coalore.isSolid() == True diff --git a/tests/entity/test_drawableEntity.py b/tests/entity/test_drawableEntity.py index 6411fd7..482dc29 100644 --- a/tests/entity/test_drawableEntity.py +++ b/tests/entity/test_drawableEntity.py @@ -1,7 +1,8 @@ from src.entity.drawableEntity import DrawableEntity + def test_initialization(): drawableEntity = DrawableEntity("test", "myimagepath.png") - - assert(drawableEntity.getName() == "test") - assert(drawableEntity.getImagePath() == "myimagepath.png") \ No newline at end of file + + assert drawableEntity.getName() == "test" + assert drawableEntity.getImagePath() == "myimagepath.png" diff --git a/tests/entity/test_food.py b/tests/entity/test_food.py index 23e92de..da0b7a3 100644 --- a/tests/entity/test_food.py +++ b/tests/entity/test_food.py @@ -1,8 +1,9 @@ from src.entity.food import Food + def test_initialization(): food = Food("test", "myimagepath.png", 20) - - assert(food.getName() == "test") - assert(food.getImagePath() == "myimagepath.png") - assert(food.getEnergy() == 20) \ No newline at end of file + + assert food.getName() == "test" + assert food.getImagePath() == "myimagepath.png" + assert food.getEnergy() == 20 diff --git a/tests/entity/test_grass.py b/tests/entity/test_grass.py index 6852cc7..db952bf 100644 --- a/tests/entity/test_grass.py +++ b/tests/entity/test_grass.py @@ -1,8 +1,9 @@ from src.entity.grass import Grass + def test_initialization(): grass = Grass() - - assert(grass.name == "Grass") - assert(grass.getImagePath() == "assets/images/grass.png") - assert(grass.isSolid() == False) \ No newline at end of file + + assert grass.name == "Grass" + assert grass.getImagePath() == "assets/images/grass.png" + assert grass.isSolid() == False diff --git a/tests/entity/test_ironOre.py b/tests/entity/test_ironOre.py index 5cc912e..8fffdca 100644 --- a/tests/entity/test_ironOre.py +++ b/tests/entity/test_ironOre.py @@ -1,8 +1,9 @@ from src.entity.ironOre import IronOre + def test_initialization(): ironore = IronOre() - - assert(ironore.name == "Iron Ore") - assert(ironore.getImagePath() == "assets/images/ironOre.png") - assert(ironore.isSolid() == True) \ No newline at end of file + + assert ironore.name == "Iron Ore" + assert ironore.getImagePath() == "assets/images/ironOre.png" + assert ironore.isSolid() == True diff --git a/tests/entity/test_jungleWood.py b/tests/entity/test_jungleWood.py index 40d28e5..50eb27e 100644 --- a/tests/entity/test_jungleWood.py +++ b/tests/entity/test_jungleWood.py @@ -1,8 +1,9 @@ from src.entity.jungleWood import JungleWood + def test_initialization(): junglewood = JungleWood() - - assert(junglewood.name == "Jungle Wood") - assert(junglewood.getImagePath() == "assets/images/jungleWood.png") - assert(junglewood.isSolid() == True) \ No newline at end of file + + assert junglewood.name == "Jungle Wood" + assert junglewood.getImagePath() == "assets/images/jungleWood.png" + assert junglewood.isSolid() == True diff --git a/tests/entity/test_leaves.py b/tests/entity/test_leaves.py index 974652f..f305f70 100644 --- a/tests/entity/test_leaves.py +++ b/tests/entity/test_leaves.py @@ -1,8 +1,9 @@ from src.entity.leaves import Leaves + def test_initialization(): leaves = Leaves() - - assert(leaves.name == "Leaves") - assert(leaves.getImagePath() == "assets/images/leaves.png") - assert(leaves.isSolid() == False) \ No newline at end of file + + assert leaves.name == "Leaves" + assert leaves.getImagePath() == "assets/images/leaves.png" + assert leaves.isSolid() == False diff --git a/tests/entity/test_oakWood.py b/tests/entity/test_oakWood.py index 9419bf1..f149a12 100644 --- a/tests/entity/test_oakWood.py +++ b/tests/entity/test_oakWood.py @@ -1,8 +1,9 @@ from src.entity.oakWood import OakWood + def test_initialization(): oakwood = OakWood() - - assert(oakwood.name == "Oak Wood") - assert(oakwood.getImagePath() == "assets/images/oakWood.png") - assert(oakwood.isSolid() == True) \ No newline at end of file + + assert oakwood.name == "Oak Wood" + assert oakwood.getImagePath() == "assets/images/oakWood.png" + assert oakwood.isSolid() == True diff --git a/tests/entity/test_stone.py b/tests/entity/test_stone.py index c5b06fd..bfb241a 100644 --- a/tests/entity/test_stone.py +++ b/tests/entity/test_stone.py @@ -1,8 +1,9 @@ from src.entity.stone import Stone + def test_initialization(): stone = Stone() - - assert(stone.name == "Stone") - assert(stone.getImagePath() == "assets/images/stone.png") - assert(stone.isSolid() == True) \ No newline at end of file + + assert stone.name == "Stone" + assert stone.getImagePath() == "assets/images/stone.png" + assert stone.isSolid() == True diff --git a/tests/player/test_player.py b/tests/player/test_player.py index 7cd3be1..bd048c8 100644 --- a/tests/player/test_player.py +++ b/tests/player/test_player.py @@ -1,174 +1,190 @@ from unittest.mock import MagicMock from src.player import player + def createPlayerInstance(): player.Inventory = MagicMock() return player.Player(0) + def test_initialization(): # call playerInstance = createPlayerInstance() - + # check - assert(playerInstance.getDirection() == -1) - assert(playerInstance.getLastDirection() == -1) - assert(playerInstance.isGathering() == False) - assert(playerInstance.isPlacing() == False) - assert(playerInstance.isDead() == False) - assert(playerInstance.getTickLastMoved() == -1) - assert(playerInstance.getMovementSpeed() == 30) - assert(playerInstance.getGatherSpeed() == 30) - assert(playerInstance.getPlaceSpeed() == 30) - assert(playerInstance.isCrouching() == False) - assert(playerInstance.isSolid() == False) - + assert playerInstance.getDirection() == -1 + assert playerInstance.getLastDirection() == -1 + assert playerInstance.isGathering() == False + assert playerInstance.isPlacing() == False + assert playerInstance.isDead() == False + assert playerInstance.getTickLastMoved() == -1 + assert playerInstance.getMovementSpeed() == 30 + assert playerInstance.getGatherSpeed() == 30 + assert playerInstance.getPlaceSpeed() == 30 + assert playerInstance.isCrouching() == False + assert playerInstance.isSolid() == False + player.Inventory.assert_called_once() + def test_set_direction_up(): # prepare playerInstance = createPlayerInstance() - + # call playerInstance.setDirection(0) - + # check - assert(playerInstance.getDirection() == 0) - assert(playerInstance.getLastDirection() == -1) - assert(playerInstance.imagePath == "assets/images/player_up.png") + assert playerInstance.getDirection() == 0 + assert playerInstance.getLastDirection() == -1 + assert playerInstance.imagePath == "assets/images/player_up.png" + def test_set_direction_left(): # prepare playerInstance = createPlayerInstance() - + # call playerInstance.setDirection(1) - + # check - assert(playerInstance.getDirection() == 1) - assert(playerInstance.getLastDirection() == -1) - assert(playerInstance.imagePath == "assets/images/player_left.png") + assert playerInstance.getDirection() == 1 + assert playerInstance.getLastDirection() == -1 + assert playerInstance.imagePath == "assets/images/player_left.png" + def test_set_direction_down(): # prepare playerInstance = createPlayerInstance() - + # call playerInstance.setDirection(2) - + # check - assert(playerInstance.getDirection() == 2) - assert(playerInstance.getLastDirection() == -1) - assert(playerInstance.imagePath == "assets/images/player_down.png") + assert playerInstance.getDirection() == 2 + assert playerInstance.getLastDirection() == -1 + assert playerInstance.imagePath == "assets/images/player_down.png" + def test_set_direction_right(): # prepare playerInstance = createPlayerInstance() - + # call playerInstance.setDirection(3) - + # check - assert(playerInstance.getDirection() == 3) - assert(playerInstance.getLastDirection() == -1) - assert(playerInstance.imagePath == "assets/images/player_right.png") + assert playerInstance.getDirection() == 3 + assert playerInstance.getLastDirection() == -1 + assert playerInstance.imagePath == "assets/images/player_right.png" + def test_set_gathering(): # prepare playerInstance = createPlayerInstance() - + # call playerInstance.setGathering(True) - + # check - assert(playerInstance.isGathering() == True) + assert playerInstance.isGathering() == True + def test_set_placing(): # prepare playerInstance = createPlayerInstance() - + # call playerInstance.setPlacing(True) - + # check - assert(playerInstance.isPlacing() == True) + assert playerInstance.isPlacing() == True + def test_set_tick_last_moved(): # prepare playerInstance = createPlayerInstance() - + # call playerInstance.setTickLastMoved(10) - + # check - assert(playerInstance.getTickLastMoved() == 10) + assert playerInstance.getTickLastMoved() == 10 + def test_set_inventory(): # prepare playerInstance = createPlayerInstance() inventory = MagicMock() - + # call playerInstance.setInventory(inventory) - + # check - assert(playerInstance.getInventory() == inventory) + assert playerInstance.getInventory() == inventory + def test_set_movement_speed(): # prepare playerInstance = createPlayerInstance() - + # call playerInstance.setMovementSpeed(10) - + # check - assert(playerInstance.movementSpeed == 10) + assert playerInstance.movementSpeed == 10 + def test_set_gather_speed(): # prepare playerInstance = createPlayerInstance() - + # call playerInstance.setGatherSpeed(10) - + # check - assert(playerInstance.gatherSpeed == 10) + assert playerInstance.gatherSpeed == 10 + def test_set_place_speed(): # prepare playerInstance = createPlayerInstance() - + # call playerInstance.setPlaceSpeed(10) - + # check - assert(playerInstance.placeSpeed == 10) + assert playerInstance.placeSpeed == 10 + def test_set_crouching(): # prepare playerInstance = createPlayerInstance() - + # call playerInstance.setCrouching(True) - + # check - assert(playerInstance.crouching == True) + assert playerInstance.crouching == True + def test_is_moving(): # prepare playerInstance = createPlayerInstance() - + # call playerInstance.setDirection(0) - + # check - assert(playerInstance.isMoving() == True) + assert playerInstance.isMoving() == True + def is_moving_false(): # prepare playerInstance = createPlayerInstance() - + # call playerInstance.setDirection(-1) - + # check - assert(playerInstance.isMoving() == False) \ No newline at end of file + assert playerInstance.isMoving() == False diff --git a/tests/stats/test_stats.py b/tests/stats/test_stats.py index 7d443d4..5e24481 100644 --- a/tests/stats/test_stats.py +++ b/tests/stats/test_stats.py @@ -1,101 +1,111 @@ from unittest.mock import MagicMock from src.stats.stats import Stats -from src.config.config import Config + def createStatsInstance(): config = MagicMock() config.pathToSaveDirectory = "tests/stats" return Stats(config) + def test_initialization(): # call stats = createStatsInstance() - + # check - assert(stats.getScore() == 0) - assert(stats.getRoomsExplored() == 0) - assert(stats.getFoodEaten() == 0) - assert(stats.getNumberOfDeaths() == 0) + assert stats.getScore() == 0 + assert stats.getRoomsExplored() == 0 + assert stats.getFoodEaten() == 0 + assert stats.getNumberOfDeaths() == 0 + def test_setScore(): # prepare stats = createStatsInstance() - + # call stats.setScore(5) - + # check - assert(stats.getScore() == 5) + assert stats.getScore() == 5 + def test_setRoomsExplored(): # prepare stats = createStatsInstance() - + # call stats.setRoomsExplored(5) - + # check - assert(stats.getRoomsExplored() == 5) + assert stats.getRoomsExplored() == 5 + def test_setFoodEaten(): # prepare stats = createStatsInstance() - + # call stats.setFoodEaten(5) - + # check - assert(stats.getFoodEaten() == 5) - + assert stats.getFoodEaten() == 5 + + def test_setNumberOfDeaths(): # prepare stats = createStatsInstance() - + # call stats.setNumberOfDeaths(5) - + # check - assert(stats.getNumberOfDeaths() == 5) - + assert stats.getNumberOfDeaths() == 5 + + def test_incrementScore(): # prepare stats = createStatsInstance() - + # call stats.incrementScore() - + # check - assert(stats.getScore() == 1) - + assert stats.getScore() == 1 + + def test_incrementRoomsExplored(): # prepare stats = createStatsInstance() - + # call stats.incrementRoomsExplored() - + # check - assert(stats.getRoomsExplored() == 1) + assert stats.getRoomsExplored() == 1 + def test_incrementFoodEaten(): # prepare stats = createStatsInstance() - + # call stats.incrementFoodEaten() - + # check - assert(stats.getFoodEaten() == 1) + assert stats.getFoodEaten() == 1 + def test_incrementNumberOfDeaths(): # prepare stats = createStatsInstance() - + # call stats.incrementNumberOfDeaths() - + # check - assert(stats.getNumberOfDeaths() == 1) + assert stats.getNumberOfDeaths() == 1 + def test_save(): # prepare @@ -104,15 +114,16 @@ def test_save(): stats.incrementRoomsExplored() stats.incrementFoodEaten() stats.incrementNumberOfDeaths() - + # call stats.save() - + # check - assert(stats.getScore() == 1) - assert(stats.getRoomsExplored() == 1) - assert(stats.getFoodEaten() == 1) - assert(stats.getNumberOfDeaths() == 1) + assert stats.getScore() == 1 + assert stats.getRoomsExplored() == 1 + assert stats.getFoodEaten() == 1 + assert stats.getNumberOfDeaths() == 1 + def test_load(): # prepare @@ -121,12 +132,12 @@ def test_load(): stats.incrementRoomsExplored() stats.incrementFoodEaten() stats.incrementNumberOfDeaths() - + # call stats.load() - + # check - assert(stats.getScore() == 1) - assert(stats.getRoomsExplored() == 1) - assert(stats.getFoodEaten() == 1) - assert(stats.getNumberOfDeaths() == 1) \ No newline at end of file + assert stats.getScore() == 1 + assert stats.getRoomsExplored() == 1 + assert stats.getFoodEaten() == 1 + assert stats.getNumberOfDeaths() == 1 From 6cfae0eefabe911bcf80c440e0141326191621f3 Mon Sep 17 00:00:00 2001 From: dmccoystephenson Date: Sun, 26 Feb 2023 21:11:04 -0700 Subject: [PATCH 17/18] Added unit tests for Inventory & InventorySlot classes. --- src/inventory/inventory.py | 8 +- tests/inventory/test_inventory.py | 121 ++++++++++++++++++++++++++ tests/inventory/test_inventorySlot.py | 72 +++++++++++++++ 3 files changed, 195 insertions(+), 6 deletions(-) create mode 100644 tests/inventory/test_inventory.py create mode 100644 tests/inventory/test_inventorySlot.py diff --git a/src/inventory/inventory.py b/src/inventory/inventory.py index b85f100..870b2a9 100644 --- a/src/inventory/inventory.py +++ b/src/inventory/inventory.py @@ -49,16 +49,12 @@ def clear(self): def getNumFreeInventorySlots(self): count = 0 for inventorySlot in self.inventorySlots: - if inventorySlot.getItem() == None: + if inventorySlot.isEmpty(): count += 1 return count def getNumTakenInventorySlots(self): - count = 0 - for inventorySlot in self.inventorySlots: - if inventorySlot.isEmpty() == False: - count += 1 - return count + return self.getNumInventorySlots() - self.getNumFreeInventorySlots() def getNumItems(self): count = 0 diff --git a/tests/inventory/test_inventory.py b/tests/inventory/test_inventory.py new file mode 100644 index 0000000..1305a68 --- /dev/null +++ b/tests/inventory/test_inventory.py @@ -0,0 +1,121 @@ +from src.entity.grass import Grass +from src.inventory import inventory + + +def createInventory(): + return inventory.Inventory() + + +def createGrassEntity(): + return Grass() + + +def test_initialization(): + inventoryInstance = createInventory() + assert inventoryInstance.getNumInventorySlots() == 25 + assert inventoryInstance.getNumFreeInventorySlots() == 25 + assert inventoryInstance.getNumTakenInventorySlots() == 0 + + +def test_placeIntoFirstAvailableInventorySlot(): + inventoryInstance = createInventory() + item = createGrassEntity() + inventoryInstance.placeIntoFirstAvailableInventorySlot(item) + assert inventoryInstance.getNumFreeInventorySlots() == 24 + assert inventoryInstance.getNumTakenInventorySlots() == 1 + assert inventoryInstance.getNumItems() == 1 + assert inventoryInstance.getInventorySlots()[0].getContents() == [item] + + +def test_removeByItem(): + inventoryInstance = createInventory() + item = createGrassEntity() + inventoryInstance.placeIntoFirstAvailableInventorySlot(item) + inventoryInstance.removeByItem(item) + assert inventoryInstance.getNumFreeInventorySlots() == 25 + assert inventoryInstance.getNumTakenInventorySlots() == 0 + assert inventoryInstance.getNumItems() == 0 + assert inventoryInstance.getInventorySlots()[0].getContents() == [] + + +def test_clear(): + inventoryInstance = createInventory() + item = createGrassEntity() + inventoryInstance.placeIntoFirstAvailableInventorySlot(item) + inventoryInstance.clear() + assert inventoryInstance.getNumFreeInventorySlots() == 25 + assert inventoryInstance.getNumTakenInventorySlots() == 0 + assert inventoryInstance.getNumItems() == 0 + assert inventoryInstance.getInventorySlots()[0].getContents() == [] + + +def test_getNumFreeInventorySlots(): + inventoryInstance = createInventory() + for i in range(5 * 20): + item = createGrassEntity() + inventoryInstance.placeIntoFirstAvailableInventorySlot(item) + assert inventoryInstance.getNumFreeInventorySlots() == 20 + assert inventoryInstance.getNumTakenInventorySlots() == 5 + + +def test_getNumTakenInventorySlots(): + inventoryInstance = createInventory() + for i in range(5 * 20): + item = createGrassEntity() + inventoryInstance.placeIntoFirstAvailableInventorySlot(item) + assert inventoryInstance.getNumTakenInventorySlots() == 5 + assert inventoryInstance.getNumFreeInventorySlots() == 20 + + +def test_getNumItems(): + inventoryInstance = createInventory() + for i in range(5): + item = createGrassEntity() + inventoryInstance.placeIntoFirstAvailableInventorySlot(item) + assert inventoryInstance.getNumItems() == 5 + + +def test_getNumItemsByType(): + inventoryInstance = createInventory() + for i in range(5): + item = createGrassEntity() + inventoryInstance.placeIntoFirstAvailableInventorySlot(item) + assert inventoryInstance.getNumItemsByType(Grass) == 5 + + +def test_getSelectedInventorySlotIndex(): + inventoryInstance = createInventory() + assert inventoryInstance.getSelectedInventorySlotIndex() == 0 + + +def test_setSelectedInventorySlotIndex(): + inventoryInstance = createInventory() + inventoryInstance.setSelectedInventorySlotIndex(5) + assert inventoryInstance.getSelectedInventorySlotIndex() == 5 + + +def test_getSelectedInventorySlot(): + inventoryInstance = createInventory() + assert ( + inventoryInstance.getSelectedInventorySlot() + == inventoryInstance.getInventorySlots()[0] + ) + + +def removeSelectedItem(): + inventoryInstance = createInventory() + item = createGrassEntity() + inventoryInstance.placeIntoFirstAvailableInventorySlot(item) + inventoryInstance.removeSelectedItem() + assert inventoryInstance.getNumFreeInventorySlots() == 25 + assert inventoryInstance.getNumTakenInventorySlots() == 0 + assert inventoryInstance.getNumItems() == 0 + assert inventoryInstance.getInventorySlots()[0].getContents() == [] + + +def test_getFirstTenInventorySlots(): + inventoryInstance = createInventory() + assert ( + inventoryInstance.getFirstTenInventorySlots() + == inventoryInstance.getInventorySlots()[:10] + ) diff --git a/tests/inventory/test_inventorySlot.py b/tests/inventory/test_inventorySlot.py new file mode 100644 index 0000000..5db23fa --- /dev/null +++ b/tests/inventory/test_inventorySlot.py @@ -0,0 +1,72 @@ +from src.inventory import inventorySlot +from src.entity.grass import Grass + + +def createInventorySlot(): + return inventorySlot.InventorySlot() + + +def createItem(): + return Grass() + + +def test_initialization(): + inventorySlotInstance = createInventorySlot() + assert inventorySlotInstance.getContents() == [] + assert inventorySlotInstance.getNumItems() == 0 + assert inventorySlotInstance.isEmpty() == True + assert inventorySlotInstance.getMaxStackSize() == 20 + + +def test_add(): + inventorySlotInstance = createInventorySlot() + itemToAdd = createItem() + inventorySlotInstance.add(itemToAdd) + assert inventorySlotInstance.getContents() == [itemToAdd] + assert inventorySlotInstance.getNumItems() == 1 + assert inventorySlotInstance.isEmpty() == False + + +def test_remove(): + inventorySlotInstance = createInventorySlot() + itemToRemove = createItem() + inventorySlotInstance.add(itemToRemove) + inventorySlotInstance.remove(itemToRemove) + assert inventorySlotInstance.getContents() == [] + assert inventorySlotInstance.getNumItems() == 0 + assert inventorySlotInstance.isEmpty() == True + + +def test_pop(): + inventorySlotInstance = createInventorySlot() + itemToPop = createItem() + inventorySlotInstance.add(itemToPop) + assert inventorySlotInstance.pop() == itemToPop + assert inventorySlotInstance.getContents() == [] + assert inventorySlotInstance.getNumItems() == 0 + assert inventorySlotInstance.isEmpty() == True + + +def test_clear(): + inventorySlotInstance = createInventorySlot() + item = createItem() + inventorySlotInstance.add(item) + inventorySlotInstance.clear() + assert inventorySlotInstance.getContents() == [] + assert inventorySlotInstance.getNumItems() == 0 + assert inventorySlotInstance.isEmpty() == True + + +def test_setContents(): + inventorySlotInstance = createInventorySlot() + item1 = createItem() + item2 = createItem() + inventorySlotInstance.setContents([item1, item2]) + assert inventorySlotInstance.getContents() == [item1, item2] + assert inventorySlotInstance.getNumItems() == 2 + assert inventorySlotInstance.isEmpty() == False + + +def test_getMaxStackSize(): + inventorySlotInstance = createInventorySlot() + assert inventorySlotInstance.getMaxStackSize() == 20 From 3959b81eae8603ab3253504c9f654f14fcbca06c Mon Sep 17 00:00:00 2001 From: dmccoystephenson Date: Sun, 12 Mar 2023 00:01:06 -0700 Subject: [PATCH 18/18] Added tests for InventoryJsonReaderWriter class. --- .gitignore | 3 +- .../test_inventoryJsonReaderWriter.py | 30 +++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) create mode 100644 tests/inventory/test_inventoryJsonReaderWriter.py diff --git a/.gitignore b/.gitignore index f64939a..a386329 100644 --- a/.gitignore +++ b/.gitignore @@ -7,4 +7,5 @@ saves/*/mapImage.png output.txt .coverage tests/stats/*.json -cov.xml \ No newline at end of file +cov.xml +tests/*/*.json \ No newline at end of file diff --git a/tests/inventory/test_inventoryJsonReaderWriter.py b/tests/inventory/test_inventoryJsonReaderWriter.py new file mode 100644 index 0000000..5fee743 --- /dev/null +++ b/tests/inventory/test_inventoryJsonReaderWriter.py @@ -0,0 +1,30 @@ +from unittest.mock import MagicMock +from src.config import config +from src.inventory import inventoryJsonReaderWriter + +def createInventoryJsonReaderWriterInstance(): + config.pygame.display = MagicMock() + configInstance = config.Config() + return inventoryJsonReaderWriter.InventoryJsonReaderWriter(configInstance) + +def test_initialization(): + inventoryJsonReaderWriterInstance = createInventoryJsonReaderWriterInstance() + assert inventoryJsonReaderWriterInstance != None + +def test_loadInventory(): + inventoryJsonReaderWriterInstance = createInventoryJsonReaderWriterInstance() + inventoryInstance = inventoryJsonReaderWriterInstance.loadInventory("tests\inventory\inventory.json") + assert inventoryInstance != None + assert inventoryInstance.getNumInventorySlots() == 25 + assert inventoryInstance.getNumFreeInventorySlots() == 25 + assert inventoryInstance.getNumTakenInventorySlots() == 0 + +def test_saveInventory(): + inventoryJsonReaderWriterInstance = createInventoryJsonReaderWriterInstance() + inventoryInstance = inventoryJsonReaderWriterInstance.loadInventory("tests\inventory\inventory.json") + inventoryJsonReaderWriterInstance.saveInventory(inventoryInstance, "tests\inventory\inventory2.json") + inventoryInstance2 = inventoryJsonReaderWriterInstance.loadInventory("tests\inventory\inventory2.json") + assert inventoryInstance2 != None + assert inventoryInstance2.getNumInventorySlots() == 25 + assert inventoryInstance2.getNumFreeInventorySlots() == 25 + assert inventoryInstance2.getNumTakenInventorySlots() == 0 \ No newline at end of file