Trouble with Blocking System

maxman

Well-known member
I created a blocking system for holding the back key with animation script. Plus, there are two scripts that correlate the blocking. One is for making the opponent block and the other is for resulting the unblocking afterwards.

C:
void makeOpponentBlock(){
//void opponent = whatever method you use to get opponent;
//int opponentIndex = get your opponent player index;
//function variable name = script function
    void self = getlocalvar("self");
    //void opponent = findtarget(self);
    void opponent = getentityproperty(self, "opponent");
    int P1 = getplayerproperty(0, "entity");
    int P2 = getplayerproperty(1, "entity");
    //void opp1 = findtarget(P1);
    //void opp2 = findtarget(P2);

    void opp1 = getentityproperty(P1, "opponent");
    void opp2 = getentityproperty(P2, "opponent");

    int opponentIndex = getentityproperty(opponent, "playerindex"); // in the future, you should check that opponent is indeed of type player
    int iDir1 = getentityproperty(opp1, "direction");
    int iDir2 = getentityproperty(opp2, "direction");
    int iDir = getentityproperty(opponent, "direction");
    int iLeft = playerkeys(opponentIndex, 0, "moveleft");
    int iLeft1 = playerkeys(opp1, 0, "moveleft");
    int iLeft2 = playerkeys(opp2, 0, "moveleft");
    int iRight = playerkeys(opponentIndex, 0, "moveright");
    int iRight1 = playerkeys(opp1, 0, "moveright");
    int iRight2 = playerkeys(opp2, 0, "moveright");
    void vAniID = getentityproperty(opponent, "animationid");
    void vAniID1 = getentityproperty(opp1, "animationid");
    void vAniID2 = getentityproperty(opp2, "animationid");
    int frame = getentityproperty(opponent, "animpos");
    int frame1 = getentityproperty(opp1, "animpos");
    int frame2 = getentityproperty(opp2, "animpos");
    int type;
    int attacking = getentityproperty(opponent, "attacking");
    float x = getentityproperty(self, "x");
    float z = getentityproperty(self, "z");

   
    int i = 0;
    void opp = NULL();
   
    for(i = 0; i < openborvariant("count_entities"); ++i){
        void entity = getentity(i);
       
        if(getentityproperty(entity, "exists")){
            void type = getentityproperty(entity, "type");
            if(type == openborconstant("TYPE_ENEMY")){
                opp = entity;
                break;
            }
        }
    }
   
    if(getentityproperty(opp, "exists") && opp != NULL()){
        int attacking = getentityproperty(opp, "attacking");
        void opp = findtarget(opponent);
       
        float Tx = getentityproperty(opp, "x");
        float Tz = getentityproperty(opp, "z");
        float Disx = Tx - x;
        float Disz = Tz - z;
       
    //    if(Disz < 0){
    //        Disz = -Disz;
    //    }
   
        //if(iDir = 0){
        //    Disx = -Disx;
        //}
           
           
            if(vAniID == openborconstant("ANI_BACKWALK")){
                if( /*Disx >= 0 && Disx <= 30 && */ iDir == 1 && iLeft) // Target within range on right facing?
                {
                    performattack(opponent, openborconstant("ANI_FOLLOW4"));
                    tossentity(opponent, 0, 0, 0);
                }else if( /*Disx >= -30 && Disx <= 0 && */ iDir == 0 && iRight) // Target within range on left facing?
                {
                    performattack(opponent, openborconstant("ANI_FOLLOW4"));
                    tossentity(opponent, 0, 0, 0);
                }
            }
           
           
           
            if(vAniID == openborconstant("ANI_DUCK") && frame == 2){
                if(iDir == 1 && iLeft) // Target within range on right facing?
                {
                    performattack(opponent, openborconstant("ANI_FOLLOW5"));
                    tossentity(opponent, 0, 0, 0);
                }else if( iDir == 0 && iRight) // Target within range on left facing?
                {
                    performattack(opponent, openborconstant("ANI_FOLLOW5"));
                    tossentity(opponent, 0, 0, 0);
                }
            }
           
        //}
    }
   
    log("\nopponentIndex" + "\nopponent");
   
}

