me.timothy.ddd.conversation.Conversation.java Source code

Java tutorial

Introduction

Here is the source code for me.timothy.ddd.conversation.Conversation.java

Source

/* DrunkDuckDispatch Copyright (C) 2014  Timothy Moore
 *
 *    This program is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU General Public License as published by
 *    the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    This program 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.
 *
 *    You should have received a copy of the GNU General Public License
 *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package me.timothy.ddd.conversation;

import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.List;

import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.newdawn.slick.Color;
import org.newdawn.slick.Graphics;

import me.timothy.ddd.DDDUtils;
import me.timothy.ddd.entities.Entity;
import me.timothy.ddd.entities.EntityConversationInfo;
import me.timothy.ddd.entities.EntityConversationInfo.ConversationChoice;
import me.timothy.ddd.entities.EntityManager;
import me.timothy.ddd.entities.Player;
import me.timothy.ddd.map.GameMap;
import me.timothy.ddd.quests.Quest;
import me.timothy.ddd.quests.QuestManager;
import me.timothy.ddd.scaling.SizeScaleSystem;

public class Conversation {
    private static final int SPACING_WIDTH = 25;
    private static final Rectangle2D.Float TEXT_AREA;
    private static final Rectangle2D.Float BUTTON_AREA;
    private static final int MAX_BUTTON_WIDTH = 410;
    private static final int MAX_BUTTON_HEIGHT = 100;

    static {
        TEXT_AREA = new Rectangle2D.Float();
        TEXT_AREA.x = 0;
        TEXT_AREA.y = (SizeScaleSystem.EXPECTED_HEIGHT * 2) / 3;
        TEXT_AREA.width = SizeScaleSystem.EXPECTED_WIDTH;
        TEXT_AREA.height = (SizeScaleSystem.EXPECTED_HEIGHT * 2) / 9;

        BUTTON_AREA = new Rectangle2D.Float();
        BUTTON_AREA.x = 0;
        BUTTON_AREA.y = (SizeScaleSystem.EXPECTED_HEIGHT * 8) / 9;
        BUTTON_AREA.width = SizeScaleSystem.EXPECTED_WIDTH;
        BUTTON_AREA.height = (SizeScaleSystem.EXPECTED_HEIGHT * 1) / 9;
    }

    private Logger logger;
    private GameMap gameMap;
    private Entity entity;
    private Player player;
    private EntityManager entityManager;
    private QuestManager questManager;

    private int[] choiceTree;
    private List<EntityConversationInfo.ConversationChoice> currentChoices;
    private List<Rectangle2D.Float> buttonLocations;
    private int index;
    private String text;
    private Color defaultBknd;
    private Color choiceBtnBknd;
    private Color textOnBtnColor;
    private int counter;

    public Conversation(Entity entity, Player player, EntityManager entityManager, QuestManager questManager,
            GameMap gameMap) {
        logger = LogManager.getLogger();
        this.entity = entity;
        this.player = player;
        this.entityManager = entityManager;
        this.questManager = questManager;
        this.gameMap = gameMap;
        buttonLocations = new ArrayList<>();

        defaultBknd = new Color(49, 79, 79);
        choiceBtnBknd = Color.black;
        textOnBtnColor = new Color(255, 250, 250);
        onClick(-1, -1); // its kind of hackey but don't question it
    }

    // Returns if the conversation is still going
    public boolean onClick(int x, int y) {
        EntityConversationInfo convInfo = entity.getEntityInfo().getConversation();
        List<EntityConversationInfo.ConversationMessage> messages = convInfo.getText();
        if (messages.size() <= index) {
            if (convInfo.getQuest() != null) {
                questManager.convoEnded(entity, convInfo.getQuest(), choiceTree);
            }
            text = null;
            return false;
        }

        EntityConversationInfo.ConversationMessage currentMessage = messages.get(index);
        if (currentChoices == null) {
            logger.info("Conversation continued..");
            text = currentMessage.getMsg();
            text = DDDUtils.addNewlines(text, 45);

            currentChoices = currentMessage.getChoices();
            createButtons();

            if (choiceTree == null) {
                choiceTree = new int[messages.size()];
            }
            if (currentChoices == null) {
                if (currentMessage.getJumpTo() != EntityConversationInfo.NO_JUMP_TO) {
                    index = currentMessage.getJumpTo();
                } else if (!currentMessage.isEnd())
                    index++;
                else
                    index = Integer.MAX_VALUE;
            }
        } else {
            int choice = -1;
            for (int i = 0; i < currentChoices.size(); i++) {
                Rectangle2D.Float rect = buttonLocations.get(i);
                if (rect.contains(x, y)) {
                    choice = i;
                    break;
                }
            }
            if (choice == -1) {
                return true;
            }

            choiceTree[counter++] = choice;
            ConversationChoice choiceObj = currentChoices.get(choice);
            boolean finished = choiceObj.isEnd() || choiceObj.getJumpTo() == EntityConversationInfo.NO_JUMP_TO;
            if (finished) {
                if (convInfo.getQuest() != null) {
                    questManager.convoEnded(entity, convInfo.getQuest(), choiceTree);
                }
                text = null;
                return false;
            }

            int newIndex = choiceObj.getJumpTo();
            index = newIndex;
            currentMessage = messages.get(index);

            text = currentMessage.getMsg();
            text = DDDUtils.addNewlines(text, 45);

            currentChoices = currentMessage.getChoices();
            createButtons();
            if (currentChoices == null) {
                if (currentMessage.isEnd()) {
                    index = Integer.MAX_VALUE;
                } else {
                    index++;
                }
            }
            logger.printf(Level.INFO, "Chose choice %d which jumped up to index %d", choice, newIndex);
        }
        return true;
    }

    private void createButtons() {
        buttonLocations.clear();
        if (currentChoices != null) {
            int bAreaX = (int) SizeScaleSystem.adjRealToPixelX(BUTTON_AREA.x);
            int bAreaY = (int) SizeScaleSystem.adjRealToPixelY(BUTTON_AREA.y);
            int bAreaWidth = (int) SizeScaleSystem.adjRealToPixelX(BUTTON_AREA.width);
            int bAreaHeight = (int) SizeScaleSystem.adjRealToPixelX(BUTTON_AREA.height);

            int spacingWidth = (currentChoices.size() - 1) * SPACING_WIDTH;
            int buttonWidth = (int) ((bAreaWidth - spacingWidth) / currentChoices.size());
            if (buttonWidth > MAX_BUTTON_WIDTH) {
                buttonWidth = MAX_BUTTON_WIDTH;
            }

            int sidePadding = (int) ((bAreaWidth - (buttonWidth * currentChoices.size()) - spacingWidth) / 2);

            int buttonHeight = bAreaHeight;
            if (buttonHeight > MAX_BUTTON_HEIGHT) {
                buttonHeight = MAX_BUTTON_HEIGHT;
            }

            int topPadding = (bAreaHeight - buttonHeight) / 2;

            int x = bAreaX + sidePadding;
            int y = bAreaY + topPadding;

            for (int i = 0; i < currentChoices.size(); i++) {
                buttonLocations.add(new Rectangle2D.Float(x, y, buttonWidth, buttonHeight));
                x += buttonWidth + SPACING_WIDTH;
            }
        }
    }

    public void render(Graphics g) {
        if (text != null) {
            g.setColor(defaultBknd);
            g.fillRect((int) SizeScaleSystem.adjRealToPixelX(TEXT_AREA.x),
                    (int) SizeScaleSystem.adjRealToPixelY(TEXT_AREA.y),
                    (int) SizeScaleSystem.adjRealToPixelX(TEXT_AREA.width),
                    (int) SizeScaleSystem.adjRealToPixelY(TEXT_AREA.height));
            g.fillRect((int) SizeScaleSystem.adjRealToPixelX(BUTTON_AREA.x),
                    (int) SizeScaleSystem.adjRealToPixelY(BUTTON_AREA.y) - 1, // correct for rounding
                    (int) SizeScaleSystem.adjRealToPixelX(BUTTON_AREA.width),
                    (int) SizeScaleSystem.adjRealToPixelY(BUTTON_AREA.height));

            int y = (int) (SizeScaleSystem.adjRealToPixelX(TEXT_AREA.y + TEXT_AREA.height / 2)
                    - g.getFont().getHeight(text) / 2);
            int x = (int) (SizeScaleSystem.adjRealToPixelY(TEXT_AREA.x + TEXT_AREA.width / 2)
                    - g.getFont().getWidth(text) / 2);

            g.setColor(Color.black);
            g.drawString(text, x, y);

            if (currentChoices != null) {
                for (int i = 0; i < currentChoices.size(); i++) {
                    Rectangle2D.Float rect = buttonLocations.get(i);
                    g.setColor(choiceBtnBknd);
                    g.fillRect(rect.x, rect.y, rect.width, rect.height);

                    String choiceText = currentChoices.get(i).getMsg();
                    if (choiceText == null) {
                        logger.warn(entity.getEntityInfo().toString());
                    }
                    y = (int) (rect.y + rect.height / 2 - g.getFont().getHeight(choiceText) / 2);
                    x = (int) (rect.x + rect.width / 2 - g.getFont().getWidth(choiceText) / 2);

                    g.setColor(textOnBtnColor);
                    g.drawString(choiceText, x, y);
                }
            }
        }
    }
}