912 lines
28 KiB
Python
912 lines
28 KiB
Python
from tkinter import *
|
|
from random import randrange as rand
|
|
from tkinter import ttk
|
|
from tkinter import messagebox
|
|
|
|
from PIL import ImageTk, Image
|
|
from noise import pnoise2
|
|
from random import uniform as uni
|
|
from math import radians, cos, sin, atan2, sqrt, pi, degrees
|
|
from tkinter import PhotoImage
|
|
import os
|
|
|
|
|
|
def pobierz_obrazek_jednostki(nazwa):
|
|
plik = f"{nazwa} min.png"
|
|
|
|
if plik not in obrazki_jednostek:
|
|
try:
|
|
obrazki_jednostek[plik] = PhotoImage(file=plik)
|
|
except Exception as e:
|
|
print("Brak obrazka:", plik, e)
|
|
return None
|
|
|
|
return obrazki_jednostek[plik]
|
|
|
|
|
|
def zawsze():
|
|
global jednostki
|
|
for j in jednostki:
|
|
if j["linia"]["nazwa"] is not None:
|
|
canvas.itemconfig(j["linia"]["nazwa"], dashoffset=j["linia"]["prze"])
|
|
j["linia"]["prze"] += 1
|
|
if j["linia"]["prze"] >= j["linia"]["dash"]["kropka"] + j["linia"]["dash"]["przerwa"]:
|
|
j["linia"]["prze"] = 0
|
|
root.after(60, zawsze)
|
|
|
|
|
|
def animuj(krok):
|
|
ANIMACJA_KROKI = 100
|
|
|
|
if krok >= ANIMACJA_KROKI:
|
|
global koniec_planowania
|
|
for j in jednostki:
|
|
j["x"] = j["cel_x"]
|
|
j["y"] = j["cel_y"]
|
|
|
|
koniec_planowania = True
|
|
return
|
|
|
|
for j in jednostki:
|
|
dx = (j["cel_x"] - j["x"]) / (ANIMACJA_KROKI - krok)
|
|
dy = (j["cel_y"] - j["y"]) / (ANIMACJA_KROKI - krok)
|
|
|
|
canvas.move(j["rect"], dx, dy)
|
|
canvas.move(j["text"], dx, dy)
|
|
|
|
j["x"] += dx
|
|
j["y"] += dy
|
|
|
|
if "kat_docelowy" in j:
|
|
roznica = j["kat_docelowy"] - j["kat"]
|
|
|
|
if abs(roznica) > 180:
|
|
if roznica > 0:
|
|
roznica -= 360
|
|
else:
|
|
roznica += 360
|
|
|
|
j["kat"] += roznica * 0.15
|
|
|
|
root.after(15, lambda: animuj(krok + 1))
|
|
|
|
|
|
def zmien_predkosc(*args):
|
|
if not jednostki:
|
|
return
|
|
global BONUS_RUCHU
|
|
global aktualna_strona
|
|
global wybrana_jednostka
|
|
|
|
nowy_bonus = int(
|
|
predkosc_ruchu.get().replace("x", "")
|
|
)
|
|
|
|
BONUS_RUCHU = nowy_bonus
|
|
|
|
for j in jednostki:
|
|
dane = pobierz_dane_pojazdu(j["nazwa"])
|
|
|
|
j["ruch"] = int(
|
|
dane["ruch"]
|
|
* mnoznik_ruchu
|
|
* BONUS_RUCHU
|
|
)
|
|
|
|
j["wykonal_ruch"] = False
|
|
j["cel_x"] = j["x"]
|
|
j["cel_y"] = j["y"]
|
|
|
|
canvas.itemconfig(
|
|
j["rect"],
|
|
outline="black",
|
|
width=1
|
|
)
|
|
|
|
wybrana_jednostka = None
|
|
aktualna_strona = "USA"
|
|
|
|
canvas.delete("plan")
|
|
|
|
if jednostki:
|
|
lbl_aktywny_pojazd.config(
|
|
text="Wybierz jednostkę USA"
|
|
)
|
|
global zasieg_podglad
|
|
|
|
if zasieg_podglad:
|
|
canvas.delete(zasieg_podglad)
|
|
zasieg_podglad = None
|
|
|
|
|
|
def pobierz_dane_pojazdu(nazwa):
|
|
BAZA_POJAZDOW = {p["naz"]: p for p in pojazdy}
|
|
return BAZA_POJAZDOW.get(nazwa)
|
|
|
|
|
|
def strona_pojazdu(nazwa):
|
|
if nazwa in usa:
|
|
return "USA"
|
|
elif nazwa in IIIRzesza:
|
|
return "GER"
|
|
return None
|
|
|
|
|
|
def check_collision(x1, y1, x2, y2):
|
|
for ux1, uy1, ux2, uy2 in placed_units:
|
|
if not (
|
|
x2 + ODSTEP < ux1 or
|
|
x1 - ODSTEP > ux2 or
|
|
y2 + ODSTEP < uy1 or
|
|
y1 - ODSTEP > uy2
|
|
):
|
|
return True
|
|
return False
|
|
|
|
|
|
def update_ghost(event):
|
|
global ghost
|
|
|
|
if not pojazdy_do_ustawienia:
|
|
return
|
|
|
|
nazwa = pojazdy_do_ustawienia[0]
|
|
dane = pobierz_dane_pojazdu(nazwa)
|
|
|
|
size_x = dane["sze"] * SKALA_JEDNOSTKI
|
|
size_y = dane["wys"] * SKALA_JEDNOSTKI
|
|
strona = strona_pojazdu(nazwa)
|
|
|
|
kolor = "lime"
|
|
w = canvas.winfo_width()
|
|
|
|
granica_usa = w * 0.125
|
|
granica_ger = w * 0.875
|
|
|
|
if strona == "USA" and event.x > granica_usa:
|
|
kolor = "red"
|
|
|
|
if strona == "GER" and event.x < granica_ger:
|
|
kolor = "red"
|
|
|
|
if ghost:
|
|
canvas.delete(ghost)
|
|
|
|
ghost = canvas.create_rectangle(
|
|
event.x - size_x // 2,
|
|
event.y - size_y // 2,
|
|
event.x + size_x // 2,
|
|
event.y + size_y // 2,
|
|
outline=kolor,
|
|
fill="",
|
|
width=3
|
|
)
|
|
|
|
|
|
def ustaw_pojazd(event):
|
|
global pojazdy_do_ustawienia, aktualny_plan, kolejka_planowania, mnoznik_ruchu
|
|
|
|
if not pojazdy_do_ustawienia:
|
|
return
|
|
|
|
nazwa = pojazdy_do_ustawienia[0]
|
|
dane = pobierz_dane_pojazdu(nazwa)
|
|
|
|
size_x = dane["sze"] * SKALA_JEDNOSTKI
|
|
size_y = dane["wys"] * SKALA_JEDNOSTKI
|
|
|
|
strona = strona_pojazdu(nazwa)
|
|
|
|
w = canvas.winfo_width()
|
|
|
|
granica_usa = w * 0.125
|
|
granica_ger = w * 0.875
|
|
|
|
if strona == "USA" and event.x > granica_usa:
|
|
messagebox.showwarning(
|
|
"RTS",
|
|
"USA można ustawiać tylko w lewej strefie!"
|
|
)
|
|
return
|
|
|
|
if strona == "GER" and event.x < granica_ger:
|
|
messagebox.showwarning(
|
|
"RTS",
|
|
"III Rzesza może być ustawiana tylko w prawej strefie!"
|
|
)
|
|
return
|
|
|
|
x1 = event.x - size_x // 2
|
|
y1 = event.y - size_y // 2
|
|
x2 = event.x + size_x // 2
|
|
y2 = event.y + size_y // 2
|
|
|
|
if check_collision(x1, y1, x2, y2):
|
|
messagebox.showwarning("RTS", "Kolizja!")
|
|
return
|
|
|
|
placed_units.append((x1, y1, x2, y2))
|
|
|
|
nazwa_pliku = f"{nazwa} min.png"
|
|
|
|
img_org = Image.open(nazwa_pliku)
|
|
|
|
img_tk = ImageTk.PhotoImage(img_org)
|
|
|
|
sprite = canvas.create_image(
|
|
300,
|
|
200,
|
|
image=img_tk
|
|
)
|
|
|
|
jednostki.append({
|
|
"nazwa": nazwa,
|
|
"strona": strona,
|
|
|
|
"x": event.x,
|
|
"y": event.y,
|
|
|
|
"cel_x": event.x,
|
|
"cel_y": event.y,
|
|
|
|
"sprite": sprite,
|
|
|
|
"img_org": img_org,
|
|
"img_tk": img_tk,
|
|
|
|
"kat": 0,
|
|
|
|
"hp": 100,
|
|
|
|
"wykonal_ruch": False,
|
|
|
|
"ruch": int(
|
|
dane["ruch"]
|
|
* mnoznik_ruchu
|
|
* BONUS_RUCHU
|
|
),
|
|
"linia": {"nazwa": None, "dash": {"kropka": None, "przerwa": None}, "prze": 0}
|
|
})
|
|
pojazdy_do_ustawienia.pop(0)
|
|
|
|
if pojazdy_do_ustawienia:
|
|
lbl_aktywny_pojazd.config(text=f"Ustaw: {pojazdy_do_ustawienia[0]}")
|
|
else:
|
|
messagebox.showinfo(
|
|
"RTS",
|
|
"Wszystkie jednostki rozmieszczone. Rozpoczyna się planowanie."
|
|
)
|
|
|
|
aktualny_plan = 0
|
|
kolejka_planowania.clear()
|
|
|
|
canvas.bind("<Button-1>", planowanie)
|
|
|
|
lbl_aktywny_pojazd.config(
|
|
text="Ustaw jednoske USA"
|
|
)
|
|
|
|
|
|
def generuj_mape_noise():
|
|
bazowe_x = canvas.winfo_toplevel().winfo_screenwidth()
|
|
bazowe_y = canvas.winfo_toplevel().winfo_screenheight()
|
|
x_w = bazowe_x
|
|
y_w = bazowe_y
|
|
|
|
wybor = jakosc_mapy.get()
|
|
if "Bardzo wysoka" in wybor:
|
|
pixel = 1
|
|
skala = 0.0133
|
|
elif "Wysoka" in wybor:
|
|
pixel = 2
|
|
skala = 0.0266
|
|
elif "Preferowana" in wybor:
|
|
pixel = 3
|
|
skala = 0.04
|
|
elif "Niska" in wybor:
|
|
pixel = 4
|
|
skala = 0.0533
|
|
else:
|
|
pixel = 5
|
|
skala = 0.0666
|
|
|
|
rozmiar = rozmiar_mapy.get()
|
|
|
|
if rozmiar == "Mała":
|
|
pixel *= 2
|
|
skala /= 2
|
|
|
|
elif rozmiar == "Średnia":
|
|
pass
|
|
|
|
elif rozmiar == "Duża":
|
|
pixel = max(1, round(pixel * 0.75))
|
|
skala /= 0.75
|
|
|
|
else: # Ogromna
|
|
pixel = max(1, round(pixel * 0.5))
|
|
skala *= 2
|
|
max_y = y_w // pixel
|
|
|
|
seed_x = uni(0, 1000)
|
|
seed_y = uni(0, 1000)
|
|
# print(f"Seed: {seed_x, seed_y}")
|
|
|
|
for x in range(x_w // pixel):
|
|
for y in range(max_y):
|
|
szum = pnoise2(seed_x + x * skala, seed_y + y * skala, octaves=3)
|
|
val = (szum + 1) / 2
|
|
v = val
|
|
g_start = 122
|
|
g_end = 160
|
|
|
|
if v < 0.28:
|
|
r, g, b = "00", "00", "FF"
|
|
elif v <= 0.30:
|
|
procent = (v - 0.28) / 0.02
|
|
wygladzenie = (1.0 - cos(procent * pi)) / 2.0
|
|
|
|
r_val = int(wygladzenie * 255)
|
|
g_val = int(wygladzenie * 255)
|
|
b_val = int((1.0 - wygladzenie) * 255)
|
|
|
|
r = f"{max(0, min(255, r_val)):02X}"
|
|
g = f"{max(0, min(255, g_val)):02X}"
|
|
b = f"{max(0, min(255, b_val)):02X}"
|
|
elif v <= 0.33:
|
|
procent = (v - 0.30) / 0.03
|
|
wygladzenie = (1.0 - cos(procent * pi)) / 2.0
|
|
|
|
r_val = int((1.0 - wygladzenie) * 255)
|
|
g_val = int(255 - wygladzenie * (255 - g_start))
|
|
|
|
r = f"{max(0, min(255, r_val)):02X}"
|
|
g = f"{max(0, min(255, g_val)):02X}"
|
|
b = "00"
|
|
else:
|
|
r = "00"
|
|
b = "00"
|
|
|
|
procent_g = (v - 0.33) / (1.0 - 0.33)
|
|
wartosc_g = int(g_start + procent_g * (g_end - g_start))
|
|
g = f"{max(g_start, min(g_end, wartosc_g)):02X}"
|
|
|
|
kolor = f"#{r}{g}{b}"
|
|
|
|
canvas.create_rectangle(x * pixel, y * pixel, (x + 1) * pixel, (y + 1) * pixel, fill=kolor, outline="")
|
|
|
|
|
|
def rysuj_pojazdy():
|
|
pixel = 1
|
|
x_w = canvas.winfo_toplevel().winfo_screenwidth()
|
|
y_w = canvas.winfo_toplevel().winfo_screenheight()
|
|
if len(usa) > 0:
|
|
dzielnik_usa = (len(usa) - 1) if len(usa) > 1 else 1
|
|
|
|
u = int(y_w / (dzielnik_usa + 1))
|
|
|
|
for c in kolejnosc_pojazdow:
|
|
if c in usa:
|
|
canvas.create_rectangle(
|
|
15,
|
|
u - 7,
|
|
30,
|
|
u + 8,
|
|
fill="black",
|
|
)
|
|
if len(usa) > 1:
|
|
u += int(y_w / (len(usa) + 1))
|
|
|
|
if len(IIIRzesza) > 0:
|
|
dzielnik_rzesza = (len(IIIRzesza) - 1) if len(IIIRzesza) > 1 else 1
|
|
I = int(y_w / (dzielnik_rzesza + 1))
|
|
|
|
for c in kolejnosc_pojazdow:
|
|
if c in IIIRzesza:
|
|
canvas.create_rectangle(
|
|
x_w - 30,
|
|
I - 7,
|
|
x_w - 15,
|
|
I + 8,
|
|
fill="black",
|
|
outline="",
|
|
)
|
|
|
|
if len(IIIRzesza) > 1:
|
|
I += int(y_w / (len(IIIRzesza) + 1))
|
|
|
|
|
|
def start():
|
|
global SKALA_JEDNOSTKI, mnoznik_ruchu, BONUS_RUCHU
|
|
canvas.master.update_idletasks()
|
|
canvas.delete("all")
|
|
if rozmiar_mapy.get() == "Mała":
|
|
SKALA_JEDNOSTKI = 6
|
|
mnoznik_ruchu = 1.3
|
|
|
|
elif rozmiar_mapy.get() == "Średnia":
|
|
SKALA_JEDNOSTKI = 5
|
|
mnoznik_ruchu = 1.0
|
|
|
|
elif rozmiar_mapy.get() == "Duża":
|
|
SKALA_JEDNOSTKI = 4
|
|
mnoznik_ruchu = 0.7
|
|
|
|
else:
|
|
SKALA_JEDNOSTKI = 3
|
|
mnoznik_ruchu = 0.3
|
|
|
|
BONUS_RUCHU = int(
|
|
predkosc_ruchu.get().replace("x", "")
|
|
)
|
|
for j in jednostki:
|
|
j["ruch"] = int(j["ruch"] * mnoznik_ruchu)
|
|
|
|
generuj_mape_noise()
|
|
|
|
if pojazdy_do_ustawienia:
|
|
lbl_aktywny_pojazd.config(text=f"Ustaw: {pojazdy_do_ustawienia[0]}")
|
|
canvas.bind("<Button-1>", ustaw_pojazd)
|
|
zawsze()
|
|
|
|
|
|
# --- INICJALIZACJA UTWORZENIA OKNA I BAZY DANYCH ---
|
|
|
|
root = Tk()
|
|
root.geometry("1000x700")
|
|
root.attributes("-fullscreen", True)
|
|
|
|
root.update()
|
|
root.update_idletasks()
|
|
|
|
kwadraty_lewe = ["LVT", "M3 St.", "M3 GMC", "M3 Lee", "M4A3", "M15 CGMC", "M22"]
|
|
kwadraty_prawa = ["sd.KFz.222", "sd.KFz.251-9", "Pz.IIIF", "Pz.IIIC", "A7V", "Stug IIIb", "Beutepanzer IV"]
|
|
|
|
zmienne_lewa = []
|
|
zmienne_prawa = []
|
|
|
|
baza_podgladu = {
|
|
"M3 St.": {
|
|
"foto": "M3.png",
|
|
"lista": "Nr 1: M3 Stuart\nZasięg: 500m | Damage: 35 | Kierunek: Obrotowy | Ilość: 1\nHP: 200\nPrędkość: 58 km/h\nOpis: Amerykański lekki czołg, niezwykle szybki i zwrotny na polu bitwy.\nCiekawostka: Brytyjskie załogi nazywały go czule 'Honey' ze względu na płynną jazdę."
|
|
},
|
|
"M22": {
|
|
"foto": "M22.png",
|
|
"lista": "Nr 2: M22 Locust\nZasięg: 450m | Damage: 30 | Kierunek: Obrotowy | Ilość: 1\nHP: 160\nPrędkość: 64 km/h\nOpis: Ultra lekki czołg zaprojektowany specjalnie z myślą o transporcie drogą powietrzną przez szybowce.\nCiekawostka: Aby zmieścił się pod szybowcem Hamilcar, trzeba było demontować mu wieżę na czas lotu."
|
|
},
|
|
"sd.KFz.222": {
|
|
"foto": "sd.KFz.222.png",
|
|
"lista": "Nr 3: sd.KFz.222\nZasięg: 500m | Damage: 25 | Kierunek: Obrotowy | Ilość: 1\nHP: 100\nPrędkość: 80 km/h\nOpis: Lekki czterokołowy pojazd opancerzony, wykorzystywany przez Wehrmacht do szybkiego zwiadu.\nCiekawostka: Posiadał charakterystyczną drucianą siatkę nad wieżą chroniącą przed granatami ręcznymi."
|
|
},
|
|
"M3 GMC": {
|
|
"foto": "M3 GMC.png",
|
|
"lista": "Nr 4: M3 GMC\nZasięg: 700m | Damage: 75 | Kierunek: Przód | Ilość: 1\nHP: 120\nPrędkość: 70 km/h\nOpis: Samobieżne działo przeciwpancerne zbudowane na bazie podwozia typu Halftrack.\nCiekawostka: Był kluczową bronią USA w walkach z czołgami Rommla w Afryce Północnej."
|
|
},
|
|
"M15 CGMC": {
|
|
"foto": "M15 CGMC.png",
|
|
"lista": "Nr 5: M15 CGMC\nZasięg: 800m | Damage: 30 | Kierunek: Obrotowy | Ilość: 3\nHP: 140\nPrędkość: 65 km/h\nOpis: Samobieżne działo przeciwlotnicze wyposażone w automatyczną armatę i dwa karabiny maszynowe.\nCiekawostka: Jego siła ognia była tak duża, że często używano go do niszczenia piechoty wroga."
|
|
},
|
|
"sd.KFz.251-9": {
|
|
"foto": "sd.KFz.251-9.png",
|
|
"lista": "Nr 6: sd.KFz.251-9\nZasięg: 550m | Damage: 50 | Kierunek: Przód (Wąski) | Ilość: 1\nHP: 160\nPrędkość: 50 km/h\nOpis: Półgąsienicowy transporter opancerzony wyposażony w krótkolufowe działo 7,5 cm KwK 37 L/24.\nCiekawostka: Ze względu na charakterystyczny kształt krótkiej, grubej lufy, niemieccy żołnierze nazywali ten pojazd 'Stummel' (Kikut)."
|
|
},
|
|
"Pz.IIIF": {
|
|
"foto": "Pz.IIIF.png",
|
|
"lista": "Nr 7: Pz.IIIF\nZasięg: 600m | Damage: 45 | Kierunek: Obrotowy | Ilość: 1\nHP: 320\nPrędkość: 35 km/h\nOpis: Niemiecki czołg średni, wersja Ausf. F otrzymała ulepszone chłodzenie i armatę 50mm KwK 38.\nCiekawostka: Był kręgosłupem dywizji pancernych podczas początkowej fazy ataku na Związek Radziecki."
|
|
},
|
|
"Pz.IIIC": {
|
|
"foto": "Pz.IIIC.png",
|
|
"lista": "Nr 8: Pz.IIIC\nZasięg: 450m | Damage: 20 | Kierunek: Obrotowy | Ilość: 1\nHP: 250\nPrędkość: 40 km/h\nOpis: Wczesna, rzadka wersja Panzer III o skomplikowanym zawieszeniu złożonym z 8 małych kół jezdnych.\nCiekawostka: Wyprodukowano zaledwie kilkadziesiąt sztuk, zanim system zawieszenia zmieniono na drążki skrętne."
|
|
},
|
|
"M3 Lee": {
|
|
"foto": "M3 Lee.png",
|
|
"lista": "Nr 9: M3 Lee\nZasięg: 600m | Damage: 55 | Kierunek: Boczny + Obrotowy | Ilość: 2\nHP: 300\nPrędkość: 38 km/h\nOpis: Czołg średni o nietypowej konstrukcji z głównym działem zamontowanym w kadłubie.\nCiekawostka: Posiadał tak wysoką sylwetkę, że załogi nazywały go 'katedrą na gąsienicach'."
|
|
},
|
|
"LVT": {
|
|
"foto": "LVT.png",
|
|
"lista": "Nr 10: LVT\nZasięg: 400m | Damage: 40 | Kierunek: Przód | Ilość: 1\nHP: 150\nPrędkość: 40 km/h\nOpis: Amfibijny pojazd gąsienicowy używany do operacji desantowych na Pacyfiku.\nCiekawostka: Początkowo został zaprojektowany jako cywilny pojazd ratunkowy na Florydzie."
|
|
},
|
|
"M4A3": {
|
|
"foto": "M4A3.png",
|
|
"lista": "Nr 11: M4A3 Sherman\nZasięg: 650m | Damage: 60 | Kierunek: Obrotowy | Ilość: 1\nHP: 400\nPrędkość: 45 km/h\nOpis: Kultowa wersja amerykańskiego czołgu średniego wyposażona w ulepszony silnik Ford GAA.\nCiekawostka: Wersje te stały się bazą dla słynnych czołgów 'Easy Eight' z nowym zawieszeniem HVSS."
|
|
},
|
|
"Stug IIIb": {
|
|
"foto": "Stug IIIb.png",
|
|
"lista": "Nr 12: Stug IIIb\nZasięg: 580m | Damage: 65 | Kierunek: Przód (Wąski) | Ilość: 1\nHP: 350\nPrędkość: 40 km/h\nOpis: Działo szturmowe pozbawione obrotowej wieży, zaprojektowane do bezpośredniego wspierania piechoty.\nCiekawostka: Z powodu braku wieży był tańszy w produkcji niż czołgi, stając się najskuteczniejszą bronią pancerną Niemiec."
|
|
},
|
|
"Beutepanzer IV": {
|
|
"foto": "Beutepanzer IV.png",
|
|
"lista": "Nr 13: Beutepanzer IV\nZasięg: 450m | Damage: 60 | Kierunek: Boki i Przód | Ilość: 2\nHP: 450\nPrędkość: 6 km/h\nOpis: Brytyjski czołg ciężki Mark IV zdobyty podczas I wojny światowej, przebudowany i wcielony do armii niemieckiej.\nCiekawostka: Niemcy zamontowali w nim własne działa 5,7 cm oraz zmienili układ chłodzenia, tworząc z niego ruchomą fortecę."
|
|
},
|
|
"A7V": {
|
|
"foto": "A7V.png",
|
|
"lista": "Nr 14: A7V\nZasięg: 550m | Damage: 70 | Kierunek: Przód i Boki | Ilość: 6\nHP: 500\nPrędkość: 15 km/h\nOpis: Konstrukcja wzorowana na jedynym niemieckim czołgu z okresu I Wojny Światowej (A7V).\nCiekawostka: Do obsługi tego giganta w wersji bojowej wymagana była monstrualna załoga licząca aż 18 osób."
|
|
}
|
|
}
|
|
kolejnosc_pojazdow = [
|
|
"M3 St.", "M22", "sd.KFz.222", "M3 GMC", "M15 CGMC", "sd.KFz.251-9",
|
|
"Pz.IIIF", "Pz.IIIC", "M3 Lee", "LVT", "M4A3", "Stug IIIb",
|
|
"Beutepanzer IV", "A7V"
|
|
]
|
|
pojazdy = [
|
|
# ==================== USA (Po kolei numerycznie) ====================
|
|
{"naz": "M3 St.", "x": 0, "y": 0, "wys": 2, "sze": 2, "ruch": 120},
|
|
{"naz": "M22", "x": 0, "y": 0, "wys": 1, "sze": 2, "ruch": 140},
|
|
{"naz": "M3 GMC", "x": 0, "y": 0, "wys": 2, "sze": 3, "ruch": 110},
|
|
{"naz": "M15 CGMC", "x": 0, "y": 0, "wys": 2, "sze": 3, "ruch": 100},
|
|
{"naz": "M3 Lee", "x": 0, "y": 0, "wys": 2, "sze": 3, "ruch": 80},
|
|
{"naz": "LVT", "x": 0, "y": 0, "wys": 3, "sze": 3, "ruch": 70},
|
|
{"naz": "M4A3", "x": 0, "y": 0, "wys": 2, "sze": 3, "ruch": 90},
|
|
|
|
{"naz": "sd.KFz.222", "x": 0, "y": 0, "wys": 1, "sze": 2, "ruch": 130},
|
|
{"naz": "sd.KFz.251-9", "x": 0, "y": 0, "wys": 2, "sze": 3, "ruch": 100},
|
|
{"naz": "Pz.IIIF", "x": 0, "y": 0, "wys": 2, "sze": 2, "ruch": 95},
|
|
{"naz": "Pz.IIIC", "x": 0, "y": 0, "wys": 2, "sze": 2, "ruch": 105},
|
|
{"naz": "Stug IIIb", "x": 0, "y": 0, "wys": 2, "sze": 4, "ruch": 70},
|
|
{"naz": "Beutepanzer IV", "x": 0, "y": 0, "wys": 3, "sze": 4, "ruch": 40},
|
|
{"naz": "A7V", "x": 0, "y": 0, "wys": 4, "sze": 6, "ruch": 30},
|
|
]
|
|
zaladowane_obrazki = {}
|
|
obrazki_jednostek = {}
|
|
zasieg_podglad = None
|
|
|
|
|
|
# --- INTERFEJS I LOGIKA WYBORU ---
|
|
|
|
def sprawdz_limit(strona, zmienna_kliknieta):
|
|
lista_zmiennych = [para[0] for para in (zmienne_lewa if strona == "USA" else zmienne_prawa)]
|
|
zaznaczone_count = sum(z.get() for z in lista_zmiennych)
|
|
if zaznaczone_count > 4:
|
|
zmienna_kliknieta.set(False)
|
|
messagebox.showwarning("Limit", f"Możesz wybrać maksymalnie 4 elementy w {strona}")
|
|
|
|
|
|
def pokaz_podglad(event, nazwa_opcji):
|
|
dane = baza_podgladu.get(nazwa_opcji, {"lista": "Brak opisu", "foto": ""})
|
|
|
|
lbl_tekstowy.config(text=dane["lista"])
|
|
lbl_tekstowy.place(relx=0.5, rely=0.35, anchor="center")
|
|
# lbl_graficzny.place(x=500, y=300)
|
|
lbl_graficzny.config(bd=2, relief="solid")
|
|
try:
|
|
nazwa_pliku = f"{nazwa_opcji}.png"
|
|
|
|
if nazwa_pliku not in zaladowane_obrazki:
|
|
zaladowane_obrazki[nazwa_pliku] = PhotoImage(file=nazwa_pliku)
|
|
|
|
img = zaladowane_obrazki[nazwa_pliku]
|
|
|
|
lbl_graficzny.config(image=img)
|
|
lbl_graficzny.image = img
|
|
|
|
|
|
except Exception as e:
|
|
print(e)
|
|
lbl_graficzny.config(image="", text="[ Podgląd Obrazka ]", bg="lightgray")
|
|
# root.update_idletasks()
|
|
# print(lbl_graficzny.image,dane["foto"],lbl_graficzny.winfo_ismapped())
|
|
lbl_graficzny.place(relx=0.5, rely=0.60, anchor="center")
|
|
|
|
|
|
def ukryj_podglad(event):
|
|
lbl_tekstowy.place_forget()
|
|
lbl_graficzny.place_forget()
|
|
|
|
|
|
aktualny_plan = 0
|
|
kolejka_planowania = []
|
|
|
|
wybrana_jednostka = None
|
|
aktualna_strona = "USA"
|
|
|
|
|
|
def planowanie(event):
|
|
global wybrana_jednostka, aktualna_strona, koniec_planowania, zasieg_podglad
|
|
if koniec_planowania:
|
|
|
|
klikniete = canvas.find_overlapping(
|
|
event.x,
|
|
event.y,
|
|
event.x,
|
|
event.y
|
|
)
|
|
|
|
if wybrana_jednostka is None:
|
|
|
|
for j in jednostki:
|
|
|
|
if j["rect"] in klikniete or j["text"] in klikniete:
|
|
|
|
if j["strona"] != aktualna_strona:
|
|
return
|
|
|
|
if j["wykonal_ruch"]:
|
|
return
|
|
|
|
wybrana_jednostka = j
|
|
|
|
canvas.itemconfig(
|
|
j["rect"],
|
|
outline="yellow",
|
|
width=3
|
|
)
|
|
global zasieg_podglad
|
|
|
|
if zasieg_podglad:
|
|
canvas.delete(zasieg_podglad)
|
|
|
|
r = j["ruch"]
|
|
|
|
zasieg_podglad = canvas.create_oval(
|
|
j["x"] - r,
|
|
j["y"] - r,
|
|
j["x"] + r,
|
|
j["y"] + r,
|
|
fill="chartreuse3",
|
|
stipple="gray50",
|
|
activestipple="gray12",
|
|
outline="green",
|
|
width=2
|
|
)
|
|
lbl_aktywny_pojazd.config(
|
|
text=f"Wybierz cel dla {j['nazwa']}"
|
|
)
|
|
return
|
|
|
|
else:
|
|
dx = event.x - wybrana_jednostka["x"]
|
|
dy = event.y - wybrana_jednostka["y"]
|
|
wybrana_jednostka["kat_docelowy"] = degrees(
|
|
atan2(dy, dx)
|
|
)
|
|
odleglosc = (dx * dx + dy * dy) ** 0.5
|
|
|
|
if odleglosc > wybrana_jednostka["ruch"]:
|
|
|
|
skala = wybrana_jednostka["ruch"] / odleglosc
|
|
|
|
event_x = int(wybrana_jednostka["x"] + dx * skala)
|
|
event_y = int(wybrana_jednostka["y"] + dy * skala)
|
|
|
|
else:
|
|
|
|
event_x = event.x
|
|
event_y = event.y
|
|
|
|
wybrana_jednostka["cel_x"] = event_x
|
|
wybrana_jednostka["cel_y"] = event_y
|
|
wybrana_jednostka["wykonal_ruch"] = True
|
|
|
|
canvas.delete("plan")
|
|
|
|
for j in jednostki:
|
|
if j["wykonal_ruch"]:
|
|
if j["linia"]["nazwa"] is None:
|
|
j["linia"]["dash"]["kropka"] = rand(2, 10)
|
|
j["linia"]["dash"]["przerwa"] = rand(3, 6)
|
|
j["linia"]["nazwa"] = canvas.create_line(
|
|
j["cel_x"],
|
|
j["cel_y"],
|
|
j["x"],
|
|
j["y"],
|
|
fill="yellow",
|
|
dash=(j["linia"]["dash"]["kropka"], j["linia"]["dash"]["przerwa"]),
|
|
dashoffset=0,
|
|
capstyle="round",
|
|
tags="plan")
|
|
|
|
canvas.itemconfig(
|
|
wybrana_jednostka["rect"],
|
|
outline="black",
|
|
width=1
|
|
)
|
|
|
|
wybrana_jednostka = None
|
|
if zasieg_podglad:
|
|
canvas.delete(zasieg_podglad)
|
|
zasieg_podglad = None
|
|
aktualna_strona = (
|
|
"GER"
|
|
if aktualna_strona == "USA"
|
|
else "USA"
|
|
)
|
|
|
|
lbl_aktywny_pojazd.config(
|
|
text=f"Wybierz jednostkę {aktualna_strona}"
|
|
)
|
|
|
|
if all(j["wykonal_ruch"] for j in jednostki):
|
|
|
|
canvas.delete("plan")
|
|
koniec_planowania = False
|
|
animuj(0)
|
|
|
|
for j in jednostki:
|
|
j["wykonal_ruch"] = False
|
|
|
|
aktualna_strona = "USA"
|
|
|
|
lbl_aktywny_pojazd.config(
|
|
text="Wybierz jednostkę USA"
|
|
)
|
|
|
|
|
|
kontener = Frame(root)
|
|
kontener.pack(pady=20, expand=True, fill="both")
|
|
lbl_tekstowy = Label(root, text="", font=("Arial", 11), bg="#f0f0f0", bd=2, relief="groove", padx=10, pady=10)
|
|
lbl_graficzny = Label(root, text="")
|
|
koniec_planowania = True
|
|
|
|
kolumna_lewa = Frame(kontener)
|
|
kolumna_lewa.pack(side="left", expand=True, padx=20)
|
|
Label(kolumna_lewa, text="USA", font=("Arial", 12, "bold")).pack(pady=10)
|
|
|
|
for txt_kwadrat in kwadraty_lewe:
|
|
wiersz = Frame(kolumna_lewa)
|
|
wiersz.pack(pady=4, anchor="w")
|
|
|
|
stan = BooleanVar()
|
|
zmienne_lewa.append((stan, txt_kwadrat))
|
|
|
|
chk = Checkbutton(
|
|
wiersz,
|
|
text=txt_kwadrat,
|
|
variable=stan,
|
|
indicatoron=False,
|
|
width=18,
|
|
selectcolor="lightblue",
|
|
command=lambda s=stan: sprawdz_limit("USA", s)
|
|
)
|
|
chk.pack(side="left")
|
|
chk.bind("<Enter>", lambda event, nazwa=txt_kwadrat: pokaz_podglad(event, nazwa))
|
|
chk.bind("<Leave>", ukryj_podglad)
|
|
|
|
kolumna_prawa = Frame(kontener)
|
|
kolumna_prawa.pack(side="right", expand=True, padx=20)
|
|
Label(kolumna_prawa, text="III Rzesza", font=("Arial", 12, "bold")).pack(pady=10)
|
|
|
|
for txt_kwadrat in kwadraty_prawa:
|
|
wiersz = Frame(kolumna_prawa)
|
|
wiersz.pack(pady=4, anchor="w")
|
|
|
|
stan = BooleanVar()
|
|
zmienne_prawa.append((stan, txt_kwadrat))
|
|
|
|
chk = Checkbutton(
|
|
wiersz,
|
|
text=txt_kwadrat,
|
|
variable=stan,
|
|
indicatoron=False,
|
|
width=18,
|
|
selectcolor="lightgreen",
|
|
command=lambda s=stan: sprawdz_limit("GER", s)
|
|
)
|
|
chk.pack(side="left")
|
|
chk.bind("<Enter>", lambda event, nazwa=txt_kwadrat: pokaz_podglad(event, nazwa))
|
|
chk.bind("<Leave>", ukryj_podglad)
|
|
|
|
canvas = Canvas(root, bg="white", highlightthickness=0)
|
|
usa = []
|
|
IIIRzesza = []
|
|
|
|
|
|
def zatwierdz():
|
|
global usa, IIIRzesza, pojazdy_do_ustawienia
|
|
if tryb_gry.get() == "PvAI":
|
|
messagebox.showinfo(
|
|
"PvAI",
|
|
"AI Wkrótce dostępne!"
|
|
)
|
|
return
|
|
usa = [nazwa for stan, nazwa in zmienne_lewa if stan.get()]
|
|
IIIRzesza = [nazwa for stan, nazwa in zmienne_prawa if stan.get()]
|
|
pojazdy_do_ustawienia = usa + IIIRzesza
|
|
if not usa or not IIIRzesza:
|
|
messagebox.showwarning("Brak wyboru", "Musisz wybrać przynajmniej jeden pojazd w USA i w III Rzeszy, aby rozpocząć!")
|
|
return
|
|
|
|
decyzja = messagebox.askokcancel("Potwierdzenie", "Czy chcesz wygenerować mapę z wybranymi jednostkami?")
|
|
if decyzja:
|
|
do_ukrycia = [kontener, btn_koniec, lbl_tekstowy, lbl_graficzny, tryb, pvp, pvai, jakosc, menu_jakosci, rozmiar, menu_rozmiaru]
|
|
for widget in do_ukrycia:
|
|
widget.pack_forget()
|
|
|
|
lbl_tekstowy.place_forget()
|
|
lbl_graficzny.place_forget()
|
|
canvas.pack(fill="both", expand=True)
|
|
lbl_aktywny_pojazd.pack(pady=5)
|
|
lbl_aktywny_pojazd.config(text=f"Ustaw: {pojazdy_do_ustawienia[0]}")
|
|
root.update()
|
|
start()
|
|
|
|
|
|
jakosc = Label(root, text="Jakość mapy", font=("Arial", 11, "bold"))
|
|
rozmiar = Label(root, text="Rozmiar mapy", font=("Arial", 11, "bold"))
|
|
|
|
jakosc_mapy = StringVar(value="Preferowana")
|
|
rozmiar_mapy = StringVar(value="Średnia")
|
|
|
|
opcje_jakosci = [
|
|
"Bardzo wysoka",
|
|
"Wysoka",
|
|
"Preferowana",
|
|
"Niska",
|
|
"Bardzo niska"
|
|
]
|
|
opcje_rozmiaru = [
|
|
"Mała",
|
|
"Średnia",
|
|
"Duża",
|
|
"Ogromna"
|
|
]
|
|
|
|
menu_jakosci = OptionMenu(root, jakosc_mapy, *opcje_jakosci)
|
|
menu_rozmiaru = OptionMenu(root, rozmiar_mapy, *opcje_rozmiaru)
|
|
|
|
tryb_gry = StringVar(value="PvP")
|
|
tryb = Label(root, text="Tryb gry", font=("Arial", 11, "bold"))
|
|
pvp = Radiobutton(
|
|
root,
|
|
text="PvP",
|
|
variable=tryb_gry,
|
|
value="PvP"
|
|
)
|
|
pvai = Radiobutton(
|
|
root,
|
|
text="PvAI",
|
|
variable=tryb_gry,
|
|
value="PvAI"
|
|
)
|
|
jakosc.pack()
|
|
menu_jakosci.pack()
|
|
|
|
rozmiar.pack()
|
|
menu_rozmiaru.pack()
|
|
|
|
mnoznik_ruchu = 0
|
|
|
|
tryb.pack()
|
|
pvp.pack()
|
|
pvai.pack()
|
|
|
|
btn_koniec = Button(root, text="Zatwierdź wybór", command=zatwierdz, bg="gold", font=("Arial", 10, "bold"))
|
|
btn_koniec.pack(pady=20)
|
|
|
|
aktualny_pojazd = None
|
|
pojazdy_do_ustawienia = []
|
|
|
|
placed_units = []
|
|
ghost = None
|
|
jednostki = []
|
|
kolej_tury = []
|
|
|
|
ODSTEP = 15
|
|
|
|
SKALA_JEDNOSTKI = 10
|
|
lbl_aktywny_pojazd = Label(root, text="Kliknij, aby rozpocząć ustawianie", font=("Arial", 12, "bold"))
|
|
aktualny_index = 0
|
|
|
|
BONUS_RUCHU = 1
|
|
opcje_predkosci = [
|
|
"x1",
|
|
"x2",
|
|
"x3",
|
|
"x4",
|
|
"x5"
|
|
]
|
|
predkosc_ruchu = StringVar(value="x1")
|
|
predkosc_ruchu.trace_add("write", zmien_predkosc)
|
|
menu_predkosci = OptionMenu(
|
|
root,
|
|
predkosc_ruchu,
|
|
*opcje_predkosci
|
|
)
|
|
|
|
Label(root, text="Zasięg ruchu").pack()
|
|
menu_predkosci.pack()
|
|
|
|
canvas.bind("<Button-1>", ustaw_pojazd)
|
|
canvas.bind("<Motion>", update_ghost)
|
|
root.bind("<Escape>", lambda event: root.destroy())
|
|
root.mainloop()
|