From DimensioneX
Jump to: navigation, search

How the guild system works - game: Underworld

The guilds system is a small application within the Underworld game, built thanks to two features of DimensioneX: the support for SET objects and the SaveSetting/LoadSetting instructions.

This article refers to version 6.9.5 of [Underworld], and to DimensioneX version 6.1.0.

If you have other versions of the software you could meet some inaccuracies. Being this article hosted on a WIKI site, you can correct errors by using the EDIT tab or eave comments by using the DISCUSSION tab.

1 the guilds room

Everything starts from a room ( guildroom ), that is where the application runs mostly.

I have created this special room (tower the south-west) and a specific character ( Lord Guilford ) who has the purpose to dispatch to the user a message in case he/she does something wrong.

ROOM guildroom
	NAME	Southwest room
	DESCRIPTION	This the room of the guards' captain. He knows about all existing Guilds.
	IMAGE S 	armoroom2.jpg
	PANEL pguilds

In this room we will manage the guilds, that's why in the definition of the room I have specified that it uses a special panel "pguilds" about which we will speak now

2 the panel

To make it possible to manage guilds, I have created an appropriate set of commands.

I defined a new panel of commands, pguilds , that is defined as follows:

PANEL pguilds VERSION OF default
	BUTTON guildcmd, "Do this: ", "Guild action", doGuildOperation
	DROPDOWN guildop, guildOps, join
	DROPDOWN guildsel, guildnames, 0

As it stands, it is derived from the default panel. We added two drop-down lists ( DROPDOWN control ). This is a new control that has been introduced in version 6.0.2 of DimensioneX, and it works like this (we see the guildop list first):

3 the drop-down list

The first ID, guildop is the dropdwn itself.

We don't have to worry about this ID until we have to read the player's input.

Second, we find a name of a SET, guildOps. This is fundamental because it should contain all the available choices, that is, all the commands that I am setting up for the users.

4 il set comandi

The guildOps command set could have been defined in the SETS section, but I found it more convenient to create it inside the onStart event, which is called automatically at the game's start. If you go and check it out, you will find out that this event's code is in the file named underworld.dxw:

