export let grid = createGrid(10, 10); // Example grid size
export let player = {
position: { x: 0, y: 0 },
inventory: [],
health: 10,
power: 10,
level: 0,
steps: 0,
par: 0,
didScan: false,
flashing: false
};
let targetPosition = { x: 0, y: 0 };
export let levelPar;
function createGrid(rows, cols) {
let grid = [];
for (let i = 0; i < rows; i++) {
let row = [];
for (let j = 0; j < cols; j++) {
row.push(null);
}
grid.push(row);
}
return grid;
}
function generatePar(level) {
let par;
if (level < 4) {
par = 7;
} else {
par = Math.floor(Math.random() * 7) + 1;
}
updatePlayerStatus();
return par;
}
function generateCollectables(grid, numCollectables) {
const collectableTypes = ['potion', 'shield', 'battery'];
const collectableColors = {
'potion': 'peachpuff',
'shield': 'cornflowerBlue',
'battery': 'gold'
};
for (let i = 0; i < numCollectables; i++) {
let x, y;
do {
x = Math.floor(Math.random() * grid.length);
y = Math.floor(Math.random() * grid[0].length);
} while (x === 0 && y === 0); // don't put items at (0,0)
const type = collectableTypes[Math.floor(Math.random() * collectableTypes.length)];
grid[x][y] = { type, color: collectableColors[type] };
}
}
function generateDamagingSpaces(grid, numSpaces) {
for (let i = 0; i < numSpaces; i++) {
let x, y;
do {
x = Math.floor(Math.random() * grid.length);
y = Math.floor(Math.random() * grid[0].length);
} while (x === 0 && y === 0); // don't put damaging stuff at (0,0)
grid[x][y] = { type: 'damage', color: 'tomato' };
}
}
function generateTraps(grid, numTraps) {
for (let i = 0; i < numTraps; i++) {
let x, y;
do {
x = Math.floor(Math.random() * grid.length);
y = Math.floor(Math.random() * grid[0].length);
} while (x === 0 && y === 0); // don't be an asshole
grid[x][y] = { type: 'trap', color: 'rgba(0,0,0,0)' };
}
}
function generateTargetBlock(grid) {
let x, y;
do {
x = Math.floor(Math.random() * grid.length);
y = Math.floor(Math.random() * grid[0].length);
} while (x === 0 && y === 0); // don't make it too easy
grid[x][y] = { type: 'target', color: 'lightgreen' }; // x marks the spot!
targetPosition = { x, y };
}
export function drawGrid(grid) {
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
const cellSize = Math.min(canvas.width / grid.length, canvas.height / grid[0].length);
ctx.clearRect(0, 0, canvas.width, canvas.height);
grid.forEach((row, x) => {
row.forEach((cell, y) => {
ctx.strokeStyle = '#2d2d2d';
ctx.strokeRect(x * cellSize, y * cellSize, cellSize, cellSize);
if (cell && cell.color) {
ctx.fillStyle = cell.color;
ctx.fillRect(x * cellSize, y * cellSize, cellSize, cellSize);
ctx.fillStyle = '#2d2d2d';
ctx.font = `${cellSize / 2}px Arial`;
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
let char = '';
if (cell.type === 'potion') char = 'p';
if (cell.type === 'shield') char = 's';
if (cell.type === 'battery') char = 'b';
if (cell.type === 'damage') char = '!';
if (cell.type === 'target') char = '#';
if (cell.type === 'trap' && player.didScan) char = 't';
ctx.fillText(char, x * cellSize + cellSize / 2, y * cellSize + cellSize / 2);
}
});
});
// Draw player
ctx.fillStyle = player.flashing ? 'white' : 'thistle';
ctx.fillRect(player.position.x * cellSize, player.position.y * cellSize, cellSize, cellSize);
ctx.fillStyle = '#2d2d2d';
ctx.font = `${cellSize / 2}px Arial`;
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText('@', player.position.x * cellSize + cellSize / 2, player.position.y * cellSize + cellSize / 2);
}
export function initializeGame() {
grid = createGrid(10, 10); // reset grid
levelPar = generatePar(player.level);
generateCollectables(grid, Math.floor(Math.random() * 7) + 1); // how many collectables?
generateDamagingSpaces(grid, Math.floor(Math.random() * 22) + 1); // random number of damaging spaces, no more than 22
generateTargetBlock(grid);
generateTraps(grid, Math.floor(Math.random() * 10) + 1); // random number of traps, no more than 10
if (player.level === 0) {
player.inventory = [];
player.health = 10;
player.power = 10;
}
player.par = 0; // always reset player par to 0
player.position = { x: 0, y: 0 }; // player always starts at 0,0
player.steps = 0; // steps are counted per-level
player.didScan = false; // scans are counted per-level
resizeCanvas();
drawGrid(grid);
updatePlayerStatus();
}
export function resizeCanvas() {
const canvas = document.getElementById('gameCanvas');
const width = Math.min(window.innerWidth, window.innerHeight) * 0.5;
canvas.width = width;
canvas.height = width;
drawGrid(grid);
}
export function updatePlayerPosition(newX, newY) {
player.position.x = newX;
player.position.y = newY;
checkForDamageOrTarget();
drawGrid(grid);
updatePlayerStatus();
}
export function updatePlayerStatus() {
document.getElementById('par').textContent = `Par: ${player.par} : ${levelPar}`;
document.getElementById('playerPosition').textContent = `Position: (${player.position.x}, ${player.position.y})`;
document.getElementById('playerHealth').textContent = `Health: ${player.health}`;
document.getElementById('playerPower').textContent = `Power: ${player.power}`;
document.getElementById('playerLevel').textContent = `Level: ${player.level}`;
const inventoryCounts = player.inventory.reduce((acc, item) => {
acc[item] = acc[item] ? acc[item] + 1 : 1;
return acc;
}, {});
const inventoryString = Object.entries(inventoryCounts).map(([item, count]) => `${item} ${count}`).join(', ');
document.getElementById('playerInventory').textContent = `Inventory: ${inventoryString}`;
}
function checkForDamageOrTarget() {
const { x, y } = player.position;
const cell = grid[x][y];
if (cell && cell.type === 'damage') {
const shieldIndex = player.inventory.indexOf('shield');
if (shieldIndex > -1) {
player.inventory.splice(shieldIndex, 1); // Use one shield
console.log('Used shield to avoid damage');
} else {
player.health -= 2;
console.log(`Stepped on damaging space, health is now ${player.health}`);
if (player.health <= 0) {
alertGameOver();
return;
}
flashPlayer();
}
} else if (cell && cell.type === 'trap') {
const itemIndex = Math.floor(Math.random() * player.inventory.length);
player.inventory.splice(itemIndex, 1);
console.log(`Stepped on a trap and lost an item`);
player.health -= Math.floor(Math.random() * 5) + 1;
console.log(`Stepped on a trap and took damage, health is now ${player.health}`);
if (player.health <= 0) {
alertGameOver();
return;
} else {
alert('Ouch! You hit a trap.');
flashPlayer();
}
} else if (x === targetPosition.x && y === targetPosition.y) {
player.level += 1;
console.log(`Reached target block, level is now ${player.level}`);
initializeGame(); // generate a new level and reset player position to 0,0
}
}
export function alertGameOver() {
const gameStatsString = `Level: ${player.level}, Par: ${player.par} : ${levelPar}, Health: ${player.health}, Power: ${player.power}`;
alert('Game Over' + '\n' + gameStatsString);
player.level = 0;
initializeGame();
}