305 lines
10 KiB
Python
305 lines
10 KiB
Python
# Copyright (C) 2020-2021 by ÿnérant, eichhornchen, nicomarg, charlse
|
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
import random
|
|
import unittest
|
|
|
|
from ..entities.friendly import Chest, Trumpet
|
|
from ..entities.items import BodySnatchPotion, Bomb, Explosion, Heart, Item
|
|
from ..entities.monsters import GiantSeaEagle, Hedgehog, Rabbit, \
|
|
TeddyBear, Tiger
|
|
from ..entities.player import Player
|
|
from ..interfaces import Entity, Map
|
|
from ..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, 30)
|
|
self.assertEqual(entity.maxhealth, entity.health)
|
|
self.assertEqual(entity.strength, 5)
|
|
for _ in range(5):
|
|
self.assertEqual(entity.hit(entity),
|
|
"Tiger hits tiger. Tiger takes 5 damage.")
|
|
self.assertFalse(entity.dead)
|
|
self.assertEqual(entity.hit(entity), "Tiger hits tiger. "
|
|
+ "Tiger takes 5 damage. Tiger dies.")
|
|
self.assertTrue(entity.dead)
|
|
|
|
entity = Rabbit()
|
|
entity.health = 15
|
|
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 that a chest is destroyed by a bomb
|
|
bomb = Bomb()
|
|
bomb.owner = self.player
|
|
bomb.move(3, 6)
|
|
self.map.add_entity(bomb)
|
|
chest = Chest()
|
|
chest.move(4, 6)
|
|
self.map.add_entity(chest)
|
|
bomb.exploding = True
|
|
for _ in range(5):
|
|
self.map.tick(self.player)
|
|
self.assertTrue(chest.annihilated)
|
|
|
|
def test_familiar(self) -> None:
|
|
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(6, 5)
|
|
fam.move(5, 5)
|
|
fam.target = None
|
|
self.player.move_down()
|
|
self.map.tick(self.player)
|
|
self.assertTrue(fam.target == self.player)
|
|
self.assertEqual(fam.y, 6)
|
|
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.assertIsNone(item.held_by)
|
|
item.hold(self.player)
|
|
self.assertEqual(item.held_by, self.player)
|
|
item.drop()
|
|
self.assertEqual(item.y, 1)
|
|
self.assertEqual(item.x, 6)
|
|
|
|
# Pick up item
|
|
self.player.move_left()
|
|
self.player.move_right()
|
|
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.assertIsNone(explosion.held_by)
|
|
|
|
# The explosion disappears after two ticks
|
|
explosion.act(self.map)
|
|
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)
|
|
|
|
player = Player()
|
|
player.map = self.map
|
|
player.add_xp(700)
|
|
for _ in range(13):
|
|
player.level_up()
|
|
self.assertEqual(player.level, 12)
|
|
self.assertEqual(player.critical, 5 + 95 // 30)
|
|
self.assertEqual(player.charisma, 3)
|
|
|
|
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)
|