Open source Star Ruler 2 source code!
This commit is contained in:
@@ -0,0 +1,326 @@
|
||||
#priority init 10
|
||||
import navigation.scopes;
|
||||
import navigation.SmartCamera;
|
||||
from input import activeCamera;
|
||||
import elements.BaseGuiElement;
|
||||
|
||||
const int TOPBAR_OFFSET = 77;
|
||||
const int SCOPE_SPACING = 4;
|
||||
const int SCOPE_WIDTH = 50;
|
||||
const int SCOPE_HEIGHT = 50;
|
||||
const int SCOPE_PADDING = 2;
|
||||
|
||||
const double SEARCH_INTERVAL = 1.0;
|
||||
const uint MAX_SCOPES = 16;
|
||||
|
||||
Color scopeColor(0xffffff40);
|
||||
Color scopeHoverColor(0x00ff0040);
|
||||
Color scopeActiveColor(0xff000040);
|
||||
Color scopePanningColor(0x0000ff40);
|
||||
string ellipsis = "-";
|
||||
|
||||
const double smartPanSpeed = 10000.0;
|
||||
const double fadeDistanceMin = 10000.0;
|
||||
const double fadeDistanceMax = 16000.0;
|
||||
|
||||
ScopeSearch search;
|
||||
double searchTimer = 0.0;
|
||||
ScopeButton@ panningButton;
|
||||
ScopeButton@[] buttons;
|
||||
bool shown = false;
|
||||
uint displayedScopes = 0;
|
||||
|
||||
void init() {
|
||||
search.maxDistance = 16000.0;
|
||||
|
||||
@panningButton = ScopeButton();
|
||||
panningButton.visible = false;
|
||||
|
||||
buttons.length = MAX_SCOPES;
|
||||
for(uint i = 0; i < MAX_SCOPES; ++i) {
|
||||
@buttons[i] = ScopeButton();
|
||||
buttons[i].visible = false;
|
||||
}
|
||||
}
|
||||
|
||||
void showSmartPan() {
|
||||
shown = true;
|
||||
update();
|
||||
searchTimer = SEARCH_INTERVAL;
|
||||
}
|
||||
|
||||
void hideSmartPan() {
|
||||
shown = false;
|
||||
for(uint i = 0; i < MAX_SCOPES; ++i)
|
||||
buttons[i].visible = false;
|
||||
}
|
||||
|
||||
void toggleSmartPan() {
|
||||
if(shown)
|
||||
hideSmartPan();
|
||||
else
|
||||
showSmartPan();
|
||||
}
|
||||
|
||||
void update() {
|
||||
search.position = activeCamera.lookAt;
|
||||
displayedScopes = searchScopes(search, MAX_SCOPES);
|
||||
|
||||
for(uint i = 0; i < displayedScopes; ++i) {
|
||||
Scope@ scope = search.results[i];
|
||||
|
||||
//Ignore current scope
|
||||
if(search.position.distanceTo(scope.position) < scope.radius
|
||||
|| (panningButton.visible && panningButton.scope is scope)) {
|
||||
buttons[i].visible = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
//Ready the scope button
|
||||
buttons[i].visible = true;
|
||||
buttons[i].set(scope);
|
||||
buttons[i].updatePosition();
|
||||
}
|
||||
|
||||
//Hide extra buttons
|
||||
for(uint i = displayedScopes; i < MAX_SCOPES; ++i)
|
||||
buttons[i].visible = false;
|
||||
}
|
||||
|
||||
void updatePositions() {
|
||||
for(uint i = 0; i < displayedScopes; ++i) {
|
||||
Scope@ scope = buttons[i].scope;
|
||||
if(scope is null || search.position.distanceTo(scope.position) < scope.radius
|
||||
|| (panningButton.visible && panningButton.scope is scope)) {
|
||||
buttons[i].visible = false;
|
||||
}
|
||||
else {
|
||||
buttons[i].visible = true;
|
||||
buttons[i].updatePosition();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool waitForMove = true;
|
||||
int buttonAlpha = 80;
|
||||
void tick(double time) {
|
||||
if(!shown)
|
||||
return;
|
||||
|
||||
//Fade the buttons out at large distances
|
||||
double dist = activeCamera.distance;
|
||||
if(dist > fadeDistanceMin) {
|
||||
if(dist >= fadeDistanceMax) {
|
||||
buttonAlpha = 0;
|
||||
return;
|
||||
}
|
||||
else {
|
||||
buttonAlpha = 80 - ceil(80.0 * (dist - fadeDistanceMin) / (fadeDistanceMax - fadeDistanceMin));
|
||||
}
|
||||
}
|
||||
else {
|
||||
buttonAlpha = 80;
|
||||
}
|
||||
|
||||
//Check if we're panning with a button
|
||||
vec2i mpos = mousePos;
|
||||
if(buttonAlpha > 0 && mpos.x < 6 || mpos.x >= screenSize.width - 6) {
|
||||
if(!waitForMove) {
|
||||
bool found = false;
|
||||
if(panningButton.visible) {
|
||||
if(!panningButton.AbsolutePosition.isWithin(mpos)) {
|
||||
panningButton.visible = false;
|
||||
}
|
||||
else {
|
||||
double tickPan = time * smartPanSpeed;
|
||||
if(activeCamera.panTo(panningButton.scope.position, tickPan)) {
|
||||
panningButton.visible = false;
|
||||
waitForMove = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
for(uint i = 0; i < displayedScopes; ++i) {
|
||||
if(buttons[i].visible && buttons[i].AbsolutePosition.isWithin(mpos)) {
|
||||
buttons[i].visible = false;
|
||||
panningButton.set(buttons[i].scope);
|
||||
panningButton.AbsolutePosition = buttons[i].AbsolutePosition;
|
||||
panningButton.AbsoluteClipRect = buttons[i].AbsoluteClipRect;
|
||||
panningButton.visible = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
panningButton.visible = false;
|
||||
waitForMove = false;
|
||||
}
|
||||
|
||||
//Update the buttons
|
||||
//if(searchTimer <= 0.0) {
|
||||
//searchTimer = SEARCH_INTERVAL;
|
||||
update();
|
||||
//}
|
||||
//else {
|
||||
//updatePositions();
|
||||
//searchTimer -= time;
|
||||
//}
|
||||
}
|
||||
|
||||
class ScopeButton : BaseGuiElement {
|
||||
Scope@ scope;
|
||||
string name;
|
||||
bool left;
|
||||
bool Hovered;
|
||||
bool Pressed;
|
||||
|
||||
ScopeButton() {
|
||||
Hovered = false;
|
||||
Pressed = false;
|
||||
super(null, recti(0, 0, SCOPE_WIDTH, SCOPE_HEIGHT));
|
||||
}
|
||||
|
||||
void updatePosition() {
|
||||
vec3d camPos = activeCamera.lookAt;
|
||||
vec3d scopePos = scope.position;
|
||||
double flatAngle = activeCamera.screenAngle(scopePos);
|
||||
double percentage = 0.0;
|
||||
|
||||
vec2i pos();
|
||||
if(flatAngle >= 0 && flatAngle <= 0.5) {
|
||||
left = false;
|
||||
percentage = 0.5 - flatAngle;
|
||||
}
|
||||
else if(flatAngle > 0.5 && flatAngle <= 1.0) {
|
||||
left = true;
|
||||
percentage = flatAngle - 0.5;
|
||||
}
|
||||
else if(flatAngle < 0 && flatAngle >= -0.5) {
|
||||
left = false;
|
||||
percentage = 0.5 + flatAngle * -1.0;
|
||||
}
|
||||
else if(flatAngle < -0.5 && flatAngle >= -1.0) {
|
||||
left = true;
|
||||
percentage = 1.5 + flatAngle;
|
||||
}
|
||||
|
||||
if(left)
|
||||
pos.x = 0;
|
||||
else
|
||||
pos.x = screenSize.width - size.width;
|
||||
|
||||
pos.y = TOPBAR_OFFSET;
|
||||
pos.y += double(screenSize.height - TOPBAR_OFFSET - SCOPE_HEIGHT) * percentage;
|
||||
|
||||
bool overlap;
|
||||
do {
|
||||
overlap = false;
|
||||
recti box = recti_area(pos, size);
|
||||
if(panningButton.visible && panningButton.AbsolutePosition.overlaps(box)) {
|
||||
overlap = true;
|
||||
pos.y = panningButton.AbsolutePosition.topLeft.y;
|
||||
|
||||
if(percentage < 0.5)
|
||||
pos.y += SCOPE_HEIGHT + SCOPE_SPACING;
|
||||
else
|
||||
pos.y -= SCOPE_HEIGHT + SCOPE_SPACING;
|
||||
continue;
|
||||
}
|
||||
|
||||
for(uint i = 0; i < MAX_SCOPES; ++i) {
|
||||
if(buttons[i] is this)
|
||||
break;
|
||||
if(buttons[i].left == left && buttons[i].AbsolutePosition.overlaps(box)) {
|
||||
overlap = true;
|
||||
pos.y = buttons[i].AbsolutePosition.topLeft.y;
|
||||
|
||||
if(percentage < 0.5)
|
||||
pos.y += SCOPE_HEIGHT + SCOPE_SPACING;
|
||||
else
|
||||
pos.y -= SCOPE_HEIGHT + SCOPE_SPACING;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(pos.y < 0 || pos.y + SCOPE_HEIGHT > screenSize.height) {
|
||||
visible = false;
|
||||
return;
|
||||
}
|
||||
} while(overlap);
|
||||
|
||||
position = pos;
|
||||
}
|
||||
|
||||
void set(Scope@ s) {
|
||||
@scope = s;
|
||||
name = scope.name;
|
||||
}
|
||||
|
||||
void trigger() {
|
||||
activeCamera.zoomTo(scope.position);
|
||||
}
|
||||
|
||||
bool onGuiEvent(const GuiEvent& event) {
|
||||
if(event.caller is this && buttonAlpha > 0) {
|
||||
switch(event.type) {
|
||||
case GUI_Mouse_Entered:
|
||||
Hovered = true;
|
||||
break;
|
||||
case GUI_Mouse_Left:
|
||||
Hovered = false;
|
||||
Pressed = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return BaseGuiElement::onGuiEvent(event);
|
||||
}
|
||||
|
||||
bool onMouseEvent(const MouseEvent& event, IGuiElement@ source) {
|
||||
if(source is this && buttonAlpha > 0) {
|
||||
switch(event.type) {
|
||||
case MET_Button_Down:
|
||||
if(event.button == 0) {
|
||||
Pressed = true;
|
||||
}
|
||||
return true;
|
||||
case MET_Button_Up:
|
||||
if(event.button == 0 && Pressed) {
|
||||
Pressed = false;
|
||||
trigger();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return BaseGuiElement::onMouseEvent(event, source);
|
||||
}
|
||||
|
||||
void draw() {
|
||||
if(buttonAlpha <= 0)
|
||||
return;
|
||||
|
||||
Color col = scopeColor;
|
||||
if(panningButton is this)
|
||||
col = scopePanningColor;
|
||||
else if(Pressed)
|
||||
col = scopeActiveColor;
|
||||
else if(Hovered && !panningButton.visible)
|
||||
col = scopeHoverColor;
|
||||
|
||||
col.a = buttonAlpha;
|
||||
drawRectangle(AbsolutePosition, col);
|
||||
|
||||
const Font@ fnt = skin.getFont(FT_Normal);
|
||||
recti textPos = AbsolutePosition;
|
||||
textPos.topLeft.x += SCOPE_PADDING;
|
||||
textPos.botRight.x -= SCOPE_PADDING;
|
||||
|
||||
int vpadd = (textPos.height - fnt.getLineHeight()) / 2;
|
||||
textPos.topLeft.y += vpadd;
|
||||
textPos.botRight.y -= vpadd;
|
||||
|
||||
fnt.draw(textPos, name, ellipsis);
|
||||
|
||||
BaseGuiElement::draw();
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user