Training Lessons

dantedevil

Well-known member
I have the idea of ​​doing a lesson-based training. In order to advance to the next lesson you must fulfill a goal. Like they had some fighting games in training.
To make this possible, I think you would need a script that gives the enemy immunity to all attack animations, except one that we can specify.
I need this script to give the enemy immunity against attack animations and not against certain attacks, since there are many animations that share the same type of attack.
So this way the lesson only can advance when you connect the attack animation.
 
It's still the basics so it's expandable :)

all the dialogue lesson begin to pass one another until I finish, without my having taken a single blow

Why do you want to receive a blow during training?

In my endlevel.c, I need add the lines of your enlevel.c

It's okay as long you don't erase any lines I added before

If I execute a fatality on the enemy at the wrong time, how do I reset the positions and disappear all the remains of the fatality?

Hmm... I haven't made position reset yet let alone clean up script
Now that you mention that, you might need to disable fatality FX if it's executed at wrong time

I'm going to make position reset in mean time
 
Hmmm... are you using indexed variable somewhere before?
This lesson system uses two indexed variable : 0 and 1 BTW

[couple minutes later]

I discovered that story system is using some indexed variables and that might conflict this lesson system. Alright, I'll rename indexed variables I'm using to prevent conflict in the future :)
 
Thanks my firend!

So I need to modify some scripts, or do you already have the demo with the necessary modifications?

The indexed variables where are they located in updated.c?
 
I've updated the demo with position reset FX and will upload it after I'm done renaming indexed variable

The indexed variables where are they located in updated.c?

Technically, they are located in memory. And there are multiple files calling these variables
 
Bloodbane said:
Here you go:

https://www.mediafire.com/file/sp5638gssobdd6a/Lesson2.rar

Thanks my friend!

The reset works great.

Sorry but not working in my demo.
Still the same problem of the video.

You need my script folder to check?

I send you a pm with a link to my folder scripts.
 
Finally work!!!

II decided to delete all files and copy the new ones instead of replacing them. Then all works ok.

I have a problems with the reset, because some moves look bad after the reset. Like you perform ok the grabattack lesson, then the reset push away the characters, but sill in grab both.
I think the reset will be better off, and turn on in certain moves.

After some test, only have some questions:

1) Is it possible to deactivate the PosReset and to only activate if you kill the enemy with the wrong movement?

2) Is there a limit to add animations in this script?

Code:
void Lesson(int Code)
{// Selects animation constant based on defined code
    void Anim;

    if(Code==6){
      Anim = openborconstant("ANI_FREESPECIAL");
    } else if(Code==5){
      Anim = openborconstant("ANI_SPECIAL");
    } else if(Code==4){
      Anim = openborconstant("ANI_GRABATTACK2");
    } else if(Code==3){
      Anim = openborconstant("ANI_GRABATTACK");
    } else if(Code==2){
      Anim = openborconstant("ANI_JUMPATTACK2");
    } else if(Code==1){
      Anim = openborconstant("ANI_JUMPATTACK");
    } else {
      Anim = openborconstant("ANI_ATTACK3");
    }

    return Anim;
}

3) Do ANIM FOLLOW work in this script?

4) Is it possible to make one lesson accept two different animations as correct?
Because there are cases where my heroes have Random Attack at the end of the combo, and the script of the lesson sometimes does not recognize as successful.

5) If I add 30 animations, how should I edit the Lesson.txt?
I do not understand much the relation in the order of the frames

Code:
name		Lesson
type		panel
speed		10
facing		1
setlayer 	10000


