Open source Star Ruler 2 source code!
This commit is contained in:
@@ -0,0 +1,619 @@
|
||||
#priority init -200
|
||||
import tabs.Tab;
|
||||
import tabs.tabbar;
|
||||
import elements.GuiButton;
|
||||
import elements.GuiText;
|
||||
import elements.GuiMarkupText;
|
||||
import elements.GuiEmpire;
|
||||
import elements.GuiSkinElement;
|
||||
import elements.GuiListbox;
|
||||
import elements.GuiPanel;
|
||||
import elements.MarkupTooltip;
|
||||
import util.formatting;
|
||||
import icons;
|
||||
from multiplayer import wantSpectator;
|
||||
|
||||
class VictoryTab : Tab {
|
||||
GuiText@ heading;
|
||||
|
||||
GuiSkinElement@ victorPanel;
|
||||
GuiMarkupText@ description;
|
||||
GuiEmpire@ victor;
|
||||
|
||||
GuiSkinElement@ buttonBar;
|
||||
GuiPanel@ buttonPanel;
|
||||
|
||||
GuiButton@ rankingsButton;
|
||||
GuiListbox@ rankings;
|
||||
|
||||
array<StatPage@> stats;
|
||||
array<GuiButton@> statButtons;
|
||||
Alignment@ statAlign;
|
||||
|
||||
Sprite typeIcon;
|
||||
|
||||
VictoryTab() {
|
||||
super();
|
||||
|
||||
@heading = GuiText(this, Alignment(Left, Top+30, Right, Top+90));
|
||||
heading.horizAlign = 0.5;
|
||||
heading.font = FT_Big;
|
||||
heading.color = colors::Green;
|
||||
heading.stroke = colors::Black;
|
||||
|
||||
@victorPanel = GuiSkinElement(this, Alignment(Left+0.1f, Top+90, Right-0.1f, Top+242), SS_Panel);
|
||||
|
||||
@victor = GuiEmpire(victorPanel, Alignment(Left+6, Top+6, Width=140, Height=140));
|
||||
|
||||
@description = GuiMarkupText(victorPanel, Alignment(Left+220, Top+20, Right-6, Bottom-6));
|
||||
description.defaultFont = FT_Subtitle;
|
||||
|
||||
@buttonBar = GuiSkinElement(this, Alignment(Left+0.1f, Top+242+20, Right-0.1f, Height=42), SS_PlainBox);
|
||||
@buttonPanel = GuiPanel(this, Alignment(Left+0.1f, Top+242, Right-0.1f, Height=62));
|
||||
buttonPanel.vertType = ST_Never;
|
||||
|
||||
@statAlign = Alignment(Left+0.1f, Top+242+62, Right-0.1f, Bottom-30);
|
||||
|
||||
if(!playerEmpire.valid) {
|
||||
victorPanel.visible = false;
|
||||
heading.visible = false;
|
||||
buttonBar.alignment.top.pixels = 32;
|
||||
buttonPanel.alignment.top.pixels = 12;
|
||||
statAlign.top.pixels = 74;
|
||||
}
|
||||
|
||||
@rankingsButton = GuiButton(buttonPanel, Alignment(Left, Bottom-40, Width=135, Height=40), locale::V_RANKINGS);
|
||||
rankingsButton.buttonIcon = Sprite(material::PointsIcon);
|
||||
rankingsButton.toggleButton = true;
|
||||
rankingsButton.pressed = true;
|
||||
rankingsButton.font = FT_Bold;
|
||||
@rankings = GuiListbox(this, statAlign);
|
||||
rankings.itemHeight = 40;
|
||||
rankings.disabled = true;
|
||||
rankings.vertPadding = 8;
|
||||
rankings.style = SS_Panel;
|
||||
|
||||
addStat(ST_Int, stat::Points, 60, locale::STAT_POINTS, Sprite(material::PointsIcon), 2000);
|
||||
addStat(ST_Float, stat::Military, 60, locale::STAT_STRENGTH, icons::Strength, 5000);
|
||||
addStat(ST_Int, stat::Planets, 15, locale::STAT_PLANETS, icons::Planet, 10);
|
||||
addStat(ST_Int, stat::Ships, 15, locale::STAT_SHIPS, icons::Defense, 10);
|
||||
addStat(ST_Float, stat::Budget, 60, locale::STAT_BUDGET, icons::Money, 2000);
|
||||
addStat(ST_Float, stat::NetBudget, 60, locale::STAT_NET_BUDGET, icons::Money, 2000);
|
||||
addStat(ST_Float, stat::EnergyIncome, 60, locale::STAT_ENERGY_INCOME, icons::Energy, 2);
|
||||
addStat(ST_Float, stat::InfluenceIncome, 60, locale::STAT_INFLUENCE_INCOME, icons::Influence, 3/60.0);
|
||||
addStat(ST_Float, stat::ResearchIncome, 60, locale::STAT_RESEARCH_INCOME, icons::Research, 2);
|
||||
addStat(ST_Float, stat::ResearchTotal, 60, locale::STAT_RESEARCH_TOTAL, icons::Research, 1000);
|
||||
|
||||
updateAbsolutePosition();
|
||||
update();
|
||||
|
||||
locked = true;
|
||||
}
|
||||
|
||||
void addStat(StatType type, stat::EmpireStat Stat, int FilterDuration, const string& name, const Sprite& icon, double baseMax = 1) {
|
||||
StatPage page(this, statAlign, type, Stat, FilterDuration, name, baseMax);
|
||||
page.visible = false;
|
||||
stats.insertLast(page);
|
||||
|
||||
int index = stats.length;
|
||||
GuiButton btn(buttonPanel, Alignment(Left+135*index, Bottom-40, Width=135, Height=40), name);
|
||||
btn.toggleButton = true;
|
||||
btn.pressed = false;
|
||||
btn.buttonIcon = icon;
|
||||
btn.font = FT_Bold;
|
||||
statButtons.insertLast(btn);
|
||||
}
|
||||
|
||||
Color get_activeColor() {
|
||||
return Color(0xffc283ff);
|
||||
}
|
||||
|
||||
Color get_inactiveColor() {
|
||||
return Color(0xffb900ff);
|
||||
}
|
||||
|
||||
Color get_seperatorColor() {
|
||||
return Color(0x8d7949ff);
|
||||
}
|
||||
|
||||
Sprite get_icon() {
|
||||
return typeIcon;
|
||||
}
|
||||
|
||||
void switchPage(uint page) {
|
||||
rankings.visible = page == 0;
|
||||
rankingsButton.pressed = page == 0;
|
||||
|
||||
for(uint i = 0, cnt = stats.length; i < cnt; ++i) {
|
||||
stats[i].visible = i+1 == page;
|
||||
statButtons[i].pressed = i+1 == page;
|
||||
}
|
||||
}
|
||||
|
||||
void tick(double time) {
|
||||
update();
|
||||
}
|
||||
|
||||
int lastUpdate = systemTime - 1000;
|
||||
bool fullUpdate = true;
|
||||
uint nextUpdateIndex = 0;
|
||||
|
||||
void update() {
|
||||
if(systemTime - lastUpdate < 1000)
|
||||
return;
|
||||
lastUpdate = systemTime;
|
||||
|
||||
Empire@ winner = playerEmpire;
|
||||
int myVictory = playerEmpire.Victory;
|
||||
|
||||
for(uint i = 0, cnt = getEmpireCount(); i < cnt; ++i) {
|
||||
if(getEmpire(i).Victory == 1) {
|
||||
@winner = getEmpire(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//Show the appropriate victory message
|
||||
if(myVictory == 1) {
|
||||
heading.text = locale::V_WON_TITLE;
|
||||
heading.color = colors::Green;
|
||||
description.text = format(locale::V_WON_TEXT, formatEmpireName(winner), formatEmpireName(playerEmpire));
|
||||
typeIcon = Sprite(material::PointsIcon);
|
||||
}
|
||||
else if(myVictory == -2 && playerEmpire.SubjugatedBy.Victory == 1) {
|
||||
heading.text = locale::V_LESSER_TITLE;
|
||||
heading.color = Color(0xfff500ff);
|
||||
description.text = format(locale::V_LESSER_TEXT, formatEmpireName(winner), formatEmpireName(playerEmpire));
|
||||
typeIcon = Sprite(material::PointsIcon);
|
||||
}
|
||||
else {
|
||||
heading.text = locale::V_LOST_TITLE;
|
||||
heading.color = colors::Red;
|
||||
description.text = format(locale::V_LOST_TEXT, formatEmpireName(winner), formatEmpireName(playerEmpire));
|
||||
typeIcon = Sprite(material::SystemUnderAttack);
|
||||
}
|
||||
|
||||
if(victorPanel.visible)
|
||||
title = heading.text;
|
||||
else
|
||||
title = locale::V_SCORES;
|
||||
|
||||
//Update rankings
|
||||
array<EmpSorter> sorted;
|
||||
for(uint i = 0, cnt = getEmpireCount(); i < cnt; ++i) {
|
||||
Empire@ other = getEmpire(i);
|
||||
if(other.major) {
|
||||
EmpSorter sort;
|
||||
@sort.emp = other;
|
||||
sorted.insertLast(sort);
|
||||
}
|
||||
}
|
||||
sorted.sortAsc();
|
||||
|
||||
rankings.clearItems();
|
||||
for(uint i = 0, cnt = sorted.length; i < cnt; ++i) {
|
||||
Empire@ emp = sorted[i].emp;
|
||||
string text = "";
|
||||
|
||||
text += format(" #$1", toString(i+1));
|
||||
text += format("[offset=100][img=$2;28;$3/] $1[/offset]", formatEmpireName(emp),
|
||||
getSpriteDesc(Sprite(emp.flag)), toString(emp.color));
|
||||
|
||||
if(hasGameEnded()) {
|
||||
string victory = "";
|
||||
if(emp.SubjugatedBy !is null)
|
||||
victory = format("[color=#aaa]$1[/color]", format(locale::V_SUBJUGATED, formatEmpireName(emp.SubjugatedBy)));
|
||||
else if(emp.Victory == 1)
|
||||
victory = format("[color=#0f0]$1[/color]", locale::V_WON_TITLE);
|
||||
else
|
||||
victory = format("[color=#f00]$1[/color]", locale::V_LOST_TITLE);
|
||||
text += format("[offset=450]$1[/offset]", victory);
|
||||
}
|
||||
else {
|
||||
string victory;
|
||||
if(emp.SubjugatedBy !is null)
|
||||
victory = format("[color=#aaa]$1[/color]", format(locale::V_SUBJUGATED, formatEmpireName(emp.SubjugatedBy)));
|
||||
text += format("[offset=450]$1[/offset]", victory);
|
||||
}
|
||||
|
||||
text += format("[offset=880]$1[/offset]", format(locale::EMPIRE_POINTS, toString(emp.points.value)));
|
||||
rankings.addItem(GuiMarkupListText(text, FT_Subtitle));
|
||||
}
|
||||
|
||||
//Update stats data
|
||||
if(fullUpdate) {
|
||||
fullUpdate = false;
|
||||
for(uint i = 0, cnt = stats.length; i < cnt; ++i)
|
||||
stats[i].update();
|
||||
}
|
||||
else {
|
||||
//TODO: Even this probably isn't necessary, make sure
|
||||
stats[(nextUpdateIndex++) % stats.length].update();
|
||||
}
|
||||
|
||||
victorPanel.color = winner.color;
|
||||
@victor.empire = winner;
|
||||
|
||||
if(!victorPanel.visible && playerEmpire.valid) {
|
||||
locked = false;
|
||||
shownVictory = false;
|
||||
closeTab(this);
|
||||
}
|
||||
}
|
||||
|
||||
bool onKeyEvent(const KeyboardEvent& event, IGuiElement@ source) {
|
||||
return BaseGuiElement::onKeyEvent(event, source);
|
||||
}
|
||||
|
||||
bool onGuiEvent(const GuiEvent& event) {
|
||||
if(event.type == GUI_Clicked) {
|
||||
if(event.caller is rankingsButton) {
|
||||
switchPage(0);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
for(uint i = 0, cnt = statButtons.length; i < cnt; ++i) {
|
||||
if(event.caller is statButtons[i]) {
|
||||
switchPage(i+1);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return BaseGuiElement::onGuiEvent(event);
|
||||
}
|
||||
|
||||
void draw() {
|
||||
skin.draw(SS_DesignOverviewBG, SF_Normal, AbsolutePosition);
|
||||
BaseGuiElement::draw();
|
||||
}
|
||||
};
|
||||
|
||||
class EmpSorter {
|
||||
Empire@ emp;
|
||||
|
||||
int opCmp(const EmpSorter& other) const {
|
||||
if(other.emp.Victory != emp.Victory) {
|
||||
if(emp.Victory == 1)
|
||||
return -1;
|
||||
if(emp.Victory == -1)
|
||||
return 1;
|
||||
if(other.emp.Victory == 1)
|
||||
return 1;
|
||||
if(other.emp.Victory == -1)
|
||||
return -1;
|
||||
if(emp.Victory == -2) {
|
||||
if(other.emp.Victory == 0)
|
||||
return 1;
|
||||
if(emp.SubjugatedBy.Victory == 1)
|
||||
return -1;
|
||||
}
|
||||
if(other.emp.Victory == -2) {
|
||||
if(emp.Victory == 0)
|
||||
return -1;
|
||||
if(other.emp.SubjugatedBy.Victory == 1)
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
if(emp.points.value > other.emp.points.value)
|
||||
return -1;
|
||||
if(emp.points.value < other.emp.points.value)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
class StatPage : BaseGuiElement {
|
||||
stat::EmpireStat stat;
|
||||
StatType type;
|
||||
array<StatTracker@> trackers;
|
||||
double endTime = 0;
|
||||
double minVal = 0;
|
||||
double maxVal = 0;
|
||||
double baseMin = 0;
|
||||
double baseMax = 1;
|
||||
bool sqrScale = false;
|
||||
|
||||
StatPage(IGuiElement@ parent, Alignment@ align, StatType type, stat::EmpireStat Stat, int FilterDuration, const string& name, double baseMax = 1) {
|
||||
super(parent, align);
|
||||
this.stat = Stat;
|
||||
this.type = type;
|
||||
this.baseMax = baseMax;
|
||||
if(stat == stat::Military) {
|
||||
this.sqrScale = true;
|
||||
this.baseMin = 2000;
|
||||
}
|
||||
for(uint i = 0, cnt = getEmpireCount(); i <cnt; ++i) {
|
||||
Empire@ emp = getEmpire(i);
|
||||
if(emp.major)
|
||||
trackers.insertLast(StatTracker(type, Stat, emp.color, FilterDuration, emp, sqrScale));
|
||||
}
|
||||
|
||||
addLazyMarkupTooltip(this, width=300, update=true);
|
||||
}
|
||||
|
||||
double getOffsetTime(int offset) {
|
||||
return double(offset-52) / double(size.x-64) * endTime;
|
||||
}
|
||||
|
||||
string formatValue(double amt, bool shortForm = false) {
|
||||
if(stat == stat::Budget || stat == stat::NetBudget)
|
||||
return formatMoney(int(amt));
|
||||
if(stat == stat::EnergyIncome || stat == stat::ResearchIncome)
|
||||
return standardize(amt, true)+locale::PER_SECOND;
|
||||
if(stat == stat::InfluenceIncome)
|
||||
return standardize(amt * 60.0, true)+locale::PER_MIN;
|
||||
if(type == ST_Int) {
|
||||
if(shortForm && amt >= 1000)
|
||||
return standardize(amt, true);
|
||||
else
|
||||
return toString(floor(amt), 0);
|
||||
}
|
||||
return standardize(amt, true);
|
||||
}
|
||||
|
||||
string get_tooltip() override {
|
||||
int mx = mousePos.x;
|
||||
if(mx < AbsolutePosition.topLeft.x+52 || mx > AbsolutePosition.botRight.x-12)
|
||||
return "";
|
||||
string text;
|
||||
double time = getOffsetTime(mx - absolutePosition.topLeft.x);
|
||||
text += format("[center][font=Subtitle]$1[/font][/center]", formatGameTime(time));
|
||||
for(uint i = 0, cnt = trackers.length; i < cnt; ++i) {
|
||||
double amt = trackers[i].getClosest(time).y;
|
||||
text += format("[b]$1[offset=150]$2[/offset][/b]\n",
|
||||
formatEmpireName(trackers[i].emp),
|
||||
formatValue(amt));
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
void update() {
|
||||
endTime = gameTime;
|
||||
minVal = baseMin; maxVal = baseMax;
|
||||
for(uint i = 0, cnt = trackers.length; i < cnt; ++i) {
|
||||
trackers[i].update();
|
||||
minVal = min(minVal, trackers[i].minVal);
|
||||
maxVal = max(maxVal, trackers[i].maxVal);
|
||||
}
|
||||
for(uint i = 0, cnt = trackers.length; i < cnt; ++i) {
|
||||
trackers[i].minVal = minVal;
|
||||
trackers[i].maxVal = maxVal;
|
||||
}
|
||||
}
|
||||
|
||||
void draw() {
|
||||
skin.draw(SS_Panel, SF_Normal, AbsolutePosition);
|
||||
|
||||
const Font@ ft = skin.getFont(FT_Normal);
|
||||
|
||||
{
|
||||
int interval = 100;
|
||||
vec2i pos(154, size.height-15);
|
||||
while(pos.x < size.x) {
|
||||
double time = double(pos.x-52) / double(size.x-64) * endTime;
|
||||
ft.draw(pos=recti_centered(pos+AbsolutePosition.topLeft, vec2i(200,30)),
|
||||
horizAlign=0.5, text=formatTime(time), color=Color(0xaaaaaaff));
|
||||
drawLine(vec2i(pos.x, 12)+AbsolutePosition.topLeft,
|
||||
vec2i(pos.x, size.height-40)+AbsolutePosition.topLeft,
|
||||
Color(0xaaaaaa20));
|
||||
pos.x += interval;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
int interval = 40;
|
||||
vec2i pos(26, size.height-40);
|
||||
string prevVal;
|
||||
if(type == ST_Int) {
|
||||
double mult = ceil(double(size.height-52) / ceil(maxVal-minVal));
|
||||
interval = ceil(ceil(double(interval) / mult) * mult);
|
||||
}
|
||||
while(pos.y > 14) {
|
||||
double val = 0;
|
||||
if(sqrScale)
|
||||
val = minVal + (maxVal - minVal) * sqr(1.0 - (double(pos.y-12) / double(size.y-52)));
|
||||
else
|
||||
val = minVal + (maxVal - minVal) * (1.0 - (double(pos.y-12) / double(size.y-52)));
|
||||
string valDisp = formatValue(val, true);
|
||||
if(valDisp != prevVal) {
|
||||
ft.draw(pos=recti_centered(pos+AbsolutePosition.topLeft, vec2i(200,30)),
|
||||
horizAlign=0.5, text=valDisp, color=Color(0xaaaaaaff));
|
||||
prevVal = valDisp;
|
||||
}
|
||||
drawLine(vec2i(42, pos.y)+AbsolutePosition.topLeft,
|
||||
vec2i(size.width-12, pos.y)+AbsolutePosition.topLeft,
|
||||
Color(0xaaaaaa20));
|
||||
pos.y -= interval;
|
||||
}
|
||||
|
||||
if(minVal < 0 && maxVal > 0 && !sqrScale) {
|
||||
int y = size.height-40 - size.y * (-minVal) / (maxVal - minVal);
|
||||
drawLine(vec2i(42, y)+AbsolutePosition.topLeft,
|
||||
vec2i(size.width-12, y)+AbsolutePosition.topLeft,
|
||||
Color(0xaa000040), size=3);
|
||||
}
|
||||
}
|
||||
|
||||
for(uint i = 0, cnt = trackers.length; i < cnt; ++i)
|
||||
trackers[i].draw(skin, AbsolutePosition.padded(42,12,12,40));
|
||||
|
||||
if(AbsolutePosition.isWithin(mousePos)) {
|
||||
int mx = mousePos.x;
|
||||
if(mx >= AbsolutePosition.topLeft.x+52 && mx <= AbsolutePosition.botRight.x-12) {
|
||||
drawLine(vec2i(mx, AbsolutePosition.topLeft.y+12),
|
||||
vec2i(mx, AbsolutePosition.botRight.y-40),
|
||||
Color(0xaaaaaaff));
|
||||
}
|
||||
}
|
||||
|
||||
BaseGuiElement::draw();
|
||||
}
|
||||
};
|
||||
|
||||
enum StatType {
|
||||
ST_Int,
|
||||
ST_Float,
|
||||
}
|
||||
|
||||
final class StatTracker {
|
||||
double minVal = 0, maxVal = 1;
|
||||
stat::EmpireStat stat;
|
||||
Color color;
|
||||
int filterDuration = 1;
|
||||
array<vec2d> data;
|
||||
Empire@ emp;
|
||||
StatType type;
|
||||
double endTime;
|
||||
bool sqrScale = false;
|
||||
|
||||
array<vec2i> points;
|
||||
vec2i lastSize;
|
||||
|
||||
StatTracker(StatType type, stat::EmpireStat Stat, const Color& col, int FilterDuration, Empire@ emp = playerEmpire, bool sqrScale = false) {
|
||||
stat = Stat;
|
||||
color = col;
|
||||
filterDuration = FilterDuration;
|
||||
this.type = type;
|
||||
@this.emp = emp;
|
||||
this.sqrScale = sqrScale;
|
||||
}
|
||||
|
||||
vec2d getClosest(double time) {
|
||||
vec2d closest(0, 0);
|
||||
double dist = INFINITY;
|
||||
//Don't make me do a binary search you monster
|
||||
for(uint i = 0, cnt = data.length; i < cnt; ++i) {
|
||||
double d = abs(data[i].x - time);
|
||||
if(d < dist) {
|
||||
dist = d;
|
||||
closest = data[i];
|
||||
}
|
||||
}
|
||||
return closest;
|
||||
}
|
||||
|
||||
void rebuildPoints(vec2i size) {
|
||||
array<vec3d> pts(1);
|
||||
|
||||
vec2d factor(double(size.x) / endTime, -double(size.y) / (maxVal - minVal));
|
||||
vec2d offset(0.0, -minVal);
|
||||
|
||||
uint lastX = 0;
|
||||
for(uint i = 0, cnt = data.length; i < cnt; ++i) {
|
||||
vec2d pt = data[i] + offset;
|
||||
pt.x *= factor.x;
|
||||
|
||||
if(!sqrScale) {
|
||||
pt.y *= factor.y;
|
||||
}
|
||||
else {
|
||||
if(pt.y != 0)
|
||||
pt.y = -double(size.y) * sqrt(pt.y / (maxVal - minVal));
|
||||
}
|
||||
|
||||
uint x = int(pt.x);
|
||||
if(i == 0 && x != 0)
|
||||
pts[0] = vec3d(0.0, pt.y, 1.0);
|
||||
|
||||
if(x != lastX)
|
||||
pts.resize(pts.length + 1);
|
||||
pts[pts.length-1] += vec3d(pt.x, pt.y, 1.0);
|
||||
}
|
||||
|
||||
int maxTimeDelta = max(int(ceil(double(size.x * filterDuration) / endTime)), int(1));
|
||||
|
||||
points.length = 0;
|
||||
points.reserve(pts.length + 1);
|
||||
for(uint i = 0, cnt = pts.length; i < cnt; ++i) {
|
||||
vec3d pt = pts[i];
|
||||
vec2i px = vec2i(pt.x / pt.z, pt.y / pt.z + 0.5);
|
||||
if(i > 0) {
|
||||
vec2i prev = points.last;
|
||||
if(prev.x < px.x - maxTimeDelta)
|
||||
points.insertLast(vec2i(px.x - 1, prev.y));
|
||||
}
|
||||
points.insertLast(px);
|
||||
}
|
||||
|
||||
if(points.last.x < size.x - 1)
|
||||
points.insertLast(vec2i(size.x - 1, points.last.y));
|
||||
|
||||
lastSize = size;
|
||||
}
|
||||
|
||||
void update() {
|
||||
minVal = INFINITY;
|
||||
maxVal = -INFINITY;
|
||||
data.length = 0;
|
||||
|
||||
StatHistory history(emp, stat);
|
||||
endTime = gameTime;
|
||||
|
||||
while(history.advance(1)) {
|
||||
double val = 0;
|
||||
if(type == ST_Int)
|
||||
val = history.intVal;
|
||||
else
|
||||
val = history.floatVal;
|
||||
|
||||
if(val > maxVal)
|
||||
maxVal = val;
|
||||
if(val < minVal)
|
||||
minVal = val;
|
||||
|
||||
data.insertLast(vec2d(history.time, val));
|
||||
}
|
||||
|
||||
lastSize = vec2i();
|
||||
}
|
||||
|
||||
void draw(const Skin@ skin, recti bound) {
|
||||
vec2i size = bound.size;
|
||||
if(size != lastSize)
|
||||
rebuildPoints(size);
|
||||
|
||||
if(points.length == 0) {
|
||||
drawLine(bound.topLeft + vec2i(0, bound.height), bound.botRight, color);
|
||||
return;
|
||||
}
|
||||
|
||||
vec2i corner = bound.topLeft + vec2i(0,size.y);
|
||||
vec2i prev = points[0] + corner;
|
||||
|
||||
uint lines = points.length - 1;
|
||||
uint index = 0;
|
||||
while(index < lines) {
|
||||
drawPolygonStart(PT_LineStrip, min(lines - index, 250));
|
||||
drawPolygonPoint(prev, color);
|
||||
for(uint i = 0; i < 250 && index + i < lines; ++i) {
|
||||
vec2i pt = points[index + i + 1] + corner;
|
||||
drawPolygonPoint(pt);
|
||||
prev = pt;
|
||||
}
|
||||
drawPolygonEnd();
|
||||
index += 250;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Tab@ createVictoryTab() {
|
||||
return VictoryTab();
|
||||
}
|
||||
|
||||
void init() {
|
||||
/*auto@ tab = createVictoryTab();*/
|
||||
/*newTab(tab);*/
|
||||
/*switchToTab(tab);*/
|
||||
}
|
||||
|
||||
bool shownVictory = false;
|
||||
void tick(double time) {
|
||||
if(!shownVictory && (hasGameEnded() || (wantSpectator && !playerEmpire.valid))) {
|
||||
auto@ tab = createVictoryTab();
|
||||
newTab(tab);
|
||||
if(hasGameEnded())
|
||||
switchToTab(tab);
|
||||
shownVictory = true;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user