diff --git a/src/screenComponents/radarView.cpp b/src/screenComponents/radarView.cpp index def1c8912d..b2f05f7ecd 100644 --- a/src/screenComponents/radarView.cpp +++ b/src/screenComponents/radarView.cpp @@ -56,6 +56,7 @@ GuiRadarView::GuiRadarView(GuiContainer* owner, string id, TargetsContainer* tar view_position(0.0f,0.0f), view_rotation(0), auto_center_target(my_spaceship), + track_my_spaceship(true), auto_center_on_ship(true), auto_rotate_on_ship(false), auto_distance(true), @@ -93,6 +94,7 @@ GuiRadarView::GuiRadarView(GuiContainer* owner, string id, float distance, Targe view_position(0.0f, 0.0f), view_rotation(0), auto_center_target(my_spaceship), + track_my_spaceship(true), auto_center_on_ship(true), auto_rotate_on_ship(false), distance(distance), @@ -123,6 +125,10 @@ GuiRadarView::GuiRadarView(GuiContainer* owner, string id, float distance, Targe void GuiRadarView::onDraw(sp::RenderTarget& renderer) { + // Keep centered on my_spaceship when the player's assigned ship changes. + if (track_my_spaceship && my_spaceship) + auto_center_target = my_spaceship; + // Auto-center on the target, defaulting to my_spaceship on creation. auto transform = auto_center_target.getComponent(); diff --git a/src/screenComponents/radarView.h b/src/screenComponents/radarView.h index 28cb3afa83..06d255edcb 100644 --- a/src/screenComponents/radarView.h +++ b/src/screenComponents/radarView.h @@ -46,6 +46,7 @@ class GuiRadarView : public GuiElement glm::vec2 view_position{0, 0}; float view_rotation; sp::ecs::Entity auto_center_target; + bool track_my_spaceship; bool auto_center_on_ship; bool auto_rotate_on_ship; bool auto_distance = false; @@ -108,7 +109,7 @@ class GuiRadarView : public GuiElement bool getAutoCentering() { return auto_center_on_ship; } GuiRadarView* setAutoCentering(bool value) { this->auto_center_on_ship = value; return this; } sp::ecs::Entity getAutoCenterTarget() { return auto_center_target; } - GuiRadarView* setAutoCenterTarget(sp::ecs::Entity target) { this->auto_center_target = target; return this; } + GuiRadarView* setAutoCenterTarget(sp::ecs::Entity target) { this->auto_center_target = target; this->track_my_spaceship = false; return this; } bool getAutoRotating() { return auto_rotate_on_ship; } GuiRadarView* setAutoRotating(bool value) { this->auto_rotate_on_ship = value; return this; } GuiRadarView* setCallbacks(bpfunc_t mouse_down_func, pfunc_t mouse_drag_func, pfunc_t mouse_up_func, fpfunc_t mouse_wheel_func) { this->mouse_down_func = mouse_down_func; this->mouse_drag_func = mouse_drag_func; this->mouse_up_func = mouse_up_func; this->mouse_wheel_func = mouse_wheel_func; return this; } diff --git a/src/script.cpp b/src/script.cpp index 1d153a9e65..8990bf7d11 100644 --- a/src/script.cpp +++ b/src/script.cpp @@ -464,18 +464,63 @@ static int luaGetEnemiesInRadiusFor(lua_State* L) static void luaTransferPlayers(sp::ecs::Entity source, sp::ecs::Entity target, std::optional station) { - if (!target.getComponent()) return; - // For each player, move them to the same station on the target. - for(auto i : player_info_list) - if (i->ship == source && (!station.has_value() || i->hasPosition(station.value()))) - i->ship = target; + // Relevant only to player-controlled entities. + auto target_pc = target.getOrAddComponent(); + if (target.hasComponent()) target.removeComponent(); + + if (!target_pc.allowed_positions.mask) + { + LOG(Error, "transferPlayersToShip: destination ship has no allowed crew positions. Resetting to Any."); + target_pc.allowed_positions = CrewPositions::all(); + } + + // For each matching player, reassign their ship, filter crew positions + // against the new ship's allowed positions, and clear their cached ship + // password. + for (auto i : player_info_list) + { + if (i->ship != source || (station.has_value() && !i->hasPosition(station.value()))) + continue; + + // Move player to new ship. + i->ship = target; + + // Check against the destination's allowed crew positions. If a player's + // in a position prohibited by the new ship, log a warning for the + // scenario author and drop the player into the next allowed position. + for (auto& cps : i->crew_positions) + { + CrewPositions lost{cps.mask & ~target_pc.allowed_positions.mask}; + if (lost.mask) + { + // This is probably not what the script user intended, so log + // it. + for (auto cp : lost) + LOG(Warning, "transferPlayersToShip: player ", i->name, " held the ", crewPositionToString(cp), " crew position, which is prohibited on the destination ship. Reassigning to next allowed position."); + // Assign the first allowed position not already held on this + // monitor. + for (int n = 0; n < static_cast(CrewPosition::MAX); n++) + { + auto cp = static_cast(n); + if (target_pc.allowed_positions.has(cp) && !cps.has(cp)) + { + cps.add(cp); + break; + } + } + } + cps.mask &= target_pc.allowed_positions.mask; + } + + // Clear last ship password. + i->last_ship_password = ""; + } } static bool luaHasPlayerAtPosition(sp::ecs::Entity source, CrewPosition station) { - for(auto i : player_info_list) - if (i->ship == source && i->hasPosition(station)) - return true; + for (auto i : player_info_list) + if (i->ship == source && i->hasPosition(station)) return true; return false; } @@ -484,16 +529,14 @@ static int luaGetPlayersInfo(lua_State* L) auto source = sp::script::Convert::fromLua(L, 1); lua_newtable(L); int index = 1; - for(auto i : player_info_list) { - if (i->ship != source) - continue; + for (auto i : player_info_list) + { + if (i->ship != source) continue; lua_newtable(L); lua_pushstring(L, i->name.c_str()); lua_setfield(L, -2, "name"); CrewPositions positions; - for(auto cp : i->crew_positions) { - positions.mask |= cp.mask; - } + for (auto cp : i->crew_positions) positions.mask |= cp.mask; sp::script::Convert::toLua(L, positions); lua_setfield(L, -2, "positions"); lua_seti(L, -2, index);