Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
182 changes: 128 additions & 54 deletions src/screenComponents/dockingButton.cpp
Original file line number Diff line number Diff line change
@@ -1,54 +1,99 @@
#include <i18n.h>
#include "playerInfo.h"
#include "dockingButton.h"
#include "gui/gui2_button.h"
#include "gui/gui2_listbox.h"
#include "gui/gui2_panel.h"
#include "systems/collision.h"
#include "systems/docking.h"
#include "components/collision.h"
#include "components/docking.h"
#include "components/faction.h"
#include "components/name.h"
#include "ecs/query.h"


GuiDockingButton::GuiDockingButton(GuiContainer* owner, string id)
: GuiButton(owner, id, "", [this]() { click(); })
: GuiElement(owner, id)
{
setIcon("gui/icons/docking");
}
background_panel = new GuiPanel(this, id + "_BG");
background_panel
->setSize(GuiElement::GuiSizeMax, GuiElement::GuiSizeMax)
->setPosition(0.0f, 0.0f, sp::Alignment::TopLeft)
->hide();

void GuiDockingButton::click()
{
if (!my_spaceship) { return; }
auto port = my_spaceship.getComponent<DockingPort>();
if (!port) { return; }
action_button = new GuiButton(this, id + "_BTN", tr("Request dock"),
[this]()
{
if (!my_spaceship || !my_player_info) return;
auto port = my_spaceship.getComponent<DockingPort>();
if (!port) return;

switch(port->state)
{
case DockingPort::State::NotDocking:
my_player_info->commandDock(findDockingTarget());
break;
case DockingPort::State::Docking:
my_player_info->commandAbortDock();
break;
case DockingPort::State::Docked:
my_player_info->commandUndock();
break;
}
switch (port->state)
{
case DockingPort::State::NotDocking:
dock_targets = findDockingTargets();
// Expand list if it has more than one entry.
// Otherwise, just dock.
if (dock_targets.size() == 1)
my_player_info->commandDock(dock_targets[0]);
else if (dock_targets.size() > 1) expanded = true;
break;
case DockingPort::State::Docking:
my_player_info->commandAbortDock();
break;
case DockingPort::State::Docked:
my_player_info->commandUndock();
break;
}
}
);
action_button
->setIcon("gui/icons/docking")
->setSize(GuiElement::GuiSizeMax, GuiElement::GuiSizeMax)
->setPosition(0.0f, 0.0f, sp::Alignment::TopLeft);

target_list = new GuiListbox(this, id + "_LIST",
[this](int index, string value)
{
if (!my_player_info) return;
expanded = false;
if (value == "cancel") return;
int idx = value.toInt();
if (idx >= 0 && idx < static_cast<int>(dock_targets.size()))
my_player_info->commandDock(dock_targets[idx]);

}
);
target_list
->setPosition(0.0f, 0.0f, sp::Alignment::TopLeft)
->setSize(GuiElement::GuiSizeMax, GuiElement::GuiSizeMax)
->hide();
}

void GuiDockingButton::onUpdate()
{
if (!my_spaceship) { hide(); return; }
if (!my_spaceship)
{
hide();
return;
}
auto port = my_spaceship.getComponent<DockingPort>();
setVisible(port != nullptr);
if (!port) return;

// Keyboard shortcuts dock to the nearest.
if (isVisible())
{
if (keys.helms_dock_action.getDown())
{
switch(port->state)
{
case DockingPort::State::NotDocking:
my_player_info->commandDock(findDockingTarget());
{
auto targets = findDockingTargets();
if (!targets.empty())
my_player_info->commandDock(targets[0]);
}
break;
case DockingPort::State::Docking:
my_player_info->commandAbortDock();
Expand All @@ -59,62 +104,91 @@ void GuiDockingButton::onUpdate()
}
}
else if (keys.helms_dock_request.getDown())
my_player_info->commandDock(findDockingTarget());
{
auto targets = findDockingTargets();
if (!targets.empty())
my_player_info->commandDock(targets[0]);
}
else if (keys.helms_dock_abort.getDown())
my_player_info->commandAbortDock();
else if (keys.helms_undock.getDown())
my_player_info->commandUndock();
}
}

