pjo website


const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');

// 1. Game State Setup
const player = {
    x: 400,
    y: 350,
    radius: 12,
    speed: 4,
    color: '#e67e22', // Camp Half-Blood Orange
    currentZone: 'The Main Green'
};

// Fast Travel Portal Infrastructure
const portals = [
    { name: "Big House Portal", x: 160, y: 440, targetX: 620, targetY: 170, radius: 20 },
    { name: "Half-Blood Hill Portal", x: 620, y: 140, targetX: 160, targetY: 410, radius: 20 }
];

let travelCooldown = 0;
const keys = { w: false, a: false, s: false, d: false };

// Input Event Hooks
window.addEventListener('keydown', (e) => {
    const k = e.key.toLowerCase();
    if (['w', 'a', 's', 'd'].includes(k)) keys[k] = true;
});
window.addEventListener('keyup', (e) => {
    const k = e.key.toLowerCase();
    if (['w', 'a', 's', 'd'].includes(k)) keys[k] = false;
});

function getDistance(x1, y1, x2, y2) {
    return Math.hypot(x2 - x1, y2 - y1);
}

// 2. Logic & Core Math Updates
function update() {
    // Player Movement
    if (keys.w && player.y - player.radius > 0) player.y -= player.speed;
    if (keys.s && player.y + player.radius < canvas.height) player.y += player.speed;
    if (keys.a && player.x - player.radius > 0) player.x -= player.speed;
    if (keys.d && player.x + player.radius < canvas.width) player.x += player.speed;

    // Track active zone coordinates to update HUD text
    updateZoneLabel();

    // Portal Collision & Fast Travel Teleport Loop
    if (travelCooldown > 0) {
        travelCooldown--;
    } else {
        portals.forEach(portal => {
            if (getDistance(player.x, player.y, portal.x, portal.y) < player.radius + portal.radius) {
                player.x = portal.targetX;
                player.y = portal.targetY;
                travelCooldown = 90; // 1.5 seconds cooldown to prevent infinite looping
            }
        });
    }
}

function updateZoneLabel() {
    if (player.y < 120) {
        player.currentZone = "Long Island Sound (Beach)";
    } else if (player.x > 550 && player.y < 250) {
        player.currentZone = "Half-Blood Hill (Thalia's Pine)";
    } else if (player.x < 250 && player.y > 350) {
        player.currentZone = "The Big House Grounds";
    } else if (player.x > 300 && player.x < 500 && player.y > 220 && player.y < 420) {
        player.currentZone = "The Cabin Green (U-Shape Layout)";
    } else if (player.x > 520 && player.y > 400) {
        player.currentZone = "The Fireworks Amphitheater";
    } else if (player.x < 250 && player.y < 250) {
        player.currentZone = "Strawberry Fields";
    } else {
        player.currentZone = "Camp Wilderness Woods";
    }
}

