Solved Vortex that attracts all enemies on screen

Question that is answered or resolved.

kimono

Well-known member
Hi, I'm trying lately to set a new blender item which spawns a vortex that can attract to its center and damage enemies for a certain period:
I just need to know how the vortex can aspirate them without they are able to do anything to avoid that.
Currently, the vortex is type none, that's why they ignore it.
The archive for testing purpose (stage motobar):

I tried a negative dropv with 0 damage and a second attack when they are near but maybye there is a better solution.
Thanks for your lights :)
 
Last edited:
Solution
@DCurrent

Yeah, I really do not want to put this update script on every entity. The trick here was the "getentity" function, to be honest I never used or even knew what it does, thanks to clarify. For a global script that affects all entities, I think it's the best way.

The only thing I maintained is the "vortexRate" to avoid the script to be connected with every engine cycle, maintaining it "timed", otherwise the fps will change the effect according to the current platform (Windows runs at 200+ fps and Android always at 60 fps or below).

I will update my library with this new script, thanks again.


@kimono

Now the script became more simple to use. All you need to do is to put in the updateentity event on the...
hey @kimono

i tried to fix the behavior of Christopher's specials in nighslashers so i have thought about windy or tossing enemies behaviors for a while now
, the only thing that could work is for yout vortex to summon invisible entities right beside on screen enemies, kind of like Jasmine's thunderbolts - bind them & after that the entites carryin the enemies move toward the vortex, more complex things , like the enemies have a spin that ends up to the center of the vortex might need lots of maths or brute lines of animation...
 
hey @kimono

i tried to fix the behavior of Christopher's specials in nighslashers so i have thought about windy or tossing enemies behaviors for a while now
, the only thing that could work is for yout vortex to summon invisible entities right beside on screen enemies, kind of like Jasmine's thunderbolts - bind them & after that the entites carryin the enemies move toward the vortex, more complex things , like the enemies have a spin that ends up to the center of the vortex might need lots of maths or brute lines of animation...
I don't want to be snide, but virtually every word of this is wrong. This is just like your posts claiming beams are not possible. It isn't true at all and I must ask you to stop answering questions until you have a better understanding of the subject.

Wind effects are not difficult or complex at all. All you need to do is run an update that loops through entities on screen, check any conditions (like enemy vs. player), then adjust their position very slightly toward vortex. Then it's a matter of how much. You could make it small enough there's a slight pull they'd only notice when standing still, an overwhelming force that sucks them in almost instantly, or anything in between.

@kimono, it would help if you were more specific. Vortex can mean several things in American English, so I'm not fully certain what you want. How exactly do you want the effect to work?

DC
 

Guys, my two cents here. If I understand correctly, this "vortex" is like a "swirl", right? If the wind effect is enough to create it, I will post my code used on the SOR2X at the stage 3 on SOR3 route.

Note that this code is used on the "onmovea" event and only works if the entity is in the air. To work on the ground at any time, I think it need to be placed on the other events like ondraw/updateentity.

C:
void windForce()
{//Simulates the "wind" force effect in the SOR3 stage3
    void self    = getlocalvar("self");
    void branch    = openborvariant("current_branch");
    float xDir     = getentityproperty(self, "xdir");
    float wind    = getglobalvar("windForce");
    float time    = openborvariant("elapsed_time");

    if(branch == "sor3_st3a"){
        if(wind != 0){
            changeentityproperty(self, "velocity", xDir+wind);
        }
    }
    else
    {
        if(wind != NULL()){setglobalvar("windForce", NULL());}
    }
}

The code that defines the "windForce" variable is managed by the "lamps" entity, it's a panel type.
@cmd setVar "windForce" -0.015

C:
void setVar(void variable, float value)
{//Set generic global variable for further use
    
    setglobalvar(variable, value);
}

The "lamps" entity enables and disables the wind effect according to the frame.

Code:
name            St3_Lamps
type            panel
shadow            0
speed            5
scroll            -1.13
setlayer        1010
animationscript    data/scripts/animation/default.c

anim idle
    loop    1
    delay    24
    offset    1 180
    @cmd setVar "windForce" -0.015
    frame    data/bgs/sor3/st3a/lamps00.gif
    frame    data/bgs/sor3/st3a/lamps01.gif
        delay    18
    @cmd looper 0 2
    @cmd soundRandom "Wind.wav" 50 "Wind2.wav" 50 0
    frame    data/bgs/sor3/st3a/lamps00.gif
    frame    data/bgs/sor3/st3a/lamps01.gif
    frame    data/bgs/sor3/st3a/lamps02.gif
    frame    data/bgs/sor3/st3a/lamps01.gif
        delay    12
    @cmd looper 4 4
    frame    data/bgs/sor3/st3a/lamps02.gif
    @cmd spawnScreen "St3_Trash2" 480 140 240
    frame    data/bgs/sor3/st3a/lamps01.gif
    frame    data/bgs/sor3/st3a/lamps02.gif
    frame    data/bgs/sor3/st3a/lamps03.gif
    @cmd looper 8 8
    frame    data/bgs/sor3/st3a/lamps02.gif
    frame    data/bgs/sor3/st3a/lamps01.gif
        delay    320
    @cmd setVar "windForce" 0
    frame    data/bgs/sor3/st3a/lamps00.gif
    @cmd aniRandom "ANI_IDLE2"
    frame    data/bgs/sor3/st3a/lamps00.gif

Another thing that can be made is using a "reverse" dash+target. Commonly it's used for attacks, but this vortex entity can detect every opponent and use the dash+target code to apply a defined velocity according to the current distance from his offset and move all opponents near him.
 
@DCurrent & @kimono
correction: it is the only thing that sorta worked on my attempts.
so it is not the best solution.

basically, you have invisible entities "grabbing" the enemies on screen, & this activates their animation where they "panic" while grabbed, but i was neve able to give this a natural feel or randommized look, it was way too stiff & limited

so the biggest ingredient is missing and it pretty much what you describe here:
Wind effects are not difficult or complex at all. All you need to do is run an update that loops through entities on screen, check any conditions (like enemy vs. player), then adjust their position very slightly toward vortex. Then it's a matter of how much. You could make it small enough there's a slight pull they'd only notice when standing still, an overwhelming force that sucks them in almost instantly, or anything in between.

add to this wind effect a trigger for enemies to react using an animation & the effect should be good


i don't know the extent of what kimono wants , but i picture his "shadow" enemies being sort of tossed around the air PLUS a sort of "toilet flush" effect on them..

as far a the proton beams, i don't remeber saying it was impossible, but i dont think they would be walk in the park in the way i picture them...
 
@DCurrent: You are right, the vortex term is too general, the correct expression is a maelstrom:
75063691.jpg

A spiral move may be too complicated to code so an aspiration toward the center of the maelstrom could do the job like this:
v2xUAaC.png

@oldyz: Yes it's like a "toilet flush".
@Kratus: It's a swirl ;) . A wind effect could work and I can set a special pain that makes the enemies turn when they are in contact of the centered attack box :) .
 
Last edited:
@kimono

This script is not organized, I made it this way only to test and see how it works. But if you think it's useful, you can make the proper changes and adapt for your game.

In the video below, I used the attack button to activate the script, and the jump to disable it, but you can define any other way to activate/deactivate. The test was made using updateentity event of the Abadede (yes, the own entity will detect the variable and move itself), I believe this is one of the best places to use the code.

As a suggestion, you can put the setVar in the "swirl" entity, same as I did with Axel on the attack/jump animations. You can also activate attack boxes or detect animations, you can decide what is the best for your game.

C:
void main()
{//Simulates a "swirl" effect
    void self        = getlocalvar("self");
    void target        = findtarget(self);
    void ani        = getentityproperty(self, "animationID");
    float Px        = getentityproperty(self, "x");
    float Pz        = getentityproperty(self, "z");
    float Tx        = getentityproperty(target, "x");
    float Tz        = getentityproperty(target, "z");
    float xDir        = getentityproperty(self, "xdir");
    float zDir        = getentityproperty(self, "zdir");
    float xVel;
    float zVel;
    
    if(getglobalvar("test") == 1){
        if(Px > Tx){xVel = -0.004;}
        if(Px < Tx){xVel = 0.004;}
        if(Pz > Tz){zVel = -0.002;}
        if(Pz < Tz){zVel = 0.002;}
        
        executeanimation(self, openborconstant("ANI_PAIN"), 1);
        changeentityproperty(self, "velocity", xDir+xVel, zDir+zVel);

        if(Px - Tx < 4 && Px - Tx > -4){changeentityproperty(self, "velocity", 0, NULL());}
        if(Pz - Tz < 2 && Pz - Tz > -2){changeentityproperty(self, "velocity", NULL(), 0);}
    }
}

The "setVar" script is the same as I posted before.
anim attack1
fastattack 1
jugglecost 5
forcedirection -1
otg 1
loop 0
delay 4
offset 62 126
bbox 50 55 23 74
@cmd hitfx "LowPunch.wav"
@cmd sound "LowAttack.wav"
@cmd setVar "test" 1
#attack 62 61 9999 999 2000 1 1 0 5 999 #DEBUG TEST
frame data/chars/heroes/axel/a100.png
attack 62 61 42 13 2 0 0 0 5 12
frame data/chars/heroes/axel/a101.png
attack 0 0 0 0 0 0 0 0 0 0
frame data/chars/heroes/axel/a100.png

anim jump
loop 0
delay 30
offset 62 126
bbox 56 50 19 61
@cmd sound "Jumping.wav"
@cmd setVar "test" 0
frame data/chars/heroes/axel/jump00.png
frame data/chars/heroes/axel/jump01.png

 
You are very stong @Kratus and this swirl effect is great! I'm wondering one thing: how can I change the entity type that are affected by the aspiration?
For example, if I wish that obstacles and enemies are vulnerable to swirl how can I set this?
The contrary for an enemy that uses swirl, how can I determine and change the target(s)?
Is the opposite effect possible too, like pushing back all enemies?

Here is how I set the blendervortex but I miss something I suppose:

Code:
name            blendervortex

type            none
candamage         enemy obstacle
nolife            1
facing             1
lifespan        15
gfxshadow        1 1
offscreenkill    50
setlayer        -1

animationscript        data/chars/items/blender/vortex.c

anim     spawn
    delay    16
    offset    44 31
    bbox 0 0 88 40
    @cmd setVar "test" 1
    frame    data/chars/items/blender/blendervortex1.png
    frame    data/chars/items/blender/blendervortex2.png
    frame    data/chars/items/blender/blendervortex3.png
    frame    data/chars/items/blender/blendervortex4.png


anim    idle
    loop     1
    delay    16
    offset    44 31
    bbox 0 0 88 40
    delay    12   
    attack1 0 0 88 40 3 1 0 0 0 80   
    frame    data/chars/items/blender/blendervortex5.png
    frame    data/chars/items/blender/blendervortex6.png
    frame    data/chars/items/blender/blendervortex7.png
    attack1 0
    frame    data/chars/items/blender/blendervortex8.png

The vortex.c :
Code:
#import "data/scripts/library/target.h"
#import "data/scripts/library/spawn.h"
#import "data/scripts/library/basic.h"
#import "data/scripts/library/enemies.h"

void main()
{//Simulates a "swirl" effect
    void self        = getlocalvar("self");
    void target        = findtarget(self);
    void ani        = getentityproperty(self, "animationID");
    float Px        = getentityproperty(self, "x");
    float Pz        = getentityproperty(self, "z");
    float Tx        = getentityproperty(target, "x");
    float Tz        = getentityproperty(target, "z");
    float xDir        = getentityproperty(self, "xdir");
    float zDir        = getentityproperty(self, "zdir");
    float xVel;
    float zVel;
    
    if(getglobalvar("test") == 1){
        if(Px > Tx){xVel = -0.004;}
        if(Px < Tx){xVel = 0.004;}
        if(Pz > Tz){zVel = -0.002;}
        if(Pz < Tz){zVel = 0.002;}
        
        executeanimation(self, openborconstant("ANI_PAIN"), 1);
        changeentityproperty(self, "velocity", xDir+xVel, zDir+zVel);

        if(Px - Tx < 4 && Px - Tx > -4){changeentityproperty(self, "velocity", 0, NULL());}
        if(Pz - Tz < 2 && Pz - Tz > -2){changeentityproperty(self, "velocity", NULL(), 0);}
    }
}
 
Last edited:
@kimono

I made some updates in the script. Now you can select which type you want to affect by declaring it on the variable.
In addition, I turned the script "timed" to avoid the fps to change it's rate, otherwise you can have different aspiration forces on Windows and Android platforms.

C:
void swirl()
{//Simulates a "swirl" effect
    void self       = getlocalvar("self");
    void target     = getglobalvar("swirlEnt");
    void type       = getentityproperty(self, "type");
    void ani        = getentityproperty(self, "animationID");
    float time      = openborvariant("elapsed_time")/10;
    float Px        = getentityproperty(self, "x");
    float Pz        = getentityproperty(self, "z");
    float Tx        = getentityproperty(target, "x");
    float Tz        = getentityproperty(target, "z");
    float xDir      = getentityproperty(self, "xdir");
    float zDir      = getentityproperty(self, "zdir");
    float xVel;
    float zVel;

    if( getglobalvar("swirlType") == 2 && type == openborconstant("TYPE_PLAYER")||
        getglobalvar("swirlType") == 1 && type == openborconstant("TYPE_ENEMY")||
        getglobalvar("swirlType") == 1 && type == openborconstant("TYPE_OBSTACLE")){
       
        if(Px > Tx){xVel = -0.04;}
        if(Px < Tx){xVel = 0.04;}
        if(Pz > Tz){zVel = -0.02;}
        if(Pz < Tz){zVel = 0.02;}

        if(getglobalvar("swirlRate"+self) == NULL()){setglobalvar("swirlRate"+self, time);}

        if(time > getglobalvar("swirlRate"+self)){
            if(ani != openborconstant("ANI_IDLE")){executeanimation(self, openborconstant("ANI_IDLE"), 1);}
            changeentityproperty(self, "velocity", xDir+xVel, zDir+zVel);
            if(Px - Tx < 5 && Px - Tx > -5){changeentityproperty(self, "velocity", 0, NULL());}
            if(Pz - Tz < 5 && Pz - Tz > -5){changeentityproperty(self, "velocity", NULL(), 0);}
            setglobalvar("swirlRate"+self, time);
        }
    }
    else
    {
        changeentityproperty(self, "velocity", 0, 0);
    }
}

Another change was in the "findtarget" line. Now there's a "swirlEnt" that defines which entity is the current valid swirl at the moment.
anim attack1
fastattack 1
jugglecost 5
forcedirection -1
otg 1
loop 0
delay 4
offset 62 126
bbox 50 55 23 74
@cmd hitfx "LowPunch.wav"
@cmd sound "LowAttack.wav"
@cmd setVar "swirlType" 1
@cmd setVar "swirlEnt" getlocalvar("self")
#attack 62 61 9999 999 2000 1 1 0 5 999 #DEBUG TEST
frame data/chars/heroes/axel/a100.png
attack 62 61 42 13 2 0 0 0 5 12
frame data/chars/heroes/axel/a101.png
attack 0 0 0 0 0 0 0 0 0 0
frame data/chars/heroes/axel/a100.png


For example, if I wish that obstacles and enemies are vulnerable to swirl how can I set this?
The contrary for an enemy that uses swirl, how can I determine and change the target(s)?
Is the opposite effect possible too, like pushing back all enemies?
In case you do not want an specific entity to be vulnerable to any swirl, all you need to do is to not declare the script on your updateentity event. Remember that every entity manages its own swirl effect, the swirl entity in fact only is used to enable or disable the effect and declare itself as the current swirl.

If you want to change the affected entity, simple replace a type by another like this:
@cmd setVar "swirlType" 1
or
@cmd setVar "swirlType" 2

In addition, you can make multiple entities be vulnerable by the same variable. For example, you can define the obstacles to be vulnerable when the "1" type is enabled.
All you need to do is to make the obstacle entity use the same updateentity script event as the enemy, same as I made on the video below.

 
@kimono and @Kratus,

I don't think you need or even want to put this into every single model. It's much simpler to use a central update script with an entity enumerator. I would put this into the vortex model's update script, and at the bottom (see my comments) execute the math to pull other entities in. That way you only need to have code in one place, and it also doesn't need a bunch of variables. Just fire and forget.

C:
void main()
{
     dc_vortex_control();
}

/*
* Caskey, Damon V.
* 2022-01-26
*
* Example function to enumerate the entity
* collection and take action on each
* if they meet specfifc conditions.
*/
void dc_vortex_control()
{
    void    entity_cursor = NULL();
    int     entity_count = openborvariant("count_entities");
    int     entity_index = 0;
    int     exists = 0;

 
    /*   
    * This loop runs on every entity in play.
    * It works by iterating from 0 to <entity count>.
    * At each iteration it gets an entity using the
    * index cursor, verifies its existence, and then
    * runs some custom checks.
    *
    * If any check fails, the loop skips and
    * moves on to the next iteration. If all the
    * checks pass, it runs whatever action code
    * you place inside of it. The best practice
    * is to put your action code into another
    * function and let the loop execute that.
    */
    for (entity_index = 0; entity_index < entity_count; entity_index++)
    {
        /*
        * Get target entity for this loop increment,
        * verify it is a valid pointer, and make
        * sure it exists in play. The last check
        * appears redundant, but it's possible for
        * an entity to be removed while its pointer
        * is still valid.
        */

        entity_cursor = getentity(entity_index);

        if (!entity_cursor)
        {
            continue;
        }

        exists = getentityproperty(entity_cursor, "exists");

        if (!exists)
        {
            continue;
        }

        /*
        * Check for specific conditions to your module here.
        * This example skips non-enemy types.
        */

        if (getentityproperty(entity_cursor, "type") != openborconstant("TYPE_ENEMY"))
        {
            continue;
        }

        /* Take your actions here. Sucking in, doing damage, etc. */

    }
}
 
@DCurrent

Yeah, I really do not want to put this update script on every entity. The trick here was the "getentity" function, to be honest I never used or even knew what it does, thanks to clarify. For a global script that affects all entities, I think it's the best way.

The only thing I maintained is the "vortexRate" to avoid the script to be connected with every engine cycle, maintaining it "timed", otherwise the fps will change the effect according to the current platform (Windows runs at 200+ fps and Android always at 60 fps or below).

I will update my library with this new script, thanks again.


@kimono

Now the script became more simple to use. All you need to do is to put in the updateentity event on the "blendervortex" entity and make the final adjustments, like which animation will activate, on which entities it can affect and others like velocity.

C++:
void dc_vortex_control()
{    /*
    * Caskey, Damon V.
    * 2022-01-26
    *
    * Example function to enumerate the entity
    * collection and take action on each
    * if they meet specfifc conditions.
    */

    float time = openborvariant("elapsed_time")/10;
    if(getglobalvar("vortexRate") == NULL()){setglobalvar("vortexRate", time);}

    if(time > getglobalvar("vortexRate")){
        void entity_cursor    = NULL();
        int entity_count    = openborvariant("count_entities");
        int entity_index    = 0;
        int exists            = 0;

        /*
        * This loop runs on every entity in play.
        * It works by iterating from 0 to <entity count>.
        * At each iteration it gets an entity using the
        * index cursor, verifies its existence, and then
        * runs some custom checks.
        *
        * If any check fails, the loop skips and
        * moves on to the next iteration. If all the
        * checks pass, it runs whatever action code
        * you place inside of it. The best practice
        * is to put your action code into another
        * function and let the loop execute that.
        */

        for(entity_index = 0; entity_index < entity_count; entity_index++){
            /*
            * Get target entity for this loop increment,
            * verify it is a valid pointer, and make
            * sure it exists in play. The last check
            * appears redundant, but it's possible for
            * an entity to be removed while its pointer
            * is still valid.
            */

            entity_cursor = getentity(entity_index);

            if(!entity_cursor){
                continue;
            }

            exists = getentityproperty(entity_cursor, "exists");

            if(!exists){
                continue;
            }

            /*
            * Check for specific conditions to your module here.
            * This example skips non-enemy types.
            */

            if( getentityproperty(entity_cursor, "type") != openborconstant("TYPE_ENEMY")&&
                getentityproperty(entity_cursor, "type") != openborconstant("TYPE_OBSTACLE")){
                
                continue;
            }

            /* Take your actions here. Sucking in, doing damage, etc. */

            void self    = getlocalvar("self");
            void pAni    = getentityproperty(self, "animationID");

            //THIS IS THE ANIMATION THAT WILL ACTIVATE THE SWIRL EFFECT, YOU CAN PUT ANY OTHER
            if(pAni == openborconstant("ANI_FOLLOW11")){
                void tAni    = getentityproperty(entity_cursor, "animationID");
                float Px    = getentityproperty(self, "x");
                float Pz    = getentityproperty(self, "z");
                float Tx    = getentityproperty(entity_cursor, "x");
                float Tz    = getentityproperty(entity_cursor, "z");
                float xDir    = getentityproperty(entity_cursor, "xdir");
                float zDir    = getentityproperty(entity_cursor, "zdir");
                float xVel;
                float zVel;
                float range    = 5;

                if(Px > Tx){xVel = 0.04;}
                if(Px < Tx){xVel = -0.04;}
                if(Pz > Tz){zVel = 0.02;}
                if(Pz < Tz){zVel = -0.02;}

                if(tAni != openborconstant("ANI_IDLE") && !getentityproperty(entity_cursor, "dead")){
                    executeanimation(entity_cursor, openborconstant("ANI_IDLE"), 1);
                }

                changeentityproperty(entity_cursor, "velocity", xDir+xVel, zDir+zVel);

                if(Px - Tx < range && Px - Tx > -range){changeentityproperty(entity_cursor, "velocity", 0, NULL());}
                if(Pz - Tz < range && Pz - Tz > -range){changeentityproperty(entity_cursor, "velocity", NULL(), 0);}
            }
        }
        setglobalvar("vortexRate", time);
    }
}
 
Solution
Ok, first I try to use a anim follow1 but the entity stays like this at the end of the anim follow (I surely need to add a @beidle at the end of this :) ).
So, I activate the command with an animationscript and it seems to work correctly:

Code:
name            blendervortex
type            none
candamage         enemy obstacle
nolife            1
facing             1
lifespan        15
gfxshadow        1 1
offscreenkill    50
setlayer        -1

animationscript                data/chars/items/blender/vortex.c

anim     spawn
    delay    16
    offset    44 31
    bbox 0 0 88 40
    #@script
    #if(frame==3) {
    #performattack(getlocalvar("self"), openborconstant("ANI_follow1"));
    #}
    #@end_script   
    frame    data/chars/items/blender/blendervortex1.png
    frame    data/chars/items/blender/blendervortex2.png
    frame    data/chars/items/blender/blendervortex3.png
    frame    data/chars/items/blender/blendervortex4.png
    
anim    follow1
    loop     0
    delay    16
    offset    44 31
    bbox 0 0 88 40
    delay    12   
    attack1 0 0 88 40 3 1 0 0 0 80
    frame    data/chars/items/blender/blendervortex5.png
    frame    data/chars/items/blender/blendervortex6.png
    frame    data/chars/items/blender/blendervortex7.png
    attack1 0
    frame    data/chars/items/blender/blendervortex8.png   
    
anim    idle
    loop     1
    delay    16
    offset    44 31
    bbox 0 0 88 40
    delay    12   
    attack1 0 0 88 40 3 1 0 0 0 80   
    @cmd dc_vortex_control   
    frame    data/chars/items/blender/blendervortex5.png
    frame    data/chars/items/blender/blendervortex6.png
    frame    data/chars/items/blender/blendervortex7.png
    attack1 0
    frame    data/chars/items/blender/blendervortex8.png

Many thanks @Kratus and @DCurrent for this great script :). This opens gates for some new game type, like Luigi Mansion for example :) .
 
@kimono
It's good to know that the script worked :)

Did you test it on the update event? It's used to gradually increase speed or stop when necessary.
I'm showing an example in the video below.


@DCurrent
Thanks for the "getentity" example, it opens many possibilities.

 
@Kratus : I tried to declare the script with the line script {pathofthescript} but I obtain an exception error at the updateentity script at the openborlog.txt so I miss one step somewhere. I will take a look carefully at your video 😉.
 
Last edited:
@Kratus : I tried to declare the script with the line script {pathofthescript} but I obtain an exception error at the updateentity script at the openborlog.txt so I miss one step somewhere. I will take a look carefully at your video 😉.
Can you post the latest version of your game? I can take a look to see what's happening.

@kimono

EDIT: I downloaded the game using the link you posted before. I made two changes, removed the "setVar" from the blendervortex entity to not cause the engine crash (it's not necessary anymore) and replaced the "void swirl" by the "void main" on the "vortex.c" file, once it's the only script in this file.

I saw that you added the blender update even on Billy, I removed it to not interfere on the vortex.

Here's the full version of the latest vortex.c file:
C:
void main()
{    /*
    * Caskey, Damon V.
    * 2022-01-26
    *
    * Example function to enumerate the entity
    * collection and take action on each
    * if they meet specfifc conditions.
    */

    float time = openborvariant("elapsed_time")/10;
    if(getglobalvar("vortexRate") == NULL()){setglobalvar("vortexRate", time);}

    if(time > getglobalvar("vortexRate")){
        void entity_cursor    = NULL();
        int entity_count    = openborvariant("count_entities");
        int entity_index    = 0;
        int exists            = 0;

        /*
        * This loop runs on every entity in play.
        * It works by iterating from 0 to <entity count>.
        * At each iteration it gets an entity using the
        * index cursor, verifies its existence, and then
        * runs some custom checks.
        *
        * If any check fails, the loop skips and
        * moves on to the next iteration. If all the
        * checks pass, it runs whatever action code
        * you place inside of it. The best practice
        * is to put your action code into another
        * function and let the loop execute that.
        */

        for(entity_index = 0; entity_index < entity_count; entity_index++){
            /*
            * Get target entity for this loop increment,
            * verify it is a valid pointer, and make
            * sure it exists in play. The last check
            * appears redundant, but it's possible for
            * an entity to be removed while its pointer
            * is still valid.
            */

            entity_cursor = getentity(entity_index);

            if(!entity_cursor){
                continue;
            }

            exists = getentityproperty(entity_cursor, "exists");

            if(!exists){
                continue;
            }

            /*
            * Check for specific conditions to your module here.
            * This example skips non-enemy types.
            */

            if( getentityproperty(entity_cursor, "type") != openborconstant("TYPE_ENEMY")&&
                getentityproperty(entity_cursor, "type") != openborconstant("TYPE_OBSTACLE")){
               
                continue;
            }

            /* Take your actions here. Sucking in, doing damage, etc. */

            void self    = getlocalvar("self");
            void pAni    = getentityproperty(self, "animationID");

            //THIS IS THE ANIMATION THAT WILL ACTIVATE THE SWIRL EFFECT, YOU CAN PUT ANY OTHER
            if(pAni == openborconstant("ANI_IDLE")){
                void tAni    = getentityproperty(entity_cursor, "animationID");
                float Px    = getentityproperty(self, "x");
                float Pz    = getentityproperty(self, "z");
                float Tx    = getentityproperty(entity_cursor, "x");
                float Tz    = getentityproperty(entity_cursor, "z");
                float xDir    = getentityproperty(entity_cursor, "xdir");
                float zDir    = getentityproperty(entity_cursor, "zdir");
                float xVel;
                float zVel;
                float range    = 5;

                if(Px > Tx){xVel = 0.04;}
                if(Px < Tx){xVel = -0.04;}
                if(Pz > Tz){zVel = 0.02;}
                if(Pz < Tz){zVel = -0.02;}

                if(tAni != openborconstant("ANI_IDLE") && !getentityproperty(entity_cursor, "dead")){
                    executeanimation(entity_cursor, openborconstant("ANI_IDLE"), 1);
                }

                changeentityproperty(entity_cursor, "velocity", xDir+xVel, zDir+zVel);

                if(Px - Tx < range && Px - Tx > -range){changeentityproperty(entity_cursor, "velocity", 0, NULL());}
                if(Pz - Tz < range && Pz - Tz > -range){changeentityproperty(entity_cursor, "velocity", NULL(), 0);}
            }
        }
        setglobalvar("vortexRate", time);
    }
}

Here's the result using update event:
 
Last edited:
You can use the Shadows of Death swirl effect some posts above if you wish.
If I understand correctly, I need to create a new update entity script and add this one in void main dc_vortex_control.
 
You can use the Shadows of Death swirl effect some posts above if you wish.
If I understand correctly, I need to create a new update entity script and add this one in void main dc_vortex_control.
No need to create a new update entity script file, you can use the same "vortex.c" file.

In fact you will replace the "void dc_vortex_control()" by the "void main()". As an option, if you have the intention of adding multiple update entity scripts in the same file, you will need to declare the "void main()" and "void dc_vortex_control()" separately, same as DC did on the first original version of your script:

C:
void main()
{
     dc_vortex_control();
}

void dc_vortex_control()
{
    pasteAllScriptHere();
}

EDIT: A last addtion on the script after testing it directly on your game. I added a "lifespancountdown" check because sometimes when the vortex ends, some entities will continue moving. Now, a little before the vortex ends, it will stop velocity and set to idle instance in case certain enemies are not killed yet.

The only problem I saw (and it doesn't have connection with the script) is when the vortex ends and some enemies do not disapear. In fact they are dead because they already touched the vortex, but for some reason the "sucking" animation does not have enough time to finish and these enemies stay on the screen forever.
Maybe it can be solved with a delay adjustment.

**Solved it by adding a dead check at the end of the script.

Here's the file with all changes:

Here's the new script:
C:
void main()
{    /*
    * Caskey, Damon V.
    * 2022-01-26
    *
    * Example function to enumerate the entity
    * collection and take action on each
    * if they meet specfifc conditions.
    */
    void self   = getlocalvar("self");
    float time  = openborvariant("elapsed_time")/10;

    if(getglobalvar("vortexRate"+self) == NULL()){setglobalvar("vortexRate"+self, time);}

    if(time > getglobalvar("vortexRate"+self)){
        void entity_cursor    = NULL();
        int entity_count    = openborvariant("count_entities");
        int entity_index    = 0;
        int exists            = 0;

        /*
        * This loop runs on every entity in play.
        * It works by iterating from 0 to <entity count>.
        * At each iteration it gets an entity using the
        * index cursor, verifies its existence, and then
        * runs some custom checks.
        *
        * If any check fails, the loop skips and
        * moves on to the next iteration. If all the
        * checks pass, it runs whatever action code
        * you place inside of it. The best practice
        * is to put your action code into another
        * function and let the loop execute that.
        */

        for(entity_index = 0; entity_index < entity_count; entity_index++){
            /*
            * Get target entity for this loop increment,
            * verify it is a valid pointer, and make
            * sure it exists in play. The last check
            * appears redundant, but it's possible for
            * an entity to be removed while its pointer
            * is still valid.
            */

            entity_cursor = getentity(entity_index);

            if(!entity_cursor){
                continue;
            }

            exists = getentityproperty(entity_cursor, "exists");

            if(!exists){
                continue;
            }

            /*
            * Check for specific conditions to your module here.
            * This example skips non-enemy types.
            */

            if( getentityproperty(entity_cursor, "type") != openborconstant("TYPE_ENEMY")&&
                getentityproperty(entity_cursor, "type") != openborconstant("TYPE_OBSTACLE")){
             
                continue;
            }

            /* Take your actions here. Sucking in, doing damage, etc. */

            int lifespan    = getentityproperty(self, "lifespancountdown");

            //THIS IS THE ANIMATION THAT WILL ACTIVATE THE SWIRL EFFECT, YOU CAN PUT ANY OTHER
            if(lifespan > 5){
                void tAni    = getentityproperty(entity_cursor, "animationID");
                float Px    = getentityproperty(self, "x");
                float Pz    = getentityproperty(self, "z");
                float Tx    = getentityproperty(entity_cursor, "x");
                float Tz    = getentityproperty(entity_cursor, "z");
                float xDir    = getentityproperty(entity_cursor, "xdir");
                float zDir    = getentityproperty(entity_cursor, "zdir");
                float xVel;
                float zVel;
                float range    = 5;

                if(Px > Tx){xVel = 0.04;}
                if(Px < Tx){xVel = -0.04;}
                if(Pz > Tz){zVel = 0.02;}
                if(Pz < Tz){zVel = -0.02;}

                if(tAni != openborconstant("ANI_IDLE") && !getentityproperty(entity_cursor, "dead")){
                    executeanimation(entity_cursor, openborconstant("ANI_IDLE"), 1);
                }

                changeentityproperty(entity_cursor, "velocity", xDir+xVel, zDir+zVel);

                if(Px - Tx < range && Px - Tx > -range){changeentityproperty(entity_cursor, "velocity", 0, NULL());}
                if(Pz - Tz < range && Pz - Tz > -range){changeentityproperty(entity_cursor, "velocity", NULL(), 0);}
            }
            else
            {
                int dead = getentityproperty(entity_cursor, "dead");

                if(!dead){
                    changeentityproperty(entity_cursor, "velocity", 0, 0);
                    setidle(entity_cursor, openborconstant("ANI_IDLE"));
                }
            }
        }
        setglobalvar("vortexRate"+self, time);

    }
}
 
Last edited:
Thanks @Kratus, the script now works perfectly and I like the changing speed according the distance between the vortex and the affected entity :) . I like the way this script can simulate a magnetic force too, this can have many cool applications 8) .

I'm wondering if the opposite force is possible, starting for this script: an entity that generates a wave that pushes other entities away from the source?
Example: A sismic wave that pushes back obstacles and enemies.
 
Last edited:
Back
Top Bottom