import pygame
import random
import sys
import json
import os
from datetime import datetime

pygame.init()
pygame.mixer.init()

# ==================== 全局配置 横竖屏双适配 ====================
W_WIN, H_WIN = 900, 700
W_PHONE, H_PHONE = 450, 800
IS_PHONE = False
SCREEN_W, SCREEN_H = W_WIN, H_WIN
screen = pygame.display.set_mode((SCREEN_W, SCREEN_H))
pygame.display.set_caption("超级双人战机大战｜全功能终极版")
clock = pygame.time.Clock()
FPS = 60

# 颜色
WHITE = (255,255,255)
BLACK = (0,0,0)
RED = (255,30,30)
GREEN = (30,255,30)
BLUE = (30,150,255)
YELLOW = (255,230,0)
PURPLE = (180,60,255)
ORANGE = (255,150,0)
CYAN = (0,255,255)

# 字体（全部修复）
font16 = pygame.font.SysFont("simhei",16)
font20 = pygame.font.SysFont("simhei",20)
font24 = pygame.font.SysFont("simhei",24)
font36 = pygame.font.SysFont("simhei",36)
font48 = pygame.font.SysFont("simhei",48)

# 排行榜文件
RANK_FILE = "game_rank.json"
def init_rank():
    if not os.path.exists(RANK_FILE):
        with open(RANK_FILE,"w",encoding="utf-8") as f:
            json.dump([],f)
def save_rank(name,score):
    init_rank()
    with open(RANK_FILE,"r",encoding="utf-8") as f:
        data = json.load(f)
    data.append({"name":name,"score":score,"time":datetime.now().strftime("%m-%d %H:%M")})
    data.sort(key=lambda x:-x["score"])
    data = data[:10]
    with open(RANK_FILE,"w",encoding="utf-8") as f:
        json.dump(data,f,ensure_ascii=False,indent=2)
def get_rank():
    init_rank()
    with open(RANK_FILE,"r",encoding="utf-8") as f:
        return json.load(f)

# ==================== 战机皮肤素材 ====================
SKINS = [
    {"name":"疾风蓝鹰","c1":BLUE,"c2":CYAN},
    {"name":"烈焰战神","c1":RED,"c2":ORANGE},
    {"name":"暗影魔龙","c1":PURPLE,"c2":(80,0,120)},
    {"name":"黄金至尊","c1":YELLOW,"c2":(255,200,0)},
]

# ==================== 道具类型 ====================
ITEM_TYPE = {
    "hp":GREEN,
    "speed":YELLOW,
    "bomb":RED,
    "shield":CYAN,
    "track":PURPLE
}

