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