anim	idle
@script
    void self = getlocalvar("self");
    int Code = getindexedvar("Lesn");
    int Warn = getindexedvar("Wait");

    if(Code==NULL()){
      Code = 0;
    }

    if(Warn==NULL()){
      Warn = 0;
    }

    if(frame==2 && (Code < 1 || Warn != 2)){
      updateframe(self, 1);
    }
    if(frame==3 || frame==6 || frame==9 || frame==12 || frame==15 || frame==18){
      setindexedvar("Wait", 0);
    }
    if(frame==5 && (Code < 2 || Warn != 2)){
      updateframe(self, 4);
    }
    if(frame==8 && (Code < 3 || Warn != 2)){
      updateframe(self, 7);
    }
    if(frame==11 && (Code < 4 || Warn != 2)){
      updateframe(self, 10);
    }
    if(frame==14 && (Code < 5 || Warn != 2)){
      updateframe(self, 13);
    }
    if(frame==17 && (Code < 6 || Warn != 2)){
      updateframe(self, 16);
    }
    if(frame==20 && (Code < 7 || Warn != 2)){
      updateframe(self, 19);
    }
    if(frame==21){
      setindexedvar("Wait", 0);
      killentity(self);
    }
@end_script
	delay	5
	offset	160 200
	frame	data/chars/misc/dialogue/lesson1.png
	frame	data/chars/misc/dialogue/lesson1.png
	frame	data/chars/misc/dialogue/lesson1.png
	frame	data/chars/misc/dialogue/lesson2.png
	frame	data/chars/misc/dialogue/lesson2.png
	frame	data/chars/misc/dialogue/lesson2.png
	frame	data/chars/misc/dialogue/lesson3.png
	frame	data/chars/misc/dialogue/lesson3.png
	frame	data/chars/misc/dialogue/lesson3.png
	frame	data/chars/misc/dialogue/lesson6.png # 10
	frame	data/chars/misc/dialogue/lesson6.png
	frame	data/chars/misc/dialogue/lesson6.png
	frame	data/chars/misc/dialogue/lesson7.png
	frame	data/chars/misc/dialogue/lesson7.png
	frame	data/chars/misc/dialogue/lesson7.png
	frame	data/chars/misc/dialogue/lesson5.png
	frame	data/chars/misc/dialogue/lesson5.png
	frame	data/chars/misc/dialogue/lesson5.png
	frame	data/chars/misc/dialogue/lesson4.png
	frame	data/chars/misc/dialogue/lesson4.png # 20
	frame	data/chars/misc/dialogue/lesson4.png
	frame	data/chars/misc/empty.png
 
Glad you got this to work :)

1) Is it possible to deactivate the PosReset and to only activate if you kill the enemy with the wrong movement?

Yes, I'll edit the script for you :)

2) Is there a limit to add animations in this script?

Currently I limit it to 7 animations but you can expand the limit by editing this line:

Code:
    if(Code<7){

in lecmun.c in data/scripts folder

3) Do ANIM FOLLOW work in this script?

As long it has attackbox, it should work

4) Is it possible to make one lesson accept two different animations as correct?
Because there are cases where my heroes have Random Attack at the end of the combo, and the script of the lesson sometimes does not recognize as successful.

It's possible but I'd need to modify the script for that

5) If I add 30 animations, how should I edit the Lesson.txt?
I do not understand much the relation in the order of the frames

Hmmm... basically, one lesson image is for one move (though since it's only an image, you can type two or more moves). So for 30 more moves you need to add 30 more images
And you need to define 3 frames for one image
Also:
Code:
    if(frame==17 && (Code < 6 || Warn != 2)){
      updateframe(self, 16);
    }

this portion of code loops image until player has performed the correct move on the enemy. That means you need to clone that part per added image.
This next part:
Code:
    if(frame==21){
      setindexedvar("Wait", 0);
      killentity(self);
    }

is for killing this entity after all moves are done properly. The frame counter should expanded after adding more frames of course :)
This line:
Code:
    if(frame==3 || frame==6 || frame==9 || frame==12 || frame==15 || frame==18){
      setindexedvar("Wait", 0);
    }

is for resetting wait system. This lesson entity will only proceed to next image only after positions of fighters have been reseted BTW
That line must be expanded with added frames too

It may sound much but don't worry, I'll help you if you find problem :)
 
Well my friend, I have all the info to make all changes.

1) The animations marked in red are those that fail to advance to the next lesson, because they do not have a frame with has attackbox.
The main problem comes qhen the the characters spawn an entity to attack.
To solve this would be necessary (in the animations in red) , that the lesson is effective at the moment the animation is executed, without the need a frame with it has attackbox.

