Untitled - MARKUP 56.08 KB
                                
                                    // engine.js
let canvas, ctx;
let player, map, enemies;
let cameraOffsetX = 0, cameraOffsetY = 0;
let npcs = [];  // Tablica NPC



function initGame() {
    canvas = document.getElementById('gameCanvas');
    ctx = canvas.getContext('2d');
    canvas.width = 1024;
    canvas.height = 748;

    // Generowanie siatki kolizji
    const gridSize = 32; // Rozmiar kafelka
    const cols = 1024 / gridSize; // Kolumny
    const rows = 1024 / gridSize; // Wiersze
    
    const collisionGrid = [
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [1,1,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,1,0,0,1,1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
        [0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [1,0,0,0,0,0,0,1,0,0,0,0,0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,1,1,1,1,1,0,0,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,1,1,1,1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
      ];

    // Inicjalizacja mapy z siatką kolizji
    map = new Map('assets/maps/miasteczko.png', 1024, 1024, collisionGrid, gridSize);

    // Inicjalizacja gracza
    player = new Player(map.width, map.height);

    // Inicjalizacja wrogów
    enemies = new Enemies();

    // Inicjalizacja NPC z ustalonymi pozycjami
    const zofia = new Zofia(500, 150);
    const gustaw = new Gustaw(300, 180);

    // Dodaj NPC do tablicy
    npcs.push(zofia);
    npcs.push(gustaw);

    // Tworzenie kratki torby
    createInventoryGrid('inventoryContainer', 24);
    
    // Tworzenie kratki ekwipunku
    createInventoryGrid('equipmentContainer', 6);

    // Pętla gry
    function gameLoop() {
        ctx.clearRect(0, 0, canvas.width, canvas.height);

        // Zapisz poprzednią pozycję gracza
        const previousX = player.x;
        const previousY = player.y;

        // Aktualizacja gracza
        player.update(ctx, cameraOffsetX, cameraOffsetY);

        // Sprawdzenie kolizji
        if (map.checkCollision(player.x, player.y, player.width, player.height)) {
            // Cofnij ruch, jeśli gracz koliduje
            player.x = previousX;
            player.y = previousY;
        }

        // Aktualizacja pozycji kamery
        updateCamera();

        // Rysowanie mapy
        map.draw(ctx, cameraOffsetX, cameraOffsetY);

        // Rysowanie gracza
        player.draw(ctx, cameraOffsetX, cameraOffsetY);

        // Aktualizacja i rysowanie wrogów
        enemies.update(ctx, cameraOffsetX, cameraOffsetY);

        // Rysowanie i aktualizacja NPC
        npcs.forEach(npc => {
            npc.draw(ctx, cameraOffsetX, cameraOffsetY);  // Rysowanie NPC
        });

        // Aktualizacja UI
        updateUI();

        checkPlayerDistanceToNPC();

        requestAnimationFrame(gameLoop);
    }

    gameLoop();
}
// Dodaj funkcje interakcji z NPC
function interactWithNPC(npc) {
    npc.talk();
    npc.heal(player);  // Tylko leczenie w przypadku Zofii
}

function createInventoryGrid(containerId, slots) {
  const container = document.getElementById(containerId);
  container.innerHTML = ''; // Czyści poprzednie kratki

  const slotNames = containerId === 'equipmentContainer'
      ? ['head', 'body', 'additional', 'feet', 'weapon', 'accessory']
      : Array(slots).fill(null);

  slotNames.forEach((name, index) => {
      const slot = document.createElement('div');
      slot.className = 'inventory-slot';
      slot.dataset.index = name || index; // Przypisz nazwę lub indeks slotu
      container.appendChild(slot);

      // Jeśli slot zawiera przedmiot, dodaj obsługę przeciągania
      slot.addEventListener('dragstart', (e) => {
          const item = containerId === 'equipmentContainer'
              ? player.equipment[name]
              : player.inventory[index];
          if (item) {
              e.dataTransfer.setData('itemName', item.name); // Nazwa przedmiotu
              e.dataTransfer.setData('itemType', item.type); // Typ przedmiotu
              e.dataTransfer.setData('source', containerId); // Skąd przeciągamy
          }
      });

      slot.addEventListener('dragover', (e) => {
          e.preventDefault(); // Wymagane, aby drop działał
      });

      slot.addEventListener('drop', (e) => {
          e.preventDefault();
          const itemName = e.dataTransfer.getData('itemName');
          const itemType = e.dataTransfer.getData('itemType');
          const source = e.dataTransfer.getData('source');

          // Jeśli przeciągnięto z torby do ekwipunku
          if (source === 'inventoryContainer' && containerId === 'equipmentContainer') {
              const item = player.inventory.find(i => i.name === itemName && i.type === itemType);
              if (item) {
                  player.equipItem(item);
              }
          }

          // Jeśli przeciągnięto z ekwipunku do torby
          if (source === 'equipmentContainer' && containerId === 'inventoryContainer') {
              const item = player.equipment[itemType];
              if (item) {
                  player.unequipItem(itemType);
              }
          }

          player.updateInventoryUI(); // Aktualizacja interfejsu
          player.updateEquipmentUI();
      });

      slot.addEventListener('mouseenter', (event) => {
        const item = containerId === 'equipmentContainer'
            ? player.equipment[name]
            : player.inventory[index];
        if (item) {
            showItemDetails(event, item); // Wyświetl podpowiedź
        }
    });

    slot.addEventListener('mouseleave', hideItemDetails);
});
}


function showItemDetails(event, item) {
  const detailsElement = document.getElementById('item-info');

  if (item) {
      let statsInfo = `
          <center><strong>${item.name}</strong><br>
          Typ: ${item.type}<br>
      `;

      // Zależnie od typu przedmiotu wyświetlamy inne statystyki
      if (item.type === 'head') {
          statsInfo += `
              Pancerz: ${item.stats.armor || 0}<br>
              Siła: ${item.stats.strength || 0}<br>
              Zręczność: ${item.stats.dexterity || 0}<br>
              Intelekt: ${item.stats.intellect || 0}<br>
              <b>Wymagany poziom: ${item.levelRequirement || 0}</b> <br>
              Wartość: ${item.value || 0}
          `;
      } else if (item.type === 'body') {
          statsInfo += `
              Pancerz: ${item.stats.armor || 0}<br>
              Siła: ${item.stats.strength || 0}<br>
              Zręczność: ${item.stats.dexterity || 0}<br>
              Intelekt: ${item.stats.intellect || 0}<br>
              <b>Wymagany poziom: ${item.levelRequirement || 0}</b> <br>
              Wartość: ${item.value || 0}
          `;
      } else if (item.type === 'additional') {
          statsInfo += `
              Siła: ${item.stats.strength || 0}<br>
              Zręczność: ${item.stats.dexterity || 0}<br>
              Intelekt: ${item.stats.intellect || 0}<br>
              Życie: ${item.stats.maxHp || 0}<br>
              Pancerz: ${item.stats.armor || 0}<br>
              <b>Wymagany poziom: ${item.levelRequirement || 0}</b> <br>
              Wartość: ${item.value || 0}
          `;
      } else if (item.type === 'feet') {
          statsInfo += `
              Pancerz: ${item.stats.armor || 0}<br>
              <b>Wymagany poziom: ${item.levelRequirement || 0}</b> <br>
              Wartość: ${item.value || 0}
          `;
      } else if (item.type === 'weapon') {
          statsInfo += `
              Siła: ${item.stats.strength || 0}<br>
              Zręczność: ${item.stats.dexterity || 0}<br>
              Intelekt: ${item.stats.intellect || 0} <br>
              <b>Wymagany poziom: ${item.levelRequirement || 0}</b> <br>
              Wartość: ${item.value || 0}
          `;
      } else if (item.type === 'accessory') {
          statsInfo += `
              Siła: ${item.stats.strength || 0}<br>
              Zręczność: ${item.stats.dexterity || 0}<br>
              Intelekt: ${item.stats.intellect || 0}<br>
              Życie: ${item.stats.maxHp || 0}<br>
              <b>Wymagany poziom: ${item.levelRequirement || 0}</b> <br>
              Wartość: ${item.value || 0}
          `;
      } else if (item.type === 'consumable') {
          statsInfo += `
              Leczy: ${item.stats.health || 0}<br>
              Wartość: ${item.value || 0}
          `;
      } else {
          statsInfo += 'Brak dodatkowych statystyk';
      }

      statsInfo += '</center>';
      detailsElement.innerHTML = statsInfo;
      detailsElement.style.display = 'block';
      detailsElement.style.left = `${event.pageX + 10}px`;
      detailsElement.style.top = `${event.pageY + 10}px`;
  }
}


function hideItemDetails() {
  const detailsElement = document.getElementById('item-info');
  detailsElement.style.display = 'none';
  detailsElement.innerHTML = '';
}



function updateCamera() {
    cameraOffsetX = Math.max(0, Math.min(player.x - canvas.width / 2, map.width - canvas.width));
    cameraOffsetY = Math.max(0, Math.min(player.y - canvas.height / 2, map.height - canvas.height));
}

function updateUI() {
    const levelElement = document.getElementById('level');
    const experienceElement = document.getElementById('experience');
    const strengthElement = document.getElementById('strength');
    const dexterityElement = document.getElementById('dexterity');
    const intellectElement = document.getElementById('intellect');
    const goldElement = document.getElementById('gold');
    const hpElement = document.getElementById('hp');
    const chclass = document.getElementById('chclass');

    if (hpElement) hpElement.textContent = `Życie: ${player.hp}/${player.maxHp}`;
    if (levelElement) levelElement.textContent = `Poziom: ${player.level}`;
    if (chclass) chclass.textContent = `Klasa: ${player.characterClass}`;
    if (experienceElement) experienceElement.textContent = `Doświadczenie: ${player.experience}/${player.experienceToNextLevel()}`;
    if (strengthElement) strengthElement.textContent = `Siła: ${player.strength}`;
    if (dexterityElement) dexterityElement.textContent = `Zręczność: ${player.dexterity}`;
    if (intellectElement) intellectElement.textContent = `Intelekt: ${player.intellect}`;
    if (goldElement) goldElement.textContent = `Złoto: ${player.gold}`;

    // Aktualizacja torby
    const inventoryContainer = document.getElementById('inventoryContainer');
    player.inventory.forEach((item, index) => {
        const slot = inventoryContainer.children[index];
        if (slot) {
            slot.innerHTML = `<img src="${item.imageSrc}" alt="${item.name}">`;
        }
    });

    // Aktualizacja ekwipunku
    const equipmentContainer = document.getElementById('equipmentContainer');
    Object.entries(player.equipment).forEach(([key, item]) => {
        const slot = equipmentContainer.querySelector(`[data-index="${key}"]`);
        if (slot) {
            slot.innerHTML = item ? `<img src="${item.imageSrc}" alt="${item.name}">` : '';
        }
    });
}

// Dodajemy zdarzenie kliknięcia do obsługi interakcji z NPC
window.addEventListener('click', function(event) {
    const mouseX = event.clientX - canvas.offsetLeft + cameraOffsetX;
    const mouseY = event.clientY - canvas.offsetTop + cameraOffsetY;

    npcs.forEach(npc => {
        const distance = Math.hypot(player.x - npc.x, player.y - npc.y);
        if (distance < 50) {  // Zakładając, że odległość w pikselach do interakcji wynosi 50
            if (npc.shopItems.length > 0) {
                npc.openShop();  // Otwórz sklep, jeśli NPC ma przedmioty w sklepie
            } else {
                interactWithNPC(npc); // Inna interakcja, jeśli NPC nie ma sklepu
            }
        }
    });
});

window.onload = function() {
    initGame();
    addDragAndDropHandlers();
    player.load();
};

function checkPlayerDistanceToNPC() {
    npcs.forEach(npc => {
        const distance = Math.hypot(player.x - npc.x, player.y - npc.y);
        if (distance > 210) {  // Jeżeli gracz oddali się na więcej niż 50px
            npc.closeShop();  // Zamknij sklep, jeśli NPC nie jest wystarczająco blisko
        }
    });
}

class NPC {
  constructor(name, dialogue, healing = 0, shopItems = []) {
      this.name = name;
      this.dialogue = dialogue;
      this.healing = healing;
      this.currentDialogueIndex = 0;
      this.shopItems = shopItems;
      this.image = new Image();
      this.image.src = `assets/npcs/${name.toLowerCase()}.gif`; // Używamy .png dla spójności
      this.width = 32;
      this.height = 48;
  }

  talk() {
      if (this.currentDialogueIndex < this.dialogue.length) {
          console.log(`${this.name}: ${this.dialogue[this.currentDialogueIndex]}`);
          this.currentDialogueIndex++;
      } else {
          console.log(`${this.name}: Hej, jak się masz?`);
      }
  }

  heal(player) {
      if (this.healing > 0) {
          player.hp = player.maxHp;
      }
  }

  draw(ctx, cameraOffsetX, cameraOffsetY) {
      ctx.drawImage(this.image, this.x - cameraOffsetX, this.y - cameraOffsetY, this.width, this.height);
  }

  // Funkcja otwierająca sklep
  openShop() {
      const shopContainer = document.getElementById('shop'); // Miejsce na sklep w HTML
      shopContainer.innerHTML = ''; // Czyści sklep przed załadowaniem nowych przedmiotów

      // Ustawienie kontenera z 32 kratkami
      const gridItems = 30;

      // Dodajemy dostępne przedmioty do sklepu
      this.shopItems.forEach((item, index) => {
          const itemDiv = document.createElement('div');
          itemDiv.classList.add('shop-item');
          const itemImage = document.createElement('img');
          itemImage.src = item.imageSrc; // Obrazek przedmiotu
          itemImage.alt = item.name;
          itemDiv.appendChild(itemImage);

          // Dodajemy tooltip
          itemDiv.addEventListener('mouseover', (e) => this.showItemDetails(e, item));
          itemDiv.addEventListener('mouseout', this.hideItemDetails);

          // Dodajemy zdarzenie na kliknięcie do zakupu przedmiotu
          itemDiv.addEventListener('click', () => {
              this.buyItem(item);
          });

          shopContainer.appendChild(itemDiv);
      });

      // Dodajemy puste kratki (pozostałe, jeśli przedmiotów jest mniej niż 32)
      for (let i = this.shopItems.length; i < gridItems; i++) {
          const emptyDiv = document.createElement('div');
          shopContainer.appendChild(emptyDiv);
      }
  }

  closeShop() {
      const shopContainer = document.getElementById('shop');
      shopContainer.innerHTML = '';  // Usuwa wszystkie przedmioty i przycisk
  }

  // Funkcja realizująca zakup przedmiotu
  buyItem(item) {
      if (player.gold >= item.value) {
          player.gold -= item.value;
          player.inventory.push(item);  // Dodanie przedmiotu do ekwipunku gracza
          console.log(`Zakupiono przedmiot: ${item.name}`);
      } else {
          console.log('Nie masz wystarczająco złota!');
      }
  }

  // Funkcja wyświetlająca szczegóły przedmiotu w tooltipie
  showItemDetails(event, item) {
    const detailsElement = document.getElementById('item-info');

    if (item) {
        let statsInfo = `
            <center><strong>${item.name}</strong><br>
            Typ: ${item.type}<br>
        `;
        
        // Zależnie od typu przedmiotu, wyświetlamy inne statystyki
        if (item.type === 'head') {
            statsInfo += `
                Pancerz: ${item.stats.armor || 0}<br>
                Siła: ${item.stats.strength || 0}<br>
                Zręczność: ${item.stats.dexterity || 0}<br>
                Intelekt: ${item.stats.intellect || 0}<br>
              <b>Wymagany poziom: ${item.levelRequirement || 0}</b> <br>
              Wartość: ${item.value || 0}
            `;
        } else if (item.type === 'body') {
            statsInfo += `
              Pancerz: ${item.stats.armor || 0}<br>
                Siła: ${item.stats.strength || 0}<br>
                Zręczność: ${item.stats.dexterity || 0}<br>
                Intelekt: ${item.stats.intellect || 0}<br>
              <b>Wymagany poziom: ${item.levelRequirement || 0}</b> <br>
              Wartość: ${item.value || 0}
            `;
        } else if (item.type === 'additional') {
            statsInfo += `
                Siła: ${item.stats.strength || 0}<br>
                Zręczność: ${item.stats.dexterity || 0}<br>
                Intelekt: ${item.stats.intellect || 0}<br>
                Życie: ${item.stats.maxHp || 0}<br>
                Pancerz: ${item.stats.armor || 0}<br>
              <b>Wymagany poziom: ${item.levelRequirement || 0}</b> <br>
              Wartość: ${item.value || 0}
            `;
        } else if (item.type === 'feet') {
            statsInfo += `
                Pancerz: ${item.stats.armor || 0}<br>
              <b>Wymagany poziom: ${item.levelRequirement || 0}</b> <br>
              Wartość: ${item.value || 0}
            `;
        } else if (item.type === 'weapon') {
            statsInfo += `
                Siła: ${item.stats.strength || 0}<br>
                Zręczność: ${item.stats.dexterity || 0}<br>
                Intelekt: ${item.stats.intellect || 0} <br>
              <b>Wymagany poziom: ${item.levelRequirement || 0}</b> <br>
              Wartość: ${item.value || 0}
            `;
        } else if (item.type === 'accessory') {
            statsInfo += `
                Siła: ${item.stats.strength || 0}<br>
                Zręczność: ${item.stats.dexterity || 0}<br>
                Intelekt: ${item.stats.intellect || 0}<br>
                Życie: ${item.stats.maxHp || 0}<br>
              <b>Wymagany poziom: ${item.levelRequirement || 0}</b> <br>
              Wartość: ${item.value || 0}
            `;
        } else if (item.type === 'consumable') {
            statsInfo += `
                Leczy: ${item.stats.health || 0}<br>
              Wartość: ${item.value || 0}
            `;
        } else {
            statsInfo += 'Brak dodatkowych statystyk';
        }

        statsInfo += `</center>`;
        detailsElement.innerHTML = statsInfo;

        // Ustawiamy pozycję tooltipu na podstawie kursora
        const offsetX = 10; // Odstęp od kursora
        const offsetY = 10; // Odstęp od kursora

        detailsElement.style.left = `${event.pageX + offsetX}px`;
        detailsElement.style.top = `${event.pageY + offsetY}px`;

        detailsElement.style.display = 'block'; // Ustawiamy, by tooltip był widoczny
    }
}

  // Funkcja ukrywająca tooltip
  hideItemDetails() {
      const detailsElement = document.getElementById('item-info');
      detailsElement.style.display = 'none';
      detailsElement.innerHTML = '';
  }
}

class Zofia extends NPC {
  constructor(x, y) {
      super("Zofia", ["Witaj, podróżniku! Z chęcią przywrócę Twoje zdrowie!"], 30);
      this.x = x;
      this.y = y;
  }

  heal(player) {
      if (player.hp < player.maxHp) {
          super.heal(player);
      }
  }
}

class Gustaw extends NPC {
  constructor(x, y) {
      const dialogue = ["Witaj, podróżniku! Zajrzyj do mojego sklepu!"];
      const shopItems = [
          new Item('Szata łowcy', 'body', { strength: 3, dexterity: 8, intellect: 0, armor: 2 }, 'assets/images/zbrojalow1.gif', 0, 1),
          new Item('Łowiecka bandana', 'head', { strength: 2, dexterity: 2, intellect: 0, armor: 2 }, 'assets/images/helmlow1.gif', 0, 1),
          new Item('Łuk I', 'weapon', { strength: 0, dexterity: 5, intellect: 0}, 'assets/images/luk01.gif', 0, 1),
          new Item('Strzały I', 'additional', { strength: 0, dexterity: 5, intellect: 0, armor: 0, maxHp: 0 }, 'assets/images/strzaly1.gif', 0, 1),
          new Item('Dziurawe skarpety', 'feet', { armor: 1 }, 'assets/images/buty1.gif', 0, 1),
          new Item('Naszyjnik blasku', 'accessory', { strength: 1, dexterity: 2, intellect: 5, armor: 0, maxHp:100 }, 'assets/images/naszyj1.gif', 0, 1),
          new Item('Mikstura', 'consumable', { health: 50 }, 'assets/images/potka1.gif', 1, 1)
      ];
      super("Gustaw", dialogue, 0, shopItems);
      this.x = x;
      this.y = y;
  }
}


///////////////////////////////////////


class Enemies {
    constructor() {
        this.enemies = [
            this.createEnemy(400, 270, 32, 48, 100, 'assets/images/krolik.gif', 'Królik', 1, 2),
            this.createEnemy(600, 200, 32, 48, 100, 'assets/images/zuk.gif', 'Żuk', 2, 4),
            this.createEnemy(480, 440, 32, 48, 100, 'assets/images/zajac.gif', 'Zając', 3, 6),
            this.createEnemy(520, 580, 32, 48, 100, 'assets/images/szczur1.gif', 'Szczur', 5, 12),
            this.createEnemy(440, 620, 32, 48, 100, 'assets/images/szczur2.gif', 'Szczur Królewski', 7, 24),
        ];
  
        // Obsługa kliknięcia
        canvas.addEventListener('click', (e) => this.handleClick(e));
    }
  
    createEnemy(x, y, width, height, hp, imageSrc, name, level, strength) {
        const image = new Image();
        image.src = imageSrc;
  
   return {
        x: x,
        y: y,
        width: width,
        height: height,
        hp: hp,
        maxHp: hp,
        isAlive: true,
        respawnTimer: 0,
        image: image,
        name: name,
        level: level,
        strength: strength,
        baseExp: 15 * level,
        attackPlayer: function() {
          const damage = Math.floor(Math.random() * 5) + this.strength;
          const damageTaken = player.receiveDamage(damage);
          return damageTaken;
        }
        };
    }
  
    update(ctx, cameraOffsetX = 0, cameraOffsetY = 0) {
        for (let enemy of this.enemies) {
            if (enemy.isAlive) {
                this.draw(ctx, enemy, cameraOffsetX, cameraOffsetY);
            } else {
                enemy.respawnTimer += 1;
                if (enemy.respawnTimer >= 300) { // 5 sekund w 60 FPS
                    enemy.isAlive = true;
                    enemy.hp = enemy.maxHp;
                    enemy.respawnTimer = 0;
                }
            }
        }
    }
  
    draw(ctx, enemy, offsetX = 0, offsetY = 0) {
        if (enemy.isAlive) {
            // Rysowanie obrazu wroga
            ctx.drawImage(
                enemy.image,
                0, 0, 
                enemy.width, enemy.height,
                enemy.x - offsetX, enemy.y - offsetY, 
                enemy.width, enemy.height
            );
  
            // Rysowanie paska zdrowia
            ctx.fillStyle = 'red';
            ctx.fillRect(enemy.x - offsetX, enemy.y - offsetY - 10, enemy.width, 5);
            ctx.fillStyle = 'green';
            ctx.fillRect(enemy.x - offsetX, enemy.y - offsetY - 10, enemy.width * (enemy.hp / enemy.maxHp), 5);
  
            // Rysowanie nazwy i poziomu wroga
            ctx.fillStyle = 'white';
            ctx.font = '12px Arial';
            ctx.fillText(`${enemy.name} (Lv ${enemy.level})`, enemy.x - offsetX, enemy.y - offsetY - 15);
        }
    }
  
    handleClick(event) {
        const rect = canvas.getBoundingClientRect();
        const clickX = event.clientX - rect.left + cameraOffsetX;
        const clickY = event.clientY - rect.top + cameraOffsetY;
  
        for (let enemy of this.enemies) {
            if (enemy.isAlive && 
                clickX >= enemy.x && clickX <= enemy.x + enemy.width &&
                clickY >= enemy.y && clickY <= enemy.y + enemy.height) {
                
                // Sprawdzenie, czy gracz jest blisko
                const distance = Math.hypot(player.x - enemy.x, player.y - enemy.y);
                if (distance <= 100) { // Zasięg ataku
                    this.startCombat(enemy);
                }
            }
        }
    }
  
  
    startCombat(enemy) {
      const playerDamage = player.attack(enemy);
  
      if (enemy.hp > 0) {
        const enemyDamage = enemy.attackPlayer(); // Teraz obrażenia zależą od siły
        this.updateCombatLog(playerDamage, enemyDamage, enemy.name, enemy.level);
      } else {
        const expGained = this.calculateExpGain(enemy);
        this.updateCombatLog(playerDamage, 0, enemy.name, enemy.level, expGained); // Wróg zginął
      }
    }
  
    calculateExpGain(enemy) {
      const levelDifference = player.level - enemy.level;
      let expGain = enemy.baseExp;
  
      if (levelDifference >= 5) {
          expGain = Math.floor(expGain * 0.2); // Gracz jest o 5+ poziomów wyższy - 20% EXP
      } else if (levelDifference >= 3) {
          expGain = Math.floor(expGain * 0.5); // Gracz jest o 3-4 poziomy wyższy - 50% EXP
      } else if (levelDifference >= 1) {
          expGain = Math.floor(expGain * 0.9); // Gracz jest o 1-2 poziomy wyższy - 90% EXP
      }
      // W przeciwnym razie pełne EXP
      return expGain;
    }
  
    updateCombatLog(playerDamage, enemyDamage, enemyName, enemyLevel, expGained = 0) {
      const combatLog = document.getElementById('combat-log');
      const combatText = document.getElementById('combat-text');
  
      combatText.innerHTML = `Zadałeś ${playerDamage} obrażeń ${enemyName} (Lv ${enemyLevel}).<br>Wróg zadał ${enemyDamage} obrażeń.`;
  
      if (expGained > 0) {
          combatText.innerHTML += `<br>Zyskałeś ${expGained} EXP.`;
      }
  
      // Pokaż okno logu walki
      combatLog.style.display = 'block';
  
      // Ukryj okno po 3 sekundach
      setTimeout(() => {
          combatLog.style.display = 'none';
      }, 2000);
    }
  }

  class Item {
    constructor(name, type, stats, imageSrc, value, levelRequirement = 0) {
      this.name = name;
      this.type = type;
      this.stats = stats;
      this.imageSrc = imageSrc;
      this.value = value;
      this.levelRequirement = levelRequirement;
    }
  }
  
  const luk1 = new Item('Łuk I', 'weapon', {
    strength: 0,
    dexterity: 5,
    intellect: 0,
  }, 'assets/images/luk01.gif', 3, 1);
  
  
  const helm1 = new Item('Czerep', 'head', {
    strength: 2,
    dexterity: 1,
    intellect: 0,
    armor: 1
  }, 'assets/images/helmwoj1.gif', 2, 2);
  
  // Możesz dodać więcej przedmiotów w podobny sposób
  
  document.getElementById('inventoryContainer').addEventListener('drop', (e) => {
    e.preventDefault();
    const itemName = e.dataTransfer.getData('text/plain');
    const item = player.inventory.find(i => i.name === itemName);
  
    if (item) {
        player.equipItem(item); // Wywołanie odpowiedniej metody
        player.updateInventoryUI();
        player.updateEquipmentUI();
    } else {
        console.log('Przedmiot nie został znaleziony w torbie.');
    }
  });
  
  
  function addDragAndDropHandlers() {
    const inventorySlots = document.querySelectorAll('#inventoryContainer .inventory-slot');
    inventorySlots.forEach(slot => {
      slot.addEventListener('dragstart', (e) => {
        const index = e.target.dataset.index;
        const item = player.inventory[index];
        if (item) {
          e.dataTransfer.setData('text/plain', item.name);
          e.dataTransfer.setData('item-type', item.type);
        }
      });
    });
  
    const equipmentSlots = document.querySelectorAll('#equipmentContainer .inventory-slot');
    equipmentSlots.forEach(slot => {
      slot.addEventListener('dragover', (e) => e.preventDefault());
      slot.addEventListener('drop', (e) => {
        e.preventDefault();
        const itemName = e.dataTransfer.getData('text/plain');
        const itemType = e.dataTransfer.getData('item-type');
        const item = player.inventory.find(i => i.name === itemName && i.type === itemType);
        
        if (slot.dataset.index && item) { // Ensure item exists and slot is valid
          player.equipItem(item);
          updateUI(); // Ensure UI is updated
        }
      });
    });
  }

  class Map {
    constructor(imageSrc, width, height, collisionGrid, tileSize = 32) {
      this.image = new Image();
      this.image.src = imageSrc;
      this.width = width;
      this.height = height;
      this.tileSize = tileSize;
      this.collisionGrid = collisionGrid;
      this.colliders = [];
      this.debugMode = false; // Flaga kontrolująca widoczność kolizji
      this.processCollisionGrid();
    }
  
    processCollisionGrid() {
      for (let y = 0; y < this.collisionGrid.length; y++) {
        for (let x = 0; x < this.collisionGrid[y].length; x++) {
          const cell = this.collisionGrid[y][x];
          if (cell === 1) {
            this.addCollider(x * this.tileSize, y * this.tileSize, this.tileSize, this.tileSize);
          } else if (cell === 2) {
            // Przykład: Dodanie przejścia na inną mapę
            this.addCollider(x * this.tileSize, y * this.tileSize, this.tileSize, this.tileSize, true);
          }
        }
      }
    }
  
    addCollider(x, y, width, height, isPortal = false) {
      this.colliders.push({ x, y, width, height, isPortal });
    }
  
    draw(ctx, offsetX = 0, offsetY = 0) {
      ctx.drawImage(this.image, -offsetX, -offsetY, this.width, this.height);
  
      if (this.debugMode) {
        // Rysowanie kolizji tylko w trybie debugowania
        this.colliders.forEach(collider => {
          ctx.strokeStyle = collider.isPortal ? 'blue' : 'red';
          ctx.strokeRect(collider.x - offsetX, collider.y - offsetY, collider.width, collider.height);
        });
      }
    }
  
    checkCollision(playerX, playerY, playerWidth, playerHeight) {
      const toleranceX = 16; // Tolerancja dla nachodzenia w osi X (w pikselach)
      const toleranceY = 4; // Tolerancja dla nachodzenia w osi Y (w pikselach)
  
      for (let collider of this.colliders) {
        const collX = collider.x;
        const collY = collider.y;
        const collWidth = collider.width;
        const collHeight = collider.height;
  
        // Sprawdzamy, czy jakakolwiek część gracza nachodzi na kolizję z tolerancją
        if (
          playerX + playerWidth - toleranceX > collX &&
          playerX + toleranceX < collX + collWidth &&
          playerY + playerHeight - toleranceY > collY &&
          playerY + toleranceY < collY + collHeight
        ) {
          // Dostosowanie pozycji gracza, aby nie nachodził na kolizję
          if (playerX + playerWidth - toleranceX > collX && playerX + toleranceX < collX + collWidth) {
            // Kolizja w osi X
            if (playerX < collX) {
              // Gracz znajduje się po lewej stronie kolizji
              playerX = collX - playerWidth + toleranceX; // Przyciągnięcie gracza do lewej krawędzi kolizji
            } else if (playerX + playerWidth > collX + collWidth) {
              // Gracz znajduje się po prawej stronie kolizji
              playerX = collX + collWidth - toleranceX; // Przyciągnięcie gracza do prawej krawędzi kolizji
            }
          }
  
          if (playerY + playerHeight - toleranceY > collY && playerY + toleranceY < collY + collHeight) {
            // Kolizja w osi Y
            if (playerY < collY) {
              // Gracz znajduje się powyżej kolizji
              playerY = collY - playerHeight + toleranceY; // Przyciągnięcie gracza do góry kolizji
            } else if (playerY + playerHeight > collY + collHeight) {
              // Gracz znajduje się poniżej kolizji
              playerY = collY + collHeight - toleranceY; // Przyciągnięcie gracza do dołu kolizji
            }
          }
  
          if (collider.isPortal) {
            console.log("Przejście na inną mapę!");
            // Tutaj zaimplementuj zmianę mapy
          }
  
          return true;
        }
      }
      return false;
    }
  
    toggleDebugMode() {
      this.debugMode = !this.debugMode;
    }
  }
  
  //map.toggleDebugMode(); sprawdzanie kolizji

  class Player {
    constructor(mapWidth, mapHeight, characterClass) {
      this.x = 96;
      this.y = 100;
      this.width = 32;
      this.height = 48;
      this.speed = 0.7;
      this.armor = 0;
      this.direction = 'down';
      this.currentFrame = 0;
      this.frameTimer = 0;
      this.frameDelay = 10;
      this.mapWidth = mapWidth;
      this.mapHeight = mapHeight;
  
      // Wybór klasy postaci
      this.characterClass = characterClass || 'Wojownik';
      this.setInitialStats();
      this.setGraphicsAndAnimations();
  
      // Ekwipunek
      this.equipment = {
        head: null,
        body: null,
        additional: null,
        feet: null,
        weapon: null,
        accessory: null
      };
  
      // Torba
      this.inventory = [];
  
      // Obiekt do zarządzania klawiaturą
      this.keys = {};
      window.addEventListener('keydown', (e) => this.keys[e.key] = true);
      window.addEventListener('keyup', (e) => this.keys[e.key] = false);
    }
  
    setInitialStats() {
      switch(this.characterClass) {
        case 'Wojownik':
          this.level = 1;
          this.hp = 400;
          this.maxHp = 400;
          this.experience = 0;
          this.strength = 5;
          this.dexterity = 3;
          this.intellect = 2;
          break;
        case 'Łowca':
          this.level = 1;
          this.hp = 300;
          this.maxHp = 300;
          this.experience = 0;
          this.strength = 4;
          this.dexterity = 5;
          this.intellect = 3;
          break;
        case 'Mag':
          this.level = 1;
          this.hp = 250;
          this.maxHp = 250;
          this.experience = 0;
          this.strength = 2;
          this.dexterity = 3;
          this.intellect = 6;
          break;
      }
      this.gold = 0;
      this.calculateArmor();
    }
  
    setGraphicsAndAnimations() {
      // Wybór grafiki i animacji w zależności od klasy postaci
      this.image = new Image();
      switch(this.characterClass) {
        case 'Wojownik':
          this.image.src = 'assets/images/outfit/warrior.gif';
          this.animations = {
            'down': { start: 0, end: 3, row: 0 },
            'left': { start: 4, end: 7, row: 1 },
            'right': { start: 8, end: 11, row: 2 },
            'up': { start: 12, end: 15, row: 3 }
          };
          break;
        case 'Łowca':
          this.image.src = 'assets/images/outfit/hunter.gif';
          this.animations = {
            'down': { start: 0, end: 3, row: 0 },
            'left': { start: 4, end: 7, row: 1 },
            'right': { start: 8, end: 11, row: 2 },
            'up': { start: 12, end: 15, row: 3 }
          };
          break;
        case 'Mag':
          this.image.src = 'assets/images/outfit/mage.gif';
          this.animations = {
            'down': { start: 0, end: 3, row: 0 },
            'left': { start: 4, end: 7, row: 1 },
            'right': { start: 8, end: 11, row: 2 },
            'up': { start: 12, end: 15, row: 3 }
          };
          break;
      }
    }
  
    calculateAttackDamage() {
      let baseDamage = 0;
      switch (this.characterClass) {
        case 'Wojownik':
          baseDamage = Math.floor(Math.random() * 10) + this.strength;
          break;
        case 'Łowca':
          baseDamage = Math.floor(Math.random() * 10) + this.dexterity;
          break;
        case 'Mag':
          baseDamage = Math.floor(Math.random() * 10) + this.intellect;
          break;
      }
  
      // Szansa na krytyczne uderzenie
      const criticalChance = this.intellect * 0.002; // 0.2% szansy na krytyka na każdy punkt intelektu
      if (Math.random() < criticalChance) {
        baseDamage *= 3; // Krytyczne uderzenie potraja obrażenia
        console.log('Krytyczne uderzenie!');
      }
  
      return baseDamage;
    }
  
    // Metoda obliczająca szansę na unik
    calculateDodgeChance() {
      return this.dexterity * 0.001; // 1% szansy na unik na każdy punkt zręczności
    }
  
    // Metoda obliczająca obrażenia po uwzględnieniu pancerza
    takeDamage(amount) {
      const reducedDamage = Math.max(amount - this.armor, 0); // Obrażenia po uwzględnieniu pancerza
      this.hp -= reducedDamage;
      if (this.hp <= 0) {
        this.hp = 0;
        alert('Zginąłeś!');
        // Możesz dodać restart gry lub inne działania
      }
      return reducedDamage;
    }
  
    calculateArmor() {
      this.armor = Math.floor(this.strength / 5); // Przykładowa formuła, która zwiększa pancerz o 5 wartości siły
    }
    
    update(ctx, cameraOffsetX = 0, cameraOffsetY = 0) {
      let moved = this.handleMovement();
      if (moved) {
        this.handleAnimation();
      } else {
        this.currentFrame = this.animations[this.direction].start;
      }
  
      this.draw(ctx, cameraOffsetX, cameraOffsetY);
    }
  
    draw(ctx, offsetX = 0, offsetY = 0) {
      const anim = this.animations[this.direction];
      const frameX = (this.currentFrame % (anim.end - anim.start + 1)) * this.width;
      const frameY = anim.row * this.height;
  
      ctx.drawImage(
        this.image,
        frameX,
        frameY,
        this.width,
        this.height,
        this.x - offsetX,
        this.y - offsetY,
        this.width,
        this.height
      );
    }
  
    handleMovement() {
      let newX = this.x;
      let newY = this.y;
      let moved = false;
  
      if (this.keys['ArrowLeft']) {
        newX -= this.speed;
        this.direction = 'left';
        moved = true;
      }
      if (this.keys['ArrowRight']) {
        newX += this.speed;
        this.direction = 'right';
        moved = true;
      }
      if (this.keys['ArrowUp']) {
        newY -= this.speed;
        this.direction = 'up';
        moved = true;
      }
      if (this.keys['ArrowDown']) {
        newY += this.speed;
        this.direction = 'down';
        moved = true;
      }
  
      // Ograniczenia ruchu gracza
      if (newX < 0) newX = 0;
      if (newY < 0) newY = 0;
      if (newX + this.width > this.mapWidth) newX = this.mapWidth - this.width;
      if (newY + this.height > this.mapHeight) newY = this.mapHeight - this.height;
  
      this.x = newX;
      this.y = newY;
  
      return moved;
    }
  
    handleAnimation() {
      this.frameTimer++;
      if (this.frameTimer >= this.frameDelay) {
        this.frameTimer = 0;
        this.currentFrame++;
        const anim = this.animations[this.direction];
        if (this.currentFrame > anim.end) {
          this.currentFrame = anim.start;
        }
      }
    }
  
    addItemToInventory(item) {
      if (!this.inventory.find(i => i.name === item.name) && !Object.values(this.equipment).includes(item)) {
        this.inventory.push(item);
        this.updateInventoryUI();
      }
    }
  
    equipItem(item) {
      if (!item) {
          console.log('Przedmiot nie istnieje.');
          return;
      }
  
      console.log(`Próba założenia: ${item.name}`);
  
      // Sprawdzenie, czy slot istnieje
      if (!(item.type in this.equipment)) {
          console.log(`Brak slotu dla typu: ${item.type}`);
          return;
      }
  
      // Sprawdzenie, czy spełniono wymagania
      if (this.level < (item.levelRequirement || 0)) {
          console.log(`Za niski poziom, aby założyć ${item.name}`);
          return;
      }
  
      // Załóż przedmiot
      this.equipment[item.type] = item;
      this.inventory = this.inventory.filter(i => i !== item);
  
      // Aktualizacja statystyk i interfejsu
      this.updateStats(item, true);
      this.updateInventoryUI();
      this.updateEquipmentUI();
      console.log(`${item.name} został założony.`);
  }
  
  
  
  unequipItem(itemType) {
      const item = this.equipment[itemType];
      if (item) {
          if (this.inventory.length >= this.maxInventorySize) { // Możliwe ograniczenie torby
              console.log('Brak miejsca w torbie, nie można zdjąć przedmiotu.');
              return;
          }
          this.updateStats(item, false);
          this.inventory.push(item);
          this.equipment[itemType] = null;
          this.updateInventoryUI();
          this.updateEquipmentUI();
          console.log(`${item.name} został zdjęty.`);
      } else {
          console.log(`Nie ma przedmiotu w slocie ${itemType}.`);
      }
  }
  
  
    updateStats(item, adding = true) {
      if (item && item.stats) {
          this.strength += (item.stats.strength || 0) * (adding ? 1 : -1);
          this.dexterity += (item.stats.dexterity || 0) * (adding ? 1 : -1);
          this.intellect += (item.stats.intellect || 0) * (adding ? 1 : -1);
          this.armor += (item.stats.armor || 0) * (adding ? 1 : -1);
          this.maxHp += (item.stats.maxHp || 0) * (adding ? 1 : -1);
          this.gold += (item.stats.gold || 0) * (adding ? 1 : -1);
      }
    }
  
    updateInventoryUI() {
      const inventoryContainer = document.getElementById('inventoryContainer');
      const slots = inventoryContainer.children;
  
      for (let i = 0; i < slots.length; i++) {
          const slot = slots[i];
          const item = this.inventory[i]; // Pobierz przedmiot z torby dla tego slotu
  
          // Usuń istniejące obrazki, aby zapobiec duplikatom
          while (slot.firstChild) {
              slot.removeChild(slot.firstChild);
          }
  
          // Jeśli przedmiot istnieje, dodaj obrazek i przypisz zdarzenie
          if (item) {
              const img = document.createElement('img');
              img.src = item.imageSrc;
              img.alt = item.name;
              img.title = item.name;
  
              // Dodaj zdarzenie kliknięcia
              img.addEventListener('click', () => {
                  console.log(`Kliknięto na przedmiot: ${item.name}`);
                  this.equipItem(item); // Zakładanie przedmiotu
                  this.updateInventoryUI(); // Aktualizacja UI
                  this.updateEquipmentUI();
              });
  
              slot.appendChild(img);
          }
      }
  }
  
    updateEquipmentUI() {
      const equipmentContainer = document.getElementById('equipmentContainer');
  
      Object.entries(this.equipment).forEach(([type, item]) => {
          const slot = equipmentContainer.querySelector(`[data-index="${type}"]`);
          if (slot) {
              slot.innerHTML = item
                  ? `<img src="${item.imageSrc}" alt="${item.name}" title="${item.name}">`
                  : '';
          }
      });
  }
  
  
    setupDropzones() {
      const equipmentContainer = document.getElementById('equipmentContainer');
      equipmentContainer.addEventListener('dragover', (e) => {
        e.preventDefault();
      });
  
      equipmentContainer.addEventListener('drop', (e) => {
        e.preventDefault();
        const itemName = e.dataTransfer.getData('text/plain');
        const itemType = e.dataTransfer.getData('item-type');
    
        const item = this.inventory.find(i => i.name === itemName && i.type === itemType);
        if (item) {
            this.equipItem(item); // Obsługa weryfikacji poziomu
        }
    });
    
    inventoryContainer.addEventListener('click', (e) => {
      if (e.target.tagName === 'IMG') { // Sprawdź, czy kliknięto obrazek
          const index = e.target.parentElement.dataset.index;
          const item = player.inventory[index];
          if (item) {
              console.log(`Zakładanie przedmiotu: ${item.name}`);
              player.equipItem(item);
              player.updateInventoryUI(); // Aktualizuj UI
              player.updateEquipmentUI();
          }
      }
  });
  
  
    
  
      const inventoryContainer = document.getElementById('inventoryContainer');
      inventoryContainer.addEventListener('dragover', (e) => {
        e.preventDefault();
      });
  
      inventoryContainer.addEventListener('drop', (e) => {
        e.preventDefault();
        const itemName = e.dataTransfer.getData('text/plain');
        const item = this.inventory.find(i => i.name === itemName);
        if (item) {
          this.equipItem(item);
        }
      });
    }
  
    adminAddItem(item) {
      if (item instanceof Item) {
        this.addItemToInventory(item);
      }
    }
  
    // Metoda wywołująca atak na wroga
    attack(enemy) {
      const damage = this.calculateAttackDamage();
      enemy.hp -= damage;
      if (enemy.hp <= 0) {
          enemy.hp = 0;
          enemy.isAlive = false;
          const expGained = enemy.baseExp;
          this.gainExperience(expGained);
      }
      return damage;
    }
  
    // Metoda przyjmująca obrażenia od wroga
    receiveDamage(amount) {
      const dodgeChance = this.calculateDodgeChance();
      if (Math.random() < dodgeChance) {
        // Uniknięcie ataku
        return 0;
      }
  
      // Oblicz obrażenia po uwzględnieniu pancerza
      return this.takeDamage(amount);
    }
    gainExperience(exp) {
      this.experience += exp;
      if (this.experience >= this.level * 175) {
          this.levelUp();
      }
    }
  
    experienceToNextLevel() {
      return this.level * 175;
    }
  
    levelUp() {
      this.level += 1;
      this.experience = 0;
  
      // Zmienne do przechowywania przyrostów
      let hpGain = 0;
      let strengthGain = 0;
      let dexterityGain = 0;
      let intellectGain = 0;
  
      // Przyrost zdrowia, siły, zręczności i intelektu w zależności od klasy
      switch (this.characterClass) {
          case 'Wojownik':
              hpGain = this.level * 125;
              strengthGain = 3;
              dexterityGain = 1;
              intellectGain = 1;
              break;
          case 'Łowca':
              hpGain = this.level * 100;
              strengthGain = 2;
              dexterityGain = 3;
              intellectGain = 1;
              break;
          case 'Mag':
              hpGain = this.level * 75;
              strengthGain = 1;
              dexterityGain = 2;
              intellectGain = 4;
              break;
      }
  
      this.maxHp += hpGain;
      this.strength += strengthGain;
      this.dexterity += dexterityGain;
      this.intellect += intellectGain;
  
      // Ustawienie aktualnych wartości zdrowia
      this.hp = this.maxHp;
      this.calculateArmor();
  
      // Wyświetlenie powiadomienia o awansie z szczegółami
      this.showLevelUpNotification(`<strong>Awansowałeś na poziom ${this.level}!</strong>\n` +
        `Siła: +${strengthGain}\n` +
        `Zręczność: +${dexterityGain}\n` +
        `Intelekt: +${intellectGain}`);
  }
  
  showLevelUpNotification(message) {
    const notification = document.getElementById('level-up-notification');
    const messageElement = document.getElementById('level-up-message');
  
    // Ustawienie tekstu z użyciem HTML, aby przejścia linii były widoczne
    messageElement.innerHTML = message.replace(/\n/g, '<br>');
  
    notification.style.display = 'flex';
    notification.style.flexDirection = 'column'; // Ustawienie kierunku kolumny, aby linie były jedna pod drugą
    notification.style.alignItems = 'flex-start'; // Ustawienie wyrównania do początku osi głównej
  
    // Ukryj komunikat po 3 sekundach
    setTimeout(() => {
        notification.style.display = 'none';
    }, 3000);
  }
  
  
    save() {
      const playerData = {
        x: this.x,
        y: this.y,
        width: this.width,
        height: this.height,
        speed: this.speed,
        armor: this.armor,
        direction: this.direction,
        currentFrame: this.currentFrame,
        frameTimer: this.frameTimer,
        frameDelay: this.frameDelay,
        mapWidth: this.mapWidth,
        mapHeight: this.mapHeight,
        characterClass: this.characterClass,
        level: this.level,
        hp: this.hp,
        maxHp: this.maxHp,
        experience: this.experience,
        strength: this.strength,
        dexterity: this.dexterity,
        intellect: this.intellect,
        gold: this.gold,
        equipment: this.equipment,
        inventory: this.inventory
      };
  
      localStorage.setItem('playerData', JSON.stringify(playerData));
      console.log('Dane postaci zostały zapisane.');
    }
  
    load() {
      const savedData = localStorage.getItem('playerData');
      if (savedData) {
        const playerData = JSON.parse(savedData);
        this.x = playerData.x;
        this.y = playerData.y;
        this.width = playerData.width;
        this.height = playerData.height;
        this.speed = playerData.speed;
        this.armor = playerData.armor;
        this.direction = playerData.direction;
        this.currentFrame = playerData.currentFrame;
        this.frameTimer = playerData.frameTimer;
        this.frameDelay = playerData.frameDelay;
        this.mapWidth = playerData.mapWidth;
        this.mapHeight = playerData.mapHeight;
        this.characterClass = playerData.characterClass;
        this.setGraphicsAndAnimations(); // Ustaw grafikę po wczytaniu danych
        this.level = playerData.level;
        this.hp = playerData.hp;
        this.maxHp = playerData.maxHp;
        this.experience = playerData.experience;
        this.strength = playerData.strength;
        this.dexterity = playerData.dexterity;
        this.intellect = playerData.intellect;
        this.gold = playerData.gold;
        this.equipment = playerData.equipment;
        this.inventory = playerData.inventory;
  
        console.log('Dane postaci zostały wczytane.');
      } else {
        console.log('Brak zapisanych danych.');
      }
    }
  
    reset() {
      // Przywróć wartości domyślne dla postaci
      this.x = 96;
      this.y = 100;
      this.width = 32;
      this.height = 48;
      this.speed = 0.7;
      this.direction = 'down';
      this.currentFrame = 0;
      this.frameTimer = 0;
      this.frameDelay = 10;
      this.armor = 0;
      this.mapWidth = 800; // Przykładowa szerokość mapy
      this.mapHeight = 600; // Przykładowa wysokość mapy
      this.characterClass = 'Wojownik';
      this.setInitialStats();
      this.setGraphicsAndAnimations(); // Ustaw grafikę po resecie
      this.equipment = {
        head: null,
        body: null,
        additional: null,
        feet: null,
        weapon: null,
        accessory: null
      };
      this.inventory = [];
      this.gold = 0;
  
      console.log('Dane postaci zostały zresetowane.');
    }
  }
  
  // Dodaj obsługę kliknięcia dla przycisków
  document.getElementById('save-button').addEventListener('click', () => player.save());
  document.getElementById('load-button').addEventListener('click', () => player.load());
  document.getElementById('reset-button').addEventListener('click', () => player.reset());
  
  // Obsługa przycisków klas
  document.getElementById('warrior-class').addEventListener('click', () => {
    player.characterClass = 'Wojownik';
    player.setInitialStats();
    player.setGraphicsAndAnimations(); // Ustaw grafikę po zmianie klasy
  });
  
  document.getElementById('hunter-class').addEventListener('click', () => {
    player.characterClass = 'Łowca';
    player.setInitialStats();
    player.setGraphicsAndAnimations(); // Ustaw grafikę po zmianie klasy
  });
  
  document.getElementById('mage-class').addEventListener('click', () => {
    player.characterClass = 'Mag';
    player.setInitialStats();
    player.setGraphicsAndAnimations(); // Ustaw grafikę po zmianie klasy
  });
                                
                            

Paste Hosted With By Wklejamy.pl