orlog2023.py

Created by florian-allard

Created on March 02, 2024

15.2 KB

Adaptation du jeu Orlog (mini-jeu de dés et de jetons dans le jeu Assassin’s Creed Valhalla®). Une version avec les noms raccourcis pour les sorts d’invocation mais avec un résumé du plateau affiché en bas lors du choix de la divinité de la prochaine manche est disponible ici : https://my.numworks.com/python/florian-allard/orlog


from random import choice
from kandinsky import set_pixel,fill_rect as fr,draw_string as ds
from ion import keydown as kd,KEY_EXE as KE,KEY_LEFT as KL,KEY_RIGHT as KR,KEY_DOWN as KD,KEY_UP as KU
from time import sleep as sp

inf={"Thrymr":("Vol de ",1,"Niveau d'invocation adverse\n   réduit.",3,6,9,"-",1,2,3," niv","  "),\
"Var":("Lien de ",1,"Soin par Jeton adverse\n   dépensé.",10,14,18,"+",1,2,3,"   /  ","<J"),\
"Freyja":("Abondance de ",2,"Dés supplémentaires lancés.",2,4,6,"+",1,2,3,"   ","v "),\
"Frigg":("Vue de ",2,"Dés à soi et/ou adverses au\n   choix relancés.",2,3,4,"",2,3,4,"    ","v "),\
"Loki":("Ruse de ",2,"Dés adverses au choix\n   bannis.",3,6,9,"-",1,2,3,"   ","v "),\

"Skuld":("Annonce de ",3,"Jetons adverses détruits\n   par face flèche.",4,6,8,"-",2,3,4,"   /  ","Jf"),\
"Tyr":("Gage de ",3,"Jetons adverses détruits\n   par PV sacrifié.",4,6,8,"",-2,-3,-4,"   /  ","J<"),\
"Baldr":("Invulnérabilité de ",4,"Multiplie casques et\n   boucliers.",3,6,9,"",2,3,4,"x(  &  )","cb"),\
"Bragi":("Verve de ",4,"Jetons gagnés par face main.",4,8,12,"+",2,3,4,"   /  ","Jm"),\
"Brunehilde":("Fureur de ",4,"Multiplie les haches.",6,10,18," ",1.5,2,3,"x(    )"," h"),\

"Freyr":("Don de ",4,"Ajout de faces majoritaires.",4,6,8,"+",2,3,4,"    majoritaire","v "),\
"Heimdal":("Guet de ",4,"Soin par attaque bloquée.",4,7,10,"+",1,2,3,"   /blocage","< "),\
"Hel":("Etreinte de ",4,"Soin par coup de hache\n   infligé.",6,12,18,"+",1,2,3,"   /  infligée","<h"),\
"Mimir":("Sagesse de ",4,"Gain de Jetons par coup subi.",3,5,7,"+",1,2,3,"   /dégât subi","J "),\
"Skadi":("Chasse de ",4,"Multiplie les flèches.",6,10,14,"",2,3,4,"x(  )","f "),\

"Ullr":("Visée d'",4,"Boucliers adverses ignorés.",2,3,4,"-",2,3,6,"   ","b "),\
"Vidar":("Puissance de ",4,"Casques adverses enlevés.",2,4,6,"-",2,4,6,"   ","c "),\
"Thor":("Frappe de ",8,"Dégâts infligés après la\n   phase de résolution.",4,8,12,"-",2,5,8,"   ","< "),\
"Idunn":("Rajeunissement d'",9,"Soin après la phase de\n   résolution.",4,7,10,"+",2,4,6,"   ","< "),\
"Odin":("Sacrifice d'",9,"Gain de Jetons par PV\n   sacrifié.",6,8,10,"+",3,4,5,"   /  ","J<")}