C:
void makeOpponentUnblock(){

    void self = getlocalvar("self");
    void opponent = findtarget(self);
    int opponentIndex = getentityproperty(opponent, "playerindex");
    int iDir = getentityproperty(opponent, "direction");
    int iLeftH = playerkeys(opponentIndex, 0, "moveleft");
    int iRightH = playerkeys(opponentIndex, 0, "moveright");
    int iLeftR = playerkeys(opponentIndex, 2, "moveleft");
    int iRightR = playerkeys(opponentIndex, 2, "moveright");
    void vAniID = getentityproperty(opponent, "animationid");
   
//    log("\nopponentIndex " + opponent);
//    makeOpponentBlock();

    if(vAniID == openborconstant("ANI_FOLLOW5")){ //During Crouch block
        if(iDir == 1 && (iLeftR || iLeftH)){ //Facing right?
            performattack(opponent, openborconstant("ANI_DUCK"),2); //Switch back to crouching? 2 is not used as frame, but as a reset flag and it's recommended
//            changeentityproperty(opponent, "animation", openborconstant("ANI_DUCK"),2);
            updateframe(opponent,2); //Change to third frame under animation if an animation flag is set to 2 (NOT third frame; NOT anim attack2)
        }else if(iDir == 0 && (iRightR || iRightH)){ //Facing left?
            performattack(opponent, openborconstant("ANI_DUCK"),2); //Crouch unblocked? performattack(entity, animation, flag);
            updateframe(opponent,2);//updateframe(entity, frame);
        }
    }
   
    if(vAniID == openborconstant("ANI_FOLLOW4")){
        if((iDir == 1 && (iLeftR || iLeftH)) || (iDir == 0 && (iRightR || iRightH))){ //Facing RIGHT while HOLDING OR RELEASING left, OR facing LEFT while HOLDING OR RELEASING right?
            setidle(opponent, openborconstant("ANI_IDLE"));
        }
    }

}

Code:
anim    attack #Low punch
    delay    2
    offset    24 99
    bbox 5 0 56 101
    @cmd    makeOpponentBlock
    @cmd    attack1 0 58 0 "ANI_ATTACK4" #attack1 {minx} {maxx} {z} {animation}
    sound data/sounds/common/punch.wav
    frame    data/chars/ryu/161.gif
    attack1 50 6 46 20 7 0 0 0 23 0 0
    bbox 5 0 63 101
    @cmd    makeOpponentBlock
    frame    data/chars/ryu/162.gif
    @cmd    makeOpponentBlock
    frame    data/chars/ryu/163.gif
    attack1 0 0 0 0 0 0 0 0 0 0 0
    bbox 5 0 56 101
    @cmd    makeOpponentUnblock
    frame    data/chars/ryu/164.gif
    offset    25 99
    frame    data/chars/ryu/165.gif

Here are the blocking animations.
blocking-animations-png.5528


I copied the guard script under anim pain from the Map demo but modified it for holding the back key. But when I hold back while getting hit with pain anim, the health bar doesn't reduce.
anim-pain-on-blocking-mechanics-png.5525


My main problem with the blocking system is that when you hold the back key for performing it, you have to get hit first. That's when you're able to perform blocking animation after.

I use findtarget and it seems to work, but it crashes when you try to use block when a projectile reaches you. That's why I started using the opponent property instead of findtarget.

Code:
    void opp1 = findtarget(P1);
    void opp2 = findtarget(P2);

Player projectile:
Code:
name  KHadoken
type  trap
nolife 1
health 1
gfxshadow 0
speed 8
remove 1
#nomove 1
alpha 1
setlayer 300
#hitenemy 1 0
antigravity 100
#lifespan 100000
offscreenkill 69 #USING OFFSCREENKILL IS A MUST WHEN IT COMES TO SUMMONING PROJECTILES ONCE UNTIL IT GETS KILLED OFFSCREEN OR HITS A FIGHTER OR PROJECTILE
hostile trap player enemy none npc
candamage npc none enemy player trap
#hitenemy 1 0
didhitscript data/scripts/projectilehit.c
animationscript data/scripts/special.c
#ondoattackscript data/scripts/knocker.c
#onspawnscript @script
    void main(){
        void self = getlocalvar("self");
        changeentityproperty(self, "candamage", (1 + 4096) || (2 + 4096) || (1 + 2048) || (2 + 2048) || (5 + 4096) || (9 + 2048) || (9 + 4096));
//Players, enemies, none, and trap types
    }
