1140 lines
29 KiB
ActionScript
1140 lines
29 KiB
ActionScript
#section disable menu
|
|
import elements.BaseGuiElement;
|
|
import elements.GuiPanel;
|
|
import elements.GuiText;
|
|
import elements.GuiTextbox;
|
|
import elements.GuiSprite;
|
|
import elements.GuiOverlay;
|
|
import elements.GuiDropdown;
|
|
import elements.GuiSkinElement;
|
|
import elements.GuiButton;
|
|
import elements.GuiMarkupText;
|
|
import elements.GuiEmpire;
|
|
import elements.MarkupTooltip;
|
|
import elements.GuiBackgroundPanel;
|
|
import influence;
|
|
import icons;
|
|
import hooks;
|
|
import util.formatting;
|
|
from gui import animate_time, navigateInto;
|
|
|
|
#section game
|
|
import tabs.Tab;
|
|
import targeting.ObjectTarget;
|
|
#section all
|
|
|
|
export GuiInfluenceCard;
|
|
export updateCardList;
|
|
export GuiInfluenceCardPopup;
|
|
export GUI_CARD_WIDTH, GUI_CARD_HEIGHT;
|
|
export drawCardIcon;
|
|
|
|
const int GUI_CARD_WIDTH = 207;
|
|
const int GUI_CARD_HEIGHT = 137;
|
|
|
|
const vec2i CARD_ART_OFFSET(2, 32);
|
|
const vec2i CARD_ART_SIZE(201,99);
|
|
|
|
class GuiInfluenceCard : BaseGuiElement {
|
|
InfluenceCard@ card;
|
|
bool Hovered = false;
|
|
bool Focused = false;
|
|
bool Pressed = false;
|
|
bool disabled = false;
|
|
Color disabledColor;
|
|
|
|
Color cardColor = colors::White;
|
|
GuiMarkupText@ title;
|
|
|
|
GuiSprite@ qualityIcon;
|
|
GuiSprite@ typeIcon;
|
|
|
|
GuiSprite@ leaderIcon;
|
|
|
|
GuiEmpire@ empireIcon;
|
|
GuiSprite@ purchaseIcon;
|
|
GuiText@ purchaseCost;
|
|
|
|
array<GuiSprite@> varIcons;
|
|
array<GuiText@> varTexts;
|
|
|
|
GuiInfluenceCard(IGuiElement@ ParentElement) {
|
|
super(ParentElement, recti(0, 0, GUI_CARD_WIDTH, GUI_CARD_HEIGHT));
|
|
updateAbsolutePosition();
|
|
|
|
@title = GuiMarkupText(this, recti(10, 5, GUI_CARD_WIDTH - 10, 30));
|
|
|
|
@leaderIcon = GuiSprite(this, recti_area(8, 34, 34, 34));
|
|
leaderIcon.desc = Sprite(material::LeaderIcon);
|
|
setMarkupTooltip(leaderIcon, locale::TT_LEADER_CARD, false);
|
|
leaderIcon.visible = false;
|
|
|
|
@purchaseIcon = GuiSprite(this, recti_area(GUI_CARD_WIDTH - 50, GUI_CARD_HEIGHT - 50, 44, 44));
|
|
purchaseIcon.desc = icons::InfluencePurchaseCost;
|
|
@purchaseCost = GuiText(this, recti_area(GUI_CARD_WIDTH - 120, GUI_CARD_HEIGHT - 45, 70, 44));
|
|
purchaseCost.vertAlign = 0.5;
|
|
purchaseCost.horizAlign = 1.0;
|
|
purchaseCost.font = FT_Big;
|
|
purchaseCost.stroke = colors::Black;
|
|
|
|
@typeIcon = GuiSprite(this, recti_area(GUI_CARD_WIDTH - 42, 34, 34, 34));
|
|
|
|
@qualityIcon = GuiSprite(this, recti_area(GUI_CARD_WIDTH - 72, 6, 64, 22));
|
|
qualityIcon.color = Color(0xffffff40);
|
|
setMarkupTooltip(qualityIcon, locale::INFLUENCE_TT_QUALITY, false);
|
|
|
|
navigable = true;
|
|
}
|
|
|
|
void set(InfluenceCard@ c, InfluenceVote@ vote = null, bool showVariables = true, bool centerTitle = false) {
|
|
@card = c;
|
|
|
|
//Title on top
|
|
string ttext = card.formatTitle();
|
|
if(showVariables) {
|
|
if(card.uses < 0)
|
|
ttext += " ("+locale::USES_UNLIMITED+")";
|
|
else if(card.uses > 1)
|
|
ttext += " ("+card.uses+"x)";
|
|
}
|
|
|
|
if(ttext.length > 20) {
|
|
title.defaultFont = FT_Small;
|
|
title.position = vec2i(6, 6);
|
|
}
|
|
else {
|
|
title.defaultFont = FT_Normal;
|
|
title.position = vec2i(10, 4);
|
|
}
|
|
if(centerTitle)
|
|
ttext = "[center]"+ttext+"[/center]";
|
|
title.text = ttext;
|
|
title.updateAbsolutePosition();
|
|
|
|
typeIcon.desc = getInfluenceCardClassSprite(card.type.cls);
|
|
leaderIcon.visible = card.type.leaderOnly;
|
|
setMarkupTooltip(typeIcon, getInfluenceCardClassTooltip(card.type.cls), false);
|
|
|
|
//Purchase cost
|
|
auto@ stackCard = cast<StackInfluenceCard>(c);
|
|
disabled = false;
|
|
if(stackCard !is null) {
|
|
if(stackCard.purchasedBy !is null) {
|
|
if(empireIcon is null) {
|
|
@empireIcon = GuiEmpire(this, Alignment(Right-60, Bottom-60, Width=55, Height=55));
|
|
empireIcon.padding = 4;
|
|
empireIcon.background = SS_EmpireBox;
|
|
}
|
|
|
|
if(playerEmpire.valid && playerEmpire.ContactMask & stackCard.purchasedBy.mask != 0) {
|
|
empireIcon.visible = true;
|
|
@empireIcon.empire = stackCard.purchasedBy;
|
|
setMarkupTooltip(empireIcon, format(locale::INFLUENCE_TT_BOUGHTBY,
|
|
formatEmpireName(stackCard.purchasedBy)), false);
|
|
}
|
|
else {
|
|
empireIcon.visible = false;
|
|
}
|
|
|
|
purchaseIcon.visible = false;
|
|
purchaseCost.visible = false;
|
|
disabled = true;
|
|
disabledColor = stackCard.purchasedBy.color;
|
|
}
|
|
else {
|
|
int cost = card.getPurchaseCost(playerEmpire);
|
|
bool canPurchase = card.canPurchase(playerEmpire);
|
|
|
|
purchaseIcon.visible = canPurchase;
|
|
purchaseCost.visible = canPurchase;
|
|
purchaseCost.text = toString(cost);
|
|
purchaseCost.font = FT_Big;
|
|
|
|
if(canPurchase) {
|
|
string tt = format(locale::INFLUENCE_TT_BUY_COST, toString(cost));
|
|
setMarkupTooltip(purchaseIcon, tt, false);
|
|
setMarkupTooltip(purchaseCost, tt, false);
|
|
}
|
|
|
|
if(empireIcon !is null)
|
|
empireIcon.visible = false;
|
|
}
|
|
}
|
|
else {
|
|
purchaseIcon.visible = false;
|
|
purchaseCost.visible = false;
|
|
|
|
if(empireIcon !is null)
|
|
empireIcon.visible = false;
|
|
}
|
|
|
|
//Rarity
|
|
cardColor = getInfluenceCardRarityColor(c.type.rarity);
|
|
|
|
//Quality
|
|
if(c.quality > c.type.minQuality) {
|
|
int qlev = c.quality - c.type.minQuality;
|
|
|
|
int qdist = c.type.maxQuality - c.type.minQuality + 1;
|
|
if(qdist > 4)
|
|
qlev = floor(double(qlev) / double(qdist) * 4) + 1;
|
|
|
|
if(qlev > 0) {
|
|
qualityIcon.desc = Sprite(spritesheet::PlanetLevelIcons, qlev-1);
|
|
qualityIcon.visible = true;
|
|
}
|
|
else {
|
|
qualityIcon.visible = false;
|
|
}
|
|
}
|
|
else {
|
|
qualityIcon.visible = false;
|
|
}
|
|
|
|
//Variables
|
|
uint index = 0;
|
|
Sprite sprt;
|
|
string name, text, tooltip;
|
|
bool highlight = false;
|
|
if(showVariables) {
|
|
if(card.getCostVariable(sprt, name, tooltip, text, highlight, vote = vote))
|
|
addVar(index, IVM_Property, sprt, name, tooltip,text, highlight);
|
|
if(card.getWeightVariable(sprt, name, tooltip, text, highlight, vote = vote))
|
|
addVar(index, IVM_Property, sprt, name, tooltip,text, highlight);
|
|
for(uint i = 0, cnt = card.type.hooks.length; i < cnt; ++i) {
|
|
uint mode = card.type.hooks[i].getVariable(card, vote, sprt, name, tooltip, text, highlight);
|
|
if(mode != IVM_None)
|
|
addVar(index, mode, sprt, name, tooltip, text, highlight);
|
|
}
|
|
}
|
|
for(uint i = index, cnt = varIcons.length; i < cnt; ++i) {
|
|
varIcons[i].remove();
|
|
varTexts[i].remove();
|
|
}
|
|
varIcons.length = index;
|
|
varTexts.length = index;
|
|
}
|
|
|
|
void addVar(uint& index, uint mode, const Sprite& sprt, const string& name, const string& tooltip, const string& text, bool highlight) {
|
|
if(mode == IVM_PurchaseCost) {
|
|
if(purchaseIcon !is null) {
|
|
purchaseIcon.desc = sprt;
|
|
purchaseCost.text = text;
|
|
if(purchaseCost.getTextDimension().x >= purchaseCost.size.width)
|
|
purchaseCost.font = FT_Medium;
|
|
else
|
|
purchaseCost.font = FT_Big;
|
|
}
|
|
return;
|
|
}
|
|
|
|
if(varIcons.length <= index) {
|
|
varIcons.resize(index+1);
|
|
varTexts.resize(index+1);
|
|
}
|
|
|
|
auto@ icon = varIcons[index];
|
|
if(icon is null) {
|
|
@icon = GuiSprite(this, recti_area(vec2i(8, GUI_CARD_HEIGHT - 30 - 26*index), vec2i(24, 24)));
|
|
@varIcons[index] = icon;
|
|
}
|
|
|
|
setMarkupTooltip(icon, tooltip, false);
|
|
icon.desc = sprt;
|
|
|
|
auto@ txt = varTexts[index];
|
|
if(txt is null) {
|
|
@txt = GuiText(this, recti_area(vec2i(38, GUI_CARD_HEIGHT - 29 - 26*index), vec2i(40, 24)));
|
|
txt.stroke = colors::Black;
|
|
@varTexts[index] = txt;
|
|
}
|
|
|
|
setMarkupTooltip(txt, tooltip, false);
|
|
txt.text = text;
|
|
|
|
if(highlight) {
|
|
txt.font = FT_Bold;
|
|
txt.color = Color(0xffcd00ff);
|
|
}
|
|
else {
|
|
txt.font = FT_Normal;
|
|
txt.color = colors::White;
|
|
}
|
|
|
|
index += 1;
|
|
}
|
|
|
|
bool onGuiEvent(const GuiEvent& event) {
|
|
if(event.caller is this) {
|
|
switch(event.type) {
|
|
case GUI_Mouse_Entered:
|
|
Hovered = true;
|
|
break;
|
|
case GUI_Mouse_Left:
|
|
Hovered = false;
|
|
break;
|
|
case GUI_Focused:
|
|
Focused = true;
|
|
break;
|
|
case GUI_Focus_Lost:
|
|
Focused = false;
|
|
break;
|
|
case GUI_Controller_Down:
|
|
if(event.caller is this) {
|
|
if(event.value == GP_A) {
|
|
Pressed = true;
|
|
return true;
|
|
}
|
|
}
|
|
break;
|
|
case GUI_Controller_Up:
|
|
if(Focused) {
|
|
if(event.value == GP_A) {
|
|
Pressed = false;
|
|
emitClicked();
|
|
return true;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
return BaseGuiElement::onGuiEvent(event);
|
|
}
|
|
|
|
bool onMouseEvent(const MouseEvent& event, IGuiElement@ source) {
|
|
switch(event.type) {
|
|
case MET_Button_Down:
|
|
if(event.button == 0) {
|
|
Pressed = true;
|
|
return true;
|
|
}
|
|
break;
|
|
case MET_Button_Up:
|
|
if(event.button == 0) {
|
|
if(Pressed) {
|
|
Pressed = false;
|
|
emitClicked();
|
|
}
|
|
return true;
|
|
}
|
|
break;
|
|
}
|
|
return BaseGuiElement::onMouseEvent(event, source);
|
|
}
|
|
|
|
void updateAbsolutePosition() {
|
|
BaseGuiElement::updateAbsolutePosition();
|
|
}
|
|
|
|
uint get_flags() {
|
|
uint flags = SF_Normal;
|
|
if(disabled)
|
|
flags |= SF_Disabled;
|
|
if(Pressed)
|
|
flags |= SF_Active;
|
|
if(Hovered)
|
|
flags |= SF_Hovered;
|
|
if(Focused)
|
|
flags |= SF_Focused;
|
|
return flags;
|
|
}
|
|
|
|
void draw() {
|
|
if(card is null)
|
|
return;
|
|
|
|
uint index = 0;
|
|
if(Hovered)
|
|
index = 2;
|
|
else if(Pressed || Focused)
|
|
index = 1;
|
|
|
|
if(card.uses > 1)
|
|
spritesheet::ActionCard.draw(index, AbsolutePosition+vec2i(3,3), cardColor);
|
|
recti ipos = recti_area(AbsolutePosition.topLeft+CARD_ART_OFFSET, CARD_ART_SIZE);
|
|
drawRectangle(ipos, Color(0x202020ff));
|
|
if(card.type.icon.valid)
|
|
card.type.icon.draw(ipos.aspectAligned(card.type.icon.aspect));
|
|
spritesheet::ActionCard.draw(index, AbsolutePosition, cardColor);
|
|
if(disabled)
|
|
spritesheet::ActionCard.draw(4, AbsolutePosition, disabledColor);
|
|
skin.draw(SS_FullTitle, SF_Normal, recti_area(
|
|
AbsolutePosition.topLeft + vec2i(2, 2),
|
|
vec2i(GUI_CARD_WIDTH - 6, 30)), card.type.color);
|
|
BaseGuiElement::draw();
|
|
}
|
|
};
|
|
|
|
int updateCardList(IGuiElement@ panel, array<InfluenceCard@> cards, GuiInfluenceCard@[]@ boxes, double horizAlign = 0.0, InfluenceVote@ vote = null, bool filterPlayable = true) {
|
|
uint oldCnt = boxes.length;
|
|
uint newCnt = cards.length;
|
|
|
|
//Remove old boxes
|
|
for(uint i = newCnt; i < oldCnt; ++i) {
|
|
if(boxes[i] !is null)
|
|
boxes[i].remove();
|
|
}
|
|
boxes.length = newCnt;
|
|
|
|
//Do alignment
|
|
vec2i pos(4, 4);
|
|
if(horizAlign != 0.0) {
|
|
int perRow = floor(double(panel.size.width) / double(GUI_CARD_WIDTH + 4));
|
|
int rowWidth = min(perRow, newCnt) * (GUI_CARD_WIDTH + 4);
|
|
pos.x = (panel.size.width - rowWidth) / 2;
|
|
}
|
|
|
|
//Update boxes
|
|
uint n = 0;
|
|
for(uint i = 0; i < newCnt; ++i) {
|
|
//Figure out if the card is usable
|
|
if(vote !is null) {
|
|
if(filterPlayable) {
|
|
if(!cards[i].canPlay(vote, null))
|
|
continue;
|
|
}
|
|
else {
|
|
if(cards[i].type.cls != ICC_Support)
|
|
continue;
|
|
}
|
|
}
|
|
|
|
//Create box if needed
|
|
if(boxes[n] is null)
|
|
@boxes[n] = GuiInfluenceCard(panel);
|
|
|
|
//Update the card box
|
|
GuiInfluenceCard@ box = boxes[n];
|
|
box.set(cards[i], vote);
|
|
|
|
//Position the card
|
|
box.position = pos;
|
|
|
|
pos.x += GUI_CARD_WIDTH + 4;
|
|
if(pos.x + GUI_CARD_WIDTH > panel.size.width - 20) {
|
|
pos.x = 4;
|
|
pos.y += GUI_CARD_HEIGHT + 4;
|
|
}
|
|
++n;
|
|
}
|
|
|
|
for(uint i = n; i < newCnt; ++i) {
|
|
if(boxes[i] !is null) {
|
|
boxes[i].remove();
|
|
@boxes[i] = null;
|
|
}
|
|
}
|
|
|
|
if(pos.x == 4)
|
|
return pos.y;
|
|
else
|
|
return pos.y + GUI_CARD_HEIGHT + 4;
|
|
}
|
|
|
|
final class TargetingOption {
|
|
uint target = uint(-1);
|
|
GuiDropdown@ dropdown;
|
|
GuiTextbox@ textbox;
|
|
array<Target@> potentials;
|
|
Target defaultTarget;
|
|
|
|
TargetingOption(uint index) {
|
|
target = index;
|
|
}
|
|
|
|
void create(IGuiElement@ elem, int y, Target@ target) {
|
|
Alignment align(Left+CARD_ART_SIZE.x+30, Bottom-y, Right-30, Bottom-y+34);
|
|
if(target.type == TT_String)
|
|
@textbox = GuiTextbox(elem, align, target.str);
|
|
else
|
|
@dropdown = GuiDropdown(elem, align);
|
|
defaultTarget = target;
|
|
}
|
|
|
|
void add(InfluenceCard@ card, Target@ targ, const string& name) {
|
|
if(!card.isValidTarget(target, targ))
|
|
return;
|
|
if(dropdown is null)
|
|
return;
|
|
|
|
dropdown.addItem(GuiMarkupListText(name));
|
|
potentials.insertLast(targ);
|
|
|
|
if(targ == defaultTarget)
|
|
dropdown.selected = potentials.length - 1;
|
|
}
|
|
|
|
void fill(Targets@ targets) {
|
|
if(target >= targets.targets.length)
|
|
return;
|
|
|
|
if(dropdown !is null) {
|
|
uint sel = uint(dropdown.selected);
|
|
if(sel >= potentials.length) {
|
|
targets[target].filled = false;
|
|
return;
|
|
}
|
|
|
|
targets[target].filled = true;
|
|
targets[target] = potentials[sel];
|
|
}
|
|
else if(textbox !is null) {
|
|
targets[target].filled = true;
|
|
targets[target].str = textbox.text;
|
|
}
|
|
}
|
|
};
|
|
|
|
class GuiInfluenceCardPopup : BaseGuiElement {
|
|
GuiOverlay@ overlay;
|
|
IGuiElement@ around;
|
|
int cardId = -1;
|
|
int cost = 0;
|
|
bool animating = false;
|
|
|
|
int awaitsObjectTarget = -1;
|
|
|
|
InfluenceVote@ vote;
|
|
InfluenceCard@ card;
|
|
Targets targets;
|
|
|
|
GuiBackgroundPanel@ panel;
|
|
GuiSprite@ qualityIcon;
|
|
GuiSprite@ image;
|
|
GuiMarkupText@ description;
|
|
|
|
array<TargetingOption@> options;
|
|
array<Empire@> targetEmpireList;
|
|
|
|
GuiButton@ supportButton;
|
|
GuiButton@ opposeButton;
|
|
|
|
bool haveButtons = false;
|
|
|
|
GuiButton@ purchaseButton;
|
|
GuiSprite@ purchaseIcon;
|
|
GuiText@ purchaseCost;
|
|
|
|
GuiButton@ playButton;
|
|
|
|
array<GuiSprite@> varIcons;
|
|
array<GuiText@> varNames;
|
|
array<GuiText@> varTexts;
|
|
|
|
GuiInfluenceCardPopup(IGuiElement@ Parent, IGuiElement@ Around, InfluenceCard@ card, bool animate = true, InfluenceVote@ vote = null, bool playable = true) {
|
|
@around = Around;
|
|
@overlay = GuiOverlay(Parent);
|
|
overlay.closeSelf = false;
|
|
super(overlay, recti(0, 0, 600, 400));
|
|
@this.card = card;
|
|
@this.vote = vote;
|
|
cardId = card.id;
|
|
|
|
targets = card.targets;
|
|
card.targetDefaults(targets);
|
|
|
|
@panel = GuiBackgroundPanel(this, Alignment_Fill());
|
|
panel.titleStyle = SS_FullTitle;
|
|
panel.markup = true;
|
|
panel.titleColor = card.type.color;
|
|
|
|
string ttext = card.formatTitle();
|
|
if(card.uses < 0)
|
|
ttext += " ("+locale::USES_UNLIMITED+")";
|
|
else if(card.uses > 1)
|
|
ttext += " ("+card.uses+"x)";
|
|
panel.title = ttext;
|
|
|
|
//Quality
|
|
@qualityIcon = GuiSprite(panel, Alignment(Right-72, Top+6, Width=64, Height=22));
|
|
qualityIcon.color = Color(0xffffff40);
|
|
setMarkupTooltip(qualityIcon, locale::INFLUENCE_TT_QUALITY, false);
|
|
|
|
if(card.quality > card.type.minQuality) {
|
|
int qlev = card.quality - card.type.minQuality;
|
|
|
|
int qdist = card.type.maxQuality - card.type.minQuality + 1;
|
|
if(qdist > 4)
|
|
qlev = floor(double(qlev) / double(qdist) * 4) + 1;
|
|
|
|
if(qlev > 0) {
|
|
qualityIcon.desc = Sprite(spritesheet::PlanetLevelIcons, qlev-1);
|
|
qualityIcon.visible = true;
|
|
}
|
|
else {
|
|
qualityIcon.visible = false;
|
|
}
|
|
}
|
|
else {
|
|
qualityIcon.visible = false;
|
|
}
|
|
|
|
@image = GuiSprite(this, recti_area(vec2i(16, 36), CARD_ART_SIZE));
|
|
image.desc = card.type.icon;
|
|
|
|
@description = GuiMarkupText(this, recti(26+CARD_ART_SIZE.x, 36, size.width-16, CARD_ART_SIZE.y+96));
|
|
description.text = card.formatDescription();
|
|
|
|
int btnWidth = (size.width - CARD_ART_SIZE.x - 42);
|
|
int btnStart = CARD_ART_SIZE.x + 30;
|
|
if(cast<StackInfluenceCard>(card) !is null) {
|
|
bool canPurchase = card.canPurchase(playerEmpire);
|
|
|
|
if(canPurchase) {
|
|
@purchaseIcon = GuiSprite(this, Alignment(Right-50, Bottom-50, Width=44, Height=44));
|
|
purchaseIcon.desc = icons::InfluencePurchaseCost;
|
|
|
|
@purchaseCost = GuiText(this, Alignment(Right-120, Bottom-45, Width=70, Height=44));
|
|
purchaseCost.vertAlign = 0.5;
|
|
purchaseCost.horizAlign = 1.0;
|
|
purchaseCost.font = FT_Big;
|
|
|
|
cost = card.getPurchaseCost(playerEmpire);
|
|
purchaseCost.text = toString(cost);
|
|
|
|
@purchaseButton = GuiButton(this, Alignment(
|
|
Left+((btnWidth-160)/2+btnStart), Bottom-44,
|
|
Width=160, Height=34), locale::PURCHASE_CARD);
|
|
purchaseButton.color = Color(0x20adffff);
|
|
purchaseButton.disabled = !card.hasPurchaseCost(playerEmpire);
|
|
haveButtons = true;
|
|
}
|
|
}
|
|
else if(playable) {
|
|
if(card.type.cls == ICC_Support) {
|
|
if(vote !is null) {
|
|
if(card.type.sideMode == ICS_Neutral) {
|
|
@playButton = GuiButton(this, Alignment(
|
|
Left+((btnWidth-160)/2+btnStart), Bottom-44,
|
|
Width=160, Height=34), locale::PLAY_NEUTRAL);
|
|
playButton.color = Color(0xffad20ff);
|
|
haveButtons = true;
|
|
}
|
|
else if(card.type.sideMode == ICS_Both) {
|
|
@supportButton = GuiButton(this, Alignment(
|
|
Left+((btnWidth-160)/2+btnStart)-84, Bottom-44,
|
|
Width=160, Height=34), locale::PLAY_SUPPORT);
|
|
supportButton.color = Color(0xddffdbff);
|
|
haveButtons = true;
|
|
|
|
@opposeButton = GuiButton(this, Alignment(
|
|
Left+((btnWidth-160)/2+btnStart)+84, Bottom-44,
|
|
Width=160, Height=34), locale::PLAY_OPPOSE);
|
|
opposeButton.color = Color(0xffe3dbff);
|
|
haveButtons = true;
|
|
}
|
|
else if(card.type.sideMode == ICS_Support) {
|
|
@supportButton = GuiButton(this, Alignment(
|
|
Left+((btnWidth-160)/2+btnStart), Bottom-44,
|
|
Width=160, Height=34), locale::PLAY_SUPPORT);
|
|
supportButton.color = Color(0xddffdbff);
|
|
haveButtons = true;
|
|
}
|
|
else if(card.type.sideMode == ICS_Oppose) {
|
|
@opposeButton = GuiButton(this, Alignment(
|
|
Left+((btnWidth-160)/2+btnStart), Bottom-44,
|
|
Width=160, Height=34), locale::PLAY_OPPOSE);
|
|
opposeButton.color = Color(0xffe3dbff);
|
|
haveButtons = true;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
@playButton = GuiButton(this, Alignment(
|
|
Left+((btnWidth-160)/2+btnStart), Bottom-44,
|
|
Width=160, Height=34), locale::PLAY_CARD);
|
|
playButton.color = Color(0xffad20ff);
|
|
haveButtons = true;
|
|
}
|
|
|
|
if(haveButtons) {
|
|
uint targCnt = targets.targets.length;
|
|
int y = 82;
|
|
for(uint i = 0; i < targCnt; ++i) {
|
|
auto@ targ = targets.targets[i];
|
|
if(card.targets[i].filled)
|
|
continue;
|
|
if(targ.type == TT_Empire) {
|
|
TargetingOption opt(i);
|
|
opt.create(this, y, targ);
|
|
options.insertLast(opt);
|
|
|
|
for(uint i = 0, cnt = getEmpireCount(); i < cnt; ++i) {
|
|
Empire@ emp = getEmpire(i);
|
|
if(!emp.major)
|
|
continue;
|
|
if(playerEmpire.ContactMask & emp.mask == 0)
|
|
continue;
|
|
|
|
Target targ(TT_Empire);
|
|
targ.filled = true;
|
|
@targ.emp = emp;
|
|
|
|
opt.add(card, targ, formatEmpireName(emp));
|
|
}
|
|
|
|
y += 40;
|
|
}
|
|
else if(targ.type == TT_Card) {
|
|
array<InfluenceCard> cards;
|
|
cards.syncFrom(playerEmpire.getInfluenceCards());
|
|
|
|
TargetingOption opt(i);
|
|
opt.create(this, y, targ);
|
|
options.insertLast(opt);
|
|
|
|
for(uint i = 0, cnt = cards.length; i < cnt; ++i) {
|
|
auto@ c = cards[i];
|
|
|
|
Target targ(TT_Card);
|
|
targ.filled = true;
|
|
targ.id = c.id;
|
|
|
|
opt.add(card, targ, c.formatBlurb());
|
|
}
|
|
|
|
y += 40;
|
|
}
|
|
else if(targ.type == TT_Effect) {
|
|
array<InfluenceEffect> effects;
|
|
effects.syncFrom(getActiveInfluenceEffects());
|
|
|
|
TargetingOption opt(i);
|
|
opt.create(this, y, targ);
|
|
options.insertLast(opt);
|
|
|
|
for(uint i = 0, cnt = effects.length; i < cnt; ++i) {
|
|
auto@ eff = effects[i];
|
|
if(eff.owner !is null && playerEmpire.valid && playerEmpire.ContactMask & eff.owner.mask == 0)
|
|
continue;
|
|
|
|
Target targ(TT_Effect);
|
|
targ.filled = true;
|
|
targ.id = eff.id;
|
|
|
|
string title = eff.formatTitle();
|
|
title = format("$3: [color=$2]$1[/color]", title, toString(eff.type.color), formatEmpireName(eff.owner));
|
|
|
|
opt.add(card, targ, title);
|
|
}
|
|
|
|
y += 40;
|
|
}
|
|
else if(targ.type == TT_String) {
|
|
TargetingOption opt(i);
|
|
opt.create(this, y, targ);
|
|
options.insertLast(opt);
|
|
|
|
y += 40;
|
|
}
|
|
else if(targ.type == TT_Object) {
|
|
awaitsObjectTarget = int(i);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//Add variables
|
|
uint index = 0;
|
|
Sprite sprt;
|
|
string name, text, tooltip;
|
|
bool highlight = false;
|
|
if(card.getCostVariable(sprt, name, tooltip, text, highlight, vote=vote))
|
|
addVar(index, IVM_Property, sprt, name, tooltip, text, highlight);
|
|
if(card.getWeightVariable(sprt, name, tooltip, text, highlight, vote=vote))
|
|
addVar(index, IVM_Property, sprt, name, tooltip, text, highlight);
|
|
for(uint i = 0, cnt = card.type.hooks.length; i < cnt; ++i) {
|
|
uint mode = card.type.hooks[i].getVariable(card, vote, sprt, name, tooltip, text, highlight);
|
|
if(mode != IVM_None)
|
|
addVar(index, mode, sprt, name, tooltip, text, highlight);
|
|
}
|
|
|
|
for(uint i = index, cnt = varIcons.length; i < cnt; ++i) {
|
|
varIcons[i].remove();
|
|
varTexts[i].remove();
|
|
}
|
|
varIcons.length = index;
|
|
varTexts.length = index;
|
|
|
|
updateAbsolutePosition();
|
|
if(animate) {
|
|
recti target = targetPosition;
|
|
rect = around.absolutePosition - Parent.absolutePosition.topLeft;
|
|
animating = true;
|
|
animate_time(this, target, 0.2);
|
|
}
|
|
|
|
navigateInto(this);
|
|
onChange();
|
|
}
|
|
|
|
void onChange() {
|
|
bool playable = true;
|
|
for(uint i = 0, cnt = options.length; i < cnt; ++i) {
|
|
options[i].fill(targets);
|
|
if(!card.isValidTarget(options[i].target, targets.targets[options[i].target]))
|
|
playable = false;
|
|
}
|
|
|
|
if(awaitsObjectTarget == -1 && playable) {
|
|
if(vote !is null)
|
|
playable = card.canPlay(vote, targets);
|
|
else
|
|
playable = card.canPlay(targets);
|
|
}
|
|
|
|
if(card.type.sideMode != ICS_Neutral) {
|
|
auto@ targ = targets.fill("VoteSide");
|
|
if(targ !is null) {
|
|
if(supportButton !is null) {
|
|
targ.side = true;
|
|
supportButton.disabled = !card.canPlay(vote, targets)
|
|
|| playerEmpire.Influence < card.getPlayCost(vote, targets);
|
|
}
|
|
if(opposeButton !is null) {
|
|
targ.side = false;
|
|
opposeButton.disabled = !card.canPlay(vote, targets)
|
|
|| playerEmpire.Influence < card.getPlayCost(vote, targets);
|
|
}
|
|
}
|
|
}
|
|
|
|
if(playButton !is null) {
|
|
if(vote !is null) {
|
|
playButton.disabled = !playable
|
|
|| playerEmpire.Influence < card.getPlayCost(vote, targets);
|
|
}
|
|
else {
|
|
playButton.disabled = !playable
|
|
|| (playerEmpire.Influence < card.getPlayCost(null, targets) && awaitsObjectTarget == -1);
|
|
}
|
|
}
|
|
|
|
if(purchaseButton !is null) {
|
|
int cost = card.getPurchaseCost(playerEmpire);
|
|
purchaseButton.disabled = !card.hasPurchaseCost(playerEmpire);
|
|
}
|
|
}
|
|
|
|
void addVar(uint& index, uint mode, const Sprite& sprt, const string& name, const string& tooltip, const string& text, bool highlight) {
|
|
if(mode == IVM_PurchaseCost) {
|
|
if(purchaseIcon !is null) {
|
|
purchaseIcon.desc = sprt;
|
|
purchaseCost.text = text;
|
|
if(purchaseCost.getTextDimension().x >= purchaseCost.size.width)
|
|
purchaseCost.font = FT_Medium;
|
|
else
|
|
purchaseCost.font = FT_Big;
|
|
}
|
|
return;
|
|
}
|
|
|
|
if(varIcons.length <= index) {
|
|
varIcons.resize(index+1);
|
|
varTexts.resize(index+1);
|
|
varNames.resize(index+1);
|
|
}
|
|
|
|
auto@ icon = varIcons[index];
|
|
if(icon is null) {
|
|
@icon = GuiSprite(this, Alignment(Left+8, Bottom - 30 - 26*index, Width=24, Height=24));
|
|
@varIcons[index] = icon;
|
|
}
|
|
|
|
icon.desc = sprt;
|
|
setMarkupTooltip(icon, tooltip, false);
|
|
|
|
auto@ nm = varNames[index];
|
|
if(nm is null) {
|
|
@nm = GuiText(this, Alignment(Left+38, Bottom - 32 - 26*index, Width=CARD_ART_SIZE.x-90, Height=30));
|
|
@varNames[index] = nm;
|
|
}
|
|
|
|
nm.text = name;
|
|
setMarkupTooltip(nm, tooltip, false);
|
|
|
|
auto@ txt = varTexts[index];
|
|
if(txt is null) {
|
|
@txt = GuiText(this, Alignment(Left+CARD_ART_SIZE.x-50, Bottom - 32 - 26*index, Width=50, Height=30));
|
|
txt.horizAlign = 1.0;
|
|
@varTexts[index] = txt;
|
|
}
|
|
|
|
txt.text = text;
|
|
setMarkupTooltip(txt, tooltip, false);
|
|
|
|
if(highlight) {
|
|
txt.font = FT_Bold;
|
|
txt.color = Color(0xffcd00ff);
|
|
}
|
|
else {
|
|
txt.font = FT_Normal;
|
|
txt.color = colors::White;
|
|
}
|
|
|
|
index += 1;
|
|
}
|
|
|
|
void play() {
|
|
for(uint i = 0, cnt = options.length; i < cnt; ++i)
|
|
options[i].fill(targets);
|
|
|
|
if(vote !is null) {
|
|
if(awaitsObjectTarget != -1) {
|
|
#section game
|
|
targetObject(CardTargeting(card, uint(awaitsObjectTarget), targets, vote), cast<Tab>(overlay.parent));
|
|
#section all
|
|
}
|
|
else {
|
|
sound::card_play.play(priority=true);
|
|
playInfluenceCard(cardId, targets, voteId = vote.id);
|
|
}
|
|
}
|
|
else {
|
|
if(awaitsObjectTarget != -1) {
|
|
#section game
|
|
targetObject(CardTargeting(card, uint(awaitsObjectTarget), targets), cast<Tab>(overlay.parent));
|
|
#section all
|
|
}
|
|
else {
|
|
sound::card_play.play(priority=true);
|
|
playInfluenceCard(cardId, targets);
|
|
}
|
|
}
|
|
overlay.close();
|
|
emitConfirmed();
|
|
}
|
|
|
|
bool onGuiEvent(const GuiEvent& event) {
|
|
switch(event.type) {
|
|
case GUI_Clicked:
|
|
if(event.caller is supportButton) {
|
|
targets.fill("VoteSide").side = true;
|
|
for(uint i = 0, cnt = options.length; i < cnt; ++i)
|
|
options[i].fill(targets);
|
|
if(awaitsObjectTarget != -1) {
|
|
#section game
|
|
targetObject(CardTargeting(card, uint(awaitsObjectTarget), targets, vote), cast<Tab>(overlay.parent));
|
|
#section all
|
|
}
|
|
else {
|
|
sound::card_play.play(priority=true);
|
|
playInfluenceCard(cardId, targets, voteId = vote.id);
|
|
}
|
|
overlay.close();
|
|
emitConfirmed();
|
|
return true;
|
|
}
|
|
else if(event.caller is opposeButton) {
|
|
targets.fill("VoteSide").side = false;
|
|
for(uint i = 0, cnt = options.length; i < cnt; ++i)
|
|
options[i].fill(targets);
|
|
if(awaitsObjectTarget != -1) {
|
|
#section game
|
|
targetObject(CardTargeting(card, uint(awaitsObjectTarget), targets, vote), cast<Tab>(overlay.parent));
|
|
#section all
|
|
}
|
|
else {
|
|
sound::card_play.play(priority=true);
|
|
playInfluenceCard(cardId, targets, voteId = vote.id);
|
|
}
|
|
overlay.close();
|
|
emitConfirmed();
|
|
return true;
|
|
}
|
|
else if(event.caller is purchaseButton) {
|
|
sound::card_draw.play(priority=true);
|
|
buyCardFromInfluenceStack(cardId);
|
|
overlay.close();
|
|
emitConfirmed();
|
|
return true;
|
|
}
|
|
else if(event.caller is playButton) {
|
|
play();
|
|
return true;
|
|
}
|
|
break;
|
|
case GUI_Confirmed:
|
|
if(event.caller !is this) {
|
|
if(playButton !is null)
|
|
play();
|
|
return true;
|
|
}
|
|
break;
|
|
case GUI_Changed:
|
|
onChange();
|
|
return true;
|
|
case GUI_Animation_Complete:
|
|
animating = false;
|
|
updateAbsolutePosition();
|
|
return true;
|
|
case GUI_Controller_Down:
|
|
return true;
|
|
case GUI_Controller_Up:
|
|
overlay.close();
|
|
return true;
|
|
}
|
|
return BaseGuiElement::onGuiEvent(event);
|
|
}
|
|
|
|
recti get_targetPosition() {
|
|
if(around is null || overlay is null || overlay.parent is null)
|
|
return recti();
|
|
|
|
int bpos = CARD_ART_SIZE.y + varTexts.length * 30;
|
|
int afterdesc = 8 + 40 * options.length;
|
|
if(haveButtons)
|
|
afterdesc += 40;
|
|
bpos = max(bpos, description.size.height + afterdesc);
|
|
|
|
vec2i sz = vec2i(size.width, bpos+38);
|
|
vec2i pos = (around.absolutePosition.topLeft - overlay.parent.absolutePosition.topLeft);
|
|
pos -= (sz - around.size) / 2;
|
|
if(pos.x < 4)
|
|
pos.x = 4;
|
|
if(pos.x + sz.x > overlay.size.x - 4)
|
|
pos.x = overlay.size.x - sz.x - 4;
|
|
if(pos.y < 4)
|
|
pos.y = 4;
|
|
if(pos.y + sz.y > overlay.size.y - 4)
|
|
pos.y = overlay.size.y - sz.y - 4;
|
|
return recti_area(pos, sz);
|
|
}
|
|
|
|
void updateAbsolutePosition() {
|
|
if(!animating)
|
|
rect = targetPosition;
|
|
BaseGuiElement::updateAbsolutePosition();
|
|
}
|
|
|
|
void remove() {
|
|
setGuiFocus(around);
|
|
@around = null;
|
|
BaseGuiElement::remove();
|
|
}
|
|
|
|
double update = 0.0;
|
|
void draw() override {
|
|
update += frameLength;
|
|
if(update >= 1.0) {
|
|
onChange();
|
|
update = 0.0;
|
|
}
|
|
BaseGuiElement::draw();
|
|
}
|
|
};
|
|
|
|
void drawCardIcon(const InfluenceCard@ card, const recti& pos, int uses = 0) {
|
|
Sprite icon = card.type.icon;
|
|
vec2i iconSize = icon.size;
|
|
recti iconPos;
|
|
if(uses == 0)
|
|
uses = card.uses;
|
|
if(iconSize.y != 0) {
|
|
iconPos = pos.padded(6, 6);
|
|
iconPos = iconPos.aspectAligned(double(iconSize.width) / double(iconSize.height));
|
|
}
|
|
|
|
Empire@ purchaser;
|
|
auto@ stackCard = cast<const StackInfluenceCard@>(card);
|
|
if(stackCard !is null)
|
|
@purchaser = stackCard.purchasedBy;
|
|
|
|
Color col;
|
|
if(purchaser !is null)
|
|
col = purchaser.color;
|
|
|
|
icon.draw(iconPos);
|
|
|
|
//Draw uses
|
|
int x = 4;
|
|
if(uses > 1) {
|
|
for(int i = 0; i < uses; ++i) {
|
|
drawRectangle(recti_area(vec2i(pos.topLeft.x+x, pos.botRight.y-9), vec2i(5, 5)), Color(0x991c1cff));
|
|
x += 8;
|
|
}
|
|
}
|
|
|
|
//Draw quality
|
|
uint quality = card.extraQuality;
|
|
x = pos.size.x - 9;
|
|
for(uint i = 0; i < quality; ++i) {
|
|
drawRectangle(recti_area(vec2i(pos.topLeft.x+x, pos.topLeft.y+4), vec2i(5, 5)), Color(0xe4d154ff));
|
|
x -= 8;
|
|
}
|
|
|
|
//Draw purchaser
|
|
if(purchaser !is null)
|
|
spritesheet::ContextIcons.draw(1, iconPos, col);
|
|
}
|
|
|
|
#section game
|
|
class CardTargeting : ObjectTargeting {
|
|
InfluenceCard@ card;
|
|
Targets@ targets;
|
|
uint index;
|
|
InfluenceVote@ vote;
|
|
|
|
bool canPlay = false;
|
|
bool canPay = false;
|
|
|
|
CardTargeting(InfluenceCard@ card, uint index, Targets@ targets, InfluenceVote@ vote = null) {
|
|
this.index = index;
|
|
@this.vote = vote;
|
|
@this.card = card;
|
|
@this.targets = targets;
|
|
}
|
|
|
|
bool valid(Object@ obj) override {
|
|
@targets.targets[index].obj = obj;
|
|
targets.targets[index].filled = true;
|
|
if(vote is null) {
|
|
if(!card.canPlay(targets)) {
|
|
canPlay = false;
|
|
return false;
|
|
}
|
|
}
|
|
else {
|
|
if(!card.canPlay(vote, targets)) {
|
|
canPlay = false;
|
|
return false;
|
|
}
|
|
}
|
|
canPlay = true;
|
|
if(playerEmpire.Influence < card.getPlayCost(vote, targets)) {
|
|
canPay = false;
|
|
return false;
|
|
}
|
|
canPay = false;
|
|
return true;
|
|
}
|
|
|
|
void call(Object@ obj) override {
|
|
@targets.targets[index].obj = obj;
|
|
targets.targets[index].filled = true;
|
|
sound::card_play.play(priority=true);
|
|
if(vote is null)
|
|
playInfluenceCard(card.id, targets);
|
|
else
|
|
playInfluenceCard(card.id, targets, voteId = vote.id);
|
|
}
|
|
|
|
string message(Object@ obj, bool valid) override {
|
|
if(!canPlay)
|
|
return card.formatTitle(pretty=false);
|
|
@targets.targets[index].obj = obj;
|
|
targets.targets[index].filled = true;
|
|
int cost = card.getPlayCost(vote, targets);
|
|
return format(locale::PLAY_CARD_OPTION, card.formatTitle(pretty=false), toString(cost));
|
|
}
|
|
|
|
string desc(Object@ target, bool valid) {
|
|
if(valid)
|
|
return "";
|
|
@targets[index].obj = target;
|
|
targets[index].filled = true;
|
|
return card.getTargetError(targets);
|
|
}
|
|
};
|
|
#section all
|