Initial commit: Plants turn-based battle game
This commit is contained in:
@@ -0,0 +1,313 @@
|
||||
import atexit
|
||||
import os
|
||||
import pathlib
|
||||
import tempfile
|
||||
import time
|
||||
import unittest
|
||||
|
||||
# Point the engine at a fresh empty save to keep these tests hermetic.
|
||||
import engine.collection as collection
|
||||
|
||||
_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 SoilTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
data = collection.load()
|
||||
data["owned"] = ["Rose", "Lavender", "Zinnia"]
|
||||
data["soil"] = {"seed_cd_until": 0.0, "seeds": [], "plots": []}
|
||||
data["water"] = 10
|
||||
data["fertilizer"] = 10
|
||||
collection.save(data)
|
||||
|
||||
def test_retrieve_seed(self):
|
||||
self.assertEqual(collection.retrieve_seed("Rose"), "")
|
||||
state = collection.soil_state()
|
||||
self.assertEqual(len(state["seeds"]), 1)
|
||||
self.assertEqual(state["seeds"][0]["plant"], "Rose")
|
||||
self.assertGreater(state["cd_left"], 0) # cooldown set
|
||||
|
||||
def test_retrieve_respects_cooldown(self):
|
||||
collection.retrieve_seed("Rose")
|
||||
self.assertNotEqual(collection.retrieve_seed("Lavender"), "")
|
||||
state = collection.soil_state()
|
||||
self.assertEqual(len(state["seeds"]), 1)
|
||||
|
||||
def test_retrieve_requires_owned(self):
|
||||
self.assertNotEqual(collection.retrieve_seed("NotAPlant"), "")
|
||||
data = collection.load()
|
||||
data["discovered"] = ["Marigold"]
|
||||
collection.save(data)
|
||||
self.assertNotEqual(collection.retrieve_seed("Marigold"), "")
|
||||
|
||||
def test_plant_creates_stage_zero_plot(self):
|
||||
collection.retrieve_seed("Rose")
|
||||
self.assertEqual(collection.plant_seed(0), "")
|
||||
state = collection.soil_state()
|
||||
self.assertEqual(len(state["plots"]), 1)
|
||||
self.assertEqual(state["seeds"], [])
|
||||
plot = state["plots"][0]
|
||||
self.assertEqual(plot["stage"], 0)
|
||||
self.assertFalse(plot["grown"])
|
||||
self.assertFalse(plot["stalled"]) # stage not yet full
|
||||
|
||||
def test_stage_fills_over_time(self):
|
||||
data = collection.load()
|
||||
data["soil"]["plots"] = [{"plant": "Rose", "stage_started_at": 0, "stage": 0, "water": 0}]
|
||||
collection.save(data)
|
||||
state = collection.soil_state()
|
||||
plot = state["plots"][0]
|
||||
self.assertEqual(plot["stage_progress"], 1.0)
|
||||
self.assertTrue(plot["stalled"]) # stage full -> needs water
|
||||
self.assertFalse(plot["grown"]) # but not the last stage
|
||||
|
||||
def test_water_requires_stalled(self):
|
||||
collection.retrieve_seed("Rose")
|
||||
collection.plant_seed(0)
|
||||
self.assertNotEqual(collection.water_plot(0), "") # not stalled yet
|
||||
|
||||
def test_water_advances_stage(self):
|
||||
data = collection.load()
|
||||
data["soil"]["plots"] = [{"plant": "Rose", "stage_started_at": 0, "stage": 0, "water": 0}]
|
||||
collection.save(data)
|
||||
self.assertEqual(collection.water_plot(0), "")
|
||||
self.assertEqual(collection.available_fertilizer(), 9)
|
||||
state = collection.soil_state()
|
||||
self.assertEqual(state["plots"][0]["stage"], 1)
|
||||
self.assertEqual(state["plots"][0]["water"], 1)
|
||||
self.assertFalse(state["plots"][0]["stalled"]) # new stage just started
|
||||
|
||||
def test_water_requires_fertilizer_pool(self):
|
||||
data = collection.load()
|
||||
data["fertilizer"] = 0
|
||||
data["soil"]["plots"] = [{"plant": "Rose", "stage_started_at": 0, "stage": 0, "water": 0}]
|
||||
collection.save(data)
|
||||
self.assertNotEqual(collection.water_plot(0), "")
|
||||
|
||||
def test_harvest_requires_grown(self):
|
||||
collection.retrieve_seed("Rose")
|
||||
collection.plant_seed(0)
|
||||
self.assertNotEqual(collection.harvest_plot(0), "") # not grown
|
||||
|
||||
def test_grow_all_stages_then_harvest(self):
|
||||
# Rose is super-rare -> 4 stages. Plant with an old stage_started_at so each
|
||||
# stage is instantly full, then water through stages 0..2.
|
||||
data = collection.load()
|
||||
data["soil"]["plots"] = [{"plant": "Rose", "stage_started_at": 0, "stage": 0, "water": 0}]
|
||||
collection.save(data)
|
||||
total = collection.GROWTH_STAGES["super_rare"]
|
||||
for expected in range(total - 1):
|
||||
self.assertNotEqual(collection.harvest_plot(0), "") # not grown mid-way
|
||||
self.assertEqual(collection.water_plot(0), "", f"water to advance to {expected + 1}")
|
||||
# each watered stage is instantly full again (stage_started_at=now)
|
||||
data = collection.load()
|
||||
data["soil"]["plots"][0]["stage_started_at"] = 0
|
||||
collection.save(data)
|
||||
state = collection.soil_state()
|
||||
self.assertTrue(state["plots"][0]["grown"])
|
||||
dup_before = collection.get_progress("Rose")["duplicates"]
|
||||
self.assertEqual(collection.harvest_plot(0), "")
|
||||
state = collection.soil_state()
|
||||
self.assertEqual(state["plots"], [])
|
||||
self.assertEqual(collection.get_progress("Rose")["duplicates"], dup_before + 1)
|
||||
|
||||
def test_higher_rarity_more_stages(self):
|
||||
self.assertGreater(collection.GROWTH_STAGES["super_super_rare"],
|
||||
collection.GROWTH_STAGES["super_rare"])
|
||||
self.assertGreater(collection.GROWTH_STAGES["super_rare"],
|
||||
collection.GROWTH_STAGES["rare"])
|
||||
self.assertGreater(collection.GROWTH_STAGES["rare"],
|
||||
collection.GROWTH_STAGES["common"])
|
||||
|
||||
def test_default_one_plot_unlocked(self):
|
||||
state = collection.soil_state()
|
||||
self.assertEqual(state["plots_unlocked"], 1)
|
||||
self.assertEqual(state["plots_max"], collection.SOIL_PLOTS_MAX)
|
||||
|
||||
def test_soil_gated_by_owned_plants(self):
|
||||
data = collection.load()
|
||||
data["owned"] = ["Rose", "Lavender"]
|
||||
collection.save(data)
|
||||
self.assertFalse(collection.soil_unlocked())
|
||||
data = collection.load()
|
||||
data["owned"] = [f"Plant{i}" for i in range(collection.SOIL_GATE_PLANTS)]
|
||||
for n in data["owned"]:
|
||||
data["progress"].setdefault(n, {"level": 1, "stage": 1, "xp": 0,
|
||||
"duplicates": 0, "watered_at": 0})
|
||||
collection.save(data)
|
||||
self.assertTrue(collection.soil_unlocked())
|
||||
|
||||
def test_plot_unlock_costs_escalate(self):
|
||||
self.assertEqual(collection.plot_unlock_cost(2), (10, 5))
|
||||
self.assertEqual(collection.plot_unlock_cost(3), (50, 20))
|
||||
self.assertEqual(collection.plot_unlock_cost(4), (100, 50))
|
||||
self.assertEqual(collection.plot_unlock_cost(5), (0, 0))
|
||||
|
||||
def test_plant_limited_to_unlocked_plots(self):
|
||||
data = collection.load()
|
||||
data["soil"]["plots"] = [{"plant": "Rose", "stage_started_at": 0, "stage": 0, "water": 0}]
|
||||
collection.save(data)
|
||||
# 1 unlocked, 1 planted -> planting another seed fails
|
||||
collection.retrieve_seed("Lavender")
|
||||
self.assertEqual(len(collection.soil_state()["seeds"]), 1)
|
||||
self.assertNotEqual(collection.plant_seed(0), "")
|
||||
|
||||
def test_unlock_plot_spends_coins_and_fertilizer(self):
|
||||
data = collection.load()
|
||||
data["coins"] = 10
|
||||
data["fertilizer"] = 5
|
||||
collection.save(data)
|
||||
self.assertEqual(collection.unlock_plot(), "")
|
||||
self.assertEqual(collection.soil_state()["plots_unlocked"], 2)
|
||||
self.assertEqual(collection.available_coins(), 0)
|
||||
self.assertEqual(collection.available_fertilizer(), 0)
|
||||
# too little fertilizer now
|
||||
self.assertNotEqual(collection.unlock_plot(), "")
|
||||
|
||||
def test_unlock_plot_requires_coins(self):
|
||||
data = collection.load()
|
||||
data["coins"] = 0
|
||||
data["fertilizer"] = 50
|
||||
collection.save(data)
|
||||
self.assertNotEqual(collection.unlock_plot(), "")
|
||||
|
||||
def test_unlock_plot_requires_fertilizer(self):
|
||||
data = collection.load()
|
||||
data["coins"] = 50
|
||||
data["fertilizer"] = 4
|
||||
collection.save(data)
|
||||
self.assertNotEqual(collection.unlock_plot(), "")
|
||||
|
||||
def test_unlock_plot_max_four(self):
|
||||
data = collection.load()
|
||||
data["coins"] = 500
|
||||
data["fertilizer"] = 500
|
||||
collection.save(data)
|
||||
for _ in range(3):
|
||||
self.assertEqual(collection.unlock_plot(), "")
|
||||
self.assertEqual(collection.soil_state()["plots_unlocked"], collection.SOIL_PLOTS_MAX)
|
||||
self.assertNotEqual(collection.unlock_plot(), "") # capped
|
||||
|
||||
def test_after_unlock_extra_plot_usable(self):
|
||||
data = collection.load()
|
||||
data["coins"] = 10
|
||||
data["fertilizer"] = 5
|
||||
data["soil"]["plots"] = [{"plant": "Rose", "stage_started_at": 0, "stage": 0, "water": 0}]
|
||||
collection.save(data)
|
||||
collection.unlock_plot() # now 2 unlocked, 1 used
|
||||
collection.retrieve_seed("Lavender")
|
||||
self.assertEqual(collection.plant_seed(0), "")
|
||||
self.assertEqual(len(collection.soil_state()["plots"]), 2)
|
||||
|
||||
|
||||
class AutoFarmerTest(unittest.TestCase):
|
||||
def setUp(self):
|
||||
data = collection.load()
|
||||
data["owned"] = ["Rose", "Lavender", "Zinnia"]
|
||||
data["soil"] = {"seed_cd_until": 0.0, "seeds": [], "plots": []}
|
||||
data["fertilizer"] = 10
|
||||
data["coins"] = 100
|
||||
data["auto_farmer"] = False
|
||||
collection.save(data)
|
||||
|
||||
def _stalled_plot(self):
|
||||
data = collection.load()
|
||||
data["soil"]["plots"] = [{"plant": "Rose", "stage_started_at": 0, "stage": 0, "water": 0}]
|
||||
collection.save(data)
|
||||
|
||||
def test_accrue_fertilizer_grants_one_per_hour(self):
|
||||
data = collection.load()
|
||||
data["fertilizer_accrued_at"] = time.time() - 7200 # 2 hours ago
|
||||
data["fertilizer"] = 0
|
||||
collection.save(data)
|
||||
self.assertEqual(collection.accrue_fertilizer(), 2)
|
||||
self.assertEqual(collection.available_fertilizer(), 2)
|
||||
|
||||
def test_accrue_fertilizer_caps(self):
|
||||
data = collection.load()
|
||||
data["fertilizer_accrued_at"] = time.time() - 7200
|
||||
data["fertilizer"] = 99
|
||||
collection.save(data)
|
||||
self.assertEqual(collection.accrue_fertilizer(), 1)
|
||||
self.assertEqual(collection.available_fertilizer(), 100)
|
||||
|
||||
def test_add_fertilizer_caps(self):
|
||||
data = collection.load()
|
||||
data["fertilizer"] = 99
|
||||
collection.save(data)
|
||||
collection.add_fertilizer(10)
|
||||
self.assertEqual(collection.available_fertilizer(), 100)
|
||||
|
||||
def test_buy_auto_farmer(self):
|
||||
self.assertEqual(collection.buy_auto_farmer(), "")
|
||||
self.assertTrue(collection.auto_farmer_owned())
|
||||
self.assertEqual(collection.available_coins(), 0)
|
||||
self.assertNotEqual(collection.buy_auto_farmer(), "") # already owned
|
||||
|
||||
def test_buy_auto_farmer_requires_coins(self):
|
||||
data = collection.load()
|
||||
data["coins"] = 50
|
||||
collection.save(data)
|
||||
self.assertNotEqual(collection.buy_auto_farmer(), "")
|
||||
self.assertFalse(collection.auto_farmer_owned())
|
||||
|
||||
def test_buy_activates_farmer(self):
|
||||
self.assertEqual(collection.buy_auto_farmer(), "")
|
||||
self.assertTrue(collection.auto_farmer_active())
|
||||
|
||||
def test_toggle_auto_farmer(self):
|
||||
collection.buy_auto_farmer()
|
||||
self.assertTrue(collection.auto_farmer_active())
|
||||
self.assertFalse(collection.toggle_auto_farmer()) # turned off
|
||||
self.assertFalse(collection.auto_farmer_active())
|
||||
self.assertTrue(collection.toggle_auto_farmer()) # back on
|
||||
self.assertTrue(collection.auto_farmer_owned()) # still owns it
|
||||
|
||||
def test_auto_farm_respects_toggle(self):
|
||||
self._stalled_plot()
|
||||
collection.buy_auto_farmer()
|
||||
collection.toggle_auto_farmer() # turn it off
|
||||
self.assertEqual(collection.auto_farm(), "Auto farmer off")
|
||||
self.assertEqual(collection.available_fertilizer(), 10) # nothing spent
|
||||
self.assertEqual(collection.soil_state()["plots"][0]["stage"], 0)
|
||||
|
||||
def test_auto_farm_fertilizes_stalled_plot(self):
|
||||
self._stalled_plot()
|
||||
self.assertEqual(collection.buy_auto_farmer(), "")
|
||||
self.assertEqual(collection.auto_farm(), "")
|
||||
self.assertEqual(collection.available_fertilizer(), 9)
|
||||
self.assertEqual(collection.soil_state()["plots"][0]["stage"], 1)
|
||||
|
||||
def test_auto_farm_requires_farmer(self):
|
||||
self._stalled_plot()
|
||||
self.assertEqual(collection.auto_farm(), "No auto farmer")
|
||||
|
||||
def test_auto_farm_does_not_plant_or_harvest(self):
|
||||
data = collection.load()
|
||||
data["soil"]["plots"] = [
|
||||
{"plant": "Rose", "stage_started_at": 0, "stage": 0, "water": 0}, # stalled
|
||||
{"plant": "Rose", "stage_started_at": 0, "stage": 3, "water": 0}, # grown (epic)
|
||||
]
|
||||
data["soil"]["seeds"] = [{"plant": "Lavender"}]
|
||||
collection.save(data)
|
||||
self.assertEqual(collection.buy_auto_farmer(), "")
|
||||
self.assertEqual(collection.auto_farm(), "")
|
||||
state = collection.soil_state()
|
||||
self.assertEqual(len(state["plots"]), 2) # grown plot not harvested
|
||||
self.assertEqual(len(state["seeds"]), 1) # seed not planted
|
||||
self.assertEqual(state["plots"][0]["stage"], 1) # stalled plot advanced
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in New Issue
Block a user