Difference between revisions of "Tutorial for code structure"

From XStoryPlayer Wiki
Jump to: navigation, search
Line 246: Line 246:
 
These say that the current line has ended
 
These say that the current line has ended
 
<syntaxhighlight lang="cpp">
 
<syntaxhighlight lang="cpp">
state.dyn.me.do.changingcases = NEXT;</syntaxhighlight>  
+
state.dyn.me.do.changingcases = NEXT;
 +
</syntaxhighlight>  
 
And thats it do this
 
And thats it do this
 
Without the ;
 
Without the ;
 
<syntaxhighlight lang="cpp">
 
<syntaxhighlight lang="cpp">
state.dyn.me.do.changingcases = NEXT</syntaxhighlight>  
+
state.dyn.me.do.changingcases = NEXT
 +
</syntaxhighlight>  
 
This line never ends and will result in an error
 
This line never ends and will result in an error
  
Line 295: Line 297:
 
You can add in custom timers but i will not cover this because most people wont need them
 
You can add in custom timers but i will not cover this because most people wont need them
 
<syntaxhighlight lang="cpp">
 
<syntaxhighlight lang="cpp">
loc.ts = GetTs();  loc.</syntaxhighlight> stands for local which means this is only stored inside this innercase
+
loc.ts = GetTs();  loc.
 +
</syntaxhighlight>
 +
  stands for local which means this is only stored inside this innercase
  
So <syntaxhighlight lang="cpp">loc.ts</syntaxhighlight> is a varaible we are setting it could be <syntaxhighlight lang="cpp">loc.howyagoingm8</syntaxhighlight>  but ts is eaiser because we know what it means timeset or something like that
+
So
 +
<syntaxhighlight lang="cpp">
 +
loc.ts
 +
</syntaxhighlight>
 +
  is a varaible we are setting it could be <syntaxhighlight lang="cpp">loc.howyagoingm8</syntaxhighlight>  but ts is eaiser because we know what it means timeset or something like that
  
  
<syntaxhighlight lang="cpp">GetTs();</syntaxhighlight> is a function in another file somewhere that gets the game time
+
<syntaxhighlight lang="cpp">
 +
GetTs();
 +
</syntaxhighlight>
 +
is a function in another file somewhere that gets the game time
  
So we are saying that <syntaxhighlight lang="cpp">loc.ts</syntaxhighlight> is whatever the current gametime is
+
So we are saying that
 +
<syntaxhighlight lang="cpp">
 +
loc.ts
 +
</syntaxhighlight>
 +
is whatever the current gametime is
 
this next part is a condition
 
this next part is a condition
  
if <syntaxhighlight lang="cpp">loc.ts</syntaxhighlight> is less then the current time then go back up the top
+
if  
<syntaxhighlight lang="cpp">[loc.ts < state.dyn.me.do.ts] return;</syntaxhighlight>  
+
<syntaxhighlight lang="cpp">
 +
loc.ts
 +
</syntaxhighlight>
 +
is less then the current time then go back up the top
 +
<syntaxhighlight lang="cpp">
 +
[loc.ts < state.dyn.me.do.ts] return;
 +
</syntaxhighlight>  
  
The inner case will stay the same but it will reset and run the <syntaxhighlight lang="cpp">loc.ts</syntaxhighlight> again and the time will update until  
+
The inner case will stay the same but it will reset and run the
 +
<syntaxhighlight lang="cpp">
 +
loc.ts
 +
</syntaxhighlight>
 +
again and the time will update until  
  
<syntaxhighlight lang="cpp">loc.ts</syntaxhighlight> is greater then the time then it will no longer return back to the start
+
<syntaxhighlight lang="cpp">
<syntaxhighlight lang="cpp">[loc.ts < state.dyn.me.do.ts] return;</syntaxhighlight>  
+
loc.ts
 +
</syntaxhighlight>
 +
is greater then the time then it will no longer return back to the start
 +
<syntaxhighlight lang="cpp">
 +
[loc.ts < state.dyn.me.do.ts] return;
 +
</syntaxhighlight>  
  
 
Then it will run the code under it which in our case is
 
Then it will run the code under it which in our case is
  
  <syntaxhighlight lang="cpp">state.dyn.me.do.timersarefun = START2;</syntaxhighlight>  
+
<syntaxhighlight lang="cpp">
+
state.dyn.me.do.timersarefun = START2;
and that will move it to the next innercase
+
</syntaxhighlight>  
 
 
theres 2 main timers  
+
and that will move it to the next innercase
<syntaxhighlight lang="cpp">do_set_timer(6);
+
 
