API:World

From WCell Wiki
Jump to: navigation, search

You can use both, NPCs as well as GameObjects to change the looks of your world.
It is recommended to fall back on those two articles as reference while working with NPCs and GOs.

Contents

Maps, Regions and Zones

  • Every map (such as continents, instances and battlegrounds) are of type Region
  • Everything that happens within one Region is thread-safe
  • Every Region has at least one Zone
    • Zones can have child-zones (or areas) which are also of type Zone
    • You can access child and parent zones through the Children and ParentZone properties respectively
  • Regions can be spawned (once data has been loaded, using the load command) and cleared ingame at any time without risk
    • The command #map spawn (or short: #map s) will spawn all default objects on a map
    • The command #map clear will remove all objects that are not owned by any player
  • Static default data of Regions is defined in RegionInfo
  • Static default data of Zones is defined in ZoneInfo

Ingame-Object Class Hierarchy

  • ObjectBase (represents any entity that exists in the world)
    • Item (anything that can be put in the backpack, such as weapons, ore etc)
      • Container (anything that can hold hold other items, such as bags etc)
    • WorldObject (anything that exists on the map)
      • GameObjects (any static -often interactable- object, such as MailBox, Chairs, collectable flowers (and Transports) etc)
      • Unit (any living character or creature)
        • Character (playable Characters that users can login with)
        • NPC (computer-controlled characters, vendors and creatures)
      • DynamicObject (static animations, such as Blizzard, Flamestrike etc - usually created temporarily when casting spells)
      • Corpse (a Player's Corpse - NPC's corpses are actual NPC objects)

WorldObject

  • The WorldObject is very important because it represents anything that can be put onto the face of the ingame world
  • It is the base class for playable Characters, NPCs and GameObjects

Events

  • Events can be used to execute code when something interesting happens
  • In order to execute code you have to attach a delegate (or simply a method) to it, using the += operator
    • The signature of the method to be executed is defined by the delegate in the event-signature
    • The code can be attached in the form of:
      • An anonymous method: MyEvent += delegate(ArgType1 arg1, ArgType2) { ... }
      • A lambda expression: MyEvent += (arg1, arg2) => returnValue or: (arg1, arg2) => { CodeToBeExecuted(); return expectedValue; }
      • The name of a well-named method: MyEvent += MyMethod
  • You can remove these event-handlers from the event by using the -= operator
  • All RealmServer-events can be found in the Events/ folder
  • WCell defines a whole range of events - for example:
    • static event CharacterLoginHandler Character.LoggedIn is triggered when a new Character is logged in
    • event Action<Item> ItemTemplate.Equipped is triggered when an Item of that ItemTemplate is equipped

Event Examples