N°  LESSON Name           Animation
1    COMBO                         attack3
2    JUMPATTACK                 anim jumpforward
3    JUMPATTACK2               anim jumpattack2
4    JUMPATTACK3             anim jumpattack3
5    ATTACKBACKWARD      anim attackbackward
6    GRABATTACK               anim grabattack2
7    GRABBACKWARD       anim grabbackward
8    GRABFORWARD         anim grabforward
9    GRABDOWN               anim grabdown
10  GRABUP                     anim grabup
11  MORTAL GRAB         anim freespecial9
12  DIVE CATCH             anim jumpspecial
13  GROUND ATTACK     anim follow 15
14  COMBO BREAKER   anim freespecial41
15  RISEATTACK             anim riseattack
16  SUPER RISEATTACK  anim freespecial8

17  SPECIAL                     anim freespecial6
18  SUPER ATTACK       anim special
19  SUPER COMBO       anim freespecial5
20  FINAL COMBO         anim freespecial33
21  NO MERCY               anim follow32
22  FATALITY1               anim follow20
23  FATALITY2               anim follow42
24  FATALITY3               anim follow43
25  FATALITY4               anim follow44
26  Standard Stage Fat.  anim freespecial35

2)  There are certain animations that would not look good if the lesson ends when they are still running. But if we delete the reset and only leave it for certain animations, there is no problem.
Ideally, the reset will be executed after the animations of the No Mercy and the 4 fatalities are finished.
21  NO MERCY               anim follow32
22  FATALITY1               anim follow20
23  FATALITY2               anim follow42
24  FATALITY3               anim follow43
25  FATALITY4               anim follow44
Once the Standard Stage Fatality is finished, it would be best if there was no reset.
And that will show a message saying "TRaining Complete", and then send us to the menu.

3) Here the updated  Lecmun.c:

Code:
void main()
{// Deny damage if attacked with wrong animation
    void self = getlocalvar("self"); //Get calling entity.
    int HP = getentityproperty(self, "health");
    void target = getentityproperty(self,"opponent");
    void TAnim = getentityproperty(target, "animationID");
    int Damage = getlocalvar("damage"); //Get received damage
    int Code = getindexedvar("Lesn");
    int Warn = getindexedvar("Wait");

    if(Code==NULL()){
      Code = 0;
    }

    if(Warn==NULL()){
      Warn = 0;
    }

    if(Code<26){
      void LAnim = Lesson(Code);

      if(TAnim == LAnim && Warn==0){
        setindexedvar("Lesn", Code+1);
        setindexedvar("Wait", 1);
      } else {
        changeentityproperty(self, "health", HP + Damage);
      }
    }
}

void Lesson(int Code)
{// Selects animation constant based on defined code
    void Anim;

    if(Code==25){
      Anim = openborconstant("ANI_FREESPECIAL35");
    } else if(Code==24){
      Anim = openborconstant("ANI_FOLLOW44");
    } else if(Code==23){
      Anim = openborconstant("ANI_FOLLOW43");
    } else if(Code==22){
      Anim = openborconstant("ANI_FOLLOW42");
    } else if(Code==21){
      Anim = openborconstant("ANI_FOLLOW20");
    } else if(Code==20){
      Anim = openborconstant("ANI_FOLLOW32");
    } else if(Code==19){
      Anim = openborconstant("ANI_FREESPECIAL33");
    } else if(Code==18){
      Anim = openborconstant("ANI_FREESPECIAL5");
    } else if(Code==17){
      Anim = openborconstant("ANI_SPECIAL");
    } else if(Code==16){
      Anim = openborconstant("ANI_FREESPECIAL6");
    } else if(Code==15){
      Anim = openborconstant("ANI_FREESPECIAL8");
    } else if(Code==14){
      Anim = openborconstant("ANI_RISEATTACK");
    } else if(Code==13){
      Anim = openborconstant("ANI_FREESPECIAL41");
    } else if(Code==12){
      Anim = openborconstant("ANI_FOLLOW15");
    } else if(Code==11){
      Anim = openborconstant("ANI_JUMPSPECIAL");
    } else if(Code==10){
      Anim = openborconstant("ANI_FREESPECIAL9");
    } else if(Code==9){
      Anim = openborconstant("ANI_GRABUP");
    } else if(Code==8){
      Anim = openborconstant("ANI_GRABDOWN");
    } else if(Code==7){
      Anim = openborconstant("ANI_GRABFORWARD");
    } else if(Code==6){
      Anim = openborconstant("ANI_GRABBACKWARD");
    } else if(Code==5){
      Anim = openborconstant("ANI_GRABATTACK2");
    } else if(Code==4){
      Anim = openborconstant("ANI_ATTACKBACKWARD");
    } else if(Code==3){
      Anim = openborconstant("ANI_JUMPATTACK3");
    } else if(Code==2){
      Anim = openborconstant("ANI_JUMPATTACK2");
    } else if(Code==1){
      Anim = openborconstant("ANI_JUMPFORWARD");
    } else {
      Anim = openborconstant("ANI_ATTACK3");
    }

    return Anim;
}
 
