diff --git a/games/pioneer/README b/games/pioneer/README index 68ed72ee23..e19fd95e46 100644 --- a/games/pioneer/README +++ b/games/pioneer/README @@ -8,8 +8,9 @@ try your hand at piracy, make your fortune trading between systems, or do missions for the various factions fighting for power, freedom or self-determination. -WARNING: If pioneer is already installed, uninstall it before compiling -or important game data may be missing and pioneer will fail to start. +To build with debugging support, use: + + DEBUG="yes" ./pioneer.SlackBuild OpenGL core profile version 3.1 or newer is a runtime dependency. To determine what version of OpenGL is installed, use: @@ -17,11 +18,3 @@ determine what version of OpenGL is installed, use: glxinfo | grep "core profile version" lua52 is an optional dependency. - -To build with debugging support, use: - - DEBUG="yes" ./pioneer.SlackBuild - -If building in a graphical session, a popup window about a failure to -write to a log file will likely appear and stop the build. This is -harmless, and the build proceeds normally after clicking "OK." diff --git a/games/pioneer/fix-build.patch b/games/pioneer/fix-build.patch deleted file mode 100644 index 35afdec062..0000000000 --- a/games/pioneer/fix-build.patch +++ /dev/null @@ -1,41 +0,0 @@ ---- src/lua/LuaPushPull.h.orig 2023-09-18 14:23:51.229000000 +0900 -+++ src/lua/LuaPushPull.h 2023-09-18 14:32:10.777000000 +0900 -@@ -12,10 +12,10 @@ - #include - - inline void pi_lua_generic_push(lua_State *l, bool value) { lua_pushboolean(l, value); } --inline void pi_lua_generic_push(lua_State *l, int value) { lua_pushinteger(l, value); } -+inline void pi_lua_generic_push(lua_State *l, int32_t value) { lua_pushinteger(l, value); } - inline void pi_lua_generic_push(lua_State *l, int64_t value) { lua_pushinteger(l, value); } --inline void pi_lua_generic_push(lua_State *l, unsigned int value) { lua_pushinteger(l, value); } --inline void pi_lua_generic_push(lua_State *l, size_t value) { lua_pushinteger(l, value); } -+inline void pi_lua_generic_push(lua_State *l, uint32_t value) { lua_pushinteger(l, value); } -+inline void pi_lua_generic_push(lua_State *l, uint64_t value) { lua_pushinteger(l, value); } - inline void pi_lua_generic_push(lua_State *l, double value) { lua_pushnumber(l, value); } - inline void pi_lua_generic_push(lua_State *l, const char *value) { lua_pushstring(l, value); } - inline void pi_lua_generic_push(lua_State *l, const std::string &value) -@@ -29,10 +29,10 @@ - inline void pi_lua_generic_push(lua_State *l, const std::nullptr_t &value) { lua_pushnil(l); } - - inline void pi_lua_generic_pull(lua_State *l, int index, bool &out) { out = lua_toboolean(l, index); } --inline void pi_lua_generic_pull(lua_State *l, int index, int &out) { out = luaL_checkinteger(l, index); } -+inline void pi_lua_generic_pull(lua_State *l, int index, int32_t &out) { out = luaL_checkinteger(l, index); } - inline void pi_lua_generic_pull(lua_State *l, int index, int64_t &out) { out = luaL_checkinteger(l, index); } --inline void pi_lua_generic_pull(lua_State *l, int index, unsigned int &out) { out = luaL_checkunsigned(l, index); } --inline void pi_lua_generic_pull(lua_State *l, int index, size_t &out) { out = luaL_checkunsigned(l, index); } -+inline void pi_lua_generic_pull(lua_State *l, int index, uint32_t &out) { out = luaL_checkinteger(l, index); } -+inline void pi_lua_generic_pull(lua_State *l, int index, uint64_t &out) { out = luaL_checkinteger(l, index); } - inline void pi_lua_generic_pull(lua_State *l, int index, float &out) { out = luaL_checknumber(l, index); } - inline void pi_lua_generic_pull(lua_State *l, int index, double &out) { out = luaL_checknumber(l, index); } - inline void pi_lua_generic_pull(lua_State *l, int index, const char *&out) { out = luaL_checkstring(l, index); } ---- src/lua/LuaShip.cpp.orig 2023-09-18 14:42:08.048000000 +0900 -+++ src/lua/LuaShip.cpp 2023-09-18 14:42:20.781000000 +0900 -@@ -19,7 +19,7 @@ - #include "SpaceStation.h" - #include "ship/PlayerShipController.h" - #include "ship/PrecalcPath.h" --#include "src/lua.h" -+#include "lua.h" - - /* - * Class: Ship diff --git a/games/pioneer/pioneer.SlackBuild b/games/pioneer/pioneer.SlackBuild index 1e08159da2..4ed508daef 100644 --- a/games/pioneer/pioneer.SlackBuild +++ b/games/pioneer/pioneer.SlackBuild @@ -3,7 +3,7 @@ # Slackware build script for pioneer # Copyright 2015-2019 Hunter Sezen California, USA -# Copyright 2023 K. Eugene Carlson Tsukuba, JP +# Copyright 2023-2024 K. Eugene Carlson Tsukuba, JP # All rights reserved. # # Redistribution and use of this script, with or without modification, is @@ -26,7 +26,7 @@ cd $(dirname $0) ; CWD=$(pwd) PRGNAM=pioneer -VERSION=${VERSION:-20230203} +VERSION=${VERSION:-20240203} BUILD=${BUILD:-1} TAG=${TAG:-_SBo} PKGTYPE=${PKGTYPE:-tgz} @@ -94,17 +94,19 @@ pkg-config --exists glew && GLEW=ON # as cmake seems to search for them in order. pkg-config --exists lua5.2 && ! pkg-config --exists lua && LUA=ON -# Fix 32-bit build (PR 5538) and system lua build (PR 5526). -patch -p0 < $CWD/fix-build.patch -# Post-release autopilot fixes (PR 5481, 5551). -patch -p1 < $CWD/ship-ai.patch - # 20210214 bkw: prevent the build from writing to /root/, without # breaking ccache if it's in use. -mkdir -p tmphome +mkdir -p tmphome/.local/share/pioneer export CCACHE_DIR=${CCACHE_DIR:-$HOME/.ccache} export HOME=$( pwd )/tmphome +OSNAME="$(awk -F= '/^ID=/{print $2}' /etc/os-release)" +OSVER="$(awk -F= '/^VERSION_ID=/{print $2}' /etc/os-release)" +OSCODENAME="$(awk -F= '/^VERSION_CODENAME=/{print $2}' /etc/os-release)" +# This version information string can be included when reporting issues +# upstream. +INFOSTRING="$OSNAME-$OSVER-$OSCODENAME-$PRGNAM-$VERSION-$ARCH-$BUILD$TAG" + mkdir -p build cd build cmake \ @@ -112,9 +114,10 @@ cd build -DCMAKE_CXX_FLAGS:STRING="$SLKCFLAGS" \ -DCMAKE_INSTALL_PREFIX=/usr \ -DCMAKE_INSTALL_BINDIR=games \ - -DPIONEER_DATA_DIR=/usr/share/games/$PRGNAM \ + -DCMAKE_INSTALL_DATADIR=/usr/share/games \ -DUSE_SYSTEM_LIBGLEW=$GLEW \ -DUSE_SYSTEM_LIBLUA=$LUA \ + -DPROJECT_VERSION_INFO="$INFOSTRING" \ -DCMAKE_BUILD_TYPE=$RELEASE .. make make install DESTDIR=$PKG @@ -126,6 +129,14 @@ if [ "$DEBUG" = 0 ]; then grep ELF | cut -f 1 -d : | xargs strip --strip-unneeded 2> /dev/null || true fi +# Clean up the data directory, put icons and files where they are +# supposed to be and install an SVG icon. +rm -rf $PKG/usr/share/games/$PRGNAM/{licenses,*txt,*md} +mv $PKG/usr/share/games/{icons,applications,metainfo} $PKG/usr/share +mkdir -p $PKG/usr/share/icons/hicolor/scalable/apps +install -m 0644 application-icon/badge-full.svg \ + $PKG/usr/share/icons/hicolor/scalable/apps/net.pioneerspacesim.Pioneer.svg + mkdir -p $PKG/usr/doc/$PRGNAM-$VERSION cp -a licenses *.txt README.md $PKG/usr/doc/$PRGNAM-$VERSION rm -f $PKG/usr/doc/$PRGNAM-$VERSION/{CMakeLists,SAVEBUMP}.txt diff --git a/games/pioneer/pioneer.info b/games/pioneer/pioneer.info index dc36db10b9..0b43c1f9fe 100644 --- a/games/pioneer/pioneer.info +++ b/games/pioneer/pioneer.info @@ -1,8 +1,8 @@ PRGNAM="pioneer" -VERSION="20230203" +VERSION="20240203" HOMEPAGE="https://pioneerspacesim.net/" -DOWNLOAD="https://github.com/pioneerspacesim/pioneer/archive/20230203/pioneer-20230203.tar.gz" -MD5SUM="15f3e74303a098bb198f15c8674c43d4" +DOWNLOAD="https://github.com/pioneerspacesim/pioneer/archive/20240203/pioneer-20240203.tar.gz" +MD5SUM="0404c477b33d428f7b48686c71569b52" DOWNLOAD_x86_64="" MD5SUM_x86_64="" REQUIRES="assimp" diff --git a/games/pioneer/ship-ai.patch b/games/pioneer/ship-ai.patch deleted file mode 100644 index 8347881554..0000000000 --- a/games/pioneer/ship-ai.patch +++ /dev/null @@ -1,447 +0,0 @@ ---- pioneer-20230203.orig/src/ShipAICmd.cpp 2023-07-19 23:54:00.245824921 +0900 -+++ pioneer-20230203/src/ShipAICmd.cpp 2023-07-19 23:54:15.061778840 +0900 -@@ -731,7 +731,7 @@ - //2 - unsafe escape from effect radius - //3 - unsafe entry to effect radius - //4 - probable path intercept --int CheckCollision(DynamicBody *dBody, const vector3d &pathdir, double pathdist, const vector3d &tpos, double endvel, double r) -+int CheckCollision(DynamicBody *dBody, const vector3d &pathdir, double pathdist, double tlen, double endvel, double r) - { - Propulsion *prop = dBody->GetComponent(); - if (!prop) // This body doesn't have any propulsion to avoid collision -@@ -742,24 +742,35 @@ - Body *body = Frame::GetFrame(dBody->GetFrame())->GetBody(); - if (!body) return 0; - vector3d spos = dBody->GetPosition(); -- double tlen = tpos.Length(), slen = spos.Length(); -+ double slen = spos.Length(); - double fr = MaxFeatureRad(body); - -- // if target inside, check if direct entry is safe (30 degree) -+ // find closest point to obstructor -+ double distToTangent = -spos.Dot(pathdir); -+ -+ // if target inside, check if direct entry is safe -+ // no 30 deg aproach anymore as after FlyAround this couses overshoot - if (tlen < r) { -- double af = (tlen > fr) ? 0.5 * (1 - (tlen - fr) / (r - fr)) : 0.5; -- if (pathdir.Dot(tpos) > -af * tlen) -- if (slen < fr) -+ -+ vector3d tangent = spos + distToTangent * pathdir; -+ -+ //The target is obscured -+ if(distToTangent < pathdist && tangent.LengthSqr() < fr * fr) { -+ if (slen < fr ) - return 1; -- else -- return 3; -- else -- return 0; -+ -+ return 3; -+ } -+ -+ //The speed checks are now done in the CheckSuicide function -+ return 0; - } - -- // if ship inside, check for max feature height and direct escape (30 degree) -+ // if ship inside, target outside, check for max feature height and direct escape (30 degree) - if (slen < r) { -- if (slen < fr) return 1; -+ if (slen < fr) -+ return 1; -+ - double af = (slen > fr) ? 0.5 * (1 - (slen - fr) / (r - fr)) : 0.5; - if (pathdir.Dot(spos) < af * slen) - return 2; -@@ -768,25 +779,15 @@ - } - - // now for the intercept calc -- // find closest point to obstructor -- double tanlen = -spos.Dot(pathdir); -- if (tanlen < 0 || tanlen > pathdist) return 0; // closest point outside path -+ if (distToTangent < 0 || distToTangent > pathdist) return 0; // closest point to obstructor outside path -+ -+ -+ vector3d sidePos = spos - pathdir * spos.Dot(pathdir); -+ -+ //Check if the path goes through the obstructor effective radious -+ if(sidePos.LengthSqr() < r * r) return 4; - -- vector3d perpdir = (tanlen * pathdir + spos).Normalized(); -- double perpspeed = dBody->GetVelocity().Dot(perpdir); -- double parspeed = dBody->GetVelocity().Dot(pathdir); -- if (parspeed < 0) parspeed = 0; // shouldn't break any important case -- if (perpspeed > 0) perpspeed = 0; // prevent attempts to speculatively fly through planets -- -- // find time that dBody will pass through that point -- // get velocity as if accelerating from start or end, pick smallest -- double ivelsqr = endvel * endvel + 2 * prop->GetAccelFwd() * (pathdist - tanlen); // could put endvel in here -- double fvelsqr = parspeed * parspeed + 2 * prop->GetAccelFwd() * tanlen; -- double tanspeed = sqrt(ivelsqr < fvelsqr ? ivelsqr : fvelsqr); -- double time = tanlen / (0.5 * (parspeed + tanspeed)); // actually correct? - -- double dist = spos.Dot(perpdir) + perpspeed * time; // spos.perpdir should be positive -- if (dist < r) return 4; - return 0; - } - -@@ -828,20 +829,57 @@ - return true; - } - -+ - // check for collision course with frame body --// tandir is normal vector from planet to target pos or dir --static bool CheckSuicide(DynamicBody *dBody, const vector3d &tandir) -+//#define DEBUG_CHECK_SUICIDE -+static bool CheckSuicide(DynamicBody *dBody, const vector3d &obspos, double obsMass, double safeAlt, double targetAlt, bool recovering) - { -- Body *body = Frame::GetFrame(dBody->GetFrame())->GetBody(); - if (!dBody->HasComponent()) return false; - Propulsion *prop = dBody->GetComponent(); - assert(prop != nullptr); -- if (!body || !body->IsType(ObjectType::TERRAINBODY)) return false; - -- double vel = dBody->GetVelocity().Dot(tandir); // vel towards is negative -- double dist = dBody->GetPosition().Length() - MaxFeatureRad(body); -- if (vel < -1.0 && vel * vel > 2.0 * prop->GetAccelMin() * dist) -+ double obsDist = obspos.Length(); -+ -+ //sanity check -+ if(obsDist > 100 * safeAlt) -+ return false; -+ -+ vector3d velDir = dBody->GetVelocity().NormalizedSafe(); -+ double tangDist = obspos.Dot(velDir); -+ -+ //ship passed the planet -+ if(tangDist < 0) return false; -+ -+ double tangLenSqr = (obspos - velDir * tangDist).LengthSqr(); -+ -+ //or pitched speed vector above the safty horizon -+ if(tangLenSqr > safeAlt * safeAlt) return false; -+ -+ //Ignore speed check -> continue the recovery until speed vector is over horizon -+ if(recovering) return true; -+ //below are more strict speed conditions to enter the recovery -+ -+ //for final apreach the targetAlt must be used for safe speed check -+ double zeroSpeedAlt = std::min(safeAlt, targetAlt); -+ -+ if(zeroSpeedAlt*zeroSpeedAlt < tangLenSqr) return false; -+ -+ //distance to point of pircing of planet surface or sefe alt sphere by speed vector -+ double breakingDist = tangDist - sqrt(zeroSpeedAlt*zeroSpeedAlt - tangLenSqr); -+ -+#ifdef DEBUG_CHECK_SUICIDE -+ if (dBody->IsType(ObjectType::PLAYER)) { -+ std::cout << "CheckSuicide breakingDist=" << breakingDist << std::endl; -+ std::cout << "Speed Check v^2 vs maxV^2: " << dBody->GetVelocity().LengthSqr() << "\t" -+ << 2*(prop->GetAccelFwd()*breakingDist - G*obsMass*(obsDist-zeroSpeedAlt)/(obsDist*zeroSpeedAlt)) << std::endl; -+ } -+#endif -+ -+ //Energy equation with planet gravity taken into account -+ if (breakingDist > 100 -+ && dBody->GetVelocity().LengthSqr() > 2*(prop->GetAccelFwd()*breakingDist - G*obsMass*(obsDist-zeroSpeedAlt)/(obsDist*zeroSpeedAlt))) - return true; -+ - return false; - } - -@@ -869,7 +907,6 @@ - { - AICommand::PostLoadFixup(space); - m_target = space->GetBodyByIndex(m_targetIndex); -- m_lockhead = true; - m_frameId = m_target ? m_target->GetFrame() : FrameId(); - // Ensure needed sub-system: - m_prop = m_dBody->GetComponent(); -@@ -884,10 +921,11 @@ - assert(m_prop != nullptr); - m_frameId = FrameId::Invalid; - m_state = -6; -- m_lockhead = true; - m_endvel = 0; - m_tangent = false; - m_is_flyto = true; -+ m_suicideRecovery = false; -+ - if (!target->IsType(ObjectType::TERRAINBODY)) - m_dist = VICINITY_MIN; - else -@@ -915,8 +953,8 @@ - m_endvel(endvel), - m_tangent(tangent), - m_state(-6), -- m_lockhead(true), -- m_frameId(FrameId::Invalid) -+ m_frameId(FrameId::Invalid), -+ m_suicideRecovery(false) - { - m_prop = dBody->GetComponent(); - assert(m_prop != nullptr); -@@ -933,6 +971,10 @@ - m_endvel = jsonObj["end_vel"]; - m_tangent = jsonObj["tangent"]; - m_state = jsonObj["state"]; -+ if(jsonObj.find("suicide_recovery") != jsonObj.end()) -+ m_suicideRecovery = jsonObj["suicide_recovery"]; -+ else -+ m_suicideRecovery = false; - } catch (Json::type_error &) { - throw SavedGameCorruptException(); - } -@@ -952,6 +994,7 @@ - aiCommandObj["end_vel"] = m_endvel; - aiCommandObj["tangent"] = m_tangent; - aiCommandObj["state"] = m_state; -+ aiCommandObj["suicide_recovery"] = m_suicideRecovery; - jsonObj["ai_command"] = aiCommandObj; // Add ai command object to supplied object. - } - -@@ -992,9 +1035,51 @@ - FrameId targframeId = m_target ? m_target->GetFrame() : m_targframeId; - ParentSafetyAdjust(m_dBody, targframeId, targpos, targvel); - vector3d relpos = targpos - m_dBody->GetPosition(); -+ double targdist = relpos.Length(); -+ -+ Body* planetNear = Frame::GetFrame(m_dBody->GetFrame())->GetBody(); -+ double targetAlt = targpos.Length(); -+ -+ if(planetNear) { -+ double M = planetNear->IsType(ObjectType::TERRAINBODY) ? planetNear->GetMass() : 0; -+ double safeAlt = MaxEffectRad(planetNear, m_prop); -+ vector3d obspos = -m_dBody->GetPosition(); -+ -+ -+ if ((m_suicideRecovery = CheckSuicide(m_dBody, obspos, M, safeAlt, targetAlt, m_suicideRecovery))) { -+ -+ //find best orientationg to get to horizon -+ vector3d sidedir = obspos.Cross(m_dBody->GetVelocity()).NormalizedSafe(); -+ vector3d updir = sidedir.Cross(m_dBody->GetVelocity()).NormalizedSafe(); -+ -+ //clamped tangent of Yaw mismatch to target - for driving side trust -+ constexpr double cSideDriveRange = 0.02; -+ double targetSideTan = Clamp(targdist > 1 ? relpos.Dot(sidedir)/targdist : 0, -cSideDriveRange, cSideDriveRange); -+ -+ //Bellow safe alt (gravity too big for thrusters) breaking will kill the ship eventually -+ //so in this case ship accelerates along speed vector otherwise it is safe to break -+ float sign = G*M/obspos.LengthSqr() > 0.9 * m_prop->GetAccelUp() ? 1.0 : -1.0; -+ -+ double ang = m_prop->AIFaceDirection(m_dBody->GetVelocity() * sign); -+ m_prop->AIFaceUpdir(updir); -+#ifdef DEBUG_CHECK_SUICIDE -+ if (m_dBody->IsType(ObjectType::PLAYER)) { -+ std::cout << "SUICIDE recovery! ang=" << ang << " targetSideTan=" << targetSideTan << std::endl; -+ std::cout << "safeAlt=" << safeAlt << " obsdist=" << obspos.Length() << " targetpos.Length()=" << targpos.Length() << std::endl; -+ } -+#endif -+ -+ //Full Up and Forward thruster. -+ //Side thrust depends on relative pos of the target - not relevant for recovery but it is nice -+ //to be aligned with the target after surviving. -+ m_prop->SetLinThrusterState(ang < 0.05 ? vector3d(sign * targetSideTan * (1/cSideDriveRange), 1, -1) : vector3d(0.0)); -+ -+ return false; -+ } -+ } -+ - vector3d reldir = relpos.NormalizedSafe(); - vector3d relvel = targvel - m_dBody->GetVelocity(); -- double targdist = relpos.Length(); - - #ifdef DEBUG_AUTOPILOT - if (m_ship->IsType(ObjectType::PLAYER)) -@@ -1018,7 +1103,7 @@ - double erad = MaxEffectRad(body, m_prop); - Frame *targframe = Frame::GetFrame(targframeId); - if ((m_target && body != m_target) || (targframe && (!m_tangent || body != targframe->GetBody()))) { -- int coll = CheckCollision(m_dBody, reldir, targdist, targpos, m_endvel, erad); -+ int coll = CheckCollision(m_dBody, reldir, targdist, targetAlt, m_endvel, erad); - if (coll == 0) { // no collision - if (m_child) { - m_child.reset(); -@@ -1027,7 +1112,7 @@ - double ang = m_prop->AIFaceDirection(m_dBody->GetPosition()); - m_prop->AIMatchVel(ang < 0.05 ? 1000.0 * m_dBody->GetPosition().Normalized() : vector3d(0.0)); - } else { // same thing for 2/3/4 -- if (!m_child) m_child.reset(new AICmdFlyAround(m_dBody, Frame::GetFrame(m_frameId)->GetBody(), erad * 1.05, 0.0)); -+ if (!m_child) m_child.reset(new AICmdFlyAround(m_dBody, body, erad * 1.05, 0.0)); - static_cast(m_child.get())->SetTargPos(targpos); - ProcessChild(); - } -@@ -1068,7 +1153,7 @@ - const vector3d perpdir = (perpspeed > 1e-30) ? perpvel / perpspeed : vector3d(0, 0, 1); - - double sidefactor = perpspeed / (tt * 0.5); -- if (curspeed > (tt + timestep) * maxdecel || maxdecel < sidefactor) { -+ if (curspeed - m_endvel > (tt + timestep) * maxdecel || maxdecel < sidefactor) { - m_prop->AIFaceDirection(relvel); - m_prop->AIMatchVel(targvel); - m_state = -5; -@@ -1118,7 +1203,11 @@ - // then flip the ship so we can use our main thrusters to decelerate - if (m_state && !is_zero_exact(sdiff) && sdiff < maxdecel * timestep * 60) head = -head; - if (!m_state && decel) sidefactor = -sidefactor; -- head = head * maxdecel + perpdir * sidefactor; -+ -+ // check that head does not become zero length -+ if (maxdecel > 0.001 || abs(sidefactor) > 0.001) { -+ head = head * maxdecel + perpdir * sidefactor; -+ } - - // face appropriate direction - if (m_state >= 3) { -@@ -1410,7 +1499,6 @@ - assert(!std::isnan(alt)); - assert(!std::isnan(vel)); - m_obstructor = obstructor; -- m_alt = alt; - m_vel = vel; - m_targmode = mode; - -@@ -1423,6 +1511,8 @@ - Frame *nonRot = Frame::GetFrame(obsFrame->GetNonRotFrame()); - alt = std::min(alt, 0.95 * nonRot->GetRadius()); - -+ m_alt = alt; -+ - // generate suitable velocity if none provided - double minacc = (mode == 2) ? 0 : m_prop->GetAccelMin(); - double mass = obstructor->IsType(ObjectType::TERRAINBODY) ? obstructor->GetMass() : 0; -@@ -1484,8 +1574,8 @@ - assert(prop != 0); - - if (targalt > m_alt) return m_vel; -- double t = sqrt(2.0 * targdist / prop->GetAccelFwd()); -- double vmaxprox = prop->GetAccelMin() * t; // limit by target proximity -+ //either use reverse accel or implement dir flipping in FlyAround -+ double vmaxprox = sqrt(2 * prop->GetAccelRev() * targdist); - double vmaxstep = std::max(m_alt * 0.05, m_alt - targalt); - vmaxstep /= Pi::game->GetTimeStep(); // limit by distance covered per timestep - return std::min(m_vel, std::min(vmaxprox, vmaxstep)); -@@ -1514,22 +1604,16 @@ - } - - double timestep = Pi::game->GetTimeStep(); -- vector3d targpos = (!m_targmode) ? m_targpos : -- m_dBody->GetVelocity().NormalizedSafe() * m_dBody->GetPosition().LengthSqr(); -+ vector3d targpos = (!m_targmode) ? m_targpos : m_dBody->GetVelocity().NormalizedSafe() * m_dBody->GetPosition().LengthSqr(); - vector3d obspos = m_obstructor->GetPositionRelTo(m_dBody); - double obsdist = obspos.Length(); - vector3d obsdir = obspos / obsdist; - vector3d relpos = targpos - m_dBody->GetPosition(); -+ double targetDist = relpos.Length(); -+ vector3d shipToTargDir = relpos / targetDist; - -- // frame body suicide check, response -- if (CheckSuicide(m_dBody, -obsdir)) { -- m_prop->AIFaceDirection(m_dBody->GetPosition()); // face away from planet -- m_prop->AIMatchVel(vector3d(0.0)); -- return false; -- } -- -- // if too far away, fly to tangent -- if (obsdist > 1.1 * m_alt) { -+ // if too far away or overshoot -> fly to tangent -+ if (obsdist > 1.1 * m_alt || m_dBody->GetVelocity().Dot(shipToTargDir) < 0) { - double v; - FrameId obsframeId = Frame::GetFrame(m_obstructor->GetFrame())->GetNonRotFrame(); - vector3d tangent = GenerateTangent(m_dBody, obsframeId, targpos, m_alt); -@@ -1546,7 +1630,7 @@ - } - - // limit m_vel by target proximity & distance covered per frame -- double vel = (m_targmode) ? m_vel : MaxVel(relpos.Length(), targpos.Length()); -+ double vel = (m_targmode) ? m_vel : MaxVel(targetDist, targpos.Length()); - - // all calculations in ship's frame - vector3d fwddir = (obsdir.Cross(relpos).Cross(obsdir)).NormalizedSafe(); ---- pioneer-20230203.orig/src/ShipAICmd.h 2023-07-19 23:54:00.245824921 +0900 -+++ pioneer-20230203/src/ShipAICmd.h 2023-07-20 00:09:55.718866370 +0900 -@@ -137,10 +137,10 @@ - bool m_tangent; // true if path is to a tangent of the target frame's body - int m_state; - -- bool m_lockhead; - int m_targetIndex; // used during deserialisation - vector3d m_reldir; // target direction relative to ship at last frame change - FrameId m_frameId; // last frame of ship -+ bool m_suicideRecovery; - }; - - class AICmdFlyAround : public AICommand { ---- pioneer-20230203.orig/src/lua/LuaSpace.cpp 2023-07-19 23:54:00.250824905 +0900 -+++ pioneer-20230203/src/lua/LuaSpace.cpp 2023-07-20 00:12:51.625324432 +0900 -@@ -187,7 +187,7 @@ - } - - // functions from ShipAiCmd.cpp --extern int CheckCollision(DynamicBody *dBody, const vector3d &pathdir, double pathdist, const vector3d &tpos, double endvel, double r); -+extern int CheckCollision(DynamicBody *dBody, const vector3d &pathdir, double pathdist, double targAlt, double endvel, double r); - extern double MaxEffectRad(const Body *body, Propulsion *prop); - - /* -@@ -256,19 +256,20 @@ - // check for collision at spawn position - const vector3d shippos = ship->GetPosition(); - const vector3d targpos = targetbody->GetPositionRelTo(ship->GetFrame()); -+ double targAlt = targpos.Length(); - const vector3d relpos = targpos - shippos; - const vector3d reldir = relpos.NormalizedSafe(); - const double targdist = relpos.Length(); - Body *body = Frame::GetFrame(ship->GetFrame())->GetBody(); - const double erad = MaxEffectRad(body, ship->GetPropulsion()); -- const int coll = CheckCollision(ship, reldir, targdist, targpos, 0, erad); -+ const int coll = CheckCollision(ship, reldir, targdist, targAlt, 0, erad); - if (coll) { - // need to correct positon, to avoid collision -- if (targpos.Length() > erad) { -+ if (targAlt > erad) { - // target is above the effective radius of obstructor - rotate the ship's position - // around the target position, so that the obstructor's "effective radius" does not cross the path - // direction obstructor -> target -- const vector3d z = targpos.Normalized(); -+ const vector3d z = targpos/targAlt; - // the axis around which the position of the ship will rotate - const vector3d y = z.Cross(shippos).NormalizedSafe(); - // just the third axis of this basis -@@ -276,7 +277,7 @@ - - // this is the basis in which the position of the ship will rotate - const matrix3x3d corrCS = matrix3x3d::FromVectors(x, y, z).Transpose(); -- const double len = targpos.Length(); -+ const double len = targAlt; - // two possible positions of the ship, when flying around the obstructor to the right or left - // rotate (in the given basis) the direction from the target to the obstructor, so that it passes tangentially to the obstructor - const vector3d safe1 = corrCS.Transpose() * (matrix3x3d::RotateY(+asin(erad / len)) * corrCS * -targpos).Normalized() * targdist; -@@ -288,7 +289,7 @@ - ship->SetPosition(safe2 + targpos); - } else { - // target below the effective radius of obstructor. Position the ship direct above the target -- ship->SetPosition(targpos + targpos.Normalized() * targdist); -+ ship->SetPosition(targpos + targpos/targAlt * targdist); - } - // update velocity direction - ship->SetVelocity((targpos - ship->GetPosition()).Normalized() * pp.getVel() + targetbody->GetVelocityRelTo(ship->GetFrame())); ---- pioneer-20230203.orig/src/ship/Propulsion.cpp 2023-07-19 23:54:00.252824899 +0900 -+++ pioneer-20230203/src/ship/Propulsion.cpp 2023-07-20 00:14:14.857068275 +0900 -@@ -185,9 +185,9 @@ - double Propulsion::GetThrustMin() const - { - // These are the weakest thrusters in a ship -- double val = static_cast(m_linThrust[THRUSTER_UP]); -- val = std::min(val, static_cast(m_linThrust[THRUSTER_RIGHT])); -- val = std::min(val, static_cast(m_linThrust[THRUSTER_LEFT])); -+ double val = GetThrust(THRUSTER_UP); -+ val = std::min(val, GetThrust(THRUSTER_RIGHT)); -+ val = std::min(val, GetThrust(THRUSTER_LEFT)); - return val; - } -