JCarter426

Subroutine within a subroutine

Recommended Posts

This is kind of a stupid question. I was working on a script earlier and I was saying you can do this with loops instead of 600 lines of code, and then... well, now I'm wondering if you can. Of course there must be a way to do it, I thought... but every attempt so far to compile resulted in errors.

I'm trying to write a subroutine that will fire another subroutine repeatedly for any duration of time, and with any interval between each firing. For example, 5 seconds of blaster shot, with a quarter second between each actual shot. The code for the blaster shot goes in one subroutine, and all the looping code goes in another subroutine, and I want that to be able to fire the first subroutine as well as any number of others, and then finally I have the main body.

This is essentially the code that I want:
 

void JC_SUB_1() {

//Subroutine contents

}



void JC_SUB_2() {

//Another subroutine, why not

}



void JC_SUB_TRIGGER(void JC_SUB_HERE(), object oObject, float fDuration, float fInterval) {

int nDuration = FloatToInt(fDuration / fInterval);

int i;

for( i = 0; i < nDuration; i++ ) DelayCommand(IntToFloat(i) * fInterval, AssignCommand(oObject, JC_SUB_HERE() ));

}



void main() {

//Our first subroutine, with a duration of 5 seconds and an interval of one quarter of a second...

JC_SUB_TRIGGER(JC_SUB_1(), OBJECT_SELF, 5.0, 0.25);

//And later in the script, let's have the second subroutine, with a duration of 2 seconds and an interval of one tenth of a second...

DelayCommand(30.0, JC_SUB_TRIGGER(JC_SUB_1(), OBJECT_SELF, 2.0, 0.1));

}

 

And the problem is right here:

 

void JC_SUB_TRIGGER(void JC_SUB_HERE(), object oObject, float fDuration, float fInterval) {

 

I can't get it to accept a subroutine as one of a subroutine's variables... or to be more specific, I can't get it to accept any data type for that variable. It won't take a void. it won't take an action because only nwscript.nss can use action. I looked up data types on the NWN Lexicon and tried command, but apparently KOTOR doesn't support that type, as the compiler wouldn't recognize it. And it wouldn't take a few other things I tried and forgot what they were.

 

Now, I could get around this by removing the subroutine as a variable and defining it in the body, but that would mean duplicating all the trigger code for each different subroutine I want triggered. I could use ExecuteScript, but I'd rather keep everything in one script. So I know other ways to do it, but I want to do it my way.

 

I thought of course there must be a way to do it... but I've tried everything I can think of. But most of my scripting knowledge comes from modifying video games, so maybe I missed something.

Share this post


Link to post
Share on other sites

That was one of the things I forgot I had tried... when I do it like that, I get a type mismatch for the AssignCommand. And that really shouldn't be the case, because I can use a subroutine with AssignCommand just fine otherwise.

 

Also, I'm not sure if removing the parenthesis would later allow me to run that subroutine with its own variables... I think it should, but obviously I can't test it until it actually runs at all.

Share this post


Link to post
Share on other sites

Nah, doesn't work. If I remove the parenthesis from the declaration but keep them in the body, it says it can't invoke that as a function - because it's not recognizing it from the declaration, I would assume.

Share this post


Link to post
Share on other sites

As NW Script is built on C, speaking from a C standpoint...You can't define a function as a parameter. Your first parameter in the declaration of JC_SUB_HERE should be the return of the function or a pointer to it, not the function itself. From what I've read of the language, action is a predefined pointer, and that's why it works in that regard, but the language won't allow you to declare pointers yourself. So the easiest way I could think to pull off what you're wanting to do would be to  do something like this:

void JC_SUB_1() {

//Subroutine contents

}



void JC_SUB_2() {

//Another subroutine, why not

}



void JC_SUB_TRIGGER(int JC_SUB_HERE, object oObject, float fDuration, float fInterval) {

int nDuration = FloatToInt(fDuration / fInterval);

int i;

for( i = 0; i < nDuration; i++ ) DelayCommand(IntToFloat(i) * fInterval, AssignCommand(oObject, switch (JC_SUB_HERE){
case 1:
JC_SUB_1();
break;
} ));

}



void main() {

//Our first subroutine, with a duration of 5 seconds and an interval of one quarter of a second...

JC_SUB_TRIGGER(1, OBJECT_SELF, 5.0, 0.25);

//And later in the script, let's have the second subroutine, with a duration of 2 seconds and an interval of one tenth of a second...

DelayCommand(30.0, JC_SUB_TRIGGER(2, OBJECT_SELF, 2.0, 0.1));

}

Although I'm not sure that level of nesting would work, if not you could also try..

void JC_SUB_1() {

//Subroutine contents

}



void JC_SUB_2() {

//Another subroutine, why not

}



void JC_SUB_TRIGGER(int JC_SUB_HERE, object oObject, float fDuration, float fInterval) {

int nDuration = FloatToInt(fDuration / fInterval);
int i; 

switch(JC_SUB_HERE){
case 1:
for( i = 0; i < nDuration; i++ ) DelayCommand(IntToFloat(i) * fInterval, AssignCommand(oObject, JC_SUB_1() ));
break;

case 2:
for( i = 0; i < nDuration; i++ ) DelayCommand(IntToFloat(i) * fInterval, AssignCommand(oObject, JC_SUB_2() ));
break;

}

}



void main() {

//Our first subroutine, with a duration of 5 seconds and an interval of one quarter of a second...

JC_SUB_TRIGGER(1, OBJECT_SELF, 5.0, 0.25);

//And later in the script, let's have the second subroutine, with a duration of 2 seconds and an interval of one tenth of a second...

DelayCommand(30.0, JC_SUB_TRIGGER(2, OBJECT_SELF, 2.0, 0.1));

}

Share this post


Link to post
Share on other sites

I was afraid of that. The grenade script is set up similarly... it doesn't use cases but it does have an if tree for all the grenade types to run. I'll have to think about which way I prefer but I think I can still manage it all in the same code. Not as efficient as it would be if I were allowed to define my own actions but ah well. Thanks.

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.