tanks/2os._tenks.py

912 lines
28 KiB
Python
Raw Normal View History

2026-06-24 21:49:01 +02:00
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()