package net.scapeemulator.game.dialogue;
import net.scapeemulator.game.model.definition.NPCDefinitions;
import net.scapeemulator.game.model.player.interfaces.InterfaceSet.Component;
import net.scapeemulator.game.model.player.Player;
import net.scapeemulator.game.msg.impl.inter.InterfaceAnimationMessage;
import net.scapeemulator.game.msg.impl.inter.InterfaceNPCHeadMessage;
import net.scapeemulator.game.msg.impl.inter.InterfacePlayerHeadMessage;
import org.codehaus.plexus.util.StringUtils;
/**
* @author Hadyn Richard
*/
public final class DialogueContext<T> {
private static final int TEXT_OFFSET = 210;
private static final int TEXT_OFFSET_NO_INPUT = 214;
private static final int OPTION_OFFSET = 228;
private static final int RIGHT_CONVERSATION_OFFSET = 64;
private static final int RIGHT_CONVERSATION_OFFSET_NO_INPUT = 68;
private static final int LEFT_CONVERSATION_OFFSET = 241;
private static final int LEFT_CONVERSATION_OFFSET_NO_INPUT = 245;
private static final int LESS_OPTIONS = 1;
private static final int MORE_OPTIONS = 5;
private final Player player;
private final Dialogue<T> dialogue;
private DialogueType displayedType;
private final DialogueContextListener listener;
private String[] options;
private boolean inputDisplayed;
private boolean overflowDisplayed;
private T stage;
private int interfaceId = -2;
private boolean isStopped;
private enum DialogueType {
/* The enumeration for each conversation dialogue */
PLAYER_CONVERSATION, NPC_CONVERSATION,
/* The enumeration for each option dialogue */
TWO_OPTION, THREE_OPTION, FOUR_OPTION, FIVE_OPTION, SIX_OPTION, SEVEN_OPTION, EIGHT_OPTION, NINE_OPTION,
/* The enumeration for the text dialogue */
TEXT
}
public DialogueContext(Player player, Dialogue dialogue) {
this.player = player;
this.dialogue = dialogue;
listener = new DialogueContextListener(this);
init();
}
private void init() {
dialogue.initialize(this);
}
public void handleInput(int id, int componentId) {
/* Dont handle input if there is no input displayed */
if (!inputDisplayed) {
return;
}
switch (displayedType) {
case PLAYER_CONVERSATION:
case NPC_CONVERSATION:
case TEXT:
dialogue.handleOption(this, DialogueOption.CONTINUE);
break;
case TWO_OPTION:
case THREE_OPTION:
case FOUR_OPTION:
case FIVE_OPTION:
case SIX_OPTION:
case SEVEN_OPTION:
case EIGHT_OPTION:
case NINE_OPTION:
int offset = componentId - 1;
int count = getAmountOptions(displayedType);
if (count > 5) {
/* Swap from overflow to option chatbox */
if (offset == LESS_OPTIONS && overflowDisplayed) {
interfaceId = getOptionInterfaceId(count);
player.setInterfaceText(interfaceId, 6, "More Options...");
for (int i = 0; i < 4; i++) {
player.setInterfaceText(interfaceId, i + 2, options[i]);
}
player.getInterfaceSet().openChatbox(interfaceId);
overflowDisplayed = false;
return;
}
/* Swap from overflow to option chatbox */
if (offset == MORE_OPTIONS && !overflowDisplayed) {
interfaceId = getOverflowInterfaceId(count);
player.setInterfaceText(interfaceId, 2, "Less Options...");
for (int i = 4; i < count; i++) {
player.setInterfaceText(interfaceId, i - 1, options[i]);
}
player.getInterfaceSet().getChatbox().removeListener();
player.getInterfaceSet().openChatbox(interfaceId);
player.getInterfaceSet().getChatbox().setListener(new DialogueContextListener(this));
overflowDisplayed = true;
return;
}
}
if (overflowDisplayed) {
offset += 4;
}
dialogue.handleOption(this, DialogueOption.forId(offset));
break;
}
}
public void openPlayerConversationDialogue(String text, HeadAnimation animation, boolean displayInput) {
String[] chunks = split(text);
if (chunks.length >= 5) {
throw new IllegalArgumentException();
}
interfaceId = (displayInput ? RIGHT_CONVERSATION_OFFSET : RIGHT_CONVERSATION_OFFSET_NO_INPUT) + chunks.length - 1;
for (int i = 0; i < chunks.length; i++) {
player.setInterfaceText(interfaceId, i + 4, chunks[i]);
}
player.setInterfaceText(interfaceId, 3, StringUtils.capitalise(player.getDisplayName()));
player.send(new InterfaceAnimationMessage(interfaceId, 2, animation.getAnimationId()));
player.send(new InterfacePlayerHeadMessage(interfaceId, 2));
player.getInterfaceSet().openChatbox(interfaceId);
player.getInterfaceSet().getChatbox().setListener(listener);
displayedType = DialogueType.PLAYER_CONVERSATION;
inputDisplayed = displayInput;
}
public void openNpcConversationDialogue(String text, int npcType, HeadAnimation animation, boolean displayInput) {
String[] chunks = split(text);
if (chunks.length >= 5) {
throw new IllegalArgumentException();
}
interfaceId = (displayInput ? LEFT_CONVERSATION_OFFSET : LEFT_CONVERSATION_OFFSET_NO_INPUT) + chunks.length - 1;
for (int i = 0; i < chunks.length; i++) {
player.setInterfaceText(interfaceId, i + 4, chunks[i]);
}
player.setInterfaceText(interfaceId, 3, StringUtils.capitalise(NPCDefinitions.forId(npcType).getName()));
player.send(new InterfaceAnimationMessage(interfaceId, 2, animation.getAnimationId()));
player.send(new InterfaceNPCHeadMessage(interfaceId, 2, npcType));
player.getInterfaceSet().openChatbox(interfaceId);
player.getInterfaceSet().getChatbox().setListener(listener);
displayedType = DialogueType.PLAYER_CONVERSATION;
inputDisplayed = displayInput;
}
public void openTextDialogue(String text, boolean displayInput) {
String[] chunks = split(text);
if (chunks.length >= 5) {
throw new IllegalArgumentException();
}
interfaceId = (displayInput ? TEXT_OFFSET : TEXT_OFFSET_NO_INPUT) + chunks.length - 1;
for (int i = 1; i <= chunks.length; i++) {
player.setInterfaceText(interfaceId, i, chunks[i - 1]);
}
player.getInterfaceSet().openChatbox(interfaceId);
player.getInterfaceSet().getChatbox().setListener(listener);
displayedType = DialogueType.TEXT;
inputDisplayed = displayInput;
}
public void openOptionDialogue(String... opts) {
if (opts.length >= 10 || opts.length <= 1) {
throw new IllegalArgumentException();
}
int amountOptions = opts.length;
interfaceId = getOptionInterfaceId(amountOptions);
/* If overflow is present do not send the fifth option yet */
for (int i = 0; i < (amountOptions > 5 ? 4 : amountOptions); i++) {
player.setInterfaceText(interfaceId, i + 2, opts[i]);
}
/* Send the overflow junk */
if (amountOptions > 5) {
player.setInterfaceText(interfaceId, 6, "More Options...");
}
player.getInterfaceSet().openChatbox(interfaceId);
player.getInterfaceSet().getChatbox().setListener(listener);
displayedType = getOptionDialogue(amountOptions);
inputDisplayed = true;
overflowDisplayed = false;
options = opts;
}
private static int getOptionInterfaceId(int count) {
/* Limit the count if nessecary */
if (count > 5) {
count = 5;
}
return OPTION_OFFSET + 2 * (count - 2);
}
private static int getOverflowInterfaceId(int count) {
return getOptionInterfaceId(count - 4);
}
private static int getAmountOptions(DialogueType type) {
switch (type) {
case TWO_OPTION:
return 2;
case THREE_OPTION:
return 3;
case FOUR_OPTION:
return 4;
case FIVE_OPTION:
return 5;
case SIX_OPTION:
return 6;
case SEVEN_OPTION:
return 7;
case EIGHT_OPTION:
return 8;
case NINE_OPTION:
return 9;
default:
break;
}
throw new IllegalArgumentException();
}
private static DialogueType getOptionDialogue(int amount) {
switch (amount) {
case 2:
return DialogueType.TWO_OPTION;
case 3:
return DialogueType.THREE_OPTION;
case 4:
return DialogueType.FOUR_OPTION;
case 5:
return DialogueType.FIVE_OPTION;
case 6:
return DialogueType.SIX_OPTION;
case 7:
return DialogueType.SEVEN_OPTION;
case 8:
return DialogueType.EIGHT_OPTION;
case 9:
return DialogueType.NINE_OPTION;
}
throw new IllegalArgumentException();
}
public void stop() {
if (!isStopped) {
Component component = player.getInterfaceSet().getChatbox();
component.removeListener();
component.reset();
isStopped = true;
}
}
public boolean isStopped() {
return isStopped;
}
private static String[] split(String str) {
StringBuilder builder = new StringBuilder();
int counter = 0;
for (char c : str.toCharArray()) {
if (counter >= 40 && c == ' ') {
builder.append("\n");
counter = 0;
continue;
}
builder.append(c);
counter++;
}
return builder.toString().split("\n");
}
public T getStage() {
return stage;
}
public void setStage(T stage) {
this.stage = stage;
}
public int getInterfaceId() {
return interfaceId;
}
public Player getPlayer() {
return player;
}
}