def AffDv(Dv):
    fr(15,44,290,192,"w")
    fr(0,43,320,1,"purple")
    ds("<                             >",5,126,"b")
    if Dv=="aucune":
        ds("Ne pas choisir\n          de divinité.",90,80,"r")
    else:
        CHN=inf[Dv][0]+Dv
        ds(CHN,160-5*len(CHN),50,"g") # nom
        ds(str(inf[Dv][1]),155,70,"r") # priorité
        ds(inf[Dv][2],29,90,"b") # description
        dess("d",305,5,"purple")
        for niv in (0,1,2):
            Y=135+25*niv
            Cout=inf[Dv][3+niv]
            ds(str(Cout)+"   : "+inf[Dv][6]+str(inf[Dv][7+niv])+inf[Dv][-2],55+10*(Cout<10),Y,"purple")
            ds(" >"[niv==NvDv[Jr]],40,Y,"r")
            dess("J",85,Y+3,dore,dore)
            for k in (2,1):
                dess(inf[Dv][-1][-k],220-30*k,Y+3,"brown","brown","brown")
    sp(0.2)

def cadre(x,y,l,h,clr):
    for k in (0,1):
        fr(x,y+h*k,l+1,1,clr)
        fr(x+l*k,y,1,h+1,clr)


mtfs={"<":(0,0,0,0,252,252,252,252),"":()," ":(),"v":(),"V":(),"h":(8,28,62,111,206,396,768,1536,1024),"f":(15,3,5,9,16,32,64,896,128,128),"c":(120,252,510,1023,1023,819,819,390,390),"b":(120,204,390,891,585,585,891,390,204,120),"m":(168,170,170,682,766,1022,508,248,120,120),"j":(0,462,330,510,72,72,510,330,462),"d":(1799,1022,260,340,260,396,626,1025,1539,1285,1161,1105,1105,1105,2047)}
dore=(200,150,0)

def dess(ltr,x,y,Mtf="b",Ctr="g",Lsr=dore):
    mtf=mtfs[ltr.lower()]
    for lig in range(len(mtf)):
        elt=mtf[lig]
        elt="0"*(12+(ltr in ("d","h"))-len(bin(elt)))+bin(elt)[2:]
        for col in range(len(elt)):
            set_pixel(x+col,y+lig,(("w",Mtf)[int(elt[col])],"g")[ltr=="<"])
    if ltr not in ("<",""," ","d"):
        cadre(x-4,y-4,17,17,Ctr)
        cadre(x-2,y-2,13,13,("w",Lsr)[ltr.isupper()])


def ChF(jr,n,DR,Affch,NB=9):
    L=len(DR)
    Verr=[0]*L
    pos,ch=-1,1
    POS=(165-10*len(Affch),180-150*jr)[n>0]
    #ch=1
    Num=102+100*jr
    if IA and not jr and n>0:
        Verr=[Affch[k] in ("BCFM",("hfF","bBcC")[Vie[0]<Vie[1]])[Jet[1]>5] for k in range(L)]
        sp(1)
    else:
        while not ((kd(KE) and n>0) or n==3 or L*NB==0 or (kd(KE) and n<1 and sum(Verr)<=NB)):
            ds("^ "[ch],20*pos+POS,Num,"b")
            sp(0.2*(ch!=0))
            pos=(pos+ch)%L
            while Affch[pos]==" " and ch:
                pos=(pos+ch)%L
            ds("^",20*pos+POS,Num,"b")
            ch=kd(KR)-kd(KL)

            if kd(KU) or kd(KD):
                while kd(KU) or kd(KD):1
                dess(Affch[pos],20*pos+POS,Num-15,"b","rg"[Verr[pos]])
                Verr[pos]=1-Verr[pos]
        while kd(KE) and n<3:1

    Nvl=tuple(Affch[i] for i in range(L) if (Verr[i] or n==3))*(n>0)
    chs[jr]=(chs[jr]+list(Nvl),list(Nvl)+chs[jr])[jr]
    fr(0,Num,320,16,"w")#ds(" "*32,0,102+100*jr) # efface les ^

    for i in range(L): # efface les faces des nouveaux dés choisis
        dess(Affch[i]*(Verr[i]>0 or n==3),20*i+POS,Num-15,"kw"[n>0],"kw"[n>0],"kw"[n>0])
        if n<1 and Verr[i]>0:
            chs[jr][i]=(" ",choice(choice(Des)))[n]

    return DR,Verr