do_set_timer2(6);
+
theres 2 main timers  
 +
<syntaxhighlight lang="cpp">
 +
do_set_timer(6);
 +
do_set_timer2(6);
 
[loc.ts < state.dyn.me.do.ts] return;
 
[loc.ts < state.dyn.me.do.ts] return;
[loc.ts < state.dyn.me.do.ts2] return;</syntaxhighlight>  
+
[loc.ts < state.dyn.me.do.ts2] return;
 +
</syntaxhighlight>  
 
These timers dont work well with other timers but very raly will 2 timers be needed
 
These timers dont work well with other timers but very raly will 2 timers be needed
 
Now this is a bit more advanced but ill add it anyway
 
Now this is a bit more advanced but ill add it anyway
  
 
I found this works well if you need multiple timers running at the same time
 
I found this works well if you need multiple timers running at the same time
<syntaxhighlight lang="cpp">[loc.ts >= state.dyn.me.do.ts]
+
<syntaxhighlight lang="cpp">
 +
[loc.ts >= state.dyn.me.do.ts]
 
{
 
{
  
Line 342: Line 377:
 
</syntaxhighlight>  
 
</syntaxhighlight>  
 
Then we can do some more
 
Then we can do some more
<syntaxhighlight lang="cpp">[loc.ts == state.dyn.me.do.ts & state.dyn.me.do.timersarefun == START2 ]</syntaxhighlight>  
+
<syntaxhighlight lang="cpp">
 +
[loc.ts == state.dyn.me.do.ts & state.dyn.me.do.timersarefun == START2 ]
 +
</syntaxhighlight>  
 
if loc.ts is equal to ts and timersarefun is equal to START2  
 
if loc.ts is equal to ts and timersarefun is equal to START2  
  
<syntaxhighlight lang="cpp">[loc.ts == state.dyn.me.do.ts | state.dyn.me.do.timersarefun == START2 ]</syntaxhighlight>  
+
<syntaxhighlight lang="cpp">
 +
[loc.ts == state.dyn.me.do.ts | state.dyn.me.do.timersarefun == START2 ]
 +
</syntaxhighlight>  
 
if loc.ts is equal to ts or timersarefun is equal to START2  
 
if loc.ts is equal to ts or timersarefun is equal to START2  
  
 
But wait theres even more
 
But wait theres even more
 
<syntaxhighlight lang="cpp">
 
<syntaxhighlight lang="cpp">
state.dyn.me.do.playwithvalues = 1;</syntaxhighlight>  
+
state.dyn.me.do.playwithvalues = 1;
 +
</syntaxhighlight>  
 
This sets playwithvalues to whatever is set
 
This sets playwithvalues to whatever is set
 
<syntaxhighlight lang="cpp">
 
<syntaxhighlight lang="cpp">
state.dyn.me.do.playwithvalues += 1;</syntaxhighlight>  
+
state.dyn.me.do.playwithvalues += 1;
 +
</syntaxhighlight>  
 
This adds a the value to the exsisting varaible
 
This adds a the value to the exsisting varaible
 
<syntaxhighlight lang="cpp">
 
<syntaxhighlight lang="cpp">
state.dyn.me.do.playwithvalues -= 1;</syntaxhighlight>  
+
state.dyn.me.do.playwithvalues -= 1;
 +
</syntaxhighlight>  
 
This subtracts the value to the exsisting varaible
 
This subtracts the value to the exsisting varaible
 
<syntaxhighlight lang="cpp">
 
<syntaxhighlight lang="cpp">
state.dyn.me.do.playwithvalues *= 1;</syntaxhighlight>  
+
state.dyn.me.do.playwithvalues *= 1;
 +
</syntaxhighlight>  
 
This multiplys the value of the exsisting variable by whatever is set
 
This multiplys the value of the exsisting variable by whatever is set
 
<syntaxhighlight lang="cpp">
 
<syntaxhighlight lang="cpp">
state.dyn.me.do.playwithvalues /= 1;</syntaxhighlight>  
+
state.dyn.me.do.playwithvalues /= 1;
 +
</syntaxhighlight>  
 
This divides the value of the exsisting variable by whatever is set
 
This divides the value of the exsisting variable by whatever is set
  
 
<syntaxhighlight lang="cpp">
 
<syntaxhighlight lang="cpp">
state.dyn.me.do.playwithvalues ^= state.dyn.me.do.valuedoesnotexsist;</syntaxhighlight>  
+
state.dyn.me.do.playwithvalues ^= state.dyn.me.do.valuedoesnotexsist;
 +
</syntaxhighlight>  
 
This ones a little bit diffrent it sets a value even if it does not exsist
 
This ones a little bit diffrent it sets a value even if it does not exsist
  
We can even do things like this<syntaxhighlight lang="cpp">
+
We can even do things like this
 +
<syntaxhighlight lang="cpp">
 
state.dyn.me.do.playwithvalues = state.dyn.me.do.somevalue;
 
state.dyn.me.do.playwithvalues = state.dyn.me.do.somevalue;
state.dyn.me.do.playwithvalues += state.dyn.me.do.somevalue;</syntaxhighlight>  
+
state.dyn.me.do.playwithvalues += state.dyn.me.do.somevalue;
 +
</syntaxhighlight>  
  
 
Ok lets move on to getting them to talk
 
Ok lets move on to getting them to talk
  
 
This is the basic talk function
 
This is the basic talk function
<syntaxhighlight lang="cpp">talk.s = "hello";</syntaxhighlight>  
+
<syntaxhighlight lang="cpp">
 +
talk.s = "hello";
 +
</syntaxhighlight>  
  
 
There are ways we can control this
 
There are ways we can control this
Line 382: Line 431:
 
talk.dur  = 6000;//Time in milliseconds 1000 milliseconds is 1 second
 
talk.dur  = 6000;//Time in milliseconds 1000 milliseconds is 1 second
 
talk.delay = 4000;
 
talk.delay = 4000;
</syntaxhighlight>  
+
</syntaxhighlight>  
 
We can even use a case to control what is said
 
We can even use a case to control what is said
 
<syntaxhighlight lang="cpp">
 
<syntaxhighlight lang="cpp">
Rnd(3);</syntaxhighlight> This is a function to randomly select a value between the set number
+
Rnd(3);
 +
</syntaxhighlight>
 +
This is a function to randomly select a value between the set number
 
0 is included so its 0 1 2 but (3)
 
0 is included so its 0 1 2 but (3)
 
 
<syntaxhighlight lang="cpp">
+
<syntaxhighlight lang="cpp">
 
     loc.rnd = Rnd(3);
 
     loc.rnd = Rnd(3);
 
     case (loc.rnd)
 
     case (loc.rnd)
Line 406: Line 457:
  
 
It adds 1 to the count variable and adds a 5 second timer and goes back up the top and will do this until we change the state which will happen when the count reaches 4 then the condition will be met and it will move to the next innercase
 
It adds 1 to the count variable and adds a 5 second timer and goes back up the top and will do this until we change the state which will happen when the count reaches 4 then the condition will be met and it will move to the next innercase
<syntaxhighlight lang="cpp">
+
<syntaxhighlight lang="cpp">
 
[START]
 
[START]
 
{  
 
{  
Line 446: Line 497:
 
}
 
}
 
</syntaxhighlight>  
 
</syntaxhighlight>  
Thats it for now the rest you will have to figure out on your own my susgestion is to open every game file you can and see how things are done
+
Thats it for now the rest you will have to figure out on your own my suggestion is to open every game file you can and see how things are done
  
All i had was the tutorials that XPA did and the rest iv lernt by either tinkering around or asking  
+
All i had was the tutorials that XPA did and the rest iv learned by either tinkering around or asking  
  
If you need help feel free to ask on the forums but try to figure it out first you dont learn by people doing it for you
+
If you need help feel free to ask on the forums but try to figure it out first you don't learn by people doing it for you

Revision as of 03:12, 13 January 2016

Eskarn's tutorial for code structure

This is an introduction on how to code in XStoryPlayer The coding language is based off C++

I strongly recommend using Notepad ++ its awesome

I am in no way a master of this stuff but the tutorial should help


PDF VERSION


There will be no pictures and I'm not going to focus on story's but rather the code involved

Where to start

Each character in the game has a run.dat

<*state_run>
 
res = true;
 
case (state.dyn.me.do.state)
{
  [RUN0] run0_state();
  [RUN1] run1_state();
  [RUN2] run2_state();
  [RUN3] run3_state();
  [RUN4] run4_state();
}
 
</state_run>

This file keeps running the set state in this case it will be [RUN0] until changed and that will happen when the story progresses

If it did not keep running the function we would not be able to do things like timers and the whole game would just stop well the characters atleast

So we are currently running run0_state which is in another file

run0_state.dat

<run0_state> <- opening
code goes in here
</run0_state> <- closing

i think these would be called functions im not to sure but im gonna call em functions

Everything between the opening function line and the closing function line will run when we tell it to

Now we move onto cases

Cases go in functions and give us more control

Cases can be called whatever you want past the do and every case needs an opening bracket and a closing bracket { }

This tells the engine that the case is between the brackets Without a opening bracket the case would never have anything in it Without a closing bracket the case would never end

Both ending in errors

case (state.dyn.me.do.whateveryouwanttocallit)
 
{ <- opening bracket
 
} <- closing bracket

So we have a case what now

Now we can add in i really dont know what to call em but im gonna go with innercase

case (state.dyn.me.do.whateveryouwanttocallit)
 
{ <- opening bracket
 
 [NONE]
  { <- opening bracket
 
  } <- closing bracket
 
} <- closing bracket

Now we still need an opening bracket and a closing bracket { } to tell the innercase what belongs in it

This is where having a organised system to your code helps This examples a little bit pointless because there's only 2 opening brackets and 2 closing brackets

But when you have 50 opeing and 49 closing brackets its really hard to find the missing one


This is my system and it works for me and this code ill explain that a bit later

Here is an example of non orgnised code It's chaos but again its a small scale example some of my dunegon files are 4k lines

But as you can see its hard to tell where the brackets are and what is happening So lets clean it up

case (state.dyn.me.do.orgsystem)
{
[NONE]
{
  [more code bits]
		{
 
  bla bla bla code bla code
  [even more code]
 
   ya more code
	}
  [wow more code]
  {
 
 
	bla code
  }
}
  [NEXT]
  {
		[more code bits]
		{
 
 bla bla bla code bla code
	[even more code]
 
   ya more code
		}
  [wow more code]
  {
 
 
	bla code
  }
 
 
 
  }
}

My system is below it looks a lot more cleaner and all the brackets line up so you can see if you are missing one and using notepad ++ it shows the connecting brackets

Now im using tabs to move the code across and this is not the best practice because some programming languages do not recognize tabs or they do different things and break

My brother who is a coder uses 3 spaces instead of tab but because this programming language does not care i'm using tabs

Moral of the story is to use what you are comfortable with and what works with the current programming language you are working on

case (state.dyn.me.do.orgsystem)
{
 
[NONE]
 
	{
 
	[more code bits]
 
		{
 
		bla bla bla code bla code
 
		[even more code]  
 
			{
 
			ya more code
 
			}
		}
 
	[wow more code]
 
		{
 
		bla code
 
		}
	}
 
[NEXT]
 
	{
 
	[more code bits]
 
		{ 
 
		bla bla bla code bla code
 
		[even more code]
 
			{
 
			ya more code
 
			}
		}
 
	[wow more code]
 
		{
 
	bla code
 
		} 
	}
}

So by now you should know how to structure your brackets { }


Now onto moving between innercases We can call the innercases whatever we want so long as they are all in capitals

We are at [NONE] and we want to move to [NEXT]

So we will use

state.dyn.me.do.changingcases = NEXT;
state.dyn.me.do.changingcases = BOOBIES1234;
 
case (state.dyn.me.do.changingcases)
{
[NONE]
	{
 
	}
[NEXT]
	{
 
	}
[BOOBIES1234]
	{
 
	}
}

Now we have semicolons ;;;;;;;;;

These say that the current line has ended

state.dyn.me.do.changingcases = NEXT;

And thats it do this Without the ;

state.dyn.me.do.changingcases = NEXT

This line never ends and will result in an error

Now to actually change the case we would need to trigger something so lets introduce timers

case (state.dyn.me.do.timersarefun)
{
[NONE]
 
	{
 
  	do_set_timer(6);
	state.dyn.me.do.timersarefun = START;
 
	}
 
[START]
 
	{ 
 
	loc.ts = GetTs();  
	[loc.ts < state.dyn.me.do.ts] return;
 
   	state.dyn.me.do.timersarefun = START2;
 
	}
 
[START2]
 
	{
 
	}
 
}

First part of the timers are setting the time duration

do_set_timer(6);

do_set_timer is a function in another file and we are giving it the infomation of (6) this is seconds


You can add in custom timers but i will not cover this because most people wont need them

loc.ts = GetTs();  loc.
 stands for local which means this is only stored inside this innercase

So

loc.ts
is a varaible we are setting it could be
loc.howyagoingm8
but ts is eaiser because we know what it means timeset or something like that


GetTs();

is a function in another file somewhere that gets the game time

So we are saying that

loc.ts

is whatever the current gametime is this next part is a condition

if

loc.ts

is less then the current time then go back up the top

[loc.ts < state.dyn.me.do.ts] return;

The inner case will stay the same but it will reset and run the

loc.ts

again and the time will update until

loc.ts

is greater then the time then it will no longer return back to the start

[loc.ts < state.dyn.me.do.ts] return;

Then it will run the code under it which in our case is

state.dyn.me.do.timersarefun = START2;

and that will move it to the next innercase

theres 2 main timers

do_set_timer(6);
do_set_timer2(6);
[loc.ts < state.dyn.me.do.ts] return;
[loc.ts < state.dyn.me.do.ts2] return;

These timers dont work well with other timers but very raly will 2 timers be needed Now this is a bit more advanced but ill add it anyway

I found this works well if you need multiple timers running at the same time

[loc.ts >= state.dyn.me.do.ts]
{
 
}

Next is operators

[loc.ts == state.dyn.me.do.ts] if loc.ts is equal to ts
[loc.ts != state.dyn.me.do.ts] if loc.ts is  not equal to ts
[loc.ts > state.dyn.me.do.ts] if loc.ts is greater then ts
[loc.ts >= state.dyn.me.do.ts] if loc.ts is greater then or equal to ts
[loc.ts <= state.dyn.me.do.ts]if loc.ts is less then or equal to ts

Then we can do some more

[loc.ts == state.dyn.me.do.ts & state.dyn.me.do.timersarefun == START2 ]

if loc.ts is equal to ts and timersarefun is equal to START2

[loc.ts == state.dyn.me.do.ts | state.dyn.me.do.timersarefun == START2 ]

if loc.ts is equal to ts or timersarefun is equal to START2

But wait theres even more

state.dyn.me.do.playwithvalues = 1;

This sets playwithvalues to whatever is set

state.dyn.me.do.playwithvalues += 1;

This adds a the value to the exsisting varaible

state.dyn.me.do.playwithvalues -= 1;

This subtracts the value to the exsisting varaible

state.dyn.me.do.playwithvalues *= 1;

This multiplys the value of the exsisting variable by whatever is set

state.dyn.me.do.playwithvalues /= 1;

This divides the value of the exsisting variable by whatever is set

state.dyn.me.do.playwithvalues ^= state.dyn.me.do.valuedoesnotexsist;

This ones a little bit diffrent it sets a value even if it does not exsist

We can even do things like this

state.dyn.me.do.playwithvalues = state.dyn.me.do.somevalue;
state.dyn.me.do.playwithvalues += state.dyn.me.do.somevalue;

Ok lets move on to getting them to talk

This is the basic talk function

talk.s = "hello";

There are ways we can control this

talk.dur   = 6000;//Time in milliseconds 1000 milliseconds is 1 second
talk.delay = 4000;

We can even use a case to control what is said

Rnd(3);

This is a function to randomly select a value between the set number 0 is included so its 0 1 2 but (3)

    loc.rnd = Rnd(3);
    case (loc.rnd)
    {
	    [0] talk.s = "random0";
	    [1] talk.s = "random1";
	    [2] talk.s = "random2";
    }

So what we are saying here is loc.rnd is a number between 0-2 and the case is what ever number that loc.rnd is then the whatever that number is the innercase will run

Here's another example but a bit more controlled

So this starts in start and set the count variable then make s 6 second timer and moves to START2

When it gets to START2 it waits till the 6 seconds are over then says say0

It adds 1 to the count variable and adds a 5 second timer and goes back up the top and will do this until we change the state which will happen when the count reaches 4 then the condition will be met and it will move to the next innercase

[START]
{ 
state.dyn.me.do.count = 0;    
do_set_timer(6); 
state.dyn.me.do.state2 = START2;
 
}
 
[START2]
{
loc.ts = GetTs();  
[loc.ts < state.dyn.me.do.ts] return;
 
case (state.dyn.me.do.count)
	{
	[0] talk.s = "say0";
	[1] talk.s = "say1";
	[2] talk.s = "say2";
	[3] talk.s = "say3";
	[4] talk.s = "say4";
	}
 
	[state.dyn.me.do.count == 4]
		{
 
		state.dyn.me.do.state2 = NEXT;
 
		}
state.dyn.me.do.count += 1;
do_set_timer(5);
 
}	
 
 
[NEXT]
{ 
 
}

Thats it for now the rest you will have to figure out on your own my suggestion is to open every game file you can and see how things are done

All i had was the tutorials that XPA did and the rest iv learned by either tinkering around or asking

If you need help feel free to ask on the forums but try to figure it out first you don't learn by people doing it for you