@end_script


anim    follow1
@script
void self = getlocalvar("self");
if(frame==0){
    changeentityproperty(self, "velocity", 0, 0, 0);
    setindexedvar("AfterHadou",1);
}
if(frame==16){
    killentity(self);
}
    @end_script    
    delay    2
    offset    37 22
    @cmd    makeOpponentUnblock
    frame    data/chars/misc/hadoken/0700500000.gif # 0
    offset    71 54
    frame    data/chars/misc/hadoken/0700500001.gif # 1
    offset    61 42
    frame    data/chars/misc/hadoken/0700500002.gif # 2
    offset    59 45
    frame    data/chars/misc/hadoken/0700500003.gif # 3
    offset    62 46
    frame    data/chars/misc/hadoken/0700500004.gif # 4
    offset    65 46
    frame    data/chars/misc/hadoken/0700500005.gif # 5
    offset    68 46
    frame    data/chars/misc/hadoken/0700500006.gif # 6
    offset    70 44
    frame    data/chars/misc/hadoken/0700500007.gif # 7
    offset    71 38
    frame    data/chars/misc/hadoken/0700500008.gif # 8
    offset    71 39
    frame    data/chars/misc/hadoken/0700500009.gif # 9
    offset    70 40
    frame    data/chars/misc/hadoken/0700500010.gif # 10
    offset    69 40
    frame    data/chars/misc/hadoken/0700500011.gif # 11
    offset    67 41
    frame    data/chars/misc/hadoken/0700500012.gif # 12
    frame    data/chars/misc/hadoken/0700500013.gif # 13
    offset    63 40
    frame    data/chars/misc/hadoken/0700500014.gif # 14
    offset    46 37
    frame    data/chars/misc/hadoken/0700500015.gif # 15
    offset    1 1
    frame    data/chars/misc/empty.gif # 16
        
anim    follow2
@script
void self = getlocalvar("self");
if(frame==0){
    changeentityproperty(self, "velocity", 0, 0, 0);
}
if(frame==15){
    killentity(self);
}
    @end_script
    loop    0
    delay    2
    offset    37 22
    @cmd    makeOpponentUnblock
    frame    data/chars/misc/hadoken/0700500000.gif
    offset    71 54
    frame    data/chars/misc/hadoken/0700500001.gif
    offset    61 42
    frame    data/chars/misc/hadoken/0700500002.gif
    offset    59 45
    frame    data/chars/misc/hadoken/0700500003.gif
    offset    62 46
    frame    data/chars/misc/hadoken/0700500004.gif
    offset    65 46
    frame    data/chars/misc/hadoken/0700500005.gif
    offset    68 46
    frame    data/chars/misc/hadoken/0700500006.gif
    offset    70 44
    frame    data/chars/misc/hadoken/0700500007.gif
    offset    71 38
    frame    data/chars/misc/hadoken/0700500008.gif
    offset    71 39
    frame    data/chars/misc/hadoken/0700500009.gif
    offset    70 40
    frame    data/chars/misc/hadoken/0700500010.gif
    offset    69 40
    frame    data/chars/misc/hadoken/0700500011.gif
    offset    67 41
    frame    data/chars/misc/hadoken/0700500012.gif
    frame    data/chars/misc/hadoken/0700500013.gif
    offset    63 40
    frame    data/chars/misc/hadoken/0700500014.gif
    offset    46 37
    frame    data/chars/misc/hadoken/0700500015.gif
    offset    1 1
    frame    data/chars/misc/empty.gif
        
anim follow3
@script
void self = getlocalvar("self");
if(frame==0){
    changeentityproperty(self, "velocity", 0, 0, 0);
    setindexedvar("AfterHadou",1);
}
if(frame==4){
    killentity(self);
}
    @end_script
    delay    2
    offset    1 1
    frame    data/chars/misc/empty.gif
    frame    data/chars/misc/empty.gif
    frame    data/chars/misc/empty.gif
    frame    data/chars/misc/empty.gif
    frame    data/chars/misc/empty.gif

