GC Shalane's Pyramids Game Helper and Keyboard Controls

Highlights playable cards, adds keyboard controls, displays a helper message for Grundo's Cafe Pyramids game, and handles game over conditions.

// ==UserScript==
// @name         GC Shalane's Pyramids Game Helper and Keyboard Controls
// @namespace    https://gf.qytechs.cn/en/users/1192105
// @version      1.0
// @description  Highlights playable cards, adds keyboard controls, displays a helper message for Grundo's Cafe Pyramids game, and handles game over conditions.
// @match        https://www.grundos.cafe/games/pyramids/
// @icon         https://www.google.com/s2/favicons?sz=64&domain=grundos.cafe
// @license      MIT
// ==/UserScript==

    // Add event listener for key presses
    document.addEventListener('keydown', function(event) {
        // If "Enter" or "Left Arrow" key is pressed
        if (event.key === "Enter" || event.key === "ArrowLeft") {
            // Simulate a click on the "Play Pyramids Again!" button
            document.querySelector("input[value='Play Pyramids Again!']").click();
        }
    });
    // Add event listener for key presses
    document.addEventListener('keydown', function(event) {
        // If "Enter" or "Left Arrow" key is pressed
        if (event.key === "Enter" || event.key === "ArrowLeft") {
            // Simulate a click on the "Play Pyramids!" button
            document.querySelector("input[value='Play Pyramids!']").click();
        }
    });

// Helper function to get the numerical value of a card based on its image source
function getCardValue(cardImgSrc) {
    const fileName = cardImgSrc.split('/').pop();
    const numMatch = fileName.match(/(\d+)_/);
    if (numMatch) {
        const num = parseInt(numMatch[1], 10);
        return num === 14 ? 14 : num; // Ace is 14
    }
    return null;
}

// Helper function to get the name of the card (e.g., "Queen of Spades") based on the card's image source
function getCardName(cardImgSrc) {
    const fileName = cardImgSrc.split('/').pop();
    const parts = fileName.split('_');
    const cardValue = parseInt(parts[0], 10);
    const suit = parts[1].replace('.gif', '').charAt(0).toUpperCase() + parts[1].replace('.gif', '').slice(1);

    // Patch for Neggs instead of Hearts
    const suitDisplay = (suit === "Hearts") ? "Neggs" : suit;

    let cardName;
    switch (cardValue) {
        case 11:
            cardName = `Jack of ${suitDisplay}`;
            break;
        case 12:
            cardName = `Queen of ${suitDisplay}`;
            break;
        case 13:
            cardName = `King of ${suitDisplay}`;
            break;
        case 14:
            cardName = `Ace of ${suitDisplay}`;
            break;
        default:
            cardName = `${cardValue} of ${suitDisplay}`;
            break;
    }

    return cardName;
}

// Function to check if a card is playable based on the top card's value
function isPlayable(cardValue, topCardValue) {
    if (cardValue === null || topCardValue === null) return false;

    // Allow wrapping between Ace (14) and 2
    if (topCardValue === 14 && cardValue === 2) return true;
    if (topCardValue === 2 && cardValue === 14) return true;

    // Check for difference of 1 (either direction)
    return Math.abs(cardValue - topCardValue) === 1;
}

// Check if a card is revealed (not hidden or blank)
function isRevealed(card) {
    const src = card.src;
    return !src.includes("pyramid.gif") && !src.includes("blank.gif"); // Revealed cards do not have "pyramid" or "blank"
}

// Function to display a helper message at the bottom of the screen
function displayHelperMessage(message) {
    let helperDiv = document.querySelector("#helperMessage");
    if (!helperDiv) {
        // Create the helper message div if it doesn't exist
        helperDiv = document.createElement("div");
        helperDiv.id = "helperMessage";
        helperDiv.style.cssText = "text-align: center; padding: 10px; border: 1px solid #ccc; background: #f8f8f8; margin: 10px auto; width: 80%; font-size: 16px;";
        const desertButton = document.querySelector("input[value='Return to The Lost Desert']");
        desertButton.parentNode.insertBefore(helperDiv, desertButton);
    }
    helperDiv.innerHTML = message;
}

