This tutorial covers creating new Player Guilds. You can create them in Java or Jython, and we'll focus on Jython since the code is more elegant, easier to understand, and easier to code and test. Once your guild becomes stable, you should email Rhialto and ask for your python files to be compiled, which will speed them up considerably.
OverviewIn Wyvern, a Guild is an organization that grants its members unique abilities and penalties. The list of currently-available guilds can be found in the Guilds Section of the Player Manual.Guilds tend to have these things in common:
Guild Coding OverviewHere are the steps involved in creating a new Guild:
Blazing Your Own TrailThe Guild-creation framework we're discussing in this Tutorial is the simplest way to create new Guilds. It relies heavily on two helper classes: All the existing Wyvern guilds are currently written by simply subclassing these two classes, and adding in a few customizations.However, you're not required to use this framework. You can create a Guild using Jython or Java and the Wyvern APIs, and it can work any way you like, provided that it gets approved by the Wyvern staff. We wouldn't recommend trying this, though, unless you have a good reason for it, and you're a very experienced programmer. The existing Guild framework is pretty flexible, and should give you a good jumpstart on your own Guild.
The Guild ClassThe Guild class provides the functionality joining and leaving the guild. The actual abilities for the guild are provided by a GuildSkills object.Usually, you don't have to create a subclass of Guild. You can just create an archetype for it that sets various properties that control joining the guild. The following table lists the properties you can set to configure your Guild. The Default Value column shows what the value will be if you don't explicitly set the property in your archetype.
Here's an example, the Paladins Guild, in a file called wiz/wyvern/guilds/paladins/paladins_guild.arch:
Note that in the case of the Paladins Guild, we actually did write a subclass of Guild, and it's referenced as the class for this archetype. Compare it to the (simpler) Archers Guild:
Notice that the Archers Guild is just a plain old Guild, and that it specifies a "guild-skills" property in the archetype. The PaladinsGuild also specifies a "guild-skills" property, but it does it in the class. Either way is fine, as long as you provide one.
The GuildSkills ClassThis is the heart of writing a Guild. All the Guild's abilities and penalties reside in this class.In our example, you'll get to walk through the construction of a fairly simple example guild, called the Coders Guild. It's written in Jython, and is, in fact, the first-ever Wyvern guild written in Jython. Just so you can get your eyes on it, take a look at the Coders Guild source code. We recommend opening up the source code in a separate window, so you can follow along while we go through it.
Coders GuildThe first thing you should do when designing a guild is, well, design the guild! Don't start coding until you know exactly how you want the guild to work. And then it's still not time to start coding yet — after you know how it will work, spend some time figuring out how it will work technically, and write that down as well.These two documents are known as the "Functional Spec" (how it will work for Players) and the "Technical Spec" (how you'll implement it in code). You should do these two docs for every object you write, even if it's just a few lines in the comment header for the class.
Coders Guild Func SpecIn order to keep you focused on the bare minimum required for a Guild, our Coders Guild doesn't do much. It gives you a new command, and it monitors your kills and decides whether you should get Guild XP for them.We should probably also note that we're getting some functionality "for free", simply by extending the GuildSkills class:
In deciding whether to award Guild XP, we'll check if the player is wielding a Pen at the time the monster died. We'll create a Pen class just for the guild — actually just an archetype. We can do all this simply by overriding some methods in the GuildSkills class, so we'll move on to the tech spec.
Coders Guild Tech SpecThis isn't a full technical spec, but it covers a few of the important details of creating the guild.First, here's the Pen archetype:
We can test to see if something is a Pen by calling Kernel.isInstance() on it. Our Guild will be very straightforward, so here it is:
Notice that we set the admission fee to 1 gold coin, to make it easy to test. Your guild will want to set appropriate values for admission-fee, min-level, and the other properties. To create new commands for players, you have to create an object that implements the Command interface. There's a tutorial on the Command interface, so we won't talk about it much here. All we have to decide is which object will implement the interface. The simplest approach might be to have our GuildSkills subclass implement it, but it's slightly clearer and more Object-Oriented to declare a nested class that implements the interface. We'll call it the code_command class. Note that the class names in Jython are like_this, and the Java class names are LikeThis. This is because Python and Java have different naming conventions, and we prefer to stick with each language's recommending naming convention while we're working in that language.
JythonBean InterfaceOur GuildSkills object is a "bean" property, meaning it's a named property whose value is a Java object, and not one of our standard types (string, int, boolean, double, etc.)Jython bean properties present a bit of a problem, because (due to some technical issues with the Jython language implementation that you probably shouldn't care about) you can't ask a Jython object what Java classes or interfaces it extends or implements. You have to tell it what class you're extending. This is an issue because we want Wyvern to be able to cast it to a GuildSkills object, so it can call the Java methods: startup(), shutdown(), getGuildName(), etc. The solution Wyvern has chosen is to provide a JythonBean interface, in which you return the name of the class or interface that you want to be known as on the Java side of the house. Note that you're required to implement this interface for all Jython Bean properties. They won't save and restore properly if you don't provide a valid Java classname, even if it's just "java.lang.Object". In our case, we're a GuildSkills, so that's what we'll return from the getJavaClass() method.
GuildSkills Required MethodsThe GuildSkills class has eleven abstract methods, meaning you are required to implement them in your subclass. In a nutshell, the methods are:
Even though there isn't much code for most of them, at least in the Coders Guild, we'll cover them each briefly so you know what they're supposed to do. startupThis method adds the guild abilities to the player. This happens at two different times:
shutdownThe opposite of startup, this method removes all special abilities (and penalties) from the player. It's called when the player logs out, or when the player permanently quits (or is fired from) the guild.
getGuildNameReturns the "official" guild name. Used whenever the game is referring to the guild. For instance, when a new member joins a guild, the Guildmaster will shout a message to all the members, saying "Foobaz has joined the Coders Guild!".Note that the " Guild" is not returned — the system will add that to the name that you return from this function.
getGuildShortNameReturns a short name for the guild — used in constructing messages such as: Foobaz coder-tells: hi everyone!In our case, we return "coder".
getGuildPluralNameSome guilds have different singular and plural names. Ours is the same: "Coders" for both.
getGuildTitleThis returns the generic, singular guild name to show in the High Score List or Who List. We return "Coder", so the Who list would show "Foobaz the High-Elven Coder".
getGuildTagThis returns a unique "tag-property" (just a boolean property), that tells the system we're in the Coders Guild. Tag props are almost of the form "wizname-shortname", e.g. "legolas-oldmage" or "rhialto-moonquest". In our case, we'll just call it "coders-guild", but in a real guild you'd want to put your wizard name in front, to avoid any collisions with identifiers from other Wizards.
getTitleThis method examines the player's Guild Level and returns an appropriate Guild-title for the player. This is almost always implemented just the way we did it, by having a table of 10 titles, and using the guild level to index into the table.Some guilds have different titles for male and female members. In this case, the guild would have two title-lists, and use the correct one based on the agent's gender.
getWhoCommandReturns the word to use for our Who command — in our case, "coderwho". We could have used anything at all, but this seemed most appropriate.
getTellCommandReturns the word to use for the guild-specific tell command, which can be used as an individual chat-channel or a group-chat channel. We return "codertell".
awardXPThis is the doozy.When a monster is killed, all of the group members who are in a Guild have their guild's awardXP() function called. That's this function. awardXP() looks at the group member, the monster that was killed, the weapon that was used, and/or other properties, and figures out whether it should award any guild experience to the group member. If we're going to award experience, we do it in this method. It's up to this method to decide how much guild XP to award. In most guilds, you get 1 guild XP for each regular XP, but you could define your own ratio. This function should return 1 if we awarded some guild XP. Pass: event — a TargetedEvent that encapsulates the final blow. It may or may not have actually killed the monster, but you should assume that it has, and you'll usually be right. The passed event can be null in some (rare) cases, so check if it's null and don't award any guild XP in that case. Properties set on the event include:
NOTE: "weapon" is the attack used by the player who killed the opponent, who is not necessarily the member getting awarded experience in this call. If the killer is different from the member, then you have no way of knowing if they used their guild skill to fight the monster. It's OK to assume that they did, though. For fighter classes, you can check the @attacks list on the member to see if they're wielding a weapon of the correct type, if you want. The event is reused to give XP to every group member, so don't modify the event — treat it as read-only. The property can be null, so make sure to do null checks on the values after you extract them from the event. There are additional comments in the source code, explaining some further nuances of how we decide what to do.
Putting It All TogetherIt'll take some careful study of this document and the Coders Guild source code before it all starts making sense.To get started, you can simply copy the source code into your own Guild source file, change the name of the class, and start changing the functions one at a time to do what you want your Guild to do.
Be sure to ask an Elder Wizard or Arch Wizard for help, if you're having difficulties.
|