Jump to content
Existing user? Sign In

Sign In



Sign Up

[Elvarg / OSRSPK] Improved dialogue system


Sanity

Recommended Posts

Hello guys, its been a while since i posted my last snippet. So i decided to make one. This one is an improved dialogue system. I was looking at the dialogue system (after not having used it for a while) and decided it needed a change. It is not smaller, more compact and easier to use. It still needs work but its like 95%.
Difficultly: 2 / 10 - C+P. extending classes.

First of all if you do not have the class Node. Make a class called nodes in the models package. You can just leave it blank for now or add a method to check which type of node it is.
With this class that you have now made go into the following classes and extend Node.
Item.java
Entity.java
It would have looked like this

Code:
public class Item {

and now look like this

Code:
public class Item extends Node {

Do that to Entity.java and your done with Node.java
Btw Node class isn't used for anything atm but just do something in the npc option class and if dialogue.nodes()[0] == npc.getId() or something like that to make it functional. 

Now make Dialogue.java

Code:
package com.elvarg.world.content.dialogue;

import com.elvarg.world.entity.impl.player.Player;
import com.elvarg.world.model.Node;

/**
 * A peice of dialogue. this is the abstract dialogue so this is the class which 
 * will be extended into other dialogue classes.
 * @author jamix77
 *
 */
public abstract class Dialogue {
	
	/**
	 * This is the player who is in the dialogue with (whoever).
	 */
	protected final Player player;
	
	/**
	 * Our dialogue stage. Used for the handling of the dialogue. Not always used but best way to do this.
	 */
	protected int stage;
	
	/**
	 * Our node in which we are talking to.
	 */
	private Node node;
	
	/**
	 * The interpreter for the dialogue at this moment.
	 */
	protected DialogueInterpreter interpreter;
	
	/**
	 * Constructor to set our player.
	 * @param player The player.
	 */
	public Dialogue(final Player player) {
		this.player = player;
		interpreter = new DialogueInterpreter(this.player,this);
	}
	
	/**
	 * Handle our dialogue. 
	 * @return {@code True} If we should quit.
	 * @return {@code False} If we should continue.
	 */
	protected abstract boolean handle(int option);
	
	/**
	 * Defaultly handle our dialogue here. Then call the abstract dialogue. This one contains no option so it does the
	 * other method also called defaultHandle but it supplys that one with the argument of -1. Indicating that there
	 * is no button id chosen.
	 */
	public void defaultHandle() {
		defaultHandle(-1);
	}
	
	/**
	 * Defaultly handle our dialogue here. Then call the abstract dialogue.
	 */
	public void defaultHandle(int option) {
		if (handle(option)) {
			end();
		}
		stage++;
	}
	
	/**
	 * Initilize the dialogue.
	 */
	public void init() {
		player.setNewDialogue(this);
		defaultHandle();
	}
	
	/**
	 * End our dialogue session and resume back to whatever we were doing previously.
	 */
	private void end() {
		player.setNewDialogue(null);
	}
	
	/**
	 * The nodes that can initilize a dialogue.
	 * @return
	 */
	public abstract Node[] nodes();

	public Node getNode() {
		return node;
	}

