API:Gossip Menus
From WCell Wiki
This article is related to development using the WCell API.
- Gossip menus are very useful for administration/commands and/or user-given options.
- They allow the server to query the user for custom feedback in a form of a dialog
- And they are very easy to create
Contents |
Defining Gossips
Every GossipMenu consists of the following parts:
- A text to be displayed (which is identified and cached client-side using the BodyTextId and not sent directly)
- A set of GossipMenuItem (representing clickable buttons in the menu)
GossipMenuItems have:
- An optional icon (indicated by the GossipMenuIcon Enum)
- An optional Text
- An optional ConfirmText which will be displayed to the user within an Ok/Cancel dialog when the item is clicked (to prevent users from accidently selecting an option with serious consequences)
- An optional Action that defines what to do when the item is selected
- An optional SubMenu (also of type GossipMenu) that will be opened when the item is clicked
- GossipMenus can be unclosable in which case they will only be closed if the User selects the "Quit" option
- The SubMenus give you the power of nesting Gossip Menus as deep as you like
- You can add "Back" (to the parent menu) and "Quit" buttons automatically
Using Gossips
- You can either attach GossipMenus to NPCs, by assigning:
- NPCEntry.DefaultGossipMenu or
- NPC.GossipMenu
- Or you can start a gossip on any player by calling:
- Character.StartGossip(GossipMenu)
Examples
Assign a Menu to NPCs
[Initialization]
[DependentInitialization(typeof(NPCMgr))]
public static void InitMyNPCs
{
var entry = NPCMgr.GetEntry(NPCId.HeraldOfTheAlliance);
entry.DefaultGossipMenu = new GossipMenu(
new GossipMenuItem("Click Me!", convo => {
convo.Speaker.SendSystemMessage("You clicked me!");
});
var entry = NPCMgr.GetEntry(NPCId.FallenHeroOfTheHorde);
entry.BeforeDeath += hero => {
var killer = hero.FirstAttacker as Character;
if (killer == null) // do nothing if not killed by a player
return true;
if (!(killer is Character))
killer = killer.MasterChar;
if (killer == null || !(killer is Character))
return true;
hero.FactionId = FactionId.Friendly; // become friendly to everyone and idle
hero.Brain.State = BrainState.Idle;
hero.GossipMenu = new GossipMenu( // give the NPC a new Gossip right when he is about to die
new GossipMenuItem("I forgive you!", convo => { // give player the option to forgive the hero
convo.Speaker.Say("Thank you so much!"); // say something
convo.Speaker.CallDelayed(2000, obj => obj.Delete()); // delete after 2 seconds
convo.Character.GainXp(1000); // give xp
});
killer.StartGossip(hero.GossipMenu); // start gossip automatically
return false; // don't die
}
}
Teleport Menu
From the TeleportCommand:
public static GossipMenu CreateTeleMenu(Unit user, List<WorldZoneLocation> locations)
{
// create gossip of all options
var menu = new GossipMenu();
foreach (var location in locations)
{
var loc = location; // allocate a local copy
menu.AddItem(new GossipMenuItem(loc.Name, convo =>
{
user.TeleportTo(loc);
}));
}
return menu;
}
Sample Menu
As found in MixedSamples:
return new GossipMenu(
new GossipMenuItem("Click Me!", convo => {
convo.Speaker.SendSystemMessage("You clicked me!");
}),
new GossipMenuItem("Icon List", convo => {
convo.Speaker.SendSystemMessage("A list of all available Gossip Icons");
},
new GossipMenu(
new GossipMenuItem(GossipMenuIcon.Talk, "Talk"),
new GossipMenuItem(GossipMenuIcon.Trade, "Trade"),
new GossipMenuItem(GossipMenuIcon.Taxi, "Taxi"),
new GossipMenuItem(GossipMenuIcon.Train, "Train"),
new GossipMenuItem(GossipMenuIcon.Resurrect, "Resurrect"),
new GossipMenuItem(GossipMenuIcon.Bind, "Bind"),
new GossipMenuItem(GossipMenuIcon.Bank, "Bank"),
new GossipMenuItem(GossipMenuIcon.Guild, "Guild"),
new GossipMenuItem(GossipMenuIcon.Tabard, "Tabard"),
new GossipMenuItem(GossipMenuIcon.Battlefield, "Battlefield")
) {
BodyTextId = sampleGossipTextId
}
),
// we need this to close the Gossip again
new QuitGossipMenuItem("Done")) {
KeepOpen = true
};
Advanced Examples
Spawn Gossip Menu
The Spawn Gossip Menu can be used to customize NPC Spawn information and waypoints ingame (not fully done yet):
/// <summary>
/// The GossipMenu used to customize SpawnPoints
/// </summary>
public class SpawnPointMenu : GossipMenu
{
private readonly SpawnPoint m_point;
public SpawnPointMenu(SpawnPoint point)
: base(point.SpawnEntry.Entry.NameGossipId)
{
m_point = point;
KeepOpen = true;
AddItem(new GossipMenuItem("Go to Spawn", HandleTeleport));
AddItem(new GossipMenuItem("Remove Spawn", HandleRemove,
"This will remove the Spawn with all its Waypoints (" + m_point.SpawnEntry.Entry + ")"));
AddItem(new GossipMenuItem("Waypoint List", WPMenu = CreateWaypointMenu()));
AddItem(new GossipMenuItem("Add new Wapyoint", HandleAddWP));
AddQuitMenuItem("Done");
}
/// <summary>
/// The Waypoint-submenu
/// </summary>
public GossipMenu WPMenu
{
get;
internal set;
}
/// <summary>
/// Returns the GossipMenuItem of the given Waypoint from this menu
/// </summary>
/// <param name="wp"></param>
public void RemoveWPItem(WaypointEntry wp)
{
foreach (WPItem item in WPMenu.GossipItems)
{
if (item.Wp == wp)
{
WPMenu.GossipItems.Remove(item);
return;
}
}
}
/// <summary>
/// Creates and returns the sub-menu for Waypoints
/// </summary>
/// <returns></returns>
private GossipMenu CreateWaypointMenu()
{
var menu = new GossipMenu(m_point.SpawnEntry.Entry.NameGossipId);
menu.AddGoBackItem("Go back...");
foreach (var wp in m_point.SpawnEntry.Waypoints)
{
menu.AddItem(new WPItem(m_point, wp));
}
menu.AddQuitMenuItem("Done");
return menu;
}
/// <summary>
/// Handle what happens when clicking on the Teleport option
/// </summary>
void HandleTeleport(GossipConversation convo)
{
convo.Speaker.TeleportTo(m_point);
}
/// <summary>
/// Handle what happens when clicking on the Remove option
/// </summary>
private void HandleRemove(GossipConversation convo)
{
m_point.RemoveSpawnLater();
}
/// <summary>
/// Handle what happens when clicking on the Add WP button
/// </summary>
private void HandleAddWP(GossipConversation convo)
{
var chr = convo.Speaker;
m_point.InsertAfter(null, chr.Position, chr.Orientation);
}
public SpawnPoint Point
{
get { return m_point; }
}
/// <summary>
/// A GossipMenuItem for each Waypoint
/// </summary>
public class WPItem : GossipMenuItem
{
private readonly SpawnPoint m_Point;
private WaypointEntry m_wp;
public WPItem(SpawnPoint point, WaypointEntry wp)
{
m_Point = point;
m_wp = wp;
Text = "WP #" + wp.Id;
SubMenu = new GossipMenu(point.SpawnEntry.Entry.NameGossipId);
SubMenu.AddGoBackItem();
SubMenu.AddRange(
new GossipMenuItem("Go to " + Text, HandleGoto),
new GossipMenuItem("Remove", HandleRemove),
new GossipMenuItem("Move here", HandleMoveOver),
new GossipMenuItem("Insert New", HandleInsert));
}
public WaypointEntry Wp
{
get { return m_wp; }
}
public SpawnPoint Point
{
get { return m_Point; }
}
/// <summary>
/// Go to the WP
/// </summary>
void HandleGoto(GossipConversation convo)
{
convo.Speaker.TeleportTo(m_Point.Region, m_wp.Position);
}
/// <summary>
/// Remove the WP
/// </summary>
void HandleRemove(GossipConversation convo)
{
m_Point.RemoveWP(m_wp);
// the WP is now gone, so let's send the Menu again (without this Item in it)
convo.Invalidate();
}
/// <summary>
/// Move the Waypoint over to the Character
/// </summary>
void HandleMoveOver(GossipConversation convo)
{
m_Point.MoveWP(m_wp, convo.Speaker.Position);
}
/// <summary>
/// Move the Waypoint over to the Character
/// </summary>
void HandleInsert(GossipConversation convo)
{
m_Point.InsertAfter(m_wp, convo.Speaker.Position, convo.Speaker.Orientation);
}
}
}