guildOps = NewSet("0new=Start new guild,
1edt_logo=Change logo,
2edt_web=Change website,
3del=Delete my guild,
4ban=Ban a member,
5-=------(all users)------,
join=Join this guild:,
leave=Leave this guild:")

A SET is an associative array, and the NewSet function allows me to define it via a simple syntax: Elements are separated by commas and are key=value pairs.

The key is a unique identifier inside the set, I have made some of them starting with a number so to have a well defined ordering. The value is a string which is what the user will actually see in the drop-down list. The key is what I will have to check to discover what the user has chosen.

now, thanks to the DROPDOWN control this SET is automatically turned into a dropdown list.

5 the guilds set

Coming back to the pguilds panel, you see that there is a second drop-down control there. This is because for example, if the user wants to join a guild, he has to choose which one.

So I put a second drop-down, with the guilds' names. Here you see the used SET is called guildnames.

guildnames is a set that contains the guild names. I decided to use as keys the names of the guild founders, since each person can start no more than one guild a time. In this way it gets easy to see, for any given person, if he/she owns a guild.

guildnames is created this way:

	guildnames = NewSet()

which is called by the onStart event.

For the sharpest programmers: This instruction can be found in the commons.dxl file in the common_onStart Sub.

This contains all the initialisation code which is common to the several areas of Underworld. The guilds are valid for all areas in fact, while the operations on the guilds are allowed only in the castle area, that is why the initialisations of these sets are done in different places in the code. This however is not of much importance.

The above mentioned instruction creates and empty set.

The guilds application, which we will examine straight away (but we can already say that code lays is in the doGuildOperation() event), simply adds new guild names to the set when the user requests so.

6 the persistence

To avoid that guilds data, such as their names stored in guildnames, vanish when the game or is restarted we must save on disk these information.

To do this, in the procedure which actually represents the guilds application: doGuildOperation() - you will find it inside underworld.dxw- we use the following:

saveSetting "ctx_guildnames",guildnames

This saveSetting saves the whole set guildnames in a setting related to the game's context, which we will load back once the game is restarted. Please not that in the local onStart event we have got:

Call LoadContext() ' Reads game saved status from disk

Which is a call to a single function which is designed to load, at the game start, these context values with a number of getSetting. These will reconstruct the exact guilds situation as it was before game restart.

It is interesting to notice that saveSetting with the guilds data is performed only when necessary, that is when a guild operation is performed. The saveSetting is not performed a regular intervals in time. This is because saveSetting is a slow operation and causes performance degradation in the game, which is what we want to avoid.

7 the guilds application

The guilds management application is contained in a single procedure which handles the possible operations. This is done in the single event doGuildOperation() which you find in underworld.dxw.

This event is called (just see the pguilds panel) by menas of the guildcmd button. This is because - at least in the version we used - it is not enough to select a new value on a drop-down to make the form to be submitted. This can be made only via pressing a button, so that's why that button was inserted..

Finally, let's see the code:

EVENT doGuildOperation
	'Speak guildOps(input("guildOp"))
	Dim tmp = $
	If Int(tmp) > 0
		tmp = "_" + tmp ' fix for number nicks
	If input("guildOp") = "0new"
		If input("txtBox") <> ""
			If guildnames(tmp) <> null
				Speak guilford,$AGENT,"You already own a guild, sir."
			If $AGENT.Experience < $AGENT.mxe
				Speak guilford,$AGENT,"To found a guild requires more Experience, sir. Come back later."
			Dim s = guildSubscribed($AGENT)
			If s <> null
				Speak guilford,$AGENT,"You have to leave " + guildnames(s) + " first." 
			SetAdd guildnames,tmp,input("txtBox")
			saveSetting "ctx_guildnames",guildnames
			Speak guilford,$AGENT,"How do you want it to be named? Write it down."
	If input("guildOp") = "3del"
		If guildnames(tmp) = null
			Speak guilford,$AGENT,"You don't own any Guild, sir."
		If input("txtBox") <> "YES"
			Speak guilford,$AGENT,"Are you sure? Type YES and redo."
			Speak guilford,$AGENT,"Ok, no more " + guildnames($
			SetRemove guildnames,tmp
			SetRemove guildlogos,tmp
			SetRemove guildwebs,tmp
			SetRemove guildkills,tmp
			SetRemove guildsubscribers,tmp
	If input("guildOp") = "1edt_logo"
		If guildnames(tmp) = null
			Speak guilford,$AGENT,"You don't own any guild, sir."
		If input("txtBox") = ""
			Speak guilford,$AGENT,"Type logo URL and redo."
			Speak guilford,$AGENT,"Ok, sir. New logo for your guild!"
			SetAdd guildlogos,tmp,input("txtBox")
	If input("guildOp") = "2edt_web"
		If guildnames(tmp) = null
			Speak guilford,$AGENT,"You don't own any guild, sir."
		If input("txtBox") = ""
			Speak guilford,$AGENT,"Type web page's URL and redo."
			Speak guilford,$AGENT,"Ok, " + $ + ". Make that page to describe you guild's mission."
			SetAdd guildwebs,tmp,input("txtBox")
	If input("guildOp") = "4ban"
		If guildnames(tmp) = null
			Speak guilford,$AGENT,"You don't own any guild, sir."
		If input("txtBox") = ""
			Speak guilford,$AGENT,"Type the name of the member and redo."
			If Not(GuildUnsubscribe2(tmp,input("txtBox")))
				Speak guilford,$AGENT,"-" + input("txtBox") + "- is not a member of your guild, sir."
				Speak guilford,$AGENT,"Done, sir."
	If input("guildOp") = "join"
		If guildnames(tmp) <> null
			Speak guilford,$AGENT,"You cannot join a guild if you own one."
			Dim s = guildSubscribed($AGENT)
			If s <> null
				Speak guilford,$AGENT,"You have to leave " + guildnames(s) + " first." 
			Call GuildSubscribe(input("guildsel"),$AGENT)
			Speak guilford,$AGENT,"You now belong to " + guildnames(input("guildsel"))
	If input("guildOp") = "leave"
		If guildnames(tmp) <> null
			Speak guilford,$AGENT,"You cannot leave a guild if you own one, sir."
			Speak guilford,$AGENT,GuildUnsubscribe(input("guildsel"),$AGENT)
			$AGENT.guild = null
	If input("guildOp") = "5-"
	Call guildroom.onReceive
	saveSetting "ctx_guildnames",guildnames
	saveSetting "ctx_guildlogos",guildlogos
	saveSetting "ctx_guildsubscribers",guildsubscribers
	saveSetting "ctx_guildwebs",guildwebs
	saveSetting "ctx_guildkills",guildkills

Here we notice how a drop-down control works. The choice on the control called guildOp comes to the server in a pre-defined set named input, which contains all data sent by the commands panel. The keys of the input set are IDs of the controls of the panel, and their values are the entered values - in the case of the dropdown, the key of the chosen option -.

Still about the drop-down, the value that I will receive in input, is not what the user has seen (description) but the code (key) I specified in the set defining possible options. Go back and see section 4 above for a reference.

8 management of SET objects

To this point the guild management is fairly simple. To each command we have an IF branch and a sequence of operations to be executed, which are not quite complex.

Be careful: All data about guilds are in SETs whose keys are the names of the guild owners.

In the DimensioneX version we used (6.0.2) we cannot add a new element in a set this way:

myset("newkey") = "newvalue" 'will not work

but we must use the SetAdd instruction as you see in the source code. It is possible that this changes in the upcoming releases, but if you modify the code you have to remember about that because by using the above syntax you won't get errors nor any useful result, and you will be wondering why.

In a summary, the SETs used by guilds system are these ones (you will find them all in LoadContext() that is defined in commons.dxl)

Names of the guilds
Logos of the guilds (URL)
Semicolon ";" separated list of the names of the subscribers of each guild
web pages of each guild (URL)
killed enemies for each guild

The last one, guildkills, gets updated at each killed character and is stored bymeans of saveSetting each 4 minutes by means of careful use of the onTick event.

Please note that this update is based on the guild property that is set at the player's joining, with a check to see if the guilds he subscribed to is still existing - see the onNew() event.

9 mostrare i dati di gilda

Guilds data are displayed by means of the little function: getGuildBox(), defined in commons.dxl. This function requires you specify the name of the guild owner and if you want ot not to see the list of the subscribers with killed enemies data.

Function getGuildBox(owner,withmembers)
	Dim txt = ""
	Dim tmp
	Dim link1 = ""
	Dim link0 = ""
	If Int(owner) > 0
		owner = "_" + owner
	If guildwebs(owner) <> null
		link1 = "<A HREF=" + Chr(34) + "javascript:top.popupWin('" + guildwebs(owner) + "',-1,-1);" + Chr(34) + ">"
		link0 = "</A>"
	If guildlogos(owner) <> ""
		tmp = link1 + "<IMG SRC=" + guildlogos(owner) + " WIDTH=32 HEIGHT=32 ALIGN=MIDDLE BORDER=0>" + link0
	txt = txt + "" + tmp + link1 + guildnames(owner) + link0 + " founded by " + owner + ""
	If withmembers
		txt = txt + "
Members: " + Replace(guildsubscribers(owner),";",", ") txt = txt + "
Kills count: " + guildkills(owner) End_If Return txt End_Function

This function is repeatedly called with a loop each time we enter in the guilds room, so that all guilds are displayed:

EVENT guildroom.onReceive
	Dim txt="This the room of the guards' captain. He knows about all existing Guilds."
txt = txt + "
    " Dim i Dim owner For i = 1 To SetLen(guildnames) owner = SetKey(guildnames,i) txt = txt + "
  • " + getGuildBox(owner,true) Next txt = txt + "
	guildroom.description = txt

so that when I enter there I always see the updated situation.

Furthermore, the function is called also by the Info command button, which returns information about the player himself (find it in battlesystem.dxl).

Sub doCheckup()
	Dim item
	Dim name
	Dim s,guild
	s = guildSubscribed($AGENT)
	If s=null
		guild = "Guild: None."
		guild = getGuildBox(s,false)
	Print guild

First of all, by means of the guildSubscribed() function, this one checks to which guild you are subscribed to then it calls getGuildBox to print guild data out.

The getGuildBox itself is used in the onLook EVENT to provide this information about you when somebody looks at you.

10 Conclusions

The guilds system is a tiny application we built into Underworld that demonstrates how to use the following features of DimensioneX:

  • drop-down lists
  • SET
  • saveSetting/getSetting

moreover, it is perfectly compatible with the multi-area structure of the game, so it can be applied to all contexts. It would be possible, at this point, to add more elements to make the guild management more interesting for gameplay.

If you have comments or questions, you can either use the DISCUSSION tab on this page, or to post on our [Forum].