anim idle
@script
       void self = getlocalvar("self");

    changeentityproperty(self, "name", "Ken");

    changeentityproperty(self, "candamage", openborconstant("TYPE_NONE"), openborconstant("TYPE_ENEMY"), openborconstant("TYPE_PLAYER"), openborconstant("TYPE_NPC"), openborconstant("TYPE_TRAP"));
    changeentityproperty(self, "subject_to_platform", 0);

    @end_script
    hitfx data/sounds/empty.wav
    platform 1 1 1 1 1 1 1 1
    attack17 309 284 34 21 15 0 0 0 0 0 0
    sound data/chars/misc/hadoken/sp1a.wav
    loop    1 1
    delay    2
    followanim    1
    #followanim    3
    followcond    1
    #hitflash empty
    hitflash kiru
    #hitflash specflash
    offset    336 292
    bbox 309 284 34 21
    platform 1 1 1 1 1 1 1 1
    @cmd    makeOpponentBlock
    #delay 8
    frame    data/chars/misc/kenf/cvs2_ken_39.png
    @cmd    makeOpponentBlock
    attack17 309 284 34 21 15 0 0 0 0 0 0
    bbox 309 284 34 21
    delay 8
    frame    data/chars/misc/kenf/cvs2_ken_39.png
    attack17 309 284 34 21 15 0 0 0 0 0 0
    bbox 309 284 34 21
    @cmd    makeOpponentBlock
    frame    data/chars/misc/kenf/cvs2_ken_40.png
    attack17 309 284 34 21 15 0 0 0 0 0 0
    bbox 309 284 34 21
    @cmd    makeOpponentBlock
    frame    data/chars/misc/kenf/cvs2_ken_41.png
    attack17 309 284 34 21 15 0 0 0 0 0 0
    bbox 309 284 34 21
    @cmd    makeOpponentBlock
    frame    data/chars/misc/kenf/cvs2_ken_42.png
    attack17 309 284 34 21 15 0 0 0 0 0 0
    bbox 309 284 34 21
    @cmd    makeOpponentBlock
    frame    data/chars/misc/kenf/cvs2_ken_43.png
    attack17 309 284 34 21 15 0 0 0 0 0 0
    bbox 309 284 34 21
    @cmd    makeOpponentBlock
    frame    data/chars/misc/kenf/cvs2_ken_44.png
    attack17 309 284 34 21 15 0 0 0 0 0 0
    bbox 309 284 34 21
    @cmd    makeOpponentBlock
    frame    data/chars/misc/kenf/cvs2_ken_45.png
    attack17 309 284 34 21 15 0 0 0 0 0 0
    bbox 309 284 34 21
    @cmd    makeOpponentBlock
    frame    data/chars/misc/kenf/cvs2_ken_46.png
    attack17 309 284 34 21 15 0 0 0 0 0 0
    bbox 309 284 34 21
    @cmd    makeOpponentBlock
    frame    data/chars/misc/kenf/cvs2_ken_47.png
    attack17 309 284 34 21 15 0 0 0 0 0 0
    bbox 309 284 34 21
    @cmd    makeOpponentBlock
    frame    data/chars/misc/kenf/cvs2_ken_48.png
        
#|edited by openBor Stats v 0.67

This code is behind limiting how many projectiles to unleash.
C:
anim    freespecial11 #Hadoken
@script

if(frame==0){
    void self = getlocalvar("self");
    setlocalvar("hadouken_count" + self, 0);
    int i;
    for(i = 0;i < openborvariant("ent_max"); ++i){
        void ent = getentity(i);
        if(getentityproperty(ent, "exists")){
            if(getentityproperty(ent, "type") == openborconstant("type_trap") && getentityproperty(ent, "model") == "KHadoken"){
                setlocalvar("hadouken_count" + self, getlocalvar("hadouken_count" + self + 1));
            }
        }
    }
    int hadouken_count = getlocalvar("hadouken_count" + self);
    if(hadouken_count<1){
        performattack(self, openborconstant("ani_follow21"));
    }
    setlocalvar("hadouken_count" + self, NULL());
}

@end_script
    bbox    312 193 56 103
    offset    336 292
    delay    6
    platform 312 292 0 0 45 45 4 75
    frame    data/chars/ken/cvs2_ken_65.png


