:set x=command before topic should not crash
>reply:reply before topic should not crash
other lines before topic should not crash
because everything above =start is ignored.

===start
start (in this example) is just used to set up some variables
:set angry=Y
:set FriendList=|superman|spiderman|batman|wonderwoman|
:if (notexists(npcname)) then set npcname=NPC
:set brackets1=@[
:set brackets2=]@
:set ranvartest=
:set rannpcvars=
:set ransetvars=
:set raniftest=
:set ranbasiciftest=
:set ranifgoto=
:set ranpuppy1=
:set ranpuppy2=
:set ranpuppy=
:set rantreasuremap1=
:set rantreasuremap2=
:set rantreasuremap3=
:set rantreasure=
:set ranweight=
:set rangoto=
:set ransomeplaceelse=
:set rangotoloop=
:set ranfunctions=
:set ranbadweight1=
:set ranbadweight2=
:set ranbadweight3=
:set ranbadweight4=
:set ranbadweight5=
:set ranbadweight=
:set rantopicwithnodialog=
:set ranerrors=
:goto begin

All of the crazy ran variables are just to make it easy to tell you ran through all the tests.


===Begin
Hello @[playername]@, this is a test conversation.
Chose a reply to test various aspects of simple dialogs
:if ((@[rannpcvars]@==*) and (@[ransetvars]@==*)) then set ranvartest=*
:if ((@[ranbasiciftest]@==*) and (@[ranifgoto]@==*)) then set raniftest=*
:if ((@[ranpuppy]@==*) and (@[rantreasuremap]@==*)) then set ranweight=*
:if ((@[ransomeplaceelse]@==*) and (@[rangotoloop]@==*)) then set rangoto=*
:if ((@[rantopicwithnodialog]@==*) and (@[ranbadweight]@==*) then set ranerrors=*
>vartest:@[ranvartest]@ Test variables
>iftest:@[raniftest]@ Test :If to set things conditionaly based on variables values
>weight:@[ranweight]@ Test multiple possible outcomes (weighted topics)
>gototest:@[rangoto]@ Test GOTO functionality
>functions:@[ranfunctions]@ Test functions
>errors:@[ranerrors]@ Test to see if we can make simple_dialogs crash?
>hooks:Test Hooks

--------------------------------------------

===vartest
There are several variable functionalities to test.
Select from below to step through the list
>npcvars:@[rannpcvars]@ Test Variables set in the calling mod
>setvars:@[ransetvars]@ Test setting variables within the dialog itself
>begin:Back to the begining
>End

===npcvars
The below variables are set in TenPlus1 MOBS REDO.  A different implementation may not have these variables or may have different ones.
My name is @[npcname]@, and my owner is @[owner]@
my hunger is @[food]@, my state is @[state]@, and my health is @[health]@
:set rannpcvars=*
>setvars:@[ransetvars]@ Test setting variables within the dialog itself
>begin:Back to the begining
>End

===setvars
This conversation tests setting variables within the dialog itself

the variable location has been set to: @[location]@

The list variable should contain a list of superheroes, with the player name added (using the add function)
Are you on my Friend List? @[FriendList]@

The variable friendlist2 was set to the same as list, but batman was removed with the rmv function
friendlist2=@[friendlist2]@

the variable angry was set in a different topic, but can still be displayed here because variables live for as long as the npc lives.
Am I angry? yesno(@[angry]@)

And we have a compound, player specific variable:
@[brackets1]@playername@[brackets2]@.trust=@[@[playername]@.trust]@
:set ransetvars=*
:set location=mountaains
:set FriendList=add(FriendList,@[playername]@)
:set FriendList2=rmv(FriendList,batman)
:set @[playername]@.trust=High
>begin:Back to the begining
>End

--------------------------------------------

===iftest
the :if command allows you to operate any other command (set, goto, or hook) based on conditions.  Remember when using it that ALL conditions must be enclosed in parenthesis and that variables should be in @[brackets1]@brackets@[brackets2]@ if you want them replaced with their values
>basiciftest:@[ranbasiciftest]@ Test setting variables using :if
>ifgoto:@[ranifgoto]@ Test using if to goto another topic
>begin:Back to the begining
>End

===basiciftest
This dialog illustrates using the command :if to set variables

am I angry right now? yesno(@[angry]@)
The below "mood" line is based on the status of angry
@[mood]@

My friendlist is @[friendlist]@
Are you in my friendlist? YesNo(isinlist(FriendList,@[playername]@))

The below line changes based on both angry AND whether the player is in friendlist

And what do I think about you? *** @[friendstatus]@ ***

:set mood=I guess I'm just in a good mood
:if (@[angry]@==Y) then set mood=I'm in a lousy mood today
:if ( (@[angry]@==N) and (isinlist(FriendList,@[playername]@)) ) then set friendstatus=You are my very best friend!
:if ( (@[angry]@==N) and (isinlist(FriendList,@[playername]@)==0) ) then set friendstatus=Hmmm, I don't really know you.
:if ( (@[angry]@==Y) and (isinlist(FriendList,@[playername]@)) ) then set friendstatus=Some friend YOU are
:if ( (@[angry]@==Y) and (isinlist(FriendList,@[playername]@)==0) ) then set friendstatus=I HATE you!
:set ranbasiciftest=*

>angry:Make @[npcname]@ angry!
>happy:Make @[npcname]@ not angry.
>addplayer:Add @[playername]@ to friend list
>rmvplayer:Remove @[playername]@ from friend list
>ifgoto:@[ranifgoto]@ Test using if to goto another topic
>begin:Back to the begining
>End


===angry
Ohhh!  That makes me so ANGRY!  angry=@[angry]@
:set angry=Y
>basiciftest:back to Test setting variables using :if

===happy
Well, that was nice of you, I feel much better now!  angry=@[angry]@
:set angry=N
>basiciftest:back to Test setting variables using :if

===addplayer
Well, I guess I'll just put your name in my little black book as a friend.
:set FriendList=add(FriendList,@[playername]@)
>basiciftest:back to Test setting variables using :if

===rmvplayer
I am erasing your name from my little black book!  You are no longer my friend!
:set FriendList=rmv(FriendList,@[playername]@)
>basiciftest:back to Test setting variables using :if


===ifgoto
From here you can test the :if goto command.
My friendlist is @[friendlist]@
Are you in my friendlist? YesNo(isinlist(FriendList,@[playername]@))

When you select the reply "Where did you bury the treasure" below, it will take you to the topic treasuremap.
if playername is on the friendlist, you will stay at the treasuremap topic.
BUT, if playername is NOT on the friendlist, you will be taken to the "enemy" topic.
>treasuremap:Where did you bury the treasure?
>addplayer2:Add player to friend list
>rmvplayer2:Remove player from friend list
>begin:Back to the begining
>End

===TreasureMap
Shiver me Timbers, that be a bold request!  But, seeing how you are my friend, I suppose I can let you in on the secret.
:set ranifgoto=*
:if (notinlist(FriendList,@[playername]@)) then goto enemy
>ifgoto:back to testing if with goto

===Enemy
Keep your grubby paws off of me booty ye lily-livered, feculent, sorry sea dog!
:set ranifgoto=*
>ifgoto:back to testing if with goto

===addplayer2
Well, I guess I'll just put your name in my little black book as a friend.
:set FriendList=add(FriendList,@[playername]@)
>ifgoto:back to testing if with goto

===rmvplayer2
I am erasing your name from my little black book!  You are no longer my friend!
:set FriendList=rmv(FriendList,@[playername]@)
>ifgoto:back to testing if with goto


--------------------------------------------


===weight
Its possible to have multiple topics with the same name.  When you do, simple dialogs will choose randomly between them.
So, for example, this test npc has 2 topics for "puppy" and 3 topics "treasure"
The two topics for puppy do not have a weight, so if you select puppy below, there is a 50/50 chance of you getting either response.
BUT, the three topics for "treasure" are weighted.  That means the topics have a number after them like this:
  ==treasure(1)
  ==treasure(3)
  ==treasure(5)
So when you select "treasure" below, simple dialogs rolls a random number between 1 and 9.  If the result is 1, you get the first response.  If the result is 2, 3, or 4, you get the second.  And if the result is between 5 and 9 you will get the third one.
Try it below.
>puppy:@[ranpuppy]@ I want to pet the puppy!
>treasure:@[rantreasure]@ I want to look for treasure!
>begin:Back to the begining
>End

===puppy
The puppy shivers from tip of his nose all the way back to the tip of his tail and gives one sharp bark of pure joy.
:set ranpuppy1=*
:if (@[ranpuppy1]@@[ranpuppy2]@==**) then set ranpuppy=*
>puppy:@[ranpuppy]@ Pet the puppy again!
>weight:@[ranweight]@ Back to test multiple possible outcomes (weighted topics)
>begin:Back to the begining

===puppy
The puppy wags his tail and then runs around you in a circle, coming back to right in front of you, where it sits and waits anxiously for another petting!
:set ranpuppy2=*
:if (@[ranpuppy1]@@[ranpuppy2]@==**) then set ranpuppy=*
>puppy:@[ranpuppy]@ How can I resist?  I pet the puppy again of course!
>weight:@[ranweight]@ Back to test multiple possible outcomes (weighted topics)
>begin:Back to the begining

===treasure(1)
Well, hmmm.  Why not, you seem like a nice person @[playername]@.  I WILL give you the treasure map!
(this is the entry with treasure(1) you will only see it about 1 out of 9 times)
:set rantreasure1=*
:if (@[rantreasure1]@@[rantreasure2]@@[rantreasure3]@==***) then set ranweight=*
>treasure:@[ranweight]@ That is GREAT, now hand that map over!
>begin:Back to the begining

===treasure(3)
I don't think so.  That treasure is nothing but trouble.  I'm not just going to hand it over to some landlubber who will just get themselves lost looking for it.
(this is the entry with treasure(3) you will see it about 3 out of 9 times)
:set rantreasure2=*
:if (@[rantreasure1]@@[rantreasure2]@@[rantreasure3]@==***) then set ranweight=*
>treasure:@[rantweight]@ Will you give me the treasure if I ask PRETTY PLEASE?, With Sugar On Top?
>begin:Back to the begining

===treasure(5)
Nope, not a chance.  It's MY treasure, you will never get your grubby paws on it!
(this is the entry with treasure(5) you will see it about 5 out of 9 times, by far most often)
:set rantreasure3=*
:if (@[rantreasure1]@@[rantreasure2]@@[rantreasure3]@==***) then set rantreasure=*
>treasure:@[ranweight]@ I said give me the treasure map!
>begin:Back to the begining


--------------------------------------------


===gototest
This is a simple test of goto, you should not see this screen
>End
:goto someplaceelse

===someplaceelse
This is someplace else.  Whenever you go to gototest, it has a goto that takes you here.  So you never actually see gototest
:set ransomeplaceelse=*
>gototest:@[ransomeplaceelse]@ Back to the first gototest dialog, which will take you back here.
>gotoloop1:@[rangotoloop]@ Test a goto loop
>begin:Back to the begining
>End

===gotoloop1
This is gotoloop1, it goes to gotoloop2 (which goes to gotoloop1)
This will NOT form an enternal loop because simple_dialogs will automatically break out of the loop
:goto gotoloop2
>gotoloop1:@[rangotoloop]@ Test a goto loop
>begin:Back to the begining
>End

===gotoloop2
this is gotoloop2, it goes to gotoloop1 (which goes to gotoloop2)
This will NOT form an enternal loop because simple_dialogs will automatically break out of the loop
:set rangotoloop=*
:goto gotoloop1
>begin:Back to the begining
>gotoloop1:@[rangotoloop]@ Test a goto loop
>End


--------------------------------------------

===functions
This topic tests simple_dialog functions

petlist=@[petlist]@
gold=@[gold]@

(note that the add and rmv changes do not persist because I'm just displaying the result of the function, I am not reassigning the variable)

add (petlist,alligator)=add(petlist,alligator)
add (petlist,dog)=add(petlist,dog)
rmv (petlist,mouse)=rmv(petlist,mouse)
rmv (petlist,hippo)=rmv(petlist,hippo)
isInList (petlist,cat)=isinlist(petlist,cat)
isInList (petlist,hippo)=isinlist(petlist,hippo)
notInList (petlist,cat)=notinlist(petlist,cat)
notInList (petlist,hippo)=notinlist(petlist,hippo)
isSet (petlist)=isset(petlist)
isSet (nosuchvar)=isset(nosuchvar)
isNotSet (petlist)=isnotset(petlist)
isNotSet (nosuchvar)=isnotset(nosuchvar)
yesno (isinlist (petlist,cat))=yesno(isinlist(petlist,cat))
yesno (isinlist (petlist,hippo))=yesno(isinlist(petlist,hippo))
calc (2*(12/4)+1)=calc(2*(12/4)+1)
calc (@[brackets1]@gold@[brackets2]@*2)=calc(@[gold]@*2)
timeofday ()= timeofday()
timeofday (hours)= timeofday(hours) same as timeofday ()
timeofday (dayornight) = timeofday(dayornight)
timeofday (nightorday) = timeofday(nightorday) same as dayornight
:set petlist=|dog|cat|mouse|parakeet|
:set gold=42
:set ranfunctions=*
>begin:Back to the begining
>End
note that on the left I put a space between the function name and the open paren so it wont be processed as a function.
also you will see the bizzare gold variable which is a way to trick simple_dialogs into displaying @[gold]@ without
interpreting the variable.  (I need escape logic!)

--------------------------------------------

===hooks
Hooks are ways for you to call more advanced functionality from a dialog that goes beyond conversation with the npc.
For example, this test uses a hook that allows an npc who's owner has the teleport priv, to teleport people.
Hooks are called from simple_dialogs, but they are run in the entity mod, and security around hooks is entirely the responsibility of the entity mod.  For example, the example teleport hook in mods redo checks to see if the npc owner has teleport privs before it executes the teleport.
Test below:
>teleport:teleport to -500,3,-80
>begin:Back to the begining
>End
--- -496,3,-82

===teleport
If there is a working teleport hook, then you shouldn't see this screen because you teleport from here.
:hook teleport -500,3,-80
>hooks:Back to the hook screen
>begin:Back to the begining
>End


--------------------------------------------

===errors
This dialog's purpose it to try everything I can think of to make simple_dialogs crash.
how about using the calc function to divide by zero=calc(3/0)
or just crazy bad calc function with not mathematical symbols and bad variables=calc(M/3+@[doesnotexist]@-@[friendlist]@()(@[angry]@))
how about functions with messed up or incomplete parens add(rmv(calc(  and some other garbage here
next we will try variables that do not exist @[doesnotexist]@
variables that are not closed correctly @[badvariable@
nested bad variables will not crash, @[nested@[badvariable]@]@ @[nested@[friendlist]@]@
nor will recursive variable attempts @[var1]@ @[@[var3]@]@ @[var2]@ @[var4]@@[var5]@

below we will also have a bad command, empty set, bad set, and strange spacing in sets (var9 should equal 12: var9=@[var9]@<)
and some bad if statements
All of this should be ignored and none of it should cause a crash
:set var1=var2
:set var2=@[var1]@
:set var3=var1
:set var4=@[var
:set var5=5]@
:badcommand nothing here should matter
:
:set
:set =3
:set @[var6]@=calc(3/0)
:set var7=@[doesnotexist]@
:set var8=calc(isinlist()
:set  var9   = 12
:if
:if (@[var5]@>=x) then set
:if (@[var5]@<=x)
:if (@[var5]@>x) then badcommand
:if (@[doesnotexist]@==flaming@[doesnotexist]@@[var2]@@[var5]@ calc(3/0)) then
:if () then set x=3
:if then
:if (1==1) then goto
:if (1==1) then goto topicdoesnotexist
:if ( then set x=only open paren
:if ) then set x=only close paren
:if (badcondition) then set x=bad condition
:if )()( then set x=bad parens
:if (1=1) then set x=bad operator
:if (1==1) then
:if (1==1) set x=no then
:if timeofday(nightorday)=0 then set x=good example
:if timeofday(allskjfl)=0 then set x=dont crash on bad parameter
:if timeofday(1,2,3)=1 then set x=dont crash on multiple parameters
:goto
:goto topicdoesnotexist
:set test=exists(
:set test=yesno()
:set test=yesno(calc(5/0))
:set test=yesno(calc(3+2))
>topicwithnodialog:@[rantopicwithnodialog]@ Test if a topic with no dialog will crash
>topicwithbadweight:@[ranbadweight]@ Test a topic with a bad weight (there are 5 of them)
>topicwithnoreplies:Test if a topic with no replies will crash (you will not be able to return)
>topicwithnothing:Test if a topic with nothing in it at all will crash (you will not be able to return)
>topicwithcommandsbutnodialog: Test if a topic with commands but no dialog or replies will crash (you will not be able to return)
>doesnotexist:Test if a reply target pointing at a topic that does not exist will crash. (you will not be able to return)
>topicwithnothingeof:Test a topic at the end of file (you will not be able to return)
>begin:Back to the begining
>End
>begin:replies below this point test various bad replies
>
>:
>:reply but no target before the colon
>target but no colon
>End

===topicwithnoreplies
What happens if you have a topic with no replies?
(an END reply is automagically added)
===topicwithnothing
===topicwithnodialog
:set rantopicwithnodialog=*
>errors:@[ranerrors]@ back to primary error dialog
>begin:Back to the begining
>end:end
===topicwithcommandsbut no dialog
:set x=3
===topicwithboth commands and replies but no dialog
:set x=4
>errors:@[ranerrors]@ back to primary error dialog
>begin:Back to the begining
>end:end
===topicwithbadweight(not a number)
1 of 5, This topic had a weight of (not a number)
:set ranbadweight1=*
:if (@[ranbadweight1]@@[ranbadweight2]@@[ranbadweight3]@@[ranbadweight4]@@[ranbadweight5]@==*****) then set ranbadweight=*
>topicwithbadweight:@[ranbadweight]@ Test a topic with a bad weight (there are 5 of them)
>errors:@[ranerrors]@ back to primary error dialog
>begin:Back to the begining
>end:end
===topicwithbadweight(23
2 of 5, This topic had a weight of (23
:set ranbadweight2=*
:if (@[ranbadweight1]@@[ranbadweight2]@@[ranbadweight3]@@[ranbadweight4]@@[ranbadweight5]@==*****) then set ranbadweight=*
>topicwithbadweight:@[ranbadweight]@ Test a topic with a bad weight (there are 5 of them)
>errors:@[ranerrors]@ back to primary error dialog
>begin:Back to the begining
>end:end
===topicwithbadweight(
3 of 5, This topic had a weight of (
:set ranbadweight3=*
:if (@[ranbadweight1]@@[ranbadweight2]@@[ranbadweight3]@@[ranbadweight4]@@[ranbadweight5]@==*****) then set ranbadweight=*
>topicwithbadweight:@[ranbadweight]@ Test a topic with a bad weight (there are 5 of them)
>errors:@[ranerrors]@ back to primary error dialog
>begin:Back to the begining
>end:end
===topicwithbadweight()
:set ranbadweight4=*
:if (@[ranbadweight1]@@[ranbadweight2]@@[ranbadweight3]@@[ranbadweight4]@@[ranbadweight5]@==*****) then set ranbadweight=*
4 of 5, This topic had a weight of ()
>topicwithbadweight:@[ranbadweight]@ Test a topic with a bad weight (there are 5 of them)
>errors:@[ranerrors]@ back to primary error dialog
>begin:Back to the begining
>end:end
===topicwithbadweight)
:set ranbadweight5=*
:if (@[ranbadweight1]@@[ranbadweight2]@@[ranbadweight3]@@[ranbadweight4]@@[ranbadweight5]@==*****) then set ranbadweight=*
5 of 5, This topic had a weight of )
If this works correctly the weights should just be ignored.
>topicwithbadweight:@[ranbadweight]@ Test a topic with a bad weight (there are 5 of them)
>errors:@[ranerrors]@ back to primary error dialog
>begin:Back to the begining
>end:end
===topicwithnothingeof
