in coinrun/coinrun.cpp [481:596]
bool jump_and_build_platform_somewhere()
{
float gravity = .2;
float max_jump = 1.5;
float max_speed = 0.5;
if (rec_stack.empty()) return false;
int n = int(sqrt(randn(rec_stack.size() * rec_stack.size())));
assert(n < (int)rec_stack.size());
Rec r = rec_stack[n];
float vx = (rand01()*2-1)*0.5*max_speed;
float vy = (0.8 + 0.2*rand01())*max_jump;
int top = 1 + int(vy/gravity);
int ix, iy;
if (randn(2)==1) {
int steps = top + (randn(top/2));
float x = r.x;
float y = r.y + 1;
ix = -1;
iy = -1;
for (int s=0; s<steps; s++) {
vy -= gravity;
x += vx;
y += vy;
if (ix != int(x) || iy != int(y)) {
ix = int(x);
iy = int(y);
bool ouch = false;
ouch |= ix<1;
ouch |= ix>=maze->w-1;
ouch |= iy<1;
ouch |= iy>=maze->h-1;
if (ouch) return false;
char c = maze->get_elem(ix, iy);
ouch |= c!=SPACE && c!=' ';
if (ouch) return false;
maze->set_elem(ix, iy, ' ');
}
}
} else {
ix = r.x;
iy = r.y;
if (is_crat(maze->get_elem(ix, iy)) || is_crat(maze->get_elem(ix, iy-1)))
return false; // don't build ladders starting from crates
rec_stack.erase(rec_stack.begin()+n);
std::vector<Rec> future_ladder;
int ladder_len = 5 + randn(10);
for (int s=0; s<ladder_len; s++) {
future_ladder.push_back(Rec({ ix, iy }));
iy += 1;
bool ouch = false;
ouch |= iy>=maze->h-3;
ouch |= maze->get_elem(ix, iy) != SPACE;
ouch |= maze->get_elem(ix-1, iy) == LADDER;
ouch |= maze->get_elem(ix+1, iy) == LADDER;
if (ouch) return false;
}
for (const Rec& f: future_ladder)
maze->set_elem(f.x, f.y, LADDER);
maze->set_elem(ix, iy, LADDER);
}
char c = maze->get_elem(ix, iy);
if (c==SPACE || c==' ')
maze->set_elem(ix, iy, vx>0 ? 'a':'b');
std::vector<Rec> crates;
std::vector<Rec> monster_candidates;
int len = 2 + randn(10);
int crates_shift = randn(20);
for (int platform=0; platform<len; platform++) {
ix += (vx>0 ? +1 : -1);
int c = maze->get_elem(ix, iy);
if (c == ' ' || c == SPACE) {
maze->set_elem(ix, iy, (platform<len-1) ? WALL_SURFACE : (vx>0 ? 'b':'a'));
rec_stack.push_back(Rec({ ix, iy+1 }));
if (int(ix*0.2 + iy + crates_shift) % 4 == 0)
crates.push_back(Rec({ ix, iy+1 }));
else if (platform>0 && platform<len-1)
monster_candidates.push_back(Rec({ ix, iy+1 }));
} else {
if (c =='a' || c == 'b')
maze->set_elem(ix, iy, WALL_SURFACE);
break;
}
}
if (monster_candidates.size() > 1) {
const Rec& r = monster_candidates[randn(monster_candidates.size())];
maze->set_elem(r.x, r.y, WALKING_MONSTER);
}
while (1) {
int cnt = crates.size();
if (cnt==0) break;
for (int c=0; c<(int)crates.size(); ) {
char w = maze->get_elem(crates[c].x, crates[c].y);
char wl = maze->get_elem(crates[c].x-1, crates[c].y);
char wr = maze->get_elem(crates[c].x+1, crates[c].y);
char wu = maze->get_elem(crates[c].x, crates[c].y+1);
int want = 2 + is_crat(wl) + is_crat(wr) - (wr==LADDER) - (wl==LADDER) - is_wall(wu);
if (randn(4) < want && crates[c].y < maze->h-2) {
if (w==' ' || w==SPACE)
maze->set_elem(crates[c].x, crates[c].y, choose_crate());
crates[c].y += 1;
rec_stack.push_back(Rec({ crates[c].x, crates[c].y })); // coins on crates, jumps from crates
c++;
} else {
crates.erase(crates.begin() + c);
}
}
}
return true;
}