/* Generator.js */ // Contains functions that procedurally generate maps // To do: make this entirely state-based and contained // jsperf.com/josh-random-number-generators // It's only 7 lines, who cares if it's ~393 x slower than Math.random()? lulz function resetSeed() { window.seeder = 1777771 / (window.seed = (round(random() * 10000000))); // 1777771 is prime window.seedlast = .007; window.getSeed = function() { return seedlast = "0." + String(seeder / seedlast).substring(4).replace('.', ''); } } // Section Generators /////////////////////// // Things must be added in (approximately) sorted order! // If they aren't, then prethings must be sorted.... // which opens possibility of something being added twice. Not good. function pushRandomSectionOverworld(xloc) { // Initial preparations var bwidth = max(randTrue(117),1), floorlev = 0; ++map.num_random_sections; pushPreFuncCollider(xloc, zoneDisableCheeps); map.had_floor = false; // Because it looks cool, smaller sections might have different solids as floors if(map.needs_floor || bwidth >= 14 || bwidth < 3 || randTrue()) { pushPreFloor(xloc, 0, bwidth); map.had_floor = true; } else { floorlev = 0;//randTrue(2) * 8; disabled because of pipe and weirdness pushPreThing(Stone, xloc, floorlev, bwidth); } window.randcount_powerup = 3; // If the section is 1 or 2 blocks wide and has floor, it may have small scenery if(bwidth <= 3 && map.had_floor) { if(randTrue()) { switch(randTrue(3)) { case 0: if(bwidth > 3) { pushPreScenery("HillSmall", xloc, 0); break; } case 1: if(bwidth > 2) { pushPreScenery("Bush1", xloc + max(0, randTrue(bwidth - 2)) * 8, floorlev); break; } case 2: pushPreScenery("PlantLarge", xloc + max(0, randTrue(bwidth - 2)) * 8, floorlev); break; case 3: pushPreScenery("PlantSmall", xloc + max(0, randTrue(bwidth - 2)) * 8, floorlev); break; } } } // Otherwise, create the section by chunks else { // Don't put too much stuff over the edge var maxwidth = bwidth - 2, hadcloud = 0, numenemychunks = 0; // Each chunk is 3 blocks wide for(var i = randTrue(2); i < maxwidth; i += 3) { if(!randTrue(7)) continue; // Each chunk either has an obstacle... if(!randTrue(2)) pushRandomObstacle(xloc, i); // ...or (maybe) an enemy, which might have bricks/blocks overhead, along with scenery. else { map.hadObstacle = false; if(numenemychunks % 3 == 0 || randTrue()) { pushRandomChunkEnemy(xloc, i); ++numenemychunks; } if(map.had_floor) pushRandomGroundScenery(xloc + i * 8, i, bwidth); } if(!hadcloud && randTrue()) { pushRandomSkyScenery(xloc + i * 8); hadcloud = true; } else hadcloud = false; } } prepareNextGeneratorStandard(xloc, bwidth, pushRandomSectionOverworld); } function startRandomSectionBridge(xloc) { pushPreFuncCollider(xloc - 24, zoneDisableCheeps); pushPreFuncCollider(xloc, zoneEnableCheeps); var bwidth = 5 + randTrue(4), bheight = 24, mwidth = bwidth - 4; map.needs_bridge = true; map.treelev = map.treeheight = 0; // to do: remember which is which... pushPreTree(xloc, 0, bwidth + 1); pushPreThing(Stone, xloc + 16, 8, 1, 1); pushPreThing(Stone, xloc + 24, 16, 1, 2); pushPreThing(Stone, xloc + 32, bheight, mwidth, bheight / 8); pushRandomSectionBridge(xloc + (bwidth - 1) * 8, bheight, true); spawnMap(); map.had_floor = false; } function pushRandomSectionBridge(xloc, bheight, nofirstcol) { var bwidth, next_no_unusuals = false; bheight = bheight || 24 + randTrue() * 16 - 8; // Bridges: long, short, etc. if(randTrue() || map.needs_bridge) { switch(randTrue(3)) { // Unusual bridge case 0: // switch(randTrue()) { switch(randTrue()) { // 1-4 shorter platforms case 0: var pnum = randTrue(3) + 1, bwidth = pnum * 4; next_no_unusuals = true; for(var i = 1; i <= pnum * 2; i += 2) pushPreBridge(xloc + (i) * 16, bheight, 3); break; // A smaller bridge width case 1: bwidth = randTrue(7) + 7; var pDtB = DtB(bheight, 8); if(!nofirstcol) pushPreThing(Stone, xloc, bheight, 1, pDtB); pushPreBridge(xloc + 8, bheight, bwidth - 1); pushPreThing(Stone, xloc + bwidth * 8, bheight, 1, pDtB); break; } break; // Typical bridge: a series of long bridges with stone columns between default: map.needs_bridge = map.treeheight = 0; var sep = 17, sepd2 = 8, pDtB = DtB(bheight, 8); bwidth = (randTrue(3) + 3) * sep; for(var i=0; i= 7) { pushPreScenery("CastleWall", xloc + (i + randTrue()) * 8, 0, chunk - randTrue(2)); if(randTrue()) pushPreThing(Brick, xloc + (i + randTrue(chunk)) * 8, jumplev1, randTrue() ? Mushroom : getRandomBrickItem(false, randTrue())); } // And the scenery for(var k = 0; k < chunk; k += 3) { if(randTrue(2)) pushRandomGroundScenery(xloc + (i + k) * 8, 0); if(!hadcloud && randTrue()) { pushRandomSkyScenery(xloc + (i + k) * 8); hadcloud = true; } else hadcloud = false; } } // If the last chunk goes over pushPreFloor(xloc + bwidth * 8, 0, i + 3 - bwidth); var next = 4 + randTrue(3); if(num >= 3) endCastleOutsideRandom(xloc + (bwidth + next + 1) * 8, true); else pushRandomSectionPreCastle(xloc + (bwidth + next) * 8, num + 1); spawnMap(); } function endCastleOutsideRandom(xloc) { var leadwidth = 9, nextwidth, i; // Leadup can be: switch(randTrue()) { // No floor, with all floating columns case 0: for(i = 1 + randTrue(); i < leadwidth; i += 2) pushPreThing(Stone, xloc + i * 8, (i - randTrue()) * 8, 1, 1 + randTrue()); pushPreThing(Stone, xloc + leadwidth * 8, (leadwidth - 1) * 8, 2); nextwidth = 12; break; // Floor, with some columns case 1: pushPreFloor(xloc, 0, leadwidth + 2); for(i = 1, hadlast = false; i < leadwidth; ++i) { // Either put a column... if(!hadlast || randTrue(2) || i == leadwidth - 1) { pushPreThing(Stone, xloc + i * 8, i * 8, 1, i); hadlast = true; } // ...or a pipe else { hadlast = false; pushPrePipe(xloc + i * 8, 0, max(i - randTrue(2), 2) * 8, true); ++i; } } pushPreThing(Stone, xloc + leadwidth * 8, 72, 2, 9); nextwidth = 7; break; } pushPreFloor(xloc + (leadwidth + 2) * 8, 0, round(gamescreen.width / 8)); endCastleOutside(xloc + (leadwidth + nextwidth) * 8 + 4, 0, true, round(gamescreen.width / 8)); } function startRandomSectionCastle(xloc) { xloc += 32; var cwidth = randTrue(7) + 3, moat = randTrue(4) + 3, floorlev = randTrue(4); // Initial starting pushPreFloor(xloc, 24, cwidth); pushPreThing(Stone, xloc, 88, cwidth, 3); fillPreWater(xloc + cwidth * 8, 0, moat * 2); pushPreThing(Podoboo, xloc + cwidth * 8 + max(0, randTrue(moat - 3) * 8), -32); pushRandomSectionCastle(xloc + (cwidth + moat) * 8, 0); spawnMap(); } function pushRandomSectionCastle(xloc, num) { var cwidth, nextwidth; switch(randTrue(3)) { // Platforms - each is either falling or a generator case 0: cwidth = 1 + randTrue(2); nextwidth = cwidth * 64 - 8; for(var i = 0; i < cwidth; ++i) { // Falling platform on lava if(randTrue()) { makeCeilingCastle(xloc + i * 64, 8); fillPreWater(xloc + i * 64, 0, 16); pushPreThing(Platform, xloc + i * 64 + 8 + randTrue(2) * 8, 8 + randTrue(max(i + 2, 4)) * 8, 4, moveFalling); } // Platform generator else { pushPreFloor(xloc + i * 64 - 8, 8, 1); pushPrePlatformGenerator(xloc + i * 64 + 24, 4, 1.75); pushPreFloor(xloc + i * 64 + 64, 8, 1); } } break; // Podoboo pits case 1: cwidth = 2 * (1 + randTrue()); var platoff, platheight, platwidth; nextwidth = cwidth * 64 - 8; makeCeilingCastle(xloc, cwidth * 8); fillPreWater(xloc, 0, cwidth * 16); for(var i = 0; i < cwidth; ++i) { platoff = xloc + i * 64; platheight = randTrue(max(i + 1, 2 + randTrue(2))) * 8; platwidth = 2 + randTrue(3); // Something to land on switch(randTrue(2)) { // Floor case 0: pushPreFloor(platoff + randTrue(3) * 8, platheight, platwidth); break; // Stone case 1: pushPreThing(Stone, platoff + randTrue(3) * 8, platheight, platwidth); break; // Platform (sliding) case 2: platoff += 8 + randTrue() * 8; pushPreThing(Platform, platoff, randTrue(3) * 8, 4, [moveSliding, platoff, platoff + 56 + randTrue(2) * 8, 2]); break; } // Block on top if(!randTrue(2) && platwidth % 2 == 1) pushPreThing(Block, platoff + platwidth * 4 - 8, platheight + 40, Mushroom); // Podoboo after if(platwidth <= 4) pushPreThing(Podoboo, platoff + (platwidth + 1) * 8, -32); } break; // Traditional floor case 2: var chunk; cwidth = 14 + randTrue(21); nextwidth = cwidth * 8 - 8; ceilheight = 1; pushPreFloor(xloc, 0, cwidth); switch(randTrue()) { // Split at jumplev1 case 0: ceilheight = 3; makeCeilingCastle(xloc, cwidth, ceilheight); for(var i = 1 + randTrue(); i < cwidth - 6; ++i) { chunk = min(7, cwidth - i); pushPreThing(Stone, xloc + i * 8, jumplev1, chunk); if(randTrue()) pushPreThing(CastleBlock, xloc + (i + chunk - 4) * 8, 0, [6, randTrue()], true); pushPreThing(CastleBlock, xloc + (i + chunk) * 8, jumplev1, 6, randTrue()); if(randTrue()) pushPreThing(CastleBlock, xloc + (i + chunk + 4) * 8, jumplev2 + 8, [6, randTrue()], true); i += chunk; } break; // Stations of rotater thingies case 1: makeCeilingCastle(xloc, cwidth, ceilheight); var floorlev = randTrue(), off = randTrue(); pushPreThing(Stone, xloc, floorlev * 8, cwidth, floorlev); for(var i = randTrue(2); i < cwidth - 3; i += 4) { // Below pushPreThing(Stone, xloc + (i + off) * 8, 16 + floorlev * 8, 3, 2); pushPreThing(CastleBlock, xloc + (i + off + 1) * 8, 24 + floorlev * 8, randTrue(2) ? 6 : 0, randSign()); // Above pushPreThing(Stone, xloc + (i + off) * 8, 80, 3, 2); if(i < cwidth - 5) pushPreThing(CastleBlock, xloc + (i + off + 1) * 8, 64, randTrue(2) ? 6 : 0, randSign()); i += 1 + randTrue(3); } // nextwidth -= 8; break; } break; // Tunnel case 3: cwidth = 21 + randTrue(21); nextwidth = cwidth * 8 - 8; var floorheight = 1 + randTrue(3), ceilheight = 11 - floorheight - 4; pushPreFloor(xloc, 8 * floorheight, cwidth); makeCeilingCastle(xloc, cwidth, ceilheight); for(var i = 0; i < cwidth; i += 8) { // Enemy if(randTrue()) { pushRandomEnemy(xloc + i * 8, floorheight * 8, 0); if(randTrue()) { pushRandomEnemy(xloc + i * 8 + 12, floorheight * 8, 0); if(randTrue()) pushRandomEnemy(xloc + i * 8 + 24, floorheight * 8, 0); } } } break; } var next = (num <= 280 ? pushRandomSectionCastle : endCastleInsideRandom); pushPreThing(GenerationStarter, xloc + nextwidth, ceilmax + 20, next, num + nextwidth / 8); spawnMap(); } function endCastleInsideRandom(xloc) { var num = 2 + randTrue(2), each = 5, bottom = randTrue() * 8, top = bottom + 24 + randTrue() * 8, width; pushPreFloor(xloc, bottom, num * each); for(var i = 0; i < num; ++i) { width = max(2, randTrue(each - 2)); pushPreFloor(xloc + ((i + 1) * each * 8), top, width); } var end = xloc + num * each * 8, extra = randTrue(7) * 8; fillPreWater(end, 0, extra/* * 2*/); // endCastleInsideFinal(end + extra); endCastleInsideRandomFinal(end + extra); spawnMap(); } function endCastleInsideRandomFinal(xloc) { fillPreWater(xloc, 0, 16); pushPreFloor(xloc + 24, 24, 3); endCastleInside(xloc + 48, 2); if(randTrue()) pushPreThing(Podoboo, xloc + 72 + randTrue(3) * 8, -32); if(randTrue()) fillPreThing(Brick, xloc + 56 + randTrue(3) * 8, 64, 3 + randTrue(3), 1, 8); if(randTrue()) pushPreThing(CastleBlock, xloc + 56 + randTrue(2) * 8, 24, [6, randSign()], true); spawnMap(); } // Returns [Name, Text2] function placeRandomCastleNPC(xloc) { var npc = pushPreThing(Toad, xloc + 194, 12).object; npc.text = [ pushPreText({innerHTML: "THANK YOU MARIO!"}, xloc + 160, 66).object, pushPreText({innerHTML: "LOL YOU THOUGHT THERE WOULD BE SOMETHING HERE DIDN'T YOU!"}, xloc + 148, 50).object ]; } function pushRandomCoinRow(xloc, yloc, size) { if(!size) return; if(size == 3) xloc += 8; var pattern; if(randTrue(2)) { switch(size) { case 3: pattern = [1,0,1]; break; case 4: switch(randTrue()) { case 0: pattern = [1,0,0,1]; break; case 1: pattern = [0,1,1,0]; break; } break; case 5: switch(randTrue()) { case 0: pattern = [1,0,1,0,1]; break; case 1: pattern = [0,1,0,1,0]; break; } break; } } else pattern = arrayOf(true, size); for(var i=0; i 3 || randTrue()) if(randTrue(3)) pushRandomSmallEnemy(treex + (randTrue() + 1) * 8, treeheight * 8); else if(randTrue(2)) for(var i=1; i 7 && randTrue() ) { func = map.randtype; map.sincechange = 0 } else func = pushRandomSectionTrees; pushPreThing(GenerationStarter, xloc + (treewidth + randSign()) * 8, ceilmax + 20, func); spawnMap(); map.treelev = treeheight; } function pushRandomSmallEnemy(xloc, yloc, canjump) { // pushPreThing(Beetle, xloc, yloc + 8.5); switch(randTrue(7)) { case 1: case 2: case 3: pushPreThing(Koopa, xloc, yloc + 12, true, canjump); break; case 7: pushPreThing(Beetle, xloc, yloc + 8.5); break; default: pushPreThing(Goomba, xloc, yloc + 8); break; } } function pushRandomSectionUnderworld(xloc) { // Initial preparations var bwidth = max(randTrue(117),1), each = 14, maxwidth = bwidth - (bwidth % each), divwidth = floor(bwidth / each), i, j; pushPreFloor(xloc, 0, bwidth); window.randcount_powerup = 3; // Smaller / normal if(bwidth < each) { switch(randTrue()) { // Chunk enemy case 0: for(i = 0; i < bwidth - 2; i += 3) pushRandomChunkEnemy(xloc + i * 8, 0, i); break; case 1: for(i = 0; i < bwidth - 2; i += 3) { // Each chunk either has an obstacle... if(!randTrue(2)) pushRandomObstacle(xloc, i); // ...or (maybe) an enemy, which might have bricks/blocks overhead else if(i % 3 == 0) pushRandomChunkEnemy(xloc, i); } break; } } // Bigger / unusual else { for(i = 1; i < maxwidth; i += each) { switch(randTrue(5)) { // Just have squiggly stuff case 0: pushRandomUnderworldSquigglies(xloc + i * 8, each); makeCeiling(xloc + i * 8, each); break; // Have squigglies with a fill on top case 1: var diff = 1 + randTrue(), lev = 4 + randTrue(7); i += diff; // pushRandomUnderworldSquigglies(xloc + i * 8, each - 2, lev - 3, true); for(j = 0; j < each; j += 1 + randTrue() / 2) { if(randTrue()) pushRandomSmallEnemy(xloc + (i + j) * 8,0); } fillPreThing(Brick, xloc + i * 8, lev * 8, each - 1, 12 - lev, 8, 8); i -= diff; break; // Create a tunnel case 2: createTunnel(xloc + (i + 2) * 8, each - 4, Brick); break; // Pipes case 3: pushUnderworldPipes(xloc + (i + 2) * 8, each - 2); makeCeiling(xloc + (i + 1) * 8, each); break; // Stones case 4: pushUnderworldStones(xloc + (i + 2) * 8, each - 2); makeCeiling(xloc + (i + 1) * 8, each); break; // Chunk enemies, with rares case 5: for(j = 0; j < each - 4; j += 3) { pushRandomChunkEnemy(xloc + (i + j) * 8, j); } break; case 6: for(j = 0; j < bwidth - 2; j += 3) { // Each chunk either has an obstacle... if(!randTrue(2)) pushRandomObstacle(xloc + (i + j) * 8, j); // ...or (maybe) an enemy, which might have bricks/blocks overhead else { if(i % 3 == 0 || randTrue()) { pushRandomChunkEnemy(xloc + (i + j) * 8, j); ++numenemychunks; } } } break; } } } prepareNextGeneratorStandard(xloc, bwidth, pushRandomSectionUnderworld, true); spawnMap(); } function pushRandomUnderworldSquigglies(xloc, maxwidth, maxheight, nocoins) { maxheight = maxheight || Infinity; var bottom = 3 + randTrue(2), top = min(maxheight, bottom + 1 + randTrue(4)), lev = (bottom == 1) ? top : (randTrue(2) ? bottom : top), diff = 1 + top - bottom, had_brick = false, coincap = top + 16; for(var i = 0; i < maxwidth; ++i) { // Continue at lev if(randTrue()) { // fillPreThing(Brick, xloc + i * 8, lev * 8, 3, 1, 8); for(var j = 0; j < 3; ++j) pushPreThing(Brick, xloc + (i + j) * 8, lev * 8, randTrue() ? null : getRandomBrickItem()); if(!nocoins && randTrue(2)) fillPreThing(Coin, xloc + 1 + i * 8, min(coincap, (lev + randTrue(4) + 1)) * 8 - 1, 3 + randTrue(), 1, 8); if(!had_brick) { if(randTrue()) pushPreThing(Block, xloc + (i + 3) * 8, lev * 8, getRandomBlockItem()); else pushPreThing(Brick, xloc + (i + 3) * 8, lev * 8); had_brick = true; } i += 3; } // Switch else { fillPreThing(Brick, xloc + i * 8, bottom * 8, 1, diff, 8, 8); lev = (lev == top) ? bottom : top; had_brick = false; } if(i % 3 == 1 || (randTrue() && i < maxwidth - 3)) pushRandomSmallEnemy(xloc + i * 8, 0, false); // if(i % 3 == 1 || (randTrue() && i < maxwidth - 3)) pushRandomEnemy(xloc + i * 8, 0, i, true); } } function pushUnderworldPipes(xloc, width) { var maxwidth = width - 4, had_ok = false, out, lev, i; for(i = 0; i < maxwidth; i += 4) { switch(randTrue()) { // Just a regular, small pipe case 0: out = randTrue(); addPipeRandom(xloc + (i + out) * 8, 0, (2 + randTrue(2)) * 8); i += (1 - out); had_ok = true; break; // A big pipe, with a brick before it if necessary case 1: out = randTrue() || !had_ok; lev = 4 + randTrue(4); if(out) pushPreThing(Brick, xloc + i * 8, max(lev - 4, (3 + randTrue())) * 8, getRandomBrickItem(false)); addPipeRandom(xloc + (i + out) * 8, 0, lev * 8); had_ok = false; break; } } for(i; i < width - 1; ++i) { if(randTrue()) pushRandomChunkEnemy(xloc + i * 8, 0); } } function pushUnderworldStones(xloc, width) { var maxwidth = width - 4, had_ok = false, out, lev, i; for(i = 0; i < maxwidth; i += 2) { switch(randTrue()) { // Just a regular, small pipe case 0: out = randTrue(); lev = 2 + randTrue(2); pushPreThing(Stone, xloc + (i + out) * 8, lev * 8, 1, lev); i += (1 - out); had_ok = true; break; // A big pipe, with a brick before it if necessary case 1: out = randTrue() || !had_ok; lev = 4 + randTrue(4); if(out) pushPreThing(Brick, xloc + i * 8, max(lev - 4, (3 + randTrue())) * 8, getRandomBrickItem(false)); pushPreThing(Stone, xloc + (i + out) * 8, lev * 8, 1, lev); had_ok = false; break; } } for(i; i < width - 1; i += 3) { if(randTrue()) pushRandomChunkEnemy(xloc + i * 8, 0); } } function pushRandomSectionUnderwater(xloc) { // Initial preparations // var bwidth = max(randTrue(117),1); var bwidth = max(randTrue(117),7); bwidth -= bwidth % 3; pushPreFloor(xloc, 0, bwidth); pushPreScenery("Water", xloc, ceilmax - 21, bwidth * 8 / 3, 1) pushPreThing(WaterBlock, xloc, ceilmax, bwidth * 8); window.randcount_powerup = 3; // Each chunk is 4 blocks wide, not the normal 3 for(var i=0; i=1 stones with it // var pheight = jumplev1 * (1 + randTrue()), cheight = 3; var pwidth = randTrue(3) + 2, pheight = jumplev1 * (1 + randTrue(2)), cheight = 3, cx = xloc + i * 8, cy; if(pheight == jumplev1 * 3) { var ontop = true; pheight -= 8; } pushPreThing(Stone, xloc + i * 8, pheight, pwidth); if(!ontop && (randTrue(3) || pwidth <= 3)) cy = pheight + cheight * 8; // above stone else cy = pheight - 8; // below stone if(randTrue()) pushPreThing(Coral, cx, cy, cheight); // beginning of stone if(randTrue() && pwidth > 3 && pheight < 64) pushPreThing(Coral, cx + (pwidth - 1) * 8, cy, cheight); // end of stone if(pwidth >= 3) i += (pwidth - 3); break; } break; } if(map.countCheep > 1) { pushPreThing(CheepCheep, xloc + i * 8, randTrue(80) + 8, randTrue()); map.countCheep = 0; } if(map.countBlooper > 7) { pushPreThing(Blooper, xloc + i * 8, randTrue(80) + 8); map.countBlooper = 0; } if(randTrue(7)) ++map.countCheep; if(randTrue(3)) ++map.countBlooper; } if(++map.sincechange < 3) { var tonext = prepareNextGeneratorStandard(xloc, bwidth, pushRandomSectionUnderwater, false, true); pushPreScenery("Water", xloc + bwidth * 8, ceilmax - 21, (tonext + 1) * 8 / 3, 1) pushPreThing(WaterBlock, xloc + bwidth * 8, ceilmax, (tonext + 1) * 8); } else endRandomSectionUnderwater(xloc + bwidth * 8); } function endRandomSectionUnderwater(xloc) { // 1488 is xloc............1488 pushPreFloor(xloc, 0, 19); pushPreScenery("Water", xloc, ceilmax - 21, 10.5 * 8 / 3, 1); pushPreThing(WaterBlock, xloc, ceilmax, 10.5 * 15); pushPreThing(Stone, xloc, 8, 5, 1); // 88 pushPreThing(Stone, xloc + 8, 16, 4, 1); // 96 pushPreThing(Stone, xloc + 16, 24, 3, 1); // 04 pushPreThing(Stone, xloc + 24, 32, 2, 1); // 12 pushPreThing(Stone, xloc + 24, 88, 2, 4); // 12 pushPreThing(PipeSide, xloc + 32, 48, ["Random", randTrue() ? "Overworld" : "Underworld", "Up"]); // 20 pushPreThing(Stone, xloc + 40, 88, 14, 11); // 28 map.scrollblockerok = true; pushPreThing(ScrollBlocker, xloc + 56, 80, true); spawnMap(); } function startRandomSectionSky(xloc) { pushPreThing(Stone, xloc, 0, 78); pushPreThing(Platform, xloc + 88, 24, 6, [collideTransport]); pushRandomSectionSky(xloc + 80, 1); spawnMap(); } function pushRandomSectionSky(xloc, num) { if(num++ > 7) { fillPreThing(Coin, xloc + 8, 8, 3, 1, 8); return spawnMap(); } var cwidth = 0; // Short section if(num % 2) { fillPreThing(Coin, xloc + 1, 71, 3, 1, 8); cwidth = 32; } // Long section else { switch(randTrue(num)) { // Two double clouds with 7 coins in between case 3: pushPreThing(Stone, xloc + 8, 48, 1, 2); fillPreThing(Coin, xloc + 25, 63, 7, 1, 8); pushPreThing(Stone, xloc + 88, 48, 1, 2); cwidth = 104; break; // Alternating clouds, with coins on top case 4: case 5: case 6: pushPreThing(Stone, xloc + 8, 56, 2); for(var i=0; i<=7; i += 2) { pushPreThing(Stone, xloc + (i + 5) * 8, 56); fillPreThing(Coin, xloc + (i + 5) * 8 + 1, 63, 2, 1, 8); } cwidth = 104; break; // Typical stretch of 16 coins followed by a cloud default: fillPreThing(Coin, xloc + 1, 55 + randTrue() * 8, 16, 1, 8); cwidth = 128; break; } } pushPreThing(GenerationStarter, xloc + cwidth, ceilmax + 20, pushRandomSectionSky, num); spawnMap(); } function prepareNextGeneratorStandard(xloc, bwidth, func, allow_platforms, no_unusuals) { // How the world ends var nextdist = 0, nofancy = 0; if(!no_unusuals) { switch(randTrue(7)) { // Spring to the next area case 0: if(bwidth > 7 && map.underwater && !randTrue(7)) { nextdist = randTrue(3) + 7; pushPreThing(Springboard, xloc + (bwidth - 1) * 8, 14.5); } else nofancy = true; break; // Stairway of stone case 1: var numpoles = max(1, randTrue(7)); nextdist = numpoles + randTrue(3); pushPreFloor(xloc + bwidth * 8, 0, numpoles); for(var j=1; j<=numpoles; ++j) pushPreThing(Stone, xloc + (bwidth + j - 1) * 8, j * 8, 1, j); // There may be an exit stairway if(randTrue()) { numpoles = max(1, randTrue(numpoles)); pushPreFloor(xloc + (bwidth + nextdist + numpoles - 1) * 8, 0, numpoles); for(var k=0; k= 3 + randTrue(7))) func = pushRandomSectionPreCastle; if(!no_unusuals && ++map.sincechange > 3) { func = getRandomNextSection(); map.sincechange = 0; // pushPreThing(zoneToggler, xloc + bwidth * 8, ceilmax + 40, zoneDisableCheeps); pushPreFuncCollider(xloc, zoneDisableCheeps); // pushPreThing(zoneToggler, xloc, ceilmax + 40, zoneDisableLakitu); } pushPreThing(GenerationStarter, xloc + (bwidth + nextdist) * 8, ceilmax + 20, func); // console.log(xloc + (bwidth + nextdist) * 8); spawnMap(); return nextdist; } function getRandomNextSection() { switch(randTrue()) { case 0: map.treeheight = 0; return pushRandomSectionTrees; case 1: return startRandomSectionBridge; } } function pushRandomChunkEnemy(xloc, i, noRares) { pushRandomEnemy(xloc, 0, i, noRares); if(randTrue(2)) { pushRandomSolidRow(xloc + i * 8, jumplev1, randTrue(2) + 1); if(randTrue()) pushRandomEnemy(xloc, jumplev1, i + 1, true); if(randTrue()) { pushRandomSolidRow(xloc + i * 8, jumplev2, randTrue(2) + 1); if(randTrue()) pushRandomEnemy(xloc, jumplev2, i + 1, true); } } } function pushRandomEnemy(xloc, yloc, i, noRares) { switch(randTrue(14)) { case 0: case 1: fillPreThing(Beetle, xloc + i * 8, yloc + 8.5, randTrue(2), 1, 12); break; case 3: if(!noRares) { switch(randTrue(4)) { case 0: pushPreThing(HammerBro, xloc + i * 8, yloc + 12); if(randTrue()) pushPreThing(HammerBro, xloc + i * 8 + 16, yloc + 40); break; case 1: if(map.randname != "Underworld") { pushPreThing(Lakitu, xloc + i * 8, yloc + 80, true); break; } case 2: pushPreThing(Blooper, xloc + i * 8, yloc + 40); break; } break; } break; default: if(!randTrue(3)) return; switch(randTrue(3)) { case 1: fillPreThing(Koopa, xloc + i * 8, yloc + 12, randTrue(2), 1, 12, 0, randTrue() || map.onlysmartkoopas, randTrue()); break; default: fillPreThing(Goomba, xloc + i * 8, yloc + 8, randTrue(2), 1, 12); break; } break; } } function addPipeRandom(xloc, yloc, height) { var transport; if(height <= 24 || randTrue(2)) transport = false; else transport = getRandomTransport(); pushPrePipe(xloc, yloc, height, randTrue(7), transport); } function getRandomTransport() { var nextloc, direction, locpos, loctypes = [["Overworld","Up"], ["Underworld","Down"], ["Underwater","Up"]]; locpos = randTrue(loctypes.length - 1); if(loctypes[locpos][0] == map.randname) locpos = (locpos + randTrue(loctypes.length - 2) + 1) % (loctypes.length); nextloc = loctypes[locpos][0]; direction = loctypes[locpos][1]; return ["Random", nextloc, direction]; } function getAfterSkyTransport() { switch(randTrue(3)) { case 0: return ["Random", "Underworld", "Down"]; default: return ["Random", "Overworld" + (body.className.indexOf("Night" != -1) ? " Night" : ""), "Down"]; } } function pushRandomObstacle(xloc, i) { var num = randTrue(3); if(num > 1) map.hadPipe = false; switch(num) { // Adding a Pipe case 0: case 1: if(i > 1) { // The highest possible pipe will be 40 units (5 blocks) high, which is higher than Mario can jump // That's why it's only reached if map.hadObstacle = true addPipeRandom(xloc + i * 8, 0, (randTrue(2 + (map.hadObstacle == true && map.hadPipe == false && i > 7)) + 2) * 8); map.hadObstacle = map.hadPipe = true; break; } // Adding some vertical stones case 2: var height; for(var j=0; j<2; ++j) { if(randTrue() || i < 1) continue; height = randTrue(2) + 2; pushPreThing(Stone, xloc + (i + j) * 8, height * 8, 1, height); } break; // Miscellaneous things default: var j = randTrue(2); switch(randTrue(7)) { case 0: var height = randTrue(2) + 1; pushPreThing(Cannon, xloc + (i + j) * 8, height * 8, height); if(height == 1 && randTrue(2) && j != 2) { // durpliact var newheight = randTrue() + 2; pushPreThing(Cannon, xloc + (i + j) * 8, height * 8 + newheight * 8, newheight); } map.hadObstacle = true; break; case 1: if(!map.underwater) { if(randTrue()) { if(!map.underwater && randTrue(2)) pushPreThing(Brick, xloc + i * 8, jumplev1); pushPreThing(Block, xloc + (i + 1) * 8, jumplev1, [Mushroom, 1], true); if(!map.underwater && randTrue(2)) pushPreThing(Brick, xloc + (i + 2) * 8, jumplev1); map.hadObstacle = true; } break; } case 2: // If it's not underwater, add a pipe at jumplev1 if(!map.underwater) { var offx = randTrue(); if(!offx) pushPreThing(Brick, xloc + i * 8, jumplev1, getRandomBrickItem()); pushPreThing(Stone, xloc + (i + offx) * 8, jumplev1, 2); addPipeRandom(xloc + (i + offx) * 8, jumplev1, 24 + randTrue() * 8); if(offx) pushPreThing(Brick, xloc + i * 8, jumplev1, getRandomBrickItem()); break; } } break; } } function pushRandomSolidRow(xloc, yloc, len) { for(var i=0; i 4) { pushPreScenery("Bush3", xloc, 0); break; } case 1: if(bwidth - curblock > 2) { pushPreScenery("Bush2", xloc, 0); break; } case 0: pushPreScenery("Bush1", xloc, 0); break; case 3: if(bwidth - curblock > 4) { pushPreScenery("HillLarge", xloc, 0); break; } case 4: pushPreScenery("HillSmall", xloc, 0); break; case 5: pushPreScenery("PlantLarge", xloc, 0); break; case 6: pushPreScenery("PlantSmall", xloc, 0); break; case 7: pushPreScenery("Fence", xloc, 0, randTrue(2)+1); break; } } function pushRandomSkyScenery(xloc) { switch(randTrue(2)) { case 0: pushPreScenery("Cloud1", xloc, (randTrue(5) + 5) * 8); break; case 1: pushPreScenery("Cloud2", xloc, (randTrue(4) + 6) * 8); break; case 2: pushPreScenery("Cloud3", xloc, (randTrue(3) + 7) * 8); break; } } function addDistanceCounter() { counter = createElement("div", { className: "indisplay counter randomdisplay", innerText: data.traveledold + " blocks traveled" }); body.appendChild(counter); TimeHandler.addEventInterval(function(counter) { data.traveled = max(0,Math.round((mario.right + gamescreen.left) / unitsizet8) - 3); counter.innerText = (data.traveledold + data.traveled) + " blocks traveled"; }, 3, Infinity, counter); } function addSeedDisplay() { // counter = createElement("div", { // className: "indisplay seed randomdisplay", // innerText: "This map's seed is " + seed // }); // body.appendChild(counter); } function createTunnel(xloc, width, btype) { var top = randTrue(2) + 3, bottom = randTrue(2) + 2, hadenemy = false; for(var i=0; i= 0; --i) body.removeChild(elems[i]); }