User prompt
vampire touch kartı nın gelme olasılığı her yeni kart çekişilinde %18 olsun
User prompt
Please fix the bug: 'playerDeck is undefined' in or related to this line: 'playerDeck.push(52);' Line Number: 466
User prompt
oyuna yeni bir kart ekle bu kart diğerlerinden farklı gözüksün joker jartı olucak bu kartı oynayınca karşı tarfın hpsinden 20 can çalıp kendi hp sine eklesin kartın ismi vampire touch olsun
User prompt
end turn tuşuna basınca karşı taraf sıra onda olmasına rağmen kartını oynamıyor sıra kendisinde olduğunda kartını oynıycak şekilde kodu düzelt
User prompt
oyuncular kartlarını sırayla oynasınlar
User prompt
end turn tuşuna basınca karşı taraf sırası geldince kartını oynasın
User prompt
karşı tarafın oynanmış hiç bir kartı yok ise oynanan kart karşı tarafın destesine saldırabilir hasarının 2 katını verir
User prompt
hasar verme mekaniğini animasyon olark ekle güçü yüksek olan kart gücü düşük olan karta çarptığı görünsün hasar alan kartın üzerinde kırmızı x işareti çıksın,oyun sırasında hasar verilicek kartı oyuncular kendileri seçsin bunada kartın üzerine tıklayınca yönlendirilebilen ok çıksın oku hasar verilicek düşman kartına yönlendirince saldırsın ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
oynanan kartın karşısında düşman kartı yok ise düşmana destesine direk saldırır kendi atak gücünün 2 katı hasar veriri hp den düşer
User prompt
canavarlar birbirlerini öldürünce hp aralarındaki atak gücü farkı hp den düşsün
User prompt
oyunu oynanabilir 5 karta çıkar üç karttan
User prompt
eşit güçteki kartlar birbirini yok etsin
User prompt
atk ve def ateş topusun yanına doğrı sağ tarafa kaydır
User prompt
atk ve df yazılarını rakamlarının yanıya yaklaştır yıldızları kapatmasın
User prompt
yıldızları sol alt köşeye kaydır
User prompt
yıldız ve yanındaki rakamın etrafındaki kırmızı çerçeveyi kaldır
User prompt
yıldızların etrafındaki kırmızı gölgeyi kaldır
User prompt
yıldızlar karttların dıla çıkmasın yıldızların yanındaki rakamlar okunmuyo daha güzel bir görsellle okunabilir yap
User prompt
yıldızları biraz küçült etrafına kırmızı gölge ekle
User prompt
yıldızları daha görünür yap
User prompt
kartlar oynandıktan sonra oyuncular hangi karta saldırıcaklarını kendi karar versin ve saldırsın buna uygun animasyon ve görsel ekle ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
defansı ve atakı yüksek olan kart kendinden zayıf olan kartı yok etsin,kartların güçleri eşit ise birbirlerini yok etsinler hp düşmeden
User prompt
yıldız sistemini dengeli bir şekilde düzenle güçlü kartların yıldızı daha çok olsun daha az güçlü kartın yıldızı az olsun
User prompt
kartı oynayan oyuncu istediği karta saldırsın bu saldırma mekaniği bir okla hangi karta saldırılcak göstersin ok saldırılcak kartı seçince güçlü kart zayıf karta çarparak parçalanma ekfekti ile yok etsin ↪💡 Consider importing and using the following plugins: @upit/tween.v1
User prompt
oyunun arka pilanın çalıcak seçtiğim müziği ekle
/**** * Plugins ****/ var tween = LK.import("@upit/tween.v1"); /**** * Classes ****/ // Card class: visual and logical representation of a monster card var Card = Container.expand(function () { var self = Container.call(this); // Card properties self.cardId = null; self.cardData = null; self.isInHand = false; self.isPlayable = false; self.isSelected = false; self.owner = null; // "player" or "opponent" // Card visuals var cardWidth = 260; var cardHeight = 380; // Card background (use a generic box for all cards) var cardBg = self.attachAsset('monsters', { width: cardWidth, height: cardHeight, color: 0xffffff, shape: 'box', anchorX: 0.5, anchorY: 0.5 }); // Baroque frame overlay (always on top of cardBg, but below all text/icons) var baroqueFrame = self.attachAsset('baroque_frame', { anchorX: 0.5, anchorY: 0.5, width: 300, height: 420, x: 0, y: 0 }); self.addChild(baroqueFrame); baroqueFrame.zIndex = 10; // ensure it's above cardBg, but below text/icons // Monster illustration: (removed for all cards, no monsterArt shown) var monsterArt = null; // Card name var nameTxt = new Text2('', { size: 48, fill: 0x222222, font: "Impact,'Arial Black',Tahoma", // bold font for readability stroke: "#fff", strokeThickness: 6 }); nameTxt.anchor.set(0.5, 0); // Move name higher (from -0.45 to -0.54 of cardHeight) nameTxt.y = -cardHeight * 0.54; self.addChild(nameTxt); // Star cost display - improved: always inside card, visually grouped, with a gold circle background and better contrast // Gold circle background for star cost (moved to bottom left) var starBg = LK.getAsset('monsters', { width: 70, height: 70, color: 0xffe066, shape: 'ellipse', anchorX: 0.5, anchorY: 0.5 }); // Move to bottom left, with margin inside card starBg.x = -cardWidth * 0.5 + 50; starBg.y = cardHeight * 0.5 - 50; self.addChild(starBg); // Star icon, centered in circle, with subtle shadow var starIcon = new Text2("★", { size: 38, fill: 0xffd700, font: "Impact,'Arial Black',Tahoma", stroke: "#fff", strokeThickness: 6 }); starIcon.anchor.set(0.5, 0.5); starIcon.x = starBg.x - 14; starIcon.y = starBg.y + 2; self.addChild(starIcon); // Star number, large, bold, high-contrast, with dark outline for readability (no red border) var starTxt = new Text2('', { size: 40, fill: 0x222222, font: "Impact,'Arial Black',Tahoma", stroke: "#fff", strokeThickness: 8 }); starTxt.anchor.set(0.5, 0.5); starTxt.x = starBg.x + 16; starTxt.y = starBg.y + 2; self.addChild(starTxt); // Burn button (shows only if burnable) var burnBtn = new Text2("🔥", { size: 48, fill: 0xff6600 }); burnBtn.anchor.set(0.5, 0.5); burnBtn.x = cardWidth * 0.36; burnBtn.y = cardHeight * 0.36; burnBtn.visible = false; self.addChild(burnBtn); // Burn button logic burnBtn.down = function (x, y, obj) { if (self.isInHand && self.owner === "player") { burnCard(self); } }; // Attack/Defense // ATK label (ateş topu = flame icon, so we use a flame emoji for visual cue) var atkFlame = new Text2('🔥', { size: 44, fill: 0xd83318, font: "Impact,'Arial Black',Tahoma", stroke: "#fff", strokeThickness: 6 }); atkFlame.anchor.set(1, 0.5); // Place flame icon left of ATK number, right side of card, above DEF atkFlame.x = cardWidth * 0.18; atkFlame.y = cardHeight * 0.32 - 38; self.addChild(atkFlame); var atkTxt = new Text2('', { size: 54, fill: 0xd83318, font: "Impact,'Arial Black',Tahoma", stroke: "#fff", strokeThickness: 6 }); atkTxt.anchor.set(0, 0.5); // Place number just right of flame icon atkTxt.x = atkFlame.x + 32; atkTxt.y = atkFlame.y; self.addChild(atkTxt); // DEF label (shield icon for defense) var defShield = new Text2('🛡️', { size: 38, fill: 0x1877f2, font: "Impact,'Arial Black',Tahoma", stroke: "#fff", strokeThickness: 6 }); defShield.anchor.set(1, 0.5); // Place shield icon left of DEF number, right side of card, below ATK defShield.x = cardWidth * 0.18; defShield.y = cardHeight * 0.32 + 38; self.addChild(defShield); var defTxt = new Text2('', { size: 54, fill: 0x1877f2, font: "Impact,'Arial Black',Tahoma", stroke: "#fff", strokeThickness: 6 }); defTxt.anchor.set(0, 0.5); // Place number just right of shield icon defTxt.x = defShield.x + 32; defTxt.y = defShield.y; self.addChild(defTxt); // (Removed flameIcon and shieldIcon for ATK/DEF) // Element var elementTxt = new Text2('', { size: 28, fill: 0x666666 }); elementTxt.anchor.set(0.5, 0); elementTxt.y = -cardHeight * 0.32; self.addChild(elementTxt); // Ability var abilityTxt = new Text2('', { size: 24, fill: 0x444444 }); abilityTxt.anchor.set(0.5, 0); abilityTxt.y = cardHeight * 0.12; self.addChild(abilityTxt); // Set card data self.setCard = function (cardId, owner) { self.cardId = cardId; self.cardData = CARD_DATA[cardId]; self.owner = owner; // Always use the starCost from cardData (already assigned based on stats) self.starCost = self.cardData.starCost; // Set visuals // Assign unique color for each card if (self.cardData.isJoker) { // Special visuals for Vampire Touch cardBg.color = 0x8e24aa; // Deep purple baroqueFrame.tint = 0xffe066; // Gold frame nameTxt.setText("🦇 " + self.cardData.name + " 🦇"); nameTxt.fill = 0xff1744; // Red name abilityTxt.setText(self.cardData.ability); abilityTxt.fill = 0xff1744; // Add a bat emoji to element elementTxt.setText("🦇 " + self.cardData.element); // Add a subtle glow effect (simulate by scaling up slightly) self.scaleX = self.scaleY = 1.08; } else { cardBg.color = self.cardData.color || 0xffffff; baroqueFrame.tint = 0xffffff; nameTxt.setText(self.cardData.name); nameTxt.fill = 0x222222; abilityTxt.setText(self.cardData.ability); abilityTxt.fill = 0x444444; elementTxt.setText(self.cardData.element); self.scaleX = self.scaleY = 1; } // Show ATK and DEF values separately, icons are already present atkTxt.setText(self.cardData.attack + ""); defTxt.setText(self.cardData.defense + ""); // Show star cost (number only, star icon is always visible and grouped) starTxt.setText(self.starCost + ""); // For MVP, no evolution/fusion visuals }; // Highlight if playable/selected self.setPlayable = function (playable) { self.isPlayable = playable; // Only playable if player has enough stars var canPlay = playable; if (self.owner === "player" && typeof self.starCost === "number") { canPlay = playable && playerStars >= self.starCost; } cardBg.color = canPlay ? 0xffe066 : 0xffffff; // Show burn button if in hand and owned by player burnBtn.visible = self.isInHand && self.owner === "player"; }; self.setSelected = function (selected) { self.isSelected = selected; cardBg.color = selected ? 0x66ccff : self.isPlayable ? 0xffe066 : 0xffffff; }; // Animate card (e.g. on play) self.animatePlay = function (_onFinish) { // Save original y for jump landing var originalY = self.y; // Jump up tween(self, { y: originalY - 120, scaleX: 1.15, scaleY: 1.15 }, { duration: 180, easing: tween.cubicOut, onFinish: function onFinish() { // Fall down and squash tween(self, { y: originalY, scaleX: 1.08, scaleY: 0.95 }, { duration: 120, easing: tween.cubicIn, onFinish: function onFinish() { // Restore scale tween(self, { scaleX: 1, scaleY: 1 }, { duration: 100, easing: tween.linear, onFinish: _onFinish }); } }); } }); }; // For MVP, no drag/drop, just tap to play self.down = function (x, y, obj) { if (self.isPlayable && self.owner === "player") { // Click animation: quick scale up and back tween(self, { scaleX: 1.18, scaleY: 1.18 }, { duration: 80, easing: tween.cubicOut, onFinish: function onFinish() { tween(self, { scaleX: 1, scaleY: 1 }, { duration: 80, easing: tween.cubicIn, onFinish: function onFinish() { playCard(self); } }); } }); } }; return self; }); /**** * Initialize Game ****/ var game = new LK.Game({ backgroundColor: 0x22222a }); /**** * Game Code ****/ // --- Mana/Star System State (Magic-style) --- // Each player has a "maximum stars" (like max mana) and "current stars" (like available mana this turn) var playerMaxStars = 0; var playerStars = 0; var opponentMaxStars = 0; var opponentStars = 0; // Tween plugin for card animations (e.g. draw, play, evolve) // Card Data: 52 unique monsters with stats, element, and ability // For MVP, we'll define a small sample and generate the rest as placeholders // Pyro Drake // Aqua Serpent // Terra Golem // Zephyr Sprite var CARD_DATA = [{ id: 0, name: "Pyro Drake", element: "Fire", attack: 7, defense: 4, ability: "Scorch: Deal 2 extra damage on summon.", color: 0xff5733, starCost: 3 // atk+def = 11 }, { id: 1, name: "Aqua Serpent", element: "Water", attack: 5, defense: 6, ability: "Tidecall: Heal 2 defense on play.", color: 0x3399ff, starCost: 3 // atk+def = 11 }, { id: 2, name: "Terra Golem", element: "Earth", attack: 4, defense: 8, ability: "Fortify: Gain +2 defense if not attacked this turn.", color: 0x7cfc00, starCost: 4 // atk+def = 12 }, { id: 3, name: "Zephyr Sprite", element: "Air", attack: 6, defense: 3, ability: "Gust: Can attack twice if opponent has no Air monsters.", color: 0xfafad2, starCost: 2 // atk+def = 9 }, { id: 4, name: "Shadow Wraith", element: "Dark", attack: 8, defense: 2, ability: "Ambush: Ignores defense on first attack.", color: 0x222244, starCost: 3 // atk+def = 10 }, // --- Vampire Touch (Joker) Card --- { id: 52, name: "Vampire Touch", element: "Dark", attack: 5, defense: 5, ability: "Joker: Steal 20 HP from opponent and add to your HP.", color: 0x8e24aa, // Deep purple for unique look starCost: 4, isJoker: true // custom property for visuals }]; // Generate 52 visually distinct colors using HSL to RGB conversion function hslToHex(h, s, l) { // h: 0-360, s: 0-1, l: 0-1 var c = (1 - Math.abs(2 * l - 1)) * s; var x = c * (1 - Math.abs(h / 60 % 2 - 1)); var m = l - c / 2; var r1, g1, b1; if (h < 60) { r1 = c; g1 = x; b1 = 0; } else if (h < 120) { r1 = x; g1 = c; b1 = 0; } else if (h < 180) { r1 = 0; g1 = c; b1 = x; } else if (h < 240) { r1 = 0; g1 = x; b1 = c; } else if (h < 300) { r1 = x; g1 = 0; b1 = c; } else { r1 = c; g1 = 0; b1 = x; } var r = Math.round((r1 + m) * 255); var g = Math.round((g1 + m) * 255); var b = Math.round((b1 + m) * 255); return (r << 16) + (g << 8) + b; } // Precompute 52 unique colors var CARD_COLORS = []; for (var ci = 0; ci < 52; ci++) { var hue = ci * 360 / 52 % 360; var color = hslToHex(hue, 0.65, 0.60); CARD_COLORS.push(color); } // 52 unique monster names, all different and fantasy-themed var MONSTER_NAMES = ["Pyro Drake", "Aqua Serpent", "Terra Golem", "Zephyr Sprite", "Shadow Wraith", "Solar Griffin", "Frost Lynx", "Thunder Roc", "Venom Hydra", "Crystal Beetle", "Blaze Minotaur", "Mist Kitsune", "Iron Basilisk", "Storm Djinn", "Nightmare Mare", "Sunflare Lion", "Glacier Yeti", "Volt Mantis", "Toxic Moth", "Quartz Turtle", "Ember Jackal", "Rain Nymph", "Mud Troll", "Gale Harpy", "Phantom Fox", "Radiant Stag", "Snow Owl", "Sparkle Hare", "Swamp Croc", "Gemstone Ant", "Wildfire Wolf", "Bubble Slime", "Root Dryad", "Wind Imp", "Specter Bat", "Corona Tiger", "Polar Bear", "Plasma Jelly", "Bog Lizard", "Amber Spider", "Char Salamander", "Cascade Crab", "Boulder Ram", "Cyclone Hawk", "Shade Panther", "Star Unicorn", "Ice Ferret", "Magneton", "Fungal Gnome", "Opal Cobra", "Scorch Falcon", "Abyssal Eel", "Vampire Touch"]; // Fill up to 52 cards with unique monster names and unique color for (var i = CARD_DATA.length; i < 52; i++) { var attack = 3 + i % 7; var defense = 3 + i * 2 % 7; // Star cost: 1 for weak (atk+def <= 7), 2 for 8-10, 3 for 11-13, 4 for 14-15, 5 for 16+ var total = attack + defense; var starCost = 1; if (total >= 16) starCost = 5;else if (total >= 14) starCost = 4;else if (total >= 11) starCost = 3;else if (total >= 8) starCost = 2; CARD_DATA.push({ id: i, name: MONSTER_NAMES[i], element: ["Fire", "Water", "Earth", "Air", "Dark", "Light"][i % 6], attack: attack, defense: defense, ability: "No special ability.", color: CARD_COLORS[i], starCost: starCost }); } var playerDeck = []; var opponentDeck = []; // Add Vampire Touch (id: 52) to both decks // (If you want only one per deck, add here) playerDeck.push(52); opponentDeck.push(52); var playerHand = []; var opponentHand = []; var playerField = []; var opponentField = []; var playerGrave = []; var opponentGrave = []; var playerHP = 100; var opponentHP = 100; var turn = "player"; // "player" or "opponent" var phase = "draw"; // "draw", "main", "battle", "end" var selectedCard = null; var handY = 2732 - 420; var fieldY = 2732 - 900; var oppHandY = 420; var oppFieldY = 900; var handCardSpacing = 320; var fieldCardSpacing = 400; var maxHand = 5; var maxField = 5; var gameActive = true; // --- GUI Elements --- var playerHpTxt = new Text2("HP: 20", { size: 60, fill: 0xFF4444 }); playerHpTxt.anchor.set(0, 0.5); LK.gui.left.addChild(playerHpTxt); var playerStarTxt = new Text2("★: 1", { size: 60, fill: 0xffd700 }); playerStarTxt.anchor.set(0, 0.5); playerStarTxt.y = 70; LK.gui.left.addChild(playerStarTxt); var opponentHpTxt = new Text2("HP: 20", { size: 60, fill: 0x44AAFF }); opponentHpTxt.anchor.set(1, 0.5); LK.gui.right.addChild(opponentHpTxt); var opponentStarTxt = new Text2("★: 1", { size: 60, fill: 0xffd700 }); opponentStarTxt.anchor.set(1, 0.5); opponentStarTxt.y = 70; LK.gui.right.addChild(opponentStarTxt); var turnTxt = new Text2("Your Turn", { size: 60, fill: "#fff" }); turnTxt.anchor.set(0.5, 0); LK.gui.top.addChild(turnTxt); // --- Utility Functions --- function shuffleDeck(deck) { for (var i = deck.length - 1; i > 0; i--) { var j = Math.floor(Math.random() * (i + 1)); var temp = deck[i]; deck[i] = deck[j]; deck[j] = temp; } } function drawCard(deck, hand, owner) { if (deck.length === 0 || hand.length >= maxHand) return null; // --- Vampire Touch 18% draw chance logic --- var vampireTouchId = 52; var hasVampireTouch = deck.indexOf(vampireTouchId) !== -1; var drawVampireTouch = false; if (hasVampireTouch && Math.random() < 0.18) { // Remove Vampire Touch from deck and draw it var idx = deck.indexOf(vampireTouchId); if (idx !== -1) { deck.splice(idx, 1); drawVampireTouch = true; } } var cardId; if (drawVampireTouch) { cardId = vampireTouchId; } else { cardId = deck.pop(); } var card = new Card(); card.setCard(cardId, owner); card.isInHand = true; hand.push(card); return card; } function updateHandPositions() { // Player hand for (var i = 0; i < playerHand.length; i++) { var card = playerHand[i]; card.x = 2048 / 2 + (i - (playerHand.length - 1) / 2) * handCardSpacing; card.y = handY; card.scaleX = card.scaleY = 1; // Only playable if enough stars card.setPlayable(turn === "player" && phase === "main" && playerField.length < maxField); card.setSelected(selectedCard === card); } // Opponent hand (hidden) for (var i = 0; i < opponentHand.length; i++) { var card = opponentHand[i]; card.x = 2048 / 2 + (i - (opponentHand.length - 1) / 2) * handCardSpacing; card.y = oppHandY; card.scaleX = card.scaleY = 1; card.setPlayable(false); card.setSelected(false); } } function updateFieldPositions() { // Player field for (var i = 0; i < playerField.length; i++) { var card = playerField[i]; card.x = 2048 / 2 + (i - (playerField.length - 1) / 2) * fieldCardSpacing; card.y = fieldY; card.scaleX = card.scaleY = 1.1; card.setPlayable(false); card.setSelected(false); } // Opponent field for (var i = 0; i < opponentField.length; i++) { var card = opponentField[i]; card.x = 2048 / 2 + (i - (opponentField.length - 1) / 2) * fieldCardSpacing; card.y = oppFieldY + 400; card.scaleX = card.scaleY = 1.1; card.setPlayable(false); card.setSelected(false); } } function updateHpText() { playerHpTxt.setText("HP: " + playerHP); opponentHpTxt.setText("HP: " + opponentHP); // Show current/max stars, Magic-style playerStarTxt.setText("★: " + playerStars + "/" + playerMaxStars); opponentStarTxt.setText("★: " + opponentStars + "/" + opponentMaxStars); } function updateTurnText() { turnTxt.setText(turn === "player" ? "Your Turn" : "Opponent Turn"); } // --- Game Setup --- function setupGame() { // Reset state playerDeck = []; opponentDeck = []; playerHand = []; opponentHand = []; playerField = []; opponentField = []; playerGrave = []; opponentGrave = []; playerHP = 100; opponentHP = 100; // Magic-style: start with 0 max stars, will increment at start of turn playerMaxStars = 0; playerStars = 0; opponentMaxStars = 0; opponentStars = 0; turn = "player"; phase = "draw"; selectedCard = null; gameActive = true; // Remove all children from game for (var i = game.children.length - 1; i >= 0; i--) { game.children[i].destroy(); } // Build decks (for MVP, both get all 52 cards, shuffled) for (var i = 0; i < 52; i++) { playerDeck.push(i); opponentDeck.push(i); } shuffleDeck(playerDeck); shuffleDeck(opponentDeck); // Draw starting hands (5 cards) for (var i = 0; i < maxHand; i++) { var card = drawCard(playerDeck, playerHand, "player"); if (card) game.addChild(card); var oppCard = drawCard(opponentDeck, opponentHand, "opponent"); if (oppCard) game.addChild(oppCard); } // Add all cards in hand to the game scene for interaction for (var i = 0; i < playerHand.length; i++) { if (!game.children.includes(playerHand[i])) { game.addChild(playerHand[i]); } } for (var i = 0; i < opponentHand.length; i++) { if (!game.children.includes(opponentHand[i])) { game.addChild(opponentHand[i]); } } updateHandPositions(); updateFieldPositions(); updateHpText(); updateTurnText(); } setupGame(); // Play background music (loops by default) LK.playMusic('monsters'); // --- Card Play Logic --- function burnCard(card) { if (!gameActive) return; if (!card.isInHand || card.owner !== "player") return; // Remove from hand var idx = playerHand.indexOf(card); if (idx !== -1) playerHand.splice(idx, 1); // Add to grave playerGrave.push(card); card.isInHand = false; // Animate burn (fade out and destroy) tween(card, { alpha: 0, scaleX: 1.3, scaleY: 1.3 }, { duration: 350, easing: tween.cubicIn, onFinish: function onFinish() { card.destroy(); } }); // Gain 1 max star (like Magic: play a land) // Only increase max, refill current to max at next turn playerMaxStars += 1; updateHpText(); updateHandPositions(); } function playCard(card) { if (!gameActive) return; if (turn !== "player" || phase !== "main") return; if (!card.isInHand || playerField.length >= maxField) return; if (typeof card.starCost === "number" && playerStars < card.starCost) return; // Not enough stars // Remove from hand var idx = playerHand.indexOf(card); if (idx !== -1) playerHand.splice(idx, 1); // Deduct stars from current (not max) if (typeof card.starCost === "number") { playerStars -= card.starCost; if (playerStars < 0) playerStars = 0; updateHpText(); } // Add to field card.isInHand = false; playerField.push(card); // Animate play card.animatePlay(function () { updateHandPositions(); updateFieldPositions(); // Ability triggers if (card.cardData.ability.indexOf("Scorch") !== -1) { // Pyro Drake: deal 2 to opponent HP opponentHP -= 2; LK.effects.flashObject(opponentHpTxt, 0xff0000, 500); updateHpText(); } if (card.cardData.ability.indexOf("Tidecall") !== -1) { // Aqua Serpent: heal 2 defense (for MVP, just flash) LK.effects.flashObject(card, 0x3399ff, 500); } // Vampire Touch: Steal 20 HP from opponent, add to player if (card.cardData.isJoker) { var steal = Math.min(20, opponentHP); opponentHP -= steal; playerHP += steal; // Animate: flash both HP, show red X on opponent, green + on player LK.effects.flashObject(opponentHpTxt, 0xff1744, 600); LK.effects.flashObject(playerHpTxt, 0x44ff44, 600); // Red X on opponent var xMarkHp = new Text2("✖", { size: 120, fill: 0xff1744, font: "Impact,'Arial Black',Tahoma", stroke: "#fff", strokeThickness: 10 }); xMarkHp.anchor.set(0.5, 0.5); xMarkHp.x = 0; xMarkHp.y = 0; opponentHpTxt.addChild(xMarkHp); xMarkHp.alpha = 0.9; tween(xMarkHp, { alpha: 0, scaleX: 1.7, scaleY: 1.7 }, { duration: 400, onFinish: function onFinish() { if (xMarkHp && xMarkHp.parent) xMarkHp.parent.removeChild(xMarkHp); } }); // Green + on player var plusMark = new Text2("+20", { size: 90, fill: 0x44ff44, font: "Impact,'Arial Black',Tahoma", stroke: "#fff", strokeThickness: 8 }); plusMark.anchor.set(0.5, 0.5); plusMark.x = 0; plusMark.y = 0; playerHpTxt.addChild(plusMark); plusMark.alpha = 0.9; tween(plusMark, { alpha: 0, y: -60 }, { duration: 600, onFinish: function onFinish() { if (plusMark && plusMark.parent) plusMark.parent.removeChild(plusMark); } }); updateHpText(); } // End main phase if field is full if (playerField.length >= maxField) { phase = "battle"; selectedCard = null; updateHandPositions(); updateFieldPositions(); } }); } // --- Battle Phase Logic --- // --- Arrow Attack Selection State --- var attackArrow = null; // Container for arrow var attackFromCard = null; // Card being used to attack var attackToCard = null; // Card being targeted // Helper: create an arrow from (x1, y1) to (x2, y2) function createArrow(x1, y1, x2, y2) { var arrow = new Container(); // Use a long, thin box for the shaft var dx = x2 - x1; var dy = y2 - y1; var len = Math.sqrt(dx * dx + dy * dy); var angle = Math.atan2(dy, dx); var shaft = LK.getAsset('monsters', { width: len - 40, height: 18, color: 0x44d17a, shape: 'box', anchorX: 0, anchorY: 0.5 }); shaft.x = 0; shaft.y = 0; shaft.rotation = 0; arrow.addChild(shaft); // Arrowhead (triangle, use a box as a stub) var head = LK.getAsset('monsters', { width: 40, height: 40, color: 0x44d17a, shape: 'box', anchorX: 0, anchorY: 0.5 }); head.x = len - 40; head.y = 0; head.rotation = 0.8; arrow.addChild(head); // Position and rotate arrow.x = x1; arrow.y = y1; arrow.rotation = angle; arrow.zIndex = 9999; return arrow; } // Helper: destroy arrow function destroyArrow() { if (attackArrow && attackArrow.parent) { attackArrow.parent.removeChild(attackArrow); } attackArrow = null; attackFromCard = null; attackToCard = null; } // --- Player Battle Phase: Now triggers attack selection --- function playerBattlePhase() { // If no cards to attack with, skip if (playerField.length === 0) { phase = "end"; nextPhase(); return; } // If opponent has no field cards, allow direct attack to HP for each player card if (opponentField.length === 0 && playerField.length > 0) { // For each card, animate attack to HP and deal double attack damage var attacksRemaining = playerField.length; for (var i = 0; i < playerField.length; i++) { (function (attacker) { // Animate attacker to HP var origX = attacker.x; var origY = attacker.y; var hpX = opponentHpTxt.parent.x + opponentHpTxt.x; var hpY = opponentHpTxt.parent.y + opponentHpTxt.y; tween(attacker, { x: hpX, y: hpY }, { duration: 180, easing: tween.cubicIn, onFinish: function onFinish() { // Impact: flash HP and show red X on HP LK.effects.flashObject(opponentHpTxt, 0xff0000, 500); var xMarkHp = new Text2("✖", { size: 120, fill: 0xff2222, font: "Impact,'Arial Black',Tahoma", stroke: "#fff", strokeThickness: 10 }); xMarkHp.anchor.set(0.5, 0.5); xMarkHp.x = 0; xMarkHp.y = 0; opponentHpTxt.addChild(xMarkHp); xMarkHp.alpha = 0.9; tween(xMarkHp, { alpha: 0, scaleX: 1.7, scaleY: 1.7 }, { duration: 400, onFinish: function onFinish() { if (xMarkHp && xMarkHp.parent) xMarkHp.parent.removeChild(xMarkHp); } }); // Damage: deal double attack if no defender opponentHP -= attacker.cardData.attack * 2; updateHpText(); checkGameEnd(); // Move attacker back tween(attacker, { x: origX, y: origY }, { duration: 120, onFinish: function onFinish() { attacksRemaining--; // After all attacks, advance phase if (attacksRemaining === 0) { phase = "end"; nextPhase(); } } }); } }); })(playerField[i]); } // Prevent further attack selection return; } // Let player select attacker phase = "attack_select"; // Highlight player's field cards as selectable for (var i = 0; i < playerField.length; i++) { var card = playerField[i]; card.setPlayable(true); card.setSelected(false); // Add down handler for attack selection card.down = function (x, y, obj) { if (phase !== "attack_select" || !gameActive) return; attackFromCard = this; // Highlight attacker for (var j = 0; j < playerField.length; j++) { playerField[j].setSelected(playerField[j] === attackFromCard); } // Show arrow following finger/mouse if (attackArrow && attackArrow.parent) attackArrow.parent.removeChild(attackArrow); attackArrow = createArrow(attackFromCard.x, attackFromCard.y, attackFromCard.x, attackFromCard.y); game.addChild(attackArrow); // Enable dragging arrow to select target game.move = function (mx, my, obj) { if (attackArrow && attackFromCard) { // Arrow points from attacker to current pointer var dx = mx - attackFromCard.x; var dy = my - attackFromCard.y; var len = Math.sqrt(dx * dx + dy * dy); // Update shaft and head if (attackArrow.children.length >= 2) { var shaft = attackArrow.children[0]; var head = attackArrow.children[1]; shaft.width = Math.max(40, len - 40); head.x = Math.max(0, len - 40); } attackArrow.rotation = Math.atan2(dy, dx); } }; // On up, check if released over a valid target game.up = function (ux, uy, obj) { if (!attackFromCard || !attackArrow) return; // Check if released over an opponent card var foundTarget = null; for (var k = 0; k < opponentField.length; k++) { var oppCard = opponentField[k]; if (oppCard.containsPoint && oppCard.containsPoint(ux, uy)) { foundTarget = oppCard; break; } } if (foundTarget) { // Animate arrow to target var toCard = foundTarget; attackToCard = toCard; tween(attackArrow, { x: attackFromCard.x, y: attackFromCard.y, rotation: Math.atan2(toCard.y - attackFromCard.y, toCard.x - attackFromCard.x) }, { duration: 120, onFinish: function onFinish() { tween(attackArrow, { alpha: 0, scaleX: 0.2, scaleY: 0.2 }, { duration: 120, onFinish: function onFinish() { destroyArrow(); } }); } }); // Animate attacker to defender (impact) var origX = attackFromCard.x, origY = attackFromCard.y; tween(attackFromCard, { x: toCard.x, y: toCard.y }, { duration: 180, easing: tween.cubicIn, onFinish: function onFinish() { // Impact: shake, then show red X, then destroy defender with "shatter" effect tween(toCard, { scaleX: 1.3, scaleY: 0.7, rotation: 0.2 }, { duration: 90, onFinish: function onFinish() { // Show red X on defender var xMark = new Text2("✖", { size: 120, fill: 0xff2222, font: "Impact,'Arial Black',Tahoma", stroke: "#fff", strokeThickness: 10 }); xMark.anchor.set(0.5, 0.5); xMark.x = 0; xMark.y = 0; toCard.addChild(xMark); xMark.alpha = 0.9; // Animate X: fade out and scale up tween(xMark, { alpha: 0, scaleX: 1.7, scaleY: 1.7 }, { duration: 400, onFinish: function onFinish() { if (xMark && xMark.parent) xMark.parent.removeChild(xMark); } }); // Continue with shatter effect tween(toCard, { alpha: 0, scaleX: 1.7, scaleY: 0.2, rotation: -0.7 }, { duration: 180, onFinish: function onFinish() { var attacker = attackFromCard; var defender = toCard; var attackerPower = attacker.cardData.attack + attacker.cardData.defense; var defenderPower = defender.cardData.attack + defender.cardData.defense; var idxDef = opponentField.indexOf(defender); var idxAtk = playerField.indexOf(attacker); // Determine outcome: stronger destroys weaker, equal destroys both, HP loss = difference if (attackerPower > defenderPower) { // Attacker wins, destroy defender only if (idxDef !== -1) opponentField.splice(idxDef, 1); defender.destroy(); // HP loss: opponent loses (attackerPower - defenderPower) var hpLoss = attackerPower - defenderPower; opponentHP -= hpLoss; LK.effects.flashObject(opponentHpTxt, 0xff0000, 500); } else if (attackerPower < defenderPower) { // Defender wins, show red X on attacker, then destroy attacker only var xMarkAtk = new Text2("✖", { size: 120, fill: 0xff2222, font: "Impact,'Arial Black',Tahoma", stroke: "#fff", strokeThickness: 10 }); xMarkAtk.anchor.set(0.5, 0.5); xMarkAtk.x = 0; xMarkAtk.y = 0; attacker.addChild(xMarkAtk); xMarkAtk.alpha = 0.9; tween(xMarkAtk, { alpha: 0, scaleX: 1.7, scaleY: 1.7 }, { duration: 400, onFinish: function onFinish() { if (xMarkAtk && xMarkAtk.parent) xMarkAtk.parent.removeChild(xMarkAtk); } }); if (idxAtk !== -1) playerField.splice(idxAtk, 1); attacker.destroy(); // HP loss: player loses (defenderPower - attackerPower) var hpLoss = defenderPower - attackerPower; playerHP -= hpLoss; LK.effects.flashObject(playerHpTxt, 0xff0000, 500); } else { // Equal power, show red X on both, then destroy both var xMarkDef = new Text2("✖", { size: 120, fill: 0xff2222, font: "Impact,'Arial Black',Tahoma", stroke: "#fff", strokeThickness: 10 }); xMarkDef.anchor.set(0.5, 0.5); xMarkDef.x = 0; xMarkDef.y = 0; defender.addChild(xMarkDef); xMarkDef.alpha = 0.9; tween(xMarkDef, { alpha: 0, scaleX: 1.7, scaleY: 1.7 }, { duration: 400, onFinish: function onFinish() { if (xMarkDef && xMarkDef.parent) xMarkDef.parent.removeChild(xMarkDef); } }); var xMarkAtk = new Text2("✖", { size: 120, fill: 0xff2222, font: "Impact,'Arial Black',Tahoma", stroke: "#fff", strokeThickness: 10 }); xMarkAtk.anchor.set(0.5, 0.5); xMarkAtk.x = 0; xMarkAtk.y = 0; attacker.addChild(xMarkAtk); xMarkAtk.alpha = 0.9; tween(xMarkAtk, { alpha: 0, scaleX: 1.7, scaleY: 1.7 }, { duration: 400, onFinish: function onFinish() { if (xMarkAtk && xMarkAtk.parent) xMarkAtk.parent.removeChild(xMarkAtk); } }); if (idxDef !== -1) opponentField.splice(idxDef, 1); if (idxAtk !== -1) playerField.splice(idxAtk, 1); defender.destroy(); attacker.destroy(); // HP loss: none for equal power } updateHpText(); checkGameEnd(); // Move attacker back if still alive if (playerField.indexOf(attacker) !== -1) { tween(attacker, { x: origX, y: origY }, { duration: 120, onFinish: function onFinish() { // End attack phase after one attack for MVP phase = "end"; nextPhase(); } }); } else { // End attack phase after one attack for MVP phase = "end"; nextPhase(); } } }); } }); } }); } else { // Not released over a card: direct attack to HP var hpX = opponentHpTxt.parent.x + opponentHpTxt.x; var hpY = opponentHpTxt.parent.y + opponentHpTxt.y; tween(attackArrow, { x: attackFromCard.x, y: attackFromCard.y, rotation: Math.atan2(hpY - attackFromCard.y, hpX - attackFromCard.x) }, { duration: 120, onFinish: function onFinish() { tween(attackArrow, { alpha: 0, scaleX: 0.2, scaleY: 0.2 }, { duration: 120, onFinish: function onFinish() { destroyArrow(); } }); } }); // Animate attacker to HP var origX = attackFromCard.x, origY = attackFromCard.y; tween(attackFromCard, { x: hpX, y: hpY }, { duration: 180, easing: tween.cubicIn, onFinish: function onFinish() { // Impact: flash HP and show red X on HP LK.effects.flashObject(opponentHpTxt, 0xff0000, 500); var xMarkHp = new Text2("✖", { size: 120, fill: 0xff2222, font: "Impact,'Arial Black',Tahoma", stroke: "#fff", strokeThickness: 10 }); xMarkHp.anchor.set(0.5, 0.5); xMarkHp.x = 0; xMarkHp.y = 0; opponentHpTxt.addChild(xMarkHp); xMarkHp.alpha = 0.9; tween(xMarkHp, { alpha: 0, scaleX: 1.7, scaleY: 1.7 }, { duration: 400, onFinish: function onFinish() { if (xMarkHp && xMarkHp.parent) xMarkHp.parent.removeChild(xMarkHp); } }); // Damage: deal double attack if no defender opponentHP -= attackFromCard.cardData.attack * 2; updateHpText(); checkGameEnd(); // Move attacker back tween(attackFromCard, { x: origX, y: origY }, { duration: 120, onFinish: function onFinish() { phase = "end"; nextPhase(); } }); } }); } // Clean up attackFromCard = null; attackToCard = null; attackArrow = null; // Remove move/up handlers game.move = function () {}; game.up = function () {}; }; }; } // Opponent field cards: set as not playable, no down handler for (var i = 0; i < opponentField.length; i++) { var card = opponentField[i]; card.setPlayable(false); card.setSelected(false); card.down = null; } } function opponentBattlePhase() { for (var i = 0; i < opponentField.length; i++) { var attacker = opponentField[i]; var defender = playerField[i] || null; if (defender) { var attackerPower = attacker.cardData.attack + attacker.cardData.defense; var defenderPower = defender.cardData.attack + defender.cardData.defense; var idxDef = playerField.indexOf(defender); var idxAtk = opponentField.indexOf(attacker); // Determine outcome: stronger destroys weaker, equal destroys both, HP loss = difference if (attackerPower > defenderPower) { // Attacker wins, destroy defender only if (idxDef !== -1) playerField.splice(idxDef, 1); defender.destroy(); // HP loss: player loses (attackerPower - defenderPower) var hpLoss = attackerPower - defenderPower; playerHP -= hpLoss; LK.effects.flashObject(playerHpTxt, 0xff0000, 500); } else if (attackerPower < defenderPower) { // Defender wins, destroy attacker only if (idxAtk !== -1) opponentField.splice(idxAtk, 1); attacker.destroy(); // HP loss: opponent loses (defenderPower - attackerPower) var hpLoss = defenderPower - attackerPower; opponentHP -= hpLoss; LK.effects.flashObject(opponentHpTxt, 0xff0000, 500); } else { // Equal power, destroy both if (idxDef !== -1) playerField.splice(idxDef, 1); if (idxAtk !== -1) opponentField.splice(idxAtk, 1); defender.destroy(); attacker.destroy(); // HP loss: none for equal power } } else { // Direct attack: deal double attack damage to player HP playerHP -= attacker.cardData.attack * 2; LK.effects.flashObject(playerHpTxt, 0xff0000, 500); } } updateHpText(); checkGameEnd(); } // --- Turn/Phase Management --- function nextPhase() { if (!gameActive) return; if (turn === "player") { if (phase === "draw") { // Draw phase (Magic-style: increment max, refill current) playerMaxStars += 1; playerStars = playerMaxStars; updateHpText(); var card = drawCard(playerDeck, playerHand, "player"); if (card) game.addChild(card); phase = "main"; updateHandPositions(); updateFieldPositions(); } else if (phase === "main") { // End main phase, go to battle phase = "battle"; selectedCard = null; updateHandPositions(); updateFieldPositions(); // Battle playerBattlePhase(); phase = "end"; nextPhase(); } else if (phase === "end") { // End turn turn = "opponent"; phase = "draw"; updateTurnText(); // Immediately start opponent's turn logic opponentTurn(); } } else { // Opponent phases if (phase === "draw") { // Draw phase (Magic-style: increment max, refill current) opponentMaxStars += 1; opponentStars = opponentMaxStars; updateHpText(); var card = drawCard(opponentDeck, opponentHand, "opponent"); if (card) game.addChild(card); phase = "main"; updateHandPositions(); updateFieldPositions(); // Immediately proceed to main phase logic opponentTurn(); } else if (phase === "main") { // Play first playable card if field not full if (opponentField.length < maxField && opponentHand.length > 0) { // Find first card opponent can afford var card = null; for (var i = 0; i < opponentHand.length; i++) { if (typeof opponentHand[i].starCost === "number" && opponentStars >= opponentHand[i].starCost) { card = opponentHand[i]; break; } } if (card) { var idx = opponentHand.indexOf(card); if (idx !== -1) opponentHand.splice(idx, 1); // Deduct stars from current (not max) opponentStars -= card.starCost; if (opponentStars < 0) opponentStars = 0; updateHpText(); card.isInHand = false; opponentField.push(card); card.animatePlay(function () { updateHandPositions(); updateFieldPositions(); // After playing a card, proceed to battle phase after a short delay LK.setTimeout(opponentTurn, 600); }); // Ability triggers if (card.cardData.ability.indexOf("Scorch") !== -1) { playerHP -= 2; LK.effects.flashObject(playerHpTxt, 0xff0000, 500); updateHpText(); } if (card.cardData.ability.indexOf("Tidecall") !== -1) { LK.effects.flashObject(card, 0x3399ff, 500); } return; } } // If no card played or field is full, proceed to battle phase after a short delay phase = "battle"; LK.setTimeout(opponentTurn, 600); } else if (phase === "battle") { opponentBattlePhase(); phase = "end"; LK.setTimeout(opponentTurn, 600); } else if (phase === "end") { turn = "player"; phase = "draw"; updateTurnText(); updateHandPositions(); updateFieldPositions(); } } } function opponentTurn() { if (!gameActive) return; if (turn !== "opponent") return; nextPhase(); } // --- Game End --- function checkGameEnd() { if (playerHP <= 0) { LK.effects.flashScreen(0xff0000, 1200); LK.showGameOver(); gameActive = false; } else if (opponentHP <= 0) { LK.effects.flashScreen(0x00ff88, 1200); LK.showYouWin(); gameActive = false; } } // --- Input Handling --- game.down = function (x, y, obj) { if (!gameActive) return; if (turn !== "player" || phase !== "main") return; // Only allow the player to play one card per tap, and only on their turn // Check if a card in hand was tapped var tappedCard = null; for (var i = 0; i < playerHand.length; i++) { var card = playerHand[i]; if (card.containsPoint && card.containsPoint(x, y)) { tappedCard = card; break; } } if (tappedCard && tappedCard.isPlayable) { // Only allow playing if it's player's turn and phase is main if (turn === "player" && phase === "main") { selectedCard = tappedCard; updateHandPositions(); // Play the card playCard(tappedCard); } return; } // Deselect if tap outside hand selectedCard = null; updateHandPositions(); }; game.move = function (x, y, obj) { // No drag for MVP }; game.up = function (x, y, obj) { // No drag for MVP }; // --- End Turn Button --- // Create a container for the button for animation var endTurnBtnContainer = new Container(); endTurnBtnContainer.x = 0; endTurnBtnContainer.y = -40; LK.gui.bottom.addChild(endTurnBtnContainer); // Button background (animated on press) var endTurnBtnBg = LK.getAsset('monsters', { width: 420, height: 120, color: 0x2e8b57, shape: 'box', anchorX: 0.5, anchorY: 0.5 }); endTurnBtnContainer.addChild(endTurnBtnBg); // Button label var endTurnBtn = new Text2("End Turn", { size: 64, fill: "#fff", font: "Impact", stroke: "#222", strokeThickness: 6 }); endTurnBtn.anchor.set(0.5, 0.5); endTurnBtnContainer.addChild(endTurnBtn); // Button press sound (use a built-in sound, e.g. 'shoot' as a placeholder) endTurnBtnContainer.interactive = true; endTurnBtnContainer.buttonMode = true; endTurnBtnContainer.down = function (x, y, obj) { if (!gameActive) return; if (turn === "player" && (phase === "main" || phase === "draw")) { // Animate button press: scale down and up, tint flash tween(endTurnBtnContainer, { scaleX: 0.93, scaleY: 0.93 }, { duration: 60, easing: tween.cubicIn, onFinish: function onFinish() { tween(endTurnBtnContainer, { scaleX: 1, scaleY: 1 }, { duration: 90, easing: tween.cubicOut }); } }); tween(endTurnBtnBg, { color: 0x44d17a }, { duration: 80, easing: tween.linear, onFinish: function onFinish() { tween(endTurnBtnBg, { color: 0x2e8b57 }, { duration: 120, easing: tween.linear }); } }); // Play sound LK.getSound('endturn_press').play(); // Advance phase nextPhase(); } }; // --- Game Update Loop --- game.update = function () { // If the game is not active, do nothing if (!gameActive) return; // If it's the player's turn and the phase is "battle", auto-advance to end phase after a short delay if (turn === "player" && phase === "battle") { phase = "end"; nextPhase(); return; } // If it's the opponent's turn, the phase advancement is handled by timeouts in opponentTurn/nextPhase }; // --- Card Asset Initialization (for MVP, only shapes) --- // (No-op: assets are initialized at the top)
===================================================================
--- original.js
+++ change.js
@@ -510,9 +510,26 @@
}
}
function drawCard(deck, hand, owner) {
if (deck.length === 0 || hand.length >= maxHand) return null;
- var cardId = deck.pop();
+ // --- Vampire Touch 18% draw chance logic ---
+ var vampireTouchId = 52;
+ var hasVampireTouch = deck.indexOf(vampireTouchId) !== -1;
+ var drawVampireTouch = false;
+ if (hasVampireTouch && Math.random() < 0.18) {
+ // Remove Vampire Touch from deck and draw it
+ var idx = deck.indexOf(vampireTouchId);
+ if (idx !== -1) {
+ deck.splice(idx, 1);
+ drawVampireTouch = true;
+ }
+ }
+ var cardId;
+ if (drawVampireTouch) {
+ cardId = vampireTouchId;
+ } else {
+ cardId = deck.pop();
+ }
var card = new Card();
card.setCard(cardId, owner);
card.isInHand = true;
hand.push(card);
design monsters in different styles for monster card game let there be only 1 monster design in each frame. In-Game asset. 2d. High contrast. No shadows
design monsters in different styles for monster card game let there be only 1 monster design in each frame. In-Game asset. 2d. High contrast. No shadows
Modern App Store icon, high definition, square with rounded corners, for a game. No text on icon! monster card deck
basılabilir tuş görseli dikdörtgen. In-Game asset. 2d. High contrast. No shadows