Well my friend, I am trying to help as much as I can and I continued to update the Lesson.txt.

Here my updated Lesson.txt, let me know if ok.

Code:
name		Lesson
type		panel
speed		10
facing		1
setlayer 	10000


anim	idle
@script
    void self = getlocalvar("self");
    int Code = getindexedvar("Lesn");
    int Warn = getindexedvar("Wait");

    if(Code==NULL()){
      Code = 0;
    }

    if(Warn==NULL()){
      Warn = 0;
    }

    if(frame==2 && (Code < 1 || Warn != 2)){
      updateframe(self, 1);
    }
    if(frame==3 || frame==6 || frame==9 || frame==12 || frame==15 || frame==18 ||
 frame==21 || frame==24 || frame==27 || frame==30 || frame==33 || frame==36 ||
 frame==39 || frame==42 || frame==45 || frame==48 || frame==51 || frame==54 ||
 frame==57 || frame==60 || frame==63 || frame==66 || frame==69 || frame==72 ||frame==75){
      setindexedvar("Wait", 0);
    }
    if(frame==5 && (Code < 2 || Warn != 2)){
      updateframe(self, 4);
    }
    if(frame==8 && (Code < 3 || Warn != 2)){
      updateframe(self, 7);
    }
    if(frame==11 && (Code < 4 || Warn != 2)){
      updateframe(self, 10);
    }
    if(frame==14 && (Code < 5 || Warn != 2)){
      updateframe(self, 13);
    }
    if(frame==17 && (Code < 6 || Warn != 2)){
      updateframe(self, 16);
    }
    if(frame==20 && (Code < 7 || Warn != 2)){
      updateframe(self, 19);
    }
    if(frame==23 && (Code < 8 || Warn != 2)){
      updateframe(self, 22);
    }
    if(frame==26 && (Code < 9 || Warn != 2)){
      updateframe(self, 25);
    }
    if(frame==29 && (Code < 10 || Warn != 2)){
      updateframe(self, 28);
    }
    if(frame==32 && (Code < 11 || Warn != 2)){
      updateframe(self, 31);
    }
    if(frame==35 && (Code < 12 || Warn != 2)){
      updateframe(self, 34);
    }
    if(frame==38 && (Code < 13 || Warn != 2)){
      updateframe(self, 37);
    }
    if(frame==41 && (Code < 14 || Warn != 2)){
      updateframe(self, 40);
    }
    if(frame==44 && (Code < 15 || Warn != 2)){
      updateframe(self, 43);
    }
    if(frame==47 && (Code < 16 || Warn != 2)){
      updateframe(self, 46);
    }
    if(frame==50 && (Code < 17 || Warn != 2)){
      updateframe(self, 49);
    }
    if(frame==53 && (Code < 18 || Warn != 2)){
      updateframe(self, 52);
    }
    if(frame==56 && (Code < 19 || Warn != 2)){
      updateframe(self, 55);
    }
    if(frame==59 && (Code < 20 || Warn != 2)){
      updateframe(self, 58);
    }
    if(frame==62 && (Code < 21 || Warn != 2)){
      updateframe(self, 61);
    }
    if(frame==65 && (Code < 22 || Warn != 2)){
      updateframe(self, 64);
    }
    if(frame==68 && (Code < 23 || Warn != 2)){
      updateframe(self, 67);
    }
    if(frame==71 && (Code < 24 || Warn != 2)){
      updateframe(self, 70);
    }
    if(frame==74 && (Code < 25 || Warn != 2)){
      updateframe(self, 73);
    }
    if(frame==77 && (Code < 26 || Warn != 2)){
      updateframe(self, 76);
    }
    if(frame==78){
      setindexedvar("Wait", 0);
      killentity(self);
    }
