# Copyright (C) 2020-2021 by ÿnérant, eichhornchen, nicomarg, charlse # SPDX-License-Identifier: GPL-3.0-or-later import random import unittest from squirrelbattle.entities.items import BodySnatchPotion, Bomb, Heart, Item, \ Explosion from squirrelbattle.entities.monsters import Tiger, Hedgehog, Rabbit,\ TeddyBear, GiantSeaEagle from squirrelbattle.entities.friendly import Trumpet from squirrelbattle.entities.player import Player from squirrelbattle.interfaces import Entity, Map from squirrelbattle.resources import ResourceManager class TestEntities(unittest.TestCase): def setUp(self) -> None: """ Loads example map that can be used in tests. """ self.map = Map.load(ResourceManager.get_asset_path("example_map.txt")) self.player = Player() self.player.constitution = 0 self.map.add_entity(self.player) self.player.move(self.map.start_y, self.map.start_x) def test_basic_entities(self) -> None: """ Tests some random stuff with basic entities. """ entity = Entity() entity.move(42, 64) self.assertEqual(entity.y, 42) self.assertEqual(entity.x, 64) self.assertIsNone(entity.act(self.map)) other_entity = Entity() other_entity.move(45, 68) self.assertEqual(entity.distance_squared(other_entity), 25) self.assertEqual(entity.distance(other_entity), 5) def test_fighting_entities(self) -> None: """ Tests some random stuff with fighting entities. """ entity = Tiger() self.map.add_entity(entity) self.assertEqual(entity.maxhealth, 20) self.assertEqual(entity.maxhealth, entity.health) self.assertEqual(entity.strength, 2) for _ in range(9): self.assertEqual(entity.hit(entity), "Tiger hits tiger. Tiger takes 2 damage.") self.assertFalse(entity.dead) self.assertEqual(entity.hit(entity), "Tiger hits tiger. " + "Tiger takes 2 damage. Tiger dies.") self.assertTrue(entity.dead) entity = Rabbit() entity.critical = 0 self.map.add_entity(entity) entity.move(15, 44) # Move randomly self.map.tick(self.player) self.assertFalse(entity.y == 15 and entity.x == 44) # Move to the player entity.move(3, 6) self.map.tick(self.player) self.assertTrue(entity.y == 2 and entity.x == 6) # Rabbit should fight old_health = self.player.health self.map.tick(self.player) self.assertTrue(entity.y == 2 and entity.x == 6) self.assertEqual(old_health - entity.strength, self.player.health) self.assertEqual(self.map.logs.messages[-1], f"{entity.name.capitalize()} hits {self.player.name}. \ {self.player.name.capitalize()} takes {entity.strength} damage.") # Fight the rabbit self.player.critical = 0 old_health = entity.health self.player.move_down() self.assertEqual(entity.health, old_health - self.player.strength) self.assertFalse(entity.dead) old_health = entity.health self.player.move_down() self.assertEqual(entity.health, old_health - self.player.strength) self.assertFalse(entity.dead) old_health = entity.health self.player.move_down() self.assertEqual(entity.health, old_health - self.player.strength) self.assertTrue(entity.dead) self.assertGreaterEqual(self.player.current_xp, 3) # Test the familiars fam = Trumpet() entity = Rabbit() self.map.add_entity(entity) self.map.add_entity(fam) self.player.move(1, 6) entity.move(2, 6) fam.move(2, 7) # Test fighting entity.health = 2 entity.paths = [] entity.recalculate_paths() fam.target = entity self.map.tick(self.player) self.assertTrue(entity.dead) # Test finding a new target entity2 = Rabbit() self.map.add_entity(entity2) entity2.move(2, 6) self.map.tick(self.player) self.assertTrue(fam.target == entity2) self.map.remove_entity(entity2) # Test following the player and finding the player as target self.player.move(5, 5) fam.move(4, 5) fam.target = None self.player.move_down() self.map.tick(self.player) self.assertTrue(fam.target == self.player) self.assertEqual(fam.y, 5) self.assertEqual(fam.x, 5) # Test random move fam.move(13, 20) fam.target = self.player self.map.tick(self.player) self.assertTrue(fam.x != 20 or fam.y != 13) def test_items(self) -> None: """ Tests some random stuff with items. """ item = Item() self.map.add_entity(item) self.assertFalse(item.held) item.hold(self.player) self.assertTrue(item.held) item.drop() self.assertEqual(item.y, 1) self.assertEqual(item.x, 6) # Pick up item self.player.move_left() self.player.move_right() self.assertTrue(item.held) self.assertEqual(item.held_by, self.player) self.assertIn(item, self.player.inventory) self.assertNotIn(item, self.map.entities) def test_bombs(self) -> None: """ Tests some random stuff with bombs. """ item = Bomb() hedgehog = Hedgehog() teddy_bear = TeddyBear() self.map.add_entity(item) self.map.add_entity(hedgehog) self.map.add_entity(teddy_bear) hedgehog.health = 2 teddy_bear.health = 2 hedgehog.move(41, 42) teddy_bear.move(42, 41) item.act(self.map) self.assertFalse(hedgehog.dead) self.assertFalse(teddy_bear.dead) self.player.move(42, 42) item.hold(self.player) item.use() self.assertEqual(item.y, 42) self.assertEqual(item.x, 42) # Wait for the explosion for _ignored in range(5): item.act(self.map) self.assertTrue(hedgehog.dead) self.assertTrue(teddy_bear.dead) bomb_state = item.save_state() self.assertEqual(bomb_state["damage"], item.damage) explosions = self.map.find_entities(Explosion) self.assertTrue(explosions) explosion = explosions[0] self.assertEqual(explosion.y, item.y) self.assertEqual(explosion.x, item.x) # The player can't hold the explosion explosion.hold(self.player) self.assertNotIn(explosion, self.player.inventory) self.assertFalse(explosion.held) # The explosion disappears after one tick explosion.act(self.map) self.assertNotIn(explosion, self.map.entities) def test_hearts(self) -> None: """ Tests some random stuff with hearts. """ item = Heart() self.map.add_entity(item) item.move(2, 6) self.player.health -= 2 * item.healing self.player.move_down() self.assertNotIn(item, self.map.entities) self.assertEqual(self.player.health, self.player.maxhealth - item.healing) heart_state = item.save_state() self.assertEqual(heart_state["healing"], item.healing) def test_body_snatch_potion(self) -> None: """ Tests some random stuff with body snatch potions. """ item = BodySnatchPotion() self.map.add_entity(item) item.hold(self.player) tiger = Tiger(y=42, x=42) self.map.add_entity(tiger) # The player becomes a tiger, and the tiger becomes a squirrel item.use() self.assertEqual(self.player.name, "tiger") self.assertEqual(tiger.name, "player") self.assertEqual(self.player.y, 42) self.assertEqual(self.player.x, 42) def test_players(self) -> None: """ Tests some random stuff with players. """ player = Player() self.map.add_entity(player) player.move(1, 6) self.assertEqual(player.strength, 5) self.assertEqual(player.health, player.maxhealth) self.assertEqual(player.maxhealth, 20) # Test movements and ensure that collisions are working self.assertFalse(player.move_up()) self.assertTrue(player.move_left()) self.assertFalse(player.move_left()) for _ in range(8): self.assertTrue(player.move_down()) self.assertFalse(player.move_down()) self.assertTrue(player.move_right()) self.assertTrue(player.move_right()) self.assertTrue(player.move_right()) self.assertFalse(player.move_right()) self.assertTrue(player.move_down()) self.assertTrue(player.move_down()) player.add_xp(70) self.assertEqual(player.current_xp, 10) self.assertEqual(player.max_xp, 40) self.assertEqual(player.level, 4) player_state = player.save_state() self.assertEqual(player_state["current_xp"], 10) def test_critical_hit(self) -> None: """ Ensure that critical hits are working. """ random.seed(2) # Next random.randint(1, 100) will output 8 self.player.critical = 10 sea_eagle = GiantSeaEagle() self.map.add_entity(sea_eagle) sea_eagle.move(2, 6) old_health = sea_eagle.health self.player.hit(sea_eagle) self.assertEqual(sea_eagle.health, old_health - self.player.strength * 4)