Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
2b2fba1
add hotkey for probeview
Mar 30, 2026
65adb03
setting up a toggle option to call onclick()
gwaland Apr 7, 2026
0a8543d
forgot to declare the toggle
gwaland Apr 7, 2026
dacb62d
Refactor previous/next target selection
oznogon Apr 7, 2026
4a30d51
trying to fix probe view next scannable object
gwaland Apr 7, 2026
303b75d
Merge branch 'master' into 2703-target-cycle-keybinds
oznogon Apr 14, 2026
4c83cea
Merge branch 'master' into 2703-target-cycle-keybinds
oznogon Apr 15, 2026
3125cd4
Merge branch 'daid:master' into Feature/probe-view-toggle-button
gwaland Apr 19, 2026
eea6cec
Merge branch 'daid:master' into Feature/probe-view-toggle-button
gwaland May 6, 2026
520cf8d
Merge branch 'daid:master' into Feature/probe-view-toggle-button
gwaland May 22, 2026
fd0f66b
Merge branch 'daid:master' into Feature/probe-view-toggle-button
gwaland Jun 2, 2026
62b8091
Merge branch 'daid:master' into Feature/probe-view-toggle-button
gwaland Jun 8, 2026
8745a74
Merge branch 'daid:master' into Feature/probe-view-toggle-button
gwaland Jun 19, 2026
4b2f0e0
Merge remote-tracking branch 'oznogon/2703-target-cycle-keybinds' int…
gwaland Jun 19, 2026
e32a8da
Add Scan/Abort toggle keybind for science screen
gwaland Jun 20, 2026
12e507b
Auto-return to ship selection after destruction in autoconnect mode
gwaland Jun 20, 2026
6d6a894
Fix relay probe selection and science target cycling visibility
gwaland Jun 20, 2026
d5e3618
Document fork maintenance workflow
gwaland Jul 19, 2026
fada6a6
Add hardware scenario state variables
gwaland Jul 19, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 52 additions & 0 deletions FORK_MAINTENANCE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# Fork Maintenance

This fork uses two long-lived branches:

- `master` is a pristine mirror of official EmptyEpsilon from `upstream/master`.
- `gwaland-main` is the version to build, run, and maintain with local custom changes.

New custom features should branch from `gwaland-main`, not `master`. Upstream changes should be merged into `gwaland-main` with merge commits so the custom branch history remains intact.

Do not rebase `gwaland-main` after it has been published. Rebasing would rewrite published history and make collaboration and future maintenance harder.

The word "backport" is not quite right for this workflow. The maintained fork is merging or forward-porting upstream changes from official EmptyEpsilon into `gwaland-main`.

## Remotes

- `origin`: `gwaland/EmptyEpsilon`
- `upstream`: `daid/EmptyEpsilon`

## Direct Upstream Update Workflow

Use this when updating the maintained fork directly:

```bash
git fetch upstream
git switch master
git merge --ff-only upstream/master
git push origin master

git switch gwaland-main
git merge --no-ff master
git push origin gwaland-main
```

The `--ff-only` merge keeps `master` as a clean mirror of official EmptyEpsilon. The `--no-ff` merge into `gwaland-main` preserves an explicit merge point for upstream updates.

## Pull-Request-Based Update Workflow

Use this when you want to review upstream changes in a pull request before merging them into `gwaland-main`:

```bash
git fetch upstream

git switch master
git merge --ff-only upstream/master
git push origin master

git switch gwaland-main
git switch -c sync/upstream-YYYY-MM-DD
git merge --no-ff master
```

After resolving any conflicts and validating the build, push the `sync/upstream-YYYY-MM-DD` branch and open a pull request into `gwaland-main`.
56 changes: 56 additions & 0 deletions NEW_STATES_PLAN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Hardware Game-State Lighting Variables

## Summary

Add two numeric variables for `hardware.ini` mappings:

- `RunningScenario`: `1.0` while a scenario is loaded/running, `0.0` otherwise.
- `ShuttingDown`: `1.0` only during final hardware shutdown flush, `0.0` during normal runtime.

These variables should work on both the host/server and connected client stations so station-attached lighting can respond consistently.

## Implementation