@end_script
	delay	5
	offset	160 200
	frame	data/chars/misc/dialogue/lesson1.png
	frame	data/chars/misc/dialogue/lesson1.png
	frame	data/chars/misc/dialogue/lesson1.png
	frame	data/chars/misc/dialogue/lesson2.png
	frame	data/chars/misc/dialogue/lesson2.png
	frame	data/chars/misc/dialogue/lesson2.png
	frame	data/chars/misc/dialogue/lesson3.png
	frame	data/chars/misc/dialogue/lesson3.png
	frame	data/chars/misc/dialogue/lesson3.png
	frame	data/chars/misc/dialogue/lesson4.png
	frame	data/chars/misc/dialogue/lesson4.png
	frame	data/chars/misc/dialogue/lesson4.png
	frame	data/chars/misc/dialogue/lesson5.png
	frame	data/chars/misc/dialogue/lesson5.png
	frame	data/chars/misc/dialogue/lesson5.png
	frame	data/chars/misc/dialogue/lesson6.png
	frame	data/chars/misc/dialogue/lesson6.png
	frame	data/chars/misc/dialogue/lesson6.png
	frame	data/chars/misc/dialogue/lesson7.png
	frame	data/chars/misc/dialogue/lesson7.png 
	frame	data/chars/misc/dialogue/lesson7.png
	frame	data/chars/misc/dialogue/lesson8.png
	frame	data/chars/misc/dialogue/lesson8.png
	frame	data/chars/misc/dialogue/lesson8.png
	frame	data/chars/misc/dialogue/lesson9.png
	frame	data/chars/misc/dialogue/lesson9.png
	frame	data/chars/misc/dialogue/lesson9.png
	frame	data/chars/misc/dialogue/lesson10.png
	frame	data/chars/misc/dialogue/lesson10.png
	frame	data/chars/misc/dialogue/lesson10.png
	frame	data/chars/misc/dialogue/lesson11.png 
	frame	data/chars/misc/dialogue/lesson11.png
	frame	data/chars/misc/dialogue/lesson11.png
	frame	data/chars/misc/dialogue/lesson12.png
	frame	data/chars/misc/dialogue/lesson12.png
	frame	data/chars/misc/dialogue/lesson12.png
	frame	data/chars/misc/dialogue/lesson13.png
	frame	data/chars/misc/dialogue/lesson13.png
	frame	data/chars/misc/dialogue/lesson13.png
	frame	data/chars/misc/dialogue/lesson14.png
	frame	data/chars/misc/dialogue/lesson14.png
	frame	data/chars/misc/dialogue/lesson14.png
	frame	data/chars/misc/dialogue/lesson15.png
	frame	data/chars/misc/dialogue/lesson15.png
	frame	data/chars/misc/dialogue/lesson15.png
	frame	data/chars/misc/dialogue/lesson16.png
	frame	data/chars/misc/dialogue/lesson16.png
	frame	data/chars/misc/dialogue/lesson16.png
	frame	data/chars/misc/dialogue/lesson17.png
	frame	data/chars/misc/dialogue/lesson17.png
	frame	data/chars/misc/dialogue/lesson17.png
	frame	data/chars/misc/dialogue/lesson18.png
	frame	data/chars/misc/dialogue/lesson18.png
	frame	data/chars/misc/dialogue/lesson18.png
	frame	data/chars/misc/dialogue/lesson19.png
	frame	data/chars/misc/dialogue/lesson19.png
	frame	data/chars/misc/dialogue/lesson19.png
	frame	data/chars/misc/dialogue/lesson20.png
	frame	data/chars/misc/dialogue/lesson20.png
	frame	data/chars/misc/dialogue/lesson20.png
	frame	data/chars/misc/dialogue/lesson21.png
	frame	data/chars/misc/dialogue/lesson21.png
	frame	data/chars/misc/dialogue/lesson21.png
	frame	data/chars/misc/dialogue/lesson22.png
	frame	data/chars/misc/dialogue/lesson22.png
	frame	data/chars/misc/dialogue/lesson23.png
	frame	data/chars/misc/dialogue/lesson23.png
	frame	data/chars/misc/dialogue/lesson23.png
	frame	data/chars/misc/dialogue/lesson24.png
	frame	data/chars/misc/dialogue/lesson24.png
	frame	data/chars/misc/dialogue/lesson24.png
	frame	data/chars/misc/dialogue/lesson25.png
	frame	data/chars/misc/dialogue/lesson25.png
	frame	data/chars/misc/dialogue/lesson25.png
	frame	data/chars/misc/dialogue/lesson26.png
	frame	data/chars/misc/dialogue/lesson26.png
	frame	data/chars/misc/dialogue/lesson26.png
	frame	data/chars/misc/empty.png
 