// Function to handle the game state when the deck is empty
function handleGameOver() {
    const collectButton = document.querySelector("input[value='Collect Winnings']");
    if (collectButton) {
        collectButton.classList.add('highlight');
        collectButton.style.border = '5px solid red'; // Highlight with red for game over

        displayHelperMessage("Game is Over! ⬅️ Collect Winnings");

        // Add event listener for clicking "Collect Winnings"
        document.addEventListener("keydown", function collectWinningsListener(event) {
            if (event.key === "ArrowLeft") {
                collectButton.click(); // Simulate clicking the Collect Winnings button
                document.removeEventListener("keydown", collectWinningsListener); // Remove listener after clicking
            }
        });
    }
}

// Highlight playable cards and add keyboard controls
function highlightPlayableCards() {
    // Reset previous highlights
    document.querySelectorAll('.highlight').forEach(card => {
        card.classList.remove('highlight');
        card.style.border = '';
    });

    const topCard = document.querySelector("#pyramids_board .hand.face_up");
    const deckEmpty = document.querySelector("img[src='https://grundoscafe.b-cdn.net/desert/pyramids/empty.gif']");

    if (!topCard || topCard.src.includes("empty.gif")) {
        if (deckEmpty) {
            handleGameOver(); // Handle game over if no draws are left
        }
        return;
    }

    const topCardValue = getCardValue(topCard.src);

    const revealedCards = Array.from(document.querySelectorAll("#pyramids_board .rows img")).filter(card => {
        const cardValue = getCardValue(card.src);
        const playable = cardValue && isPlayable(cardValue, topCardValue);
        const revealed = isRevealed(card);
        return revealed && playable;
    });

    if (revealedCards.length === 0) {
        if (deckEmpty) {
            handleGameOver(); // Handle game over if deck is empty and no playable cards
        } else {
            const deck = document.querySelector("img[src='https://grundoscafe.b-cdn.net/games/php_games/sakhmetsolitaire/pyramid.gif']");
            deck.classList.add('highlight');
            deck.style.border = '5px solid red';

            displayHelperMessage("No playable cards. ⬅️ Reveal Card");

            document.addEventListener("keydown", function deckDrawListener(event) {
                if (event.key === "ArrowLeft" || event.key === "Enter") {
                    if (deck) deck.click(); // Check if deck is available before clicking
                    document.removeEventListener("keydown", deckDrawListener); // Remove listener after clicking
                }
            });
        }
    } else {
        // If there are playable cards, highlight and show helper message
        const arrowMap = ["⬅️", "⬆️", "➡️", "⬇️"];
        let message = `Playable cards:<br>`;

        revealedCards.forEach((card, index) => {
            card.classList.add('highlight');
            card.style.border = '5px solid yellow';

            const cardName = getCardName(card.src);
            message += `${cardName} ${arrowMap[index] || ""}<br>`; // Display correct arrow

            document.addEventListener("keydown", function arrowKeyListener(event) {
                const arrowKeys = ["ArrowLeft", "ArrowUp", "ArrowRight", "ArrowDown"];
                if (event.key === arrowKeys[index]) {  // Ensure correct key
                    if (card) {
                        card.click();  // Safeguard to check if card is present before clicking
                    } else {
                        console.warn("Card is missing or not available for interaction.");
                    }
                    document.removeEventListener("keydown", arrowKeyListener); // Remove listener after clicking
                }
            });
        });

        displayHelperMessage(message);
    }
}

// Run the highlight function initially and whenever the Enter key is pressed to draw a new card
document.addEventListener("keydown", (event) => {
    if (event.key === "Enter") {
        const deck = document.querySelector("img[src='https://grundoscafe.b-cdn.net/games/php_games/sakhmetsolitaire/pyramid.gif']");
        if (deck) {
            deck.click();
        }
        setTimeout(highlightPlayableCards, 500); // Wait a bit for the new card to load before highlighting
    }
});

highlightPlayableCards(); // Initial run

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址