mirror of
https://gitlab.com/skysthelimit.dev/selenite.git
synced 2025-06-16 10:32:08 -05:00
1201 lines
41 KiB
JavaScript
1201 lines
41 KiB
JavaScript
/* 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<bwidth; i += sep) {
|
|
if(i || !nofirstcol) pushPreThing(Stone, xloc + i * 8, bheight, 1, pDtB);
|
|
pushPreBridge(xloc + (i + 1) * 8, bheight, sep - 1);
|
|
// Add a creature
|
|
if(randTrue()) {
|
|
pushRandomSmallEnemy(xloc + (i + sepd2) * 8, bheight);
|
|
}
|
|
// Add some coins...
|
|
if(randTrue(2)) {
|
|
var big = randTrue(), coinrowsize = 3 + randTrue(2);
|
|
pushRandomCoinRow(xloc + (i + sepd2) * 8, bheight + 32, coinrowsize);
|
|
pushRandomCoinRow(xloc + (i + sepd2) * 8, bheight + 40, getNextCoinRowSize(coinrowsize));
|
|
}
|
|
// ...or maybe add a Mushroom block
|
|
else {
|
|
pushPreThing(Block, xloc + (i + sepd2) * 8, bheight + jumplev1, Mushroom);
|
|
}
|
|
}
|
|
pushPreThing(Stone, xloc + (bwidth) * 8, bheight, 1, pDtB);
|
|
break;
|
|
}
|
|
}
|
|
// Tree
|
|
else {
|
|
bwidth = 10;
|
|
pushPreTree(xloc + 16, randTrue() * 8, bwidth);
|
|
}
|
|
|
|
prepareNextGeneratorStandard(xloc, bwidth + 2, randTrue() ? pushRandomSectionBridge : pushRandomSectionOverworld, false, next_no_unusuals);
|
|
}
|
|
|
|
function pushRandomSectionPreCastle(xloc, num) {
|
|
var bwidth = randTrue(35) + 35,
|
|
maxwidth = bwidth - 3,
|
|
havewall = false,
|
|
chunk, i;
|
|
num = num || 0;
|
|
|
|
pushPreFloor(xloc, 0, bwidth);
|
|
hadcloud = false;
|
|
|
|
// Chunks can be:
|
|
// Small width (3)
|
|
// Cannon, Stone, Pipe
|
|
// Medium width (7)
|
|
// Koopa, HammerBro, Bricks w/HammerBro
|
|
// Nothing (just scenery)
|
|
for(i = randTrue(3); i < maxwidth; i += chunk || 3) {
|
|
switch(randTrue(3)) {
|
|
// Small width
|
|
case 0:
|
|
chunk = 3;
|
|
switch(randTrue(2)) {
|
|
// Cannon
|
|
case 0:
|
|
var height = randTrue(2) + 1;
|
|
pushPreThing(Cannon, xloc + (i + randTrue(2)) * 8, height * 8, height);
|
|
break;
|
|
// Stone
|
|
case 1:
|
|
var height;
|
|
for(var j = 0; j < chunk; ++j) {
|
|
if(randTrue()) continue;
|
|
height = randTrue(3) + 1;
|
|
pushPreThing(Stone, xloc + (i + j) * 8, height * 8, 1, height);
|
|
}
|
|
break;
|
|
// Pipe
|
|
case 2:
|
|
pushPrePipe(xloc + (i + randTrue()) * 8, 0, (2 + randTrue(2)) * 8, true);
|
|
break;
|
|
}
|
|
break;
|
|
// Medium width
|
|
case 1:
|
|
chunk = 7;
|
|
havewall = true;
|
|
switch(randTrue(2)) {
|
|
// Koopa
|
|
case 0:
|
|
pushPreThing(Koopa, xloc + (i + randTrue(7)) * 8, 12 + randTrue(3) * 8, randTrue(), true);
|
|
break;
|
|
// HammerBro
|
|
case 1:
|
|
if(randTrue()) pushPreThing(HammerBro, xloc + (i + randTrue(7)) * 8, 12 + randTrue(3) * 2);
|
|
break;
|
|
// Bricks w/HammerBro
|
|
case 2:
|
|
chunk = 10;
|
|
havewall = false;
|
|
for(var j = 1; j < 8; ++j)
|
|
for(var k = jumplev1; k <= jumplev2; k += 32)
|
|
// Higher chance of getting an item (this part is freaking hard)
|
|
pushPreThing(Brick, xloc + (i + j) * 8, k, getRandomBrickItem(false, randTrue()));
|
|
var height1 = randTrue() ? jumplev1 : jumplev2;
|
|
height2 = (height == jumplev1) ? jumplev2 : jumplev1;
|
|
if(randTrue(2)) pushPreThing(HammerBro, xloc + (i + randTrue(3)) * 8, height1 + 12);
|
|
if(randTrue(2)) pushPreThing(HammerBro, xloc + (i + 4 + randTrue(3)) * 8, height2 + 12);
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if(havewall && chunk >= 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<size; ++i)
|
|
if(pattern[i])
|
|
pushPreThing(Coin, xloc + i * 8, yloc);
|
|
}
|
|
|
|
function getNextCoinRowSize(prev) {
|
|
switch(prev) {
|
|
case 3: return 5;
|
|
case 5: return 3;
|
|
default: return prev;
|
|
}
|
|
}
|
|
|
|
function pushRandomSectionTrees(xloc) {
|
|
var treewidth, treeheight;
|
|
|
|
switch(randTrue(7)) {
|
|
case 0:
|
|
// Base tree - far below, with variable trees coming up from below
|
|
treewidth = randTrue(14) + 7;
|
|
treeheight = randTrue(3);
|
|
map.treefunc(xloc, treeheight * 8, treewidth);
|
|
var minwidth, topheight;
|
|
for(var i=randTrue(2); i<treewidth - 2; i += minwidth - 1) {
|
|
if(randTrue(2)) pushRandomSmallEnemy(xloc + i * 8, treeheight * 8);
|
|
if(randTrue(2)) {
|
|
minwidth = 3 + (randTrue(3) ? 0 : randTrue(4));
|
|
topheight = min(9, treeheight + randTrue(7) + 3) * 8;
|
|
map.treefunc(xloc + i * 8, topheight, minwidth);
|
|
if(randTrue()) pushRandomSmallEnemy(xloc + i * 8, topheight * 8);
|
|
i += minwidth - 1;
|
|
pushRandomSmallEnemy(xloc + i * 8, treeheight * 8);
|
|
}
|
|
}
|
|
break;
|
|
case 1:
|
|
// Special things: scales and platform generators
|
|
treewidth = 14;
|
|
treeheight = 7;
|
|
switch(randTrue()) {
|
|
default:
|
|
treewidth = 4 + randTrue(2);
|
|
pushPrePlatformGenerator(xloc + 8 * (randTrue() + 1), treewidth, -1);
|
|
treewidth += randTrue(3) + 3;
|
|
break;
|
|
// Scales disabled because they may make it impossible to continue
|
|
// case 1:
|
|
// treewidth = 7 + randTrue(2);
|
|
// var left = 7 + randTrue(7), right = 21 - left;
|
|
// pushPreScale(xloc + 8 + (randTrue() + 3), 64 + randTrue(3) * 8, treewidth + 3, [5 + randTrue(2), left, right]);
|
|
// treeheight = randTrue(4);
|
|
// treewidth += 3 + randTrue(3);
|
|
// break;
|
|
// case 0:
|
|
}
|
|
break;
|
|
default:
|
|
// A typical tree
|
|
treewidth = 4 + randSign() + randTrue();
|
|
treeheight = min(randTrue(2) + 4 + randSign(2), map.treelev + 4);
|
|
var treex = xloc - randTrue() * 8;
|
|
if(treeheight == map.treelev) treeheight += randSign();
|
|
map.treefunc(treex, treeheight * 8, treewidth);
|
|
if(treewidth > 3 || randTrue())
|
|
if(randTrue(3))
|
|
pushRandomSmallEnemy(treex + (randTrue() + 1) * 8, treeheight * 8);
|
|
else if(randTrue(2))
|
|
for(var i=1; i<treewidth - 1; ++i)
|
|
// if(randTrue(3))
|
|
pushPreThing(Coin, treex + 1 + i * 8, (treeheight + 1) * 8 - 1);
|
|
break;
|
|
}
|
|
|
|
var func;
|
|
if(++map.sincechange > 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<bwidth; i += 4) {
|
|
switch(randTrue(21)) {
|
|
case 0: if(i < bwidth -2) { pushRandomObstacle(xloc, i); break; }
|
|
case 1: pushRandomEnemy(xloc, 0, i, true); break;
|
|
default:
|
|
switch(randTrue(7)) {
|
|
case 0:
|
|
// Opening in stone: at least 5 blocks high, out of 11
|
|
var topblock = randTrue() + 2, botblock = randTrue() + 2;
|
|
pushPreThing(Stone, xloc + i * 8, botblock * 8, randTrue(3) + 1, botblock); // bottom
|
|
pushPreThing(Stone, xloc + i * 8, ceillev, randTrue(3) + 1, topblock); // top
|
|
|
|
break;
|
|
case 1:
|
|
// Simple stone pattern
|
|
if(randTrue()) pushPreThing(Stone, xloc + i * 8, jumplev1, 4);
|
|
if(randTrue()) pushPreThing(Stone, xloc + i * 8, jumplev2, 4);
|
|
break;
|
|
case 2:
|
|
// A few coins
|
|
fillPreThing(Coin, xloc + (i + randTrue()) * 8 + 1, (randTrue(8) + 1) * 8 - 1, 3, 1, 8);
|
|
break;
|
|
default:
|
|
if(map.had_coral) {
|
|
map.had_coral = false;
|
|
break;
|
|
}
|
|
map.had_coral = true;
|
|
// Coral sitting on either floor or a jumplev
|
|
// If it's at a jumplev, it has >=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<numpoles; ++k)
|
|
pushPreThing(Stone, xloc + (bwidth + nextdist + numpoles + k - 1) * 8, (numpoles - k) * 8, 1, numpoles - k);
|
|
nextdist += numpoles + numpoles - 2;
|
|
}
|
|
break;
|
|
default:
|
|
if(allow_platforms && randTrue()) {
|
|
nextdist = randTrue(1) + 4;
|
|
pushPrePlatformGenerator(xloc + (bwidth + 1.5) * 8, (nextdist - 2) * 2, randSign());
|
|
}
|
|
else nofancy = true;
|
|
break;
|
|
}
|
|
}
|
|
else nextdist = 1;
|
|
if(nofancy || !nextdist || nextdist < 1) nextdist = randTrue(3) + 1;
|
|
|
|
// Water disabled because it sucks
|
|
// // There may be water between the things
|
|
// if(map.had_floor && randTrue()) {
|
|
// fillPreWater(xloc + bwidth * 8, 0, nextdist * 4); // this overestimates the water, but that's normally ok
|
|
// map.needs_floor = true;
|
|
// }
|
|
// else map.needs_floor = false;
|
|
|
|
if(func == pushRandomSectionOverworld && (map.num_random_sections >= 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<len; ++i) {
|
|
if(randTrue(2)) pushPreThing(Brick, xloc + i * 8, yloc, getRandomBrickItem(map.randname == "Overworld" && yloc == jumplev2));
|
|
else pushPreThing(Block, xloc + i * 8, yloc, getRandomBlockItem());
|
|
}
|
|
}
|
|
|
|
function getRandomBrickItem(higher, something) {
|
|
if(higher && !randTrue(14)) return [Vine, ["Random", "Sky", "Vine"]];
|
|
return (something || !randTrue(7)) ? (randTrue(3) ? Coin : Star) : false;
|
|
}
|
|
function getRandomBlockItem() {
|
|
++randcount_powerup;
|
|
if(randcount_powerup <= 7) return false;
|
|
return randTrue(7) ? false : Mushroom
|
|
}
|
|
|
|
function pushRandomGroundScenery(xloc, curblock, bwidth) {
|
|
switch(randTrue(7)) {
|
|
case 2: if(bwidth - curblock > 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<width; ++i) {
|
|
fillPreThing(btype, xloc + i * 8, 8, 1, bottom, 8, 8);
|
|
if(!randTrue(3) && !hadenemy) pushRandomSmallEnemy(xloc + i * 8, bottom * 8);
|
|
else hadenemy = false;
|
|
fillPreThing(btype, xloc + i * 8, 96 - top * 8, 1, top, 8, 8);
|
|
}
|
|
// fillPreThing(btype, xloc, 8, width, bottom, 8, 8);
|
|
// fillPreThing(btype, xloc, 96 - top * 8, width, top, 8, 8);
|
|
}
|
|
|
|
// Get rid of previous elements
|
|
function removeRandomDisplays() {
|
|
var elems = body.getElementsByClassName("randomdisplay"),
|
|
i;
|
|
for(i = elems.length - 1; i >= 0; --i)
|
|
body.removeChild(elems[i]);
|
|
} |