Orbit-Wars / game.py
ONYX-APP's picture
Upload game.py
5ec11a4 verified
Raw
History Blame Contribute Delete
25.6 kB
import pygame
import asyncio
import math
import random
# =========================
# CONFIG & CONSTANTS
# =========================
WIDTH, HEIGHT = 1000, 750
SUN_POS = (WIDTH // 2, HEIGHT // 2 + 30)
SUN_RADIUS = 45
FPS = 60
COLOR_BG = (10, 10, 15)
COLOR_TEXT = (255, 255, 255)
COLOR_PROD = (0, 255, 255)
COLOR_NEUTRAL = (80, 80, 80) # --- تعديل: خليت الكواكب المحايدة لونها رمادي باهت لتبين الألوان التانية ---
DIFFICULTY_MAP = {"Easy": 250, "Medium": 180, "Hard": 100}
PRODUCTION_MULTIPLIER = {"Easy": 1.3, "Medium": 1.0, "Hard": 0.7} # تأثير الصعوبة على الإنتاج
# Quick send presets
SEND_PRESETS = {
pygame.K_1: 0.25,
pygame.K_2: 0.50,
pygame.K_3: 0.75,
pygame.K_4: 1.00
}
class Planet:
def __init__(self, pid, owner, dist, angle, vel, color, production):
self.id = pid
self.owner = owner
self.dist = dist
self.angle = angle
self.vel = vel * 0.3
self.base_color = color
self.production = production
self.radius = 15 + (production * 3)
self.ships = 20 if owner != -1 else random.randint(15, 40)
self.x, self.y = 0, 0
self.selected = False
def update(self):
self.x = SUN_POS[0] + math.cos(self.angle) * self.dist
self.y = SUN_POS[1] + math.sin(self.angle) * self.dist
self.angle += self.vel
if self.owner != -1:
self.ships += self.production / 120 # أسرع في الإنتاج
def draw(self, screen, font_main, font_sub):
if self.selected:
pygame.draw.circle(screen, (255, 255, 255), (int(self.x), int(self.y)), self.radius + 4, 2)
pygame.draw.circle(screen, self.base_color, (int(self.x), int(self.y)), self.radius)
pygame.draw.circle(screen, (30, 30, 30), (int(self.x), int(self.y)), self.radius, 2)
txt = font_main.render(str(int(self.ships)), True, COLOR_TEXT)
txt_rect = txt.get_rect(center=(self.x, self.y))
screen.blit(txt, txt_rect)
prod_txt = font_sub.render(f"+{self.production}", True, COLOR_PROD)
screen.blit(prod_txt, (self.x - 8, self.y - self.radius - 15))
class Fleet:
def __init__(self, owner, color, start_pos, target, count):
self.owner = owner
self.color = color
self.x, self.y = start_pos
self.target = target
self.ships = count
self.total_ships = count # العدد الإجمالي الذي سيتم إرساله
# حساب السرعة بناءً على عدد السفن (لوغاريتمي مثل Orbit Wars)
if count >= 1000:
self.speed = 5.8
elif count >= 500:
self.speed = 5.0
elif count >= 100:
self.speed = 3.5
elif count >= 20:
self.speed = 2.5
else:
self.speed = 2.0
self.active = True
self.trail = [] # آثار الحركة
self.distance_traveled = 0
def update(self):
dist_to_sun = math.hypot(SUN_POS[0] - self.x, SUN_POS[1] - self.y)
if dist_to_sun < SUN_RADIUS:
self.active = False
return
dx = self.target.x - self.x
dy = self.target.y - self.y
dist = math.hypot(dx, dy)
if dist < self.target.radius * 1.5:
self.impact()
self.active = False
else:
angle = math.atan2(dy, dx)
self.x += math.cos(angle) * self.speed
self.y += math.sin(angle) * self.speed
self.distance_traveled += self.speed
# حفظ آثار الحركة
if len(self.trail) < 30:
self.trail.append((self.x, self.y))
else:
self.trail.pop(0)
self.trail.append((self.x, self.y))
def impact(self):
if self.target.owner == self.owner:
self.target.ships += self.ships
else:
# قتال: الأكبر ينجي والباقي ينتقل
self.target.ships -= self.ships
if self.target.ships <= 0:
self.target.owner = self.owner
self.target.ships = abs(self.target.ships)
self.target.base_color = self.color
def draw(self, screen):
# رسم الآثار بتدرج
for i, (tx, ty) in enumerate(self.trail):
size = max(1, int(3 - (i / max(len(self.trail), 1)) * 2))
pygame.draw.circle(screen, self.color, (int(tx), int(ty)), size, 1)
# حساب اتجاه السفينة والحجم
angle = math.atan2(self.target.y - self.y, self.target.x - self.x)
ship_size = max(3, min(8, self.ships / 80))
# حساب نقاط المثلث البسيط
# نقطة الرأس (الأمام)
tip_x = self.x + math.cos(angle) * ship_size * 2.5
tip_y = self.y + math.sin(angle) * ship_size * 2.5
# نقطتا القاعدة (الخلف)
base_left_x = self.x + math.cos(angle + 2.5) * ship_size
base_left_y = self.y + math.sin(angle + 2.5) * ship_size
base_right_x = self.x + math.cos(angle - 2.5) * ship_size
base_right_y = self.y + math.sin(angle - 2.5) * ship_size
# رسم المثلث البسيط
points = [
(int(tip_x), int(tip_y)),
(int(base_left_x), int(base_left_y)),
(int(base_right_x), int(base_right_y))
]
pygame.draw.polygon(screen, self.color, points)
pygame.draw.polygon(screen, (255, 255, 255), points, 1)
class OnyxWarsPro:
def __init__(self):
pygame.init()
self.screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("onyx_wars - Galaxy Wars")
self.font_l = pygame.font.SysFont("Arial", 24, bold=True)
self.font_m = pygame.font.SysFont("Arial", 16, bold=True)
self.font_s = pygame.font.SysFont("Arial", 12, bold=True)
self.state = "MENU"
self.num_enemies = 1
self.player_color = (0, 162, 255)
self.difficulty = "Medium"
self.menu_options = ["Enemies", "Color", "Difficulty", "Start"]
self.menu_index = 0
self.colors_list = [(0, 162, 255), (50, 255, 50), (255, 50, 50)]
self.color_idx = 0
self.diffs_list = ["Easy", "Medium", "Hard"]
self.diff_idx = 1
self.planets = []
self.fleets = []
self.dragging = False
self.drag_start_p = None
self.selected_planet = None
self.target_planet = None
self.ai_turn_counter = 0
self.ai_turn_interval = 15 # AI يلعب كل 15 frame
def check_victory(self):
"""Check win/loss conditions"""
enemy_planets = sum(1 for p in self.planets if p.owner > 0)
enemy_ships = sum(p.ships for p in self.planets if p.owner > 0) + sum(f.ships for f in self.fleets if f.owner > 0)
if enemy_planets == 0 and enemy_ships == 0:
return "WIN" # لاعب يفوز
player_planets = sum(1 for p in self.planets if p.owner == 0)
player_ships = sum(p.ships for p in self.planets if p.owner == 0) + sum(f.ships for f in self.fleets if f.owner == 0)
if player_planets == 0 and player_ships == 0:
return "LOSS" # لاعب يخسر
return None
def draw_win_screen(self):
"""عرض شاشة الفوز"""
self.screen.fill(COLOR_BG)
title = self.font_l.render("🎉 YOU WIN! 🎉", True, (0, 255, 100))
self.screen.blit(title, (WIDTH//2 - 150, 250))
restart_txt = self.font_m.render("Press SPACE to return to menu", True, COLOR_TEXT)
self.screen.blit(restart_txt, (WIDTH//2 - 180, 350))
def draw_loss_screen(self):
"""عرض شاشة الخسارة"""
self.screen.fill(COLOR_BG)
title = self.font_l.render("GAME OVER", True, (255, 50, 50))
self.screen.blit(title, (WIDTH//2 - 120, 250))
restart_txt = self.font_m.render("Press SPACE to return to menu", True, COLOR_TEXT)
self.screen.blit(restart_txt, (WIDTH//2 - 180, 350))
def draw_menu(self):
self.screen.fill(COLOR_BG)
title = self.font_l.render("RUI GALAXY WARS", True, (0, 255, 150))
self.screen.blit(title, (WIDTH//2 - 120, 100))
for i, option in enumerate(self.menu_options):
color = (0, 255, 150) if i == self.menu_index else COLOR_TEXT
if option == "Enemies": text = f"Enemies: {self.num_enemies} (Left/Right)"
elif option == "Color": text = f"Color: {self.player_color} (Left/Right)"
elif option == "Difficulty": text = f"Difficulty: {self.difficulty} (Left/Right)"
else: text = "--- PRESS SPACE TO START ---"
surf = self.font_m.render(text, True, color)
self.screen.blit(surf, (WIDTH//2 - 150, 250 + i*50))
def draw_top_bar(self):
pygame.draw.rect(self.screen, (15, 20, 35), (0, 0, WIDTH, 60))
pygame.draw.line(self.screen, (50, 50, 80), (0, 60), (WIDTH, 60), 2)
p_ships = sum(p.ships for p in self.planets if p.owner == 0) + sum(f.ships for f in self.fleets if f.owner == 0)
p_planets = sum(1 for p in self.planets if p.owner == 0)
txt_p = self.font_m.render(f"RUI Company: {int(p_ships)} ships | {p_planets} planets", True, self.player_color)
self.screen.blit(txt_p, (20, 15))
for i in range(self.num_enemies):
e_ships = sum(p.ships for p in self.planets if p.owner == i+1) + sum(f.ships for f in self.fleets if f.owner == i+1)
e_planets = sum(1 for p in self.planets if p.owner == i+1)
e_color = self.planets[1+i].base_color if len(self.planets) > 1+i else (255,0,0)
txt_e = self.font_s.render(f"Enemy {i+1}: {int(e_ships)}sh|{e_planets}pl", True, e_color)
self.screen.blit(txt_e, (WIDTH - 280 - (i*180), 20))
def draw_game_help(self):
"""عرض تعليمات اللعب والمعلومات الحالية"""
# الأساسيات
txt1 = self.font_s.render("1. CLICK your planet → 2. CLICK target → 3. PRESS 1-4 for amount", True, (150, 200, 255))
self.screen.blit(txt1, (20, HEIGHT - 40))
txt_esc = self.font_s.render("Press ESC to deselect", True, (200, 100, 100))
self.screen.blit(txt_esc, (20, HEIGHT - 20))
if self.selected_planet:
txt2 = self.font_s.render(f"SELECTED: Planet #{self.selected_planet.id} ({int(self.selected_planet.ships):.0f} ships, +{self.selected_planet.production}/turn)", True, (100, 255, 100))
self.screen.blit(txt2, (WIDTH - 500, HEIGHT - 40))
def draw_attack_lines(self):
"""رسم خطوط الهجوم من الكوكب المختار - معطل"""
# لا يتم رسم المسارات
pass
def setup_game(self):
self.planets = []
self.fleets = []
self.planets.append(Planet(0, 0, 160, 0, 0.005, self.player_color, 5))
enemy_colors = [(255, 50, 50), (200, 50, 255), (50, 255, 50)]
for i in range(self.num_enemies):
angle = (2 * math.pi / (self.num_enemies + 1)) * (i + 1)
self.planets.append(Planet(i+1, i+1, 280, angle, -0.004, enemy_colors[i], 4))
for i in range(len(self.planets), 12):
d = random.randint(150, 380)
p = random.randint(1, 4)
self.planets.append(Planet(i, -1, d, random.random()*6, random.uniform(0.002, 0.005), COLOR_NEUTRAL, p))
self.ai_turn_interval = max(8, 20 - (5 if self.difficulty == "Hard" else 0)) # AI أسرع في الصعوبة العالية
self.state = "GAME"
def calculate_target_priority(self, from_planet):
"""حساب أولوية الأهداف بناءً على استراتيجية متقدمة"""
targets = [(t, 0) for t in self.planets if t != from_planet]
priorities = []
for target, _ in targets:
dist = math.hypot(target.x - from_planet.x, target.y - from_planet.y)
strength_diff = from_planet.ships - target.ships
priority = 0
if target.owner == 0: # عدو (اللاعب) - أولوية عالية جداً
priority = 100 - (dist / 5)
if strength_diff > 30:
priority += 50
elif target.owner == -1: # محايد - أولوية متوسطة
if target.production > 3:
priority = 70 - (dist / 8) + (target.production * 10)
else:
priority = 40 - (dist / 10)
if strength_diff > target.ships * 0.5:
priority += 30
elif target.owner != from_planet.owner: # عدو آخر
if strength_diff > target.ships * 0.3:
priority = 60 - (dist / 6)
else:
priority = 20 - (dist / 15)
else: # نفس المالك - تعزيز
priority = -100
priorities.append((target, priority))
return sorted(priorities, key=lambda x: x[1], reverse=True)
def enemy_ai_turn(self):
"""AI محسّن يلعب بذكاء"""
for p in self.planets:
if p.owner <= 0:
continue
# تقييم قوة العدو والتحالفات
enemy_strength = sum(x.ships for x in self.planets if x.owner == 0) + \
sum(f.ships for f in self.fleets if f.owner == 0)
own_strength = sum(x.ships for x in self.planets if x.owner == p.owner) + \
sum(f.ships for f in self.fleets if f.owner == p.owner)
# احسب الحد الأدنى للهجوم بناءً على الصعوبة
min_ships = DIFFICULTY_MAP.get(self.difficulty, 180) / 100
# إذا كان لديك سفن كافية
if p.ships > min_ships:
targets = self.calculate_target_priority(p)
if targets and len(targets) > 0:
target, priority = targets[0]
if priority > 0: # هناك هدف يستحق
# تحديد نسبة الإرسال بناءً على الموقف
send_ratio = 0.25
if target.owner == 0: # اللاعب - أولوية عالية
if own_strength > enemy_strength * 1.5:
send_ratio = 0.7
elif own_strength > enemy_strength:
send_ratio = 0.55
else:
send_ratio = 0.35
elif target.owner == -1: # محايد
send_ratio = min(0.5, (p.ships / max(target.ships + 5, 1)) * 0.4)
elif target.owner != p.owner: # عدو آخر
if own_strength > enemy_strength:
send_ratio = 0.45
else:
send_ratio = 0.28
send_count = int(p.ships * send_ratio)
if send_count > 5: # يجب أن يكون هناك حد أدنى
p.ships -= send_count
self.fleets.append(Fleet(p.owner, p.base_color, (p.x, p.y), target, send_count))
async def run(self):
clock = pygame.time.Clock()
while True:
if self.state == "MENU":
self.draw_menu()
for event in pygame.event.get():
if event.type == pygame.QUIT: return
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_UP:
self.menu_index = max(0, self.menu_index - 1)
elif event.key == pygame.K_DOWN:
self.menu_index = min(len(self.menu_options)-1, self.menu_index + 1)
elif event.key == pygame.K_RIGHT:
if self.menu_index == 0: self.num_enemies = min(3, self.num_enemies + 1)
elif self.menu_index == 1:
self.color_idx = (self.color_idx + 1) % len(self.colors_list)
self.player_color = self.colors_list[self.color_idx]
elif self.menu_index == 2:
self.diff_idx = (self.diff_idx + 1) % len(self.diffs_list)
self.difficulty = self.diffs_list[self.diff_idx]
elif event.key == pygame.K_LEFT:
if self.menu_index == 0: self.num_enemies = max(1, self.num_enemies - 1)
elif self.menu_index == 1:
self.color_idx = (self.color_idx - 1) % len(self.colors_list)
self.player_color = self.colors_list[self.color_idx]
elif self.menu_index == 2:
self.diff_idx = (self.diff_idx - 1) % len(self.diffs_list)
self.difficulty = self.diffs_list[self.diff_idx]
elif event.key == pygame.K_SPACE:
self.setup_game()
elif self.state == "GAME":
self.screen.fill(COLOR_BG)
pygame.draw.circle(self.screen, (255, 180, 0), SUN_POS, SUN_RADIUS)
pygame.draw.circle(self.screen, (255, 220, 100), SUN_POS, SUN_RADIUS - 10)
self.draw_top_bar()
for event in pygame.event.get():
if event.type == pygame.QUIT: return
pos = pygame.mouse.get_pos()
if event.type == pygame.MOUSEBUTTONDOWN:
clicked = next((p for p in self.planets if math.hypot(pos[0]-p.x, pos[1]-p.y) < p.radius), None)
if clicked and clicked.owner == 0:
if self.selected_planet == clicked:
# إلغاء التحديد
self.selected_planet = None
else:
# تحديد كوكب جديد
self.selected_planet = clicked
# نظام الإرسال السريع: اختر كوكب -> اختر هدف -> اضغط 1-4
if event.type == pygame.MOUSEBUTTONDOWN and self.selected_planet:
target = next((p for p in self.planets if math.hypot(pos[0]-p.x, pos[1]-p.y) < p.radius), None)
if target and target != self.selected_planet:
# اسأل عن كم سفينة سيتم إرسالها
# سيتم تحديده في الحدث التالي (KEYDOWN)
self.target_planet = target
# اختصارات لوحة المفاتيح للإرسال السريع
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
self.selected_planet = None
self.target_planet = None
elif self.selected_planet and hasattr(self, 'target_planet') and self.target_planet:
if event.key in SEND_PRESETS:
percent = SEND_PRESETS[event.key]
amt = int(self.selected_planet.ships * percent)
if amt > 0:
self.selected_planet.ships -= amt
self.fleets.append(Fleet(0, self.player_color,
(self.selected_planet.x, self.selected_planet.y),
self.target_planet, amt))
self.enemy_ai_turn()
self.selected_planet = None
self.target_planet = None
for p in self.planets:
p.update()
p.draw(self.screen, self.font_m, self.font_s)
for f in self.fleets[:]:
f.update()
f.draw(self.screen)
if not f.active: self.fleets.remove(f)
# رسم خطوط الهجوم عند اختيار كوكب
self.draw_attack_lines()
# رسم الكوكب المختار وتفاصيل الإرسال
if self.selected_planet:
pygame.draw.circle(self.screen, (100, 255, 100), (int(self.selected_planet.x), int(self.selected_planet.y)),
self.selected_planet.radius + 8, 4)
txt = self.font_m.render(f"SELECTED: {int(self.selected_planet.ships)} ships", True, (100, 255, 100))
self.screen.blit(txt, (self.selected_planet.x - 80, self.selected_planet.y - self.selected_planet.radius - 35))
if hasattr(self, 'target_planet') and self.target_planet:
# عرض تفاصيل الإرسال
txt2 = self.font_s.render("PRESS 1, 2, 3, or 4", True, (150, 200, 255))
self.screen.blit(txt2, (self.selected_planet.x - 60, self.selected_planet.y - self.selected_planet.radius - 55))
txt3 = self.font_s.render("(25%, 50%, 75%, 100%)", True, (100, 200, 255))
self.screen.blit(txt3, (self.selected_planet.x - 60, self.selected_planet.y - self.selected_planet.radius - 70))
# عرض الأرقام الفعلية
for key, ratio in SEND_PRESETS.items():
ships_to_send = int(self.selected_planet.ships * ratio)
if key == pygame.K_1:
txt_prev = self.font_s.render(f"1: {ships_to_send} ships", True, (255, 200, 100))
self.screen.blit(txt_prev, (self.target_planet.x - 50, self.target_planet.y - 50))
elif key == pygame.K_2:
txt_prev = self.font_s.render(f"2: {ships_to_send} ships", True, (255, 200, 100))
self.screen.blit(txt_prev, (self.target_planet.x - 50, self.target_planet.y - 30))
elif key == pygame.K_3:
txt_prev = self.font_s.render(f"3: {ships_to_send} ships", True, (255, 200, 100))
self.screen.blit(txt_prev, (self.target_planet.x - 50, self.target_planet.y - 10))
elif key == pygame.K_4:
txt_prev = self.font_s.render(f"4: {ships_to_send} ships", True, (255, 200, 100))
self.screen.blit(txt_prev, (self.target_planet.x - 50, self.target_planet.y + 10))
self.draw_game_help()
# AI يلعب تلقائياً كل فترة
self.ai_turn_counter += 1
if self.ai_turn_counter >= self.ai_turn_interval:
self.enemy_ai_turn()
self.ai_turn_counter = 0
# تحقق من الفوز/الخسارة
result = self.check_victory()
if result:
self.state = result
elif self.state == "WIN":
self.draw_win_screen()
for event in pygame.event.get():
if event.type == pygame.QUIT: return
if event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE:
self.state = "MENU"
self.menu_index = 0
elif self.state == "LOSS":
self.draw_loss_screen()
for event in pygame.event.get():
if event.type == pygame.QUIT: return
if event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE:
self.state = "MENU"
self.menu_index = 0
pygame.display.flip()
await asyncio.sleep(0)
clock.tick(FPS)
if __name__ == "__main__":
asyncio.run(OnyxWarsPro().run())