Le jeu repose sur une grande carte composée de forêts, chemins, lacs, falaises et habitations.
Chaque élément du décor, arbres, rochers, maisons, fleurs, coffres, feu de camp est dessiné directement par le programme, donnant un rendu unique et entièrement personnalisé.
Les monstres apparaissent dans la forêt, avec des niveaux et des types variés, créant une exploration dynamique et imprévisible.
Un système de combat complet
Les affrontements se déroulent dans un écran dédié où le joueur peut :
- attaquer,
- lancer un sort,
- boire une potion,
- tenter de fuir.
Les monstres ripostent, certains sont rapides, d’autres puissants, et le boss final — l’Ombre — représente le défi ultime de l’aventure.
Une progression scénarisée
L’histoire se déroule autour d’une quête principale :
- rencontrer la doyenne du village,
- s’entraîner dans la forêt,
- affronter l’Ombre dans la falaise,
- revenir annoncer la victoire.
Des PNJ accompagnent le joueur :
- la doyenne Maélis,
- le garde du chemin,
- Borin, le marchand qui propose potions, amélioration d’épée et renforcement d’armure.
- Des coffres cachés, un feu de camp pour se régénérer, et des dialogues intégrés enrichissent l’expérience.
Une aventure complète
Une fois l’Ombre vaincue, le jeu affiche un écran de victoire célébrant la libération des terres et la réussite du héros.
L’ensemble forme une petite aventure cohérente, jouable du début à la fin, avec exploration, combats, progression et conclusion.
Programme :
@ CONFIGURATION
graph est une toile
dimension(graph, 640, 520)
COTE est un nombre
COTE vaut 19
// --- Position et caméra ---
jX est un nombre
jY est un nombre
jX vaut 5
jY vaut 17
zoom est un nombre
zoom vaut 100
orientation est un nombre
orientation vaut 0
// --- Fiche du héros ---
niv est un nombre
niv vaut 1
xp est un nombre
xp vaut 0
xpSuiv est un nombre
xpSuiv vaut 30
pv est un nombre
pvMax est un nombre
pv vaut 40
pvMax vaut 40
mana est un nombre
manaMax est un nombre
mana vaut 12
manaMax vaut 12
attaque est un nombre
attaque vaut 7
defense est un nombre
defense vaut 3
pieces est un nombre
pieces vaut 25
potions est un nombre
potions vaut 2
epee est un nombre
epee vaut 0
armure est un nombre
armure vaut 0
// --- Avancement de l'histoire ---
// quete : 0 pas encore parlé au chef, 1 en cours, 2 Ombre vaincue
quete est un nombre
quete vaut 0
ombreVaincue est un booléen
ombreVaincue vaut faux
// --- Écran actif : monde, combat, dialogue, boutique, fin ---
ecran est un texte
ecran vaut "monde"
message est un texte
message vaut "Va parler au chef du village (le personnage en rouge)"
// --- Adversaire du combat en cours ---
mNom est un texte
mTyp est un nombre
mNiv est un nombre
mPv est un nombre
mPvMax est un nombre
mAtt est un nombre
mDef est un nombre
mLig est un nombre
mCol est un nombre
cbMsg1 est un texte
cbMsg2 est un texte
cbMsg1 vaut ""
cbMsg2 vaut ""
// --- Dialogue en cours ---
dlgNom est un texte
dlgL1 est un texte
dlgL2 est un texte
dlgL3 est un texte
dlgNom vaut ""
dlgL1 vaut ""
dlgL2 vaut ""
dlgL3 vaut ""
action est un nombre
@ GRILLES DU MONDE
// terr : 0 herbe, 1 eau, 2 chemin, 3 pierre
// objt : 0 rien, 1 arbre, 2 rocher, 3 mur, 5 coffre, 6 panneau,
// 7 chef, 8 marchand, 9 garde, 10 monstre, 11 fleur, 12 feu de camp
terr est un tableau
objt est un tableau
mobTyp est un tableau
mobNiv est un tableau
pour i de 0 à COTE
lT est un tableau
lO est un tableau
lMt est un tableau
lMn est un tableau
pour j de 0 à COTE
lT ajoute 0
lO ajoute 0
lMt ajoute 0
lMn ajoute 0
fin pour
terr ajoute lT
objt ajoute lO
mobTyp ajoute lMt
mobNiv ajoute lMn
fin pour
@ CONSTRUCTION DU MONDE
// --- La falaise de pierre, au nord ---
pour i de 0 à 2
pour j de 0 à COTE
terr[i][j] vaut 3
objt[i][j] vaut 2
fin pour
fin pour
// Un couloir laissé libre dans la falaise
pour i de 0 à 2
objt[i][14] vaut 0
objt[i][15] vaut 0
fin pour
// --- Le lac ---
pour i de 8 à 11
pour j de 12 à 17
terr[i][j] vaut 1
fin pour
fin pour
terr[8][17] vaut 0
terr[11][12] vaut 0
// --- Les chemins ---
pour i de 3 à 18
terr[i][5] vaut 2
fin pour
pour j de 5 à 15
terr[4][j] vaut 2
fin pour
pour i de 2 à 4
terr[i][14] vaut 2
fin pour
pour i de 16 à 17
pour j de 4 à 6
terr[i][j] vaut 2
fin pour
fin pour
// --- La forêt ---
pour i de 6 à 13
pour j de 0 à COTE
si terr[i][j] = 0 et objt[i][j] = 0 alors
si hasard(1, 100) <= 22 alors
objt[i][j] vaut 1
sinon si hasard(1, 100) <= 8 alors
objt[i][j] vaut 11
fin si
fin si
fin pour
fin pour
// --- Le village, au sud ---
pour j de 2 à 3
objt[15][j] vaut 3
objt[14][j] vaut 3
fin pour
pour j de 7 à 8
objt[15][j] vaut 3
objt[14][j] vaut 3
fin pour
pour j de 3 à 6
objt[19][j] vaut 3
fin pour
objt[16][6] vaut 7
objt[17][6] vaut 8
objt[17][4] vaut 12
objt[14][4] vaut 6
objt[4][10] vaut 9
// --- Coffres cachés dans la nature ---
objt[9][2] vaut 5
objt[12][17] vaut 5
objt[6][18] vaut 5
// --- L'Ombre garde la falaise ---
objt[1][14] vaut 10
mobTyp[1][14] vaut 4
mobNiv[1][14] vaut 8
// --- Monstres errants ---
poses est un nombre
poses vaut 0
essais est un nombre
essais vaut 0
tant que poses < 12 et essais < 600
essais ajoute 1
oi est un nombre
oj est un nombre
oi vaut hasard(5, 13)
oj vaut hasard(0, COTE)
si terr[oi][oj] = 0 et objt[oi][oj] = 0 alors
objt[oi][oj] vaut 10
nvM est un nombre
nvM vaut hasard(1, 3)
si oi <= 6 alors
nvM vaut hasard(3, 5)
fin si
mobNiv[oi][oj] vaut nvM
si nvM <= 2 alors
mobTyp[oi][oj] vaut 1
sinon si nvM <= 4 alors
mobTyp[oi][oj] vaut 2
sinon
mobTyp[oi][oj] vaut 3
fin si
poses ajoute 1
fin si
fin tant que
// La case de départ reste dégagée
objt[17][5] vaut 0
objt[16][5] vaut 0
@ TUILE DE TERRAIN
procédure dessinerSol(t, cx, cy, dx, dy, prof, cTop, cG, cD)
// contour règle le trait de TOUT ce qui suit : on l'active ici, on l'éteint à la fin
contour(t, #1B4332, 1)
pFG est un tableau
pFG ajoute cx - dx
pFG ajoute cy
pFG ajoute cx
pFG ajoute cy + dy
pFG ajoute cx
pFG ajoute cy + dy + prof
pFG ajoute cx - dx
pFG ajoute cy + prof
polygone(t, pFG, cG)
pFD est un tableau
pFD ajoute cx
pFD ajoute cy + dy
pFD ajoute cx + dx
pFD ajoute cy
pFD ajoute cx + dx
pFD ajoute cy + prof
pFD ajoute cx
pFD ajoute cy + dy + prof
polygone(t, pFD, cD)
pTop est un tableau
pTop ajoute cx
pTop ajoute cy - dy
pTop ajoute cx + dx
pTop ajoute cy
pTop ajoute cx
pTop ajoute cy + dy
pTop ajoute cx - dx
pTop ajoute cy
polygone(t, pTop, cTop)
contour(t, #0)
fin procédure
@ CUBE
procédure dessinerCube(t, cx, cy, dx, dy, h, cTop, cG, cD)
contour(t, #1F2937, 1)
lCY est un nombre
lCY vaut cy - h
pFG est un tableau
pFG ajoute cx - dx
pFG ajoute lCY
pFG ajoute cx
pFG ajoute lCY + dy
pFG ajoute cx
pFG ajoute lCY + dy + h
pFG ajoute cx - dx
pFG ajoute lCY + h
polygone(t, pFG, cG)
pFD est un tableau
pFD ajoute cx
pFD ajoute lCY + dy
pFD ajoute cx + dx
pFD ajoute lCY
pFD ajoute cx + dx
pFD ajoute lCY + h
pFD ajoute cx
pFD ajoute lCY + dy + h
polygone(t, pFD, cD)
pTop est un tableau
pTop ajoute cx
pTop ajoute lCY - dy
pTop ajoute cx + dx
pTop ajoute lCY
pTop ajoute cx
pTop ajoute lCY + dy
pTop ajoute cx - dx
pTop ajoute lCY
polygone(t, pTop, cTop)
contour(t, #0)
fin procédure
@ PERSONNAGE (héros et PNJ partagent le même dessin)
procédure dessinerPerso(t, cx, cy, e, cHaut, cBas, cChev)
ellipse(t, cx, cy + (2 * e), 11 * e, 5 * e, rgba(0, 0, 0, 0.4))
rectangle_arrondi(t, cx - (4 * e), cy - (10 * e), 8 * e, 10 * e, 2, cBas)
rectangle_arrondi(t, cx - (9 * e), cy - (20 * e), 4 * e, 9 * e, 2, #FCD34D)
rectangle_arrondi(t, cx - (5 * e), cy - (21 * e), 10 * e, 12 * e, 2, cHaut)
rectangle_arrondi(t, cx + (5 * e), cy - (20 * e), 4 * e, 9 * e, 2, #FCD34D)
rectangle_arrondi(t, cx - (6 * e), cy - (30 * e), 12 * e, 10 * e, 3, #FCD34D)
rectangle_arrondi(t, cx - (6 * e), cy - (32 * e), 13 * e, 5 * e, 2, cChev)
cercle(t, cx - (2 * e), cy - (25 * e), 1 * e, #0F172A)
cercle(t, cx + (2 * e), cy - (25 * e), 1 * e, #0F172A)
fin procédure
@ MONSTRE
procédure dessinerMonstre(t, cx, cy, e, typ)
ellipse(t, cx, cy + (2 * e), 12 * e, 6 * e, rgba(0, 0, 0, 0.4))
si typ = 1 alors
// Gluant
ellipse(t, cx, cy - (8 * e), 13 * e, 10 * e, #22C55E)
ellipse(t, cx - (4 * e), cy - (12 * e), 4 * e, 3 * e, rgba(255, 255, 255, 0.45))
cercle(t, cx - (4 * e), cy - (9 * e), 2 * e, #052E16)
cercle(t, cx + (4 * e), cy - (9 * e), 2 * e, #052E16)
sinon si typ = 2 alors
// Loup
ellipse(t, cx, cy - (10 * e), 14 * e, 7 * e, #64748B)
cercle(t, cx + (8 * e), cy - (16 * e), 6 * e, #94A3B8)
pOr est un tableau
pOr ajoute cx + (4 * e)
pOr ajoute cy - (20 * e)
pOr ajoute cx + (7 * e)
pOr ajoute cy - (28 * e)
pOr ajoute cx + (10 * e)
pOr ajoute cy - (20 * e)
polygone(t, pOr, #475569)
cercle(t, cx + (7 * e), cy - (17 * e), 2 * e, #EF4444)
cercle(t, cx + (12 * e), cy - (16 * e), 1 * e, #0F172A)
sinon si typ = 3 alors
// Squelette
rectangle_arrondi(t, cx - (2 * e), cy - (18 * e), 4 * e, 18 * e, 2, #E2E8F0)
rectangle(t, cx - (7 * e), cy - (16 * e), 14 * e, 2 * e, #CBD5E1)
rectangle(t, cx - (6 * e), cy - (12 * e), 12 * e, 2 * e, #CBD5E1)
cercle(t, cx, cy - (23 * e), 6 * e, #F8FAFC)
cercle(t, cx - (2 * e), cy - (24 * e), 2 * e, #0F172A)
cercle(t, cx + (2 * e), cy - (24 * e), 2 * e, #0F172A)
sinon
// L'Ombre
ellipse(t, cx, cy, 18 * e, 8 * e, rgba(88, 28, 135, 0.55))
appelle dessinerCube(t, cx, cy, 11 * e, 6 * e, 26 * e, #6D28D9, #4C1D95, #3B1073)
cercle(t, cx - (5 * e), cy - (24 * e), 3 * e, #F87171)
cercle(t, cx + (5 * e), cy - (24 * e), 3 * e, #F87171)
ellipse(t, cx, cy - (36 * e), 10 * e, 5 * e, rgba(168, 85, 247, 0.5))
fin si
fin procédure
@ DÉCOR
procédure dessinerDecor(t, cx, cy, val, dx, dy, e)
si val = 1 alors
// Arbre
ellipse(t, cx, cy + (2 * e), 10 * e, 5 * e, rgba(0, 0, 0, 0.35))
rectangle(t, cx - (3 * e), cy - (18 * e), 6 * e, 18 * e, #92400E)
cercle(t, cx, cy - (26 * e), 11 * e, #15803D)
cercle(t, cx - (6 * e), cy - (20 * e), 8 * e, #166534)
cercle(t, cx + (6 * e), cy - (21 * e), 8 * e, #22C55E)
sinon si val = 2 alors
// Rocher
appelle dessinerCube(t, cx, cy, dx * 3 / 4, dy * 3 / 4, 14 * e, #9CA3AF, #6B7280, #4B5563)
cercle(t, cx - (4 * e), cy - (18 * e), 3 * e, #D1D5DB)
sinon si val = 3 alors
// Mur de maison, avec son toit
appelle dessinerCube(t, cx, cy, dx, dy, 20 * e, #C2410C, #9A3412, #7C2D12)
appelle dessinerCube(t, cx, cy - (20 * e), dx, dy, 8 * e, #DC2626, #B91C1C, #991B1B)
sinon si val = 5 alors
// Coffre
appelle dessinerCube(t, cx, cy, dx * 2 / 3, dy * 2 / 3, 12 * e, #A16207, #854D0E, #713F12)
rectangle(t, cx - (3 * e), cy - (9 * e), 6 * e, 3 * e, #FDE68A)
sinon si val = 6 alors
// Panneau
rectangle(t, cx - (1 * e), cy - (14 * e), 3 * e, 14 * e, #78350F)
rectangle_arrondi(t, cx - (10 * e), cy - (24 * e), 20 * e, 11 * e, 2, #B45309)
rectangle(t, cx - (7 * e), cy - (20 * e), 14 * e, 2 * e, #FDE68A)
sinon si val = 11 alors
// Fleurs
cercle(t, cx - (5 * e), cy - (2 * e), 2 * e, #F9A8D4)
cercle(t, cx + (4 * e), cy - (4 * e), 2 * e, #FDE68A)
cercle(t, cx + (1 * e), cy + (2 * e), 2 * e, #93C5FD)
sinon si val = 12 alors
// Feu de camp
cercle(t, cx, cy, 9 * e, #57534E)
rectangle(t, cx - (8 * e), cy - (4 * e), 16 * e, 3 * e, #78350F)
ellipse(t, cx, cy - (12 * e), 6 * e, 10 * e, rgba(249, 115, 22, 0.9))
ellipse(t, cx, cy - (10 * e), 3 * e, 6 * e, #FDE68A)
fin si
fin procédure
@ INTERFACE DU MONDE
procédure dessinerHud(t, nv, p, pM, mn, mM, x, xS, po, pot, ep, ar, q, msg)
rectangle(t, 0, 0, 640, 74, rgba(15, 23, 42, 0.8))
label(t, 12, 20, "LES TERRES D'AURION", #FFFFFF, 13)
label(t, 200, 20, "Niveau " + nv, #FDE68A, 13)
// Barre de vie
rectangle_arrondi(t, 280, 9, 130, 12, 6, #334155)
lg est un nombre
lg vaut arrondi(130 * p / pM)
lg vaut limiter(lg, 0, 130)
si lg > 0 alors
rectangle_arrondi(t, 280, 9, lg, 12, 6, #EF4444)
fin si
label(t, 418, 19, "PV " + p + "/" + pM, #FCA5A5, 11)
// Barre de mana
rectangle_arrondi(t, 500, 9, 80, 12, 6, #334155)
lm est un nombre
lm vaut arrondi(80 * mn / mM)
lm vaut limiter(lm, 0, 80)
si lm > 0 alors
rectangle_arrondi(t, 500, 9, lm, 12, 6, #3B82F6)
fin si
label(t, 586, 19, "MP " + mn, #93C5FD, 11)
// Barre d'expérience
rectangle_arrondi(t, 12, 30, 200, 8, 4, #334155)
lx est un nombre
lx vaut arrondi(200 * x / xS)
lx vaut limiter(lx, 0, 200)
si lx > 0 alors
rectangle_arrondi(t, 12, 30, lx, 8, 4, #A855F7)
fin si
label(t, 220, 38, "XP " + x + "/" + xS, #E9D5FF, 11)
label(t, 320, 38, "Or : " + po + " Potions : " + pot + " Épée +" + ep + " Armure +" + ar, #CBD5E1, 11)
txtQ est un texte
si q = 0 alors
txtQ vaut "Quête : parler au chef du village"
sinon si q = 1 alors
txtQ vaut "Quête : vaincre l'Ombre, au nord de la falaise"
sinon
txtQ vaut "Quête : annoncer ta victoire au chef"
fin si
label(t, 12, 56, txtQ, #FDE68A, 11)
label(t, 340, 56, "[Z S Q D] bouger [E] potion [T] caméra [+/-] zoom", #94A3B8, 10)
rectangle(t, 0, 486, 640, 34, rgba(15, 23, 42, 0.8))
label(t, 12, 508, msg, #F8FAFC, 13)
fin procédure
@ ÉCRAN DE COMBAT
procédure dessinerCombat(t, nom, nvM, mp, mpM, typ, p, pM, mn, mM, pot, l1, l2)
effacer(t)
remplir(t, #0F172A)
contour(t, #0)
// Décor de fond
rectangle(t, 0, 0, 640, 250, #1E293B)
ellipse(t, 400, 250, 220, 60, #334155)
ellipse(t, 150, 330, 200, 50, #1E293B)
label(t, 20, 34, "COMBAT", #F87171, 20)
// L'adversaire
label(t, 380, 70, nom + " (niveau " + nvM + ")", #FCA5A5, 15)
rectangle_arrondi(t, 380, 82, 220, 14, 7, #334155)
lm est un nombre
lm vaut arrondi(220 * mp / mpM)
lm vaut limiter(lm, 0, 220)
si lm > 0 alors
rectangle_arrondi(t, 380, 82, lm, 14, 7, #EF4444)
fin si
label(t, 380, 112, mp + " / " + mpM + " PV", #CBD5E1, 12)
appelle dessinerMonstre(t, 470, 240, 3, typ)
// Le héros, de dos
appelle dessinerPerso(t, 150, 330, 3, #38BDF8, #1E3A8A, #EA580C)
label(t, 40, 380, "Toi", #93C5FD, 14)
rectangle_arrondi(t, 40, 388, 200, 14, 7, #334155)
lp est un nombre
lp vaut arrondi(200 * p / pM)
lp vaut limiter(lp, 0, 200)
si lp > 0 alors
rectangle_arrondi(t, 40, 388, lp, 14, 7, #22C55E)
fin si
label(t, 40, 418, "PV " + p + "/" + pM + " MP " + mn + "/" + mM, #CBD5E1, 12)
// Journal de combat
contour(t, #475569, 1)
rectangle_arrondi(t, 300, 370, 320, 60, 8, rgba(2, 6, 23, 0.85))
contour(t, #0)
label(t, 312, 392, l1, #FDE68A, 12)
label(t, 312, 414, l2, #FDE68A, 12)
// Menu d'actions
rectangle(t, 0, 450, 640, 70, rgba(15, 23, 42, 0.95))
label(t, 20, 476, "[A] Attaquer", #F8FAFC, 14)
label(t, 170, 476, "[M] Magie (6 MP)", #93C5FD, 14)
label(t, 360, 476, "[P] Potion (" + pot + ")", #C4B5FD, 14)
label(t, 520, 476, "[F] Fuir", #FCA5A5, 14)
label(t, 20, 502, "Appuie sur la lettre de ton choix", #64748B, 11)
affiche t
fin procédure
@ ÉCRAN DE DIALOGUE
procédure dessinerDialogue(t, nom, l1, l2, l3)
contour(t, #FDE68A, 1)
rectangle_arrondi(t, 60, 300, 520, 160, 12, rgba(2, 6, 23, 0.95))
contour(t, #0)
label(t, 80, 330, nom, #FDE68A, 16)
label(t, 80, 364, l1, #F8FAFC, 13)
label(t, 80, 388, l2, #F8FAFC, 13)
label(t, 80, 412, l3, #F8FAFC, 13)
label(t, 80, 444, "[E] continuer", #93C5FD, 12)
affiche t
fin procédure
@ ÉCRAN DE BOUTIQUE
procédure dessinerBoutique(t, po, pot, ep, ar)
contour(t, #FDE68A, 1)
rectangle_arrondi(t, 60, 240, 520, 230, 12, rgba(2, 6, 23, 0.95))
contour(t, #0)
label(t, 80, 272, "ÉCHOPPE DE BORIN", #FDE68A, 18)
label(t, 80, 300, "Ta bourse : " + po + " pièces d'or", #CBD5E1, 13)
prixEp est un nombre
prixAr est un nombre
prixEp vaut 60 + ep * 50
prixAr vaut 55 + ar * 50
label(t, 80, 336, "[P] Potion de soin", #F8FAFC, 14)
label(t, 400, 336, "20 or", #FDE68A, 14)
label(t, 80, 366, "[A] Affûter l'épée (+" + ep + " ? +" + (ep + 1) + ")", #F8FAFC, 14)
label(t, 400, 366, prixEp + " or", #FDE68A, 14)
label(t, 80, 396, "[R] Renforcer l'armure (+" + ar + " ? +" + (ar + 1) + ")", #F8FAFC, 14)
label(t, 400, 396, prixAr + " or", #FDE68A, 14)
label(t, 80, 440, "[Q] Sortir de l'échoppe", #93C5FD, 13)
label(t, 300, 440, "Potions en poche : " + pot, #64748B, 12)
affiche t
fin procédure
@ ÉCRAN DE VICTOIRE
procédure dessinerFin(t, nv, po)
effacer(t)
remplir(t, #1E1B4B)
contour(t, #0)
pour k de 0 à 40
cercle(t, hasard(0, 640), hasard(0, 300), hasard(1, 2), #FDE68A)
fin pour
label(t, 120, 180, "?? LES TERRES SONT LIBRES", #FDE68A, 26)
label(t, 120, 230, "L'Ombre a été vaincue et le village respire.", #F8FAFC, 15)
label(t, 120, 262, "Héros de niveau " + nv + ", " + po + " pièces d'or en poche.", #CBD5E1, 14)
label(t, 120, 320, "Merci d'avoir joué.", #93C5FD, 14)
affiche t
fin procédure
@ BOUCLE PRINCIPALE
tant que vrai
// ==================================================
// LE MONDE
// ==================================================
si ecran = "monde" alors
effacer(graph)
remplir(graph, #071018)
contour(graph, #0)
ech est un nombre
ech vaut zoom / 100
dx est un nombre
dy est un nombre
dx vaut 26 * ech
dy vaut 13 * ech
profSol est un nombre
profSol vaut 14 * ech
// De l'arrière vers l'avant : rY puis rX croissants
pour rY de - 8 à 8
pour rX de - 8 à 8
offX est un nombre
offY est un nombre
si orientation = 0 alors
offX vaut rX
offY vaut rY
sinon si orientation = 1 alors
offX vaut 0 - rY
offY vaut rX
sinon si orientation = 2 alors
offX vaut 0 - rX
offY vaut 0 - rY
sinon
offX vaut rY
offY vaut 0 - rX
fin si
gx est un nombre
gy est un nombre
gx vaut jX + offX
gy vaut jY + offY
si gx >= 0 et gx <= COTE et gy >= 0 et gy <= COTE alors
cx est un nombre
cy est un nombre
cx vaut 320 + (rX - rY) * dx
cy vaut 250 + (rX + rY) * dy
si cx >= - 80 et cx <= 720 et cy >= - 80 et cy <= 580 alors
tv est un nombre
ov est un nombre
tv vaut terr[gy][gx]
ov vaut objt[gy][gx]
// --- Le terrain ---
si tv = 1 alors
// L'eau est légèrement en creux
appelle dessinerSol(graph, cx, cy + (5 * ech), dx, dy, profSol, #1D4ED8, #1E3A8A, #172554)
ellipse(graph, cx - (6 * ech), cy + (2 * ech), 6 * ech, 2 * ech, rgba(191, 219, 254, 0.5))
sinon si tv = 2 alors
appelle dessinerSol(graph, cx, cy, dx, dy, profSol, #B08968, #8C6B4F, #6B5039)
sinon si tv = 3 alors
appelle dessinerSol(graph, cx, cy, dx, dy, profSol, #6B7280, #4B5563, #374151)
sinon
appelle dessinerSol(graph, cx, cy, dx, dy, profSol, #3F8F52, #2F6E3E, #235430)
fin si
// --- Ce qui se dresse dessus ---
si ov = 10 alors
appelle dessinerMonstre(graph, cx, cy, ech, mobTyp[gy][gx])
sinon si ov = 7 alors
appelle dessinerPerso(graph, cx, cy, ech, #DC2626, #7F1D1D, #E2E8F0)
sinon si ov = 8 alors
appelle dessinerPerso(graph, cx, cy, ech, #16A34A, #14532D, #78350F)
sinon si ov = 9 alors
appelle dessinerPerso(graph, cx, cy, ech, #94A3B8, #475569, #1F2937)
sinon si ov > 0 alors
appelle dessinerDecor(graph, cx, cy, ov, dx, dy, ech)
fin si
fin si
fin si
fin pour
fin pour
// Le héros est peint en dernier : rien ne peut le masquer
appelle dessinerPerso(graph, 320, 250, ech, #38BDF8, #1E3A8A, #EA580C)
appelle dessinerHud(graph, niv, pv, pvMax, mana, manaMax, xp, xpSuiv, pieces, potions, epee, armure, quete, message)
affiche graph
appuyer ["z", "s", "q", "d", "e", "t", "+", "-"] dans action
sX est un nombre
sY est un nombre
sX vaut 0
sY vaut 0
bouge est un booléen
bouge vaut faux
si action = 1 alors
sY vaut 0 - 1
bouge vaut vrai
sinon si action = 2 alors
sY vaut 1
bouge vaut vrai
sinon si action = 3 alors
sX vaut 0 - 1
bouge vaut vrai
sinon si action = 4 alors
sX vaut 1
bouge vaut vrai
sinon si action = 5 alors
si potions > 0 et pv < pvMax alors
potions vaut potions - 1
soin est un nombre
soin vaut 30 + niv * 4
pv vaut limiter(pv + soin, 0, pvMax)
message vaut "Potion bue : + " + soin + " PV"
sinon si potions <= 0 alors
message vaut "Tu n'as plus aucune potion"
sinon
message vaut "Tu es déjà en pleine forme"
fin si
sinon si action = 6 alors
orientation vaut orientation + 1
si orientation > 3 alors
orientation vaut 0
fin si
sinon si action = 7 alors
zoom vaut limiter(zoom + 20, 60, 180)
sinon si action = 8 alors
zoom vaut limiter(zoom - 20, 60, 180)
fin si
si bouge = vrai alors
// La même rotation que pour l'affichage
mX est un nombre
mY est un nombre
si orientation = 0 alors
mX vaut sX
mY vaut sY
sinon si orientation = 1 alors
mX vaut 0 - sY
mY vaut sX
sinon si orientation = 2 alors
mX vaut 0 - sX
mY vaut 0 - sY
sinon
mX vaut sY
mY vaut 0 - sX
fin si
nX est un nombre
nY est un nombre
nX vaut jX + mX
nY vaut jY + mY
si nX < 0 ou nX > COTE ou nY < 0 ou nY > COTE alors
message vaut "Les terres s'arrêtent ici"
sinon
tCible est un nombre
oCible est un nombre
tCible vaut terr[nY][nX]
oCible vaut objt[nY][nX]
si tCible = 1 alors
message vaut "Le lac est trop profond pour toi"
sinon si oCible = 1 alors
message vaut "Un arbre te barre la route"
sinon si oCible = 2 alors
message vaut "Un rocher infranchissable"
sinon si oCible = 3 alors
message vaut "Une maison aux volets clos"
sinon si oCible = 6 alors
message vaut "Panneau : « Nord = la falaise. N'y va pas seul. »"
sinon si oCible = 12 alors
pv vaut pvMax
mana vaut manaMax
message vaut "Tu te reposes près du feu : PV et MP au maximum"
sinon si oCible = 5 alors
objt[nY][nX] vaut 0
gain est un nombre
gain vaut hasard(20, 45)
pieces ajoute gain
potions ajoute 1
message vaut "Coffre ouvert : " + gain + " or et une potion !"
sinon si oCible = 7 alors
// Le chef du village
dlgNom vaut "Maélis, doyenne du village"
si ombreVaincue = vrai alors
ecran vaut "fin"
sinon si quete = 0 alors
quete vaut 1
dlgL1 vaut "Une Ombre s'est réveillée au nord, dans la falaise."
dlgL2 vaut "Nos récoltes noircissent. Va la combattre,"
dlgL3 vaut "mais entraîne-toi d'abord dans la forêt."
ecran vaut "dialogue"
sinon
dlgL1 vaut "L'Ombre rôde toujours au nord de la falaise."
dlgL2 vaut "Chasse les monstres pour gagner des niveaux,"
dlgL3 vaut "et vois Borin pour ton équipement."
ecran vaut "dialogue"
fin si
sinon si oCible = 8 alors
ecran vaut "boutique"
sinon si oCible = 9 alors
si quete = 0 alors
dlgNom vaut "Garde du chemin"
dlgL1 vaut "Halte. Personne ne monte vers la falaise"
dlgL2 vaut "sans l'accord de la doyenne Maélis."
dlgL3 vaut "Va lui parler, elle est sur la place."
ecran vaut "dialogue"
sinon
objt[nY][nX] vaut 0
dlgNom vaut "Garde du chemin"
dlgL1 vaut "La doyenne t'a donc choisi. Passe."
dlgL2 vaut "Le chemin monte vers le nord, puis tourne."
dlgL3 vaut "Que la lumière t'accompagne, héros."
ecran vaut "dialogue"
fin si
sinon si oCible = 10 alors
// Un combat commence
mTyp vaut mobTyp[nY][nX]
mNiv vaut mobNiv[nY][nX]
mLig vaut nY
mCol vaut nX
si mTyp = 1 alors
mNom vaut "Gluant des bois"
sinon si mTyp = 2 alors
mNom vaut "Loup gris"
sinon si mTyp = 3 alors
mNom vaut "Squelette errant"
sinon
mNom vaut "L'OMBRE"
fin si
si mTyp = 4 alors
mPvMax vaut 170
mAtt vaut 24
mDef vaut 7
sinon
mPvMax vaut 16 + mNiv * 9
mAtt vaut 5 + mNiv * 3
mDef vaut mNiv
fin si
mPv vaut mPvMax
cbMsg1 vaut mNom + " surgit devant toi !"
cbMsg2 vaut ""
ecran vaut "combat"
sinon
jX vaut nX
jY vaut nY
si oCible = 11 alors
message vaut "Tu traverses un tapis de fleurs"
sinon si tCible = 2 alors
message vaut "Tu suis le chemin"
sinon si tCible = 3 alors
message vaut "La roche crisse sous tes pas"
sinon
message vaut "Tu avances dans les herbes hautes"
fin si
fin si
fin si
fin si
// ==================================================
// LE COMBAT
// ==================================================
sinon si ecran = "combat" alors
appelle dessinerCombat(graph, mNom, mNiv, mPv, mPvMax, mTyp, pv, pvMax, mana, manaMax, potions, cbMsg1, cbMsg2)
appuyer ["a", "m", "p", "f"] dans action
riposte est un booléen
riposte vaut vrai
fuite est un booléen
fuite vaut faux
si action = 1 alors
// Attaquer
dg est un nombre
dg vaut attaque + epee * 4 + hasard(0, 5) - mDef
dg vaut limiter(dg, 1, 999)
mPv vaut mPv - dg
cbMsg1 vaut "Tu frappes : - " + dg + " PV pour " + mNom
sinon si action = 2 alors
// Magie
si mana >= 6 alors
mana vaut mana - 6
dg vaut 9 + niv * 4 + hasard(0, 7)
mPv vaut mPv - dg
cbMsg1 vaut "Éclair de lumière : - " + dg + " PV (la défense ne protège pas)"
sinon
cbMsg1 vaut "Pas assez de mana pour lancer le sort"
fin si
sinon si action = 3 alors
// Potion
si potions > 0 alors
potions vaut potions - 1
soin vaut 30 + niv * 4
pv vaut limiter(pv + soin, 0, pvMax)
cbMsg1 vaut "Tu bois une potion : + " + soin + " PV"
sinon
cbMsg1 vaut "Tes poches sont vides"
fin si
sinon
// Fuir
si mTyp = 4 alors
cbMsg1 vaut "Impossible de fuir l'Ombre !"
sinon si hasard(1, 100) <= 60 alors
fuite vaut vrai
riposte vaut faux
sinon
cbMsg1 vaut "Ta fuite échoue !"
fin si
fin si
si fuite = vrai alors
ecran vaut "monde"
message vaut "Tu prends la fuite, le souffle court"
sinon si mPv <= 0 alors
// Victoire
objt[mLig][mCol] vaut 0
gainXp est un nombre
gainOr est un nombre
gainXp vaut 12 + mNiv * 9
gainOr vaut 8 + mNiv * 6
si mTyp = 4 alors
gainXp vaut 200
gainOr vaut 300
ombreVaincue vaut vrai
quete vaut 2
fin si
xp ajoute gainXp
pieces ajoute gainOr
// Montées de niveau
tant que xp >= xpSuiv
xp vaut xp - xpSuiv
niv ajoute 1
pvMax ajoute 12
manaMax ajoute 5
attaque ajoute 2
defense ajoute 1
xpSuiv vaut 30 + niv * 20
pv vaut pvMax
mana vaut manaMax
fin tant que
// Un nouveau monstre apparaît ailleurs dans la forêt
si mTyp <> 4 alors
essR est un nombre
essR vaut 0
placeOk est un booléen
placeOk vaut faux
tant que placeOk = faux et essR < 200
essR ajoute 1
ri est un nombre
rj est un nombre
ri vaut hasard(5, 13)
rj vaut hasard(0, COTE)
si terr[ri][rj] = 0 et objt[ri][rj] = 0 alors
objt[ri][rj] vaut 10
nvN est un nombre
nvN vaut hasard(1, 4)
mobNiv[ri][rj] vaut nvN
si nvN <= 2 alors
mobTyp[ri][rj] vaut 1
sinon si nvN <= 4 alors
mobTyp[ri][rj] vaut 2
sinon
mobTyp[ri][rj] vaut 3
fin si
placeOk vaut vrai
fin si
fin tant que
fin si
ecran vaut "monde"
si mTyp = 4 alors
message vaut "L'OMBRE EST VAINCUE ! Retourne voir la doyenne Maélis"
sinon
message vaut mNom + " vaincu : + " + gainXp + " XP, + " + gainOr + " or"
fin si
sinon si riposte = vrai alors
// Le monstre riposte
dgM est un nombre
dgM vaut mAtt + hasard(0, 4) - (defense + armure * 3)
dgM vaut limiter(dgM, 1, 999)
pv vaut pv - dgM
cbMsg2 vaut mNom + " riposte : - " + dgM + " PV"
si pv <= 0 alors
// Défaite : on se réveille au village, allégé de la moitié de sa bourse
pv vaut arrondi(pvMax / 2)
mana vaut manaMax
perte est un nombre
perte vaut arrondi(pieces / 2)
pieces vaut pieces - perte
jX vaut 5
jY vaut 17
ecran vaut "monde"
message vaut "Tu t'effondres... On te ramène au village. Perdu : " + perte + " or"
fin si
fin si
// ==================================================
// LE DIALOGUE
// ==================================================
sinon si ecran = "dialogue" alors
appelle dessinerDialogue(graph, dlgNom, dlgL1, dlgL2, dlgL3)
appuyer ["e"] dans action
ecran vaut "monde"
message vaut "Tu reprends ta route"
// ==================================================
// LA BOUTIQUE
// ==================================================
sinon si ecran = "boutique" alors
appelle dessinerBoutique(graph, pieces, potions, epee, armure)
appuyer ["p", "a", "r", "q"] dans action
si action = 1 alors
si pieces >= 20 alors
pieces vaut pieces - 20
potions ajoute 1
message vaut "Potion achetée"
sinon
message vaut "Pas assez d'or pour une potion"
fin si
sinon si action = 2 alors
coutE est un nombre
coutE vaut 60 + epee * 50
si epee >= 3 alors
message vaut "Borin : « Ton épée est déjà parfaite. »"
sinon si pieces >= coutE alors
pieces vaut pieces - coutE
epee ajoute 1
message vaut "Épée affûtée : + " + epee
sinon
message vaut "Il te manque " + (coutE - pieces) + " or"
fin si
sinon si action = 3 alors
coutA est un nombre
coutA vaut 55 + armure * 50
si armure >= 3 alors
message vaut "Borin : « Cette armure ne peut plus être renforcée. »"
sinon si pieces >= coutA alors
pieces vaut pieces - coutA
armure ajoute 1
message vaut "Armure renforcée : + " + armure
sinon
message vaut "Il te manque " + (coutA - pieces) + " or"
fin si
sinon
ecran vaut "monde"
message vaut "Borin : « Reviens quand tu veux, héros. »"
fin si
// ==================================================
// LA VICTOIRE
// ==================================================
sinon
appelle dessinerFin(graph, niv, pieces)
appuyer ["e"] dans action
fin si
fin tant que





