summary refs log tree commit diff stats
path: root/Makefile
diff options
context:
space:
mode:
authorhut <hut@lavabit.com>2010-04-14 13:39:18 +0200
committerhut <hut@lavabit.com>2010-04-14 13:39:18 +0200
commit729286d7489f9a65550848935ebe65e3eaef095b (patch)
tree289bd7266cf585ebe87ef0f6db35cb575e0e4bae /Makefile
parent337c6d63361dddc665cfcb133a045b27f331b479 (diff)
downloadranger-729286d7489f9a65550848935ebe65e3eaef095b.tar.gz
identify devices and handle them properly
Diffstat (limited to 'Makefile')
0 files changed, 0 insertions, 0 deletions
f='#n103'>103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387
// Setup the canvas
// This'll be where the game is drawn
// Everything below is configured in relation to the canvas' size
// The canvas is 512px wide and 512px high, which makes for easier math
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
canvas.width = 512;
canvas.height = 512;
const startingX = 0;
const startingY = 0;





// Misc. helpers
const camera = {
  x: startingX,
  y: startingY,
  width: canvas.width,
  height: canvas.height
};

const cons = ["b", "c", "d", "f", "g", "h", "j", "k", "l", "m", "n", "p", "r", "s", "t", "v", "w", "z", "ch", "sh", "zh", "th"];
const vow = ["a", "e", "i", "o", "u", "y", "ee", "ai", "ae", "au"];
const rpick = t => t[Math.floor(Math.random() * t.length)];
const syl = () => rpick(cons) + rpick(vow);
const word = () => {
  const syllables = Array(Math.floor(Math.random() * 3) + 1).fill(null).map(() => syl()).join('');
  return Math.random() > 0.2 ? syllables + rpick(cons) : syllables;
};
const speak = numberOfWords => Array(numberOfWords).fill(null).map(() => word()).join(' ');






// Create the player
// This object tracks all information about the player chracter
const player = {
    x: startingX,       // X coordinate on the canvas
    y: startingY,       // Y coordinate on the canvas
    width: 8,           // Width of the player
    height: 8,          // Height of the player
    step: 8,            // How many pixels the player moves per step
    color: 'blue',      // Color of the player
    spriteUrl: "chickadee.svg"  // Sprite of the player, if any
};

// Player inventory and inventory mangement
player.inventory = [];
player.collectItem = function(item) {
  this.inventory.push(item);
}
player.dropItem = function(item) {
  const itemIndex = this.inventory.indexOf(item);
  if (itemIndex > -1) {
    this.inventory.splice(itemIndex, 1);
  }
}

// If you wanna have a sprite, you need to create an image object
const playerSprite = new Image();
playerSprite.src = player.spriteUrl;






// Map
const TILE_SIZE = 64;
const map = [
    [{ walkable: true, color: 'pink' }, { walkable: false, color: 'grey' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }],
    [{ walkable: true, color: 'pink' }, { walkable: false, color: 'grey' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: false, color: 'grey' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }],
    [{ walkable: true, color: 'pink' }, { walkable: false, color: 'grey' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }],
    [{ walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: false, color: 'grey' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }],
    [{ walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: false, color: 'grey' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }],
    [{ walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }],
    [{ walkable: true, color: 'pink' }, { walkable: false, color: 'grey' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: false, color: 'grey' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }],
    [{ walkable: true, color: 'pink' }, { walkable: false, color: 'grey' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }],
    [{ walkable: true, color: 'pink' }, { walkable: false, color: 'grey' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: false, color: 'grey' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }],
    [{ walkable: true, color: 'pink' }, { walkable: false, color: 'grey' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }],
    [{ walkable: true, color: 'pink' }, { walkable: false, color: 'grey' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: false, color: 'grey' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }],
    [{ walkable: true, color: 'pink' }, { walkable: false, color: 'grey' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }, { walkable: true, color: 'pink' }]
];






// Items
function Item(name, x, y, type, color) {
  this.name = name;
  this.x = x;
  this.y = y;
  this.type = type;
  this.color = color;
}

