XTaylorSpenceX

Tree Kingdom Battler

Sep 18th, 2025
90
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
HTML 47.90 KB | None | 0 0
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4.     <meta charset="UTF-8">
  5.     <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6.     <title>Tree Kingdom Battler</title>
  7.     <style>
  8.         * {
  9.             box-sizing: border-box;
  10.             margin: 0;
  11.             padding: 0;
  12.         }
  13.        
  14.         body {
  15.             margin: 0;
  16.             padding: 20px;
  17.             background: linear-gradient(to bottom, #1a2a6c, #b21f1f, #fdbb2d);
  18.             display: flex;
  19.             justify-content: center;
  20.             align-items: flex-start;
  21.             min-height: 100vh;
  22.             font-family: 'Courier New', monospace;
  23.             color: #fff;
  24.             overflow: auto;
  25.         }
  26.        
  27.         #game-wrapper {
  28.             display: flex;
  29.             flex-direction: column;
  30.             align-items: center;
  31.             background: rgba(0, 0, 0, 0.8);
  32.             padding: 20px;
  33.             border-radius: 10px;
  34.             box-shadow: 0 0 20px rgba(255, 215, 0, 0.5);
  35.             max-width: 1400px;
  36.             width: 100%;
  37.         }
  38.        
  39.         h1 {
  40.             color: #FFD700;
  41.             text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.8);
  42.             margin-bottom: 20px;
  43.             text-align: center;
  44.             font-size: 2em;
  45.         }
  46.        
  47.         #game-container {
  48.             position: relative;
  49.             display: flex;
  50.             flex-wrap: wrap;
  51.             justify-content: center;
  52.             gap: 20px;
  53.             width: 100%;
  54.         }
  55.        
  56.         #canvas-area {
  57.             position: relative;
  58.         }
  59.        
  60.         canvas {
  61.             border: 3px solid #FFD700;
  62.             background-color: #222;
  63.             border-radius: 5px;
  64.             image-rendering: pixelated;
  65.             image-rendering: -moz-crisp-edges;
  66.             image-rendering: crisp-edges;
  67.         }
  68.        
  69.         #ui-sidebar {
  70.             display: flex;
  71.             flex-direction: column;
  72.             gap: 20px;
  73.             min-width: 300px;
  74.             max-width: 400px;
  75.         }
  76.        
  77.         #hud {
  78.             background: rgba(0,0,0,0.8);
  79.             padding: 15px;
  80.             border-radius: 5px;
  81.             border: 1px solid #FFD700;
  82.             width: 100%;
  83.         }
  84.        
  85.         #log {
  86.             width: 100%;
  87.             height: 150px;
  88.             overflow-y: scroll;
  89.             background: rgba(0,0,0,0.8);
  90.             padding: 15px;
  91.             border-radius: 5px;
  92.             font-size: 12px;
  93.             border: 1px solid #FFD700;
  94.         }
  95.        
  96.         #log::-webkit-scrollbar {
  97.             width: 8px;
  98.         }
  99.        
  100.         #log::-webkit-scrollbar-thumb {
  101.             background: #FFD700;
  102.             border-radius: 4px;
  103.         }
  104.        
  105.         #inventory {
  106.             background: rgba(0,0,0,0.8);
  107.             padding: 15px;
  108.             border-radius: 5px;
  109.             border: 1px solid #FFD700;
  110.             width: 100%;
  111.         }
  112.        
  113.         #tree-map {
  114.             background: rgba(0,0,0,0.8);
  115.             padding: 15px;
  116.             border-radius: 5px;
  117.             font-size: 12px;
  118.             max-height: 300px;
  119.             overflow: auto;
  120.             border: 1px solid #FFD700;
  121.             width: 100%;
  122.         }
  123.        
  124.         #controls {
  125.             margin-top: 20px;
  126.             background: rgba(0,0,0,0.8);
  127.             padding: 15px;
  128.             border-radius: 5px;
  129.             text-align: center;
  130.             border: 1px solid #FFD700;
  131.             width: 100%;
  132.             max-width: 1000px;
  133.         }
  134.        
  135.         .health-bar {
  136.             display: inline-block;
  137.             width: 100px;
  138.             height: 10px;
  139.             background: #555;
  140.             border-radius: 5px;
  141.             overflow: hidden;
  142.             margin-left: 5px;
  143.         }
  144.        
  145.         .health-fill {
  146.             height: 100%;
  147.             background: linear-gradient(to right, #ff0000, #ff4500);
  148.             transition: width 0.3s ease;
  149.         }
  150.        
  151.         .neural-overlay {
  152.             position: absolute;
  153.             top: 0;
  154.             left: 0;
  155.             width: 100%;
  156.             height: 100%;
  157.             pointer-events: none;
  158.             background: repeating-linear-gradient(
  159.                 0deg,
  160.                 rgba(0, 255, 0, 0.1),
  161.                 rgba(0, 255, 0, 0.1) 1px,
  162.                 rgba(255, 255, 255, 0.05) 1px,
  163.                 rgba(255, 255, 255, 0.05) 2px
  164.             );
  165.             opacity: 0.6;
  166.             z-index: 10;
  167.             display: none;
  168.             animation: neural-flicker 2s infinite;
  169.         }
  170.        
  171.         @keyframes neural-flicker {
  172.             0%, 100% { opacity: 0.6; }
  173.             50% { opacity: 0.3; }
  174.         }
  175.        
  176.         .debug-button {
  177.             position: fixed;
  178.             bottom: 10px;
  179.             right: 10px;
  180.             padding: 8px 12px;
  181.             background: rgba(0,0,0,0.8);
  182.             color: white;
  183.             border: 1px solid #FFD700;
  184.             border-radius: 5px;
  185.             cursor: pointer;
  186.             z-index: 100;
  187.             font-family: 'Courier New', monospace;
  188.             font-size: 12px;
  189.         }
  190.        
  191.         .debug-button:hover {
  192.             background: rgba(255, 215, 0, 0.2);
  193.         }
  194.        
  195.         .completion-message {
  196.             position: absolute;
  197.             top: 50%;
  198.             left: 50%;
  199.             transform: translate(-50%, -50%);
  200.             background: rgba(0, 0, 0, 0.95);
  201.             padding: 30px;
  202.             border-radius: 15px;
  203.             border: 3px solid #FFD700;
  204.             text-align: center;
  205.             z-index: 20;
  206.             display: none;
  207.             box-shadow: 0 0 30px rgba(255, 215, 0, 0.8);
  208.         }
  209.        
  210.         .completion-message h2 {
  211.             color: #FFD700;
  212.             margin-bottom: 10px;
  213.         }
  214.        
  215.         /* Responsive design for mobile */
  216.         @media (max-width: 768px) {
  217.             body {
  218.                 padding: 10px;
  219.             }
  220.            
  221.             #game-container {
  222.                 flex-direction: column;
  223.             }
  224.            
  225.             canvas {
  226.                 width: 100%;
  227.                 height: auto;
  228.                 max-width: 500px;
  229.             }
  230.            
  231.             #ui-sidebar {
  232.                 min-width: auto;
  233.                 max-width: none;
  234.                 width: 100%;
  235.             }
  236.            
  237.             h1 {
  238.                 font-size: 1.5em;
  239.             }
  240.         }
  241.        
  242.         /* High DPI displays */
  243.         @media (min-width: 1920px) {
  244.             canvas {
  245.                 width: 800px;
  246.                 height: 800px;
  247.             }
  248.            
  249.             #game-wrapper {
  250.                 padding: 30px;
  251.             }
  252.            
  253.             #ui-sidebar {
  254.                 min-width: 350px;
  255.             }
  256.         }
  257.        
  258.         @media (min-width: 2560px) {
  259.             canvas {
  260.                 width: 900px;
  261.                 height: 900px;
  262.             }
  263.            
  264.             #game-wrapper {
  265.                 padding: 40px;
  266.             }
  267.            
  268.             #ui-sidebar {
  269.                 min-width: 400px;
  270.             }
  271.         }
  272.     </style>
  273. </head>
  274. <body>
  275.     <div id="game-wrapper">
  276.         <h1>๐ŸŒณ Tree Kingdom Battler โš”๏ธ</h1>
  277.         <div id="game-container">
  278.             <div id="canvas-area">
  279.                 <canvas id="gameCanvas"></canvas>
  280.                 <div class="neural-overlay" id="neuralOverlay"></div>
  281.                 <div class="completion-message" id="completionMessage">
  282.                     <h2>๐ŸŽ‰ Level Complete! ๐ŸŽ‰</h2>
  283.                     <p>Portals to new areas have appeared</p>
  284.                 </div>
  285.             </div>
  286.            
  287.             <div id="ui-sidebar">
  288.                 <div id="hud">
  289.                     <div>โค๏ธ Health: <span id="health">100</span>
  290.                     <div class="health-bar"><div class="health-fill" id="health-bar" style="width: 100%;"></div></div></div>
  291.                     <div>โญ Level: <span id="level">1</span> | ๐Ÿ’ฐ Gold: <span id="gold">0</span></div>
  292.                     <div>๐Ÿ“ Node: <span id="currentNode">Root</span></div>
  293.                 </div>
  294.                
  295.                 <div id="inventory">
  296.                     <div><strong>โš”๏ธ Equipment:</strong></div>
  297.                     <div>๐Ÿ—ก๏ธ Weapon: <span id="weapon">Sword</span></div>
  298.                     <div>๐ŸŽฏ Abilities: <span id="abilities">Sword, Bow</span></div>
  299.                     <div>โœจ Special: <span id="special">None</span></div>
  300.                 </div>
  301.                
  302.                 <div id="tree-map">
  303.                     <strong>๐Ÿ—บ๏ธ Tree Map:</strong>
  304.                     <div id="tree-structure"></div>
  305.                 </div>
  306.                
  307.                 <div id="log"></div>
  308.             </div>
  309.         </div>
  310.        
  311.         <div id="controls">
  312.             <p>๐ŸŽฎ <strong>Controls:</strong></p>
  313.             <p>โฌ…๏ธโžก๏ธโฌ†๏ธโฌ‡๏ธ Arrow Keys or WASD to Move | Auto-attack enemies | Collect treasures to progress</p>
  314.             <p>๐Ÿ”„ Press 'Q' to switch weapons | โšก Press 'E' for special ability (when available)</p>
  315.             <p>๐Ÿ‘๏ธ Press 'M' to toggle neural overlay | ๐Ÿ”„ Press 'R' to reset level</p>
  316.         </div>
  317.     </div>
  318.    
  319.     <button class="debug-button" onclick="toggleNeuralOverlay()">Neural View (M)</button>
  320.  
  321.     <script>
  322.         // Core game constants - will be adjusted based on screen size
  323.         let CANVAS_WIDTH = 600;
  324.         let CANVAS_HEIGHT = 600;
  325.         let BLOX_SIZE = 30;
  326.         let MAP_WIDTH = CANVAS_WIDTH / BLOX_SIZE;
  327.         let MAP_HEIGHT = CANVAS_HEIGHT / BLOX_SIZE;
  328.         const PLAYER_SPEED = 180;
  329.         const ENEMY_BASE_SPEED = 60;
  330.         const SWORD_RANGE = 1.5 * BLOX_SIZE;
  331.         const BOW_RANGE_MIN = SWORD_RANGE;
  332.         const BOW_RANGE_MAX = 10 * BLOX_SIZE;
  333.         const SPELL_RANGE_MIN = 2 * BLOX_SIZE;
  334.         const SPELL_RANGE_MAX = 5 * BLOX_SIZE;
  335.         const ARROW_SPEED = 300;
  336.         const ATTACK_COOLDOWN = 500;
  337.         const MAX_ENEMIES = 11;
  338.         const MIN_ENEMIES = 7;
  339.  
  340.         // Enhanced color palette for better visibility
  341.         const COLORS = {
  342.             grass: '#2d5016',
  343.             tree: '#8B4513',
  344.             wall: '#A52A2A',
  345.             player: '#FFD700',
  346.             enemyRed: '#FF4444',
  347.             enemyOrange: '#FF8844',
  348.             enemyBlue: '#4444FF',
  349.             enemyPurple: '#8844FF',
  350.             sword: '#C0C0C0',
  351.             bow: '#8B4513',
  352.             arrow: '#DAA520',
  353.             spell: '#9400D3',
  354.             treasure: '#FFFF00',
  355.             healthPotion: '#FF6666',
  356.             manaPotion: '#6666FF',
  357.             portal: '#00FF88'
  358.         };
  359.  
  360.         // Enemy types with balanced stats
  361.         const ENEMY_TYPES = [
  362.             { color: 'enemyRed', size: 0.5, type: 'Goblin Scout', damage: 5, health: 30, speed: ENEMY_BASE_SPEED * 1.5, weapon: 'sword' },
  363.             { color: 'enemyOrange', size: 0.75, type: 'Fire Mage', damage: 8, health: 50, speed: ENEMY_BASE_SPEED, weapon: 'spell' },
  364.             { color: 'enemyBlue', size: 0.9, type: 'Armored Knight', damage: 12, health: 80, speed: ENEMY_BASE_SPEED * 0.8, weapon: 'mace' },
  365.             { color: 'enemyPurple', size: 1.1, type: 'Shadow Archer', damage: 10, health: 60, speed: ENEMY_BASE_SPEED * 1.2, weapon: 'bow-spell' }
  366.         ];
  367.  
  368.         const ABILITIES = ['fireball', 'shield', 'speed-boost', 'health-regen', 'double-damage'];
  369.  
  370.         // Tree structure based on file system - optimized for gameplay
  371.         class Node {
  372.             constructor(name, type = 'folder', children = []) {
  373.                 this.name = name;
  374.                 this.type = type;
  375.                 this.children = children;
  376.                 this.cleared = false;
  377.                 this.visited = false;
  378.             }
  379.         }
  380.  
  381.         // Simplified tree structure for better gameplay flow
  382.         const root = new Node('๐Ÿ  Root Directory', 'folder', [
  383.             new Node('๐Ÿ“ Documents', 'folder', [
  384.                 new Node('๐Ÿ“‚ 3D Printing', 'folder', [
  385.                     new Node('๐Ÿ“„ Nintendo Switch Stand.stl', 'file'),
  386.                     new Node('๐Ÿ“„ Phone Holder.stl', 'file'),
  387.                     new Node('๐Ÿ“„ Game Cases.stl', 'file')
  388.                 ]),
  389.                 new Node('๐Ÿ“‚ Projects', 'folder', [
  390.                     new Node('๐Ÿ“„ Summer Catalog 2019.pdf', 'file'),
  391.                     new Node('๐Ÿ“„ Product Designs.doc', 'file')
  392.                 ]),
  393.                 new Node('๐Ÿ“‚ Personal', 'folder', [
  394.                     new Node('๐Ÿ“„ Resume.pdf', 'file'),
  395.                     new Node('๐Ÿ“„ Certificates.zip', 'file')
  396.                 ])
  397.             ]),
  398.             new Node('๐Ÿ–ผ๏ธ Pictures', 'folder', [
  399.                 new Node('๐Ÿ“‚ Gaming Setup', 'folder', [
  400.                     new Node('๐Ÿ“ธ Desktop.jpg', 'file'),
  401.                     new Node('๐Ÿ“ธ Controllers.jpg', 'file')
  402.                 ]),
  403.                 new Node('๐Ÿ“‚ 3D Prints', 'folder', [
  404.                     new Node('๐Ÿ“ธ Nintendo Accessories.jpg', 'file'),
  405.                     new Node('๐Ÿ“ธ Phone Stands.jpg', 'file')
  406.                 ])
  407.             ]),
  408.             new Node('๐ŸŽฎ Games', 'folder', [
  409.                 new Node('๐Ÿ“‚ Saves', 'folder', [
  410.                     new Node('๐Ÿ’พ Minecraft World', 'file'),
  411.                     new Node('๐Ÿ’พ Skyrim Save', 'file')
  412.                 ]),
  413.                 new Node('๐Ÿ“‚ ROMs', 'folder', [
  414.                     new Node('๐ŸŽฏ Retro Collection', 'file')
  415.                 ])
  416.             ]),
  417.             new Node('โฌ‡๏ธ Downloads', 'folder', [
  418.                 new Node('๐Ÿ“ฆ Software.zip', 'file'),
  419.                 new Node('๐ŸŽต Music.mp3', 'file'),
  420.                 new Node('๐ŸŽฌ Videos.mp4', 'file')
  421.             ])
  422.         ]);
  423.  
  424.         // Game state
  425.         let player = {
  426.             x: CANVAS_WIDTH / 2,
  427.             y: CANVAS_HEIGHT / 2,
  428.             size: 1 * BLOX_SIZE,
  429.             health: 100,
  430.             maxHealth: 100,
  431.             level: 1,
  432.             gold: 0,
  433.             abilities: ['sword', 'bow'],
  434.             currentWeapon: 'sword',
  435.             lastAttack: 0,
  436.             arrows: [],
  437.             specialAbility: null,
  438.             specialCooldown: 0,
  439.             kills: 0
  440.         };
  441.  
  442.         let enemies = [];
  443.         let treasures = [];
  444.         let items = [];
  445.         let portals = [];
  446.         let currentNode = root;
  447.         let map = [];
  448.         let lastLogTime = 0;
  449.         let gameOver = false;
  450.         let lastTime = 0;
  451.         let levelCompleted = false;
  452.         let enemiesKilledThisLevel = 0;
  453.         let treasuresCollectedThisLevel = 0;
  454.         let itemsCollectedThisLevel = 0;
  455.  
  456.         // DOM elements
  457.         const canvas = document.getElementById('gameCanvas');
  458.         const ctx = canvas.getContext('2d');
  459.         const logDiv = document.getElementById('log');
  460.         const healthSpan = document.getElementById('health');
  461.         const healthBar = document.getElementById('health-bar');
  462.         const levelSpan = document.getElementById('level');
  463.         const goldSpan = document.getElementById('gold');
  464.         const currentNodeSpan = document.getElementById('currentNode');
  465.         const abilitiesSpan = document.getElementById('abilities');
  466.         const weaponSpan = document.getElementById('weapon');
  467.         const specialSpan = document.getElementById('special');
  468.         const treeStructureDiv = document.getElementById('tree-structure');
  469.         const neuralOverlay = document.getElementById('neuralOverlay');
  470.         const completionMessage = document.getElementById('completionMessage');
  471.  
  472.         // Adjust canvas size based on screen resolution
  473.         function adjustCanvasSize() {
  474.             const isMobile = window.innerWidth <= 768;
  475.            
  476.            if (isMobile) {
  477.                CANVAS_WIDTH = Math.min(window.innerWidth - 40, 500);
  478.                CANVAS_HEIGHT = CANVAS_WIDTH;
  479.            } else if (window.matchMedia("(min-width: 2560px)").matches) {
  480.                CANVAS_WIDTH = 900;
  481.                CANVAS_HEIGHT = 900;
  482.            } else if (window.matchMedia("(min-width: 1920px)").matches) {
  483.                CANVAS_WIDTH = 800;
  484.                CANVAS_HEIGHT = 800;
  485.            } else {
  486.                CANVAS_WIDTH = 600;
  487.                CANVAS_HEIGHT = 600;
  488.            }
  489.            
  490.            canvas.width = CANVAS_WIDTH;
  491.            canvas.height = CANVAS_HEIGHT;
  492.            BLOX_SIZE = Math.max(20, Math.floor(CANVAS_WIDTH / 25));
  493.            MAP_WIDTH = Math.floor(CANVAS_WIDTH / BLOX_SIZE);
  494.            MAP_HEIGHT = Math.floor(CANVAS_HEIGHT / BLOX_SIZE);
  495.            
  496.            // Reset player position
  497.            player.x = CANVAS_WIDTH / 2 - player.size / 2;
  498.            player.y = CANVAS_HEIGHT / 2 - player.size / 2;
  499.            player.size = BLOX_SIZE;
  500.            
  501.            // Regenerate map with new dimensions
  502.            if (map.length > 0) generateMap();
  503.         }
  504.  
  505.         function generateMap() {
  506.             map = Array.from({length: MAP_HEIGHT}, () => Array(MAP_WIDTH).fill('grass'));
  507.            
  508.             // Add natural-looking tree clusters
  509.             const treeClusterCount = Math.floor(Math.random() * 8) + 4;
  510.             for (let cluster = 0; cluster < treeClusterCount; cluster++) {
  511.                let centerX = Math.floor(Math.random() * (MAP_WIDTH - 4)) + 2;
  512.                let centerY = Math.floor(Math.random() * (MAP_HEIGHT - 4)) + 2;
  513.                let clusterSize = Math.floor(Math.random() * 4) + 2;
  514.                
  515.                for (let i = 0; i < clusterSize; i++) {
  516.                    let ox = centerX + Math.floor(Math.random() * 3) - 1;
  517.                    let oy = centerY + Math.floor(Math.random() * 3) - 1;
  518.                    if (ox >= 0 && ox < MAP_WIDTH && oy >= 0 && oy < MAP_HEIGHT) {
  519.                        map[oy][ox] = 'tree';
  520.                     }
  521.                 }
  522.             }
  523.  
  524.             // Generate balanced enemy count
  525.             enemies = [];
  526.             const enemyCount = Math.floor(Math.random() * (MAX_ENEMIES - MIN_ENEMIES + 1)) + MIN_ENEMIES;
  527.             for (let i = 0; i < enemyCount; i++) {
  528.                const type = ENEMY_TYPES[Math.floor(Math.random() * ENEMY_TYPES.length)];
  529.                let enemyX, enemyY;
  530.                
  531.                // Ensure enemies don't spawn too close to player
  532.                do {
  533.                    enemyX = Math.random() * (CANVAS_WIDTH - BLOX_SIZE);
  534.                    enemyY = Math.random() * (CANVAS_HEIGHT - BLOX_SIZE);
  535.                } while (Math.abs(enemyX - player.x) < BLOX_SIZE * 3 && Math.abs(enemyY - player.y) < BLOX_SIZE * 3);
  536.                
  537.                enemies.push({
  538.                    ...type,
  539.                    x: enemyX,
  540.                    y: enemyY,
  541.                    currentHealth: type.health,
  542.                    abilities: Math.random() > 0.7 ? [ABILITIES[Math.floor(Math.random() * ABILITIES.length)]] : [],
  543.                     lastAttack: 0
  544.                 });
  545.             }
  546.  
  547.             // Generate treasures based on current node's children
  548.             treasures = [];
  549.             const treasureCount = Math.max(1, currentNode.children.length);
  550.             for (let i = 0; i < treasureCount; i++) {
  551.                treasures.push({
  552.                    x: Math.random() * (CANVAS_WIDTH - BLOX_SIZE),
  553.                    y: Math.random() * (CANVAS_HEIGHT - BLOX_SIZE)
  554.                });
  555.            }
  556.            
  557.            // Add helpful items
  558.            items = [];
  559.            const itemCount = Math.floor(Math.random() * 3) + 1;
  560.            for (let i = 0; i < itemCount; i++) {
  561.                items.push({
  562.                    x: Math.random() * (CANVAS_WIDTH - BLOX_SIZE),
  563.                    y: Math.random() * (CANVAS_HEIGHT - BLOX_SIZE),
  564.                    type: Math.random() > 0.6 ? 'healthPotion' : 'manaPotion'
  565.                 });
  566.             }
  567.  
  568.             // Reset level state
  569.             levelCompleted = false;
  570.             enemiesKilledThisLevel = 0;
  571.             treasuresCollectedThisLevel = 0;
  572.             itemsCollectedThisLevel = 0;
  573.             portals = [];
  574.             completionMessage.style.display = 'none';
  575.             gameOver = false;
  576.            
  577.             logMessage(`๐Ÿš€ Entered: ${currentNode.name}`);
  578.             if (enemies.length > 0) logMessage(`โš”๏ธ ${enemies.length} enemies detected!`);
  579.             if (treasures.length > 0) logMessage(`๐Ÿ’ฐ ${treasures.length} treasures to collect!`);
  580.             updateTreeMap();
  581.         }
  582.  
  583.         function spawnPortals() {
  584.             portals = [];
  585.            
  586.             // Portal back to parent
  587.             if (currentNode.name !== '๐Ÿ  Root Directory') {
  588.                 const parent = findParent(root, currentNode);
  589.                 if (parent) {
  590.                     portals.push({
  591.                         x: Math.random() * (CANVAS_WIDTH - 100) + 50,
  592.                         y: Math.random() * (CANVAS_HEIGHT - 100) + 50,
  593.                         target: parent,
  594.                         type: 'parent',
  595.                         name: `โฌ…๏ธ ${parent.name}`
  596.                     });
  597.                 }
  598.             }
  599.            
  600.             // Portals to children
  601.             currentNode.children.forEach(child => {
  602.                 portals.push({
  603.                     x: Math.random() * (CANVAS_WIDTH - 100) + 50,
  604.                     y: Math.random() * (CANVAS_HEIGHT - 100) + 50,
  605.                     target: child,
  606.                     type: 'child',
  607.                     name: `โžก๏ธ ${child.name}`
  608.                 });
  609.             });
  610.            
  611.             completionMessage.style.display = 'block';
  612.             setTimeout(() => {
  613.                 completionMessage.style.display = 'none';
  614.             }, 4000);
  615.            
  616.             logMessage('๐ŸŽ‰ Level cleared! Portals activated!');
  617.         }
  618.  
  619.         function findParent(root, node) {
  620.             if (root.children.includes(node)) return root;
  621.            
  622.             for (const child of root.children) {
  623.                 if (child.children && child.children.length > 0) {
  624.                    const parent = findParent(child, node);
  625.                     if (parent) return parent;
  626.                 }
  627.             }
  628.             return null;
  629.         }
  630.  
  631.         function updateTreeMap() {
  632.             let html = '';
  633.            
  634.             function buildTree(node, depth = 0) {
  635.                 const indent = '&nbsp;'.repeat(depth * 2);
  636.                 const isCurrent = node === currentNode;
  637.                 const clearedIndicator = node.cleared ? ' โœ…' : '';
  638.                 const visitedIndicator = node.visited && !node.cleared ? ' ๐Ÿ‘๏ธ' : '';
  639.                
  640.                 html += `${indent}${isCurrent ? '<strong style="color: #FFD700;">' : ''}${node.name}${clearedIndicator}${visitedIndicator}${isCurrent ? '</strong>' : ''}<br>`;
  641.                
  642.                 if (node.children && node.children.length > 0) {
  643.                    node.children.forEach(child => {
  644.                        buildTree(child, depth + 1);
  645.                     });
  646.                 }
  647.             }
  648.            
  649.             buildTree(root);
  650.             treeStructureDiv.innerHTML = html;
  651.         }
  652.  
  653.         function logMessage(msg) {
  654.             if (Date.now() - lastLogTime > 50) {
  655.                 const timestamp = new Date().toLocaleTimeString('en-US', {
  656.                     hour12: false,
  657.                     hour: '2-digit',
  658.                     minute: '2-digit',
  659.                     second: '2-digit'
  660.                 });
  661.                 logDiv.innerHTML += `<span style="color: #888;">[${timestamp}]</span> ${msg}<br>`;
  662.                 logDiv.scrollTop = logDiv.scrollHeight;
  663.                 lastLogTime = Date.now();
  664.             }
  665.         }
  666.  
  667.         // Enhanced input handling
  668.         const keys = {};
  669.         let touchStartX = 0;
  670.         let touchStartY = 0;
  671.         let touchMoveThreshold = 10;
  672.  
  673.         window.addEventListener('keydown', e => {
  674.             keys[e.key.toLowerCase()] = true;
  675.            
  676.             if (e.key.toLowerCase() === 'm') {
  677.                 e.preventDefault();
  678.                 toggleNeuralOverlay();
  679.             }
  680.            
  681.             if (e.key.toLowerCase() === 'r') {
  682.                 e.preventDefault();
  683.                 logMessage('๐Ÿ”„ Resetting level...');
  684.                 generateMap();
  685.             }
  686.            
  687.             if (e.key.toLowerCase() === 'q') {
  688.                 e.preventDefault();
  689.                 switchWeapon();
  690.             }
  691.            
  692.             if (e.key.toLowerCase() === 'e') {
  693.                 e.preventDefault();
  694.                 useSpecialAbility();
  695.             }
  696.         });
  697.  
  698.         window.addEventListener('keyup', e => {
  699.             keys[e.key.toLowerCase()] = false;
  700.         });
  701.  
  702.         // Touch controls for mobile
  703.         canvas.addEventListener('touchstart', e => {
  704.             e.preventDefault();
  705.             const touch = e.touches[0];
  706.             const rect = canvas.getBoundingClientRect();
  707.             touchStartX = touch.clientX - rect.left;
  708.             touchStartY = touch.clientY - rect.top;
  709.         });
  710.  
  711.         canvas.addEventListener('touchmove', e => {
  712.             e.preventDefault();
  713.             const touch = e.touches[0];
  714.             const rect = canvas.getBoundingClientRect();
  715.             const touchX = touch.clientX - rect.left;
  716.             const touchY = touch.clientY - rect.top;
  717.            
  718.             const deltaX = touchX - touchStartX;
  719.             const deltaY = touchY - touchStartY;
  720.            
  721.             if (Math.abs(deltaX) > touchMoveThreshold || Math.abs(deltaY) > touchMoveThreshold) {
  722.                 // Convert touch to movement
  723.                 if (Math.abs(deltaX) > Math.abs(deltaY)) {
  724.                     keys['arrowleft'] = deltaX < 0;
  725.                    keys['arrowright'] = deltaX > 0;
  726.                     keys['arrowup'] = false;
  727.                     keys['arrowdown'] = false;
  728.                 } else {
  729.                     keys['arrowup'] = deltaY < 0;
  730.                    keys['arrowdown'] = deltaY > 0;
  731.                     keys['arrowleft'] = false;
  732.                     keys['arrowright'] = false;
  733.                 }
  734.             }
  735.         });
  736.  
  737.         canvas.addEventListener('touchend', e => {
  738.             e.preventDefault();
  739.             // Clear movement keys
  740.             keys['arrowleft'] = false;
  741.             keys['arrowright'] = false;
  742.             keys['arrowup'] = false;
  743.             keys['arrowdown'] = false;
  744.         });
  745.        
  746.         function toggleNeuralOverlay() {
  747.             const isVisible = neuralOverlay.style.display !== 'none';
  748.             neuralOverlay.style.display = isVisible ? 'none' : 'block';
  749.             logMessage(isVisible ? '๐Ÿ‘๏ธ Neural overlay disabled' : '๐Ÿ” Neural overlay enabled');
  750.         }
  751.  
  752.         function switchWeapon() {
  753.             const currentIndex = player.abilities.indexOf(player.currentWeapon);
  754.             const nextIndex = (currentIndex + 1) % player.abilities.length;
  755.             player.currentWeapon = player.abilities[nextIndex];
  756.             weaponSpan.textContent = player.currentWeapon.charAt(0).toUpperCase() + player.currentWeapon.slice(1);
  757.             logMessage(`๐Ÿ”„ Switched to ${player.currentWeapon}`);
  758.         }
  759.  
  760.         function getClosestEnemy() {
  761.             let closest = null;
  762.             let minDist = Infinity;
  763.             enemies.forEach(enemy => {
  764.                 let dx = (player.x + player.size/2) - (enemy.x + enemy.size * BLOX_SIZE/2);
  765.                 let dy = (player.y + player.size/2) - (enemy.y + enemy.size * BLOX_SIZE/2);
  766.                 let dist = Math.sqrt(dx*dx + dy*dy);
  767.                 if (dist < minDist) {
  768.                    minDist = dist;
  769.                    closest = enemy;
  770.                }
  771.            });
  772.            return { enemy: closest, dist: minDist };
  773.        }
  774.  
  775.        function predictPosition(enemy, projectileSpeed, dt) {
  776.            let dx = (player.x + player.size/2) - (enemy.x + enemy.size * BLOX_SIZE/2);
  777.            let dy = (player.y + player.size/2) - (enemy.y + enemy.size * BLOX_SIZE/2);
  778.            let dist = Math.sqrt(dx*dx + dy*dy);
  779.            let timeToHit = dist / projectileSpeed;
  780.            
  781.            // Predict where enemy will be
  782.            let enemyVx = (dx / dist) * -enemy.speed;
  783.            let enemyVy = (dy / dist) * -enemy.speed;
  784.            
  785.            return {
  786.                x: enemy.x + enemyVx * timeToHit,
  787.                y: enemy.y + enemyVy * timeToHit
  788.            };
  789.        }
  790.  
  791.        function attackEnemy(enemy, dist, dt) {
  792.            if (Date.now() - player.lastAttack < ATTACK_COOLDOWN) return;
  793.  
  794.            let damage = 0;
  795.            let attacked = false;
  796.  
  797.            if (player.currentWeapon === 'sword' && dist <= SWORD_RANGE) {
  798.                damage = Math.floor(20 * (1 - dist / SWORD_RANGE)) + 5;
  799.                logMessage(`โš”๏ธ Sword strike! ${damage} damage`);
  800.                attacked = true;
  801.  
  802.                // Visual sword effect
  803.                setTimeout(() => {
  804.                     ctx.save();
  805.                     ctx.globalAlpha = 0.7;
  806.                     ctx.beginPath();
  807.                     ctx.moveTo(player.x + player.size/2, player.y + player.size/2);
  808.                     let ex = enemy.x + enemy.size * BLOX_SIZE / 2;
  809.                     let ey = enemy.y + enemy.size * BLOX_SIZE / 2;
  810.                     ctx.lineTo(ex, ey);
  811.                     ctx.strokeStyle = COLORS.sword;
  812.                     ctx.lineWidth = 4;
  813.                     ctx.stroke();
  814.                     ctx.restore();
  815.                 }, 0);
  816.  
  817.             } else if (player.currentWeapon === 'bow' && dist > BOW_RANGE_MIN && dist < BOW_RANGE_MAX) {
  818.                damage = Math.floor(15 + (dist / BOW_RANGE_MAX) * 10);
  819.                 logMessage(`๐Ÿน Arrow shot! ${damage} damage`);
  820.                 attacked = true;
  821.  
  822.                 // Fire arrow with prediction
  823.                 let pred = predictPosition(enemy, ARROW_SPEED, dt);
  824.                 player.arrows.push({
  825.                     x: player.x + player.size/2,
  826.                     y: player.y + player.size/2,
  827.                     tx: pred.x + enemy.size * BLOX_SIZE/2,
  828.                     ty: pred.y + enemy.size * BLOX_SIZE/2,
  829.                     speed: ARROW_SPEED,
  830.                     damage: damage,
  831.                     startTime: Date.now()
  832.                 });
  833.  
  834.             } else if (player.currentWeapon === 'fireball' && dist >= SPELL_RANGE_MIN && dist <= SPELL_RANGE_MAX) {
  835.                damage = 25;
  836.                 logMessage(`๐Ÿ”ฅ Fireball! ${damage} damage`);
  837.                 attacked = true;
  838.                
  839.                 player.arrows.push({
  840.                     x: player.x + player.size/2,
  841.                     y: player.y + player.size/2,
  842.                     tx: enemy.x + enemy.size * BLOX_SIZE/2,
  843.                     ty: enemy.y + enemy.size * BLOX_SIZE/2,
  844.                     speed: ARROW_SPEED * 0.7,
  845.                     damage: damage,
  846.                     isFireball: true,
  847.                     startTime: Date.now()
  848.                 });
  849.             }
  850.  
  851.             if (attacked) {
  852.                 if (player.currentWeapon === 'sword') {
  853.                     enemy.currentHealth -= damage;
  854.                     handleEnemyDeath(enemy);
  855.                 }
  856.                 player.lastAttack = Date.now();
  857.             }
  858.         }
  859.  
  860.         function handleEnemyDeath(enemy) {
  861.             if (enemy.currentHealth <= 0) {
  862.                logMessage(`๐Ÿ’€ Defeated ${enemy.type}! +10 gold`);
  863.                enemiesKilledThisLevel++;
  864.                player.kills++;
  865.                
  866.                // Grant abilities from defeated enemies
  867.                if (enemy.abilities.length > 0) {
  868.                     const ability = enemy.abilities[0];
  869.                     if (!player.abilities.includes(ability)) {
  870.                         player.abilities.push(ability);
  871.                         abilitiesSpan.textContent = player.abilities.join(', ');
  872.                         logMessage(`โœจ Gained ability: ${ability}!`);
  873.                     }
  874.                 }
  875.                
  876.                 player.gold += 10;
  877.                 goldSpan.textContent = player.gold;
  878.                 player.level++;
  879.                 levelSpan.textContent = player.level;
  880.                
  881.                 checkLevelCompletion();
  882.                
  883.                 // Progressive difficulty
  884.                 if (player.level % 5 === 0) {
  885.                     ENEMY_TYPES.forEach(type => {
  886.                         type.health += 10;
  887.                         type.damage += 2;
  888.                     });
  889.                     logMessage(`โฌ†๏ธ Enemies grow stronger! (Level ${player.level})`);
  890.                 }
  891.                
  892.                 const index = enemies.indexOf(enemy);
  893.                 if (index !== -1) enemies.splice(index, 1);
  894.             }
  895.         }
  896.  
  897.         function checkLevelCompletion() {
  898.             if (enemies.length === 0 && treasures.length === 0 && items.length === 0 && !levelCompleted) {
  899.                levelCompleted = true;
  900.                 currentNode.cleared = true;
  901.                 spawnPortals();
  902.             } else if (!levelCompleted && enemiesKilledThisLevel >= Math.ceil(enemies.length * 0.6) && treasuresCollectedThisLevel >= Math.ceil(treasures.length * 0.7)) {
  903.                levelCompleted = true;
  904.                 currentNode.cleared = true;
  905.                 spawnPortals();
  906.             }
  907.         }
  908.  
  909.         function useSpecialAbility() {
  910.             if (!player.specialAbility || player.specialCooldown > 0) return;
  911.            
  912.             switch(player.specialAbility) {
  913.                 case 'shield':
  914.                     logMessage('๐Ÿ›ก๏ธ Shield activated! Temporary invulnerability');
  915.                     player.specialCooldown = 300;
  916.                     break;
  917.                 case 'double-damage':
  918.                     logMessage('๐Ÿ’ฅ Double damage activated!');
  919.                     player.specialCooldown = 450;
  920.                     break;
  921.                 case 'speed-boost':
  922.                     logMessage('๐Ÿ’จ Speed boost activated!');
  923.                     player.specialCooldown = 240;
  924.                     break;
  925.                 case 'health-regen':
  926.                     player.health = Math.min(player.maxHealth, player.health + 50);
  927.                     healthSpan.textContent = player.health;
  928.                     healthBar.style.width = `${(player.health / player.maxHealth) * 100}%`;
  929.                     logMessage('๐Ÿ’š Health regeneration activated!');
  930.                     player.specialCooldown = 600;
  931.                     break;
  932.             }
  933.         }
  934.  
  935.         function enemyAttack(enemy, dist) {
  936.             if (Date.now() - enemy.lastAttack < ATTACK_COOLDOWN * 2) return;
  937.            if (dist > SWORD_RANGE * 2) return;
  938.  
  939.             let damage = Math.floor(enemy.damage * (1 + Math.random() * 0.5));
  940.            
  941.             // Different attack patterns
  942.             if (enemy.weapon === 'spell' && dist >= SPELL_RANGE_MIN && dist <= SPELL_RANGE_MAX) {
  943.                damage = Math.floor(damage * 1.2);
  944.                 logMessage(`๐Ÿ”ฅ ${enemy.type} casts spell! -${damage} health`);
  945.             } else if (enemy.weapon === 'bow-spell' && Math.random() > 0.6 && dist > SWORD_RANGE) {
  946.                damage = Math.floor(damage * 0.8);
  947.                 logMessage(`๐Ÿน ${enemy.type} shoots! -${damage} health`);
  948.             } else if (dist <= SWORD_RANGE) {
  949.                logMessage(`โš”๏ธ ${enemy.type} attacks! -${damage} health`);
  950.            } else {
  951.                return; // Too far for attack
  952.            }
  953.  
  954.            player.health -= damage;
  955.            player.health = Math.max(0, player.health);
  956.            healthSpan.textContent = player.health;
  957.            healthBar.style.width = `${(player.health / player.maxHealth) * 100}%`;
  958.            enemy.lastAttack = Date.now();
  959.  
  960.            if (player.health <= 0) {
  961.                gameOver = true;
  962.                logMessage('๐Ÿ’€ You died! Press R to restart level');
  963.            }
  964.        }
  965.  
  966.        function updateArrows(dt) {
  967.            player.arrows.forEach((arrow, i) => {
  968.                 let dx = arrow.tx - arrow.x;
  969.                 let dy = arrow.ty - arrow.y;
  970.                 let dist = Math.sqrt(dx*dx + dy*dy);
  971.                
  972.                 if (dist > 5) {
  973.                     arrow.x += (dx / dist) * arrow.speed * dt;
  974.                     arrow.y += (dy / dist) * arrow.speed * dt;
  975.                 } else {
  976.                     // Arrow reached target
  977.                     player.arrows.splice(i, 1);
  978.                     return;
  979.                 }
  980.                
  981.                 // Check collision with enemies
  982.                 enemies.forEach((enemy, enemyIndex) => {
  983.                     let ex = enemy.x + enemy.size * BLOX_SIZE/2 - arrow.x;
  984.                     let ey = enemy.y + enemy.size * BLOX_SIZE/2 - arrow.y;
  985.                     if (Math.sqrt(ex*ex + ey*ey) < enemy.size * BLOX_SIZE/2) {
  986.                        enemy.currentHealth -= arrow.damage;
  987.                        handleEnemyDeath(enemy);
  988.                        player.arrows.splice(i, 1);
  989.                    }
  990.                });
  991.                
  992.                // Remove old arrows
  993.                if (Date.now() - arrow.startTime > 3000) {
  994.                     player.arrows.splice(i, 1);
  995.                 }
  996.             });
  997.         }
  998.  
  999.         function update(currentTime) {
  1000.             if (gameOver) {
  1001.                 requestAnimationFrame(update);
  1002.                 return;
  1003.             }
  1004.  
  1005.             const dt = Math.min(0.016, (currentTime - lastTime) / 1000);
  1006.             lastTime = currentTime;
  1007.  
  1008.             // Player movement with bounds checking
  1009.             let moveSpeed = PLAYER_SPEED * dt;
  1010.             if (keys['arrowup'] || keys['w']) {
  1011.                 player.y = Math.max(0, player.y - moveSpeed);
  1012.             }
  1013.             if (keys['arrowdown'] || keys['s']) {
  1014.                 player.y = Math.min(CANVAS_HEIGHT - player.size, player.y + moveSpeed);
  1015.             }
  1016.             if (keys['arrowleft'] || keys['a']) {
  1017.                 player.x = Math.max(0, player.x - moveSpeed);
  1018.             }
  1019.             if (keys['arrowright'] || keys['d']) {
  1020.                 player.x = Math.min(CANVAS_WIDTH - player.size, player.x + moveSpeed);
  1021.             }
  1022.  
  1023.             // Auto-attack system
  1024.             const { enemy, dist } = getClosestEnemy();
  1025.             if (enemy) {
  1026.                 attackEnemy(enemy, dist, dt);
  1027.                 enemyAttack(enemy, dist);
  1028.             }
  1029.  
  1030.             // Enemy AI and movement
  1031.             enemies.forEach(enemy => {
  1032.                 let dx = (player.x + player.size/2) - (enemy.x + enemy.size * BLOX_SIZE/2);
  1033.                 let dy = (player.y + player.size/2) - (enemy.y + enemy.size * BLOX_SIZE/2);
  1034.                 let dist = Math.sqrt(dx*dx + dy*dy);
  1035.                
  1036.                 if (dist > 0) {
  1037.                     let moveSpeed = enemy.speed * dt;
  1038.                     enemy.x += (dx / dist) * moveSpeed;
  1039.                     enemy.y += (dy / dist) * moveSpeed;
  1040.                    
  1041.                     // Keep enemies in bounds
  1042.                     enemy.x = Math.max(0, Math.min(CANVAS_WIDTH - enemy.size * BLOX_SIZE, enemy.x));
  1043.                     enemy.y = Math.max(0, Math.min(CANVAS_HEIGHT - enemy.size * BLOX_SIZE, enemy.y));
  1044.                 }
  1045.             });
  1046.  
  1047.             // Treasure collection
  1048.             treasures.forEach((treasure, i) => {
  1049.                 let dx = (player.x + player.size/2) - (treasure.x + BLOX_SIZE/2);
  1050.                 let dy = (player.y + player.size/2) - (treasure.y + BLOX_SIZE/2);
  1051.                 let dist = Math.sqrt(dx*dx + dy*dy);
  1052.                
  1053.                 if (dist < player.size/2 + BLOX_SIZE/2) {
  1054.                    player.gold += 25;
  1055.                    goldSpan.textContent = player.gold;
  1056.                    treasuresCollectedThisLevel++;
  1057.                    logMessage('๐Ÿ’ฐ Treasure collected! +25 gold');
  1058.                    treasures.splice(i, 1);
  1059.                    checkLevelCompletion();
  1060.                }
  1061.            });
  1062.            
  1063.            // Portal usage
  1064.            portals.forEach(portal => {
  1065.                 let dx = (player.x + player.size/2) - portal.x;
  1066.                 let dy = (player.y + player.size/2) - portal.y;
  1067.                 let dist = Math.sqrt(dx*dx + dy*dy);
  1068.                
  1069.                 if (dist < player.size/2 + BLOX_SIZE) {
  1070.                    currentNode.visited = true;
  1071.                    currentNode = portal.target;
  1072.                    currentNodeSpan.textContent = currentNode.name;
  1073.                    logMessage(`๐Ÿšช Entering ${currentNode.name}...`);
  1074.                    generateMap();
  1075.                }
  1076.            });
  1077.            
  1078.            // Item collection
  1079.            items.forEach((item, i) => {
  1080.                 let dx = (player.x + player.size/2) - (item.x + BLOX_SIZE/2);
  1081.                 let dy = (player.y + player.size/2) - (item.y + BLOX_SIZE/2);
  1082.                 let dist = Math.sqrt(dx*dx + dy*dy);
  1083.                
  1084.                 if (dist < player.size/2 + BLOX_SIZE/2) {
  1085.                    if (item.type === 'healthPotion') {
  1086.                        player.health = Math.min(player.maxHealth, player.health + 30);
  1087.                        healthSpan.textContent = player.health;
  1088.                        healthBar.style.width = `${(player.health / player.maxHealth) * 100}%`;
  1089.                        logMessage('๐Ÿงช Health potion! +30 health');
  1090.                    } else if (item.type === 'manaPotion') {
  1091.                        player.specialCooldown = Math.max(0, player.specialCooldown - 100);
  1092.                        logMessage('๐Ÿ’™ Mana potion! Special cooldown reduced');
  1093.                    }
  1094.                    itemsCollectedThisLevel++;
  1095.                    items.splice(i, 1);
  1096.                    checkLevelCompletion();
  1097.                }
  1098.            });
  1099.  
  1100.            updateArrows(dt);
  1101.            
  1102.            // Passive abilities
  1103.            if (player.abilities.includes('health-regen') && player.health < player.maxHealth) {
  1104.                player.health = Math.min(player.maxHealth, player.health + 10 * dt);
  1105.                healthSpan.textContent = Math.floor(player.health);
  1106.                healthBar.style.width = `${(player.health / player.maxHealth) * 100}%`;
  1107.            }
  1108.            
  1109.            // Update cooldowns
  1110.            if (player.specialCooldown > 0) {
  1111.                 player.specialCooldown -= 60 * dt;
  1112.                 player.specialCooldown = Math.max(0, player.specialCooldown);
  1113.             }
  1114.  
  1115.             requestAnimationFrame(update);
  1116.         }
  1117.  
  1118.         function render() {
  1119.             ctx.clearRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
  1120.            
  1121.             // Render map tiles
  1122.             for (let y = 0; y < MAP_HEIGHT; y++) {
  1123.                for (let x = 0; x < MAP_WIDTH; x++) {
  1124.                    ctx.fillStyle = COLORS[map[y][x]];
  1125.                    ctx.fillRect(x * BLOX_SIZE, y * BLOX_SIZE, BLOX_SIZE, BLOX_SIZE);
  1126.                    
  1127.                    // Add texture to trees
  1128.                    if (map[y][x] === 'tree') {
  1129.                        ctx.fillStyle = '#654321';
  1130.                        ctx.fillRect(x * BLOX_SIZE + 2, y * BLOX_SIZE + 2, BLOX_SIZE - 4, BLOX_SIZE - 4);
  1131.                    }
  1132.                }
  1133.            }
  1134.            
  1135.            // Render player with glow effect
  1136.            ctx.shadowColor = COLORS.player;
  1137.            ctx.shadowBlur = 10;
  1138.            ctx.fillStyle = COLORS.player;
  1139.            ctx.fillRect(player.x, player.y, player.size, player.size);
  1140.            ctx.shadowBlur = 0;
  1141.            
  1142.            // Render enemies with health bars
  1143.            enemies.forEach(enemy => {
  1144.                 let es = enemy.size * BLOX_SIZE;
  1145.                 ctx.fillStyle = COLORS[enemy.color];
  1146.                 ctx.fillRect(enemy.x, enemy.y, es, es);
  1147.                
  1148.                 // Enemy health bar
  1149.                 const healthPercent = enemy.currentHealth / enemy.health;
  1150.                 ctx.fillStyle = '#333';
  1151.                 ctx.fillRect(enemy.x, enemy.y - 8, es, 4);
  1152.                 ctx.fillStyle = healthPercent > 0.5 ? '#4CAF50' : healthPercent > 0.25 ? '#FF9800' : '#F44336';
  1153.                 ctx.fillRect(enemy.x, enemy.y - 8, es * healthPercent, 4);
  1154.             });
  1155.            
  1156.             // Render treasures with sparkle effect
  1157.             treasures.forEach((treasure, i) => {
  1158.                 const sparkle = Math.sin(Date.now() * 0.01 + i) * 0.3 + 0.7;
  1159.                 ctx.globalAlpha = sparkle;
  1160.                 ctx.fillStyle = COLORS.treasure;
  1161.                 ctx.beginPath();
  1162.                 ctx.arc(treasure.x + BLOX_SIZE/2, treasure.y + BLOX_SIZE/2, BLOX_SIZE/3, 0, Math.PI * 2);
  1163.                 ctx.fill();
  1164.                 ctx.globalAlpha = 1;
  1165.             });
  1166.            
  1167.             // Render items
  1168.             items.forEach(item => {
  1169.                 ctx.fillStyle = COLORS[item.type];
  1170.                 ctx.beginPath();
  1171.                 ctx.arc(item.x + BLOX_SIZE/2, item.y + BLOX_SIZE/2, BLOX_SIZE/3, 0, Math.PI * 2);
  1172.                 ctx.fill();
  1173.             });
  1174.            
  1175.             // Render portals with animated effect
  1176.             portals.forEach((portal, i) => {
  1177.                 const pulse = Math.sin(Date.now() * 0.005 + i) * 0.2 + 0.8;
  1178.                 ctx.globalAlpha = pulse;
  1179.                 ctx.fillStyle = COLORS.portal;
  1180.                 ctx.beginPath();
  1181.                 ctx.arc(portal.x, portal.y, BLOX_SIZE * 0.7, 0, Math.PI * 2);
  1182.                 ctx.fill();
  1183.                 ctx.globalAlpha = 1;
  1184.                
  1185.                 // Portal ring
  1186.                 ctx.strokeStyle = '#FFFFFF';
  1187.                 ctx.lineWidth = 2;
  1188.                 ctx.beginPath();
  1189.                 ctx.arc(portal.x, portal.y, BLOX_SIZE * 0.7, 0, Math.PI * 2);
  1190.                 ctx.stroke();
  1191.                
  1192.                 // Portal label
  1193.                 ctx.fillStyle = '#FFFFFF';
  1194.                 ctx.font = `${Math.max(10, BLOX_SIZE/3)}px Courier New`;
  1195.                 ctx.textAlign = 'center';
  1196.                 const shortName = portal.name.length > 15 ? portal.name.substring(0, 12) + '...' : portal.name;
  1197.                 ctx.fillText(shortName, portal.x, portal.y - BLOX_SIZE);
  1198.                 ctx.textAlign = 'left';
  1199.             });
  1200.            
  1201.             // Render projectiles
  1202.             player.arrows.forEach(arrow => {
  1203.                 if (arrow.isFireball) {
  1204.                     ctx.fillStyle = '#FF4500';
  1205.                     ctx.beginPath();
  1206.                     ctx.arc(arrow.x, arrow.y, 6, 0, Math.PI * 2);
  1207.                     ctx.fill();
  1208.                     // Fire trail
  1209.                     ctx.fillStyle = '#FF6500';
  1210.                     ctx.beginPath();
  1211.                     ctx.arc(arrow.x - 3, arrow.y, 3, 0, Math.PI * 2);
  1212.                     ctx.fill();
  1213.                 } else {
  1214.                     ctx.fillStyle = COLORS.arrow;
  1215.                     ctx.fillRect(arrow.x - 2, arrow.y - 2, 4, 4);
  1216.                 }
  1217.             });
  1218.  
  1219.             requestAnimationFrame(render);
  1220.         }
  1221.  
  1222.         // Initialize game
  1223.         function initGame() {
  1224.             adjustCanvasSize();
  1225.            
  1226.             currentNodeSpan.textContent = currentNode.name;
  1227.             abilitiesSpan.textContent = player.abilities.join(', ');
  1228.             weaponSpan.textContent = player.currentWeapon.charAt(0).toUpperCase() + player.currentWeapon.slice(1);
  1229.             specialSpan.textContent = player.specialAbility || 'None';
  1230.            
  1231.             generateMap();
  1232.            
  1233.             logMessage('๐ŸŽฎ Welcome to Tree Kingdom Battler!');
  1234.             logMessage('โš”๏ธ Battle through your file system!');
  1235.             logMessage('๐Ÿ’ก Tip: Collect treasures and defeat enemies to unlock new areas!');
  1236.            
  1237.             lastTime = performance.now();
  1238.             requestAnimationFrame(update);
  1239.             requestAnimationFrame(render);
  1240.         }
  1241.  
  1242.         // Event listeners
  1243.         window.addEventListener('load', initGame);
  1244.         window.addEventListener('resize', adjustCanvasSize);
  1245.  
  1246.         // Prevent context menu on canvas
  1247.         canvas.addEventListener('contextmenu', e => e.preventDefault());
  1248.     </script>
  1249. </body>
  1250. </html>
  1251.  
Advertisement
Add Comment
Please, Sign In to add comment