After a lot of test, I can tell you that my updated files works ok.

So we go with the necessary changes:

1) Tell me what I need to do to remove the reset.

2) The reset is only necessary for these animations:
21  NO MERCY                  anim follow32
22  FATALITY1                  anim follow20
23  FATALITY2                  anim follow42
24  FATALITY3                  anim follow43
25  FATALITY4                  anim follow44
So the best, would be to include the reset at the end of each animation.

3) In the reset of these animations and in the FINAL COMBO, would it be possible to specify that the enemy only has 20 health?

4) I need a reset, if you kill the enemy with an animation that is not one of these:
21  NO MERCY                  anim follow32
22  FATALITY1                  anim follow20
23  FATALITY2                  anim follow42
24  FATALITY3                  anim follow43
25  FATALITY4                  anim follow44
26  Standard Stage Fat.  anim freespecial35

5) Is there any way to accomplish the lesson, when the hero executes an animation that does not have a frame with attackbox and only damages the enemy when spawn an element?
 
I'll modify the position reset to be controllable from lecmun.c :)

3) In the reset of these animations and in the FINAL COMBO, would it be possible to specify that the enemy only has 20 health?

Mmm... does it mean if enemy has less than 20 do the reset or don't do the rest?

5) Is there any way to accomplish the lesson, when the hero executes an animation that does not have a frame with attackbox and only damages the enemy when spawn an element?

Hmm... that would need modification to lecmun.c to accept other type of attack.
 
This is so interesting that I am thinking to add to my mod too. In fact, I had this idea for long time but never found a way to do it or had spent time trying to figuring it.

Thanks  BB!
 
Bloodbane said:
I'll modify the position reset to be controllable from lecmun.c :)

3) In the reset of these animations and in the FINAL COMBO, would it be possible to specify that the enemy only has 20 health?

Mmm... does it mean if enemy has less than 20 do the reset or don't do the rest?.

No, I only want the enemy always have 20 health after this resets.
So this way the enemy is ready to execute the No Mercy and the Fatalities.

Thanks for all your efforts to make this possible my friend!
 
Okay then

Controlling reset position or not is easy same goes with health control. However, for reset after fatality.... I find it better to fake it with PAINs instead. With PAIN, enemy won't die from the fatality and can be resetted easily
Currently it works well but with zero damage from attacker. I'm going to try using normal damage :)

Will upload after I'm done
 
Back
Top Bottom