2066 lines
54 KiB
ActionScript
2066 lines
54 KiB
ActionScript
import tabs.Tab;
|
|
import elements.GuiEmpire;
|
|
import elements.GuiPanel;
|
|
import elements.GuiText;
|
|
import elements.GuiSkinElement;
|
|
import elements.GuiMarkupText;
|
|
import elements.GuiImage;
|
|
import elements.GuiSprite;
|
|
import elements.GuiContextMenu;
|
|
import elements.GuiBackgroundPanel;
|
|
import elements.GuiCheckbox;
|
|
import elements.GuiTextbox;
|
|
import elements.GuiInfluenceCard;
|
|
import elements.GuiProgressbar;
|
|
import elements.GuiIconGrid;
|
|
import elements.GuiSprite;
|
|
import elements.MarkupTooltip;
|
|
import elements.GuiOfferList;
|
|
import dialogs.QuestionDialog;
|
|
import dialogs.InputDialog;
|
|
import util.formatting;
|
|
import systems;
|
|
import resources;
|
|
import influence;
|
|
import traits;
|
|
from gui import animate_time, animate_retarget;
|
|
import void zoomTo(Object@) from "tabs.GalaxyTab";
|
|
|
|
from tabs.tabbar import ActiveTab, browseTab, newTab, switchToTab, findTab;
|
|
from tabs.InfluenceVoteTab import createInfluenceVoteTab, InfluenceVoteTab;
|
|
from tabs.InfluenceHistoryTab import createInfluenceHistoryTab;
|
|
|
|
const int INFLUENCE_BOX_WIDTH = 100;
|
|
const int EMPIRE_BOX_WIDTH = 400;
|
|
const int EMPIRE_BOX_SPACING = 12;
|
|
const int MIN_SUB_HEIGHT = 100;
|
|
|
|
const double CARD_ANIM_TIME = 1.0;
|
|
const double CARD_ANIM_REMOVE_TIME = 0.4;
|
|
|
|
const double INFLUENCE_UPDATE_TIMER = 0.2;
|
|
const double WAR_UPDATE_TIMER = 0.2;
|
|
const double RANKS_UPDATE_TIMER = 0.2;
|
|
const double VOTES_UPDATE_TIMER = 0.2;
|
|
const double EFFECTS_UPDATE_TIMER = 0.2;
|
|
const double TREATIES_UPDATE_TIMER = 0.6;
|
|
const double CARDS_UPDATE_TIMER = 0.5;
|
|
|
|
class DiplomacyTab : Tab {
|
|
GuiPanel@ panel;
|
|
GuiSkinElement@ playerPanel;
|
|
GuiSkinElement@ playerHeading;
|
|
GuiEmpire@ playerIcon;
|
|
GuiSprite@ leaderIcon;
|
|
GuiText@ playerName;
|
|
GuiSprite@ playerFlag;
|
|
|
|
GuiSprite@ strIcon;
|
|
GuiText@ strText;
|
|
|
|
GuiSprite@ plIcon;
|
|
GuiText@ plText;
|
|
|
|
GuiSprite@ ptsIcon;
|
|
GuiText@ ptsText;
|
|
|
|
GuiSprite@ infIcon;
|
|
GuiText@ infText;
|
|
|
|
GuiButton@ electButton;
|
|
GuiButton@ unifyButton;
|
|
GuiButton@ actionButton;
|
|
|
|
BaseGuiElement@ empirePanel;
|
|
EmpireBox@[] empires;
|
|
GuiText@ noEmpireText;
|
|
|
|
GuiProgressbar@ drawProgress;
|
|
GuiBackgroundPanel@ stackBG;
|
|
BaseGuiElement@ stackPanel;
|
|
array<InfluenceCard@> cardStack;
|
|
array<StackCard@> stackBoxes;
|
|
|
|
GuiBackgroundPanel@ cardBG;
|
|
BaseGuiElement@ cardPanel;
|
|
array<InfluenceCard@> cards;
|
|
array<GuiInfluenceCard@> cardBoxes;
|
|
|
|
GuiBackgroundPanel@ voteBG;
|
|
GuiButton@ historyButton;
|
|
BaseGuiElement@ votePanel;
|
|
GuiText@ noVotesText;
|
|
|
|
InfluenceVote[] votes;
|
|
VoteBox@[] voteBoxes;
|
|
|
|
GuiBackgroundPanel@ effectBG;
|
|
BaseGuiElement@ effectPanel;
|
|
GuiText@ noEffectsText;
|
|
|
|
InfluenceEffect[] effects;
|
|
EffectBox@[] effectBoxes;
|
|
|
|
GuiBackgroundPanel@ treatyBG;
|
|
BaseGuiElement@ treatyPanel;
|
|
GuiText@ noTreatyText;
|
|
TreatyBox@[] treatyBoxes;
|
|
|
|
Treaty[] treaties;
|
|
|
|
double influenceUpdate = 0.0;
|
|
double warUpdate = 0.0;
|
|
double ranksUpdate = 0.0;
|
|
double votesUpdate = 0.0;
|
|
double effectsUpdate = 0.0;
|
|
double cardsUpdate = 0.0;
|
|
double treatiesUpdate = 0.0;
|
|
uint seenVote = 0;
|
|
|
|
double drawInterval = 0.0;
|
|
double drawTimer = 0.0;
|
|
|
|
DiplomacyTab() {
|
|
super();
|
|
title = locale::DIPLOMACY;
|
|
@panel = GuiPanel(this, Alignment_Fill());
|
|
panel.horizType = ST_Never;
|
|
drawInterval = getInfluenceDrawInterval();
|
|
|
|
//Player empire
|
|
@playerPanel = GuiSkinElement(panel, recti(12, 12, 612, 160), SS_PlayerEmpireBox);
|
|
@playerFlag = GuiSprite(playerPanel, Alignment().padded(24));
|
|
playerFlag.horizAlign = 1.0;
|
|
|
|
@playerIcon = GuiEmpire(playerPanel, recti(8, 8, 140, 140));
|
|
@playerHeading = GuiSkinElement(playerPanel, recti(), SS_CenterTitle);
|
|
@playerName = GuiText(playerPanel, recti(0, 2, 612, 26));
|
|
playerName.horizAlign = 0.5;
|
|
playerName.font = FT_Bold;
|
|
|
|
@leaderIcon = GuiSprite(playerIcon, Alignment(Left, Bottom-52, Left+52, Bottom));
|
|
leaderIcon.desc = Sprite(material::LeaderIcon);
|
|
setMarkupTooltip(leaderIcon, locale::TT_SENATE_LEADER);
|
|
leaderIcon.visible = false;
|
|
|
|
@infIcon = GuiSprite(playerPanel, recti(148, 34, 198, 64));
|
|
infIcon.desc = Sprite(material::PoliticalStrengthIcon);
|
|
@infText = GuiText(playerPanel, recti(204, 34, 318, 64));
|
|
infText.color = Color(0xccccccff);
|
|
|
|
@strIcon = GuiSprite(playerPanel, recti(148, 68, 198, 98));
|
|
strIcon.desc = Sprite(material::MilitaryStrengthIcon);
|
|
@strText = GuiText(playerPanel, recti(204, 68, 318, 98));
|
|
strText.color = Color(0xccccccff);
|
|
|
|
@plIcon = GuiSprite(playerPanel, recti(148, 102, 198, 132));
|
|
plIcon.desc = Sprite(material::TerritoryStrengthIcon);
|
|
@plText = GuiText(playerPanel, recti(204, 102, 318, 132));
|
|
plText.color = Color(0xccccccff);
|
|
|
|
@ptsIcon = GuiSprite(playerPanel, recti(328, 34, 358, 64));
|
|
ptsIcon.desc = Sprite(material::PointsIcon);
|
|
@ptsText = GuiText(playerPanel, recti(364, 34, 590, 64));
|
|
ptsText.color = Color(0xccccccff);
|
|
|
|
@electButton = GuiButton(playerPanel, recti(328, 69, 588, 97));
|
|
electButton.visible = false;
|
|
@unifyButton = GuiButton(playerPanel, recti(328, 69, 588, 97));
|
|
unifyButton.visible = false;
|
|
|
|
@actionButton = GuiButton(playerPanel, recti(328, 103, 588, 131));
|
|
GuiSprite(actionButton, Alignment(Left+0.5f-11, Top+3, Left+0.5f+11, Bottom-3),
|
|
Sprite(material::DownIcon));
|
|
actionButton.visible = false;
|
|
|
|
@empirePanel = BaseGuiElement(panel, recti(0, 0, 500, 100));
|
|
|
|
@noEmpireText = GuiText(panel, Alignment(Left+12, Top+220, Right-12, Top+260));
|
|
noEmpireText.text = locale::NO_MET_EMPIRES;
|
|
noEmpireText.font = FT_Subtitle;
|
|
noEmpireText.color = Color(0xaaaaaaff);
|
|
noEmpireText.stroke = colors::Black;
|
|
noEmpireText.horizAlign = 0.5;
|
|
noEmpireText.visible = false;
|
|
|
|
//Card stack
|
|
@stackBG = GuiBackgroundPanel(panel, recti());
|
|
stackBG.title = locale::CARD_STACK;
|
|
stackBG.titleColor = Color(0x53feb3ff);
|
|
stackBG.picture = Sprite(material::DiplomacyActions);
|
|
|
|
@drawProgress = GuiProgressbar(stackBG, Alignment(Right-185, Top+3, Right-5, Top+28), 0.f);
|
|
drawProgress.frontColor = Color(0x20adffff);
|
|
|
|
@stackPanel = BaseGuiElement(stackBG, recti(8, 34, 100, 100));
|
|
|
|
//Card list
|
|
@cardBG = GuiBackgroundPanel(panel, recti());
|
|
cardBG.title = locale::AVAILABLE_CARDS;
|
|
cardBG.titleColor = Color(0xb3fe00ff);
|
|
cardBG.picture = Sprite(material::DiplomacyActions);
|
|
|
|
@cardPanel = BaseGuiElement(cardBG, recti(8, 34, 100, 100));
|
|
|
|
//Vote list
|
|
@voteBG = GuiBackgroundPanel(panel, recti());
|
|
voteBG.title = locale::ACTIVE_VOTES;
|
|
voteBG.titleColor = Color(0x00bffeff);
|
|
voteBG.picture = Sprite(material::Propositions);
|
|
|
|
@historyButton = GuiButton(voteBG, Alignment(Right-185, Top+3, Right-5, Top+28), locale::VIEW_VOTE_HISTORY);
|
|
historyButton.color = Color(0x9be5feff);
|
|
|
|
@votePanel = BaseGuiElement(voteBG, recti(8, 34, 100, 100));
|
|
@noVotesText = GuiText(votePanel, recti(4, 4, 400, 24), locale::NO_VOTES);
|
|
noVotesText.color = Color(0xaaaaaaff);
|
|
|
|
//Effect list
|
|
@effectBG = GuiBackgroundPanel(panel, recti());
|
|
effectBG.title = locale::ACTIVE_INFLUENCE_EFFECTS;
|
|
effectBG.titleColor = Color(0xfe8300ff);
|
|
effectBG.picture = Sprite(material::ActiveEffects);
|
|
|
|
@effectPanel = BaseGuiElement(effectBG, recti(8, 34, 100, 100));
|
|
@noEffectsText = GuiText(effectPanel, recti(4, 4, 400, 24), locale::NO_EFFECTS);
|
|
noEffectsText.color = Color(0xaaaaaaff);
|
|
|
|
//Treaty list
|
|
@treatyBG = GuiBackgroundPanel(panel, recti());
|
|
treatyBG.title = locale::ACTIVE_TREATIES;
|
|
treatyBG.titleColor = Color(0x7300feff);
|
|
treatyBG.picture = Sprite(material::StatusPeace);
|
|
|
|
@treatyPanel = BaseGuiElement(treatyBG, recti(8, 34, 400, 100));
|
|
@noTreatyText = GuiText(treatyPanel, recti(4, 4, 400, 24), locale::NO_TREATIES);
|
|
noTreatyText.color = Color(0xaaaaaaff);
|
|
|
|
changeEmpire(playerEmpire);
|
|
}
|
|
|
|
int prevContact = 0;
|
|
void tick(double time) {
|
|
if(visible) {
|
|
influenceUpdate -= time;
|
|
if(influenceUpdate <= 0) {
|
|
updateInfluence();
|
|
influenceUpdate += INFLUENCE_UPDATE_TIMER;
|
|
}
|
|
|
|
ranksUpdate -= time;
|
|
if(ranksUpdate <= 0) {
|
|
updateRanks();
|
|
ranksUpdate += RANKS_UPDATE_TIMER;
|
|
}
|
|
|
|
treatiesUpdate -= time;
|
|
if(treatiesUpdate <= 0) {
|
|
updateTreaties();
|
|
treatiesUpdate += TREATIES_UPDATE_TIMER;
|
|
}
|
|
|
|
effectsUpdate -= time;
|
|
if(effectsUpdate <= 0) {
|
|
updateEffects();
|
|
effectsUpdate += EFFECTS_UPDATE_TIMER;
|
|
}
|
|
|
|
cardsUpdate -= time;
|
|
if(cardsUpdate <= 0) {
|
|
updateCards();
|
|
cardsUpdate += CARDS_UPDATE_TIMER;
|
|
}
|
|
|
|
playerPanel.visible = playerEmpire !is null && playerEmpire.valid;
|
|
}
|
|
|
|
int newContact = playerEmpire.ContactMask.value;
|
|
if(playerEmpire !is playerIcon.empire
|
|
|| newContact != prevContact) {
|
|
changeEmpire(playerEmpire);
|
|
prevContact = newContact;
|
|
}
|
|
|
|
warUpdate -= time;
|
|
if(warUpdate <= 0) {
|
|
updateWar();
|
|
warUpdate += WAR_UPDATE_TIMER;
|
|
}
|
|
|
|
votesUpdate -= time;
|
|
if(votesUpdate <= 0) {
|
|
updateVotes();
|
|
votesUpdate += VOTES_UPDATE_TIMER;
|
|
}
|
|
}
|
|
|
|
void show() {
|
|
updateInfluence();
|
|
updateRanks();
|
|
updateEffects();
|
|
updateWar();
|
|
updateVotes();
|
|
updateCards(true);
|
|
|
|
Tab::show();
|
|
}
|
|
|
|
void changeEmpire(Empire@ emp) {
|
|
@playerIcon.empire = emp;
|
|
playerName.text = emp.name;
|
|
playerName.color = emp.color;
|
|
playerHeading.color = emp.color;
|
|
playerPanel.color = emp.color;
|
|
|
|
playerFlag.desc = Sprite(playerEmpire.flag);
|
|
playerFlag.color = playerEmpire.color;
|
|
playerFlag.color.a = 0x30;
|
|
|
|
int needed = playerName.getTextDimension().width + 140;
|
|
playerHeading.size = vec2i(needed, 26);
|
|
playerHeading.position = vec2i((playerPanel.size.width-needed)/2, 1);
|
|
|
|
updateEmpires();
|
|
|
|
uint traitCnt = emp.traitCount;
|
|
string tt = format("[color=$2][font=Subtitle]$1[/font][/color]", emp.name, toString(emp.color));
|
|
for(uint i = 0; i < traitCnt; ++i) {
|
|
if(tt.length != 0)
|
|
tt += "\n\n";
|
|
auto@ trait = getTrait(emp.getTraitType(i));
|
|
if(trait !is null)
|
|
tt += format("[color=$1][b]$2[/b][/color]\n$3",
|
|
toString(trait.color), trait.name, trait.description);
|
|
}
|
|
setMarkupTooltip(playerIcon, tt, width=400);
|
|
}
|
|
|
|
void updateEmpires() {
|
|
for(uint i = 0, cnt = empires.length; i < cnt; ++i)
|
|
if(empires[i] !is null)
|
|
empires[i].remove();
|
|
empires.length = 0;
|
|
|
|
//Create boxes
|
|
uint empCnt = getEmpireCount();
|
|
for(uint i = 0; i < empCnt; ++i) {
|
|
Empire@ emp = getEmpire(i);
|
|
if(emp is playerEmpire)
|
|
continue;
|
|
if(!emp.major || !emp.valid)
|
|
continue;
|
|
if(playerEmpire.valid && playerEmpire.ContactMask.value & emp.mask == 0)
|
|
continue;
|
|
|
|
//Empire box
|
|
EmpireBox box(this);
|
|
box.set(emp);
|
|
empires.insertLast(box);
|
|
}
|
|
|
|
noEmpireText.visible = empires.length == 0;
|
|
updateAbsolutePosition();
|
|
}
|
|
|
|
void updateInfluence() {
|
|
leaderIcon.visible = getSenateLeader() is playerEmpire;
|
|
|
|
/*electButton.text = formatInfluenceCost(locale::ELECT_VOTE, getElectCost(playerEmpire));*/
|
|
/*unifyButton.text = formatInfluenceCost(locale::UNIFY_VOTE, getUnifyCost(playerEmpire));*/
|
|
|
|
int influence = playerEmpire.Influence;
|
|
/*electButton.disabled = getElectCost(playerEmpire) > influence;*/
|
|
/*unifyButton.disabled = getUnifyCost(playerEmpire) > influence;*/
|
|
|
|
/*electButton.visible = !leaderIcon.visible;*/
|
|
/*unifyButton.visible = leaderIcon.visible;*/
|
|
}
|
|
|
|
void updateRanks() {
|
|
infText.text = format(locale::EMPIRE_INFLUENCE, toString(playerEmpire.Influence));
|
|
ptsText.text = format(locale::EMPIRE_POINTS, toString(playerEmpire.points.value));
|
|
strText.text = format(locale::EMPIRE_STRENGTH, standardize(sqr(playerEmpire.TotalMilitary) * 0.001, true));
|
|
plText.text = format(locale::EMPIRE_PLANETS, toString(playerEmpire.TotalPlanets.value));
|
|
|
|
setStrengthIcon(infIcon, playerEmpire.PoliticalStrength, locale::POLITICAL_STRENGTH);
|
|
setStrengthIcon(strIcon, playerEmpire.MilitaryStrength, locale::MILITARY_STRENGTH);
|
|
setStrengthIcon(plIcon, playerEmpire.EmpireStrength, locale::TERRITORY_STRENGTH);
|
|
|
|
for(uint i = 0, cnt = empires.length; i < cnt; ++i) {
|
|
EmpireBox@ box = empires[i];
|
|
Empire@ other = box.emp;
|
|
|
|
box.setPoints(other.points.value);
|
|
setStrengthIcon(box.politicalIcon, other.PoliticalStrength, locale::POLITICAL_STRENGTH);
|
|
setStrengthIcon(box.militaryIcon, other.MilitaryStrength, locale::MILITARY_STRENGTH);
|
|
setStrengthIcon(box.territoryIcon, other.EmpireStrength, locale::TERRITORY_STRENGTH);
|
|
}
|
|
}
|
|
|
|
void updateWar() {
|
|
for(uint i = 0, cnt = empires.length; i < cnt; ++i) {
|
|
EmpireBox@ box = empires[i];
|
|
Empire@ other = box.emp;
|
|
|
|
WarState prevState = box.state;
|
|
WarState state = WS_Peace;
|
|
if(playerEmpire.isHostile(other))
|
|
state = WS_War;
|
|
else if(isForcedPeace(playerEmpire, other))
|
|
state = WS_Peace_Forced;
|
|
|
|
box.setState(state);
|
|
box.update();
|
|
|
|
//Flash if the state was changed
|
|
if(state != prevState)
|
|
flash();
|
|
}
|
|
}
|
|
|
|
void updateVotes() {
|
|
votes.syncFrom(getActiveInfluenceVotes());
|
|
|
|
uint oldCnt = voteBoxes.length;
|
|
uint newCnt = votes.length;
|
|
|
|
if(oldCnt != newCnt) {
|
|
//Flash when vote count changes
|
|
flash();
|
|
|
|
//Put amount of active votes in title
|
|
if(newCnt == 0)
|
|
title = locale::DIPLOMACY;
|
|
else
|
|
title = locale::DIPLOMACY + " ("+newCnt+")";
|
|
}
|
|
|
|
for(uint i = newCnt; i < oldCnt; ++i)
|
|
voteBoxes[i].remove();
|
|
|
|
voteBoxes.length = newCnt;
|
|
for(uint i = oldCnt; i < newCnt; ++i)
|
|
@voteBoxes[i] = VoteBox(votePanel);
|
|
|
|
for(uint i = 0; i < newCnt; ++i) {
|
|
//Flash when spotting a new vote
|
|
if(votes[i].id >= seenVote) {
|
|
seenVote = votes[i].id+1;
|
|
if(votes[i].startedBy is playerEmpire && visible)
|
|
browseTab(this, createInfluenceVoteTab(votes[i].id), true);
|
|
else
|
|
flash();
|
|
}
|
|
|
|
voteBoxes[i].set(votes[i]);
|
|
}
|
|
|
|
|
|
updateVotePosition();
|
|
|
|
if(oldCnt != newCnt)
|
|
updateAbsolutePosition();
|
|
|
|
noVotesText.visible = newCnt == 0;
|
|
}
|
|
|
|
void updateVotePosition() {
|
|
int y = 4;
|
|
for(uint i = 0, cnt = voteBoxes.length; i < cnt; ++i) {
|
|
voteBoxes[i].position = vec2i(4, y);
|
|
y += 78;
|
|
}
|
|
votePanel.size = vec2i(voteBG.size.width - 16, max(y+4, MIN_SUB_HEIGHT));
|
|
}
|
|
|
|
void updateCards(bool snap = false) {
|
|
//Player cards
|
|
auto@ data = playerEmpire.getInfluenceCards();
|
|
cards.length = 0;
|
|
InfluenceCard@ card = InfluenceCard();
|
|
while(receive(data, card)) {
|
|
cards.insertLast(card);
|
|
@card = InfluenceCard();
|
|
}
|
|
|
|
//Card stack
|
|
@data = getInfluenceCardStack();
|
|
cardStack.length = 0;
|
|
@card = StackInfluenceCard();
|
|
while(receive(data, card)) {
|
|
cardStack.insertLast(card);
|
|
@card = StackInfluenceCard();
|
|
}
|
|
|
|
//Timer
|
|
drawTimer = getInfluenceDrawTimer();
|
|
drawProgress.progress = 1.0 - (drawTimer / drawInterval);
|
|
drawProgress.text = formatTime(drawTimer);
|
|
|
|
updateCardPosition(snap);
|
|
}
|
|
|
|
recti getEmpirePosition(Empire@ emp) {
|
|
for(uint i = 0, cnt = empires.length; i < cnt; ++i) {
|
|
auto@ box = empires[i];
|
|
if(box.emp is emp)
|
|
return box.absolutePosition - absolutePosition.topLeft;
|
|
}
|
|
|
|
return recti();
|
|
}
|
|
|
|
void updateCardPosition(bool snap = false) {
|
|
bool changed = false;
|
|
|
|
//Player cards
|
|
cardPanel.size = vec2i(cardBG.size.width - 16, cardPanel.size.height);
|
|
int h = updateCardList(cardPanel, cards, cardBoxes);
|
|
if(h != cardPanel.size.y) {
|
|
cardPanel.size = vec2i(cardBG.size.width - 16, h);
|
|
changed = true;
|
|
}
|
|
|
|
//Card stack
|
|
stackPanel.size = vec2i(stackBG.size.width - 16, stackPanel.size.height);
|
|
for(uint i = 0, cnt = stackBoxes.length; i < cnt; ++i)
|
|
stackBoxes[i].found = false;
|
|
for(uint i = 0, cnt = cardStack.length; i < cnt; ++i) {
|
|
auto@ card = cardStack[i];
|
|
|
|
//Find box
|
|
StackCard@ box;
|
|
for(uint n = 0, ncnt = stackBoxes.length; n < ncnt; ++n) {
|
|
if(stackBoxes[n].card.id == card.id) {
|
|
@box = stackBoxes[n];
|
|
break;
|
|
}
|
|
}
|
|
|
|
//Create new boxes
|
|
if(box is null) {
|
|
@box = StackCard(stackPanel);
|
|
box.adding = true;
|
|
|
|
box.position = vec2i(stackPanel.size.width + 16, 4);
|
|
stackBoxes.insertLast(box);
|
|
}
|
|
|
|
box.set(card);
|
|
box.found = true;
|
|
}
|
|
|
|
//Remove old boxes
|
|
for(int i = stackBoxes.length - 1; i >= 0; --i) {
|
|
auto@ box = stackBoxes[i];
|
|
|
|
//Show animation for buys
|
|
auto@ stackCard = cast<StackInfluenceCard>(box.card);
|
|
if(stackCard.purchasedBy !is null && !box.bought) {
|
|
if(!snap) {
|
|
StackCard animBox(this);
|
|
animBox.set(stackCard);
|
|
|
|
recti fromPos = box.absolutePosition - position;
|
|
animBox.rect = fromPos;
|
|
|
|
recti toPos;
|
|
if(stackCard.purchasedBy is playerEmpire)
|
|
toPos = recti_centered(cardBG.rect, vec2i(16, 16));
|
|
else
|
|
toPos = recti_centered(getEmpirePosition(stackCard.purchasedBy), vec2i(16, 16));
|
|
|
|
animBox.removing = true;
|
|
animBox.animateTo(toPos, true);
|
|
}
|
|
box.bought = true;
|
|
}
|
|
|
|
//Remove old boxes
|
|
if(!box.found) {
|
|
if(snap) {
|
|
box.remove();
|
|
}
|
|
else {
|
|
recti toPos = recti_area(vec2i(-16-box.size.width, box.position.y), box.size);
|
|
box.animateTo(toPos, true);
|
|
}
|
|
|
|
stackBoxes.removeAt(i);
|
|
}
|
|
}
|
|
|
|
//Position boxes correctly
|
|
int haveWidth = stackPanel.size.width;
|
|
int perRow = floor(double(stackPanel.size.width) / double(GUI_CARD_WIDTH + 4));
|
|
int rowWidth = min(perRow, stackBoxes.length) * (GUI_CARD_WIDTH + 4);
|
|
int xoffset = (haveWidth - rowWidth) / 2;
|
|
int x = xoffset, y = 4;
|
|
|
|
for(uint i = 0, cnt = stackBoxes.length; i < cnt; ++i) {
|
|
if(x + GUI_CARD_WIDTH + 4 >= haveWidth) {
|
|
x = xoffset;
|
|
y += GUI_CARD_HEIGHT + 4;
|
|
}
|
|
|
|
auto@ box = stackBoxes[i];
|
|
recti pos = recti_area(vec2i(x, y), vec2i(GUI_CARD_WIDTH, GUI_CARD_HEIGHT));
|
|
if(box.adding) {
|
|
box.position = vec2i(box.position.x, pos.topLeft.y);
|
|
box.adding = false;
|
|
}
|
|
if(snap)
|
|
box.rect = pos;
|
|
else
|
|
box.animateTo(pos);
|
|
x += GUI_CARD_WIDTH + 4;
|
|
}
|
|
|
|
y += GUI_CARD_HEIGHT + 4;
|
|
if(y != stackPanel.size.y) {
|
|
stackPanel.size = vec2i(stackBG.size.width - 16, y);
|
|
changed = true;
|
|
}
|
|
|
|
if(changed)
|
|
updateAbsolutePosition();
|
|
}
|
|
|
|
void updateEffects() {
|
|
effects.syncFrom(getActiveInfluenceEffects());
|
|
|
|
uint oldCnt = effectBoxes.length;
|
|
uint newCnt = effects.length;
|
|
|
|
for(uint i = newCnt; i < oldCnt; ++i)
|
|
effectBoxes[i].remove();
|
|
|
|
effectBoxes.length = newCnt;
|
|
for(uint i = oldCnt; i < newCnt; ++i)
|
|
@effectBoxes[i] = EffectBox(effectPanel);
|
|
|
|
for(uint i = 0; i < newCnt; ++i)
|
|
effectBoxes[i].set(effects[i]);
|
|
|
|
updateEffectPosition();
|
|
|
|
if(oldCnt != newCnt)
|
|
updateAbsolutePosition();
|
|
|
|
noEffectsText.visible = newCnt == 0;
|
|
}
|
|
|
|
void updateEffectPosition() {
|
|
int y = 4;
|
|
for(uint i = 0, cnt = effectBoxes.length; i < cnt; ++i) {
|
|
effectBoxes[i].position = vec2i(4, y);
|
|
y += 36;
|
|
}
|
|
effectPanel.size = vec2i(effectBG.size.width - 16, max(y+4, MIN_SUB_HEIGHT));
|
|
}
|
|
|
|
void updateTreaties() {
|
|
treaties.syncFrom(getActiveTreaties());
|
|
|
|
uint oldCnt = treatyBoxes.length;
|
|
uint newCnt = treaties.length;
|
|
|
|
for(uint i = newCnt; i < oldCnt; ++i)
|
|
treatyBoxes[i].remove();
|
|
|
|
treatyBoxes.length = newCnt;
|
|
for(uint i = oldCnt; i < newCnt; ++i)
|
|
@treatyBoxes[i] = TreatyBox(treatyPanel);
|
|
|
|
for(uint i = 0; i < newCnt; ++i)
|
|
treatyBoxes[i].set(treaties[i]);
|
|
|
|
updateTreatyPosition();
|
|
|
|
if(oldCnt != newCnt)
|
|
updateAbsolutePosition();
|
|
|
|
noTreatyText.visible = newCnt == 0;
|
|
}
|
|
|
|
void updateTreatyPosition() {
|
|
int y = 4;
|
|
for(uint i = 0, cnt = treatyBoxes.length; i < cnt; ++i) {
|
|
treatyBoxes[i].position = vec2i(4, y);
|
|
y += 68;
|
|
}
|
|
treatyPanel.size = vec2i(treatyBG.size.width - 16, max(y+4, MIN_SUB_HEIGHT));
|
|
}
|
|
|
|
void updateAbsolutePosition() {
|
|
updateCardPosition();
|
|
updateVotePosition();
|
|
updateEffectPosition();
|
|
updateTreatyPosition();
|
|
|
|
//Arrange player box
|
|
playerPanel.position = vec2i((size.width - playerPanel.size.width) / 2, 12);
|
|
|
|
//Arrange empire boxes
|
|
empirePanel.position = vec2i(12, 172);
|
|
empirePanel.size = vec2i(size.width - 24, empirePanel.size.height);
|
|
bool hadScroll = panel.vert.visible;
|
|
|
|
uint w = size.width - 24;
|
|
if(hadScroll)
|
|
w -= 20;
|
|
|
|
uint box = EMPIRE_BOX_WIDTH + EMPIRE_BOX_SPACING;
|
|
uint perline = (w + 12) / box;
|
|
uint x = (w + 12 - min(perline, empires.length) * box) / 2;
|
|
uint y = 0;
|
|
|
|
for(uint i = 0, cnt = empires.length; i < cnt; ++i) {
|
|
if(x + EMPIRE_BOX_WIDTH > w) {
|
|
x = (w + 12 - min(perline, empires.length - i) * box) / 2;
|
|
y += 132;
|
|
}
|
|
|
|
empires[i].position = vec2i(x, y);
|
|
x += EMPIRE_BOX_WIDTH + 12;
|
|
}
|
|
|
|
int needHeight = y + 132;
|
|
if(empirePanel.size.height != needHeight)
|
|
empirePanel.size = vec2i(size.width - 24, needHeight);
|
|
|
|
//Determine organization based on the width of the screen
|
|
w += 8;
|
|
stackBG.position = vec2i(8, empirePanel.rect.botRight.y + 20);
|
|
stackBG.size = vec2i(w, stackPanel.size.y + 40);
|
|
|
|
if(size.width >= 1900) {
|
|
//Arrange cards as a sidebar
|
|
int start = stackBG.rect.botRight.y + 10;
|
|
|
|
int sub_h = max(40 + cardPanel.size.y, size.height - start - 10) / 3 - 10;
|
|
int left_w = double(w) * 0.5 - 5;
|
|
int right_w = double(w) * 0.5 - 5;
|
|
|
|
int total = max(10 + max(votePanel.size.y + 40, sub_h)
|
|
+ max(effectPanel.size.y + 40, sub_h)
|
|
+ max(treatyPanel.size.y + 40, sub_h),
|
|
40 + cardPanel.size.y);
|
|
total = max(total, size.height - start - 10);
|
|
|
|
cardBG.position = vec2i(8, start);
|
|
cardBG.size = vec2i(left_w, max(cardPanel.size.y + 40, total));
|
|
|
|
voteBG.position = vec2i(8+left_w+10, start);
|
|
voteBG.size = vec2i(right_w, max(votePanel.size.y + 40, sub_h));
|
|
|
|
treatyBG.position = vec2i(8+left_w+10, voteBG.rect.botRight.y + 10);
|
|
treatyBG.size = vec2i(right_w, max(treatyPanel.size.y + 40, sub_h));
|
|
|
|
effectBG.position = vec2i(8+left_w+10, treatyBG.rect.botRight.y + 10);
|
|
effectBG.size = vec2i(right_w, max(effectPanel.size.y + 40, sub_h));
|
|
|
|
}
|
|
else {
|
|
//Arrange all the boxes vertically
|
|
cardBG.position = vec2i(8, stackBG.rect.botRight.y + 10);
|
|
cardBG.size = vec2i(w, cardPanel.size.y + 40);
|
|
|
|
voteBG.position = vec2i(8, cardBG.rect.botRight.y + 10);
|
|
voteBG.size = vec2i(w, votePanel.size.y + 40);
|
|
|
|
treatyBG.position = vec2i(8, voteBG.rect.botRight.y + 10);
|
|
treatyBG.size = vec2i(w, treatyPanel.size.y + 40);
|
|
|
|
effectBG.position = vec2i(8, treatyBG.rect.botRight.y + 10);
|
|
effectBG.size = vec2i(w, effectPanel.size.y + 40);
|
|
}
|
|
|
|
Tab::updateAbsolutePosition();
|
|
if(hadScroll != panel.vert.visible) {
|
|
updateAbsolutePosition();
|
|
return;
|
|
}
|
|
}
|
|
|
|
Color get_activeColor() {
|
|
return Color(0x74fc4eff);
|
|
}
|
|
|
|
Color get_inactiveColor() {
|
|
return Color(0x37ff00ff);
|
|
}
|
|
|
|
Color get_seperatorColor() {
|
|
return Color(0x408c2bff);
|
|
}
|
|
|
|
TabCategory get_category() {
|
|
return TC_Diplomacy;
|
|
}
|
|
|
|
Sprite get_icon() {
|
|
return Sprite(material::TabDiplomacy);
|
|
}
|
|
|
|
void draw() {
|
|
skin.draw(SS_DiplomacyBG, SF_Normal, AbsolutePosition);
|
|
skin.draw(SS_HorizAccent, SF_Normal,
|
|
recti_area(panel.AbsolutePosition.topLeft + vec2i(0, 85),
|
|
vec2i(AbsolutePosition.size.width, 140)));
|
|
shader::SATURATION_LEVEL = 0.f;
|
|
Tab::draw();
|
|
}
|
|
|
|
bool onGuiEvent(const GuiEvent& evt) {
|
|
switch(evt.type) {
|
|
case GUI_Confirmed:
|
|
updateCards();
|
|
cardsUpdate = 0.3;
|
|
return true;
|
|
case GUI_Clicked:
|
|
if(false) {}
|
|
/*if(evt.caller is electButton) {*/
|
|
/* InfluenceVote vote(getInfluenceVoteType("ElectLeaderVote"));*/
|
|
/* createInfluenceVote(vote);*/
|
|
/*}*/
|
|
/*else if(evt.caller is unifyButton) {*/
|
|
/* InfluenceVote vote(getInfluenceVoteType("UnifyVote"));*/
|
|
/* createInfluenceVote(vote);*/
|
|
/*}*/
|
|
else if(evt.caller is historyButton) {
|
|
browseTab(this, createInfluenceHistoryTab(), true);
|
|
return true;
|
|
}
|
|
/*else if(evt.caller is actionButton) {*/
|
|
/* recti pos = actionButton.absolutePosition;*/
|
|
/* playerContextMenu(GuiContextMenu(*/
|
|
/* pos.topLeft + vec2i(-12, pos.size.height),*/
|
|
/* pos.size.width, false));*/
|
|
/*}*/
|
|
else if(cast<GuiInfluenceCard>(evt.caller) !is null) {
|
|
auto@ box = cast<GuiInfluenceCard>(evt.caller);
|
|
if(ctrlKey) {
|
|
sound::card_draw.play(priority=true);
|
|
buyCardFromInfluenceStack(box.card.id);
|
|
updateCards();
|
|
cardsUpdate = 0.3;
|
|
}
|
|
else {
|
|
sound::card_examine.play(priority=true);
|
|
GuiInfluenceCardPopup(this, evt.caller, box.card);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
return Tab::onGuiEvent(evt);
|
|
}
|
|
|
|
void playerContextMenu(GuiContextMenu@ menu) {
|
|
//menu.addOption(ZealotOption(), format(locale::ZEALOT_OPTION, getZealotCost(playerEmpire)));
|
|
menu.updateAbsolutePosition();
|
|
}
|
|
|
|
bool onMouseEvent(const MouseEvent& event, IGuiElement@ source) {
|
|
if(event.type == MET_Button_Down && event.button == 1) {
|
|
return true;
|
|
}
|
|
if(event.type == MET_Button_Up && event.button == 1) {
|
|
if(source is playerPanel || source.isChildOf(playerPanel)) {
|
|
playerContextMenu(GuiContextMenu(mousePos));
|
|
}
|
|
return true;
|
|
}
|
|
return BaseGuiElement::onMouseEvent(event, source);
|
|
}
|
|
};
|
|
|
|
enum WarState {
|
|
WS_Peace,
|
|
WS_Peace_Forced,
|
|
WS_War,
|
|
};
|
|
|
|
class EmpireBox : BaseGuiElement {
|
|
Empire@ emp;
|
|
GuiEmpire@ picture;
|
|
GuiSprite@ leaderIcon;
|
|
GuiSkinElement@ nameBG;
|
|
GuiText@ name;
|
|
|
|
GuiSprite@ ptsIcon;
|
|
GuiText@ ptsText;
|
|
|
|
GuiText@ stateLabel;
|
|
GuiImage@ statePicture;
|
|
GuiMarkupText@ vassalText;
|
|
|
|
GuiSprite@ relationIcon;
|
|
GuiSprite@ politicalIcon;
|
|
GuiSprite@ militaryIcon;
|
|
GuiSprite@ territoryIcon;
|
|
|
|
GuiSprite@ flag;
|
|
|
|
GuiButton@ actionButton;
|
|
|
|
WarState state;
|
|
|
|
EmpireBox(DiplomacyTab@ tab) {
|
|
super(tab.empirePanel, recti(0, 0, EMPIRE_BOX_WIDTH, 128));
|
|
|
|
@flag = GuiSprite(this, Alignment().padded(5));
|
|
flag.horizAlign = 1.0;
|
|
flag.visible = false;
|
|
|
|
@picture = GuiEmpire(this, recti(8, 8, 120, 120));
|
|
|
|
@leaderIcon = GuiSprite(picture, Alignment(Left, Bottom-52, Left+52, Bottom));
|
|
leaderIcon.desc = Sprite(material::LeaderIcon);
|
|
setMarkupTooltip(leaderIcon, locale::TT_SENATE_LEADER);
|
|
leaderIcon.visible = false;
|
|
|
|
@nameBG = GuiSkinElement(this, recti(120, 1, 280, 27), SS_CenterTitle);
|
|
|
|
@name = GuiText(this, recti(0, 2, EMPIRE_BOX_WIDTH, 26));
|
|
name.font = FT_Bold;
|
|
name.horizAlign = 0.5;
|
|
|
|
@statePicture = GuiImage(this, recti(132, 34, 162, 64), null);
|
|
@stateLabel = GuiText(this, recti(172, 34, 330, 64));
|
|
@vassalText = GuiMarkupText(this, recti(132, 36, 360, 64));
|
|
vassalText.visible = false;
|
|
|
|
@ptsIcon = GuiSprite(this, recti(132, 68, 162, 98));
|
|
ptsIcon.desc = Sprite(material::PointsIcon);
|
|
@ptsText = GuiText(this, recti(172, 68, 330, 98));
|
|
ptsText.color = Color(0xccccccff);
|
|
|
|
@actionButton = GuiButton(this, Alignment(Left+0.5f-50, Bottom-26, Left+0.5f+50, Bottom-2));
|
|
actionButton.style = SS_BaselineButton;
|
|
|
|
@relationIcon = GuiSprite(this, Alignment(Left+280, Top+0.5f-25, Width=50, Height=50));
|
|
|
|
@politicalIcon = GuiSprite(this, recti(335, 16, 385, 46));
|
|
politicalIcon.desc = Sprite(material::PoliticalStrengthIcon);
|
|
|
|
@militaryIcon = GuiSprite(this, recti(335, 50, 385, 80));
|
|
militaryIcon.desc = Sprite(material::MilitaryStrengthIcon);
|
|
|
|
@territoryIcon = GuiSprite(this, recti(335, 84, 385, 114));
|
|
territoryIcon.desc = Sprite(material::TerritoryStrengthIcon);
|
|
|
|
GuiSprite(actionButton, Alignment(Left+0.5f-11, Top+4, Left+0.5f+11, Bottom-4),
|
|
Sprite(material::DownIcon));
|
|
|
|
setState(WS_Peace);
|
|
}
|
|
|
|
void fillContextMenu(GuiContextMenu@ menu) {
|
|
menu.itemHeight = 40;
|
|
|
|
if(emp.SubjugatedBy is null && playerEmpire.SubjugatedBy is null) {
|
|
//War status change
|
|
if(state == WS_Peace)
|
|
menu.addOption(WarOption(emp), locale::DECLARE_WAR, Sprite(material::StatusWar));
|
|
else if(state == WS_War)
|
|
menu.addOption(PeaceOption(emp), locale::PROPOSE_PEACE, Sprite(material::StatusPeace));
|
|
|
|
//New treaty
|
|
menu.addOption(ProposeTreatyOption(emp), locale::PROPOSE_TREATY, Sprite(material::Propositions));
|
|
}
|
|
|
|
//Invite to treaty
|
|
array<Treaty> treaties;
|
|
treaties.syncFrom(getActiveTreaties());
|
|
for(uint i = 0, cnt = treaties.length; i < cnt; ++i) {
|
|
if(treaties[i].canInvite(playerEmpire, emp))
|
|
menu.addOption(InviteTreatyOption(emp, treaties[i]));
|
|
}
|
|
|
|
if(emp.SubjugatedBy is null && playerEmpire.SubjugatedBy is null) {
|
|
if(emp.team == -1 || config::ALLOW_TEAM_SURRENDER != 0)
|
|
menu.addOption(DemandSurrenderOption(emp),
|
|
playerEmpire.isHostile(emp) ? locale::DEMAND_SURRENDER_OPTION : locale::DEMAND_SUBJUGATE_OPTION,
|
|
Sprite(material::LoyaltyIcon));
|
|
|
|
if(playerEmpire.team == -1 || config::ALLOW_TEAM_SURRENDER != 0)
|
|
menu.addOption(OfferSurrenderOption(emp),
|
|
playerEmpire.isHostile(emp) ? locale::SURRENDER_OPTION : locale::OFFER_SUBJUGATE_OPTION,
|
|
Sprite(material::LoyaltyIcon, Color(0xff0000ff)));
|
|
}
|
|
|
|
//Donations
|
|
if(!playerEmpire.isHostile(emp))
|
|
menu.addOption(DonationOption(this, emp), locale::DONATE_OPTION, icons::Donate);
|
|
|
|
//Edicts
|
|
bool haveVassals = false;
|
|
for(uint i = 0, cnt = getEmpireCount(); i < cnt; ++i) {
|
|
if(getEmpire(i).SubjugatedBy is playerEmpire) {
|
|
haveVassals = true;
|
|
break;
|
|
}
|
|
}
|
|
if(haveVassals) {
|
|
if(playerEmpire.isHostile(emp)) {
|
|
menu.addOption(ConquerEdictOption(emp),
|
|
format(locale::EDICT_CONQUER_OPTION, formatEmpireName(emp)),
|
|
Sprite(material::StatusWar));
|
|
}
|
|
}
|
|
|
|
menu.finalize();
|
|
}
|
|
|
|
void update() {
|
|
leaderIcon.visible = getSenateLeader() is emp;
|
|
flag.desc = Sprite(emp.flag);
|
|
flag.color = emp.color;
|
|
flag.color.a = 0x20;
|
|
|
|
if(emp.SubjugatedBy !is null) {
|
|
string txt = format(locale::VASSAL_TEXT, formatEmpireName(emp.SubjugatedBy));
|
|
if(playerEmpire.isHostile(emp))
|
|
txt = format("[color=#f00][b]$1[/b][/color]", txt);
|
|
|
|
vassalText.text = txt;
|
|
vassalText.updateAbsolutePosition();
|
|
|
|
stateLabel.visible = false;
|
|
vassalText.visible = true;
|
|
statePicture.visible = false;
|
|
}
|
|
else if(playerEmpire.SubjugatedBy is emp) {
|
|
vassalText.text = locale::PARENT_VASSAL_TEXT;
|
|
vassalText.updateAbsolutePosition();
|
|
|
|
stateLabel.visible = false;
|
|
vassalText.visible = true;
|
|
statePicture.visible = false;
|
|
}
|
|
else {
|
|
stateLabel.visible = true;
|
|
statePicture.visible = true;
|
|
vassalText.visible = false;
|
|
}
|
|
|
|
if(emp.isAI && emp.SubjugatedBy is null && emp.getRelation().length != 0) {
|
|
int rel = emp.getRelationState();
|
|
relationIcon.visible = true;
|
|
relationIcon.desc = getRelationIcon(rel);
|
|
}
|
|
else {
|
|
relationIcon.visible = false;
|
|
}
|
|
}
|
|
|
|
void setPoints(int pts) {
|
|
ptsText.text = format(locale::EMPIRE_POINTS, toString(pts));
|
|
}
|
|
|
|
void setState(WarState newState) {
|
|
state = newState;
|
|
|
|
if(state == WS_Peace || state == WS_Peace_Forced) {
|
|
stateLabel.color = Color(0xccccccff);
|
|
stateLabel.text = locale::PEACEFUL;
|
|
stateLabel.font = FT_Normal;
|
|
}
|
|
else {
|
|
stateLabel.color = Color(0xff0000ff);
|
|
stateLabel.text = locale::WAR;
|
|
stateLabel.font = FT_Bold;
|
|
}
|
|
|
|
switch(state) {
|
|
case WS_Peace_Forced:
|
|
case WS_Peace:
|
|
@statePicture.mat = material::StatusPeace;
|
|
break;
|
|
case WS_War:
|
|
@statePicture.mat = material::StatusWar;
|
|
break;
|
|
}
|
|
}
|
|
|
|
string traitTooltip;
|
|
void set(Empire@ empire) {
|
|
@emp = empire;
|
|
@picture.empire = empire;
|
|
|
|
name.text = empire.name;
|
|
|
|
int needed = name.getTextDimension().width + 140;
|
|
nameBG.size = vec2i(needed, 26);
|
|
nameBG.position = vec2i((EMPIRE_BOX_WIDTH-needed)/2, 1);
|
|
|
|
name.color = empire.color;
|
|
nameBG.color = empire.color;
|
|
actionButton.color = empire.color;
|
|
|
|
uint traitCnt = empire.traitCount;
|
|
traitTooltip = "";
|
|
for(uint i = 0; i < traitCnt; ++i) {
|
|
if(traitTooltip.length != 0)
|
|
traitTooltip += "\n\n";
|
|
auto@ trait = getTrait(empire.getTraitType(i));
|
|
if(trait !is null)
|
|
traitTooltip += format("[color=$1][b]$2[/b][/color]\n$3",
|
|
toString(trait.color), trait.name, trait.description);
|
|
}
|
|
}
|
|
|
|
bool onMouseEvent(const MouseEvent& event, IGuiElement@ source) {
|
|
if(event.type == MET_Button_Down && event.button == 1) {
|
|
return true;
|
|
}
|
|
if(event.type == MET_Button_Up && event.button == 1) {
|
|
fillContextMenu(GuiContextMenu(mousePos));
|
|
return true;
|
|
}
|
|
return BaseGuiElement::onMouseEvent(event, source);
|
|
}
|
|
|
|
bool onGuiEvent(const GuiEvent& evt) {
|
|
switch(evt.type) {
|
|
case GUI_Mouse_Entered:
|
|
if(evt.caller is relationIcon || evt.caller is picture) {
|
|
string tt = format("[color=$2][font=Medium]$1[/font][/color]", emp.name, toString(emp.color));
|
|
if(emp.isAI) {
|
|
int rel = emp.getRelationState();
|
|
string relationText = emp.getRelation();
|
|
if(relationText.length != 0) {
|
|
string relTT = format(locale::TT_RELATION, emp.name, relationText);
|
|
tt += "\n\n"+relTT;
|
|
setMarkupTooltip(relationIcon, relTT, width=300);
|
|
relationIcon.visible = true;
|
|
}
|
|
else {
|
|
setMarkupTooltip(relationIcon, "", width=300);
|
|
relationIcon.visible = false;
|
|
}
|
|
}
|
|
if(config::HIDE_EMPIRE_RELATIONS == 0) {
|
|
for(uint i = 0, cnt = getEmpireCount(); i < cnt; ++i) {
|
|
auto@ other = getEmpire(i);
|
|
if(other.major && other !is emp && other !is playerEmpire) {
|
|
if(emp.isHostile(other))
|
|
tt += "\n\n"+format(locale::RELATION_WAR, formatEmpireName(other));
|
|
}
|
|
}
|
|
}
|
|
tt += "\n\n"+traitTooltip;
|
|
setMarkupTooltip(picture, tt, width=400);
|
|
}
|
|
break;
|
|
case GUI_Clicked:
|
|
if(evt.caller is actionButton) {
|
|
fillContextMenu(GuiContextMenu(
|
|
absolutePosition.topLeft + vec2i(-12, size.height),
|
|
size.width, false));
|
|
return true;
|
|
}
|
|
break;
|
|
}
|
|
return BaseGuiElement::onGuiEvent(evt);
|
|
}
|
|
|
|
void draw() {
|
|
if(emp is null)
|
|
return;
|
|
skin.draw(SS_EmpireBox, SF_Normal, AbsolutePosition, emp.color);
|
|
BaseGuiElement::draw();
|
|
}
|
|
};
|
|
|
|
void setStrengthIcon(GuiSprite@ sprite, int str, const string& prefix) {
|
|
if(str == -1) {
|
|
sprite.color = Color(0xff8080aa);
|
|
@sprite.shader = shader::Desaturate;
|
|
sprite.tooltip = prefix+" "+locale::STR_WEAK;
|
|
}
|
|
else if(str == 0) {
|
|
sprite.color = Color(0xffffffaa);
|
|
@sprite.shader = shader::Desaturate;
|
|
sprite.tooltip = prefix+" "+locale::STR_AVERAGE;
|
|
}
|
|
else {
|
|
sprite.color = Color(0xffffffff);
|
|
@sprite.shader = null;
|
|
sprite.tooltip = prefix+" "+locale::STR_STRONG;
|
|
}
|
|
}
|
|
|
|
class StackCard : GuiInfluenceCard {
|
|
bool removing = false;
|
|
bool animating = false;
|
|
bool found = true;
|
|
bool adding = false;
|
|
bool bought = false;
|
|
|
|
StackCard(IGuiElement@ parent) {
|
|
super(parent);
|
|
}
|
|
|
|
void animateTo(const recti& pos, bool force = false) {
|
|
if(animating && !force)
|
|
return;
|
|
if(pos == rect)
|
|
return;
|
|
animate_time(this, pos, removing ? CARD_ANIM_REMOVE_TIME : CARD_ANIM_TIME);
|
|
animating = true;
|
|
}
|
|
|
|
bool onGuiEvent(const GuiEvent& evt) override {
|
|
if(evt.type == GUI_Animation_Complete) {
|
|
animating = false;
|
|
if(removing)
|
|
remove();
|
|
return true;
|
|
}
|
|
return GuiInfluenceCard::onGuiEvent(evt);
|
|
}
|
|
};
|
|
|
|
class VoteBox : BaseGuiElement {
|
|
uint prevId = uint(-1);
|
|
InfluenceVote@ vote;
|
|
|
|
GuiMarkupText@ titleBox;
|
|
GuiSprite@ icon;
|
|
|
|
GuiProgressbar@ forBar;
|
|
GuiProgressbar@ againstBar;
|
|
|
|
GuiText@ timerBox;
|
|
GuiText@ totalBox;
|
|
GuiSprite@ totalPic;
|
|
|
|
GuiButton@ zoomButton;
|
|
|
|
bool Hovered = false;
|
|
|
|
VoteBox(IGuiElement@ parent) {
|
|
super(parent, recti(0, 0, parent.size.width - 32, 74));
|
|
|
|
@titleBox = GuiMarkupText(this, Alignment(Left+74, Top+6, Right-74, Top+38));
|
|
titleBox.defaultFont = FT_Subtitle;
|
|
|
|
@totalBox = GuiText(this, Alignment(Right-74, Top+6, Right-12, Bottom-6));
|
|
totalBox.horizAlign = 0.5;
|
|
totalBox.font = FT_Big;
|
|
totalBox.stroke = colors::Black;
|
|
|
|
@totalPic = GuiSprite(this, Alignment(Right-74, Top+6, Right-12, Bottom-6));
|
|
totalPic.color = Color(0xffffff20);
|
|
|
|
@icon = GuiSprite(this, Alignment(Left+4, Top+4, Left+70, Bottom-4));
|
|
|
|
@againstBar = GuiProgressbar(this, Alignment(Left+47+74, Top+40, Left+0.5f-50, Bottom-6));
|
|
againstBar.invert = true;
|
|
againstBar.backColor = Color(0xffffff40);
|
|
againstBar.frontColor = Color(0xff0000ff);
|
|
|
|
@timerBox = GuiText(this, Alignment(Left+0.5f-50, Top+40, Left+0.5f+50, Bottom-6));
|
|
timerBox.horizAlign = 0.5;
|
|
timerBox.vertAlign = 0.5;
|
|
timerBox.font = FT_Medium;
|
|
|
|
@forBar = GuiProgressbar(this, Alignment(Left+0.5f+50, Top+40, Right-47-74, Bottom-6));
|
|
forBar.backColor = Color(0xffffff40);
|
|
forBar.frontColor = Color(0x00ff00ff);
|
|
|
|
GuiSprite failIcon(this, Alignment(Left+76+11, Top+40, Left+76+11+32, Bottom-2), Sprite(spritesheet::VoteIcons, 6));
|
|
setMarkupTooltip(failIcon, locale::INFLUENCE_TT_FAIL);
|
|
GuiSprite passIcon(this, Alignment(Right-43-74, Top+40, Right-11-74, Bottom-2), Sprite(spritesheet::CardCategoryIcons, 4));
|
|
setMarkupTooltip(passIcon, locale::INFLUENCE_TT_PASS);
|
|
|
|
@zoomButton = GuiButton(this, Alignment(Right-74-80-47, Top+6, Right-74-47, Top+38));
|
|
zoomButton.visible = false;
|
|
zoomButton.text = locale::ZOOM;
|
|
zoomButton.buttonIcon = icons::Zoom;
|
|
|
|
updateAbsolutePosition();
|
|
}
|
|
|
|
void set(InfluenceVote@ newVote) {
|
|
//Only update mutable data when set to the same vote
|
|
if(vote !is null && newVote.id == prevId) {
|
|
@vote = newVote;
|
|
update();
|
|
return;
|
|
}
|
|
@vote = newVote;
|
|
prevId = vote.id;
|
|
|
|
//Set the data fields
|
|
if(vote.startedBy.major)
|
|
titleBox.text = formatEmpireName(vote.startedBy)+": "+vote.formatTitle();
|
|
else
|
|
titleBox.text = vote.formatTitle();
|
|
|
|
Color color;
|
|
if(vote.startedBy !is null && vote.startedBy.major)
|
|
color = vote.startedBy.color;
|
|
|
|
string desc = vote.formatDescription();
|
|
if(desc.length != 0) {
|
|
setMarkupTooltip(this, format("[font=Medium][color=$3]$1[/color][/font]\n$2",
|
|
vote.formatTitle(), desc, toString(color)), width=350);
|
|
}
|
|
else {
|
|
setMarkupTooltip(this, "", width=350);
|
|
}
|
|
|
|
icon.desc = vote.type.icon;
|
|
|
|
if(vote.targets.length != 0 && vote.targets[0].type == TT_Object)
|
|
zoomButton.visible = true;
|
|
else
|
|
zoomButton.visible = false;
|
|
|
|
update();
|
|
}
|
|
|
|
void update() {
|
|
if(vote is null)
|
|
return;
|
|
|
|
string totalText = toString(abs(vote.totalFor - vote.totalAgainst));
|
|
if(vote.totalFor > vote.totalAgainst)
|
|
totalText = "+"+totalText;
|
|
else if(vote.totalAgainst > vote.totalFor)
|
|
totalText = "-"+totalText;
|
|
totalBox.text = totalText;
|
|
|
|
Color timerColor;
|
|
string timeText;
|
|
if(vote.totalFor > vote.totalAgainst) {
|
|
totalPic.desc = Sprite(material::ThumbsUp);
|
|
totalBox.color = Color(0x00ff00ff);
|
|
|
|
timerColor = Color(0x00ff00ff);
|
|
timeText = formatTime(vote.remainingTime);
|
|
}
|
|
else {
|
|
totalPic.desc = Sprite(material::ThumbsDown);
|
|
totalBox.color = Color(0xff0000ff);
|
|
|
|
timerColor = Color(0xff0000ff);
|
|
timeText = formatTime(vote.remainingTime);
|
|
}
|
|
|
|
//Update timer
|
|
if(vote.currentTime < 0.0) {
|
|
forBar.progress = 0.f;
|
|
againstBar.progress = vote.currentTime / config::INFLUENCE_FAIL_THRES;
|
|
}
|
|
else {
|
|
againstBar.progress = 0.f;
|
|
forBar.progress = vote.currentTime / config::INFLUENCE_PASS_THRES;
|
|
}
|
|
timerBox.text = timeText;
|
|
timerBox.color = timerColor;
|
|
}
|
|
|
|
void remove() {
|
|
@vote = null;
|
|
BaseGuiElement::remove();
|
|
}
|
|
|
|
void updateAbsolutePosition() {
|
|
BaseGuiElement::updateAbsolutePosition();
|
|
|
|
int w = parent.size.width - 32;
|
|
if(size.width != w)
|
|
size = vec2i(w, size.height);
|
|
}
|
|
|
|
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;
|
|
case GUI_Clicked:
|
|
if(evt.caller is zoomButton) {
|
|
if(vote.targets.length != 0 && vote.targets[0].type == TT_Object) {
|
|
zoomTo(vote.targets[0].obj);
|
|
return true;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
return BaseGuiElement::onGuiEvent(evt);
|
|
}
|
|
|
|
bool onMouseEvent(const MouseEvent& event, IGuiElement@ source) {
|
|
if(source is this || source.isChildOf(this)) {
|
|
switch(event.type) {
|
|
case MET_Button_Down:
|
|
if(event.button == 0 || event.button == 2)
|
|
return true;
|
|
break;
|
|
case MET_Button_Up:
|
|
if(event.button == 0 || event.button == 2) {
|
|
if(event.button == 2)
|
|
newTab(createInfluenceVoteTab(vote.id));
|
|
else
|
|
browseTab(ActiveTab, createInfluenceVoteTab(vote.id), true);
|
|
return true;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
return BaseGuiElement::onMouseEvent(event, source);
|
|
}
|
|
|
|
void draw() {
|
|
Color color;
|
|
if(vote !is null && vote.type !is null)
|
|
color = vote.type.color;
|
|
skin.draw(SS_PatternBox, SF_Normal, AbsolutePosition, color);
|
|
if(Hovered)
|
|
skin.draw(SS_SubtleGlow, SF_Normal, AbsolutePosition, color);
|
|
BaseGuiElement::draw();
|
|
}
|
|
};
|
|
|
|
class TreatyBox : BaseGuiElement, QuestionDialogCallback {
|
|
Treaty treaty;
|
|
GuiMarkupText@ titleBox;
|
|
GuiMarkupText@ signatories;
|
|
GuiSpriteGrid@ clauses;
|
|
GuiButton@ btn;
|
|
GuiButton@ btn1;
|
|
GuiButton@ btn2;
|
|
|
|
TreatyBox(IGuiElement@ parent) {
|
|
super(parent, recti(0, 0, parent.size.width - 32, 64));
|
|
|
|
@titleBox = GuiMarkupText(this, Alignment(Left+4, Top+6, Right-350, Top+30));
|
|
@signatories = GuiMarkupText(this, Alignment(Left+4, Bottom-30, Right, Bottom-6));
|
|
@clauses = GuiSpriteGrid(this, Alignment(Right-350, Top+6, Right-184, Bottom-6), vec2i(34,34));
|
|
|
|
@btn = GuiButton(this, Alignment(Right-184, Top+8, Right-8, Bottom-8));
|
|
btn.visible = false;
|
|
|
|
@btn1 = GuiButton(this, Alignment(Right-184, Top+4, Right-8, Top+0.5f-1));
|
|
btn1.visible = false;
|
|
@btn2 = GuiButton(this, Alignment(Right-184, Top+0.5f+1, Right-8, Bottom-4));
|
|
btn2.visible = false;
|
|
|
|
updateAbsolutePosition();
|
|
}
|
|
|
|
void set(Treaty@ newTreaty) {
|
|
treaty = newTreaty;
|
|
|
|
//Update title
|
|
string title;
|
|
if(treaty.leader !is null) {
|
|
title = format("$1's [b]$2[/b]",
|
|
formatEmpireName(treaty.leader),
|
|
treaty.name);
|
|
}
|
|
else {
|
|
title = format("[b]$1[/b]",
|
|
treaty.name);
|
|
}
|
|
titleBox.text = title;
|
|
|
|
//Update signatories
|
|
string emps;
|
|
for(uint i = 0, cnt = treaty.joinedEmpires.length; i < cnt; ++i) {
|
|
if(emps.length != 0)
|
|
emps += ", ";
|
|
emps += formatEmpireName(treaty.joinedEmpires[i]);
|
|
}
|
|
if(emps.length == 0)
|
|
emps = locale::NO_SIGNATORIES;
|
|
else
|
|
emps = locale::SIGNED_BY+" "+emps;
|
|
signatories.text = emps;
|
|
|
|
//Update clause icons
|
|
clauses.clear();
|
|
for(uint i = 0, cnt = treaty.clauses.length; i < cnt; ++i)
|
|
clauses.add(treaty.clauses[i].type.icon);
|
|
|
|
//Update tooltip
|
|
setMarkupTooltip(this, treaty.getTooltip(), width=350);
|
|
|
|
//Update button action
|
|
if(treaty.inviteMask & playerEmpire.mask != 0) {
|
|
btn1.text = locale::JOIN_TREATY;
|
|
btn1.buttonIcon = Sprite(material::Propositions);
|
|
btn1.color = colors::Green;
|
|
|
|
btn2.text = locale::DECLINE_TREATY;
|
|
btn2.buttonIcon = icons::Remove;
|
|
btn2.color = colors::Red;
|
|
|
|
btn.visible = false;
|
|
btn1.visible = true;
|
|
btn2.visible = true;
|
|
}
|
|
else if(treaty.presentMask & playerEmpire.mask != 0 && treaty.canLeave(playerEmpire)) {
|
|
btn.text = treaty.leader is playerEmpire ? locale::DISMISS_TREATY : locale::LEAVE_TREATY;
|
|
btn.buttonIcon = icons::Remove;
|
|
btn.color = colors::Red;
|
|
btn.visible = true;
|
|
btn1.visible = false;
|
|
btn2.visible = false;
|
|
}
|
|
else {
|
|
btn.visible = false;
|
|
btn1.visible = false;
|
|
btn2.visible = false;
|
|
}
|
|
}
|
|
|
|
void updateAbsolutePosition() {
|
|
BaseGuiElement::updateAbsolutePosition();
|
|
|
|
int w = parent.size.width - 32;
|
|
if(size.width != w)
|
|
size = vec2i(w, size.height);
|
|
}
|
|
|
|
void draw() {
|
|
skin.draw(SS_TreatyBox, SF_Normal, AbsolutePosition);
|
|
BaseGuiElement::draw();
|
|
}
|
|
|
|
void questionCallback(QuestionDialog@ dialog, int answer) {
|
|
if(answer == QA_Yes)
|
|
joinTreaty(treaty.id);
|
|
}
|
|
|
|
bool onGuiEvent(const GuiEvent& evt) {
|
|
switch(evt.type) {
|
|
case GUI_Clicked:
|
|
if(evt.caller is btn) {
|
|
if(treaty.presentMask & playerEmpire.mask != 0 && treaty.canLeave(playerEmpire)) {
|
|
leaveTreaty(treaty.id);
|
|
}
|
|
return true;
|
|
}
|
|
else if(evt.caller is btn1) {
|
|
if(treaty.inviteMask & playerEmpire.mask != 0) {
|
|
if(treaty.hasClause("ConstClause"))
|
|
question(
|
|
locale::PERMANENT_PROMPT,
|
|
locale::JOIN_TREATY, locale::CANCEL,
|
|
this).titleBox.color = Color(0xe00000ff);
|
|
else
|
|
joinTreaty(treaty.id);
|
|
}
|
|
return true;
|
|
}
|
|
else if(evt.caller is btn2) {
|
|
if(treaty.inviteMask & playerEmpire.mask != 0) {
|
|
declineTreaty(treaty.id);
|
|
}
|
|
return true;
|
|
}
|
|
break;
|
|
}
|
|
return BaseGuiElement::onGuiEvent(evt);
|
|
}
|
|
};
|
|
|
|
class EffectBox : BaseGuiElement {
|
|
int prevId = -1;
|
|
InfluenceEffect@ eff;
|
|
|
|
GuiMarkupText@ titleBox;
|
|
GuiText@ timerBox;
|
|
GuiText@ costBox;
|
|
GuiButton@ dismissButton;
|
|
|
|
EffectBox(IGuiElement@ parent) {
|
|
super(parent, recti(0, 0, parent.size.width - 32, 32));
|
|
|
|
@titleBox = GuiMarkupText(this, Alignment(Left+4, Top+4, Right-432, Top+26));
|
|
|
|
@timerBox = GuiText(this, Alignment(Right-428, Top+4, Right-328, Top+26));
|
|
|
|
@costBox = GuiText(this, Alignment(Right-328, Top+4, Right-168, Top+26));
|
|
|
|
@dismissButton = GuiButton(this, Alignment(Right-164, Top+2, Right-4, Bottom-2), locale::EFFECT_DISMISS);
|
|
dismissButton.buttonIcon = icons::Close;
|
|
updateAbsolutePosition();
|
|
}
|
|
|
|
void set(InfluenceEffect@ newEffect) {
|
|
//Only update mutable data when set to the same effect
|
|
if(eff !is null && newEffect.id == prevId) {
|
|
@eff = newEffect;
|
|
prevId = eff.id;
|
|
update();
|
|
return;
|
|
}
|
|
|
|
@eff = newEffect;
|
|
prevId = eff.id;
|
|
|
|
//Set the data fields
|
|
if(eff.owner !is null && eff.owner.major)
|
|
titleBox.text = formatEmpireName(eff.owner)+": "+eff.formatTitle();
|
|
else
|
|
titleBox.text = eff.formatTitle();
|
|
|
|
Color color;
|
|
if(eff.owner !is null && eff.owner.major)
|
|
color = eff.owner.color;
|
|
setMarkupTooltip(this, format("[font=Medium][color=$3]$1[/color][/font]\n$2",
|
|
eff.formatTitle(), eff.formatDescription(), toString(color)), width=350);
|
|
|
|
update();
|
|
}
|
|
|
|
void update() {
|
|
//Update timer
|
|
if(eff.remainingTime < 0) {
|
|
timerBox.visible = false;
|
|
}
|
|
else {
|
|
timerBox.visible = true;
|
|
timerBox.text = formatTime(eff.remainingTime);
|
|
|
|
if(eff.remainingTime < 60.0) {
|
|
timerBox.color = Color(0xff0000ff).interpolate(
|
|
Color(0xffffffff), eff.remainingTime / 60.0);
|
|
timerBox.font = FT_Bold;
|
|
}
|
|
else {
|
|
timerBox.color = Color(0xffffffff);
|
|
timerBox.font = FT_Normal;
|
|
}
|
|
}
|
|
|
|
//Update cost
|
|
if(eff.type.reservation != 0) {
|
|
costBox.visible = true;
|
|
costBox.text = format(locale::EFFECT_UPKEEP, toString(eff.type.reservation*100, 0));
|
|
}
|
|
else {
|
|
costBox.visible = false;
|
|
}
|
|
|
|
//Update dismissing
|
|
dismissButton.visible = eff.canDismiss(playerEmpire);
|
|
}
|
|
|
|
void remove() {
|
|
@eff = null;
|
|
BaseGuiElement::remove();
|
|
}
|
|
|
|
void updateAbsolutePosition() {
|
|
BaseGuiElement::updateAbsolutePosition();
|
|
|
|
int w = parent.size.width - 32;
|
|
if(size.width != w)
|
|
size = vec2i(w, size.height);
|
|
}
|
|
|
|
void draw() {
|
|
skin.draw(SS_InfluenceEffectBox, SF_Normal, AbsolutePosition);
|
|
BaseGuiElement::draw();
|
|
}
|
|
|
|
bool onGuiEvent(const GuiEvent& evt) {
|
|
switch(evt.type) {
|
|
case GUI_Clicked:
|
|
if(evt.caller is dismissButton) {
|
|
question(locale::EFFECT_CONFIRM_DISMISS, DismissEffect(eff.id));
|
|
return true;
|
|
}
|
|
break;
|
|
}
|
|
return BaseGuiElement::onGuiEvent(evt);
|
|
}
|
|
}
|
|
|
|
class DismissEffect : QuestionDialogCallback {
|
|
int id;
|
|
DismissEffect(int id) {
|
|
this.id = id;
|
|
}
|
|
|
|
void questionCallback(QuestionDialog@ dialog, int answer) {
|
|
if(answer == QA_Yes)
|
|
dismissInfluenceEffect(id);
|
|
}
|
|
}
|
|
|
|
class WarOption : GuiContextOption {
|
|
Empire@ emp;
|
|
WarOption(Empire@ empire) {
|
|
@emp = empire;
|
|
}
|
|
|
|
void call(GuiContextMenu@ menu) {
|
|
question(
|
|
locale::DECLARE_WAR,
|
|
format(locale::PROMPT_WAR, formatEmpireName(emp)),
|
|
locale::DECLARE_WAR, locale::CANCEL,
|
|
WarCallback(emp)).titleBox.color = Color(0xe00000ff);
|
|
}
|
|
};
|
|
|
|
class PeaceOption : GuiContextOption {
|
|
Empire@ emp;
|
|
PeaceOption(Empire@ empire) {
|
|
@emp = empire;
|
|
}
|
|
|
|
void call(GuiContextMenu@ menu) {
|
|
sendPeaceOffer(emp);
|
|
}
|
|
};
|
|
|
|
class WarCallback : QuestionDialogCallback {
|
|
Empire@ emp;
|
|
WarCallback(Empire@ onEmpire) {
|
|
@emp = onEmpire;
|
|
}
|
|
|
|
void questionCallback(QuestionDialog@ dialog, int answer) {
|
|
if(answer == QA_Yes)
|
|
declareWar(emp);
|
|
}
|
|
};
|
|
|
|
class ProposeTreatyOption : GuiContextOption {
|
|
Empire@ emp;
|
|
ProposeTreatyOption(Empire@ empire) {
|
|
@emp = empire;
|
|
}
|
|
|
|
void call(GuiContextMenu@ menu) {
|
|
TreatyDialog(ActiveTab, emp);
|
|
}
|
|
};
|
|
|
|
class InviteTreatyOption : GuiMarkupContextOption {
|
|
Empire@ emp;
|
|
Treaty treaty;
|
|
InviteTreatyOption(Empire@ empire, Treaty@ treaty) {
|
|
@emp = empire;
|
|
this.treaty = treaty;
|
|
|
|
string txt = "[vspace=10/]"+format(locale::INVITE_TO_TREATY, treaty.name, formatEmpireName(empire));
|
|
for(uint i = 0, cnt = treaty.clauses.length; i < cnt; ++i)
|
|
txt += format(" [img=$1;24/]", getSpriteDesc(treaty.clauses[i].type.icon));
|
|
super(txt);
|
|
}
|
|
|
|
void call(GuiContextMenu@ menu) {
|
|
inviteToTreaty(treaty.id, emp);
|
|
}
|
|
};
|
|
|
|
class ConquerEdictOption : GuiMarkupContextOption {
|
|
Empire@ emp;
|
|
ConquerEdictOption(Empire@ empire) {
|
|
@emp = empire;
|
|
super("");
|
|
}
|
|
|
|
void call(GuiContextMenu@ menu) {
|
|
playerEmpire.conquerEdict(emp);
|
|
}
|
|
};
|
|
|
|
class DemandSurrenderOption : GuiContextOption {
|
|
Empire@ emp;
|
|
DemandSurrenderOption(Empire@ empire) {
|
|
@emp = empire;
|
|
}
|
|
|
|
void call(GuiContextMenu@ menu) {
|
|
demandSurrender(emp);
|
|
}
|
|
};
|
|
|
|
class OfferSurrenderOption : GuiContextOption, QuestionDialogCallback {
|
|
Empire@ emp;
|
|
OfferSurrenderOption(Empire@ empire) {
|
|
@emp = empire;
|
|
}
|
|
|
|
void call(GuiContextMenu@ menu) {
|
|
question(
|
|
locale::SURRENDER_OPTION,
|
|
format(locale::SURRENDER_PROMPT, formatEmpireName(emp)),
|
|
locale::OFFER, locale::CANCEL,
|
|
this).titleBox.color = Color(0xe00000ff);
|
|
}
|
|
|
|
void questionCallback(QuestionDialog@ dialog, int answer) {
|
|
if(answer == QA_Yes)
|
|
offerSurrender(emp);
|
|
}
|
|
|
|
void draw(GuiListbox@ ele, uint flags, const recti& absPos) override {
|
|
drawRectangle(absPos, Color(0xff000020));
|
|
GuiContextOption::draw(ele, flags, absPos);
|
|
}
|
|
};
|
|
|
|
class TreatyDialog : Dialog {
|
|
Empire@ withEmpire;
|
|
GuiMarkupText@ description;
|
|
GuiButton@ accept;
|
|
GuiButton@ cancel;
|
|
|
|
GuiText@ nameLabel;
|
|
GuiTextbox@ nameBox;
|
|
|
|
GuiPanel@ clausePanel;
|
|
array<const InfluenceClauseType@> clauses;
|
|
array<GuiCheckbox@> clauseChecks;
|
|
|
|
TreatyDialog(IGuiElement@ bind, Empire@ withEmpire) {
|
|
@this.withEmpire = withEmpire;
|
|
super(bind, bindInside=true);
|
|
width = 500;
|
|
height = 400;
|
|
|
|
@accept = GuiButton(bg, recti());
|
|
accept.text = locale::PROPOSE;
|
|
accept.tabIndex = 100;
|
|
accept.color = Color(0xaaffaaff);
|
|
@accept.callback = this;
|
|
|
|
@cancel = GuiButton(bg, recti());
|
|
cancel.text = locale::CANCEL;
|
|
cancel.tabIndex = 101;
|
|
@cancel.callback = this;
|
|
|
|
@description = GuiMarkupText(window, Alignment(Left+12, Top+32, Right-12, Top+85));
|
|
description.text = locale::TREATY_DESC;
|
|
|
|
//Generate a random treaty name
|
|
string genName;
|
|
array<string> names;
|
|
for(uint i = 0, cnt = systemCount; i < cnt; ++i) {
|
|
auto@ reg = getSystem(i).object;
|
|
if(reg.TradeMask & playerEmpire.mask != 0)
|
|
names.insertLast(reg.name);
|
|
if(reg.visiblePrimaryEmpire is withEmpire)
|
|
names.insertLast(reg.name);
|
|
}
|
|
if(names.length > 0)
|
|
genName = names[randomi(0, names.length-1)];
|
|
else
|
|
genName = getSystem(randomi(0, systemCount-1)).object.name;
|
|
genName = format(locale::TREATY_NAME_GEN, genName);
|
|
|
|
//Name input
|
|
@nameLabel = GuiText(window, Alignment(Left+18, Top+85, Left+100, Height=34), locale::NAME);
|
|
nameLabel.font = FT_Bold;
|
|
@nameBox = GuiTextbox(window, Alignment(Left+100, Top+85, Right-18, Height=34), genName);
|
|
nameBox.font = FT_Subtitle;
|
|
|
|
//Clause selection
|
|
@clausePanel = GuiPanel(window, Alignment(Left+12, Top+125, Right-12, Bottom-40));
|
|
int y = 0;
|
|
for(uint i = 0, cnt = getInfluenceClauseTypeCount(); i < cnt; ++i) {
|
|
auto@ type = getInfluenceClauseType(i);
|
|
if(!type.freeClause)
|
|
continue;
|
|
|
|
GuiSprite(clausePanel, Alignment(Left+12, Top+y, Width=30, Height=30), type.icon);
|
|
clauses.insertLast(type);
|
|
|
|
GuiCheckbox check(clausePanel, Alignment(Left+46, Top+y, Right-22, Height=30),
|
|
type.name, type.defaultClause);
|
|
clauseChecks.insertLast(check);
|
|
setMarkupTooltip(check, format("[b]$1[/b]\n$2", type.name, type.description), width=350);
|
|
|
|
y += 40;
|
|
}
|
|
|
|
addTitle(locale::PROPOSE_TREATY, color=colors::Green);
|
|
alignAcceptButtons(accept, cancel);
|
|
|
|
updatePosition();
|
|
}
|
|
|
|
void close() {
|
|
close(false);
|
|
}
|
|
|
|
void close(bool accepted) {
|
|
if(accepted) {
|
|
Treaty treaty;
|
|
treaty.name = nameBox.text;
|
|
for(uint i = 0, cnt = clauses.length; i < cnt; ++i) {
|
|
if(clauseChecks[i].checked)
|
|
treaty.addClause(clauses[i]);
|
|
}
|
|
treaty.inviteMask |= withEmpire.mask;
|
|
|
|
createTreaty(treaty);
|
|
}
|
|
Dialog::close();
|
|
}
|
|
|
|
void confirmDialog() {
|
|
close(true);
|
|
}
|
|
|
|
bool onGuiEvent(const GuiEvent& event) {
|
|
if(Closed)
|
|
return false;
|
|
if(event.type == GUI_Clicked && (event.caller is accept || event.caller is cancel)) {
|
|
close(event.caller is accept);
|
|
return true;
|
|
}
|
|
return Dialog::onGuiEvent(event);
|
|
}
|
|
};
|
|
|
|
class DonationOption : GuiContextOption {
|
|
Empire@ emp;
|
|
IGuiElement@ bind;
|
|
DonationOption(IGuiElement@ bind, Empire@ empire) {
|
|
@emp = empire;
|
|
@this.bind = bind;
|
|
}
|
|
|
|
void call(GuiContextMenu@ menu) {
|
|
DonateDialog(findTab(bind), emp);
|
|
}
|
|
};
|
|
|
|
class DonateDialog : Dialog {
|
|
GuiMarkupText@ description;
|
|
GuiOfferList@ offer;
|
|
GuiButton@ accept;
|
|
GuiButton@ cancel;
|
|
Empire@ toEmp;
|
|
|
|
DonateDialog(IGuiElement@ bind, Empire@ toEmpire) {
|
|
super(bind, bindInside=true);
|
|
width = 600;
|
|
height = 500;
|
|
@toEmp = toEmpire;
|
|
|
|
@accept = GuiButton(bg, recti());
|
|
accept.text = locale::DONATE;
|
|
accept.tabIndex = 100;
|
|
accept.disabled = true;
|
|
@accept.callback = this;
|
|
|
|
@cancel = GuiButton(bg, recti());
|
|
cancel.text = locale::CANCEL;
|
|
cancel.tabIndex = 101;
|
|
@cancel.callback = this;
|
|
|
|
@description = GuiMarkupText(window, Alignment(Left+12, Top+32, Right-12, Top+58));
|
|
addTitle(locale::DONATE_OPTION, color=colors::Green);
|
|
description.text = locale::DONATE_TEXT;
|
|
accept.color = Color(0xaaffaaff);
|
|
|
|
alignAcceptButtons(accept, cancel);
|
|
@offer = GuiOfferList(window, Alignment(Left+4, Top+58, Right-4, Bottom-40), prefix="DONATE");
|
|
|
|
updatePosition();
|
|
}
|
|
|
|
void update() {
|
|
bool canOffer = offer.offers.length != 0;
|
|
for(uint i = 0, cnt = offer.offers.length; i < cnt; ++i) {
|
|
if(!offer.offers[i].offer.canOffer(playerEmpire)) {
|
|
canOffer = false;
|
|
break;
|
|
}
|
|
}
|
|
accept.disabled = !canOffer;
|
|
}
|
|
|
|
void close() {
|
|
close(false);
|
|
}
|
|
|
|
void close(bool accepted) {
|
|
if(accepted) {
|
|
for(uint i = 0, cnt = offer.offers.length; i < cnt; ++i)
|
|
makeDonation(toEmp, offer.offers[i].offer);
|
|
}
|
|
Dialog::close();
|
|
}
|
|
|
|
void confirmDialog() {
|
|
close(true);
|
|
}
|
|
|
|
bool onGuiEvent(const GuiEvent& event) {
|
|
if(Closed)
|
|
return false;
|
|
if(event.type == GUI_Clicked && (event.caller is accept || event.caller is cancel)) {
|
|
close(event.caller is accept);
|
|
return true;
|
|
}
|
|
if(event.type == GUI_Changed) {
|
|
update();
|
|
return true;
|
|
}
|
|
return Dialog::onGuiEvent(event);
|
|
}
|
|
};
|
|
|
|
Sprite getRelationIcon(int num) {
|
|
if(num < 0)
|
|
return Sprite(material::MaskAngry);
|
|
else if(num > 0)
|
|
return Sprite(material::MaskHappy);
|
|
return Sprite(material::MaskNeutral);
|
|
}
|
|
|
|
Tab@ createDiplomacyTab() {
|
|
return DiplomacyTab();
|
|
}
|
|
|
|
void showInfluenceVote(uint voteId) {
|
|
Tab@ tab = findTab(TC_Diplomacy);
|
|
if(tab is null) {
|
|
@tab = createInfluenceVoteTab(voteId);
|
|
newTab(tab);
|
|
switchToTab(tab);
|
|
}
|
|
else {
|
|
InfluenceVoteTab@ ivt = cast<InfluenceVoteTab>(tab);
|
|
if(ivt !is null) {
|
|
ivt.update(voteId);
|
|
switchToTab(ivt);
|
|
}
|
|
else {
|
|
switchToTab(tab);
|
|
browseTab(tab, createInfluenceVoteTab(voteId), true);
|
|
}
|
|
}
|
|
}
|
|
|
|
void showDiplomacy() {
|
|
Tab@ found = findTab(TC_Diplomacy);
|
|
if(cast<DiplomacyTab>(found) !is null)
|
|
switchToTab(found);
|
|
else
|
|
browseTab(TC_Diplomacy, createDiplomacyTab(), true, true);
|
|
}
|
|
|
|
bool isDiplomacyVisible() {
|
|
return cast<DiplomacyTab>(ActiveTab) !is null;
|
|
}
|