// Create some bespoke items
let items = [
  new Item('helmet', 16, 16, 'clothes', 'red'),
  new Item('banana', 24, 128, 'food', 'yellow'),
  new Item('bucket', 128, 256, 'object', 'green'),
  new Item('big key', 216, 216, 'key', 'cyan'),
  new Item('small key', 456, 256, 'key', 'cyan'),
  new Item('bike', 0, 48, 'bike', 'orange'),
];

// Populate the world with really very weird objects
// FIXME: update this so that items aren't always placed within the 0x0 space of a tile
const appendRandomItems = () => {
  const getRandomColor = () => '#' + Math.floor(Math.random() * 16777215).toString(16);
  const getRandomName = () => speak(Math.floor(Math.random() * 3) + 1);
  const getRandomCoordinates = () => {
    let x, y;
    do {
      x = Math.floor(Math.random() * (map[0].length - 2)) + 1;
      y = Math.floor(Math.random() * (map.length - 2)) + 1;
    } while (!map[y][x].walkable);
    return { x, y };
  };
  const createRandomItem = () => {
    const { x, y } = getRandomCoordinates();
    const name = getRandomName();
    const color = getRandomColor();
    return new Item(name, x * TILE_SIZE, y * TILE_SIZE, 'mystery', color);
  };
  const numberOfItems = Math.floor(Math.random() * 39);
  const randomItems = Array.from({ length: numberOfItems }, createRandomItem);
  items.push(...randomItems);
};

function checkForSpecialItems() {
  if (player.inventory.find(item => item.type === 'bike')) {
    player.step = 12;
  } else {
    player.step = 8;
  }
}





// Define the Sign class
function Sign(x, y, width, height, message) {
  this.x = x;
  this.y = y;
  this.width = width;
  this.height = height;
  this.message = message;
}

// Create some signs
let signs = [
  new Sign(34, 38, player.width, player.height, speak(3).toUpperCase()),
  new Sign(28, 64, player.width, player.height, 'Welcome to the game!'),
  new Sign(128, 128, player.width, player.height, 'You cannot pass through walls!'),
  new Sign(24, 212, player.width, player.height, 'You can collect items!'),
  new Sign(428, 712, player.width, player.height, 'This sign has very long text that will wrap around to the next line!'),
  new Sign(28, 712, player.width, player.height, 'This sign is very far away.'),
];





// Display the player's stats, useful for debugging
function displayStats() {
  document.getElementById("stats").innerHTML = "";
  for (let stat in player) {
    if (typeof player[stat] === "string" || typeof player[stat] === "number") {
      if (player[stat] !== player.spriteUrl) {
        document.getElementById("stats").innerHTML += stat + ": " + player[stat] + "<br>";
      }
    }
  }
  document.getElementById("stats").innerHTML += "Inventory: ";
  for (let i = 0; i < player.inventory.length; i++) {
    document.getElementById("stats").innerHTML += player.inventory[i].name + ", ";
  }
}






