###########################################################################
## Talk System v 0.8  - by Masklin Jun-2003
###########################################################################

                                                English version by Prospero



Description.
---------------------------------------------------------------------------

The Talk System (TS) is a module that makes it possible to add dialogue 
among characters to the Blade maps 


The basic objective has been to build an independent module that  can be
added easily to any map, by liberating the programmer from the control of
the conversations. It is only necessary to design and to write the flow
of the conversation: TS will take charge of the rest.  

This is a Readme, not a manual. Maybe someday there will be better 
documentation. But, at the moment, TS is an internal Mod for Moria...



Interface.
---------------------------------------------------------------------------

TS adds a new key to Blade (the key T by default that allows the player to begin 
a conversation with the facing NPC. If there is not nobody in the surroundings or 
the NPC doesn't have any associated conversation (or is out of the available 
ones), then TS shows random monologues defaulted by the programmer.

If the NPC has a associated dialogue there begins a conversation.  The dialogue 
can show, optionally, several alternative answers. The user will be able to navigate 
among the different answers with the right mouse button and activate 
the chosen answer by pressing the left mouse button. One answer can conclude the 
conversation or continue with new dialogue.

The text is sometimes too long to visualize it in the frame. If so you will
be able to use PgUp/PgDown or the mouse wheel to scroll the text. 

In these situations an arrow is shown at the end indicating that the text is not
complete.

The selected answer will be marked by the symbol '> ' and it will be of a 
different color. We can navigate to another answer by using Tab or R-Click. 
Press Enter or L-Click to confirm the answer.


The complete keyboard map is the following: :

	T 		To begin a conversation

	PgUp 		Scroll up
	WheelUp 

	PgDown 		Scroll down
	WHeelDown  

	Tab 		Next answer
	R-Click

	Enter 		Select answer
	L-Click

	Esc 		Cancel conversation


TS also adds a Journal that is activated with the key "J" (by
default). The programmer can use this Journal to show the most interesting 
information in the conversations. Press key "J" to test the Journal system.


General operations.
---------------------------------------------------------------------------

The programmer designs one or several dialogues for each NPC. Then, he uses the 
function     
    
	Talk.Assign (pers.Name, 'Hello')    
    
to assign to the character pers.Name the identified (dlgId) of the initial 
dialogue: in the example 'Hello.' Each NPC keeps its dlgId in its Data 
structure. When the character comes close to the player and he presses the   
speaking key, TS is enabled and triggers  the associated dialogue. The programmer 
no longer has to intervene during the dialogue until it's conclusion.  

The data structure of TS is quite flexible and we can enlarge if it is 
necessary. TS takes charge of everything but the programmer can intervene if 
need be.



Making a dialogue.
---------------------------------------------------------------------------

The dialogue is stored in data structures defined in a python file.  By 
default, these files are in the directory TS inside the current map folder. 
Maybe there can be a sub-folder for each language so TS loads the dialogue 
corresponding to the current language.  

A map can store all the dialogue in an single file or create a file for each 
situation. This will depend on the quantity and duration of the conversations. 
In principle you could manage hundreds of conversations, so the the 
performance is a factor to consider.  

Each dialogue is identified by an code selected by the programmer: dlgId. This 
dlgId is unique for each character. The structure of the conversations is 
complex and it is explained in the example included (example.py).



Assignment of a dialogue.
---------------------------------------------------------------------------

Once you create a database with the dialogue to use in TS you must import:

	import Talk

and load the dialogues:

	Talk.Load ('example')

Now, you assign the dlgId of the initial dialogue after create the NPC:

	kt=Bladex.CreateEntity("Khor Tao","Knight_N", 0,0,0, "Person")
	kt.Angle=1.63607286472
	kt.Life=100
	import Basic_Funcs
	kt.Data=Basic_Funcs.PlayerPerson(kt)
	kt.Data.ResetSounds("Khor Tao")
	Talk.Assign (kt.Name, 'Hello')

The name of the entity NPC, Khor Tao in the example, is important because TS 
uses it to find the corresponding dialogue. In the database you can have more 
than one dialogue with the dlgId 'Hello', but only one associated to Khor Tao.

The name also appears in the conversation. Don't use names like Ork_234 and 
similar.

Once you have created the NPC's and with their starter dlgId assigned, the player can 
begin his adventure and start a conversation with the NPC's just by pressing the 
speaking key.    

As will see later, the dialogue can also be triggered by events. Also, the 
programmer will be able to call at any moment the function Talk.Say to start 
a conversation.

Often, you  want to make it so that a NPC begins a conversation when he sees the 
player. For that reason, the function Assign admits a third optional argument: 
the event that triggers the conversation. At the moment there is only one
supported event: the NPC sees the player and it is indicated with Talk.SeeEvent:

	Talk.Assign (kt.Name, 'I have seen you', Talk.SeeEvent)