anim follow21 #Start Hadouken
    offset    336 292
    delay 7
    bbox 316 192 50 101
    sound    data/chars/ken/khadou.wav
    frame    data/chars/ken/cvs2_ken_414.png
    bbox 316 197 51 98
    frame    data/chars/ken/cvs2_ken_415.png
    bbox 316 200 51 94
    frame    data/chars/ken/cvs2_ken_416.png
    bbox 324 200 53 94
    frame    data/chars/ken/cvs2_ken_417.png
    @cmd    makeOpponentBlock
    @cmd spawnAndThrow "khadoken" 80 0 70 0.5 NULL() NULL() #spawnAndThrow {projectilename} {x} {z} {y} {vx} {vz} {vy}
    bbox 335 202 52 91
    frame    data/chars/ken/cvs2_ken_418.png
    frame    data/chars/ken/cvs2_ken_419.png
    frame    data/chars/ken/cvs2_ken_420.png
    delay 13
    frame    data/chars/ken/cvs2_ken_421.png
    delay 8
    frame    data/chars/ken/cvs2_ken_422.png
    bbox 330 200 57 91
    frame    data/chars/ken/cvs2_ken_423.png
    bbox 324 195 57 98
    frame    data/chars/ken/cvs2_ken_424.png
    bbox 316 192 56 101
    frame    data/chars/ken/cvs2_ken_425.png
    bbox 312 192 56 103
    frame    data/chars/ken/cvs2_ken_426.png

This one is for projectile and it works like you play in any SF game which you are limited to unleash a projectile once until it hits or misses its target.
C:
void spawnAndThrow(void projName, float xPos, float zPos, float yPos, float fX, float fZ, float fY){
    
    void proj = spawn01(projName, xPos, yPos, zPos);
    throwProj(proj, fX, fZ, fY); 
}

void throwProj(void proj, float fX, float fZ, float fY){

    void self = getlocalvar("self");
    void target = getentityproperty(self, "opponent");
    void parent = getentityproperty(self, "parent");
    void index = getentityproperty(self, "playerindex");

    if(fX == -77) fX = getlocalvar("x"+self);
    else if(fX == -33) fX = getlocalvar("x"+self) / 2;
    else if (getentityproperty(proj, "direction")==0){
        fX = -fX;
    }
    
    if(fZ == -77) fZ = getlocalvar("z"+self);
    else if(fZ == -33) fZ = getlocalvar("z"+self) / 2;
    
    
    changeentityproperty(proj, "velocity", fX, fZ, fY);

}

How can I allow a player to make a firmly automatic block without having to get hit first? The player does not block every time its opponent poses any attacks.
 
I copied the guard script under anim pain from the Map demo but modified it for holding the back key

Which guard script? I've checked it and Fighter is the only one with 50% dodge script in his damagescript.

Anyways, I've made quick read of this thread and I really don't understand why you would need the attacker to order the opponent to block.
I always consider blocking in Fighting games as "if opponent is attacking when player is moving back, do block instead". IOW you should be checking if opponent is attacking you or not to decide to block or not when moving backward. I guess range check is also needed here.
 
Which guard script? I've checked it and Fighter is the only one with 50% dodge script in his damagescript.
Indeed. That's the Fighter's guard damagescript (Dodger.c). I used the Fighter's damage script as a reference for the pain animation.

I copied this one from the Map demo.
C:
anim pain1
@script
    if(frame == 0){
      void self = getlocalvar("self");
      int Dodge = getentityvar(self, 8);

      if(Dodge == 1){
        changeentityproperty(self, "animation", openborconstant("ANI_FREESPECIAL5"));
      }
    }
