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
+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();
}
}
}