* *
Welcome, Guest. Please login or register.
Did you miss your activation email?
October 20, 2017, 01:51:41 PM

Login with username, password and session length

Optimizing scripts

  • 13 Replies
  • 380 Views
*

Online dantedevil

  • Hero Member
  • *****
  • 1435
  • Dante
Optimizing scripts
« on: September 28, 2017, 12:41:03 PM »
After know exactly how works the different types of the scripts,  thanks to this info of DC.
Now I start to modify my enemies txt, because I see they have a lots of large scripts in the same animation. Some of these scripts are large Inline scripts, and I don't know how convert this in a predefined function called on a animation frame.

Quote
Event scripts - This is the best and most optimal way by far to execute a script, and allows very easy reuse of any given function.

Predefined functions called on an animation frame
- Define function methods, import them into an animation script, and then execute them with @cmd. This is the preferred method for executing actions on an animation frame when there isn't an event that can do it for you.

Inline script (@script & @end_script tags) - This is the least optimal way to add scripts. You should only ever do it for extremely simple (one or two line at most) custom logic, never for anything else. It is very sub optimal compared to running defined functions and does not allow reuse of code.

I have this large script, I want convert this in a scrip  to call in an animation frame. The only I need is control the time in red of this line:
Quote
iTime +  8.2*200);
Here the scrip to convert:
Code: [Select]
   @script
   void vSelf = getlocalvar("self");                 //Caller.
   void vEntity;                                     //Target entity placeholder.   
   int  iEntity;                                     //Entity enumeration holder.   
   int  iType;                                       //Entity type.   
   int  iMax      = openborvariant("ent_max");       //Entity count.   
   if(frame==1){                                     //Enumerate and loop through entity collection.     
   for(iEntity=0; iEntity<iMax; iEntity++){           
       vEntity = getentity(iEntity);                     //Get target entity from current loop.
     
       iType   = getentityproperty(vEntity,    "type"); //Get target type.       
                                                        //Enemy type?   
       if (vEntity != vSelf)                                               //Not Self?
   
       if (iType == openborconstant("TYPE_ENEMY")){         
   void iTime = openborvariant("elapsed_time") + getentityproperty(vEntity, "freezetime");         
   changeentityproperty(vEntity, "frozen", 1);         
   changeentityproperty(vEntity, "freezetime", iTime + 8.2*200);
         }      }    }
   @end_script

For now I have managed to optimize some on my own. But if I find or some other script, and I do not understand how to do it, I will share it here to help me again.
Thanks!
« Last Edit: October 05, 2017, 05:11:41 AM by dantedevil »
Dantedevil

*

Offline Damon Caskey

  • Administrator
  • Hero Member
  • *****
  • 1760
    • DC Current
Re: Optimizing scripts
« Reply #1 on: September 28, 2017, 04:57:47 PM »
I'm working it up for, and adding a little extra touch. Should be ready later tonight.

DC
Projects in progress are now available here: https://github.com/DCurrent

*

Online dantedevil

  • Hero Member
  • *****
  • 1435
  • Dante
Re: Optimizing scripts
« Reply #2 on: September 28, 2017, 05:00:14 PM »
I'm working it up for, and adding a little extra touch. Should be ready later tonight.

DC

Oh that's great my friend!
Thanks!
Dantedevil

*

Offline Damon Caskey

  • Administrator
  • Hero Member
  • *****
  • 1760
    • DC Current
Re: Optimizing scripts
« Reply #3 on: October 04, 2017, 03:26:39 PM »
Sorry for the delay, life went haywire again. But here you are. I noticed that code was derived from my old pause function, so I just rewrote it for you. The bonus I refered to is the freeze time - the time conversion is based on current framerate instead of a static 200. IOW, it will try and adapt to the platform speed so you get the most time consistency possible. It does require you to be using one of the newest releases, so make sure you're staying up to date.

Anyway, step by step...

Copy this code into a new blank script file named "whatever.c", and put it in your data/scripts folder.
Code: [Select]
// Caskey, Damon V.
// 2017-09-28
//
// Freeze all entities aside from caller for specified duration.
//
// *duration: Time in seconds to pause target entities.
void dc_freeze_all(float duration)
{
    int frame_rate;         // Current frame rate.
    void entity_caller;     // Entity executing method.
    int entity_count;       // Number of entities in play.
    void entity_current;    // Current entity targeted by loop index.
    int entity_index;       // Entity index cursor.
    int time_current;       // Engine time to end freeze.
    int time_freeze;        // Time to add for freeze effect.
    int time_expire;        // Time freeze effect should expire.

    // Get the basic attributes we need.
    entity_caller   = getlocalvar("self");
    entity_count    = openborvariant("ent_max");
    frame_rate      = openborvariant("fps");
    time_current    = openborvariant("elapsed_time");

    // We need to convert our desired duration length
    // from real time seconds into an OpenBOR elapsed time.
    // This is done by multiplying seconds by frame rate.
    // Frame rate should be 200 but can vary across platforms
    // so we'll use the current known frame rate to get
    // better consistency.
    time_freeze = duration * frame_rate;

    //Enumerate and loop through entity collection.
    for(entity_index = 0; entity_index < entity_count; entity_index++)
    {
        // Get current entity from loop.
        entity_current = getentity(entity_index);

        if (entity_current != entity_caller)
        {
            // Add target's current freeze time (if any) to our set
            // freeze add time.
            time_freeze += getentityproperty(entity_current, "freezetime");

            // Add the current time to our freeze duration. This
            // gives us the OpenBOR time when freeze effect should
            // expire for current target entity.
            time_expire = time_freeze + time_current;

            // Apply freeze effect and expiration time.
            changeentityproperty(entity_current, "frozen", 1);
            changeentityproperty(entity_current, "freezetime", time_expire);           
        }
    }
}

