/*
* 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.graphics;
import illarion.client.IllaClient;
import illarion.client.input.CurrentMouseLocationEvent;
import illarion.client.world.World;
import illarion.client.world.characters.CharacterAttribute;
import illarion.common.types.DisplayCoordinate;
import org.illarion.engine.Engine;
import org.illarion.engine.EngineException;
import org.illarion.engine.GameContainer;
import org.illarion.engine.graphic.Scene;
import org.illarion.engine.graphic.effects.FogEffect;
import org.illarion.engine.graphic.effects.GrayScaleEffect;
import org.illarion.engine.input.Input;
import org.jetbrains.annotations.Contract;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
/**
* The map display manager stores and manages all objects displayed on the map. It takes care for rendering the objects
* in the proper order, for animations of the entire map and it manages the current location of the avatar.
*
* @author Martin Karing <nitram@illarion.org>
* @author Nop
*/
public final class MapDisplayManager implements AnimatedMove {
/**
* Offset of the tiles due the perspective of the map view.
*/
public static final int TILE_PERSPECTIVE_OFFSET = 3;
private boolean active;
@Nonnull
private final FadingCorridor corridor;
@Nullable
private DisplayCoordinate origin;
/**
* The scene the game is displayed in.
*/
@Nonnull
private final Scene gameScene;
public MapDisplayManager(@Nonnull Engine engine) {
active = false;
corridor = FadingCorridor.getInstance();
gameScene = engine.getAssets().createNewScene();
}
/**
* Get the game scene that is managed by this display manager.
*
* @return the game scene
*/
@Nonnull
@Contract(pure = true)
public Scene getGameScene() {
return gameScene;
}
public int getWorldX(int x) {
if (origin == null) {
throw new IllegalStateException("Origin of the map display is not set.");
}
return (x - getMapCenterX()) + origin.getX();
}
public int getWorldY(int y) {
if (origin == null) {
throw new IllegalStateException("Origin of the map display is not set.");
}
return (y - getMapCenterY()) + origin.getY();
}
private static int getMapCenterX() {
GameContainer window = IllaClient.getInstance().getContainer();
return window.getWidth() >> 1;
}
private static int getMapCenterY() {
GameContainer window = IllaClient.getInstance().getContainer();
return window.getHeight() >> 1;
}
/**
* Fix avatar's position in the middle of the screen and Z-Order
*
* @param av
*/
public void glueAvatarToOrigin(@Nonnull Avatar av) {
//av.setScreenPos(origin.getDcX() - dX, (origin.getDcY() - dY) + dL, origin.getDcZ());
}
public boolean isActive() {
return active && (origin != null);
}
/**
* Update the display entries.
*
* @param container the container that holds the game
* @param delta the time in milliseconds since the last update
*/
public void update(@Nonnull GameContainer container, int delta) {
if (!isActive()) {
return;
}
assert origin != null;
int centerX = container.getWidth() >> 1;
int centerY = container.getHeight() >> 1;
int offX = centerX - origin.getX();
int offY = centerY - origin.getY();
Avatar av = World.getPlayer().getCharacter().getAvatar();
if (av != null) {
glueAvatarToOrigin(av);
corridor.setCorridor(av);
}
Camera.getInstance().setViewport(-offX, -offY, container.getWidth(), container.getHeight());
Input engineInput = container.getEngine().getInput();
gameScene.publishEvent(new CurrentMouseLocationEvent(engineInput.getMouseX(), engineInput.getMouseY()));
gameScene.update(container, delta);
updateFog(container);
updateDeadView(container);
}
/**
* This flag stores if the fog effect was already applied to the scene.
*/
private boolean fogEnabled;
/**
* This flag stores if the gray scale filter that is applied in case the character is dead was already enabled.
*/
private boolean deadViewEnabled;
/**
* Update the graphical effects applied in case the character died.
*
* @param c the game container
*/
private void updateDeadView(@Nonnull GameContainer c) {
int hitPoints = World.getPlayer().getCharacter().getAttribute(CharacterAttribute.HitPoints);
if (hitPoints == 0) {
if (!deadViewEnabled) {
try {
GrayScaleEffect effect = c.getEngine().getAssets().getEffectManager()
.getGrayScaleEffect(true);
gameScene.addEffect(effect);
deadViewEnabled = true;
} catch (EngineException e) {
// error activating gray scale
}
}
} else {
if (deadViewEnabled) {
try {
GrayScaleEffect effect = c.getEngine().getAssets().getEffectManager()
.getGrayScaleEffect(true);
gameScene.removeEffect(effect);
deadViewEnabled = false;
} catch (EngineException e) {
// error activating gray scale
}
}
}
}
/**
* Update the graphical effect that shows the fog on the map.
*
* @param c the game container
*/
private void updateFog(@Nonnull GameContainer c) {
float fog = World.getWeather().getFog();
if (fog > 0.f) {
try {
FogEffect effect = c.getEngine().getAssets().getEffectManager().getFogEffect(true);
effect.setDensity(fog);
if (!fogEnabled) {
gameScene.addEffect(effect);
fogEnabled = true;
}
} catch (EngineException e) {
// error activating fog
}
} else if (fogEnabled) {
try {
FogEffect effect = c.getEngine().getAssets().getEffectManager().getFogEffect(true);
gameScene.removeEffect(effect);
fogEnabled = false;
} catch (EngineException e) {
// error activating fog
}
}
}
/**
* Render all visible map items
*
* @param c the game container the map is rendered in
*/
public void render(@Nonnull GameContainer c) {
if (!isActive()) {
return;
}
Camera camera = Camera.getInstance();
gameScene.render(c.getEngine().getGraphics(), camera.getViewportOffsetX(), camera.getViewportOffsetY());
}
public void setActive(boolean active) {
if (!active) {
origin = null;
}
this.active = active;
}
/**
* Move the map origin to a new location
*
* @param location
*/
public void setLocation(@Nonnull DisplayCoordinate location) {
origin = location;
}
@Override
public void animationStarted() {
}
/**
* Map movement is complete
*/
@Override
public void animationFinished(boolean finished) {
}
/**
* Animation implementation. Does the same as {@link #setLocation}
*/
@Override
public void setPosition(@Nonnull DisplayCoordinate position) {
setLocation(position);
}
}