// 3. Render Pipeline (Drawing the Actual Camp Map Graphics)
function drawMap() {
    // Basic Grass Floor Base
    ctx.fillStyle = '#27ae60';
    ctx.fillRect(0, 0, canvas.width, canvas.height);

    // North Coast: Long Island Sound (Ocean Water)
    ctx.fillStyle = '#2980b9';
    ctx.fillRect(0, 0, canvas.width, 100);
    // Sandy Beach shoreline
    ctx.fillStyle = '#f1c40f';
    ctx.fillRect(0, 100, canvas.width, 15);

    // Northwest Quadrant: Strawberry Fields (Rows of Crops)
    ctx.fillStyle = '#1e824c';
    for (let i = 30; i < 220; i += 30) {
        ctx.fillRect(i, 150, 15, 120);
        // Small red berries
        ctx.fillStyle = '#e74c3c';
        for(let j = 160; j < 270; j += 20) ctx.fillRect(i + 6, j, 4, 4);
        ctx.fillStyle = '#1e824c';
    }

    // Southwest: The Big House (Blue Building Structure Layout)
    ctx.fillStyle = '#3498db';
    ctx.fillRect(80, 400, 120, 90);
    ctx.fillStyle = '#2980b9'; // Porch roof extension wrap
    ctx.fillRect(70, 480, 140, 15);
    ctx.fillStyle = '#ffffff';
    ctx.font = '11px Arial';
    ctx.fillText("Big House", 140, 450);

    // Southeast: Outdoor Amphitheater semicircles
    ctx.strokeStyle = '#d35400';
    ctx.lineWidth = 4;
    for (let r = 20; r <= 60; r += 15) {
        ctx.beginPath();
        ctx.arc(660, 500, r, Math.PI, 0);
        ctx.stroke();
    }
    ctx.fillStyle = '#e67e22'; // Central campfire hearth point
    ctx.beginPath(); ctx.arc(660, 500, 8, 0, Math.PI*2); ctx.fill();

    // Center: The Divine Cabins (Arranged in a U-Shape opening North)
    ctx.fillStyle = '#7f8c8d';
    // Left Wing Cabins (Zeus, Poseidon, Ares, etc.)
    for (let y = 240; y <= 390; y += 35) {
        ctx.fillRect(320, y, 35, 22);
        ctx.fillRect(445, y, 35, 22); // Right Wing (Hera, Athena, Apollo...)
    }
    // Bottom Base Cabins (Hermes, Dionysus)
    ctx.fillRect(362, 400, 35, 22);
    ctx.fillRect(403, 400, 35, 22);

    // Northeast Corner: Half-Blood Hill & Thalia's Pine Tree
    ctx.fillStyle = '#5ebd74'; // Shaded elevation ground curve rings
    ctx.beginPath(); ctx.arc(700, 120, 90, 0, Math.PI * 2); ctx.fill();
    ctx.beginPath(); ctx.arc(720, 100, 50, 0, Math.PI * 2); ctx.fill();
    // Tree Trunk
    ctx.fillStyle = '#795548';
    ctx.fillRect(710, 80, 10, 30);
    // Pine Foliage Triangles
    ctx.fillStyle = '#0e4d22';
    ctx.beginPath(); ctx.moveTo(715, 30); ctx.lineTo(690, 70); ctx.lineTo(740, 70); ctx.closePath(); ctx.fill();
    ctx.beginPath(); ctx.moveTo(715, 45); ctx.lineTo(685, 90); ctx.lineTo(745, 90); ctx.closePath(); ctx.fill();

    // Render Fast Travel Matrices / Shiny Rings
    portals.forEach(portal => {
        let pulse = 2 * Math.sin(Date.now() / 150);
        ctx.strokeStyle = '#00ffff';
        ctx.lineWidth = 3;
        ctx.beginPath();
        ctx.arc(portal.x, portal.y, portal.radius + pulse, 0, Math.PI * 2);
        ctx.stroke();
        
        ctx.fillStyle = 'rgba(0, 255, 255, 0.2)';
        ctx.beginPath();
        ctx.arc(portal.x, portal.y, portal.radius - 2, 0, Math.PI * 2);
        ctx.fill();
    });
}

function drawHUD() {
    // Dynamic overlay stats box card frame
    ctx.fillStyle = 'rgba(26, 15, 6, 0.85)';
    ctx.fillRect(15, 15, 310, 75);
    ctx.strokeStyle = '#d4af37';
    ctx.lineWidth = 2;
    ctx.strokeRect(15, 15, 310, 75);

    ctx.fillStyle = '#f1c40f';
    ctx.font = 'bold 13px Georgia';
    ctx.textAlign = 'left';
    ctx.fillText(`📍 Current Location:`, 28, 38);
    ctx.fillStyle = '#ffffff';
    ctx.font = '13px Arial';
    ctx.fillText(player.currentZone, 160, 38);

    ctx.font = '12px Georgia';
    if (travelCooldown > 0) {
        ctx.fillStyle = '#e74c3c';
        ctx.fillText(`✨ Teleport Matrix Re-aligning: ${Math.ceil(travelCooldown/60)}s`, 28, 65);
    } else {
        ctx.fillStyle = '#2ecc71';
        ctx.fillText(`✨ Fast Travel Matrices: READY TO BEAM`, 28, 65);
    }
}

