Mercurial > maze-src
view game.js @ 0:1eef88068f9f tip
initial commit of maze game source
| author | ferencd |
|---|---|
| date | Sun, 15 Sep 2019 11:46:47 +0200 |
| parents | |
| children |
line wrap: on
line source
const pic_size = 64; // The size of 1 cell in the maze // initial position of the player is always: (0,0) ie. 12px 12px considering the wall size the the top and left let x = 12; let y = 12; // moving direction of the player var x_delta = 0; var y_delta = 0; // player location in grid var col = 0; // The column in the maze where the player is var row = 0; // The row in the maze where the player is // Prepare the canvas var canvas = document.getElementById("canvas"); var canvas_container = document.getElementById("canvasdiv"); var context = canvas.getContext('2d'); // canvas size calculation var canvas_calc_width = w * pic_size ; var canvas_calc_height = h * pic_size; canvas.style.width = canvas_calc_width + "px"; canvas.style.height = canvas_calc_height + "px"; canvas.width = canvas_calc_width; canvas.height = canvas_calc_height; // Approximates the last row/col drawn for the canvas scrolling var last_row_drawn = canvas_container.offsetHeight / pic_size; var first_row_drawn = 0; var last_col_drawn = canvas_container.offsetWidth / pic_size; var first_col_drawn = 0; // fill the canvas with black context.fillStyle = "black"; context.fillRect(0, 0, canvas.width, canvas.height); // constants for direction checking const N = 1; const S = 2; const E = 4; const W = 8; // Corner constants, to know where to put a torch const TOP_LEFT = 1; const TOP_RIGHT = 2; const BOTTOM_LEFT = 4; const BOTTOM_RIGHT = 8; // How far must we be from the maze edge to trigger scrolling const MAZE_EDGE_DISTANCE_SCROLL_TRIGGER = 4; // How much we can see from the maze var LIGHT_RADIUS = 3; // how the maze looks const FULL_FOG = 0; const FULL_DRAWN = 1; const FOG_DRAWN = 2; // indexes of the various directions the player can go const MOVE_IDX_LEFT = 0; const MOVE_IDX_UP = 1; const MOVE_IDX_RIGHT = 2; const MOVE_IDX_DOWN = 3; // Player state: Dead/Alive const PLAYER_ALIVE = 1; const PLAYER_DIED = 2; var player_state = PLAYER_ALIVE; // Player weapon const WEAPON_NONE = -1; const WEAPON_SPEAR = 0; var player_weapon = WEAPON_NONE; // Player armor const ARMOR_NONE = -1; const ARMOR_CHAINMAIL = 1; const SHOES = 2; const RING = 3; var player_armor = ARMOR_NONE; // whether we remove life from steps or not const STEPS_COST = 0; // each step is 1 life const STEPS_FREE = 1; // steps do not cost 1 life const STEPS_SICK = 2; // player is sick, steps cost 2 life var player_steps = STEPS_COST; var step_count = 0; const TIME_HAS_EFFECT = 0; const TIME_HAS_NO_EFFECT = 1; var time_effect = TIME_HAS_EFFECT; const GAME_SUSPENDED = 1; const GAME_RUNNING = 0; var game_state = GAME_SUSPENDED; var time_passing_timeout = null; // These correspond to specific igw types: // 0 - empty handed skeleton. Can be killed with SPEAR or anything above // 1 - skeleton with spear. Can be killed with Spear but only if player has armor // 2 - skeleton with bow. Does not move, just shoots. Can be killed with spear and armor // 3 - skeletong with spear and armor. Cannot be killed function init_maze_draw_array() { var r = new Array(h); for(var j=0; j<h; j++) { r[j] = new Array(w); for(var i=0; i<w; i++) { r[j][i] = FULL_FOG; } } return r; } function update_step_visuals() { document.getElementById("steps_passed").innerHTML = " Steps: " + step_count.toString(); } function update_life_visuals(current_life) { document.getElementById("energy").innerHTML = current_life.toString(); document.getElementById("lifeprg").value = current_life; } var dying_plyr_img_idx = 0; var killer_igwidx = -1; var dancing_kille_igw = 0; var dancing_mod = 0; var death_wall_drawn = false; var skdc = 0; // skeleton dancer index, ie. the one rotating the skeleton function player_dies() { context.putImageData(imgDataPrev, x, y); // clear canvas if (dying_plyr_img_idx < 6) { context.drawImage(dying_player[dying_plyr_img_idx], x, y); dying_plyr_img_idx ++; } if(killer_igwidx !== -1) { if (!death_wall_drawn) { draw_a_wall(row, col); death_wall_drawn = true; } dancing_mod ++; context.drawImage(skel_dancer[skdc][dancing_kille_igw], x, y); if(dancing_mod % 3) { dancing_kille_igw++; if(dancing_kille_igw === 6) { dancing_kille_igw = 0; skdc ++; if(skdc === 4) { skdc = 0; } } } } requestAnimationFrame(player_dies); } function kill_igw(i) { igw[i].state = DEAD; var current_kills = parseInt(document.getElementById("skels_killed").innerHTML); current_kills ++; document.getElementById("skels_killed").innerHTML = current_kills.toString(); } var go_texts=["Maybe you shouldn't have had eaten that mushroom.<p>Not all food is safe down here.", "The <img src='/img/skel/wl/d_wl_1.png' title='... it is a spear ...' style='vertical-align:middle;'> is an easy prey when you have a <img src='/img/weapons/spear.png' title='... it is a spear ...' style='vertical-align:middle;'>.<p>Wearing <img src='/img/weapons/armor.png' title='... the chainmail ...' style='vertical-align:middle;'> also increases your chance of survival.<p>Otherwise ... you are easy prey to them.", "You definitely should have eaten something on the way.<p>Finding the <img src='/img/weapons/shoe.png' title='Boots of Lightness' style='vertical-align:middle;'> and the <img src='/img/weapons/ring.png' title='Ring of Health' style='vertical-align:middle;'> also helps.", leave_text ]; const GO_BAD_FOOD = 1; const GO_SKELETON = 2; const GO_FATIGUE = 3; const GO_LEVEL_DONE = 4; // reason: 1 = player died since he ate something he wasn't supposed to // 2 = player was killed by a skeleton // 3 = fatigue // 4 = player finished the current level function game_over(reason, i) { if(reason === GO_SKELETON) { killer_igwidx = i; context.putImageData(igw[killer_igwidx].savedImage, igw[killer_igwidx].x, igw[killer_igwidx].y); } document.getElementById("goimg").style.visibility = 'visible'; var final_message = go_texts[reason - 1]; if(reason !== GO_LEVEL_DONE) { update_life_visuals(0); player_dies(); draw_a_wall(row,col); context.drawImage(dying_player[5], x, y); final_message += story_text; document.getElementById("goimg").src ="/img/gameover.png"; player_state = PLAYER_DIED; } else { document.getElementById('gonextlevel').style.visibility='visible'; clearTimeout(time_passing_timeout); } if(game_type === GAME_TYPE_TIMERUN) { final_message += "<p>" + document.getElementById("time_passed").innerHTML; } document.getElementById("messages").style.visibility = 'visible'; document.getElementById("messages").style.display = 'block'; document.getElementById("gotext1").style.visibility = 'visible'; document.getElementById("gotext1").innerHTML = final_message; document.getElementById("gospan").style.visibility = 'hidden'; document.getElementById("sysmenu").style.visibility = 'hidden'; game_state = GAME_SUSPENDED; } var maze_stats = init_maze_draw_array(); function point_in_circle(center_x, center_y, radius, x, y) { var D = Math.sqrt(Math.pow(center_x - x, 2) + Math.pow(center_y - y, 2)); return D <= radius } function draw_torches(next) { for(var i=0; i<torches.length; i++) { if(next) { torches[i].ctr ++; } if(torches[i].ctr % 5 === 0) { context.putImageData(torches[i].backgr, torches[i].x, torches[i].y); if(next) { torches[i].anim_idx ++; } if(torches[i].anim_idx === 3 && next) { torches[i].anim_idx = 0; } context.drawImage(torch_images[torches[i].anim_idx], torches[i].x, torches[i].y); } } } function draw_a_wall(saver, savec) { if(maze_stats[saver][savec] === FULL_FOG) { return; } if(maze_stats[saver][savec] === FULL_DRAWN) { var current_wall = wall_images[ maze[saver][savec] ]; // Any door here? let door_t = door_at(savec, saver); if( door_t !== -1 ) { current_wall = get_doored_wall(maze[saver][savec], door_t); } context.drawImage(current_wall, savec * pic_size, saver * pic_size); draw_extra_objects(saver, savec, savec * pic_size, saver * pic_size); } else { context.drawImage(fog_drawn_wall_images[ maze[saver][savec] ], savec * pic_size, saver * pic_size); } } // The torch animations var torches = []; var top_btm_chooser = []; top_btm_chooser[0] = top_closed_doors; top_btm_chooser[1] = bottom_closed_doors; var small_fellow = new Image(); small_fellow.src = '/img/funnyfellow.png'; // index is the number of the cell we are looking for, type is whether the door is on // the top part of the cell (0) or the bottom part (1) function get_doored_wall(index, type) { if(type !== 5) { for(var i=0; i<top_btm_chooser[type].length; i++) { if(top_btm_chooser[type][i].idx === index) { return top_btm_chooser[type][i].img; } } return wall_images[ index ]; } else { return stairs_down[index]; } } // returns the torch type number if we have a torch at this location function have_torch_here(ii, jj) { for(var i=0; i<torch_placements.length; i++) { if(torch_placements[i].i === ii && torch_placements[i].j === jj) { return torch_placements[i].p } } return 0; } // returns the food type number if we have a food item at this location function have_food_here(r, c) { for(var i=0; i<food.length; i++) { if(food[i].r === r && food[i].c === c) { return food[i].t; } } return -1; } function have_loot_here(r, c) { for(var i=0; i<loot.length; i++) { if(loot[i].r === r && loot[i].c === c) { return loot[i].t; } } return -1; } function draw_food(x, y, t) { context.drawImage(food_image[t], x + (pic_size - 24) / 2 - food_image[t].clientWidth / 2, y + (pic_size -24)/ 2 - food_image[t].clientHeight / 2); } function draw_loot(x, y, t) { context.drawImage(item_image[t], x + (pic_size - 24) / 2 - item_image[t].clientWidth / 2, y + (pic_size -24)/ 2 - item_image[t].clientHeight / 2); } // returns the food type number if we have a food item at this location function have_weapon_here(r, c) { for(var i=0; i<weapon_locations.length; i++) { if(weapon_locations[i].r === r && weapon_locations[i].c === c) { return weapon_locations[i].t; } } return -1; } function draw_weapon(x, y, t) { context.drawImage(weapon_images[t], x + (pic_size - 24) / 2 - weapon_images[t].clientWidth / 2, y + (pic_size -24)/ 2 - weapon_images[t].clientHeight / 2); } function draw_torch(torch_x, torch_y, i, j, cond) { if(cond) { var torch_backgr = context.getImageData(torch_x, torch_y, 6, 10); context.drawImage(torch_images[0], torch_x, torch_y); torches.push({x: torch_x, y: torch_y, anim_idx: 0, ctr: 0, i: i, j: j, backgr: torch_backgr}); } } function door_at(i, j) { for(var k=0; k<doors.length; k++) if(doors[k].r === j && doors[k].c === i) return doors[k].v; return -1; } // true if we are just drawing a maze window.maze_drawing = false; // true if we are updating the walkers. Don't move the playuer meanwhile window.walkers_updating = false; function draw_extra_objects(j, i, mx, my) { var food_type = have_food_here(j, i); if (food_type !== -1) { draw_food(mx, my, food_type); } var loot_type = have_loot_here(j, i); if (loot_type !== -1) { draw_loot(mx, my, loot_type); } var weapon_type = have_weapon_here(j, i); if (weapon_type !== -1) { draw_weapon(mx, my, weapon_type); } } var small_fellow_needs_to_be_drawn = true; if(game_type !== GAME_TYPE_STORY) { small_fellow_needs_to_be_drawn = false; } var ffx = 0; // funny fellow x,y var ffy = 0; var ffdx = 0; // funny fellow deltax,deltay var ffdy = 0; var ffImgDataPrev = null; function draw_maze(mid_col, mid_row, force) { window.maze_drawing = true; var mx = 0; var my = 0; // var strow = Math.max(mid_row - LIGHT_RADIUS - 1, 0); // var stcol = Math.max(mid_col - LIGHT_RADIUS - 1, 0); for(var j=0; j<h; j++) // j - row // for(var j=strow; j<mid_row + LIGHT_RADIUS + 1; j++) // j - row { // for (var i = stcol; i < mid_col + LIGHT_RADIUS + 1; i++) // i - col for (var i = 0; i <w; i++) // i - col { mx = i * pic_size; my = j * pic_size; var current_idx = maze[j][i]; var current_wall = wall_images[ current_idx ]; if( point_in_circle(mid_col, mid_row, LIGHT_RADIUS, i, j) ) { if( maze_stats[j][i] !== FULL_DRAWN || force) { maze_stats[j][i] = FULL_DRAWN; var door_t = door_at(i, j); // Any door here? if(door_t !== -1) { current_wall = get_doored_wall(current_idx, door_t); } context.drawImage(current_wall, mx, my); // let's see if this is the last cell, ie. stairs down if(door_t === 5 && small_fellow_needs_to_be_drawn) { //1,8,9 ffx = mx + 15; ffy = my + 15; if(current_idx === 1 || current_idx === 9) // small guy will stand above the stairs { ffy = ffy - pic_size; ffdy = 1; } else // small guy will stand on the left of it { ffx = ffx - pic_size; ffdx = 1; } ffImgDataPrev = context.getImageData(ffx,ffy, anim_size, anim_size); context.drawImage(small_fellow, ffx, ffy); } // Torches lying around the corner? var torch_location_in_cell = have_torch_here(i,j); if(torch_location_in_cell !== 0) { draw_torch(mx, my, i, j, torch_location_in_cell & TOP_LEFT); draw_torch(mx, my + pic_size - 22, i, j, torch_location_in_cell & BOTTOM_LEFT); draw_torch(mx+ pic_size - 10, my, i, j, torch_location_in_cell & TOP_RIGHT); draw_torch(mx + pic_size - 10, my + pic_size - 22, i, j, torch_location_in_cell & BOTTOM_RIGHT); } draw_extra_objects(j, i, mx, my); } } else { if(point_in_circle(mid_col, mid_row, LIGHT_RADIUS + 2, i, j) ) { if(maze_stats[j][i] === FULL_DRAWN || (maze_stats[j][i] === FOG_DRAWN && force) ) { context.drawImage(fog_drawn_wall_images[ current_idx ], mx, my); maze_stats[j][i] = FOG_DRAWN; // and remove the torch if found at i,j for(var ti=0; ti < torches.length; ti++) { if(torches[ti].i === i && torches[ti].j === j) { torches.splice(ti, 1); } } } } } } } window.maze_drawing = false; } // true if we are in between animation of the player // Will be "window.animation_running" in scripts var animation_running = false; // the current animation counter var current_anim_counter = 0; // the direction in which the player is going, indexes into the array of images var player_dir = MOVE_IDX_RIGHT; // 0 - Left, 1 - Up, 2 - Right, 3 - Down // The size of the animation frame, ie. what must be saved from the canvas var anim_size = pic_size / 2; var player_imgset = [lr_player, lr_player_spear, lr_player_armor_spear, lr_player_armor, lr_player_shoes, lr_player_shoes_spear, // +6 will give the thrust images lr_player_thrust, lr_player_spear_thrust, lr_player_armor_spear_thrust, lr_player_armor_thrust, lr_player_shoes_thrust, lr_player_shoes_spear_thrust ]; var player_imgset_index = 0; // returns the current player image according to // direction and current animation counter var anim_modder = step_anim_cnt; function get_current_player_image(dir) { return player_imgset[player_imgset_index][dir][current_anim_counter % anim_modder]; } function get_direction(c,fwd) { if(fwd === 1) { if(c === 'N') return N; if(c === 'S') return S; if(c === 'E') return E; if(c === 'W') return W; } else { if(c === 'N') return S; if(c === 'S') return N; if(c === 'E') return W; if(c === 'W') return E; } return 0; } function get_dir_idx(dir) { if(dir === W) return MOVE_IDX_LEFT; if(dir === N) return MOVE_IDX_UP; if(dir === E) return MOVE_IDX_RIGHT; if(dir === S) return MOVE_IDX_DOWN; return -1; } const WALKING = 1; // IGW normally goes around const DEAD = 5; // igw was killed // in game walkers var igw = []; function update_igw_location(i) { switch(igw[i].dir) { case N: igw[i].r --; break; case E: igw[i].c ++; break; case S: igw[i].r ++; break; case W: igw[i].c --; break; } } function init_walkers() { for(var i=0; i<walkers_count; i++) { var wx = walkers[i].c * pic_size + 12; var wy = walkers[i].r * pic_size + 12; var cwalker = { r:walkers[i].r, c:walkers[i].c, saver:-1, savec:-1, t:walkers[i].t, p:walkers[i].p, dir:get_direction(walkers[i].p[0], 1), anim_ctr:0, step_cnt:9, x:wx, y:wy, savedImage:null, path_ctr:0, path_len:walkers[i].path_len, move_dir:1, state:WALKING, just_updated: false, anim_mod:true, }; igw.push(cwalker); } // Now patch the rows and cols for the walker to reflect the first step for(i=0; i<walkers_count; i++) { update_igw_location(i); } } function move_igw(i) { switch(igw[i].dir) { case N: igw[i].y --; return; case E: igw[i].x ++; return; case W: igw[i].x --; return; case S: igw[i].y ++; return; } igw[i].just_updated = true; } function can_go(fromrow, fromcol, pxd, pyd) { if(fromrow < 0) fromrow = 0; if(fromcol < 0) fromcol = 0; var cell = maze[fromrow][fromcol]; var cango = 0; if(pyd === 1) cango = cell & S; if(pyd === -1) cango = cell & N; if(pxd === 1) cango = cell & E; if(pxd === -1) cango = cell & W; return cango !== 0; } function igw_touches_player(i, dist_comp) { var dc = (Math.abs(igw[i].x -x) < 5 && Math.abs(igw[i].y -y)<5 ); if(dist_comp) { return dc; } return (( ( igw[i].r === row && igw[i].c === col && igw[i].anim_ctr >= pic_size / 2) || (igw[i].saver === row && igw[i].savec === col) )) || dc; } // Checks whether the player has a corresponding weapon which he can use to kill igw[i]. // igw[i].t is the type of the igw and if the player weapon > igw[i].t then it can kill. function player_has_corresponding_weapon(i) { // Fully equipped player will kill everything if (player_armor === ARMOR_CHAINMAIL && player_weapon === WEAPON_SPEAR) { return true; } // player with spear will kill simple skeletons if(player_weapon === WEAPON_SPEAR && igw[i].t === 0) { return true; } return (player_weapon >= igw[i].t); } function player_has_armor() { return player_armor === ARMOR_CHAINMAIL; } var anim_mod = 0; function resolve_weapon(weapon_here) { if (weapon_here === RING) // ring, will stop the time { time_effect = TIME_HAS_NO_EFFECT; document.getElementById("ring_of_health_div").style.visibility = 'visible'; } else if (weapon_here === SHOES) // shoes { if (player_armor === ARMOR_NONE) // player has no armor, images shoudl be lr_player_shoes { if(player_weapon === WEAPON_SPEAR) { player_imgset_index = 5; } else { player_imgset_index = 4; } } player_steps = STEPS_FREE; document.getElementById("boots_of_light_div").style.visibility = 'visible'; LIGHT_RADIUS = 5; } else if (weapon_here === WEAPON_SPEAR) // spear { player_weapon = WEAPON_SPEAR; if (player_armor === ARMOR_NONE) // player has no armor, images shoudl be lr_player_spear { if(player_steps === STEPS_FREE) // Are there shoes on the player? { player_imgset_index = 5; } else { player_imgset_index = 1; } } else if (player_armor === ARMOR_CHAINMAIL) // player has armor, images should be lr_player_armor_spear { player_imgset_index = 2; } } else if (weapon_here === ARMOR_CHAINMAIL) // found the armor { player_armor = ARMOR_CHAINMAIL; if (player_weapon === WEAPON_SPEAR) { player_imgset_index = 2; } else if (player_weapon === WEAPON_NONE) { player_imgset_index = 3; } } } function resolve_loot(t) { var loot_value = item_value[t]; var current_gold = parseInt(document.getElementById("gold").innerHTML); current_gold += loot_value; document.getElementById("gold").innerHTML = current_gold.toString(); } function igw_kills_player(i) { if (!player_has_corresponding_weapon(i)) { if(player_has_armor()) { let current_life = parseInt(document.getElementById("energy").innerHTML); let temp_health = current_life - 1; if (temp_health <= 0) { game_over(GO_SKELETON, i); return true; } update_life_visuals(temp_health); return false; } else { game_over(GO_SKELETON, i); return true; } } else { if(igw_touches_player(i, true)) { kill_igw(i); } return false; } } var small_fellow_anim_idx = 0; var small_fellow_anim_runs = false; function walkers_simulation() { if(player_state === PLAYER_DIED) { context.drawImage(dying_player[5], x, y); return; } if(game_state === GAME_SUSPENDED) { return; } if(small_fellow_anim_runs && small_fellow_anim_idx < pic_size) { if(ffImgDataPrev) { context.putImageData(ffImgDataPrev, ffx, ffy); // clear canvas } small_fellow_anim_idx ++; ffx += ffdx; ffy += ffdy; ffImgDataPrev = context.getImageData(ffx,ffy, anim_size, anim_size); context.drawImage(small_fellow, ffx, ffy); } // moving player drawing if(animation_running) { if(!walkers_updating) { context.putImageData(imgDataPrev, x, y); // clear canvas x += x_delta; y += y_delta; anim_mod = anim_mod + 1; if (anim_mod % 4 === 0) current_anim_counter += 1; if (current_anim_counter < pic_size / 4) { imgDataPrev = context.getImageData(x, y, anim_size, anim_size); } else { animation_running = false; current_anim_counter = 0; // and here verify what is on the square we arrived to // 1. See did we find the exit? if (col === exit_col && row === exit_row) { game_over(GO_LEVEL_DONE, -1); return; } // 2. Any foodstuff or other here? var food_type_here = have_food_here(row, col); var maze_redraw_needed = false; if (food_type_here !== -1) { var current_life = parseInt(document.getElementById("energy").innerHTML); var temp_health = current_life + food_effects[food_type_here]; remove_food(row, col); maze_redraw_needed = true; if (temp_health > 100) { temp_health = 100; } if (temp_health <= 0) { game_over(GO_BAD_FOOD, -1); return; } update_life_visuals(temp_health); } // Are we next to the small guy with a visible line? if( row > h - 4 && col > w - 4 && game_type === GAME_TYPE_STORY) { small_fellow_needs_to_be_drawn = false; maze_redraw_needed = true; small_fellow_anim_runs = true; } // see if there is a wepon there var weapon_here = have_weapon_here(row, col); if (weapon_here !== -1) { resolve_weapon(weapon_here); remove_weapon(row, col); maze_redraw_needed = true; } // if this is an adventure game, see if there is any loot here if(game_type === GAME_TYPE_ADVENTURE) { // see if there is a wepon there var loot_here = have_loot_here(row, col); if (loot_here !== -1) { resolve_loot(loot_here); remove_loot(row, col); maze_redraw_needed = true; } } if (maze_redraw_needed) { draw_maze(col, row, true); imgDataPrev = context.getImageData(x, y, anim_size, anim_size); } // see if this was a hit operation or not if(anim_modder === thrust_anim_cnt) { // update the image set for the walking anim_modder = step_anim_cnt; player_imgset_index -= 6; } } context.drawImage(get_current_player_image(player_dir), x, y); } } draw_torches(true); window.walkers_updating = true; var drawn_walkers = []; for (var i = 0; i < igw.length; i++) { if (igw[i].state === DEAD) { context.drawImage(skel_dies[5], igw[i].x, igw[i].y); continue; } igw[i].anim_mod = !igw[i].anim_mod; if (igw[i].anim_mod) igw[i].anim_ctr++; igw[i].just_updated = false; igw[i].saver = igw[i].r; igw[i].savec = igw[i].c; if (igw_touches_player(i,false)) { if(igw_kills_player(i)) { return; } } if (igw[i].anim_ctr > pic_size / 2 - 1) { // means we have stepped over the current tile, time to advance to the next one igw[i].path_ctr = igw[i].path_ctr + igw[i].move_dir; // console.log("igw[",i,'].path_ctr=',igw[i].path_ctr,' path_len=',igw[i].path_len); if (igw[i].path_ctr === igw[i].path_len || igw[i].path_ctr < 0) { // just perform a routine check that the last step of the igw does not kill the player var tempr = igw[i].r; var tempc = igw[i].c; update_igw_location(i); if (igw_touches_player(i,false)) { if(igw_kills_player(i)) { return; } } //draw_a_wall(igw[i].r, igw[i].c); igw[i].r = tempr; igw[i].c = tempc; // this reverses the igw igw[i].move_dir = -igw[i].move_dir; igw[i].path_ctr --; if(igw[i].path_ctr < 0) { igw[i].path_ctr = 0; } } igw[i].dir = get_direction(igw[i].p[igw[i].path_ctr], igw[i].move_dir); update_igw_location(i); igw[i].anim_ctr = 0; } if (maze_stats[igw[i].r][igw[i].c] === FULL_DRAWN && igw[i].savedImage === null) { igw[i].savedImage = context.getImageData(igw[i].x, igw[i].y, anim_size, anim_size); } else { if (maze_stats[igw[i].r][igw[i].c] === FOG_DRAWN) { context.drawImage(fog_drawn_wall_images[maze[igw[i].r][igw[i].c]], igw[i].c * pic_size, igw[i].r * pic_size); } // do we move away from a full drawn cell? if (maze_stats[igw[i].saver][igw[i].savec] === FULL_DRAWN) { draw_a_wall(igw[i].saver, igw[i].savec); } if (igw[i].savedImage === null) { igw[i].savedImage = context.getImageData(igw[i].x, igw[i].y, anim_size, anim_size); } } // restore the background if( maze_stats[igw[i].r][igw[i].c] === FULL_DRAWN && igw[i].savedImage !== null && maze_stats[igw[i].saver][igw[i].savec] === FULL_DRAWN ) { draw_a_wall(igw[i].r, igw[i].c); // draw_extra_objects(igw[i].r, igw[i].c, igw[i].r * pic_size, igw[i].c * pic_size) context.putImageData(igw[i].savedImage, igw[i].x, igw[i].y); // draw only torches which are being affected for (var k = 0; k < torches.length; k++) { if (torches[k].i === igw[i].c && torches[k].j === igw[i].r) { context.drawImage(torch_images[torches[k].anim_idx], torches[k].x, torches[k].y); } } } // move the walker on the screen move_igw(i); if (maze_stats[igw[i].r][igw[i].c] === FULL_DRAWN) { igw[i].savedImage = context.getImageData(igw[i].x, igw[i].y, anim_size, anim_size); let dir_idx = get_dir_idx(igw[i].dir); let ani_idx = igw[i].anim_ctr % igw[i].step_cnt; // console.log('igw[i].dir',igw[i].dir, 'dir_idx',dir_idx,'ani_idx',ani_idx); context.drawImage(walker_images[igw[i].t][dir_idx][ani_idx], igw[i].x, igw[i].y); drawn_walkers.push({ img: walker_images[igw[i].t][dir_idx][igw[i].anim_ctr % igw[i].step_cnt], x: igw[i].x, y: igw[i].y, r: igw[i].r, c: igw[i].c }); } } // and just draw again all the walkers that were drawn if (drawn_walkers.length > 0) { for (i = 0; i < drawn_walkers.length; i++) { if (maze_stats[drawn_walkers[i].r][drawn_walkers[i].c] === FULL_DRAWN && maze_stats[igw[i].saver][igw[i].savec] === FULL_DRAWN) { context.drawImage(drawn_walkers[i].img, drawn_walkers[i].x, drawn_walkers[i].y); } } // and the player context.drawImage(get_current_player_image(player_dir), x, y); } window.walkers_updating = false; requestAnimationFrame(walkers_simulation); } // previous image which was placed on the canvas var imgDataPrev = null; /* Mouse scroll handling */ // The canvas will scroll back to these coordinates when done with mouse move var marginLeftBackup = 0; var marginTopBackup = 0; var dragging = false; var lastX = 0; var lastY = 0; var marginLeft = 0; var marginTop = 0; // mouse press handler function mouse_press(e) { var evt = e || event; dragging = true; lastX = evt.clientX; lastY = evt.clientY; marginLeftBackup = canvas.style.marginLeft; marginTopBackup = canvas.style.marginTop; e.preventDefault(); } function mouse_move(e) { var evt = e || event; if (dragging) { var deltaX = evt.clientX - lastX; lastX = evt.clientX; if(marginLeft + deltaX <= 0 && canvas.width - Math.abs(marginLeft + deltaX) >= canvas_container.offsetWidth) // did we scroll out left/right { marginLeft += deltaX; canvas.style.marginLeft = marginLeft + "px"; } var deltaY = evt.clientY - lastY; lastY = evt.clientY; if(marginTop + deltaY <= 0 && canvas.height - Math.abs(marginTop + deltaY) >= canvas_container.offsetHeight) { marginTop += deltaY; canvas.style.marginTop = marginTop + "px"; } } e.preventDefault(); } function mouse_up() { dragging = false; canvas.style.marginLeft = marginLeftBackup; canvas.style.marginTop = marginTopBackup; } var canv_anim_counter = 0; var canv_moving_direction_ud = 0; function animate_canvas_movement_up_down() { canv_anim_counter += 1; marginTop += canv_moving_direction_ud; if (canv_anim_counter < pic_size) { requestAnimationFrame(animate_canvas_movement_up_down); } else { canv_anim_counter = 0; } if(canv_moving_direction_ud === -1) { if(canvas.height - Math.abs(marginTop) >= canvas_container.offsetHeight) { canvas.style.marginTop = marginTop + "px"; } } else { if(marginTop <= 0) { canvas.style.marginTop = marginTop + "px"; } } } var canv_moving_direction_lr = 0; function animate_canvas_movement_left_right() { canv_anim_counter += 1; marginLeft += canv_moving_direction_lr; if (canv_anim_counter < pic_size) { requestAnimationFrame(animate_canvas_movement_left_right); } else { canv_anim_counter = 0; } if(canv_moving_direction_lr === -1) { if(canvas.width - Math.abs(marginLeft) >= canvas_container.offsetWidth) { canvas.style.marginLeft = marginLeft + "px"; } } else { if(marginLeft <= 0) { canvas.style.marginLeft = marginLeft + "px"; } } } function remove_food(row, col) { for(var i=0; i<food.length; i++) { if(food[i].r === row && food[i].c === col) { food.splice(i, 1); return; } } } function remove_weapon(row, col) { for(var i=0; i<weapon_locations.length; i++) { if(weapon_locations[i].r === row && weapon_locations[i].c === col) { weapon_locations.splice(i, 1); return; } } } function remove_loot(row, col) { for(var i=0; i<loot.length; i++) { if(loot[i].r === row && loot[i].c === col) { loot.splice(i, 1); return; } } } var time_pass_timeout_set = false; function step(dir, px_delta, py_delta) { if(!time_pass_timeout_set) { time_passing_timeout = setTimeout(time_tick, 1000); time_pass_timeout_set = true; } if(! animation_running) // this tells us if we are in an animation { var current_life = parseInt(document.getElementById("energy").innerHTML); player_dir = dir; var t_row = row + py_delta; var t_col = col + px_delta; if(can_go(row, col, px_delta, py_delta)) { if(player_steps === STEPS_COST) { current_life --; } else if(player_steps === STEPS_SICK) { current_life -= 2; } if(current_life <= 0) { game_over(GO_FATIGUE, -1); return; } update_life_visuals(current_life); step_count ++; if(game_type === GAME_TYPE_TIMERUN) { update_step_visuals(); } var ud_scrolled = false; var lr_scrolled = false; if(px_delta === 1) // right { if(col >= last_col_drawn - MAZE_EDGE_DISTANCE_SCROLL_TRIGGER) { last_col_drawn ++ ; first_col_drawn ++; canv_moving_direction_lr = -1; canv_anim_counter = 0; animate_canvas_movement_left_right(); lr_scrolled = true; } } if(px_delta === -1) // left { if(col <= first_col_drawn + MAZE_EDGE_DISTANCE_SCROLL_TRIGGER && !lr_scrolled && first_col_drawn > 0) { last_col_drawn -- ; first_col_drawn --; canv_moving_direction_lr = 1; canv_anim_counter = 0; animate_canvas_movement_left_right(); lr_scrolled = true; } } if(py_delta === 1) // down { if(row >= last_row_drawn - MAZE_EDGE_DISTANCE_SCROLL_TRIGGER && !lr_scrolled) { last_row_drawn ++ ; first_row_drawn ++; canv_moving_direction_ud = -1; canv_anim_counter = 0; animate_canvas_movement_up_down(); ud_scrolled = true; } } if(py_delta === -1) //up { if(row <= first_row_drawn + MAZE_EDGE_DISTANCE_SCROLL_TRIGGER && !lr_scrolled && !ud_scrolled && first_row_drawn > 0) { last_row_drawn -- ; first_row_drawn --; canv_moving_direction_ud = 1; canv_anim_counter = 0; animate_canvas_movement_up_down(); } } row = t_row; col = t_col; anim_modder = step_anim_cnt; window.animation_running = true; current_anim_counter = 0; x_delta = px_delta; y_delta = py_delta; } // and finally make sure the player is drawn back normally where it's supposed to be draw_maze(col, row, true); context.drawImage(get_current_player_image(player_dir), x, y); } } function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } function hit_something() { if(! animation_running) // this tells us if we are in an animation { x_delta = 0; y_delta = 0; player_imgset_index += 6; anim_modder = thrust_anim_cnt; window.animation_running = true; current_anim_counter = 0; } } // the keyboard handler async function keypressed(e) { if(player_state === PLAYER_ALIVE) { let slept = 1; while(window.walkers_updating && slept < 60) { slept ++; await sleep(20); } var code = e.keyCode; switch (code) { case 37: step(MOVE_IDX_LEFT, -1, 0); break; //Left key case 38: step(MOVE_IDX_UP, 0, -1); break; //Up key case 39: step(MOVE_IDX_RIGHT, 1, 0); break; //Right key case 40: step(MOVE_IDX_DOWN, 0, 1); break; //Down key case 32: hit_something(); // Space default: console.log(code); //Everything else } } } Element.prototype.remove = function() { this.parentElement.removeChild(this); }; NodeList.prototype.remove = HTMLCollection.prototype.remove = function() { for(var i = this.length - 1; i >= 0; i--) { if(this[i] && this[i].parentElement) { this[i].parentElement.removeChild(this[i]); } } }; function toggle_gos(visible) { document.getElementById('gotext1').style.visibility=visible?'visible':'hidden'; document.getElementById('gotext2').style.visibility=visible?'visible':'hidden'; document.getElementById('gotext3').style.visibility=visible?'visible':'hidden'; document.getElementById('gotext4').style.visibility=visible?'visible':'hidden'; document.getElementById('gotext5').style.visibility=visible?'visible':'hidden'; } document.getElementById('badbrowser').remove(); document.getElementById('gobutton').style.visibility='visible'; toggle_gos(true); function time_passes_by() { if(player_state === PLAYER_DIED) { context.drawImage(dying_player[5], x, y); return; } if(time_effect === TIME_HAS_EFFECT) { var current_life = parseInt(document.getElementById("energy").innerHTML); current_life --; update_life_visuals(current_life); if(current_life <= 0) { game_over(GO_FATIGUE, -1); } else { setTimeout(time_passes_by, 3000); } } } var seconds_passed = 0; var minutes_passed = 0; var hours_passed = 0; var days_passed = 0; function time_tick() { seconds_passed ++; if(seconds_passed === 60) { minutes_passed ++; if(minutes_passed === 60) { hours_passed ++; if(hours_passed === 24) { days_passed ++; hours_passed = 0; } minutes_passed = 0; } seconds_passed = 0; } let new_time = hours_passed.toString() + "h : " + minutes_passed.toString() + "m : " + seconds_passed.toString() + "s " + " "; if(days_passed > 0) { new_time = days_passed.toString() + "days "; } document.getElementById('time_passed').innerHTML = new_time; time_passing_timeout = setTimeout(time_tick, 1000); } function get_current_level() { var lid = document.getElementById('lid').value; var level = parseInt(lid); return {level: level}; } function setup_labyrinth(evt) { if(game_type === GAME_TYPE_TIMERUN) { time_effect = TIME_HAS_NO_EFFECT; player_steps = STEPS_FREE; } var __ret = get_current_level(); var level = __ret.level; document.getElementById('levelctr').innerHTML = level.toString(); var gid = document.getElementById('gid').value; document.getElementById('gameid').innerHTML = "<a href=/" + gid + ">" + gid + " </a>"; document.getElementById('messages').style.visibility='hidden'; document.getElementById('gobutton').style.visibility='hidden'; toggle_gos(false); // draw the maze draw_maze(col, row, false); // set up the previous image data in order to save it for the next animation step imgDataPrev = context.getImageData(x,y, anim_size, anim_size); // draw the player context.drawImage(get_current_player_image(player_dir), x, y); // setting up the event listeners window.addEventListener('keydown', keypressed, false); canvas.addEventListener('mousedown', mouse_press, false); window.addEventListener('mousemove', mouse_move, false); window.addEventListener('mouseup', mouse_up, false); init_walkers(); setTimeout(time_passes_by, 3000); game_state = GAME_RUNNING; walkers_simulation(); } function post(path, params, method) { method = method || "post"; var form = document.createElement("form"); form.setAttribute("method", method); form.setAttribute("action", path); for(var key in params) { if(params.hasOwnProperty(key)) { console.log(key, params[key]); var hiddenField = document.createElement("input"); hiddenField.setAttribute("type", "hidden"); hiddenField.setAttribute("name", key); hiddenField.setAttribute("value", params[key]); form.appendChild(hiddenField); } } document.body.appendChild(form); form.submit(); } function go_next_level() { var gid = document.getElementById('gid').value; post(window.location.href, {gid: gid}); } function show_menu() { document.getElementById("messages").style.visibility = 'visible'; document.getElementById("messages").style.display = 'block'; document.getElementById("sysmenu").style.visibility = 'visible'; document.getElementById("sysmenu").style.display = 'block'; document.getElementById("goimg").src = "/img/dungeonslogo.png"; } document.addEventListener('touchstart', handleTouchStart, false); document.addEventListener('touchmove', handleTouchMove, false); var xDown = null; var yDown = null; function handleTouchStart(evt) { xDown = evt.touches[0].clientX; yDown = evt.touches[0].clientY; }; function handleTouchMove(evt) { if ( ! xDown || ! yDown ) { return; } var xUp = evt.touches[0].clientX; var yUp = evt.touches[0].clientY; var xDiff = xDown - xUp; var yDiff = yDown - yUp; if ( Math.abs( xDiff ) > Math.abs( yDiff ) ) {/*most significant*/ if ( xDiff > 0 ) { step(MOVE_IDX_LEFT, -1, 0); } else { step(MOVE_IDX_RIGHT, 1, 0); } } else { if ( yDiff > 0 ) { step(MOVE_IDX_UP, 0, -1); } else { step(MOVE_IDX_DOWN, 0, 1); } } /* reset values */ xDown = null; yDown = null; };
