bool NextPathElement( std::string& out, size_t& pos, size_t& length, const std::string& path ) { if(pos >= (path.length()-1)) return false; size_t next = path.find_first_of(DirSeperators, pos); if(next == std::string::npos) next = path.length(); length = next-pos; out = path.substr(pos, length); pos = next+1; if(!length) return NextPathElement(out, pos, length, path); return true; }
/** ** Unit moves! Generic function called from other actions. ** ** @param unit Pointer to unit. ** ** @return >0 remaining path length, 0 wait for path, -1 ** reached goal, -2 can't reach the goal. */ int DoActionMove(CUnit &unit) { Vec2i posd; // movement in tile. int d; Assert(unit.CanMove()); if (!unit.Moving && (unit.Type->Animations->Move != unit.Anim.CurrAnim || !unit.Anim.Wait)) { Assert(!unit.Anim.Unbreakable); // FIXME: So units flying up and down are not affected. unit.IX = 0; unit.IY = 0; UnmarkUnitFieldFlags(unit); d = NextPathElement(unit, &posd.x, &posd.y); MarkUnitFieldFlags(unit); switch (d) { case PF_UNREACHABLE: // Can't reach, stop if (unit.Player->AiEnabled) { AiCanNotMove(unit); } unit.Moving = 0; return d; case PF_REACHED: // Reached goal, stop unit.Moving = 0; return d; case PF_WAIT: // No path, wait // Reset frame to still frame while we wait // FIXME: Unit doesn't animate. unit.Frame = unit.Type->StillFrame; UnitUpdateHeading(unit); unit.Wait = 10; unit.Moving = 0; return d; default: // On the way moving unit.Moving = 1; break; } if (unit.Type->UnitType == UnitTypeNaval) { // Boat (un)docking? const CMapField &mf_cur = *Map.Field(unit.Offset); const CMapField &mf_next = *Map.Field(unit.tilePos + posd); if (mf_cur.WaterOnMap() && mf_next.CoastOnMap()) { PlayUnitSound(unit, VoiceDocking); } else if (mf_cur.CoastOnMap() && mf_next.WaterOnMap()) { PlayUnitSound(unit, VoiceDocking); // undocking } } Vec2i pos = unit.tilePos + posd; unit.MoveToXY(pos); // Remove unit from the current selection if (unit.Selected && !Map.Field(pos)->playerInfo.IsTeamVisible(*ThisPlayer)) { if (NumSelected == 1) { // Remove building cursor CancelBuildingMode(); } if (!ReplayRevealMap) { UnSelectUnit(unit); SelectionChanged(); } } unit.IX = -posd.x * PixelTileSize.x; unit.IY = -posd.y * PixelTileSize.y; unit.Frame = unit.Type->StillFrame; UnitHeadingFromDeltaXY(unit, posd); } else { posd.x = Heading2X[unit.Direction / NextDirection]; posd.y = Heading2Y[unit.Direction / NextDirection]; d = unit.pathFinderData->output.Length + 1; } unit.pathFinderData->output.Cycles++;//reset have to be manualy controled by caller. int move = UnitShowAnimationScaled(unit, unit.Type->Animations->Move, Map.Field(unit.Offset)->Cost); unit.IX += posd.x * move; unit.IY += posd.y * move; // Finished move animation, set Moving to 0 so we recalculate the path // next frame // FIXME: this is broken for subtile movement if (!unit.Anim.Unbreakable && !unit.IX && !unit.IY) { unit.Moving = 0; } return d; }
void Path::canonicalize( Path& out, int type ) const { // "./Foo/./Bar/../Xyz" // "foo/bar/../.." // "/home/foo/bar" // On a relative path the working directory is appened at the front. // "." elements will be removed. // On ".." elements the previous element will be removed. // Path separators will be changed to fit the system. std::vector<std::string> entries; entries.reserve(10); // TODO: Maybe declare this as a constant. <.< if((type == Path::Absolute) && !isAbsolutePath()) out = CurDir(); out /= *this; size_t pos = 0; size_t length = 0; std::string entry; while(NextPathElement(entry, pos, length, out.m_Path)) { if(entry == ".") { continue; } else if(entry == "..") { if(!entries.empty()) { entries.pop_back(); // easy peasy ;) continue; } else if(type != Path::Relative) { // Expect(false, "Can't process path entry '..'! (path: '%s')", out.m_Path.c_str()); } } entries.push_back( entry ); } switch(type) { case Path::Absolute: // ... break; case Path::Relative: { if(entries.empty()) out.m_Path = "."; else out.m_Path = ""; } break; default: FatalError("Invalid path type: %u", type); } for(int i = 0; i < entries.size(); i++) { out.m_Path += entries[i]; if(i < entries.size()-1) // not last element? out.m_Path.push_back(DirSeperator); // Could fail if you process something like this: '/..', see security test below. } // if(type != Path::Relative) // Expect(out.isAbsolutePath(), "Processing path '%s' did not yield a valid result. (result: '%s')", m_Path.c_str(), out.m_Path.c_str()); }