	public void setNode(Node node) {
		this.node = node;
	}

}

This is a piece of dialogue which can be extended into a class. EG: public class LumbridgeGuideDialogue extends Dialogue {

Now make DialogueInterpreter.java

Code:
package com.elvarg.world.content.dialogue;

import com.elvarg.cache.impl.definitions.NpcDefinition;
import com.elvarg.world.entity.impl.npc.NPC;
import com.elvarg.world.entity.impl.player.Player;
import com.elvarg.world.model.Item;

/**
 * The interpreter for dialogue system.
 * @author jamix77
 *
 */
public class DialogueInterpreter {
	
	/**
	 * Player who owns the interpreter at this current moment.
	 */
	protected final Player player;
	
	/**
	 * The dialogue that we are interpreting and sending to the player
	 */
	protected final Dialogue dialogue;
	
	/**
	 * Constructor with player inside to indicate which player is owning the interpreter at this current moment.
	 * @param player The player.
	 */
	public DialogueInterpreter(final Player player,final Dialogue dialogue) {
		this.player = player;
		this.dialogue = dialogue;
	}
	
	/**
	 * Send an npc dialogue.
	 * @param lines the lines of dialogue
	 * @return the interpreter instance.
	 */
	public DialogueInterpreter npc(String...lines) {
		if (!(dialogue.getNode() instanceof NPC)) {
			return this;//cant continue because the node is not an npc.
		}
		return npc((NPC)dialogue.getNode(),Expression.DEFAULT,lines);
	}
	
	/**
	 * Sends an npc dialogue. This is with more detail.
	 * @param npc the npc.
	 * @param e the expression on the npcs face.
	 * @param lines the lines of dialogue.
	 * @return the interpreter instance.
	 */
	public DialogueInterpreter npc(NPC npc,Expression e,String...lines) {
		int startDialogueChildId = NODE_DIALOGUE_ID[lines.length - 1];
		int headChildId = startDialogueChildId - 2;
		player.getPacketSender().sendNpcHeadOnInterface(npc.getId(), headChildId);
		player.getPacketSender().sendInterfaceAnimation(headChildId, e.getAnimation());
		player.getPacketSender().sendString(startDialogueChildId - 1, NpcDefinition.forId(npc.getId()) != null ? NpcDefinition.forId(npc.getId()).getName().replaceAll("_", " ") : "");
		for (int i = 0; i < lines.length; i++) {
			player.getPacketSender().sendString(startDialogueChildId + i, lines[i]);
		}
		player.getPacketSender().sendChatboxInterface(startDialogueChildId - 3);
		return this;
	}
	
	/**
	 * Sends a player dialogue.
	 * @param lines the lines of dialogue
	 * @return the interpreter instance.
	 */
	public DialogueInterpreter player(String...lines) {
		return player(Expression.DEFAULT,lines);
	}
	
	/**
	 * Sends a player dialogue. With more detail on what to do.
	 * @param e the expression of the dialogue speaker.
	 * @param lines the lines of the dialogue.
	 * @return the interpreter instance.
	 */
	public DialogueInterpreter player(Expression e, String...lines) {
		int startDialogueChildId = PLAYER_DIALOGUE_ID[lines.length - 1];
		int headChildId = startDialogueChildId - 2;
		player.getPacketSender().sendPlayerHeadOnInterface(headChildId);
		player.getPacketSender().sendInterfaceAnimation(headChildId, e.getAnimation());
		player.getPacketSender().sendString(startDialogueChildId - 1, player.getUsername());
		for (int i = 0; i < lines.length; i++) {
			player.getPacketSender().sendString(startDialogueChildId + i, lines[i]);
		}
		player.getPacketSender().sendChatboxInterface(startDialogueChildId - 3);
		return this;
	}
	
	/**
	 * Sends an item dialogue.
	 * @param lines the lines of dialogue.
	 * @return the interpreter instance.
	 */
	public DialogueInterpreter item(String...lines) {
		if (!(dialogue.getNode() instanceof Item)) {
			return this;//cannot continue with the dialogue because not isnt an instance of item. to send an item send the other method that asks you to specify an item.
		}
		return item((Item)dialogue.getNode(),lines);
	}
	
	/**
	 * Sends an item dialogue. With more detail.
	 * @param item the item to send.
	 * @param lines the lines of dialogue.
	 * @return the interpreter instance.
	 */
	public DialogueInterpreter item(Item item, String...lines) {
		int startDialogueChildId = NODE_DIALOGUE_ID[lines.length - 1];
		int headChildId = startDialogueChildId - 2;
		player.getPacketSender().sendInterfaceModel(headChildId, item.getId(), 150);
		player.getPacketSender().sendString(startDialogueChildId - 1, item.getDefinition() == null ? "?" : item.getDefinition().getName() == null ? "?" : item.getDefinition().getName());
		for (int i = 0; i < lines.length; i++) {
			player.getPacketSender().sendString(startDialogueChildId + i, lines[i]);
		}
		player.getPacketSender().sendChatboxInterface(startDialogueChildId - 3);
		return this;
	}
	
	/**
	 * Sends a set of options.
	 * @param lines
	 * @return
	 */
	public DialogueInterpreter options(String...lines) {
		int firstChildId = OPTION_DIALOGUE_ID[lines.length - 1];
		player.getPacketSender().sendString(firstChildId - 1, "Choose an option");
		for (int i = 0; i < lines.length; i++) {
			player.getPacketSender().sendString(firstChildId + i, lines[i]);
		}
		player.getPacketSender().sendChatboxInterface(firstChildId - 2);
		return this;
	}
	
	
	
	/**
	 * This array contains the child id where the dialogue
	 * statement starts for npc and item dialogues.
	 */
	private static final int[] NODE_DIALOGUE_ID = {
		4885,
		4890,
		4896,
		4903
	};
	
	/**
	 * This array contains the child id where the dialogue
	 * statement starts for player dialogues.
	 */
	private static final int[] PLAYER_DIALOGUE_ID = {
		971,
		976,
		982,
		989
	};
	
	/**
	 * This array contains the child id where the dialogue
	 * statement starts for option dialogues.
	 */
	private static final int[] OPTION_DIALOGUE_ID = {
		13760,
		2461,
		2471,
		2482,
		2494,
	};

}

This is the class which dialogues will be sent. Heres an example usage when inside your class which is extending Dialogue. interpreter.npc(new NPC(825,null),"Well hello there young adventurer.");

Expression.java

Code:
package com.elvarg.world.content.dialogue;

import com.elvarg.world.model.Animation;
/**
 * The dialogue facial expressions
 * @author jamix77
 *
 */
public enum Expression {
	/**
	 * Value for a good mood.
	 */
	HAPPY(588),

	/**
	 * Value for a calm mood.
	 */
	CALM(589),

	/**
	 * Value for a calm mood.
	 */
	CALM_2(590),

	/**
	 * Value for the default conversation mood.
	 */
	DEFAULT(591),

	/**
	 * Value for an evil mood.
	 */
	EVIL(592),

	/**
	 * Value for an evil mood.
	 */
	EVIL_2(593),

	/**
	 * Value for an evil, yet delighted mood.
	 */
	EVIL_DELIGHTED(594),

	/**
	 * Value for an annoyed mood.
	 */
	ANNOYED(595),

	/**
	 * Value for a distressed mood.
	 */
	DISTRESSED(596),

	/**
	 * Value for a distressed mood.
	 */
	DISTRESSED_2(597),

	/**
	 * Value for an almost-crying mood.
	 */
	CRYING_ALMOST(598),

	/**
	 * Value for a sad mood, with the head bowing down.
	 */
	SAD_HEAD_BOW(599),

	/**
	 * Value for a sleepy/drunken mood.
	 */
	SLEEPY(600),

	/**
	 * Value for a sleepy/drunken mood.
	 */
	SLEEPY_2(601),

	/**
	 * Value for a sleepy/drunken mood.
	 */
	SLEEPY_3(602),

	/**
	 * Value for a sleepy/drunken mood.
	 */
	SLEEPY_4(603),

	/**
	 * Value for an evil mood.
	 */
	EVIL_3(604),

	/**
	 * Value for a laughing mood.
	 */
	LAUGHING(605),

	/**
	 * Value for a laughing mood.
	 */
	LAUGHING_2(606),

	/**
	 * Value for a laughing mood.
	 */
	LAUGHING_3(607),

	/**
	 * Value for a laughing mood.
	 */
	LAUGHING_4(608),

	/**
	 * Value for an evil mood.
	 */
	EVIL_4(609),

	/**
	 * Value for a sad mood.
	 */
	SAD(610),

	/**
	 * Value for a sad mood.
	 */
	SAD_2(611),

	/**
	 * Value for a sad mood.
	 */
	SAD_3(612),

	/**
	 * Value for an almost-crying mood.
	 */
	CRYING_ALMOST_2(613),

	/**
	 * Value for an angry mood.
	 */
	ANGRY(614),

	/**
	 * Value for an angry mood.
	 */
	ANGRY_2(615),

	/**
	 * Value for an angry mood.
	 */
	ANGRY_3(616),

	/**
	 * Value for an angry mood.
	 */
	ANGRY_4(617);
	
	/**
	 * The DialogueExpression constructor.
	 * @param animationId	The id of the animation for said expression.
	 */
	private Expression(int animationId) {
		animation = new Animation(animationId);
	}
	
	/**
	 * The animation the dialogue head model will perform.
	 */
	private final Animation animation;
	
	/**
	 * Gets the animation for dialogue head model to perform.
	 * @return	animation.
	 */
	public Animation getAnimation() {
		return animation;
	}
}

These are the facial expressions of the chatheads.

Replace your DialoguePacketListener.java to this

Code:
package com.elvarg.net.packet.impl;

import com.elvarg.net.packet.Packet;
import com.elvarg.net.packet.PacketConstants;
import com.elvarg.net.packet.PacketListener;
import com.elvarg.world.entity.impl.player.Player;
import com.elvarg.world.model.dialogue.DialogueManager;

/**
 * This packet listener handles player's mouse click on the
 * "Click here to continue" option, etc.
 * 
 * @author relex lawl
 * @author jamix77
 */

public class DialoguePacketListener implements PacketListener {

	@Override
	public void handleMessage(Player player, Packet packet) {
		switch (packet.getOpcode()) {
		case PacketConstants.DIALOGUE_OPCODE:
			player.getPacketSender().sendInterfaceRemoval();
			if (player.getNewDialogue() != null) {
				player.getNewDialogue().defaultHandle();
			}
			break;
		}
	}
}

In ButtonClickPacketListener

Code:
case FIRST_DIALOGUE_OPTION_OF_FIVE:
		case FIRST_DIALOGUE_OPTION_OF_FOUR:
		case FIRST_DIALOGUE_OPTION_OF_THREE:
		case FIRST_DIALOGUE_OPTION_OF_TWO:
			if(player.getDialogueOptions() != null) {
				player.getDialogueOptions().handleOption(player, 1);
			}
			if (player.getNewDialogue() != null) {
				player.getNewDialogue().defaultHandle(1);
			}
			break;

		case SECOND_DIALOGUE_OPTION_OF_FIVE:
		case SECOND_DIALOGUE_OPTION_OF_FOUR:
		case SECOND_DIALOGUE_OPTION_OF_THREE:
		case SECOND_DIALOGUE_OPTION_OF_TWO:
			if(player.getDialogueOptions() != null) {
				player.getDialogueOptions().handleOption(player, 2);
			}
			if (player.getNewDialogue() != null) {
				player.getNewDialogue().defaultHandle(2);
			}
		break;

		case THIRD_DIALOGUE_OPTION_OF_FIVE:
		case THIRD_DIALOGUE_OPTION_OF_FOUR:
		case THIRD_DIALOGUE_OPTION_OF_THREE:
			if(player.getDialogueOptions() != null) {
				player.getDialogueOptions().handleOption(player, 3);
			}
			if (player.getNewDialogue() != null) {
				player.getNewDialogue().defaultHandle(3);
			}
			break;

		case FOURTH_DIALOGUE_OPTION_OF_FIVE:
		case FOURTH_DIALOGUE_OPTION_OF_FOUR:
			if(player.getDialogueOptions() != null) {
				player.getDialogueOptions().handleOption(player, 4);
			}
			if (player.getNewDialogue() != null) {
				player.getNewDialogue().defaultHandle(4);
			}
			break;

		case FIFTH_DIALOGUE_OPTION_OF_FIVE:
			if(player.getDialogueOptions() != null) {
				player.getDialogueOptions().handleOption(player, 5);
			}
			if (player.getNewDialogue() != null) {
				player.getNewDialogue().defaultHandle(1);
			}
			break;

Last thing in Player.java

Code:
private com.elvarg.world.content.dialogue.Dialogue newDialogue;

and make its getters and setters.

And your done!

Here is an example class if you want.

Code:
package com.elvarg.world.content.dialogue.impl;

import com.elvarg.world.content.dialogue.Dialogue;
import com.elvarg.world.entity.impl.npc.NPC;
import com.elvarg.world.entity.impl.player.Player;
import com.elvarg.world.model.Node;

/**
 * A dialogue that belongs to the npc of Man.
 * First dialogue made with new system. Testing it out.
 * @author jamix77
 *
 */
public class ManDialogue extends Dialogue {

	/**
	 * Our default constructor with player inside :P
	 * @param player the player.
	 */
	public ManDialogue(Player player) {
		super(player);
	}

	/**
	 * Handle our dialogue
	 */
	@Override
	protected boolean handle(int option) {
		switch (stage) {
		case 0:
			interpreter.npc("Hello dude!");
			break;
		case 1:
			interpreter.player("Hi");
			break;
		case 2:
			interpreter.options("Op1","op2");
			break;
		case 3:
			switch (option) {
			case -1:
				stage = 1;
				return false;
			}
			player.getPacketSender().sendInterfaceRemoval()
			.sendMessage(option == 1 ? "Spaghetti meatballs":"Steak");
			break;
		case 4:
			return true;
		}
		return false;
	}

	/**
	 * Nodes that initlize the {@code ManDialogue} dialogue.
	 */
	@Override
	public Node[] nodes() {
		return new Node[] {new NPC(385,null)};
	}

}

The way you initialise a dialogue is this

Code:
ManDialogue md = new ManDialogue(player);
md.setNode(new NPC(NPCID,null));
md.init();

Switch out what you need there to suit your new dialogue.

Edit: in the handle method inside your npc's separate dialogue class when you return false it will continue when you return true the dialogue will be exited.

Thanks everybody.
Constructive criticism is welcome.

Screen_Shot_2017-09-17_at_11.41.25.png

Edited by MummaPig
Link to comment
Share on other sites

  • 1 year later...
  • 3 months later...
  • 1 year later...
  • 2 years later...

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Contact

[email protected]

astra.security

What is a RSPS?

A RSPS, also known as RuneScape private server, is an online game based on RuneScape, and controlled by independent individuals.

Popular RSPS Servers

Runewild Ikov RedemptionRSPS

Disclaimer

Runesuite is not affiliated with runescape, jagex in any way & exists solely for educational purposes.

×
×
  • Create New...