SOLVED Mantain same target during slamstarts

Toranks

Active member
Is there a way to keep the same target once the slamstart starts and until it ends?

There are a couple of bugs in a lot of grabs that I don't know how to solve and they are related to changing the target/opponent.

One of them is when I grab an enemy and progressively hurt him with the 'hurt' script, if in the middle of that grab I hit a third enemy, this third enemy is the one that receives the damage from hurt, and not the one I have grabbed.

Another bug, more problematic, is if an enemy grabs me and with that grab hits another player. The same thing happens, the other player receives the damage even though I am still in the grab, and also the release script (allows release by pressing all buttons quickly), switch players and go to the other player. And to make it even more complicated, if the hitted player presses the release buttons and succeeds, the original player is frozen and glued to the enemy.

I want to find a way that "opponent" and "target" with getentityproperty and getlocalvar do not change from slamstart to finish / throw, even if they hit third enemies, both for the player and for the enemy.
 
I think I had a similar problem in the past for a system I would like to implement through grabs/slams. At this time I gave up because of my lack of knowledge.
It can be fixed I think.
But I'm pretty sure some skilled creators can give you a way to avoid this problem.
 
After a talk with Kratus i've changed my scripted slam from localvar to entityvar. So I can have more control over my target.
With localvar, you can't do it - you would need to store the value into globalvar to utilize it later.

After some tests, I've discovered that entityvars aren't persistent - they are destroyed after the entity is destroyed too. Global var ARE persistent and they will even get saved from
 
Toranks said:
Can you show me an example? I need the variable to be saved from slamstart to finish/throw or until the player releases from the grab.
Hi Toranks
Like O Ilusionista said, is better to use entityvar/globalvar instead of localvar. The slam script I sent you before is already using entityvar, but I will show an example:

Code:
void grabStart()
{//Grab Starter for grab moves
 //Use SLAM or THROW after using this
	void self = getlocalvar("self");
	void target = getentityvar(self,"grabbed");

	if(target == NULL()){
		target = getentityproperty(self, "grabbing");
		if(target == NULL() || getentityproperty(target, "dead") == 1){ //USED WHEN PLAYER DIES BY TIME OVER AND THE GRABBER IS THE ENEMY
			setidle(self);
		}else{
			setentityvar(self, "grabbed", target);
		}
	}
	
	if(target != NULL()){
		damageentity(target, self, 0, 1, openborconstant("ATK_NORMAL7"));
	}
}

Also, if you don't want to use entityvar, simply replace the setlocalvar("target"+self) by setglobalvar("target"+self). The same goes for getlocalvar / getglobalvar.
 
Toranks said:
Is there a way to keep the same target once the slamstart starts and until it ends?

That's strange cause slam script system was designed to maintain same grabbed opponent from the start of slam/throw.

I want to find a way that "opponent" and "target" with getentityproperty and getlocalvar do not change from slamstart to finish / throw, even if they hit third enemies, both for the player and for the enemy.

There's a stability check in some slam functions to prevent player/enemy from slamming/throwing nothing.
Code:
   void target = getlocalvar("Target" + self);

   if(target==NULL())
   {
     target = getentityproperty(self, "opponent");
     setlocalvar("Target" + self, target);
   }

If you remove this check from each function, you could ensure grabbed opponent will always be the same.
Nonetheless, changing local variable into entity variable is good solution. It also allow non-invincible slams/throws, if you ever need some.
 
Kratus said:
Hi Toranks
Like O Ilusionista said, is better to use entityvar/globalvar instead of localvar. The slam script I sent you before is already using entityvar, but I will show an example:

Code:
void grabStart()
{//Grab Starter for grab moves
 //Use SLAM or THROW after using this
	void self = getlocalvar("self");
	void target = getentityvar(self,"grabbed");

	if(target == NULL()){
		target = getentityproperty(self, "grabbing");
		if(target == NULL() || getentityproperty(target, "dead") == 1){ //USED WHEN PLAYER DIES BY TIME OVER AND THE GRABBER IS THE ENEMY
			setidle(self);
		}else{
			setentityvar(self, "grabbed", target);
		}
	}
	
	if(target != NULL()){
		damageentity(target, self, 0, 1, openborconstant("ATK_NORMAL7"));
	}
}

Also, if you don't want to use entityvar, simply replace the setlocalvar("target"+self) by setglobalvar("target"+self). The same goes for getlocalvar / getglobalvar.

Thanks! That one works for me for slamstart moves inside grabs. Can you show me the script that is used for movements that are not grabs? (slamstart2 for me) There this line does not works:

Code:
void target = getentityvar (self, "grabbed");

This is my slamstart2:
Code:
void slamstart2()
{ // Slam Starter for nongrab slams
// Use finish or throw after using this
   void self = getlocalvar("self");
   void target = getlocalvar("Target" + self);

   if(target==NULL())
   {
    target = getentityproperty(self, "opponent");
	if(target == NULL() || getentityproperty(target, "dead") == 1){
		setidle(self);
	}else{
    setlocalvar("Target" + self, target);
   }
 }  
   if(target!=NULL())
   {
     damageentity(target, self, 0, 1, openborconstant("ATK_NORMAL7")); // Slam Starter
   }
}

On the other hand, I don't know what the possible variables are. In the manual it is not clear. Grabbed does not appear among manual variables
 
That's strange cause slam script system was designed to maintain same grabbed opponent from the start of slam/throw.

This is not really my problem, but "target"/"opponent" changes for other additional scripts if the grabber entity hits a third entity. For example, hurt (subtracts life), works by applying its properties to "target" or "opponent" (for example, void target = getentityproperty(self, "opponent"); ). What I want is that these scripts are always applied on the same grabbed entity, not on the last hitted entity, until throw/finish.
This is necessary for grabs that hit third enemies. For example, spinning the grabbed opponent.
Is there a way to recognize the grabbed entity using getentityproperty or similar?
 
To be more specific than what I'm looking for, I need entity victim/victim2 to not change until the script finishes even if another enemy ("opponent" property) is hit, only the first entity grabbed or hitted, and make it compatible with grab based and non-grab based slamstarts. I can't think of what type of variable to ask for, because the manual doesn't go into much detail with variables and properties:

Code:
script   @script
void main()
{
    	void self = getlocalvar("self");
	void attacker = getentityproperty(self,"parent");
   	void victim2 = getentityproperty(attacker, "opponent");
  	void victim = getentityproperty(victim2, "playerindex");
	int HP = getentityproperty(self,"health");
	int HPmax = getentityproperty(self,"maxhealth");

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

    	int escape = getentityvar(self, "grabgo"); //johnny madjon
  if (attacker!=NULL() && victim2 !=NULL())
   {// checking if the pointers are valid
   
	if(HP>=HPmax && escape == 1){
	changeentityproperty(victim2, "position", x1, z1);
     	performattack(victim2, openborconstant("ANI_FOLLOW15"));
    	setidle(attacker, openborconstant("ANI_IDLE"));
     	bindentity(victim2, NULL());
     	performattack(attacker, openborconstant("ANI_PAIN8"));
	setentityvar(self, "madjon", NULL());
	killentity(self);

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

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

If anybody can give me a clue on how to modify this code to do what I want, I will be able to modify the rest of the scripts involved. This is the most troublesome script right now.
 
So... from analyzing the script, instead of the main entity does the grab, other entity does the grab.

Your source of problem might be this:
Code:
void victim2 = getentityproperty(attacker, "opponent");

Opponent is dynamic depending on what last entity you hit. You'll need to acquire this just once at beginning of slam/throw then store it in entity variable. After that, slam/throw scripts must get the grabbed entity from that entity variable.
 
Bloodbane said:
Opponent is dynamic depending on what last entity you hit. You'll need to acquire this just once at beginning of slam/throw then store it in entity variable. After that, slam/throw scripts must get the grabbed entity from that entity variable.

Yes, how I can do that? I can't quite understand the difference between entityvar and entityproperty
 
Toranks said:
Bloodbane said:
Opponent is dynamic depending on what last entity you hit. You'll need to acquire this just once at beginning of slam/throw then store it in entity variable. After that, slam/throw scripts must get the grabbed entity from that entity variable.

Yes, how I can do that? I can't quite understand the difference between entityvar and entityproperty

Toranks
I agree with Bloodbane, you need to store the opponent in a variable first.

About the differences, entityproperty is a value that sometimes can change dynamically according to your actions in the game. For example, the entityproperty("opponent") refers to the last entity you interacted with. So, if you hit an enemy, he will be your opponent, but if you hit a npc after that, now this will be your new opponent and the last value will be overwritten. Here's a explanation from the manual:

"opponent" - Last entity interacted with (damaged, damaged by, grabbed, etc.). Essentially this returns
whoever would be showing up on a player's enemy life meter, but works for all entities

Entityvar is a place where you can store any value that's related to the defined entity. For example, you can store your current opponent in an entityvar related to you, like this

Code:
void self = getlocalvar("self");
void opponent = getentityproperty(self, "opponent");

setentityvar(self, "target", opponent);
The first value is the entity to which the entityvar is related (self).
The second value is the variable name defined by you
The third value is what you will want to store (opponent)

So, every time you call the function getentityvar(self, "target"), you will call exactly the opponent that is stored in the variable called "target", and it will always be the same until you rewrite the variable.

You can do the same thing with globalvars and localvars too, like this:
Code:
void self = getlocalvar("self");
void opponent = getentityproperty(self, "opponent");

setlocalvar("target"+self, opponent);
setglobalvar("target"+self, opponent);

getlocalvar("target"+self);
getglobalvar("target"+self);

In resume, it is always better to manage grabs by using the opponent that is stored in a variable, not the entityproperty itself. In the case of the "@cmd slamstart2" function, the opponent will be stored as soon as the attacker hits him. After that, all other scripts like "@cmd position" will work according to the opponent that is stored in the variable, not the entityproperty.
 
Thank you! But I have a question.
Considering that the script is active for the entire duration of the grab / slamstart-finish
Won't the variable be rewritten every time the opponent changes? How can I control when that variable is written and erased?

Edit: I've an idea. If I add the entity variable inside an animation (for example the attack that initiates the grab, or in spawn animation of the entity that allows the player to releases from the grab) instead of in the header of the entity, it will only be executed once, right? The variable remains linked to the entity until it is overwritten again when the entity makes another grab or the release entity is spawned again. I'm going to try that ...
 
Won't the variable be rewritten every time the opponent changes? How can I control when that variable is written and erased?
It depends on how your animation is coded. Let's take the example below:

Code:
anim freespecial #AERIAL SPECIAL PILE
	followanim 1
	followcond 1
	loop	0
	delay	8
	offset	150 188
	bbox 	141 90 26 82
	frame	data/chars/heroes/max/throw00.gif
	attack 157 105 27 35 0 0 1 1 0 12
	dropv 0 1 0
	bbox 	131 112 40 42
	frame	data/chars/heroes/max/throw01.gif
		delay	24
	attack 145 139 53 34 0 0 1 1 0 12
	dropv 0 1 0
	bbox 	131 122 57 47
	frame	data/chars/heroes/max/throw02.gif
	attack 0 0 0 0 0 0 0 0 0 0
	bbox 	135 109 34 67
	frame	data/chars/heroes/max/jump01.gif

Code:
anim follow1 #AERIAL SPECIAL PILE
	loop	0
	delay	2
	offset	150 188
	hitfx	data/sounds/MediumKick.wav
	@cmd slamstart2
	@cmd position 5 20 0 0 -1
	frame	data/chars/heroes/max/pile00.gif
	@cmd position 5 20 0 0 -1
	frame	data/chars/heroes/max/pile00.gif
	@cmd depost
	@cmd finish 24 1 -1.6 3 0 0
	frame	data/chars/heroes/max/pile01.gif
	@cmd clearL
	frame	data/chars/heroes/max/pile01.gif

As you can see, the "slamstart2" is declared once in the "follow1" animation. So, if the player perform the freespecial and hits any opponent, the function "followanim" will change the current animation to "follow1".

The slamstart2 will write the entity variable once and after that you can freely hit any other entity and the entityvar will not change, except when the follow1 animation ends, the variable is cleared by @cmd clearL and the freespecial is performed again.

In other words, the @slamstart2 will register only the opponent damaged in the freespecial animation. If you have attack boxes in your follow1 animation, the variable will not be changed, unless you declare the slamstart2 again in another frame
 
Yes!! You are right. The key is to use the variables written in a specific animation, not in the header of the entity, or other generic script that is always active.

This is the changes I've maded.

On the grab release entity which allows to release by pressing all the buttons very fast (this entity show the buttons to press and a progress bar), I put this in the spawn animation:

Code:
anim	spawn
@script
	void self = getlocalvar("self");
	void atk = getentityproperty(self,"parent");
  	void vtm = getentityproperty(atk, "opponent");
  	void plyr = getentityproperty(vtm, "playerindex");
    	changeentityproperty(self, "health",-5);
    	setentityvar(self, "target", vtm);
    	setentityvar(self, "player", plyr);

	if(getentityproperty(vtm, "type")==openborconstant("TYPE_NPC"))
	{
	killentity(self);
	}
	@end_script
	loop	0
	delay	5
	offset	50 90
	bbox	0 0 0 0
	platform	1 1 1 1 1 1 1 1
	frame	data/chars/misc/grab/empty.gif
	frame	data/chars/misc/grab/empty.gif
	frame	data/chars/misc/grab/empty.gif
	frame	data/chars/misc/grab/empty.gif

On the header of this entity, the script that is always active, I change the victim/victim2 getentityproperty for the getentityvar previously saved:

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

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

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

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

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

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

And works!! Now victim and victim2 never changes once the grab begins, and until it ends. And it is rewritten again when the entity is spawned again

For the hurt script bug, I change the code of hurt command from:

Code:
void hurt(int Damage)
{ // Damage opponent if health is higher than 20
	void self = getlocalvar("self");
	void target = getentityproperty(self, "opponent");

   if(target!=NULL())
   {
     void THealth = getentityproperty(target,"health");
     if(THealth > 20)
     {
       changeentityproperty(target, "health", THealth - Damage);
     }
   }
}

To this:

Code:
void hurt(int Damage)
{ // Damage opponent if health is higher than 20
	void self = getlocalvar("self");
	void target = getlocalvar("Target" + self);
	void target1 = getentityproperty(self, "grabbing");
	void target2 = getentityproperty(self, "opponent");

   if(target!=NULL())
   {
     void THealth = getentityproperty(target,"health");
     if(THealth > 20)
     {
       changeentityproperty(target, "health", THealth - Damage);
     }
   }
   else if (target1 !=NULL())
   {
	  void THealth = getentityproperty(target1,"health");
     if(THealth > 20)
     {
       changeentityproperty(target1, "health", THealth - Damage);
     }
   }
   else if (target2 !=NULL())
   {
	  void THealth = getentityproperty(target2,"health");
     if(THealth > 20)
     {
       changeentityproperty(target2, "health", THealth - Damage);
     }
   }
}

And works too!!

Thanks to all, Kratus  Bloodbane  and O Ilusionista you are great, you have helped me solve many errors that have not been solved for years. I have had to learn scripting from scratch with this game, but I had a fun time learning and solving  ;D
 
Back
Top Bottom