Replacing all instances of a function

Started by Scarab, Tue 06/10/2009 17:26:41

Previous topic - Next topic

Scarab

Just thought I might pick some brains before I dive back in and try to take a second try at this...

I was wondering if there was a way to create a function which built upon other functions that already occur within the script, specifically, replacing Say() with SayAt().
Firstly, I'm assuming that dialog functions run through Say() (not some other function which do not appear in the editor), and there's currently no way to change this. (If I am wrong, stop me now)

I was thinking something along the lines of
Code: ags

bool CharacterTalking
string FromSay
if (CharacterTalking==true){
//somehow access the string...
string FromSay="blah";//the contents of the Say() string
}

and then access this file for the contents which can then be placed into
Code: ags

character.SayAt(0,280,300,"%s",FromSay);


I understand that my way is unlikely to work with my rudimentry understanding of coding, but I was just wondering if there was some way to run dialog scripts indirectly through the SayAt command (even through the File function perhaps? Not sure how to use them yet) :-[

Peace
Scarab

RickJ

I don't fully understand  precisely what you are trying to accomplish  but I can help with a couple of points.

Dialogs
I am not sure but I don't think the builtin dialog system uses the Say(_) function.   Any commonality they have is likely at amuch lower level and only accessable from within the AGSruntime itself.

Extender Functions
There is a feature called extender functions.  There are good examples in the manual.  Essentially you create a function like this:
Code: ags

*** Script Header ***
function SayIt(this Character*, String text);

import 
*** Global Script ***
function SayIt(this Character*, String text) {
   // put any code you want here to get or manipulate the string
   String it = String.Format("It says: %s",text);
   
   // The "this" pointer accesses what ever character is talking
   this.Say(it);
}

*** Room Script ***
function some_functio_or_another() {
   // Make ego say "It says: Hello world"
   cEgo.SayIt("Hello world");
}


The parameter declaration "this Character*" is a pointer to the character who is talking. This function can then be used just like any other Character function (or moreproperly method).   When the functionis called in the room script as shown above  pointer parameterisfilled in automatically by ags.

Conclusion
I'm not sure what you are trying to do exactly but it will probably entailcreating a custom dialog system.

monkey0506

What version of AGS are you using? In the most recent versions it's possible to add "normal" script directly within a dialog script so long as the normal script lines are preceded with whitespace. So if you want to specify exact co-ordinates with SayAt instead of using the internally calculated co-ordinates you could change your dialog script from (for example) something like this:

Code: ags
@1 // Hi Bob. - with "Say" checked on the left, the player will say this line normally
BOB: Hi Frank.
FRANK: What have you got for sale today?
BOB: Let's take a look...
// blah blah


To something like:

Code: ags
@1 // Hi Bob. - with "Say" UNchecked on the left we can use SayAt instead
  cFrank.SayAt(0, 280, 300, "Hi Bob.");
BOB: Hi Frank.
  cFrank.SayAt(0, 280, 300, "What have you got for sale today?");
BOB: Let's take a look...
// blah blah


Is that what you're wanting to do?

Scarab

Quote from: monkey_05_06 on Tue 06/10/2009 20:34:05
What version of AGS are you using?

3.1.2

Quote from: monkey_05_06 on Tue 06/10/2009 20:34:05
Is that what you're wanting to do?
Quote from: RickJ on Tue 06/10/2009 18:12:12
I'm not sure what you are trying to do...

Im sorry if I'm not coming across clearly, what I am trying to do is find a way to run SayAt() through the dialog system. I see how Monkey's method would work , however it requires each parameter to be entered every time, but because these parameters never change, surely there's a way of making it easier.

I just looked up Extender functons, which appear to be able to get around this to an extent;
Code: ags

function SayNew(this character*,string Dialog){
this.SayAt(0,280,300,"%s",Dialog);
}


Hopefully achieving:

Code: ags

cEGO.SayNew("How appropriate...");  //?



Which would cut out having to add in the extra parameters every time, but finding a way to run this from:

Code: ags
Ego: How appropriate...


...is what I'm aiming for.


Quote from: RickJ on Tue 06/10/2009 18:12:12
...a custom dialog system.

How exactly would I go about this? and how extensive would the process be?
The reason I'm being so picky about this is because I feel that any time that features of a code are repeated, it's wasted space, and I feel like I'm cheating the player or something...
I guess I just don't like cutting corners and want to make this script as neat as possible. ;D

I hope I managed to make sense. If not, third time's a charm :P

peace
scar

Khris

Unfortunately, what you want to do isn't possible.
The "workaround", coding a custom dialog system, is a LOT of work.

RickJ

You've got the right idea about how to apply the extender functions to your situation and combine them with monkey's solution.   The only other thing I can suggest that may help you get closer to your goal without creating a custom dialog system is to play around a bit with #define in the script header.   You may be able to do some clever things like this:

Code: ags

*** Script Header ***
#define :`` .SayAt((0,280,300,"
#define `` ");

*** Dialog ***
cEGO:`` How appropriate... ``                             // This would be the same as the next line
cEGO.SayAt(0, 280, 300, "How appropriate...");


In the above example .SayAt((0,280,300," is substituted for the 3 characters :`` and "); is substituted for the 2 characters ``. The resulting line then contains cEGO.SayAt(0, 280, 300, "How appropriate..."); which is what thecopmpiler sees.

Creating a custom dialog system, IMHO, would be a lot of work and is probably not worth it in your case.   You can already achieve the end result you desire and are, at this point only trying to simplify the necessary code and to give it a clean appearance.  

Just to satisfy everyone's curiosity, a cutom dialog system could be constructed in a number of ways.   One way to approach this problem is to use an interpreter to execute each dialog function or operation.  
A GUI would be used to display the results of such operations and to take user imnputs (i.e. selecting options).  A struct capable of holding the necessary information for any of the functions or operations could be defined.   This definition could then be used to create a data array containing dialog scripts.

Next a parser would be needed that could read your custom dialog script and populate the data array with the corresponding data.  Optionally the parser could output the results to a binary file which is then loaded into data array.  With the second option the ASCII file wouldn't need to be shipped with the game , only the binary which would be a little more difficult to hack.  

Instead of using a parser to read an ASCII file to populate the data array a series of function calls could be used.   For example there could be a character extender function called Dialog() and a function called DialogOption().   So in a module you could put something like the followingin an init function of some sor.

Code: ags

   DialogOption(0);
      cEgo.Dialog("Hello World");
      DialogOption(2, false);
   DialogOption(1);
      cEgo.Dialog("Goodbye World");
      DialogOption(2, true);
   DialogOption(2);
      cEgo.Dialog("What...You again");  
 

and with some macro trickery such as this
  #define @0 DialogOption(0);
  #define @1 DialogOption(1);
  #define @2 DialogOption(2);
  #define 2-on  DialogOption(2,true);
  #define 2-off  DialogOption(2,false);
  #define : .Dialog("
  #define ` ");

you could end up with script code that looked like this
Code: ags

@0
      cEgo: Hello World '
     2-off 

@1
      cEgo: Goodbye World '
     2-on 

@2
      cEgo: What...You again '


I suppose it's also possible for the parser to generate actual AGS script code, perhaps in the form of a module .   In this case the parser is in effect a dialog compiler that would be run before the AGS compiler is run.   The interpreter would of course not be needed in this case.

I am sure that there are many other approaches to implementing a custom dialog system.  I am also fairly certain that the apove approach is fraught with pitfalls and unforeseen difficulties.  But I think there is enough there for you aor anyone who is interested to get an idea of the scope and magnitude of the task andsome ideas of how to begin the process.

monkey0506

Quote from: RickJ on Wed 07/10/2009 10:00:12You've got the right idea about how to apply the extender functions to your situation and combine them with monkey's solution.

Quote from: Scarab on Wed 07/10/2009 06:29:28I see how Monkey's method would work , however it requires each parameter to be entered every time, but because these parameters never change, surely there's a way of making it easier.

I just looked up Extender functons, which appear to be able to get around this to an extent

Just to clarify, the resulting code should look something more like this then:

Code: ags
// global script header
import function SayDialog(this Character*, String text);
import function SayDialogOption(this Character*, Dialog *theDialog, int option);

// global script file
function SayDialog(this Character*, String text) {
  if (String.IsNullOrEmpty(text)) return; // invalid text, abort
  this.SayAt(0, 280, 300, text); // note you DO NOT use string-formatting techniques here
}

function SayDialogOption(this Character*, Dialog *theDialog, int option) {
  if ((theDialog == null) || (option <= 0) || (option > theDialog.OptionCount)) return; // invalid dialog or option, abort
  this.SayAt(0, 280, 300, theDialog.GetOptionText(option));
}

// dialog script
@1 // Hi Bob. - with "Say" UNchecked on the left we can use our function instead
  cFrank.SayDialogOption(dBob, 1); // say the text for option 1 of dialog 'dBob'
BOB: Hi Frank. // normal text-positioning
  cFrank.SayDialog("What have you got for sale today?"); // say the text
BOB: Let's take a look... // normal text positioning
// blah blah


That should hopefully give you a better idea of how to accomplish what you're trying to do.

Oh and you have a lot of "%s",string_variable-stuff going on in your pseudo-code. I just wanted to point out to you here that the only functions which accept this type of string formatting are the built-in functions which have a (const) string parameter followed by "..." listed as a parameter. You cannot design your own custom function that will accept string formatting in this fashion.

If necessary, you can however pass the function String.Format to the function such as:

Code: ags
some_function(String.Format("%s of %s", val1, val2));


It's also probably important to note that you do not have to use string formatting to pass the value of a string (const string, String, or string-literal ("such as this; text enclosed in quotes")) to a function.

Also make sure you're using String and not string. The capital 'S' indicates new-style strings. If for some reason you need to work with old-style strings, make the function parameter listed as type const string or it won't work with Strings or string-literals. ;)

SMF spam blocked by CleanTalk