anticipate next chapter and few rectification

This commit is contained in:
Didictateur 2025-03-30 15:29:08 +02:00
parent b1ddcc6c84
commit 8678f46816
7 changed files with 183 additions and 17 deletions

View file

@ -75,15 +75,17 @@
<a href="#" onclick="loadScript('dp2.js')">Chap 2: La main</a> <a href="#" onclick="loadScript('dp2.js')">Chap 2: La main</a>
<a href="#" onclick="loadScript('dp3.js')">Chap 3: Les groupes</a> <a href="#" onclick="loadScript('dp3.js')">Chap 3: Les groupes</a>
<a href="#" onclick="loadScript('dp4.js')">Chap 4: Avoir une main valide en jeu</a> <a href="#" onclick="loadScript('dp4.js')">Chap 4: Avoir une main valide en jeu</a>
<a href="#" onclick="loadScript('dp5.js')">Chap 5: Le vent du joueur</a> <a href="#" onclick="loadScript('dp5.js')">Chap 5: Annoncer la victoire</a>
<a href="#" onclick="loadScript('dp6.js')">Chap 6: Les yakus</a> <a href="#" onclick="loadScript('dp6.js')">Chap 6: Le furiten</a>
<a href="#" onclick="loadScript('dp7.js')">Chap 7: Le riichi</a> <a href="#" onclick="loadScript('dp7.js')">Chap 7: Le vent du joueur</a>
<a href="#" onclick="loadScript('dp8.js')">Chap 8: Première partie complète</a> <a href="#" onclick="loadScript('dp8.js')">Chap 8: Les yakus</a>
<a href="#" onclick="loadScript('dp9.js')">Chap 9: Score: les Hans</a> <a href="#" onclick="loadScript('dp9.js')">Chap 9: Le riichi</a>
<a href="#" onclick="loadScript('dp10.js')">Chap 10: Score: les doras</a> <a href="#" onclick="loadScript('dp10.js')">Chap 10: Première partie complète</a>
<a href="#" onclick="loadScript('dp11.js')">Chap 11: Score: les Fus</a> <a href="#" onclick="loadScript('dp11.js')">Chap 11: Score: les Hans</a>
<a href="#" onclick="loadScript('dp12.js')">Chap 12: Score: le calcul des points</a> <a href="#" onclick="loadScript('dp12.js')">Chap 12: Score: les doras</a>
<a href="#" onclick="loadScript('dp13.js')">Chap 13: Partie avec les scores</a> <a href="#" onclick="loadScript('dp13.js')">Chap 13: Score: les Fus</a>
<a href="#" onclick="loadScript('dp14.js')">Chap 14: Score: le calcul des points</a>
<a href="#" onclick="loadScript('dp15.js')">Chap 15: Partie avec les scores</a>
</div> </div>
</ul> </ul>
<ul class="menu-item"> <ul class="menu-item">
@ -158,7 +160,7 @@
} }
//script initial //script initial
loadScript('dp4.js'); loadScript('dp5.js');
</script> </script>
</body> </body>
</html> </html>

102
src/display/dp5.ts Normal file
View file

