You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Fox-V3/conquest/conquestgame.py

187 lines
6.2 KiB

import asyncio
import json
import logging
import pathlib
from shutil import copyfile
from types import SimpleNamespace
from typing import Optional, Union
import discord
from PIL import Image, ImageOps
from redbot.core import commands
from conquest.regioner import ConquestMap, composite_regions
log = logging.getLogger("red.fox_v3.conquest.conquestgame")
class ConquestGame:
ext = "PNG"
ext_format = "PNG"
default_zoom_json = {"enabled": False, "x": -1, "y": -1, "zoom": 1.0}
def __init__(self, map_path: pathlib.Path, game_name: str, custom_map_path: pathlib.Path):
self.source_map = ConquestMap(map_path)
self.source_map.load_data()
self.game_name = game_name
self.current_map_folder = custom_map_path
self.settings_json = self.current_map_folder / "settings.json"
self.current_filename = f"current.{self.ext}"
self.current_map = self.current_map_folder / self.current_filename
self.zoomed_current_filename = f"current_zoomed.{self.ext}"
self.zoomed_current_map = self.current_map_folder / self.zoomed_current_filename
self.numbered_current_filename = f"current_numbered.{self.ext}"
self.numbered_current_map = self.current_map_folder / self.numbered_current_filename
self.zoomed_numbered_current_filename = f"current_zoomed_numbered.{self.ext}"
self.zoomed_numbered_current_map = (
self.current_map_folder / self.zoomed_numbered_current_filename
)
self.region_max = self.source_map.region_max
# self.zoom_is_out_of_date = {'current': True, 'blank': True}
async def save_region(self, region):
if not self.custom:
return False
pass # TODO: region data saving
async def start_game(self):
if not self.current_map_folder.exists():
self.current_map_folder.mkdir()
copyfile(self.source_map.blank_path(), self.current_map)
async def resume_game(self, ctx: commands.Context, reset: bool):
if not reset and self.current_map.exists():
await ctx.maybe_send_embed(
"This map is already in progress, resuming from last game\n"
"Use `[p]conquest set map [mapname] True` to start a new game"
)
else:
await self.start_game()
async def _process_take_regions(self, color, regions):
im = Image.open(self.current_map)
out: Optional[Image.Image] = await composite_regions(
im,
regions,
color,
self.source_map.masks_path(),
)
out.save(self.current_map, self.ext_format) # Overwrite current map with new map
# self.zoom_is_out_of_date.current = True
async def create_numbered_map(self):
if (
not self.source_map.numbers_path().exists()
): # No numbers map, can't add numbers to current
return self.source_map.numbered_path()
current_map = Image.open(self.current_map)
numbers = Image.open(self.source_map.numbers_path()).convert("L")
inverted_map = ImageOps.invert(current_map)
loop = asyncio.get_running_loop()
current_numbered_img = await loop.run_in_executor(
None, Image.composite, current_map, inverted_map, numbers
)
current_numbered_img.save(self.numbered_current_map, self.ext_format)
return self.numbered_current_map
async def create_zoomed_map(
self,
x,
y,
zoom,
source_map: Union[Image.Image, pathlib.Path],
target_path: pathlib.Path,
**kwargs,
):
"""Pass out_of_date when created a zoomed map based on something other than the settings json"""
# if out_of_date:
# self.zoom_is_out_of_date.current = True
# if current_map is None:
# current_map = Image.open(self.current_map_folder)
# target_map = self.zoomed_current_map
if not isinstance(source_map, Image.Image):
source_map = Image.open(source_map)
w, h = source_map.size
zoom2 = zoom * 2
zoomed_map = source_map.crop((x - w / zoom2, y - h / zoom2, x + w / zoom2, y + h / zoom2))
# zoomed_map = zoomed_map.resize((w, h), Image.LANCZOS)
zoomed_map.save(target_path, self.ext_format)
return True
async def get_maybe_zoomed_map(self, version):
zoom_data = {"enabled": False}
if self.settings_json.exists():
with self.settings_json.open() as zoom_json:
zoom_data = json.load(zoom_json)
if version == "numbered":
map_path = self.create_numbered_map()
zoomed_path = self.zoomed_numbered_current_map
else: # version == "current"
map_path = self.current_map
zoomed_path = self.zoomed_current_map
if zoom_data["enabled"]: # Send zoomed map instead of current map
# if self.zoom_is_out_of_date:
await self.create_zoomed_map(**zoom_data, source_map=map_path, target_map=zoomed_path)
map_path = zoomed_path
# self.zoom_is_out_of_date = False
return discord.File(fp=map_path) # lol file names
async def reset_zoom(self):
if not self.settings_json.exists():
return False
with self.settings_json.open("w+") as zoom_json:
json.dump({"enabled": False}, zoom_json, sort_keys=True, indent=4)
# self.zoom_is_out_of_date = True
return True
async def set_zoom(self, x, y, zoom):
zoom_data = self.default_zoom_json.copy()
zoom_data["enabled"] = True
zoom_data["x"] = x
zoom_data["y"] = y
zoom_data["zoom"] = zoom
# self.zoom_is_out_of_date = True
with self.settings_json.open("w+") as zoom_json:
json.dump(zoom_data, zoom_json, sort_keys=True, indent=4)
async def save_as(self, save_name):
copyfile(self.current_map, self.current_map_folder / f"{save_name}.{self.ext}")
async def load_from(self, save_name):
saved_map = self.current_map_folder / f"{save_name}.{self.ext}"
if not saved_map.exists():
return False
copyfile(saved_map, self.current_map) # Overwrite current map with saved map
return True