In the script you want to use the function method, add the following:
Code: [Select]
#import "data/scripts/<yourfilename>.c"

Now you can execute the function like this. The 2 can be whatever you like when you execute the function. So you could use it in one place to freeze everyone for 2 seconds, another to freeze them for 4, and so on. It accepts a floating value too, so you could freeze for 2.5 seconds.:
Code: [Select]
// Freeze everyone for 2 seconds.
dc_freeze_all(2);

If you put it in an animation script, you can execute it with a @cmd tag in the model text. Same rules as above.
Code: [Select]
@cmd dc_freeze_all 2
frame ....

Notice how these steps are the same as setting up the random palettes? Similar principals always apply. :)

DC
« Last Edit: October 04, 2017, 03:28:33 PM by Damon Caskey »
Projects in progress are now available here: https://github.com/DCurrent

*

Online dantedevil

  • Hero Member
  • *****
  • 1435
  • Dante
Re: Optimizing scripts
« Reply #4 on: October 04, 2017, 03:44:13 PM »
Thanks DC!
Now I can update my mod a lot.
I have only one question:
My original script has this line,
Code: [Select]
if (iType == openborconstant("TYPE_ENEMY")){
Then changing the type, I can use the script  in enemies or players.
So, If I want use your script system for  both, need make some modifications?
« Last Edit: October 04, 2017, 06:31:37 PM by dantedevil »
Dantedevil

*

Offline Damon Caskey

  • Administrator
  • Hero Member
  • *****
  • 1760
    • DC Current
Re: Optimizing scripts
« Reply #5 on: October 04, 2017, 04:17:25 PM »
Thanks DC!
Now I can update my mod a lot.
I have only one question:
My original scripta has this line,
Code: [Select]
if (iType == openborconstant("TYPE_ENEMY")){
Then changing the type, I can use the script  in enemies or players.
So, If I want use your script system for  both, need make some modifications?

Yeah, just add in a check for enemy type. You should be able to figure it out looking at how the script works - but if you have trouble let me know.

DC
Projects in progress are now available here: https://github.com/DCurrent

*

Online dantedevil

  • Hero Member
  • *****
  • 1435
  • Dante
Re: Optimizing scripts
« Reply #6 on: October 04, 2017, 06:48:13 PM »
The script works great my friend!
But I have some problems in the fatalities. Let me explain better:

When the hero perform the fatality, I need freeze the other heros and not the enemies, because the dead enemy need perform the fatality animation.

The same with the killed enemy, I need freeze the other enemies and not the hero's,  because the hero need preform the fatality animation to kill the enemy.

So actually I use the old large script in hero's and enemies, but only need change type depending of the character.

So I need to know how can add to your script the possibility to set the enemy o player.
I mean something like this:
Code: [Select]
@cmd dc_freeze_all 2 player
Code: [Select]
@cmd dc_freeze_all 2 enemy
Or the other alternative would be to modify your script to create 2 different ones. One for heroes and one for enemies.
« Last Edit: October 04, 2017, 07:42:38 PM by dantedevil »
Dantedevil

*

Offline Damon Caskey

  • Administrator
  • Hero Member
  • *****
  • 1760
    • DC Current
Re: Optimizing scripts
« Reply #7 on: October 04, 2017, 09:59:58 PM »
The best way to handle this scenario is with a local bar array.

Funny thing, I was going to update it to accept arrays but I figured best to keep it simple for you.

No big, give me a bit and I'll get it going.

DC
Projects in progress are now available here: https://github.com/DCurrent

*

Offline O Ilusionista

  • Global Moderator
  • Hero Member
  • *****
  • 4884
  • >> I WILL BE AWAY FOR SOME TIME <<
    • BMT - Brazil Mugen Team
Re: Optimizing scripts
« Reply #8 on: October 05, 2017, 07:15:35 AM »
Hi DC, I have some questions about your code:

Quote
    void entity_caller;     // Entity executing method.
    int entity_count;       // Number of entities in play.

Are you using entity_caller as VOID and not INT because you want to return its value, right? (and because the valur is not an integer, but an string). Can you explain why we can't use it as CHAR, for example?

Quote
entity_count    = openborvariant("ent_max");

Long time ago, White Dragon had explained why we should avoid using this and use "count_entities" instead.  in generally (always really) MAX_ENTS > count_entities. In some cases, you can have a side effect by using MAX_ENTS (like I've mentioned at the link above).


*

Offline Damon Caskey

  • Administrator
  • Hero Member
  • *****
  • 1760
    • DC Current
Re: Optimizing scripts
« Reply #9 on: October 05, 2017, 02:37:51 PM »
Are you using entity_caller as VOID and not INT because you want to return its value, right? (and because the valur is not an integer, but an string). Can you explain why we can't use it as CHAR, for example?

First, Openbor script is weak typed, so you can declare a variable it as whatever type you like, but that doesn't make it so. Regular C will throw a fatal error if you use the wrong type. OpenBOR ignores you and uses whatever type is appropriate for the value.

Second, entity_caller is neither an int or a char - it's a pointer, in this case referring to the entity that executed the script. In OpenBOR script, you declare a pointer with void. Now again see above - the engine is going to use the type it wants regardless of what you do, but that doesn't mean you shouldn't use the appropriate declaration for readability.

See here for a full explanation of how variables and types work in OpenBOR Script.

Quote
entity_count    = openborvariant("ent_max");

Long time ago, White Dragon had explained why we should avoid using this and use "count_entities" instead.  in generally (always really) MAX_ENTS > count_entities. In some cases, you can have a side effect by using MAX_ENTS (like I've mentioned at the link above).

Who do you think told WD that in the first place?  ;)

In an enumeration loop like mine here, ent_max vs. ent_count won't make a functional difference - but yes, you should use ent_count for maximum optimization. I was in a hurry and just keyed in the wrong one. I'll correct it in the next version.

DC
« Last Edit: October 05, 2017, 02:40:04 PM by Damon Caskey »
Projects in progress are now available here: https://github.com/DCurrent

*

Offline O Ilusionista

  • Global Moderator
  • Hero Member
  • *****
  • 4884
  • >> I WILL BE AWAY FOR SOME TIME <<
    • BMT - Brazil Mugen Team
Re: Optimizing scripts
« Reply #10 on: October 05, 2017, 04:42:07 PM »
Got it. Thanks for the explanation.

*

Online dantedevil

  • Hero Member
  • *****
  • 1435
  • Dante
Re: Optimizing scripts
« Reply #11 on: October 08, 2017, 10:27:37 AM »
I try to use this script in an animation, without teh @cmd. But not work.
Code: [Select]
void force_game_over() {
        int p = 0;

        for (p = 0; p < openborvariant("maxplayers"); p++) {
            if ( getplayerproperty(p,"credits") > 0 ) changeplayerproperty(p,"credits",0);
            if ( getplayerproperty(p,"lives") > 0 ) changeplayerproperty(p,"lives",0);
        }
        jumptobranch("inexistent ",1); // inexistent branch to simulate gameover
}

Here my last try, what is wrong?

Code: [Select]
anim idle
loop 0
delay 500
offset  0 278
frame data/chars/misc/dialogue/trcomplete.png
@script
        int p = 0;

        for (p = 0; p < openborvariant("maxplayers"); p++) {
            if ( getplayerproperty(p,"credits") > 0 ) changeplayerproperty(p,"credits",0);
            if ( getplayerproperty(p,"lives") > 0 ) changeplayerproperty(p,"lives",0);
        }
      if(frame == 1){
        jumptobranch("inexistent ",1); // inexistent branch to simulate gameover
}

@end_script
frame data/chars/misc/dialogue/trcomplete.png
frame data/chars/misc/dialogue/trcomplete.png


Dantedevil

*

Offline Damon Caskey

  • Administrator
  • Hero Member
  • *****
  • 1760
    • DC Current
Re: Optimizing scripts
« Reply #12 on: October 08, 2017, 07:44:46 PM »
You never set the frame variable. But honestly, the "wrong" you're doing is taking a function and trying to make it inline in the first place. That's the exact opposite of what you should be doing.

Use the function with a @cmd tag the way it was meant to be.

DC

Projects in progress are now available here: https://github.com/DCurrent

*

Online dantedevil

  • Hero Member
  • *****
  • 1435
  • Dante
Re: Optimizing scripts
« Reply #13 on: October 08, 2017, 08:08:08 PM »
Ok. Thanks!
Dantedevil

 

Recent

Members
Stats
  • Total Posts: 46532
  • Total Topics: 3188
  • Online Today: 46
  • Online Ever: 316
  • (January 04, 2013, 09:43:02 AM)
Users Online
Users: 4
Guests: 38
Total: 42