fr.fg.client.core.ResearchManager.java Source code

Java tutorial

Introduction

Here is the source code for fr.fg.client.core.ResearchManager.java

Source

/*
Copyright 2010 Jeremie Gottero
    
This file is part of Fallen Galaxy.
    
Fallen Galaxy 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.
    
Fallen Galaxy 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 Affero General Public License for more details.
    
You should have received a copy of the GNU Affero General Public License
along with Fallen Galaxy. If not, see <http://www.gnu.org/licenses/>.
*/

package fr.fg.client.core;

import java.util.HashMap;

import com.google.gwt.core.client.GWT;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Event;
import com.google.gwt.user.client.EventPreview;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.AbsolutePanel;
import com.google.gwt.user.client.ui.Widget;

import fr.fg.client.ajax.Action;
import fr.fg.client.ajax.ActionCallback;
import fr.fg.client.ajax.ActionCallbackAdapter;
import fr.fg.client.animation.ProgressBarUpdater;
import fr.fg.client.animation.ToolTipTextUpdater;
import fr.fg.client.animation.ToolTipTimeUpdater;
import fr.fg.client.data.AdvancementData;
import fr.fg.client.data.AnswerData;
import fr.fg.client.data.BuildingData;
import fr.fg.client.data.ResearchData;
import fr.fg.client.data.ResearchedTechnologyData;
import fr.fg.client.data.ShipData;
import fr.fg.client.data.TechnologyData;
import fr.fg.client.i18n.Formatter;
import fr.fg.client.i18n.StaticMessages;
import fr.fg.client.map.Map;
import fr.fg.client.map.ScrollController;
import fr.fg.client.openjwt.animation.Callback;
import fr.fg.client.openjwt.animation.CallbackHandler;
import fr.fg.client.openjwt.animation.TimerManager;
import fr.fg.client.openjwt.core.Config;
import fr.fg.client.openjwt.core.EventManager;
import fr.fg.client.openjwt.core.Point;
import fr.fg.client.openjwt.core.ToolTipManager;
import fr.fg.client.openjwt.ui.DialogListener;
import fr.fg.client.openjwt.ui.JSDialog;
import fr.fg.client.openjwt.ui.JSLabel;
import fr.fg.client.openjwt.ui.JSRowLayout;

public class ResearchManager implements DialogListener, Map, EventPreview, ActionCallback {
    // ------------------------------------------------------- CONSTANTES -- //

    private final static int TECH_TREE_WIDTH = 2000, TECH_TREE_HEIGHT = 1200;

    // -------------------------------------------------------- ATTRIBUTS -- //

    private int viewX, viewY;

    private JSDialog researchDialog;

    private JSLabel researchPointValue;

    private ScrollController controller;

    private AbsolutePanel rootContainer, mapContainer;

    private int halfWindowWidth, halfWindowHeight;

    private ResearchData researchData;

    private long researchLastUpdate;

    private Action currentAction;

    // ---------------------------------------------------- CONSTRUCTEURS -- //

    public ResearchManager() {
        StaticMessages messages = (StaticMessages) GWT.create(StaticMessages.class);

        this.viewX = 0;
        this.viewY = 0;

        mapContainer = new AbsolutePanel();
        mapContainer.setSize(TECH_TREE_WIDTH + "px", TECH_TREE_HEIGHT + "px");
        mapContainer.getElement().setAttribute("unselectable", "on");
        mapContainer.addStyleName("scrollarea");

        rootContainer = new AbsolutePanel();
        rootContainer.setStyleName("technologiesTree");
        rootContainer.getElement().setAttribute("unselectable", "on");
        rootContainer.add(mapContainer);

        controller = new ScrollController(this, rootContainer);
        controller.setEnabled(false);

        // Recherche totale gnre par le joueur
        JSLabel researchPointLabel = new JSLabel("Recherche");
        researchPointLabel.setPixelWidth(100);
        researchPointValue = new JSLabel();
        researchPointValue.setPixelWidth(120);
        researchPointValue.setAlignment(JSLabel.ALIGN_RIGHT);

        // Mise en forme des composants
        JSRowLayout layout = new JSRowLayout();
        layout.addComponent(researchPointLabel);
        layout.addComponent(researchPointValue);

        researchDialog = new JSDialog("<img src=\"" + Config.getMediaUrl()
                + "images/misc/blank.gif\" class=\"iconResearch\"/> " + messages.research(), false, true, true);
        researchDialog.setComponent(layout);
        researchDialog.setLocation(20, 20, false);
        researchDialog.addDialogListener(this);
    }