# ==================== 玩家类（双人+皮肤+技能） ====================
class Plane(pygame.sprite.Sprite):
    def __init__(self,pid,skin_idx=0):
        super().__init__()
        self.pid = pid
        self.skin = SKINS[skin_idx]
        self.skin_idx = skin_idx
        self.w,self.h = 45,38
        self.image = pygame.Surface((self.w,self.h),pygame.SRCALPHA)
        self.draw_plane()
        self.rect = self.image.get_rect()
        if pid==1:
            self.rect.centerx = SCREEN_W//2-120
            self.rect.bottom = SCREEN_H-60
        else:
            self.rect.centerx = SCREEN_W//2+120
            self.rect.bottom = SCREEN_H-60
        self.speed = 6
        self.hp = 5
        self.max_hp =5
        self.shoot_cd = 180
        self.last_shot = 0
        self.invincible = False
        self.inv_time = 0
        # 技能
        self.has_shield = False
        self.shield_time =0
        self.has_laser = False
        self.laser_time =0
        self.has_track = False
        self.track_time =0
        self.speed_up = False
        self.speed_time =0
        self.bomb_num =3

    def draw_plane(self):
        self.image.fill((0,0,0,0))
        c1,c2 = self.skin["c1"],self.skin["c2"]
        pygame.draw.polygon(self.image,c1,[(22,0),(0,38),(44,38)])
        pygame.draw.circle(self.image,c2,(22,18),8)

    def change_skin(self):
        self.skin_idx = (self.skin_idx+1)%len(SKINS)
        self.skin = SKINS[self.skin_idx]
        self.draw_plane()

    def update(self):
        if self.invincible:
            if pygame.time.get_ticks()-self.inv_time>1200:
                self.invincible=False
                self.image.set_alpha(255)
            else:
                self.image.set_alpha(120 if (pygame.time.get_ticks()//100)%2 else 255)
        if self.speed_up and pygame.time.get_ticks()>self.speed_time:
            self.speed_up=False
            self.speed=6
        if self.has_shield and pygame.time.get_ticks()>self.shield_time:
            self.has_shield=False
        if self.has_track and pygame.time.get_ticks()>self.track_time:
            self.has_track=False
        if self.has_laser and pygame.time.get_ticks()>self.laser_time:
            self.has_laser=False

        spd = self.speed*1.5 if self.speed_up else self.speed
        if self.pid==1:
            keys = pygame.key.get_pressed()
            if keys[pygame.K_a] and self.rect.left>0:self.rect.x-=spd
            if keys[pygame.K_d] and self.rect.right<SCREEN_W:self.rect.x+=spd
            if keys[pygame.K_w] and self.rect.top>0:self.rect.y-=spd
            if keys[pygame.K_s] and self.rect.bottom<SCREEN_H:self.rect.y+=spd
        else:
            keys = pygame.key.get_pressed()
            if keys[pygame.K_LEFT] and self.rect.left>0:self.rect.x-=spd
            if keys[pygame.K_RIGHT] and self.rect.right<SCREEN_W:self.rect.x+=spd
            if keys[pygame.K_UP] and self.rect.top>0:self.rect.y-=spd
            if keys[pygame.K_DOWN] and self.rect.bottom<SCREEN_H:self.rect.y+=spd

    def fire(self,bullet_group,all_sp):
        now = pygame.time.get_ticks()
        if now-self.last_shot>self.shoot_cd:
            self.last_shot=now
            if self.has_track:
                b = TrackBullet(self.rect.centerx,self.rect.top,self.pid)
            elif self.has_laser:
                b = LaserBullet(self.rect.centerx,self.rect.top,self.pid)
            else:
                b = NormalBullet(self.rect.centerx,self.rect.top,self.pid)
            bullet_group.add(b)
            all_sp.add(b)

    def use_bomb(self,enemy_group,score_dict):
        if self.bomb_num<=0:return
        self.bomb_num-=1
        for e in enemy_group:
            e.hp=0
            score_dict[self.pid]+=20

# 普通子弹
class NormalBullet(pygame.sprite.Sprite):
    def __init__(self,x,y,pid):
        super().__init__()
        self.image = pygame.Surface((6,18))
        self.image.fill(YELLOW if pid==1 else CYAN)
        self.rect = self.image.get_rect(center=(x,y))
        self.speed = -14
    def update(self):
        self.rect.y+=self.speed
        if self.rect.bottom<0:self.kill()

# 激光子弹
class LaserBullet(pygame.sprite.Sprite):
    def __init__(self,x,y,pid):
        super().__init__()
        self.image = pygame.Surface((12,25))
        self.image.fill(RED)
        self.rect = self.image.get_rect(center=(x,y))
        self.speed = -18
    def update(self):
        self.rect.y+=self.speed
        if self.rect.bottom<0:self.kill()

# 追踪子弹
class TrackBullet(pygame.sprite.Sprite):
    def __init__(self,x,y,pid):
        super().__init__()
        self.image = pygame.Surface((8,20))
        self.image.fill(PURPLE)
        self.rect = self.image.get_rect(center=(x,y))
        self.speed = -12
        self.tar = None
    def set_target(self,enems):
        if enems:self.tar = random.choice(list(enems))
    def update(self):
        if self.tar and self.tar.alive():
            if self.rect.centerx<self.tar.rect.centerx:self.rect.x+=1
            elif self.rect.centerx>self.tar.rect.centerx:self.rect.x-=1
        self.rect.y+=self.speed
        if self.rect.bottom<0:self.kill()

# 敌机
class Enemy(pygame.sprite.Sprite):
    def __init__(self,is_boss=False):
        super().__init__()
        self.is_boss = is_boss
        if is_boss:
            self.w,self.h=110,90
            self.hp=25
            self.speed=2
        else:
            sz = random.randint(28,45)
            self.w=self.h=sz
            self.hp=1
            self.speed=random.randint(3,7)
        self.image = pygame.Surface((self.w,self.h),pygame.SRCALPHA)
        self.draw_enemy()
        self.rect = self.image.get_rect()
        self.rect.x = random.randint(0,SCREEN_W-self.w)
        self.rect.y = random.randint(-120,-40)

    def draw_enemy(self):
        if self.is_boss:
            pygame.draw.circle(self.image,RED,(55,45),45)
            pygame.draw.circle(self.image,BLACK,(55,45),25)
        else:
            pygame.draw.circle(self.image,PURPLE,(self.w//2,self.h//2),self.w//2)

    def update(self):
        self.rect.y+=self.speed
        if self.is_boss:
            if self.rect.left<=0 or self.rect.right>=SCREEN_W:self.speed*=-1
            self.rect.x+=self.speed
        if self.rect.top>SCREEN_H:
            self.kill()

# 掉落道具
class Item(pygame.sprite.Sprite):
    def __init__(self,x,y):
        super().__init__()
        self.typ = random.choice(["hp","speed","bomb","shield","track"])
        self.image = pygame.Surface((22,22))
        self.image.fill(ITEM_TYPE[self.typ])
        self.rect = self.image.get_rect(center=(x,y))
        self.speed=4
    def update(self):
        self.rect.y+=self.speed
        if self.rect.top>SCREEN_H:self.kill()

# 爆炸特效
class Boom(pygame.sprite.Sprite):
    def __init__(self,pos,sz):
        super().__init__()
        self.img = pygame.Surface((sz,sz),pygame.SRCALPHA)
        pygame.draw.circle(self.img,YELLOW,(sz//2,sz//2),sz//2)
        self.image=self.img
        self.rect = self.image.get_rect(center=pos)
        self.t = pygame.time.get_ticks()
    def update(self):
        if pygame.time.get_ticks()-self.t>150:self.kill()

# ==================== 界面绘制 ====================
def draw_ui(p1,p2,sc1,sc2):
    pygame.draw.rect(screen,RED,(15,15,120,18))
    pygame.draw.rect(screen,GREEN,(15,15,24*p1.hp,18))
    screen.blit(font24.render(f"P1:{sc1}",True,WHITE),(15,40))
    screen.blit(font16.render(f"炸弹:{p1.bomb_num}",True,WHITE),(15,65))

    pygame.draw.rect(screen,RED,(SCREEN_W-135,15,120,18))
    pygame.draw.rect(screen,GREEN,(SCREEN_W-135,15,24*p2.hp,18))
    screen.blit(font24.render(f"P2:{sc2}",True,WHITE),(SCREEN_W-135,40))
    screen.blit(font16.render(f"炸弹:{p2.bomb_num}",True,WHITE),(SCREEN_W-135,65))

def draw_text(txt,font,col,x,y):
    r=font.render(txt,True,col)
    screen.blit(r,r.get_rect(center=(x,y)))

def start_menu():
    screen.fill((10,10,35))
    draw_text("🔥双人终极战机大战🔥",font48,YELLOW,SCREEN_W//2,120)
    draw_text("1.回车开始游戏",font24,WHITE,SCREEN_W//2,220)
    draw_text("2.R键切换战机皮肤",font24,WHITE,SCREEN_W//2,270)
    draw_text("3.1键护盾 2键激光 3键追踪弹",font24,WHITE,SCREEN_W//2,320)
    draw_text("4.空格P1射击 0键P1炸弹 | P2方向键射击 .键炸弹",font20,WHITE,SCREEN_W//2,370)
    draw_text("5.M键查看排行榜 T键切换手机/电脑屏",font24,WHITE,SCREEN_W//2,420)
    pygame.display.flip()
    wait=True
    while wait:
        for e in pygame.event.get():
            if e.type==pygame.QUIT:sys.exit()
            if e.type==pygame.KEYDOWN:
                if e.key==pygame.K_RETURN:wait=False
                if e.key==pygame.K_t:switch_screen()
        clock.tick(FPS)

def switch_screen():
    global SCREEN_W,SCREEN_H,screen,IS_PHONE
    IS_PHONE=not IS_PHONE
    if IS_PHONE:
        SCREEN_W,SCREEN_H=W_PHONE,H_PHONE
    else:
        SCREEN_W,SCREEN_H=W_WIN,H_WIN
    screen=pygame.display.set_mode((SCREEN_W,SCREEN_H))

def rank_show():
    rank = get_rank()
    screen.fill((20,20,50))
    draw_text("🏆游戏排行榜",font36,YELLOW,SCREEN_W//2,60)
    y=120
    for i,d in enumerate(rank[:10]):
        s=f"{i+1}.{d['name']} 分数:{d['score']} {d['time']}"
        draw_text(s,font24,WHITE,SCREEN_W//2,y)
        y+=35
    draw_text("按任意键返回",font24,RED,SCREEN_W//2,SCREEN_H-80)
    pygame.display.flip()
    wait=True
    while wait:
        for e in pygame.event.get():
            if e.type in (pygame.KEYDOWN,pygame.QUIT):wait=False
        clock.tick(FPS)

# ==================== 主游戏 ====================
def game_run():
    all_sp = pygame.sprite.Group()
    bullets = pygame.sprite.Group()
    enems = pygame.sprite.Group()
    items = pygame.sprite.Group()
    booms = pygame.sprite.Group()

    p1 = Plane(1)
    p2 = Plane(2)
    all_sp.add(p1,p2)
    score = {1:0,2:0}
    wave=1
    game_end=False

    for _ in range(6):
        e=Enemy()
        all_sp.add(e)
        enems.add(e)

    while True:
        clock.tick(FPS)
        screen.fill((5,5,20))
        for e in pygame.event.get():
            if e.type==pygame.QUIT:sys.exit()
            if e.type==pygame.KEYDOWN:
                if e.key==pygame.K_r:
                    p1.change_skin()
                    p2.change_skin()
                if e.key==pygame.K_1:
                    p1.has_shield=True
                    p1.shield_time=pygame.time.get_ticks()+6000
                if e.key==pygame.K_2:
                    p1.has_laser=True
                    p1.laser_time=pygame.time.get_ticks()+5000
                if e.key==pygame.K_3:
                    p1.has_track=True
                    p1.track_time=pygame.time.get_ticks()+5000
                if e.key==pygame.K_0:p1.use_bomb(enems,score)
                if e.key==pygame.K_PERIOD:p2.use_bomb(enems,score)
                if e.key==pygame.K_m:rank_show()
                if e.key==pygame.K_t:switch_screen()
                if e.key==pygame.K_ESCAPE:return

        keys = pygame.key.get_pressed()
        if keys[pygame.K_SPACE] and not game_end:
            p1.fire(bullets, all_sp)
        if keys[pygame.K_RSHIFT] and not game_end:
            p2.fire(bullets, all_sp)

        if not game_end:
            all_sp.update()
            booms.update()
            items.update()

            hit_e = pygame.sprite.groupcollide(enems,bullets,False,True)
            for ee,bs in hit_e.items():
                ee.hp-=len(bs)
                if ee.hp<=0:
                    booms.add(Boom(ee.rect.center,70 if ee.is_boss else 40))
                    score[1 if ee.rect.centerx<SCREEN_W//2 else 2]+=15
                    if random.random()<0.25:
                        it=Item(ee.rect.centerx,ee.rect.centery)
                        items.add(it)
                        all_sp.add(it)
                    ee.kill()

            hit_it1 = pygame.sprite.spritecollide(p1,items,True)
            for it in hit_it1:
                if it.typ=="hp":p1.hp=min(p1.max_hp,p1.hp+1)
                elif it.typ=="speed":p1.speed_up=True;p1.speed_time=pygame.time.get_ticks()+8000;p1.speed=9
                elif it.typ=="bomb":p1.bomb_num+=1
                elif it.typ=="shield":p1.has_shield=True;p1.shield_time=pygame.time.get_ticks()+6000
                elif it.typ=="track":p1.has_track=True;p1.track_time=pygame.time.get_ticks()+5000

            hit_it2 = pygame.sprite.spritecollide(p2,items,True)
            for it in hit_it2:
                if it.typ=="hp":p2.hp=min(p2.max_hp,p2.hp+1)
                elif it.typ=="speed":p2.speed_up=True;p2.speed_time=pygame.time.get_ticks()+8000;p2.speed=9
                elif it.typ=="bomb":p2.bomb_num+=1
                elif it.typ=="shield":p2.has_shield=True;p2.shield_time=pygame.time.get_ticks()+6000
                elif it.typ=="track":p2.has_track=True;p2.track_time=pygame.time.get_ticks()+5000

            for pl in [p1,p2]:
                coll = pygame.sprite.spritecollide(pl,enems,True)
                if coll and not pl.invincible and not pl.has_shield:
                    pl.hp-=1
                    pl.invincible=True
                    pl.inv_time=pygame.time.get_ticks()
                    if pl.hp<=0:
                        game_end=True
                        save_rank("玩家1", score[1])
                        save_rank("玩家2", score[2])

            if len(enems)<6+wave:
                ne = Enemy()
                enems.add(ne)
                all_sp.add(ne)
            if score[1]+score[2]>wave*800:
                wave+=1
                boss=Enemy(True)
                enems.add(boss)
                all_sp.add(boss)

        all_sp.draw(screen)
        booms.draw(screen)
        draw_ui(p1,p2,score[1],score[2])
        draw_text(f"关卡:{wave}",font24,WHITE,SCREEN_W//2,25)
        pygame.display.flip()

if __name__=="__main__":
    while True:
        start_menu()
        game_run()