JCarter426 1,214 Posted February 9, 2016 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. Quote Share this post Link to post Share on other sites
VarsityPuppet 1,085 Posted February 9, 2016 JC_SUB_HERE() --> JC_SUB_HERE In the method header Quote Share this post Link to post Share on other sites
JCarter426 1,214 Posted February 9, 2016 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. Quote Share this post Link to post Share on other sites
VarsityPuppet 1,085 Posted February 9, 2016 You keep the parens there, I believe. Remove them from the declaration of void JC_SUB_TRIGGER( void JC_SUB_HERE,etc...) Quote Share this post Link to post Share on other sites
JCarter426 1,214 Posted February 9, 2016 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. Quote Share this post Link to post Share on other sites
DarthTyren 103 Posted February 9, 2016 Is JC_SUB_HERE actually defined anywhere? Quote Share this post Link to post Share on other sites
Vriff 21 Posted February 10, 2016 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)); } Quote Share this post Link to post Share on other sites
JCarter426 1,214 Posted February 10, 2016 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. Quote Share this post Link to post Share on other sites