Spaces:
Paused
Paused
| 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()) |