feat(qol & backup): add wave progress bar, hover collection, area explosion preview, hotkeys, auto-sync and json save export/import
This commit is contained in:
1 parent
7cd0792799
commit
23918dab1f
7 files changed
+710
-38
No files matched your search
+140
-1
@@ -313,7 +313,12 @@ window.GridSystem = class GridSystem {
|
||||
this.drawGravestone(ctx, bounds.centerX, bounds.centerY);
|
||||
}
|
||||
|
||||
// 3. Hover effect
|
||||
// 2.5 Area / Range Preview Highlight (Cherry Bomb 3x3, Jalapeno row, Potato Mine, Doom-shroom 5x5)
|
||||
if (hoverCell && selectedPlantType) {
|
||||
this.drawAreaPreview(ctx, hoverCell, selectedPlantType);
|
||||
}
|
||||
|
||||
// 3. Hover placement indicator
|
||||
if (hoverCell && selectedPlantType) {
|
||||
const bounds = this.getCellBounds(hoverCell.col, hoverCell.row);
|
||||
const isWater = this.isWaterCell(hoverCell.row);
|
||||
@@ -560,4 +565,138 @@ window.GridSystem = class GridSystem {
|
||||
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
drawAreaPreview(ctx, hoverCell, selectedPlantType) {
|
||||
if (!hoverCell || !selectedPlantType) return;
|
||||
|
||||
ctx.save();
|
||||
|
||||
// 1. Cherry Bomb / Bowling Cherry: 3x3 explosion area
|
||||
if (selectedPlantType === 'cherrybomb' || selectedPlantType === 'bowling_cherry') {
|
||||
const minCol = Math.max(0, hoverCell.col - 1);
|
||||
const maxCol = Math.min(this.cols - 1, hoverCell.col + 1);
|
||||
const minRow = Math.max(0, hoverCell.row - 1);
|
||||
const maxRow = Math.min(this.rows - 1, hoverCell.row + 1);
|
||||
|
||||
// Fill affected tiles
|
||||
for (let r = minRow; r <= maxRow; r++) {
|
||||
for (let c = minCol; c <= maxCol; c++) {
|
||||
const b = this.getCellBounds(c, r);
|
||||
ctx.fillStyle = 'rgba(255, 87, 34, 0.28)';
|
||||
ctx.fillRect(b.x, b.y, b.w, b.h);
|
||||
ctx.strokeStyle = 'rgba(255, 112, 67, 0.45)';
|
||||
ctx.lineWidth = 1;
|
||||
ctx.strokeRect(b.x + 1, b.y + 1, b.w - 2, b.h - 2);
|
||||
}
|
||||
}
|
||||
|
||||
// Enclosing blast perimeter
|
||||
const tl = this.getCellBounds(minCol, minRow);
|
||||
const br = this.getCellBounds(maxCol, maxRow);
|
||||
const areaW = (br.x + br.w) - tl.x;
|
||||
const areaH = (br.y + br.h) - tl.y;
|
||||
|
||||
ctx.strokeStyle = '#ff3d00';
|
||||
ctx.lineWidth = 2.5;
|
||||
ctx.setLineDash([8, 4]);
|
||||
ctx.strokeRect(tl.x, tl.y, areaW, areaH);
|
||||
ctx.setLineDash([]);
|
||||
|
||||
ctx.fillStyle = '#ff1744';
|
||||
ctx.font = 'bold 11px sans-serif';
|
||||
ctx.textAlign = 'left';
|
||||
ctx.shadowColor = '#000000';
|
||||
ctx.shadowBlur = 4;
|
||||
ctx.fillText('💥 ЗОНА ВЗРЫВА 3х3', tl.x + 6, tl.y - 4);
|
||||
}
|
||||
// 2. Jalapeno: Entire Row Lane
|
||||
else if (selectedPlantType === 'jalapeno') {
|
||||
const r = hoverCell.row;
|
||||
const startX = this.startX;
|
||||
const totalW = this.cols * this.cellW;
|
||||
const y = this.startY + r * this.cellH;
|
||||
const h = this.cellH;
|
||||
|
||||
ctx.fillStyle = 'rgba(244, 67, 54, 0.28)';
|
||||
ctx.fillRect(startX, y, totalW, h);
|
||||
|
||||
// Fiery boundary lines
|
||||
ctx.strokeStyle = '#ff5722';
|
||||
ctx.lineWidth = 2.5;
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(startX, y);
|
||||
ctx.lineTo(startX + totalW, y);
|
||||
ctx.moveTo(startX, y + h);
|
||||
ctx.lineTo(startX + totalW, y + h);
|
||||
ctx.stroke();
|
||||
|
||||
ctx.fillStyle = '#ff3d00';
|
||||
ctx.font = 'bold 11px sans-serif';
|
||||
ctx.textAlign = 'left';
|
||||
ctx.shadowColor = '#000000';
|
||||
ctx.shadowBlur = 4;
|
||||
ctx.fillText('🔥 ОГНЕННАЯ ЛИНИЯ ПО ВСЕЙ ПОЛОСЕ', startX + 6, y - 4);
|
||||
}
|
||||
// 3. Potato Mine: Single tile armed trigger zone
|
||||
else if (selectedPlantType === 'potatomine') {
|
||||
const b = this.getCellBounds(hoverCell.col, hoverCell.row);
|
||||
ctx.fillStyle = 'rgba(255, 193, 7, 0.25)';
|
||||
ctx.fillRect(b.x, b.y, b.w, b.h);
|
||||
|
||||
ctx.strokeStyle = '#ffb300';
|
||||
ctx.lineWidth = 2;
|
||||
ctx.setLineDash([4, 4]);
|
||||
ctx.strokeRect(b.x + 3, b.y + 3, b.w - 6, b.h - 6);
|
||||
ctx.setLineDash([]);
|
||||
|
||||
// Crosshair / target marker in tile center
|
||||
ctx.strokeStyle = 'rgba(255, 179, 0, 0.6)';
|
||||
ctx.lineWidth = 1.5;
|
||||
ctx.beginPath();
|
||||
ctx.arc(b.centerX, b.centerY, 18, 0, Math.PI * 2);
|
||||
ctx.stroke();
|
||||
|
||||
ctx.fillStyle = '#ffa000';
|
||||
ctx.font = 'bold 10px sans-serif';
|
||||
ctx.textAlign = 'center';
|
||||
ctx.shadowColor = '#000000';
|
||||
ctx.shadowBlur = 3;
|
||||
ctx.fillText('💣 МИНА', b.centerX, b.y - 3);
|
||||
}
|
||||
// 4. Doom-shroom: Large 5x5 blast area
|
||||
else if (selectedPlantType === 'doomshroom') {
|
||||
const minCol = Math.max(0, hoverCell.col - 2);
|
||||
const maxCol = Math.min(this.cols - 1, hoverCell.col + 2);
|
||||
const minRow = Math.max(0, hoverCell.row - 2);
|
||||
const maxRow = Math.min(this.rows - 1, hoverCell.row + 2);
|
||||
|
||||
for (let r = minRow; r <= maxRow; r++) {
|
||||
for (let c = minCol; c <= maxCol; c++) {
|
||||
const b = this.getCellBounds(c, r);
|
||||
ctx.fillStyle = 'rgba(156, 39, 176, 0.28)';
|
||||
ctx.fillRect(b.x, b.y, b.w, b.h);
|
||||
}
|
||||
}
|
||||
|
||||
const tl = this.getCellBounds(minCol, minRow);
|
||||
const br = this.getCellBounds(maxCol, maxRow);
|
||||
const areaW = (br.x + br.w) - tl.x;
|
||||
const areaH = (br.y + br.h) - tl.y;
|
||||
|
||||
ctx.strokeStyle = '#ab47bc';
|
||||
ctx.lineWidth = 2.5;
|
||||
ctx.setLineDash([8, 4]);
|
||||
ctx.strokeRect(tl.x, tl.y, areaW, areaH);
|
||||
ctx.setLineDash([]);
|
||||
|
||||
ctx.fillStyle = '#ba68c8';
|
||||
ctx.font = 'bold 11px sans-serif';
|
||||
ctx.textAlign = 'left';
|
||||
ctx.shadowColor = '#000000';
|
||||
ctx.shadowBlur = 4;
|
||||
ctx.fillText('☢️ ЯДЕРНЫЙ ВЗРЫВ 5х5', tl.x + 6, tl.y - 4);
|
||||
}
|
||||
|
||||
ctx.restore();
|
||||
}
|
||||
};
|
||||
Reference in new issue
Block a user