    // --------------------------------------------------------- METHODES -- //

    public int getShipAvailableAbilities(int shipId) {
        return getShipAvailableAbilities(ShipData.SHIPS[shipId]);
    }

    public int getShipAvailableAbilities(ShipData ship) {
        int availableAbilities = 0;

        for (int i = 0; i < ship.getAbilities().length; i++) {
            int[] requirements = ship.getAbilities()[i].getRequirements();
            boolean available = true;

            for (int requirement : requirements)
                if (!hasResearchedTechnology(requirement)) {
                    available = false;
                    break;
                }

            if (available)
                availableAbilities |= 1 << i;
        }

        return availableAbilities;
    }

    public void show() {
        updateUI();

        // Passe en plein cran
        Client.getInstance().setFullScreenMode(true);
        Client.getInstance().getFullScreenPanel().add(rootContainer);

        halfWindowWidth = Window.getClientWidth() / 2;
        halfWindowHeight = Window.getClientHeight() / 2;

        // Centre la vue sur la technologie en cours
        int currentTechnologyId = researchData.getPendingTechnologiesCount() > 0
                ? researchData.getPendingTechnologyAt(0)
                : 0;

        if (currentTechnologyId != 0) {
            TechnologyData currentTechnology = TechnologyData.getTechnologyById(currentTechnologyId);
            setView(new Point(currentTechnology.getX() - 80, currentTechnology.getY() - 15));
        } else {
            setView(new Point(halfWindowWidth - 200, halfWindowHeight - 200));
        }

        controller.setEnabled(true);
        Client.getInstance().getAreaContainer().getScrollController().setEnabled(false);

        researchDialog.setVisible(true);

        EventManager.addEventHook(this);

        Client.getInstance().getTutorial().setLesson(Tutorial.LESSON_RESEARCH);

        updateResearches();
    }

    public void hide() {
        EventManager.removeEventHook(this);

        researchDialog.setVisible(false);

        mapContainer.clear();

        controller.setEnabled(false);
        Client.getInstance().getAreaContainer().getScrollController().setEnabled(true);

        Client.getInstance().setFullScreenMode(false);
    }

    public void setResearches(ResearchData researchData) {
        this.researchData = researchData;
        this.researchLastUpdate = Utilities.getCurrentTime();

        Client.getInstance().getToolBar().blinkResearch(researchData.getPendingTechnologiesCount() == 0
                && researchData.getResearchedTechnologiesCount() < TechnologyData.TECHNOLOGIES.length);
    }

    public double getZoom() {
        return 1;
    }

    public Point getView() {
        return new Point(viewX, viewY);
    }

    public void setView(Point location) {
        int x = location.getX();
        int y = location.getY();

        // Vrifie que la vue reste dans les limites de la carte
        if (x < halfWindowWidth - 200)
            x = halfWindowWidth - 200;
        if (y < halfWindowHeight - 200)
            y = halfWindowHeight - 200;
        if (x > TECH_TREE_WIDTH - halfWindowWidth + 200)
            x = TECH_TREE_WIDTH - halfWindowWidth + 200;
        if (y > TECH_TREE_HEIGHT - halfWindowHeight + 200)
            y = TECH_TREE_HEIGHT - halfWindowHeight + 200;

        this.viewX = x;
        this.viewY = y;

        // Dplace la carte de la galaxie
        mapContainer.getElement().getStyle().setProperty("left", -viewX + halfWindowWidth + "px");
        mapContainer.getElement().getStyle().setProperty("top", -viewY + halfWindowHeight + "px");

        rootContainer.getElement().getStyle().setProperty("backgroundPosition",
                (-viewX / 2) + "px " + (-viewY / 2) + "px");
    }

