User prompt
Please fix the bug: 'ReferenceError: increasePressure is not defined' in or related to this line: 'increasePressure(steamGained);' Line Number: 431
User prompt
убери pressure_bar и pressure_bg
User prompt
исправь 124 строку
User prompt
Please fix the bug: 'self.shuffleBoard is not a function' in or related to this line: 'self.shuffleBoard();' Line Number: 124
User prompt
Please fix the bug: 'self is undefined' in or related to this line: 'self.shuffleBoard = function () {' Line Number: 753
User prompt
Please fix the bug: 'self.shuffleBoard is not a function' in or related to this line: 'self.shuffleBoard();' Line Number: 125
User prompt
пусть шестерни будут раскиданы более рандомно а также пусть прогресс бар пара на бойлере увелчивается за каждую комбинацию
User prompt
сделай так чтобы так часто 3 в ряд не выпадало
User prompt
Please fix the bug: 'right-hand side of 'in' should be an object, got undefined' in or related to this line: 'tween(self.hammerButtonBg, {' Line Number: 76
User prompt
убери steam hummer и turbo charger
User prompt
убери кнопки selected_cell
Code edit (1 edits merged)
Please save this source code
User prompt
Steam Gear Fusion
Initial prompt
Концепт игры «3 в ряд» в стиле Стимпанк-Механик Название: «Паровая Комбинация» 🎮 Основная механика: Классический матч-3 (три в ряд), но с стимпанк-твистами: Шестерни вместо фишек – игрок собирает линии из медных, стальных и латунных деталей. Давление пара – каждая комбинация наполняет паровой котёл, который дает бонусы. Механические помехи – иногда на поле появляются заклинившие шестерни, которые нужно убирать спец-ходом. ⚙️ Уникальные особенности: ✔ Режим «Перегрузка» – при заполнении шкалы пара можно активировать супер-способности: Паровой Молот – уничтожает все детали в одном ряду. Турбо-Нагнетатель – перемешивает поле, создавая новые комбинации. ✔ Босс-уровни – сражение с гигантской паровой машиной, которая усложняет игру: Добавляет ржавые болты, блокирующие ходы. Запускает конвейер, смещающий ряды. ✔ Квестовый сюжет – герой-механик чинит огромный завод-мегаполис, уровень за уровнем. 🎨 Визуальный стиль: Тёмные металлические тона с огненными вспышками пара. Анимация – детали скрепляются, взрываются и превращаются в пар. Саундтрек – заводские шумы, лязг металла, гудки.
/****
* Plugins
****/
var tween = LK.import("@upit/tween.v1");
var storage = LK.import("@upit/storage.v1", {
highScore: 0,
currentLevel: 1
});
/****
* Classes
****/
var Boiler = Container.expand(function () {
var self = Container.call(this);
// Boiler background
self.boilerBg = self.attachAsset('boiler', {
anchorX: 0.5,
anchorY: 0.5
});
// Pressure bar background
self.pressureBg = self.attachAsset('pressure_bg', {
anchorX: 0.5,
anchorY: 0.5,
y: 25
});
// Pressure bar
self.pressureBar = self.attachAsset('pressure_bar', {
anchorX: 0,
anchorY: 0.5,
x: -275,
y: 25,
scaleX: 0 // Start with empty bar
});
// Current pressure and max pressure
self.currentPressure = 0;
self.maxPressure = 100;
// Labels for abilities
self.hammerLabel = new Text2('Steam Hammer', {
size: 40,
fill: 0xFFFFFF
});
self.hammerLabel.anchor.set(0.5, 0.5);
self.hammerLabel.x = -150;
self.hammerLabel.y = -40;
self.addChild(self.hammerLabel);
self.turboLabel = new Text2('Turbo-Charger', {
size: 40,
fill: 0xFFFFFF
});
self.turboLabel.anchor.set(0.5, 0.5);
self.turboLabel.x = 150;
self.turboLabel.y = -40;
self.addChild(self.turboLabel);
// Button backgrounds
self.hammerButtonBg = self.attachAsset('cell_bg', {
anchorX: 0.5,
anchorY: 0.5,
x: -150,
y: 0,
scaleX: 0.8,
scaleY: 0.6
});
self.turboButtonBg = self.attachAsset('cell_bg', {
anchorX: 0.5,
anchorY: 0.5,
x: 150,
y: 0,
scaleX: 0.8,
scaleY: 0.6
});
// Ability costs
self.hammerCost = 25;
self.turboCost = 50;
// Ability availability
self.canUseHammer = false;
self.canUseTurbo = false;
// Update pressure bar
self.updatePressure = function (newPressure) {
self.currentPressure = Math.min(newPressure, self.maxPressure);
// Update pressure bar scale
tween(self.pressureBar, {
scaleX: self.currentPressure / self.maxPressure
}, {
duration: 300,
easing: tween.easeOut
});
// Update ability availability
var previousHammer = self.canUseHammer;
var previousTurbo = self.canUseTurbo;
self.canUseHammer = self.currentPressure >= self.hammerCost;
self.canUseTurbo = self.currentPressure >= self.turboCost;
// Visual feedback for available abilities
if (self.canUseHammer !== previousHammer) {
tween(self.hammerButtonBg, {
tint: self.canUseHammer ? 0x44FF44 : 0x444444
}, {
duration: 300,
easing: tween.easeOut
});
}
if (self.canUseTurbo !== previousTurbo) {
tween(self.turboButtonBg, {
tint: self.canUseTurbo ? 0x44FF44 : 0x444444
}, {
duration: 300,
easing: tween.easeOut
});
}
};
// Initialize buttons as disabled
self.hammerButtonBg.tint = 0x444444;
self.turboButtonBg.tint = 0x444444;
// Add click handlers for ability buttons
self.hammerButtonBg.interactive = true;
self.turboButtonBg.interactive = true;
self.hammerButtonBg.down = function () {
if (self.canUseHammer) {
if (gameBoard.useHammerAbility()) {
// Ability used successfully
self.currentPressure -= self.hammerCost;
self.updatePressure(self.currentPressure);
// Play steam release sound
LK.getSound('steam_release').play();
}
}
};
self.turboButtonBg.down = function () {
if (self.canUseTurbo) {
if (gameBoard.useTurboChargerAbility()) {
// Ability used successfully
self.currentPressure -= self.turboCost;
self.updatePressure(self.currentPressure);
// Play steam release sound
LK.getSound('steam_release').play();
}
}
};
return self;
});
var GameBoard = Container.expand(function () {
var self = Container.call(this);
self.gridSize = 8;
self.cellSize = 160;
self.padding = 10;
self.boardSize = (self.cellSize + self.padding) * self.gridSize;
// Metrics for positioning
self.boardStartX = (2048 - self.boardSize) / 2;
self.boardStartY = (2732 - self.boardSize) / 2;
// Game state
self.selectedGear = null;
self.grid = [];
self.gearTypes = ['copper', 'steel', 'brass'];
// Board background
var boardBg = self.attachAsset('board_bg', {
anchorX: 0.5,
anchorY: 0.5,
x: self.boardSize / 2,
y: self.boardSize / 2
});
// Selection indicator
self.selectionIndicator = self.attachAsset('selected_cell', {
anchorX: 0.5,
anchorY: 0.5
});
self.selectionIndicator.alpha = 0;
// Initialize grid cells
for (var row = 0; row < self.gridSize; row++) {
self.grid[row] = [];
for (var col = 0; col < self.gridSize; col++) {
// Create cell background
var cellBg = self.attachAsset('cell_bg', {
anchorX: 0.5,
anchorY: 0.5,
x: col * (self.cellSize + self.padding) + self.cellSize / 2,
y: row * (self.cellSize + self.padding) + self.cellSize / 2
});
// Initialize with null (empty cell)
self.grid[row][col] = null;
}
}
// Fill the board with gears
self.fillBoard = function () {
for (var row = 0; row < self.gridSize; row++) {
for (var col = 0; col < self.gridSize; col++) {
self.createRandomGear(row, col);
}
}
// Add some rusty bolts as obstacles
var numBolts = Math.min(Math.floor(currentLevel / 2) + 2, 10);
for (var i = 0; i < numBolts; i++) {
var randomRow = Math.floor(Math.random() * self.gridSize);
var randomCol = Math.floor(Math.random() * self.gridSize);
if (self.grid[randomRow][randomCol]) {
self.removeGearAt(randomRow, randomCol);
}
self.createRustyBolt(randomRow, randomCol);
}
// Check for initial matches and resolve them
self.checkAndResolveMatches();
};
self.createRandomGear = function (row, col) {
if (self.grid[row][col]) {
self.removeGearAt(row, col);
}
var randomType = self.gearTypes[Math.floor(Math.random() * self.gearTypes.length)];
var gear = new Gear(randomType);
gear.row = row;
gear.col = col;
gear.x = col * (self.cellSize + self.padding) + self.cellSize / 2;
gear.y = row * (self.cellSize + self.padding) + self.cellSize / 2;
self.grid[row][col] = gear;
self.addChild(gear);
return gear;
};
self.createRustyBolt = function (row, col) {
if (self.grid[row][col]) {
self.removeGearAt(row, col);
}
var bolt = new RustyBolt();
bolt.row = row;
bolt.col = col;
bolt.x = col * (self.cellSize + self.padding) + self.cellSize / 2;
bolt.y = row * (self.cellSize + self.padding) + self.cellSize / 2;
self.grid[row][col] = bolt;
self.addChild(bolt);
return bolt;
};
self.removeGearAt = function (row, col) {
if (self.grid[row][col]) {
self.removeChild(self.grid[row][col]);
self.grid[row][col] = null;
}
};
self.handleGearClick = function (gear) {
if (!gear || gear instanceof RustyBolt) {
return;
}
if (self.selectedGear === null) {
// Select the gear
self.selectedGear = gear;
gear.select();
// Show selection indicator
self.selectionIndicator.x = gear.x;
self.selectionIndicator.y = gear.y;
self.selectionIndicator.alpha = 1;
} else if (self.selectedGear === gear) {
// Deselect the gear
self.selectedGear.deselect();
self.selectedGear = null;
self.selectionIndicator.alpha = 0;
} else {
// Check if the gears are adjacent
var row1 = self.selectedGear.row;
var col1 = self.selectedGear.col;
var row2 = gear.row;
var col2 = gear.col;
if (self.areGearsAdjacent(row1, col1, row2, col2)) {
// Swap gears
self.swapGears(row1, col1, row2, col2);
// Deselect after swapping
self.selectedGear.deselect();
self.selectedGear = null;
self.selectionIndicator.alpha = 0;
} else {
// Not adjacent, select the new gear instead
self.selectedGear.deselect();
self.selectedGear = gear;
gear.select();
// Move selection indicator
self.selectionIndicator.x = gear.x;
self.selectionIndicator.y = gear.y;
}
}
};
self.areGearsAdjacent = function (row1, col1, row2, col2) {
return Math.abs(row1 - row2) === 1 && col1 === col2 || Math.abs(col1 - col2) === 1 && row1 === row2;
};
self.swapGears = function (row1, col1, row2, col2) {
var gear1 = self.grid[row1][col1];
var gear2 = self.grid[row2][col2];
if (!gear1 || !gear2 || gear1 instanceof RustyBolt || gear2 instanceof RustyBolt) {
return false;
}
// Update grid references
self.grid[row1][col1] = gear2;
self.grid[row2][col2] = gear1;
// Update gear positions
var tempRow = gear1.row;
var tempCol = gear1.col;
gear1.row = gear2.row;
gear1.col = gear2.col;
gear2.row = tempRow;
gear2.col = tempCol;
// Animate the swapping
tween(gear1, {
x: col2 * (self.cellSize + self.padding) + self.cellSize / 2,
y: row2 * (self.cellSize + self.padding) + self.cellSize / 2
}, {
duration: 300,
easing: tween.easeOut
});
tween(gear2, {
x: col1 * (self.cellSize + self.padding) + self.cellSize / 2,
y: row1 * (self.cellSize + self.padding) + self.cellSize / 2
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
// After swapping, check for matches
var foundMatches = self.checkAndResolveMatches();
// If no matches, swap back
if (!foundMatches) {
// Update grid references back
self.grid[row1][col1] = gear1;
self.grid[row2][col2] = gear2;
// Update gear data
gear1.row = row1;
gear1.col = col1;
gear2.row = row2;
gear2.col = col2;
// Animate swapping back
tween(gear1, {
x: col1 * (self.cellSize + self.padding) + self.cellSize / 2,
y: row1 * (self.cellSize + self.padding) + self.cellSize / 2
}, {
duration: 300,
easing: tween.easeOut
});
tween(gear2, {
x: col2 * (self.cellSize + self.padding) + self.cellSize / 2,
y: row2 * (self.cellSize + self.padding) + self.cellSize / 2
}, {
duration: 300,
easing: tween.easeOut
});
}
}
});
return true;
};
self.checkAndResolveMatches = function () {
var matches = self.findMatches();
if (matches.length > 0) {
self.resolveMatches(matches);
return true;
}
return false;
};
self.findMatches = function () {
var matches = [];
// Check horizontal matches
for (var row = 0; row < self.gridSize; row++) {
var currentType = null;
var count = 0;
var startCol = 0;
for (var col = 0; col < self.gridSize; col++) {
var gear = self.grid[row][col];
if (gear && gear instanceof Gear) {
if (currentType === null) {
currentType = gear.type;
count = 1;
startCol = col;
} else if (gear.type === currentType) {
count++;
} else {
if (count >= 3) {
matches.push({
row: row,
startCol: startCol,
endCol: col - 1,
direction: 'horizontal',
type: currentType,
count: count
});
}
currentType = gear.type;
count = 1;
startCol = col;
}
} else {
if (count >= 3) {
matches.push({
row: row,
startCol: startCol,
endCol: col - 1,
direction: 'horizontal',
type: currentType,
count: count
});
}
currentType = null;
count = 0;
}
}
// Check at the end of row
if (count >= 3) {
matches.push({
row: row,
startCol: startCol,
endCol: self.gridSize - 1,
direction: 'horizontal',
type: currentType,
count: count
});
}
}
// Check vertical matches
for (var col = 0; col < self.gridSize; col++) {
var currentType = null;
var count = 0;
var startRow = 0;
for (var row = 0; row < self.gridSize; row++) {
var gear = self.grid[row][col];
if (gear && gear instanceof Gear) {
if (currentType === null) {
currentType = gear.type;
count = 1;
startRow = row;
} else if (gear.type === currentType) {
count++;
} else {
if (count >= 3) {
matches.push({
col: col,
startRow: startRow,
endRow: row - 1,
direction: 'vertical',
type: currentType,
count: count
});
}
currentType = gear.type;
count = 1;
startRow = row;
}
} else {
if (count >= 3) {
matches.push({
col: col,
startRow: startRow,
endRow: row - 1,
direction: 'vertical',
type: currentType,
count: count
});
}
currentType = null;
count = 0;
}
}
// Check at the end of column
if (count >= 3) {
matches.push({
col: col,
startRow: startRow,
endRow: self.gridSize - 1,
direction: 'vertical',
type: currentType,
count: count
});
}
}
return matches;
};
self.resolveMatches = function (matches) {
var gearsToRemove = [];
var pointsGained = 0;
var steamGained = 0;
// Mark all gears to be removed
for (var i = 0; i < matches.length; i++) {
var match = matches[i];
var matchCount = 0;
if (match.direction === 'horizontal') {
for (var col = match.startCol; col <= match.endCol; col++) {
if (self.grid[match.row][col] && self.grid[match.row][col] instanceof Gear) {
gearsToRemove.push({
row: match.row,
col: col
});
matchCount++;
}
}
} else {
// vertical
for (var row = match.startRow; row <= match.endRow; row++) {
if (self.grid[row][match.col] && self.grid[row][match.col] instanceof Gear) {
gearsToRemove.push({
row: row,
col: match.col
});
matchCount++;
}
}
}
// Calculate points and steam for this match
var matchPoints = matchCount * 10; // Basic points
var matchSteam = 0;
// Special bonuses based on match length
if (matchCount >= 5) {
matchPoints *= 2; // Double points for 5+ matches
matchSteam = 25; // Big steam boost
} else if (matchCount >= 4) {
matchPoints += 20; // Bonus for 4 matches
matchSteam = 15; // Good steam boost
} else {
matchSteam = 10; // Basic steam boost
}
// Type bonuses
if (match.type === 'brass') {
matchPoints += 5; // Bonus for brass gears
matchSteam += 5; // Extra steam for brass
} else if (match.type === 'steel') {
matchPoints += 3; // Small bonus for steel
}
pointsGained += matchPoints;
steamGained += matchSteam;
}
// Remove duplicate entries
var uniqueRemoves = [];
for (var i = 0; i < gearsToRemove.length; i++) {
var alreadyIncluded = false;
for (var j = 0; j < uniqueRemoves.length; j++) {
if (gearsToRemove[i].row === uniqueRemoves[j].row && gearsToRemove[i].col === uniqueRemoves[j].col) {
alreadyIncluded = true;
break;
}
}
if (!alreadyIncluded) {
uniqueRemoves.push(gearsToRemove[i]);
}
}
// Play match sound
LK.getSound('gear_match').play();
// Add to score
score += pointsGained;
scoreTxt.setText(score);
// Add to steam pressure
increasePressure(steamGained);
// Animate and remove matched gears
for (var i = 0; i < uniqueRemoves.length; i++) {
var pos = uniqueRemoves[i];
var gear = self.grid[pos.row][pos.col];
if (gear && gear instanceof Gear) {
gear.matched();
self.grid[pos.row][pos.col] = null;
}
}
// Wait for animations to complete before dropping gears
LK.setTimeout(function () {
self.dropGears();
LK.setTimeout(function () {
self.fillEmptyCells();
LK.setTimeout(function () {
// Check for more matches after filling
self.checkAndResolveMatches();
}, 500);
}, 500);
}, 300);
return uniqueRemoves.length;
};
self.dropGears = function () {
// For each column, check from bottom to top
for (var col = 0; col < self.gridSize; col++) {
var emptySpaces = 0;
// Start from bottom and count empty spaces
for (var row = self.gridSize - 1; row >= 0; row--) {
var cell = self.grid[row][col];
if (!cell) {
// Empty cell
emptySpaces++;
} else if (cell instanceof RustyBolt) {
// Rusty bolts don't drop
emptySpaces = 0;
} else if (emptySpaces > 0) {
// Move gear down
var newRow = row + emptySpaces;
self.grid[newRow][col] = cell;
self.grid[row][col] = null;
// Update gear data
cell.row = newRow;
// Animate the drop
tween(cell, {
y: newRow * (self.cellSize + self.padding) + self.cellSize / 2
}, {
duration: 300,
easing: tween.bounceOut
});
}
}
}
};
self.fillEmptyCells = function () {
for (var col = 0; col < self.gridSize; col++) {
for (var row = 0; row < self.gridSize; row++) {
if (!self.grid[row][col]) {
// Create new gear from top (with animation)
var gear = self.createRandomGear(row, col);
// Start position above the board
gear.y = -150;
// Animate dropping in
tween(gear, {
y: row * (self.cellSize + self.padding) + self.cellSize / 2
}, {
duration: 300,
easing: tween.easeIn
});
}
}
}
};
self.useHammerAbility = function () {
if (self.selectedGear) {
// Deselect the current gear
self.selectedGear.deselect();
self.selectedGear = null;
self.selectionIndicator.alpha = 0;
}
// Find a rusty bolt to destroy
var boltPositions = [];
for (var row = 0; row < self.gridSize; row++) {
for (var col = 0; col < self.gridSize; col++) {
if (self.grid[row][col] instanceof RustyBolt) {
boltPositions.push({
row: row,
col: col
});
}
}
}
if (boltPositions.length > 0) {
var randomBolt = boltPositions[Math.floor(Math.random() * boltPositions.length)];
var bolt = self.grid[randomBolt.row][randomBolt.col];
if (bolt) {
// Flash effect
LK.effects.flashObject(bolt, 0xFFFFFF, 500);
// Play sound
LK.getSound('ability_use').play();
// Break the bolt
bolt.breakBolt();
self.grid[randomBolt.row][randomBolt.col] = null;
// Fill in after delay
LK.setTimeout(function () {
self.dropGears();
LK.setTimeout(function () {
self.fillEmptyCells();
LK.setTimeout(function () {
self.checkAndResolveMatches();
}, 500);
}, 500);
}, 500);
return true;
}
}
return false;
};
self.useTurboChargerAbility = function () {
if (self.selectedGear) {
// Deselect the current gear
self.selectedGear.deselect();
self.selectedGear = null;
self.selectionIndicator.alpha = 0;
}
// Find random positions to make a pattern that will match
var row = Math.floor(Math.random() * (self.gridSize - 2));
var col = Math.floor(Math.random() * self.gridSize);
var type = self.gearTypes[Math.floor(Math.random() * self.gearTypes.length)];
// Make sure positions don't contain rusty bolts
if (self.grid[row][col] instanceof RustyBolt || self.grid[row + 1][col] instanceof RustyBolt || self.grid[row + 2][col] instanceof RustyBolt) {
// Try horizontally instead
row = Math.floor(Math.random() * self.gridSize);
col = Math.floor(Math.random() * (self.gridSize - 2));
// Check again
if (self.grid[row][col] instanceof RustyBolt || self.grid[row][col + 1] instanceof RustyBolt || self.grid[row][col + 2] instanceof RustyBolt) {
// Find any viable position
var foundViablePosition = false;
for (var r = 0; r < self.gridSize; r++) {
for (var c = 0; c < self.gridSize - 2; c++) {
if (!(self.grid[r][c] instanceof RustyBolt) && !(self.grid[r][c + 1] instanceof RustyBolt) && !(self.grid[r][c + 2] instanceof RustyBolt)) {
row = r;
col = c;
foundViablePosition = true;
break;
}
}
if (foundViablePosition) {
break;
}
}
if (!foundViablePosition) {
// No viable position found
return false;
}
}
// Create horizontal match
if (self.grid[row][col]) {
self.removeGearAt(row, col);
}
if (self.grid[row][col + 1]) {
self.removeGearAt(row, col + 1);
}
if (self.grid[row][col + 2]) {
self.removeGearAt(row, col + 2);
}
var gear1 = self.createRandomGear(row, col);
var gear2 = self.createRandomGear(row, col + 1);
var gear3 = self.createRandomGear(row, col + 2);
gear1.type = gear2.type = gear3.type = type;
// Flash effect on the new gears
LK.effects.flashObject(gear1, 0xFFD700, 500);
LK.effects.flashObject(gear2, 0xFFD700, 500);
LK.effects.flashObject(gear3, 0xFFD700, 500);
// Play sound
LK.getSound('ability_use').play();
} else {
// Create vertical match
if (self.grid[row][col]) {
self.removeGearAt(row, col);
}
if (self.grid[row + 1][col]) {
self.removeGearAt(row + 1, col);
}
if (self.grid[row + 2][col]) {
self.removeGearAt(row + 2, col);
}
var gear1 = self.createRandomGear(row, col);
var gear2 = self.createRandomGear(row + 1, col);
var gear3 = self.createRandomGear(row + 2, col);
gear1.type = gear2.type = gear3.type = type;
// Flash effect on the new gears
LK.effects.flashObject(gear1, 0xFFD700, 500);
LK.effects.flashObject(gear2, 0xFFD700, 500);
LK.effects.flashObject(gear3, 0xFFD700, 500);
// Play sound
LK.getSound('ability_use').play();
}
// Check for matches after a delay
LK.setTimeout(function () {
self.checkAndResolveMatches();
}, 700);
return true;
};
return self;
});
var Gear = Container.expand(function (type) {
var self = Container.call(this);
self.type = type || 'copper'; // Default to copper if no type specified
var color;
switch (self.type) {
case 'copper':
color = 'gear_copper';
break;
case 'steel':
color = 'gear_steel';
break;
case 'brass':
color = 'gear_brass';
break;
default:
color = 'gear_copper';
}
self.gearGraphic = self.attachAsset(color, {
anchorX: 0.5,
anchorY: 0.5,
scaleX: 0.9,
scaleY: 0.9
});
// Add teeth to make it look more like a gear
self.teethCount = 8;
self.radius = self.gearGraphic.width / 2;
// Apply a small rotation animation to make gears feel mechanical
self.rotationSpeed = Math.random() * 0.01 + 0.005;
if (Math.random() > 0.5) {
self.rotationSpeed *= -1;
} // Random direction
self.update = function () {
self.gearGraphic.rotation += self.rotationSpeed;
};
self.select = function () {
tween(self.gearGraphic, {
scaleX: 1.1,
scaleY: 1.1
}, {
duration: 200,
easing: tween.easeOut
});
LK.getSound('gear_select').play();
};
self.deselect = function () {
tween(self.gearGraphic, {
scaleX: 0.9,
scaleY: 0.9
}, {
duration: 200,
easing: tween.easeOut
});
};
self.matched = function () {
tween(self, {
alpha: 0
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
if (self.parent) {
self.parent.removeChild(self);
}
}
});
};
self.down = function (x, y, obj) {
gameBoard.handleGearClick(self);
};
return self;
});
var RustyBolt = Container.expand(function () {
var self = Container.call(this);
self.boltGraphic = self.attachAsset('rusty_bolt', {
anchorX: 0.5,
anchorY: 0.5
});
self.breakBolt = function () {
tween(self, {
alpha: 0
}, {
duration: 300,
easing: tween.easeOut,
onFinish: function onFinish() {
if (self.parent) {
self.parent.removeChild(self);
}
}
});
};
self.down = function (x, y, obj) {
// Rusty bolts cannot be selected
};
return self;
});
/****
* Initialize Game
****/
var game = new LK.Game({
backgroundColor: 0x2C3E50 // Dark blue-gray background
});
/****
* Game Code
****/
// Game variables
var score = 0;
var currentLevel = storage.currentLevel || 1;
var targetScore = currentLevel * 1000; // Score needed to complete the level
var gameBoard;
var boiler;
// UI elements
var scoreTxt = new Text2('0', {
size: 80,
fill: 0xFFFFFF
});
scoreTxt.anchor.set(0.5, 0);
LK.gui.top.addChild(scoreTxt);
scoreTxt.y = 50;
var levelTxt = new Text2('Level: ' + currentLevel, {
size: 60,
fill: 0xFFFFFF
});
levelTxt.anchor.set(0, 0);
LK.gui.topLeft.addChild(levelTxt);
levelTxt.x = 120; // Leave space for menu icon
levelTxt.y = 50;
var targetTxt = new Text2('Target: ' + targetScore, {
size: 60,
fill: 0xFFFFFF
});
targetTxt.anchor.set(1, 0);
LK.gui.topRight.addChild(targetTxt);
targetTxt.y = 50;
// Initialize game board
gameBoard = new GameBoard();
game.addChild(gameBoard);
gameBoard.x = (2048 - gameBoard.boardSize) / 2;
gameBoard.y = (2732 - gameBoard.boardSize) / 2;
// Initialize boiler (steam pressure meter)
boiler = new Boiler();
game.addChild(boiler);
boiler.x = 2048 / 2;
boiler.y = 2732 - 200;
// Fill the board with initial gears
gameBoard.fillBoard();
// Function to increase steam pressure
function increasePressure(amount) {
boiler.updatePressure(boiler.currentPressure + amount);
}
// Play background music
LK.playMusic('steampunk_bgm');
// Main game update loop
game.update = function () {
// Check if level is complete
if (score >= targetScore) {
// Level complete logic
currentLevel++;
storage.currentLevel = currentLevel;
// Update high score
if (score > storage.highScore) {
storage.highScore = score;
}
// Show win screen
LK.showYouWin();
}
};
// Global input handling
game.down = function (x, y, obj) {
// Handle any global click events if needed
};
game.move = function (x, y, obj) {
// Handle any global move events if needed
};
game.up = function (x, y, obj) {
// Handle any global release events if needed
}; ===================================================================
--- original.js
+++ change.js
@@ -1,6 +1,921 @@
-/****
+/****
+* Plugins
+****/
+var tween = LK.import("@upit/tween.v1");
+var storage = LK.import("@upit/storage.v1", {
+ highScore: 0,
+ currentLevel: 1
+});
+
+/****
+* Classes
+****/
+var Boiler = Container.expand(function () {
+ var self = Container.call(this);
+ // Boiler background
+ self.boilerBg = self.attachAsset('boiler', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ // Pressure bar background
+ self.pressureBg = self.attachAsset('pressure_bg', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ y: 25
+ });
+ // Pressure bar
+ self.pressureBar = self.attachAsset('pressure_bar', {
+ anchorX: 0,
+ anchorY: 0.5,
+ x: -275,
+ y: 25,
+ scaleX: 0 // Start with empty bar
+ });
+ // Current pressure and max pressure
+ self.currentPressure = 0;
+ self.maxPressure = 100;
+ // Labels for abilities
+ self.hammerLabel = new Text2('Steam Hammer', {
+ size: 40,
+ fill: 0xFFFFFF
+ });
+ self.hammerLabel.anchor.set(0.5, 0.5);
+ self.hammerLabel.x = -150;
+ self.hammerLabel.y = -40;
+ self.addChild(self.hammerLabel);
+ self.turboLabel = new Text2('Turbo-Charger', {
+ size: 40,
+ fill: 0xFFFFFF
+ });
+ self.turboLabel.anchor.set(0.5, 0.5);
+ self.turboLabel.x = 150;
+ self.turboLabel.y = -40;
+ self.addChild(self.turboLabel);
+ // Button backgrounds
+ self.hammerButtonBg = self.attachAsset('cell_bg', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: -150,
+ y: 0,
+ scaleX: 0.8,
+ scaleY: 0.6
+ });
+ self.turboButtonBg = self.attachAsset('cell_bg', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: 150,
+ y: 0,
+ scaleX: 0.8,
+ scaleY: 0.6
+ });
+ // Ability costs
+ self.hammerCost = 25;
+ self.turboCost = 50;
+ // Ability availability
+ self.canUseHammer = false;
+ self.canUseTurbo = false;
+ // Update pressure bar
+ self.updatePressure = function (newPressure) {
+ self.currentPressure = Math.min(newPressure, self.maxPressure);
+ // Update pressure bar scale
+ tween(self.pressureBar, {
+ scaleX: self.currentPressure / self.maxPressure
+ }, {
+ duration: 300,
+ easing: tween.easeOut
+ });
+ // Update ability availability
+ var previousHammer = self.canUseHammer;
+ var previousTurbo = self.canUseTurbo;
+ self.canUseHammer = self.currentPressure >= self.hammerCost;
+ self.canUseTurbo = self.currentPressure >= self.turboCost;
+ // Visual feedback for available abilities
+ if (self.canUseHammer !== previousHammer) {
+ tween(self.hammerButtonBg, {
+ tint: self.canUseHammer ? 0x44FF44 : 0x444444
+ }, {
+ duration: 300,
+ easing: tween.easeOut
+ });
+ }
+ if (self.canUseTurbo !== previousTurbo) {
+ tween(self.turboButtonBg, {
+ tint: self.canUseTurbo ? 0x44FF44 : 0x444444
+ }, {
+ duration: 300,
+ easing: tween.easeOut
+ });
+ }
+ };
+ // Initialize buttons as disabled
+ self.hammerButtonBg.tint = 0x444444;
+ self.turboButtonBg.tint = 0x444444;
+ // Add click handlers for ability buttons
+ self.hammerButtonBg.interactive = true;
+ self.turboButtonBg.interactive = true;
+ self.hammerButtonBg.down = function () {
+ if (self.canUseHammer) {
+ if (gameBoard.useHammerAbility()) {
+ // Ability used successfully
+ self.currentPressure -= self.hammerCost;
+ self.updatePressure(self.currentPressure);
+ // Play steam release sound
+ LK.getSound('steam_release').play();
+ }
+ }
+ };
+ self.turboButtonBg.down = function () {
+ if (self.canUseTurbo) {
+ if (gameBoard.useTurboChargerAbility()) {
+ // Ability used successfully
+ self.currentPressure -= self.turboCost;
+ self.updatePressure(self.currentPressure);
+ // Play steam release sound
+ LK.getSound('steam_release').play();
+ }
+ }
+ };
+ return self;
+});
+var GameBoard = Container.expand(function () {
+ var self = Container.call(this);
+ self.gridSize = 8;
+ self.cellSize = 160;
+ self.padding = 10;
+ self.boardSize = (self.cellSize + self.padding) * self.gridSize;
+ // Metrics for positioning
+ self.boardStartX = (2048 - self.boardSize) / 2;
+ self.boardStartY = (2732 - self.boardSize) / 2;
+ // Game state
+ self.selectedGear = null;
+ self.grid = [];
+ self.gearTypes = ['copper', 'steel', 'brass'];
+ // Board background
+ var boardBg = self.attachAsset('board_bg', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: self.boardSize / 2,
+ y: self.boardSize / 2
+ });
+ // Selection indicator
+ self.selectionIndicator = self.attachAsset('selected_cell', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.selectionIndicator.alpha = 0;
+ // Initialize grid cells
+ for (var row = 0; row < self.gridSize; row++) {
+ self.grid[row] = [];
+ for (var col = 0; col < self.gridSize; col++) {
+ // Create cell background
+ var cellBg = self.attachAsset('cell_bg', {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ x: col * (self.cellSize + self.padding) + self.cellSize / 2,
+ y: row * (self.cellSize + self.padding) + self.cellSize / 2
+ });
+ // Initialize with null (empty cell)
+ self.grid[row][col] = null;
+ }
+ }
+ // Fill the board with gears
+ self.fillBoard = function () {
+ for (var row = 0; row < self.gridSize; row++) {
+ for (var col = 0; col < self.gridSize; col++) {
+ self.createRandomGear(row, col);
+ }
+ }
+ // Add some rusty bolts as obstacles
+ var numBolts = Math.min(Math.floor(currentLevel / 2) + 2, 10);
+ for (var i = 0; i < numBolts; i++) {
+ var randomRow = Math.floor(Math.random() * self.gridSize);
+ var randomCol = Math.floor(Math.random() * self.gridSize);
+ if (self.grid[randomRow][randomCol]) {
+ self.removeGearAt(randomRow, randomCol);
+ }
+ self.createRustyBolt(randomRow, randomCol);
+ }
+ // Check for initial matches and resolve them
+ self.checkAndResolveMatches();
+ };
+ self.createRandomGear = function (row, col) {
+ if (self.grid[row][col]) {
+ self.removeGearAt(row, col);
+ }
+ var randomType = self.gearTypes[Math.floor(Math.random() * self.gearTypes.length)];
+ var gear = new Gear(randomType);
+ gear.row = row;
+ gear.col = col;
+ gear.x = col * (self.cellSize + self.padding) + self.cellSize / 2;
+ gear.y = row * (self.cellSize + self.padding) + self.cellSize / 2;
+ self.grid[row][col] = gear;
+ self.addChild(gear);
+ return gear;
+ };
+ self.createRustyBolt = function (row, col) {
+ if (self.grid[row][col]) {
+ self.removeGearAt(row, col);
+ }
+ var bolt = new RustyBolt();
+ bolt.row = row;
+ bolt.col = col;
+ bolt.x = col * (self.cellSize + self.padding) + self.cellSize / 2;
+ bolt.y = row * (self.cellSize + self.padding) + self.cellSize / 2;
+ self.grid[row][col] = bolt;
+ self.addChild(bolt);
+ return bolt;
+ };
+ self.removeGearAt = function (row, col) {
+ if (self.grid[row][col]) {
+ self.removeChild(self.grid[row][col]);
+ self.grid[row][col] = null;
+ }
+ };
+ self.handleGearClick = function (gear) {
+ if (!gear || gear instanceof RustyBolt) {
+ return;
+ }
+ if (self.selectedGear === null) {
+ // Select the gear
+ self.selectedGear = gear;
+ gear.select();
+ // Show selection indicator
+ self.selectionIndicator.x = gear.x;
+ self.selectionIndicator.y = gear.y;
+ self.selectionIndicator.alpha = 1;
+ } else if (self.selectedGear === gear) {
+ // Deselect the gear
+ self.selectedGear.deselect();
+ self.selectedGear = null;
+ self.selectionIndicator.alpha = 0;
+ } else {
+ // Check if the gears are adjacent
+ var row1 = self.selectedGear.row;
+ var col1 = self.selectedGear.col;
+ var row2 = gear.row;
+ var col2 = gear.col;
+ if (self.areGearsAdjacent(row1, col1, row2, col2)) {
+ // Swap gears
+ self.swapGears(row1, col1, row2, col2);
+ // Deselect after swapping
+ self.selectedGear.deselect();
+ self.selectedGear = null;
+ self.selectionIndicator.alpha = 0;
+ } else {
+ // Not adjacent, select the new gear instead
+ self.selectedGear.deselect();
+ self.selectedGear = gear;
+ gear.select();
+ // Move selection indicator
+ self.selectionIndicator.x = gear.x;
+ self.selectionIndicator.y = gear.y;
+ }
+ }
+ };
+ self.areGearsAdjacent = function (row1, col1, row2, col2) {
+ return Math.abs(row1 - row2) === 1 && col1 === col2 || Math.abs(col1 - col2) === 1 && row1 === row2;
+ };
+ self.swapGears = function (row1, col1, row2, col2) {
+ var gear1 = self.grid[row1][col1];
+ var gear2 = self.grid[row2][col2];
+ if (!gear1 || !gear2 || gear1 instanceof RustyBolt || gear2 instanceof RustyBolt) {
+ return false;
+ }
+ // Update grid references
+ self.grid[row1][col1] = gear2;
+ self.grid[row2][col2] = gear1;
+ // Update gear positions
+ var tempRow = gear1.row;
+ var tempCol = gear1.col;
+ gear1.row = gear2.row;
+ gear1.col = gear2.col;
+ gear2.row = tempRow;
+ gear2.col = tempCol;
+ // Animate the swapping
+ tween(gear1, {
+ x: col2 * (self.cellSize + self.padding) + self.cellSize / 2,
+ y: row2 * (self.cellSize + self.padding) + self.cellSize / 2
+ }, {
+ duration: 300,
+ easing: tween.easeOut
+ });
+ tween(gear2, {
+ x: col1 * (self.cellSize + self.padding) + self.cellSize / 2,
+ y: row1 * (self.cellSize + self.padding) + self.cellSize / 2
+ }, {
+ duration: 300,
+ easing: tween.easeOut,
+ onFinish: function onFinish() {
+ // After swapping, check for matches
+ var foundMatches = self.checkAndResolveMatches();
+ // If no matches, swap back
+ if (!foundMatches) {
+ // Update grid references back
+ self.grid[row1][col1] = gear1;
+ self.grid[row2][col2] = gear2;
+ // Update gear data
+ gear1.row = row1;
+ gear1.col = col1;
+ gear2.row = row2;
+ gear2.col = col2;
+ // Animate swapping back
+ tween(gear1, {
+ x: col1 * (self.cellSize + self.padding) + self.cellSize / 2,
+ y: row1 * (self.cellSize + self.padding) + self.cellSize / 2
+ }, {
+ duration: 300,
+ easing: tween.easeOut
+ });
+ tween(gear2, {
+ x: col2 * (self.cellSize + self.padding) + self.cellSize / 2,
+ y: row2 * (self.cellSize + self.padding) + self.cellSize / 2
+ }, {
+ duration: 300,
+ easing: tween.easeOut
+ });
+ }
+ }
+ });
+ return true;
+ };
+ self.checkAndResolveMatches = function () {
+ var matches = self.findMatches();
+ if (matches.length > 0) {
+ self.resolveMatches(matches);
+ return true;
+ }
+ return false;
+ };
+ self.findMatches = function () {
+ var matches = [];
+ // Check horizontal matches
+ for (var row = 0; row < self.gridSize; row++) {
+ var currentType = null;
+ var count = 0;
+ var startCol = 0;
+ for (var col = 0; col < self.gridSize; col++) {
+ var gear = self.grid[row][col];
+ if (gear && gear instanceof Gear) {
+ if (currentType === null) {
+ currentType = gear.type;
+ count = 1;
+ startCol = col;
+ } else if (gear.type === currentType) {
+ count++;
+ } else {
+ if (count >= 3) {
+ matches.push({
+ row: row,
+ startCol: startCol,
+ endCol: col - 1,
+ direction: 'horizontal',
+ type: currentType,
+ count: count
+ });
+ }
+ currentType = gear.type;
+ count = 1;
+ startCol = col;
+ }
+ } else {
+ if (count >= 3) {
+ matches.push({
+ row: row,
+ startCol: startCol,
+ endCol: col - 1,
+ direction: 'horizontal',
+ type: currentType,
+ count: count
+ });
+ }
+ currentType = null;
+ count = 0;
+ }
+ }
+ // Check at the end of row
+ if (count >= 3) {
+ matches.push({
+ row: row,
+ startCol: startCol,
+ endCol: self.gridSize - 1,
+ direction: 'horizontal',
+ type: currentType,
+ count: count
+ });
+ }
+ }
+ // Check vertical matches
+ for (var col = 0; col < self.gridSize; col++) {
+ var currentType = null;
+ var count = 0;
+ var startRow = 0;
+ for (var row = 0; row < self.gridSize; row++) {
+ var gear = self.grid[row][col];
+ if (gear && gear instanceof Gear) {
+ if (currentType === null) {
+ currentType = gear.type;
+ count = 1;
+ startRow = row;
+ } else if (gear.type === currentType) {
+ count++;
+ } else {
+ if (count >= 3) {
+ matches.push({
+ col: col,
+ startRow: startRow,
+ endRow: row - 1,
+ direction: 'vertical',
+ type: currentType,
+ count: count
+ });
+ }
+ currentType = gear.type;
+ count = 1;
+ startRow = row;
+ }
+ } else {
+ if (count >= 3) {
+ matches.push({
+ col: col,
+ startRow: startRow,
+ endRow: row - 1,
+ direction: 'vertical',
+ type: currentType,
+ count: count
+ });
+ }
+ currentType = null;
+ count = 0;
+ }
+ }
+ // Check at the end of column
+ if (count >= 3) {
+ matches.push({
+ col: col,
+ startRow: startRow,
+ endRow: self.gridSize - 1,
+ direction: 'vertical',
+ type: currentType,
+ count: count
+ });
+ }
+ }
+ return matches;
+ };
+ self.resolveMatches = function (matches) {
+ var gearsToRemove = [];
+ var pointsGained = 0;
+ var steamGained = 0;
+ // Mark all gears to be removed
+ for (var i = 0; i < matches.length; i++) {
+ var match = matches[i];
+ var matchCount = 0;
+ if (match.direction === 'horizontal') {
+ for (var col = match.startCol; col <= match.endCol; col++) {
+ if (self.grid[match.row][col] && self.grid[match.row][col] instanceof Gear) {
+ gearsToRemove.push({
+ row: match.row,
+ col: col
+ });
+ matchCount++;
+ }
+ }
+ } else {
+ // vertical
+ for (var row = match.startRow; row <= match.endRow; row++) {
+ if (self.grid[row][match.col] && self.grid[row][match.col] instanceof Gear) {
+ gearsToRemove.push({
+ row: row,
+ col: match.col
+ });
+ matchCount++;
+ }
+ }
+ }
+ // Calculate points and steam for this match
+ var matchPoints = matchCount * 10; // Basic points
+ var matchSteam = 0;
+ // Special bonuses based on match length
+ if (matchCount >= 5) {
+ matchPoints *= 2; // Double points for 5+ matches
+ matchSteam = 25; // Big steam boost
+ } else if (matchCount >= 4) {
+ matchPoints += 20; // Bonus for 4 matches
+ matchSteam = 15; // Good steam boost
+ } else {
+ matchSteam = 10; // Basic steam boost
+ }
+ // Type bonuses
+ if (match.type === 'brass') {
+ matchPoints += 5; // Bonus for brass gears
+ matchSteam += 5; // Extra steam for brass
+ } else if (match.type === 'steel') {
+ matchPoints += 3; // Small bonus for steel
+ }
+ pointsGained += matchPoints;
+ steamGained += matchSteam;
+ }
+ // Remove duplicate entries
+ var uniqueRemoves = [];
+ for (var i = 0; i < gearsToRemove.length; i++) {
+ var alreadyIncluded = false;
+ for (var j = 0; j < uniqueRemoves.length; j++) {
+ if (gearsToRemove[i].row === uniqueRemoves[j].row && gearsToRemove[i].col === uniqueRemoves[j].col) {
+ alreadyIncluded = true;
+ break;
+ }
+ }
+ if (!alreadyIncluded) {
+ uniqueRemoves.push(gearsToRemove[i]);
+ }
+ }
+ // Play match sound
+ LK.getSound('gear_match').play();
+ // Add to score
+ score += pointsGained;
+ scoreTxt.setText(score);
+ // Add to steam pressure
+ increasePressure(steamGained);
+ // Animate and remove matched gears
+ for (var i = 0; i < uniqueRemoves.length; i++) {
+ var pos = uniqueRemoves[i];
+ var gear = self.grid[pos.row][pos.col];
+ if (gear && gear instanceof Gear) {
+ gear.matched();
+ self.grid[pos.row][pos.col] = null;
+ }
+ }
+ // Wait for animations to complete before dropping gears
+ LK.setTimeout(function () {
+ self.dropGears();
+ LK.setTimeout(function () {
+ self.fillEmptyCells();
+ LK.setTimeout(function () {
+ // Check for more matches after filling
+ self.checkAndResolveMatches();
+ }, 500);
+ }, 500);
+ }, 300);
+ return uniqueRemoves.length;
+ };
+ self.dropGears = function () {
+ // For each column, check from bottom to top
+ for (var col = 0; col < self.gridSize; col++) {
+ var emptySpaces = 0;
+ // Start from bottom and count empty spaces
+ for (var row = self.gridSize - 1; row >= 0; row--) {
+ var cell = self.grid[row][col];
+ if (!cell) {
+ // Empty cell
+ emptySpaces++;
+ } else if (cell instanceof RustyBolt) {
+ // Rusty bolts don't drop
+ emptySpaces = 0;
+ } else if (emptySpaces > 0) {
+ // Move gear down
+ var newRow = row + emptySpaces;
+ self.grid[newRow][col] = cell;
+ self.grid[row][col] = null;
+ // Update gear data
+ cell.row = newRow;
+ // Animate the drop
+ tween(cell, {
+ y: newRow * (self.cellSize + self.padding) + self.cellSize / 2
+ }, {
+ duration: 300,
+ easing: tween.bounceOut
+ });
+ }
+ }
+ }
+ };
+ self.fillEmptyCells = function () {
+ for (var col = 0; col < self.gridSize; col++) {
+ for (var row = 0; row < self.gridSize; row++) {
+ if (!self.grid[row][col]) {
+ // Create new gear from top (with animation)
+ var gear = self.createRandomGear(row, col);
+ // Start position above the board
+ gear.y = -150;
+ // Animate dropping in
+ tween(gear, {
+ y: row * (self.cellSize + self.padding) + self.cellSize / 2
+ }, {
+ duration: 300,
+ easing: tween.easeIn
+ });
+ }
+ }
+ }
+ };
+ self.useHammerAbility = function () {
+ if (self.selectedGear) {
+ // Deselect the current gear
+ self.selectedGear.deselect();
+ self.selectedGear = null;
+ self.selectionIndicator.alpha = 0;
+ }
+ // Find a rusty bolt to destroy
+ var boltPositions = [];
+ for (var row = 0; row < self.gridSize; row++) {
+ for (var col = 0; col < self.gridSize; col++) {
+ if (self.grid[row][col] instanceof RustyBolt) {
+ boltPositions.push({
+ row: row,
+ col: col
+ });
+ }
+ }
+ }
+ if (boltPositions.length > 0) {
+ var randomBolt = boltPositions[Math.floor(Math.random() * boltPositions.length)];
+ var bolt = self.grid[randomBolt.row][randomBolt.col];
+ if (bolt) {
+ // Flash effect
+ LK.effects.flashObject(bolt, 0xFFFFFF, 500);
+ // Play sound
+ LK.getSound('ability_use').play();
+ // Break the bolt
+ bolt.breakBolt();
+ self.grid[randomBolt.row][randomBolt.col] = null;
+ // Fill in after delay
+ LK.setTimeout(function () {
+ self.dropGears();
+ LK.setTimeout(function () {
+ self.fillEmptyCells();
+ LK.setTimeout(function () {
+ self.checkAndResolveMatches();
+ }, 500);
+ }, 500);
+ }, 500);
+ return true;
+ }
+ }
+ return false;
+ };
+ self.useTurboChargerAbility = function () {
+ if (self.selectedGear) {
+ // Deselect the current gear
+ self.selectedGear.deselect();
+ self.selectedGear = null;
+ self.selectionIndicator.alpha = 0;
+ }
+ // Find random positions to make a pattern that will match
+ var row = Math.floor(Math.random() * (self.gridSize - 2));
+ var col = Math.floor(Math.random() * self.gridSize);
+ var type = self.gearTypes[Math.floor(Math.random() * self.gearTypes.length)];
+ // Make sure positions don't contain rusty bolts
+ if (self.grid[row][col] instanceof RustyBolt || self.grid[row + 1][col] instanceof RustyBolt || self.grid[row + 2][col] instanceof RustyBolt) {
+ // Try horizontally instead
+ row = Math.floor(Math.random() * self.gridSize);
+ col = Math.floor(Math.random() * (self.gridSize - 2));
+ // Check again
+ if (self.grid[row][col] instanceof RustyBolt || self.grid[row][col + 1] instanceof RustyBolt || self.grid[row][col + 2] instanceof RustyBolt) {
+ // Find any viable position
+ var foundViablePosition = false;
+ for (var r = 0; r < self.gridSize; r++) {
+ for (var c = 0; c < self.gridSize - 2; c++) {
+ if (!(self.grid[r][c] instanceof RustyBolt) && !(self.grid[r][c + 1] instanceof RustyBolt) && !(self.grid[r][c + 2] instanceof RustyBolt)) {
+ row = r;
+ col = c;
+ foundViablePosition = true;
+ break;
+ }
+ }
+ if (foundViablePosition) {
+ break;
+ }
+ }
+ if (!foundViablePosition) {
+ // No viable position found
+ return false;
+ }
+ }
+ // Create horizontal match
+ if (self.grid[row][col]) {
+ self.removeGearAt(row, col);
+ }
+ if (self.grid[row][col + 1]) {
+ self.removeGearAt(row, col + 1);
+ }
+ if (self.grid[row][col + 2]) {
+ self.removeGearAt(row, col + 2);
+ }
+ var gear1 = self.createRandomGear(row, col);
+ var gear2 = self.createRandomGear(row, col + 1);
+ var gear3 = self.createRandomGear(row, col + 2);
+ gear1.type = gear2.type = gear3.type = type;
+ // Flash effect on the new gears
+ LK.effects.flashObject(gear1, 0xFFD700, 500);
+ LK.effects.flashObject(gear2, 0xFFD700, 500);
+ LK.effects.flashObject(gear3, 0xFFD700, 500);
+ // Play sound
+ LK.getSound('ability_use').play();
+ } else {
+ // Create vertical match
+ if (self.grid[row][col]) {
+ self.removeGearAt(row, col);
+ }
+ if (self.grid[row + 1][col]) {
+ self.removeGearAt(row + 1, col);
+ }
+ if (self.grid[row + 2][col]) {
+ self.removeGearAt(row + 2, col);
+ }
+ var gear1 = self.createRandomGear(row, col);
+ var gear2 = self.createRandomGear(row + 1, col);
+ var gear3 = self.createRandomGear(row + 2, col);
+ gear1.type = gear2.type = gear3.type = type;
+ // Flash effect on the new gears
+ LK.effects.flashObject(gear1, 0xFFD700, 500);
+ LK.effects.flashObject(gear2, 0xFFD700, 500);
+ LK.effects.flashObject(gear3, 0xFFD700, 500);
+ // Play sound
+ LK.getSound('ability_use').play();
+ }
+ // Check for matches after a delay
+ LK.setTimeout(function () {
+ self.checkAndResolveMatches();
+ }, 700);
+ return true;
+ };
+ return self;
+});
+var Gear = Container.expand(function (type) {
+ var self = Container.call(this);
+ self.type = type || 'copper'; // Default to copper if no type specified
+ var color;
+ switch (self.type) {
+ case 'copper':
+ color = 'gear_copper';
+ break;
+ case 'steel':
+ color = 'gear_steel';
+ break;
+ case 'brass':
+ color = 'gear_brass';
+ break;
+ default:
+ color = 'gear_copper';
+ }
+ self.gearGraphic = self.attachAsset(color, {
+ anchorX: 0.5,
+ anchorY: 0.5,
+ scaleX: 0.9,
+ scaleY: 0.9
+ });
+ // Add teeth to make it look more like a gear
+ self.teethCount = 8;
+ self.radius = self.gearGraphic.width / 2;
+ // Apply a small rotation animation to make gears feel mechanical
+ self.rotationSpeed = Math.random() * 0.01 + 0.005;
+ if (Math.random() > 0.5) {
+ self.rotationSpeed *= -1;
+ } // Random direction
+ self.update = function () {
+ self.gearGraphic.rotation += self.rotationSpeed;
+ };
+ self.select = function () {
+ tween(self.gearGraphic, {
+ scaleX: 1.1,
+ scaleY: 1.1
+ }, {
+ duration: 200,
+ easing: tween.easeOut
+ });
+ LK.getSound('gear_select').play();
+ };
+ self.deselect = function () {
+ tween(self.gearGraphic, {
+ scaleX: 0.9,
+ scaleY: 0.9
+ }, {
+ duration: 200,
+ easing: tween.easeOut
+ });
+ };
+ self.matched = function () {
+ tween(self, {
+ alpha: 0
+ }, {
+ duration: 300,
+ easing: tween.easeOut,
+ onFinish: function onFinish() {
+ if (self.parent) {
+ self.parent.removeChild(self);
+ }
+ }
+ });
+ };
+ self.down = function (x, y, obj) {
+ gameBoard.handleGearClick(self);
+ };
+ return self;
+});
+var RustyBolt = Container.expand(function () {
+ var self = Container.call(this);
+ self.boltGraphic = self.attachAsset('rusty_bolt', {
+ anchorX: 0.5,
+ anchorY: 0.5
+ });
+ self.breakBolt = function () {
+ tween(self, {
+ alpha: 0
+ }, {
+ duration: 300,
+ easing: tween.easeOut,
+ onFinish: function onFinish() {
+ if (self.parent) {
+ self.parent.removeChild(self);
+ }
+ }
+ });
+ };
+ self.down = function (x, y, obj) {
+ // Rusty bolts cannot be selected
+ };
+ return self;
+});
+
+/****
* Initialize Game
-****/
+****/
var game = new LK.Game({
- backgroundColor: 0x000000
-});
\ No newline at end of file
+ backgroundColor: 0x2C3E50 // Dark blue-gray background
+});
+
+/****
+* Game Code
+****/
+// Game variables
+var score = 0;
+var currentLevel = storage.currentLevel || 1;
+var targetScore = currentLevel * 1000; // Score needed to complete the level
+var gameBoard;
+var boiler;
+// UI elements
+var scoreTxt = new Text2('0', {
+ size: 80,
+ fill: 0xFFFFFF
+});
+scoreTxt.anchor.set(0.5, 0);
+LK.gui.top.addChild(scoreTxt);
+scoreTxt.y = 50;
+var levelTxt = new Text2('Level: ' + currentLevel, {
+ size: 60,
+ fill: 0xFFFFFF
+});
+levelTxt.anchor.set(0, 0);
+LK.gui.topLeft.addChild(levelTxt);
+levelTxt.x = 120; // Leave space for menu icon
+levelTxt.y = 50;
+var targetTxt = new Text2('Target: ' + targetScore, {
+ size: 60,
+ fill: 0xFFFFFF
+});
+targetTxt.anchor.set(1, 0);
+LK.gui.topRight.addChild(targetTxt);
+targetTxt.y = 50;
+// Initialize game board
+gameBoard = new GameBoard();
+game.addChild(gameBoard);
+gameBoard.x = (2048 - gameBoard.boardSize) / 2;
+gameBoard.y = (2732 - gameBoard.boardSize) / 2;
+// Initialize boiler (steam pressure meter)
+boiler = new Boiler();
+game.addChild(boiler);
+boiler.x = 2048 / 2;
+boiler.y = 2732 - 200;
+// Fill the board with initial gears
+gameBoard.fillBoard();
+// Function to increase steam pressure
+function increasePressure(amount) {
+ boiler.updatePressure(boiler.currentPressure + amount);
+}
+// Play background music
+LK.playMusic('steampunk_bgm');
+// Main game update loop
+game.update = function () {
+ // Check if level is complete
+ if (score >= targetScore) {
+ // Level complete logic
+ currentLevel++;
+ storage.currentLevel = currentLevel;
+ // Update high score
+ if (score > storage.highScore) {
+ storage.highScore = score;
+ }
+ // Show win screen
+ LK.showYouWin();
+ }
+};
+// Global input handling
+game.down = function (x, y, obj) {
+ // Handle any global click events if needed
+};
+game.move = function (x, y, obj) {
+ // Handle any global move events if needed
+};
+game.up = function (x, y, obj) {
+ // Handle any global release events if needed
+};
\ No newline at end of file
латунная шестерня в стиле hand-paint. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
медная шестерня в стиле hand-paint. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
стальная шестерня в стиле hand-paint. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
ржавый болт в стиле hand-paint. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
котел в стиле hand-paint. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
A hand-painted, steampunk-style illustration of billowing steam and smoke, rich with warm copper tones and industrial textures. The vapor swirls dynamically around intricate brass gears and pipes, glowing with subtle orange highlights as if lit by flickering gaslight. The painting style should mimic traditional concept art with visible brush strokes, soft edges, and a slightly weathered, vintage feel. The background features hints of a dimly lit factory, with atmospheric perspective fading into deep browns and blues. The steam itself appears thick, almost liquid, with a mix of transparency and volumetric density, evoking a sense of pressurized heat. Artstation trending, fantasy illustration, painterly style, warm lighting. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows
фон для прогресс бара. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows