Code slower on different software filter

Toranks

Active member
I have an entity to release from grabs mashing buttons. This is the first lines of this entity and the problematic code. On my brother computer, I can release easy, but on my computer that is not bad but does not reach the power of him's, I can release but a bit harder with 16-bit advance Mame2x. But with with 16-bit simple2X it becomes very hard to achieve, with some enemies it becomes absolutely impossible. This is strange, but I suppose is related to some bad use of variables and commands in this code. Could someone help me improve it? Basically what I want is to add 1 + hp to the entity each time one of the buttons that I indicate at the end of the code is pressed, and if the life of the entity is filled, the player is released from the enemy grab. From the beginning this entity has worked with problems because of this code, and I had to make many modifications to make it work well over the years, and now that it was doing better than ever, this strange problem appears to me...

C#:
name            grab1
type            obstacle


scroll            1
health            300
speed            0
nomove            1 1
facing            1
noquake            1
shadow            0
falldie            1
antigrab        10
offscreenkill             30000
subject_to_wall        0
subject_to_platform     0
subject_to_obstacle     0
subject_to_hole     0
subject_to_gravity     0
diesound        data/sounds/empty.wav
setlayer    999999998


lifebarstatus 150 20 0 1 0 2 5
lifeposition 120  240
nameposition -200 -200
nolife 1






script   @script
void main()
{
        void self = getlocalvar("self");
    void attacker = getentityproperty(self,"parent");
       void victim2 = getentityvar(self, "target");
      void victim = getentityvar(self, "player");
    int HP = getentityproperty(self,"health");
    int HPmax = getentityproperty(self,"maxhealth");


    int x1 = getentityproperty(attacker,"x");
    int z1 = getentityproperty(attacker,"z");


        int escape = getentityvar(self, "grabgo"); //johnny madjon
  if (attacker!=NULL() && victim2 !=NULL())
   {// checking if the pointers are valid


    if(HP>=HPmax && escape == 1){
    changeentityproperty(victim2, "position", x1, z1);
         performattack(victim2, openborconstant("ANI_FOLLOW15"));
        setidle(attacker, openborconstant("ANI_IDLE"));
         bindentity(victim2, NULL());
         performattack(attacker, openborconstant("ANI_PAIN8"));
    setentityvar(self, "madjon", NULL());
    killentity(self);


    } else if(HP>=HPmax && escape == 2){
    changeentityproperty(victim2, "position", x1, z1);
         performattack(victim2, openborconstant("ANI_FOLLOW16"));
        setidle(attacker, openborconstant("ANI_IDLE"));
         bindentity(victim2, NULL());
        performattack(attacker, openborconstant("ANI_PAIN8"));
    setentityvar(self, "madjon", NULL());
    killentity(self);


          } else if(playerkeys(victim, 2, "moveleft") || playerkeys(victim, 2, "moveup") || playerkeys(victim, 2, "movedown") || playerkeys(victim, 2, "moveright") || playerkeys(victim, 2, "attack") || playerkeys(victim, 2, "jump") || playerkeys(victim, 2, "special")){// button is pressed?
        changeentityproperty(self, "health", HP+1);
      }
   }// end checking valid pointers
}
@end_script
 
Last edited:
@Toranks

I suggest using "keyscript" events instead of using "in-line" scripts, DC posted an explanation some time ago saying that it's not recommended.
You can use basically the same script you created but calling it in event like this:

Code:
keyscript            data/scripts/key/abadede.c

EDIT: I'm curious to know why you are using an obstacle entity to do this task.

Maybe this can be useful. I have a similar code in SORX called "grab escape", the only difference is that the player will escape instantly if the attack button is pressed at the moment he enters in the "grabbed" animation, instead of yours that needs to fill hp.

Code:
void grabEscape()
{//Escape when grabbed
    if(getglobalvar("grabEscape") == "on"){
        void self   = getlocalvar("self");
        void target = getentityproperty(self,"opponent");
        void vAniID = getentityproperty(self,"animationID");
        int iPIndex = getlocalvar("player");
        int dir     = getentityproperty(self,"direction");
        int dead    = getentityproperty(self,"dead");
        int maxGp   = getentityproperty(self,"maxguardpoints");
        int gp      = getentityproperty(self,"guardpoints");
        int costGp  = maxGp/5*4;
        int xVel    = 2;
       
        if(dir == 0){xVel = -xVel;}
       
        if(vAniID == openborconstant("ANI_GRABBED")){
            if(gp == maxGp && !dead){
                if(playerkeys(iPIndex, 1, "attack")){
                    gpCost(costGp);
                    damageentity(target, self, 0, 0, openborconstant("ATK_NORMAL"));
                    tossentity(target, 0.2, xVel, 0);
                    performattack(self, openborconstant("ANI_FOLLOW8"), 0);
                }
            }
        }
    }
}
 
Last edited:
I've changed type from obstacle to none and works the same. This entity is not mine, and It's been like this for years and I hadn't thought about it.

script @script...

changed to

script data/scripts/grab.c

grab.c:
C#:
void main()
{
    void self = getlocalvar("self");
    void attacker = getentityproperty(self,"parent");
       void victim2 = getentityproperty(attacker, "opponent");
      void victim = getentityvar(self, "player");
    int HP = getentityproperty(self,"health");
    int HPmax = getentityproperty(self,"maxhealth");
    int x1 = getentityproperty(attacker,"x");
    int z1 = getentityproperty(attacker,"z");
    int escape = getentityvar(self, "grabgo");
    void iUp = playerkeys(victim, 1, "moveup");
    void iDown = playerkeys(victim, 1, "movedown");
    void iLeft = playerkeys(victim, 1, "moveleft");
    void iRight = playerkeys(victim, 1, "moveright");
    void iJump = playerkeys(victim, 1, "jump");
    void iSpecial = playerkeys(victim, 1, "special");
    void iAttack = playerkeys(victim, 1, "attack");
        
  if (attacker == NULL() && victim2 == NULL()) {
        killentity(self);
    
    } else if (attacker == NULL() && victim2 != NULL() ) {
        changeentityproperty(victim2, "position", x1, z1);
        performattack(victim2, openborconstant("ANI_FOLLOW15"));
        bindentity(victim2, NULL());
        setglobalvar("grabbed", NULL());
        killentity(self);
            
    } else if (attacker != NULL() && victim2 == NULL()) {
        setidle(attacker, openborconstant("ANI_IDLE"));
         performattack(attacker, openborconstant("ANI_PAIN8"));
        setglobalvar("grabbed", NULL());
        killentity(self);
    
    } else if(HP>=HPmax && escape == 1){
        changeentityproperty(victim2, "position", x1, z1);
         performattack(victim2, openborconstant("ANI_FOLLOW15"));
        setidle(attacker, openborconstant("ANI_IDLE"));
         bindentity(victim2, NULL());
         performattack(attacker, openborconstant("ANI_PAIN8"));
        killentity(self);

    } else if(HP>=HPmax && escape == 2){
        changeentityproperty(victim2, "position", x1, z1);
         performattack(victim2, openborconstant("ANI_FOLLOW16"));
        setidle(attacker, openborconstant("ANI_IDLE"));
         bindentity(victim2, NULL());
        performattack(attacker, openborconstant("ANI_PAIN8"));
        killentity(self);

    } else if(iUp || iDown || iLeft || iRight || iJump || iSpecial || iAttack){// button is pressed?
        
        changeentityproperty(self, "health", HP+1);

   }// end checking valid pointers
}


Works the same, and with the same problem with the software filter, become a LOT harder to release on 16-bit simple2X

Using keyscript to split code in two parts doesn't works. Nothing happens when I press any button.

keyscript data/scripts/release.c
script data/scripts/grab.c


release.c:
C#:
void main()
{
       void self = getlocalvar("self");
       void victim = getentityvar(self, "player");
        int HP = getentityproperty(self,"health");
        void iUp = playerkeys(victim, 1, "moveup"); // New key status of "Up"
        void iDown = playerkeys(victim, 1, "movedown"); // New key status of "Down"
        void iLeft = playerkeys(victim, 1, "moveleft"); // New key status of "Left"
        void iRight = playerkeys(victim, 1, "moveright"); // New key status of "Right"
        void iJump = playerkeys(victim, 1, "jump"); //New key status of "Jump"
        void iSpecial = playerkeys(victim, 1, "special"); //New key status of "Special"
        void iAttack = playerkeys(victim, 1, "attack"); //New key status of "Attack

        if(iUp || iDown || iLeft || iRight || iJump || iSpecial || iAttack){// button is pressed?
      
        changeentityproperty(self, "health", HP+1);
      
    }
}
 
Last edited:
@Toranks

I've changed type from obstacle to none and works the same
What I'm trying to understand is why you need an obstacle entity if a code only involves a player against an enemy. What is this obstacle entity is supposed to do?

Using keyscript to split code in two parts doesn't works. Nothing happens when I press any button.

keyscript data/scripts/release.c
script data/scripts/grab.c
The keyscript I meant doesn't need to have two parts, it can work alone. The second event you added (script data/scripts/grab.c) in fact is an "update entity" script, which runs at every engine cycle and can make the game run slower depending on what you are trying to do.

void victim2 = getglobalvar("grabbed");
void victim = getentityvar(victim2, "player");
Sometimes the problem could be other scripts that work on the used variables. I saw that the "getglobalvar" is on your original script, but where do the "getentityvar" variable come from?

I tested your code on SORX and worked fine without the variables. I think that this is the effect you want:
 
I've fixed the code before you answered me, sorry. The code I put in was just one that I was using for testing. Apparently the use of globalvar does not detect the buttons of the appropriate player, and only activates with player 1 buttons. But it isn't related with the problem I have. See my post again (the one with 'grab.c')
@Toranks


What I'm trying to understand is why you need an obstacle entity if a code only involves a player against an enemy. What is this obstacle entity is supposed to do?
I don't really know what the original author's intention is to use an obstacle type entity, but as I say, I changed it to none and it works the same
The keyscript I meant doesn't need to have two parts, it can work alone. The second event you added (script data/scripts/grab.c) in fact is an "update entity" script, which runs at every engine cycle and can make the game run slower depending on what you are trying to do.
Ok, now it is on one scrip, and works fine, but with the software filter problem
Sometimes the problem could be other scripts that work on the used variables. I saw that the "getglobalvar" is on your original script, but where do the "getentityvar" variable come from?

I tested your code on SORX and worked fine without the variables. I think that this is the effect you want:
getentivyvar detect the player grabbed with this code, on spawn animation of grab1 entity:

C#:
anim    spawn
@script
    void self = getlocalvar("self");
    void atk = getentityproperty(self,"parent");
      void vtm = getentityproperty(atk, "opponent");
      void plyr = getentityproperty(vtm, "playerindex");
        changeentityproperty(self, "health",-5);
        setentityvar(self, "target", vtm);
        setentityvar(self, "player", plyr);
   
     if(getentityproperty(vtm, "type")==openborconstant("TYPE_NPC"))
    {
    killentity(self);
    }
    @end_script   
    loop    0
    delay    5
    offset    50 90
    bbox    0 0 0 0
    platform    1 1 1 1 1 1 1 1
    frame    data/chars/misc/grab/empty.gif
    frame    data/chars/misc/grab/empty.gif
    frame    data/chars/misc/grab/empty.gif
    frame    data/chars/misc/grab/empty.gif


What are you doing on your video? Grab1 entity is the HP bar who appears with a buttons picture on second 3. (Ignore the bug, this is an old video and is solved)

 
Last edited:
What are you doing on your video?
I'm mashing buttons, same as you wanted to do in your game. The Axel's hp bar is refilled always at the same rate, no matter the video filter I'm using.
In this video I used only keyscripts. Differently from ondraw/update scripts, this works at every key press and it's not affected by video filters.

The only issue related to the video I found until now (and it's not a bug) is related to the "v-sync", which changes the cycles of update scripts and if you run a code at every engine cycle, it will run slower when the "v-sync" is enabled.

For these events, I suggest using "elapsed_time" as reference to maintain the same rate.

Grab1 entity is the HP bar who appears with a buttons picture on second 3
I readed the entire code again and now I understand what this obstacle is doing. The author is using the entity's lifebar only to draw a bar on the screen.
The obstacle entity changes his own health and shows the progress for the player.

In this case, I suggest using the "ondrawscript" event directly on the player or enemy entities, instead of creating a "third" entity to read these scripts and show a bar on the screen. Maybe there's some delay between the buttons pressed, script working and the health bar.

Below is an example I'm using to draw the cpu partner's lifebar on the screen. You can remove all unnecessary variables related to my game and leave only the values related to position, size and color.
C:
void drawLife()
{//Draw life bar in the screen, entity binded like RPG games
    if(openborvariant("in_level")){ //IN ANY LEVEL??
        void self   = getlocalvar("self");

        if(getglobalvar("partnerLifebar") == "simple"){
            int maxLife     = getentityproperty(self, "maxhealth");
            int life        = getentityproperty(self, "health");
            int x           = getentityproperty(self, "x");
            int y           = getentityproperty(self, "y");
            int z           = getentityproperty(self, "z");
            float xPos      = openborvariant("xpos");
            float yPos      = openborvariant("ypos");
            float xSize     = 30; //BAR WIDTH INCREASE FACTOR, MORE VALUE IS MORE SIZE
            float ySize     = 2; //BAR HEIGHT INCREASE FACTOR, MORE VALUE IS MORE SIZE
            float xDif      = 0; //BAR POSITION IN X AXIS, USE THIS TO MOVE ALL BARS TOGETHER
            float yDif      = 4; //BAR POSITION IN Y AXIS, USE THIS TO MOVE ALL BARS TOGETHER
            float screen    = openborvariant("gfx_y_offset");
            float greenBar;
           
            //ENTITY IS ALIVE??
            if(life > 0){
                greenBar    = (getglobalvar("greenBar"+self)*xSize)/(maxLife); //CALCULATE REMAINING LIFE TO BE HEALED
                life        = (life*xSize)/(maxLife); //CALCULATE REMAINING LIFE BAR SIZE
                maxLife     = (maxLife*xSize)/(maxLife); //CALCULATE MAX LIFE BAR SIZE
                x           = x-xPos-(maxLife/2)+xDif; //CALCULATE X POSITION TO BIND BAR IN THE ENTITY, OFFSET IS ALWAYS THE CENTER
                y           = z-yPos+screen-y+yDif; //CALCULATE Y POSITION TO BIND BAR IN THE ENTITY
                drawbox(x, y, life, ySize, z+3, rgbcolor(0xFF,0xFF,0x00), 0); //YELLOW BAR, LIFE REMAINING
                drawbox(x, y, maxLife, ySize, z+1, rgbcolor(0xFF,0x00,0x00), 0); //RED BAR, LIFE LOST
                drawbox(x, y-1, maxLife, ySize*2, z, rgbcolor(0xFF,0xFF,0xFF), 0); //WHITE BORDER (UP/DOWN)
                drawbox(x-1, y, maxLife+2, ySize, z, rgbcolor(0xFF,0xFF,0xFF), 0); //WHITE BORDER (LEFT/RIGHT)
            }
        }
    }
}
 
Last edited by a moderator:
I'll try to explain the complete process and why I need a dedicated entity (not neccesarily an obstacle).

First, this is a sample of an ungrabbable enemy grab
C#:
anim    special
    loop    0
    delay    30
    offset    125 215
    bbox    0 0 0 0
    sound    data/sounds/grab.wav
    @cmd    slamstart2
    @cmd    spawngrab "grab1" 200 200 450 80 1 8
    @cmd    position 7 45 40 -1 1
    frame    data/chars/3bub/grab00.gif
    delay    17
    @cmd    position 1 15 40 1 1
    frame    data/chars/3bub/grab01.gif
    @cmd    position 9 5 150 1 -1
    frame    data/chars/3bub/grab02.gif
    @cmd    position 9 5 155 1 -1
    frame    data/chars/3bub/grab03.gif
    delay    11
    @cmd    position 9 5 160 1 -1
    frame    data/chars/3bub/grab04.gif
    @cmd    position 9 5 161 1 -1
    frame    data/chars/3bub/grab05.gif
    @cmd    position 9 5 160 1 -1
    frame    data/chars/3bub/grab04.gif
    @cmd    position 9 5 161 1 -1
    frame    data/chars/3bub/grab05.gif
    @cmd    position 9 5 160 1 -1
    frame    data/chars/3bub/grab04.gif
    @cmd    position 9 5 161 1 -1
    frame    data/chars/3bub/grab05.gif
    @cmd    position 9 5 160 1 -1
    frame    data/chars/3bub/grab04.gif
    @cmd    position 9 5 161 1 -1
    frame    data/chars/3bub/grab05.gif
    @cmd    position 9 5 160 1 -1
    frame    data/chars/3bub/grab04.gif
    @cmd    position 9 5 161 1 -1
    frame    data/chars/3bub/grab05.gif
    @cmd    position 9 5 160 1 -1
    frame    data/chars/3bub/grab04.gif
    @cmd    position 9 5 161 1 -1
    frame    data/chars/3bub/grab05.gif
    delay    16
    @cmd    killgrab
    @cmd    position 2 5 125 1 1
    frame    data/chars/3bub/grab06.gif
    sound    data/sounds/beat4.wav
    @cmd    spawn01 "flashscreen2" 1 75 1
    @cmd    position 14 5 135 1 1
    frame    data/chars/3bub/grab07.gif
    @cmd    depost 0
    @cmd    finish 35 1 0 6 0 0
    frame    data/chars/3bub/grab08.gif
    @cmd    clearL
    frame    data/chars/3bub/grab09.gif
    sound    data/sounds/bguylaugh2.wav
    frame    data/chars/3bub/grab10.gif


This starts with slamstart2, grabbing the nearest player:

C#:
void slamstart2()
{ // Slam Starter for nongrab slams
// Use finish or throw after using this
   void self = getlocalvar("self");
  void target = getentityproperty(self, "opponent");


  if(target == NULL() || getentityproperty(target, "dead") == 1){
    setidle(self);
  } else{
    setlocalvar("Target" + self, target);


 }
   if(target!=NULL())
   {
     damageentity(target, self, 0, 1, openborconstant("ATK_NORMAL7")); // Slam Starter
   }
}

Next, spawns the grab1 entity with this @cmd:
C#:
void spawngrab(void vName, float fX, float fY, float fZ,int HPgv, int Num2, int Num)
{    //Spawns.a.grab---set.it.as.child--with.HP.MAX--opponent.plays.follow
    //opponent.follow.Num=1jumpback
    //          Num=2dashlow
    //HPgv = amount/time/health -> button press to incress once max is reach grabEscape


    void self = getlocalvar("self");
    void vSpawn;
    vSpawn = spawn02(vName, fX, fY, fZ);


        setentityvar(vSpawn, "grabgo", Num2);
        setentityvar(self, Num, vSpawn);
        changeentityproperty(vSpawn, "maxhealth", HPgv);
        changeentityproperty(vSpawn, "parent", self); //Set caller as parent.
    return vSpawn; //Return spawn.
}

Inside grab1, spawn animation includes this script:
C#:
anim    spawn
@script
    void self = getlocalvar("self");
    void atk = getentityproperty(self,"parent");
      void vtm = getentityproperty(atk, "opponent");
      void plyr = getentityproperty(vtm, "playerindex");
        changeentityproperty(self, "health",-5);
        setentityvar(self, "target", vtm);
        setentityvar(self, "player", plyr);
  
     if(getentityproperty(vtm, "type")==openborconstant("TYPE_NPC"))
    {
    killentity(self);
    }
    @end_script 
    loop    0
    delay    5
    offset    50 90
    bbox    0 0 0 0
    platform    1 1 1 1 1 1 1 1
    frame    data/chars/misc/grab/empty.gif
    frame    data/chars/misc/grab/empty.gif
    frame    data/chars/misc/grab/empty.gif
    frame    data/chars/misc/grab/empty.gif


This is for declare target and player as setentityvar to use later, and kill entity if grabbed entity is a NPC (A NPC can't release this grab)

Now, the main (and problematic) script starts on every engine cycle with script header:

C#:
name            grab1
type            none


scroll            1
health            300
speed            0
nomove            1 1
facing            1
noquake            1
shadow            0
falldie            1
antigrab        10
offscreenkill             30000
subject_to_wall        0
subject_to_platform     0
subject_to_obstacle     0
subject_to_hole     0
subject_to_gravity     0
diesound        data/sounds/empty.wav
setlayer    999999998


lifebarstatus 150 20 0 1 0 2 5
lifeposition 120  240
nameposition -200 -200
nolife 1




script   data/scripts/grab.c


This is grab.c content now (with the best behavior I have achieved so far, tested multiple times):

C#:
void main()
{
    void self = getlocalvar("self");
    void attacker = getentityproperty(self,"parent");
       void victim2 = getentityproperty(attacker, "opponent");
      void victim = getentityvar(self, "player");
    int HP = getentityproperty(self,"health");
    int HPmax = getentityproperty(self,"maxhealth");
    int x1 = getentityproperty(attacker,"x");
    int z1 = getentityproperty(attacker,"z");
    int escape = getentityvar(self, "grabgo");
    void iUp = playerkeys(victim, 1, "moveup");
    void iDown = playerkeys(victim, 1, "movedown");
    void iLeft = playerkeys(victim, 1, "moveleft");
    void iRight = playerkeys(victim, 1, "moveright");
    void iJump = playerkeys(victim, 1, "jump");
    void iSpecial = playerkeys(victim, 1, "special");
    void iAttack = playerkeys(victim, 1, "attack");
      
  if (attacker == NULL() && victim2 == NULL()) {
        killentity(self);
  
    } else if (attacker == NULL() && victim2 != NULL() ) {
        changeentityproperty(victim2, "position", x1, z1);
        performattack(victim2, openborconstant("ANI_FOLLOW15"));
        bindentity(victim2, NULL());
        killentity(self);
          
    } else if (attacker != NULL() && victim2 == NULL()) {
        setidle(attacker, openborconstant("ANI_IDLE"));
         performattack(attacker, openborconstant("ANI_PAIN8"));
        killentity(self);
  
    } else if(HP>=HPmax && escape == 1){
        changeentityproperty(victim2, "position", x1, z1);
         performattack(victim2, openborconstant("ANI_FOLLOW15"));
        setidle(attacker, openborconstant("ANI_IDLE"));
         bindentity(victim2, NULL());
         performattack(attacker, openborconstant("ANI_PAIN8"));
        killentity(self);


    } else if(HP>=HPmax && escape == 2){
        changeentityproperty(victim2, "position", x1, z1);
         performattack(victim2, openborconstant("ANI_FOLLOW16"));
        setidle(attacker, openborconstant("ANI_IDLE"));
         bindentity(victim2, NULL());
        performattack(attacker, openborconstant("ANI_PAIN8"));
        killentity(self);


    } else if(iUp || iDown || iLeft || iRight || iJump || iSpecial || iAttack){// button is pressed?
      
        changeentityproperty(self, "health", HP+1);


   }// end checking valid pointers
}

First, check if attacker and victim are valid pointers, if not, release player, idle attacker, or both. Next, check if HP is at max or not. When in MAX, release the player with one of two different animations previously declared on @cmd spawngrab. If not in MAX, continue checking player buttons and increasing 1HP every button push until MAX is reached.
If the player can't release during all of the grab animation, the player suffer the final hit, is released, and grab1 entity is killed with @cmd killgrab
C#:
void killgrab()
{ // Kill bound gun based on number
    void self = getlocalvar("self");
    void Gun = getentityvar(self, 8);


    if(Gun!=NULL()){
    bindentity(Gun, NULL());
    killentity(Gun);
    setentityvar(self, 8, NULL());
    }
}


This is because I need a separate entity to draw the HP bar and check all this stuff to release (or not) the player. All enemies and players use the same entity as intermediary, instead of using the same code on every enemy.

Can you think of any way to improve the efficiency of this entire process?

I don't know why, but if I erase the last 'else if' of grab.c and separate the code in two scripts:

C#:
keyscript    data/scripts/release.c
script   data/scripts/grab.c


Content of release.c using the code on your video, with main() and release() on separated void

C#:
void main()
{
    release();
}


void release()
{
        void self = getlocalvar("self");
        void victim = getentityvar(self, "player");
        int HP = getentityproperty(self,"health");
        void iUp = playerkeys(victim, 1, "moveup"); // New key status of "Up"
        void iDown = playerkeys(victim, 1, "movedown"); // New key status of "Down"
        void iLeft = playerkeys(victim, 1, "moveleft"); // New key status of "Left"
        void iRight = playerkeys(victim, 1, "moveright"); // New key status of "Right"
        void iJump = playerkeys(victim, 1, "jump"); //New key status of "Jump"
        void iSpecial = playerkeys(victim, 1, "special"); //New key status of "Special"
        void iAttack = playerkeys(victim, 1, "attack"); //New key status of "Attack


        if(iUp || iDown || iLeft || iRight || iJump || iSpecial || iAttack){// button is pressed?
      
        changeentityproperty(self, "health", HP+1);
      
    }
}

This simply ignore my button pushes, doesn't work.

PD: Vsync doesn't affect to this script, apparently. Only SOFTWARE FILTER
 
Now, the main (and problematic) script starts on every engine cycle with script header:
This is exactly where the performance changes from one PC to another, this is why I do not recommend using scripts based on engine cycle, because it certainly will change depending on the hardware used.

I had the same problem with the green health recovery bar on SOR2X (same as the one on SOR4). Depending on the PC I'm playing, the recovery was slower or faster. The only way I was able to solve this was by adding the "elapsed_time" as a reference for all update scripts.

This simply ignore my button pushes, doesn't work.
According to what I saw in your script, you are calling the"victim" with "void" but in fact it's an "int" value. This code refers to the "playerindex" number to be used on "playerkeys" function, not a string "name".
I suggest trying to change the "void" to "int" in this case.

C:
int victim = getentityvar(self, "player");

I can share with you the method I'm currently using to turn any update/ondraw script into a "timed" script by synchronizing with a defined rate.
It's really very simple but maintains everything running at the same rate, no matter the hardware used. You can customize the rate to any value you want.

C:
void main()
{
    float rate    = 4; //CYCLE RATE
    float time    = openborvariant("elapsed_time")/rate; //ELAPSED TIME

    //START THE TIME COUNTER
    if(getglobalvar("timedCycle") == NULL()){setglobalvar("timedCycle", time);}

    //CHECK TIME AND PERFORM ALL OPERATIONS
    if(time > getglobalvar("timedCycle")){
        void self = getlocalvar("self");
        void attacker = getentityproperty(self,"parent");
        void victim2 = getentityproperty(attacker, "opponent");
        int victim = getentityvar(self, "player");
        int HP = getentityproperty(self,"health");
        int HPmax = getentityproperty(self,"maxhealth");
        int x1 = getentityproperty(attacker,"x");
        int z1 = getentityproperty(attacker,"z");
        int escape = getentityvar(self, "grabgo");
        void iUp = playerkeys(victim, 1, "moveup");
        void iDown = playerkeys(victim, 1, "movedown");
        void iLeft = playerkeys(victim, 1, "moveleft");
        void iRight = playerkeys(victim, 1, "moveright");
        void iJump = playerkeys(victim, 1, "jump");
        void iSpecial = playerkeys(victim, 1, "special");
        void iAttack = playerkeys(victim, 1, "attack");

        if (attacker == NULL() && victim2 == NULL()) {
            killentity(self);
           
        } else if (attacker == NULL() && victim2 != NULL() ) {
            changeentityproperty(victim2, "position", x1, z1);
            performattack(victim2, openborconstant("ANI_FOLLOW15"));
            bindentity(victim2, NULL());
            killentity(self);
           
        } else if (attacker != NULL() && victim2 == NULL()) {
            setidle(attacker, openborconstant("ANI_IDLE"));
            performattack(attacker, openborconstant("ANI_PAIN8"));
            killentity(self);
           
        } else if(HP>=HPmax && escape == 1){
            changeentityproperty(victim2, "position", x1, z1);
            performattack(victim2, openborconstant("ANI_FOLLOW15"));
            setidle(attacker, openborconstant("ANI_IDLE"));
            bindentity(victim2, NULL());
            performattack(attacker, openborconstant("ANI_PAIN8"));
            killentity(self);


        } else if(HP>=HPmax && escape == 2){
            changeentityproperty(victim2, "position", x1, z1);
            performattack(victim2, openborconstant("ANI_FOLLOW16"));
            setidle(attacker, openborconstant("ANI_IDLE"));
            bindentity(victim2, NULL());
            performattack(attacker, openborconstant("ANI_PAIN8"));
            killentity(self);


        } else if(iUp || iDown || iLeft || iRight || iJump || iSpecial || iAttack){// button is pressed?

            changeentityproperty(self, "health", HP+1);
        }// end checking valid pointers

        setglobalvar("timedCycle", time); //RENEW THE VARIABLE FOR THE NEXT CYCLE
    }
}
 
Last edited:
LOL this works the same as before, but with the same problem, no matter what 'float rate = X' I use, approximately 1/3 or 1/4 of velocity on 16 bit simple 2X respect of 16 bit Advanced Mame 2X.
With rate>1 I can compensate with plus of +1HP (2, 3, 4...), but regardless of the value, it goes at a fraction of speed in 16 bit simple 2X 🙀:unsure:

@DCurrent Can you take a look at this? It's really strange

@Kratus change void for int to "player" entityvar works for script as before, but keyscript keep resisting me...
 
Last edited:
@Toranks

It's really strange. I have a lot of update scripts in SORX, tested some of them with all software filters one by one but they don't change anything in my game. The only thing that changes performance in SORX is the v-sync.

What OpenBOR build are you using? I could take a look at your pak file if you send me a copy.
 
@Toranks

I'm using Openbor 4 alpha build 7142
Hmm now I understand the problem. This build is not stable and very outdated.
Tested the Alpha 7142 and can confirm the problem you said, there's a considerable difference between the software filters.

I never saw this problem before because I always used the 6330, 6391 and then jumped to the main source, where this problem does not happen.

In this case I suggest the 6391 because it is the latest stable official version. Tested my update scripts in the 6330/6391 and they are running all at the same speed on both 16 bit simple 2X and 16 bit Advanced Mame 2X.

EDIT: Is there an easy way to reproduce the same test you did in your last video?
 
Last edited:
Hmmm but you are using 7123 to SOR2X, this is alpha too

@Toranks

EDIT: Is there an easy way to reproduce the same test you did in your last video?

Yes go to South town free map (you need to erase ifcomplete 1 in levels.txt), next go to St. Town Mountains star, and then go to Waterfall end. Stay away from Remuinho, so he will try to do the same grab of the video immediately
 

Attachments

  • Sin título.jpg
    Sin título.jpg
    208.1 KB · Views: 1
Last edited:
Hmmm but you are using 7123 to SOR2X, this is alpha too
This 7123 is based on the main/latest source code, which is constantly updated and tested. This build I compiled directly from the main source code and contains a few updates I added.

This Alpha 7142 was a test build that DC launched in 2019, and the last update was in December-2019.
For some reason the Alpha 7142 build number is not following the correct commit sequence, that currently reached 7141 due to the latest update added in "November 10, 2021".

You can see the correct sequence in the GitHub.

If you want to try the build 7123 I'm currently using, you can download it here.
But keep in mind that this one was not launched as a stable official version, like the 6391.
 
You can see the correct sequence in the GitHub.

If you want to try the build 7123 I'm currently using, you can download it here.
But keep in mind that this one was not launched as a stable official version, like the 6391.
Ooooooh thanks!!!! 7123 works perfect!! And is save-compatible with 7142! I can finally guarantee correct behavior of this script on any PC and software filter without the need for elapsed_time based scripts or anything

I assume it is a bug of the unstable version and if you don't mind, I will use your Openbor version as the recommended version for my game from now on 😻
(On public download file I included 3 versions, the original 4153, the latest stable release, and 7142)
 
Last edited:
Ooooooh thanks!!!! 7123 works perfect!! And is save-compatible with 7142! I can finally guarantee correct behavior of this script on any PC and software filter without the need for elapsed_time based scripts or anything

I assume it is a bug of the unstable version and if you don't mind, I will use your Openbor version as the recommended version for my game from now on 😻
(On public download file I included 3 versions, the original 4153, the latest release, and 7142)
Great! I'm glad that this build worked for your game :)
But don't forget what I said about the v-sync. In some of my update scripts, I also need the "elapsed_time" to maintain the same rate with both v-sync on (60 fps) or off (200 fps).
 
Great! I'm glad that this build worked for your game :)
But don't forget what I said about the v-sync. In some of my update scripts, I also need the "elapsed_time" to maintain the same rate with both v-sync on (60 fps) or off (200 fps).
I know, but I tested with and without vsync and I have not noticed differences. I usually have it activated
 
Is there a way to change certain animal names to a different color? Lets say make a timber wolve green on their name instead of grey when walking through the forest.

Thank You.


 
Back
Top Bottom