@ -0,0 +1,102 @@
import { Deck } from "../deck";
import { Hand } from "../hand";
import { Game } from "../game"
// Configuration globale
const CANVAS_ID = "myCanvas";
const BG_RECT = { x: 0, y: 0, w: 1050, h: 1050 };
var MOUSE = { x: 0, y: 0 };
const FPS = 30;
const FRAME_INTERVAL = 1000 / FPS;
// variables globales
const DECKS: Array<Deck> = [];
const HANDS: Array<Hand> = [];
var GAME: Game|undefined;
// Optimisation des références
let animationFrameId: number;
let lastFrameTime = 0;
const callbacks: Array<() => void> = [];
// Pré-calcul des dimensions
const canvas = document.getElementById(CANVAS_ID) as HTMLCanvasElement;
const ctx = canvas.getContext("2d") as NonNullable<CanvasRenderingContext2D>;
canvas.width = BG_RECT.w;
canvas.height = BG_RECT.h;
// Cache statique
const staticCanvas = document.createElement('canvas') as HTMLCanvasElement;
const staticCtx = staticCanvas.getContext("2d") as NonNullable<CanvasRenderingContext2D>;
staticCanvas.width = canvas.width;
staticCanvas.height = canvas.height;
function drawFrame() {
if (!ctx) return;
GAME?.draw(MOUSE);
}
function animationLoop(currentTime: number) {
animationFrameId = requestAnimationFrame(animationLoop);
const deltaTime = currentTime - lastFrameTime;
if (deltaTime < FRAME_INTERVAL) return;
lastFrameTime = currentTime - (deltaTime % FRAME_INTERVAL);
drawFrame();
}
function initEventListeners() {
const handlers = {
mousedown: (e: MouseEvent) => {
GAME?.click(e);
},
mousemove: (e: MouseEvent) => {
MOUSE.x = e.x;
MOUSE.y = e.y;
}
};
callbacks.push(() => {
canvas.removeEventListener('mousemove', handlers.mousemove);
});
canvas.addEventListener('mousedown', handlers.mousedown);
}
async function preloadDeck(deck: Deck) {
await deck.preload();
}
async function preloadHand(hand: Hand) {
await hand.preload();
}
export function cleanup() {
cancelAnimationFrame(animationFrameId);
callbacks.forEach(fn => fn());
}
export async function initDisplay() {
if (!ctx) {
console.error("Context canvas indisponible");
return;
}
console.log("Load begining\n");
// Préchargement des ressources si nécessaire
// const deck = new Deck();
// await preloadDeck(deck);
}
// Déclaration globale pour TypeScript
declare global {
interface Window {
cleanup: () => void;
}
}
// Initialisation automatique si le script est chargé directement
if (typeof window !== 'undefined') {
initDisplay().catch(console.error);
}

View file