Character.LoggedIn

  • The event and its delegate are defined like this:
		/// <param name="character"></param>
		/// <param name="firstLogin">Indicates whether the Character starts a new session or if 
		/// the client re-connected to a Character that was already logged in.</param>
		public delegate void CharacterLoginHandler(Character chr, bool firstLogin);
		
		// ...
		
		/// <summary>
		/// Is called when the Player logs in or reconnects to a Character that was logged in before and not logged out yet (due to logout delay).
		/// </summary>
		public static event CharacterLoginHandler LoggedIn;
  • The delegate of the event is CharacterLoginHandler
  • Which means, the event requires a method with return-type void (don't return anything) and 2 arguments: One Character and one bool
  • The event is static, meaning delegates have to be attached through the containing class and not its objects (Character.LoggedIn rather than myChr.LoggedIn)
  • You can use it like this:
[Initialization]
public static void InitCharEvents()
{
	Character.LoggedIn += (chr, firstLogin) => chr.Say("Hello, I just logged in!");  // let a new Character say something when logging in
}
  • Or a little more advanced:
[Initialization]
public static void InitCharEvents()
{
	Character.LoggedIn += (chr, firstLogin) => {
		// determine whether the Player logs in with a new Character, or simply reconnects to a logged in Character
	  string welcome;
		if (!firstLogin) {
			welcome = "Welcome back";
		}
		else {
			welcome = "Welcome";
		}
		
		if (chr.Role.IsStaff) {
			// tell staff members about the ticket-situation
			chr.SendSystemMessage("{0} sir - There are {1} Tickets in the queue!", welcome, TicketMgr.TicketCount);
		}
		else {
			// Charge players everytime they login, if they have anything
			if (chr.Money >= 10) 
			{
				chr.Money -= 10;
			}
			chr.SendSystemMessage("{0} - You have been charged {1} copper!", welcome, 10);
		}
	}
}

ItemTemplate.Equipped and Unequipped

		/// <summary>
		/// Called whenever an Item of this ItemTemplate is equipped
		/// </summary>
		public event Action<Item> Equipped;

		/// <summary>
		/// Called whenever an Item of this ItemTemplate is unequipped
		/// </summary>
		public event Action<Item> Unequipped;
  • The delegate is Action<Item> which is of return-type void and has one argument of type Item
  • The events belong to ItemTemplate and are not static, meaning they need to be accessed through ItemTemplate-objects, rather than the ItemTemplate class
  • You can use these events to add a specialty other than StatModifiers (which can be easily done by using ItemTemplate.AddMod) to specific items
  • As described in the Items API, any item-related initializer method is dependent on the ItemMgr:
  • You can easily make the wearer of any item invulnerable to any kind of damage, using this code:
[Initialization]
[DependentInitialization(typeof(ItemMgr))]
public static void InitItemEvents()
{
	var templ = ItemMgr.GetTemplate(ItemId.ChestguardOfTheVanquishedChampion);
	
	// let this item make the wearer invulnerable
	templ.Equipped += chestGuard => chestGuard.OwningCharacter.Invul++;
	templ.Unequipped += chestGuard => chestGuard.OwningCharacter.Invul--;
}


Add content to the world

Ingame

  • Make sure that NPC and/or GOs are loaded, using the commands: #load all, #load npcs and/or #load gos
  • Use the commands:
    • #go add <goid> (create a default GameObject of the given id)
    • #npc add <npcid> (create a homeless (without SpawnPoint) NPC of the given id at your current location)
    • #npc spawn -c [<npcid>] (trigger spawning of the closest NPC to your location - optionally specify what kind of NPC you want - teleports you to the location)

Code

GameObjects

[Initialization]
[DependentInitialization(typeof(GOMgr))]
public static void InitMyGOs
{
	var lightEntry = GOMgr.GetEntry(GOEntryId.CrusaderDargathsLight);
	lightEntry.AddTemplate(MapId.Kalimdor, new Vector3(1, 2, 3));
}
  • IMPORTANT: If you load GOs using the #load command, the GO won't be added automatically before it is (re-)spawned the next time (using #rgn clear and #rgn spawn)
  • If you want to spawn a GO at a specific time, rather than having them spawned automatically when starting the region, you need to:
    • Deactivate auto-spawning and
    • Call the Spawn method yourself:
static GOTemplate lightTemplate;

[Initialization]
[DependentInitialization(typeof(GOMgr))]
public static void InitMyGOs
{
	var lightEntry = GOMgr.GetEntry(GOEntryId.CrusaderDargathsLight);
	lightTemplate = lightEntry.AddTemplate(MapId.Kalimdor, new Vector3(1, 2, 3), false); // the last parameter decides whether to auto-spawn (true by default)
}

// ...

public static void SpawnLight()
{
       lightTemplate.Spawn();
}
  • You can also create GameObjects at any point on the map without defining a GOTemplate:
static GOEntry lightEntry;

[Initialization]
[DependentInitialization(typeof(GOMgr))]
public static void InitMyGOs
{
        // remember the light-entry as soon as it gets initialized
	lightEntry = GOMgr.GetEntry(GOEntryId.CrusaderDargathsLight);

       // hook up an event to spawn the light when someone dies at night in EK:
       World.EasternKingdom.RegionInfo.PlayerDied += action => {
              var chr = action.Victim as Character;
              if (RealmServer.IngameTime.Hour < 6) {                              // only spawn before 6 am
                     var light = lightEntry.Spawn(chr);                           // spawn at the victim's location
                     light.CallDelayed(60000, obj => obj.Delete);                 // delete after 60 seconds
              }
       };
}

NPCs

This is a stub

static NPCEntry arthasImageEntry;

[Initialization]
[DependentInitialization(typeof(NPCMgr))]
public static void InitMyNPCs
{
        // remember the entry as soon as it gets initialized
	arthasImageEntry = NPCMgr.GetEntry(NPCId.ImageOfArthas);

       // hook up an event to let arthas scold everyone who dies
       World.EasternKingdom.RegionInfo.PlayerDied += action => {
              var chr = action.Victim as Character;
              var arthas = arthasImageEntry.Create();
              chr.Region.AddObject(arthas, chr);             // spawn Arthas ontop of the victim
              arthas.Brain.DefaultState = BrainState.Idle;   // make Arthas idle
              arthas.Invul++;                                // make Arthas invulnerable
              arthas.Face(chr);                              // face the character
              arthas.CallDelayed(1000,                       // wait a second before saying something
                     obj => arthas.Say("You naughty little {0}!", chr.Gender == GenderId.Male ? "boy" : "girl"));
              arthas.CallDelayed(6000, obj => obj.Delete);   // delete after a total of 6 seconds (5 seconds after saying something)
       };
}

Personal tools