The NPC doesn't begin to speak until the player comes within 
Talk.TSTalkRange (5 meters by default) and he can see the player. The NPC 
doesn't recover its standard SeeFunc function until the conversation 
concludes.




The basic behavior.
---------------------------------------------------------------------------

In the design of the conversation it is possible to indicate the different 
answers associated to each text of a conversation. For each selected answer
you assign the next dialogue.   

The chosen answers by the player are disabled so that they don't appear in the 
conversations again.

To conclude a conversation you define a dialogue without answers. This way TS 
knows that the conversation has finished. Optionally you can indicate what the 
following dialogue will be if the player speaks with the NPC again. This way the 
programmer has freedom to make it so that the conversations don't repeat.
  
You can use variables in the conversations so you can create dialogue of the 
type 'Welcome %Playername' or 'I see that you take the shield %Shieldname'. The 
names of the variables and their value are fixed by the programmer.

You can use an additional attribute, NewDlg,  indicating the dialogue that the 
character will begin next time that  he speaks. If you want him not to speak 
more you will set to None.

An interesting  option is  the attribute  ExtraDlg that  allows to add extra dialogues
to a conversation to simulate  the intervention of other NPJs. A  dialogue
can  have  an entrance  ExtraDlg  with two  fields:  the name  of  the PNJ  that
intervenes and the text. This dialogue is included between the original dialogue
and the admitted answers:

        'ExtraDlg': ['FuManChu 2',
             """I like to bother! ...""",

Sometimes you can offer  several alternative answers  so when the  player chooses one
then  the other  answers are  no longer  valid. To  get this  you must  use the
attribute DisableAns. An answer can have this attribute with a list of  answers
that will be disabled:  

        'DisableAns': ['No', 'A veces', 'Muy a menudo']

The  last dialogue  doesn't contain  answers and, therefore, TS  shows the  text
during a time before being disabled. As  we will see, this time is specified  by
the global parameter TSHideDelay. However, for some texts  the default value can
be modified by using HideDelay:

        'HideDelay': 7

To make conversations with more than a simultaneous flow is a bit more  complex.
For  that, TS  introduces the  attribute ReplaceAns  that allows you  to indicate  a
substitution order for a determined answer. This way, if in a  dialogue we
indicate:

        'Answers': ['Mountains'],
	'ReplaceAns':{'Mountains':['What it happened','And later']}

then,  if when  this dialogue is triggered the answer 'Mountains' is already
disabled (usually because the player selected it previously) TS will
offer the answer 'What it happened'. If  this answer is not valid, then TS uses
'And later'. Combining answers this way, one can obtain a quite rich dialogue.   

Talk System offers  a callback system so the programmer can carry out actions
during  a  conversation. As TS takes the control during the flow of the
conversation, the programmer only recovers the control at the end.  

For that reason, TS introduces a  system to be  able to make  a callback before
certain answers or dialogues. If a callback functionf has been  defined for an answer 
or dialogue then TS  will call to this function when the player  selects
the answer or when the NPC says  the dialogue. This way, the programmer will  be
able to carry out actions as  to open doors, to reproduce sounds,... or even  to
modify the conversation dynamically.    
  
This function should be declared with two arguments: personName and ansId/dlgId
and it should be defined in DefFuncs.py. Also, each function must be registered
by calling to AddCallBackFunc function:  

	AddCallBackFunc ('MiFunction', MiFunction)

where 'MiFunction' it is the name that has been given in the attribute  CallBack
and  MiFunction is the function  proper. Obviously, the function  has to  be
defined  before  calling  to  AddCallBackFunc. It is  also  important  that the
functions are registered directly in DefFuncs.py. In this way we make sure  that
the correct functions are indexed when we load a savegame.

For performance, TS doesn't carry out any confirmation of the structure of the 
database supposing that all the flow is correct. To help to debug errors, TS 
includes a function that  carries out a validation of the basic flow of the 
conversation:

	Talk.Load ('example')
	Talk.Validate ()

You can also set Talk.Debug=1 to show additional debug messages.


Journal System.
---------------------------------------------------------------------------


TS includes a system to register the most important data in a
conversation. The user can press the key 'J' to show a Journal with this
information.

The programmer should previously define the Journal's entries in the
same file in which the conversations are loaded. To enable a Journal 
entry this function it is used:

        AddToJournal (jrlId)

where jrlId is the key used to identify the entry:

        AddToJournal ('FindOrcs')

When a new entry is added the player is warned with a small book that
appears on the screen. If you wants to disable this warning use:

        AddToJournal ('FindOrcs', Talk.NoWarning)

The entries are added sequentially to the Journal and they are not
deleted unless the programmer calls to the routine:

        RemoveFromJournal (jrlId)

The Journal is driven with similar keys to the conversations, 
although its behavior is simpler.

In the dialogues and in the answers you can add an attribute Journal
so that automatically TS adds the requested entry to the Journal when
the dialogue is shown or when the answer is selected. This is the
preferred method to add entries to the Journal:

        'Journal': 'BuscaOrco'

Last, a function is included to clear the whole Journal:

        ClearJournal ()


Controlling the conversation.
---------------------------------------------------------------------------

The programmer may want more control over the flow of some conversations. This
is possible thanks to the methods that TS makes public.    

To begin the conversation associated to personName use this function:

	Say (personName)
	Say ('FuManChu')

If you don't want to change the conversation assigned to a NPC but you want  him
to begin a different dialogue:

	Say (personName, dlgId)
	Say ('FuManChu', 'Help me')

To define a variable: 

	SetVar (name, value)
	SetVar ('WeaponName', OrcoCabreado.InvRight)

To get the current value of a variable:

	GetVar (name) return value
	wName = GetVar ('WeaponName')

To clear all defined variables:

	ClearVars ()


TS disables all the answers used by the player. You can enable an answer  again
with:  

	AnswerEnable (person, ansId)
	AnswerEnable ('FuManChu', 'Soy pesao')

this way TS shows this answer again in the dialogue.

It is also possible to disable an answer although the player has not yet seen
it:

	AnswerDisable (personName, ansId)
	AnswerDisable ('FuManChu', "It doesn't make sense")

for example, as reply to a event.

You can change dynamically the dialogue as well as the answers:

SetDialog (personName, dlgId, text, answers=None)
SetAnswer (personName, ansId, text, nextdlgId=None)

Perhaps, the most  useful modification is  to change the  text to adapt it as a
function of the events:

	SetDialog ('FuManChu', 'Later I return', 'Wait for me, I go to for tobacco')

but you can also change dynamically the flow of a conversation if necessary.


Finally, if you want to use the  interface of Talk System to show a  message you
can use the function ShowMessage:

        ShowMessage (Text, HideDelay=TSHideDelay)

For example, to show the message for 15 seconds duration:

        ShowMessage ("his is a message", 15)

To hide the interface you must use:

	Hide()
	
You can change some bitmaps with the function:
     
	SetBitMap (Name, File)

The bitmap's names are:
	
	TSBarra1, TSBarra2 y TSBarra3 for the text background.
	TSJournal: for the Journal background.
	TSWarning: for the Journal warning icon.
	
	
For example, to change the bitmap of Journal warning use:

	SetBitMap ('TSWarnig', 'MyBook.bmp')
	

Configurable parameters.
---------------------------------------------------------------------------

In TS it is possible to change some parameters to adapt it to our map:  

* MMP with the used textures as background of the dialogues. The
  textures are three of type TrueColourAlpha: Barra1, Barra2 and
  Barra3, corresponding to the left area, center and right of the background.    
  For the Journal use TSJournal and TSWarning for the warning book.
  TSmmp            = "../../Data/TSWidgets.mmp"
  It's not possible to modify this variable dynamically because TS 
  is loaded before DefFuncs and the Widgets is created to the beginning.  
* Text fonts.
  TSFont        = "../../Data/letras menu med.bmp"
  It's not possible to modify this variable dynamically because TS 
  is loaded before DefFuncs and the Widgets is created to the beginning.  
* Dialogues color.
  ColorDlg         = 207,144,49
* Answer color.
  ColorAns         = 207,144,49
* Selected answer color.
  ColorAnsSelected = 252,247,167
* Max number of lines.
  MaxLines         = 8
* Right margin.
  RMargin          = 66
* Horizontal position of dialogues.
  TextXBase        = 35
* Vertical position (starting point) of dialogues.
  TextYBase        = 300
* Line text vertical size.
  TextYSize        = 14
* Similar parameters for the Journal System: 
  jMaxLines, jRMargin,jTextYBase,jTextYSize,jTextXBase 
  ColorjTitle, ColorjText, ColorjTextSelected  
* Minimum range so that a NPC begins a conversation.
  TSTalkRange      = 5000
* Time in seconds that it takes in disappearing the interface
  of TS after showing last dialogue.
  TSHideDelay      = 10
* Max. distance to a NPC to begin a conversation.
  SelectNPCArea    = 10000

You can group the configuration parameters in an optional script  called 
TSCustom.py. If TS finds this script in the current map folder, it executes it. 
It's python, you can use any python code in this scritpt. Also, it's possible to 
modify TSmmp and TSFont settings.  

An example.
---------------------------------------------------------------------------

With the distribution of this Mod a small conversation example is included.  It
is only  necessary to  copy the  file TestTS.py  and the  directory TS (with the
whole structure) in the directory of any map. Then  you must edit TestTS.py  and
change the start coords of the Ork so that they are adjusted to your map.

Load the map and from the console:

	execfile ('TestTS.py')

You will see an ork with which  you will be able to begin several  conversations
by pressing the speaking key (T).  

If you like to test the behavior with Talk.SeeEvent you  have uncomment the
corresponding line in TestTS.py and to move away from the start position of  the
Ork before executing it.  


To test the Journal systen press J key.

Revision history
---------------------------------------------------------------------------

Please read spanish Leeme.txt for revision details.

