Slamscript/antiwall struggles, enemies don't like walls?

MysticalMist

Active member
Hey guys,

So recently, I've just started working in OpenBOR to get my current project "Helluva Brawl", off the ground. So far, everything's been going fine and I've loved working with the slam/grab scripts. However, I can't seem to understand how to use the antiwall commands or overall, just how to address this situation.

My test stage has two walls (I am using Chronocrash Modder Toosl for reference): 1698599548627.png

The stage itself is pretty simple. I just wanted to make borders where the edges of the ring are.

However, when the player slams the opponent right up against or close enough to the wall, either the enemy teleports to the very top of the wall or gets stuck inside it.

Here's a video I recorded showing the issue:

Below is how I programmed the player's suplexes & piledriver:

PILEDRIVER (grabup):

landframe 4
attackone 0
fastattack 1
quakeframe 4 1 12
jumpframe 1 6
sound data/sounds/coco_pd.wav
attack.damage.force 0
attack.effect.hit.sound.path data/sounds/silence.wav
attack.position.x 0
attack.position.y 0
attack.size.x 0
attack.size.y 0
delay 30
offset 44 117
@cmd slamstart
@cmd position 0 5 0 -1 -1
frame data/chars/coco/jump/0.png
@cmd position 0 5 50 -1 -1
@cmd keymove 0.7
frame data/chars/coco/piledrive/0.png
sound data/sounds/swing.wav
delay 7
offset 21 88
@cmd position 0 15 5 -1 -1
@cmd keymove 0.7
frame data/chars/coco/piledrive/1.png
delay 999
offset 21 68
@cmd position 2 30 5 -1 -1
@cmd keymove 0.7
frame data/chars/coco/piledrive/2.png
delay 12
offset 21 68
sound data/sounds/slam.wav
@cmd spawn01 "flash" 30 1 1
frame data/chars/coco/piledrive/2.png
delay 24
offset 75 117
@cmd depost 0
@cmd throw 28 2 -2 2 0 0
@cmd clearL

FRONT SUPLEX (grabforward):

flipframe 1
attackone 0
quakeframe 2 1 8
fastattack 1
delay 20
sound data/sounds/Coco_atk03.wav
@cmd slamstart
@cmd position 0 40 25 -1 1
offset 55 114
attack.damage.force 0
attack.effect.hit.sound.path data/sounds/silence.wav
attack.position.x 0
attack.position.y 0
attack.size.x 0
attack.size.y 0
frame data/chars/coco/grabwalk/0.png
@cmd position 3 15 25 -1 1
delay 24
offset 80 114
frame data/chars/coco/backgrab/2.png
delay 18
offset 80 114
sound data/sounds/slam.wav
@cmd position 2 -60 0 -1 1
@cmd spawn01 "flash" -70 1 -5
frame data/chars/coco/backgrab/3.png
@cmd depost 0
@cmd throw 28 2 -2 2 0 0
@cmd antiwall -10 600 0
@cmd clearL
frame data/chars/coco/backgrab/3.png
offset 75 117
frame Data/Chars/Coco/backgrab/4.png

REAR SUPLEX (grabbackward):

attackone 0
quakeframe 2 1 8
fastattack 1
delay 20
sound data/sounds/Coco_atk03.wav
@cmd slamstart
@cmd position 0 40 25 -1 1
offset 55 114
attack.damage.force 0
attack.effect.hit.sound.path data/sounds/silence.wav
attack.position.x 0
attack.position.y 0
attack.size.x 0
attack.size.y 0
frame data/chars/coco/grabwalk/0.png
delay 24
@cmd position 3 15 25 -1 1
delay 24
offset 80 114
frame data/chars/coco/backgrab/2.png
delay 18
offset 80 114
sound data/sounds/slam.wav
@cmd position 2 -60 0 -1 1
@cmd spawn01 "flash" -70 1 -5
frame data/chars/coco/backgrab/3.png
@cmd depost 0
@cmd antiwall -10 600 0
@cmd throw 28 2 -2 2 0 0
@cmd clearL
frame data/chars/coco/backgrab/3.png
offset 75 117
frame Data/Chars/Coco/backgrab/4.png


I've read the entire manual and did what I could to dissect the scripts and figure out what the problem was, however I am not the best obviously, even I fear the solution may have been in front of me the whole time haha.

I would definitely appreciate the help, thank you all!
 
When I saw your other post, I was worried it would be too early to try to use a scripted slam.
Sorry for the wall of text, but I have a lot of (painful) experience with slamscript + antiwall so I can give you some tips.

I will give you the same advice I gave to other user here

I recommend that you study how the engine works first and then start worrying about scripts. Especially a script like scripted slam which can give you a lot of headaches.
And I saw you are using an antiwall script too, with makes things even more complicated if you don't know what you are doing.

I started writing a tutorial to explain my method, but I never finished it. However, you can read it here and get some ideas.

I'm not trying to discourage you, but every dev who wants to use scripts needs to keep this phrase in mind: "Scripts give you TOTAL control over the entity. And when we say TOTAL, we mean TOTAL - the engine will do solely and exclusively what you say for it to do."
In your example, the engine is doing exactly what you said - it is "dropping" the entity in the position you said. If there is a wall in that position, the engine takes one of two actions:

- If the wall is lower than a certain value (if I'm not mistaken, 3500), the entity appears on top of it.
- If the entity is higher than this, the entity is killed (better said, exterminated, as it does not perform any death animation, it is simply obliterated).

Looking at your code, I can see that the error is here:

@cmd position 2 -60 0 -1 1
@cmd spawn01 "flash" -70 1 -5
frame data/chars/coco/backgrab/3.png
@cmd depost 0
@cmd antiwall -10 600 0

1 - You are positioned the entity at -60 from you
2 - you are letting go of the entity
3 - and is applying an antiwall with a value of -10

The order in which this occurs and the values you passed are wrong. If you are not using an antiwall on the enemy's fall animation, you need to use the antiwall BEFORE dropping the enemy.

Another point: if you are going to drop the entity at -60 pixels from you, you need to check if there is a wall using the same value. In your case, you are dropping the entity at -60 but you are checking if there is a wall at -10px from you. In other words: if there is a wall -20px from you, the antiwall will not work, but the entity you dropped will remain inside the wall.

Also, you are making your character to move 600px from the wall if there is a wall at -10. On stages with walls on both sides, there is a huge chance of putting your character inside the other wall, killing it.

I usually always drop the entity in position 0 in relation to my character and this saves me a lot of headaches. But there are cases where this is not possible, like in a suplex.

This is the code I use in Hercules (I left only the frames that matter):

@cmd move 3 0 0
@cmd antiwall -15 55 0
@cmd spawn01 "stompfx" -48 0 0
@cmd spawn01 "crack" -48 0 -1
frame data/chars/hercules/hercules101.gif
delay 12
@cmd position 14 -44 5 0 0
@cmd depost 0
@cmd finish 35 2 4 -8 0 0
frame data/chars/hercules/ghit07.gif
delay 6
@cmd clearL
offset 39 87
frame data/chars/hercules/rise01.gif

See that I check if there is a wall at -15 but, if there is, I move my character 55px forward - and this happens BEFORE I even position the enemy in relation to me.

After that, I set the character to -44px (a value lower than 55), to be safe.

This value may be confusing for you, until you see where I position the axis:
1698602360811.png

and only after all this do I release the entity.
Keep in mind that this is a complex script and that it works well in an ideal scenario, but since you are working with scripts, you need to anticipate all possible scenarios.
For example, what happens to the enemy if your character dies from a time over? I'll give you a spoiler: it will stick with you.

That's why we always suggest studying the manual, understanding how the engine's native functions work before starting to use scripts, especially the more complex ones.
 
I'll give you an example of the difference between how native functions work versus scripting: moving a character a few pixels on the screen.

There is the native function "move {x}"

move {x}

Starting with the next frame, the entity will move forward (x) pixels with every new frame.
This value must be set to 0 again to stop the entity from moving any further during the animation.
You can use a negative value for (x) to move the entity backwards (Or slow their movement if they move automatically, like a jump attack).
Somewhere above 200, this value will allow an entity to run offscreen, out of play, and into oblivion. If you want to get rid of an entity, this should fit the bill, but otherwise you'll have a suicidal entity. If you ARE trying to kill something, use a value like 1000, just in case.

In the previous code, I used this function:

@cmd move 3 0 0
C-like:
void move(int dx, int dz, int da)
{ // Moves entity freely and ignores obstacles
     void self = getlocalvar("self");
     int x = getentityproperty(self,"x"); //Get character's x coordinate
     int z = getentityproperty(self,"z"); //Get character's z coordinate
     int a = getentityproperty(self,"a"); //Get character's a coordinate
     int dir = getentityproperty(self,"direction"); //Get character's facing direction


      if(dir==0){ // Facing left?
       changeentityproperty(self, "position", x-dx, z+dz, a+da); //Move
      }
      else if(dir==1){ // Facing right?
       changeentityproperty(self, "position", x+dx, z+dz, a+da); //Move
      }
}

What is the difference between the two?
In addition to the native "move" function remaining active in the same animation until you stop it, there is a big difference:

- The native version moves the entity by the value you passed but, behind the scenes, it performs a series of checks such as if there is a wall there, if there is an obstacle there, if the position is within the limits of the screen, etc. (The engine always does a series of checks behind the scenes and is very good at it).

- The scripted version doesn't give a sh*t about any of this - it simply takes the X position of your entity, adds a value and puts your entity in that new position.

And why doesn't the script care about this? Because you didn't tell the engine to worry about that :) It only does what you order.
 
Here's some updated scripts to use in conjuncture to what O Illu said.

C:
void throw(int damage, int type, int Vx, int Vy, int Vz, int face)
{//Damage as throw finisher
    void self     = getlocalvar("self");
    void target = getentityvar(self,"grabbed");
    int z         = getentityproperty(self,"z");
    int tDir     = getentityproperty(target,"direction");
    int vDir;
    
    if(face == 0){ //SAME FACING?
        vDir = tDir;
    }

    if(face == 1){ //OPPOSITE FACING?
        if(tDir == 0){ //FACING LEFT?
            vDir = 1;
        }else{
            vDir = 0;
        }
    }

    if(target != NULL()){
        void eType = getentityproperty(target,"type");
        int dir    = getentityproperty(target,"direction");
        void atkType;
        void projectile;
        
        if(dir == 0){Vx = -Vx;}
        if(type == 1){atkType = openborconstant("ATK_NORMAL8");}
        if(type == 2){atkType = openborconstant("ATK_NORMAL9");}
        if(z > (openborconstant("PLAYER_MIN_Z")+openborconstant("PLAYER_MAX_Z"))/2){Vz = -Vz ;}
        
        if(eType == openborconstant("TYPE_PLAYER") || eType == openborconstant("TYPE_NPC")){
            changeentityproperty(target, "projectilehit", "type_player", "type_npc", "type_obstacle");
        }
        else
        if(eType == openborconstant("TYPE_ENEMY")){
            changeentityproperty(target, "projectilehit", "type_enemy", "type_obstacle");
        }
        
        damageentity(target, self, 0, 1, atkType);
        changeentityproperty(target, "direction", vDir);
        changeentityproperty(target, "aiflag", "projectile", 1);
        changeentityproperty(target, "damage_on_landing", damage); //RESET PROJECTILE STATUS TO 0 WHEN FALL ON THE GROUND, TOTAL DAMAGE
        tossentity(target, Vy, Vx, Vz); //TOSS OPPONENT
        antiWallG();
        antiWall();
        setentityvar(self, "grabbed", NULL()); //CLEAR ENTITYVAR
    }
}

C:
void slam(int damage, int type, int Vx, int Vy, int Vz, int face)
{//Damage as slam finisher
    void self     = getlocalvar("self");
    void target = getentityvar(self,"grabbed");
    int tDir     = getentityproperty(target,"direction");
    int vDir;
    
    if(face == 0){ //SAME FACING?
        vDir = tDir;
    }

    if(face == 1){ //OPPOSITE FACING?
        if(tDir == 0){ //FACING LEFT?
            vDir = 1;
        }else{
            vDir = 0;
        }
    }

    if(target != NULL()){
        void eType = getentityproperty(target,"type");
        int dir    = getentityproperty(target,"direction");
        void atkType;
        void projectile;
        
        if(dir == 0){Vx = -Vx;}
        if(type == 1){atkType = openborconstant("ATK_NORMAL8");}
        if(type == 2){atkType = openborconstant("ATK_NORMAL");}
        
        if(eType == openborconstant("TYPE_PLAYER") || eType == openborconstant("TYPE_NPC")){
            changeentityproperty(target, "projectilehit", "type_player", "type_npc", "type_obstacle");
        }
        else
        if(eType == openborconstant("TYPE_ENEMY")){
            changeentityproperty(target, "projectilehit", "type_enemy", "type_obstacle");
        }
        
        damageentity(target, self, damage/1.5, 1, atkType); //SPLIT DAMAGE
        changeentityproperty(target, "direction", vDir);
        changeentityproperty(target, "aiflag", "projectile", 1);
        changeentityproperty(target, "damage_on_landing", damage/3); //RESET PROJECTILE STATUS TO 0 WHEN FALL ON THE GROUND, SPLIT DAMAGE
        antiWallG();
        antiWall();
        tossentity(target, Vy, Vx, Vz); //TOSS OPPONENT
        setentityvar(self, "grabbed", NULL()); //CLEAR ENTITYVAR
    }
}

these are to be used all together

C:
void antiWallG()
{//Checks distance from the walls, same as used in "animation event" but only for grab animations
 //If inside of the walls, entity will be moved away with defined movement
    void self         = getlocalvar("self");
    void target     = getentityvar(self, "grabbed");
    int x             = getentityproperty(self, "x");
    int Tx             = getentityproperty(target, "x");
    int z             = getentityproperty(self, "z");
    int Tz             = getentityproperty(target, "z");
    int subWall        = getentityproperty(self, "subject_to_wall");
    float wall         = checkwall(Tx, Tz);

    if(target != NULL()){
        if(wall){
            if(subWall == 1){
                changeentityproperty(target, "position", x, z);
                changeentityproperty(target, "velocity", 0, 0, NULL());
            }
        }
    }
}



void antiWall()
{//Checks distance from the walls
 //If inside of the walls, entity will be moved away with defined movement
    void self         = getlocalvar("self");
    void target     = getentityvar(self, "grabbed");
    int direction     = getentityproperty(self, "direction");
    int x             = getentityproperty(self, "x");
    int Tx             = getentityproperty(target, "x");
    int z             = getentityproperty(self, "z");
    int Tz             = getentityproperty(target, "z");
    int subWall        = getentityproperty(self, "subject_to_wall");
    float wall         = checkwall(Tx, Tz);

    if(target != NULL()){
        if(wall){
            if(subWall == 1){
                changeentityproperty(target, "position", x);
                changeentityproperty(target, "velocity", 0, 0, NULL());
            }
        }
    }
}
 
Just chiming in to confirm what both @O Ilusionista and @danno said. You need to check if your slammed opponent is in a wall before you release him. You can actually see this in professional games. Some move the slammed entity only, some move both. Ever notice how in Streets of Rage series if you slam someone into a wall, both of you are instantly pushed away enough the enemy doesn't end up inside it? Same principal.

What I like to do is run a loop that creates a temporary counting variable, tries moving the slammed opponent's offset one pixel away, then checks again. It keeps doing this until the slammed entity's theoretical location is exactly one pixel out of the wall. Once I have the amount I need to move, I then move the slamming entity that many pixels away. Since they are still bound together, this effectively moves both entities, and then I can release the slammed enemy safely.

My version is a bit more complex than the ones above, but I think it gives a more polished look.

Try out the methods posted, and if you have any questions, jump in and ask!

DC
 
Oh... bonus tip. This same principal also lets you create terrain based slams. Why just shunt from the wall, when you can USE the wall too. :D

See here At 00:42. At the start of a slam, if there's a wall nearby, the animation changes to an alternate where Ax picks Henninger up, smashes him into the wall behind, and then back around into his knee. Of course, the wall slam itself still needs a wall check, and if you look close you can see it working. Notice how Ax gets pushed away exactly enough to prevent wall clipping.

 
@O Ilusionista,

I absolutely agree and I thank you for the advice. I assure I've been doing my best to follow that. Even when I haven't been dedicated to a specific project, I've loved to test, experiment with native OpenBOR features, tinker with templates, used the manual practically like a bible, etc. I apologize if I was seemingly jumping the gun. I sometimes rush accidentally and have to backtrack in order to fix things, so boy I wanted to smack myself once you pointed out the obvious flaws in my command usage. I know I kind of over-relied on the scripts, so I'll try to be more specific and practice making the code unique to my purposes. I more or less kinda sorta have the same issues that user had with small details (especially with brackets and such), but I swear I'm trying to be as competent as I can be lol. So I'll be sure to fix that. Thank you!

@danno,

Much appreciated! I'll definitely check those scripts out in accordance to what Ilusionista mentioned. I'll get back to y'all, including @DCurrent, once I double-down and actually focus on what I'm doing.

Thank you all so much for your patience and replies!
 
So far, I'm trying out @danno's updated scripts, however the issue still persists and the new throwscript has seemingly messed with the enemy's fall animation (ex: the old throw script allowed the fall animation to work when set to 2, but now the enemy just remains upside down in its fall7 state until it recovers). Can someone help me figure out what I'm doing wrong real quick?

Also the antiwall cmd doesn't apply anymore it seems once I put that in unless I misinterpreted that as well?
 
Would you mind posting the text where you implemented the script?

Code:
anim grabup
    landframe    4
    attackone    0
    fastattack    1
    quakeframe    4 1 12
    jumpframe 1 6
    sound data/sounds/coco_pd.wav
    attack.damage.force 0
    attack.effect.hit.sound.path data/sounds/silence.wav
    attack.position.x 0
    attack.position.y 0
    attack.size.x 0
    attack.size.y 0
    delay    30
    offset    44 117
    @cmd slamstart
            @cmd position 0 5 0  -1 -1
    frame    data/chars/coco/jump/0.png
        @cmd position 0 5 50 -1 -1
        @cmd keymove 0.7
    frame    data/chars/coco/piledrive/0.png
    sound data/sounds/swing.wav
    delay    7
    offset    21 88
            @cmd position 0 15 5 -1 -1
            @cmd keymove 0.7
    frame    data/chars/coco/piledrive/1.png
    delay    999
    offset    21 68
            @cmd position 2 30 5 -1 -1
            @cmd keymove 0.7
    frame    data/chars/coco/piledrive/2.png
    delay    12
    offset    21 68
    sound data/sounds/slam.wav
    @cmd    spawn01 "flash" 30 1 1
    frame    data/chars/coco/piledrive/2.png
    offset    75 117

    frame    Data/Chars/Coco/backgrab/4.png
        @cmd    throw 28 2 4 -8 0 0
        @cmd    depost 0
        @cmd    clearL
        frame    Data/Chars/Coco/backgrab/4.png


This is just the piledriver script, but the result was more or less the same for the front and rear suplex.
 
Last edited by a moderator:
Thanks @MysticalMist! I'm about to leave on a long trip (literally have family over my shoulder pecking at me as I type this... yes, I'm going lol). I'll try to have a look when I get back... @Bloodbane, @danno, or @O Ilusionista might also be able to tell you something before I do.

In the meantime, something that will help us and you a lot, use code tags when you post stuff. It's a cool feature of the forum that will make things a lot more readable.

DC
 
@MysticalMist I just got back and took a quick look, and let @Bloodbane know about the thread since you are using his scripts. I also edited your post to use the code tags to give you an idea what they look like.

However, maybe I missed something, but I don't see a call to the Antiwall function at all. Are you calling it as part of another function?

DC
 
I misinterpreted @danno's post somewhat, the reason it wasn't added was because the "antiwall" in Danno's script didn't seem to be callable function, but my mistake was that I probably thought it was supposed to replace the animationscript function of "antiwall" and be an integrated thing for the slam & throw scripts (in which I did replace with).

Here's the updated code. Though, still not seeming to work the way I was hoping.


Code:
anim grabbackward
    attackone    0
    quakeframe 3 1 8
    fastattack    1
    @cmd slamstart
    @cmd antiwall -60 55 0
    delay 1
    frame    data/chars/coco/grabwalk/0.png
    offset    55 114
    attack.damage.force 0
    attack.effect.hit.sound.path data/sounds/silence.wav
    attack.position.x 0
    attack.position.y 0
    attack.size.x 0
    attack.size.y 0
    frame    data/chars/coco/grabwalk/0.png
    delay 24
    @cmd position 3 15 25 -1 1
    delay    24
    offset    80 114
    frame    data/chars/coco/backgrab/2.png
    delay  18
    offset    80 114
    sound data/sounds/slam.wav
    @cmd position 2 -60 0 -1 1
    @cmd    spawn01 "flash" -70 1 -5
    frame    data/chars/coco/backgrab/3.png
    offset    75 117
    @cmd    depost 0
    @cmd    slam 28 2 4 -8 0 0
    @cmd    clearL
    frame    Data/Chars/Coco/backgrab/4.png
   
anim grabforward
    flipframe 0
    attackone    0
    quakeframe 3 1 8
    fastattack    1
    @cmd slamstart
    @cmd antiwall -70 55 0
    delay 1
    frame    data/chars/coco/grabwalk/0.png
    sound data/sounds/Coco_atk03.wav
    delay 20
    @cmd position 0 40 25 -1 1
    offset    55 114
    attack.damage.force 0
    attack.effect.hit.sound.path data/sounds/silence.wav
    attack.position.x 0
    attack.position.y 0
    attack.size.x 0
    attack.size.y 0
    frame    data/chars/coco/grabwalk/0.png
    @cmd position 3 15 25 -1 1
    delay    24
    offset    80 114
    frame    data/chars/coco/backgrab/2.png
    delay  18
    offset    80 114
    sound data/sounds/slam.wav
    @cmd position 2 -60 0 -1 1
    @cmd    spawn01 "flash" -70  1 -5
    frame    data/chars/coco/backgrab/3.png
    offset    75 117
    @cmd    depost 0
    @cmd    throw 25 2 -1 3 0 0
    @cmd    clearL
    frame    Data/Chars/Coco/backgrab/4.png
anim grabup
    landframe    4
    attackone    0
    fastattack    1
    quakeframe    4 1 12
    jumpframe 1 6
    sound data/sounds/coco_pd.wav
    attack.damage.force 0
    attack.effect.hit.sound.path data/sounds/silence.wav
    attack.position.x 0
    attack.position.y 0
    attack.size.x 0
    attack.size.y 0
    delay    30
    offset    44 117
    @cmd slamstart
    @cmd position 0 5 0  -1 -1
    frame    data/chars/coco/jump/0.png
    @cmd position 0 5 50 -1 -1
    @cmd keymove 0.7
    frame    data/chars/coco/piledrive/0.png
    sound data/sounds/swing.wav
    delay    7
    offset    21 88
    @cmd position 0 15 5 -1 -1
    @cmd keymove 0.7
    frame    data/chars/coco/piledrive/1.png
    delay    999
    offset    21 68
    @cmd position 2 30 5 -1 -1
    @cmd keymove 0.7
    frame    data/chars/coco/piledrive/2.png
    delay    12
    offset    21 68
    sound data/sounds/slam.wav
    @cmd    spawn01 "flash" 30 1 1
    frame    data/chars/coco/piledrive/2.png
    offset    75 117
    frame    Data/Chars/Coco/backgrab/4.png
    @cmd    depost 0
    @cmd    throw 28 2 4 -8 0 0
    @cmd    clearL
    frame    Data/Chars/Coco/backgrab/4.png
 
I'll need to look closer when I start the day tomorrow, but at first glance it seems to me Antiwall is way too early. It should be called just before you unbind (release) the grabbed entity.

DC
 
I came here late so I'll start from latest posted code.
antiwall declaration looks good but I suggest breaking it into 3 or 4 steps like this:
Code:
anim grabbackward
    attackone    0
    quakeframe 3 1 8
    fastattack    1
    @cmd slamstart
    @cmd antiwall -60 15 0
    delay 1
    frame    data/chars/coco/grabwalk/0.png
    offset    55 114
    attack.damage.force 0
    attack.effect.hit.sound.path data/sounds/silence.wav
    attack.position.x 0
    attack.position.y 0
    attack.size.x 0
    attack.size.y 0
    @cmd antiwall -60 15 0
    frame    data/chars/coco/grabwalk/0.png
    delay 24
    @cmd antiwall -60 15 0
    @cmd position 3 15 25 -1 1
    delay    24
    offset    80 114
    frame    data/chars/coco/backgrab/2.png
    delay  18
    offset    80 114
    sound data/sounds/slam.wav
    @cmd antiwall -60 15 0
    @cmd position 2 -60 0 -1 1
    @cmd    spawn01 "flash" -70 1 -5
    frame    data/chars/coco/backgrab/3.png
    offset    75 117
    @cmd    depost 0
    @cmd    slam 28 2 4 -8 0 0
    @cmd    clearL
    frame    Data/Chars/Coco/backgrab/4.png

and this:
Code:
anim grabforward
    flipframe 0
    attackone    0
    quakeframe 3 1 8
    fastattack    1
    @cmd slamstart
    @cmd antiwall -60 15 0
    delay 1
    frame    data/chars/coco/grabwalk/0.png
    sound data/sounds/Coco_atk03.wav
    delay 20
    @cmd antiwall -60 15 0
    @cmd position 0 40 25 -1 1
    offset    55 114
    attack.damage.force 0
    attack.effect.hit.sound.path data/sounds/silence.wav
    attack.position.x 0
    attack.position.y 0
    attack.size.x 0
    attack.size.y 0
    frame    data/chars/coco/grabwalk/0.png
    @cmd position 3 15 25 -1 1
    @cmd antiwall -60 15 0
    delay    24
    offset    80 114
    frame    data/chars/coco/backgrab/2.png
    delay  18
    offset    80 114
    sound data/sounds/slam.wav
    @cmd antiwall -60 15 0
    @cmd position 2 -60 0 -1 1
    @cmd    spawn01 "flash" -70  1 -5
    frame    data/chars/coco/backgrab/3.png
    offset    75 117
    @cmd    depost 0
    @cmd    throw 25 2 -1 3 0 0
    @cmd    clearL
    frame    Data/Chars/Coco/backgrab/4.png

and this also:
Code:
anim grabup
    landframe    4
    attackone    0
    fastattack    1
    quakeframe    4 1 12
    jumpframe 1 6
    sound data/sounds/coco_pd.wav
    attack.damage.force 0
    attack.effect.hit.sound.path data/sounds/silence.wav
    attack.position.x 0
    attack.position.y 0
    attack.size.x 0
    attack.size.y 0
    delay    30
    offset    44 117
    @cmd slamstart
    @cmd position 0 5 0  -1 -1
    frame    data/chars/coco/jump/0.png
    @cmd position 0 5 50 -1 -1
    @cmd keymove 0.7
    frame    data/chars/coco/piledrive/0.png
    sound data/sounds/swing.wav
    delay    7
    offset    21 88
    @cmd position 0 15 5 -1 -1
    @cmd keymove 0.7
    frame    data/chars/coco/piledrive/1.png
    delay    999
    offset    21 68
    @cmd antiwall 30 -15 0
    @cmd position 2 30 5 -1 -1
    @cmd keymove 0.7
    frame    data/chars/coco/piledrive/2.png
    delay    12
    offset    21 68
    sound data/sounds/slam.wav
    @cmd antiwall 30 -15 0
    @cmd    spawn01 "flash" 30 1 1
    frame    data/chars/coco/piledrive/2.png
    offset    75 117
    frame    Data/Chars/Coco/backgrab/4.png
    @cmd    depost 0
    @cmd    throw 28 2 4 -8 0 0
    @cmd    clearL
    frame    Data/Chars/Coco/backgrab/4.png
 
@MysticalMist Just my two cents, here's the latest SORX grab scripts code that prevents wall stuck. The concept is simple, the grabbed opponent will be moved to the grabber's position once he is certainly outside of any wall, you can see my comments to understand what each step does.

Here's the effect.

Here's how used on Max.
C:
anim grabbackward #FRONT SLAM
    attackone 0
    fastattack 1
    jugglecost 0
    forcedirection 0
    otg 1
    loop    0
    delay    24
    offset    150 187
    @cmd grabStart
    @cmd position 0 20 0 0 0
    @cmd hitfx "data/sounds/sor3_hit6.wav"
    @cmd voice "data/voices/sor2_max_attack2.wav"
    frame    data/chars/heroes/max/slam00.png
        delay    8
    @cmd position 5 0 20 0 0
    frame    data/chars/heroes/max/slam01.png
    @cmd position 2 -40 35 0 0
    frame    data/chars/heroes/max/slam02.png
        delay    16
    attack 72 151 59 39 4 1 0 0 0 12
    @cmd position 4 -60 1 0 0
    @cmd quake "gradual" 10 4 1
    @cmd sound "data/sounds/sor3_slam.wav"
    frame    data/chars/heroes/max/slam03.png
    attack 0 0 0 0 0 0 0 0 0 0
    @cmd slam 8 2 2 2 0 0
    frame    data/chars/heroes/max/slam03.png
        delay    8
    @cmd clearL
    frame    data/chars/heroes/max/slam04.png

anim grabbackward2 #BACK SLAM
    attackone 0
    fastattack 1
    jugglecost 0
    forcedirection 0
    otg 1
    loop    0
    delay    24
    offset    150 187
    @cmd grabStart
    @cmd position 0 20 0 0 1
    @cmd hitfx "data/sounds/sor3_hit6.wav"
    @cmd voice "data/voices/sor2_max_attack2.wav"
    frame    data/chars/heroes/max/slam00.png
        delay    8
    @cmd position 5 0 20 0 0
    frame    data/chars/heroes/max/slam01.png
    @cmd position 4 -40 35 0 0
    frame    data/chars/heroes/max/slam02.png
        delay    16
    attack 72 151 59 39 4 1 0 0 0 12
    @cmd position 4 -60 1 0 0
    @cmd quake "gradual" 10 4 1
    @cmd sound "data/sounds/sor3_slam.wav"
    frame    data/chars/heroes/max/slam03.png
    attack 0 0 0 0 0 0 0 0 0 0
    @cmd slam 8 2 -2 2 0 0
    frame    data/chars/heroes/max/slam03.png
        delay    8
    @cmd clearL
    frame    data/chars/heroes/max/slam04.png

And here's the script, I cleaned the SORX variables but please let me know if you have crashes due to some typo.
C:
void grabStart()
{//Grab Starter for grab moves
 //Use SLAM or THROW after using this
    void self    = getlocalvar("self");
    void target    = getentityproperty(self, "grabbing");

    //IS THERE A GRABBED ENTITY?? PROCEED!!
    if(target != NULL()){
        setentityvar(self, "grabbed", target); //SAVE THE GRABBED ENTITY AS A NEW TARGET INSIDE AN ENTITYVAR
        damageentity(target, self, 0, 1, openborconstant("ATK_NORMAL7")); //PUT THE ENTITY IN A FALLING STATE
        changeentityproperty(target, "aiflag", "frozen", 1); //USED TO AVOID GRAB INTERRUPTION WHEN THE NODROPEN IS OFF AND ANY PLAYER IS RESPAWNED
    }
}

void grabStart2()
{//Grab Starter for non-grab moves
 //Use SLAM or THROW after using this
    void self    = getlocalvar("self");
    void target    = getentityproperty(self, "opponent");

    //IS THERE A DAMAGED ENTITY?? PROCEED!!
    if(target != NULL()){
        setentityvar(self, "grabbed", target); //SAVE THE GRABBED ENTITY AS A NEW TARGET INSIDE AN ENTITYVAR
        damageentity(target, self, 0, 1, openborconstant("ATK_NORMAL7")); //PUT THE ENTITY IN A FALLING STATE
        changeentityproperty(target, "aiflag", "frozen", 1); //USED TO AVOID GRAB INTERRUPTION WHEN THE NODROPEN IS OFF AND ANY PLAYER IS RESPAWNED
    }
}

void position(int tFrame, float dx, float dy, float dz, int face, void noWeight)
{//Modify grabbed entity's position relative to grabber
 //Use grabstart 1st before using this
    void self        = getlocalvar("self");
    void target        = getentityvar(self,"grabbed");
    int dead        = getentityproperty(target,"dead");

    //THERE'S A NEW TARGET SAVED IN THE VARIABLE??
    if(target != NULL()){

        //USED WHEN PLAYER DIES BY TIME OVER AND THE GRABBER IS THE ENEMY
        if(dead){
            bindentity(target, NULL());
            damageentity(target, self, 0, 1, openborconstant("ATK_NORMAL"));
            damageentity(self, self, 0, 1, openborconstant("ATK_NORMAL"));
            setentityvar(self, "grabbed", NULL());
        }else
        
        //DEFAULT
        {
            updateframe(target, tFrame);
            bindentity(target, self, dx, dz, dy, face, 0);
        }
    }
}

void slam(int damage, int type, int Vx, int Vy, int Vz, int face)
{//Damage as slam finisher
    void self    = getlocalvar("self");
    void target    = getentityvar(self,"grabbed");
    int tDir    = getentityproperty(target,"direction");
    int vDir;
    
    if(face == 0){ //SAME FACING?
        vDir = tDir;
    }

    if(face == 1){ //OPPOSITE FACING?
        if(tDir == 0){ //FACING LEFT?
            vDir = 1;
        }
        else
        {
            vDir = 0;
        }
    }

    if(target != NULL()){
        void atkType;
        void eType        = getentityproperty(target,"type");
        int dir            = getentityproperty(target,"direction");
        int dropType    = 1;
        
        if(dir == 0){Vx = -Vx;}
        if(type == 1){atkType = openborconstant("ATK_NORMAL8");}
        if(type == 2){atkType = openborconstant("ATK_NORMAL9");}
        
        if(eType == openborconstant("TYPE_PLAYER") || eType == openborconstant("TYPE_NPC")){
            changeentityproperty(target, "projectilehit", "type_player", "type_npc", "type_obstacle");
        }
        else
        if(eType == openborconstant("TYPE_ENEMY")){
            changeentityproperty(target, "projectilehit", "type_enemy", "type_obstacle");
        }
        
        //SPLIT DAMAGE, USE "1" TO NOT PLAY THE "SLAM" SOUND WHEN HIT THE GROUND
        damageentity(target, self, damage-1, dropType, atkType);
        changeentityproperty(target, "direction", vDir);
        changeentityproperty(target, "damage_on_landing", 1); //RESET PROJECTILE STATUS TO 0 WHEN FALL ON THE GROUND, SPLIT DAMAGE
        changeentityproperty(target, "aiflag", "projectile", 1);
        finishGrab(Vx, Vy, Vz); //EXECUTE ALL NECESSARY TASKS TO END THE GRAB MOVE (ANTIWALL, UNBIND AND TOSSENTITY)
        setentityvar(self, "grabbed", NULL()); //CLEAR ENTITYVAR
    }
}

void throw(int damage, int type, int Vx, int Vy, int Vz, int face)
{//Damage as throw finisher
    void self    = getlocalvar("self");
    void target    = getentityvar(self,"grabbed");
    int z        = getentityproperty(self,"z");
    int tDir    = getentityproperty(target,"direction");
    int vDir;
    
    if(face == 0){ //SAME FACING?
        vDir = tDir;
    }

    if(face == 1){ //OPPOSITE FACING?
        if(tDir == 0){ //FACING LEFT?
            vDir = 1;
        }
        else
        {
            vDir = 0;
        }
    }

    if(target != NULL()){
        void atkType;
        void eType        = getentityproperty(target,"type");
        int dir            = getentityproperty(target,"direction");
        int dropType    = 1;
        
        if(dir == 0){Vx = -Vx;}
        if(type == 1){atkType = openborconstant("ATK_NORMAL8");}
        if(type == 2){atkType = openborconstant("ATK_NORMAL9");}
        
        if(eType == openborconstant("TYPE_PLAYER") || eType == openborconstant("TYPE_NPC")){
            changeentityproperty(target, "projectilehit", "type_player", "type_npc", "type_obstacle");
        }
        else
        if(eType == openborconstant("TYPE_ENEMY")){
            changeentityproperty(target, "projectilehit", "type_enemy", "type_obstacle");
        }
        
        damageentity(target, self, 0, dropType, atkType);
        changeentityproperty(target, "direction", vDir);
        changeentityproperty(target, "damage_on_landing", damage); //RESET PROJECTILE STATUS TO 0 WHEN FALL ON THE GROUND, TOTAL DAMAGE
        changeentityproperty(target, "aiflag", "projectile", 1);
        finishGrab(Vx, Vy, Vz); //EXECUTE ALL NECESSARY TASKS TO END THE GRAB MOVE (ANTIWALL, UNBIND AND TOSSENTITY)
        setentityvar(self, "grabbed", NULL()); //CLEAR ENTITYVAR
    }
}

void finishGrab(int Vx, int Vy, int Vz)
{//This new function was created by mixing the "antiwall", "depost" and "tossentity" into a unique function
    void self    = getlocalvar("self");
    void target    = getentityvar(self, "grabbed");
    
    if(target != NULL()){
        int x        = getentityproperty(self, "x");
        int Tx        = getentityproperty(target, "x");
        int z        = getentityproperty(self, "z");
        int Tz        = getentityproperty(target, "z");
        int wall    = checkwall(Tx, Tz);

        if(wall){ //WAS DETECTED ANY WALL IN THE TARGET'S POSITION?? RUN ALL TASKS BELOW!!
            changeentityproperty(target, "position", x, z); //FIX THE GRABBED ENTITY'S POSITION ACCORDING TO GRABBER CORRDINATES BEFORE THE OPPONENT IS RELEASED
            bindentity(target, NULL()); //RELEASE GRABBED ENTITY, NOW THE OLD FUNCTION "DEPOST" WORKS HERE
            tossentity(target, Vy); //TOSS OPPONENT WITH Y VELOCITY ONLY, THIS WAY THE RELEASED OPPONENT WILL NOT BE MOVED AGAINST A WALL AGAIN
        }
        else //NO WALLS DETECTED?? ONLY THE DEFAULT TASKS WILL RUN
        {
            bindentity(target, NULL()); //RELEASE GRABBED ENTITY, NOW THE OLD FUNCTION "DEPOST" WORKS HERE
            tossentity(target, Vy, Vx, Vz); //TOSS OPPONENT WITH NORMAL VELOCITY, X, Y AND Z
        }
    }
}
 
Hey guys, sorry for the delay!

First of all, @Kratus, thank you so, so much. I think those scripts seemingly worked out pretty well! I won't jump the gun and guarantee the grapples are flawless now but I will take full accountability since I ended up having to fix up the walls anyway. That being said, the wall issues have yet to re-occur, much to my relief.

Thank you all as well (@O Ilusionista, @danno, @DCurrent, @Bloodbane). I will follow up on this thread just in case anything else goes south regarding the slamscripts, but things have definitely improved. I definitely appreciate the detailed info and scripts everyone shared, actually kinda help me get back in the habit of dissecting and tinkering with variables, functions, etc. since I last worked in the engine lol. Hopefully I can be smarter about coding/complex aspects of OpenBOR moving forward.
 
Back
Top Bottom