@end_script
    shadowcoords 218 198
    bbox    0 0 0 0
    delay   1
    offset     225 198
    frame    data/chars/fighter/pain101.gif
    delay   6
    sound   data/sounds/pain01.wav
    frame    data/chars/fighter/pain101.gif
    delay   2
    frame    data/chars/fighter/pain102.gif
    delay   2
    frame    data/chars/fighter/pain101.gif
    delay   2
    frame    data/chars/fighter/pain102.gif
    delay   2
    frame    data/chars/fighter/pain101.gif
    delay   2
    frame    data/chars/fighter/pain102.gif
    
    delay   2
    move    -5
    frame    data/chars/fighter/pain101.gif
    frame    data/chars/fighter/pain101.gif
    move    -4
    frame    data/chars/fighter/pain101.gif
    frame    data/chars/fighter/pain101.gif
    move    -4
    frame    data/chars/fighter/pain101.gif
    frame    data/chars/fighter/pain101.gif
    move    -3
    frame    data/chars/fighter/pain101.gif
    frame    data/chars/fighter/pain101.gif
    move    -3
    frame    data/chars/fighter/pain101.gif
    frame    data/chars/fighter/pain101.gif
    move    -2
    frame    data/chars/fighter/pain101.gif
    frame    data/chars/fighter/pain101.gif
    move    -2
    frame    data/chars/fighter/pain101.gif
    frame    data/chars/fighter/pain101.gif
    move    -1
    frame    data/chars/fighter/pain101.gif
    frame    data/chars/fighter/pain101.gif
    move    -1
    frame    data/chars/fighter/pain101.gif
    frame    data/chars/fighter/pain101.gif
    
    move    0
    delay   2
    offset     228 198
    frame    data/chars/fighter/pain101.gif
    offset     225 198
    frame    data/chars/fighter/pain101.gif
    offset     222 198
    frame    data/chars/fighter/pain101.gif
    offset     225 198
    frame    data/chars/fighter/pain101.gif
    offset     228 198
    frame    data/chars/fighter/pain101.gif
    offset     225 198
    frame    data/chars/fighter/pain101.gif
    offset     222 198
    frame    data/chars/fighter/pain101.gif
    offset     225 198
    frame    data/chars/fighter/pain101.gif


anim    freespecial5
    shadowcoords 218 198
    delay    36
#    counterframe 0 1 0
#    followanim 1
#    bbox    212 143 30 55
     offset     225 198
    sound   data/sounds/block01.wav
    frame    data/chars/fighter/guard00.gif

This is my damage script I have for the player which I renamed it to guard.c.
C:
void main(){
    void self = getlocalvar("self");
    int index = getentityproperty(self, "playerindex");
    int left = playerkeys(index, 0, "moveleft");
    int right = playerkeys(index, 0, "moveright");
    int y = getentityproperty(self, "a");
    int direction = getentityproperty(self, "direction");
    int HP = getentityproperty(self, "health");
    void aniID = getentityproperty(self, "animationid");
    void target = getentityproperty(self, "opponent");
    void tAniID = getentityproperty(target, "animationid");
    int damage = getlocalvar("damage");
    int r = rand()%30;
    int lastHitY = openborvariant("lasthity");
    //void Block = loadsample("data/sounds/block.wav");
    
    if((lastHitY > 52) && ((direction == 1 && left) || (direction == 0 && right))){
//        if(r > 0){
            setentityvar(self, "guard", 1);
            changeentityproperty(self, "health", HP + damage);
        }else if((lastHitY <= 52) && ((direction == 1 && left) || (direction == 0 && right))){
            setentityvar(self, "guard", NULL());
//        }
    }
}

While you block, the player plays pain animation instead of block animation after the projectile hits you. However, the player's lifebar doesn't deplete. That's because I'm trying to not let the health bar reduce after/while blocking. Maybe I would like the health bar to reduce slightly when the opponent performs with any special move.

Anyways, I've made quick read of this thread and I really don't understand why you would need the attacker to order the opponent to block.
I always consider blocking in Fighting games as "if opponent is attacking when player is moving back, do block instead". IOW you should be checking if opponent is attacking you or not to decide to block or not when moving backward. I guess range check is also needed here.
Thanks, Bloodbane! 😁 Does that mean I'm gonna have to use checkrange() for range checks between a player and the opponent? Do you have an example of how checkrange is used? Not only am I struggling with the player blocking in PvP matches, but also one player mode against any CPU opponents. I do want the players to block as you said. Block when the opponent does attack. In closed range or open (far) range?

checkrange(entity, target, int animid)

  • Check if the given target is in range. Range, rangez, rangea of the specified animation will be used for checking.
  • entity - animation owner. Must be a valid entity handle. Required.
  • target - must be a valid entity handle. Required.
  • animid - animation id. Optional. If it is not given, current animation will be used.
 
Back
Top Bottom