// main.js // the main game loop // kbrecordzz 2023 // vid publicering: // diff med filer i files-mapp, EP1 / EP2 // kolla publish.txt // måste ha en fade-funktion!! // osynliga väggar (förmodligen antique ornaments) i epper land!! // stäng in magnet factory area innan man ska kunna åka dit!! // man ska inte kunna spara sig förbi vakterna!! // man ska inte kunna åka ut ur magnet labyrinth, genom att åka upp på husen!! // magnet labyrinth måste vara helt instängt. få tillbaka husen till sidorna!! // sätt ihop 38 27 och 37 27 mm. next station så att de ser bra ut ihop! // långsamt att starta i magnet island, kolla performance i ascend! // mer detaljer i epilogue så man fattar att de är på en tågstation!! // polish cow bilderna måste anpassas till mobil layouter mm!! // race varv!! // skjuta varandra i race, testa!! // testa race med alla olika vinnare, se vad som händer!! // kolla så att musiken funkar rätt, startar och slutar rätt, osv! testa en eller fler hel genomspelning med ljud på! // stor bokstav, rätt stavning, rätt stavning/stil på namn. konsekvent i allt!! Rätt stora och små bokst på namn t.ex. osv!! // renskriv: sök på " i " " i'm " för att se vilka som har gammal dålig stavning!! // kör spellcheck!! // korrekt teckenkodning!! å måste skrivas på ett speciellt sätt. stora Å också. Ã¥. kolla å ä ö osv... // head_3 osv!! i QUIZ. på mobil landscape/portrait också // layout background_head är lite konstigt placerad på mobil ibland..! kolla head_2 på landscape mobile! // shelf's huvud ska inte visas under shelfanswer i portrait! och kanske inte i mobile landscape heller? // shelf är kanske för långt ner på skärmen i mobile landscape?! // musik i rings när man inte åker race?! vind? // (the govern men) läs igenom hela story-dialogen från början till slut på EPISODE 1, och EPISODE 2!! leta efter plotholes och få det rimligt, ladda in hela storyn i huvudet i ett svep, utan att stoppa // FILES-ÄNDRINGAR! o'malley fick en fez. hur löser jag detta så att han inte har fez i EP1 men har det i EP2? jag bytte namn på omalley.png t omalley_fez.png o använder bara det filnamnet i EP2. kolla bakåtkompabilitet osv! // lägg in länk till EP3 i episode 1- och 2-filerna. enda ändringen i EP1 och EP2 efter release?!! // copy link to continue playing in another browser - separat sparning för varje episode, är det tydligt för spelaren?!! // se till att allt länkar till ____3.php-filer osv, även i index3.php och info3.php, inget får råka länka tillbaka till första avsnittet!! // alla länkar på index info-sidorna osv ska vara target=_blank så att man aldrig kan råka hoppa ur sin spelprogress!! // byt ut cookie_cut cookie_x cookie_z till nya nummer, och gör rätt länk i "START FROM THE BEGINNING" (i index.php och info.php? vet inte om något mer ställe?). för nu är det EPISODE [insert episode number]!! "use strict"; player.rotation.y = 0; // // copy from CUT_SPLASHSCREEN: // this must be put at the start, in case the player pauses and uses the "save and continue" link before doing anything else // get cut from URL // ,,, add functionality for IE?! i have that for x and z! let cookie_cut = parseInt(params.cut); if (cookie_cut >= 0) { startcut = cookie_cut; } // get cut from cookies else if (document.cookie.search("cookie_cut3=") !== -1) { let kaka_cut1 = document.cookie.split("cookie_cut3="); let kaka_cut2 = kaka_cut1[1].split(";"); startcut = parseInt(kaka_cut2[0]); } // cut if the first time playing else { // startcut = CUT_CUTSCENE_WAKEUP; // EP1 // startcut = CUT_CUTSCENE_RECAP; // EP2 startcut = CUT_FREEROAM_KILLEPPER; // ny start-cut!! och ny start-position. se till att alla länkar i index2 info2 osv är rätt!! player.rotation.y = 1.734; } if (startcut === 0) throw new Error(); document.getElementById("save_text").href = "?x=" + start_chunk_x + "&z=" + start_chunk_z + "&cut=" + startcut; ascend_intro(0.6511030308479817); document.getElementById("loadingscreen").style.visibility = "hidden"; document.getElementsByTagName("body")[0].style.backgroundColor = "#000000"; frame_counter = FRAMES_PER_HOUR*9; // start game in the morning const url = new URL(location.protocol + "\/\/" + location.host + location.pathname); history.pushState({}, "", url); if (start_x[start_chunk_x][start_chunk_z] > 0) { player.position.x = start_x[start_chunk_x][start_chunk_z]; player.position.z = start_z[start_chunk_x][start_chunk_z]; } // this shouldn't happen else { player.position.x = start_chunk_x*49+25; player.position.z = start_chunk_z*49+25; // throw new Error(); } looking_at_object = player; cut = CUT_CUTSCENE_OUTRO;//SPLASHSCREEN; if (!/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) mobile = false; // ej klockren! else mobile = true; let lowres = 1; let lowres_count = 0; let highfps_count = 0; var lastframe; // main game loop function main() { let frame_start = performance.now(); ci1 = Math.floor((player.position.x)/49); cj1 = Math.floor((player.position.z)/49); // DEBUG chaos monkey if (1 === 0) { if (chaosmode === 0) { game_speed = 1; if (Math.random() > 0.5) key_w = true; if (Math.random() > 0.999) key_w = false; if (Math.random() > 0.9) key_a = true; if (Math.random() > 0.99) key_a = false; if (Math.random() > 0.9) key_d = true; if (Math.random() > 0.99) key_d = false; if (Math.random() > 0.999) key_s = true; if (Math.random() > 0.9) key_s = false; if (Math.random() > 0.99) mouseclick = true; else mouseclick = false; if (cut % MODULUS_FREEROAM_ONLY === 0 && Math.random() > 0.9995) ts_end(cut+100); if (Math.random() > 0.999) q += 2; if (Math.random() > 0.9998) player.position.x += 50; if (Math.random() > 0.9998) player.position.x -= 50; if (Math.random() > 0.9998) player.position.z += 50; if (Math.random() > 0.9998) player.position.z -= 50; for (let t = 0; t < NUMBER_OF_CARS; t++) { if (cz_turned_on[t] === 1) { if (distance_get(player, cz[t]) > 50) player.position.set(cz[t].position.x, 0, cz[t].position.z); if (distance_get(player, cz[t]) > 3) player.rotation.y = lookat_datass(player, cz[t]); } } if (cut % MODULUS_FREEROAM_OR_RACE !== 0 && Math.random() > 0.9) cut++; if (shelfanswer === 0) shelfanswer = 1; else shelfanswer = 0; if (Math.random() > 0.999) chaosmode = 1; if (Math.random() > 0.5) { if (cut % MODULUS_FREEROAM_OR_RACE === 0 && shot_timer <= 60) { if (interact_timer <= 0) { let whichf = -1; for (let t = 0; t < 4; t++) { if (fayah_timer[t] <= 0) whichf = t; } if (whichf !== -1) { fayah_timer[whichf] = 50; } } } } } else if (chaosmode === 1) { game_speed = 2; if (Math.random() > 0.7) key_w = true; if (Math.random() > 0.9) key_w = false; if (Math.random() > 0.8) key_a = true; if (Math.random() > 0.99) key_a = false; if (Math.random() > 0.8) key_d = true; if (Math.random() > 0.99) key_d = false; if (Math.random() > 0.999) key_s = true; if (Math.random() > 0.9) key_s = false; if (Math.random() > 0.99) mouseclick = true; else mouseclick = false; if (cut % MODULUS_FREEROAM_ONLY === 0 && Math.random() > 0.9995) ts_end(cut+100); if (Math.random() > 0.9997) q += 4; if (Math.random() > 0.9998) player.position.x += 50; if (Math.random() > 0.9998) player.position.x -= 50; if (Math.random() > 0.9998) player.position.z += 50; if (Math.random() > 0.9998) player.position.z -= 50; if (cut % MODULUS_FREEROAM_OR_RACE !== 0 && Math.random() > 0.9) cut++; if (Math.random() > 0.999) chaosmode = 0; } } // override in cut_set() if you want to change: camera_cutscene.fov = 60; lookheight = 0; move_player = false; speedchange = 1; from_x = 0; from_z = 0; from_y = 0; hide_cut_sprites(); sprite_ui_mouseclick.position.set(player.position.x, shelf.position.y+1.3, player.position.z); sprite_ui_mouseclick.visible = false; sprite_iloveyou.position.set(player.position.x, shelf.position.y+0.8, player.position.z); sprite_iloveyou.visible = false; // automatic rescue UI. rest is in functions.js if (frame_counter % (60*20) === 0) drown_count = 0; if (drown_count >= 5) { sprite_ui_mouseclick.visible = true; if (ci1 !== last_chunk_x || cj1 !== last_chunk_z) drown_count = 0; // ! if (mouseclick === true) { drown_count = 0; // denna skulle i praktiken kunna släppa spelaren mitt i havet när den ska rädda en från drunkning...! if (start_x[ci1][cj1] > 0) { player.position.x = start_x[ci1][cj1]; player.position.z = start_z[ci1][cj1]; } else { player.position.x = ci1*49+25; player.position.z = cj1*49+25; } } } // out of bounds if (player.position.x <= 26*49) { player.position.x = 26*49; if (cut !== CUT_CUTSCENE_OUTRO) { sound_error.play(); } } // !! if (player.position.x >= 41*49+49) { player.position.x = 41*49+49; if (cut !== CUT_CUTSCENE_OUTRO) { sound_error.play(); } } if (player.position.z <= 26*49) { player.position.z = 26*49; if (cut !== CUT_CUTSCENE_OUTRO) { sound_error.play(); } } if (player.position.z >= 41*49+49) { player.position.z = 41*49+49; if (cut !== CUT_CUTSCENE_OUTRO) { sound_error.play(); } } if (player.position.x < 26*49 || player.position.z < 26*49 || player.position.x > 42*49 || player.position.z > 42*49) throw new Error("player is outside of world, position: " + player.position.x + " " + player.position.z); layout_set(); if (cut % MODULUS_FREEROAM_OR_RACE === 0) chunk_set(); cut_set(); if (cut === CUT_CUTSCENE_RECAP) player.position.y = 100; // tillägg för cutscene i början! if (cut === CUT_FREEROAM_MRSS) player.position.y = 100; // tillägg för cutscene i början! if (cut % MODULUS_FREEROAM_OR_RACE === 0) { for (let t = 0; t < NUMBER_OF_CARS; t++) { if (cz_turned_on[t] === 1) { if (cz_goal_x[t] <= 0 || cz_goal_z[t] <= 0) throw new Error("goal for character " + t + " is <= 0"); } } } camera_set(); // fire animation sprite_fff1.visible = false; sprite_fff2.visible = false; sprite_fff3.visible = false; sprite_fff4.visible = false; if (frame_counter % 20 > 15) sprite_fff1.visible = true; else if (frame_counter % 20 > 10) sprite_fff2.visible = true; else if (frame_counter % 20 > 5) sprite_fff3.visible = true; else sprite_fff4.visible = true; // fps tillägg EP2! let brealrot = player.rotation.y - (2*Math.PI)*Math.floor(player.rotation.y/(2*Math.PI)); sprite_bullseye.position.x = player.position.x + 1*(Math.cos(Math.PI*0.5-brealrot)); sprite_bullseye.position.z = player.position.z + 1*(Math.sin(Math.PI*0.5-brealrot)); sprite_bullseye.position.y = player.position.y + 1; if ((cut % MODULUS_FREEROAM_OR_RACE === 0 && cut % MODULUS_FREEROAM_ONLY !== 0 && race_state === RACE_DURING) || cut === CUT_FREEROAM_HARASSFAN) sprite_bullseye.visible = true; // if certain cuts! else sprite_bullseye.visible = false; ascend_main(); if (cut % MODULUS_FREEROAM_OR_RACE === 0) { light_set(); fog_set(); } if (cut === CUT_CUTSCENE_BOMB || cut === CUT_CUTSCENE_BOMB+1 || cut === CUT_CUTSCENE_BOMB+2) fog_set(); room.position.set(player.position.x, 100, player.position.z); if (cut !== CUT_PAUSEMENU) { last_cut_before_pause = cut; } // finns ocksa i input.js! // save progress if (cut >= 0 && cut % MODULUS_FREEROAM_OR_RACE === 0 && cut !== CUT_FREEROAM_INTRO && cut !== CUT_FREEROAM_1B && cut !== CUT_FREEROAM_1C && cut !== CUT_FREEROAM_1D && cut !== CUT_FREEROAM_1E && cut !== CUT_FREEROAM_1F && cut !== CUT_FREEROAM_CARCHASE2 && cut !== CUT_FREEROAM_CARCHASE3 && cut !== CUT_FREEROAM_CARCHASE4 && cut !== CUT_FREEROAM_LICENSE_2 && cut !== CUT_FREEROAM_LICENSE_3 && cut !== CUT_FREEROAM_LICENSE_4 && cut !== CUT_FREEROAM_LICENSE_5) { if (ci1 >= 26 && ci1 <= 41 && cj1 >= 26 && cj1 <= 41) { if (frame_counter % 30 === 0) document.cookie = "cookie_cut3=" + cut + "; expires=Thu, 18 Dec 2099 12:00:00 UTC"; // lagg in vilka chunks man inte kan spara vid! i start_x start_z osv i ascend.js if (start_x[ci1][cj1] > 0) { if (frame_counter % 30 === 5) document.cookie = "cookie_x3=" + ci1 + "; expires=Thu, 18 Dec 2099 12:00:00 UTC"; if (frame_counter % 30 === 10) document.cookie = "cookie_z3=" + cj1 + "; expires=Thu, 18 Dec 2099 12:00:00 UTC"; } if (last_cut_before_pause === 0) throw new Error(); if (frame_counter % 30 === 20) document.getElementById("save_text").href = "?x=" + ci1 + "&z=" + cj1 + "&cut=" + last_cut_before_pause; } } if (cut % MODULUS_FREEROAM_OR_RACE === 0) { last_cut_before_talk = cut; cars_control(); cars_physics(); if (frame_counter % 5 === 0) cars_sound(); } else { // stop car sound in cutscenes sound_washingmachine.pause(); sound_car.pause(); sound_car_is_playing = false; for (let t = 0; t < NUMBER_OF_CARS; t++) { sound_cz_car[t].pause(); sound_cz_car_is_playing = false; } sound_grass.pause(); sound_water.pause(); } if (cut % MODULUS_FREEROAM_ONLY === 0) last_cut_before_race = cut; if (lastcut % MODULUS_FREEROAM_OR_RACE !== 0 && cut % MODULUS_FREEROAM_OR_RACE === 0) interact_timer = 60; if ((cut % MODULUS_FREEROAM_OR_RACE === 0 && cut % MODULUS_FREEROAM_ONLY !== 0 && race_state === RACE_DURING) || cut === CUT_FREEROAM_HARASSFAN) // byt ut denna för att begränsa gameplay_fps vissa tillfällen! { gameplay_fps(); } else { // resets things that get changed in gameplay_fps() for (let t = 0; t < 4; t++) sprite_fayah[t].visible = false; sprite_efayah.visible = false; } // EP3! keep player out of rings !! if (player.position.x >= 1905 && player.position.x <= 1910 && player.position.z >= 1398 && player.position.z <= 1523) { player.position.x = lastpos_x; player.position.z = lastpos_z; speed *= -1; sound_error.play(); } // EP3! keep player out of guard zone - stäng av denna när det behövs, vakterna ska öppna dead zone efter en viss cut! if (cut < CUT_FREEROAM_MAGNETFACTORY_V && player.position.x >= 1803 && player.position.x <= 1910 && player.position.z >= 1453 && player.position.z <= 1458) { player.position.x = lastpos_x; player.position.z = lastpos_z; speed *= -1; sound_error.play(); } // EP3!! cut?!! avkommentera if (cut <= CUT_FREEROAM_MAGNETFACTORY_V && player.position.x >= 1811 && player.position.x <= 1865 && player.position.z >= 1369 && player.position.z <= 1377) { player.position.x = lastpos_x; player.position.z = lastpos_z; speed *= -1; sound_error.play(); } // EP3!! cut?!! avkommentera if (player.position.x >= 1858 && player.position.x <= 1867 && player.position.z >= 1317 && player.position.z <= 1377) { // player.position.x = lastpos_x; // player.position.z = lastpos_z; // speed *= -1; sound_error.play(); } if (interact_timer > 0) { sprite_ui_mouseclick.visible = false; interact_timer--; } if (collision_timer > 0) collision_timer--; if (cz_collision_timer > 0) cz_collision_timer--; if (turbo_timer > 0) turbo_timer--; for (let t = 0; t < NUMBER_OF_CARS; t++) cz_turbo_timer[t]--; // fixa areatext och scene text, de ska inte synas samtidigt. och kanske på olika ställen? och snyggare stil på scene-text. kanske som ett filmmanus? area text visas aldrig i början av något, men det gör scene text. // lägg in stil för scene text i layout_set förmodligen, så att den ser bra ut på alla enheter. if (areatext_timer > 0) { areatext_timer--; document.getElementById("area").style.visibility = "visible"; if (areatext_timer > 200) document.getElementById("area").style.opacity = 1-0.01*(areatext_timer-200); if (areatext_timer < 100) document.getElementById("area").style.opacity = 0.01*(areatext_timer-100); } else { document.getElementById("area").style.visibility = "hidden"; } if (washingmachine_timer > 0) washingmachine_timer--; else sound_washingmachine.pause(); // not used for characters if (cut % MODULUS_FREEROAM_OR_RACE !== 0) sprite_washingmachine.visible = false; if (jump_timer > 0) jump_timer--; for (let t = 0; t < NUMBER_OF_CARS; t++) cz_jump_timer[t]--; // aker if ((cut === CUT_FREEROAM_AUCTION || (q > 2 && cut === CUT_FREEROAM_SVINERI_1)) && ci1 === 38 && cj1 === 34) { let tx = Math.floor(x_to_x_in_chunk(player.position.x))-3; let tz = Math.floor(x_to_x_in_chunk(player.position.z))-3; let tx2 = Math.floor(x_to_x_in_chunk(cz[CAR_DARK_GANDALF].position.x))-3; let tz2 = Math.floor(x_to_x_in_chunk(cz[CAR_DARK_GANDALF].position.z))-3; let akerpos = 45*3*tx+3*tz + 1; let akerpos2 = 45*3*tx2+3*tz2 + 1; // kolla om man är utanför! // bara i en viss cut! // flytta den lilla tomtegubben hit! if (akerpos >= 0 && akerpos < 6075) { if (!(pointsprites_aker === undefined)) // ! { if (pointsprites_aker.geometry.attributes.position.array[akerpos] > -100) // lägg till andra karaktärerna! { if (speed >= 0.13) { speed -= 0.065; if (cut === CUT_FREEROAM_AUCTION) akerpoints++; sound_play(sound_glasshatter); pointsprites_aker.geometry.attributes.position.array[akerpos] = -100; // y? pointsprites_aker.geometry.attributes.position.needsUpdate = true; if (cut === CUT_FREEROAM_SVINERI_1 && q > 2) ts_end(CUT_FREEROAM_AUCTION); } else { let sfac = speed; if (speed < 0) sfac = -speed; if (sfac < 0.3) sound_crash.volume = sfac*2; else sound_crash.volume = 0.6; sound_crash.play(); speed *= -1; player.position.x = lastpos_x; player.position.z = lastpos_z; } } } } if (akerpos2 >= 0 && akerpos2 < 6075) { if (!(pointsprites_aker === undefined)) // ! { if (pointsprites_aker.geometry.attributes.position.array[akerpos2] > -100) { if (cut === CUT_FREEROAM_AUCTION) akerpoints++; sound_play(sound_glasshatter); pointsprites_aker.geometry.attributes.position.array[akerpos2] = -100; // y? pointsprites_aker.geometry.attributes.position.needsUpdate = true; } } } } // quiz let quiz_total = quiz1_correct + quiz2_correct + quiz3_correct + quiz4_correct + quiz5_correct + quiz6_correct + quiz7_correct + quiz8_correct + quiz9_correct + quiz10_correct; if (cut === CUT_FREEROAM_MAGNETFACTORY_X && quiz_total >= 8) { sound_play(sound_lapfanfare); ts_end(CUT_FREEROAM_QUIZ); } // last_chunk_x = ci1; // in create_terrain_chunks_before_showing_them() // last_chunk_z = cj1; lastpos_x = player.position.x; lastpos_z = player.position.z; lastpos_y = player.position.y; if (height_get(player) > sealevel+0.4)// && start_x[ci1][cj1] >= 0 && start_z[ci1][cj1] >= 0) // la till så att man inte sparar lastlandpos i chunks där man inte kan spara. det är ofta vatten-chunks där man kan fastna och inte kommer tillbaka till land. det finns tvättmaskiner, men här är en extra koll som gör att man inte blir fast mitt ute på havet! kan bli störande om man hamnar på ett ställe där man inte förväntar sig, så testa. TAR BORT { lastlandpos_x = player.position.x; lastlandpos_z = player.position.z; } // for (let t = 0; t < NUMBER_OF_CARS; t++) // { // if (cz_turned_on[t] === 1) // { // console.log("t: " + t); // DEBUG // if (height_get(cz[t]) > sealevel+0.4) // { // cz_lastlandpos_x[t] = cz[t].position.x; // cz_lastlandpos_z[t] = cz[t].position.z; // } // } // } lastcut = cut; renderer.render(scene, camera); if (cut >= 0 && cut % MODULUS_FREEROAM_OR_RACE === 0) frame_counter += game_speed; if (frame_counter > FRAMES_PER_DAY) frame_counter = 0; mouseclick = false; let frame_end = performance.now(); requestAnimationFrame(main); // new limit fps if (performance.now()-lastframe < 14) highfps_count++; if (frame_counter % (60*10) === 0) highfps_count = 0; // se om detta intervall är rimligt för skärmar med hög refresh rate!! denna funktion behöver utvecklas och testas noga efter att projektet är klart. if (highfps_count >= 100) { console.log("highfps"); while (performance.now()-frame_start < 15) { } } // automatic low resolution if too bad performance if (frame_end-frame_start >= 16.67) lowres_count++; else lowres_count -= 0.1; if (frame_counter % (60*20) === 0) lowres_count = 0; if (lowres_count >= 10) lowres = 0.75; else if (lowres_count < -10) lowres = 1; lastframe = performance.now(); } requestAnimationFrame(main);