    public void dialogClosed(Widget sender) {
        hide();
    }

    public boolean onEventPreview(Event event) {
        switch (event.getTypeInt()) {
        case Event.ONKEYUP:
            if (event.getKeyCode() == 27)
                hide();
            break;
        }
        return false;
    }

    public void onFailure(String error) {
        ActionCallbackAdapter.onFailureDefaultBehavior(error);
    }

    public void onSuccess(AnswerData data) {
        setResearches(data.getResearch());
        updateUI();
    }

    public boolean hasResearchedTechnology(int idTechnology) {
        for (int j = 0; j < researchData.getResearchedTechnologiesCount(); j++) {
            ResearchedTechnologyData researchedTechData = researchData.getResearchedTechnologyAt(j);

            if (researchedTechData.getId() == idTechnology) {
                TechnologyData techData = TechnologyData.getTechnologyById(idTechnology);

                double progress;
                if (researchData.getPendingTechnologiesCount() > 0
                        && researchData.getPendingTechnologyAt(0) == idTechnology) {
                    progress = Math.min(1,
                            (researchedTechData.getProgress() * getTechLength(techData)
                                    + (Utilities.getCurrentTime() - researchLastUpdate)
                                            * researchData.getResearchPoints() * BuildingData.RESEARCH_RATE)
                                    / getTechLength(techData));
                } else {
                    progress = researchedTechData.getProgress();
                }

                return progress == 1;
            }
        }

        return false;
    }

    // ------------------------------------------------- METHODES PRIVEES -- //

    private static long getTechLength(TechnologyData techData) {
        return (long) Math.ceil(techData.getLength() * Math.pow(.95,
                Client.getInstance().getAdvancementDialog().getAdvancementLevel(AdvancementData.TYPE_RESEARCH)));
    }

    private void updateUI() {
        researchPointValue.setText("<b>" + Formatter.formatNumber(researchData.getResearchPoints())
                + "<img class=\"resource research\" src=\"" + Config.getMediaUrl()
                + "images/misc/blank.gif\" unselectable=\"on\"/></b> / min");

        mapContainer.clear();

        // Ajoute les technologies accessibles au joueurs  la liste des
        // technologies recherchs ou en cours de recherche
        loop: for (TechnologyData technology : TechnologyData.TECHNOLOGIES) {
            // Teste si le joueur a dj recherch ou est en train de
            // rechercher la technologie
            for (int j = 0; j < researchData.getResearchedTechnologiesCount(); j++)
                if (researchData.getResearchedTechnologyAt(j).getId() == technology.getId())
                    continue loop;

            // Teste si le joueur a dvelopp toutes les technologies requises
            boolean available = true;
            for (int requirement : technology.getRequirements()) {
                boolean found = false;

                for (int k = 0; k < researchData.getResearchedTechnologiesCount(); k++)
                    if (researchData.getResearchedTechnologyAt(k).getId() == requirement) {
                        ResearchedTechnologyData researchedTechData = researchData.getResearchedTechnologyAt(k);
                        TechnologyData techData = TechnologyData.getTechnologyById(researchedTechData.getId());

                        found = true;

                        double progress;
                        if (researchData.getPendingTechnologiesCount() > 0
                                && researchData.getPendingTechnologyAt(0) == requirement) {
                            progress = Math.min(1,
                                    (researchedTechData.getProgress() * getTechLength(techData)
                                            + (Utilities.getCurrentTime() - researchLastUpdate)
                                                    * researchData.getResearchPoints() * BuildingData.RESEARCH_RATE)
                                            / getTechLength(techData));
                        } else {
                            progress = researchedTechData.getProgress();
                        }
                        available = progress >= 1;
                        break;
                    }

                if (!found)
                    available = false;
                if (!available)
                    break;
            }

            // Ajoute la technologie a la liste des technologies du joueur
            if (available)
                addResearch(TechnologyData.getTechnologyById(technology.getId()), 0, -1,
                        researchData.getResearchPoints() * BuildingData.RESEARCH_RATE);
        }

        for (int i = 0; i < researchData.getResearchedTechnologiesCount(); i++) {
            ResearchedTechnologyData researchedTechData = researchData.getResearchedTechnologyAt(i);

            TechnologyData techData = TechnologyData.getTechnologyById(researchedTechData.getId());

            int queuePosition = -1;

            for (int j = 0; j < researchData.getPendingTechnologiesCount(); j++) {
                if (researchData.getPendingTechnologyAt(j) == techData.getId()) {
                    queuePosition = j;
                    break;
                }
            }

            double progress;
            if (queuePosition == 0) {
                progress = Math.min(1,
                        (researchedTechData.getProgress() * getTechLength(techData)
                                + (Utilities.getCurrentTime() - researchLastUpdate)
                                        * researchData.getResearchPoints() * BuildingData.RESEARCH_RATE)
                                / getTechLength(techData));
            } else {
                progress = researchedTechData.getProgress();
            }

            addResearch(techData, progress, queuePosition,
                    researchData.getResearchPoints() * BuildingData.RESEARCH_RATE);
        }
    }

