Code edit (1 edits merged)
Please save this source code
Code edit (1 edits merged)
Please save this source code
Code edit (1 edits merged)
Please save this source code
Code edit (1 edits merged)
Please save this source code
Code edit (1 edits merged)
Please save this source code
Code edit (1 edits merged)
Please save this source code
Code edit (1 edits merged)
Please save this source code
Code edit (1 edits merged)
Please save this source code
Code edit (21 edits merged)
Please save this source code
User prompt
Please fix the bug: 'animatedHitFrame is not defined' in or related to this line: 'if (animatedHitFrame) {' Line Number: 688
Code edit (1 edits merged)
Please save this source code
Code edit (1 edits merged)
Please save this source code
Code edit (14 edits merged)
Please save this source code
User prompt
Please fix the bug: 'DEFAULT_HIT_ZONE_LINE_HEIGHT is not defined' in or related to this line: 'var hitZoneLine = LK.getAsset('lineAsset', {' Line Number: 2874
User prompt
Please fix the bug: 'Timeout.tick error: hitZoneLine is not defined' in or related to this line: 'if (hitZoneLine) {' Line Number: 672
User prompt
Please fix the bug: 'Timeout.tick error: hitZoneLine is not defined' in or related to this line: 'if (hitZoneLine) {' Line Number: 672
Code edit (1 edits merged)
Please save this source code
Code edit (22 edits merged)
Please save this source code
User prompt
Please fix the bug: 'Timeout.tick error: hitZoneLine is not defined' in or related to this line: 'if (hitZoneLine) {' Line Number: 847
Code edit (1 edits merged)
Please save this source code
Code edit (1 edits merged)
Please save this source code
Code edit (1 edits merged)
Please save this source code
Code edit (4 edits merged)
Please save this source code
User prompt
add new asset miniGameRollSoulsBg
Code edit (1 edits merged)
Please save this source code
/****
* Plugins
****/
var storage = LK.import("@upit/storage.v1");
var tween = LK.import("@upit/tween.v1");
/****
* Classes
****/
var Note = Container.expand(function (noteType, swipeDir, targetHitTimeFull, centerXVal, noteColumnIndex, isIncomingBuffNote, incomingBuffType, holdDurationMs) {
var self = Container.call(this);
self.noteType = noteType || 'tap';
self.swipeDir = swipeDir || null;
self.targetHitTime = targetHitTimeFull;
self.visualSpawnTime = self.targetHitTime - noteTravelTime; //
self.hit = false;
self.judged = false;
self.scaleStart = 1.0; // Zgodnie z ostatnią zmianą (stały rozmiar)
self.scaleEnd = 1.0; // Zgodnie z ostatnią zmianą (stały rozmiar)
self.centerX = centerXVal;
self.centerY = 1800;
self.startY = -150; // Zgodnie z ostatnią zmianą (start zza ekranu)
self.noteAsset = null;
self.isWiderSwipePart = false;
self.isBuffNote = isIncomingBuffNote || false;
self.buffType = incomingBuffType || null;
self.isHoldNote = self.noteType === 'hold';
self.holdDuration = self.isHoldNote ? holdDurationMs || 1000 : 0;
self.holdPressTime = 0;
self.isBeingHeld = false;
self.holdFullyCompleted = false;
self.holdBroken = false;
self.initialHoldHeight = 0;
// Logika przypisywania assetów - tak jak w naszej ostatniej wspólnej wersji
if (self.isBuffNote) {
var buffAssetKey = '';
if (self.buffType === 'potion') {
buffAssetKey = 'hpPotionAsset';
} else if (self.buffType === 'shield') {
buffAssetKey = 'shieldAsset';
} else if (self.buffType === 'precision') {
buffAssetKey = 'precisionAsset';
}
if (buffAssetKey) {
self.noteAsset = self.attachAsset(buffAssetKey, {
anchorX: 0.5,
anchorY: 0.5,
width: 150,
// Przykładowe rozmiary dla buffów
height: 180
});
}
if (self.isBuffNote) {
// Traktuj buffy jako tap dla interakcji
self.noteType = 'tap';
self.isHoldNote = false;
}
} else if (self.isHoldNote) {
var pixelsPerMs = (self.centerY - self.startY) / noteTravelTime;
var minVisualHeight = 50;
var calculatedTotalHeight = Math.max(minVisualHeight, self.holdDuration * pixelsPerMs);
self.initialHoldHeight = calculatedTotalHeight;
self.noteAsset = self.attachAsset('hold', {
// Używamy assetu 'hold'
anchorX: 0.5,
anchorY: 0,
// Górny anchor dla hold
height: self.initialHoldHeight
});
} else {
// Tap, Swipe, Trap - używają swoich dedykowanych assetów
if (self.noteType === 'tap') {
var tapAssetKey = 'tap0'; // Domyślnie tap0, potem można dodać logikę dla tap1, tap2 z noteColumnIndex
if (noteColumnIndex !== undefined) {
if (noteColumnIndex === 0) {
tapAssetKey = 'tap0';
} else if (noteColumnIndex === 1) {
tapAssetKey = 'tap1';
} else if (noteColumnIndex === 2) {
tapAssetKey = 'tap2';
}
}
self.noteAsset = self.attachAsset(tapAssetKey, {
// Użyj tapNote ze starego kodu lub odpowiedniego assetu
anchorX: 0.5,
anchorY: 0.5
});
} else if (self.noteType === 'swipe') {
var swipeAssetKey = 'swipe_col0'; // Domyślnie, potem można dodać logikę dla swipe_col1, swipe_col2
if (noteColumnIndex !== undefined) {
if (noteColumnIndex === 0) {
swipeAssetKey = 'swipe_col0';
} else if (noteColumnIndex === 1) {
swipeAssetKey = 'swipe_col1';
} else if (noteColumnIndex === 2) {
swipeAssetKey = 'swipe_col2';
}
}
self.noteAsset = self.attachAsset(swipeAssetKey, {
// Użyj swipeNote ze starego kodu lub odpowiedniego assetu
anchorX: 0.5,
anchorY: 0.5
});
if (self.swipeDir && self.noteAsset) {
// Dodawanie strzałki jak w starym kodzie, jeśli asset sam jej nie ma
var arrowText = '';
var rotationAngle = 0;
if (self.swipeDir === 'left') {
arrowText = '←';
rotationAngle = Math.PI;
} else if (self.swipeDir === 'right') {
arrowText = '→';
rotationAngle = 0;
} else if (self.swipeDir === 'up') {
arrowText = '↑';
rotationAngle = -Math.PI / 2;
} else if (self.swipeDir === 'down') {
arrowText = '↓';
rotationAngle = Math.PI / 2;
}
// Jeśli asset 'swipe_colN' nie ma strzałki, można ją dodać jak w starym kodzie
// lub po prostu obrócić asset, jeśli jest np. pojedynczą strzałką w prawo
self.noteAsset.rotation = rotationAngle; // Obracamy asset zamiast dodawać tekstową strzałkę
}
} else if (self.noteType === 'trap') {
self.noteAsset = self.attachAsset('trapNote', {
anchorX: 0.5,
anchorY: 0.5
});
}
}
self.alpha = 0; // Nuty startują niewidoczne
// PRZYWRÓCONA LOGIKA Z `walkman fighterv2.txt` z drobnymi adaptacjami
self.showHitFeedback = function (result, feedbackTextOverride) {
// feedbackTextOverride z nowszej wersji
var feedbackCircle = LK.getAsset('hitFeedback', {
//
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: 0,
scaleX: 0.7,
scaleY: 0.7,
alpha: 0.7
});
// Dostosowanie Y dla feedbackCircle jeśli nuta ma inny anchor niż 0.5
if (self.noteAsset && self.noteAsset.anchorY !== 0.5) {
if (self.isHoldNote && self.noteAsset.width > 0) {
feedbackCircle.y = self.noteAsset.width * 0.25 + self.noteAsset.y;
} else {
feedbackCircle.y = self.noteAsset.height / 2 + self.noteAsset.y;
}
}
var feedbackTextContent = feedbackTextOverride || ""; // Używamy override jeśli jest
var feedbackTextColor = 0xFFFFFF;
if (!feedbackTextOverride) {
// Logika kolorów i tekstu jak w nowszej wersji, bo jest bardziej rozbudowana
if (self.isBuffNote && result !== 'miss') {
feedbackCircle.tint = 0x40E0D0;
feedbackTextContent = self.buffType.charAt(0).toUpperCase() + self.buffType.slice(1) + "!";
feedbackTextColor = 0x40E0D0;
} else if (result === 'perfect') {
feedbackCircle.tint = 0xffff00;
feedbackTextContent = "Perfect!";
feedbackTextColor = 0xffff00;
} else if (result === 'good') {
feedbackCircle.tint = 0x00ff00;
feedbackTextContent = "Good!";
feedbackTextColor = 0x00ff00;
} else if (result === 'hold_ok') {
// Z nowszej wersji dla hold
feedbackCircle.tint = 0x00FF7F;
feedbackTextContent = "Held!";
feedbackTextColor = 0x00FF7F;
} else {
// miss, hold_broken
feedbackCircle.tint = 0xff0000;
feedbackTextContent = result === 'hold_broken' ? "Broken!" : "Miss"; //
feedbackTextColor = 0xff0000;
}
}
self.addChild(feedbackCircle);
tween(feedbackCircle, {
alpha: 0,
scaleX: 1.5,
scaleY: 1.5
}, {
duration: 350,
easing: tween.easeOut,
onFinish: function onFinish() {
if (feedbackCircle.parent) {
feedbackCircle.destroy();
}
}
});
if (feedbackTextContent) {
var scorePopup = new Text2(feedbackTextContent, {
size: 60,
fill: feedbackTextColor,
stroke: 0x000000,
strokeThickness: 3
});
scorePopup.anchor.set(0.5, 0.5);
var noteVisualHeight = SWIPE_NOTE_WIDTH; // Domyślna ze starego kodu
if (self.noteAsset) {
// Jeśli asset istnieje, użyj jego wysokości
noteVisualHeight = self.noteAsset.height;
}
// Pozycjonowanie scorePopup jak w starym kodzie (nad nutą)
// self.x i self.y to absolutne pozycje kontenera nuty
var popupAbsX = self.x;
var popupAbsY = self.y - noteVisualHeight * self.scale.y / 2 - 30; // self.scale.y będzie 1.0
if (self.isHoldNote && self.noteAsset) {
// Dla holda, nad "główką"
var headApproxHeight = self.noteAsset.width > 0 ? self.noteAsset.width * 0.25 : 50;
popupAbsY = self.y + self.noteAsset.y + headApproxHeight - noteVisualHeight * 0.25 - 30; // Dostosuj
} else if (self.noteAsset && self.noteAsset.anchorY === 0) {
// Inne nuty z anchorY 0
popupAbsY = self.y + noteVisualHeight / 2 - 30; // Na środku
}
scorePopup.x = popupAbsX;
scorePopup.y = popupAbsY;
if (self.parent) {
self.parent.addChild(scorePopup);
// Animacja scorePopup W GÓRĘ, jak w starym kodzie
tween(scorePopup, {
y: popupAbsY - 80,
// Przesunięcie w górę
alpha: 0
}, {
duration: 700,
easing: tween.easeOut,
onFinish: function onFinish() {
if (scorePopup.parent) {
scorePopup.destroy();
}
}
});
}
}
if (self.parent && (result === 'good' || result === 'perfect' || result === 'hold_ok')) {
var particleSpawnX = self.x;
var particleSpawnY;
if (self.isHoldNote && self.noteAsset) {
particleSpawnY = self.y + self.noteAsset.y + self.noteAsset.width * 0.25;
} else if (self.noteAsset && self.noteAsset.anchorY === 0.5) {
particleSpawnY = self.y;
} else if (self.noteAsset) {
particleSpawnY = self.y + self.noteAsset.height / 2;
} else {
particleSpawnY = self.y;
}
spawnParticleEffect(particleSpawnX, particleSpawnY, result, self.parent);
}
};
self.update = function () {
var now = Date.now();
// Logika dla ocenionych nut (tap/swipe) - pozwalamy im kontynuować ruch
if (self.judged && !self.isHoldNote) {
// Jeśli oceniona I NIE JEST nutą hold
if (self.alpha > 0) {
// Jeśli jest jeszcze widoczna
// Kontynuuj ruch i skalowanie (teraz skala stała 1.0)
var elapsedTimeSinceSpawn = now - self.visualSpawnTime;
var currentProgress = elapsedTimeSinceSpawn / noteTravelTime;
self.x = self.centerX;
self.y = self.startY + (self.centerY - self.startY) * currentProgress; // Nuta leci dalej
// Skala jest stała 1.0, więc nie ma potrzeby jej tu aktualizować na podstawie progress,
// chyba że chcemy specjalny efekt po trafieniu. Na razie zostawiamy self.scale = 1.0.
// self.scale.x = self.scaleEnd; // Byłoby 1.0
// self.scale.y = self.scaleEnd; // Byłoby 1.0
}
// Nie robimy return, aby logika auto-miss dla długo wiszących ocenionych nut mogła zadziałać
// lub removeOldNotes je usunęło. Jeśli alpha > 0, będzie się ruszać.
// Jeśli alpha zostało ustawione na 0 przez game.onNoteMiss, to po prostu będzie czekać na removeOldNotes.
}
// Dla ocenionych i zakończonych nut HOLD (nie są już isBeingHeld)
else if (self.judged && self.isHoldNote && !self.isBeingHeld) {
// Np. po judgeHoldRelease, alpha powinno być już 0.
// Jeśli nie jest, to problem. Ta gałąź dla bezpieczeństwa.
if (self.alpha > 0) {
self.alpha = 0;
}
return;
}
// Pojawianie się nowych nut
if (self.alpha === 0 && !self.judged && now >= self.visualSpawnTime) {
if (!self.isBeingHeld || self.isBeingHeld && now < self.targetHitTime + self.holdDuration + 500) {
self.alpha = 1;
}
}
if (self.alpha === 0 && !self.judged) {
// Jeśli nadal niewidoczna (nie jej czas)
return;
}
// Aktualizacja dla aktywnych, nieocenionych nut lub aktywnych holdów
if (self.isHoldNote && self.isBeingHeld) {
// Tylko dla aktywnie trzymanych holdów
if (self.holdBroken) {
self.isBeingHeld = false;
self.judged = true;
self.alpha = 0;
return;
}
if (self.noteAsset) {
self.noteAsset.tint = 0xAAAA00;
if (now >= self.targetHitTime) {
var timeHeldPastHitLine = now - self.targetHitTime;
var pixelsPerMs = (self.centerY - self.startY) / noteTravelTime;
var pixelsConsumed = Math.min(timeHeldPastHitLine * pixelsPerMs, self.initialHoldHeight);
self.noteAsset.y = pixelsConsumed;
self.noteAsset.height = Math.max(0, self.initialHoldHeight - pixelsConsumed);
} else {
self.noteAsset.height = self.initialHoldHeight;
self.noteAsset.y = 0;
}
}
if (now >= self.targetHitTime + self.holdDuration && !self.holdFullyCompleted) {
self.holdFullyCompleted = true;
console.log("Hold note duration completed for note at " + self.targetHitTime);
}
}
// Dla wszystkich aktywnych (nieocenionych lub trzymanych holdów) nut, aktualizuj pozycję:
// (chyba że jest to oceniony tap/swipe, wtedy ruch jest już obsłużony wyżej)
if (!self.judged || self.isHoldNote && self.isBeingHeld) {
self.scale.x = 1.0; // Stała skala
self.scale.y = 1.0; // Stała skala
self.x = self.centerX;
var progress = (now - self.visualSpawnTime) / noteTravelTime;
var newY = self.startY + (self.centerY - self.startY) * progress;
if (self.isHoldNote && self.isBeingHeld && newY >= self.centerY) {
self.y = self.centerY;
} else if (!self.isHoldNote) {
// Tap, swipe, trap - pozwól im lecieć dalej, jeśli nie ocenione
self.y = newY;
} else if (self.isHoldNote && !self.isBeingHeld && !self.judged) {
// Hold nie trzymany i nie oceniony
self.y = newY;
}
// Jeśli jest to oceniony tap/swipe, jego Y jest już aktualizowane na początku tej funkcji.
}
// Automatyczne missy (logika z naszej nowszej wersji, bardziej kompletna)
if (!self.judged && now > self.targetHitTime + hitWindowGood) {
// Ogólny auto-miss, jeśli nie oceniono na czas
if (self.noteType === 'trap') {// Trapów nie missujemy, same znikają lub są klikane
// Można dodać logikę zniknięcia trapa po czasie, jeśli nie kliknięty
} else if (self.isHoldNote && self.holdPressTime === 0) {
// Główka holda nie wciśnięta
console.log("Hold note head auto-missed: " + self.targetHitTime);
self.judged = true;
self.showHitFeedback('miss');
if (!isTutorialMode && !isShieldActive) {
resetCombo();
}
self.alpha = 0;
} else if (!self.isHoldNote) {
// Dla tap, swipe, buff
self.judged = true;
if (self.isBuffNote) {
self.showHitFeedback('miss');
if (!isTutorialMode && !isShieldActive) {
resetCombo();
}
self.alpha = 0;
} else {
// Zwykły tap/swipe
game.onNoteMiss(self); // game.onNoteMiss powinno obsłużyć feedback i ewentualne ukrycie
}
}
}
// Dla długo nieusuniętych ocenionych nut hold (zabezpieczenie z nowszej wersji)
if (self.isHoldNote && self.judged && !self.isBeingHeld && now > self.targetHitTime + self.holdDuration + 500) {
if (this.alpha > 0) {
this.alpha = 0;
}
}
};
self.isInHitWindow = function () {
var now = Date.now();
var dt = Math.abs(now - self.targetHitTime);
return dt <= hitWindowGood;
};
self.getHitAccuracy = function () {
var now = Date.now();
var dt = Math.abs(now - self.targetHitTime);
if (dt <= hitWindowPerfect) {
return 'perfect';
}
if (dt <= hitWindowGood) {
return 'good';
}
return 'miss';
};
self.judgeHoldRelease = function () {
if (!self.isHoldNote || self.judged && self.holdFullyCompleted && !self.holdBroken) {
if (self.isBeingHeld) {
self.isBeingHeld = false;
}
return;
}
var now = Date.now();
self.isBeingHeld = false;
self.judged = true;
if (self.holdBroken) {
if (!this.feedbackShownForBroken) {
this.showHitFeedback('hold_broken');
this.feedbackShownForBroken = true;
}
console.log("Hold broken and released for note: " + self.targetHitTime);
if (!isTutorialMode && !isShieldActive) {
resetCombo();
}
self.alpha = 0;
return;
}
var actualHoldDuration = now - self.holdPressTime;
var requiredHoldTimeOnScreen = self.targetHitTime + self.holdDuration;
if (now >= requiredHoldTimeOnScreen - hitWindowGood) {
self.holdFullyCompleted = true;
self.showHitFeedback('hold_ok');
if (!isTutorialMode) {
addScore('perfect');
addCombo();
if (!gameOverFlag) {
bossCurrentHP = Math.max(0, bossCurrentHP - 2);
updateBossHpDisplay();
}
}
console.log("Hold OK for note: " + self.targetHitTime);
} else {
self.showHitFeedback('miss', 'Too Early!');
console.log("Hold released too early for note: " + self.targetHitTime + ". Held for: " + actualHoldDuration + "ms, required full duration by map: " + self.holdDuration + "ms until time " + requiredHoldTimeOnScreen);
if (!isTutorialMode && !isShieldActive) {
resetCombo();
}
}
self.alpha = 0;
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x181828
});
/****
* Game Code
****/
// np. węższa środkowa
// Pomarańczowa główka
// Złoty segment ogona (wysokość bazowa)
var currentScreenState = '';
var columnFlashOverlays = [null, null, null];
var mainMenuScreenElements = [];
var isTutorialMode = false;
var currentlyHeldNotes = {};
var tutorialSongData = {
id: "TutorialTrack",
title: "How to Play",
artist: "Game System",
musicAsset: "tutorial",
bossAssetKey: null,
config: {
playerMaxHP: 10,
bossMaxHP: 1
},
rawRhythmMap: [{
time: 1000,
type: "tap",
columnIndex: 1
}, {
time: 2000,
type: "tap",
columnIndex: 0
}, {
time: 3000,
type: "tap",
columnIndex: 2
}, {
time: 4500,
type: "swipe",
columnIndex: 0,
swipeDir: "up"
}, {
time: 5500,
type: "swipe",
columnIndex: 2,
swipeDir: "down"
}, {
time: 7000,
// <<< NOWA NUTA HOLD
type: "hold",
columnIndex: 0,
duration: 1500 // Czas trwania w ms
}, {
time: 9500,
// <<< NOWA NUTA HOLD
type: "hold",
columnIndex: 2,
duration: 2000 // Czas trwania w ms
}, {
time: 12500,
// <<< NOWA NUTA HOLD
type: "hold",
columnIndex: 1,
duration: 1000 // Czas trwania w ms
}, {
time: 14000,
type: "tap",
// Zwykły tap dla kontrastu
columnIndex: 1
}],
isTutorial: true
};
var tutorialExitPrompt = null;
var statsScreenElements = [];
var currentBossDisplayElements = [];
var currentStatsBossIndex = 0;
var walkmanScreenContainer = null;
var mainMenuTextElementsContainer = null;
var miniGamePlayContainer = null;
var glassEffectAsset = null;
var layoutAndHighlightFunction = null;
var miniGameBackgroundInstance = null;
var miniGameViewport = {
x: 380,
y: 1020,
width: 1150,
height: 780
};
var miniGameScreenElements = [];
var miniGamePlayer = null;
var miniGameObstacles = [];
var miniGameScore = 0;
var miniGameScoreText = null;
var isMiniGameOver = false;
var currentMiniGameMusicTrack = null;
var MINI_GAME_LANE_Y_POSITIONS = [];
var MINI_GAME_NUMBER_OF_LANES = 3;
var MINI_GAME_LANE_HEIGHT = 0;
var MINI_GAME_OBJECT_SPEED = 8;
var currentMiniGameObjectSpeed = 0;
var miniGameTimeActive = 0;
var MINI_GAME_SPEED_INCREASE_INTERVAL = 5000;
var MINI_GAME_OBSTACLE_SPAWN_INTERVAL = 2000;
var MINI_GAME_SPEED_INCREMENT = 0.5;
var MINI_GAME_MOB_SPAWN_INTERVAL = 3500;
var lastMiniGameObstacleSpawnTime = 0;
var MINI_GAME_OBSTACLE_WIDTH = 100;
var MINI_GAME_OBSTACLE_HEIGHT = 100;
var mainMenuItemTextObjects = [];
var currentMainMenuMusicTrack = null;
var mainMenuItems = ["Music Battle", "How To Play", "Credits", "Stats", "Mini game"];
var selectedMainMenuItemIndex = 0;
var gameScreenWidth = 2048;
var hitZoneY = 1800;
// === PONIŻSZE DEKLARACJE PRZENOSIMY NA GÓRĘ ===
var STATIC_HIT_FRAME_WIDTH = 2500; // Dodana nowa stała dla szerokości statycznej ramki
var STATIC_HIT_FRAME_HEIGHT = 300; // Dodana nowa stała dla wysokości statycznej ramki
var staticHitFrame = null; // Deklaracja statycznej ramki obszaru uderzenia
var staticPerfectLine = null; // Deklaracja statycznej linii perfect
var PERFECT_LINE_ASSET_KEY = 'perfectLineAsset'; // Nazwa assetu dla cienkiej linii
var PERFECT_LINE_HEIGHT = 2; // Wysokość cienkiej linii perfect
// === KONIEC PRZENIESIONYCH DEKLARACJI ===
var gameScreenHeight = Math.round(gameScreenWidth * (2732 / 2048));
var playfieldWidth = 1808;
var NUM_COLUMNS = 3;
var columnCenterXs = [350, 1024, 1700]; // Podaj swoje wartości!
var columnFlashWidths = [620, 400, 620];
var SWIPE_NOTE_WIDTH = 180;
// HP System Variables
var playerMaxHP = 10;
var playerCurrentHP = 10;
var bossMaxHP = 30;
var bossCurrentHP = 30;
var gameOverFlag = false;
// HP Bar UI Elements Configuration (actual elements created in setupHpBars)
var hpBarWidth = 400;
var hpBarHeight = 30;
// UI Container
var gameUIContainer; // Declare gameUIContainer
// HP Bar Containers (will be initialized in setupHpBars)
var playerHpBarContainer;
var playerHpBarFill;
var bossHpBarContainer;
var bossHpBarFill;
var activePowerUpItems = [];
var SHIELD_DURATION = 6000;
var isShieldActive = false;
var shieldEndTime = 0;
var POTION_HEAL_AMOUNT = 5;
var SWIPE_TO_TAP_BUFF_DURATION = 5000;
var isSwipeToTapBuffActive = false;
var swipeToTapBuffEndTime = 0;
var shieldTimerDisplayContainer;
var precisionBuffTimerDisplayContainer;
var smallPrecisionIconDisplay;
var precisionBuffTimerTextDisplay;
var smallShieldIconDisplay;
var shieldTimerTextDisplay;
// var shieldTimerDisplayContainer; // Usunąć duplikat
// var smallShieldIconDisplay; // Usunąć duplikat
// var shieldTimerTextDisplay; // Usunąć duplikat
var swipeToTapTimerDisplayContainer;
var smallSwipeToTapIconDisplay;
var swipeToTapTimerTextDisplay;
var currentBossSprite;
var powerUpDisplayContainer;
var hpPotionIcon, shieldIcon, swipeToTapIcon;
var hpPotionCountText, shieldCountText, swipeToTapCountText;
var currentActiveRhythmMap = null;
var currentMusic = null;
var noteTravelTime = 3300;
var BUFF_CHANCE = 0.08;
var gameplayBackground = null;
var PRECISION_BUFF_DURATION = 7000;
var isPrecisionBuffActive = false;
var precisionBuffEndTime = 0;
var originalHitWindowPerfect = 0;
var precisionBuffHitWindowMultiplier = 1.8;
var hitWindowPerfect = 220;
var hitWindowGood = 270;
var MIN_SWIPE_DISTANCE = 60;
var notes = [];
var nextNoteIdx = 0;
var gameStartTime = 0;
var score = 0;
var bossWasDefeatedThisSong = false;
var songSummaryContainer = null;
var bossUnlockProgress = {};
var GAME_SCORES_KEY = 'walkmanFighters_scores';
var BOSS_UNLOCK_KEY = 'walkmanFighters_bossUnlock';
var currentFightingBossId = null;
var lastPlayedSongKeyForRestart = null;
var combo = 0;
var maxCombo = 0;
var swipeStart = null;
var inputLocked = false;
var hpBarsInitialized = false;
function _typeof5(o) {
"@babel/helpers - typeof";
return _typeof5 = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {
return typeof o;
} : function (o) {
return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
}, _typeof5(o);
}
function _typeof4(o) {
"@babel/helpers - typeof";
return _typeof4 = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {
return typeof o;
} : function (o) {
return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
}, _typeof4(o);
}
function _typeof3(o) {
"@babel/helpers - typeof";
return _typeof3 = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {
return typeof o;
} : function (o) {
return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
}, _typeof3(o);
}
function _typeof2(o) {
"@babel/helpers - typeof";
return _typeof2 = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {
return typeof o;
} : function (o) {
return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
}, _typeof2(o);
}
function _typeof(o) {
"@babel/helpers - typeof";
return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {
return typeof o;
} : function (o) {
return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
}, _typeof(o);
}
function setupGameplayElements() {
if (staticPerfectLine && staticPerfectLine.parent) {
staticPerfectLine.destroy();
}
staticPerfectLine = LK.getAsset(PERFECT_LINE_ASSET_KEY, {
anchorX: 0.5,
anchorY: 0.5,
x: gameScreenWidth / 2,
y: hitZoneY,
width: playfieldWidth,
height: PERFECT_LINE_HEIGHT,
alpha: 0.9,
visible: false
});
game.addChild(staticPerfectLine);
if (staticHitFrame && staticHitFrame.parent) {
staticHitFrame.destroy();
}
staticHitFrame = LK.getAsset('FRAME1', {
anchorX: 0.5,
anchorY: 0.5,
x: gameScreenWidth / 2,
y: hitZoneY,
width: STATIC_HIT_FRAME_WIDTH,
height: STATIC_HIT_FRAME_HEIGHT,
alpha: 0.7,
visible: false
});
game.addChild(staticHitFrame);
// Tworzenie nakładek błysku
for (var i = 0; i < NUM_COLUMNS; i++) {
if (columnFlashOverlays[i] && columnFlashOverlays[i].parent) {
columnFlashOverlays[i].destroy();
}
var overlayAssetKey = 'flashOverlay_col' + i;
columnFlashOverlays[i] = LK.getAsset(overlayAssetKey, {
// Pobieramy asset
anchorX: 0.5,
anchorY: 0.5,
x: columnCenterXs[i],
y: gameScreenHeight / 2
// Nie ustawiamy tu alpha, zrobimy to poniżej
});
if (columnFlashOverlays[i]) {
// Sprawdzenie, czy asset został poprawnie załadowany
game.addChild(columnFlashOverlays[i]);
columnFlashOverlays[i].alpha = 0; // <<<< KLUCZOWA ZMIANA: Ustawiamy alpha na 0 ZARAZ PO DODANIU
}
}
}
var allParticleAssetKeys = [];
for (var i = 1; i <= 12; i++) {
allParticleAssetKeys.push('particle' + i);
}
function createAndAnimateParticle(assetKey, startX, startY, parentContainer) {
var comboScaleMultiplier = 1 + Math.floor(combo / 20) * 0.1; // Bazowy mnożnik 1, zwiększa się o 0.1 co 20 combo
var particle = LK.getAsset(assetKey, {
anchorX: 0.5,
anchorY: 0.5,
x: startX,
y: startY,
alpha: 1,
scaleX: (3 + Math.random() * 1.2) * comboScaleMultiplier,
scaleY: (3 + Math.random() * 1.2) * comboScaleMultiplier,
rotation: Math.random() * Math.PI * 2 // Losowa rotacja początkowa
});
parentContainer.addChild(particle);
var travelAngle = Math.random() * Math.PI * 2;
var travelDistance = 50 + Math.random() * 100; // 50 do 150px
var targetX = startX + Math.cos(travelAngle) * travelDistance;
var targetY = startY + Math.sin(travelAngle) * travelDistance;
var duration = 500 + Math.random() * 500; // 500ms do 1000ms
tween(particle, {
x: targetX,
y: targetY,
alpha: 0,
scaleX: 1 + Math.random() * 1,
// Większa skala końcowa X (np. od 0.3 do 0.6)
scaleY: 1 + Math.random() * 1,
// Większa skala końcowa Y (np. od 0.3 do 0.6)
// Skala końcowa Y
rotation: particle.rotation + (Math.random() * Math.PI - Math.PI / 2) // Dodatkowa losowa rotacja
}, {
duration: duration,
easing: tween.easeOutQuad,
onFinish: function onFinish() {
if (particle.parent) {
particle.destroy();
}
}
});
}
function spawnParticleEffect(spawnX, spawnY, accuracy, parentContainer) {
var numParticlesBase = 0;
var numTypesToPick = 0;
if (accuracy === 'good') {
numParticlesBase = 3;
numTypesToPick = 2 + Math.floor(Math.random() * 2); // 2 lub 3 typy
} else if (accuracy === 'perfect') {
numParticlesBase = 7;
numTypesToPick = 3 + Math.floor(Math.random() * 2); // 3 lub 4 typy
} else {
return; // Nie twórz cząsteczek dla 'miss' lub innych
}
// Wzmocnienie z combo (prosty przykład, można dostosować)
var comboBonusParticles = Math.floor(combo / 3); // 1 dodatkowa cząsteczka co 10 combo
var totalParticlesToSpawn = numParticlesBase + comboBonusParticles;
if (totalParticlesToSpawn === 0) {
return;
}
// Losowy wybór typów cząsteczek
var availableTypes = [].concat(allParticleAssetKeys); // Kopia tablicy
var pickedTypes = [];
for (var i = 0; i < numTypesToPick; i++) {
if (availableTypes.length === 0) {
break;
}
var randomIndex = Math.floor(Math.random() * availableTypes.length);
pickedTypes.push(availableTypes.splice(randomIndex, 1)[0]);
}
if (pickedTypes.length === 0) {
// Na wszelki wypadek, jeśli coś pójdzie nie tak
pickedTypes.push(allParticleAssetKeys[Math.floor(Math.random() * allParticleAssetKeys.length)]);
}
for (var i = 0; i < totalParticlesToSpawn; i++) {
var particleAssetKey = pickedTypes[i % pickedTypes.length]; // Cyklicznie przez wybrane typy
createAndAnimateParticle(particleAssetKey, spawnX, spawnY, parentContainer);
}
}
function showStartScreen() {
currentScreenState = 'start';
if (gameUIContainer) {
gameUIContainer.visible = false;
}
if (staticHitFrame) {
staticHitFrame.visible = false;
}
if (staticPerfectLine) {
staticPerfectLine.visible = false;
}
game.setBackgroundColor(0x000000);
var startButton = new Text2("MAKE SOME NOISEE", {
size: 150,
fill: 0xFFFFFF
});
startButton.anchor.set(0.5, 0.5);
startButton.x = gameScreenWidth / 2;
startButton.y = gameScreenHeight / 2;
startButton.interactive = true;
startButton.cursor = "pointer";
game.addChild(startButton);
startButton.down = function () {
if (startButton.parent) {
startButton.destroy();
}
showIntro();
};
}
function updateMainMenuHighlight(newIndex) {
var defaultTint = 0xFFFFFF; // Biały tint (brak efektu, oryginalny kolor tekstu)
var highlightTint = 0xFFD700; // Żółty tint dla podświetlenia
var defaultScale = 1.0;
var highlightScale = 1.15; // Skala dla podświetlonej opcji
// Resetuj styl dla wszystkich opcji
for (var i = 0; i < mainMenuItemTextObjects.length; i++) {
if (mainMenuItemTextObjects[i] && mainMenuItemTextObjects[i].parent) {
// Zakładamy, że bazowy .fill tekstu jest biały (ustawiony przy tworzeniu)
mainMenuItemTextObjects[i].tint = defaultTint;
mainMenuItemTextObjects[i].scale.set(defaultScale);
}
}
// Ustaw styl dla nowo wybranej opcji
if (newIndex >= 0 && newIndex < mainMenuItemTextObjects.length) {
if (mainMenuItemTextObjects[newIndex] && mainMenuItemTextObjects[newIndex].parent) {
var targetItem = mainMenuItemTextObjects[newIndex];
targetItem.tint = highlightTint;
targetItem.scale.set(highlightScale);
}
}
selectedMainMenuItemIndex = newIndex; // Aktualizuj globalny indeks
}
function showMiniGameScreen() {
currentScreenState = 'miniGameActive';
isMiniGameOver = false;
miniGameScore = 0;
miniGameObstacles = [];
while (miniGameScreenElements.length > 0) {
var el_mg_clear = miniGameScreenElements.pop();
if (el_mg_clear && el_mg_clear.parent) {
el_mg_clear.destroy();
}
}
if (miniGamePlayer && miniGamePlayer.asset && miniGamePlayer.asset.parent) {
miniGamePlayer.asset.destroy();
}
miniGamePlayer = null;
if (miniGameScoreText && miniGameScoreText.parent) {
miniGameScoreText.destroy();
}
miniGameScoreText = null;
if (currentMainMenuMusicTrack && typeof currentMainMenuMusicTrack.stop === 'function') {
currentMainMenuMusicTrack.stop();
}
if (currentMiniGameMusicTrack && typeof currentMiniGameMusicTrack.stop === 'function') {
currentMiniGameMusicTrack.stop();
}
currentMiniGameMusicTrack = LK.getSound('rollsouls');
if (currentMiniGameMusicTrack && typeof currentMiniGameMusicTrack.play === 'function') {
currentMiniGameMusicTrack.volume = 0;
currentMiniGameMusicTrack.play({
loop: true
}); // <--- TUTAJ JEST KLUCZOWE {loop: true}
currentMiniGameMusicTrack.play({
loop: true
});
tween(currentMiniGameMusicTrack, {
volume: 1.0
}, {
duration: 2000,
easing: tween.easeLinear
});
}
if (!miniGameBackgroundInstance || !miniGameBackgroundInstance.parent) {
miniGameBackgroundInstance = LK.getAsset('miniGameRollSoulsBg', {});
if (miniGameBackgroundInstance) {
var faktorSkali = 0.8;
var nowaSzerokoscTla = miniGameViewport.width * faktorSkali;
var nowaWysokoscTla = miniGameViewport.height * faktorSkali;
miniGameBackgroundInstance.width = nowaSzerokoscTla;
miniGameBackgroundInstance.height = nowaWysokoscTla;
miniGameBackgroundInstance.x = miniGameViewport.x + (miniGameViewport.width - nowaSzerokoscTla) / 2;
miniGameBackgroundInstance.y = miniGameViewport.y + (miniGameViewport.height - nowaWysokoscTla) / 2;
game.addChild(miniGameBackgroundInstance);
}
}
if (miniGameBackgroundInstance) {
miniGameBackgroundInstance.visible = true;
miniGameBackgroundInstance.alpha = 0.7;
if (!miniGameScreenElements.includes(miniGameBackgroundInstance)) {
miniGameScreenElements.push(miniGameBackgroundInstance);
}
}
MINI_GAME_LANE_HEIGHT = miniGameViewport.height / MINI_GAME_NUMBER_OF_LANES;
MINI_GAME_LANE_Y_POSITIONS = [];
for (var lane_idx = 0; lane_idx < MINI_GAME_NUMBER_OF_LANES; lane_idx++) {
MINI_GAME_LANE_Y_POSITIONS.push(miniGameViewport.y + lane_idx * MINI_GAME_LANE_HEIGHT + MINI_GAME_LANE_HEIGHT / 2);
}
miniGamePlayer = {
lane: 1,
y: MINI_GAME_LANE_Y_POSITIONS[1],
x: miniGameViewport.x + 100,
width: 50,
height: 50,
asset: null
};
var playerAsset_mg = LK.getAsset('miniGamePlayerAsset', {});
if (playerAsset_mg) {
playerAsset_mg.anchor.set(0.5, 0.5);
playerAsset_mg.x = miniGamePlayer.x;
playerAsset_mg.y = miniGamePlayer.y;
game.addChild(playerAsset_mg);
miniGameScreenElements.push(playerAsset_mg);
miniGamePlayer.asset = playerAsset_mg;
}
var scoreTextInstance = new Text2("Score: 0", {
size: 40,
fill: 0xFFFFFF,
align: 'left'
});
scoreTextInstance.anchor.set(0, 0);
scoreTextInstance.x = miniGameViewport.x + 20;
scoreTextInstance.y = miniGameViewport.y + 20;
game.addChild(scoreTextInstance);
miniGameScreenElements.push(scoreTextInstance);
miniGameScoreText = scoreTextInstance;
lastMiniGameObstacleSpawnTime = Date.now();
currentMiniGameObjectSpeed = MINI_GAME_OBJECT_SPEED;
miniGameTimeActive = 0;
var glassAssetFromMainMenu = null;
for (var i_glass = 0; i_glass < mainMenuScreenElements.length; i_glass++) {
var el_glass_check = mainMenuScreenElements[i_glass];
if (el_glass_check && el_glass_check.x === miniGameViewport.x && el_glass_check.y === miniGameViewport.y && el_glass_check.width === miniGameViewport.width && el_glass_check.height === miniGameViewport.height && el_glass_check.alpha && Math.abs(el_glass_check.alpha - 0.3) < 0.01) {
glassAssetFromMainMenu = el_glass_check;
break;
}
}
if (glassAssetFromMainMenu && glassAssetFromMainMenu.parent) {
var parentContainer = glassAssetFromMainMenu.parent;
parentContainer.removeChild(glassAssetFromMainMenu);
parentContainer.addChild(glassAssetFromMainMenu);
}
}
function exitMiniGameAndReturnToMainMenu() {
if (miniGamePlayer && miniGamePlayer.asset && miniGamePlayer.asset.hasOwnProperty('tint')) {
miniGamePlayer.asset.tint = 0xFFFFFF;
}
isMiniGameOver = true;
if (currentMiniGameMusicTrack && typeof currentMiniGameMusicTrack.stop === 'function') {
currentMiniGameMusicTrack.stop();
currentMiniGameMusicTrack = null;
}
if (miniGameBackgroundInstance && miniGameBackgroundInstance.parent) {
miniGameBackgroundInstance.visible = false;
}
while (miniGameScreenElements.length > 0) {
var el_exit_mg = miniGameScreenElements.pop();
if (el_exit_mg && el_exit_mg.parent) {
if (el_exit_mg === miniGameBackgroundInstance && miniGameBackgroundInstance && miniGameBackgroundInstance.visible === false) {} else {
el_exit_mg.destroy();
}
}
}
if (miniGameBackgroundInstance && miniGameBackgroundInstance.parent && miniGameBackgroundInstance.visible === false) {} else if (miniGameBackgroundInstance && !miniGameBackgroundInstance.parent) {
miniGameBackgroundInstance = null;
}
miniGamePlayer = null;
miniGameObstacles = [];
if (miniGameScoreText && miniGameScoreText.parent) {
miniGameScoreText.destroy();
}
miniGameScoreText = null;
currentScreenState = 'mainmenu_walkman';
showMainMenu();
}
function spawnMiniGameObstacle() {
// Zmieniona nazwa i usunięte mobki
var now = Date.now();
if (now > lastMiniGameObstacleSpawnTime + MINI_GAME_OBSTACLE_SPAWN_INTERVAL * (0.5 + Math.random())) {
var randomLane = Math.floor(Math.random() * MINI_GAME_NUMBER_OF_LANES);
var newObstacle = {
x: miniGameViewport.x + miniGameViewport.width + MINI_GAME_OBSTACLE_WIDTH / 2 - 50,
// Dodatkowe 100 pikseli w prawo
y: MINI_GAME_LANE_Y_POSITIONS[randomLane],
width: MINI_GAME_OBSTACLE_WIDTH,
height: MINI_GAME_OBSTACLE_HEIGHT,
type: 'obstacle',
asset: null,
scored: false // Flaga do śledzenia, czy za tę przeszkodę przyznano już punkty
};
var obstacleAsset = LK.getAsset('miniGameObstacleAsset', {
anchorX: 0.5,
anchorY: 0.5,
x: newObstacle.x,
y: newObstacle.y
});
game.addChild(obstacleAsset);
miniGameScreenElements.push(obstacleAsset);
newObstacle.asset = obstacleAsset;
miniGameObstacles.push(newObstacle);
lastMiniGameObstacleSpawnTime = now;
// console.log("Spawned obstacle in lane " + randomLane);
}
}
function moveMiniGameObstacles() {
if (!miniGamePlayer || isMiniGameOver) {
return;
}
for (var i = miniGameObstacles.length - 1; i >= 0; i--) {
var obs = miniGameObstacles[i];
obs.x -= currentMiniGameObjectSpeed;
if (obs.asset) {
obs.asset.x = obs.x;
}
if (!obs.scored && obs.x < miniGamePlayer.x - miniGamePlayer.width / 2) {
miniGameScore += 5;
obs.scored = true;
updateMiniGameScoreDisplay();
}
if (obs.x < miniGameViewport.x - obs.width / 2 + 50) {
if (obs.asset && obs.asset.parent) {
obs.asset.destroy();
}
var obsAssetIndex = miniGameScreenElements.indexOf(obs.asset);
if (obsAssetIndex > -1) {
miniGameScreenElements.splice(obsAssetIndex, 1);
}
miniGameObstacles.splice(i, 1);
}
}
}
function updateMiniGameScoreDisplay() {
if (miniGameScoreText) {
miniGameScoreText.setText("Score: " + miniGameScore);
}
}
function showMainMenu() {
while (mainMenuScreenElements.length > 0) {
var el = mainMenuScreenElements.pop();
if (el && el.parent) {
el.destroy();
}
}
mainMenuItemTextObjects = [];
currentScreenState = 'mainmenu_walkman';
if (gameUIContainer) {
gameUIContainer.visible = false;
}
if (staticHitFrame) {
staticHitFrame.visible = false;
// animatedHitFrame.stop(); // Ta linia już nie będzie potrzebna
}
if (staticPerfectLine) {
staticPerfectLine.visible = false;
}
if (shieldTimerDisplayContainer) {
shieldTimerDisplayContainer.visible = false;
}
if (swipeToTapTimerDisplayContainer) {
swipeToTapTimerDisplayContainer.visible = false;
}
if (songSummaryContainer && songSummaryContainer.parent) {
songSummaryContainer.destroy();
}
if (currentlyPlayingMusic && typeof currentlyPlayingMusic.stop === 'function') {
currentlyPlayingMusic.stop();
currentlyPlayingMusic = null;
}
if (currentMiniGameMusicTrack && typeof currentMiniGameMusicTrack.stop === 'function') {
currentMiniGameMusicTrack.stop(); // Zatrzymaj muzykę mini-gry, jeśli grała
currentMiniGameMusicTrack = null;
}
if (miniGameBackgroundInstance && miniGameBackgroundInstance.parent) {
miniGameBackgroundInstance.visible = false; // Ukryj tło mini-gry
}
if (!currentMainMenuMusicTrack) {
currentMainMenuMusicTrack = LK.getSound('mainMenuTheme');
}
if (currentMainMenuMusicTrack && typeof currentMainMenuMusicTrack.play === 'function') {
if (typeof currentMainMenuMusicTrack.getIsPlaying === 'function' && !currentMainMenuMusicTrack.getIsPlaying()) {
currentMainMenuMusicTrack.play({
loop: true
});
} else if (typeof currentMainMenuMusicTrack.getIsPlaying !== 'function') {
currentMainMenuMusicTrack.play({
loop: true
});
}
}
var glassX = 380;
var glassY = 1020;
var glassWidth = 1150;
var glassHeight = 820;
var glassAlpha = 0.3;
var menuItemFontSize = 120;
var menuItemSpacing = 225;
var TARGET_CENTER_X_FOR_MENU_ITEMS = glassX + glassWidth / 2;
var TARGET_CENTER_Y_FOR_SELECTED_ITEM = glassY + glassHeight / 2;
var menuTextContainer = new Container();
game.addChild(menuTextContainer);
mainMenuScreenElements.push(menuTextContainer);
selectedMainMenuItemIndex = 0;
for (var i_menu = 0; i_menu < mainMenuItems.length; i_menu++) {
var itemText_menu = new Text2(mainMenuItems[i_menu], {
size: menuItemFontSize,
fill: 0xFFFFFF,
align: 'center'
});
itemText_menu.anchor.set(0.5, 0.5);
itemText_menu.interactive = false;
menuTextContainer.addChild(itemText_menu);
mainMenuItemTextObjects.push(itemText_menu);
}
var layoutAndHighlightFunctionRef = function layoutAndHighlightFunctionRef() {
var defaultTint = 0xFFFFFF;
var highlightTint = 0xFFD700;
var defaultScale = 1.0;
var highlightScale = 1.15;
for (var idx = 0; idx < mainMenuItemTextObjects.length; idx++) {
var item_layout = mainMenuItemTextObjects[idx];
if (item_layout && item_layout.parent) {
item_layout.y = TARGET_CENTER_Y_FOR_SELECTED_ITEM + (idx - selectedMainMenuItemIndex) * menuItemSpacing;
item_layout.x = TARGET_CENTER_X_FOR_MENU_ITEMS;
if (idx === selectedMainMenuItemIndex) {
item_layout.tint = highlightTint;
item_layout.scale.set(highlightScale);
} else {
item_layout.tint = defaultTint;
item_layout.scale.set(defaultScale);
}
}
}
};
var glass = LK.getAsset('glass', {
x: glassX,
y: glassY,
width: glassWidth,
height: glassHeight,
alpha: glassAlpha,
interactive: false
});
game.addChild(glass);
mainMenuScreenElements.push(glass);
var walkmanFrame = LK.getAsset('mainmenu', {
x: 0,
y: 0,
width: gameScreenWidth,
height: gameScreenHeight
});
game.addChild(walkmanFrame);
mainMenuScreenElements.push(walkmanFrame);
var upButton = LK.getAsset('upbutton', {});
upButton.x = 210;
upButton.y = gameScreenHeight / 2 - 180;
upButton.anchor.set(0.5, 0.5);
upButton.interactive = true;
upButton.cursor = "pointer";
upButton.down = function () {
if (currentScreenState === 'mainmenu_walkman') {
selectedMainMenuItemIndex = (selectedMainMenuItemIndex - 1 + mainMenuItems.length) % mainMenuItems.length;
layoutAndHighlightFunctionRef();
} else if (currentScreenState === 'miniGameActive' && miniGamePlayer && !isMiniGameOver) {
if (miniGamePlayer.lane > 0) {
miniGamePlayer.lane--;
var newY_up = MINI_GAME_LANE_Y_POSITIONS[miniGamePlayer.lane];
miniGamePlayer.y = newY_up;
if (miniGamePlayer.asset) {
miniGamePlayer.asset.y = newY_up;
}
}
} else if (currentScreenState === 'statsScreen') {
if (currentStatsBossIndex > 0) {
currentStatsBossIndex--;
displayStatsForBoss(currentStatsBossIndex);
}
}
};
game.addChild(upButton);
mainMenuScreenElements.push(upButton);
var downButton = LK.getAsset('downbutton', {});
downButton.x = 210;
downButton.y = gameScreenHeight / 2 + 220;
downButton.anchor.set(0.5, 0.5);
downButton.interactive = true;
downButton.cursor = "pointer";
downButton.down = function () {
if (currentScreenState === 'mainmenu_walkman') {
selectedMainMenuItemIndex = (selectedMainMenuItemIndex + 1) % mainMenuItems.length;
layoutAndHighlightFunctionRef();
} else if (currentScreenState === 'miniGameActive' && miniGamePlayer && !isMiniGameOver) {
if (miniGamePlayer.lane < MINI_GAME_NUMBER_OF_LANES - 1) {
miniGamePlayer.lane++;
var newY_down = MINI_GAME_LANE_Y_POSITIONS[miniGamePlayer.lane];
miniGamePlayer.y = newY_down;
if (miniGamePlayer.asset) {
miniGamePlayer.asset.y = newY_down;
}
}
} else if (currentScreenState === 'statsScreen') {
if (currentStatsBossIndex < allBossData.length - 1) {
currentStatsBossIndex++;
displayStatsForBoss(currentStatsBossIndex);
}
}
};
game.addChild(downButton);
mainMenuScreenElements.push(downButton);
var playButton = LK.getAsset('play', {});
playButton.x = gameScreenWidth - 350;
playButton.y = gameScreenHeight / 2 - 240;
playButton.anchor.set(0.5, 0.5);
playButton.interactive = true;
playButton.cursor = "pointer";
playButton.down = function () {
if (currentScreenState === 'mainmenu_walkman') {
if (currentMainMenuMusicTrack && typeof currentMainMenuMusicTrack.play === 'function') {
if (typeof currentMainMenuMusicTrack.getIsPlaying === 'function' && !currentMainMenuMusicTrack.getIsPlaying()) {
currentMainMenuMusicTrack.play({
loop: true
});
} else if (typeof currentMainMenuMusicTrack.getIsPlaying !== 'function') {
currentMainMenuMusicTrack.play({
loop: true
});
}
}
} else if (currentScreenState === 'miniGameActive' && !isMiniGameOver) {
if (currentMiniGameMusicTrack && typeof currentMiniGameMusicTrack.play === 'function') {
if (typeof currentMiniGameMusicTrack.getIsPlaying === 'function' && !currentMiniGameMusicTrack.getIsPlaying()) {
currentMiniGameMusicTrack.play({
loop: true
}); // <--- TUTAJ TEŻ
} else if (typeof currentMiniGameMusicTrack.getIsPlaying !== 'function') {
currentMiniGameMusicTrack.play({
loop: true
}); // <--- I TUTAJ
}
}
}
};
game.addChild(playButton);
mainMenuScreenElements.push(playButton);
var stopButton = LK.getAsset('stop', {});
stopButton.x = gameScreenWidth - 350;
stopButton.y = gameScreenHeight / 2;
stopButton.anchor.set(0.5, 0.5);
stopButton.interactive = true;
stopButton.cursor = "pointer";
stopButton.down = function () {
if (currentScreenState === 'mainmenu_walkman') {
if (currentMainMenuMusicTrack && typeof currentMainMenuMusicTrack.stop === 'function') {
currentMainMenuMusicTrack.stop();
}
} else if (currentScreenState === 'miniGameActive' && !isMiniGameOver) {
if (currentMiniGameMusicTrack && typeof currentMiniGameMusicTrack.stop === 'function') {
currentMiniGameMusicTrack.stop();
}
}
};
game.addChild(stopButton);
mainMenuScreenElements.push(stopButton);
var fightButton = LK.getAsset('fight', {});
fightButton.x = gameScreenWidth - 350;
fightButton.y = gameScreenHeight / 2 + 240;
fightButton.anchor.set(0.5, 0.5);
fightButton.interactive = true;
fightButton.cursor = "pointer";
fightButton.down = function () {
var selectedAction = mainMenuItems[selectedMainMenuItemIndex];
if (currentScreenState === 'mainmenu_walkman') {
if (selectedAction === "Mini game") {
if (typeof menuTextContainer !== 'undefined' && menuTextContainer) {
menuTextContainer.visible = false;
}
if (currentMainMenuMusicTrack && typeof currentMainMenuMusicTrack.stop === 'function') {
currentMainMenuMusicTrack.stop();
}
showMiniGameScreen();
return;
} else if (selectedAction === "Stats") {
if (typeof menuTextContainer !== 'undefined' && menuTextContainer) {
menuTextContainer.visible = false;
}
if (currentMainMenuMusicTrack && typeof currentMainMenuMusicTrack.stop === 'function') {
currentMainMenuMusicTrack.stop();
}
showStatsScreen();
return;
}
if (selectedAction === "How To Play") {
runTutorialGameplay();
} else {
if (currentMainMenuMusicTrack && typeof currentMainMenuMusicTrack.stop === 'function') {
currentMainMenuMusicTrack.stop();
}
while (mainMenuScreenElements.length > 0) {
var elemToDestroy = mainMenuScreenElements.pop();
if (elemToDestroy && elemToDestroy.parent) {
elemToDestroy.destroy();
}
}
mainMenuItemTextObjects = [];
if (typeof menuTextContainer !== 'undefined' && menuTextContainer && menuTextContainer.parent) {
menuTextContainer.destroy();
}
menuTextContainer = null;
if (selectedAction === "Music Battle") {
showBossSelectionScreen();
} else if (selectedAction === "Credits") {
showCreditsScreen();
}
}
} else if (currentScreenState === 'miniGameActive' && isMiniGameOver) {
exitMiniGameAndReturnToMainMenu();
showMiniGameScreen();
}
};
game.addChild(fightButton);
mainMenuScreenElements.push(fightButton);
var rewindButtonMainMenu = LK.getAsset('rewindbutton', {});
rewindButtonMainMenu.x = 350;
rewindButtonMainMenu.y = gameScreenHeight / 2 + 650;
rewindButtonMainMenu.anchor.set(0.5, 0.5);
rewindButtonMainMenu.interactive = true;
rewindButtonMainMenu.cursor = "pointer";
rewindButtonMainMenu.down = function () {
if (currentScreenState === 'miniGameActive') {
exitMiniGameAndReturnToMainMenu();
} else if (currentScreenState === 'statsScreen') {
while (statsScreenElements.length > 0) {
var elS = statsScreenElements.pop();
if (elS && elS.parent) {
elS.destroy();
}
}
while (currentBossDisplayElements.length > 0) {
var elCBD = currentBossDisplayElements.pop();
if (elCBD && elCBD.parent) {
elCBD.destroy();
}
}
showMainMenu();
} else if (currentScreenState === 'mainmenu_walkman') {
if (currentMainMenuMusicTrack && typeof currentMainMenuMusicTrack.stop === 'function') {
currentMainMenuMusicTrack.stop();
}
while (mainMenuScreenElements.length > 0) {
var elM = mainMenuScreenElements.pop();
if (elM && elM.parent) {
elM.destroy();
}
}
mainMenuItemTextObjects = [];
menuTextContainer = null;
showStartScreen();
}
};
game.addChild(rewindButtonMainMenu);
mainMenuScreenElements.push(rewindButtonMainMenu);
layoutAndHighlightFunctionRef();
}
var allBossData = [];
var currentBossViewStartIndex = 0;
var cardsContainer = null;
var visibleBossCards = [null, null, null, null];
var selectedCardSlotIndex = 0;
var currentlyPlayingMusic = null;
var peekingBossCards = [null, null];
var placeholderMusicKey = 'test1';
var placeholderSongMapKey = 'defaultTestTrack';
var visibleBossCards = [null, null];
function initializeBossData() {
allBossData = [{
id: 'boss1',
displayName: 'Boss 1',
cardAssetKey: 'boss1',
musicAssetKey: 'Orctave',
songMapKey: 'OrctaveBossTrack',
defeatsRequired: 0
}, {
id: 'boss2',
displayName: 'Boss 2',
cardAssetKey: 'boss2',
musicAssetKey: placeholderMusicKey,
songMapKey: placeholderSongMapKey,
defeatsRequired: 0
}, {
id: 'boss3',
displayName: 'Boss 3',
cardAssetKey: 'boss3',
musicAssetKey: placeholderMusicKey,
songMapKey: placeholderSongMapKey,
defeatsRequired: 0
}, {
id: 'boss4',
displayName: 'Boss 4',
cardAssetKey: 'boss4',
musicAssetKey: placeholderMusicKey,
songMapKey: placeholderSongMapKey,
defeatsRequired: 1
}, {
id: 'boss5',
displayName: 'Boss 5',
cardAssetKey: 'boss5',
musicAssetKey: placeholderMusicKey,
songMapKey: placeholderSongMapKey,
defeatsRequired: 2
}, {
id: 'boss6',
displayName: 'Boss 6',
cardAssetKey: 'boss6',
musicAssetKey: placeholderMusicKey,
songMapKey: placeholderSongMapKey,
defeatsRequired: 3
}, {
id: 'boss7',
displayName: 'Boss 7',
cardAssetKey: 'boss7',
musicAssetKey: placeholderMusicKey,
songMapKey: placeholderSongMapKey,
defeatsRequired: 4
}, {
id: 'boss8',
displayName: 'Boss 8',
cardAssetKey: 'boss8',
musicAssetKey: placeholderMusicKey,
songMapKey: placeholderSongMapKey,
defeatsRequired: 5
}];
var loadedUnlockProgress = storage[BOSS_UNLOCK_KEY];
if (loadedUnlockProgress) {
bossUnlockProgress = loadedUnlockProgress;
// Upewnij się, że wszyscy zdefiniowani bossowie mają wpis w postępie
// (na wypadek dodania nowych bossów w przyszłości i starym zapisie w storage)
for (var i = 0; i < allBossData.length; i++) {
var bossId = allBossData[i].id;
if (!bossUnlockProgress.hasOwnProperty(bossId)) {
bossUnlockProgress[bossId] = false;
}
}
} else {
// Inicjalizuj, jeśli nie znaleziono w storage
bossUnlockProgress = {};
for (var j = 0; j < allBossData.length; j++) {
bossUnlockProgress[allBossData[j].id] = false;
}
}
}
function updateSelectedCardVisual() {
for (var i = 0; i < visibleBossCards.length; i++) {
var cardContainer = visibleBossCards[i];
if (cardContainer && cardContainer.visualAsset) {
if (i === selectedCardSlotIndex) {
cardContainer.visualAsset.tint = 0xFFFF00;
cardContainer.scale.set(1.05);
} else {
cardContainer.visualAsset.tint = 0xFFFFFF;
cardContainer.scale.set(1.0);
}
}
}
}
function displayBossCards(newStartIndex, isInitialDisplay, numberOfDefeated) {
currentBossViewStartIndex = newStartIndex;
var singleCardDisplayWidth = 400;
var singleCardDisplayHeight = 380;
var spacingBetweenCardsX = 80;
var cardSlotX_0 = singleCardDisplayWidth / 2;
var cardSlotX_1 = singleCardDisplayWidth * 1.5 + spacingBetweenCardsX;
var mainCardsCenterY_relative = singleCardDisplayHeight / 2;
var peekingCardVisibleSliceHeight = 80;
var verticalOffsetMainToPeeking = 140;
var mainCardSlotsPositions = [{
x: cardSlotX_0,
y: mainCardsCenterY_relative
}, {
x: cardSlotX_1,
y: mainCardsCenterY_relative
}];
var peekingCardsTopY_relative = mainCardsCenterY_relative + singleCardDisplayHeight / 2 + verticalOffsetMainToPeeking;
var peekingCardSlotsPositions = [{
x: cardSlotX_0,
y: peekingCardsTopY_relative
}, {
x: cardSlotX_1,
y: peekingCardsTopY_relative
}];
if (!cardsContainer) {
return;
}
while (cardsContainer.children[0]) {
cardsContainer.removeChild(cardsContainer.children[0]).destroy();
}
visibleBossCards = [null, null];
peekingBossCards = [null, null];
for (var i = 0; i < 2; i++) {
var dataIndex = currentBossViewStartIndex + i;
if (dataIndex < allBossData.length) {
var bossData = allBossData[dataIndex];
var cardContainer = new Container();
cardContainer.x = mainCardSlotsPositions[i].x;
cardContainer.y = mainCardSlotsPositions[i].y;
cardContainer.bossData = bossData;
cardContainer.slotIndex = i;
var cardAsset = LK.getAsset(bossData.cardAssetKey, {});
cardAsset.anchor.set(0.5, 0.5);
cardAsset.width = singleCardDisplayWidth;
cardAsset.height = singleCardDisplayHeight;
cardContainer.visualAsset = cardAsset;
cardContainer.addChild(cardAsset);
var nameText = new Text2(bossData.displayName, {
size: 30,
fill: 0xFFFFFF,
stroke: 0x000000,
strokeThickness: 2
});
nameText.anchor.set(0.5, 0);
nameText.x = 0;
nameText.y = singleCardDisplayHeight / 2 + 5;
cardContainer.addChild(nameText);
var isUnlocked = bossData.defeatsRequired === 0 || numberOfDefeated >= bossData.defeatsRequired;
bossData.isUnlocked = isUnlocked; // Zapiszmy status odblokowania
// Wszystkie karty są interaktywne
cardContainer.interactive = true;
cardContainer.cursor = "pointer";
cardContainer.down = function () {
selectedCardSlotIndex = this.slotIndex;
updateSelectedCardVisual();
};
// Usunięto wizualne zmiany dla zablokowanych kart (alpha, tekst "LOCKED")
cardsContainer.addChild(cardContainer);
visibleBossCards[i] = cardContainer;
}
}
for (var j = 0; j < 2; j++) {
var peekingDataIndex = currentBossViewStartIndex + 2 + j;
if (peekingDataIndex < allBossData.length) {
var peekingBossData = allBossData[peekingDataIndex];
var peekingCardContainer = new Container();
peekingCardContainer.x = peekingCardSlotsPositions[j].x;
peekingCardContainer.y = peekingCardSlotsPositions[j].y;
var peekingCardAsset = LK.getAsset(peekingBossData.cardAssetKey, {});
peekingCardAsset.anchor.set(0.5, 0); // Anchor u góry na środku dla "zajawki"
peekingCardAsset.width = singleCardDisplayWidth;
peekingCardAsset.height = singleCardDisplayHeight;
peekingCardContainer.addChild(peekingCardAsset);
// Usunięto wizualne zmiany dla zablokowanych kart "zajawek" (alpha, tekst "LOCKED")
peekingCardContainer.interactive = false; // Zajawki pozostają nieinteraktywne
cardsContainer.addChild(peekingCardContainer);
peekingBossCards[j] = peekingCardContainer;
}
}
if (isInitialDisplay) {
selectedCardSlotIndex = 0;
} else {
var maxSlotOnNewPage = Math.min(1, allBossData.length - 1 - currentBossViewStartIndex);
if (selectedCardSlotIndex > maxSlotOnNewPage) {
selectedCardSlotIndex = maxSlotOnNewPage;
}
}
updateSelectedCardVisual();
}
function getNumberOfDefeatedBosses() {
var count = 0;
for (var i = 0; i < allBossData.length; i++) {
// Zakładamy, że allBossData zawiera tylko standardowych bossów (1-8)
var bossId = allBossData[i].id;
if (bossUnlockProgress.hasOwnProperty(bossId) && bossUnlockProgress[bossId] === true) {
count++;
}
}
return count;
}
function showBossSelectionScreen() {
if (songSummaryContainer && songSummaryContainer.parent) {
songSummaryContainer.destroy();
songSummaryContainer = null;
}
currentScreenState = 'bossGallery_paged';
if (gameUIContainer) {
gameUIContainer.visible = false;
}
if (staticHitFrame) {
staticHitFrame.visible = false;
}
if (staticPerfectLine) {
staticPerfectLine.visible = false;
}
if (shieldTimerDisplayContainer) {
shieldTimerDisplayContainer.visible = false;
}
if (swipeToTapTimerDisplayContainer) {
swipeToTapTimerDisplayContainer.visible = false;
}
initializeBossData();
var numberOfDefeated = getNumberOfDefeatedBosses();
var screenElements = [];
var tempSingleCardDisplayWidth = 400;
var tempSingleCardDisplayHeight = 380;
var tempSpacingBetweenCardsX = 80;
var tempGroupHorizontalOffset = -60;
var tempGroupVerticalOffset = -90;
var screenAreaContentWidth = tempSingleCardDisplayWidth * 2 + tempSpacingBetweenCardsX;
var screenAreaX = (gameScreenWidth - screenAreaContentWidth) / 2 + tempGroupHorizontalOffset;
var screenAreaY = gameScreenHeight / 2 + tempGroupVerticalOffset - tempSingleCardDisplayHeight / 2;
if (cardsContainer && cardsContainer.parent) {
cardsContainer.destroy();
}
cardsContainer = new Container();
cardsContainer.x = screenAreaX;
cardsContainer.y = screenAreaY;
game.addChild(cardsContainer);
screenElements.push(cardsContainer);
displayBossCards(0, true, numberOfDefeated);
var glassAsset = LK.getAsset('glass', {
x: 424,
y: 886,
width: 1180,
height: 1200,
alpha: 0.3,
interactive: false
});
game.addChild(glassAsset);
screenElements.push(glassAsset);
var galleryBg = LK.getAsset('galleryBackground', {
width: gameScreenWidth,
height: gameScreenHeight,
x: 0,
y: 0
});
game.addChild(galleryBg);
screenElements.push(galleryBg);
var upButton = LK.getAsset('upbutton', {});
upButton.x = 210;
upButton.y = gameScreenHeight / 2 - 180;
upButton.anchor.set(0.5, 0.5);
upButton.interactive = true;
upButton.cursor = "pointer";
upButton.down = function () {
var newIndex = Math.max(0, currentBossViewStartIndex - 2);
if (newIndex !== currentBossViewStartIndex) {
displayBossCards(newIndex, false, getNumberOfDefeatedBosses());
}
};
game.addChild(upButton);
screenElements.push(upButton);
var downButton = LK.getAsset('downbutton', {});
downButton.x = 210;
downButton.y = gameScreenHeight / 2 + 220;
downButton.anchor.set(0.5, 0.5);
downButton.interactive = true;
downButton.cursor = "pointer";
downButton.down = function () {
var newIndex = currentBossViewStartIndex + 2;
if (newIndex < allBossData.length) {
var potentialMaxViewable = allBossData.length - 2;
if (currentBossViewStartIndex < potentialMaxViewable || allBossData.length % 2 !== 0 && newIndex < allBossData.length) {
displayBossCards(newIndex, false, getNumberOfDefeatedBosses());
} else if (newIndex >= allBossData.length - 1 && allBossData.length % 2 !== 0) {
displayBossCards(allBossData.length - 1, false, getNumberOfDefeatedBosses());
}
}
};
game.addChild(downButton);
screenElements.push(downButton);
var playButton = LK.getAsset('play', {});
playButton.x = gameScreenWidth - 350;
playButton.y = gameScreenHeight / 2 - 240;
playButton.anchor.set(0.5, 0.5);
playButton.interactive = true;
playButton.cursor = "pointer";
playButton.down = function () {
var selectedBossIndexGlobal = currentBossViewStartIndex + selectedCardSlotIndex;
if (selectedBossIndexGlobal < 0 || selectedBossIndexGlobal >= allBossData.length) {
return;
}
var selectedBossData = allBossData[selectedBossIndexGlobal];
if (selectedBossData) {
if (currentlyPlayingMusic && typeof currentlyPlayingMusic.stop === 'function') {
currentlyPlayingMusic.stop();
}
currentlyPlayingMusic = LK.getSound(selectedBossData.musicAssetKey);
if (currentlyPlayingMusic && typeof currentlyPlayingMusic.play === 'function') {
currentlyPlayingMusic.play();
}
}
};
game.addChild(playButton);
screenElements.push(playButton);
var stopButton = LK.getAsset('stop', {});
stopButton.x = gameScreenWidth - 350;
stopButton.y = gameScreenHeight / 2;
stopButton.anchor.set(0.5, 0.5);
stopButton.interactive = true;
stopButton.cursor = "pointer";
stopButton.down = function () {
if (currentlyPlayingMusic && typeof currentlyPlayingMusic.stop === 'function') {
currentlyPlayingMusic.stop();
currentlyPlayingMusic = null;
}
};
game.addChild(stopButton);
screenElements.push(stopButton);
var fightButton = LK.getAsset('fight', {});
fightButton.x = gameScreenWidth - 350;
fightButton.y = gameScreenHeight / 2 + 240;
fightButton.anchor.set(0.5, 0.5);
fightButton.interactive = true;
fightButton.cursor = "pointer";
fightButton.down = function () {
var selectedBossIndexGlobal = currentBossViewStartIndex + selectedCardSlotIndex;
if (selectedBossIndexGlobal < 0 || selectedBossIndexGlobal >= allBossData.length) {
return;
}
var selectedBossData = allBossData[selectedBossIndexGlobal];
if (selectedBossData) {
if (selectedBossData.isUnlocked) {
if (currentlyPlayingMusic && typeof currentlyPlayingMusic.stop === 'function') {
currentlyPlayingMusic.stop();
currentlyPlayingMusic = null;
}
screenElements.forEach(function (el) {
if (el && el.parent) {
el.destroy();
}
});
screenElements = [];
if (cardsContainer && cardsContainer.parent) {
cardsContainer.destroy();
}
cardsContainer = null;
loadSong(selectedBossData.songMapKey);
currentScreenState = 'gameplay';
} else {
var requirementTextContent = "This boss is locked.";
if (selectedBossData.defeatsRequired > 0) {
var remainingDefeats = selectedBossData.defeatsRequired - getNumberOfDefeatedBosses();
if (remainingDefeats > 0) {
requirementTextContent = "Defeat " + remainingDefeats + (remainingDefeats === 1 ? " more boss" : " more bosses") + " to unlock!";
}
}
var infoPopup = new Text2(requirementTextContent, {
size: 70,
fill: 0xe24203,
stroke: 0x000000,
strokeThickness: 2,
align: 'center',
wordWrap: true,
wordWrapWidth: gameScreenWidth * 0.5
});
infoPopup.anchor.set(0.5, 0.5);
infoPopup.x = gameScreenWidth / 2 - 90;
infoPopup.y = gameScreenHeight / 2;
game.addChild(infoPopup);
LK.setTimeout(function () {
if (infoPopup.parent) {
infoPopup.destroy();
}
}, 3500);
}
}
};
game.addChild(fightButton);
screenElements.push(fightButton);
var actualDefeatedCount = getNumberOfDefeatedBosses();
var allStandardBossesDefeated = actualDefeatedCount === allBossData.length;
var specialBossButtonAssetKey = allStandardBossesDefeated ? 'specialboss_unlocked' : 'specialboss_locked';
var specialBossButton = LK.getAsset(specialBossButtonAssetKey, {});
specialBossButton.width = 400;
specialBossButton.height = 370;
specialBossButton.x = 950;
specialBossButton.y = 2000;
specialBossButton.anchor.set(0.5, 0.5);
specialBossButton.interactive = true;
if (allStandardBossesDefeated) {
specialBossButton.cursor = "pointer";
specialBossButton.down = function () {
console.log("Special Boss Fight Initiated! (Not Implemented)");
};
} else {
specialBossButton.cursor = "default";
specialBossButton.down = function () {
var infoPopup = new Text2("Defeat all other bosses (" + actualDefeatedCount + "/" + allBossData.length + ")\nto unlock!", {
size: 70,
fill: 0xe24203,
stroke: 0x000000,
strokeThickness: 2,
align: 'center',
wordWrap: true,
wordWrapWidth: gameScreenWidth * 0.5
});
infoPopup.anchor.set(0.5, 0.5);
infoPopup.x = gameScreenWidth / 2 - 90;
infoPopup.y = gameScreenHeight / 2;
game.addChild(infoPopup);
LK.setTimeout(function () {
if (infoPopup.parent) {
infoPopup.destroy();
}
}, 3500);
};
}
game.addChild(specialBossButton);
screenElements.push(specialBossButton);
var backToMainButton = new Text2("Back to Main Menu", {
size: 50,
fill: 0xDDDDDD
});
backToMainButton.anchor.set(0.5, 1);
backToMainButton.x = gameScreenWidth / 2;
backToMainButton.y = gameScreenHeight - 20;
backToMainButton.interactive = true;
backToMainButton.cursor = "pointer";
backToMainButton.down = function () {
if (currentlyPlayingMusic && typeof currentlyPlayingMusic.stop === 'function') {
currentlyPlayingMusic.stop();
currentlyPlayingMusic = null;
}
screenElements.forEach(function (el) {
if (el && el.parent) {
el.destroy();
}
});
screenElements = [];
if (cardsContainer && cardsContainer.parent) {
cardsContainer.destroy();
}
cardsContainer = null;
currentBossViewStartIndex = 0;
selectedCardSlotIndex = 0;
showMainMenu();
};
game.addChild(backToMainButton);
screenElements.push(backToMainButton);
var rewindButton = LK.getAsset('rewindbutton', {
x: 350,
y: gameScreenHeight / 2 + 420 + 20 + 210,
anchorX: 0.5,
anchorY: 0.5,
interactive: true,
cursor: "pointer"
});
rewindButton.down = function () {
if (currentlyPlayingMusic && typeof currentlyPlayingMusic.stop === 'function') {
currentlyPlayingMusic.stop();
currentlyPlayingMusic = null;
}
screenElements.forEach(function (el) {
if (el && el.parent) {
el.destroy();
}
});
screenElements = [];
if (cardsContainer && cardsContainer.parent) {
cardsContainer.destroy();
cardsContainer = null;
}
currentBossViewStartIndex = 0;
selectedCardSlotIndex = 0;
showMainMenu();
};
game.addChild(rewindButton);
screenElements.push(rewindButton);
}
function displayStatsForBoss(bossIndex) {
console.log("--- displayStatsForBoss called for index: " + bossIndex + " ---");
while (currentBossDisplayElements.length > 0) {
var el = currentBossDisplayElements.pop();
if (el && el.parent) {
el.destroy();
}
}
if (bossIndex < 0 || bossIndex >= allBossData.length) {
console.error("Invalid bossIndex for stats: " + bossIndex);
return;
}
var bossData = allBossData[bossIndex];
if (!bossData) {
console.error("No bossData found for index: " + bossIndex);
return;
}
console.log("Displaying stats for boss: " + bossData.displayName);
var viewport = miniGameViewport;
var padding = 40;
var bossStatDetailsContainer = new Container();
bossStatDetailsContainer.x = viewport.x;
bossStatDetailsContainer.y = viewport.y + 60 + 80;
game.addChild(bossStatDetailsContainer);
currentBossDisplayElements.push(bossStatDetailsContainer);
var bossImageWidth = viewport.width * 0.35;
var bossImageHeight = (viewport.height - (viewport.y + 60 + 80 - bossStatDetailsContainer.y)) * 0.7;
if (bossImageHeight > bossImageWidth * 1.5) {
bossImageHeight = bossImageWidth * 1.5;
}
var bossImageX = padding + bossImageWidth / 2;
var bossImageY = padding + bossImageHeight / 2;
var bossAssetKeyToDisplay = bossData.cardAssetKey;
if (!bossAssetKeyToDisplay) {
console.warn("Boss " + bossData.displayName + " has an empty cardAssetKey. Using placeholder.");
bossAssetKeyToDisplay = 'statsBossPlaceholder';
}
var bossImage = LK.getAsset(bossAssetKeyToDisplay, {
anchorX: 0.5,
anchorY: 0.5,
x: bossImageX,
y: bossImageY,
width: bossImageWidth,
height: bossImageHeight
});
bossStatDetailsContainer.addChild(bossImage);
console.log("Boss image: " + bossAssetKeyToDisplay + " at x=" + bossImageX + ", y=" + bossImageY);
// B. Teksty statystyk
var statsTextX = bossImageX + bossImageWidth / 2 + 40; // Zwiększony odstęp od obrazka
var currentTextY = padding + 30; // Startowa pozycja Y dla pierwszego tekstu statystyk (Best Score)
// Możesz dostosować tę wartość, aby ładnie pasowała pod/obok obrazka
var valueFontSize = 65; // Zwiększyłem trochę rozmiar dla wartości statystyk
var lineSpacing = 115; // Zwiększyłem trochę odstęp między liniami
var statsMaxWidth = viewport.width - statsTextX - padding * 1.5;
var songStats = getSongStats(bossData.songMapKey);
var bestScore = songStats.bestScore;
var bestCombo = songStats.bestCombo;
var defeatedStatus = bossUnlockProgress[bossData.id] ? "YES" : "NO";
var defeatedColor = bossUnlockProgress[bossData.id] ? 0x32CD32 : 0xFF4500;
console.log("Stats values - Score: " + bestScore + ", Combo: " + bestCombo + ", Defeated: " + defeatedStatus);
// Usunięto wyświetlanie "nameText" (nazwy bossa)
// Best Score - teraz jako pierwszy tekst
var scoreText = new Text2("Best Score: " + bestScore, {
size: valueFontSize,
fill: 0xFFFFFF,
align: 'left',
wordWrap: true,
wordWrapWidth: statsMaxWidth
});
scoreText.anchor.set(0, 0);
scoreText.x = statsTextX;
scoreText.y = currentTextY;
bossStatDetailsContainer.addChild(scoreText);
currentTextY += valueFontSize + 65; // Odstęp pod Best Score (dostosuj)
// Best Combo
var comboText = new Text2("Best Combo: " + bestCombo, {
size: valueFontSize,
fill: 0xFFFFFF,
align: 'left',
wordWrap: true,
wordWrapWidth: statsMaxWidth
});
comboText.anchor.set(0, 0);
comboText.x = statsTextX;
comboText.y = currentTextY;
bossStatDetailsContainer.addChild(comboText);
currentTextY += valueFontSize + 65; // Odstęp pod Best Combo (dostosuj)
// Boss Defeated
var defeatedText = new Text2("Defeated: ", {
size: valueFontSize,
fill: 0xFFFFFF,
align: 'left'
});
defeatedText.anchor.set(0, 0);
defeatedText.x = statsTextX;
defeatedText.y = currentTextY;
bossStatDetailsContainer.addChild(defeatedText);
var defeatedValue = new Text2(defeatedStatus, {
size: valueFontSize,
fill: defeatedColor,
align: 'left'
});
defeatedValue.anchor.set(0, 0);
defeatedValue.x = statsTextX + defeatedText.width + 10;
defeatedValue.y = currentTextY;
bossStatDetailsContainer.addChild(defeatedValue);
console.log("Stat texts (without boss name) added to container.");
}
function showStatsScreen() {
console.log("Showing Stats Screen - Full Setup");
while (statsScreenElements.length > 0) {
var el = statsScreenElements.pop();
if (el && el.parent) {
el.destroy();
}
}
while (currentBossDisplayElements.length > 0) {
var cbdEl = currentBossDisplayElements.pop();
if (cbdEl && cbdEl.parent) {
cbdEl.destroy();
}
}
initializeBossData(); // <<<< DODAJ TĘ LINIĘ NA POCZĄTKU FUNKCJI
currentScreenState = 'statsScreen';
currentStatsBossIndex = 0;
var walkmanFrameStats = LK.getAsset('mainmenu', {
x: 0,
y: 0,
width: gameScreenWidth,
height: gameScreenHeight
});
game.addChild(walkmanFrameStats);
statsScreenElements.push(walkmanFrameStats);
var glassStats = LK.getAsset('glass', {
x: miniGameViewport.x,
y: miniGameViewport.y,
width: miniGameViewport.width,
height: miniGameViewport.height,
alpha: 0.15,
interactive: false
});
game.addChild(glassStats);
statsScreenElements.push(glassStats);
var statsTitle = new Text2("PLAYER STATS", {
size: 60,
fill: 0xFFFFFF,
align: 'center',
stroke: 0x000000,
strokeThickness: 4
});
statsTitle.anchor.set(0.5, 0.5);
statsTitle.x = miniGameViewport.x + miniGameViewport.width / 2;
statsTitle.y = miniGameViewport.y + 100;
game.addChild(statsTitle);
statsScreenElements.push(statsTitle);
displayStatsForBoss(currentStatsBossIndex);
// Przyciski nawigacyjne dla ekranu Stats
var upButtonStats = LK.getAsset('upbutton', {});
upButtonStats.x = 210;
upButtonStats.y = gameScreenHeight / 2 - 180;
upButtonStats.anchor.set(0.5, 0.5);
upButtonStats.interactive = true;
upButtonStats.cursor = "pointer";
upButtonStats.down = function () {
if (currentStatsBossIndex > 0) {
currentStatsBossIndex--;
displayStatsForBoss(currentStatsBossIndex);
}
};
game.addChild(upButtonStats);
statsScreenElements.push(upButtonStats);
var downButtonStats = LK.getAsset('downbutton', {});
downButtonStats.x = 210;
downButtonStats.y = gameScreenHeight / 2 + 220;
downButtonStats.anchor.set(0.5, 0.5);
downButtonStats.interactive = true;
downButtonStats.cursor = "pointer";
downButtonStats.down = function () {
if (currentStatsBossIndex < allBossData.length - 1) {
currentStatsBossIndex++;
displayStatsForBoss(currentStatsBossIndex);
}
};
game.addChild(downButtonStats);
statsScreenElements.push(downButtonStats);
var rewindButtonStats = LK.getAsset('rewindbutton', {
x: 350,
y: gameScreenHeight / 2 + 650,
anchorX: 0.5,
anchorY: 0.5,
interactive: true,
cursor: "pointer"
});
rewindButtonStats.down = function () {
console.log("Rewind button pressed: Exiting Stats screen.");
while (statsScreenElements.length > 0) {
var elToDestroyStats = statsScreenElements.pop();
if (elToDestroyStats && elToDestroyStats.parent) {
elToDestroyStats.destroy();
}
}
while (currentBossDisplayElements.length > 0) {
var cbdElExit = currentBossDisplayElements.pop(); // Zmieniona nazwa zmiennej
if (cbdElExit && cbdElExit.parent) {
cbdElExit.destroy();
}
}
showMainMenu();
};
game.addChild(rewindButtonStats);
statsScreenElements.push(rewindButtonStats);
var playButtonStats = LK.getAsset('play', {});
playButtonStats.x = gameScreenWidth - 350;
playButtonStats.y = gameScreenHeight / 2 - 240;
playButtonStats.anchor.set(0.5, 0.5);
playButtonStats.interactive = false;
playButtonStats.alpha = 0.5;
game.addChild(playButtonStats);
statsScreenElements.push(playButtonStats);
var stopButtonStats = LK.getAsset('stop', {});
stopButtonStats.x = gameScreenWidth - 350;
stopButtonStats.y = gameScreenHeight / 2;
stopButtonStats.anchor.set(0.5, 0.5);
stopButtonStats.interactive = false;
stopButtonStats.alpha = 0.5;
game.addChild(stopButtonStats);
statsScreenElements.push(stopButtonStats);
var fightButtonStats = LK.getAsset('fight', {});
fightButtonStats.x = gameScreenWidth - 350;
fightButtonStats.y = gameScreenHeight / 2 + 240;
fightButtonStats.anchor.set(0.5, 0.5);
fightButtonStats.interactive = false;
fightButtonStats.alpha = 0.5;
game.addChild(fightButtonStats);
statsScreenElements.push(fightButtonStats);
}
function showCreditsScreen() {
currentScreenState = 'credits';
if (gameUIContainer) {
gameUIContainer.visible = false;
}
if (staticHitFrame) {
staticHitFrame.visible = false;
}
if (staticPerfectLine) {
staticPerfectLine.visible = false;
}
game.setBackgroundColor(0x1a1a1a); // Ciemnoszary dla creditsów
var elements = [];
var creditsText = new Text2("Gra stworzona przez:\nNasz Wspaniały Duet!", {
size: 90,
fill: 0xFFFFFF,
align: 'center' // Wyśrodkowanie tekstu wieloliniowego
});
creditsText.anchor.set(0.5, 0.5);
creditsText.x = gameScreenWidth / 2;
creditsText.y = gameScreenHeight / 2 - 100;
game.addChild(creditsText);
elements.push(creditsText);
var backButton = new Text2("Back to Menu", {
size: 80,
fill: 0xCCCCCC
});
backButton.anchor.set(0.5, 0.5);
backButton.x = gameScreenWidth / 2;
backButton.y = gameScreenHeight - 200;
backButton.interactive = true;
backButton.cursor = "pointer";
game.addChild(backButton);
elements.push(backButton);
backButton.down = function () {
elements.forEach(function (item) {
if (item.parent) {
item.destroy();
}
});
showMainMenu();
};
}
function showIntro() {
currentScreenState = 'intro';
if (gameUIContainer) {
gameUIContainer.visible = false;
}
if (staticHitFrame) {
staticHitFrame.visible = false;
}
if (staticPerfectLine) {
staticPerfectLine.visible = false;
}
if (typeof shieldTimerDisplayContainer !== 'undefined' && shieldTimerDisplayContainer) {
shieldTimerDisplayContainer.visible = false;
}
if (typeof precisionBuffTimerDisplayContainer !== 'undefined' && precisionBuffTimerDisplayContainer) {
precisionBuffTimerDisplayContainer.visible = false;
}
game.setBackgroundColor(0x111111);
var introPlaceholderText = new Text2("Intro Sequence Placeholder", {
size: 100,
fill: 0xFFFFFF
});
introPlaceholderText.anchor.set(0.5, 0.5);
introPlaceholderText.x = gameScreenWidth / 2;
introPlaceholderText.y = gameScreenHeight / 2;
game.addChild(introPlaceholderText);
LK.setTimeout(function () {
if (introPlaceholderText.parent) {
introPlaceholderText.destroy();
}
showMainMenu();
}, 1000);
}
function checkMiniGameCollisions() {
if (!miniGamePlayer || !miniGamePlayer.asset || isMiniGameOver) {
return;
}
for (var i = miniGameObstacles.length - 1; i >= 0; i--) {
var obs = miniGameObstacles[i];
if (miniGameRectsIntersect(miniGamePlayer, obs)) {
console.log("Game Over - Hit obstacle!");
isMiniGameOver = true;
if (miniGamePlayer.asset) {
miniGamePlayer.asset.tint = 0xFF0000;
}
return;
}
}
}
function miniGameRectsIntersect(r1Player, r2Object) {
// r1Player to obiekt miniGamePlayer
// r2Object to obiekt przeszkody lub mobka
// Zakładamy, że wszystkie assety mają anchor 0.5, 0.5
var r1Details = {
x: r1Player.x,
y: r1Player.y,
width: r1Player.width,
height: r1Player.height
};
var r2Details = {
x: r2Object.x,
y: r2Object.y,
width: r2Object.width,
height: r2Object.height
};
var r1left = r1Details.x - r1Details.width / 2;
var r1right = r1Details.x + r1Details.width / 2;
var r1top = r1Details.y - r1Details.height / 2;
var r1bottom = r1Details.y + r1Details.height / 2;
var r2left = r2Details.x - r2Details.width / 2;
var r2right = r2Details.x + r2Details.width / 2;
var r2top = r2Details.y - r2Details.height / 2;
var r2bottom = r2Details.y + r2Details.height / 2;
return !(r2left >= r1right || r2right <= r1left || r2top >= r1bottom || r2bottom <= r1top);
}
function runTutorialGameplay() {
if (currentMainMenuMusicTrack && typeof currentMainMenuMusicTrack.stop === 'function') {
currentMainMenuMusicTrack.stop();
}
while (mainMenuScreenElements.length > 0) {
var elemToDestroy = mainMenuScreenElements.pop();
if (elemToDestroy && elemToDestroy.parent) {
elemToDestroy.destroy();
}
}
mainMenuItemTextObjects = [];
if (typeof menuTextContainer !== 'undefined' && menuTextContainer && menuTextContainer.parent) {
menuTextContainer.destroy(); // Zniszcz kontener, jeśli istnieje
}
menuTextContainer = null; // Zresetuj referencję
isTutorialMode = true;
currentScreenState = 'gameplay';
allSongData["TutorialTrack"] = tutorialSongData;
currentFightingBossId = null;
loadSong("TutorialTrack");
}
function exitTutorialGameplay() {
isTutorialMode = false;
if (currentMusic) {
currentMusic.stop();
currentMusic = null;
}
resetGameState();
if (scoreTxt) {
scoreTxt.visible = true;
}
if (comboTxt) {
comboTxt.visible = true;
}
if (gameUIContainer) {
gameUIContainer.visible = false;
}
if (staticHitFrame) {
staticHitFrame.visible = false;
// animatedHitFrame.stop(); // Ta linia już nie będzie potrzebna
}
if (staticPerfectLine) {
staticPerfectLine.visible = false;
}
showMainMenu();
}
// Game State & Rhythm Logic Variables
var allSongData = {
"OrctaveBossTrack": {
musicAsset: "Orctave",
// Upewnij się, że masz asset muzyczny o tym kluczu
bossAssetKey: 'Boss1_Asset',
// Asset dla pierwszego bossa
config: {
playerMaxHP: 100,
bossMaxHP: 200
},
rawRhythmMap: [{
time: 8000,
type: 'tap',
columnIndex: 0
}, {
time: 8210,
type: 'tap',
columnIndex: 1
}, {
time: 8401,
type: 'tap',
columnIndex: 2
}, {
time: 8596,
type: 'tap',
columnIndex: 0
}, {
time: 8795,
type: 'tap',
columnIndex: 1
}, {
time: 9117,
type: 'tap',
columnIndex: 2
}, {
time: 9832,
type: 'swipe',
columnIndex: 0,
swipeDir: 'right'
}, {
time: 10536,
type: 'swipe',
columnIndex: 0,
swipeDir: 'right'
}, {
time: 11245,
type: 'swipe',
columnIndex: 0,
swipeDir: 'right'
}, {
time: 11888,
type: 'swipe',
columnIndex: 2,
swipeDir: 'left'
}, {
time: 12628,
type: 'swipe',
columnIndex: 2,
swipeDir: 'left'
}, {
time: 13308,
type: 'swipe',
columnIndex: 2,
swipeDir: 'left'
}, {
time: 13986,
type: 'swipe',
columnIndex: 2,
swipeDir: 'left'
}, {
time: 14696,
type: 'tap',
columnIndex: 2
}, {
time: 15456,
type: 'tap',
columnIndex: 2
}, {
time: 16140,
type: 'tap',
columnIndex: 1
}, {
time: 16863,
type: 'tap',
columnIndex: 1
}, {
time: 17547,
type: 'tap',
columnIndex: 0
}, {
time: 18275,
type: 'tap',
columnIndex: 0
}, {
time: 18955,
type: 'tap',
columnIndex: 0
}, {
time: 19670,
type: 'tap',
columnIndex: 0
}, {
time: 20333,
type: 'tap',
columnIndex: 1
}, {
time: 20740,
type: 'tap',
columnIndex: 2
}, {
time: 21063,
type: 'tap',
columnIndex: 1
}, {
time: 21411,
type: 'tap',
columnIndex: 0
}, {
time: 21742,
type: 'tap',
columnIndex: 1
}, {
time: 22110,
type: 'tap',
columnIndex: 2
}, {
time: 22463,
type: 'tap',
columnIndex: 1
}, {
time: 22797,
type: 'tap',
columnIndex: 0
}, {
time: 23336,
type: 'tap',
columnIndex: 2
}, {
time: 26163,
type: 'swipe',
columnIndex: 0,
swipeDir: 'right'
}, {
time: 26737,
type: 'swipe',
columnIndex: 2,
swipeDir: 'left'
}, {
time: 27351,
type: 'swipe',
columnIndex: 0,
swipeDir: 'right'
}, {
time: 27764,
type: 'swipe',
columnIndex: 0,
swipeDir: 'right'
}, {
time: 28116,
type: 'swipe',
columnIndex: 2,
swipeDir: 'left'
}, {
time: 28827,
type: 'swipe',
columnIndex: 1,
swipeDir: 'right'
}, {
time: 29546,
type: 'swipe',
columnIndex: 0,
swipeDir: 'left'
}, {
time: 30102,
type: 'swipe',
columnIndex: 1,
swipeDir: 'right'
}, {
time: 30534,
type: 'swipe',
columnIndex: 1,
swipeDir: 'right'
}, {
time: 30931,
type: 'swipe',
columnIndex: 0,
swipeDir: 'left'
}, {
time: 31677,
type: 'tap',
columnIndex: 2
}, {
time: 32392,
type: 'tap',
columnIndex: 1
}, {
time: 32989,
type: 'tap',
columnIndex: 2
}, {
time: 33386,
type: 'tap',
columnIndex: 2
}, {
time: 33781,
type: 'tap',
columnIndex: 1
}, {
time: 34568,
type: 'tap',
columnIndex: 2
}, {
time: 35234,
type: 'tap',
columnIndex: 1
}, {
time: 35749,
type: 'tap',
columnIndex: 2
}, {
time: 36182,
type: 'tap',
columnIndex: 2
}, {
time: 36583,
type: 'tap',
columnIndex: 0
}, {
time: 37302,
type: 'tap',
columnIndex: 0
}, {
time: 37681,
type: 'tap',
columnIndex: 1
}, {
time: 38033,
type: 'tap',
columnIndex: 2
}, {
time: 38354,
type: 'tap',
columnIndex: 2
}, {
time: 38721,
type: 'tap',
columnIndex: 1
}, {
time: 39067,
type: 'tap',
columnIndex: 0
}, {
time: 39471,
type: 'tap',
columnIndex: 1
}, {
time: 39821,
type: 'tap',
columnIndex: 2
}, {
time: 40164,
type: 'tap',
columnIndex: 1
}, {
time: 40488,
type: 'tap',
columnIndex: 0
}, {
time: 40861,
type: 'tap',
columnIndex: 0
}, {
time: 41250,
type: 'tap',
columnIndex: 1
}, {
time: 41609,
type: 'tap',
columnIndex: 2
}, {
time: 41946,
type: 'tap',
columnIndex: 1
}, {
time: 42290,
type: 'tap',
columnIndex: 0
}, {
time: 42643,
type: 'tap',
columnIndex: 2
}, {
time: 43068,
type: 'tap',
columnIndex: 1
}, {
time: 43379,
type: 'tap',
columnIndex: 2
}, {
time: 43726,
type: 'tap',
columnIndex: 1
}, {
time: 44078,
type: 'tap',
columnIndex: 2
}, {
time: 44414,
type: 'tap',
columnIndex: 1
}, {
time: 44728,
type: 'tap',
columnIndex: 2
}, {
time: 45115,
type: 'tap',
columnIndex: 1
}, {
time: 45475,
type: 'tap',
columnIndex: 2
}, {
time: 45809,
type: 'tap',
columnIndex: 0
}, {
time: 46199,
type: 'tap',
columnIndex: 1
}, {
time: 46521,
type: 'tap',
columnIndex: 2
}, {
time: 46855,
type: 'tap',
columnIndex: 1
}, {
time: 47190,
type: 'tap',
columnIndex: 0
}, {
time: 47535,
type: 'tap',
columnIndex: 2
}, {
time: 47874,
type: 'tap',
columnIndex: 1
}, {
time: 48252,
type: 'tap',
columnIndex: 2
}, {
time: 51448,
type: 'swipe',
columnIndex: 2,
swipeDir: 'left'
}, {
time: 52112,
type: 'swipe',
columnIndex: 2,
swipeDir: 'left'
}, {
time: 52853,
type: 'swipe',
columnIndex: 2,
swipeDir: 'left'
}, {
time: 53536,
type: 'swipe',
columnIndex: 2,
swipeDir: 'left'
}, {
time: 54251,
type: 'swipe',
columnIndex: 0,
swipeDir: 'right'
}, {
time: 54964,
type: 'swipe',
columnIndex: 0,
swipeDir: 'right'
}, {
time: 55618,
type: 'swipe',
columnIndex: 0,
swipeDir: 'right'
}, {
time: 56339,
type: 'swipe',
columnIndex: 0,
swipeDir: 'right'
}, {
time: 57058,
type: 'swipe',
columnIndex: 1,
swipeDir: 'left'
}, {
time: 57799,
type: 'swipe',
columnIndex: 1,
swipeDir: 'left'
}, {
time: 58512,
type: 'swipe',
columnIndex: 1,
swipeDir: 'left'
}, {
time: 59170,
type: 'swipe',
columnIndex: 1,
swipeDir: 'left'
}, {
time: 59911,
type: 'swipe',
columnIndex: 2,
swipeDir: 'right'
}, {
time: 60668,
type: 'tap',
columnIndex: 2
}, {
time: 61334,
type: 'swipe',
columnIndex: 2,
swipeDir: 'right'
}, {
time: 62084,
type: 'tap',
columnIndex: 2
}, {
time: 62744,
type: 'swipe',
columnIndex: 2,
swipeDir: 'right'
}, {
time: 63445,
type: 'tap',
columnIndex: 2
}, {
time: 64134,
type: 'swipe',
columnIndex: 1,
swipeDir: 'left'
}, {
time: 64827,
type: 'tap',
columnIndex: 1
}, {
time: 65532,
type: 'swipe',
columnIndex: 1,
swipeDir: 'left'
}, {
time: 66199,
type: 'tap',
columnIndex: 1
}, {
time: 66921,
type: 'swipe',
columnIndex: 1,
swipeDir: 'left'
}, {
time: 67679,
type: 'tap',
columnIndex: 1
}, {
time: 68353,
type: 'swipe',
columnIndex: 0,
swipeDir: 'right'
}, {
time: 69005,
type: 'tap',
columnIndex: 0
}, {
time: 69772,
type: 'swipe',
columnIndex: 0,
swipeDir: 'right'
}, {
time: 70457,
type: 'tap',
columnIndex: 0
}, {
time: 71178,
type: 'swipe',
columnIndex: 1,
swipeDir: 'left'
}, {
time: 71892,
type: 'swipe',
columnIndex: 2,
swipeDir: 'right'
}, {
time: 72585,
type: 'swipe',
columnIndex: 1,
swipeDir: 'left'
}, {
time: 73287,
type: 'swipe',
columnIndex: 0,
swipeDir: 'right'
}, {
time: 74094,
type: 'tap',
columnIndex: 2
}, {
time: 75031,
type: 'tap',
columnIndex: 1
}, {
time: 75469,
type: 'tap',
columnIndex: 2
}, {
time: 75831,
type: 'tap',
columnIndex: 2
}, {
time: 76181,
type: 'tap',
columnIndex: 1
}, {
time: 76909,
type: 'tap',
columnIndex: 0
}, {
time: 77641,
type: 'tap',
columnIndex: 1
}, {
time: 78208,
type: 'tap',
columnIndex: 2
}, {
time: 78675,
type: 'tap',
columnIndex: 2
}, {
time: 79001,
type: 'tap',
columnIndex: 1
}, {
time: 79743,
type: 'tap',
columnIndex: 0
}, {
time: 80401,
type: 'tap',
columnIndex: 1
}, {
time: 80982,
type: 'tap',
columnIndex: 0
}, {
time: 81387,
type: 'tap',
columnIndex: 0
}, {
time: 81769,
type: 'tap',
columnIndex: 1
}, {
time: 82537,
type: 'tap',
columnIndex: 2
}, {
time: 83216,
type: 'tap',
columnIndex: 1
}, {
time: 83789,
type: 'tap',
columnIndex: 0
}, {
time: 84229,
type: 'tap',
columnIndex: 0
}, {
time: 84566,
type: 'tap',
columnIndex: 0
}, {
time: 84923,
type: 'tap',
columnIndex: 0
}, {
time: 85105,
type: 'tap',
columnIndex: 0
}, {
time: 85305,
type: 'tap',
columnIndex: 1
}]
}
};
// Initialize and add gameUIContainer to the game scene
gameUIContainer = new Container();
game.addChild(gameUIContainer);
// Function to process raw rhythm map data (remains unchanged, ensure it's here)
function processRawRhythmMap(rawMapData, songKeyForLogging) {
console.log("Processing raw map for: " + songKeyForLogging + " with " + rawMapData.length + " initial notes.");
var processedMap = [];
var tempMap = [];
for (var k = 0; k < rawMapData.length; k++) {
var originalNote = rawMapData[k];
var copiedNote = {};
for (var key in originalNote) {
if (originalNote.hasOwnProperty(key)) {
copiedNote[key] = originalNote[key];
}
}
tempMap.push(copiedNote);
}
for (var i = 0; i < tempMap.length; i++) {
var note = tempMap[i];
if (note.type === 'swipe' && note.swipeDir) {
var dir = note.swipeDir.toLowerCase();
if (dir.includes('right')) {
note.swipeDir = 'right';
} else if (dir.includes('left')) {
note.swipeDir = 'left';
} else if (dir.includes('up')) {
note.swipeDir = 'up';
} else if (dir.includes('down')) {
note.swipeDir = 'down';
}
}
}
var timeGroupedNotes = {};
tempMap.forEach(function (note) {
if (!timeGroupedNotes[note.time]) {
timeGroupedNotes[note.time] = [];
}
timeGroupedNotes[note.time].push(note);
});
var finalMapNotes = [];
var sortedTimes = Object.keys(timeGroupedNotes).map(Number).sort(function (a, b) {
return a - b;
});
for (var tIdx = 0; tIdx < sortedTimes.length; tIdx++) {
var time = sortedTimes[tIdx];
var notesAtThisTime = timeGroupedNotes[time];
var notesToKeepAtThisTime = [];
var processedForWiderSwipeConversion = [];
var colsWithVerticalSwipes = [null, null, null, null];
notesAtThisTime.forEach(function (note) {
if (note.type === 'swipe' && (note.swipeDir === 'up' || note.swipeDir === 'down')) {
if (note.columnIndex >= 0 && note.columnIndex < NUM_COLUMNS) {
var alreadyConverted = false;
for (var convIdx = 0; convIdx < processedForWiderSwipeConversion.length; convIdx++) {
if (processedForWiderSwipeConversion[convIdx].originalTime === note.time && processedForWiderSwipeConversion[convIdx].originalColumn === note.columnIndex) {
alreadyConverted = true;
break;
}
}
if (!alreadyConverted) {
colsWithVerticalSwipes[note.columnIndex] = note.swipeDir;
}
}
}
});
for (var c = 0; c < NUM_COLUMNS - 1; c++) {
if (colsWithVerticalSwipes[c] && colsWithVerticalSwipes[c + 1] && colsWithVerticalSwipes[c] === colsWithVerticalSwipes[c + 1]) {
var randomHorizontalDir = Math.random() < 0.5 ? 'left' : 'right';
var pairCenterX = (columnCenterXs[c] + columnCenterXs[c + 1]) / 2;
notesToKeepAtThisTime.push({
time: time,
type: 'swipe',
swipeDir: randomHorizontalDir,
partOfWiderSwipe: 'leftHalf',
widerSwipePairCenterX: pairCenterX,
originalColumnHint: c
});
notesToKeepAtThisTime.push({
time: time,
type: 'swipe',
swipeDir: randomHorizontalDir,
partOfWiderSwipe: 'rightHalf',
widerSwipePairCenterX: pairCenterX,
originalColumnHint: c + 1
});
processedForWiderSwipeConversion.push({
originalTime: time,
originalColumn: c
});
processedForWiderSwipeConversion.push({
originalTime: time,
originalColumn: c + 1
});
colsWithVerticalSwipes[c] = null;
colsWithVerticalSwipes[c + 1] = null;
c++;
}
}
notesAtThisTime.forEach(function (note) {
var wasConverted = false;
for (var convIdx = 0; convIdx < processedForWiderSwipeConversion.length; convIdx++) {
if (processedForWiderSwipeConversion[convIdx].originalTime === note.time && processedForWiderSwipeConversion[convIdx].originalColumn === note.columnIndex && (note.swipeDir === 'up' || note.swipeDir === 'down')) {
wasConverted = true;
break;
}
}
if (!wasConverted) {
notesToKeepAtThisTime.push(note);
}
});
var horizontalWiderSwipePairs = {};
var notesForFinalProcessing = [];
var uniqueNotesAtThisTime = [];
var seenNotesKeysAtThisTime = {};
notesToKeepAtThisTime.forEach(function (note) {
var key = "" + note.type + "_" + (note.columnIndex !== undefined ? note.columnIndex : note.partOfWiderSwipe ? note.widerSwipePairCenterX + note.partOfWiderSwipe : '') + "_" + (note.swipeDir || '');
if (!seenNotesKeysAtThisTime[key]) {
uniqueNotesAtThisTime.push(note);
seenNotesKeysAtThisTime[key] = true;
}
});
uniqueNotesAtThisTime.sort(function (a, b) {
var valA = a.originalColumnHint !== undefined ? a.originalColumnHint : a.columnIndex !== undefined ? a.columnIndex : a.widerSwipePairCenterX || 0;
var valB = b.originalColumnHint !== undefined ? b.originalColumnHint : b.columnIndex !== undefined ? b.columnIndex : b.widerSwipePairCenterX || 0;
return valA - valB;
});
for (var nIdx = 0; nIdx < uniqueNotesAtThisTime.length; nIdx++) {
var note = uniqueNotesAtThisTime[nIdx];
if (note.partOfWiderSwipe) {
notesForFinalProcessing.push(note);
continue;
}
var potentialPartner = null;
if (nIdx + 1 < uniqueNotesAtThisTime.length) {
potentialPartner = uniqueNotesAtThisTime[nIdx + 1];
}
if (note.type === 'swipe' && (note.swipeDir === 'left' || note.swipeDir === 'right') && potentialPartner && potentialPartner.type === 'swipe' && potentialPartner.time === note.time && potentialPartner.swipeDir === note.swipeDir && potentialPartner.columnIndex === note.columnIndex + 1) {
var pairCenterX = (columnCenterXs[note.columnIndex] + columnCenterXs[potentialPartner.columnIndex]) / 2;
notesForFinalProcessing.push({
time: note.time,
type: 'swipe',
swipeDir: note.swipeDir,
partOfWiderSwipe: 'leftHalf',
widerSwipePairCenterX: pairCenterX,
originalColumnHint: note.columnIndex
});
notesForFinalProcessing.push({
time: potentialPartner.time,
type: 'swipe',
swipeDir: potentialPartner.swipeDir,
partOfWiderSwipe: 'rightHalf',
widerSwipePairCenterX: pairCenterX,
originalColumnHint: potentialPartner.columnIndex
});
nIdx++;
} else {
notesForFinalProcessing.push(note);
}
}
finalMapNotes.push.apply(finalMapNotes, notesForFinalProcessing);
}
var uniqueNotesOverall = [];
var seenNotesOverall = {};
finalMapNotes.sort(function (a, b) {
return a.time - b.time;
});
finalMapNotes.forEach(function (note) {
var cX;
var keyPartForColumn;
if (note.partOfWiderSwipe) {
cX = note.widerSwipePairCenterX + (note.partOfWiderSwipe === 'leftHalf' ? -(SWIPE_NOTE_WIDTH / 2) : SWIPE_NOTE_WIDTH / 2);
keyPartForColumn = "pC" + note.widerSwipePairCenterX + "h" + (note.partOfWiderSwipe === 'leftHalf' ? 'L' : 'R');
} else if (note.columnIndex !== undefined) {
cX = columnCenterXs[note.columnIndex];
keyPartForColumn = "c" + note.columnIndex;
} else {
cX = gameScreenWidth / 2;
keyPartForColumn = "cX" + cX;
}
var key = "" + note.time + "_" + note.type + "_" + keyPartForColumn + "_" + (note.swipeDir || '');
if (!seenNotesOverall[key]) {
uniqueNotesOverall.push(note);
seenNotesOverall[key] = true;
} else {
// console.log("Filtered final duplicate note: " + key);
}
});
console.log("Processed map for: " + songKeyForLogging + " FINALLY contains " + uniqueNotesOverall.length + " notes.");
return uniqueNotesOverall;
}
var hpBarsInitialized = false;
var scoreTxt = new Text2('Score: 0', {
size: 100,
fill: 0xFFFFFF,
alpha: 1
});
scoreTxt.anchor.set(1, 0); // Anchor center-top
scoreTxt.x = gameScreenWidth / 1;
scoreTxt.y = 20; // Position from the top of its container (gameUIContainer)
gameUIContainer.addChild(scoreTxt);
console.log("Restored scoreTxt: X=" + scoreTxt.x + " Y=" + scoreTxt.y + " Visible:" + scoreTxt.visible + " Parent: gameUIContainer");
var comboTxt = new Text2('Combo: 0', {
size: 50,
// Możesz dostosować rozmiar tekstu combo
fill: 0xFFFF00,
// Żółty kolor
alpha: 0.5
});
comboTxt.anchor.set(0, 0.5);
comboTxt.x = 100;
comboTxt.y = 1000;
comboTxt.rotation = -0.26;
gameUIContainer.addChild(comboTxt);
console.log("ComboTxt positioned: X=" + comboTxt.x + " Y=" + comboTxt.y + " Visible:" + comboTxt.visible + " Parent: gameUIContainer");
var hitZoneY = 1800;
var hitZoneVisualWidth = playfieldWidth;
function rectsIntersect(r1, r2) {
return !(r2.x > r1.x + r1.width || r2.x + r2.width < r1.x || r2.y > r1.y + r1.height || r2.y + r2.height < r1.y);
}
function resetGameState() {
notes.forEach(function (n) {
if (n && n.parent) {
n.destroy();
}
});
notes = [];
nextNoteIdx = 0;
score = 0;
combo = 0;
maxCombo = 0;
swipeStart = null;
inputLocked = false;
scoreTxt.setText('Score: 0');
comboTxt.setText('Combo: 0');
gameOverFlag = false;
playerCurrentHP = playerMaxHP;
bossCurrentHP = bossMaxHP;
hpBarsInitialized = false;
if (isShieldActive) {
isShieldActive = false;
}
if (shieldTimerDisplayContainer) {
shieldTimerDisplayContainer.visible = false;
}
if (isPrecisionBuffActive) {
isPrecisionBuffActive = false;
if (originalHitWindowPerfect > 0) {
hitWindowPerfect = originalHitWindowPerfect;
}
if (originalHitWindowGood > 0) {
hitWindowGood = originalHitWindowGood;
}
// Reset rozmiaru ramki, jeśli była powiększona
}
if (precisionBuffTimerDisplayContainer) {
precisionBuffTimerDisplayContainer.visible = false;
}
if (hpBarsInitialized && playerHpBarFill && bossHpBarFill) {
updatePlayerHpDisplay();
updateBossHpDisplay();
}
}
function loadSong(songKey) {
if (songSummaryContainer && songSummaryContainer.parent) {
songSummaryContainer.destroy();
songSummaryContainer = null;
}
if (gameUIContainer) {
gameUIContainer.visible = true;
}
setupGameplayElements();
lastPlayedSongKeyForRestart = songKey;
bossWasDefeatedThisSong = false;
var songData;
if (isTutorialMode && songKey === "TutorialTrack") {
songData = tutorialSongData;
} else {
songData = allSongData[songKey];
}
if (!songData) {
console.log("Error: Song data not found for key: " + songKey);
if (allSongData["defaultTestTrack"]) {
songData = allSongData["defaultTestTrack"];
console.log("Fallback to defaultTestTrack");
} else {
currentActiveRhythmMap = [];
console.log("No fallback song data found.");
return;
}
}
currentFightingBossId = null;
if (!isTutorialMode) {
for (var i = 0; i < allBossData.length; i++) {
if (allBossData[i].songMapKey === songKey) {
currentFightingBossId = allBossData[i].id;
break;
}
}
}
if (songData.config) {
playerMaxHP = songData.config.playerMaxHP || 10;
bossMaxHP = songData.config.bossMaxHP || 50;
} else {
playerMaxHP = 10;
bossMaxHP = 50;
}
if (currentMusic && typeof currentMusic.stop === 'function') {
currentMusic.stop();
}
currentMusic = null;
resetGameState();
// === ZMIENIONY KOD DLA TŁA GRY, UŻYWAJĄCY 'gameplayBg' ===
if (gameplayBackground && gameplayBackground.parent) {
gameplayBackground.destroy();
gameplayBackground = null;
}
gameplayBackground = LK.getAsset('gameplayBg', {
// Używamy NOWEGO assetu 'gameplayBg'
x: 0,
y: 0,
width: gameScreenWidth,
height: gameScreenHeight,
alpha: 0.8 // Możesz dostosować przezroczystość
});
game.addChildAt(gameplayBackground, 0);
// ===========================================
if (staticHitFrame) {
staticHitFrame.visible = true;
}
if (staticPerfectLine) {
staticPerfectLine.visible = true;
}
if (gameUIContainer) {
gameUIContainer.visible = true;
}
if (isTutorialMode) {
if (scoreTxt) {
scoreTxt.visible = false;
}
if (comboTxt) {
comboTxt.visible = false;
}
} else {
if (scoreTxt) {
scoreTxt.visible = true;
}
if (comboTxt) {
comboTxt.visible = true;
}
}
hpBarsInitialized = false;
nextNoteIdx = 0;
if (currentBossSprite && currentBossSprite.parent) {
currentBossSprite.destroy();
currentBossSprite = null;
}
if (!isTutorialMode && songData.bossAssetKey) {
currentBossSprite = LK.getAsset(songData.bossAssetKey, {
anchorX: 0.5,
anchorY: 0.5
});
currentBossSprite.x = gameScreenWidth / 2;
currentBossSprite.y = 350;
currentBossSprite.alpha = 0.8;
game.addChildAt(currentBossSprite, 0);
} else if (isTutorialMode) {
if (currentBossSprite && currentBossSprite.parent) {
currentBossSprite.destroy();
currentBossSprite = null;
}
}
if (songData.rawRhythmMap) {
currentActiveRhythmMap = processRawRhythmMap(songData.rawRhythmMap, songKey);
} else {
currentActiveRhythmMap = [];
}
gameStartTime = Date.now();
if (songData.musicAsset) {
currentMusic = LK.getSound(songData.musicAsset);
if (currentMusic && typeof currentMusic.play === 'function') {
currentMusic.play();
}
}
currentScreenState = 'gameplay';
}
function setupHpBars() {
if (bossHpBarContainer) {
bossHpBarContainer.destroy();
}
bossHpBarContainer = new Container();
bossHpBarContainer.x = gameScreenWidth / 2;
bossHpBarContainer.y = 100; // Adjusted Y slightly lower than scoreTxt for clarity
gameUIContainer.addChild(bossHpBarContainer); // Add to gameUIContainer
var bossBg = LK.getAsset('hpBarBackground', {
width: hpBarWidth,
height: hpBarHeight,
anchorX: 0.5,
anchorY: 0.5
});
bossHpBarContainer.addChild(bossBg);
bossHpBarFill = LK.getAsset('bossHpFill', {
width: hpBarWidth,
height: hpBarHeight,
anchorX: 0,
anchorY: 0.5,
x: -hpBarWidth / 2
});
bossHpBarContainer.addChild(bossHpBarFill);
if (playerHpBarContainer) {
playerHpBarContainer.destroy();
}
playerHpBarContainer = new Container();
playerHpBarContainer.x = gameScreenWidth / 2;
playerHpBarContainer.y = gameScreenHeight - 80;
gameUIContainer.addChild(playerHpBarContainer); // Add to gameUIContainer
var playerBg = LK.getAsset('hpBarBackground', {
width: hpBarWidth,
height: hpBarHeight,
anchorX: 0.5,
anchorY: 0.5
});
playerHpBarContainer.addChild(playerBg);
playerHpBarFill = LK.getAsset('playerHpFill', {
width: hpBarWidth,
height: hpBarHeight,
anchorX: 0,
anchorY: 0.5,
x: -hpBarWidth / 2
});
playerHpBarContainer.addChild(playerHpBarFill);
updateBossHpDisplay();
updatePlayerHpDisplay();
console.log("HP Bars setup and added to gameUIContainer. PlayerHP Y: " + playerHpBarContainer.y + " BossHP Y: " + bossHpBarContainer.y);
}
function setupPowerUpDisplay() {
var smallIconSize = 60;
if (shieldTimerDisplayContainer && shieldTimerDisplayContainer.parent) {
shieldTimerDisplayContainer.destroy();
}
shieldTimerDisplayContainer = new Container();
shieldTimerDisplayContainer.x = gameScreenWidth - 120;
shieldTimerDisplayContainer.y = 150;
if (gameUIContainer) {
gameUIContainer.addChild(shieldTimerDisplayContainer);
}
smallShieldIconDisplay = LK.getAsset('shieldAsset', {
anchorX: 0.5,
anchorY: 0.5,
width: smallIconSize,
height: smallIconSize
});
shieldTimerDisplayContainer.addChild(smallShieldIconDisplay);
shieldTimerTextDisplay = new Text2("", {
size: 35,
fill: 0xFFFFFF,
anchorX: 0.5,
anchorY: 0
});
shieldTimerTextDisplay.y = smallIconSize / 2 + 5;
shieldTimerDisplayContainer.addChild(shieldTimerTextDisplay);
shieldTimerDisplayContainer.visible = false;
// Usunięto konfigurację dla swipeToTapTimerDisplayContainer
// Dodano konfigurację dla precisionBuffTimerDisplayContainer
if (precisionBuffTimerDisplayContainer && precisionBuffTimerDisplayContainer.parent) {
precisionBuffTimerDisplayContainer.destroy();
}
precisionBuffTimerDisplayContainer = new Container();
precisionBuffTimerDisplayContainer.x = gameScreenWidth - 120;
// Umieść poniżej timera tarczy lub w innym odpowiednim miejscu
precisionBuffTimerDisplayContainer.y = shieldTimerDisplayContainer.y + smallIconSize + 40 + 10;
if (gameUIContainer) {
gameUIContainer.addChild(precisionBuffTimerDisplayContainer);
}
// Użyj dedykowanego assetu dla ikony "Większej Precyzji", jeśli masz.
// Na razie używamy 'shieldAsset' jako placeholdera.
smallPrecisionIconDisplay = LK.getAsset('shieldAsset', {
anchorX: 0.5,
anchorY: 0.5,
width: smallIconSize,
height: smallIconSize
});
precisionBuffTimerDisplayContainer.addChild(smallPrecisionIconDisplay);
precisionBuffTimerTextDisplay = new Text2("", {
size: 35,
fill: 0xFFFFFF,
anchorX: 0.5,
anchorY: 0
});
precisionBuffTimerTextDisplay.y = smallIconSize / 2 + 5;
precisionBuffTimerDisplayContainer.addChild(precisionBuffTimerTextDisplay);
precisionBuffTimerDisplayContainer.visible = false;
console.log("Timer UIs for Shield & Precision Buff created.");
}
function updatePowerUpDisplayCounts() {
if (hpPotionCountText) {
// Sprawdzamy, czy UI zostało już zainicjalizowane
hpPotionCountText.setText("x" + collectedPowerUps.potion);
shieldCountText.setText("x" + collectedPowerUps.shield);
swipeToTapCountText.setText("x" + collectedPowerUps.swipeToTap);
}
}
function updatePlayerHpDisplay() {
if (playerHpBarFill) {
var healthPercent = playerCurrentHP / playerMaxHP;
playerHpBarFill.width = hpBarWidth * Math.max(0, healthPercent);
}
}
function updateBossHpDisplay() {
if (bossHpBarFill) {
var healthPercent = bossCurrentHP / bossMaxHP;
bossHpBarFill.width = hpBarWidth * Math.max(0, healthPercent);
}
}
function spawnNotes() {
if (!currentActiveRhythmMap || currentActiveRhythmMap.length === 0) {
return;
}
var now = Date.now();
if (!currentActiveRhythmMap) {
return;
}
while (nextNoteIdx < currentActiveRhythmMap.length) {
var noteData = currentActiveRhythmMap[nextNoteIdx];
var noteTargetHitTime = gameStartTime + noteData.time;
if (noteTargetHitTime - noteTravelTime <= now) {
var targetCenterX;
if (noteData.partOfWiderSwipe && noteData.widerSwipePairCenterX !== undefined) {
if (noteData.partOfWiderSwipe === 'leftHalf') {
targetCenterX = noteData.widerSwipePairCenterX - SWIPE_NOTE_WIDTH / 2;
} else if (noteData.partOfWiderSwipe === 'rightHalf') {
targetCenterX = noteData.widerSwipePairCenterX + SWIPE_NOTE_WIDTH / 2;
} else {
targetCenterX = columnCenterXs[noteData.originalColumnHint !== undefined ? noteData.originalColumnHint : Math.floor(NUM_COLUMNS / 2)];
}
} else if (noteData.columnIndex !== undefined && noteData.columnIndex >= 0 && noteData.columnIndex < NUM_COLUMNS) {
targetCenterX = columnCenterXs[noteData.columnIndex];
} else {
targetCenterX = playfieldStartX + playfieldWidth / 2;
console.warn("spawnNotes - Note spawned without proper columnIndex or widerSwipe info:", noteData);
}
var finalNoteType = noteData.type;
var finalSwipeDir = noteData.swipeDir;
var noteWillBeBuff = false;
var awardedBuffType = null;
if (finalNoteType === 'tap' && !isTutorialMode && !gameOverFlag) {
if (Math.random() < BUFF_CHANCE) {
noteWillBeBuff = true;
var buffTypesAvailable = ['potion', 'shield', 'precision'];
awardedBuffType = buffTypesAvailable[Math.floor(Math.random() * buffTypesAvailable.length)];
}
}
var n = new Note(finalNoteType, finalSwipeDir, noteTargetHitTime, targetCenterX, noteData.columnIndex, noteWillBeBuff, awardedBuffType, noteData.duration);
n.mapData = noteData;
if (noteData.partOfWiderSwipe) {
n.isWiderSwipePart = true;
}
notes.push(n);
game.addChild(n);
nextNoteIdx++;
} else {
break;
}
}
}
function removeOldNotes() {
var now = Date.now();
for (var i = notes.length - 1; i >= 0; i--) {
var n = notes[i];
var timeToRemoveAfterJudged = 700; // ms po targetHitTime dla ocenionych notatek
var timeToRemoveIfNotJudged = noteTravelTime / 2 + hitWindowGood + 500; // Dłuższy czas, jeśli nieoceniona, liczony od targetHitTime
if (n.judged && now > n.targetHitTime + timeToRemoveAfterJudged) {
if (n.parent) {
n.destroy();
}
notes.splice(i, 1);
} else if (!n.judged && now > n.targetHitTime + timeToRemoveIfNotJudged) {
if (n.noteType !== 'trap') {}
if (n.parent) {
n.destroy();
}
notes.splice(i, 1);
}
}
}
function findNoteAt(x, y, typeToFind) {
var now = Date.now();
var bestNote = null;
var smallestTimeDiff = hitWindowGood + 1;
for (var i = 0; i < notes.length; i++) {
var n = notes[i];
if (n.judged || n.noteType !== typeToFind && !(typeToFind === 'tap' && n.isHoldNote && !n.isBeingHeld)) {
continue;
}
var timeDiff = Math.abs(now - n.targetHitTime);
if (timeDiff > hitWindowGood) {
continue;
}
var currentNoteAsset = n.noteAsset;
if (!currentNoteAsset) {
continue;
}
var currentNoteWidth = currentNoteAsset.width * n.scale.x;
var currentNoteHeight = currentNoteAsset.height * n.scale.y;
if (n.noteType === 'swipe') {
currentNoteWidth = SWIPE_NOTE_WIDTH * n.scale.x;
currentNoteHeight = SWIPE_NOTE_WIDTH * n.scale.y;
}
var dx = x - n.x;
var dy = y - n.y;
if (Math.abs(dx) <= currentNoteWidth / 2 && Math.abs(dy) <= currentNoteHeight / 2) {
if (timeDiff < smallestTimeDiff) {
bestNote = n;
smallestTimeDiff = timeDiff;
}
}
}
return bestNote;
}
function addScore(result) {
if (isTutorialMode) {
return;
}
if (result === 'perfect') {
score += 100;
} else if (result === 'good') {
score += 50;
}
scoreTxt.setText('Score: ' + score);
}
function addCombo() {
if (isTutorialMode) {
return;
}
combo += 1;
if (combo > maxCombo) {
maxCombo = combo;
}
comboTxt.setText('Combo: ' + combo);
if (combo > 1) {
var originalScale = comboTxt.scale.x;
tween(comboTxt.scale, {
x: originalScale * 1.3,
y: originalScale * 1.3
}, {
duration: 100,
easing: tween.easeOut,
onFinish: function onFinish() {
tween(comboTxt.scale, {
x: originalScale,
y: originalScale
}, {
duration: 100,
easing: tween.easeIn
});
}
});
}
}
function resetCombo() {
combo = 0;
comboTxt.setText('Combo: 0');
}
function checkGameEnd() {
if (isTutorialMode || gameOverFlag) {
return;
}
var summaryData = {
score: score,
maxCombo: maxCombo,
bossWasActuallyDefeated: bossWasDefeatedThisSong,
statusMessage: ""
};
if (playerCurrentHP <= 0) {
gameOverFlag = true;
console.log("GAME OVER - Player HP depleted");
if (currentMusic && typeof currentMusic.stop === 'function') {
currentMusic.stop();
}
summaryData.statusMessage = "GAME OVER";
summaryData.bossWasActuallyDefeated = false;
displayEndOfSongScreen(summaryData);
return;
}
if (bossCurrentHP <= 0 && !bossWasDefeatedThisSong) {
bossWasDefeatedThisSong = true;
console.log("Boss HP depleted during song! Player continues playing.");
if (currentFightingBossId && bossUnlockProgress.hasOwnProperty(currentFightingBossId)) {
bossUnlockProgress[currentFightingBossId] = true;
console.log("Boss " + currentFightingBossId + " marked as defeated in progress.");
storage[BOSS_UNLOCK_KEY] = bossUnlockProgress;
console.log("Boss unlock progress saved to storage.");
}
}
if (currentActiveRhythmMap && nextNoteIdx >= currentActiveRhythmMap.length && notes.length === 0) {
gameOverFlag = true;
console.log("SONG ENDED");
if (currentMusic && typeof currentMusic.stop === 'function') {
currentMusic.stop();
}
if (bossWasDefeatedThisSong) {
summaryData.statusMessage = "VICTORY!";
} else {
summaryData.statusMessage = "SONG COMPLETED";
}
summaryData.bossWasActuallyDefeated = bossWasDefeatedThisSong;
displayEndOfSongScreen(summaryData);
return;
}
}
function getSongStats(songMapKey) {
console.log("getSongStats called for songMapKey:", songMapKey);
if (!songMapKey) {
console.warn("getSongStats: No songMapKey provided, returning default stats.");
return {
bestScore: 0,
bestCombo: 0
};
}
var individualSongStorageKey = 'wf_stats_' + songMapKey;
console.log("getSongStats: Attempting to read from storage key:", individualSongStorageKey);
var songStats = storage[individualSongStorageKey];
// ZMIENIONA LINIA DEBUGOWANIA:
console.log("getSongStats: Raw data from storage for " + individualSongStorageKey + ":", songStats);
// Po prostu logujemy surowy obiekt songStats, bez JSON.parse(JSON.stringify(...))
if (songStats) {
var statsToReturn = {
bestScore: parseInt(songStats.bestScore, 10) || 0,
bestCombo: parseInt(songStats.bestCombo, 10) || 0
};
console.log("getSongStats: Parsed and returning stats:", statsToReturn);
return statsToReturn;
}
console.log("getSongStats: No stats found in storage for " + individualSongStorageKey + ", returning default stats.");
return {
bestScore: 0,
bestCombo: 0
};
}
function saveSongStats(songMapKey, currentScore, currentCombo) {
if (!songMapKey) {
return;
}
var individualSongStorageKey = 'wf_stats_' + songMapKey; // Unikalny klucz dla piosenki
// Odczytaj istniejące statystyki dla tej konkretnej piosenki lub utwórz nowy obiekt
var storedData = storage[individualSongStorageKey];
var songStats;
if (storedData) {
songStats = {
bestScore: storedData.bestScore,
bestCombo: storedData.bestCombo
};
} else {
songStats = {
bestScore: 0,
bestCombo: 0
};
}
var updated = false;
var numericCurrentScore = parseInt(currentScore, 10) || 0;
var numericCurrentCombo = parseInt(currentCombo, 10) || 0;
if (numericCurrentScore > (parseInt(songStats.bestScore, 10) || 0)) {
songStats.bestScore = numericCurrentScore;
updated = true;
console.log("New best score for " + songMapKey + " (" + individualSongStorageKey + "): " + numericCurrentScore);
}
if (numericCurrentCombo > (parseInt(songStats.bestCombo, 10) || 0)) {
songStats.bestCombo = numericCurrentCombo;
updated = true;
console.log("New best combo for " + songMapKey + " (" + individualSongStorageKey + "): " + numericCurrentCombo);
}
if (updated) {
storage[individualSongStorageKey] = songStats; // Zapisz obiekt statystyk dla tej piosenki
console.log("Song stats saved to storage for key: " + individualSongStorageKey);
}
}
function displayEndOfSongScreen(summaryData) {
if (songSummaryContainer && songSummaryContainer.parent) {
songSummaryContainer.destroy();
}
songSummaryContainer = new Container();
songSummaryContainer.x = 0;
songSummaryContainer.y = 0;
game.addChild(songSummaryContainer);
currentScreenState = 'songSummary';
if (lastPlayedSongKeyForRestart) {
saveSongStats(lastPlayedSongKeyForRestart, summaryData.score, summaryData.maxCombo);
}
var bestStats = getSongStats(lastPlayedSongKeyForRestart || summaryData.songMapKey);
var overlay = LK.getAsset('summaryOverlayAsset', {
width: gameScreenWidth,
height: gameScreenHeight,
alpha: 0.7,
interactive: true
});
songSummaryContainer.addChild(overlay);
var popupWidth = gameScreenWidth * 0.6;
var popupHeight = 720;
var popupX = (gameScreenWidth - popupWidth) / 2;
var popupY = (gameScreenHeight - popupHeight) / 2;
var popupBackground = LK.getAsset('summaryPopupBackgroundAsset', {
x: popupX,
y: popupY,
width: popupWidth,
height: popupHeight
});
songSummaryContainer.addChild(popupBackground);
var currentY = popupY;
currentY += 40;
var titleTextContent = summaryData.statusMessage || "SONG ENDED";
var titleText = new Text2(titleTextContent, {
size: 70,
fill: 0xFFFFFF,
align: 'center',
wordWrap: true,
wordWrapWidth: popupWidth * 0.9
});
titleText.anchor.set(0.5, 0);
titleText.x = popupX + popupWidth / 2;
titleText.y = currentY;
songSummaryContainer.addChild(titleText);
currentY += titleText.height + 35;
var bossDefeatedStatusText = new Text2("Boss Defeated: ", {
size: 60,
fill: 0xFFFFFF
});
bossDefeatedStatusText.anchor.set(0, 0.5);
var bossDefeatedValueText = new Text2(summaryData.bossWasActuallyDefeated ? "YES" : "NO", {
size: 60,
fill: summaryData.bossWasActuallyDefeated ? 0x00FF00 : 0xFF0000
});
bossDefeatedValueText.anchor.set(0, 0.5);
var tempBossContainer = new Container();
tempBossContainer.addChild(bossDefeatedStatusText);
bossDefeatedValueText.x = bossDefeatedStatusText.width + 10;
tempBossContainer.addChild(bossDefeatedValueText);
var combinedBossTextWidth = tempBossContainer.width;
bossDefeatedStatusText.x = popupX + (popupWidth - combinedBossTextWidth) / 2;
bossDefeatedStatusText.y = currentY;
bossDefeatedValueText.x = bossDefeatedStatusText.x + bossDefeatedStatusText.width + 10;
bossDefeatedValueText.y = currentY;
songSummaryContainer.addChild(bossDefeatedStatusText);
songSummaryContainer.addChild(bossDefeatedValueText);
currentY += bossDefeatedStatusText.height + 30;
var scoreTextSummary = new Text2("Score: " + summaryData.score, {
// Zmieniono nazwę zmiennej, aby uniknąć konfliktu
size: 50,
fill: 0xFFFFFF,
align: 'center'
});
scoreTextSummary.anchor.set(0.5, 0.5);
scoreTextSummary.x = popupX + popupWidth / 2;
scoreTextSummary.y = currentY;
songSummaryContainer.addChild(scoreTextSummary);
currentY += scoreTextSummary.height + 25;
var comboTextSummary = new Text2("Max Combo: " + summaryData.maxCombo, {
// Zmieniono nazwę zmiennej
size: 50,
fill: 0xFFFFFF,
align: 'center'
});
comboTextSummary.anchor.set(0.5, 0.5);
comboTextSummary.x = popupX + popupWidth / 2;
comboTextSummary.y = currentY;
songSummaryContainer.addChild(comboTextSummary);
currentY += comboTextSummary.height + 35;
var bestScoreText = new Text2("Best Score: " + bestStats.bestScore, {
size: 50,
fill: 0xFFFF00,
align: 'center'
});
bestScoreText.anchor.set(0.5, 0.5);
bestScoreText.x = popupX + popupWidth / 2;
bestScoreText.y = currentY;
songSummaryContainer.addChild(bestScoreText);
currentY += bestScoreText.height + 25;
var bestComboText = new Text2("Best Combo: " + bestStats.bestCombo, {
size: 50,
fill: 0xFFFF00,
align: 'center'
});
bestComboText.anchor.set(0.5, 0.5);
bestComboText.x = popupX + popupWidth / 2;
bestComboText.y = currentY;
songSummaryContainer.addChild(bestComboText);
var buttonWidth = popupWidth * 0.4;
var buttonHeight = 70;
var buttonBottomMargin = 35;
var buttonY = popupY + popupHeight - buttonHeight - buttonBottomMargin;
var backButtonBg = LK.getAsset('summaryButtonBackgroundAsset', {
x: popupX + (popupWidth / 2 - buttonWidth - 15),
y: buttonY,
width: buttonWidth,
height: buttonHeight,
interactive: true,
cursor: "pointer"
});
songSummaryContainer.addChild(backButtonBg);
var backToMenuButton = new Text2("Back to Menu", {
size: 40,
fill: 0xFFD700,
stroke: 0x000000,
strokeThickness: 2
});
backToMenuButton.anchor.set(0.5, 0.5);
backToMenuButton.x = backButtonBg.x + buttonWidth / 2;
backToMenuButton.y = backButtonBg.y + buttonHeight / 2;
songSummaryContainer.addChild(backToMenuButton);
backButtonBg.down = function () {
if (songSummaryContainer && songSummaryContainer.parent) {
songSummaryContainer.destroy();
songSummaryContainer = null;
}
showBossSelectionScreen();
};
var restartButtonBg = LK.getAsset('summaryButtonBackgroundAsset', {
x: popupX + (popupWidth / 2 + 15),
y: buttonY,
width: buttonWidth,
height: buttonHeight,
interactive: true,
cursor: "pointer"
});
songSummaryContainer.addChild(restartButtonBg);
var restartButton = new Text2("Restart Battle", {
size: 40,
fill: 0xFFD700,
stroke: 0x000000,
strokeThickness: 2
});
restartButton.anchor.set(0.5, 0.5);
restartButton.x = restartButtonBg.x + buttonWidth / 2;
restartButton.y = restartButtonBg.y + buttonHeight / 2;
songSummaryContainer.addChild(restartButton);
restartButtonBg.down = function () {
if (songSummaryContainer && songSummaryContainer.parent) {
songSummaryContainer.destroy();
songSummaryContainer = null;
}
if (lastPlayedSongKeyForRestart) {
loadSong(lastPlayedSongKeyForRestart);
} else {
showMainMenu();
}
};
if (gameUIContainer) {
gameUIContainer.visible = false;
}
if (staticHitFrame) {
staticHitFrame.visible = false;
}
if (staticPerfectLine) {
staticPerfectLine.visible = false;
} // Ukryj nową linię
}
game.onNoteMiss = function (note) {
if (!note) {
return;
}
note.showHitFeedback('miss');
if (!isTutorialMode) {
if (!isShieldActive) {
resetCombo();
} else {
console.log("Gracz ominął nutę, ale tarcza jest aktywna! Combo NIE zresetowane.");
}
if (isShieldActive) {
console.log("Gracz ominął nutę, ale tarcza jest aktywna! Brak utraty HP.");
} else if (!gameOverFlag) {
playerCurrentHP = Math.max(0, playerCurrentHP - 1);
updatePlayerHpDisplay();
console.log("Player HP after miss: " + playerCurrentHP);
}
}
if (note.parent) {
LK.effects.flashObject(note, 0xff0000, 300);
}
};
game.down = function (x, y, obj) {
if (currentScreenState === 'gameplay') {
if (inputLocked) {
return;
}
swipeStart = {
x: x,
y: y,
time: Date.now()
};
var now = Date.now();
// Najpierw obsługa PowerUpów (jeśli istnieje) - zachowujemy z ostatniej wersji
for (var i_gp_pu = activePowerUpItems.length - 1; i_gp_pu >= 0; i_gp_pu--) {
var pItem_gp = activePowerUpItems[i_gp_pu];
if (pItem_gp && !pItem_gp.collected && pItem_gp.visualAsset && pItem_gp.parent) {
var pWidth_gp = pItem_gp.visualAsset.width * pItem_gp.scale.x; // scale.x będzie 1
var pHeight_gp = pItem_gp.visualAsset.height * pItem_gp.scale.y; // scale.y będzie 1
if (x >= pItem_gp.x - pWidth_gp / 2 && x <= pItem_gp.x + pWidth_gp / 2 && y >= pItem_gp.y - pHeight_gp / 2 && y <= pItem_gp.y + pHeight_gp / 2) {
if (Math.abs(pItem_gp.y - hitZoneY) < pHeight_gp * 1.5) {
// Tolerancja kliknięcia
pItem_gp.collect();
return; // PowerUp kliknięty, nie przetwarzaj dalej jako nuta
}
}
}
}
var noteUnderCursorTrap = findNoteAt(x, y, 'trap'); //
if (noteUnderCursorTrap && !noteUnderCursorTrap.judged && noteUnderCursorTrap.isInHitWindow()) {
//
noteUnderCursorTrap.judged = true; //
noteUnderCursorTrap.showHitFeedback('miss'); //
if (!isTutorialMode) {
// Dodane z nowszej logiki
if (isShieldActive) {
//
console.log("Gracz trafił w TRAP NOTE, ale tarcza jest aktywna! Brak utraty HP i combo NIE zresetowane."); //
} else {
//
resetCombo(); //
LK.effects.flashScreen(0xff0000, 400); //
if (!gameOverFlag) {
//
playerCurrentHP = Math.max(0, playerCurrentHP - 1); //
updatePlayerHpDisplay(); //
}
}
}
noteUnderCursorTrap.alpha = 0; // Trap znika od razu
inputLocked = true;
LK.setTimeout(function () {
inputLocked = false;
}, 200); //
return;
}
var noteUnderCursor = findNoteAt(x, y, 'tap'); //
if (noteUnderCursor && !noteUnderCursor.judged && !noteUnderCursor.isBeingHeld && noteUnderCursor.isInHitWindow()) {
//
var result = noteUnderCursor.getHitAccuracy();
noteUnderCursor.hit = true;
noteUnderCursor.judged = true; // Ustawiamy judged tutaj dla wszystkich typów (tap, buff, główka hold)
noteUnderCursor.showHitFeedback(result);
if (noteUnderCursor.isHoldNote) {
if (result !== 'miss') {
noteUnderCursor.isBeingHeld = true;
noteUnderCursor.holdPressTime = now;
// Reszta logiki dla hold (score, combo, bossHP) jest w porządku
if (!isTutorialMode) {
addScore(result);
addCombo();
if (!gameOverFlag) {
if (result === 'perfect') bossCurrentHP = Math.max(0, bossCurrentHP - 2);else if (result === 'good') bossCurrentHP = Math.max(0, bossCurrentHP - 1);
updateBossHpDisplay();
}
}
if (noteUnderCursor.mapData && noteUnderCursor.mapData.columnIndex !== undefined) {
currentlyHeldNotes[noteUnderCursor.mapData.columnIndex] = noteUnderCursor;
} else if (noteUnderCursor.originalColumnHint !== undefined) {
currentlyHeldNotes[noteUnderCursor.originalColumnHint] = noteUnderCursor;
}
} else {
// Miss na główce holda
if (!isTutorialMode && !isShieldActive) resetCombo();
noteUnderCursor.alpha = 0; // Główka holda znika jeśli miss
}
} else if (noteUnderCursor.isBuffNote) {
if (result !== 'miss' && !isTutorialMode) {
// Logika aktywacji buffów ... (zachowana)
var buffType = noteUnderCursor.buffType;
if (buffType === 'potion') {
playerCurrentHP = Math.min(playerMaxHP, playerCurrentHP + POTION_HEAL_AMOUNT);
updatePlayerHpDisplay();
} else if (buffType === 'shield') {
if (!isShieldActive) {
isShieldActive = true;
shieldEndTime = Date.now() + SHIELD_DURATION;
if (shieldTimerDisplayContainer) shieldTimerDisplayContainer.visible = true;
}
} else if (buffType === 'precision') {
if (!isPrecisionBuffActive) {
isPrecisionBuffActive = true;
precisionBuffEndTime = Date.now() + PRECISION_BUFF_DURATION;
originalHitWindowPerfect = hitWindowPerfect;
originalHitWindowGood = hitWindowGood;
hitWindowPerfect = Math.round(hitWindowPerfect * precisionBuffHitWindowMultiplier);
hitWindowGood = Math.round(hitWindowGood * precisionBuffHitWindowMultiplier);
if (precisionBuffTimerDisplayContainer) precisionBuffTimerDisplayContainer.visible = true;
if (staticHitFrame) tween(staticHitFrame, {
height: STATIC_HIT_FRAME_HEIGHT * 2
}, {
duration: 250,
easing: tween.easeOutQuad
});
}
}
} else if (result === 'miss' && !isTutorialMode && !isShieldActive) {
resetCombo();
}
// Nie ustawiamy alpha = 0, pozwalamy jej kontynuować ruch (jak w starym kodzie)
} else {
// Zwykły Tap Note
if (result !== 'miss') {
addScore(result);
addCombo(); //
if (!isTutorialMode && !gameOverFlag) {
//
if (result === 'perfect') bossCurrentHP = Math.max(0, bossCurrentHP - 2); //
else if (result === 'good') bossCurrentHP = Math.max(0, bossCurrentHP - 1); //
updateBossHpDisplay(); //
}
} else if (!isTutorialMode) {
// Miss na tapie
if (!isShieldActive) resetCombo(); //
else console.log("Tapnięcie nuty ocenione jako 'miss', ale tarcza jest aktywna! Combo NIE zresetowane.");
}
// Nie ustawiamy alpha = 0, pozwalamy jej kontynuować ruch
}
inputLocked = true;
LK.setTimeout(function () {
inputLocked = false;
}, 120);
return;
}
}
};
game.move = function (x, y, obj) {};
game.up = function (x, y, obj) {
if (currentScreenState === 'gameplay') {
// Logika puszczania Hold Note
var releasedHoldNoteInColumn = null; // Ta zmienna nie była używana
for (var colIdx in currentlyHeldNotes) {
if (currentlyHeldNotes.hasOwnProperty(colIdx)) {
var heldNote = currentlyHeldNotes[colIdx];
// Sprawdź, czy puszczono palec nad kolumną, w której trzymana jest nuta
// Ta logika może wymagać dostosowania, jeśli x,y puszczenia ma być precyzyjnie nad nutą
// Prostsze sprawdzenie: jeśli jakakolwiek nuta jest trzymana, oceń ją.
if (heldNote && heldNote.isBeingHeld) {
// Można by tu dodać logikę sprawdzania, czy palec został puszczony "z dala" od nuty,
// co mogłoby oznaczać 'holdBroken' jeszcze przed wywołaniem judgeHoldRelease.
// Na razie zakładamy, że puszczenie gdziekolwiek kończy trzymanie.
console.log("Releasing hold note in column: " + (heldNote.mapData ? heldNote.mapData.columnIndex : 'unknown'));
heldNote.judgeHoldRelease(); // judgeHoldRelease ustawi .judged i .alpha
delete currentlyHeldNotes[colIdx];
swipeStart = null;
inputLocked = true;
LK.setTimeout(function () {
inputLocked = false;
}, 80);
return;
}
}
}
// Standardowa logika Swipe (jeśli nie było puszczenia holda)
if (inputLocked || !swipeStart) {
swipeStart = null;
return;
}
var swipeEndX = x;
var swipeEndY = y;
var swipeEndTime = Date.now();
var dx = swipeEndX - swipeStart.x;
var dy = swipeEndY - swipeStart.y;
var dist = Math.sqrt(dx * dx + dy * dy);
var potentialSwipe = dist >= MIN_SWIPE_DISTANCE;
if (potentialSwipe) {
var detectedDir = null;
if (Math.abs(dx) > Math.abs(dy)) {
detectedDir = dx > 0 ? 'right' : 'left';
} else {
detectedDir = dy > 0 ? 'down' : 'up';
}
var swipeBoundingBox = {
// Bounding box samego gestu swipe
x: Math.min(swipeStart.x, swipeEndX),
y: Math.min(swipeStart.y, swipeEndY),
width: Math.abs(dx),
height: Math.abs(dy)
};
var notesHitThisSwipe = [];
for (var i_swipe = 0; i_swipe < notes.length; i_swipe++) {
var n_swipe = notes[i_swipe];
if (n_swipe.judged || n_swipe.noteType !== 'swipe' || n_swipe.alpha === 0) {
// Ignoruj już ocenione lub niewidoczne
continue;
}
// Czy czas swipe'a pokrywa się z oknem nuty?
var overallSwipeTimeMatchesNote = false;
if (n_swipe.targetHitTime >= swipeStart.time - hitWindowGood && n_swipe.targetHitTime <= swipeEndTime + hitWindowGood) {
overallSwipeTimeMatchesNote = true;
}
if (!overallSwipeTimeMatchesNote) {
// Dodatkowe sprawdzenie, jeśli nuta była w trakcie swipe'a
if (swipeStart.time >= n_swipe.targetHitTime - hitWindowGood && swipeStart.time <= n_swipe.targetHitTime + hitWindowGood || swipeEndTime >= n_swipe.targetHitTime - hitWindowGood && swipeEndTime <= n_swipe.targetHitTime + hitWindowGood) {
overallSwipeTimeMatchesNote = true;
}
}
if (!overallSwipeTimeMatchesNote) {
continue;
}
// Sprawdzenie kolizji bounding boxów
var noteCurrentWidth_swipe = n_swipe.noteAsset ? n_swipe.noteAsset.width * n_swipe.scale.x : SWIPE_NOTE_WIDTH; // Użyj rzeczywistej szerokości assetu
var noteCurrentHeight_swipe = n_swipe.noteAsset ? n_swipe.noteAsset.height * n_swipe.scale.y : SWIPE_NOTE_WIDTH; // Użyj rzeczywistej wysokości assetu
var noteBoundingBox_swipe = {
x: n_swipe.x - noteCurrentWidth_swipe / 2,
y: n_swipe.y - noteCurrentHeight_swipe / 2,
width: noteCurrentWidth_swipe,
height: noteCurrentHeight_swipe
};
if (rectsIntersect(swipeBoundingBox, noteBoundingBox_swipe)) {
// rectsIntersect musi być zdefiniowane
if (detectedDir === n_swipe.swipeDir) {
// Dodatkowe sprawdzenie, czy swipe był wystarczająco blisko pionowej pozycji nuty
// (można uprościć, jeśli rectsIntersect jest wystarczająco precyzyjne)
var verticalProximity = Math.abs(n_swipe.y - swipeStart.y); // lub swipeEndY
var verticalToleranceOnSwipe = noteCurrentHeight_swipe * 1.5; // Zwiększona tolerancja
if (verticalProximity < verticalToleranceOnSwipe) {
notesHitThisSwipe.push(n_swipe);
}
}
}
}
if (notesHitThisSwipe.length > 0) {
notesHitThisSwipe.sort(function (a, b) {
// Sortuj wg bliskości czasu do końca swipe'a
return Math.abs(swipeEndTime - a.targetHitTime) - Math.abs(swipeEndTime - b.targetHitTime);
});
var maxNotesToHitPerSwipe = notesHitThisSwipe.length > 0 && notesHitThisSwipe[0].isWiderSwipePart ? 2 : 1;
var notesActuallyHitCount = 0;
for (var k_swipe = 0; k_swipe < notesHitThisSwipe.length && notesActuallyHitCount < maxNotesToHitPerSwipe; k_swipe++) {
var noteToJudge_swipe = notesHitThisSwipe[k_swipe];
if (noteToJudge_swipe.judged) {
// Powtórne sprawdzenie na wszelki wypadek
continue;
}
// Logika dla wider swipe (jeśli istnieje)
if (notesActuallyHitCount === 1 && notesHitThisSwipe[0].isWiderSwipePart) {
if (!noteToJudge_swipe.isWiderSwipePart || noteToJudge_swipe.mapData && notesHitThisSwipe[0].mapData && noteToJudge_swipe.mapData.widerSwipePairCenterX !== notesHitThisSwipe[0].mapData.widerSwipePairCenterX || noteToJudge_swipe.mapData && notesHitThisSwipe[0].mapData && noteToJudge_swipe.mapData.partOfWiderSwipe === notesHitThisSwipe[0].mapData.partOfWiderSwipe) {
continue;
}
}
// Dla swipe, 'result' często jest binarny (trafiony/nietrafiony) lub uproszczony.
// Użyjemy getHitAccuracy, ale można to uprościć do 'perfect' jeśli kierunek się zgadza w oknie.
var result_swipe = noteToJudge_swipe.getHitAccuracy();
noteToJudge_swipe.judged = true;
noteToJudge_swipe.showHitFeedback(result_swipe);
if (result_swipe !== 'miss') {
addScore(result_swipe);
addCombo();
if (!isTutorialMode && !gameOverFlag) {
if (result_swipe === 'perfect') {
bossCurrentHP = Math.max(0, bossCurrentHP - 2);
} else if (result_swipe === 'good') {
bossCurrentHP = Math.max(0, bossCurrentHP - 1);
}
updateBossHpDisplay();
}
} else if (!isTutorialMode && !isShieldActive) {
resetCombo();
}
noteToJudge_swipe.alpha = 0; // ZMIANA: Ukryj nutę swipe po ocenie
notesActuallyHitCount++;
}
}
}
inputLocked = true;
LK.setTimeout(function () {
inputLocked = false;
}, 80);
swipeStart = null;
}
};
game.update = function () {
if (typeof notes === 'undefined' || !Array.isArray(notes)) {
notes = [];
}
var now = Date.now();
if (currentScreenState === 'miniGameActive' && !isMiniGameOver) {
miniGameTimeActive += 16;
if (miniGameTimeActive >= MINI_GAME_SPEED_INCREASE_INTERVAL) {
currentMiniGameObjectSpeed += MINI_GAME_SPEED_INCREMENT;
miniGameTimeActive = 0;
}
spawnMiniGameObstacle();
moveMiniGameObstacles();
checkMiniGameCollisions();
updateMiniGameScoreDisplay();
} else if (currentScreenState === 'miniGameActive' && isMiniGameOver) {
if (miniGameScreenElements.find(function (el) {
return el.isGameOverText;
}) === undefined) {
var gameOverText = new Text2("GAME OVER", {
size: 100,
fill: 0xFF0000,
align: 'center'
});
gameOverText.anchor.set(0.5, 0.5);
gameOverText.x = miniGameViewport.x + miniGameViewport.width / 2;
gameOverText.y = miniGameViewport.y + miniGameViewport.height / 2;
gameOverText.isGameOverText = true;
game.addChild(gameOverText);
miniGameScreenElements.push(gameOverText);
}
} else if (currentScreenState === 'gameplay') {
if (!isTutorialMode && !hpBarsInitialized) {
setupHpBars();
setupPowerUpDisplay();
hpBarsInitialized = true;
}
if (!isTutorialMode) {
if (isShieldActive) {
if (now > shieldEndTime) {
isShieldActive = false;
if (shieldTimerDisplayContainer) {
shieldTimerDisplayContainer.visible = false;
}
console.log("Tarcza WYGASŁA.");
} else {
if (shieldTimerDisplayContainer && shieldTimerDisplayContainer.visible) {
var remainingSecondsShield = (shieldEndTime - now) / 1000;
if (shieldTimerTextDisplay) {
shieldTimerTextDisplay.setText(remainingSecondsShield.toFixed(1) + "s");
}
}
}
} else {
if (shieldTimerDisplayContainer && shieldTimerDisplayContainer.visible) {
shieldTimerDisplayContainer.visible = false;
}
}
if (isPrecisionBuffActive) {
if (now > precisionBuffEndTime) {
isPrecisionBuffActive = false;
hitWindowPerfect = originalHitWindowPerfect;
hitWindowGood = originalHitWindowGood;
if (precisionBuffTimerDisplayContainer) {
precisionBuffTimerDisplayContainer.visible = false;
}
if (staticHitFrame) {
// Przywracamy WYSOKOŚĆ statycznej ramki obszaru uderzenia do wartości domyślnych
tween(staticHitFrame, {
height: STATIC_HIT_FRAME_HEIGHT // Przywracamy oryginalną wysokość
}, {
duration: 250,
easing: tween.easeInQuad
});
}
} else {
if (precisionBuffTimerDisplayContainer && precisionBuffTimerDisplayContainer.visible) {
var remainingSecondsBuff = (precisionBuffEndTime - now) / 1000;
if (precisionBuffTimerTextDisplay) {
precisionBuffTimerTextDisplay.setText(remainingSecondsBuff.toFixed(1) + "s");
}
}
}
} else {
if (precisionBuffTimerDisplayContainer && precisionBuffTimerDisplayContainer.visible) {
precisionBuffTimerDisplayContainer.visible = false;
}
}
}
spawnNotes();
for (var i_update_notes = 0; i_update_notes < notes.length; i_update_notes++) {
if (notes[i_update_notes] && notes[i_update_notes].update) {
notes[i_update_notes].update();
}
}
removeOldNotes();
if (isTutorialMode) {
var songHasEnded = currentMusic && !currentMusic.playing && now - gameStartTime > (currentMusic.duration || 0) * 1000;
var noNotesLeftOnScreen = notes.length === 0;
var allNotesProcessed = nextNoteIdx >= (currentActiveRhythmMap ? currentActiveRhythmMap.length : 0);
if (songHasEnded && noNotesLeftOnScreen && allNotesProcessed && currentMusic && now - gameStartTime > (currentMusic.duration || 0) * 1000 + 500) {
exitTutorialGameplay();
return;
}
} else {
checkGameEnd();
}
} else {
// Not in gameplay, mini-game, or tutorial state, so hide gameplay elements
if (notes.length > 0) {
for (var i_notes_clear = notes.length - 1; i_notes_clear >= 0; i_notes_clear--) {
var n_clear = notes[i_notes_clear];
if (n_clear && n_clear.parent) {
n_clear.destroy();
}
}
notes = [];
}
if (staticHitFrame && staticHitFrame.visible) {
staticHitFrame.visible = false;
}
if (staticPerfectLine && staticPerfectLine.visible) {
staticPerfectLine.visible = false;
}
}
};
// Load the specific song for testing
showStartScreen(); ===================================================================
--- original.js
+++ change.js
@@ -11,28 +11,28 @@
var self = Container.call(this);
self.noteType = noteType || 'tap';
self.swipeDir = swipeDir || null;
self.targetHitTime = targetHitTimeFull;
- self.visualSpawnTime = self.targetHitTime - noteTravelTime;
+ self.visualSpawnTime = self.targetHitTime - noteTravelTime; //
self.hit = false;
self.judged = false;
- self.scaleStart = 0.05;
- self.scaleEnd = 1.4;
+ self.scaleStart = 1.0; // Zgodnie z ostatnią zmianą (stały rozmiar)
+ self.scaleEnd = 1.0; // Zgodnie z ostatnią zmianą (stały rozmiar)
self.centerX = centerXVal;
self.centerY = 1800;
- self.startY = 300;
- self.noteAsset = null; // Główka nuty
- self.tailAsset = null; // Ogon dla nut hold
+ self.startY = -150; // Zgodnie z ostatnią zmianą (start zza ekranu)
+ self.noteAsset = null;
self.isWiderSwipePart = false;
self.isBuffNote = isIncomingBuffNote || false;
self.buffType = incomingBuffType || null;
- // Dla Hold Notes
self.isHoldNote = self.noteType === 'hold';
- self.holdDuration = self.isHoldNote ? holdDurationMs || 1000 : 0; // Domyślnie 1s, jeśli brak
- self.holdPressTime = 0; // Kiedy gracz zaczął przytrzymywać
- self.isBeingHeld = false; // Czy gracz aktualnie przytrzymuje tę nutę
- self.holdFullyCompleted = false; // Czy przytrzymano przez cały wymagany czas
- self.holdBroken = false; // Czy przytrzymanie zostało przerwane
+ self.holdDuration = self.isHoldNote ? holdDurationMs || 1000 : 0;
+ self.holdPressTime = 0;
+ self.isBeingHeld = false;
+ self.holdFullyCompleted = false;
+ self.holdBroken = false;
+ self.initialHoldHeight = 0;
+ // Logika przypisywania assetów - tak jak w naszej ostatniej wspólnej wersji
if (self.isBuffNote) {
var buffAssetKey = '';
if (self.buffType === 'potion') {
buffAssetKey = 'hpPotionAsset';
@@ -45,84 +45,117 @@
self.noteAsset = self.attachAsset(buffAssetKey, {
anchorX: 0.5,
anchorY: 0.5,
width: 150,
+ // Przykładowe rozmiary dla buffów
height: 180
});
}
if (self.isBuffNote) {
- // Buffy są traktowane jak tap dla interakcji
+ // Traktuj buffy jako tap dla interakcji
self.noteType = 'tap';
self.isHoldNote = false;
}
} else if (self.isHoldNote) {
+ var pixelsPerMs = (self.centerY - self.startY) / noteTravelTime;
+ var minVisualHeight = 50;
+ var calculatedTotalHeight = Math.max(minVisualHeight, self.holdDuration * pixelsPerMs);
+ self.initialHoldHeight = calculatedTotalHeight;
self.noteAsset = self.attachAsset('hold', {
- // Główka nuty hold
+ // Używamy assetu 'hold'
anchorX: 0.5,
- anchorY: 0.5
- });
- self.tailAsset = LK.getAsset('tail', {
- // Ogon nuty hold
- anchorX: 0.5,
anchorY: 0,
- // Zakotwiczenie na górnej krawędzi ogona
- width: self.noteAsset.width * 0.9 // Nieco węższy niż główka, lub dostosuj
+ // Górny anchor dla hold
+ height: self.initialHoldHeight
});
- // Obliczanie wysokości ogona
- var pixelsPerMs = (self.centerY - self.startY) / noteTravelTime;
- var tailHeight = self.holdDuration * pixelsPerMs;
- self.tailAsset.height = Math.max(10, tailHeight); // Minimalna wysokość
- self.tailAsset.x = 0; // Względem środka główki
- self.tailAsset.y = 0; // Ogon zaczyna się na środku główki (anchorY główki 0.5, anchorY ogona 0)
- // Można dostosować np. self.noteAsset.height / 4 dla lepszego efektu
- self.addChild(self.tailAsset); // Dodajemy ogon jako dziecko główki (Note container)
- self.tailAsset.setChildIndex(self.noteAsset, 0); // Upewnij się, że ogon jest POD główką
} else {
- // Tap, Swipe, Trap
+ // Tap, Swipe, Trap - używają swoich dedykowanych assetów
if (self.noteType === 'tap') {
- var tapAssetKey = 'tap0';
+ var tapAssetKey = 'tap0'; // Domyślnie tap0, potem można dodać logikę dla tap1, tap2 z noteColumnIndex
if (noteColumnIndex !== undefined) {
- if (noteColumnIndex === 0) tapAssetKey = 'tap0';else if (noteColumnIndex === 1) tapAssetKey = 'tap1';else if (noteColumnIndex === 2) tapAssetKey = 'tap2';
+ if (noteColumnIndex === 0) {
+ tapAssetKey = 'tap0';
+ } else if (noteColumnIndex === 1) {
+ tapAssetKey = 'tap1';
+ } else if (noteColumnIndex === 2) {
+ tapAssetKey = 'tap2';
+ }
}
self.noteAsset = self.attachAsset(tapAssetKey, {
+ // Użyj tapNote ze starego kodu lub odpowiedniego assetu
anchorX: 0.5,
anchorY: 0.5
});
} else if (self.noteType === 'swipe') {
- var swipeAssetKey = 'swipe_col0';
+ var swipeAssetKey = 'swipe_col0'; // Domyślnie, potem można dodać logikę dla swipe_col1, swipe_col2
if (noteColumnIndex !== undefined) {
- if (noteColumnIndex === 0) swipeAssetKey = 'swipe_col0';else if (noteColumnIndex === 1) swipeAssetKey = 'swipe_col1';else if (noteColumnIndex === 2) swipeAssetKey = 'swipe_col2';
+ if (noteColumnIndex === 0) {
+ swipeAssetKey = 'swipe_col0';
+ } else if (noteColumnIndex === 1) {
+ swipeAssetKey = 'swipe_col1';
+ } else if (noteColumnIndex === 2) {
+ swipeAssetKey = 'swipe_col2';
+ }
}
self.noteAsset = self.attachAsset(swipeAssetKey, {
+ // Użyj swipeNote ze starego kodu lub odpowiedniego assetu
anchorX: 0.5,
anchorY: 0.5
});
if (self.swipeDir && self.noteAsset) {
+ // Dodawanie strzałki jak w starym kodzie, jeśli asset sam jej nie ma
+ var arrowText = '';
var rotationAngle = 0;
- if (self.swipeDir === 'left') rotationAngle = Math.PI;else if (self.swipeDir === 'up') rotationAngle = -Math.PI / 2;else if (self.swipeDir === 'down') rotationAngle = Math.PI / 2;
- self.noteAsset.rotation = rotationAngle;
+ if (self.swipeDir === 'left') {
+ arrowText = '←';
+ rotationAngle = Math.PI;
+ } else if (self.swipeDir === 'right') {
+ arrowText = '→';
+ rotationAngle = 0;
+ } else if (self.swipeDir === 'up') {
+ arrowText = '↑';
+ rotationAngle = -Math.PI / 2;
+ } else if (self.swipeDir === 'down') {
+ arrowText = '↓';
+ rotationAngle = Math.PI / 2;
+ }
+ // Jeśli asset 'swipe_colN' nie ma strzałki, można ją dodać jak w starym kodzie
+ // lub po prostu obrócić asset, jeśli jest np. pojedynczą strzałką w prawo
+ self.noteAsset.rotation = rotationAngle; // Obracamy asset zamiast dodawać tekstową strzałkę
}
} else if (self.noteType === 'trap') {
self.noteAsset = self.attachAsset('trapNote', {
anchorX: 0.5,
anchorY: 0.5
});
}
}
- self.alpha = 0;
+ self.alpha = 0; // Nuty startują niewidoczne
+ // PRZYWRÓCONA LOGIKA Z `walkman fighterv2.txt` z drobnymi adaptacjami
self.showHitFeedback = function (result, feedbackTextOverride) {
+ // feedbackTextOverride z nowszej wersji
var feedbackCircle = LK.getAsset('hitFeedback', {
+ //
anchorX: 0.5,
anchorY: 0.5,
x: 0,
y: 0,
scaleX: 0.7,
scaleY: 0.7,
alpha: 0.7
});
- var feedbackTextContent = feedbackTextOverride || "";
+ // Dostosowanie Y dla feedbackCircle jeśli nuta ma inny anchor niż 0.5
+ if (self.noteAsset && self.noteAsset.anchorY !== 0.5) {
+ if (self.isHoldNote && self.noteAsset.width > 0) {
+ feedbackCircle.y = self.noteAsset.width * 0.25 + self.noteAsset.y;
+ } else {
+ feedbackCircle.y = self.noteAsset.height / 2 + self.noteAsset.y;
+ }
+ }
+ var feedbackTextContent = feedbackTextOverride || ""; // Używamy override jeśli jest
var feedbackTextColor = 0xFFFFFF;
if (!feedbackTextOverride) {
+ // Logika kolorów i tekstu jak w nowszej wersji, bo jest bardziej rozbudowana
if (self.isBuffNote && result !== 'miss') {
feedbackCircle.tint = 0x40E0D0;
feedbackTextContent = self.buffType.charAt(0).toUpperCase() + self.buffType.slice(1) + "!";
feedbackTextColor = 0x40E0D0;
@@ -134,16 +167,16 @@
feedbackCircle.tint = 0x00ff00;
feedbackTextContent = "Good!";
feedbackTextColor = 0x00ff00;
} else if (result === 'hold_ok') {
- // Nowy typ feedbacku dla udanego holda
- feedbackCircle.tint = 0x00FF7F; // SpringGreen
+ // Z nowszej wersji dla hold
+ feedbackCircle.tint = 0x00FF7F;
feedbackTextContent = "Held!";
feedbackTextColor = 0x00FF7F;
} else {
// miss, hold_broken
feedbackCircle.tint = 0xff0000;
- feedbackTextContent = result === 'hold_broken' ? "Broken!" : "Miss";
+ feedbackTextContent = result === 'hold_broken' ? "Broken!" : "Miss"; //
feedbackTextColor = 0xff0000;
}
}
self.addChild(feedbackCircle);
@@ -154,9 +187,11 @@
}, {
duration: 350,
easing: tween.easeOut,
onFinish: function onFinish() {
- if (feedbackCircle.parent) feedbackCircle.destroy();
+ if (feedbackCircle.parent) {
+ feedbackCircle.destroy();
+ }
}
});
if (feedbackTextContent) {
var scorePopup = new Text2(feedbackTextContent, {
@@ -165,182 +200,242 @@
stroke: 0x000000,
strokeThickness: 3
});
scorePopup.anchor.set(0.5, 0.5);
- var noteAssetHeight = self.noteAsset ? self.noteAsset.height * self.scale.y : SWIPE_NOTE_WIDTH * self.scale.y;
+ var noteVisualHeight = SWIPE_NOTE_WIDTH; // Domyślna ze starego kodu
+ if (self.noteAsset) {
+ // Jeśli asset istnieje, użyj jego wysokości
+ noteVisualHeight = self.noteAsset.height;
+ }
+ // Pozycjonowanie scorePopup jak w starym kodzie (nad nutą)
+ // self.x i self.y to absolutne pozycje kontenera nuty
+ var popupAbsX = self.x;
+ var popupAbsY = self.y - noteVisualHeight * self.scale.y / 2 - 30; // self.scale.y będzie 1.0
+ if (self.isHoldNote && self.noteAsset) {
+ // Dla holda, nad "główką"
+ var headApproxHeight = self.noteAsset.width > 0 ? self.noteAsset.width * 0.25 : 50;
+ popupAbsY = self.y + self.noteAsset.y + headApproxHeight - noteVisualHeight * 0.25 - 30; // Dostosuj
+ } else if (self.noteAsset && self.noteAsset.anchorY === 0) {
+ // Inne nuty z anchorY 0
+ popupAbsY = self.y + noteVisualHeight / 2 - 30; // Na środku
+ }
+ scorePopup.x = popupAbsX;
+ scorePopup.y = popupAbsY;
if (self.parent) {
- scorePopup.x = self.x;
- scorePopup.y = self.y - noteAssetHeight / 2 * self.scale.y - 30;
self.parent.addChild(scorePopup);
+ // Animacja scorePopup W GÓRĘ, jak w starym kodzie
tween(scorePopup, {
- y: scorePopup.y - 80,
+ y: popupAbsY - 80,
+ // Przesunięcie w górę
alpha: 0
}, {
duration: 700,
easing: tween.easeOut,
onFinish: function onFinish() {
- if (scorePopup.parent) scorePopup.destroy();
+ if (scorePopup.parent) {
+ scorePopup.destroy();
+ }
}
});
}
}
if (self.parent && (result === 'good' || result === 'perfect' || result === 'hold_ok')) {
- spawnParticleEffect(self.x, self.y, result, self.parent);
+ var particleSpawnX = self.x;
+ var particleSpawnY;
+ if (self.isHoldNote && self.noteAsset) {
+ particleSpawnY = self.y + self.noteAsset.y + self.noteAsset.width * 0.25;
+ } else if (self.noteAsset && self.noteAsset.anchorY === 0.5) {
+ particleSpawnY = self.y;
+ } else if (self.noteAsset) {
+ particleSpawnY = self.y + self.noteAsset.height / 2;
+ } else {
+ particleSpawnY = self.y;
+ }
+ spawnParticleEffect(particleSpawnX, particleSpawnY, result, self.parent);
}
};
self.update = function () {
var now = Date.now();
- if (self.judged && !self.isBeingHeld) {
- // Jeśli oceniona I nie jest aktywnie trzymana
- // Standardowe znikanie po ocenieniu
- if (this.alpha > 0) {
- // Można dodać tu jakąś animację znikania, jeśli chcesz
+ // Logika dla ocenionych nut (tap/swipe) - pozwalamy im kontynuować ruch
+ if (self.judged && !self.isHoldNote) {
+ // Jeśli oceniona I NIE JEST nutą hold
+ if (self.alpha > 0) {
+ // Jeśli jest jeszcze widoczna
+ // Kontynuuj ruch i skalowanie (teraz skala stała 1.0)
+ var elapsedTimeSinceSpawn = now - self.visualSpawnTime;
+ var currentProgress = elapsedTimeSinceSpawn / noteTravelTime;
+ self.x = self.centerX;
+ self.y = self.startY + (self.centerY - self.startY) * currentProgress; // Nuta leci dalej
+ // Skala jest stała 1.0, więc nie ma potrzeby jej tu aktualizować na podstawie progress,
+ // chyba że chcemy specjalny efekt po trafieniu. Na razie zostawiamy self.scale = 1.0.
+ // self.scale.x = self.scaleEnd; // Byłoby 1.0
+ // self.scale.y = self.scaleEnd; // Byłoby 1.0
}
+ // Nie robimy return, aby logika auto-miss dla długo wiszących ocenionych nut mogła zadziałać
+ // lub removeOldNotes je usunęło. Jeśli alpha > 0, będzie się ruszać.
+ // Jeśli alpha zostało ustawione na 0 przez game.onNoteMiss, to po prostu będzie czekać na removeOldNotes.
+ }
+ // Dla ocenionych i zakończonych nut HOLD (nie są już isBeingHeld)
+ else if (self.judged && self.isHoldNote && !self.isBeingHeld) {
+ // Np. po judgeHoldRelease, alpha powinno być już 0.
+ // Jeśli nie jest, to problem. Ta gałąź dla bezpieczeństwa.
+ if (self.alpha > 0) {
+ self.alpha = 0;
+ }
return;
}
- // Logika dla aktywnie trzymanej nuty hold
+ // Pojawianie się nowych nut
+ if (self.alpha === 0 && !self.judged && now >= self.visualSpawnTime) {
+ if (!self.isBeingHeld || self.isBeingHeld && now < self.targetHitTime + self.holdDuration + 500) {
+ self.alpha = 1;
+ }
+ }
+ if (self.alpha === 0 && !self.judged) {
+ // Jeśli nadal niewidoczna (nie jej czas)
+ return;
+ }
+ // Aktualizacja dla aktywnych, nieocenionych nut lub aktywnych holdów
if (self.isHoldNote && self.isBeingHeld) {
+ // Tylko dla aktywnie trzymanych holdów
if (self.holdBroken) {
- // Jeśli hold został przerwany (np. palec zszedł z kolumny)
self.isBeingHeld = false;
- self.judged = true; // Oceniamy jako zakończony (nieudany)
- // Tu można dodać logikę kary/braku punktów za przerwany hold
- // self.showHitFeedback('hold_broken'); // Już wywołane w game.inputActiveCheck
+ self.judged = true;
+ self.alpha = 0;
return;
}
- // Aktualizacja wyglądu ogona "zużywanego"
- if (self.tailAsset) {
- var timeIntoNote = now - self.targetHitTime;
- var holdProgress = Math.max(0, Math.min(1, timeIntoNote / self.holdDuration));
- // Prosta wizualizacja "zużycia" ogona - np. zmiana alpha górnej części
- // To wymaga bardziej zaawansowanej grafiki/maskowania. Na razie ogon jest stały.
- // Dla przykładu, ogon mógłby zmieniać kolor lub alpha, gdy jest aktywny
- self.tailAsset.tint = 0xAAAA00; // Lekko przyciemniony złoty, gdy trzymany
- }
- // Sprawdzenie, czy czas trzymania upłynął
- if (now >= self.targetHitTime + self.holdDuration) {
- if (!self.holdFullyCompleted) {
- // Oceniamy tylko raz
- self.holdFullyCompleted = true;
- // self.isBeingHeld = false; // Gracz może nadal trzymać, ale my już zaliczyliśmy
- // self.judged = true; // Zostanie oceniony przy game.up
- // Daj punkty za udane przytrzymanie, jeśli jeszcze nie zostały dane
- console.log("Hold note duration completed for note at " + self.targetHitTime);
- // Punkty za samo przytrzymanie (jeśli inne niż za puszczenie)
+ if (self.noteAsset) {
+ self.noteAsset.tint = 0xAAAA00;
+ if (now >= self.targetHitTime) {
+ var timeHeldPastHitLine = now - self.targetHitTime;
+ var pixelsPerMs = (self.centerY - self.startY) / noteTravelTime;
+ var pixelsConsumed = Math.min(timeHeldPastHitLine * pixelsPerMs, self.initialHoldHeight);
+ self.noteAsset.y = pixelsConsumed;
+ self.noteAsset.height = Math.max(0, self.initialHoldHeight - pixelsConsumed);
+ } else {
+ self.noteAsset.height = self.initialHoldHeight;
+ self.noteAsset.y = 0;
}
}
- // Nuta hold pozostaje na ekranie, dopóki gracz jej nie puści lub nie minie jej czas + jakiś bufor
- }
- // Standardowe przesuwanie i skalowanie nuty
- if (now < self.visualSpawnTime && self.alpha > 0 && !self.isBeingHeld) {
- // Ukryj, jeśli za wcześnie i nie jest trzymana
- self.alpha = 0;
- return;
- }
- if (self.alpha === 0 && !self.judged && now >= self.visualSpawnTime) {
- if (!self.isBeingHeld || self.isBeingHeld && now < self.targetHitTime + self.holdDuration + 500) {
- // Pokaż, jeśli ma być widoczna
- self.alpha = 1;
+ if (now >= self.targetHitTime + self.holdDuration && !self.holdFullyCompleted) {
+ self.holdFullyCompleted = true;
+ console.log("Hold note duration completed for note at " + self.targetHitTime);
}
}
- var elapsedTimeSinceSpawn = now - self.visualSpawnTime;
- var progress = elapsedTimeSinceSpawn / noteTravelTime;
- var scale;
- if (progress >= 1) scale = self.scaleEnd;else if (progress < 0) {
- scale = self.scaleStart;
- progress = 0;
- } else scale = self.scaleStart + (self.scaleEnd - self.scaleStart) * progress;
- self.scale.x = Math.max(0.01, scale);
- self.scale.y = Math.max(0.01, scale);
- self.x = self.centerX;
- var newY = self.startY + (self.centerY - self.startY) * progress;
- // Dla nut hold, główka zatrzymuje się na linii, gdy jest trzymana
- if (self.isHoldNote && self.isBeingHeld && newY >= self.centerY) {
- self.y = self.centerY;
- if (self.tailAsset) {// Ogon też się zatrzymuje
- // Pozycja ogona jest względna, więc nie trzeba aktualizować jego Y, jeśli główka się zatrzymała
+ // Dla wszystkich aktywnych (nieocenionych lub trzymanych holdów) nut, aktualizuj pozycję:
+ // (chyba że jest to oceniony tap/swipe, wtedy ruch jest już obsłużony wyżej)
+ if (!self.judged || self.isHoldNote && self.isBeingHeld) {
+ self.scale.x = 1.0; // Stała skala
+ self.scale.y = 1.0; // Stała skala
+ self.x = self.centerX;
+ var progress = (now - self.visualSpawnTime) / noteTravelTime;
+ var newY = self.startY + (self.centerY - self.startY) * progress;
+ if (self.isHoldNote && self.isBeingHeld && newY >= self.centerY) {
+ self.y = self.centerY;
+ } else if (!self.isHoldNote) {
+ // Tap, swipe, trap - pozwól im lecieć dalej, jeśli nie ocenione
+ self.y = newY;
+ } else if (self.isHoldNote && !self.isBeingHeld && !self.judged) {
+ // Hold nie trzymany i nie oceniony
+ self.y = newY;
}
- } else {
- self.y = newY;
+ // Jeśli jest to oceniony tap/swipe, jego Y jest już aktualizowane na początku tej funkcji.
}
- // Ogon podąża za główką
- if (self.isHoldNote && self.tailAsset) {
- // Jeśli ogon ma być "zużywany" od góry, trzeba by dynamicznie zmieniać jego wysokość i pozycję Y
- // Na razie prosty ogon o stałej długości, który się przesuwa
- // Można dodać efekt "przechodzenia" przez linię, np. zmieniając alpha części ogona
- // która jest powyżej self.centerY, ale to bardziej skomplikowane z jednym assetem.
- }
- // Automatyczny miss, jeśli nuta nie-hold minęła okno bez oceny
- if (!self.isHoldNote && !self.judged && now > self.targetHitTime + hitWindowGood) {
- self.judged = true;
- if (self.noteType !== 'trap' && !self.isBuffNote) game.onNoteMiss(self);else if (self.isBuffNote) {
+ // Automatyczne missy (logika z naszej nowszej wersji, bardziej kompletna)
+ if (!self.judged && now > self.targetHitTime + hitWindowGood) {
+ // Ogólny auto-miss, jeśli nie oceniono na czas
+ if (self.noteType === 'trap') {// Trapów nie missujemy, same znikają lub są klikane
+ // Można dodać logikę zniknięcia trapa po czasie, jeśli nie kliknięty
+ } else if (self.isHoldNote && self.holdPressTime === 0) {
+ // Główka holda nie wciśnięta
+ console.log("Hold note head auto-missed: " + self.targetHitTime);
+ self.judged = true;
self.showHitFeedback('miss');
- if (!isTutorialMode && !isShieldActive) resetCombo();
+ if (!isTutorialMode && !isShieldActive) {
+ resetCombo();
+ }
+ self.alpha = 0;
+ } else if (!self.isHoldNote) {
+ // Dla tap, swipe, buff
+ self.judged = true;
+ if (self.isBuffNote) {
+ self.showHitFeedback('miss');
+ if (!isTutorialMode && !isShieldActive) {
+ resetCombo();
+ }
+ self.alpha = 0;
+ } else {
+ // Zwykły tap/swipe
+ game.onNoteMiss(self); // game.onNoteMiss powinno obsłużyć feedback i ewentualne ukrycie
+ }
}
}
- // Dla nut hold, miss jest obsługiwany inaczej (brak wciśnięcia główki lub puszczenie za wcześnie)
- // Jeśli nuta hold dotarła do końca swojego czasu + bufor, a nie jest trzymana, powinna zniknąć
- if (self.isHoldNote && !self.isBeingHeld && !self.judged && now > self.targetHitTime + self.holdDuration + hitWindowGood) {
- console.log("Hold note missed or passed without release judge: " + self.targetHitTime);
- self.judged = true;
- // game.onNoteMiss(self); // Można dodać specjalny typ miss dla hold
- self.showHitFeedback('miss'); // Lub standardowy miss
- if (!isTutorialMode && !isShieldActive) resetCombo();
+ // Dla długo nieusuniętych ocenionych nut hold (zabezpieczenie z nowszej wersji)
+ if (self.isHoldNote && self.judged && !self.isBeingHeld && now > self.targetHitTime + self.holdDuration + 500) {
+ if (this.alpha > 0) {
+ this.alpha = 0;
+ }
}
};
self.isInHitWindow = function () {
- // Dla główki nuty Hold
var now = Date.now();
var dt = Math.abs(now - self.targetHitTime);
return dt <= hitWindowGood;
};
self.getHitAccuracy = function () {
- // Dla główki nuty Hold
var now = Date.now();
var dt = Math.abs(now - self.targetHitTime);
- if (dt <= hitWindowPerfect) return 'perfect';
- if (dt <= hitWindowGood) return 'good';
+ if (dt <= hitWindowPerfect) {
+ return 'perfect';
+ }
+ if (dt <= hitWindowGood) {
+ return 'good';
+ }
return 'miss';
};
- // Nowa metoda do oceny puszczenia Hold Note
self.judgeHoldRelease = function () {
- if (!self.isHoldNote || self.judged) return; // Tylko dla nieocenionych nut hold
+ if (!self.isHoldNote || self.judged && self.holdFullyCompleted && !self.holdBroken) {
+ if (self.isBeingHeld) {
+ self.isBeingHeld = false;
+ }
+ return;
+ }
var now = Date.now();
- self.isBeingHeld = false; // Zawsze kończymy trzymanie
- self.judged = true; // Nuta jest już oceniona (przynajmniej jej część release)
+ self.isBeingHeld = false;
+ self.judged = true;
if (self.holdBroken) {
- // Jeśli wcześniej przerwano (np. zsunięcie palca)
- // self.showHitFeedback('hold_broken'); // Już powinno być wywołane
+ if (!this.feedbackShownForBroken) {
+ this.showHitFeedback('hold_broken');
+ this.feedbackShownForBroken = true;
+ }
console.log("Hold broken and released for note: " + self.targetHitTime);
- if (!isTutorialMode && !isShieldActive) resetCombo();
+ if (!isTutorialMode && !isShieldActive) {
+ resetCombo();
+ }
+ self.alpha = 0;
return;
}
- // Czy puszczono wystarczająco długo?
- // self.holdPressTime to czas wciśnięcia główki
- // self.targetHitTime + self.holdDuration to docelowy czas końca trzymania
var actualHoldDuration = now - self.holdPressTime;
var requiredHoldTimeOnScreen = self.targetHitTime + self.holdDuration;
if (now >= requiredHoldTimeOnScreen - hitWindowGood) {
- // Puszczono w dobrym momencie lub później
- self.holdFullyCompleted = true; // Potwierdzenie
- self.showHitFeedback('hold_ok'); // Specjalny feedback dla udanego holda
- // Dodaj punkty za udane przytrzymanie i puszczenie
+ self.holdFullyCompleted = true;
+ self.showHitFeedback('hold_ok');
if (!isTutorialMode) {
- addScore('perfect'); // Np. jak za perfect, lub dedykowany scoring
+ addScore('perfect');
addCombo();
- // Logika obrażeń dla bossa
if (!gameOverFlag) {
- bossCurrentHP = Math.max(0, bossCurrentHP - 2); // Np. jak za perfect
+ bossCurrentHP = Math.max(0, bossCurrentHP - 2);
updateBossHpDisplay();
}
}
console.log("Hold OK for note: " + self.targetHitTime);
} else {
- // Puszczono za wcześnie
- self.showHitFeedback('miss', 'Too Early!'); // Można dać "Too Early!" lub "Miss"
+ self.showHitFeedback('miss', 'Too Early!');
console.log("Hold released too early for note: " + self.targetHitTime + ". Held for: " + actualHoldDuration + "ms, required full duration by map: " + self.holdDuration + "ms until time " + requiredHoldTimeOnScreen);
- if (!isTutorialMode && !isShieldActive) resetCombo();
+ if (!isTutorialMode && !isShieldActive) {
+ resetCombo();
+ }
}
+ self.alpha = 0;
};
return self;
});
@@ -353,15 +448,16 @@
/****
* Game Code
****/
-// Złoty segment ogona (wysokość bazowa)
-// Pomarańczowa główka
// np. węższa środkowa
+// Pomarańczowa główka
+// Złoty segment ogona (wysokość bazowa)
var currentScreenState = '';
var columnFlashOverlays = [null, null, null];
var mainMenuScreenElements = [];
var isTutorialMode = false;
+var currentlyHeldNotes = {};
var tutorialSongData = {
id: "TutorialTrack",
title: "How to Play",
artist: "Game System",
@@ -517,9 +613,9 @@
var hpPotionCountText, shieldCountText, swipeToTapCountText;
var currentActiveRhythmMap = null;
var currentMusic = null;
var noteTravelTime = 3300;
-var BUFF_CHANCE = 0.5;
+var BUFF_CHANCE = 0.08;
var gameplayBackground = null;
var PRECISION_BUFF_DURATION = 7000;
var isPrecisionBuffActive = false;
var precisionBuffEndTime = 0;
@@ -3351,9 +3447,9 @@
var buffTypesAvailable = ['potion', 'shield', 'precision'];
awardedBuffType = buffTypesAvailable[Math.floor(Math.random() * buffTypesAvailable.length)];
}
}
- var n = new Note(finalNoteType, finalSwipeDir, noteTargetHitTime, targetCenterX, noteData.columnIndex, noteWillBeBuff, awardedBuffType);
+ var n = new Note(finalNoteType, finalSwipeDir, noteTargetHitTime, targetCenterX, noteData.columnIndex, noteWillBeBuff, awardedBuffType, noteData.duration);
n.mapData = noteData;
if (noteData.partOfWiderSwipe) {
n.isWiderSwipePart = true;
}
@@ -3390,9 +3486,9 @@
var bestNote = null;
var smallestTimeDiff = hitWindowGood + 1;
for (var i = 0; i < notes.length; i++) {
var n = notes[i];
- if (n.judged || n.noteType !== typeToFind) {
+ if (n.judged || n.noteType !== typeToFind && !(typeToFind === 'tap' && n.isHoldNote && !n.isBeingHeld)) {
continue;
}
var timeDiff = Math.abs(now - n.targetHitTime);
if (timeDiff > hitWindowGood) {
@@ -3780,73 +3876,101 @@
};
game.down = function (x, y, obj) {
if (currentScreenState === 'gameplay') {
if (inputLocked) {
- console.log("Input locked, returning.");
return;
}
- console.log("Raw click coords: x=" + x + ", y=" + y);
- var clickIsInFrame = false;
- if (staticHitFrame && staticHitFrame.visible) {
- console.log("staticHitFrame.visible is TRUE.");
- console.log("staticHitFrame current pos: x=" + staticHitFrame.x + ", y=" + staticHitFrame.y);
- console.log("staticHitFrame current scale: x=" + staticHitFrame.scale.x + ", y=" + staticHitFrame.scale.y);
- var bounds = staticHitFrame.getBounds();
- console.log("staticHitFrame bounds (from getBounds()): x=" + bounds.x + ", y=" + bounds.y + ", width=" + bounds.width + ", height=" + bounds.height);
- if (x >= bounds.x && x <= bounds.x + bounds.width && y >= bounds.y && y <= bounds.y + bounds.height) {
- clickIsInFrame = true;
- console.log("Click IS inside static hit frame.");
- } else {
- console.log("Click IS NOT inside static hit frame.");
- }
- } else {
- console.log("staticHitFrame is not defined or not visible.");
- }
swipeStart = {
x: x,
y: y,
time: Date.now()
};
- var noteUnderCursor_gp = findNoteAt(x, y, 'trap');
- if (noteUnderCursor_gp && !noteUnderCursor_gp.judged && noteUnderCursor_gp.isInHitWindow()) {
- noteUnderCursor_gp.judged = true;
- noteUnderCursor_gp.showHitFeedback('miss');
+ var now = Date.now();
+ // Najpierw obsługa PowerUpów (jeśli istnieje) - zachowujemy z ostatniej wersji
+ for (var i_gp_pu = activePowerUpItems.length - 1; i_gp_pu >= 0; i_gp_pu--) {
+ var pItem_gp = activePowerUpItems[i_gp_pu];
+ if (pItem_gp && !pItem_gp.collected && pItem_gp.visualAsset && pItem_gp.parent) {
+ var pWidth_gp = pItem_gp.visualAsset.width * pItem_gp.scale.x; // scale.x będzie 1
+ var pHeight_gp = pItem_gp.visualAsset.height * pItem_gp.scale.y; // scale.y będzie 1
+ if (x >= pItem_gp.x - pWidth_gp / 2 && x <= pItem_gp.x + pWidth_gp / 2 && y >= pItem_gp.y - pHeight_gp / 2 && y <= pItem_gp.y + pHeight_gp / 2) {
+ if (Math.abs(pItem_gp.y - hitZoneY) < pHeight_gp * 1.5) {
+ // Tolerancja kliknięcia
+ pItem_gp.collect();
+ return; // PowerUp kliknięty, nie przetwarzaj dalej jako nuta
+ }
+ }
+ }
+ }
+ var noteUnderCursorTrap = findNoteAt(x, y, 'trap'); //
+ if (noteUnderCursorTrap && !noteUnderCursorTrap.judged && noteUnderCursorTrap.isInHitWindow()) {
+ //
+ noteUnderCursorTrap.judged = true; //
+ noteUnderCursorTrap.showHitFeedback('miss'); //
if (!isTutorialMode) {
+ // Dodane z nowszej logiki
if (isShieldActive) {
- // Gracz trafił w TRAP NOTE, ale tarcza jest aktywna!
+ //
+ console.log("Gracz trafił w TRAP NOTE, ale tarcza jest aktywna! Brak utraty HP i combo NIE zresetowane."); //
} else {
- resetCombo();
- LK.effects.flashScreen(0xff0000, 400);
+ //
+ resetCombo(); //
+ LK.effects.flashScreen(0xff0000, 400); //
if (!gameOverFlag) {
- playerCurrentHP = Math.max(0, playerCurrentHP - 1);
- updatePlayerHpDisplay();
+ //
+ playerCurrentHP = Math.max(0, playerCurrentHP - 1); //
+ updatePlayerHpDisplay(); //
}
}
}
+ noteUnderCursorTrap.alpha = 0; // Trap znika od razu
inputLocked = true;
LK.setTimeout(function () {
inputLocked = false;
- }, 200);
+ }, 200); //
return;
}
- noteUnderCursor_gp = findNoteAt(x, y, 'tap');
- if (noteUnderCursor_gp && !noteUnderCursor_gp.judged && noteUnderCursor_gp.isInHitWindow()) {
- var result_gp = noteUnderCursor_gp.getHitAccuracy();
- noteUnderCursor_gp.judged = true;
- if (noteUnderCursor_gp.isBuffNote) {
- noteUnderCursor_gp.showHitFeedback(result_gp === 'miss' ? 'miss' : 'perfect');
- if (result_gp !== 'miss' && !isTutorialMode) {
- var buffType = noteUnderCursor_gp.buffType;
+ var noteUnderCursor = findNoteAt(x, y, 'tap'); //
+ if (noteUnderCursor && !noteUnderCursor.judged && !noteUnderCursor.isBeingHeld && noteUnderCursor.isInHitWindow()) {
+ //
+ var result = noteUnderCursor.getHitAccuracy();
+ noteUnderCursor.hit = true;
+ noteUnderCursor.judged = true; // Ustawiamy judged tutaj dla wszystkich typów (tap, buff, główka hold)
+ noteUnderCursor.showHitFeedback(result);
+ if (noteUnderCursor.isHoldNote) {
+ if (result !== 'miss') {
+ noteUnderCursor.isBeingHeld = true;
+ noteUnderCursor.holdPressTime = now;
+ // Reszta logiki dla hold (score, combo, bossHP) jest w porządku
+ if (!isTutorialMode) {
+ addScore(result);
+ addCombo();
+ if (!gameOverFlag) {
+ if (result === 'perfect') bossCurrentHP = Math.max(0, bossCurrentHP - 2);else if (result === 'good') bossCurrentHP = Math.max(0, bossCurrentHP - 1);
+ updateBossHpDisplay();
+ }
+ }
+ if (noteUnderCursor.mapData && noteUnderCursor.mapData.columnIndex !== undefined) {
+ currentlyHeldNotes[noteUnderCursor.mapData.columnIndex] = noteUnderCursor;
+ } else if (noteUnderCursor.originalColumnHint !== undefined) {
+ currentlyHeldNotes[noteUnderCursor.originalColumnHint] = noteUnderCursor;
+ }
+ } else {
+ // Miss na główce holda
+ if (!isTutorialMode && !isShieldActive) resetCombo();
+ noteUnderCursor.alpha = 0; // Główka holda znika jeśli miss
+ }
+ } else if (noteUnderCursor.isBuffNote) {
+ if (result !== 'miss' && !isTutorialMode) {
+ // Logika aktywacji buffów ... (zachowana)
+ var buffType = noteUnderCursor.buffType;
if (buffType === 'potion') {
playerCurrentHP = Math.min(playerMaxHP, playerCurrentHP + POTION_HEAL_AMOUNT);
updatePlayerHpDisplay();
} else if (buffType === 'shield') {
if (!isShieldActive) {
isShieldActive = true;
shieldEndTime = Date.now() + SHIELD_DURATION;
- if (shieldTimerDisplayContainer) {
- shieldTimerDisplayContainer.visible = true;
- }
+ if (shieldTimerDisplayContainer) shieldTimerDisplayContainer.visible = true;
}
} else if (buffType === 'precision') {
if (!isPrecisionBuffActive) {
isPrecisionBuffActive = true;
@@ -3854,48 +3978,38 @@
originalHitWindowPerfect = hitWindowPerfect;
originalHitWindowGood = hitWindowGood;
hitWindowPerfect = Math.round(hitWindowPerfect * precisionBuffHitWindowMultiplier);
hitWindowGood = Math.round(hitWindowGood * precisionBuffHitWindowMultiplier);
- if (precisionBuffTimerDisplayContainer) {
- precisionBuffTimerDisplayContainer.visible = true;
- }
- // Skalowanie statycznej ramki obszaru uderzenia
- if (staticHitFrame) {
- // Zmieniamy HEIGHT zamiast SCALE.X, aby poszerzyć w pionie
- tween(staticHitFrame, {
- height: STATIC_HIT_FRAME_HEIGHT * 2 // Przykład: 150% wysokości
- }, {
- duration: 250,
- easing: tween.easeOutQuad
- });
- }
+ if (precisionBuffTimerDisplayContainer) precisionBuffTimerDisplayContainer.visible = true;
+ if (staticHitFrame) tween(staticHitFrame, {
+ height: STATIC_HIT_FRAME_HEIGHT * 2
+ }, {
+ duration: 250,
+ easing: tween.easeOutQuad
+ });
}
}
- } else if (result_gp === 'miss' && !isTutorialMode) {
- if (!isShieldActive) {
- resetCombo();
- }
+ } else if (result === 'miss' && !isTutorialMode && !isShieldActive) {
+ resetCombo();
}
+ // Nie ustawiamy alpha = 0, pozwalamy jej kontynuować ruch (jak w starym kodzie)
} else {
- noteUnderCursor_gp.showHitFeedback(result_gp);
- if (result_gp !== 'miss') {
- addScore(result_gp);
- addCombo();
+ // Zwykły Tap Note
+ if (result !== 'miss') {
+ addScore(result);
+ addCombo(); //
if (!isTutorialMode && !gameOverFlag) {
- if (result_gp === 'perfect') {
- bossCurrentHP = Math.max(0, bossCurrentHP - 2);
- } else if (result_gp === 'good') {
- bossCurrentHP = Math.max(0, bossCurrentHP - 1);
- }
- updateBossHpDisplay();
+ //
+ if (result === 'perfect') bossCurrentHP = Math.max(0, bossCurrentHP - 2); //
+ else if (result === 'good') bossCurrentHP = Math.max(0, bossCurrentHP - 1); //
+ updateBossHpDisplay(); //
}
- } else {
- if (!isTutorialMode) {
- if (!isShieldActive) {
- resetCombo();
- }
- }
+ } else if (!isTutorialMode) {
+ // Miss na tapie
+ if (!isShieldActive) resetCombo(); //
+ else console.log("Tapnięcie nuty ocenione jako 'miss', ale tarcza jest aktywna! Combo NIE zresetowane.");
}
+ // Nie ustawiamy alpha = 0, pozwalamy jej kontynuować ruch
}
inputLocked = true;
LK.setTimeout(function () {
inputLocked = false;
@@ -3906,8 +4020,33 @@
};
game.move = function (x, y, obj) {};
game.up = function (x, y, obj) {
if (currentScreenState === 'gameplay') {
+ // Logika puszczania Hold Note
+ var releasedHoldNoteInColumn = null; // Ta zmienna nie była używana
+ for (var colIdx in currentlyHeldNotes) {
+ if (currentlyHeldNotes.hasOwnProperty(colIdx)) {
+ var heldNote = currentlyHeldNotes[colIdx];
+ // Sprawdź, czy puszczono palec nad kolumną, w której trzymana jest nuta
+ // Ta logika może wymagać dostosowania, jeśli x,y puszczenia ma być precyzyjnie nad nutą
+ // Prostsze sprawdzenie: jeśli jakakolwiek nuta jest trzymana, oceń ją.
+ if (heldNote && heldNote.isBeingHeld) {
+ // Można by tu dodać logikę sprawdzania, czy palec został puszczony "z dala" od nuty,
+ // co mogłoby oznaczać 'holdBroken' jeszcze przed wywołaniem judgeHoldRelease.
+ // Na razie zakładamy, że puszczenie gdziekolwiek kończy trzymanie.
+ console.log("Releasing hold note in column: " + (heldNote.mapData ? heldNote.mapData.columnIndex : 'unknown'));
+ heldNote.judgeHoldRelease(); // judgeHoldRelease ustawi .judged i .alpha
+ delete currentlyHeldNotes[colIdx];
+ swipeStart = null;
+ inputLocked = true;
+ LK.setTimeout(function () {
+ inputLocked = false;
+ }, 80);
+ return;
+ }
+ }
+ }
+ // Standardowa logika Swipe (jeśli nie było puszczenia holda)
if (inputLocked || !swipeStart) {
swipeStart = null;
return;
}
@@ -3917,82 +4056,86 @@
var dx = swipeEndX - swipeStart.x;
var dy = swipeEndY - swipeStart.y;
var dist = Math.sqrt(dx * dx + dy * dy);
var potentialSwipe = dist >= MIN_SWIPE_DISTANCE;
- var swipedNoteSuccessfully = false;
if (potentialSwipe) {
var detectedDir = null;
if (Math.abs(dx) > Math.abs(dy)) {
detectedDir = dx > 0 ? 'right' : 'left';
} else {
detectedDir = dy > 0 ? 'down' : 'up';
}
var swipeBoundingBox = {
+ // Bounding box samego gestu swipe
x: Math.min(swipeStart.x, swipeEndX),
y: Math.min(swipeStart.y, swipeEndY),
width: Math.abs(dx),
height: Math.abs(dy)
};
var notesHitThisSwipe = [];
for (var i_swipe = 0; i_swipe < notes.length; i_swipe++) {
var n_swipe = notes[i_swipe];
- if (n_swipe.judged || n_swipe.noteType !== 'swipe') {
+ if (n_swipe.judged || n_swipe.noteType !== 'swipe' || n_swipe.alpha === 0) {
+ // Ignoruj już ocenione lub niewidoczne
continue;
}
+ // Czy czas swipe'a pokrywa się z oknem nuty?
var overallSwipeTimeMatchesNote = false;
if (n_swipe.targetHitTime >= swipeStart.time - hitWindowGood && n_swipe.targetHitTime <= swipeEndTime + hitWindowGood) {
overallSwipeTimeMatchesNote = true;
}
if (!overallSwipeTimeMatchesNote) {
+ // Dodatkowe sprawdzenie, jeśli nuta była w trakcie swipe'a
if (swipeStart.time >= n_swipe.targetHitTime - hitWindowGood && swipeStart.time <= n_swipe.targetHitTime + hitWindowGood || swipeEndTime >= n_swipe.targetHitTime - hitWindowGood && swipeEndTime <= n_swipe.targetHitTime + hitWindowGood) {
overallSwipeTimeMatchesNote = true;
}
}
if (!overallSwipeTimeMatchesNote) {
continue;
}
- if (n_swipe.alpha === 0) {
- continue;
- }
- var noteCurrentWidth_swipe = SWIPE_NOTE_WIDTH * n_swipe.scale.x;
- var noteCurrentHeight_swipe = SWIPE_NOTE_WIDTH * n_swipe.scale.y;
+ // Sprawdzenie kolizji bounding boxów
+ var noteCurrentWidth_swipe = n_swipe.noteAsset ? n_swipe.noteAsset.width * n_swipe.scale.x : SWIPE_NOTE_WIDTH; // Użyj rzeczywistej szerokości assetu
+ var noteCurrentHeight_swipe = n_swipe.noteAsset ? n_swipe.noteAsset.height * n_swipe.scale.y : SWIPE_NOTE_WIDTH; // Użyj rzeczywistej wysokości assetu
var noteBoundingBox_swipe = {
x: n_swipe.x - noteCurrentWidth_swipe / 2,
y: n_swipe.y - noteCurrentHeight_swipe / 2,
width: noteCurrentWidth_swipe,
height: noteCurrentHeight_swipe
};
if (rectsIntersect(swipeBoundingBox, noteBoundingBox_swipe)) {
+ // rectsIntersect musi być zdefiniowane
if (detectedDir === n_swipe.swipeDir) {
- var verticalProximity = Math.abs(n_swipe.y - n_swipe.centerY);
- var verticalTolerance = noteCurrentHeight_swipe / 1.5;
- if (verticalProximity < verticalTolerance) {
+ // Dodatkowe sprawdzenie, czy swipe był wystarczająco blisko pionowej pozycji nuty
+ // (można uprościć, jeśli rectsIntersect jest wystarczająco precyzyjne)
+ var verticalProximity = Math.abs(n_swipe.y - swipeStart.y); // lub swipeEndY
+ var verticalToleranceOnSwipe = noteCurrentHeight_swipe * 1.5; // Zwiększona tolerancja
+ if (verticalProximity < verticalToleranceOnSwipe) {
notesHitThisSwipe.push(n_swipe);
}
}
}
}
if (notesHitThisSwipe.length > 0) {
notesHitThisSwipe.sort(function (a, b) {
- var da = Math.abs(swipeEndTime - a.targetHitTime);
- var db = Math.abs(swipeEndTime - b.targetHitTime);
- return da - db;
+ // Sortuj wg bliskości czasu do końca swipe'a
+ return Math.abs(swipeEndTime - a.targetHitTime) - Math.abs(swipeEndTime - b.targetHitTime);
});
- var maxNotesToHitPerSwipe = 1;
- if (notesHitThisSwipe.length > 0 && notesHitThisSwipe[0].isWiderSwipePart) {
- maxNotesToHitPerSwipe = 2;
- }
+ var maxNotesToHitPerSwipe = notesHitThisSwipe.length > 0 && notesHitThisSwipe[0].isWiderSwipePart ? 2 : 1;
var notesActuallyHitCount = 0;
for (var k_swipe = 0; k_swipe < notesHitThisSwipe.length && notesActuallyHitCount < maxNotesToHitPerSwipe; k_swipe++) {
var noteToJudge_swipe = notesHitThisSwipe[k_swipe];
if (noteToJudge_swipe.judged) {
+ // Powtórne sprawdzenie na wszelki wypadek
continue;
}
+ // Logika dla wider swipe (jeśli istnieje)
if (notesActuallyHitCount === 1 && notesHitThisSwipe[0].isWiderSwipePart) {
- if (!noteToJudge_swipe.isWiderSwipePart || noteToJudge_swipe.mapData.widerSwipePairCenterX !== notesHitThisSwipe[0].mapData.widerSwipePairCenterX || noteToJudge_swipe.mapData.partOfWiderSwipe === notesHitThisSwipe[0].mapData.partOfWiderSwipe) {
+ if (!noteToJudge_swipe.isWiderSwipePart || noteToJudge_swipe.mapData && notesHitThisSwipe[0].mapData && noteToJudge_swipe.mapData.widerSwipePairCenterX !== notesHitThisSwipe[0].mapData.widerSwipePairCenterX || noteToJudge_swipe.mapData && notesHitThisSwipe[0].mapData && noteToJudge_swipe.mapData.partOfWiderSwipe === notesHitThisSwipe[0].mapData.partOfWiderSwipe) {
continue;
}
}
+ // Dla swipe, 'result' często jest binarny (trafiony/nietrafiony) lub uproszczony.
+ // Użyjemy getHitAccuracy, ale można to uprościć do 'perfect' jeśli kierunek się zgadza w oknie.
var result_swipe = noteToJudge_swipe.getHitAccuracy();
noteToJudge_swipe.judged = true;
noteToJudge_swipe.showHitFeedback(result_swipe);
if (result_swipe !== 'miss') {
@@ -4005,14 +4148,12 @@
bossCurrentHP = Math.max(0, bossCurrentHP - 1);
}
updateBossHpDisplay();
}
- } else {
- if (!isTutorialMode) {
- resetCombo();
- }
+ } else if (!isTutorialMode && !isShieldActive) {
+ resetCombo();
}
- swipedNoteSuccessfully = true;
+ noteToJudge_swipe.alpha = 0; // ZMIANA: Ukryj nutę swipe po ocenie
notesActuallyHitCount++;
}
}
}