Add pawn promotion

This commit is contained in:
jheaps
2025-03-28 10:41:29 -06:00
parent 9f6327f5d9
commit ed35a2e86f
4 changed files with 124 additions and 5 deletions
+18
View File
@@ -26,6 +26,24 @@
</div> </div>
</div> </div>
<div id="promotionModal" style="display: none;">
<p>Promote your pawn to:</p>
<div id="promotionBtnContainer">
<button onclick="selectPromotion(4)">
<img src="/images/Chess Images/WhiteQueen.svg" alt="Queen" />
</button>
<button onclick="selectPromotion(1)">
<img src="/images/Chess Images/WhiteRook.svg" alt="Rook" />
</button>
<button onclick="selectPromotion(3)">
<img src="/images/Chess Images/WhiteBishop.svg" alt="Bishop" />
</button>
<button onclick="selectPromotion(2)">
<img src="/images/Chess Images/WhiteKnight.svg" alt="Knight" />
</button>
</div>
</div>
@section Scripts { @section Scripts {
<script src="~/js/signalr/signalr.min.js"></script> <script src="~/js/signalr/signalr.min.js"></script>
<script src="~/js/ChessScripts/chessLogic.js"></script> <script src="~/js/ChessScripts/chessLogic.js"></script>
+1 -1
View File
@@ -1,6 +1,6 @@
@{ @{
Layout = null; Layout = null;
ViewData["cssVersion"] = "1.0.1"; // <--- change this once to bust cache ViewData["cssVersion"] = "1.0.2"; // <--- change this once to bust cache
} }
<!DOCTYPE html> <!DOCTYPE html>
+58 -3
View File
@@ -33,10 +33,16 @@
box-sizing: border-box; box-sizing: border-box;
} }
.chessSquare.legal { .legalOverlay {
border: 4px dashed red; position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none; /* Let clicks go through */
box-sizing: border-box; box-sizing: border-box;
cursor: pointer; border: 4px dashed red;
z-index: 10;
} }
#chessBoard.flipped { #chessBoard.flipped {
@@ -46,9 +52,58 @@
.chessSquare.previous-start { .chessSquare.previous-start {
box-sizing: border-box; box-sizing: border-box;
border: 4px solid #ffd700; /* gold or whatever you like */ border: 4px solid #ffd700; /* gold or whatever you like */
z-index: 1;
} }
.chessSquare.previous-end { .chessSquare.previous-end {
box-sizing: border-box; box-sizing: border-box;
border: 4px solid #ff8c00; /* orange */ border: 4px solid #ff8c00; /* orange */
z-index: 1;
}
#promotionModal {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background-color: #1e1e1e;
padding: 20px;
border-radius: 10px;
box-shadow: 0 0 20px rgba(0,0,0,0.6);
color: white;
z-index: 1000;
text-align: center;
}
#promotionModal p {
margin-bottom: 15px;
font-size: 18px;
font-weight: bold;
}
#promotionBtnContainer {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 10px;
justify-content: center;
}
#promotionBtnContainer button {
background-color: #2c2c2c;
border: none;
padding: 10px;
border-radius: 8px;
cursor: pointer;
transition: transform 0.2s ease;
}
#promotionBtnContainer button:hover {
transform: scale(1.1);
background-color: #3a3a3a;
}
#promotionBtnContainer img {
width: 50px;
height: 50px;
pointer-events: none; /* ensures img doesn't steal the click */
} }
@@ -137,6 +137,10 @@ function highlightLegalMoves(moves) {
const img = square.querySelector("img"); const img = square.querySelector("img");
if (img) img.onclick = null; if (img) img.onclick = null;
let overlay = document.createElement("div");
overlay.className = "legalOverlay";
square.appendChild(overlay);
// Let the square itself handle the move // Let the square itself handle the move
square.onclick = () => handleMove(r, c); square.onclick = () => handleMove(r, c);
}); });
@@ -145,6 +149,18 @@ function highlightLegalMoves(moves) {
async function handleMove(targetRow, targetCol) { async function handleMove(targetRow, targetCol) {
if (!selectedPiece) return; if (!selectedPiece) return;
const isPawn = selectedPiece.type === 0; // Assuming 0 = pawn
const reachedEnd = (Number(selectedPiece.color) === 0 && Number(targetRow) === 0) ||
(Number(selectedPiece.color) === 1 && Number(targetRow) === 0);
let choice = null;
if (isPawn && reachedEnd) {
// Show promotion UI
choice = await promptPromotion(); // function youll define
if (!choice) return; // user cancelled?
}
[targetRow, targetCol] = flipCoordinates(targetRow, targetCol); [targetRow, targetCol] = flipCoordinates(targetRow, targetCol);
const moveDto = { const moveDto = {
@@ -155,7 +171,7 @@ async function handleMove(targetRow, targetCol) {
SourceCol: selectedPiece.col, SourceCol: selectedPiece.col,
TargetRow: targetRow, TargetRow: targetRow,
TargetCol: targetCol, TargetCol: targetCol,
PromotionChoice: null // optional PromotionChoice: choice
}; };
previousMoveStart = [selectedPiece.row, selectedPiece.col]; previousMoveStart = [selectedPiece.row, selectedPiece.col];
@@ -190,6 +206,10 @@ function clearHighlights() {
for (let i = 0; i < 64; i++) { for (let i = 0; i < 64; i++) {
const square = document.getElementById(`square-${i}`); const square = document.getElementById(`square-${i}`);
// Remove legal overlays
const overlay = square.querySelector(".legalOverlay");
if (overlay) square.removeChild(overlay);
// Remove legal move markers and their onclicks // Remove legal move markers and their onclicks
if (square.classList.contains("legal")) { if (square.classList.contains("legal")) {
square.classList.remove("legal"); square.classList.remove("legal");
@@ -273,6 +293,32 @@ async function setupSignalRConnection() {
} }
} }
function promptPromotion() {
return new Promise(resolve => {
let color = 1;
if (currentPlayerIsWhite)
color = 0;
updatePromotionModalImages(color);
document.getElementById("promotionModal").style.display = "block";
window.selectPromotion = (piece) => {
document.getElementById("promotionModal").style.display = "none";
resolve(piece);
};
});
}
function updatePromotionModalImages(color) {
const pieceNames = ["Queen", "Rook", "Bishop", "Knight"];
const buttons = document.querySelectorAll("#promotionModal button img");
buttons.forEach((img, index) => {
img.src = `/images/Chess Images/${color === 0 ? "White" : "Black"}${pieceNames[index]}.svg`;
});
}
console.log("chessLogic.js loaded"); console.log("chessLogic.js loaded");
window.startNewGame = startNewGame; window.startNewGame = startNewGame;