Open source Star Ruler 2 source code!

This commit is contained in:
Lucas de Vries
2018-07-17 14:15:37 +02:00
commit cc307720ff
4342 changed files with 2365070 additions and 0 deletions
+1
View File
@@ -0,0 +1 @@
#include "../definitions/empire_data.as"
+11
View File
@@ -0,0 +1,11 @@
import version;
void init() {
string ver = SCRIPT_VERSION;
int pos = ver.findLast(" ");
if(pos != -1)
ver = ver.substr(pos+2);
else if(ver.length != 0)
ver = ver.substr(1);
errorVersion = toUInt(ver);
}
+1
View File
@@ -0,0 +1 @@
#include "../definitions/icons.as"
+64
View File
@@ -0,0 +1,64 @@
import elements.IGuiElement;
from gui import onMouseEvent, onKeyboardEvent;
void onMouseMoved(int x, int y) {
MouseEvent evt;
evt.type = MET_Moved;
evt.x = x;
evt.y = y;
onMouseEvent(evt);
}
bool onMouseButton(int button, bool pressed) {
MouseEvent evt;
if(pressed)
evt.type = MET_Button_Down;
else
evt.type = MET_Button_Up;
evt.button = button;
vec2i mpos = mousePos;
evt.x = mpos.x;
evt.y = mpos.y;
return onMouseEvent(evt);
}
bool onCharTyped(int chr) {
KeyboardEvent evt;
evt.type = KET_Key_Typed;
evt.key = chr;
return onKeyboardEvent(evt);
}
bool onKeyEvent(int key, int keyaction) {
KeyboardEvent evt;
bool pressed = (keyaction & KA_Pressed) != 0;
if(pressed)
evt.type = KET_Key_Down;
else
evt.type = KET_Key_Up;
evt.key = key;
return onKeyboardEvent(evt);
}
void onMouseWheel(double x, double y) {
MouseEvent evt;
evt.type = MET_Scrolled;
evt.x = int(floor(x));
evt.y = int(floor(y));
onMouseEvent(evt);
}
void main_menu(bool pressed) {
if(pressed) {
if(game_state == GS_Menu) {
if(game_running)
switchToGame();
}
else
switchToMenu();
}
}
void init() {
keybinds::Global.addBind(KB_TOGGLE_MENU, "main_menu");
}
+115
View File
@@ -0,0 +1,115 @@
import menus;
import saving;
import dialogs.MessageDialog;
const string DATE_FORMAT("%Y-%m-%d %H:%M");
class SaveItem : MenuAction {
string fname;
int64 mtime;
string date;
SaveItem(const string& filename) {
fname = filename;
super(getBasename(filename, false), 1);
mtime = getModifiedTime(filename);
date = strftime(DATE_FORMAT, mtime);
}
void draw(GuiListbox@ ele, uint flags, const recti& absPos) override {
MenuAction::draw(ele, flags, absPos);
const Font@ detail = ele.skin.getFont(FT_Small);
detail.draw(pos=absPos.padded(6), text=date, vertAlign=1.0, horizAlign=1.0);
}
int opCmp(const SaveItem@ other) const {
if(mtime < other.mtime)
return -1;
if(mtime > other.mtime)
return 1;
return 0;
}
};
class LoadMenu : MenuBox {
LoadMenu() {
super();
}
void buildMenu() {
title.text = locale::LOAD_GAME;
items.addItem(MenuAction(Sprite(spritesheet::MenuIcons, 11), locale::MENU_BACK, 0));
string dir = baseProfile["saves"];
FileList files(dir, "*.sr2");
uint cnt = files.length;
array<SaveItem@> list;
for(uint i = 0; i < cnt; ++i)
list.insertLast(SaveItem(files.path[i]));
list.sortDesc();
for(uint i = 0; i < cnt; ++i)
items.addItem(list[i]);
}
void onSelected(const string& name, int value) {
if(value == 0) {
if(mpServer && !game_running)
mpDisconnect();
switchToMenu(main_menu, false);
return;
}
else if(value == 1) {
string path = path_join(baseProfile["saves"], name)+".sr2";
SaveFileInfo info;
getSaveFileInfo(path, info);
if(!info.hasMods()) {
message(locale::SAVE_NO_MODS);
return;
}
uint version = getSaveVersion(path);
if(!isSaveCompatible(version)) {
auto@ dialog = message(locale::SAVE_NO_COMPAT);
dialog.titleColor = colors::Red;
return;
}
switchToMenu(main_menu, false, true);
loadGame(path);
return;
}
}
void hide() {
backgroundFile = "";
MenuBox::hide();
}
bool onGuiEvent(const GuiEvent& event) {
switch(event.type) {
case GUI_Hover_Changed:
if(event.caller is items) {
MenuAction@ act = cast<MenuAction>(items.hoveredItem);
if(act !is null && act.value == 1) {
backgroundFile = path_join(baseProfile["saves"], act.text)+".png";
if(!fileExists(backgroundFile))
backgroundFile = "";
}
else
backgroundFile = "";
return true;
}
break;
}
return MenuBox::onGuiEvent(event);
}
};
void init() {
@load_menu = LoadMenu();
}
+343
View File
@@ -0,0 +1,343 @@
import menus;
import settings.game_settings;
from new_game import showNewGame;
from multiplayer_menu import showMultiplayer;
from irc_window import openIRC, closeIRC, LinkableMarkupText;
import dialogs.QuestionDialog;
import icons;
// TODO: Switch this out once we fix multiple starts.
const bool M_BROKEN = false;
enum MenuActions {
MA_NewGame,
MA_EndGame,
MA_Tutorial,
MA_Campaign,
MA_LoadGame,
MA_SaveGame,
MA_Options,
MA_Resume,
MA_Quit,
MA_OpenIRC,
MA_CloseIRC,
MA_Multiplayer,
MA_Disconnect,
MA_Sandbox,
MA_Update,
MA_Mods,
};
class MainMenu : MenuBox {
MenuNews news;
MainMenu() {
super();
}
void buildMenu() {
if(game_running && gameSpeed == 0)
title.text = locale::PAUSED_MENU;
else
title.text = locale::MAIN_MENU;
if(game_running) {
if(gameSpeed == 0 && settings::bMenuPause)
items.addItem(MenuAction(Sprite(spritesheet::MenuIcons, 10), locale::RESUME_GAME, MA_Resume));
else
items.addItem(MenuAction(Sprite(spritesheet::MenuIcons, 10), locale::RETURN_TO_GAME, MA_Resume));
}
if(mpClient)
items.addItem(MenuAction(Sprite(spritesheet::MenuIcons, 8), locale::DISCONNECT, MA_Disconnect));
else if(game_running)
items.addItem(MenuAction(Sprite(spritesheet::MenuIcons, 8), locale::END_GAME, MA_EndGame));
items.addItem(MenuAction(Sprite(spritesheet::MenuIcons, 3), locale::TUTORIAL, MA_Tutorial));
//items.addItem(MenuAction(Sprite(material::TabPlanets), locale::CAMPAIGN, MA_Campaign));
items.addItem(MenuAction(Sprite(spritesheet::MenuIcons, 0), locale::NEW_GAME, MA_NewGame));
items.addItem(MenuAction(Sprite(spritesheet::MenuIcons, 1), locale::LOAD_GAME, MA_LoadGame));
if(game_running && !mpClient)
items.addItem(MenuAction(Sprite(spritesheet::MenuIcons, 2), locale::SAVE_GAME, MA_SaveGame));
items.addItem(MenuAction(Sprite(spritesheet::ResourceIconsSmall, 46), locale::MODS_MENU, MA_Mods));
if(!game_running && !STEAM_EQUIV_BUILD)
items.addItem(MenuAction(icons::Refresh, locale::CHECK_FOR_UPDATES, MA_Update));
items.addItem(MenuAction(Sprite(spritesheet::MenuIcons, 4), locale::MULTIPLAYER, MA_Multiplayer));
items.addItem(MenuAction(Sprite(material::TabDesigns), locale::SANDBOX, MA_Sandbox));
if(IRC.running)
items.addItem(MenuAction(Sprite(spritesheet::MenuIcons, 5), locale::CLOSE_IRC, MA_CloseIRC));
else
items.addItem(MenuAction(Sprite(spritesheet::MenuIcons, 6), locale::OPEN_IRC, MA_OpenIRC));
items.addItem(MenuAction(Sprite(spritesheet::MenuIcons, 7), locale::MENU_OPTIONS, MA_Options));
items.addItem(MenuAction(Sprite(spritesheet::MenuIcons, 8), locale::QUIT_GAME, MA_Quit));
}
void tick(double time) {
if(!game_running && !menu_container.animating && menu_container.visible) {
if(mpIsConnected())
showNewGame(true);
else if(mpIsConnecting() || cloud::queueRequest)
showMultiplayer();
}
}
void startTutorial() {
GameSettings settings;
settings.defaults();
settings.galaxies[0].map_id = "Tutorial.Tutorial";
Message msg;
settings.write(msg);
if(topMod !is baseMod) {
array<string> basemods = {"base"};
switchToMods(basemods);
}
startNewGame(msg);
}
void startSandbox() {
GameSettings settings;
settings.defaults();
settings.galaxies[0].map_id = "Sandbox.Sandbox";
Message msg;
settings.write(msg);
startNewGame(msg);
}
void _stopGame() {
stopGame();
refresh();
}
void animate(MenuAnimation type) {
if(type == MAni_LeftOut || type == MAni_RightOut)
showDescBox(null);
MenuBox::animate(type);
}
void completeAnimation(MenuAnimation type) {
if(type == MAni_LeftShow || type == MAni_RightShow)
showDescBox(news);
MenuBox::completeAnimation(type);
}
void onSelected(const string& name, int value) {
switch(value) {
case MA_Resume:
switchToGame();
break;
case MA_NewGame:
showNewGame();
break;
case MA_Tutorial:
if(game_running)
question(locale::PROMPT_TUTORIAL, ConfirmChoice(MenuChoice(this.startTutorial)));
else
startTutorial();
break;
case MA_Campaign:
switchToMenu(campaign_menu);
break;
case MA_Sandbox:
if(game_running)
question(locale::PROMPT_SANDBOX, ConfirmChoice(MenuChoice(this.startSandbox)));
else
startSandbox();
break;
case MA_Options:
switchToMenu(options_menu);
break;
case MA_LoadGame:
switchToMenu(load_menu);
break;
case MA_SaveGame:
switchToMenu(save_menu);
break;
case MA_Mods:
switchToMenu(mods_menu);
break;
case MA_EndGame:
if(game_running)
question(locale::PROMPT_END, ConfirmChoice(MenuChoice(this._stopGame)));
else
_stopGame();
break;
case MA_Disconnect:
if(game_running)
question(locale::PROMPT_DISCONNECT, ConfirmChoice(MenuChoice(this._stopGame)));
else {
mpDisconnect();
_stopGame();
}
break;
case MA_OpenIRC:
if(!IRC.running) {
IRC.nickname = settings::sNickname;
IRC.connect();
openIRC();
refresh();
}
break;
case MA_CloseIRC:
if(IRC.running) {
IRC.disconnect();
closeIRC();
refresh();
}
break;
case MA_Quit:
if(game_running)
question(locale::PROMPT_QUIT, ConfirmChoice(quitGame));
else
quitGame();
break;
case MA_Multiplayer:
showMultiplayer();
break;
case MA_Update:
checkForUpdates();
break;
}
}
};
funcdef void MenuChoice();
class ConfirmChoice : QuestionDialogCallback {
MenuChoice@ choice;
ConfirmChoice(MenuChoice@ Choice) {
@choice = Choice;
}
void questionCallback(QuestionDialog@ dialog, int answer) {
if(answer == QA_Yes)
choice();
}
};
class MenuNews : DescBox {
GuiPanel@ newsPanel;
LinkableMarkupText@ newsText;
WebData wdata;
bool shown = false;
GuiPanel@ modsPanel;
GuiMarkupText@ modsText;
GuiButton@ modsButton;
GuiButton@ workshopButton;
GuiButton@ internetButton;
MenuNews() {
@newsPanel = GuiPanel(this, Alignment(Left, Top, Right, Bottom-100));
@newsText = LinkableMarkupText(newsPanel, recti_area(12,12,100,100));
newsText.text = "...";
newsText.paragraphize = true;
@modsPanel = GuiPanel(this, Alignment(Left, Bottom-88, Right, Bottom));
@modsText = GuiMarkupText(modsPanel, Alignment(Left+12, Top+12, Right-12, Bottom-52));
modsText.defaultFont = FT_Bold;
@modsButton = GuiButton(modsPanel, Alignment(Left+0.5f-204, Bottom-50, Width=200, Height=40), locale::MANAGE_MODS);
modsButton.buttonIcon = Sprite(spritesheet::ResourceIconsSmall, 46);
@workshopButton = GuiButton(modsPanel, Alignment(Left+0.5f+4, Bottom-50, Width=200, Height=40), locale::OPEN_WORKSHOP);
workshopButton.buttonIcon = icons::Import;
@internetButton = GuiButton(newsPanel, Alignment(Left+0.5f-200, Top+0.5f-30, Left+0.5f+200, Top+0.5f+30), locale::ENABLE_INTERNET);
internetButton.visible = false;
if(cloud::isActive) {
settings::bEnableInternet = true;
}
else {
workshopButton.visible = false;
modsButton.alignment.left.pixels += 104;
}
if(settings::bEnableInternet) {
getWikiPage("News", wdata);
}
else {
internetButton.visible = true;
newsText.text = "[font=Medium]News[/font]";
shown = true;
}
refresh();
updateAbsolutePosition();
}
void updateAbsolutePosition() {
DescBox::updateAbsolutePosition();
if(newsText !is null)
newsText.size = vec2i(newsPanel.size.width-24, newsText.renderer.height+10);
}
void refresh() {
uint installed = 0;
uint enabled = 0;
for(uint i = 0, cnt = modCount; i < cnt; ++i) {
auto@ mod = getMod(i);
if(!mod.listed)
continue;
installed += 1;
if(mod.enabled)
enabled += 1;
}
modsText.text = format("[center]"+locale::MENU_MOD_COUNTS+"[/center]", toString(installed), toString(enabled));
}
bool onGuiEvent(const GuiEvent& evt) override {
if(evt.type == GUI_Clicked) {
if(evt.caller is modsButton) {
switchToMenu(mods_menu);
return true;
}
else if(evt.caller is workshopButton) {
openBrowser("http://steamcommunity.com/app/282590/workshop/");
return true;
}
else if(evt.caller is internetButton) {
internetButton.visible = false;
shown = false;
getWikiPage("News", wdata);
settings::bEnableInternet = true;
saveSettings();
return true;
}
}
return DescBox::onGuiEvent(evt);
}
void show() {
DescBox::show();
refresh();
}
void draw() {
if(!shown && wdata.completed) {
string result = wdata.result;
newsText.text = result;
shown = true;
updateAbsolutePosition();
}
skin.draw(SS_PlainBox, SF_Normal, newsPanel.AbsolutePosition, Color(0xffffffff));
skin.draw(SS_PlainBox, SF_Normal, modsPanel.AbsolutePosition, Color(0xffffffff));
BaseGuiElement::draw();
}
};
void init() {
MainMenu menu;
@main_menu = menu;
showDescBox(menu.news);
switchToMenu(menu);
}
+1
View File
@@ -0,0 +1 @@
#include "../shared/maps.as"
+647
View File
@@ -0,0 +1,647 @@
#priority init 100
#priority draw 100
import elements.BaseGuiElement;
import elements.GuiButton;
import elements.GuiListbox;
import elements.GuiText;
import elements.GuiSprite;
import elements.GuiPanel;
import dialogs.MessageDialog;
import version;
from gui import animate_speed, animate_time, animate_remove;
enum MenuAnimation {
MAni_LeftOut,
MAni_RightHide,
MAni_RightOut,
MAni_LeftHide,
MAni_LeftIn,
MAni_RightShow,
MAni_RightIn,
MAni_LeftShow,
};
GuiText@ version;
MenuContainer@ menu_container;
GuiSprite@ menu_logo;
MenuBox@ active_menu;
DescBox@ active_desc;
MenuBox@ main_menu;
MenuBox@ campaign_menu;
MenuBox@ load_menu;
MenuBox@ save_menu;
MenuBox@ options_menu;
MenuBox@ mods_menu;
const double MSLIDE_TIME = 0.6;
const double MANI_SPEED_1 = 200.0;
const double MANI_SPEED_2 = 120.0;
const int MANI_SPACE = -240;
const double MENU_OFFSET_TIME = 0.1;
const int MENU_OFFSET = 10;
const double BG_FADE_TIME = 0.7;
const double BG_FADE_DELAY = 0.2;
DynamicTexture logo;
DynamicTexture defaultBackground;
bool hasDefaultBackground = false;
DynamicTexture currentBackground;
double bgTimer = 0;
string displayedBackground;
string backgroundFile;
string latestSave;
void init() {
//Show the version
@version = GuiText(null, Alignment(Right-200, Bottom-20, Right-4, Bottom));
version.horizAlign = 1.0;
version.text = format("Version: $1 ($2)", GAME_VERSION, SCRIPT_VERSION);
version.color = Color(0xaaaaaaaa);
//Create container
@menu_container = MenuContainer();
//Ready backgrounds
@defaultBackground.material.shader = shader::MenuBlur;
defaultBackground.material.wrapHorizontal = TW_ClampEdge;
defaultBackground.material.wrapVertical = TW_ClampEdge;
@currentBackground.material.shader = shader::MenuSaveBackground;
currentBackground.material.wrapHorizontal = TW_ClampEdge;
currentBackground.material.wrapVertical = TW_ClampEdge;
//Find latest savegame
string dir = baseProfile["saves"];
FileList files(dir, "*.sr2");
uint cnt = files.length;
int64 lastTime = 0;
for(uint i = 0; i < cnt; ++i) {
string basename = getBasename(files.basename[i], false);
string fname = path_join(dir, basename)+".sr2";
int64 mtime = getModifiedTime(fname);
if(mtime > lastTime) {
lastTime = mtime;
latestSave = basename;
}
}
//Find latest screenshot
string latestShot;
files.navigate(dir, "*.png");
lastTime = 0;
cnt = files.length;
for(uint i = 0; i < cnt; ++i) {
string fname = files.path[i];
int64 mtime = getModifiedTime(fname);
if(mtime > lastTime) {
lastTime = mtime;
latestShot = fname;
}
}
//Set background from latest screenshot
if(latestShot.length > 0 && fileExists(latestShot) && settings::bMenuBGScreenshot) {
hasDefaultBackground = true;
defaultBackground.load(latestShot);
}
else {
hasDefaultBackground = true;
defaultBackground.load("data/images/title_shot_BG.png");
}
if(hasDLC("Heralds"))
logo.load("data/images/heralds_logo.png");
else
logo.load("data/images/sr_logo.png");
}
void tick(double time) {
mouseLock = (game_state == GS_Game);
if(backgroundFile.length != 0) {
if(backgroundFile != displayedBackground) {
if(currentBackground.isLoaded()) {
currentBackground.load(backgroundFile);
bgTimer = BG_FADE_TIME;
displayedBackground = backgroundFile;
}
}
}
else {
displayedBackground = "";
}
if(bgTimer >= 0)
bgTimer = max(0.0, bgTimer - time);
if(active_menu !is null)
active_menu.tick(time);
if(isUpdating)
updateTick(time);
}
void switchToMenu(MenuBox@ menu, bool left = true, bool snap = false) {
if(snap || active_menu is null) {
if(active_menu !is null)
active_menu.hide();
if(menu !is null)
menu.show();
}
else {
active_menu.animate(left ? MAni_LeftOut : MAni_RightOut);
if(menu !is null)
menu.animate(left ? MAni_RightIn : MAni_LeftIn);
}
@active_menu = menu;
if(menu_logo !is null)
menu_logo.visible = menu !is null;
}
void showDescBox(DescBox@ box) {
if(active_desc !is null)
active_desc.hide();
if(box !is null)
box.show();
@active_desc = box;
}
class MenuContainer : BaseGuiElement {
bool animating = false;
bool hide = false;
MenuContainer() {
super(null, recti());
updateAbsolutePosition();
}
void updateAbsolutePosition() {
if(!animating) {
size = parent.size;
position = vec2i(0, 0);
}
BaseGuiElement::updateAbsolutePosition();
}
void animateIn() {
animating = true;
hide = false;
rect = recti_area(vec2i(-parent.size.x, 0), parent.size);
animate_time(this, recti_area(vec2i(), parent.size), MSLIDE_TIME);
}
void animateOut() {
animating = true;
hide = true;
rect = recti_area(vec2i(), parent.size);
animate_time(this, recti_area(vec2i(-parent.size.x, 0), parent.size), MSLIDE_TIME);
}
void show() {
hide = false;
Position = recti_area(vec2i(), parent.size);
animate_remove(this);
updateAbsolutePosition();
}
bool onGuiEvent(const GuiEvent& event) {
switch(event.type) {
case GUI_Animation_Complete:
if(event.caller is this) {
animating = false;
if(hide)
visible = false;
return true;
}
break;
}
return BaseGuiElement::onGuiEvent(event);
}
};
class MenuAction : GuiListElement {
int value = -1;
Sprite icon;
string text;
bool disabled = false;
double offset = 0.0;
Color color;
MenuAction(const string& txt, int val, bool dis = false) {
value = val;
text = txt;
disabled = dis;
}
MenuAction(const Sprite& sprt, const string& txt, int val, bool dis = false) {
value = val;
text = txt;
disabled = dis;
icon = sprt;
}
void set(const string& txt) {
text = txt;
}
string get() {
return text;
}
void draw(GuiListbox@ ele, uint flags, const recti& absPos) override {
const Font@ font = ele.skin.getFont(ele.TextFont);
int baseLine = font.getBaseline();
vec2i textOffset(ele.horizPadding, (ele.lineHeight - baseLine) / 2);
textOffset.x += offset * MENU_OFFSET;
if(ele.itemStyle == SS_NULL)
ele.skin.draw(SS_ListboxItem, flags, absPos);
if(icon.valid) {
int iSize = absPos.height - 6;
recti iPos = recti_area(absPos.topLeft + vec2i(textOffset.x, 4), vec2i(iSize, iSize));
iPos = iPos.aspectAligned(icon.aspect);
icon.draw(iPos);
textOffset.x += iSize + 8;
}
if(disabled)
font.draw(absPos.topLeft + textOffset, text, Color(0x888888ff));
else
font.draw(absPos.topLeft + textOffset, text, color);
if(flags & SF_Hovered != 0)
offset = min(1.0, offset + (frameLength / MENU_OFFSET_TIME));
else
offset = max(0.0, offset - (frameLength / MENU_OFFSET_TIME));
}
bool onMouseEvent(const MouseEvent& event) {
return disabled;
}
};
class MenuBox : BaseGuiElement {
GuiListbox@ items;
GuiText@ title;
MenuAnimation anim;
bool animating = false;
bool selectable = false;
MenuBox() {
super(menu_container, recti());
visible = false;
@title = GuiText(this, Alignment(Left, Top+4, Right, Top+44), "Load Game");
title.horizAlign = 0.5;
title.font = FT_Big;
@items = GuiListbox(this, Alignment(Left+4, Top+44, Right-4, Bottom-4));
items.itemStyle = SS_MainMenuItem;
items.font = FT_Medium;
updateAbsolutePosition();
}
void tick(double time) {
}
void animate(MenuAnimation type) {
switch(type) {
case MAni_LeftIn:
sendToBack();
show();
case MAni_LeftOut:
animate_speed(this, basePosition-vec2i(size.width/2+MANI_SPACE, 0), MANI_SPEED_1);
break;
case MAni_RightHide:
case MAni_RightShow:
animate_speed(this, basePosition, MANI_SPEED_2);
break;
case MAni_RightIn:
sendToBack();
show();
case MAni_RightOut:
animate_speed(this, basePosition+vec2i(size.width/2+MANI_SPACE, 0), MANI_SPEED_1);
break;
case MAni_LeftHide:
case MAni_LeftShow:
animate_speed(this, basePosition, MANI_SPEED_2);
break;
}
anim = type;
animating = true;
}
void completeAnimation(MenuAnimation type) {
animating = false;
switch(type) {
case MAni_LeftOut:
sendToBack();
animate(MAni_RightHide);
break;
case MAni_RightHide:
hide();
break;
case MAni_RightOut:
sendToBack();
animate(MAni_LeftHide);
break;
case MAni_LeftHide:
hide();
break;
case MAni_LeftIn:
bringToFront();
animate(MAni_RightShow);
break;
case MAni_RightShow:
break;
case MAni_RightIn:
bringToFront();
animate(MAni_LeftShow);
break;
case MAni_LeftShow:
break;
}
if(!animating)
updateAbsolutePosition();
}
recti get_basePosition() {
int width = 576;
int height = min(648, int(Parent.size.height * 0.8f - 36));
vec2i position = vec2i(Parent.size.width / 2 - 12 - width,
Parent.size.height * 0.2f + 24);
return recti_area(position, vec2i(width, height));
}
void updateAbsolutePosition() {
if(!animating)
rect = basePosition;
BaseGuiElement::updateAbsolutePosition();
}
void refresh() {
clearMenu();
buildMenu();
}
void clearMenu() {
items.clearItems();
}
void buildMenu() {
}
void show() {
clearMenu();
buildMenu();
visible = true;
}
void hide() {
visible = false;
}
bool onGuiEvent(const GuiEvent& event) {
switch(event.type) {
case GUI_Changed:
if(event.caller is items) {
MenuAction@ act = cast<MenuAction>(items.selectedItem);
if(act !is null)
onSelected(act.text, act.value);
if(!selectable)
items.clearSelection();
return true;
}
break;
case GUI_Animation_Complete:
if(event.caller is this) {
completeAnimation(anim);
return true;
}
break;
}
return BaseGuiElement::onGuiEvent(event);
}
void onSelected(const string& name, int value) {
}
void draw() {
skin.draw(SS_MainMenuPanel, SF_Normal, AbsolutePosition);
BaseGuiElement::draw();
}
};
class DescBox : BaseGuiElement {
GuiText@ title;
GuiPanel@ panel;
DescBox() {
super(menu_container, recti());
visible = false;
@title = GuiText(this, Alignment(Left, Top+4, Right, Top+44), "");
title.horizAlign = 0.5;
title.font = FT_Big;
@panel = GuiPanel(this, Alignment(Left+3, Top+44, Right-4, Bottom-4));
updateAbsolutePosition();
}
recti get_basePosition() {
int width = 576;
int height = min(648, int(Parent.size.height * 0.8f - 36));
vec2i position = vec2i(Parent.size.width / 2 + 12,
Parent.size.height * 0.2f + 24);
return recti_area(position, vec2i(width, height));
}
void updateAbsolutePosition() {
rect = basePosition;
BaseGuiElement::updateAbsolutePosition();
}
void refresh() {
}
void show() {
visible = true;
}
void hide() {
visible = false;
}
void draw() {
skin.draw(SS_MainMenuDescPanel, SF_Normal, AbsolutePosition);
BaseGuiElement::draw();
}
};
//Pause the game when entering the menu if we're set to
double prevGameSpeed = 0;
void onGameStateChange() {
if(game_state == GS_Menu) {
if(!mpClient && !mpServer) {
prevGameSpeed = gameSpeed;
if(settings::bMenuPause && gameSpeed != 0)
gameSpeed = 0;
}
active_menu.refresh();
}
else {
if(!mpClient && !mpServer && settings::bMenuPause && gameSpeed == 0)
gameSpeed = prevGameSpeed;
}
}
//Render client view if a game is active
void preRender(double time) {
if(game_running)
preRenderClient();
}
void render(double time) {
if(game_running)
renderClient();
}
void drawBackground(DynamicTexture@ bg, double alpha = 1.0) {
if(!bg.isLoaded(0))
return;
vec2i screen(screenSize);
vec2i matSize(bg.size[0]);
if(matSize.width == 0 || matSize.height == 0)
return;
float aspect = float(matSize.width) / float(matSize.height);
if(aspect > 1.f) {
matSize.height = float(screen.width) / aspect;
matSize.width = screen.width;
}
else {
matSize.height = screen.height;
matSize.width = float(screen.height) * aspect;
}
recti pos = recti_area(
vec2i((screen.width - matSize.width) / 2,
(screen.height - matSize.height) / 2),
matSize);
Color col(0xffffffff);
col.a = alpha * 255;
bg.draw(pos, col);
}
bool isUpdating = false;
bool startedUpdate = false;
WebData updateCheck;
void checkForUpdates() {
if(isUpdating)
return;
isUpdating = true;
webAPICall("updates/version", updateCheck);
}
void updateTick(double time) {
if(startedUpdate) {
if(!::updating) {
startedUpdate = false;
isUpdating = false;
if(updateStatus < 0)
message(format(locale::UPDATE_FAIL, toString(updateStatus)));
else
quitGame();
}
}
else if(updateCheck.completed) {
if(updateCheck.error) {
message(locale::CHECK_UPDATE_FAIL+":\n"+updateCheck.errorStr);
isUpdating = false;
return;
}
else {
string ver = updateCheck.result.trimmed();
if(ver == GAME_VERSION) {
message(locale::CHECK_UPDATE_UPTODATE);
isUpdating = false;
return;
}
//Do update
startedUpdate = true;
updateGame();
}
}
}
void draw() {
//Draw background screenshot
if(!game_running && defaultBackground.isLoaded() && hasDefaultBackground)
drawBackground(defaultBackground);
if(currentBackground.isLoaded() && backgroundFile.length != 0) {
if(BG_FADE_TIME - bgTimer > BG_FADE_DELAY)
drawBackground(currentBackground, (BG_FADE_TIME - bgTimer) / BG_FADE_TIME);
}
//Draw top and bottom bars
vec2i screen = screenSize;
double size = double(screen.x) / 1920;
if(isUpdating) {
gui_root.visible = false;
string txt;
if(updating)
txt = format(locale::UPDATE_PROGRESS, toString(updateProgress, 0));
else
txt = locale::CHECKING_UPDATES;
auto@ ft = gui_root.skin.getFont(FT_Big);
ft.draw(pos=recti_area(vec2i(),screenSize), horizAlign=0.5, vertAlign=0.5,
stroke=colors::Black, color=colors::Green, text=txt);
}
else if(inGalaxyCreation && !mpClient) {
gui_root.visible = false;
auto@ ft = gui_root.skin.getFont(FT_Big);
ft.draw(pos=recti_area(vec2i(),screenSize), horizAlign=0.5, vertAlign=0.5,
stroke=colors::Black, color=colors::Green, text=locale::MENU_LOADING);
}
else {
gui_root.visible = true;
if(menu_container.visible && logo.isLoaded()) {
vec2i size = logo.material.size;
int logoWidth = min(840, menu_container.size.width);
int logoHeight = min(350, int(floor(0.2 * menu_container.size.height) + 23));
recti area = recti_area(vec2i((menu_container.size.width-logoWidth)/2, 0), vec2i(logoWidth, logoHeight));
area += menu_container.absolutePosition.topLeft;
area = area.aspectAligned(float(size.x) / float(size.y), 0.5, 0.5);
logo.draw(area, colors::White);
}
}
}
+370
View File
@@ -0,0 +1,370 @@
import menus;
import saving;
import dialogs.MessageDialog;
import dialogs.QuestionDialog;
import dialogs.InputDialog;
import elements.GuiMarkupText;
import settings.game_settings;
from irc_window import LinkableMarkupText;
import icons;
class ModAction : MenuAction {
Mod@ mod;
DynamicTexture@ tex;
bool prevEnabled;
ModAction(Mod@ mod, DynamicTexture@ tex) {
super(Sprite(tex.material), mod.name, 0);
@this.mod = mod;
@this.tex = tex;
prevEnabled = mod.enabled;
}
void draw(GuiListbox@ ele, uint flags, const recti& absPos) override {
if(!mod.forCurrentVersion)
color = Color(0xaa4040ff);
else if(!mod.enabled)
color = Color(0x888888ff);
else
color = colors::White;
MenuAction::draw(ele, flags, absPos);
int h = absPos.height;
recti iPos = recti_area(vec2i(absPos.botRight.x-h-80+8, absPos.topLeft.y+10), vec2i(h-18, h-18));
recti tPos = recti_area(vec2i(absPos.botRight.x-80, absPos.topLeft.y+2), vec2i(78, h-2));
const Font@ ft = ele.skin.getFont(FT_Bold);
if(mod.enabled) {
icons::Plus.draw(iPos);
ft.draw(pos=tPos, text=locale::ENABLED, stroke=colors::Black, color=colors::Green);
}
else {
icons::Minus.draw(iPos);
ft.draw(pos=tPos, text=locale::DISABLED, stroke=colors::Black, color=colors::Red);
}
if(mod.isNew && mod.forCurrentVersion) {
recti iPos = recti_area(vec2i(absPos.botRight.x-h-80*2+4, absPos.topLeft.y+6), vec2i(h-10, h-10));
recti tPos = recti_area(vec2i(absPos.botRight.x-80*2, absPos.topLeft.y+2), vec2i(78, h-2));
const Font@ ft = ele.skin.getFont(FT_Bold);
spritesheet::CardCategoryIcons.draw(5, iPos);
ft.draw(pos=tPos, text=locale::NEW, stroke=colors::Black, color=Color(0xffff00ff));
}
}
int opCmp(const ModAction@ other) const {
if(mod.isNew && !other.mod.isNew)
return -1;
if(other.mod.isNew && !mod.isNew)
return 1;
if(mod.enabled && !other.mod.enabled)
return -1;
if(other.mod.enabled && !mod.enabled)
return 1;
return 0;
}
};
bool inOpenPage = false;
class ModsMenu : MenuBox, IInputDialogCallback {
ModBox box;
int prevSelected = -1;
array<ModAction@> actions;
GuiButton@ newButton;
GuiButton@ editButton;
ModsMenu() {
super();
items.alignment.bottom.pixels = 40;
@newButton = GuiButton(this, Alignment(Left+0.5f-202, Bottom-35, Width=200, Height=30), locale::NEW_MOD);
newButton.visible = !inOpenPage;
@editButton = GuiButton(this, Alignment(Left+0.5f+2, Bottom-35, Width=200, Height=30), locale::EDIT_MOD);
editButton.visible = items.selected >= 1 && !inOpenPage;
}
void buildMenu() {
title.text = locale::MODS_MENU;
selectable = true;
items.required = true;
if(inOpenPage)
items.addItem(MenuAction(Sprite(spritesheet::MenuIcons, 10), locale::MENU_CONTINUE_MAIN, 0));
else
items.addItem(MenuAction(Sprite(spritesheet::MenuIcons, 11), locale::MENU_BACK, 0));
string sel = "";
if(prevSelected >= 1 && uint(prevSelected-1) < actions.length)
sel = actions[prevSelected-1].mod.name;
actions.length = 0;
for(uint i = 0, cnt = modCount; i < cnt; ++i) {
auto@ mod = getMod(i);
if(!mod.listed)
continue;
DynamicTexture tex;
if(fileExists(path_join(mod.abspath, "logo.png")))
tex.load(path_join(mod.abspath, "logo.png"));
ModAction action(mod, tex);
actions.insertLast(action);
}
actions.sortAsc();
for(uint i = 0, cnt = actions.length; i < cnt; ++i) {
actions[i].value = int(i+1);
if(actions[i].mod.name == sel)
prevSelected = i;
if(prevSelected == -1 && actions[i].mod.isNew)
prevSelected = i+1;
items.addItem(actions[i]);
}
if(prevSelected < 1)
prevSelected = 1;
if(items.selected < 1)
items.selected = min(prevSelected, items.itemCount-1);
update();
}
void update() {
if(items.selected < 1 || uint(items.selected-1) >= actions.length)
return;
auto@ mod = actions[items.selected-1].mod;
if(mod !is null)
box.update(mod, actions[items.selected-1].tex.material);
editButton.visible = items.selected >= 1 && !inOpenPage;
newButton.visible = !inOpenPage;
}
void changeCallback(InputDialog@ dialog) {}
void inputCallback(InputDialog@ dialog, bool accepted) {
if(accepted) {
string dirname = dialog.getTextInput(0);
if(!createNewMod(dirname)) {
message("Could not create mod: invalid directory '"+dirname+"'");
return;
}
editMod(dirname);
}
}
void editMod(const string& modName) {
array<string> mods;
mods.insertLast(modName);
GameSettings settings;
settings.defaults();
settings.galaxies[0].map_id = "ModEditor.ModEditor";
Message msg;
settings.write(msg);
watchResources = true;
switchToMods(mods);
startNewGame(msg);
}
bool onGuiEvent(const GuiEvent& event) {
if(event.type == GUI_Clicked) {
if(event.caller is newButton) {
InputDialog@ dialog = InputDialog(this, this);
dialog.addTitle("Create New Mod");
dialog.accept.text = "Create";
dialog.addTextInput("Mod Directory", "");
auto@ tbox = cast<GuiTextbox>(dialog.getInput(0));
tbox.setIdentifierLimit();
tbox.characterLimit.insert(' ');
addDialog(dialog);
dialog.focusInput();
return true;
}
else if(event.caller is editButton) {
if(items.selected < 1 || uint(items.selected-1) >= actions.length)
return true;
Mod@ mod = actions[items.selected-1].mod;
editMod(mod.name);
return true;
}
}
return MenuBox::onGuiEvent(event);
}
void onSelected(const string& name, int value) {
if(value == 0) {
switchToMenu(main_menu, false);
saveModState();
inOpenPage = false;
if(!game_running) {
array<string> mods;
bool changed = false;
for(uint i = 0, cnt = actions.length; i < cnt; ++i) {
if(actions[i].mod.enabled != actions[i].prevEnabled)
changed = true;
if(actions[i].mod.enabled)
mods.insertLast(actions[i].mod.name);
}
if(changed)
switchToMods(mods);
}
return;
}
else {
prevSelected = value;
items.selected = value;
update();
}
}
void animate(MenuAnimation type) {
if(type == MAni_LeftOut || type == MAni_RightOut)
showDescBox(null);
MenuBox::animate(type);
}
void completeAnimation(MenuAnimation type) {
if(type == MAni_LeftShow || type == MAni_RightShow)
showDescBox(box);
MenuBox::completeAnimation(type);
}
void draw() {
for(uint i = 0, cnt = actions.length; i < cnt; ++i)
actions[i].tex.stream();
MenuBox::draw();
}
};
class ModBox : DescBox {
Mod@ mod;
GuiPanel@ descPanel;
GuiSprite@ picture;
GuiMarkupText@ description;
GuiButton@ toggleButton;
ModBox() {
super();
@picture = GuiSprite(this, Alignment(Left, Top+44, Right, Top+244));
@descPanel = GuiPanel(this, Alignment(Left+16, Top+254, Right-16, Bottom-50));
@description = LinkableMarkupText(descPanel, recti_area(0,0,100,100));
description.fitWidth = true;
@toggleButton = GuiButton(this, Alignment(Left+0.5f-100, Bottom-50, Left+0.5f+100, Bottom-8));
toggleButton.font = FT_Subtitle;
toggleButton.visible = false;
updateAbsolutePosition();
updateAbsolutePosition();
}
void update(Mod@ mod, const Material@ mat = null) {
@this.mod = mod;
title.text = mod.name;
if(mat !is null)
picture.desc = Sprite(mat);
string descText;
if(!mod.forCurrentVersion)
descText += locale::MOD_COMPATIBILITY_WARN;
descText += mod.description;
toggleButton.visible = true;
toggleButton.disabled = false;
if(mod.enabled) {
toggleButton.color = colors::Red;
toggleButton.buttonIcon = icons::Minus;
toggleButton.text = locale::DISABLE_MOD;
}
else {
toggleButton.color = colors::Green;
toggleButton.buttonIcon = icons::Plus;
toggleButton.text = locale::ENABLE_MOD;
}
//Check for conflicts
for(uint i = 0, cnt = modCount; i < cnt; ++i) {
auto@ other = getMod(i);
if(other !is mod && other.enabled) {
if(!other.isCompatible(mod)) {
array<string> conflicts;
mod.getConflicts(other, conflicts);
descText += "\n\n[color=#f00][b]";
descText += format(locale::MOD_INCOMPATIBLE, other.name);
if(mod.isBase && other.isBase) {
descText += "\n"+locale::MOD_CONFLICT_BASE;
descText += "[/b]";
}
else {
descText += "\n"+locale::MOD_CONFLICT;
descText += "[/b]\n ";
for(uint i = 0, cnt = conflicts.length; i < cnt; ++i) {
if(i != 0)
descText += ", ";
descText += conflicts[i];
}
}
descText += "[/color]";
toggleButton.disabled = true;
}
}
}
description.text = makebbLinks(descText);
updateAbsolutePosition();
}
bool onGuiEvent(const GuiEvent& evt) override {
if(evt.type == GUI_Clicked && evt.caller is toggleButton) {
bool enable = !mod.enabled;
if(enable && !mod.forCurrentVersion) {
question(locale::MOD_COMPATIBILITY, ModEnable(this, mod));
}
else {
mod.enabled = enable;
mod.forced = false;
update(mod);
saveModState();
}
return true;
}
return DescBox::onGuiEvent(evt);
}
};
class ModEnable : QuestionDialogCallback {
ModBox@ menu;
Mod@ mod;
ModEnable(ModBox@ menu, Mod@ mod) {
@this.menu = menu;
@this.mod = mod;
}
void questionCallback(QuestionDialog@ dialog, int answer) {
if(answer == QA_Yes) {
mod.enabled = true;
mod.forced = true;
menu.update(mod);
saveModState();
}
}
};
void init() {
@mods_menu = ModsMenu();
}
void postInit() {
for(uint i = 0, cnt = modCount; i < cnt; ++i) {
if(getMod(i).isNew) {
inOpenPage = true;
switchToMenu(mods_menu, snap=true);
showDescBox(cast<ModsMenu>(mods_menu).box);
mods_menu.updateAbsolutePosition();
}
}
}
+790
View File
@@ -0,0 +1,790 @@
import menus;
import elements.BaseGuiElement;
import elements.GuiButton;
import elements.GuiPanel;
import elements.GuiText;
import elements.GuiTextbox;
import elements.GuiSpinbox;
import elements.GuiCheckbox;
import elements.GuiOverlay;
import elements.GuiProgressbar;
import elements.GuiBackgroundPanel;
import dialogs.MessageDialog;
import dialogs.InputDialog;
import icons;
from irc_window import showIRC;
from new_game import showNewGame;
from maps import Map, maps, mapCount, getMap;
import util.game_options;
class ServerDesc {
GameServer srv;
bool found = false;
};
class ServerElement : GuiListElement {
string text;
Color color;
bool disabled = false;
void set(const string& txt) {
text = txt;
}
string get() {
return text;
}
void draw(GuiListbox@ ele, uint flags, const recti& absPos) {
const Font@ font = ele.skin.getFont(ele.TextFont);
int baseLine = font.getBaseline();
vec2i textOffset(ele.horizPadding, (absPos.size.height - baseLine) / 2);
if(ele.itemStyle == SS_NULL)
ele.skin.draw(SS_ListboxItem, flags, absPos);
font.draw(absPos.topLeft + textOffset, text, color);
}
bool get_isSelectable() {
return !disabled;
}
};
class PasswordDialog : InputDialogCallback {
void inputCallback(InputDialog@ dialog, bool accepted) {
if(accepted) {
string pwd = dialog.getTextInput(0);
mp_list.join(pwd);
}
}
};
class IPJoin : InputDialogCallback {
void inputCallback(InputDialog@ dialog, bool accepted) {
if(accepted)
mp_list.join(dialog.getTextInput(0), toInt(dialog.getTextInput(1)), dialog.getTextInput(2));
}
};
class Multiplayer : BaseGuiElement {
GuiBackgroundPanel@ gamesBG;
GuiBackgroundPanel@ optionsBG;
GuiBackgroundPanel@ hostBG;
GuiProgressbar@ transferProgress;
GuiButton@ backButton, joinButton, queueButton;
GuiButton@ hostButton, hostLoadButton;
GuiButton@ refreshButton;
GuiButton@ ircButton;
GuiButton@ ipButton;
GuiText@ nickLabel;
GuiTextbox@ nick;
GuiText@ serverNameLabel;
GuiTextbox@ serverName;
GuiText@ passwordLabel;
GuiTextbox@ passwordBox;
GuiText@ portLabel;
GuiTextbox@ portBox;
GuiCheckbox@ publicToggle;
GuiCheckbox@ punchToggle;
GuiText@ noServers;
GuiListbox@ servers;
array<ServerDesc@> gameServers;
array<GameServer> newServers;
GuiText@ inQueue;
GuiButton@ queueAccept, queueReject, queueLeave;
GuiText@ connectingText;
GuiButton@ cancelButton;
bool animating = false;
bool hide = false;
bool connecting = false;
double nextRefresh = 0.0;
Multiplayer() {
super(null, recti());
@gamesBG = GuiBackgroundPanel(this, Alignment(
Left+0.05f, Top+0.1f, Right-0.05f, Bottom-0.1f-242));
gamesBG.title = locale::MENU_GAMES;
gamesBG.titleColor = Color(0x00ff00ff);
@optionsBG = GuiBackgroundPanel(this, Alignment(
Left+0.05f, Bottom-0.1f-230, Right-0.5f-6, Bottom-0.1f));
optionsBG.title = locale::MP_OPTIONS;
optionsBG.titleColor = Color(0xd0ffefff);
@hostBG = GuiBackgroundPanel(this, Alignment(
Left+0.5f+6, Bottom-0.1f-230, Right-0.05f, Bottom-0.1f));
hostBG.title = locale::MP_HOST_OPTIONS;
hostBG.titleColor = Color(0xd0ffefff);
@noServers = GuiText(gamesBG, Alignment(Left+12,Top+33,Right-4,Top+55), locale::MP_NO_GAMES);
noServers.color = Color(0xaaaaaaff);
noServers.font = FT_Italic;
@servers = GuiListbox(gamesBG, Alignment(Left+4,Top+33,Right-4,Bottom-42));
servers.visible = false;
@nickLabel = GuiText(optionsBG, recti(12, 33, 110, 60), locale::NICKNAME);
@nick = GuiTextbox(optionsBG, recti(122, 33, 280, 60), settings::sNickname);
@serverNameLabel = GuiText(hostBG, recti(12, 33, 110, 60), locale::MP_SERVER_NAME);
@serverName = GuiTextbox(hostBG, recti(122, 33, 380, 60), settings::sNickname+"'s Game");
serverName.tabIndex = 1;
@passwordLabel = GuiText(hostBG, recti(11, 66, 110, 93), locale::PASSWORD);
@passwordBox = GuiTextbox(hostBG, recti(122, 66, 380, 93), "");
passwordBox.tabIndex = 2;
@publicToggle = GuiCheckbox(hostBG, recti(12, 99, 140, 126), locale::MP_PUBLIC, true);
publicToggle.tabIndex = 3;
@punchToggle = GuiCheckbox(hostBG, recti(150, 99, 280, 126), locale::MP_PUNCHTHROUGH, true);
punchToggle.tabIndex = 4;
@portLabel = GuiText(hostBG, recti(12, 132, 110, 158), locale::MP_PORT);
@portBox = GuiTextbox(hostBG, recti(122, 132, 250, 158), "2048");
portBox.tabIndex = 5;
@refreshButton = GuiButton(gamesBG, Alignment(
Right-174, Bottom-40, Width=170, Height=36),
locale::REFRESH);
refreshButton.buttonIcon = Sprite(spritesheet::MenuIcons, 12);
@ircButton = GuiButton(gamesBG, Alignment(
Left+4, Bottom-40, Width=200, Height=36),
locale::MP_IRC_CHAT);
ircButton.buttonIcon = icons::Chat;
@ipButton = GuiButton(gamesBG, Alignment(
Left+208, Bottom-40, Width=200, Height=36),
locale::MP_JOIN_IP);
ipButton.buttonIcon = Sprite(spritesheet::MenuIcons, 13);
@joinButton = GuiButton(this, Alignment(
Right-0.05f-200, Bottom-0.1f+6, Width=200, Height=46),
locale::MP_JOIN);
joinButton.buttonIcon = Sprite(spritesheet::MenuIcons, 13);
@hostButton = GuiButton(this, Alignment(
Right-0.05f-412, Bottom-0.1f+6, Width=200, Height=46),
locale::MP_HOST);
hostButton.buttonIcon = Sprite(spritesheet::MenuIcons, 14);
@hostLoadButton = GuiButton(this, Alignment(
Right-0.05f-624, Bottom-0.1f+6, Width=200, Height=46),
locale::MP_HOST_LOAD);
hostLoadButton.buttonIcon = Sprite(spritesheet::MenuIcons, 15);
@backButton = GuiButton(this, Alignment(
Left+0.05f, Bottom-0.1f+6, Width=200, Height=46),
locale::BACK);
backButton.buttonIcon = Sprite(spritesheet::MenuIcons, 11);
if(cloud::isActive) {
@queueButton = GuiButton(this, Alignment(
Right-0.05f-836, Bottom-0.1f+6, Width=200, Height=46),
locale::MP_QUEUE);
queueButton.buttonIcon = Sprite(spritesheet::MenuIcons, 4);
@inQueue = GuiText(gamesBG, Alignment(Left+12,Top+33,Right-4,Top+61), locale::MP_QUEUE_ACTIVE);
inQueue.font = FT_Medium;
inQueue.horizAlign = 0.5;
inQueue.visible = false;
@queueAccept = GuiButton(gamesBG, Alignment(
Left+0.5f-205, Top+65, Width=200, Height=46),
locale::MP_QUEUE_ACCEPT);
queueAccept.font = FT_Medium;
queueAccept.color = Color(0x88ff88ff);
queueAccept.visible = false;
@queueReject = GuiButton(gamesBG, Alignment(
Left+0.5f+5, Top+65, Width=200, Height=46),
locale::MP_QUEUE_REJECT);
queueReject.font = FT_Medium;
queueReject.color = Color(0xff8888ff);
queueReject.visible = false;
@queueLeave = GuiButton(gamesBG, Alignment(
Left+0.5f-100, Top+65, Width=200, Height=46),
locale::MP_QUEUE_LEAVE);
queueLeave.font = FT_Medium;
queueLeave.visible = false;
}
@connectingText = GuiText(this, Alignment(Left, Top+0.5f-56, Right, Top+0.5f));
connectingText.font = FT_Medium;
connectingText.horizAlign = 0.5;
connectingText.visible = false;
@cancelButton = GuiButton(this, Alignment(
Left+0.5f-100, Top+0.5f-16, Width=200, Height=46),
locale::CANCEL);
cancelButton.visible = false;
@transferProgress = GuiProgressbar(this, Alignment(Left+0.25f, Bottom-0.25f-25, Right-0.25f, Bottom-0.25f+25));
transferProgress.frontColor = colors::Orange;
transferProgress.visible = false;
updateAbsolutePosition();
}
void refresh() {
if(mpIsQuerying())
return;
mpQueryServers();
for(uint n = 0, ncnt = gameServers.length; n < ncnt; ++n)
gameServers[n].found = false;
}
void tick(double time) {
if(!visible)
return;
if(gamesBG.visible) {
if(!cloud::isActive || !cloud::inQueue) {
if(queueButton !is null) {
inQueue.visible = false;
queueAccept.visible = false;
queueReject.visible = false;
queueLeave.visible = false;
queueButton.visible = true;
}
joinButton.visible = true;
ipButton.visible = true;
refreshButton.visible = true;
hostButton.disabled = false;
hostLoadButton.disabled = false;
servers.visible = gameServers.length != 0;
noServers.visible = gameServers.length == 0;
}
else {
inQueue.visible = true;
bool queueRequested = cloud::queueRequest;
queueAccept.visible = queueRequested;
queueReject.visible = queueRequested;
queueLeave.visible = !queueRequested;
uint ready = 0, players = 0;
if(queueRequested)
inQueue.text = locale::MP_QUEUE_READY;
else if(cloud::getQueuePlayerWait(ready, players)) {
inQueue.text = format(locale::MP_QUEUE_WAITING, ready, players);
queueLeave.visible = false;
}
else {
uint players = cloud::queuePlayers;
if(players == 0)
inQueue.text = locale::MP_QUEUE_ACTIVE;
else
inQueue.text = format(locale::MP_QUEUE_ACTIVE_PLAYERS, players);
}
queueButton.visible = false;
joinButton.visible = false;
ipButton.visible = false;
refreshButton.visible = false;
hostButton.disabled = true;
hostLoadButton.disabled = true;
servers.visible = false;
noServers.visible = false;
}
}
if(!connectingText.visible) {
if(!menu_container.animating && cloud::isQueueReady) {
if(mpClient) {
showConnecting();
showMenu();
hideMultiplayer(snap=true);
showNewGame(true);
return;
}
if(mpServer) {
showMenu();
hideMultiplayer(snap=true);
showNewGame();
return;
}
}
if(awaitingGalaxy)
showConnecting();
}
if(connectingText.visible) {
if(awaitingGalaxy) {
connectingText.text = locale::MP_WAITING_TRANSFER;
}
else if(mpIsConnected()) {
connectingText.text = locale::MP_WAITING_START;
showMenu();
hideMultiplayer();
showNewGame(true);
}
else if(!mpIsConnecting()) {
mpDisconnect();
showMenu();
message(locale::MP_CANNOT_CONNECT+":\n "
+localize("DISCONNECT_"+uint(mpDisconnectReason)));
}
}
else if(mpIsConnecting()) {
connectingText.text = "Connecting...";
showConnecting();
updateAbsolutePosition();
}
if(awaitingGalaxy) {
float pct = galaxySendProgress;
transferProgress.visible = true;
transferProgress.progress = pct;
transferProgress.text = toString(pct * 100.f, 0)+"%";
}
else {
transferProgress.visible = false;
}
nextRefresh -= time;
if(nextRefresh <= 0.0) {
nextRefresh = 30.0;
refresh();
}
bool serversChanged = false;
int sel = servers.selected;
GameAddress selAddr;
if(sel != -1 && uint(sel) < gameServers.length)
selAddr = gameServers[sel].srv.address;
//Get new servers
mpGetServers(newServers);
if(newServers.length != 0) {
for(uint i = 0, cnt = newServers.length; i < cnt; ++i) {
//See if we already have this server
bool found = false;
for(uint n = 0, ncnt = gameServers.length; n < ncnt; ++n) {
if(gameServers[n].srv.address == newServers[i].address) {
gameServers[n].srv = newServers[i];
gameServers[n].found = true;
found = true;
break;
}
}
if(!found) {
ServerDesc desc;
desc.srv = newServers[i];
desc.found = true;
gameServers.insertLast(desc);
}
}
newServers.length = 0;
serversChanged = true;
}
//Prune old servers
if(!mpIsQuerying()){
for(uint n = 0, ncnt = gameServers.length; n < ncnt; ++n) {
if(!gameServers[n].found) {
gameServers.removeAt(n);
--n; --ncnt;
serversChanged = true;
}
}
}
//Update servers list
if(serversChanged) {
servers.clearItems();
servers.selected = -1;
for(uint n = 0, ncnt = gameServers.length; n < ncnt; ++n) {
ServerDesc@ desc = gameServers[n];
string name = desc.srv.name;
bool haveMods = true;
if(name.length == 0)
name = "Game at "+desc.srv.address.toString();
if(desc.srv.players > 0) {
name += " ("+desc.srv.players;
if(desc.srv.maxPlayers > 0) {
name += "/"+desc.srv.maxPlayers;
name += " Players)";
}
else if(desc.srv.players > 1) {
name += " Players)";
}
else {
name += " Player)";
}
}
if(desc.srv.started)
name += " (In Progress)";
if(desc.srv.isLocal)
name += " (LAN)";
if(desc.srv.password)
name += " ("+locale::PASSWORD+")";
if(desc.srv.mod.length != 0) {
string modString;
array<string>@ modList = desc.srv.mod.split("\n");
for(uint i = 0, cnt = modList.length; i < cnt; ++i) {
if(i != 0)
modString += ", ";
modString += modList[i];
if(getMod(modList[i]) is null)
haveMods = false;
}
name += " (Mods: "+modString+")";
}
ServerElement elem;
if(desc.srv.version != MP_VERSION) {
elem.disabled = true;
elem.color = colors::Red;
name += " "+locale::MP_VERSION_MISMATCH;
}
else if(!haveMods) {
elem.disabled = true;
elem.color = colors::Red;
name += " "+locale::MP_MISSING_MODS;
}
else if(desc.srv.password) {
elem.color = Color(0xfffa00ff);
}
elem.text = name;
servers.addItem(elem);
if(desc.srv.address == selAddr)
servers.selected = n;
}
if(joinButton.visible) {
servers.visible = gameServers.length != 0;
noServers.visible = gameServers.length == 0;
}
}
joinButton.disabled = (servers.selected == -1);
refreshButton.disabled = mpIsQuerying();
portLabel.visible = !punchToggle.checked;
portBox.visible = !punchToggle.checked;
}
void host() {
mpHost(gamename = serverName.text,
port = max(toUInt(portBox.text), 1),
isPublic = publicToggle.checked,
punchthrough = punchToggle.checked,
password = passwordBox.text);
}
void join(const string& pwd = "") {
int index = servers.selected;
if(index >= 0 && index <= int(gameServers.length)) {
if(game_running) {
stopGame();
if(mpServer)
mpDisconnect();
}
GameServer srv = gameServers[index].srv;
if(pwd.length == 0 && srv.password) {
InputDialog@ dialog = InputDialog(PasswordDialog(), this);
dialog.addTitle(locale::MP_ENTER_PASSWORD);
dialog.accept.text = locale::MP_JOIN;
dialog.addTextInput("", "");
addDialog(dialog);
dialog.focusInput();
return;
}
mpConnect(srv, password=pwd);
showConnecting();
if(srv.punchPort != -1 && srv.name.length != 0) {
connectingText.text = "Connecting to "+srv.name+"...";
}
else {
string addr = srv.address.toString(false);
int port = srv.address.port;
connectingText.text = "Connecting to "+addr+":"+port+"...";
}
}
}
void join(const string& hostname, int port, const string& pwd = "") {
if(game_running) {
stopGame();
if(mpServer || mpClient)
mpDisconnect();
}
mpConnect(hostname, port, pwd);
showConnecting();
connectingText.text = "Connecting to "+hostname+":"+port+"...";
}
void applyNick() {
if(nick.text.length != 0 && nick.text != settings::sNickname) {
settings::sNickname = nick.text;
IRC.nickname = settings::sNickname;
saveSettings();
}
}
bool onGuiEvent(const GuiEvent& event) {
switch(event.type) {
case GUI_Clicked:
if(event.caller is backButton) {
applyNick();
if(mpServer && !game_running)
mpDisconnect();
hideMultiplayer();
return true;
}
else if(event.caller is queueButton) {
if(!cloud::inQueue)
cloud::enterQueue("1v1", 2, toString(MP_VERSION));
return true;
}
else if(event.caller is queueLeave) {
if(cloud::inQueue)
cloud::leaveQueue();
return true;
}
else if(event.caller is queueAccept) {
cloud::acceptQueue();
return true;
}
else if(event.caller is queueReject) {
cloud::rejectQueue();
return true;
}
else if(event.caller is cancelButton) {
mpDisconnect();
showMenu();
return true;
}
else if(event.caller is hostButton) {
if(game_running) {
stopGame();
if(mpServer || mpClient)
mpDisconnect();
}
applyNick();
host();
hideMultiplayer();
showNewGame();
return true;
}
else if(event.caller is refreshButton) {
refresh();
return true;
}
else if(event.caller is ircButton) {
showIRC();
return true;
}
else if(event.caller is ipButton) {
InputDialog@ dialog = InputDialog(IPJoin(), this);
dialog.addTitle(locale::MP_JOIN_IP);
dialog.accept.text = locale::MP_JOIN;
dialog.addTextInput(locale::MP_IP, "127.0.0.1");
dialog.addTextInput(locale::MP_PORT, "2048");
dialog.addTextInput(locale::PASSWORD, "");
addDialog(dialog);
dialog.focusTextInput(0, selectAll=true);
return true;
}
else if(event.caller is hostLoadButton) {
if(game_running) {
stopGame();
if(mpServer || mpClient)
mpDisconnect();
}
applyNick();
host();
hideMultiplayer();
switchToMenu(load_menu);
return true;
}
else if(event.caller is joinButton) {
applyNick();
join();
return true;
}
break;
case GUI_Confirmed:
if(event.caller is servers) {
join();
return true;
}
else if(event.caller is nick) {
applyNick();
return true;
}
break;
case GUI_Focus_Lost:
if(event.caller is nick) {
applyNick();
return false;
}
break;
case GUI_Animation_Complete:
animating = false;
return true;
}
return BaseGuiElement::onGuiEvent(event);
}
void showConnecting() {
gamesBG.visible = false;
optionsBG.visible = false;
joinButton.visible = false;
backButton.visible = false;
hostButton.visible = false;
hostLoadButton.visible = false;
hostBG.visible = false;
if(queueButton !is null)
queueButton.visible = false;
connectingText.visible = true;
cancelButton.visible = true;
updateAbsolutePosition();
}
void showMenu() {
gamesBG.visible = true;
optionsBG.visible = true;
joinButton.visible = true;
backButton.visible = true;
hostButton.visible = true;
hostLoadButton.visible = true;
hostBG.visible = true;
if(queueButton !is null)
queueButton.visible = true;
connectingText.visible = false;
cancelButton.visible = false;
updateAbsolutePosition();
}
void updateAbsolutePosition() {
if(!animating) {
if(!hide) {
size = parent.size;
position = vec2i(0, 0);
}
else {
size = parent.size;
position = vec2i(size.x, 0);
}
}
BaseGuiElement::updateAbsolutePosition();
}
void animateIn() {
animating = true;
showMenu();
rect = recti_area(vec2i(parent.size.x, 0), parent.size);
animate_time(this, recti_area(vec2i(), parent.size), MSLIDE_TIME);
}
void animateOut() {
animating = true;
hide = true;
rect = recti_area(vec2i(), parent.size);
animate_time(this, recti_area(vec2i(parent.size.x, 0), parent.size), MSLIDE_TIME);
}
};
class AcceptQueue : ConsoleCommand {
void execute(const string& args) {
if(cloud::queueRequest)
cloud::acceptQueue();
}
};
class RejectQueue : ConsoleCommand {
void execute(const string& args) {
if(cloud::queueRequest)
cloud::rejectQueue();
}
};
class LeaveQueue : ConsoleCommand {
void execute(const string& args) {
if(cloud::inQueue)
cloud::leaveQueue();
}
};
Multiplayer@ mp_list;
void init() {
if(cloud::isActive) {
if(settings::sNickname == "SRPlayer" || settings::sNickname.length == 0) {
settings::sNickname = cloud::getNickname();
saveSettings();
}
}
@mp_list = Multiplayer();
mp_list.visible = false;
addConsoleCommand("accept_queue", AcceptQueue());
addConsoleCommand("reject_queue", RejectQueue());
addConsoleCommand("leave_queue", LeaveQueue());
}
void tick(double time) {
if(mp_list.visible)
mp_list.tick(time);
}
void showMultiplayer() {
mp_list.visible = true;
menu_container.animateOut();
mp_list.animateIn();
mp_list.nextRefresh = 0.0;
}
void onGameStateChange() {
if(game_state == GS_Menu) {
if(game_running && !mp_list.gamesBG.visible) {
mp_list.showMenu();
hideMultiplayer(true);
}
}
}
void hideMultiplayer(bool snap = false) {
menu_container.visible = true;
if(!snap) {
menu_container.animateIn();
mp_list.animateOut();
}
else {
mp_list.visible = false;
animate_remove(mp_list);
animate_remove(menu_container);
menu_container.show();
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+92
View File
@@ -0,0 +1,92 @@
import menus;
import elements.GuiTextbox;
from load_menu import SaveItem;
class SaveData {
string filename;
SaveData(const string& Filename) {
filename = Filename;
}
};
double SaveThread(double time, ScriptThread& thread) {
SaveData@ data;
thread.getObject(@data);
saveGame(path_join(baseProfile["saves"], data.filename)+".sr2");
thread.stop();
return 0;
}
class SaveMenu : MenuBox {
GuiTextbox@ saveName;
GuiButton@ saveButton;
SaveMenu() {
super();
items.alignment.top = Top+40;
items.alignment.bottom = Bottom-40;
@saveName = GuiTextbox(this, Alignment(Left+12, Bottom-36, Right-212, Bottom-4));
saveName.text = "quicksave";
saveName.font = FT_Medium;
@saveButton = GuiButton(this, Alignment(Right-206, Bottom-36, Right-12, Bottom-4), "Save");
saveButton.font = FT_Medium;
}
void buildMenu() {
title.text = locale::SAVE_GAME;
items.addItem(MenuAction(Sprite(spritesheet::MenuIcons, 11), locale::MENU_BACK, 0));
string dir = baseProfile["saves"];
FileList files(dir, "*.sr2");
uint cnt = files.length;
array<SaveItem@> list;
for(uint i = 0; i < cnt; ++i)
list.insertLast(SaveItem(files.path[i]));
list.sortDesc();
for(uint i = 0; i < cnt; ++i)
items.addItem(list[i]);
}
void onSelected(const string& name, int value) {
if(value == 0) {
switchToMenu(main_menu, false);
return;
}
else if(value == 1) {
saveName.text = name;
return;
}
}
bool onGuiEvent(const GuiEvent& event) {
if((event.type == GUI_Clicked && event.caller is saveButton) ||
(event.type == GUI_Confirmed && event.caller is saveName))
{
//double start = getExactTime();
ScriptThread@ thread = ScriptThread("save_menu::SaveThread", @SaveData(saveName.text));
saveWorldScreen(path_join(baseProfile["saves"], saveName.text)+".png");
while(thread.running)
sleep(0);
//double end = getExactTime();
//print(format("Saving took $1 seconds", string(end-start)));
switchToMenu(main_menu, false, true);
switchToGame();
return true;
}
return MenuBox::onGuiEvent(event);
}
};
void init() {
@save_menu = SaveMenu();
}
+1
View File
@@ -0,0 +1 @@
#include "../definitions/saving.as"
+47
View File
@@ -0,0 +1,47 @@
import util.settings_page;
GamePage page;
class GamePage : GameSettingsPage {
void makeSettings() {
color = colors::Green;
header = locale::NG_GAME_OPTIONS;
icon = Sprite(material::TabPlanets);
Title(locale::NG_UNIVERSE_GENERATION);
Frequency(locale::NG_PLANET_FREQUENCY, "PLANET_FREQUENCY", min = 0.2, max = 3.0);
Occurance(locale::NG_ANOMALY_OCCURANCE, "ANOMALY_OCCURANCE");
Occurance(locale::NG_REMNANT_OCCURANCE, "REMNANT_OCCURANCE");
Occurance(locale::NG_ASTEROID_OCCURANCE, "ASTEROID_OCCURANCE");
Occurance(locale::NG_RESOURCE_ASTEROID_OCCURANCE, "RESOURCE_ASTEROID_OCCURANCE");
Occurance(locale::NG_UNIQUE_SYSTEM_OCCURANCE, "UNIQUE_SYSTEM_OCCURANCE");
Occurance(locale::NG_UNIQUE_RESOURCE_OCCURANCE, "UNIQUE_RESOURCE_OCCURANCE");
Occurance(locale::NG_RESOURCE_SCARCITY, "RESOURCE_SCARCITY", max=2.0, tooltip=locale::NGTT_RESOURCE_SCARCITY);
Occurance(locale::NG_CIVILIAN_TRADE, "CIVILIAN_TRADE_MULT", max=10.0, tooltip=locale::NGTT_CIVILIAN_TRADE);
Frequency(locale::NG_ARTIFACT_FREQUENCY, "ARTIFACT_FREQUENCY", min = 0.2, max = 3.0);
Frequency(locale::NG_SYSTEM_SIZE, "SYSTEM_SIZE", min = 0.2, max = 3.0);
emptyline();
Title(locale::NG_GAME_OPTIONS);
//Occurance(locale::NG_RANDOM_EVENTS, "RANDOM_EVENT_OCCURRENCE", max=3.0);
Toggle(locale::NG_ENABLE_DREAD_PIRATE, "ENABLE_DREAD_PIRATE", halfWidth=true, tooltip=locale::NGTT_ENABLE_DREAD_PIRATE);
/*Toggle(locale::NG_ENABLE_CIVILIAN_TRADE, "ENABLE_CIVILIAN_TRADE", halfWidth=true);*/
Toggle(locale::NG_ENABLE_INFLUENCE_EVENTS, "ENABLE_INFLUENCE_EVENTS", halfWidth=true, tooltip=locale::NGTT_ENABLE_INFLUENCE_EVENTS);
Toggle(locale::NG_DISABLE_STARTING_FLEETS, "DISABLE_STARTING_FLEETS", halfWidth=true, tooltip=locale::NGTT_DISABLE_STARTING_FLEETS);
Toggle(locale::NG_REMNANT_AGGRESSION, "REMNANT_AGGRESSION", halfWidth=true, tooltip=locale::NGTT_REMNANT_AGGRESSION);
Toggle(locale::NG_ALLOW_TEAM_SURRENDER, "ALLOW_TEAM_SURRENDER", halfWidth=true, tooltip=locale::NGTT_ALLOW_TEAM_SURRENDER);
Toggle(locale::NG_START_EXPLORED_MAP, "START_EXPLORED_MAP", halfWidth=true, tooltip=locale::NGTT_START_EXPLORED_MAP);
auto@ tforming = Toggle(locale::NG_ENABLE_TERRAFORMING, "ENABLE_TERRAFORMING", halfWidth=true, tooltip=locale::NGTT_ENABLE_TERRAFORMING);
if(hasDLC("Heralds")) {
tforming.DefaultValue = false;
tforming.set(false);
}
emptyline();
Title(locale::NG_VICTORY_OPTIONS);
Number(locale::NG_TIME_LIMIT, "GAME_TIME_LIMIT", tooltip=locale::NGTT_TIME_LIMIT, halfWidth=true, step=10);
Toggle(locale::NG_ENABLE_REVENANT_PARTS, "ENABLE_REVENANT_PARTS", tooltip=locale::NGTT_ENABLE_REVENANT_PARTS);
if(hasDLC("Heralds"))
Toggle(locale::NG_ENABLE_INFLUENCE_VICTORY, "ENABLE_INFLUENCE_VICTORY", tooltip=locale::NGTT_ENABLE_INFLUENCE_VICTORY);
}
};
+1
View File
@@ -0,0 +1 @@
#include "../../shared/settings/game_settings.as"
+67
View File
@@ -0,0 +1,67 @@
Sound@ theme;
bool played = false;
const double themeVolume = 1.5;
double volume = 0.0;
double restartDelay = 0.5;
double musicVolume = 1.0;
double prevMusicVol = 1.0, prevMasterVol = 1.0, prevSFXVol = 1.0;
void tick(double time) {
if(!soundEnabled)
return;
if(prevMusicVol != settings::dMusicVolume || prevSFXVol != settings::dSFXVolume || prevMasterVol != settings::dMasterVolume) {
if(settings::dSFXVolume < 0.01)
{
musicVolume = settings::dMusicVolume;
soundVolume = settings::dMasterVolume;
}
else {
musicVolume = settings::dMusicVolume / settings::dSFXVolume;
soundVolume = settings::dMasterVolume * settings::dSFXVolume;
}
prevMusicVol = settings::dMusicVolume;
prevMasterVol = settings::dMasterVolume;
prevSFXVol = settings::dSFXVolume;
}
if(game_running) {
played = false;
restartDelay = 5.0;
if(theme !is null) {
volume = max(0.0, volume - (time / 4.0));
theme.volume = settings::dMusicVolume * settings::dMasterVolume * volume * themeVolume;
if(volume <= 0.0) {
theme.stop();
@theme = null;
}
}
}
else {
if(theme is null) {
if(!played) {
restartDelay -= time;
if(restartDelay <= 0.0) {
restartDelay = 5.0;
@theme = playTrack("data/music/title.ogg", loop = false, pause = true);
if(theme !is null) {
theme.volume = 0;
volume = 0;
theme.paused = false;
played = true;
}
}
}
}
else if(theme.playing) {
volume = min(1.0, volume + time);
theme.volume = musicVolume * volume * themeVolume;
}
else {
@theme = null;
}
}
}
+1
View File
@@ -0,0 +1 @@
#include "../definitions/traits.as"
+1
View File
@@ -0,0 +1 @@
#include "../../shared/util/formatting.as"
+1
View File
@@ -0,0 +1 @@
#include "../definitions/version.as"