Tech guy for special events too busy with too many things things.
82 stories
·
1 follower

CodeSOD: Swwwitch

1 Share

We're going to do something a little different. I don't like to do posts about game related code. Games are entirely about shipping something out the door on tight timelines and tight budgets, and it's very much the category of "if it works it's good". There are exceptions, like when you ship an actual WTF, but "bad game code" is not really that interesting.

Awhile back, indie game VVVVVV went open source which gives us a picture of how the sausage is actually made. Now, this is emphatically not a WTF, this isn't wrong or a mistake, this is just the kind of thing that gets a game shipped, especially when it's a small budget indie game, by basically one person.

So instead of getting angry or annoyed, let's just marvel at this 3,440 line switch which represents the game's main loop.

switch(state) { case 0: //Do nothing here! Standard game state break; case 1: //Game initilisation state = 0; break; case 2: //Opening cutscene advancetext = true; hascontrol = false; state = 3; dwgfx.createtextbox("To do: write quick", 50, 80, 164, 164, 255); dwgfx.addline("intro to story!"); //Oh no! what happen to rest of crew etc crash into dimension break; case 4: //End of opening cutscene for now dwgfx.createtextbox(" Press arrow keys or WASD to move ", -1, 195, 174, 174, 174); dwgfx.textboxtimer(60); state = 0; break; case 5: //Demo over advancetext = true; hascontrol = false; /*dwgfx.createtextbox(" Prototype Complete ", 50, 80, 164, 164, 255); dwgfx.addline("Congrats! More Info Soon!"); dwgfx.textboxcenter(); */ startscript = true; newscript="returntohub"; obj.removetrigger(5); state = 6; break; case 7: //End of opening cutscene for now dwgfx.textboxremove(); hascontrol = true; advancetext = false; state = 0; break; case 8: //Enter dialogue obj.removetrigger(8); if (obj.flags[13] == 0) { obj.changeflag(13, 1); dwgfx.createtextbox(" Press ENTER to view map ", -1, 155, 174, 174, 174); dwgfx.addline(" and quicksave"); dwgfx.textboxtimer(60); } state = 0; break; case 9: //Start SWN Minigame Mode B obj.removetrigger(9); swnmode = true; swngame = 6; swndelay = 150; swntimer = 60 * 30; //set the checkpoint in the middle of the screen savepoint = 0; savex = 148; savey = 100; savegc = 0; saverx = roomx; savery = roomy; savedir = 0; state = 0; break; case 10: //Start SWN Minigame Mode A obj.removetrigger(10); swnmode = true; swngame = 4; swndelay = 150; swntimer = 60 * 30; //set the checkpoint in the middle of the screen savepoint = 0; savex = 148; savey = 100; savegc = 0; saverx = roomx; savery = roomy; savedir = 0; state = 0; break; case 11: //Intermission 1 instructional textbox, depends on last saved dwgfx.textboxremovefast(); dwgfx.createtextbox(" When you're NOT standing on ", -1, 3, 174, 174, 174); if (dwgfx.flipmode) { if (lastsaved == 2) { dwgfx.addline(" the ceiling, Vitellary will"); } else if (lastsaved == 3) { dwgfx.addline(" the ceiling, Vermilion will"); } else if (lastsaved == 4) { dwgfx.addline(" the ceiling, Verdigris will"); } else if (lastsaved == 5) { dwgfx.addline(" the ceiling, Victoria will"); } } else { if (lastsaved == 2) { dwgfx.addline(" the floor, Vitellary will"); } else if (lastsaved == 3) { dwgfx.addline(" the floor, Vermilion will"); } else if (lastsaved == 4) { dwgfx.addline(" the floor, Verdigris will"); } else if (lastsaved == 5) { dwgfx.addline(" the floor, Victoria will"); } } dwgfx.addline(" stop and wait for you."); dwgfx.textboxtimer(180); state = 0; break; case 12: //Intermission 1 instructional textbox, depends on last saved obj.removetrigger(12); if (obj.flags[61] == 0) { obj.changeflag(61, 1); dwgfx.textboxremovefast(); dwgfx.createtextbox(" You can't continue to the next ", -1, 8, 174, 174, 174); if (lastsaved == 5) { dwgfx.addline(" room until she is safely across. "); } else { dwgfx.addline(" room until he is safely across. "); } dwgfx.textboxtimer(120); } state = 0; break; case 13: //textbox removal obj.removetrigger(13); dwgfx.textboxremovefast(); state = 0; break; case 14: //Intermission 1 instructional textbox, depends on last saved if (dwgfx.flipmode) { dwgfx.createtextbox(" When you're standing on the ceiling, ", -1, 3, 174, 174, 174); } else { dwgfx.createtextbox(" When you're standing on the floor, ", -1, 3, 174, 174, 174); } if (lastsaved == 2) { dwgfx.addline(" Vitellary will try to walk to you. "); } else if (lastsaved == 3) { dwgfx.addline(" Vermilion will try to walk to you. "); } else if (lastsaved == 4) { dwgfx.addline(" Verdigris will try to walk to you. "); } else if (lastsaved == 5) { dwgfx.addline(" Victoria will try to walk to you. "); } dwgfx.textboxtimer(280); state = 0; break; case 15: //leaving the naughty corner obj.entities[obj.getplayer()].tile = 0; state = 0; break; case 16: //entering the naughty corner if(obj.entities[obj.getplayer()].tile == 0) { obj.entities[obj.getplayer()].tile = 144; music.playef(2, 10); } state = 0; break; case 17: //Arrow key tutorial obj.removetrigger(17); dwgfx.createtextbox(" If you prefer, you can press UP or ", -1, 195, 174, 174, 174); dwgfx.addline(" DOWN instead of ACTION to flip."); dwgfx.textboxtimer(100); state = 0; break; case 20: if (obj.flags[1] == 0) { obj.changeflag(1, 1); state = 0; dwgfx.textboxremove(); } obj.removetrigger(20); break; case 21: if (obj.flags[2] == 0) { obj.changeflag(2, 1); state = 0; dwgfx.textboxremove(); } obj.removetrigger(21); break; case 22: if (obj.flags[3] == 0) { dwgfx.textboxremovefast(); obj.changeflag(3, 1); state = 0; dwgfx.createtextbox(" Press ACTION to flip ", -1, 25, 174, 174, 174); dwgfx.textboxtimer(60); } obj.removetrigger(22); break; case 30: //Generic "run script" if (obj.flags[4] == 0) { obj.changeflag(4, 1); startscript = true; newscript="firststeps"; state = 0; } obj.removetrigger(30); state = 0; break; case 31: //state = 55; statedelay = 50; state = 0; statedelay = 0; if (obj.flags[6] == 0) { obj.changeflag(6, 1); obj.changeflag(5, 1); startscript = true; newscript="communicationstation"; state = 0; statedelay = 0; } obj.removetrigger(31); break; case 32: //Generic "run script" if (obj.flags[7] == 0) { obj.changeflag(7, 1); startscript = true; newscript="teleporterback"; state = 0; } obj.removetrigger(32); state = 0; break; case 33: //Generic "run script" if (obj.flags[9] == 0) { obj.changeflag(9, 1); startscript = true; newscript="rescueblue"; state = 0; } obj.removetrigger(33); state = 0; break; case 34: //Generic "run script" if (obj.flags[10] == 0) { obj.changeflag(10, 1); startscript = true; newscript="rescueyellow"; state = 0; } obj.removetrigger(34); state = 0; break; case 35: //Generic "run script" if (obj.flags[11] == 0) { obj.changeflag(11, 1); startscript = true; newscript="rescuegreen"; state = 0; } obj.removetrigger(35); state = 0; break; case 36: //Generic "run script" if (obj.flags[8] == 0) { obj.changeflag(8, 1); startscript = true; newscript="rescuered"; state = 0; } obj.removetrigger(36); state = 0; break; case 37: //Generic "run script" if (companion == 0) { startscript = true; newscript="int2_yellow"; state = 0; } obj.removetrigger(37); state = 0; break; case 38: //Generic "run script" if (companion == 0) { startscript = true; newscript="int2_red"; state = 0; } obj.removetrigger(38); state = 0; break; case 39: //Generic "run script" if (companion == 0) { startscript = true; newscript="int2_green"; state = 0; } obj.removetrigger(39); state = 0; break; case 40: //Generic "run script" if (companion == 0) { startscript = true; newscript="int2_blue"; state = 0; } obj.removetrigger(40); state = 0; break; case 41: //Generic "run script" if (obj.flags[60] == 0) { obj.changeflag(60, 1); startscript = true; if (lastsaved == 2) { newscript = "int1yellow_2"; } else if (lastsaved == 3) { newscript = "int1red_2"; } else if (lastsaved == 4) { newscript = "int1green_2"; } else if (lastsaved == 5) { newscript = "int1blue_2"; } state = 0; } obj.removetrigger(41); state = 0; break; case 42: //Generic "run script" if (obj.flags[62] == 0) { obj.changeflag(62, 1); startscript = true; if (lastsaved == 2) { newscript = "int1yellow_3"; } else if (lastsaved == 3) { newscript = "int1red_3"; } else if (lastsaved == 4) { newscript = "int1green_3"; } else if (lastsaved == 5) { newscript = "int1blue_3"; } state = 0; } obj.removetrigger(42); state = 0; break; case 43: //Generic "run script" if (obj.flags[63] == 0) { obj.changeflag(63, 1); startscript = true; if (lastsaved == 2) { newscript = "int1yellow_4"; } else if (lastsaved == 3) { newscript = "int1red_4"; } else if (lastsaved == 4) { newscript = "int1green_4"; } else if (lastsaved == 5) { newscript = "int1blue_4"; } state = 0; } obj.removetrigger(43); state = 0; break; case 44: //Generic "run script" if (obj.flags[64] == 0) { obj.changeflag(64, 1); startscript = true; if (lastsaved == 2) { newscript = "int1yellow_5"; } else if (lastsaved == 3) { newscript = "int1red_5"; } else if (lastsaved == 4) { newscript = "int1green_5"; } else if (lastsaved == 5) { newscript = "int1blue_5"; } state = 0; } obj.removetrigger(44); state = 0; break; case 45: //Generic "run script" if (obj.flags[65] == 0) { obj.changeflag(65, 1); startscript = true; if (lastsaved == 2) { newscript = "int1yellow_6"; } else if (lastsaved == 3) { newscript = "int1red_6"; } else if (lastsaved == 4) { newscript = "int1green_6"; } else if (lastsaved == 5) { newscript = "int1blue_6"; } state = 0; } obj.removetrigger(45); state = 0; break; case 46: //Generic "run script" if (obj.flags[66] == 0) { obj.changeflag(66, 1); startscript = true; if (lastsaved == 2) { newscript = "int1yellow_7"; } else if (lastsaved == 3) { newscript = "int1red_7"; } else if (lastsaved == 4) { newscript = "int1green_7"; } else if (lastsaved == 5) { newscript = "int1blue_7"; } state = 0; } obj.removetrigger(46); state = 0; break; case 47: //Generic "run script" if (obj.flags[69] == 0) { obj.changeflag(69, 1); startscript = true; newscript="trenchwarfare"; state = 0; } obj.removetrigger(47); state = 0; break; case 48: //Generic "run script" if (obj.flags[70] == 0) { obj.changeflag(70, 1); startscript = true; newscript="trinketcollector"; state = 0; } obj.removetrigger(48); state = 0; break; case 49: //Start final level music if (obj.flags[71] == 0) { obj.changeflag(71, 1); music.niceplay(15); //Final level remix state = 0; } obj.removetrigger(49); state = 0; break; case 50: music.playef(15, 10); dwgfx.createtextbox("Help! Can anyone hear", 35, 15, 255, 134, 255); dwgfx.addline("this message?"); dwgfx.textboxtimer(60); state++; statedelay = 100; break; case 51: music.playef(15, 10); dwgfx.createtextbox("Verdigris? Are you out", 30, 12, 255, 134, 255); dwgfx.addline("there? Are you ok?"); dwgfx.textboxtimer(60); state++; statedelay = 100; break; case 52: music.playef(15, 10); dwgfx.createtextbox("Please help us! We've crashed", 5, 22, 255, 134, 255); dwgfx.addline("and need assistance!"); dwgfx.textboxtimer(60); state++; statedelay = 100; break; case 53: music.playef(15, 10); dwgfx.createtextbox("Hello? Anyone out there?", 40, 15, 255, 134, 255); dwgfx.textboxtimer(60); state++; statedelay = 100; break; case 54: music.playef(15, 10); dwgfx.createtextbox("This is Doctor Violet from the", 5, 8, 255, 134, 255); dwgfx.addline("D.S.S. Souleye! Please respond!"); dwgfx.textboxtimer(60); state++; statedelay = 100; break; case 55: music.playef(15, 10); dwgfx.createtextbox("Please... Anyone...", 45, 14, 255, 134, 255); dwgfx.textboxtimer(60); state++; statedelay = 100; break; case 56: music.playef(15, 10); dwgfx.createtextbox("Please be alright, everyone...", 25, 18, 255, 134, 255); dwgfx.textboxtimer(60); state=50; statedelay = 100; break; case 80: //Used to return to menu from the game if(dwgfx.fademode == 1) state++; break; case 81: gamestate = 1; dwgfx.fademode = 4; music.play(6); dwgfx.backgrounddrawn = false; map.tdrawback = true; dwgfx.flipmode = false; createmenu("mainmenu"); state = 0; break; case 82: //Time Trial Complete! obj.removetrigger(82); hascontrol = false; timetrialresulttime = seconds + (minutes * 60); timetrialrank = 0; if (timetrialresulttime <= timetrialpar) timetrialrank++; if (trinkets >= timetrialshinytarget) timetrialrank++; if (deathcounts == 0) timetrialrank++; if (timetrialresulttime < besttimes[timetriallevel] || besttimes[timetriallevel]==-1) { besttimes[timetriallevel] = timetrialresulttime; } if (trinkets > besttrinkets[timetriallevel] || besttrinkets[timetriallevel]==-1) { besttrinkets[timetriallevel] = trinkets; } if (deathcounts < bestlives[timetriallevel] || bestlives[timetriallevel]==-1) { bestlives[timetriallevel] = deathcounts; } if (timetrialrank > bestrank[timetriallevel] || bestrank[timetriallevel]==-1) { bestrank[timetriallevel] = timetrialrank; if(timetrialrank>=3){ if(timetriallevel==0) NETWORK_unlockAchievement("vvvvvvtimetrial_station1_fixed"); if(timetriallevel==1) NETWORK_unlockAchievement("vvvvvvtimetrial_lab_fixed"); if(timetriallevel==2) NETWORK_unlockAchievement("vvvvvvtimetrial_tower_fixed"); if(timetriallevel==3) NETWORK_unlockAchievement("vvvvvvtimetrial_station2_fixed"); if(timetriallevel==4) NETWORK_unlockAchievement("vvvvvvtimetrial_warp_fixed"); if(timetriallevel==5) NETWORK_unlockAchievement("vvvvvvtimetrial_final_fixed"); } } savestats(map, dwgfx); dwgfx.fademode = 2; music.fadeout(); state++; break; case 83: frames--; if(dwgfx.fademode == 1) state++; break; case 84: dwgfx.flipmode = false; gamestate = 1; dwgfx.fademode = 4; dwgfx.backgrounddrawn = true; map.tdrawback = true; createmenu("timetrialcomplete"); state = 0; break; case 85: //Cutscene skip version of final level change obj.removetrigger(85); //Init final stretch state++; music.playef(9, 10); music.play(2); obj.flags[72] = 1; screenshake = 10; flashlight = 5; map.finalstretch = true; map.warpx = false; map.warpy = false; map.background = 6; map.final_colormode = true; map.final_colorframe = 1; state = 0; break; //From 90-100 are run scripts for the eurogamer expo only, remove later case 90: //Generic "run script" startscript = true; newscript="startexpolevel_station1"; obj.removetrigger(90); state = 0; break; case 91: //Generic "run script" startscript = true; newscript="startexpolevel_lab"; obj.removetrigger(91); state = 0; break; case 92: //Generic "run script" startscript = true; newscript="startexpolevel_warp"; obj.removetrigger(92); state = 0; break; case 93: //Generic "run script" startscript = true; newscript="startexpolevel_tower"; obj.removetrigger(93); state = 0; break; case 94: //Generic "run script" startscript = true; newscript="startexpolevel_station2"; obj.removetrigger(94); state = 0; break; case 95: //Generic "run script" startscript = true; newscript="startexpolevel_final"; obj.removetrigger(95); state = 0; break; case 96: //Used to return to gravitron to game if(dwgfx.fademode == 1) state++; break; case 97: gamestate = 0; dwgfx.fademode = 4; startscript = true; newscript="returntolab"; state = 0; break; case 100: // // Meeting crewmate in the warpzone // obj.removetrigger(100); if (obj.flags[4] == 0) { obj.changeflag(4, 1); state++; } break; case 101: { i = obj.getplayer(); hascontrol = false; if (obj.entities[i].onroof > 0 && gravitycontrol == 1) { gravitycontrol = 0; music.playef(1, 10); } if (obj.entities[i].onground > 0) { state++; } } break; case 102: { companion = 6; i = obj.getcompanion(6); obj.entities[i].tile = 0; obj.entities[i].state = 1; advancetext = true; hascontrol = false; dwgfx.createtextbox("Captain! I've been so worried!", 60, 90, 164, 255, 164); state++; music.playef(12, 10); } break; case 104: dwgfx.createtextbox("I'm glad you're ok!", 135, 152, 164, 164, 255); state++; music.playef(11, 10); dwgfx.textboxactive(); break; case 106: { dwgfx.createtextbox("I've been trying to find a", 74, 70, 164, 255, 164); dwgfx.addline("way out, but I keep going"); dwgfx.addline("around in circles..."); state++; music.playef(2, 10); dwgfx.textboxactive(); i = obj.getcompanion(6); obj.entities[i].tile = 54; obj.entities[i].state = 0; } break; case 108: dwgfx.createtextbox("Don't worry! I have a", 125, 152, 164, 164, 255); dwgfx.addline("teleporter key!"); state++; music.playef(11, 10); dwgfx.textboxactive(); break; case 110: { i = obj.getcompanion(6); obj.entities[i].tile = 0; obj.entities[i].state = 1; dwgfx.createtextbox("Follow me!", 185, 154, 164, 164, 255); state++; music.playef(11, 10); dwgfx.textboxactive(); } break; case 112: dwgfx.textboxremove(); hascontrol = true; advancetext = false; state = 0; break; case 115: // // Test script for space station, totally delete me! // { i = obj.getplayer(); hascontrol = false; state++; } break; case 116: advancetext = true; hascontrol = false; dwgfx.createtextbox("Sorry Eurogamers! Teleporting around", 60 - 20, 200, 255, 64, 64); dwgfx.addline("the map doesn't work in this version!"); dwgfx.textboxcenterx(); state++; break; case 118: dwgfx.textboxremove(); hascontrol = true; advancetext = false; state = 0; break; case 120: // // Meeting crewmate in the space station // obj.removetrigger(120); if (obj.flags[5] == 0) { obj.changeflag(5, 1); state++; } break; case 121: { i = obj.getplayer(); hascontrol = false; if (obj.entities[i].onground > 0 && gravitycontrol == 0) { gravitycontrol = 1; music.playef(1, 10); } if (obj.entities[i].onroof > 0) { state++; } } break; case 122: companion = 7; i = obj.getcompanion(7); obj.entities[i].tile = 6; obj.entities[i].state = 1; advancetext = true; hascontrol = false; dwgfx.createtextbox("Captain! You're ok!", 60-10, 90-40, 255, 255, 134); state++; music.playef(14, 10); break; case 124: dwgfx.createtextbox("I've found a teleporter, but", 60-20, 90 - 40, 255, 255, 134); dwgfx.addline("I can't get it to go anywhere..."); state++; music.playef(2, 10); dwgfx.textboxactive(); i = obj.getcompanion(7); //obj.entities[i].tile = 66; obj.entities[i].state = 0; break; case 126: dwgfx.createtextbox("I can help with that!", 125, 152-40, 164, 164, 255); state++; music.playef(11, 10); dwgfx.textboxactive(); break; case 128: dwgfx.createtextbox("I have the teleporter", 130, 152-35, 164, 164, 255); dwgfx.addline("codex for our ship!"); state++; music.playef(11, 10); dwgfx.textboxactive(); break; case 130: dwgfx.createtextbox("Yey! Let's go home!", 60-30, 90-35, 255, 255, 134); state++; music.playef(14, 10); dwgfx.textboxactive(); i = obj.getcompanion(7); obj.entities[i].tile = 6; obj.entities[i].state = 1; break; case 132: dwgfx.textboxremove(); hascontrol = true; advancetext = false; state = 0; break; case 200: //Init final stretch state++; music.playef(9, 10); //music.play(2); obj.flags[72] = 1; screenshake = 10; flashlight = 5; map.finalstretch = true; map.warpx = false; map.warpy = false; map.background = 6; map.final_colormode = true; map.final_colorframe = 1; startscript = true; newscript="finalterminal_finish"; state = 0; break; case 300: startscript = true; newscript="custom_"+customscript[0]; obj.removetrigger(300); state = 0; break; case 301: startscript = true; newscript="custom_"+customscript[1]; obj.removetrigger(301); state = 0; break; case 302: startscript = true; newscript="custom_"+customscript[2]; obj.removetrigger(302); state = 0; break; case 303: startscript = true; newscript="custom_"+customscript[3]; obj.removetrigger(303); state = 0; break; case 304: startscript = true; newscript="custom_"+customscript[4]; obj.removetrigger(304); state = 0; break; case 305: startscript = true; newscript="custom_"+customscript[5]; obj.removetrigger(305); state = 0; break; case 306: startscript = true; newscript="custom_"+customscript[6]; obj.removetrigger(306); state = 0; break; case 307: startscript = true; newscript="custom_"+customscript[7]; obj.removetrigger(307); state = 0; break; case 308: startscript = true; newscript="custom_"+customscript[8]; obj.removetrigger(308); state = 0; break; case 309: startscript = true; newscript="custom_"+customscript[9]; obj.removetrigger(309); state = 0; break; case 310: startscript = true; newscript="custom_"+customscript[10]; obj.removetrigger(310); state = 0; break; case 311: startscript = true; newscript="custom_"+customscript[11]; obj.removetrigger(311); state = 0; break; case 312: startscript = true; newscript="custom_"+customscript[12]; obj.removetrigger(312); state = 0; break; case 313: startscript = true; newscript="custom_"+customscript[13]; obj.removetrigger(313); state = 0; break; case 314: startscript = true; newscript="custom_"+customscript[14]; obj.removetrigger(314); state = 0; break; case 315: startscript = true; newscript="custom_"+customscript[15]; obj.removetrigger(315); state = 0; break; case 316: startscript = true; newscript="custom_"+customscript[16]; obj.removetrigger(316); state = 0; break; case 317: startscript = true; newscript="custom_"+customscript[17]; obj.removetrigger(317); state = 0; break; case 318: startscript = true; newscript="custom_"+customscript[18]; obj.removetrigger(318); state = 0; break; case 319: startscript = true; newscript="custom_"+customscript[19]; obj.removetrigger(319); state = 0; break; case 320: startscript = true; newscript="custom_"+customscript[20]; obj.removetrigger(320); state = 0; break; case 321: startscript = true; newscript="custom_"+customscript[21]; obj.removetrigger(321); state = 0; break; case 322: startscript = true; newscript="custom_"+customscript[22]; obj.removetrigger(322); state = 0; break; case 323: startscript = true; newscript="custom_"+customscript[23]; obj.removetrigger(323); state = 0; break; case 324: startscript = true; newscript="custom_"+customscript[24]; obj.removetrigger(324); state = 0; break; case 325: startscript = true; newscript="custom_"+customscript[25]; obj.removetrigger(325); state = 0; break; case 326: startscript = true; newscript="custom_"+customscript[26]; obj.removetrigger(326); state = 0; break; case 327: startscript = true; newscript="custom_"+customscript[27]; obj.removetrigger(327); state = 0; break; case 328: startscript = true; newscript="custom_"+customscript[28]; obj.removetrigger(328); state = 0; break; case 329: startscript = true; newscript="custom_"+customscript[29]; obj.removetrigger(329); state = 0; break; case 330: startscript = true; newscript="custom_"+customscript[30]; obj.removetrigger(330); state = 0; break; case 331: startscript = true; newscript="custom_"+customscript[31]; obj.removetrigger(331); state = 0; break; case 332: startscript = true; newscript="custom_"+customscript[32]; obj.removetrigger(332); state = 0; break; case 333: startscript = true; newscript="custom_"+customscript[33]; obj.removetrigger(333); state = 0; break; case 334: startscript = true; newscript="custom_"+customscript[34]; obj.removetrigger(334); state = 0; break; case 335: startscript = true; newscript="custom_"+customscript[35]; obj.removetrigger(335); state = 0; break; case 336: startscript = true; newscript="custom_"+customscript[36]; obj.removetrigger(336); state = 0; break; case 1000: dwgfx.showcutscenebars = true; hascontrol = false; completestop = true; state++; statedelay = 15; break; case 1001: //Found a trinket! advancetext = true; state++; if (dwgfx.flipmode) { dwgfx.createtextbox(" Congratulations! ", 50, 105, 174, 174, 174); dwgfx.addline(""); dwgfx.addline("You have found a shiny trinket!"); dwgfx.textboxcenterx(); if(map.custommode) { dwgfx.createtextbox(" " + help.number(trinkets) + " out of " + help.number(map.customtrinkets)+ " ", 50, 65, 174, 174, 174); dwgfx.textboxcenterx(); } else { dwgfx.createtextbox(" " + help.number(trinkets) + " out of Twenty ", 50, 65, 174, 174, 174); dwgfx.textboxcenterx(); } } else { dwgfx.createtextbox(" Congratulations! ", 50, 85, 174, 174, 174); dwgfx.addline(""); dwgfx.addline("You have found a shiny trinket!"); dwgfx.textboxcenterx(); if(map.custommode) { dwgfx.createtextbox(" " + help.number(trinkets) + " out of " + help.number(map.customtrinkets)+ " ", 50, 135, 174, 174, 174); dwgfx.textboxcenterx(); } else { dwgfx.createtextbox(" " + help.number(trinkets) + " out of Twenty ", 50, 135, 174, 174, 174); dwgfx.textboxcenterx(); } } break; case 1003: dwgfx.textboxremove(); hascontrol = true; advancetext = false; completestop = false; state = 0; //music.play(music.resumesong); if(!muted && music.currentsong>-1) music.fadeMusicVolumeIn(3000); dwgfx.showcutscenebars = false; break; case 1010: dwgfx.showcutscenebars = true; hascontrol = false; completestop = true; state++; statedelay = 15; break; case 1011: //Found a trinket! advancetext = true; state++; if (dwgfx.flipmode) { dwgfx.createtextbox(" Congratulations! ", 50, 105, 174, 174, 174); dwgfx.addline(""); dwgfx.addline("You have found a lost crewmate!"); dwgfx.textboxcenterx(); if(int(map.customcrewmates-crewmates)==0) { dwgfx.createtextbox(" All crewmates rescued! ", 50, 135, 174, 174, 174); } else if(map.customcrewmates-crewmates==1) { dwgfx.createtextbox(" " + help.number(int(map.customcrewmates-crewmates))+ " remains ", 50, 135, 174, 174, 174); } else { dwgfx.createtextbox(" " + help.number(int(map.customcrewmates-crewmates))+ " remain ", 50, 135, 174, 174, 174); } dwgfx.textboxcenterx(); } else { dwgfx.createtextbox(" Congratulations! ", 50, 85, 174, 174, 174); dwgfx.addline(""); dwgfx.addline("You have found a lost crewmate!"); dwgfx.textboxcenterx(); if(int(map.customcrewmates-crewmates)==0) { dwgfx.createtextbox(" All crewmates rescued! ", 50, 135, 174, 174, 174); } else if(map.customcrewmates-crewmates==1) { dwgfx.createtextbox(" " + help.number(int(map.customcrewmates-crewmates))+ " remains ", 50, 135, 174, 174, 174); } else { dwgfx.createtextbox(" " + help.number(int(map.customcrewmates-crewmates))+ " remain ", 50, 135, 174, 174, 174); } dwgfx.textboxcenterx(); } break; case 1013: dwgfx.textboxremove(); hascontrol = true; advancetext = false; completestop = false; state = 0; if(map.customcrewmates-crewmates==0) { if(map.custommodeforreal) { dwgfx.fademode = 2; if(!muted && ed.levmusic>0) music.fadeMusicVolumeIn(3000); if(ed.levmusic>0) music.fadeout(); state=1014; } else { gamestate = EDITORMODE; dwgfx.backgrounddrawn=false; if(!muted && ed.levmusic>0) music.fadeMusicVolumeIn(3000); if(ed.levmusic>0) music.fadeout(); } } else { if(!muted && ed.levmusic>0) music.fadeMusicVolumeIn(3000); } dwgfx.showcutscenebars = false; break; case 1014: frames--; if(dwgfx.fademode == 1) state++; break; case 1015: dwgfx.flipmode = false; gamestate = TITLEMODE; dwgfx.fademode = 4; music.play(6); dwgfx.backgrounddrawn = true; map.tdrawback = true; //Update level stats if(map.customcrewmates-crewmates==0) { //Finished level if(map.customtrinkets-trinkets==0) { //and got all the trinkets! updatecustomlevelstats(customlevelfilename, 3); } else { updatecustomlevelstats(customlevelfilename, 1); } } createmenu("levellist"); state = 0; break; case 2000: //Game Saved! if (intimetrial || nodeathmode || inintermission) { state = 0; } else { savetele(map, obj, music); if (dwgfx.flipmode) { dwgfx.createtextbox(" Game Saved ", -1, 202, 174, 174, 174); dwgfx.textboxtimer(25); } else { dwgfx.createtextbox(" Game Saved ", -1, 12, 174, 174, 174); dwgfx.textboxtimer(25); } state = 0; } break; case 2500: music.play(5); //Activating a teleporter (appear) state++; statedelay = 15; flashlight = 5; screenshake = 90; music.playef(9, 10); break; case 2501: //Activating a teleporter 2 state++; statedelay = 0; flashlight = 5; screenshake = 0; //we're done here! music.playef(10, 10); break; case 2502: //Activating a teleporter 2 state++; statedelay = 5; i = obj.getplayer(); obj.entities[i].colour = 0; obj.entities[i].invis = false; obj.entities[i].xp = obj.entities[obj.getteleporter()].xp+44; obj.entities[i].yp = obj.entities[obj.getteleporter()].yp+44; obj.entities[i].ay = -6; obj.entities[i].ax = 6; obj.entities[i].vy = -6; obj.entities[i].vx = 6; i = obj.getteleporter(); obj.entities[i].tile = 1; obj.entities[i].colour = 101; break; case 2503: state++; i = obj.getplayer(); obj.entities[i].xp += 10; break; case 2504: state++; i = obj.getplayer(); //obj.entities[i].xp += 10; break; case 2505: state++; i = obj.getplayer(); obj.entities[i].xp += 8; break; case 2506: state++; i = obj.getplayer(); obj.entities[i].xp += 6; break; case 2507: state++; i = obj.getplayer(); //obj.entities[i].xp += 4; break; case 2508: state++; i = obj.getplayer(); obj.entities[i].xp += 2; break; case 2509: state++; statedelay = 15; i = obj.getplayer(); obj.entities[i].xp += 1; break; case 2510: advancetext = true; hascontrol = false; dwgfx.createtextbox("Hello?", 125+24, 152-20, 164, 164, 255); state++; music.playef(11, 10); dwgfx.textboxactive(); break; case 2512: advancetext = true; hascontrol = false; dwgfx.createtextbox("Is anyone there?", 125+8, 152-24, 164, 164, 255); state++; music.playef(11, 10); dwgfx.textboxactive(); break; case 2514: dwgfx.textboxremove(); hascontrol = true; advancetext = false; state = 0; music.play(3); break; case 3000: //Activating a teleporter (long version for level complete) state++; statedelay = 30; flashlight = 5; screenshake = 90; music.playef(9, 10); break; case 3001: //Activating a teleporter 2 state++; statedelay = 15; flashlight = 5; music.playef(9, 10); break; case 3002: //Activating a teleporter 2 state++; statedelay = 15; flashlight = 5; music.playef(9, 10); break; case 3003: //Activating a teleporter 2 state++; statedelay = 15; flashlight = 5; music.playef(9, 10); break; case 3004: //Activating a teleporter 2 state++; statedelay = 0; flashlight = 5; screenshake = 0; //we're done here! music.playef(10, 10); break; case 3005: //Activating a teleporter 2 state++; statedelay = 50; //testing! //state = 3006; //Warp Zone //state = 3020; //Space Station switch(companion) { case 6: state = 3006; break; //Warp Zone case 7: state = 3020; break; //Space Station case 8: state = 3040; break; //Lab case 9: state = 3060; break; //Tower case 10: state = 3080; break; //Intermission 2 case 11: state = 3085; break; //Intermission 1 } i = obj.getplayer(); obj.entities[i].colour = 0; obj.entities[i].invis = true; i = obj.getcompanion(companion); if(i>-1) { obj.entities[i].active = false; } i = obj.getteleporter(); obj.entities[i].tile = 1; obj.entities[i].colour = 100; break; case 3006: //Level complete! (warp zone) unlocknum(4, map, dwgfx); lastsaved = 4; music.play(0); state++; statedelay = 75; if (dwgfx.flipmode) { dwgfx.createtextbox("", -1, 180, 165, 165, 255); } else { dwgfx.createtextbox("", -1, 12, 165, 165, 255); } //dwgfx.addline(" Level Complete! "); dwgfx.addline(" "); dwgfx.addline(""); dwgfx.addline(""); dwgfx.textboxcenterx(); /* advancetext = true; hascontrol = false; state = 3; dwgfx.createtextbox("To do: write quick", 50, 80, 164, 164, 255); dwgfx.addline("intro to story!");*/ break; case 3007: state++; statedelay = 45; if (dwgfx.flipmode) { dwgfx.createtextbox("", -1, 104, 175,174,174); } else { dwgfx.createtextbox("", -1, 64+8+16, 175,174,174); } dwgfx.addline(" You have rescued "); dwgfx.addline(" a crew member! "); dwgfx.addline(""); dwgfx.textboxcenterx(); break; case 3008: state++; statedelay = 45; temp = 6 - crewrescued(); if (temp == 1) { tempstring = " One remains "; if (dwgfx.flipmode) { dwgfx.createtextbox(tempstring, -1, 72, 174, 174, 174); } else { dwgfx.createtextbox(tempstring, -1, 128+16, 174, 174, 174); } } else if (temp > 0) { tempstring = " " + help.number(temp) + " remain "; if (dwgfx.flipmode) { dwgfx.createtextbox(tempstring, -1, 72, 174, 174, 174); } else { dwgfx.createtextbox(tempstring, -1, 128+16, 174, 174, 174); } } else { if (dwgfx.flipmode) { dwgfx.createtextbox(" All Crew Members Rescued! ", -1, 72, 174, 174, 174); } else { dwgfx.createtextbox(" All Crew Members Rescued! ", -1, 128+16, 174, 174, 174); } } dwgfx.textboxcenterx(); break; case 3009: state++; statedelay = 0; if (dwgfx.flipmode) { dwgfx.createtextbox(" Press ACTION to continue ", -1, 20, 164, 164, 255); } else { dwgfx.createtextbox(" Press ACTION to continue ", -1, 196, 164, 164, 255); } dwgfx.textboxcenterx(); break; case 3010: if (jumppressed) { state++; statedelay = 30; dwgfx.textboxremove(); } break; case 3011: state = 3070; statedelay = 0; break; case 3020: //Level complete! (Space Station 2) unlocknum(3, map, dwgfx); lastsaved = 2; music.play(0); state++; statedelay = 75; if (dwgfx.flipmode) { dwgfx.createtextbox("", -1, 180, 165, 165, 255); } else { dwgfx.createtextbox("", -1, 12, 165, 165, 255); } //dwgfx.addline(" Level Complete! "); dwgfx.addline(" "); dwgfx.addline(""); dwgfx.addline(""); dwgfx.textboxcenterx(); /* advancetext = true; hascontrol = false; state = 3; dwgfx.createtextbox("To do: write quick", 50, 80, 164, 164, 255); dwgfx.addline("intro to story!");*/ break; case 3021: state++; statedelay = 45; if (dwgfx.flipmode) { dwgfx.createtextbox("", -1, 104, 174,175,174); } else { dwgfx.createtextbox("", -1, 64+8+16, 174,175,174); } dwgfx.addline(" You have rescued "); dwgfx.addline(" a crew member! "); dwgfx.addline(""); dwgfx.textboxcenterx(); break; case 3022: state++; statedelay = 45; temp = 6 - crewrescued(); if (temp == 1) { tempstring = " One remains "; if (dwgfx.flipmode) { dwgfx.createtextbox(tempstring, -1, 72, 174, 174, 174); } else { dwgfx.createtextbox(tempstring, -1, 128+16, 174, 174, 174); } } else if (temp > 0) { tempstring = " " + help.number(temp) + " remain "; if (dwgfx.flipmode) { dwgfx.createtextbox(tempstring, -1, 72, 174, 174, 174); } else { dwgfx.createtextbox(tempstring, -1, 128+16, 174, 174, 174); } } else { if (dwgfx.flipmode) { dwgfx.createtextbox(" All Crew Members Rescued! ", -1, 72, 174, 174, 174); } else { dwgfx.createtextbox(" All Crew Members Rescued! ", -1, 128+16, 174, 174, 174); } } dwgfx.textboxcenterx(); break; case 3023: state++; statedelay = 0; if (dwgfx.flipmode) { dwgfx.createtextbox(" Press ACTION to continue ", -1, 20, 164, 164, 255); } else { dwgfx.createtextbox(" Press ACTION to continue ", -1, 196, 164, 164, 255); } dwgfx.textboxcenterx(); break; case 3024: if (jumppressed) { state++; statedelay = 30; dwgfx.textboxremove(); } break; case 3025: state = 3070; statedelay = 0; break; case 3040: //Level complete! (Lab) unlocknum(1, map, dwgfx); lastsaved = 5; music.play(0); state++; statedelay = 75; if (dwgfx.flipmode) { dwgfx.createtextbox("", -1, 180, 165, 165, 255); } else { dwgfx.createtextbox("", -1, 12, 165, 165, 255); } //dwgfx.addline(" Level Complete! "); dwgfx.addline(" "); dwgfx.addline(""); dwgfx.addline(""); dwgfx.textboxcenterx(); /* advancetext = true; hascontrol = false; state = 3; dwgfx.createtextbox("To do: write quick", 50, 80, 164, 164, 255); dwgfx.addline("intro to story!");*/ break; case 3041: state++; statedelay = 45; if (dwgfx.flipmode) { dwgfx.createtextbox("", -1, 104, 174,174,175); } else { dwgfx.createtextbox("", -1, 64+8+16, 174,174,175); } dwgfx.addline(" You have rescued "); dwgfx.addline(" a crew member! "); dwgfx.addline(""); dwgfx.textboxcenterx(); break; case 3042: state++; statedelay = 45; temp = 6 - crewrescued(); if (temp == 1) { tempstring = " One remains "; if (dwgfx.flipmode) { dwgfx.createtextbox(tempstring, -1, 72, 174, 174, 174); } else { dwgfx.createtextbox(tempstring, -1, 128+16, 174, 174, 174); } } else if (temp > 0) { tempstring = " " + help.number(temp) + " remain "; if (dwgfx.flipmode) { dwgfx.createtextbox(tempstring, -1, 72, 174, 174, 174); } else { dwgfx.createtextbox(tempstring, -1, 128+16, 174, 174, 174); } } else { if (dwgfx.flipmode) { dwgfx.createtextbox(" All Crew Members Rescued! ", -1, 72, 174, 174, 174); } else { dwgfx.createtextbox(" All Crew Members Rescued! ", -1, 128+16, 174, 174, 174); } } dwgfx.textboxcenterx(); break; case 3043: state++; statedelay = 0; if (dwgfx.flipmode) { dwgfx.createtextbox(" Press ACTION to continue ", -1, 20, 164, 164, 255); } else { dwgfx.createtextbox(" Press ACTION to continue ", -1, 196, 164, 164, 255); } dwgfx.textboxcenterx(); break; case 3044: if (jumppressed) { state++; statedelay = 30; dwgfx.textboxremove(); } break; case 3045: state = 3070; statedelay = 0; break; case 3050: //Level complete! (Space Station 1) unlocknum(0, map, dwgfx); lastsaved = 1; music.play(0); state++; statedelay = 75; if (dwgfx.flipmode) { dwgfx.createtextbox("", -1, 180, 165, 165, 255); } else { dwgfx.createtextbox("", -1, 12, 165, 165, 255); } //dwgfx.addline(" Level Complete! "); dwgfx.addline(" "); dwgfx.addline(""); dwgfx.addline(""); dwgfx.textboxcenterx(); /* advancetext = true; hascontrol = false; state = 3; dwgfx.createtextbox("To do: write quick", 50, 80, 164, 164, 255); dwgfx.addline("intro to story!");*/ break; case 3051: state++; statedelay = 45; if (dwgfx.flipmode) { dwgfx.createtextbox("", -1, 104, 175,175,174); } else { dwgfx.createtextbox("", -1, 64+8+16, 175,175,174); } dwgfx.addline(" You have rescued "); dwgfx.addline(" a crew member! "); dwgfx.addline(""); dwgfx.textboxcenterx(); break; case 3052: state++; statedelay = 45; temp = 6 - crewrescued(); if (temp == 1) { tempstring = " One remains "; if (dwgfx.flipmode) { dwgfx.createtextbox(tempstring, -1, 72, 174, 174, 174); } else { dwgfx.createtextbox(tempstring, -1, 128+16, 174, 174, 174); } } else if (temp > 0) { tempstring = " " + help.number(temp) + " remain "; if (dwgfx.flipmode) { dwgfx.createtextbox(tempstring, -1, 72, 174, 174, 174); } else { dwgfx.createtextbox(tempstring, -1, 128+16, 174, 174, 174); } } else { if (dwgfx.flipmode) { dwgfx.createtextbox(" All Crew Members Rescued! ", -1, 72, 174, 174, 174); } else { dwgfx.createtextbox(" All Crew Members Rescued! ", -1, 128+16, 174, 174, 174); } } dwgfx.textboxcenterx(); break; case 3053: state++; statedelay = 0; if (dwgfx.flipmode) { dwgfx.createtextbox(" Press ACTION to continue ", -1, 20, 164, 164, 255); } else { dwgfx.createtextbox(" Press ACTION to continue ", -1, 196, 164, 164, 255); } dwgfx.textboxcenterx(); break; case 3054: if (jumppressed) { state++; statedelay = 30; dwgfx.textboxremove(); crewstats[1] = 0; //Set violet's rescue script to 0 to make the next bit easier teleportscript = ""; } break; case 3055: dwgfx.fademode = 2; state++; statedelay = 10; break; case 3056: if(dwgfx.fademode==1) { startscript = true; if (nocutscenes) { newscript="bigopenworldskip"; } else { newscript = "bigopenworld"; } state = 0; } break; case 3060: //Level complete! (Tower) unlocknum(2, map, dwgfx); lastsaved = 3; music.play(0); state++; statedelay = 75; if (dwgfx.flipmode) { dwgfx.createtextbox("", -1, 180, 165, 165, 255); } else { dwgfx.createtextbox("", -1, 12, 165, 165, 255); } //dwgfx.addline(" Level Complete! "); dwgfx.addline(" "); dwgfx.addline(""); dwgfx.addline(""); dwgfx.textboxcenterx(); /* advancetext = true; hascontrol = false; state = 3; dwgfx.createtextbox("To do: write quick", 50, 80, 164, 164, 255); dwgfx.addline("intro to story!");*/ break; case 3061: state++; statedelay = 45; if (dwgfx.flipmode) { dwgfx.createtextbox("", -1, 104, 175,174,175); } else { dwgfx.createtextbox("", -1, 64+8+16, 175,174,175); } dwgfx.addline(" You have rescued "); dwgfx.addline(" a crew member! "); dwgfx.addline(""); dwgfx.textboxcenterx(); break; case 3062: state++; statedelay = 45; temp = 6 - crewrescued(); if (temp == 1) { tempstring = " One remains "; if (dwgfx.flipmode) { dwgfx.createtextbox(tempstring, -1, 72, 174, 174, 174); } else { dwgfx.createtextbox(tempstring, -1, 128+16, 174, 174, 174); } } else if (temp > 0) { tempstring = " " + help.number(temp) + " remain "; if (dwgfx.flipmode) { dwgfx.createtextbox(tempstring, -1, 72, 174, 174, 174); } else { dwgfx.createtextbox(tempstring, -1, 128+16, 174, 174, 174); } } else { if (dwgfx.flipmode) { dwgfx.createtextbox(" All Crew Members Rescued! ", -1, 72, 174, 174, 174); } else { dwgfx.createtextbox(" All Crew Members Rescued! ", -1, 128+16, 174, 174, 174); } } dwgfx.textboxcenterx(); break; case 3063: state++; statedelay = 0; if (dwgfx.flipmode) { dwgfx.createtextbox(" Press ACTION to continue ", -1, 20, 164, 164, 255); } else { dwgfx.createtextbox(" Press ACTION to continue ", -1, 196, 164, 164, 255); } dwgfx.textboxcenterx(); break; case 3064: if (jumppressed) { state++; statedelay = 30; dwgfx.textboxremove(); } break; case 3065: state = 3070; statedelay = 0; break; case 3070: dwgfx.fademode = 2; state++; break; case 3071: if (dwgfx.fademode == 1) state++; break; case 3072: //Ok, we need to adjust some flags based on who've we've rescued. Some of there conversation options //change depending on when they get back to the ship. if (lastsaved == 2) { if (crewstats[3]) obj.flags[25] = 1; if (crewstats[4]) obj.flags[26] = 1; if (crewstats[5]) obj.flags[24] = 1; } else if (lastsaved == 3) { if (crewstats[2]) obj.flags[50] = 1; if (crewstats[4]) obj.flags[49] = 1; if (crewstats[5]) obj.flags[48] = 1; } else if (lastsaved == 4) { if (crewstats[2]) obj.flags[54] = 1; if (crewstats[3]) obj.flags[55] = 1; if (crewstats[5]) obj.flags[56] = 1; } else if (lastsaved == 5) { if (crewstats[2]) obj.flags[37] = 1; if (crewstats[3]) obj.flags[38] = 1; if (crewstats[4]) obj.flags[39] = 1; } //We're pitch black now, make a decision companion = 0; if (crewrescued() == 6) { startscript = true; newscript="startlevel_final"; state = 0; } else if (crewrescued() == 4) { companion = 11; supercrewmate = true; scmprogress = 0; startscript = true; newscript = "intermission_1"; obj.flags[19] = 1; if (lastsaved == 2) obj.flags[32] = 1; if (lastsaved == 3) obj.flags[35] = 1; if (lastsaved == 4) obj.flags[34] = 1; if (lastsaved == 5) obj.flags[33] = 1; state = 0; } else if (crewrescued() == 5) { startscript = true; newscript = "intermission_2"; obj.flags[20] = 1; if (lastsaved == 2) obj.flags[32] = 1; if (lastsaved == 3) obj.flags[35] = 1; if (lastsaved == 4) obj.flags[34] = 1; if (lastsaved == 5) obj.flags[33] = 1; state = 0; } else { startscript = true; newscript="regularreturn"; state = 0; } break; case 3080: //returning from an intermission, very like 3070 if (inintermission) { dwgfx.fademode = 2; companion = 0; state=3100; } else { unlocknum(7, map, dwgfx); dwgfx.fademode = 2; companion = 0; state++; } break; case 3081: if (dwgfx.fademode == 1) state++; break; case 3082: map.finalmode = false; startscript = true; newscript="regularreturn"; state = 0; break; case 3085: //returning from an intermission, very like 3070 //return to menu from here if (inintermission) { companion = 0; supercrewmate = false; state++; dwgfx.fademode = 2; music.fadeout(); state=3100; } else { unlocknum(6, map, dwgfx); dwgfx.fademode = 2; companion = 0; supercrewmate = false; state++; } break; case 3086: if (dwgfx.fademode == 1) state++; break; case 3087: map.finalmode = false; startscript = true; newscript="regularreturn"; state = 0; break; case 3100: if(dwgfx.fademode == 1) state++; break; case 3101: dwgfx.flipmode = false; gamestate = 1; dwgfx.fademode = 4; dwgfx.backgrounddrawn = true; map.tdrawback = true; createmenu("play"); music.play(6); state = 0; break; //startscript = true; newscript="returntohub"; //state = 0; /*case 3025: if (recording == 1) { //if recording the input, output it to debug here trace(recordstring); help.toclipboard(recordstring); } test = true; teststring = recordstring; dwgfx.createtextbox(" Congratulations! ", 50, 80, 164, 164, 255); dwgfx.addline(""); dwgfx.addline("Your play of this level has"); dwgfx.addline("been copied to the clipboard."); dwgfx.addline(""); dwgfx.addline("Please consider pasting and"); dwgfx.addline("sending it to me! Even if you"); dwgfx.addline("made a lot of mistakes - knowing"); dwgfx.addline("exactly where people are having"); dwgfx.addline("trouble is extremely useful!"); dwgfx.textboxcenter(); state = 0; break;*/ case 3500: music.fadeout(); state++; statedelay = 120; //state = 3511; //testing break; case 3501: //Game complete! NETWORK_unlockAchievement("vvvvvvgamecomplete"); unlocknum(5, map, dwgfx); crewstats[0] = true; state++; statedelay = 75; music.play(7); if (dwgfx.flipmode) { dwgfx.createtextbox("", -1, 180, 164, 165, 255); } else { dwgfx.createtextbox("", -1, 12, 164, 165, 255); } dwgfx.addline(" "); dwgfx.addline(""); dwgfx.addline(""); dwgfx.textboxcenterx(); break; case 3502: state++; statedelay = 45+15; if (dwgfx.flipmode) { dwgfx.createtextbox(" All Crew Members Rescued! ", -1, 175-24, 0, 0, 0); } else { dwgfx.createtextbox(" All Crew Members Rescued! ", -1, 64, 0, 0, 0); } savetime = timestring(help); break; case 3503: state++; statedelay = 45; tempstring = help.number(trinkets); if (dwgfx.flipmode) { dwgfx.createtextbox("Trinkets Found:", 48, 155-24, 0,0,0); dwgfx.createtextbox(tempstring, 180, 155-24, 0, 0, 0); } else { dwgfx.createtextbox("Trinkets Found:", 48, 84, 0,0,0); dwgfx.createtextbox(tempstring, 180, 84, 0, 0, 0); } break; case 3504: state++; statedelay = 45+15; tempstring = savetime; if (dwgfx.flipmode) { dwgfx.createtextbox(" Game Time:", 64, 143-24, 0,0,0); dwgfx.createtextbox(tempstring, 180, 143-24, 0, 0, 0); } else { dwgfx.createtextbox(" Game Time:", 64, 96, 0,0,0); dwgfx.createtextbox(tempstring, 180, 96, 0, 0, 0); } break; case 3505: state++; statedelay = 45; if (dwgfx.flipmode) { dwgfx.createtextbox(" Total Flips:", 64, 116-24, 0,0,0); dwgfx.createtextbox(help.String(totalflips), 180, 116-24, 0, 0, 0); } else { dwgfx.createtextbox(" Total Flips:", 64, 123, 0,0,0); dwgfx.createtextbox(help.String(totalflips), 180, 123, 0, 0, 0); } break; case 3506: state++; statedelay = 45+15; if (dwgfx.flipmode) { dwgfx.createtextbox("Total Deaths:", 64, 104-24, 0,0,0); dwgfx.createtextbox(help.String(deathcounts), 180, 104-24, 0, 0, 0); } else { dwgfx.createtextbox("Total Deaths:", 64, 135, 0,0,0); dwgfx.createtextbox(help.String(deathcounts), 180, 135, 0, 0, 0); } break; case 3507: state++; statedelay = 45+15; if (dwgfx.flipmode) { tempstring = "Hardest Room (with " + help.String(hardestroomdeaths) + " deaths)"; dwgfx.createtextbox(tempstring, -1, 81-24, 0,0,0); dwgfx.createtextbox(hardestroom, -1, 69-24, 0, 0, 0); } else { tempstring = "Hardest Room (with " + help.String(hardestroomdeaths) + " deaths)"; dwgfx.createtextbox(tempstring, -1, 158, 0,0,0); dwgfx.createtextbox(hardestroom, -1, 170, 0, 0, 0); } break; case 3508: state++; statedelay = 0; if (dwgfx.flipmode) { dwgfx.createtextbox(" Press ACTION to continue ", -1, 20, 164, 164, 255); } else { dwgfx.createtextbox(" Press ACTION to continue ", -1, 196, 164, 164, 255); } dwgfx.textboxcenterx(); break; case 3509: if (jumppressed) { state++; statedelay = 30; dwgfx.textboxremove(); } break; case 3510: //Save stats and stuff here if (obj.flags[73] == 0) { //flip mode complete NETWORK_unlockAchievement("vvvvvvgamecompleteflip"); unlock[19] = true; } if (bestgamedeaths == -1) { bestgamedeaths = deathcounts; } else { if (deathcounts < bestgamedeaths) { bestgamedeaths = deathcounts; } } if (bestgamedeaths > -1) { if (bestgamedeaths <= 500) { NETWORK_unlockAchievement("vvvvvvcomplete500"); } if (bestgamedeaths <= 250) { NETWORK_unlockAchievement("vvvvvvcomplete250"); } if (bestgamedeaths <= 100) { NETWORK_unlockAchievement("vvvvvvcomplete100"); } if (bestgamedeaths <= 50) { NETWORK_unlockAchievement("vvvvvvcomplete50"); } } savestats(map, dwgfx); if (nodeathmode) { NETWORK_unlockAchievement("vvvvvvmaster"); //bloody hell unlock[20] = true; state = 3520; statedelay = 0; } else { statedelay = 120; state++; } break; case 3511: //Activating a teleporter (long version for level complete) i = obj.getplayer(); obj.entities[i].colour = 102; obj.flags[67] = 1; state++; statedelay = 30; flashlight = 5; screenshake = 90; music.playef(9, 10); break; case 3512: //Activating a teleporter 2 state++; statedelay = 15; flashlight = 5; music.playef(9, 10); break; case 3513: //Activating a teleporter 2 state++; statedelay = 15; flashlight = 5; music.playef(9, 10); break; case 3514: //Activating a teleporter 2 state++; statedelay = 15; flashlight = 5; music.playef(9, 10); break; case 3515: //Activating a teleporter 2 state++; statedelay = 0; flashlight = 5; screenshake = 0; i = obj.getplayer(); obj.entities[i].colour = 0; obj.entities[i].invis = true; //we're done here! music.playef(10, 10); statedelay = 60; break; case 3516: dwgfx.fademode = 2; state++; break; case 3517: if (dwgfx.fademode == 1) { state++; statedelay = 30; } break; case 3518: dwgfx.fademode = 4; state = 0; statedelay = 30; //music.play(5); //music.play(10); map.finalmode = false; map.final_colormode = false; map.final_mapcol = 0; map.final_colorframe = 0; map.finalstretch = false; map.finalx = 100; map.finaly = 100; dwgfx.cutscenebarspos = 320; teleport_to_new_area = true; teleportscript = "gamecomplete"; break; case 3520: //NO DEATH MODE COMPLETE JESUS hascontrol = false; crewstats[0] = true; dwgfx.fademode = 2; state++; break; case 3521: if(dwgfx.fademode == 1) state++; break; case 3522: dwgfx.flipmode = false; gamestate = 1; dwgfx.fademode = 4; dwgfx.backgrounddrawn = true; map.tdrawback = true; createmenu("nodeathmodecomplete"); state = 0; break; case 4000: //Activating a teleporter (short version) state++; statedelay = 10; flashlight = 5; screenshake = 10; music.playef(9, 10); break; case 4001: //Activating a teleporter 2 state++; statedelay = 0; flashlight = 5; screenshake = 0; //we're done here! music.playef(10, 10); break; case 4002: //Activating a teleporter 2 state++; statedelay = 10; //testing! //state = 3006; //Warp Zone //state = 3020; //Space Station //state = 3040; //Lab i = obj.getplayer(); obj.entities[i].colour = 0; obj.entities[i].invis = true; i = obj.getteleporter(); if(i>-1) { obj.entities[i].tile = 1; obj.entities[i].colour = 100; } break; case 4003: state = 0; statedelay = 0; teleport_to_new_area = true; break; case 4010: //Activating a teleporter (default appear) state++; statedelay = 15; flashlight = 5; screenshake = 90; music.playef(9, 10); break; case 4011: //Activating a teleporter 2 state++; statedelay = 0; flashlight = 5; screenshake = 0; music.playef(10, 10); break; case 4012: //Activating a teleporter 2 state++; statedelay = 5; i = obj.getplayer(); j = obj.getteleporter(); if (j != -1) { obj.entities[i].xp = obj.entities[j].xp+44; obj.entities[i].yp = obj.entities[j].yp+44; obj.entities[j].tile = 2; obj.entities[j].colour = 101; } obj.entities[i].colour = 0; obj.entities[i].invis = false; obj.entities[i].dir = 1; obj.entities[i].ay = -6; obj.entities[i].ax = 6; obj.entities[i].vy = -6; obj.entities[i].vx = 6; break; case 4013: state++; i = obj.getplayer(); obj.entities[i].xp += 10; break; case 4014: state++; i = obj.getplayer(); obj.entities[i].xp += 10; break; case 4015: state++; i = obj.getplayer(); obj.entities[i].xp += 8; break; case 4016: state++; i = obj.getplayer(); obj.entities[i].xp += 6; break; case 4017: state++; i = obj.getplayer(); obj.entities[i].xp += 3; break; case 4018: state++; statedelay = 15; i = obj.getplayer(); obj.entities[i].xp += 1; break; case 4019: if (intimetrial || nodeathmode || inintermission) { } else { savetele(map, obj, music); } i = obj.getteleporter(); activetele = true; teleblock.x = obj.entities[i].xp - 32; teleblock.y = obj.entities[i].yp - 32; teleblock.w = 160; teleblock.h = 160; hascontrol = true; advancetext = false; state = 0; break; case 4020: //Activating a teleporter (default appear) state++; statedelay = 15; flashlight = 5; screenshake = 90; music.playef(9, 10); break; case 4021: //Activating a teleporter 2 state++; statedelay = 0; flashlight = 5; screenshake = 0; music.playef(10, 10); break; case 4022: //Activating a teleporter 2 state++; statedelay = 5; i = obj.getplayer(); j = obj.getteleporter(); if (j != -1) { obj.entities[i].xp = obj.entities[j].xp+44; obj.entities[i].yp = obj.entities[j].yp+44; obj.entities[j].tile = 2; obj.entities[j].colour = 101; } obj.entities[i].colour = 0; obj.entities[i].invis = false; obj.entities[i].dir = 1; obj.entities[i].ay = -6; obj.entities[i].ax = 6; obj.entities[i].vy = -6; obj.entities[i].vx = 6; break; case 4023: state++; i = obj.getplayer(); obj.entities[i].xp += 12; break; case 4024: state++; i = obj.getplayer(); obj.entities[i].xp += 12; break; case 4025: state++; i = obj.getplayer(); obj.entities[i].xp += 10; break; case 4026: state++; i = obj.getplayer(); obj.entities[i].xp += 8; break; case 4027: state++; i = obj.getplayer(); obj.entities[i].xp += 5; break; case 4028: state++; statedelay = 15; i = obj.getplayer(); obj.entities[i].xp += 2; break; case 4029: hascontrol = true; advancetext = false; state = 0; break; case 4030: //Activating a teleporter (default appear) state++; statedelay = 15; flashlight = 5; screenshake = 90; music.playef(9, 10); break; case 4031: //Activating a teleporter 2 state++; statedelay = 0; flashlight = 5; screenshake = 0; music.playef(10, 10); break; case 4032: //Activating a teleporter 2 state++; statedelay = 5; i = obj.getplayer(); j = obj.getteleporter(); if (j != -1) { obj.entities[i].xp = obj.entities[j].xp+44; obj.entities[i].yp = obj.entities[j].yp+44; obj.entities[j].tile = 2; obj.entities[j].colour = 101; } obj.entities[i].colour = 0; obj.entities[i].invis = false; obj.entities[i].dir = 0; obj.entities[i].ay = -6; obj.entities[i].ax = -6; obj.entities[i].vy = -6; obj.entities[i].vx = -6; break; case 4033: state++; i = obj.getplayer(); obj.entities[i].xp -= 12; break; case 4034: state++; i = obj.getplayer(); obj.entities[i].xp -= 12; break; case 4035: state++; i = obj.getplayer(); obj.entities[i].xp -= 10; break; case 4036: state++; i = obj.getplayer(); obj.entities[i].xp -= 8; break; case 4037: state++; i = obj.getplayer(); obj.entities[i].xp -= 5; break; case 4038: state++; statedelay = 15; i = obj.getplayer(); obj.entities[i].xp -= 2; break; case 4039: hascontrol = true; advancetext = false; state = 0; break; case 4040: //Activating a teleporter (default appear) state++; statedelay = 15; flashlight = 5; screenshake = 90; music.playef(9, 10); break; case 4041: //Activating a teleporter 2 state++; statedelay = 0; flashlight = 5; screenshake = 0; music.playef(10, 10); break; case 4042: //Activating a teleporter 2 state++; statedelay = 5; i = obj.getplayer(); j = obj.getteleporter(); if (j != -1) { obj.entities[i].xp = obj.entities[j].xp+44; obj.entities[i].yp = obj.entities[j].yp+44; obj.entities[j].tile = 2; obj.entities[j].colour = 101; } obj.entities[i].colour = 0; obj.entities[i].invis = false; obj.entities[i].dir = 1; obj.entities[i].ay = -6; obj.entities[i].ax = 6; obj.entities[i].vy = -6; obj.entities[i].vx = 6; break; case 4043: state++; i = obj.getplayer(); obj.entities[i].xp += 12; obj.entities[i].yp -= 15; break; case 4044: state++; i = obj.getplayer(); obj.entities[i].xp += 12; obj.entities[i].yp -= 10; break; case 4045: state++; i = obj.getplayer(); obj.entities[i].xp += 12; obj.entities[i].yp -= 10; break; case 4046: state++; i = obj.getplayer(); obj.entities[i].xp += 8; obj.entities[i].yp -= 8; break; case 4047: state++; i = obj.getplayer(); obj.entities[i].xp += 6; obj.entities[i].yp -= 8; break; case 4048: state++; statedelay = 15; i = obj.getplayer(); obj.entities[i].xp += 3; break; case 4049: hascontrol = true; advancetext = false; state = 0; break; case 4050: //Activating a teleporter (default appear) state++; statedelay = 15; flashlight = 5; screenshake = 90; music.playef(9, 10); break; case 4051: //Activating a teleporter 2 state++; statedelay = 0; flashlight = 5; screenshake = 0; music.playef(10, 10); break; case 4052: //Activating a teleporter 2 state++; statedelay = 5; i = obj.getplayer(); j = obj.getteleporter(); if (j != -1) { obj.entities[i].xp = obj.entities[j].xp+44; obj.entities[i].yp = obj.entities[j].yp+44; obj.entities[j].tile = 2; obj.entities[j].colour = 101; } obj.entities[i].colour = 0; obj.entities[i].invis = false; obj.entities[i].dir = 1; obj.entities[i].ay = -6; obj.entities[i].ax = 6; obj.entities[i].vy = -6; obj.entities[i].vx = 6; break; case 4053: state++; i = obj.getplayer(); obj.entities[i].xp += 4; obj.entities[i].yp -= 15; break; case 4054: state++; i = obj.getplayer(); obj.entities[i].xp += 4; obj.entities[i].yp -= 10; break; case 4055: state++; i = obj.getplayer(); obj.entities[i].xp += 4; obj.entities[i].yp -= 10; break; case 4056: state++; i = obj.getplayer(); obj.entities[i].xp += 4; obj.entities[i].yp -= 8; break; case 4057: state++; i = obj.getplayer(); obj.entities[i].xp += 2; obj.entities[i].yp -= 8; break; case 4058: state++; statedelay = 15; i = obj.getplayer(); obj.entities[i].xp += 1; break; case 4059: hascontrol = true; advancetext = false; state = 0; break; case 4060: //Activating a teleporter (default appear) state++; statedelay = 15; flashlight = 5; screenshake = 90; music.playef(9, 10); break; case 4061: //Activating a teleporter 2 state++; statedelay = 0; flashlight = 5; screenshake = 0; music.playef(10, 10); break; case 4062: //Activating a teleporter 2 state++; statedelay = 5; i = obj.getplayer(); j = obj.getteleporter(); if (j != -1) { obj.entities[i].xp = obj.entities[j].xp+44; obj.entities[i].yp = obj.entities[j].yp+44; obj.entities[j].tile = 2; obj.entities[j].colour = 101; } obj.entities[i].colour = 0; obj.entities[i].invis = false; obj.entities[i].dir = 0; obj.entities[i].ay = -6; obj.entities[i].ax = -6; obj.entities[i].vy = -6; obj.entities[i].vx = -6; break; case 4063: state++; i = obj.getplayer(); obj.entities[i].xp -= 28; obj.entities[i].yp -= 8; break; case 4064: state++; i = obj.getplayer(); obj.entities[i].xp -= 28; obj.entities[i].yp -= 8; break; case 4065: state++; i = obj.getplayer(); obj.entities[i].xp -= 25; break; case 4066: state++; i = obj.getplayer(); obj.entities[i].xp -= 25; break; case 4067: state++; i = obj.getplayer(); obj.entities[i].xp -= 20; break; case 4068: state++; statedelay = 15; i = obj.getplayer(); obj.entities[i].xp -= 16; break; case 4069: hascontrol = true; advancetext = false; state = 0; break; case 4070: //Activating a teleporter (special for final script, player has colour changed to match rescued crewmate) state++; statedelay = 15; flashlight = 5; screenshake = 90; music.playef(9, 10); break; case 4071: //Activating a teleporter 2 state++; statedelay = 0; flashlight = 5; screenshake = 0; music.playef(10, 10); break; case 4072: //Activating a teleporter 2 state++; statedelay = 5; i = obj.getplayer(); j = obj.getteleporter(); if (j != -1) { obj.entities[i].xp = obj.entities[j].xp+44; obj.entities[i].yp = obj.entities[j].yp+44; obj.entities[j].tile = 2; obj.entities[j].colour = 101; } obj.entities[i].invis = false; obj.entities[i].dir = 1; obj.entities[i].colour = obj.crewcolour(lastsaved); obj.entities[i].ay = -6; obj.entities[i].ax = 6; obj.entities[i].vy = -6; obj.entities[i].vx = 6; break; case 4073: state++; i = obj.getplayer(); obj.entities[i].xp += 10; break; case 4074: state++; i = obj.getplayer(); obj.entities[i].xp += 10; break; case 4075: state++; i = obj.getplayer(); obj.entities[i].xp += 8; break; case 4076: state++; i = obj.getplayer(); obj.entities[i].xp += 6; break; case 4077: state++; i = obj.getplayer(); obj.entities[i].xp += 3; break; case 4078: state++; statedelay = 15; i = obj.getplayer(); obj.entities[i].xp += 1; break; case 4079: state = 0; startscript = true; newscript = "finallevel_teleporter"; break; case 4080: //Activating a teleporter (default appear) state++; statedelay = 15; flashlight = 5; screenshake = 90; music.playef(9, 10); break; case 4081: //Activating a teleporter 2 state++; statedelay = 0; flashlight = 5; screenshake = 0; music.playef(10, 10); break; case 4082: //Activating a teleporter 2 state++; statedelay = 5; i = obj.getplayer(); j = obj.getteleporter(); if (j != -1) { obj.entities[i].xp = obj.entities[j].xp+44; obj.entities[i].yp = obj.entities[j].yp+44; obj.entities[j].tile = 2; obj.entities[j].colour = 101; } obj.entities[i].colour = 0; obj.entities[i].invis = false; obj.entities[i].dir = 1; obj.entities[i].ay = -6; obj.entities[i].ax = 6; obj.entities[i].vy = -6; obj.entities[i].vx = 6; break; case 4083: state++; i = obj.getplayer(); obj.entities[i].xp += 10; break; case 4084: state++; i = obj.getplayer(); obj.entities[i].xp += 10; break; case 4085: state++; i = obj.getplayer(); obj.entities[i].xp += 8; break; case 4086: state++; i = obj.getplayer(); obj.entities[i].xp += 6; break; case 4087: state++; i = obj.getplayer(); obj.entities[i].xp += 3; break; case 4088: state++; statedelay = 15; i = obj.getplayer(); obj.entities[i].xp += 1; break; case 4089: startscript = true; newscript = "gamecomplete_ending"; state = 0; break; case 4090: //Activating a teleporter (default appear) state++; statedelay = 15; flashlight = 5; screenshake = 90; music.playef(9, 10); break; case 4091: //Activating a teleporter 2 state++; statedelay = 0; flashlight = 5; screenshake = 0; music.playef(10, 10); break; case 4092: //Activating a teleporter 2 state++; statedelay = 5; i = obj.getplayer(); j = obj.getteleporter(); if (j != -1) { obj.entities[i].xp = obj.entities[j].xp+44; obj.entities[i].yp = obj.entities[j].yp+44; obj.entities[j].tile = 2; obj.entities[j].colour = 101; } obj.entities[i].colour = 0; obj.entities[i].invis = false; obj.entities[i].dir = 1; obj.entities[i].ay = -6; obj.entities[i].ax = 6; obj.entities[i].vy = -6; obj.entities[i].vx = 6; break; case 4093: state++; i = obj.getplayer(); obj.entities[i].xp += 10; break; case 4094: state++; i = obj.getplayer(); obj.entities[i].xp += 10; break; case 4095: state++; i = obj.getplayer(); obj.entities[i].xp += 8; break; case 4096: state++; i = obj.getplayer(); obj.entities[i].xp += 6; break; case 4097: state++; i = obj.getplayer(); obj.entities[i].xp += 3; break; case 4098: state++; statedelay = 15; i = obj.getplayer(); obj.entities[i].xp += 1; break; case 4099: if (nocutscenes) { startscript = true; newscript = "levelonecompleteskip"; } else { startscript = true; newscript = "levelonecomplete_ending"; } state = 0; break; }

Cue the Will Ferrel meme: "I'm not even mad, that's impressive." Thanks to Andy K for bringing this to our attention.

[Advertisement] Continuously monitor your servers for configuration changes, and report when there's configuration drift. Get started with Otter today!
Read the whole story
elwillow
172 days ago
reply
Ottawa, Ontario
Share this story
Delete

Control Group

3 Comments and 17 Shares
Placeble 228 x/6
⬜⬜⬜⬜⬜
⬜⬜⬜⬜⬜
⬜⬜⬜⬜⬜
⬜⬜⬜⬜⬜
⬜⬜⬜⬜⬜
⬜⬜⬜⬜⬜
Read the whole story
popular
193 days ago
reply
elwillow
193 days ago
reply
Ottawa, Ontario
Share this story
Delete
3 public comments
philipstorry
193 days ago
reply
I've suddenly realised that I have been in SO MANY control groups in my life...
And it feels fine. 😉
London, United Kingdom
jlvanderzwan
193 days ago
All these things that turned out to have no benefit and a ton of annoying side-effects that we didn't have to deal with!
cjheinz
193 days ago
reply
Nice! Really takes the pressure off!
ossiander
193 days ago
reply
Works for me

Project Zero: A Deep Dive Into an N.S.O. Zero-Click iMessage Exploit

2 Shares

Ian Beer and Samuel Groß of Google Project Zero:

Based on our research and findings, we assess this to be one of the most technically sophisticated exploits we’ve ever seen, further demonstrating that the capabilities NSO provides rival those previously thought to be accessible to only a handful of nation states.

I won’t claim to understand all of this — pointer programming was never my forte — but the overall explanation here is very cogent, and easy to follow. Basically, NSO Group’s exploit involved sending an iMessage-using target a PDF file with a .gif file name extension. The PDF file contained an image in the semi-obscure JBIG2 format, a black-and-white format created for fax machines in the late 1990s. Apple’s image-processing code for JBIG2 streams had a buffer overflow bug. Then it gets a little eye-popping:

JBIG2 doesn’t have scripting capabilities, but when combined with a vulnerability, it does have the ability to emulate circuits of arbitrary logic gates operating on arbitrary memory. So why not just use that to build your own computer architecture and script that!? That’s exactly what this exploit does. Using over 70,000 segment commands defining logical bit operations, they define a small computer architecture with features such as registers and a full 64-bit adder and comparator which they use to search memory and perform arithmetic operations. It’s not as fast as Javascript, but it’s fundamentally computationally equivalent.

The bootstrapping operations for the sandbox escape exploit are written to run on this logic circuit and the whole thing runs in this weird, emulated environment created out of a single decompression pass through a JBIG2 stream. It’s pretty incredible, and at the same time, pretty terrifying.

Read the whole story
elwillow
235 days ago
reply
Ottawa, Ontario
Share this story
Delete

Turing Complete

1 Comment and 5 Shares
Thanks to the ForcedEntry exploit, your company's entire tech stack can now be hosted out of a PDF you texted to someone.
Read the whole story
elwillow
239 days ago
reply
Ottawa, Ontario
Share this story
Delete
1 public comment
jlvanderzwan
240 days ago
reply
For those who missed it: https://googleprojectzero.blogspot.com/2021/12/a-deep-dive-into-nso-zero-click.html

Announcing Cloudflare R2 Storage: Rapid and Reliable Object Storage, minus the egress fees

2 Shares
Announcing Cloudflare R2 Storage: Rapid and Reliable Object Storage, minus the egress fees
Announcing Cloudflare R2 Storage: Rapid and Reliable Object Storage, minus the egress fees

We’re excited to announce Cloudflare R2 Storage! By giving developers the ability to store large amounts of unstructured data, we’re expanding what’s possible with Cloudflare while slashing the egress bandwidth fees associated with typical cloud storage services to zero.

Cloudflare R2 Storage includes full S3 API compatibility, working with existing tools and applications as built.

Let’s get into the R2 details.

R2 means “Really Requestable”

Object Storage, sometimes referred to as blob storage, stores arbitrarily large, unstructured files. Object storage is well suited to storing everything from media files or log files to application-specific metadata, all retrievable with consistent latency, high durability, and limitless capacity.

The most familiar API for Object Storage, and the API R2 implements, is Amazon’s Simple Storage Service (S3). When S3 launched in 2006, cloud storage services were a godsend for developers. It didn’t happen overnight, but over the last fifteen years, developers have embraced cloud storage and its promise of infinite storage space.

As transformative as cloud storage has been, a downside emerged: actually getting your data back. Over time, companies have amassed massive amounts of data on cloud provider networks. When they go to retrieve that data, they’re hit with massive egress fees that don’t correspond to any customer value — just a tax developers have grown accustomed to paying.

Enter R2.

Announcing Cloudflare R2 Storage: Rapid and Reliable Object Storage, minus the egress fees

Traditional object storage charges developers for three things: bandwidth, storage size and storage operations.

R2 builds on Cloudflare’s commitment to the Bandwidth Alliance, providing zero-cost egress for stored objects — no matter your request rate.  Egress bandwidth is often the largest charge for developers utilizing object storage and is also the hardest charge to predict.  Eliminating it is a huge win for open-access to data stored in the cloud.

That doesn’t mean we are shifting bandwidth costs elsewhere. Cloudflare R2 will be priced at $0.015 per GB of data stored per month — significantly cheaper than major incumbent providers.

Infrequent access to objects is often trivial for providers to support yet incurs the same per-operation charges. We don’t think it’s fair that typical object storage bills a developer making one request a second the same rate as an enterprise making thousands of requests a second — or frequently a higher rate when considering negotiated volume discounts.

On the flip side, providers designed for infrequent access typically can’t scale to heavy usage.

R2 will zero-rate infrequent storage operations under a threshold — currently planned to be in the single digit requests per second range. Above this range, R2 will charge significantly less per-operation than the major providers. Our object storage will be extremely inexpensive for infrequent access and yet capable of and cheaper than major incumbent providers at scale.

This cheaper price doesn’t come with reduced scalability. Behind the scenes, R2 automatically and intelligently manages the tiering of data to drive both performance at peak load and low-cost for infrequently requested objects.  We’ve gotten rid of complex, manual tiering policies in favor of what developers have always wanted out of object storage: limitless scale at the lowest possible cost.

R2 means “Repositioning Records”

Zero egress means you can get objects out easily, but what about putting objects in? Migrating data across cloud providers, even if they both support the complete S3 API, is error-prone and costly.

To make this easy for you, without requiring you to change any of your tooling, Cloudflare R2 will include automatic migration from other S3-compatible cloud storage services. Migrations are designed to be dead simple. After specifying an existing storage bucket, R2 will serve requests for objects from the existing bucket, egressing the object only once before copying and serving from R2. Our easy-to-use migrator will reduce egress costs from the second you turn it on in the Cloudflare dashboard.

Announcing Cloudflare R2 Storage: Rapid and Reliable Object Storage, minus the egress fees

Our vision for R2 includes multi-region storage that automatically replicates objects to the locations they’re frequently requested from. As with Durable Objects, we plan on introducing jurisdictional restrictions that allow developers to comply with complex data sovereignty requirements via a simple API.

R2 means “Ridiculously Reliable”

The core of what makes Object Storage great is reliability — we designed R2 for data durability and resilience at its core. R2 will provide 99.999999999% (eleven 9’s) of annual durability, which describes the likelihood of data loss. If you store 1,000,000 objects on R2, you can expect to lose one once every 100,000 years — the same level of durability as other major providers. R2 will be resistant to regional failures, replicating objects multiple times for high availability.

R2 is designed with redundancy across a large number of regions for reliability. We plan on starting from automatic global distribution and adding back region-specific controls for when data has to be stored locally, as described above.

R2 means “Radically Reprogrammable”

R2 is fully integrated with the Cloudflare Workers serverless runtime. You can bind a Worker to a specific bucket, dynamically transforming objects as they are written to or read from storage buckets. The deep integration between Workers and R2 makes building data pipelines and manipulating objects incredibly easy.

Cloudflare R2 is designed to easily integrate with the rest of Cloudflare's products. As a few examples, our plan is to allow Durable Objects to be configured with R2 as a backup target, and provide automatic integration between R2 and Cloudflare cache to greatly extend cache lifetimes for infrequently changing objects.

What will you be able to build with Cloudflare R2?

There’s a lot you can do with long-term storage, especially with access to the Workers compute platform just alongside it.

For example, streaming data from a large number of IoT devices becomes a breeze with R2. Starting with a Worker to transform and manipulate the data, R2 can ingest large volumes of sensor data and store it at low cost. With no egress fees, it becomes simple to migrate volumes of data to multiple databases and analytics solutions as needed, dramatically reducing storage costs. With the ability to run a Worker on the outgoing data as well, the data pipeline itself is more flexible.

R2 is also a great place for CDN assets and large media files. For large files, R2 can significantly extend cache lifetimes while dramatically slashing egress bills. Combined with the Cache API and Workers, content can be dynamically cached for low-latency access around the globe.

More than anything, R2’s lack of egress bandwidth charges makes it ideal for storing content that’s accessed frequently. Today, R2 scales well to handle heavy request loads, dynamically tiering your objects to provide the best performance at the lowest cost. This dynamic tiering allows us to offer the lowest prices while supporting peak performance — with no user configuration required.

Accessing Cloudflare R2

R2 is currently under development — you can sign up here to join the waitlist for access. We’re excited to work with a number of earlier users to refine and test the product. We’ll be announcing an open beta where any user will be able to sign up for the service soon.

We’re excited to continue to build the product and push towards open beta, and we have big ideas for what the future of storage at Cloudflare’s edge could look like. If you’re a distributed systems engineer who wants to help us build the future of state at the edge, come work with us!

Read the whole story
elwillow
320 days ago
reply
Ottawa, Ontario
Share this story
Delete

Apple’s NeuralHash Algorithm Has Been Reverse-Engineered

4 Comments and 10 Shares

Apple’s NeuralHash algorithm — the one it’s using for client-side scanning on the iPhone — has been reverse-engineered.

Turns out it was already in iOS 14.3, and someone noticed:

Early tests show that it can tolerate image resizing and compression, but not cropping or rotations.

We also have the first collision: two images that hash to the same value.

The next step is to generate innocuous images that NeuralHash classifies as prohibited content.

This was a bad idea from the start, and Apple never seemed to consider the adversarial context of the system as a whole, and not just the cryptography...

Read the whole story
elwillow
360 days ago
reply
Ottawa, Ontario
popular
361 days ago
reply
Share this story
Delete
4 public comments
guilhermea
361 days ago
reply
People knew it was bound to happen, but this early? Wow.
London, England
jgbishop
361 days ago
reply
Got to love when Apple blows it!
Durham, NC
freeAgent
362 days ago
reply
I wonder if we'll see people creating false positives in order to frame others OR in order to jam up Apple's system with lots of false positives. Or both. Probably both.
Los Angeles, CA
zippy72
360 days ago
I can think of at least two governments that are probably working on the former. There's a few hackers on Twitter who claim to be working on the latter.
MotherHydra
362 days ago
reply
Clearly something that while helpful on its face has immense (possibly impossible) technical hurdles to overcome lest innocent people get flagged.
Space City, USA
Next Page of Stories