// Game loop
function gameLoop() {
  // Update the camera position to follow the player
  camera.x = player.x - camera.width / 2;
  camera.y = player.y - camera.height / 2;

  // Clamp the camera position to the map boundaries
  camera.x = Math.max(0, Math.min(map[0].length * TILE_SIZE - camera.width, camera.x));
  camera.y = Math.max(0, Math.min(map.length * TILE_SIZE - camera.height, camera.y));

  // Draw the map
  map.forEach((row, y) => {
    row.forEach((tile, x) => {
      ctx.fillStyle = tile.color;

      // Draw the tile
      ctx.fillRect(x * TILE_SIZE - camera.x, y * TILE_SIZE - camera.y, TILE_SIZE, TILE_SIZE);

      // Draw the grid
      ctx.strokeStyle = 'white';
      ctx.lineWidth = 1;
      ctx.strokeRect(x * TILE_SIZE - camera.x, y * TILE_SIZE - camera.y, TILE_SIZE, TILE_SIZE);
    });
  });

  // Draw the player
  ctx.fillStyle = player.color;
  ctx.fillRect(player.x - camera.x, player.y - camera.y, player.width, player.height);

  // Draw items and check for collisions
  items.forEach(item => {
    ctx.fillStyle = item.color;
    ctx.fillRect(item.x - camera.x, item.y - camera.y, player.width, player.height);
  });
  items = items.filter(item => {
    if (player.x === item.x && player.y === item.y) {
      player.collectItem(item);
      return false; // Remove the item from the map
    }
    return true;
  });

  checkForSpecialItems();


  // Draw signs and check for collisions
  signs.forEach(sign => {
    const dx = player.x - sign.x;
    const dy = player.y - sign.y;
    const distance = Math.sqrt(dx * dx + dy * dy);

    if (distance < player.width / 2 + sign.width / 2) {
      document.getElementById("dialog").innerHTML = sign.message;

      ctx.fillStyle = 'black';
      ctx.font = '22px Serif';

      // Calculate the starting position of the text
      const lineHeight = 24;

      // Calculate the starting position of the text within the sign
      const textWidth = ctx.measureText(sign.message).width;
      const textHeight = lineHeight;
      const startX = sign.x - camera.x + (sign.width - textWidth) / 2;
      const startYWithinSign = sign.y - camera.y + (sign.height - textHeight) / 2;

      // Calculate the final position of the text within the canvas area
      const padding = 12; // Set the desired padding value
      const finalX = Math.max(padding, Math.min(canvas.width - textWidth - padding, startX));
      const finalY = Math.max(padding, Math.min(canvas.height - textHeight - padding, startYWithinSign));

      // Wrap the text to multiple lines if it exceeds the canvas width
      const words = sign.message.split(' ');
      let line = '';
      let lines = [];
      for (let i = 0; i < words.length; i++) {
        const testLine = line + words[i] + ' ';
        const testWidth = ctx.measureText(testLine).width;
        if (testWidth > canvas.width - padding * 2) {
          lines.push(line);
          line = words[i] + ' ';
        } else {
          line = testLine;
        }
      }
      lines.push(line);

      // Draw each line of the text
      for (let i = 0; i < lines.length; i++) {
        ctx.fillText(lines[i], finalX, finalY + i * lineHeight);
      }
    }

    ctx.fillStyle = 'brown';
    ctx.beginPath();
    ctx.arc(sign.x - camera.x + sign.width / 2, sign.y - camera.y + sign.height / 2, sign.width / 2, 0, Math.PI * 2);
    ctx.fill();
  });

  // Call the game loop again next frame
  requestAnimationFrame(gameLoop);
  displayStats();
}






// Start the game loop
gameLoop();






// Handle user input
window.addEventListener('keydown', (e) => {
    let newX = player.x;
    let newY = player.y;
  
    switch (e.key) {
      case 'ArrowUp':
      case 'w':
      case 'k':
        newY -= player.step;
        break;
      case 'ArrowDown':
      case 's':
      case 'j':
        newY += player.step;
        break;
      case 'ArrowLeft':
      case 'a':
      case 'h':
        newX -= player.step;
        break;
      case 'ArrowRight':
      case 'd':
      case 'l':
        newX += player.step;
        break;
      case 'z':
      case 'n':
        player.inventory.forEach(item => {
          player.dropItem(item);
          items.push(item);
        });
        break;
      case 'x':
      case 'm':
        player.color = '#' + Math.floor(Math.random()*16777215).toString(16);
        break;
      case 'q':
      case 'p':
        player.color = 'blue';
        break;
    // Add this code where you handle the 'i' key press
    case 'i':
      // Create a menu element
      const menu = document.createElement('div');
      menu.style.position = 'fixed';
      menu.style.left = '10px';
      menu.style.top = '10px';
      menu.style.backgroundColor = 'white';
      menu.style.padding = '10px';
      document.body.appendChild(menu);

      // Add each inventory item to the menu
      player.inventory.forEach((item) => {
        const itemElement = document.createElement('div');
        itemElement.textContent = item.type;
        itemElement.style.cursor = 'pointer';
        itemElement.addEventListener('click', () => {
          player.dropItem(item);
          items.push(item);
          menu.remove(); // Remove the entire menu
        });
        menu.appendChild(itemElement);
      });
      break;
    }
  
    // Calculate the tile coordinates
    const tileX = Math.floor(newX / TILE_SIZE);
    const tileY = Math.floor(newY / TILE_SIZE);
  
    // Only update the player's position if the tile is walkable
    if (map[tileY] && map[tileY][tileX] && map[tileY][tileX].walkable) {
      player.x = newX;
      player.y = newY;
    }
});