563 lines
15 KiB
ActionScript
563 lines
15 KiB
ActionScript
import tabs.Tab;
|
|
import elements.GuiButton;
|
|
import elements.GuiProgressbar;
|
|
import elements.GuiPanel;
|
|
import elements.GuiMarkupText;
|
|
import elements.GuiEmpire;
|
|
import elements.GuiOverlay;
|
|
import elements.GuiSkinElement;
|
|
import elements.MarkupTooltip;
|
|
import dialogs.QuestionDialog;
|
|
import attitudes;
|
|
import abilities;
|
|
|
|
from overlays.InfoBar import AbilityAction;
|
|
|
|
import tabs.tabbar;
|
|
|
|
class LevelMarker : BaseGuiElement {
|
|
const AttitudeLevel@ lvl;
|
|
Color color;
|
|
bool reached;
|
|
bool hovered = false;
|
|
|
|
LevelMarker(IGuiElement@ parent) {
|
|
super(parent, recti(0,0, 42,70));
|
|
noClip = true;
|
|
auto@ tt = addLazyMarkupTooltip(this, width=300);
|
|
tt.FollowMouse = false;
|
|
tt.offset = vec2i(0, 5);
|
|
}
|
|
|
|
string get_tooltip() {
|
|
string tt;
|
|
tt += format("[font=Medium]$1 $2[/font]\n", locale::LEVEL, toString(lvl.level+1));
|
|
tt += lvl.description;
|
|
return tt;
|
|
}
|
|
|
|
void update(Attitude& att) {
|
|
double finalProgress = att.levels[att.maxLevel].threshold;
|
|
double pct = clamp(lvl.threshold / finalProgress, 0.0, 1.0);
|
|
|
|
reached = att.level >= lvl.level+1;
|
|
position = vec2i(parent.size.x * pct - size.width / 2, 0);
|
|
|
|
if(reached)
|
|
color = Color(0x000000ff).interpolate(att.type.color, 0.4);
|
|
else
|
|
color = Color(0x666666ff);
|
|
}
|
|
|
|
bool onGuiEvent(const GuiEvent& evt) {
|
|
switch(evt.type) {
|
|
case GUI_Mouse_Entered:
|
|
if(evt.caller is this)
|
|
hovered = true;
|
|
break;
|
|
case GUI_Mouse_Left:
|
|
if(evt.caller is this)
|
|
hovered = false;
|
|
break;
|
|
}
|
|
return BaseGuiElement::onGuiEvent(evt);
|
|
}
|
|
|
|
void draw() override {
|
|
if(hovered) {
|
|
drawLine(AbsolutePosition.topLeft + vec2i(size.width/2, 2),
|
|
AbsolutePosition.topLeft + vec2i(size.width/2, size.height-35),
|
|
Color(0xffffff40), 12);
|
|
}
|
|
|
|
drawLine(AbsolutePosition.topLeft + vec2i(size.width/2, 2),
|
|
AbsolutePosition.topLeft + vec2i(size.width/2, size.height),
|
|
Color(0x00000080), 5);
|
|
|
|
drawLine(AbsolutePosition.topLeft + vec2i(size.width/2, 2),
|
|
AbsolutePosition.topLeft + vec2i(size.width/2, size.height),
|
|
color, 3);
|
|
|
|
recti iconPos = recti_area(5,size.height-32, 32,32) + AbsolutePosition.topLeft;
|
|
if(hovered)
|
|
drawRectangle(iconPos.padded(-4), Color(0xffffff40));
|
|
drawRectangle(iconPos.padded(-2), Color(0x00000080));
|
|
drawRectangle(iconPos, color);
|
|
|
|
lvl.icon.draw(iconPos.aspectAligned(lvl.icon.aspect));
|
|
BaseGuiElement::draw();
|
|
}
|
|
};
|
|
|
|
class DiscardConfirm : QuestionDialogCallback {
|
|
const AttitudeType@ type;
|
|
|
|
DiscardConfirm(const AttitudeType@ type) {
|
|
@this.type = type;
|
|
}
|
|
|
|
void questionCallback(QuestionDialog@ dialog, int answer) {
|
|
if(answer == QA_Yes)
|
|
playerEmpire.discardAttitude(type.id);
|
|
}
|
|
};
|
|
|
|
class AttitudeBox : BaseGuiElement {
|
|
Attitude@ att;
|
|
|
|
GuiMarkupText@ title;
|
|
GuiMarkupText@ progressText;
|
|
GuiProgressbar@ bar;
|
|
|
|
array<LevelMarker@> markers;
|
|
array<AbilityAction@> abilities;
|
|
|
|
GuiButton@ discardButton;
|
|
GuiMarkupText@ discardText;
|
|
|
|
AttitudeBox(IGuiElement@ parent) {
|
|
super(parent, recti());
|
|
|
|
@title = GuiMarkupText(this, Alignment(Left+12, Top+8, Right-12, Top+40));
|
|
title.defaultFont = FT_Medium;
|
|
title.defaultStroke = colors::Black;
|
|
|
|
@progressText = GuiMarkupText(this, Alignment(Left+20, Top+36, Right-12, Top+65));
|
|
progressText.defaultColor = Color(0x888888ff);
|
|
progressText.defaultStroke = colors::Black;
|
|
|
|
@bar = GuiProgressbar(this, Alignment(Left+12, Top+65, Right-220, Top+110));
|
|
|
|
@discardButton = GuiButton(this, Alignment(Right-140, Top+3, Right-4, Top+36));
|
|
discardButton.color = colors::Red;
|
|
@discardText = GuiMarkupText(discardButton, Alignment(Left, Top+6, Right, Bottom));
|
|
}
|
|
|
|
bool onGuiEvent(const GuiEvent& event) override {
|
|
if(event.type == GUI_Clicked) {
|
|
if(event.caller is discardButton) {
|
|
auto@ diag = question(format(locale::ATT_CONFIRM_DISCARD, att.type.name),
|
|
locale::DISCARD, locale::CANCEL, DiscardConfirm(att.type));
|
|
diag.titleBox.color = Color(0xff0000ff);
|
|
return true;
|
|
}
|
|
}
|
|
return BaseGuiElement::onGuiEvent(event);
|
|
}
|
|
|
|
void update() {
|
|
if(att is null || att.type is null)
|
|
return;
|
|
updateAbsolutePosition();
|
|
|
|
double curProgress = att.progress;
|
|
double nextProgress = att.levels[att.nextLevel].threshold;
|
|
double finalProgress = att.levels[att.maxLevel].threshold;
|
|
|
|
//Progress data
|
|
if(nextProgress > curProgress) {
|
|
progressText.text = format("[color=#aaa][b]$1 $2:[/b][/color] $3",
|
|
locale::LEVEL, toString(att.nextLevel),
|
|
format(att.type.progress, toString(nextProgress-curProgress, 0)));
|
|
}
|
|
else {
|
|
progressText.text = locale::ATT_MAX_LEVEL;
|
|
}
|
|
|
|
title.text = att.type.name;
|
|
bar.frontColor = att.type.color;
|
|
bar.progress = curProgress / finalProgress;
|
|
|
|
//Level markers
|
|
uint prevCnt = markers.length;
|
|
uint newCnt = att.type.levels.length;
|
|
for(uint i = newCnt; i < prevCnt; ++i)
|
|
markers[i].remove();
|
|
markers.length = newCnt;
|
|
for(uint i = prevCnt; i < newCnt; ++i)
|
|
@markers[i] = LevelMarker(bar);
|
|
|
|
for(uint i = 0; i < newCnt; ++i) {
|
|
@markers[i].lvl = att.type.levels[i];
|
|
markers[i].update(att);
|
|
}
|
|
|
|
//Discarding
|
|
int discardCost = att.getDiscardCost(playerEmpire);
|
|
discardText.text = "[center]"+format(locale::ATT_DISCARD, toString(discardCost))+"[/center]";
|
|
discardButton.disabled = playerEmpire.Influence < discardCost;
|
|
|
|
//Abilities
|
|
prevCnt = abilities.length;
|
|
newCnt = 0;
|
|
|
|
for(uint i = 0, cnt = att.allHookCount; i < cnt; ++i) {
|
|
Ability@ abl;
|
|
if(newCnt < prevCnt)
|
|
@abl = abilities[newCnt].abl;
|
|
@abl = att.allHooks[i].showAbility(att, playerEmpire, abl);
|
|
if(abl !is null) {
|
|
if(newCnt >= prevCnt) {
|
|
AbilityAction act(abl, abl.type.name);
|
|
act.independent = true;
|
|
@act.parent = this;
|
|
abilities.insertLast(act);
|
|
}
|
|
newCnt += 1;
|
|
}
|
|
}
|
|
|
|
for(uint i = newCnt; i < prevCnt; ++i)
|
|
abilities[i].remove();
|
|
|
|
int y = 62;
|
|
if(newCnt > 1)
|
|
y = 40;
|
|
abilities.length = newCnt;
|
|
for(uint i = 0, cnt = abilities.length; i < cnt; ++i) {
|
|
auto@ btn = abilities[i];
|
|
btn.init();
|
|
btn.position = vec2i(size.width-184, y);
|
|
btn.size = vec2i(172, 50);
|
|
y += 50;
|
|
}
|
|
}
|
|
|
|
void addAbility(Ability@ abl, uint& newCnt) {
|
|
}
|
|
|
|
void draw() override {
|
|
if(att is null || att.type is null)
|
|
return;
|
|
skin.draw(SS_EmpireBox, SF_Normal, AbsolutePosition, att.type.color);
|
|
BaseGuiElement::draw();
|
|
}
|
|
};
|
|
|
|
class AttitudesTab : Tab {
|
|
array<AttitudeBox@> boxes;
|
|
array<Attitude> attitudes;
|
|
|
|
GuiButton@ takeButton;
|
|
GuiMarkupText@ takeText;
|
|
|
|
GuiSkinElement@ header;
|
|
GuiEmpire@ portrait;
|
|
GuiMarkupText@ headerText;
|
|
|
|
GuiPanel@ panel;
|
|
|
|
AttitudesTab() {
|
|
super();
|
|
title = locale::ATTITUDES_TAB;
|
|
|
|
@panel = GuiPanel(this, Alignment());
|
|
@takeButton = GuiButton(panel, recti_area(0,0, 280,60));
|
|
@takeText = GuiMarkupText(takeButton, Alignment(Left, Top+15, Right, Bottom));
|
|
takeText.defaultFont = FT_Subtitle;
|
|
|
|
@header = GuiSkinElement(panel, Alignment(Left+0.5f-400, Top+16, Left+0.5f+400, Top+200), SS_Panel);
|
|
@portrait = GuiEmpire(header, Alignment(Left+4, Top+4, Left+180, Bottom-4));
|
|
|
|
@headerText = GuiMarkupText(header, Alignment(Left+188, Top+8, Right-8, Bottom-8));
|
|
headerText.text = locale::ATT_HEADER_DESC;
|
|
updateAbsolutePosition();
|
|
}
|
|
|
|
Color get_activeColor() {
|
|
return Color(0x63ebdbff);
|
|
}
|
|
|
|
Color get_inactiveColor() {
|
|
return Color(0x6dd6caff);
|
|
}
|
|
|
|
Color get_seperatorColor() {
|
|
return Color(0x37837aff);
|
|
}
|
|
|
|
TabCategory get_category() {
|
|
return TC_Attitudes;
|
|
}
|
|
|
|
Sprite get_icon() {
|
|
return Sprite(material::TabAttitude);
|
|
}
|
|
|
|
void tick(double time) override {
|
|
if(!visible)
|
|
return;
|
|
if(playerEmpire is null || !playerEmpire.valid) {
|
|
attitudes.length = 0;
|
|
}
|
|
else {
|
|
attitudes.syncFrom(playerEmpire.getAttitudes());
|
|
@portrait.empire = playerEmpire;
|
|
}
|
|
|
|
uint prevCnt = boxes.length;
|
|
uint newCnt = attitudes.length;
|
|
for(uint i = newCnt; i < prevCnt; ++i)
|
|
boxes[i].remove();
|
|
boxes.length = newCnt;
|
|
for(uint i = prevCnt; i < newCnt; ++i)
|
|
@boxes[i] = AttitudeBox(panel);
|
|
|
|
int y = 216, h = 150;
|
|
for(uint i = 0; i < newCnt; ++i) {
|
|
@boxes[i].att = attitudes[i];
|
|
@boxes[i].alignment = Alignment(Left+0.1f, Top+y, Right-0.1f, Top+y+h);
|
|
boxes[i].update();
|
|
y += h+8;
|
|
}
|
|
|
|
bool haveTakeable = false;
|
|
for(uint i = 0, cnt = getAttitudeTypeCount(); i < cnt; ++i) {
|
|
auto@ att = getAttitudeType(i);
|
|
if(att.canTake(playerEmpire)) {
|
|
haveTakeable = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(haveTakeable) {
|
|
takeButton.visible = true;
|
|
|
|
int extraCost = playerEmpire.getNextAttitudeCost();
|
|
takeButton.position = vec2i((size.width-takeButton.size.width)/2, y+20);
|
|
takeText.text = "[center]"+format(locale::ATT_TAKE_COST, toString(extraCost))+"[/center]";
|
|
}
|
|
else {
|
|
takeButton.visible = false;
|
|
}
|
|
|
|
if(prevCnt != newCnt)
|
|
updateAbsolutePosition();
|
|
}
|
|
|
|
bool onGuiEvent(const GuiEvent& event) {
|
|
if(event.type == GUI_Clicked) {
|
|
if(event.caller is takeButton) {
|
|
TakeAttitudeOverlay(this);
|
|
return true;
|
|
}
|
|
}
|
|
return BaseGuiElement::onGuiEvent(event);
|
|
}
|
|
|
|
void draw() {
|
|
skin.draw(SS_DesignOverviewBG, SF_Normal, AbsolutePosition, Color(0x6dd6caff));
|
|
BaseGuiElement::draw();
|
|
}
|
|
};
|
|
|
|
class GuiFlatButton : GuiButton {
|
|
bool taken = false;
|
|
bool available = false;
|
|
|
|
GuiFlatButton(IGuiElement@ ParentElement, const recti& Rectangle) {
|
|
super(ParentElement, Rectangle);
|
|
updateAbsolutePosition();
|
|
navigable = true;
|
|
style = SS_NULL;
|
|
}
|
|
|
|
void draw() {
|
|
if(!available) {
|
|
if(flags & SF_Active != 0)
|
|
drawRectangle(AbsolutePosition, color.interpolate(Color(0x00000080), 0.6));
|
|
else
|
|
drawRectangle(AbsolutePosition, Color(0x00000040));
|
|
}
|
|
else {
|
|
if(flags & SF_Active != 0)
|
|
drawRectangle(AbsolutePosition, color);
|
|
else
|
|
drawRectangle(AbsolutePosition, Color(0x00000060));
|
|
}
|
|
|
|
if(flags & SF_Hovered != 0)
|
|
drawRectangle(AbsolutePosition, Color(0xffffff20));
|
|
|
|
if(!available) {
|
|
drawLine(AbsolutePosition.topLeft+vec2i(size.width/5, size.height/2+3),
|
|
AbsolutePosition.botRight-vec2i(size.width/5, size.height/2-3),
|
|
Color(0x444444ff), 3);
|
|
}
|
|
|
|
if(taken) {
|
|
vec2i tl = AbsolutePosition.topLeft + vec2i(2,2);
|
|
vec2i br = AbsolutePosition.botRight - vec2i(2,2);
|
|
|
|
drawLine(vec2i(tl.x,tl.y), vec2i(br.x,tl.y), color.interpolate(colors::White, 0.2), 3);
|
|
drawLine(vec2i(tl.x,tl.y), vec2i(tl.x,br.y), color.interpolate(colors::White, 0.2), 3);
|
|
|
|
drawLine(vec2i(br.x,tl.y), vec2i(br.x,br.y), color.interpolate(colors::White, 0.2), 3);
|
|
drawLine(vec2i(tl.x,br.y), vec2i(br.x,br.y), color.interpolate(colors::White, 0.2), 3);
|
|
|
|
|
|
Color acolor = color;
|
|
acolor.a = 0x50;
|
|
drawRectangle(AbsolutePosition, acolor);
|
|
}
|
|
GuiButton::draw();
|
|
}
|
|
}
|
|
|
|
class TakeAttitudeOverlay : GuiOverlay {
|
|
GuiSkinElement@ bg;
|
|
GuiPanel@ leftPanel;
|
|
GuiPanel@ rightPanel;
|
|
GuiMarkupText@ text;
|
|
|
|
array<const AttitudeType@> attitudes;
|
|
array<GuiButton@> buttons;
|
|
const AttitudeType@ selected;
|
|
GuiButton@ takeButton;
|
|
GuiMarkupText@ takeText;
|
|
GuiMarkupText@ takeCaption;
|
|
|
|
TakeAttitudeOverlay(IGuiElement@ parent) {
|
|
super(parent);
|
|
closeSelf = false;
|
|
|
|
for(uint i = 0, cnt = getAttitudeTypeCount(); i < cnt; ++i) {
|
|
auto@ att = getAttitudeType(i);
|
|
/*if(att.canTake(playerEmpire))*/
|
|
attitudes.insertLast(att);
|
|
}
|
|
attitudes.sortAsc();
|
|
|
|
int h = 16 + clamp(attitudes.length/2 * 50, 370, 600) + 50;
|
|
|
|
@bg = GuiSkinElement(this, Alignment(Left+0.5f-425, Top+0.5f-(h/2), Left+0.5f+425, Top+0.5f+(h/2)), SS_Panel);
|
|
@leftPanel = GuiPanel(bg, Alignment(Left, Top, Left+300, Bottom-50));
|
|
@rightPanel = GuiPanel(bg, Alignment(Left+300, Top, Right, Bottom-50));
|
|
@text = GuiMarkupText(rightPanel, recti_area(8,8, 550-16, 100));
|
|
text.flexHeight = true;
|
|
@takeButton = GuiButton(bg, Alignment(Left+0.5f-140, Bottom-50, Left+0.5f+140, Bottom-8));
|
|
@takeText = GuiMarkupText(takeButton, Alignment(Left, Top+10, Right, Bottom));
|
|
@takeCaption = GuiMarkupText(bg, Alignment(Left+0.5f-140, Bottom-40, Left+0.5f+140, Bottom-8));
|
|
takeCaption.defaultFont = FT_Bold;
|
|
takeCaption.defaultColor = Color(0xaa8080ff);
|
|
takeCaption.visible = false;
|
|
|
|
int y = 8;
|
|
uint sel = uint(-1);
|
|
for(uint i = 0, cnt = attitudes.length; i < cnt; ++i) {
|
|
int x = 8;
|
|
if(i%2 != 0)
|
|
x = 150;
|
|
|
|
auto@ att = attitudes[i];
|
|
|
|
GuiFlatButton btn(leftPanel, recti_area(x,y+2, 140, 46));
|
|
btn.toggleButton = true;
|
|
btn.pressed = (i == 0);
|
|
btn.text = att.name;
|
|
btn.color = att.color.interpolate(colors::Black, 0.75);
|
|
|
|
if(playerEmpire.hasAttitude(att.id)) {
|
|
btn.taken = true;
|
|
btn.available = true;
|
|
btn.textColor = colors::White;
|
|
}
|
|
else if(!att.canTake(playerEmpire)) {
|
|
btn.taken = false;
|
|
btn.available = false;
|
|
btn.textColor = Color(0x666666ff);
|
|
}
|
|
else {
|
|
btn.taken = false;
|
|
btn.available = true;
|
|
btn.textColor = colors::White;
|
|
|
|
if(sel == uint(-1))
|
|
sel = i;
|
|
}
|
|
|
|
if(i%2 != 0)
|
|
y += 50;
|
|
|
|
buttons.insertLast(btn);
|
|
}
|
|
|
|
if(sel == uint(-1))
|
|
sel = 0;
|
|
if(attitudes.length != 0)
|
|
select(attitudes[sel]);
|
|
updateAbsolutePosition();
|
|
}
|
|
|
|
void select(const AttitudeType@ type) {
|
|
for(uint j = 0, cnt = buttons.length; j < cnt; ++j)
|
|
buttons[j].pressed = (type is attitudes[j]);
|
|
@selected = type;
|
|
|
|
string desc = format("[font=Medium][color=$1][stroke=#000]$2[/stroke][/color][/font]\n[vspace=6/]",
|
|
toString(type.color.interpolate(colors::White, 0.1)), type.name);
|
|
|
|
for(uint i = 0, cnt = type.levels.length; i < cnt; ++i) {
|
|
auto@ lvl = type.levels[i];
|
|
desc += format("[img=$4;32][color=#aaa][b]$1 $2:[/b][/color] [color=#888]$3[/color]\n",
|
|
locale::LEVEL, toString(i+1),
|
|
format(type.progress, toString(lvl.threshold, 0)),
|
|
getSpriteDesc(lvl.icon));
|
|
desc += "[offset=20]"+lvl.description+"[/offset][/img]";
|
|
desc += "\n[vspace=2/]";
|
|
}
|
|
|
|
takeButton.color = type.color;
|
|
|
|
int extraCost = playerEmpire.getNextAttitudeCost();
|
|
takeText.text = "[center]"+format(locale::ATT_TAKE_ATT, type.name, toString(extraCost))+"[/center]";
|
|
takeButton.disabled = playerEmpire.Influence < extraCost;
|
|
|
|
takeButton.visible = selected.canTake(playerEmpire);
|
|
takeCaption.visible = !takeButton.visible;
|
|
|
|
if(takeCaption.visible) {
|
|
if(playerEmpire.hasAttitude(selected.id))
|
|
takeCaption.text = "[center]"+locale::ATT_HAVE_ATTITUDE+"[/center]";
|
|
else
|
|
takeCaption.text = "[center]"+locale::ATT_CANNOT_ATTITUDE+"[/center]";
|
|
}
|
|
|
|
text.text = desc;
|
|
rightPanel.updateAbsolutePosition();
|
|
}
|
|
|
|
bool onGuiEvent(const GuiEvent& event) override {
|
|
if(event.type == GUI_Clicked) {
|
|
for(uint i = 0, cnt = buttons.length; i < cnt; ++i) {
|
|
if(buttons[i] is event.caller) {
|
|
select(attitudes[i]);
|
|
return true;
|
|
}
|
|
}
|
|
if(event.caller is takeButton) {
|
|
playerEmpire.takeAttitude(selected.id);
|
|
|
|
close();
|
|
return true;
|
|
}
|
|
}
|
|
return GuiOverlay::onGuiEvent(event);
|
|
}
|
|
};
|
|
|
|
Tab@ createAttitudesTab() {
|
|
return AttitudesTab();
|
|
}
|
|
|
|
void resetTabs() {
|
|
for(uint i = 0, cnt = tabs.length; i < cnt; ++i) {
|
|
if(tabs[i].category == TC_Attitudes)
|
|
browseTab(tabs[i], createAttitudesTab());
|
|
}
|
|
}
|
|
|
|
void postReload(Message& msg) {
|
|
resetTabs();
|
|
}
|