void GuiDockingButton::onDraw(sp::RenderTarget& renderer)
{
if (!my_spaceship) { return; }
auto port = my_spaceship.getComponent<DockingPort>();
if (!port) { return; }
// Collapse the listbox when docking state changes away from NotDocking.
if (port->state != DockingPort::State::NotDocking) expanded = false;

switch(port->state)
// Update the docking list if it's expanded.
if (expanded)
{
case DockingPort::State::NotDocking:
setText(tr("Request Dock"));
if (DockingSystem::canStartDocking(my_spaceship) && findDockingTarget())
dock_targets = findDockingTargets();
if (dock_targets.empty()) expanded = false;
else
{
enable();
}else{
disable();
target_list->clear();
for (int i = 0; i < static_cast<int>(dock_targets.size()); i++)
{
// Use the callsign if available for the entry name.
string name = tr("Unknown");
if (auto cs = dock_targets[i].getComponent<CallSign>())
name = cs->callsign;
target_list->addEntry(name, string(i));
}
target_list->addEntry(tr("Cancel"), "cancel");

// Expand height to fit all entries.
layout.size.y = (dock_targets.size() + 1) * item_height;
background_panel->show();
action_button->hide();
target_list->show();
return;
}
}

// If collapsed, just show the action button.
layout.size.y = item_height;
background_panel->hide();
target_list->hide();
action_button->show();

switch (port->state)
{
case DockingPort::State::NotDocking:
dock_targets = findDockingTargets();
action_button
->setText(tr("Request dock"))
->setEnable(DockingSystem::canStartDocking(my_spaceship) && !dock_targets.empty());
break;
case DockingPort::State::Docking:
setText(tr("Cancel Docking"));
enable();
action_button
->setText(tr("Cancel docking"))
->enable();
break;
case DockingPort::State::Docked:
setText(tr("Undock"));
enable();
action_button
->setText(tr("Undock"))
->enable();
break;
}

GuiButton::onDraw(renderer);
}

sp::ecs::Entity GuiDockingButton::findDockingTarget()
std::vector<sp::ecs::Entity> GuiDockingButton::findDockingTargets()
{
if (!my_spaceship) { return {}; }
std::vector<sp::ecs::Entity> targets;
if (!my_spaceship) return targets;
auto port = my_spaceship.getComponent<DockingPort>();
if (!port) { return {}; }
if (!port) return targets;
auto my_transform = my_spaceship.getComponent<sp::Transform>();
if (!my_transform) { return {}; }
if (!my_transform) return targets;

sp::ecs::Entity dock_object;
for(auto [entity, bay, transform, physics] : sp::ecs::Query<DockingBay, sp::Transform, sp::Physics>())
for (auto [entity, bay, transform, physics] : sp::ecs::Query<DockingBay, sp::Transform, sp::Physics>())
{
if (entity == my_spaceship) continue;
if (Faction::getRelation(my_spaceship, entity) == FactionRelation::Enemy) continue;
if (port->canDockOn(bay) == DockingStyle::None) continue;
if (glm::length(transform.getPosition() - my_transform->getPosition()) > 1000.0f + physics.getSize().x) continue;

dock_object = entity;
break;
if (glm::length(transform.getPosition() - my_transform->getPosition()) > 1000.0f + std::max(physics.getSize().x, physics.getSize().y)) continue;
targets.push_back(entity);
}
return dock_object;

return targets;
}
26 changes: 17 additions & 9 deletions src/screenComponents/dockingButton.h
Original file line number Diff line number Diff line change
@@ -1,19 +1,27 @@
#ifndef DOCKING_BUTTON_H
#define DOCKING_BUTTON_H
#pragma once

#include "gui/gui2_button.h"
#include "gui/gui2_element.h"
#include "ecs/entity.h"

class GuiDockingButton : public GuiButton
class GuiButton;
class GuiListbox;
class GuiPanel;

// Button/listbox combo to manage docking state and select a docking target.
class GuiDockingButton : public GuiElement
{
public:
GuiDockingButton(GuiContainer* owner, string id);

virtual void onUpdate() override;
virtual void onDraw(sp::RenderTarget& target) override;
private:
void click();
static constexpr float item_height = 50.0f;

sp::ecs::Entity findDockingTarget();
};
GuiPanel* background_panel;
GuiButton* action_button;
GuiListbox* target_list;
std::vector<sp::ecs::Entity> dock_targets;
bool expanded = false;

#endif//DOCKING_BUTTON_H
std::vector<sp::ecs::Entity> findDockingTargets();
};
Loading