Guildsystem: Difference between revisions

From DimensioneX
Jump to navigation Jump to search
 
(19 intermediate revisions by the same user not shown)
Line 1: Line 1:
= How the guild system works - game: Underworld =
= 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: SET support and the SaveSetting/LoadSetting instructions.
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 [[http://www.dimensionex.net/underworld/ Underworld]], and to DimensioneX version 6.1.0.
This article refers to version 6.9.5 of [[http://www.dimensionex.net/underworld/ Underworld]], and to DimensioneX version 6.1.0.
Line 7: Line 7:
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.
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.


Good reading.
== 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 ==


This article has been translated by using Google and then corrected by hand.  
To make it possible to manage guilds, I have created an appropriate set of commands.
The translation is in progress so if you find some errors please come back tomorrow


== 1 the guilds room ==
I defined a new panel of commands, '''pguilds''' , that is defined as follows:


Everything starts from a room ( guildroom ), that it is that one where the application is concentrated.


For this I have created this appropriate room (tower the south-west) and an appropriate personage ( Lord Guilford ) that it serves to make to arrive to the customer the messages of error if for case mistakes something.
PANEL pguilds VERSION OF default
CR
CR
BUTTON guildcmd, "Do this: ", "Guild action", doGuildOperation
DROPDOWN guildop, guildOps, join
LABEL ""
DROPDOWN guildsel, guildnames, 0


ROOM guildroom NAME in the Tower Sud-Ovest DESCRIPTION This is the room of the captain of the guards.  It knows all the Gilde. IMAGE S armoroom2.jpg  PANEL pguilds In this room the gilde will be able to be managed, here why in the definition of the room I have specified that it uses a special panel "pguilds" about which we speak endured
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):


== 2 the panel ==
== 3 the drop-down list ==


Why it is possible to manage the system of the gilde, I have created an appropriate set of commandos.
The first ID, '''guildop''' is the dropdwn itself.  


In practical it serves to create a new panel of commandos, pguilds , that therefore it is defined:
We don't have to worry about this ID until we have to read the player's input.


PANEL pguilds VERSION OF default CR CR BUTTON guildcmd, "I give this:  ", "Guild action", doGuildOperation DROPDOWN guildop, guildOps, join LABEL "" DROPDOWN guildsel, guildnames, 0 Draft, as it is looked at of varying of the panel of default to which they have been added two lists to curtain ( drop-down ). This is a new control that has been introduced in version 6,0,2 of DimensioneX, that it works therefore (we see before the first list):
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.


== 3 the list to reduction ==
== 4 il set comandi ==
The first one id, guildop represents the same curtain.


Of this ID ce we do not have any to worry until does not arrive the moment to read the input of the customer.
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''':


It follows the name of a SET, guildops . This is fundamental why it will have to contain all the choices available, that is the commandos who I decide to make to use the customers.
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:")


= 4 the set commandos =
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 set of the commandos guildOps I could define it in section SETS, but it comes me more comfortable to define it in the event onStart , called to the loading of the game. If gone to control you will discover that this event is found in the rows it_underworld.dxw :


guildOps = NewSet("0new=Nuova gilda, to 1edt_logo=Cambiare logo, to èdt_web=Cambiare page web, to 3del=Cancellare the gilda, 4-=------(per all)------, to join=Entrare in this gilda:,  to leave=Abbandonare this gilda:") A SET is an associative Array, and the NewSet function me ago to define with one sintassi much simple one. The elements are separate to you from virgole and are braces chiave=valore.
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.


The key is a mnemonic code in which I have put a number for having a very precise ordering. The value is one tightens that he is that that the customer will see. The key is that one that I will have to control in order to discover that what the customer has chosen.
now, thanks to the DROPDOWN control this SET is automatically turned into a dropdown list.


well, thanks to control DROPDOWN this SET comes automatically transformed in one curtain.
== 5 the guilds set ==


== 5 the set of the gilde ==
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.


Returning to the panel pguilds you see that there is a second curtain. This why as an example, if the customer wants to enter in a gilda, he must also dirmi which.
So I put a second drop-down, with the guilds' names. Here you see the used SET is called '''guildnames'''.


Then I put a second curtain, with the names of the gilde. Here you see that 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 it is a set that contains the names of the gilde. I have thought to use like keys the names of the founders, inasmuch as every person can found to the maximum one gilda. In this way me he is simple, date a person, to see if it possesses or not one gilda.
'''guildnames''' is created this way:


guildnames it comes created with this instruction:
guildnames = NewSet()


  guildnames = NewSet() which always comes recalled from the event onStart.
which is called by the '''onStart''' event.  


For pignoli: This instruction the found ones in the rows it_commons.dxw in the sub common_onStart .
For the sharpest programmers: This instruction can be found in the '''commons.dxl''' file in the '''common_onStart''' Sub.


This contains all the code of common inzializzazione to the several areas of Underworld. The gilde they are worth in fact for all the areas, while the operations on the gilde I concur to them alone in the area of the castle, here explained why these initializations of set are in various places. But this however does not have much importance.
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 instruction of which over it creates an empty set.
The above mentioned instruction creates and empty set.  


The application of the gilde, that we will see between little (but already we say that is found in the event doGuildOperation() ), simply goes to add, behind demand for the customer, new names of gilda to the 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 ==
== 6 the persistence ==
In order to avoid that they give you of the gilde, between which the their names contained in guildnames , they vanish in null the every time that the game or the serveur comes riavviato is necessary to save these information in permanent way.


In order to make that, in the procedure that represents the true and own ' application of the gilde ', doGuildOperation() - the found ones within it_underworld.dxw , come used following:
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:


  saveSetting "ctx_guildnames", guildnames This saveSetting goes to save the entirety guildnames in a setting relative to the context of the game, than then it will come recharged in case of riavvio. Noticed in fact that in the local event onStart we have:
  Call LoadContext() ' Reads game saved status from disk


Call LoadContext() ' Reads game saved status from disk That it is exactly one called to a called function a single time to the start, that series of loadSetting contains one . They will go to reconstruct, between the other, give you of the gilde therefore com' were before the riavvio.
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.


Interesting E' to observe that the saveSetting with they give you of the gilde comes only executed when it is necessary, therefore only when an operation on the gilde has been executed, and not at intervals regular of time. This why, well-known, the saveSetting it implies an operation on disc that slows down the performances of the game, what that we want to avoid.
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 ==
== 7 the guilds application ==
As I said, the application of the management gilde is in an only procedure that is subdivided for the possible operations. This procedure is the event doGuildOperation() that we find in it_underworld.dxw.


This event comes recalled (to see the panel pguilds ) from the push-button guildcmd . This why - at least in the version of used DimensioneX - enough not to select a commando from the list to curtain why they give to you they come sendes you to the serveur. This can be made single through a push-button, here why I have had it to insert.
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 = $AGENT.name
If Int(tmp) > 0
tmp = "_" + tmp ' fix for number nicks
End_If
If input("guildOp") = "0new"
If input("txtBox") <> ""
If guildnames(tmp) <> null
Speak guilford,$AGENT,"You already own a guild, sir."
Return
End_If
If $AGENT.Experience < $AGENT.mxe
Speak guilford,$AGENT,"To found a guild requires more Experience, sir. Come back later."
Return
End_If
Dim s = guildSubscribed($AGENT)
If s <> null
Speak guilford,$AGENT,"You have to leave " + guildnames(s) + " first."
Return
End_If
SetAdd guildnames,tmp,input("txtBox")
saveSetting "ctx_guildnames",guildnames
Else
Speak guilford,$AGENT,"How do you want it to be named? Write it down."
Return
End_If
End_If
If input("guildOp") = "3del"
If guildnames(tmp) = null
Speak guilford,$AGENT,"You don't own any Guild, sir."
Return
End_If
If input("txtBox") <> "YES"
Speak guilford,$AGENT,"Are you sure? Type YES and redo."
Else
Speak guilford,$AGENT,"Ok, no more " + guildnames($AGENT.name)
SetRemove guildnames,tmp
SetRemove guildlogos,tmp
SetRemove guildwebs,tmp
SetRemove guildkills,tmp
SetRemove guildsubscribers,tmp
End_If
End_If
If input("guildOp") = "1edt_logo"
If guildnames(tmp) = null
Speak guilford,$AGENT,"You don't own any guild, sir."
Return
End_If
If input("txtBox") = ""
Speak guilford,$AGENT,"Type logo URL and redo."
Else
Speak guilford,$AGENT,"Ok, sir. New logo for your guild!"
SetAdd guildlogos,tmp,input("txtBox")
End_If
End_If
If input("guildOp") = "2edt_web"
If guildnames(tmp) = null
Speak guilford,$AGENT,"You don't own any guild, sir."
Return
End_If
If input("txtBox") = ""
Speak guilford,$AGENT,"Type web page's URL and redo."
Else
Speak guilford,$AGENT,"Ok, " + $AGENT.name + ". Make that page to describe you guild's mission."
SetAdd guildwebs,tmp,input("txtBox")
End_If
End_If
If input("guildOp") = "4ban"
If guildnames(tmp) = null
Speak guilford,$AGENT,"You don't own any guild, sir."
Return
End_If
If input("txtBox") = ""
Speak guilford,$AGENT,"Type the name of the member and redo."
Else
If Not(GuildUnsubscribe2(tmp,input("txtBox")))
Speak guilford,$AGENT,"-" + input("txtBox") + "- is not a member of your guild, sir."
Else
Speak guilford,$AGENT,"Done, sir."
End_If
End_If
End_If
If input("guildOp") = "join"
If guildnames(tmp) <> null
Speak guilford,$AGENT,"You cannot join a guild if you own one."
Else
Dim s = guildSubscribed($AGENT)
If s <> null
Speak guilford,$AGENT,"You have to leave " + guildnames(s) + " first."
Return
End_If
Call GuildSubscribe(input("guildsel"),$AGENT)
Speak guilford,$AGENT,"You now belong to " + guildnames(input("guildsel"))
End_If
End_If
If input("guildOp") = "leave"
If guildnames(tmp) <> null
Speak guilford,$AGENT,"You cannot leave a guild if you own one, sir."
Else
Speak guilford,$AGENT,GuildUnsubscribe(input("guildsel"),$AGENT)
$AGENT.guild = null
End_If
End_If
If input("guildOp") = "5-"
Return
End_If
Call guildroom.onReceive
saveSetting "ctx_guildnames",guildnames
saveSetting "ctx_guildlogos",guildlogos
saveSetting "ctx_guildsubscribers",guildsubscribers
saveSetting "ctx_guildwebs",guildwebs
saveSetting "ctx_guildkills",guildkills
END_EVENT


Finally we see the code:


EVENT doGuildOperation ' Speak guildOps(input("guildOp")) If input("guildOp") = "0new" If input("txtBox") < > "" If guildnames($AGENT.name) < > null Speak guilford,$AGENT," you have already founded one gilda, to messere."  Return End_If If $$AGENT.Esperienza < 14 Speak guilford,$AGENT, "To found a gilda demands greater Experience, getlteman.  Returned later."  Return End_If Dim s = guildSubscribed($AGENT) If s < > null Speak guilford,$AGENT, "You must leave" + guildnames(s) + ", before."  Return End_If SetAdd guildnames, $AGENT.name, input("txtBox") saveSetting "ctx_guildnames", guildnames Else Speak guilford,$AGENT," As it will be called?  Scrivetelo, to messere."  Return End_If End_If If input("guildOp") = "3del" '...  End_If If input("guildOp") = "4 -" Return End_If Call guildroom.onReceive saveSetting "ctx_guildnames", guildnames saveSetting" ctx_guildlogos", guildlogos saveSetting "ctx_guildsubscribers", guildsubscribers saveSetting" ctx_guildwebs", guildwebs saveSetting "ctx_guildkills", guildkills END_EVENT Here we notice as the control to curtain works: the control that calls guildOp me arrives in with from the predefined name that it is called input, that contains all gives sendes to you from the panel commandos to you. The keys of the entirety are the ID of the controls specify to you, and the values are the values immessi - in the case of the curtain, the chosen value.
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 -.


Always speaking about the curtain, the value that returns to me behind is not the description that the customer has seen, but the code that I have used like key. We go see again section "4" here over for a reference.
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 the management of the set ==
== 8 management of SET objects ==
To this point the management of the gilde is enough simple. To every commando it corresponds an arm of if and a sequence of operations to execute, than they are not granché complex.


Attention but: all they give you relati you to the gilde are in of the SET whose keys are the names of the owners of the gilde.
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.


In this version of DimensioneX (6,0,2) it is not possible to in this way insert a new element in a set:
Be careful: All data about guilds are in SETs whose keys are the names of the guild owners.


mioset("nuovachiave") = "new value"
In the DimensioneX version we used (6.0.2) we cannot add a new element in a set this way:


but the SetAdd instruction must be used like is looked at in the source. It can give that to this thing changes in the next versions, but if modified the code you must be remembered some why using the sintassi here over you do not obtain errors but not even no result, and will pass hours to ask to you because it does not work.
myset("newkey") = "newvalue" 'will not work


After all, the used set from the system gilde is these (found all to them in LoadContext() defined in the rows it_commons.dxl)
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.


guildnames
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 gilde
guildlogos
loghi of gilde (the URL)
guildsubscribers
list separated from ";" of the names of the enrolled one for every gilda
guildwebs
situated web of gilde (the URL)  
guildkills
conteggio of the killings for every gilda
This last one, guildkills , comes dawned to every killing and comes saved through saveSetting every 4 minuteren taking advantage of the onTick.


To notice that this modernization makes confidence on the property guild that the customer has to the income, previo control (it is not said that from the last time that you have played the gilda it still exists!) - to see event onNew()  
;guildnames: Names of the guilds
;guildlogos: Logos of the guilds (URL)
;guildsubscribers: Semicolon ";" separated list of the names of the subscribers of each guild
;guildwebs: web pages of each guild (URL)
;guildkills: killed enemies for each guild


== 9 Show guilds data ==
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.


They give you of the gilde are shown through the funzioncina getGuildBox() , defined in it_commons.dxl . To this function enough to say who he is the wished owner of the gilda and if she wants or not to see also the list of the enrolled one with they give you of the killings.
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.


Function getGuildBox(owner, withmembers) Dim txt = "" Dim tmp Dim link1 =" "Dim link0 =" "If guildwebs(owner) < > null link1 =" < To HREF=javascript:top.popupWin(' "+ guildwebs(owner) +" ', -1, -1); > "  link0 = "</To >" End_If If guildlogos(owner) < > "" tmp = link1 +" < IMG SRC = "+ guildlogos(owner) +" WIDTH=32 HEIGHT=32 ALIGN=MIDDLE BORDER=0 > "+ link0 End_If txt = txt + tmp +"  "+ link1 + guildnames(owner) + link0 founded + " from  "+ owner +"  "If withmembers txt = txt +"Members:  "+ guildsubscribers(owner) txt = txt +"Combatt. won:  "+ guildkills(owner) End_If Return txt End_Function Questa funzioncina viene richiamata opportunamente con un bel ciclo ogni volta che si entra nella stanza delle gilde:
== 9 mostrare i dati di gilda ==


EVENT guildroom.onReceive
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.
Dim txt="Questa è la stanza del capitano delle guardie. Lui conosce tutte le Gilde."
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
END_EVENT
cosicché quando entro ho sempre la situazione aggiornata.  


Inoltre la funzione è chiamata anche dal comando Info che restituisce informazioni sul giocatore stesso (definita in it_battlesystem.dxl).
Function getGuildBox(owner,withmembers)
Dim txt = ""
Dim tmp
Dim link1 = ""
Dim link0 = ""
If Int(owner) > 0
owner = "_" + owner
End_If
If guildwebs(owner) <> null
link1 = "<A HREF=" + Chr(34) + "javascript:top.popupWin('" + guildwebs(owner) + "',-1,-1);" + Chr(34) + ">"
link0 = "</A>"
End_If
If guildlogos(owner) <> ""
tmp = link1 + "<IMG SRC=" + guildlogos(owner) + " WIDTH=32 HEIGHT=32 ALIGN=MIDDLE BORDER=0>" + link0
End_If
txt = txt + "<B>" + tmp + link1 + guildnames(owner) + link0 + "</B> founded by <B>" + owner + "</B>"
If withmembers
txt = txt + "<BR>Members: " + Replace(guildsubscribers(owner),";",", ")
txt = txt + "<BR>Kills count: " + guildkills(owner)
End_If
Return txt
End_Function


Sub doCheckup()
This function is repeatedly called with a loop each time we enter in the guilds room, so that all guilds are displayed:
Dim item
Dim name
Dim s,guild
s = guildSubscribed($AGENT)
If s=null
guild = "Gilda: Nessuna."
Else
guild = getGuildBox(s,false)
End_If
Print guild
      ...
Questa prima di tutto tramite la funzione guildSubscribed() va a vedere a quale gilda sei iscritto poi chiama la getGuildBox per stamparne i dati.


La stessa getGuildBox viene usata nell'evento onLook per fornire questa informazione su di te quando uno ti guarda.  
EVENT guildroom.onReceive
Dim txt="This the room of the guards' captain. He knows about all existing Guilds."
txt = txt + "<UL>"
Dim i
Dim owner
For i = 1 To SetLen(guildnames)
owner = SetKey(guildnames,i)
txt = txt + "<LI>" + getGuildBox(owner,true)
Next
txt = txt + "</UL>"
guildroom.description = txt
END_EVENT


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."
Else
guild = getGuildBox(s,false)
End_If
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 ==


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


Il sistema delle gilde è una mini-applicazione costruita dentro Underworld che dimostra efficacemente come usare le seguenti caratteristiche di DimensioneX:
* drop-down lists
* SET
* saveSetting/getSetting


tendine drop-down
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.  
SET
saveSetting/loadSetting
in più la cosa è perfettamente compatibile con la struttura multi-area del gioco, quindi può essere applicabile in tutti i contesti. E' fattibile a questo punto aggiungere altri elementi per rendere la gestione più interessante.  


In caso di commentie domande, consiglio di postare sul nostro Forum.
If you have comments or questions, you can either use the DISCUSSION tab on this page, or to post on our [[http://www.dimensionex.net/en/forums.asp Forum]].

Latest revision as of 05:59, 10 February 2006

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


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)

guildnames
Names of the guilds
guildlogos
Logos of the guilds (URL)
guildsubscribers
Semicolon ";" separated list of the names of the subscribers of each guild
guildwebs
web pages of each guild (URL)
guildkills
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
	End_If
	If guildwebs(owner) <> null
		link1 = "<A HREF=" + Chr(34) + "javascript:top.popupWin('" + guildwebs(owner) + "',-1,-1);" + Chr(34) + ">"
		link0 = "</A>"
	End_If
	If guildlogos(owner) <> ""
		tmp = link1 + "<IMG SRC=" + guildlogos(owner) + " WIDTH=32 HEIGHT=32 ALIGN=MIDDLE BORDER=0>" + link0
	End_If
	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
END_EVENT

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."
	Else
		guild = getGuildBox(s,false)
	End_If
	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].