double Footholdtree::get_edge(uint16_t curid, bool left) const { const Foothold& fh = get_fh(curid); if (left) { uint16_t previd = fh.prev(); if (!previd) return fh.l(); const Foothold& prev = get_fh(previd); uint16_t prev_previd = prev.prev(); if (!prev_previd) return prev.l(); return walls.first(); } else { uint16_t nextid = fh.next(); if (!nextid) return fh.r(); const Foothold& next = get_fh(nextid); uint16_t next_nextid = next.next(); if (!next_nextid) return next.r(); return walls.second(); } }
void Footholdtree::limit_movement(PhysicsObject& phobj) const { if (phobj.hmobile()) { double crnt_x = phobj.crnt_x(); double next_x = phobj.next_x(); bool left = phobj.hspeed < 0.0f; double wall = get_wall(phobj.fhid, left, phobj.next_y()); bool collision = left ? crnt_x >= wall && next_x <= wall : crnt_x <= wall && next_x >= wall; if (!collision && phobj.is_flag_set(PhysicsObject::TURNATEDGES)) { wall = get_edge(phobj.fhid, left); collision = left ? crnt_x >= wall && next_x <= wall : crnt_x <= wall && next_x >= wall; } if (collision) { phobj.limitx(wall); phobj.clear_flag(PhysicsObject::TURNATEDGES); } } if (phobj.vmobile()) { double crnt_y = phobj.crnt_y(); double next_y = phobj.next_y(); auto ground = Range<double>( get_fh(phobj.fhid).ground_below(phobj.crnt_x()), get_fh(phobj.fhid).ground_below(phobj.next_x()) ); bool collision = crnt_y <= ground.first() && next_y >= ground.second(); if (collision) { phobj.limity(ground.second()); limit_movement(phobj); } else { if (next_y < borders.first()) { phobj.limity(borders.first()); } else if (next_y > borders.second()) { phobj.limity(borders.second()); } } } }
int16_t Footholdtree::get_y_below(Point<int16_t> position) const { if (uint16_t fhid = get_fhid_below(position.x(), position.y())) { const Foothold& fh = get_fh(fhid); return static_cast<int16_t>(fh.ground_below(position.x())); } else { return borders.second(); } }
double Footholdtree::get_wall(uint16_t curid, bool left, double fy) const { auto shorty = static_cast<int16_t>(fy); Range<int16_t> vertical(shorty - 50, shorty - 1); const Foothold& cur = get_fh(curid); if (left) { const Foothold& prev = get_fh(cur.prev()); if (prev.is_blocking(vertical)) { return cur.l(); } const Foothold& prev_prev = get_fh(prev.prev()); if (prev_prev.is_blocking(vertical)) { return prev.l(); } return walls.first(); } else { const Foothold& next = get_fh(cur.next()); if (next.is_blocking(vertical)) { return cur.r(); } const Foothold& next_next = get_fh(next.next()); if (next_next.is_blocking(vertical)) { return next.r(); } return walls.second(); } }
/* (fclose fh) Close the file handle. */ value type_fclose(value f) { if (!f->L) return 0; { value out = arg(f->R); if (out->T == type_file) { fclose(get_fh(out)); f = hold(&QI); } else f = reduce_void(f); drop(out); return f; } }
static value op_flock(value f, int operation) { if (!f->L) return 0; { value x = arg(f->R); if (x->T == type_file) { int code = flock(fileno(get_fh(x)),operation); if (code < 0) { perror("flock"); die(0); } f = hold(&QI); } else f = reduce_void(f); drop(x); return f; } }
void Footholdtree::update_fh(PhysicsObject& phobj) const { if (phobj.type == PhysicsObject::FIXATED && phobj.fhid > 0) return; const Foothold& curfh = get_fh(phobj.fhid); bool checkslope = false; double x = phobj.crnt_x(); double y = phobj.crnt_y(); if (phobj.onground) { if (std::floor(x) > curfh.r()) { phobj.fhid = curfh.next(); } else if (std::ceil(x) < curfh.l()) { phobj.fhid = curfh.prev(); } if (phobj.fhid == 0) { phobj.fhid = get_fhid_below(x, y); } else { checkslope = true; } } else { phobj.fhid = get_fhid_below(x, y); } const Foothold& nextfh = get_fh(phobj.fhid); phobj.fhslope = nextfh.slope(); double ground = nextfh.ground_below(x); if (phobj.vspeed == 0.0 && checkslope) { double vdelta = abs(phobj.fhslope); if (phobj.fhslope < 0.0) { vdelta *= (ground - y); } else if (phobj.fhslope > 0.0) { vdelta *= (y - ground); } if (curfh.slope() != 0.0 || nextfh.slope() != 0.0) { if (phobj.hspeed > 0.0 && vdelta <= phobj.hspeed) { phobj.y = ground; } else if (phobj.hspeed < 0.0 && vdelta >= phobj.hspeed) { phobj.y = ground; } } } phobj.onground = phobj.y == ground; if (phobj.enablejd || phobj.is_flag_set(PhysicsObject::CHECKBELOW)) { uint16_t belowid = get_fhid_below(x, nextfh.ground_below(x) + 1.0); if (belowid > 0) { double nextground = get_fh(belowid).ground_below(x); phobj.enablejd = (nextground - ground) < 600.0; phobj.groundbelow = ground + 1.0; } else { phobj.enablejd = false; } phobj.clear_flag(PhysicsObject::CHECKBELOW); } if (phobj.fhlayer == 0 || phobj.onground) { phobj.fhlayer = nextfh.layer(); } }