/*
* 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.ElementBuilder.Align;
import de.lessvoid.nifty.builder.ElementBuilder.VAlign;
import de.lessvoid.nifty.builder.ImageBuilder;
import de.lessvoid.nifty.controls.ButtonClickedEvent;
import de.lessvoid.nifty.elements.Element;
import de.lessvoid.nifty.elements.render.ImageRenderer;
import de.lessvoid.nifty.render.NiftyImage;
import de.lessvoid.nifty.screen.Screen;
import de.lessvoid.nifty.screen.ScreenController;
import de.lessvoid.nifty.tools.SizeValue;
import illarion.client.gui.MiniMapGui;
import illarion.client.world.World;
import illarion.common.types.ServerCoordinate;
import org.illarion.engine.GameContainer;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;
/**
* This class is the GUI control of the mini map. It takes care of all the required interaction with the mini map
* GUI, however it does not draw the mini map itself. It just displays the already drawn mini map on the GUI.
*
* @author Martin Karing <nitram@illarion.org>
*/
public final class GameMiniMapHandler implements MiniMapGui, ScreenController, UpdatableHandler {
/**
* The instance of Nifty used to control the elements on the screen.
*/
private Nifty nifty;
/**
* This is the instance of the screen that is active and showing the game.
*/
private Screen screen;
/**
* The main element of the mini map.
*/
@Nullable
private Element miniMapPanel;
/**
* The buffer that stores the currently not used instances of the mini map arrows.
*/
@Nonnull
private final Queue<MiniMapArrowPointer> arrowPointerBuffer;
/**
* The buffer of currently unused start pointers.
*/
@Nonnull
private final Queue<MiniMapStartPointer> startPointerBuffer;
/**
* The list of pointers that are currently active and need to be updated.
*/
@Nonnull
private final List<MiniMapArrowPointer> activeArrowPointers;
/**
* The list of start pointers that are currently active and need to be updated.
*/
@Nonnull
private final List<MiniMapStartPointer> activeStartPointers;
/**
* Create a new game mini map handler.
*/
public GameMiniMapHandler() {
arrowPointerBuffer = new LinkedList<>();
activeArrowPointers = new LinkedList<>();
startPointerBuffer = new LinkedList<>();
activeStartPointers = new LinkedList<>();
}
@Override
public void bind(@Nonnull Nifty nifty, @Nonnull Screen screen) {
this.nifty = nifty;
this.screen = screen;
miniMapPanel = screen.findElementById("miniMapPanel");
}
@Override
@Nonnull
public Pointer createTargetPointer() {
return createTargetPointer(true);
}
@Nonnull
public Pointer createTargetPointer(boolean isCurrentQuest) {
if (arrowPointerBuffer.isEmpty()) {
ImageBuilder builder = new ImageBuilder();
builder.visible(false);
builder.align(Align.Center);
builder.valign(VAlign.Center);
Element image = builder.build(nifty, screen, miniMapPanel);
MiniMapArrowPointer pointer = new MiniMapArrowPointer(image);
pointer.setCurrentQuest(isCurrentQuest);
image.getRenderer(ImageRenderer.class).setImage(new NiftyImage(nifty.getRenderEngine(), pointer));
image.setConstraintHeight(SizeValue.px(pointer.getHeight()));
image.setConstraintWidth(SizeValue.px(pointer.getWidth()));
miniMapPanel.layoutElements();
return pointer;
}
return arrowPointerBuffer.poll();
}
@Override
@Nonnull
public Pointer createStartPointer(boolean available) {
MiniMapStartPointer pointer;
if (startPointerBuffer.isEmpty()) {
ImageBuilder builder = new ImageBuilder();
builder.visible(false);
builder.align(Align.Center);
builder.valign(VAlign.Center);
Element image = builder.build(nifty, screen, miniMapPanel);
pointer = new MiniMapStartPointer(image);
image.getRenderer(ImageRenderer.class).setImage(new NiftyImage(nifty.getRenderEngine(), pointer));
image.setConstraintHeight(SizeValue.px(pointer.getHeight()));
image.setConstraintWidth(SizeValue.px(pointer.getWidth()));
miniMapPanel.layoutElements();
} else {
pointer = startPointerBuffer.poll();
}
pointer.setAvailable(available);
return pointer;
}
@Override
public void releasePointer(@Nullable Pointer pointer) {
if (pointer instanceof MiniMapArrowPointer) {
MiniMapArrowPointer arrowPointer = (MiniMapArrowPointer) pointer;
World.getUpdateTaskManager().addTaskForLater((container, delta) -> {
if (arrowPointer.getParentElement().isVisible()) {
arrowPointer.getParentElement().hide(() -> {
activeArrowPointers.remove(arrowPointer);
arrowPointerBuffer.offer(arrowPointer);
});
} else {
activeArrowPointers.remove(arrowPointer);
arrowPointerBuffer.offer(arrowPointer);
}
});
} else if (pointer instanceof MiniMapStartPointer) {
MiniMapStartPointer startPointer = (MiniMapStartPointer) pointer;
World.getUpdateTaskManager().addTaskForLater((container, delta) -> {
if (startPointer.getParentElement().isVisible()) {
startPointer.getParentElement().hide(() -> {
activeStartPointers.remove(startPointer);
startPointerBuffer.offer(startPointer);
});
} else {
activeStartPointers.remove(startPointer);
startPointerBuffer.offer(startPointer);
}
});
}
}
@Override
public void addPointer(@Nonnull Pointer pointer) {
World.getUpdateTaskManager().addTaskForLater((container, delta) -> {
if (pointer instanceof MiniMapArrowPointer) {
MiniMapArrowPointer arrowPointer = (MiniMapArrowPointer) pointer;
arrowPointer.getParentElement().show(() -> {
if (!activeArrowPointers.contains(arrowPointer)) {
activeArrowPointers.add(arrowPointer);
}
});
} else if (pointer instanceof MiniMapStartPointer) {
MiniMapStartPointer startPointer = (MiniMapStartPointer) pointer;
startPointer.getParentElement().show(() -> {
if (!activeStartPointers.contains(startPointer)) {
activeStartPointers.add(startPointer);
}
});
}
});
}
@NiftyEventSubscriber(id = "openMiniMapBtn")
public void onMiniMapButtonClicked(String topic, ButtonClickedEvent data) {
toggleMiniMap();
}
/**
* Toggles display of minimap
* Will hide minimap if visible, show if not
*/
@Override
public void toggleMiniMap(){
World.getUpdateTaskManager().addTask((container, delta) -> {
if (miniMapPanel != null) {
if (miniMapPanel.isVisible()) {
hideMiniMap();
} else {
showMiniMap();
}
}
});
}
public void showMiniMap(){
World.getUpdateTaskManager().addTask((container, delta) -> {
if (miniMapPanel != null) {
miniMapPanel.show();
}
});
}
public void hideMiniMap(){
World.getUpdateTaskManager().addTask((container, delta) -> {
if (miniMapPanel != null) {
miniMapPanel.hide();
}
});
}
@Override
public void onStartScreen() {
arrowPointerBuffer.clear();
if (nifty != null) {
nifty.subscribeAnnotations(this);
}
miniMapPanel.findElementById("miniMapImage").getRenderer(ImageRenderer.class)
.setImage(new NiftyImage(nifty.getRenderEngine(), World.getMap().getMiniMap().getMiniMap()));
}
@Override
public void onEndScreen() {
if (nifty != null) {
nifty.unsubscribeAnnotations(this);
}
arrowPointerBuffer.clear();
}
@Override
public void update(GameContainer container, int delta) {
if (World.getPlayer().isLocationSet()) {
ServerCoordinate playerLocation = World.getPlayer().getLocation();
for (@Nonnull MiniMapArrowPointer pointer : activeArrowPointers) {
pointer.update(delta, playerLocation);
}
for (@Nonnull MiniMapStartPointer pointer : activeStartPointers) {
pointer.update(playerLocation);
}
}
}
}