- Add a replicated `GameGlobalInfo::scenario_running` boolean, initialized false.
- Set `scenario_running = true` after `startScenario()` successfully loads the scenario script.
- Set `scenario_running = false` from `reset()` and destroy paths.
- Expose `RunningScenario` in `HardwareController::getVariableValue()` from replicated `gameGlobalInfo->scenario_running`.
- Expose `ShuttingDown` in `HardwareController::getVariableValue()` from a local shutdown flag.
- Add `HardwareController::shutdown()` to set the shutdown flag, flush `update(0.0f)` once, then wait `100 ms`.
- Call the hardware shutdown flush after `engine->runMainLoop()` returns and before window/engine teardown.

## Hardware.ini Behavior

Existing syntax remains unchanged.

Example usage:

```ini
[state]
target = bridge_light
condition = RunningScenario
value = 1.0

[state]
target = menu_light
condition = RunningScenario == 0
value = 1.0

[state]
target = exit_light
condition = ShuttingDown
value = 1.0
```

`RunningScenario` uses the existing default `> 0` condition behavior when no operator is provided. `ShuttingDown` is intended for final/default exit lighting only, not for normal menu states.

## Test Plan

- Build the project to verify the replicated field and hardware controller changes compile.
- Use `VirtualOutputDevice` with a small `hardware.ini` to verify:
- `RunningScenario` is `0` at the main menu.
- `RunningScenario` becomes `1` after loading a scenario.
- `RunningScenario` returns to `0` after resetting/disconnecting back to non-scenario state.
- `ShuttingDown` activates the configured output during final application exit.
- For multiplayer behavior, start a host with a scenario and connect a client station; verify client-side hardware sees `RunningScenario == 1`.
- Confirm existing hardware variables such as `Always`, `HasShip`, and ship-system variables still behave unchanged.
5 changes: 5 additions & 0 deletions src/gameGlobalInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ GameGlobalInfo::GameGlobalInfo()
allow_main_screen_strategic_map = true;
gm_control_code = "";
elapsed_time = 0.0f;
scenario_running = false;

intercept_all_comms_to_gm = false;

Expand All @@ -53,6 +54,7 @@ GameGlobalInfo::GameGlobalInfo()
registerMemberReplication(&allow_main_screen_strategic_map);
registerMemberReplication(&gm_control_code);
registerMemberReplication(&elapsed_time, 0.1);
registerMemberReplication(&scenario_running);
registerMemberReplication(&default_skybox);
}

Expand Down Expand Up @@ -281,6 +283,7 @@ void GameGlobalInfo::reset()
script_environment_base = nullptr;