// 4. Main Executive Loop Frame
function mainLoop() {
    update();
    drawMap();
    
    // Draw Player Demigod Token
    ctx.fillStyle = player.color;
    ctx.beginPath();
    ctx.arc(player.x, player.y, player.radius, 0, Math.PI * 2);
    ctx.fill();
    ctx.strokeStyle = '#ffffff';
    ctx.lineWidth = 2;
    ctx.stroke();

    drawHUD();
    requestAnimationFrame(mainLoop);
}

mainLoop();
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Camp Half-Blood: Conversations</title>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <div id="app-wrapper">
        
        <!-- Left Sidebar: Character Affinities & Profiles -->
        <div id="stats-sidebar">
            <h3 class="sidebar-title">Demigod Bonds</h3>
            <div class="stat-card">
                <div class="stat-header">
                    <span>Percy Jackson</span>
                    <span id="affinity-percy">0 XP</span>
                </div>
                <div class="progress-bar"><div id="bar-percy" class="progress-fill"></div></div>
            </div>
            <div class="stat-card">
                <div class="stat-header">
                    <span>Annabeth Chase</span>
                    <span id="affinity-annabeth">0 XP</span>
                </div>
                <div class="progress-bar"><div id="bar-annabeth" class="progress-fill"></div></div>
            </div>
            <div class="stat-card">
                <div class="stat-header">
                    <span>Clarisse La Rue</span>
                    <span id="affinity-clarisse">0 XP</span>
                </div>
                <div class="progress-bar"><div id="bar-clarisse" class="progress-fill"></div></div>
            </div>
            <div class="stat-card">
                <div class="stat-header">
                    <span>Nico di Angelo</span>
                    <span id="affinity-nico">0 XP</span>
                </div>
                <div class="progress-bar"><div id="bar-nico" class="progress-fill"></div></div>
            </div>
            <!-- Added Grover's missing card -->
            <div class="stat-card">
                <div class="stat-header">
                    <span>Grover Underwood</span>
                    <span id="affinity-grover">0 XP</span>
                </div>
                <div class="progress-bar"><div id="bar-grover" class="progress-fill"></div></div>
            </div>
        </div>

        <!-- Right Main: Chat Interface Module Layout -->
        <div id="chat-container">
            <div class="tabs-row">
                <button id="tab-percy" class="tab-btn active" onclick="switchTab('percy')">Percy</button>
                <button id="tab-annabeth" class="tab-btn" onclick="switchTab('annabeth')">Annabeth</button>
                <button id="tab-clarisse" class="tab-btn" onclick="switchTab('clarisse')">Clarisse</button>
                <button id="tab-nico" class="tab-btn" onclick="switchTab('nico')">Nico</button>
                <button id="tab-grover" class="tab-btn" onclick="switchTab('grover')">Grover</button>
            </div>

            <!-- Dynamic Dialogue Grid Context Frame Window View -->
            <div id="chat-display-area"></div>

            <!-- Interactive Typing Status Indicator Node -->
            <div id="typing-indicator"></div>

            <!-- Operational Form Control Entry Field Bar Row -->
            <div class="input-row">
                <input type="text" id="user-msg-input" placeholder="Type a message..." maxlength="80" autocomplete="off">
                <button id="send-msg-btn">Send</button>
            </div>
        </div>

    </div>
    <script src="app.js"></script>
</body>
</html>

this is the chat file im trying to get the errors so i could’nt make much changes

these are all the files in this simulator


Leave a Reply

Your email address will not be published. Required fields are marked *