@ -18,6 +18,9 @@ export class Game {
// game values // game values
private level: number; private level: number;
private turn = 0; private turn = 0;
private minWaitingTime = 500;
private maxWaitingTime = 2000;
private waitingTime = 700;
private selectedTile: number|undefined = undefined; private selectedTile: number|undefined = undefined;
private canCall: boolean = false; private canCall: boolean = false;
private hasPicked: boolean = false; private hasPicked: boolean = false;
@ -139,6 +142,7 @@ export class Game {
} else { } else {
this.turn++; this.turn++;
} }
this.updateWaitingTime();
this.hasPicked = false; this.hasPicked = false;
this.hasPlayed = false; this.hasPlayed = false;
} else if (action === 1) { // chii } else if (action === 1) { // chii
@ -162,6 +166,7 @@ export class Game {
let i = Math.floor(Math.random() * chiis.length); let i = Math.floor(Math.random() * chiis.length);
this.chii(chiis[i], 1); this.chii(chiis[i], 1);
} else { } else {
this.updateWaitingTime();
this.turn = (this.turn + 1) % 4; this.turn = (this.turn + 1) % 4;
} }
} }
@ -196,6 +201,15 @@ export class Game {
} }
}; };
private updateWaitingTime(): void {
this.waitingTime =
Math.floor(
Math.random() *
(this.maxWaitingTime - this.minWaitingTime) +
this.minWaitingTime
);
}
private play(): void { private play(): void {
if ( if (
this.turn !== 0 && !this.end this.turn !== 0 && !this.end
@ -208,7 +222,7 @@ export class Game {
if (this.hasWin(this.turn)) { if (this.hasWin(this.turn)) {
this.end = true; this.end = true;
this.result = 2; this.result = 2;
} else if (Date.now() - this.lastPlayed > 700) { } else if (Date.now() - this.lastPlayed > this.waitingTime) {
this.lastPlayed = Date.now(); this.lastPlayed = Date.now();
let n = Math.floor(this.hands[this.turn].length() * Math.random()); let n = Math.floor(this.hands[this.turn].length() * Math.random());
this.discard(this.turn, n); this.discard(this.turn, n);
@ -238,6 +252,7 @@ export class Game {
} else { } else {
this.turn++; this.turn++;
} }
this.updateWaitingTime();
this.hasPicked = false; this.hasPicked = false;
this.hasPlayed = false; this.hasPlayed = false;
} }
@ -314,7 +329,7 @@ export class Game {
this.end = true; this.end = true;
this.result = p === 0 ? 1 : 2; this.result = p === 0 ? 1 : 2;
} }
this.updateWaitingTime();
this.turn = p; this.turn = p;
this.hasPicked = true; this.hasPicked = true;
this.hasPlayed = false; this.hasPlayed = false;
@ -381,7 +396,7 @@ export class Game {
this.end = true; this.end = true;
this.result = thief === 0 ? 1 : 2; this.result = thief === 0 ? 1 : 2;
} }
this.updateWaitingTime();
this.turn = thief; this.turn = thief;
this.hasPicked = true; this.hasPicked = true;
this.hasPlayed = false; this.hasPlayed = false;

View file

@ -3,7 +3,11 @@ Bienvenu sur ce site dédié au *Mahjong* !
Ce site est principalement destiné aux personnes découvrant ce Ce site est principalement destiné aux personnes découvrant ce
formidable jeu. formidable jeu.
De nombreux services sont proposés: Le nombre de chapitre de chaque section peut faire peur aux
premiers abords, mais chacun deux n'est pas plus long que ce
même texte
Cependant, de nombreux services y sont proposés:
- *Introduction riichi majhong* dans l'onglet #ff00ff{Riichi Mahjong} - *Introduction riichi majhong* dans l'onglet #ff00ff{Riichi Mahjong}
@ -19,8 +23,6 @@ De nombreux services sont proposés:
#ff00ff{MCR} #ff00ff{MCR}
Evidemment, ce site n'est pas encore fini, et possède encore Evidemment, ce site n'est pas encore fini, et possède encore
beaucoup de problème. Pour le moindre retour, ne pas hésiter beaucoup de problème. Pour le moindre retour, ne pas hésiter
à le faire savoir directement sur le Github pour pour aider à le faire savoir directement sur le Github pour pour aider

View file

@ -22,4 +22,4 @@ veut faire un *Pon*, alors le *Pon* a *toujours* la priorité
~Il est maintenant tant de choisir une tuile à défausser !~ ~Il est maintenant temps de choisir une tuile à défausser !~

18
src/text/txt5.ts Normal file
View file

@ -0,0 +1,18 @@
import { drawText } from "./parse"
const CANVAS_ID = "myTextCanvas";
const BG_RECT = { x: 0, y: 0, w: 800, h: 1050, color: "#007733" };
const canvas = document.getElementById(CANVAS_ID) as HTMLCanvasElement;
const ctx = canvas.getContext("2d") as NonNullable<CanvasRenderingContext2D>;
canvas.width = BG_RECT.w;
canvas.height = BG_RECT.h;
const path = "../src/text/";
ctx.fillStyle = BG_RECT.color;
ctx.fillRect(BG_RECT.x, BG_RECT.y, BG_RECT.w, BG_RECT.h);
drawText(path + "txt5.txt", ctx).catch(error => console.error(error));
export {};

27
src/text/txt5.txt Normal file
View file

@ -0,0 +1,27 @@
Nous avons appris jusque là que pour annoncer un *Chii*, il
fallait nécessairement que cela se fasse via le joueur précédent.
Il existe cependant une exception: *s'il ne nous manque plus
qu'une seule tuile*. Dans ce cas précis, nous disons que le
joueur est en #ff00ff{Tenpai} (il n'est pas obligé de retenir ce terme pour
jouer). À ce moment là, #ff0000{qui que ce soit} qui défausse une tuile,
un joueur en *Tenpai* peut la récupérer directement si elle lui
donne la victoire
Il y a alors deux situations possibles:
- Le joueur en *Tenpai* pioche une tuile qui le fait gagner. Il
l'annonce alors avec #ff00ff{Tsumo !}
- Le joueur en *Tenpai* gagne sur la défausse d'un autre joueur.
Il l'annonce alors avec #ff00ff{Ron !}
Par la suite, un nouveau bouton apparaitra pour permettre au
joueur d'annoncer sa victoire. Le plus important à retenir,
c'est que *Pon* et *Tsumo* signifie la victoire
~Dans l'exemple ci-contre, le joueur peut annoncer sa victoire
avec *Ron* sur la défausse du joueur d'en face en complétant
un *Chii*~