    private void addResearch(TechnologyData technology, double progress, int queuePosition, double researchPoints) {
        Research r = new Research(technology, progress, queuePosition, researchPoints);
        mapContainer.add(r, technology.getX(), technology.getY());

        // Affiche les technologies ncessaires au dveloppement de la
        // technologie sous forme de lien
        for (int j = 0; j < technology.getRequirements().length; j++) {
            TechnologyData requiredTechnology = TechnologyData.getTechnologyById(technology.getRequirements()[j]);

            // Dbut du lien
            int sx = requiredTechnology.getX() + 160;
            int sy = requiredTechnology.getY() + 13;

            // Fin du lien
            int ex = technology.getX();
            int ey = technology.getY() + 13;

            // Milieu du lien
            int mx = sx + 20;

            // Trace le lien
            mapContainer.add(new Line(sx, sy, mx, sy), Math.min(sx, mx), sy);
            mapContainer.add(new Line(mx, sy, mx, ey), mx, Math.min(sy, ey));
            mapContainer.add(new Line(mx, ey, ex, ey), Math.min(mx, ex), ey);
        }
    }

    private void startResearch(int researchId) {
        if (currentAction != null && currentAction.isPending())
            return;

        if (researchData.getPendingTechnologiesCount() > 0 && researchData.getPendingTechnologyAt(0) == researchId)
            return;

        HashMap<String, String> params = new HashMap<String, String>();
        params.put("queue0", String.valueOf(researchId));
        params.put("queue1", "0");
        params.put("queue2", "0");

        currentAction = new Action("research/set", params, this);
    }

    private void queueResearch(int researchId) {
        if (currentAction != null && currentAction.isPending())
            return;

        for (int i = 0; i < researchData.getPendingTechnologiesCount(); i++)
            if (researchData.getPendingTechnologyAt(i) == researchId)
                return;

        int[] queue = new int[3];

        int i;
        for (i = 0; i < Math.min(2, researchData.getPendingTechnologiesCount()); i++)
            queue[i] = researchData.getPendingTechnologyAt(i);
        queue[i] = researchId;

        HashMap<String, String> params = new HashMap<String, String>();
        params.put("queue0", String.valueOf(queue[0]));
        params.put("queue1", String.valueOf(queue[1]));
        params.put("queue2", String.valueOf(queue[2]));

        currentAction = new Action("research/set", params, this);
    }

    private void updateResearches() {
        if (currentAction != null && currentAction.isPending())
            return;

        currentAction = new Action("research/get", Action.NO_PARAMETERS, this);
    }

    private class Research extends Widget implements ActionCallback, Callback {
        // --------------------------------------------------- CONSTANTES -- //
        // ---------------------------------------------------- ATTRIBUTS -- //

        private int id;

        private double progress;

        private ToolTipTextUpdater timeUpdater;

        private ProgressBarUpdater progressBarUpdater;

        private CallbackHandler researchCallback;

        // ------------------------------------------------ CONSTRUCTEURS -- //

