139 lines
4.7 KiB
Python
139 lines
4.7 KiB
Python
import atexit
|
|
import os
|
|
import pathlib
|
|
import tempfile
|
|
import unittest
|
|
|
|
# Point the engine at a fresh empty save to keep collection-dependent tests hermetic.
|
|
import engine.collection as collection
|
|
from engine import bosses
|
|
from engine.battle import Battle
|
|
from engine.plants import make_leveled
|
|
from engine.unit import TEAM_ENEMY, TEAM_PLAYER
|
|
|
|
_fd, _tmp_path = tempfile.mkstemp(suffix=".json")
|
|
os.close(_fd)
|
|
_TMP = pathlib.Path(_tmp_path)
|
|
_ORIG_DATA_FILE = collection._DATA_FILE
|
|
collection._DATA_FILE = _TMP
|
|
|
|
|
|
@atexit.register
|
|
def _restore_collection():
|
|
collection._DATA_FILE = _ORIG_DATA_FILE
|
|
if _TMP.exists():
|
|
_TMP.unlink()
|
|
|
|
|
|
class BossSchedulingTest(unittest.TestCase):
|
|
def test_boss_appears_on_multiples_of_20(self):
|
|
self.assertEqual(bosses.boss_for_floor(20), "Stones")
|
|
self.assertEqual(bosses.boss_for_floor(40), "Stones")
|
|
self.assertEqual(bosses.boss_for_floor(100), "Stones")
|
|
self.assertIsNone(bosses.boss_for_floor(19))
|
|
self.assertIsNone(bosses.boss_for_floor(1))
|
|
|
|
def test_boss_stats_are_extreme(self):
|
|
u = bosses.make_boss("Stones", 20)
|
|
# very low speed, medium defense, high health, medium attack
|
|
self.assertLessEqual(u.speed, 40)
|
|
self.assertGreaterEqual(u.max_hp, 900)
|
|
self.assertGreaterEqual(u.defense, 80)
|
|
self.assertTrue(60 <= u.attack <= 200)
|
|
|
|
|
|
class BossMechanicTest(unittest.TestCase):
|
|
def _battle(self):
|
|
a = make_leveled("Rose", TEAM_PLAYER, 20, 1)
|
|
a.max_hp = 5000
|
|
a.hp = 5000
|
|
u = bosses.make_boss("Stones", 20)
|
|
b = Battle([a], [u])
|
|
b.start()
|
|
return b, a, u
|
|
|
|
def test_landslide_blocked_until_three_stacks(self):
|
|
b, a, u = self._battle()
|
|
b.current = u
|
|
pebble, landslide = u.skills
|
|
u.acted = False
|
|
self.assertFalse(b.use_skill(u, landslide, a)) # 0 stacks: blocked
|
|
self.assertEqual(b.valid_skill_targets(u, landslide), [])
|
|
for _ in range(3):
|
|
u.acted = False
|
|
self.assertTrue(b.use_skill(u, pebble, a))
|
|
self.assertEqual(u.status["boss_stacks"], 3)
|
|
u.acted = False
|
|
self.assertTrue(b.use_skill(u, landslide, a)) # now available
|
|
self.assertEqual(u.status["boss_stacks"], 0) # released
|
|
|
|
def test_boss_stacks_cap_at_three(self):
|
|
b, a, u = self._battle()
|
|
b.current = u
|
|
pebble, _ = u.skills
|
|
for _ in range(6):
|
|
u.acted = False
|
|
self.assertTrue(b.use_skill(u, pebble, a))
|
|
self.assertEqual(u.status["boss_stacks"], 3) # never exceeds 3
|
|
|
|
def test_boss_ai_pebbles_then_landslides_then_repeats(self):
|
|
b, a, u = self._battle()
|
|
moves = []
|
|
guard = 0
|
|
while len(moves) < 7 and guard < 120 and b.winner is None:
|
|
guard += 1
|
|
if b.current is u and not u.acted:
|
|
before = u.status.get("boss_stacks", 0)
|
|
used = b.enemy_ai(u)
|
|
after = u.status.get("boss_stacks", 0)
|
|
if used:
|
|
moves.append("Pebble" if after > before else
|
|
("Landslide" if before >= 3 and after == 0 else "?"))
|
|
b.next_turn()
|
|
self.assertEqual(moves[:4], ["Pebble", "Pebble", "Pebble", "Landslide"])
|
|
self.assertEqual(moves[4:], ["Pebble", "Pebble", "Pebble"])
|
|
|
|
def test_landslide_hits_harder_than_pebble(self):
|
|
b, a, u = self._battle()
|
|
b.current = u
|
|
pebble, landslide = u.skills
|
|
for _ in range(3):
|
|
u.acted = False
|
|
b.use_skill(u, pebble, a)
|
|
u.acted = False
|
|
pebble_dmg = b._hit_damage.get(id(a), 0)
|
|
a.hp = a.max_hp # reset before landslide
|
|
u.status["boss_stacks"] = 3
|
|
b.use_skill(u, landslide, a)
|
|
landslide_dmg = b._hit_damage.get(id(a), 0)
|
|
self.assertGreater(landslide_dmg, pebble_dmg * 2)
|
|
|
|
|
|
class BossRewardTest(unittest.TestCase):
|
|
def setUp(self):
|
|
data = collection.load()
|
|
data["owned"] = ["Rose"]
|
|
data["bosses_fought"] = []
|
|
data["runes"] = []
|
|
collection.save(data)
|
|
|
|
def test_mark_boss_fought(self):
|
|
self.assertEqual(collection.bosses_fought(), set())
|
|
collection.mark_boss_fought("Stones")
|
|
self.assertEqual(collection.bosses_fought(), {"Stones"})
|
|
|
|
def test_boss_rune_drop_is_high_chance_and_select(self):
|
|
colors = set()
|
|
total = 0
|
|
for _ in range(300):
|
|
r = collection.boss_rune_drop("Stones")
|
|
if r:
|
|
total += 1
|
|
self.assertIn(r["color"], ("ruby", "amethyst"))
|
|
colors.add(r["color"])
|
|
self.assertGreaterEqual(total, 150) # ~80% chance
|
|
self.assertEqual(colors, {"ruby", "amethyst"})
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main() |