/* * This file is part of the Illarion project. * * Copyright © 2015 - Illarion e.V. * * Illarion is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Illarion is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ package illarion.client.gui.controller.game; import de.lessvoid.nifty.Nifty; import de.lessvoid.nifty.NiftyEventSubscriber; import de.lessvoid.nifty.builder.PanelBuilder; import de.lessvoid.nifty.controls.ButtonClickedEvent; import de.lessvoid.nifty.controls.Window; import de.lessvoid.nifty.controls.label.builder.LabelBuilder; import de.lessvoid.nifty.effects.EffectEventId; import de.lessvoid.nifty.elements.Element; import de.lessvoid.nifty.elements.events.ElementShowEvent; import de.lessvoid.nifty.elements.render.TextRenderer; import de.lessvoid.nifty.screen.Screen; import de.lessvoid.nifty.screen.ScreenController; import de.lessvoid.nifty.tools.SizeValue; import illarion.client.IllaClient; import illarion.client.gui.SkillGui; import illarion.client.util.Lang; import illarion.client.world.MapTile; import illarion.client.world.World; import illarion.common.config.Config; import illarion.common.data.Skill; import illarion.common.data.SkillGroup; import illarion.common.data.SkillGroups; import org.illarion.engine.GameContainer; import org.illarion.nifty.controls.Progress; import org.illarion.nifty.controls.progress.builder.ProgressBuilder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.annotation.Nonnull; import javax.annotation.Nullable; /** * This handler controls the skill window. * * @author Martin Karing <nitram@illarion.org> */ public final class SkillsHandler implements SkillGui, ScreenController, UpdatableHandler { @Nonnull private static final Logger log = LoggerFactory.getLogger(SkillsHandler.class); /** * The Nifty-GUI instance this handler is bound to. */ private Nifty nifty; /** * The screen instance this handler is bound to. */ private Screen screen; /** * The window control that contains the skill information. */ @Nullable private Window skillWindow; @Override public void bind(@Nonnull Nifty nifty, @Nonnull Screen screen) { this.nifty = nifty; this.screen = screen; skillWindow = screen.findNiftyControl("characterInformation", Window.class); //skillWindow.getElement().getParent().layoutElements(); createSkillEntries(); } @Override public void onStartScreen() { Element skillWindowElement = getSkillWindowElement(); if (skillWindowElement != null) { skillWindowElement.setConstraintX(new SizeValue(IllaClient.getCfg().getString("skillWindowPosX"))); skillWindowElement.setConstraintY(new SizeValue(IllaClient.getCfg().getString("skillWindowPosY"))); } nifty.subscribeAnnotations(this); } @Override public void onEndScreen() { nifty.unsubscribeAnnotations(this); Element skillWindowElement = getSkillWindowElement(); if (skillWindowElement != null) { Config cfg = IllaClient.getCfg(); cfg.set("skillWindowPosX", Integer.toString(skillWindowElement.getX()) + "px"); cfg.set("skillWindowPosY", Integer.toString(skillWindowElement.getY()) + "px"); } internalHideSkillWindow(); resetAllEntries(); } @Override public void showSkillWindow() { World.getUpdateTaskManager().addTask((container, delta) -> internalShowSkillWindow()); } private void internalShowSkillWindow() { Element skillWindowElement = getSkillWindowElement(); if (skillWindowElement != null) { assert skillWindow != null; skillWindowElement.show(skillWindow::moveToFront); } } @Override public void hideSkillWindow() { World.getUpdateTaskManager().addTask((container, delta) -> internalHideSkillWindow()); } private void internalHideSkillWindow() { Element skillWindowElement = getSkillWindowElement(); if (skillWindowElement != null) { skillWindowElement.hide(); } } @Override public void toggleSkillWindow() { Element skillWindowElement = getSkillWindowElement(); if (skillWindowElement != null) { if (skillWindowElement.isVisible()) { hideSkillWindow(); } else { showSkillWindow(); } } } /** * This function creates the entries for every single skill. */ private void createSkillEntries() { @Nullable Element content = getContentPanel(); if (content == null) { return; } for (SkillGroup group : SkillGroups.getInstance().getSkillGroups()) { String groupId = content.getId() + "#group" + Integer.toString(group.getGroupId()); PanelBuilder groupPanel = new PanelBuilder(groupId); groupPanel.childLayoutVertical(); groupPanel.height(SizeValue.px(0)); groupPanel.alignCenter(); groupPanel.valignTop(); LabelBuilder headline = new LabelBuilder(groupId + "#headline"); headline.font("menuFont"); if (Lang.getInstance().isGerman()) { headline.label(group.getNameGerman()); } else { headline.label(group.getNameEnglish()); } headline.width(SizeValue.wildcard()); headline.height(SizeValue.px(0)); groupPanel.control(headline); for (Skill skill : group.getSkills()) { String skillId = groupId + "#skill" + Integer.toString(skill.getId()); PanelBuilder skillPanel = new PanelBuilder(skillId); skillPanel.childLayoutCenter(); skillPanel.width(content.getConstraintWidth().toString()); LabelBuilder skillName = new LabelBuilder(skillId + "#name"); if (Lang.getInstance().isGerman()) { skillName.label(skill.getNameGerman()); } else { skillName.label(skill.getNameEnglish()); } skillName.font("textFont"); skillName.width(content.getConstraintWidth().toString()); skillName.height(SizeValue.px(0)); skillName.alignLeft(); skillName.textHAlignLeft(); skillPanel.control(skillName); ProgressBuilder progress = new ProgressBuilder(skillId + "#progress"); progress.width(SizeValue.px(130)); progress.height(SizeValue.px(0)); progress.alignRight(); progress.valignBottom(); skillPanel.control(progress); LabelBuilder skillValue = new LabelBuilder(skillId + "#value"); skillValue.label("0"); skillValue.width(content.getConstraintWidth().toString()); skillValue.font("textFont"); skillValue.height(SizeValue.px(0)); skillValue.alignRight(); skillValue.textHAlignRight(); skillPanel.control(skillValue); groupPanel.panel(skillPanel); } groupPanel.build(nifty, screen, content); } } /** * This value is set {@code true} in case the layout needs to be updated. */ private boolean layoutDirty; @Override public void updateSkill(@Nonnull Skill skill, int value, int minor) { World.getUpdateTaskManager().addTask((container, delta) -> internalUpdateSkill(skill, value, minor)); } @Nullable private Element getSkillWindowElement() { if (skillWindow == null) { return null; } return skillWindow.getElement(); } @Nullable private Element getContentPanel() { @Nullable Element windowElement = getSkillWindowElement(); if (windowElement == null) { return null; } return windowElement.findElementById("#textContent"); } @Nullable private Element getSkillGroupPanel(@Nonnull SkillGroup group) { Element contentPanel = getContentPanel(); if (contentPanel == null) { return null; } String groupId = "#group" + group.getGroupId(); for (@Nonnull Element groupPanel : contentPanel.getChildren()) { String panelId = groupPanel.getId(); if ((panelId != null) && panelId.endsWith(groupId)) { return groupPanel; } } return null; } @Nullable private Element getSkillPanel(@Nonnull Skill skill) { Element groupPanel = getSkillGroupPanel(skill.getGroup()); if (groupPanel == null) { return null; } String skillId = "#skill" + skill.getId(); for (@Nonnull Element skillPanel : groupPanel.getChildren()) { String panelId = skillPanel.getId(); if ((panelId != null) && panelId.endsWith(skillId)) { return skillPanel; } } return null; } private void resetAllEntries() { Element content = getContentPanel(); if (content != null) { SizeValue zero = SizeValue.px(0); for (@Nonnull Element groupPanel : content.getChildren()) { groupPanel.setConstraintHeight(zero); groupPanel.setMarginBottom(zero); for (@Nonnull Element groupMember : groupPanel.getChildren()) { groupMember.setConstraintHeight(zero); for (@Nonnull Element skillEntry : groupMember.getChildren()) { skillEntry.setConstraintHeight(zero); } } } layoutDirty = true; } } /** * This function will update the data of a single skill. * * @param skill the skill that receives the update * @param value the new value of the skill */ private void internalUpdateSkill(@Nonnull Skill skill, int value, int minor) { if (!World.getNet().isLoginDone()) { return; } @Nullable Element skillPanel = getSkillPanel(skill); int skillHeight = 22; if (skillPanel == null) { return; } if (value == 0) { skillHeight = 0; } @Nullable Element skillPanelWindowContent = skillPanel.getParent(); @Nullable Element skillPanelWindow = skillPanelWindowContent.getParent(); skillPanelWindow.setConstraintHeight(SizeValue.def()); skillPanelWindowContent.setConstraintHeight(SizeValue.def()); skillPanelWindowContent.setMarginBottom(SizeValue.px(5)); skillPanelWindowContent.findElementById("#headline").setConstraintHeight(SizeValue.px(28)); skillPanel.setConstraintHeight(SizeValue.px(skillHeight)); Element valueLabel = skillPanel.findElementById("#value"); TextRenderer valueTextRenderer = valueLabel.getRenderer(TextRenderer.class); String newValue = Integer.toString(value); boolean skillChanged = !valueTextRenderer.getOriginalText().equals(newValue); valueTextRenderer.setText(newValue); valueLabel.setConstraintHeight(SizeValue.px(skillHeight)); Element progressBar = skillPanel.findElementById("#progress"); float progress = (value == 100) ? 1.f : (minor / 10000.f); progressBar.getNiftyControl(Progress.class).setProgress(progress); progressBar.setConstraintHeight(SizeValue.px(Math.max(skillHeight - 3, 0))); progressBar.setMarginRight(SizeValue.px(40)); Element nameLabel = skillPanel.findElementById("#name"); nameLabel.setConstraintHeight(SizeValue.px(skillHeight)); nameLabel.setMarginLeft(SizeValue.px(5)); if (World.getNet().isLoginDone() && skillChanged) { screen.findElementById("openSkillsBtn").startEffect(EffectEventId.onCustom, null, "pulse"); MapTile playerTile = World.getMap().getMapAt(World.getPlayer().getLocation()); if (playerTile == null) { log.error("Tile below the player is NULL?!"); } else { playerTile.showEffect(41); } } layoutDirty = true; } private void updateVisibility() { Element content = getContentPanel(); if (content != null) { updateVisibilityOfElement(content); } } private static void updateVisibilityOfElement(@Nonnull Element target) { if (0 == target.getConstraintHeight().getValueAsInt(Float.MAX_VALUE)) { if (target.isVisible()) { target.hide(); } } else { if (!target.isVisible()) { target.show(); } } target.getChildren().forEach(SkillsHandler::updateVisibilityOfElement); } @Override public void update(GameContainer container, int delta) { if (layoutDirty) { layoutDirty = false; updateVisibility(); Element windowElement = getSkillWindowElement(); if (windowElement != null) { windowElement.resetLayout(); windowElement.layoutElements(); } } } /** * The event handler for clicks on the skill window button. * * @param topic the topic of the event * @param event the event data */ @NiftyEventSubscriber(id = "openSkillsBtn") public void onSkillWindowButtonClickedEvent(String topic, ButtonClickedEvent event) { toggleSkillWindow(); } @NiftyEventSubscriber(id = "characterInformation") public void onSkillWindowShowEvent(String topic, ElementShowEvent event) { updateVisibility(); } }