        public Research(TechnologyData technology, double progress, int queuePosition, double researchPoints) {
            this.id = technology.getId();
            this.progress = progress;

            setElement(DOM.createDiv());
            setStyleName("technology" + (progress >= 1 ? " researched" : ""));
            getElement().setId("tech-" + technology.getId());

            String time;
            if (researchPoints > 0) {
                int remainingTime = (int) Math.ceil((1 - progress) * getTechLength(technology) / researchPoints);

                if (queuePosition == 0) {
                    String id = ToolTipTextUpdater.generateId();

                    time = "<span id=\"" + id + "\">" + Formatter.formatDate(remainingTime) + "</span>";

                    timeUpdater = new ToolTipTimeUpdater(getElement(), id, remainingTime);
                    TimerManager.register(timeUpdater);

                    researchCallback = new CallbackHandler(this, 1000l * remainingTime);
                    TimerManager.registerCallback(researchCallback);
                } else {
                    time = Formatter.formatDate(remainingTime);
                }
            } else {
                time = "";
            }

            StaticMessages messages = (StaticMessages) GWT.create(StaticMessages.class);

            // Slectionne la technologie si c'est la technologie en cours de
            // recherche
            if (queuePosition == 0)
                addStyleName("current");

            getElement().setInnerHTML("<div class=\"name\">" + (queuePosition != -1 ? queuePosition + 1 + ". " : "")
                    + technology.getName() + "</div>" + "<div class=\"progress\"><div class=\"currentProgress\" "
                    + "style=\"width: " + (int) Math.floor(100 * progress) + "%;\"></div>"
                    + "</div><div class=\"length\">"
                    + (progress >= 1 ? messages.researchFinished() : messages.researchLength(time)) + "</div>");
            ToolTipManager.getInstance().register(getElement(), technology.getToolTip());

            if (queuePosition == 0 && researchPoints > 0) {
                progressBarUpdater = new ProgressBarUpdater(
                        getElement().getFirstChildElement().getNextSiblingElement().getFirstChildElement(),
                        (int) Math.floor(getTechLength(technology) * progress / researchPoints),
                        (int) (getTechLength(technology) / researchPoints));
                TimerManager.register(progressBarUpdater);
            }

            sinkEvents(Event.ONCLICK);
        }

        // ----------------------------------------------------- METHODES -- //

        @Override
        protected void onUnload() {
            if (timeUpdater != null) {
                TimerManager.unregister(timeUpdater);
                timeUpdater.destroy();
                timeUpdater = null;
            }

            if (progressBarUpdater != null) {
                TimerManager.unregister(progressBarUpdater);
                progressBarUpdater.destroy();
                progressBarUpdater = null;
            }

            if (researchCallback != null) {
                TimerManager.unregisterCallback(researchCallback);
                researchCallback = null;
            }
        }

        @Override
        public void onBrowserEvent(Event event) {
            switch (event.getTypeInt()) {
            case Event.ONCLICK:
                if (progress < 1) {
                    if (event.getShiftKey() || event.getCtrlKey())
                        queueResearch(id);
                    else
                        startResearch(id);
                }
                break;
            }
        }

        public void run() {
            updateResearches();
        }

        public void onFailure(String error) {
            ActionCallbackAdapter.onFailureDefaultBehavior(error);
        }

        public void onSuccess(AnswerData data) {
            setResearches(data.getResearch());
            updateUI();
        }

        // --------------------------------------------- METHODES PRIVEES -- //
    }

    private class Line extends Widget {
        // --------------------------------------------------- CONSTANTES -- //
        // ---------------------------------------------------- ATTRIBUTS -- //
        // ------------------------------------------------ CONSTRUCTEURS -- //

        public Line(int x1, int y1, int x2, int y2) {
            setElement(DOM.createDiv());

            getElement().getStyle().setProperty("margin", "-1px 0 0 -1px");

            if (x1 == x2) {
                setWidth("3px");
                setHeight(Math.abs(y2 - y1) + 2 + "px");
            } else if (y1 == y2) {
                setWidth(Math.abs(x2 - x1) + 2 + "px");
                setHeight("3px");
            }

            getElement().getStyle().setProperty("backgroundColor", "#808080");
        }

        // ----------------------------------------------------- METHODES -- //
        // --------------------------------------------- METHODES PRIVEES -- //
    }
}