import dialogs.MessageDialog; import dialogs.InputDialog; import dialogs.Dialog; import elements.GuiButton; import elements.GuiText; import elements.GuiMarkupText; import elements.GuiPanel; import elements.GuiBackgroundPanel; import elements.GuiTextbox; import elements.GuiResizeHandle; import influence; class PlayEmpireDialog : Dialog { GuiButton@[] buttons; Empire@[] empires; PlayEmpireDialog() { super(null); addTitle(locale::PLAY_EMPIRE_TITLE, closeButton=false); height = 32; //Empires for(uint i = 0, cnt = getEmpireCount(); i < cnt; ++i) { Empire@ emp = getEmpire(i); if(!emp.major) continue; GuiText text(window, recti(12, height, width-212, height+30)); text.text = emp.name; text.color = emp.color; text.font = FT_Subtitle; GuiButton btn(window, recti(width-200, height, width-12, height+30)); btn.text = locale::PLAY_EMPIRE; btn.color = emp.color; buttons.insertLast(btn); empires.insertLast(emp); height += 34; } //Spectating { GuiButton btn(window, recti(width-200, height, width-12, height+30)); btn.text = locale::SPECTATE; buttons.insertLast(btn); empires.insertLast(null); height += 34; } height += 12; updatePosition(); } bool onGuiEvent(const GuiEvent& event) { if(Closed) return false; if(event.type == GUI_Clicked) { for(uint i = 0, cnt = buttons.length(); i < cnt; ++i) { if(buttons[i] is cast(event.caller)) { Empire@ emp = empires[i]; if(emp is null) { close(); playAsEmpire(spectatorEmpire); wantSpectator = true; } else { playAsEmpire(emp); wantSpectator = false; } if(chooseOpen) { chooseOpen = false; close(); } return true; } } } return Dialog::onGuiEvent(event); } }; class PlayEmpire : ConsoleCommand { void execute(const string& args) { int id = toInt(args); Empire@ emp; if(id == -1) @emp = spectatorEmpire; else @emp = getEmpireByID(id); if(emp !is null) playAsEmpire(emp); else throw("Invalid empire id: "+args); } } void change_emp(bool pressed) { chooseOpen = true; wantSpectator = false; if(dialog is null || dialog.Closed) { @dialog = PlayEmpireDialog(); addDialog(dialog); } } bool wasMPClient = false; bool wantSpectator = false; bool chooseOpen = false; Dialog@ dialog; MPChatWindow@ mpChatWin; void init() { if(mpClient) { addConsoleCommand("play_emp", PlayEmpire()); wasMPClient = true; } if(mpClient || mpServer) @mpChatWin = MPChatWindow(); keybinds::Global.addBind(KB_CHANGE_EMPIRE, "change_emp"); keybinds::Global.addBind(KB_MP_CHAT, "mp_chat"); } void tick(double time) { if(wasMPClient && !mpIsConnected()) { message("Lost connection to server:\n " +localize("DISCONNECT_"+uint(mpDisconnectReason))); wasMPClient = false; } if(mpClient) { if(dialog is null || dialog.Closed) { if(playerEmpire is spectatorEmpire && !wantSpectator) { @dialog = PlayEmpireDialog(); addDialog(dialog); } } else if(!chooseOpen) { if(playerEmpire !is spectatorEmpire || wantSpectator) { dialog.close(); @dialog = null; } } } if(mpChatWin !is null) mpChatWin.tick(time); } class MPChatWindow : GuiDraggable { GuiBackgroundPanel@ bg; GuiPanel@ panel; GuiMarkupText@ log; GuiTextbox@ input; GuiResizeHandle@ handle; GuiButton@ closeButton; GuiDropdown@ mode; array modeMasks; array messages; Mutex mtx; array waitingMessages; MPChatWindow() { super(null, recti_area(vec2i(screenSize.width - 412, 200), vec2i(400, 200))); @bg = GuiBackgroundPanel(this, Alignment_Fill()); bg.title = locale::CHAT; bg.titleColor = Color(0xb3fe00ff); @closeButton = GuiButton(bg, Alignment(Right-31, Top+3, Right-5, Top+28), "X"); closeButton.color = colors::Red; @handle = GuiResizeHandle(this, Alignment(Right-12, Bottom-12, Right, Bottom)); handle.minSize = vec2i(200, 100); @panel = GuiPanel(bg, Alignment(Left+7, Top+34, Right-8, Bottom-38)); @log = GuiMarkupText(panel, recti_area(0, 0, 100, 100)); @input = GuiTextbox(bg, Alignment(Left+6, Bottom-36, Right-136, Bottom-6)); @mode = GuiDropdown(bg, Alignment(Right-133, Bottom-36, Right-6, Bottom-6)); log.text = locale::MP_CHAT_INTRO; updateMode(); updateAbsolutePosition(); } array treaties; void updateMode() { string prev; if(uint(mode.selected) < mode.itemCount) prev = mode.getItemElement(mode.selected).get(); modeMasks.length = 0; uint ind = 0; mode.setItem(ind++, locale::MP_CHAT_ALL); modeMasks.insertLast(0xffffffff); mode.setItem(ind++, locale::MP_CHAT_ALLIES); modeMasks.insertLast(playerEmpire.mask); mode.setItem(ind++, locale::MP_CHAT_PEACE); modeMasks.insertLast(playerEmpire.mask); for(uint i = 0, cnt = getEmpireCount(); i < cnt; ++i) { auto@ other = getEmpire(i); if(other is playerEmpire) continue; if(!other.major) continue; if(playerEmpire.ForcedPeaceMask & other.mask != 0) modeMasks[1] |= other.mask; if(!playerEmpire.isHostile(other)) modeMasks[2] |= other.mask; mode.setItem(ind++, format(locale::MP_CHAT_TO, other.name)); modeMasks.insertLast(other.mask | playerEmpire.mask); } treaties.syncFrom(getActiveTreaties()); for(uint i = 0, cnt = treaties.length; i < cnt; ++i) { auto@ treaty = treaties[i]; mode.setItem(ind++, format(locale::MP_CHAT_TO, treaty.name)); modeMasks.insertLast(treaty.presentMask | playerEmpire.mask); } mode.removeItemsFrom(ind); mode.selected = 0; for(uint i = 0, cnt = modeMasks.length; i < cnt; ++i) { if(mode.getItemElement(i).get() == prev) { mode.selected = i; break; } } } double timer = 0; void tick(double time) { Lock lck(mtx); for(uint i = 0, cnt = waitingMessages.length; i < cnt; ++i) addChat(waitingMessages[i]); if(waitingMessages.length != 0 && !visible) visible = true; waitingMessages.length = 0; timer -= time; if(timer <= 0.0) { updateMode(); timer = 1.0; } } void addChat(const string& str) { messages.insertLast(str); if(messages.length > 80) messages.removeAt(0); string content; for(uint i = 0, cnt = messages.length; i < cnt; ++i) content += messages[i]+"\n"; bool wasBottom = panel.vert.pos >= (panel.vert.end - panel.vert.page); log.text = content; panel.updateAbsolutePosition(); if(wasBottom) { panel.vert.pos = max(0.0, panel.vert.end - panel.vert.page); panel.updateAbsolutePosition(); } } void queueMessage(const string& str) { Lock lck(mtx); waitingMessages.insertLast(str); } bool onGuiEvent(const GuiEvent& evt) override { if(evt.caller is input) { if(evt.type == GUI_Confirmed) { string text = input.text; if(text.length != 0) { if(mode.selected == 0 || uint(mode.selected) >= modeMasks.length) { mpChat(text); } else { uint mask = modeMasks[mode.selected]; string spec = mode.getItemElement(mode.selected).get(); mpChat(text, mask, spec); } } input.text = ""; return true; } } else if(evt.caller is closeButton) { if(evt.type == GUI_Clicked) { visible = false; return true; } } return GuiDraggable::onGuiEvent(evt); } void updateAbsolutePosition() override { GuiDraggable::updateAbsolutePosition(); if(log !is null) log.size = vec2i(panel.size.width-20, log.size.height); } }; void mp_chat(bool pressed) { if(!pressed && (mpClient || mpServer)) { if(mpChatWin is null) @mpChatWin = MPChatWindow(); mpChatWin.visible = true; mpChatWin.bringToFront(); setGuiFocus(mpChatWin.input); } } void chatMessage(string text) { if(mpChatWin !is null) mpChatWin.queueMessage(text); }