1430 lines
38 KiB
ActionScript
1430 lines
38 KiB
ActionScript
#include "include/resource_constants.as"
|
|
import elements.BaseGuiElement;
|
|
import elements.Gui3DObject;
|
|
import elements.GuiOverlay;
|
|
import elements.GuiSkinElement;
|
|
import elements.GuiText;
|
|
import elements.GuiSprite;
|
|
import elements.GuiStatusBox;
|
|
import elements.GuiButton;
|
|
import elements.GuiListbox;
|
|
import elements.GuiAccordion;
|
|
import elements.GuiPanel;
|
|
import elements.GuiDistributionBar;
|
|
import elements.GuiMarkupText;
|
|
import elements.MarkupTooltip;
|
|
import planets.PlanetSurface;
|
|
import elements.GuiPlanetSurface;
|
|
import elements.GuiResources;
|
|
import elements.GuiContextMenu;
|
|
import planet_levels;
|
|
import constructible;
|
|
import tile_resources;
|
|
import buildings;
|
|
import orbitals;
|
|
import util.formatting;
|
|
import icons;
|
|
import systems;
|
|
import cargo;
|
|
import statuses;
|
|
import traits;
|
|
import overlays.Construction;
|
|
from elements.GuiResources import LEVEL_REQ;
|
|
from tabs.PlanetsTab import PlanetTree;
|
|
from gui import animate_time;
|
|
|
|
const double ANIM1_TIME = 0.15;
|
|
const double ANIM2_TIME = 0.001;
|
|
const uint BORDER = 20;
|
|
const uint WIDTH = 500;
|
|
const uint S_HEIGHT = 360;
|
|
const uint INCOME_HEIGHT = 140;
|
|
const uint VAR_H = 40;
|
|
const int MIN_TILE_SIZE = 18;
|
|
const int MIN_TILE_SIZE_HD = 26;
|
|
Resources available;
|
|
|
|
bool SHOW_PLANET_TREE = false;
|
|
|
|
// {{{ Overlay
|
|
class PlanetOverlay : GuiOverlay, ConstructionParent {
|
|
Gui3DObject@ objView;
|
|
Planet@ obj;
|
|
bool closing = false;
|
|
|
|
SurfaceDisplay@ surface;
|
|
ResourceDisplay@ resources;
|
|
ConstructionDisplay@ construction;
|
|
Resource[] resList;
|
|
|
|
Alignment@ objTarget;
|
|
|
|
PlanetOverlay(IGuiElement@ parent, Planet@ Obj) {
|
|
super(parent);
|
|
fade.a = 0;
|
|
@obj = Obj;
|
|
|
|
vec2i parSize;
|
|
if(parent is null)
|
|
parSize = screenSize;
|
|
else
|
|
parSize = parent.size;
|
|
@objView = Gui3DObject(this, recti_area(vec2i(-456, parSize.y-228), vec2i(912, 912)));
|
|
objView.internalRotation = quaterniond_fromAxisAngle(vec3d(0.0, 0.0, 1.0), -0.25*pi);
|
|
@objView.object = obj;
|
|
|
|
int plSize = parSize.x * 2;
|
|
@objTarget = Alignment(Left+0.5f-plSize/2, Top+0.5f, Width=plSize, Height=plSize);
|
|
recti targPos = objTarget.resolve(parSize);
|
|
animate_time(objView, targPos, ANIM1_TIME);
|
|
|
|
float offset = 0.05f;
|
|
if(parSize.width > 1300)
|
|
offset = 0.1f;
|
|
|
|
updateAbsolutePosition();
|
|
|
|
vec2i origin = targPos.center;
|
|
@construction = ConstructionDisplay(this, origin, Alignment(Right-offset-WIDTH,
|
|
Top+BORDER, Right-offset, Bottom-BORDER));
|
|
@surface = SurfaceDisplay(this, origin, Alignment(Left+offset,
|
|
Top+BORDER, Right-offset-BORDER-WIDTH, Top+0.6f-BORDER/2));
|
|
@resources = ResourceDisplay(this, origin, Alignment(Left+offset,
|
|
Top+0.6f+BORDER/2, Right-offset-BORDER-WIDTH, Bottom-BORDER));
|
|
}
|
|
|
|
IGuiElement@ elementFromPosition(const vec2i& pos) override {
|
|
IGuiElement@ elem = BaseGuiElement::elementFromPosition(pos);
|
|
if(elem is objView)
|
|
return this;
|
|
return elem;
|
|
}
|
|
|
|
bool onGuiEvent(const GuiEvent& evt) override {
|
|
switch(evt.type) {
|
|
case GUI_Animation_Complete:
|
|
if(evt.caller is objView) {
|
|
if(closing) {
|
|
GuiOverlay::close();
|
|
return true;
|
|
}
|
|
|
|
//Make sure the object view stays in the right position
|
|
@objView.alignment = objTarget;
|
|
|
|
//Start showing all the data
|
|
surface.animate();
|
|
resources.animate();
|
|
construction.animate();
|
|
|
|
return true;
|
|
}
|
|
break;
|
|
}
|
|
return GuiOverlay::onGuiEvent(evt);
|
|
}
|
|
|
|
bool onMouseEvent(const MouseEvent& evt, IGuiElement@ source) override {
|
|
switch(evt.type) {
|
|
case MET_Button_Up:
|
|
if(surface.selBuilding !is null) {
|
|
surface.stopBuild();
|
|
return true;
|
|
}
|
|
else if(resources.tree.isDragging || resources.tree.dragging !is null) {
|
|
resources.tree.stopDragging();
|
|
return true;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return GuiOverlay::onMouseEvent(evt, source);
|
|
}
|
|
|
|
void close() override {
|
|
if(parent is null || objView is null || closing)
|
|
return;
|
|
closing = true;
|
|
@objView.alignment = null;
|
|
|
|
surface.visible = false;
|
|
resources.visible = false;
|
|
construction.visible = false;
|
|
|
|
vec2i parSize = parent.size;
|
|
recti targPos = recti_area(vec2i(-456, parSize.y-228), vec2i(912, 912));
|
|
animate_time(objView, targPos, ANIM1_TIME);
|
|
}
|
|
|
|
void startBuild(const BuildingType@ type) {
|
|
if(surface !is null)
|
|
surface.startBuild(type);
|
|
}
|
|
|
|
Object@ get_object() {
|
|
return obj;
|
|
}
|
|
|
|
Object@ get_slaved() {
|
|
return null;
|
|
}
|
|
|
|
void triggerUpdate() {
|
|
}
|
|
|
|
void update(double time) {
|
|
surface.update(time);
|
|
resources.update(time);
|
|
construction.update(time);
|
|
}
|
|
|
|
void draw() {
|
|
if(!settings::bGalaxyBG && objView.Alignment !is null)
|
|
material::Skybox.draw(AbsolutePosition);
|
|
GuiOverlay::draw();
|
|
}
|
|
};
|
|
|
|
class DisplayBox : BaseGuiElement {
|
|
PlanetOverlay@ overlay;
|
|
Alignment@ targetAlign;
|
|
|
|
DisplayBox(PlanetOverlay@ ov, vec2i origin, Alignment@ target) {
|
|
@overlay = ov;
|
|
@targetAlign = target;
|
|
super(overlay, recti_area(origin, vec2i(1,1)));
|
|
visible = false;
|
|
updateAbsolutePosition();
|
|
}
|
|
|
|
void animate() {
|
|
visible = true;
|
|
animate_time(this, targetAlign.resolve(overlay.size), ANIM2_TIME);
|
|
}
|
|
|
|
bool onGuiEvent(const GuiEvent& evt) override {
|
|
switch(evt.type) {
|
|
case GUI_Animation_Complete:
|
|
@alignment = targetAlign;
|
|
return true;
|
|
}
|
|
return BaseGuiElement::onGuiEvent(evt);
|
|
}
|
|
|
|
bool pressed = false;
|
|
bool onMouseEvent(const MouseEvent& evt, IGuiElement@ source) override {
|
|
switch(evt.type) {
|
|
case MET_Button_Down:
|
|
if(evt.button == 0) {
|
|
pressed = true;
|
|
return true;
|
|
}
|
|
break;
|
|
case MET_Button_Up:
|
|
if(evt.button == 0 && pressed) {
|
|
pressed = false;
|
|
return true;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return BaseGuiElement::onMouseEvent(evt, source);
|
|
}
|
|
|
|
void remove() override {
|
|
@overlay = null;
|
|
BaseGuiElement::remove();
|
|
}
|
|
|
|
void update(double time) {
|
|
}
|
|
|
|
void draw() {
|
|
skin.draw(SS_OverlayBox, SF_Normal, AbsolutePosition, Color(0x888888ff));
|
|
BaseGuiElement::draw();
|
|
}
|
|
};
|
|
//}}}
|
|
|
|
// {{{ Surface
|
|
class VarBox : BaseGuiElement {
|
|
GuiSprite@ icon;
|
|
GuiText@ value;
|
|
Color color;
|
|
|
|
VarBox(IGuiElement@ parent, const recti& pos) {
|
|
super(parent, pos);
|
|
|
|
@icon = GuiSprite(this, Alignment(Left+4, Top+2, Left+VAR_H, Bottom-2));
|
|
@value = GuiText(this, Alignment(Left+4, Top+2, Right-4, Bottom-6));
|
|
value.font = FT_Subtitle;
|
|
value.stroke = colors::Black;
|
|
value.vertAlign = 1.0;
|
|
value.horizAlign = 1.0;
|
|
}
|
|
|
|
void draw() {
|
|
skin.draw(SS_PlainBox, SF_Normal, AbsolutePosition.padded(-2, 2, -2, 2));
|
|
|
|
Color glowCol = color;
|
|
glowCol.a = 0x18;
|
|
drawRectangle(AbsolutePosition.padded(0, 3, 0, 3),
|
|
Color(0x22222218), Color(0x22222218),
|
|
glowCol, glowCol);
|
|
|
|
BaseGuiElement::draw();
|
|
}
|
|
};
|
|
|
|
class SurfaceDisplay : DisplayBox {
|
|
Planet@ pl;
|
|
|
|
GuiPanel@ surfPanel;
|
|
GuiPlanetSurface@ sdisplay;
|
|
PlanetSurface surface;
|
|
|
|
GuiMarkupText@ name;
|
|
GuiText@ level;
|
|
|
|
GuiSkinElement@ resDisplay;
|
|
GuiPanel@ varPanel;
|
|
|
|
const BuildingType@ selBuilding;
|
|
|
|
SurfaceDisplay(PlanetOverlay@ ov, vec2i origin, Alignment@ target) {
|
|
super(ov, origin, target);
|
|
|
|
@surfPanel = GuiPanel(this, Alignment(Left+158, Top+38, Right-8, Bottom-8));
|
|
@sdisplay = GuiPlanetSurface(surfPanel, recti());
|
|
@sdisplay.surface = surface;
|
|
sdisplay.maxSize = 0.02 * double(ov.size.width);
|
|
|
|
@name = GuiMarkupText(this, Alignment(Left+8, Top-2, Right-8, Top+38));
|
|
name.noClip = true;
|
|
name.defaultFont = FT_Big;
|
|
name.defaultStroke = colors::Black;
|
|
|
|
@level = GuiText(this, Alignment(Left+8, Top+8, Right-8, Top+38));
|
|
level.font = FT_Medium;
|
|
level.horizAlign = 1.0;
|
|
level.stroke = colors::Black;
|
|
level.visible = false;
|
|
|
|
@resDisplay = GuiSkinElement(this, Alignment(Left+1, Top+38, Left+150, Bottom-2), SS_PatternBox);
|
|
@varPanel = GuiPanel(resDisplay, Alignment().fill());
|
|
|
|
@pl = overlay.obj;
|
|
updateAbsolutePosition();
|
|
}
|
|
|
|
void updateAbsolutePosition() {
|
|
DisplayBox::updateAbsolutePosition();
|
|
|
|
if(sdisplay !is null && pl !is null) {
|
|
int minSize = screenSize.width >= 1910 ? MIN_TILE_SIZE_HD : MIN_TILE_SIZE;
|
|
int sw = max(surfPanel.size.width - (surfPanel.vert.visible ? 20 : 0), minSize * surface.size.width);
|
|
int sh = max(surfPanel.size.height - (surfPanel.horiz.visible ? 20 : 0), minSize * surface.size.height);
|
|
vec2i prevSize = sdisplay.size;
|
|
if(prevSize.x != sw || prevSize.y != sh) {
|
|
sdisplay.size = vec2i(sw, sh);
|
|
surfPanel.updateAbsolutePosition();
|
|
}
|
|
}
|
|
}
|
|
|
|
void startBuild(const BuildingType@ type) {
|
|
@selBuilding = type;
|
|
sdisplay.showTooltip = false;
|
|
}
|
|
|
|
void stopBuild() {
|
|
@selBuilding = null;
|
|
sdisplay.showTooltip = true;
|
|
}
|
|
|
|
void openBuildingMenu(const vec2i& pos, SurfaceBuilding@ bld) {
|
|
GuiContextMenu menu(mousePos);
|
|
if(bld.type.canRemove(pl)) {
|
|
if(bld.completion >= 1.f) {
|
|
if(!pl.isContested)
|
|
menu.addOption(DestroyBuildingOption(pl, format(locale::DESTROY_BUILDING, bld.type.name), pos));
|
|
}
|
|
else {
|
|
menu.addOption(DestroyBuildingOption(pl, format(locale::CANCEL_BUILDING, bld.type.name), pos));
|
|
}
|
|
}
|
|
menu.finalize();
|
|
}
|
|
|
|
uint varIndex = 0;
|
|
array<VarBox@> variables;
|
|
void resetVars() {
|
|
varIndex = 0;
|
|
}
|
|
|
|
void addVariable(const Sprite& icon, const string& value, const string& tooltip = "", const Color& color = colors::White) {
|
|
if(varIndex >= variables.length)
|
|
variables.insertLast(VarBox(varPanel, recti()));
|
|
|
|
int w = min(varPanel.size.width, 149) - 2;
|
|
if(varPanel.vert.visible && varPanel.size.height >= 30)
|
|
w -= 20;
|
|
|
|
auto@ box = variables[varIndex];
|
|
box.rect = recti_area(1, 4+varIndex*VAR_H, w, VAR_H);
|
|
|
|
box.icon.desc = icon;
|
|
box.value.text = value;
|
|
box.value.color = color;
|
|
box.color = color;
|
|
setMarkupTooltip(box, tooltip, width=399);
|
|
|
|
++varIndex;
|
|
}
|
|
|
|
void finalizeVars() {
|
|
for(uint i = varIndex, cnt = variables.length; i < cnt; ++i)
|
|
variables[i].remove();
|
|
variables.length = varIndex;
|
|
}
|
|
|
|
void updateVars() {
|
|
resetVars();
|
|
|
|
if(pl.visible) {
|
|
if(pl.owner.valid && pl.owner.HasPopulation != 0) {
|
|
Color popColor = colors::White;
|
|
if(!pl.primaryResourceUsable) {
|
|
if(pl.population < getPlanetLevelRequiredPop(pl, pl.resourceLevel) && !pl.inCombat) {
|
|
popColor = colors::Orange;
|
|
}
|
|
}
|
|
string popText = standardize(pl.population, true) + " / " + standardize(pl.maxPopulation, true);
|
|
addVariable(icons::Population, popText, locale::PLANET_POPULATION_TIP, popColor);
|
|
}
|
|
}
|
|
if(pl.owner is playerEmpire) {
|
|
auto@ scTrait = getTrait("StarChildren");
|
|
auto@ anTrait = getTrait("Ancient");
|
|
if((scTrait is null || !pl.owner.hasTrait(scTrait.id)) && (anTrait is null || !pl.owner.hasTrait(anTrait.id))) {
|
|
Color color = colors::White;
|
|
if(int(surface.totalPressure) > int(surface.pressureCap))
|
|
color = colors::Red;
|
|
string value = standardize(surface.totalPressure, true) + " / " + standardize(surface.pressureCap, true);
|
|
string ttip = format(locale::PLANET_PRESSURE_TIP, standardize(surface.totalPressure, true), standardize(surface.totalSaturate, true), standardize(surface.pressureCap, true));
|
|
addVariable(icons::Pressure, value, ttip, color);
|
|
}
|
|
{
|
|
Color color = colors::Money;
|
|
int income = pl.income;
|
|
if(income < 0)
|
|
color = colors::Red;
|
|
string value = formatMoney(income);
|
|
string ttip = format(locale::PLANET_INCOME_TIP, standardize(surface.pressures[TR_Money], true), standardize(surface.resources[TR_Money], true));
|
|
addVariable(icons::Money, value, ttip, color);
|
|
}
|
|
|
|
}
|
|
if(pl.owner.valid) {
|
|
string loyText = toString(pl.currentLoyalty, 0);
|
|
addVariable(icons::Loyalty, loyText, locale::PLANET_LOYALTY_TIP, colors::White);
|
|
}
|
|
if(pl.owner is playerEmpire) {
|
|
if(surface.resources[TR_Energy] > 0 || surface.pressures[TR_Energy] > 0) {
|
|
Color color = colors::Energy;
|
|
string value = "+"+formatRate(surface.resources[TR_Energy] * TILE_ENERGY_RATE * pl.owner.EnergyEfficiency);
|
|
string ttip = format(locale::PLANET_ENERGY_TIP, standardize(surface.pressures[TR_Energy], true), standardize(surface.saturates[TR_Energy], true));
|
|
addVariable(icons::Energy, value, ttip, color);
|
|
}
|
|
|
|
if(surface.resources[TR_Defense] > 0 || surface.pressures[TR_Defense] > 0) {
|
|
Color color = colors::Defense;
|
|
string value = standardize(surface.resources[TR_Defense], true);
|
|
string ttip = format(locale::PLANET_DEFENSE_TIP, standardize(surface.pressures[TR_Defense], true), standardize(surface.saturates[TR_Defense], true));
|
|
addVariable(icons::Defense, value, ttip, color);
|
|
}
|
|
|
|
if(surface.resources[TR_Influence] > 0 || surface.pressures[TR_Influence] > 0) {
|
|
Color color = colors::Influence;
|
|
string value = standardize(surface.resources[TR_Influence], true);
|
|
string ttip = format(locale::PLANET_INFLUENCE_TIP, standardize(surface.pressures[TR_Influence], true), standardize(surface.saturates[TR_Influence], true));
|
|
addVariable(icons::Influence, value, ttip, color);
|
|
}
|
|
|
|
if(surface.resources[TR_Research] > 0 || surface.pressures[TR_Research] > 0) {
|
|
Color color = colors::Research;
|
|
string value = "+"+formatRate(surface.resources[TR_Research] * TILE_RESEARCH_RATE * pl.owner.ResearchEfficiency);
|
|
string ttip = format(locale::PLANET_RESEARCH_TIP, standardize(surface.pressures[TR_Research], true), standardize(surface.saturates[TR_Research], true));
|
|
addVariable(icons::Research, value, ttip, color);
|
|
}
|
|
|
|
if(pl.laborIncome > 0) {
|
|
Color color = colors::Labor;
|
|
string value = formatMinuteRate(pl.laborIncome);
|
|
string ttip = format(locale::PLANET_LABOR_TIP, standardize(surface.pressures[TR_Labor], true), standardize(surface.saturates[TR_Labor], true));
|
|
addVariable(icons::Labor, value, ttip, color);
|
|
}
|
|
|
|
uint cargoCnt = pl.cargoTypes;
|
|
for(uint i = 0; i < cargoCnt; ++i) {
|
|
auto@ type = getCargoType(pl.cargoType[i]);
|
|
if(type is null)
|
|
continue;
|
|
string value = standardize(pl.getCargoStored(type.id), true);
|
|
string ttip = format("[font=Medium]$1[/font]\n$2", type.name, type.description);
|
|
addVariable(type.icon, value, ttip, type.color);
|
|
}
|
|
}
|
|
|
|
finalizeVars();
|
|
}
|
|
|
|
bool onGuiEvent(const GuiEvent& evt) {
|
|
switch(evt.type) {
|
|
case GUI_Clicked:
|
|
if(evt.caller is sdisplay) {
|
|
if(evt.value == 1) {
|
|
auto@ bld = sdisplay.surface.getBuilding(sdisplay.hovered.x, sdisplay.hovered.y);
|
|
if(selBuilding !is null)
|
|
stopBuild();
|
|
else if(sdisplay.surface.isValidPosition(sdisplay.hovered)) {
|
|
if(bld !is null && !bld.type.civilian)
|
|
openBuildingMenu(sdisplay.hovered, bld);
|
|
}
|
|
else
|
|
overlay.close();
|
|
return true;
|
|
}
|
|
|
|
if(selBuilding !is null) {
|
|
pl.buildBuilding(selBuilding.id, sdisplay.hovered);
|
|
if(!shiftKey) {
|
|
stopBuild();
|
|
overlay.construction.deselect();
|
|
overlay.construction.updateTimer = 0.0;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
break;
|
|
}
|
|
return DisplayBox::onGuiEvent(evt);
|
|
}
|
|
|
|
double updateTimer = 0.0;
|
|
void update(double time) override {
|
|
updateTimer -= time;
|
|
if(updateTimer <= 0) {
|
|
updateTimer = randomd(0.1,0.9);
|
|
|
|
Empire@ owner = pl.visibleOwner;
|
|
bool owned = owner is playerEmpire;
|
|
bool colonized = owner !is null && owner.valid;
|
|
|
|
//Update name
|
|
name.text = format("[center][obj_icon=$1;42/] $2[/center]", pl.id, pl.name);;
|
|
if(owner !is null)
|
|
name.defaultColor = owner.color;
|
|
|
|
//Update level
|
|
uint lv = pl.level;
|
|
level.text = locale::LEVEL+" "+lv;
|
|
|
|
//Update surface
|
|
@sdisplay.obj = pl;
|
|
receive(pl.getPlanetSurface(), surface);
|
|
if(!pl.visible)
|
|
surface.clearState();
|
|
updateVars();
|
|
}
|
|
}
|
|
|
|
void draw() override {
|
|
Empire@ owner = pl.visibleOwner;
|
|
Color color;
|
|
if(owner !is null)
|
|
color = owner.color;
|
|
|
|
skin.draw(SS_OverlayBox, SF_Normal, AbsolutePosition.padded(0,36,0,0), Color(0x888888ff));
|
|
skin.draw(SS_FullTitle, SF_Normal, recti_area(AbsolutePosition.topLeft, vec2i(AbsolutePosition.width, 38)), color);
|
|
BaseGuiElement::draw();
|
|
|
|
if(selBuilding !is null) {
|
|
clearClip();
|
|
drawHoverBuilding(pl, skin, selBuilding, mousePos, sdisplay.hovered, sdisplay);
|
|
}
|
|
}
|
|
};
|
|
|
|
class DestroyBuildingOption : GuiContextOption {
|
|
Object@ obj;
|
|
vec2i pos;
|
|
|
|
DestroyBuildingOption(Object@ obj, const string& text, const vec2i& pos) {
|
|
this.pos = pos;
|
|
this.text = text;
|
|
@this.obj = obj;
|
|
}
|
|
|
|
void call(GuiContextMenu@ menu) override {
|
|
obj.destroyBuilding(pos);
|
|
}
|
|
};
|
|
// }}}
|
|
|
|
// {{{ Resources
|
|
class EffectBox : BaseGuiElement {
|
|
GuiResources@ resources;
|
|
GuiMarkupText@ text;
|
|
array<const IResourceHook@> hooks;
|
|
Object@ obj;
|
|
|
|
GuiResources@ carryList;
|
|
|
|
EffectBox(IGuiElement@ elem, const recti& pos) {
|
|
super(elem, pos);
|
|
@resources = GuiResources(this, recti_area(
|
|
vec2i(2, 7), vec2i(100, pos.height-14)));
|
|
resources.horizAlign = 0.0;
|
|
@text = GuiMarkupText(this, recti(
|
|
vec2i(52, 0), pos.size - vec2i(16, 0)));
|
|
}
|
|
|
|
void add(Resource@ r, const IResourceHook@ hook, Resource@ carry = null) {
|
|
resources.resources.insertLast(r);
|
|
hooks.insertLast(hook);
|
|
|
|
if(carry !is null) {
|
|
if(carryList is null) {
|
|
@carryList = GuiResources(this, Alignment(Right-25, Bottom-25, Right+5, Bottom+5));
|
|
carryList.sendToBack();
|
|
carryList.horizAlign = 0.0;
|
|
}
|
|
|
|
bool found = false;
|
|
for(uint i = 0, cnt = carryList.resources.length; i < cnt; ++i) {
|
|
if(carryList.resources[i].type is carry.type) {
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(!found)
|
|
carryList.resources.insertLast(carry);
|
|
}
|
|
}
|
|
|
|
void update(Resource@ r) {
|
|
for(uint i = 0, cnt = resources.resources.length; i < cnt; ++i) {
|
|
Resource@ other = resources.resources[i];
|
|
if(other.id == r.id && other.origin is r.origin)
|
|
other = r;
|
|
}
|
|
}
|
|
|
|
void update() {
|
|
int rSize = min(60, resources.length * 48);
|
|
resources.size = vec2i(rSize, 30);
|
|
text.position = vec2i(rSize+8, 0);
|
|
text.size = size - vec2i(rSize+24+(carryList is null ? 0 : 20), 0);
|
|
|
|
text.text = hooks[0].formatEffect(obj, hooks);
|
|
|
|
const ResourceType@ type;
|
|
for(uint i = 0, cnt = resources.resources.length; i < cnt; ++i) {
|
|
if(i == 0) {
|
|
@type = resources.resources[i].type;
|
|
}
|
|
else {
|
|
if(type !is resources.resources[i].type) {
|
|
@type = null;
|
|
break;
|
|
}
|
|
else {
|
|
@type = resources.resources[i].type;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(type !is null)
|
|
setMarkupTooltip(this, getResourceTooltip(type));
|
|
else
|
|
setMarkupTooltip(this, "");
|
|
|
|
updateAbsolutePosition();
|
|
}
|
|
|
|
void draw() override {
|
|
skin.draw(SS_PlainOverlay, SF_Normal, AbsolutePosition);
|
|
BaseGuiElement::draw();
|
|
}
|
|
};
|
|
|
|
class ResBox : BaseGuiElement {
|
|
const ResourceRequirement@ req;
|
|
Resource@ resource;
|
|
Planet@ planet;
|
|
bool hovered = false;
|
|
uint forLevel = 0;
|
|
|
|
ResBox(IGuiElement@ parent, Alignment@ align) {
|
|
super(parent, align);
|
|
|
|
MarkupTooltip tt(350, 0.f, true, true);
|
|
tt.Lazy = true;
|
|
tt.LazyUpdate = false;
|
|
tt.Padding = 4;
|
|
@tooltipObject = tt;
|
|
}
|
|
|
|
string get_tooltip() {
|
|
string tt;
|
|
if(req !is null) {
|
|
string sprt = getSpriteDesc(getRequirementIcon(req));
|
|
switch(req.type) {
|
|
case RRT_Class:
|
|
tt = "[color=#ccc]"+format(locale::REQ_TYPE, req.cls.name, sprt)+"[/color]";
|
|
break;
|
|
case RRT_Level:
|
|
tt = "[color=#ccc]"+format(locale::REQ_LEVEL, toString(req.level), sprt)+"[/color]";
|
|
break;
|
|
}
|
|
}
|
|
if(resource !is null) {
|
|
if(tt.length != 0)
|
|
tt += "[font=Subtitle][color=#ccc]:[/color][/font]\n[hr/][vspace=6/]";
|
|
tt += getResourceTooltip(resource.type, resource, planet);
|
|
}
|
|
return tt;
|
|
}
|
|
|
|
void update() {
|
|
}
|
|
|
|
bool onGuiEvent(const GuiEvent& evt) override {
|
|
if(evt.type == GUI_Mouse_Entered)
|
|
hovered = true;
|
|
else if(evt.type == GUI_Mouse_Left)
|
|
hovered = false;
|
|
return BaseGuiElement::onGuiEvent(evt);
|
|
}
|
|
|
|
bool onMouseEvent(const MouseEvent& evt, IGuiElement@ caller) override {
|
|
if(evt.type == MET_Button_Down) {
|
|
return true;
|
|
}
|
|
if(evt.type == MET_Button_Up) {
|
|
if(hovered)
|
|
openMenu();
|
|
return true;
|
|
}
|
|
return BaseGuiElement::onMouseEvent(evt, caller);
|
|
}
|
|
|
|
void openMenu() {
|
|
if(!planet.owner.controlled)
|
|
return;
|
|
GuiContextMenu menu(mousePos);
|
|
if(resource !is null) {
|
|
if(resource.origin !is planet && resource.origin !is null) {
|
|
menu.addOption(UnexportOption(planet, resource));
|
|
}
|
|
else if(resource.origin is planet && resource.exportedTo !is null) {
|
|
menu.addOption(UnexportOption(planet, resource));
|
|
}
|
|
else if(resource.origin is null && req !is null) {
|
|
menu.addOption(CancelAutoImportOption(planet, req));
|
|
menu.addOption(CancelAllAutoImportOption(planet));
|
|
}
|
|
}
|
|
else if(req !is null) {
|
|
menu.addOption(AutoImportOption(planet, req));
|
|
if(planet.resourceLevel < forLevel)
|
|
menu.addOption(AutoImportLevelOption(planet, forLevel));
|
|
}
|
|
menu.finalize();
|
|
}
|
|
|
|
void draw() {
|
|
if(resource !is null) {
|
|
skin.draw(SS_PlainOverlay, SF_Normal, AbsolutePosition);
|
|
drawSmallResource(resource.type, resource, AbsolutePosition.padded(9), planet);
|
|
}
|
|
else if(req !is null) {
|
|
skin.draw(SS_PlainOverlay, SF_Normal, AbsolutePosition, Color(0x666666ff));
|
|
getRequirementIcon(req).draw(AbsolutePosition.padded(4), Color(0xffffff80));
|
|
}
|
|
|
|
BaseGuiElement::draw();
|
|
|
|
if(hovered)
|
|
drawRectangle(AbsolutePosition.padded(2), Color(0xffffff10), Color(0xffffff10), Color(0xffffff20), Color(0xffffff20));
|
|
}
|
|
};
|
|
|
|
class LevelRow : BaseGuiElement {
|
|
Planet@ planet;
|
|
|
|
GuiText@ reqCaption;
|
|
GuiText@ levelCaption;
|
|
|
|
const PlanetLevel@ reqLevel;
|
|
array<ResBox@> reqs;
|
|
|
|
Color bg;
|
|
Color line;
|
|
|
|
LevelRow(IGuiElement@ parent, Alignment@ align) {
|
|
super(parent, align);
|
|
|
|
@levelCaption = GuiText(this, Alignment(Left, Top, Left+80, Bottom));
|
|
levelCaption.horizAlign = 0.5;
|
|
levelCaption.vertAlign = 0.5;
|
|
levelCaption.stroke = colors::Black;
|
|
}
|
|
|
|
void take(array<Resource@>& resources, bool& doneUniversal, Resources& available) {
|
|
for(uint i = 0, cnt = reqs.length; i < cnt; ++i) {
|
|
int minSpec = INT_MAX;
|
|
Resource@ res;
|
|
reqs[i].visible = true;
|
|
for(uint n = 0, ncnt = resources.length; n < ncnt; ++n) {
|
|
int spec = reqs[i].req.meetQuality(resources[n].type, doneUniversal);
|
|
if(spec == 0 || spec >= minSpec)
|
|
continue;
|
|
auto@ r = resources[n];
|
|
if(r.exportedTo !is null && r.origin is planet)
|
|
continue;
|
|
if(!r.usable || r.origin is null)
|
|
spec += 1;
|
|
|
|
minSpec = spec;
|
|
@res = resources[n];
|
|
}
|
|
|
|
@reqs[i].resource = res;
|
|
if(res !is null) {
|
|
if(res.type.mode == RM_UniversalUnique)
|
|
doneUniversal = true;
|
|
resources.remove(res);
|
|
if(res.usable)
|
|
available.modAmount(res.type, -1);
|
|
}
|
|
else {
|
|
const ResourceType@ takeType;
|
|
uint takeSpec = 0;
|
|
for(uint n = 0, ncnt = available.types.length; n < ncnt; ++n) {
|
|
if(available.amounts[n] <= 0)
|
|
continue;
|
|
auto@ rtype = getResource(available.types[n]);
|
|
int spec = reqs[i].req.meetQuality(rtype, doneUniversal);
|
|
if(spec == 0 || spec >= minSpec)
|
|
continue;
|
|
|
|
minSpec = spec;
|
|
@takeType = rtype;
|
|
}
|
|
|
|
if(takeType !is null) {
|
|
if(takeType.mode == RM_UniversalUnique)
|
|
doneUniversal = true;
|
|
available.modAmount(takeType, -1);
|
|
reqs[i].visible = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void update() {
|
|
uint resLevel = planet.resourceLevel;
|
|
uint curLevel = planet.level;
|
|
|
|
if(reqLevel.level == curLevel) {
|
|
levelCaption.color = Color(0x80ff80ff);
|
|
levelCaption.stroke = colors::Black;
|
|
levelCaption.font = FT_Bold;
|
|
bg = Color(0x80ff80ff);
|
|
line = Color(0x80ff80ff);
|
|
}
|
|
else if(reqLevel.level <= resLevel) {
|
|
levelCaption.color = Color(0xffffffff);
|
|
levelCaption.stroke = colors::Black;
|
|
levelCaption.font = FT_Normal;
|
|
bg = Color(0xffffffff);
|
|
line = Color(0x00000000);
|
|
}
|
|
else if(reqLevel.level == resLevel+1 && !planet.primaryResourceExported) {
|
|
levelCaption.color = Color(0xff8000ff);
|
|
levelCaption.stroke = colors::Black;
|
|
levelCaption.font = FT_Italic;
|
|
bg = Color(0xffbb88ff);
|
|
line = Color(0x00000000);
|
|
}
|
|
else {
|
|
levelCaption.color = Color(0x666666ff);
|
|
levelCaption.stroke = Color(0x111111ff);
|
|
levelCaption.font = FT_Italic;
|
|
bg = Color(0xffffffff);
|
|
line = Color(0x00000000);
|
|
}
|
|
}
|
|
|
|
void set(const PlanetLevel@ prev, const PlanetLevel@ lv) {
|
|
if(reqLevel is lv)
|
|
return;
|
|
|
|
@reqLevel = lv;
|
|
levelCaption.text = locale::LEVEL+" "+lv.level;
|
|
|
|
array<ResourceRequirement@> pending;
|
|
for(uint i = 0, cnt = lv.reqs.reqs.length; i < cnt; ++i) {
|
|
auto@ p = lv.reqs.reqs[i];
|
|
|
|
ResourceRequirement cpy;
|
|
cpy = p;
|
|
pending.insertLast(cpy);
|
|
}
|
|
|
|
for(uint i = 0, cnt = prev.reqs.reqs.length; i < cnt; ++i) {
|
|
auto@ c = prev.reqs.reqs[i];
|
|
uint total = c.amount;
|
|
for(uint i = 0, cnt = pending.length; i < cnt; ++i) {
|
|
if(!pending[i].equivalent(c))
|
|
continue;
|
|
uint take = min(pending[i].amount, total);
|
|
pending[i].amount -= take;
|
|
total -= take;
|
|
|
|
if(pending[i].amount <= 0) {
|
|
pending.removeAt(i);
|
|
--i; --cnt;
|
|
}
|
|
|
|
if(total <= 0)
|
|
break;
|
|
}
|
|
}
|
|
|
|
uint r = 0;
|
|
for(uint i = 0, cnt = pending.length; i < cnt; ++i) {
|
|
auto@ p = pending[i];
|
|
|
|
for(uint n = 0; n < p.amount; ++n) {
|
|
ResBox@ disp;
|
|
if(r < reqs.length) {
|
|
@disp = reqs[r];
|
|
}
|
|
else {
|
|
@disp = ResBox(this, Alignment(Left+80+r*47, Top+3, Width=44, Height=44));
|
|
reqs.insertLast(disp);
|
|
}
|
|
|
|
@disp.planet = planet;
|
|
@disp.req = p;
|
|
disp.forLevel = lv.level;
|
|
disp.update();
|
|
r += 1;
|
|
}
|
|
}
|
|
for(uint i = r, cnt = reqs.length; i < cnt; ++i)
|
|
reqs[i].remove();
|
|
reqs.length = r;
|
|
}
|
|
|
|
void draw() {
|
|
skin.draw(SS_PlainOverlay, SF_Normal, AbsolutePosition, bg);
|
|
BaseGuiElement::draw();
|
|
|
|
if(line.a != 0) {
|
|
vec2i left = levelCaption.absolutePosition.topLeft + levelCaption.textOffset + vec2i(0, 18);
|
|
vec2i right = vec2i(levelCaption.absolutePosition.botRight.x - levelCaption.textOffset.x, left.y);
|
|
drawLine(left, right, line, 2);
|
|
}
|
|
}
|
|
};
|
|
|
|
class ResourceDisplay : DisplayBox {
|
|
Planet@ pl;
|
|
|
|
GuiSkinElement@ levelBar;
|
|
GuiText@ level;
|
|
|
|
GuiSkinElement@ requireBox;
|
|
GuiText@ reqLabel;
|
|
GuiText@ reqTimer;
|
|
GuiMarkupText@ popReq;
|
|
GuiResourceReqGrid@ reqDisplay;
|
|
|
|
GuiSkinElement@ statusBox;
|
|
array<GuiStatusBox@> statusIcons;
|
|
|
|
PlanetTree@ tree;
|
|
bool doCenter = false;
|
|
|
|
GuiText@ reqCaption;
|
|
array<LevelRow@> levelDisp;
|
|
array<ResBox@> looseDisp;
|
|
|
|
GuiPanel@ resPanel;
|
|
|
|
GuiSkinElement@ resourceBox;
|
|
GuiMarkupText@ resourceDesc;
|
|
GuiMarkupText@ resourcePressure;
|
|
|
|
GuiButton@ toggleButton;
|
|
bool showLevels = true;
|
|
int statusPos = 0;
|
|
|
|
ResourceDisplay(PlanetOverlay@ ov, vec2i origin, Alignment@ target) {
|
|
super(ov, origin, target);
|
|
@pl = ov.obj;
|
|
|
|
//Level indicator
|
|
@levelBar = GuiSkinElement(this, Alignment(Left+1, Top+1, Left+192, Top+42), SS_PlainOverlay);
|
|
@level = GuiText(levelBar, Alignment(Left+8, Top+4, Right-8, Bottom-4));
|
|
level.font = FT_Medium;
|
|
|
|
//Requirements
|
|
statusPos = 513;
|
|
if(screenSize.width < 1900)
|
|
statusPos = 400;
|
|
@statusBox = GuiSkinElement(this, Alignment(Left+statusPos, Top+1, Right-44, Top+42), SS_PlainOverlay);
|
|
@requireBox = GuiSkinElement(this, Alignment(Left+200, Top+1, Left+statusPos-10, Top+42), SS_PlainOverlay);
|
|
setMarkupTooltip(requireBox, locale::PLANET_REQUIREMENTS_TIP, width=400);
|
|
@reqLabel = GuiText(requireBox, Alignment(Left-4, Top-6, Left+96, Top+6), locale::REQUIRED_RESOURCES);
|
|
reqLabel.noClip = true;
|
|
reqLabel.font = FT_Small;
|
|
@reqTimer = GuiText(requireBox, Alignment(Right-96, Top-6, Right+4, Top+6));
|
|
reqTimer.color = Color(0xff0000fff);
|
|
reqTimer.noClip = true;
|
|
reqTimer.font = FT_Small;
|
|
reqTimer.horizAlign = 1.0;
|
|
reqTimer.visible = false;
|
|
@reqDisplay = GuiResourceReqGrid(requireBox, Alignment(Left+8, Top+8, Right-8, Bottom));
|
|
reqDisplay.iconSize = vec2i(30, 30);
|
|
reqDisplay.spacing.x = 6;
|
|
reqDisplay.horizAlign = 0.0;
|
|
reqDisplay.vertAlign = 0.0;
|
|
@popReq = GuiMarkupText(requireBox, Alignment(Left+4, Top+8, Right-4, Bottom));
|
|
popReq.visible = false;
|
|
|
|
//Tree of local planets
|
|
@tree = PlanetTree(this, Alignment().padded(8, 42, 8, 8));
|
|
@tree.focusObject = pl;
|
|
tree.visible = false;
|
|
|
|
//Requirements display
|
|
@resPanel = GuiPanel(this, Alignment().padded(0, 42, 0, 0));
|
|
resPanel.horizType = ST_Never;
|
|
|
|
showLevels = screenSize.width >= 1800;
|
|
if(showLevels)
|
|
@resourceBox = GuiSkinElement(resPanel, Alignment(Left+10, Top+10, Left+0.5f-5, Top+94), SS_PlainOverlay);
|
|
else
|
|
@resourceBox = GuiSkinElement(resPanel, Alignment(Left+10, Top+10, Right-10, Top+94), SS_PlainOverlay);
|
|
@resourceDesc = GuiMarkupText(resourceBox, Alignment().padded(6, 6, 100, 6));
|
|
@resourcePressure = GuiMarkupText(resourceBox, Alignment(Right-85, Top+3, Right-6, Bottom-3));
|
|
|
|
//Display toggle button
|
|
@toggleButton = GuiButton(this, Alignment(Right-40, Top, Right, Top+43));
|
|
toggleButton.toggleButton = true;
|
|
toggleButton.color = Color(0xaaaaaaff);
|
|
toggleButton.setIcon(Sprite(material::TabPlanets, Color(0xffffff80)));
|
|
toggleButton.pressed = SHOW_PLANET_TREE;
|
|
}
|
|
|
|
double updateTimer = 0.0;
|
|
uint modID = uint(-1);
|
|
uint reqModID = uint(-1);
|
|
|
|
void update(double time) override {
|
|
tree.visible = pl.owner is playerEmpire && SHOW_PLANET_TREE;
|
|
resPanel.visible = !tree.visible;
|
|
if(tree.visible)
|
|
tree.tick(time);
|
|
|
|
updateTimer -= time;
|
|
uint newModID = pl.resourceModID;
|
|
if(updateTimer <= 0 || reqModID != newModID) {
|
|
updateTimer = randomd(0.1,0.9);
|
|
level.text = locale::LEVEL+" "+pl.visibleLevel;
|
|
|
|
Empire@ owner = pl.owner;
|
|
bool owned = owner is playerEmpire;
|
|
bool colonized = owner !is null && owner.valid;
|
|
bool wasVis = requireBox.visible;
|
|
|
|
//Update level requirements
|
|
array<Resource>@ resList = overlay.resList;
|
|
if(owned)
|
|
resList.syncFrom(pl.getAllResources());
|
|
else
|
|
resList.syncFrom(pl.getNativeResources());
|
|
|
|
uint lv = pl.level;
|
|
double decay = pl.decayTime;
|
|
uint maxLevel = getMaxPlanetLevel(pl);
|
|
|
|
//Update statuses
|
|
{
|
|
array<Status> statuses;
|
|
if(pl.statusEffectCount > 0)
|
|
statuses.syncFrom(pl.getStatusEffects());
|
|
if(!pl.visible) {
|
|
for(uint i = 0, cnt = statuses.length; i < cnt; ++i) {
|
|
if(statuses[i].type.conditionFrequency <= 0) {
|
|
statuses.removeAt(i);
|
|
--i; --cnt;
|
|
}
|
|
}
|
|
}
|
|
uint prevCnt = statusIcons.length, cnt = statuses.length;
|
|
for(uint i = cnt; i < prevCnt; ++i)
|
|
statusIcons[i].remove();
|
|
statusIcons.length = cnt;
|
|
for(uint i = 0; i < cnt; ++i) {
|
|
auto@ icon = statusIcons[i];
|
|
if(icon is null) {
|
|
@icon = GuiStatusBox(statusBox, recti_area(2+40*i, 2, 38, 38));
|
|
icon.noClip = true;
|
|
@statusIcons[i] = icon;
|
|
}
|
|
icon.update(statuses[i]);
|
|
}
|
|
}
|
|
|
|
//Update level display
|
|
if(reqModID != newModID) {
|
|
reqModID = newModID;
|
|
|
|
available.clear();
|
|
receive(pl.getResourceAmounts(), available);
|
|
|
|
int chain = pl.levelChain;
|
|
uint maxLevel = getMaxPlanetLevel(chain);
|
|
int plMax = pl.maxLevel;
|
|
if(plMax >= 0)
|
|
maxLevel = min(plMax, maxLevel);
|
|
if(!showLevels)
|
|
maxLevel = 0;
|
|
uint y = 10;
|
|
for(uint i = 0; i < maxLevel; ++i) {
|
|
LevelRow@ row;
|
|
if(i < levelDisp.length) {
|
|
@row = levelDisp[i];
|
|
}
|
|
else {
|
|
@row = LevelRow(resPanel, Alignment(Left+0.5f+5, Top+y+(i*54), Right-10, Height=50));
|
|
levelDisp.insertLast(row);
|
|
}
|
|
|
|
@row.planet = pl;
|
|
row.set(getPlanetLevel(chain, i), getPlanetLevel(chain, i+1));
|
|
row.update();
|
|
}
|
|
for(uint i = maxLevel, cnt = levelDisp.length; i < cnt; ++i)
|
|
levelDisp[i].remove();
|
|
levelDisp.length = maxLevel;
|
|
|
|
array<Resource@> take;
|
|
for(uint i = 0, cnt = resList.length; i < cnt; ++i) {
|
|
take.insertLast(resList[i]);
|
|
}
|
|
|
|
bool doneUniversal = false;
|
|
Resources checkList;
|
|
checkList = available;
|
|
for(uint i = 0, cnt = levelDisp.length; i < cnt; ++i)
|
|
levelDisp[i].take(take, doneUniversal, checkList);
|
|
|
|
bool needUpdate = false;
|
|
for(uint i = 0, cnt = take.length; i < cnt; ++i) {
|
|
ResBox@ disp;
|
|
if(i < looseDisp.length) {
|
|
@disp = looseDisp[i];
|
|
}
|
|
else {
|
|
@disp = ResBox(resPanel, null);
|
|
looseDisp.insertLast(disp);
|
|
needUpdate = true;
|
|
}
|
|
|
|
@disp.planet = pl;
|
|
@disp.resource = take[i];
|
|
disp.update();
|
|
}
|
|
for(uint i = take.length, cnt = looseDisp.length; i < cnt; ++i)
|
|
looseDisp[i].remove();
|
|
looseDisp.length = take.length;
|
|
if(needUpdate)
|
|
updateLoosePositions();
|
|
|
|
if(resList.length > 0) {
|
|
//Update native resource description box
|
|
auto@ type = resList[0].type;
|
|
auto@ res = resList[0];
|
|
string desc = format("[img=$2;20/] [font=Bold]$1[/font]\n[color=#aaa]", type.name, getSpriteDesc(type.smallIcon));
|
|
|
|
if(type.blurb.length == 0)
|
|
desc += format(type.description, toString(pl.level, 0));
|
|
else
|
|
desc += format(type.blurb, toString(pl.level, 0));
|
|
if(type.blurb.length == 0 && type.description.length == 0) {
|
|
if(type.level > 0) {
|
|
desc += format(locale::RESOURCE_TIER_DESC,
|
|
toString(type.level),
|
|
type.level < LEVEL_REQ.length ? getSpriteDesc(LEVEL_REQ[type.level]) : "ResourceClassIcons::5");
|
|
}
|
|
}
|
|
desc += "[/color]";
|
|
resourceDesc.text = desc;
|
|
|
|
string pres;
|
|
int iconSize = 26;
|
|
uint presCount = 0;
|
|
for(uint i = 0; i < TR_COUNT; ++i) {
|
|
if(type.tilePressure[i] != 0)
|
|
presCount += 1;
|
|
}
|
|
if(presCount >= 3)
|
|
iconSize = 16;
|
|
else if(presCount > 2)
|
|
iconSize = 20;
|
|
|
|
uint c = 0;
|
|
for(uint i = 0; i < TR_COUNT; ++i) {
|
|
if(type.tilePressure[i] == 0)
|
|
continue;
|
|
|
|
int maxpres = type.tilePressure[i];
|
|
int curpres = max(round(float(maxpres) * res.efficiency), 0.f);
|
|
if(!owned)
|
|
curpres = maxpres;
|
|
|
|
if(curpres == maxpres)
|
|
pres += format("[img=$2;$3/] $1", toString(maxpres), getTileResourceSpriteSpec(i), toString(iconSize));
|
|
else
|
|
pres += format("[img=$3;$4/] $1/$2", toString(curpres), toString(maxpres), getTileResourceSpriteSpec(i), toString(iconSize));
|
|
|
|
c += 1;
|
|
if(presCount < 3 || c%2 == 0)
|
|
pres += "\n";
|
|
else
|
|
pres += " ";
|
|
}
|
|
|
|
if(presCount >= 3)
|
|
resourcePressure.text = pres;
|
|
else
|
|
resourcePressure.text = "[font=Medium]"+pres+"[/font]";
|
|
|
|
setMarkupTooltip(resourceBox, getResourceTooltip(type, res, pl), width=350);
|
|
resourceBox.visible = true;
|
|
}
|
|
else {
|
|
resourceBox.visible = false;
|
|
}
|
|
}
|
|
|
|
if(!owned || (lv == maxLevel && decay <= 0) || (lv >= uint(pl.maxLevel) && decay <= 0)) {
|
|
requireBox.visible = false;
|
|
}
|
|
else if(decay > 0) {
|
|
requireBox.visible = true;
|
|
reqTimer.visible = true;
|
|
reqTimer.text = formatTime(decay);
|
|
reqLabel.color = Color(0xff0000ff);
|
|
reqLabel.tooltip = format(locale::REQ_STOP_DECAY, toString(lv-1), formatTime(decay));
|
|
|
|
uint newMod = pl.resourceModID;
|
|
if(newMod != modID) {
|
|
const PlanetLevel@ lvl = getPlanetLevel(pl, lv);
|
|
reqDisplay.set(lvl.reqs, available);
|
|
reqDisplay.visible = true;
|
|
reqLabel.visible = true;
|
|
|
|
popReq.visible = reqDisplay.length == 0 && owner.HasPopulation != 0;
|
|
if(popReq.visible)
|
|
popReq.text = format(locale::POP_REQ, standardize(lvl.requiredPop, true));
|
|
|
|
reqLabel.tooltip = format(locale::REQ_FOR_LEVEL, toString(lv + 1));
|
|
modID = newMod;
|
|
}
|
|
}
|
|
else {
|
|
requireBox.visible = true;
|
|
reqTimer.visible = false;
|
|
reqLabel.color = Color(0xffffffff);
|
|
|
|
uint newMod = pl.resourceModID;
|
|
if(newMod != modID) {
|
|
const PlanetLevel@ lvl = getPlanetLevel(pl, lv + 1);
|
|
reqDisplay.set(lvl.reqs, available);
|
|
reqDisplay.visible = true;
|
|
reqLabel.visible = true;
|
|
|
|
popReq.visible = reqDisplay.length == 0 && owner.HasPopulation != 0;
|
|
if(popReq.visible)
|
|
popReq.text = format(locale::POP_REQ, standardize(lvl.requiredPop, true));
|
|
|
|
reqLabel.text = format(locale::REQUIRED_RESOURCES, toString(lv+1));
|
|
reqLabel.tooltip = format(locale::REQ_FOR_LEVEL, toString(lv + 1));
|
|
modID = newMod;
|
|
}
|
|
}
|
|
|
|
if(wasVis != requireBox.visible || !statusBox.visible) {
|
|
if(requireBox.visible)
|
|
statusBox.alignment.left.pixels = statusPos;
|
|
else
|
|
statusBox.alignment.left.pixels = 200;
|
|
statusBox.visible = true;
|
|
statusBox.updateAbsolutePosition();
|
|
}
|
|
}
|
|
}
|
|
|
|
void updateAbsolutePosition() {
|
|
DisplayBox::updateAbsolutePosition();
|
|
updateLoosePositions();
|
|
}
|
|
|
|
void updateLoosePositions() {
|
|
if(resPanel is null)
|
|
return;
|
|
int perRow = (resPanel.size.width/2 - 10) / 47;
|
|
if(!showLevels)
|
|
perRow = (resPanel.size.width - 30) / 47;
|
|
if(perRow == 0)
|
|
perRow = 1;
|
|
|
|
int start = 10;
|
|
for(uint i = 0, cnt = looseDisp.length; i < cnt; ++i) {
|
|
looseDisp[i].rect = recti_area(
|
|
vec2i(start+(i%perRow)*47, 100+(i/perRow)*47),
|
|
vec2i(44, 44));
|
|
}
|
|
}
|
|
|
|
bool onGuiEvent(const GuiEvent& evt) override {
|
|
switch(evt.type) {
|
|
case GUI_Animation_Complete:
|
|
updateAbsolutePosition();
|
|
tree.update();
|
|
updateAbsolutePosition();
|
|
doCenter = true;
|
|
break;
|
|
case GUI_Clicked:
|
|
if(evt.caller is toggleButton) {
|
|
SHOW_PLANET_TREE = toggleButton.pressed;
|
|
return true;
|
|
}
|
|
break;
|
|
}
|
|
return DisplayBox::onGuiEvent(evt);
|
|
}
|
|
|
|
void draw() {
|
|
DisplayBox::draw();
|
|
if(doCenter) {
|
|
doCenter = false;
|
|
tree.center();
|
|
}
|
|
}
|
|
};
|
|
|
|
class UnexportOption : GuiContextOption {
|
|
Resource r;
|
|
|
|
UnexportOption(Planet@ pl, Resource@ res) {
|
|
this.r = res;
|
|
if(res.origin is pl)
|
|
this.text = format(locale::OPT_CANCEL_EXPORT, r.type.name);
|
|
else
|
|
this.text = format(locale::OPT_CANCEL_IMPORT, r.type.name, r.origin.name);
|
|
}
|
|
|
|
void call(GuiContextMenu@ menu) override {
|
|
r.origin.exportResource(r.id, null);
|
|
}
|
|
};
|
|
|
|
class AutoImportOption : GuiContextOption {
|
|
Planet@ planet;
|
|
ResourceRequirement req;
|
|
|
|
AutoImportOption(Planet@ pl, const ResourceRequirement@ req) {
|
|
@this.planet = pl;
|
|
this.req = req;
|
|
this.text = locale::OPT_IMPORT_AUTO;
|
|
}
|
|
|
|
void call(GuiContextMenu@ menu) override {
|
|
if(req.type == RRT_Class)
|
|
planet.owner.autoImportResourceOfClass(planet, req.cls.id);
|
|
else if(req.type == RRT_Level)
|
|
planet.owner.autoImportResourceOfLevel(planet, req.level);
|
|
else if(req.type == RRT_Resource)
|
|
planet.owner.autoImportResourceOfType(planet, req.resource.id);
|
|
}
|
|
};
|
|
|
|
class AutoImportLevelOption : GuiContextOption {
|
|
Planet@ planet;
|
|
uint toLevel;
|
|
|
|
AutoImportLevelOption(Planet@ pl, uint level) {
|
|
@this.planet = pl;
|
|
this.toLevel = level;
|
|
this.text = format(locale::AUTO_IMPORT_LEVEL, toString(level));
|
|
}
|
|
|
|
void call(GuiContextMenu@ menu) override {
|
|
planet.owner.autoImportToLevel(planet, toLevel);
|
|
}
|
|
};
|
|
|
|
class CancelAutoImportOption : GuiContextOption {
|
|
Planet@ planet;
|
|
ResourceRequirement req;
|
|
|
|
CancelAutoImportOption(Planet@ pl, const ResourceRequirement@ req) {
|
|
@this.planet = pl;
|
|
this.req = req;
|
|
this.text = locale::OPT_IMPORT_AUTO_CANCEL;
|
|
}
|
|
|
|
void call(GuiContextMenu@ menu) override {
|
|
if(req.type == RRT_Class)
|
|
planet.owner.cancelAutoImportClassTo(planet, req.cls.id);
|
|
else if(req.type == RRT_Level)
|
|
planet.owner.cancelAutoImportLevelTo(planet, req.level);
|
|
else if(req.type == RRT_Resource)
|
|
planet.owner.cancelAutoImportTo(planet, req.resource.id);
|
|
}
|
|
};
|
|
|
|
class CancelAllAutoImportOption : GuiContextOption {
|
|
Planet@ planet;
|
|
|
|
CancelAllAutoImportOption(Planet@ pl) {
|
|
@this.planet = pl;
|
|
this.text = locale::OPT_IMPORT_AUTO_CANCEL_ALL;
|
|
}
|
|
|
|
void call(GuiContextMenu@ menu) override {
|
|
planet.owner.cancelAutoImportTo(planet);
|
|
}
|
|
};
|
|
// }}}
|
|
|
|
import void openOverlay(Object@) from "tabs.GalaxyTab";
|
|
import void resetInfoBar() from "tabs.GalaxyTab";
|
|
import void resetGalaxyTabs() from "tabs.GalaxyTab";
|
|
from obj_selection import selectedObject;
|
|
void postReload(Message& msg) {
|
|
resetGalaxyTabs();
|
|
resetInfoBar();
|
|
openOverlay(selectedObject);
|
|
}
|