def Duel(faces,jr,clrs=("b","r",dore)):
    symb(faces[jr],0,0,clrs)
    symb(faces[1-jr],1,faces[jr] in chs[0] or faces[jr].upper() in chs[0] or faces[1-jr] in chs[1] or faces[1-jr].upper() in chs[1],clrs)

def AV(Jr,ch):
    ch=min(max(ch,-Vie[Jr]),15-Vie[Jr])
    Vie[Jr]+=ch
    if ch:
        #for i in range(Vie[Jr]-ch*(ch>0)):
        #    affV(i,"g",Jr)
        for (clr1,clr2) in (("r","cyan"),("w","g")):
            for i in range(Vie[Jr]-ch*(ch>0),Vie[Jr]-ch*(ch<0)):
                affV(i,(clr1,clr2)[ch>0],Jr)
            sp(0.7)
    while min(Vie)==0:
        ds("Joueur "+"AB"[Vie.index(0)]+" a rejoint Odin...",10,105,"purple")

def affV(i,clr,j):
    fr(255-245*j+10*(i%5),32+100*j+8*(i//5),6,4,clr)

def symb(ltr,jr,pause=0,clrs=("b","g",dore),Nb=99,eff=0):
    L=len(chs[jr])
    for i in range(L):
        if ltr=="tout" or (chs[jr][i].lower()==ltr and Nb>0):
            dess(chs[jr][i],20*(i%16)+5+(L<17)*(160-10*L),87+100*jr-10*((L-1)//16)+20*(i//16),clrs[0],clrs[1],clrs[2])
            Nb -= 1
            chs[jr][i]=(chs[jr][i],"vV"[chs[jr][i].isupper()])[eff]
        if ltr=="tout" and Ulr[1-jr]:
            symb("b",jr,0,("cyan",clrs[1],clrs[2]),2+(NvDv[1-jr]-1)**2)
    sp(pause)


def calc(ok=True):
    if ok:
        (H[:],f[:],F[:],c[:],C[:],b[:],B[:],m[:],M[:],v[:],V[:])=tuple([chs[k].count(ltr) for k in (0,1)] for ltr in "hfFcCbBmMvV")
    #Sep=(max(H[J],c[K]+C[K]+v[K]+V[K]),max(f[J]+F[J],b[K]+B[K]),max(c[J]+C[J]+v[J]+V[J],H[K]),max(b[J]+B[J],f[K]+F[K]))
    chs[J]=list("h"*H[J]+" "*(c[K]+C[K]+v[K]+V[K]-H[J])+"f"*f[J]+"F"*F[J]+" "*(b[K]+B[K]-f[J]-F[J])+"v"*v[J]+"V"*V[J]+"c"*c[J]+"C"*C[J]+" "*(H[K]-c[J]-C[J]-v[J]-V[J])+"b"*b[J]+"B"*B[J]+" "*(f[K]+F[K]-b[J]-B[J])+"m"*m[J]+"M"*M[J]+" "*(m[K]+M[K]))
    chs[K]=list("v"*v[K]+"V"*V[K]+"c"*c[K]+"C"*C[K]+" "*(H[J]-c[K]-C[K]-v[K]-V[K])+"b"*b[K]+"B"*B[K]+" "*(f[J]+F[J]-b[K]-B[K])+"h"*H[K]+" "*(c[J]+C[J]+v[J]+V[J]-H[K])+"f"*f[K]+"F"*F[K]+" "*(b[J]+B[J]-f[K]-F[K])+" "*(m[J]+M[J])+"m"*m[K]+"M"*M[K])
    for Jr in (J,K):
        fr(0,65+100*Jr,320,49,"w")
        symb("tout",Jr)

def AJ(jr,nb=0):
    Jet[jr]=min(50,max(0,Jet[jr]+nb))
    if nb:
        for clr in ("r",dore):
            sp(0.7)
            affJ(jr,clr)

def affJ(jr,clr):
  ds(" "*jr*(Jet[jr]<10)+str(Jet[jr])+" "*(1-jr),32+235*jr,22+100*jr,clr)

def plt():
    fr(0,0,320,222,"w")
    for Jr in (J,K):
        Y=25+100*Jr
        ds("Joueur "+"AB"[Jr],120,Y+2,"g")
        for i in range(Vie[Jr]):
            affV(i,"g",Jr)
        dess("J",12+285*Jr,Y,dore,dore)
        affJ(Jr,dore)
        dess("d",10+285*Jr,Y+20,"purple")

def Tt(dv):
    if inf[dv][1]==NIV:
        co=inf[dv][NvDv[Jr]+2]
        ok=DvMch[Jr]==dv and Jet[Jr]>=co
        Ny=45+100*Jr
        dess("d"*(DvMch[Jr]==dv),10+285*Jr,Ny,"rb"[ok])
        if ok:
            chn=inf[dv][6]+str(Puiss)+inf[dv][-2]
            AJ(Jr,-co)
            AV(1-Jr,Vr[1-Jr]*co*NvDv[1-Jr])
            Nx=245*Jr-10*len(chn)*Jr
            ds(chn,30+Nx,Ny,"b")
            for k in (2,1):
                dess(inf[dv][-1][-k],125+Nx-30*k,3+Ny,"brown","brown","brown")
        sp(DvMch[Jr]==dv)
        return ok

def sacri():
    NbPV=Vie[Jr]-1
    while not kd(KE):
        NbPV=max(0,min(NbPV+kd(KR)-kd(KL),Vie[Jr]))
        for i in range(Vie[Jr]):
            affV(i,"kg"[i<NbPV],Jr)
        sp(0.2)
    #while kd(KE):1
    AJ((Jr,1-Jr)[DvMch[Jr]=="Tyr"],(Vie[Jr]-NbPV)*Puiss)
    AV(Jr,NbPV-Vie[Jr])

# Choix des divinités pour toute la partie
ds("Orlog",135,15,"g")
ds("Choisir le mode\n\n        Joueur vs Joueur\n          Joueur vs IA\n\n        Valider avec EXE",85,56,"purple")
IA=1
for k in range(6):
    fr(60,40+k//5*145,200,1,"b")
    dess("hCfbMF"[k],90+25*k,200)
while not kd(KE):
    IA=(IA,1-IA)[kd(KU)-kd(KD)]
    for k in (0,1):
        ds(" >"[k==IA],60,94+18*k,"r")
    sp(0.2)
while kd(KE):1

DvCh,NvDv=[["Vidar"]*IA,[]],[-1,-1]
#DvCh=[[],[]]
J=choice((0,1))
K=1-J
for Jr in (J,K):
    if Jr or not IA:
        rg=-1
        ds("Joueur "+"AB"[Jr]+" : Choix des divinités\n                                ",2,5,"g")
        chgt=1
        while not kd(KE):
            rg=(rg+chgt)%20
            Dv=tuple(sorted(inf.keys()))[rg]
            if chgt:
                AffDv(Dv)
            chgt=kd(KR)-kd(KL)
            if kd(KU) or kd(KD):
                if Dv in DvCh[Jr]:
                    DvCh[Jr].remove(Dv)
                elif len(DvCh[Jr])<3:
                    DvCh[Jr].append(Dv)
                    DvCh[Jr].sort()
                ds("   ".join(DvCh[Jr])+"                                ",15,22,"purple")
                while kd(KU) or kd(KD):1
        while kd(KE):1
    DvCh[Jr].append("aucune")


# Initialisation

Vie=[15,15]
Jet=[0,0]

while 1:

    plt()

    # Phase de lancer

    Des=("ChhFbm","ChhfBm","ChhfbM","chhFBm","chhFbM","chhfBM")
    Rest=[Des[:]]*2

    chs,Vr,Ulr,Hl,Hmdl,Mmr,DvMch=[[],[]],[0,0],[0,0],[0,0],[0,0],[0,0],["",""]

    ds("   Phase de lancer      ",55,5,"orange")
    for n in (1,2,3):
        for jr in (J,K):
            DR=Rest[jr]
            R=range(len(DR))
            Affch=tuple(choice(DR[i]) for i in R)
            Y=87+100*jr
            ds("Phase "+str(n),125,Y-45,"g")
            fr(170-150*jr,Y-25,150,40,"w")

            for i in R:
                dess(Affch[i],20*i+180-150*jr,Y)
            sp(n==3)
            DR,Verr=ChF(jr,n,DR,Affch)

            for i in range(len(chs[jr])):
                dess(chs[jr][i],20*i+30+(270-20*len(chs[jr]))*jr,Y)
            sp(1)

            Rest[jr]=tuple(DR[i] for i in R if (Verr[i]==0)*(n<3))

    H,f,F,c,C,b,B,m,M,v,V=tuple([0,0] for k in range(11))
    calc()
    ds("    Phase de choix    ",50,5,"orange")

    while not kd(KE):
        ds("Appuyer sur EXE",80,105,"purple")
    while kd(KE):1

    for Jr in (J,K):
        if IA and not Jr:
            DvMch[0]=("aucune","Vidar")[Jet[0]>=2]
            NvDv[0]=1+(Jet[0]>=3)
        else:
            fr(0,0,320,222,"w") # efface l'écran // à enlever ? //
            ds("Joueur "+"AB"[Jr]+" : Choisir la divinité \n   de la prochaine manche ",2,5,"g")
            rg=-1
            chgt=1
            while not kd(KE):
                rg=(rg+chgt)%len(DvCh[Jr])
                Divi=DvCh[Jr][rg]
                if chgt or kd(KU)+kd(KD):
                    NvDv[Jr]=(NvDv[Jr]-kd(KU)+kd(KD))%3
                    AffDv(Divi)
                chgt=kd(KR)-kd(KL)


            while kd(KE):1
            DvMch[Jr]=DvCh[Jr][rg]
            NvDv[Jr]+=1 # pour avoir un niveau entre 1 et 3


    plt()
    ds("Phase de résolution    ",65,5,"orange")
    calc(False)


    for NIV in range(1,10):
        for Jr in (J,K):
            if DvMch[Jr]!="aucune":
                Puiss=inf[DvMch[Jr]][6+NvDv[Jr]]

    # divinité priorité 1
            if Tt("Var"):
                Vr[Jr]=1
            if Tt("Thrymr"):
                dess("d",295-285*Jr,145-100*Jr,"cyan")
                sp(1)
                NvDv[1-Jr]=max(0,NvDv[1-Jr]-NvDv[Jr])
                DvMch[1-Jr]=(DvMch[1-Jr],"aucune")[NvDv[1-Jr]==0]

    # divinité priorité 2
            if Tt("Freyja"):
                chs[Jr]+=[choice(choice(Des)) for k in range(NvDv[Jr])]
                calc()
            if DvMch[Jr] in ("Frigg","Loki") and Tt(DvMch[Jr]):
                Nb=sum(ChF(1-Jr,0-(DvMch[Jr]=="Frigg"),chs[1-Jr],chs[1-Jr],Puiss)[1])
                ChF(Jr,-1,chs[Jr],chs[Jr],(Puiss-Nb)*(DvMch[Jr]=="Frigg"))
                sp(1)
                calc()

    # divinité priorité 3
            if Tt("Skuld"):
                symb("f",Jr,1,("b","purple",dore))
                AJ(1-Jr,-(f[Jr]+F[Jr])*Puiss)
                #symb("f",Jr)
            if Tt("Tyr"):
                sacri()

    # divinité priorité 4
            if Tt("Vidar"):
                for effacer in (False,True):
                    symb("c",1-Jr,1,("rw"[effacer],"g",dore),Puiss,effacer)
                calc()
            if DvMch[Jr] in ("Ullr","Hel","Heimdal","Mimir") and Tt(DvMch[Jr]):
                (Ulr,Hl,Hmdl,Mmr)[("Ullr","Hel","Heimdal","Mimir").index(DvMch[Jr])][Jr]=1
            if DvMch[Jr] in ("Baldr","Brunehilde","Freyr","Skadi") and Tt(DvMch[Jr]):
                b[Jr]+=(DvMch[Jr]=="Baldr")*NvDv[Jr]*(b[Jr]+B[Jr])
                c[Jr]+=(DvMch[Jr]=="Baldr")*NvDv[Jr]*(c[Jr]+C[Jr])
                H[Jr]+=(DvMch[Jr]=="Brunehilde")*int((Puiss-1)*H[Jr]+0.51)
                Liste=(H[Jr],f[Jr]+F[Jr],c[Jr]+C[Jr],b[Jr]+B[Jr],m[Jr]+M[Jr])
                (H,f,c,b,m)[choice([k for k in range(5) if Liste[k]==max(Liste)])][Jr]+=(DvMch[Jr]=="Freyr")*int(Puiss)
                f[Jr]+=(DvMch[Jr]=="Skadi")*(f[Jr]+F[Jr])*NvDv[Jr]
                calc(False)
            if Tt("Bragi"):
                symb("m",Jr,0,("b","purple",dore))
                AJ(Jr,(m[Jr]+M[Jr])*Puiss)

    # action des liserés
            if F[Jr]+C[Jr]+B[Jr]+M[Jr]+V[Jr] and NIV==5:
                sp(0.7)
                symb("tout",Jr,1,"bgr")
                AJ(Jr,F[Jr]+C[Jr]+B[Jr]+M[Jr]+V[Jr])
                symb("tout",Jr,0.5)


    # Phase d'affrontement des dés
            k=Jr
            if NIV==6:
                Duel(".v",k,"www")
                Duel("hc",k)
                MAX=max(0,H[k]-c[1-k]-C[1-k])
                AV(1-k,Hmdl[1-k]*min(H[k],c[1-k]+C[1-k])*NvDv[1-k])
                AV(1-k,-MAX)
                AJ(1-k,Mmr[1-k]*MAX*NvDv[1-k])
                AV(k,Hl[k]*MAX*NvDv[k])
                Duel("hc",k,"www")

                Duel("fb",k)
                UU=Ulr[k]*(2+(NvDv[k]-1)**2)
                symb("b",1-k,0,("cyan","r",dore),UU)
                MAX=max(0,f[k]+F[k]-b[1-k]-B[1-k])
                MIN=min(f[k]+F[k],b[1-k]+B[1-k])
                AV(1-k,Hmdl[1-k]*MIN*NvDv[1-k])
                AV(1-k,-MAX-min(MIN,UU))
                AJ(1-k,Mmr[1-k]*MAX*NvDv[1-k])
                Duel("fb",k,"www")

            if NIV==7:
                Duel("m.",k)
                if (m[k]+M[k])*Jet[1-k]:
                    vol=min(m[k]+M[k],Jet[1-k])
                    AJ(1-k,-vol)
                    AJ(k,vol)
                Duel("m.",k,"www")


    # divinité de priorité 6+2
            if Tt("Thor"):
                AV(1-Jr,-Puiss)

    # divinité de priorité 7+2
            if Tt("Idunn"):
                AV(Jr,Puiss)
            if Tt("Odin"):
                sacri()

    J,K=K,J