elapsed_time = 0.0f;
scenario_running = false;
callsign_counter = 0;
global_message = "";
global_message_timeout = 0.0f;
Expand Down Expand Up @@ -373,6 +376,8 @@ void GameGlobalInfo::startScenario(string filename, std::unordered_map<string, s

auto res = main_scenario_script->runFile<void>(filename);
LuaConsole::checkResult(res);
if (res.isOk())
scenario_running = true;
if (res.isOk() && main_scenario_script->isFunction("init"))
{
bool is_headless = !PreferencesManager::get("headless").empty();
Expand Down
1 change: 1 addition & 0 deletions src/gameGlobalInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ class GameGlobalInfo : public MultiplayerObject, public Updatable
string default_skybox = "default";
string gm_control_code;
float elapsed_time;
bool scenario_running;
string scenario;
std::unordered_map<string, string> scenario_settings;

Expand Down
4 changes: 4 additions & 0 deletions src/gui/gui2_togglebutton.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ bool GuiToggleButton::getValue() const
return value;
}

void GuiToggleButton::toggle() {
onClick(); // trigger the click event used to toggle probe view vie key.
}

GuiToggleButton* GuiToggleButton::setValue(bool value)
{
if (this->value == value)
Expand Down
1 change: 1 addition & 0 deletions src/gui/gui2_togglebutton.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ class GuiToggleButton : public GuiButton

bool getValue() const;
GuiToggleButton* setValue(bool value);
void toggle();
private:
void onClick();
};
Expand Down
34 changes: 34 additions & 0 deletions src/gui/hotkeyConfig.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,9 @@ Keys::Keys() :
{"WEAPONS_FIRE_TUBE16"},
}},
weapons_enemy_next_target("WEAPONS_TARGET_NEXT_ENEMY", "C"),
weapons_enemy_prev_target("WEAPONS_TARGET_PREV_ENEMY"),
weapons_next_target("WEAPONS_TARGET_NEXT", "Z"),
weapons_prev_target("WEAPONS_TARGET_PREV"),
weapons_toggle_shields("WEAPONS_SHIELDS_TOGGLE", "S"),
weapons_enable_shields("WEAPONS_SHIELDS_ENABLE"),
weapons_disable_shields("WEAPONS_SHIELDS_DISABLE"),
Expand All @@ -248,7 +250,14 @@ Keys::Keys() :
// Science crew screen
science_scan_object("SCIENCE_SCAN_OBJECT", "S"),
science_scan_abort("SCIENCE_SCAN_ABORT", "D"),
science_scan_toggle("SCIENCE_SCAN_TOGGLE"),
science_toggle_probe_view("SCIENCE_TOGGLE_PROBE_VIEW"),
science_select_next_scannable("SCIENCE_SELECT_NEXT_SCANNABLE", "C"),
science_select_prev_scannable("SCIENCE_SELECT_PREV_SCANNABLE"),
science_next_target("SCIENCE_TARGET_NEXT"),
science_prev_target("SCIENCE_TARGET_PREV"),
science_enemy_next_target("SCIENCE_TARGET_NEXT_ENEMY"),
science_enemy_prev_target("SCIENCE_TARGET_PREV_ENEMY"),
science_scan_param_increase{{
{"SCIENCE_SCAN_PARAM_INCREASE_1"},
{"SCIENCE_SCAN_PARAM_INCREASE_2"},
Expand Down Expand Up @@ -331,6 +340,14 @@ Keys::Keys() :
relay_alert_level_none("RELAY_ALERT_NONE"),
relay_alert_level_yellow("RELAY_ALERT_YELLOW"),
relay_alert_level_red("RELAY_ALERT_RED"),
relay_next_target("RELAY_TARGET_NEXT"),
relay_prev_target("RELAY_TARGET_PREV"),
relay_enemy_next_target("RELAY_TARGET_NEXT_ENEMY"),
relay_enemy_prev_target("RELAY_TARGET_PREV_ENEMY"),
relay_next_hackable("RELAY_TARGET_NEXT_HACKABLE"),
relay_prev_hackable("RELAY_TARGET_PREV_HACKABLE"),
relay_next_probe("RELAY_TARGET_NEXT_PROBE"),
relay_prev_probe("RELAY_TARGET_PREV_PROBE"),

// GM screen
gm_delete("GM_DELETE", "Delete"),
Expand Down Expand Up @@ -439,7 +456,9 @@ void Keys::init()
weapons_fire_tube[n].setLabel(tr("hotkey_menu", "Weapons"), tr("hotkey_Weapons", "Fire tube {number}").format({{"number", string(n + 1)}}));
}
weapons_enemy_next_target.setLabel(tr("hotkey_menu", "Weapons"), tr("hotkey_Weapons", "Select next hostile target"));
weapons_enemy_prev_target.setLabel(tr("hotkey_menu", "Weapons"), tr("hotkey_Weapons", "Select previous hostile target"));
weapons_next_target.setLabel(tr("hotkey_menu", "Weapons"), tr("hotkey_Weapons", "Select next target (any)"));
weapons_prev_target.setLabel(tr("hotkey_menu", "Weapons"), tr("hotkey_Weapons", "Select previous target (any)"));
weapons_toggle_shields.setLabel(tr("hotkey_menu", "Weapons"), tr("hotkey_Weapons", "Toggle shields"));
weapons_enable_shields.setLabel(tr("hotkey_menu", "Weapons"), tr("hotkey_Weapons", "Enable shields"));
weapons_disable_shields.setLabel(tr("hotkey_menu", "Weapons"), tr("hotkey_Weapons", "Disable shields"));
Expand All @@ -459,7 +478,14 @@ void Keys::init()
// Science
science_scan_object.setLabel(tr("hotkey_menu", "Science"), tr("hotkey_Science", "Scan object"));
science_scan_abort.setLabel(tr("hotkey_menu", "Science"), tr("hotkey_Science", "Abort scan"));
science_scan_toggle.setLabel(tr("hotkey_menu", "Science"), tr("hotkey_Science", "Scan/Abort toggle"));
science_toggle_probe_view.setLabel(tr("hotkey_menu", "Science"), tr("hotkey_Science", "Toggle probe view"));
science_select_next_scannable.setLabel(tr("hotkey_menu", "Science"), tr("hotkey_Science", "Select next scannable object"));
science_select_prev_scannable.setLabel(tr("hotkey_menu", "Science"), tr("hotkey_Science", "Select previous scannable object"));
science_next_target.setLabel(tr("hotkey_menu", "Science"), tr("hotkey_Science", "Select next target (any)"));
science_prev_target.setLabel(tr("hotkey_menu", "Science"), tr("hotkey_Science", "Select previous target (any)"));
science_enemy_next_target.setLabel(tr("hotkey_menu", "Science"), tr("hotkey_Science", "Select next hostile target"));
science_enemy_prev_target.setLabel(tr("hotkey_menu", "Science"), tr("hotkey_Science", "Select previous hostile target"));
for (auto n = 0u; n < science_scan_param_increase.size(); n++)
{
science_scan_param_increase[n].setLabel(tr("hotkey_menu", "Science"), tr("hotkey_Science", "Scanning parameter {number} increase").format({{"number", string(n + 1)}}));
Expand Down Expand Up @@ -526,6 +552,14 @@ void Keys::init()
relay_alert_level_none.setLabel(tr("hotkey_menu", "Relay"), tr("hotkey_Relay", "Alert level: Normal"));
relay_alert_level_yellow.setLabel(tr("hotkey_menu", "Relay"), tr("hotkey_Relay", "Alert level: Yellow"));
relay_alert_level_red.setLabel(tr("hotkey_menu", "Relay"), tr("hotkey_Relay", "Alert level: Red"));
relay_next_target.setLabel(tr("hotkey_menu", "Relay"), tr("hotkey_Relay", "Select next target (any)"));
relay_prev_target.setLabel(tr("hotkey_menu", "Relay"), tr("hotkey_Relay", "Select previous target (any)"));
relay_enemy_next_target.setLabel(tr("hotkey_menu", "Relay"), tr("hotkey_Relay", "Select next hostile target"));
relay_enemy_prev_target.setLabel(tr("hotkey_menu", "Relay"), tr("hotkey_Relay", "Select previous hostile target"));
relay_next_hackable.setLabel(tr("hotkey_menu", "Relay"), tr("hotkey_Relay", "Select next hackable target"));
relay_prev_hackable.setLabel(tr("hotkey_menu", "Relay"), tr("hotkey_Relay", "Select previous hackable target"));
relay_next_probe.setLabel(tr("hotkey_menu", "Relay"), tr("hotkey_Relay", "Select next probe"));
relay_prev_probe.setLabel(tr("hotkey_menu", "Relay"), tr("hotkey_Relay", "Select previous probe"));

// Cinematic view
cinematic.init();
Expand Down
17 changes: 17 additions & 0 deletions src/gui/hotkeyConfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,9 @@ class Keys
std::array<sp::io::Keybinding, 16> weapons_unload_tube;
std::array<sp::io::Keybinding, 16> weapons_fire_tube;
sp::io::Keybinding weapons_enemy_next_target;
sp::io::Keybinding weapons_enemy_prev_target;
sp::io::Keybinding weapons_next_target;
sp::io::Keybinding weapons_prev_target;
sp::io::Keybinding weapons_toggle_shields;
sp::io::Keybinding weapons_enable_shields;
sp::io::Keybinding weapons_disable_shields;
Expand All @@ -120,7 +122,14 @@ class Keys
// Science screen binds
sp::io::Keybinding science_scan_object;
sp::io::Keybinding science_scan_abort;
sp::io::Keybinding science_scan_toggle;
sp::io::Keybinding science_select_next_scannable;
sp::io::Keybinding science_toggle_probe_view;
sp::io::Keybinding science_select_prev_scannable;
sp::io::Keybinding science_next_target;
sp::io::Keybinding science_prev_target;
sp::io::Keybinding science_enemy_next_target;
sp::io::Keybinding science_enemy_prev_target;
std::array<sp::io::Keybinding, 4> science_scan_param_increase;
std::array<sp::io::Keybinding, 4> science_scan_param_decrease;
std::array<sp::io::Keybinding, 4> science_scan_param_set;
Expand Down Expand Up @@ -159,6 +168,14 @@ class Keys
sp::io::Keybinding relay_alert_level_none;
sp::io::Keybinding relay_alert_level_yellow;
sp::io::Keybinding relay_alert_level_red;
sp::io::Keybinding relay_next_target;
sp::io::Keybinding relay_prev_target;
sp::io::Keybinding relay_enemy_next_target;
sp::io::Keybinding relay_enemy_prev_target;
sp::io::Keybinding relay_next_hackable;
sp::io::Keybinding relay_prev_hackable;
sp::io::Keybinding relay_next_probe;
sp::io::Keybinding relay_prev_probe;

// Cinematic view binds
struct CinematicKeys {
Expand Down
20 changes: 20 additions & 0 deletions src/hardware/hardwareController.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@

#include "hardwareMappingEffects.h"

#include <chrono>
#include <thread>

HardwareController::~HardwareController()
{
for(HardwareOutputDevice* device : devices)
Expand Down Expand Up @@ -268,6 +271,13 @@ void HardwareController::update(float delta)
}
}

void HardwareController::shutdown()
{
shutting_down = true;
update(0.0f);
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}

void HardwareController::createNewHardwareMappingState(int channel_number, std::unordered_map<string, string>& settings)
{
string condition = settings["condition"];
Expand Down Expand Up @@ -377,6 +387,16 @@ bool HardwareController::getVariableValue(string variable_name, float& value)
value = bool(ship) ? 1.0f : 0.0f;
return true;
}
if (variable_name == "RunningScenario")
{
value = gameGlobalInfo && gameGlobalInfo->scenario_running ? 1.0f : 0.0f;
return true;
}
if (variable_name == "ShuttingDown")
{
value = shutting_down ? 1.0f : 0.0f;
return true;
}
SHIP_VARIABLE("Hull", Hull, 100.0f * c->current / c->max);
SHIP_VARIABLE("FrontShield", Shields, c->entries.size() > 0 ? c->entries[0].percentage() : 0.0f);
SHIP_VARIABLE("RearShield", Shields, c->entries.size() > 1 ? c->entries[1].percentage() : 0.0f);
Expand Down
2 changes: 2 additions & 0 deletions src/hardware/hardwareController.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,11 +56,13 @@ class HardwareController : public Updatable
std::vector<HardwareMappingState> states;
std::vector<HardwareMappingEvent> events;
std::vector<float> channels;
bool shutting_down = false;
public:
HardwareController() = default;
~HardwareController();

void loadConfiguration(string filename);
void shutdown();

virtual void update(float delta) override;

Expand Down
1 change: 1 addition & 0 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,7 @@ int main(int argc, char** argv)
}

engine->runMainLoop();
hardware_controller->shutdown();

// Set FSAA and fullscreen defaults from windowManager.
if (windows.size() > 0)
Expand Down
15 changes: 15 additions & 0 deletions src/screenComponents/shipDestroyedPopup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include "playerInfo.h"
#include "soundManager.h"
#include "main.h"
#include "preferenceManager.h"

#include "gui/gui2_overlay.h"
#include "gui/gui2_canvas.h"
Expand Down Expand Up @@ -33,8 +34,22 @@ void GuiShipDestroyedPopup::onDraw(sp::RenderTarget& target)
{
ship_destroyed_overlay->hide();
show_timeout.start(5.0);
return_timeout = {};
}else{
if (show_timeout.isExpired())
{
ship_destroyed_overlay->show();
if (!PreferencesManager::get("autoconnect").empty())
{
if (!return_timeout.isRunning())
return_timeout.start(15.0);
if (return_timeout.isExpired())
{
soundManager->stopMusic();
returnToShipSelection(this->owner->getRenderLayer());
this->owner->destroy();
}
}
}
}
}
1 change: 1 addition & 0 deletions src/screenComponents/shipDestroyedPopup.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ class GuiShipDestroyedPopup : public GuiElement
GuiOverlay* ship_destroyed_overlay;
GuiCanvas* owner;
sp::SystemTimer show_timeout;
sp::SystemTimer return_timeout;

public:
GuiShipDestroyedPopup(GuiCanvas* owner);
Expand Down
Loading
Loading