[SOLVED] Get Y acceleration (gravity) value

Don Drago

Member
Hello!

I'm making a small script that allows a character to jump at nearest opponent where you can input:
  • desired X position relative to opponent
  • desired Y position relative to opponent
  • desired Z position relative to opponent
  • X velocity if there are no opponents
  • Y velocity if there are no opponents
  • Z velocity if there are no opponents
  • AutoTurn if needed
  • Time needed to reach the opponent
Explaining it:
"I want to reach X in front, Y above and Z around nearest opponent in Time frame, and maybe AutoTurn to face the enemy. If there's no opponent, just jump with vX, vY and vZ velocities."

It's all well and good, except one thing. I don't know how to get openBOR's jump gravity value (vertical acceleration). That's needed to calculate how high the character has to jump to respect the Time input.

Can anyone point me to the reight direction? I suspect that I'll have to measure antigravity as well (but at least THAT I'm able to get by myself).
 
Gravity is a level property. It's available as "gravity" in the getlevelproperty and changelevelproperty methods.

Also, here's the engine function that handles gravity to help you with setting up your calculations.

Code:
void check_gravity(entity *e)
{
    int heightvar;
    entity *other = NULL, *dust, *tempself, *plat = NULL;
    s_collision_attack attack;
    float gravity;
    float fmin, fmax;

    if(e->update_mark & 8)
    {
        return;
    }

    tempself = self;
    self = e;

    adjust_base(self, &plat);

    if(!is_frozen(self) )// Incase an entity is in the air, don't update animations
    {
        if(self->animation->size.y)
        {
            heightvar = self->animation->size.y;
        }
        else
        {
            heightvar = self->modeldata.size.y;
        }

        // White Dragon: turn-off the hitwall flag  if you're not near a obstacle. this help to avoid a hit loop
        /*if( (self->position.y <= self->base || !inair(self)) && self->velocity.y <= 0)
        {
            if ( self->hitwall && !is_obstacle_around(self,1.0) ) self->hitwall = 0;
        }*/

        if((self->falling || self->velocity.y || self->position.y != self->base) && self->toss_time <= time)
        {
            if(heightvar && self->modeldata.subject_to_platform > 0 && self->velocity.y > 0)
            {
                other = check_platform_above_entity(self);
            }
            else
            {
                other = NULL;
            }

            if( other && other->position.y <= self->position.y + heightvar && !other->modeldata.nohithead)
            {
                if(self->hithead == NULL) // bang! Hit the ceiling.
                {
                    self->velocity.y = 0;
                    self->hithead = other;
                    execute_onblocka_script(self, other);
                }
            }
            else
            {
                self->hithead = NULL;
            }
            // gravity, antigravity factors
            self->position.y += self->velocity.y * 100.0 / GAME_SPEED;
            if(self->animation->antigrav)
            {
                gravity = 0;
            }
            else
            {
                gravity = (level ? level->gravity : default_level_gravity) * (1.0 - self->modeldata.antigravity);
            }
            if(self->modeldata.subject_to_gravity > 0)
            {
                self->velocity.y += gravity * 100.0 / GAME_SPEED;
            }

            fmin = (level ? level->maxfallspeed : default_level_maxfallspeed);
            fmax = (level ? level->maxtossspeed : default_level_maxtossspeed);

            if(self->velocity.y < fmin)
            {
                self->velocity.y = fmin;
            }
            else if(self->velocity.y > fmax)
            {
                self->velocity.y = fmax;
            }

            // Dropframe set?
            if(self->animation->dropframe)
            {
                // If falling and frame has not
                // passed dropframe, set frame to dropframe.
                if(self->velocity.y <= 0 && self->animpos < self->animation->dropframe->frame) // begin dropping
                {
                    update_frame(self, self->animation->dropframe->frame);
                }
            }

            if (self->velocity.y)
            {
                execute_onmovea_script(self);    //Move A event.
            }

            if( self->idling && validanim(self, ANI_WALKOFF) && diff(self->position.y, self->base) > T_WALKOFF )
            {
                entity *cplat = check_platform_below(self->position.x,self->position.z-1.0,self->position.y,self);

                // White Dragon: fix for too low velocityz
                if ( !cplat || (cplat && diff(get_platform_base(cplat),self->position.y) > T_WALKOFF) )
                {
                    self->idling = 0;
                    self->takeaction = common_walkoff;
                    ent_set_anim(self, ANI_WALKOFF, 0);
                    self->landed_on_platform = plat = NULL;
                }
            }

            // UTunnels: tossv <= 0 means land, while >0 means still rising, so
            // you wont be stopped if you are passing the edge of a wall
            if( (self->position.y <= self->base || !inair(self)) && self->velocity.y <= 0)
            {
                self->position.y = self->base;
                self->falling = 0;

                if ( self->hitwall ) self->hitwall = 0;

                //self->projectile = 0;
                // cust dust entity
                if(self->modeldata.dust.fall_land >= 0 && self->velocity.y < -1 && self->drop)
                {
                    dust = spawn(self->position.x, self->position.z, self->position.y, self->direction, NULL, self->modeldata.dust.fall_land, NULL);
                    if(dust)
                    {
                        dust->base = self->position.y;
                        dust->autokill = 2;
                        execute_onspawn_script(dust);
                    }
                }
                // bounce/quake
                if(tobounce(self) && self->modeldata.bounce)
                {
                    int i;
                    self->velocity.x /= self->animation->bounce;
                    self->velocity.z /= self->animation->bounce;
                    toss(self, (-self->velocity.y) / self->animation->bounce);
                    if(level && !(self->modeldata.noquake & NO_QUAKE))
                    {
                        level->quake = 4;    // Don't shake if specified
                    }
                    if(SAMPLE_FALL >= 0)
                    {
                        sound_play_sample(SAMPLE_FALL, 0, savedata.effectvol, savedata.effectvol, 100);
                    }
                    if(self->modeldata.type & TYPE_PLAYER)
                    {
                        control_rumble(self->playerindex, 100 * (int)self->velocity.y / 2);
                    }
                    for(i = 0; i < MAX_PLAYERS; i++)
                    {
                        control_rumble(i, 75 * (int)self->velocity.y / 2);
                    }
                }
                else if((!self->animation->move[self->animpos]->base || self->animation->move[self->animpos]->base < 0) &&
                        (!self->animation->move[self->animpos]->y || self->animation->move[self->animpos]->y <= 0))
                {
                    if( !(self->modeldata.aimove & AIMOVE1_BOOMERANG) ) self->velocity.x = self->velocity.z = self->velocity.y = 0;
                }
                else
                {
                    self->velocity.y = 0;
                }

                if(plat && !self->landed_on_platform && self->position.y <= plat->position.y + plat->animation->platform[plat->animpos][7])
                {
                    self->landed_on_platform = plat;
                }

                if(self->animation->landframe.frame >= 0                               //Has landframe?
                        && self->animation->landframe.frame <= self->animation->numframes  //Not over animation frame count?
                        && self->animpos < self->animation->landframe.frame)               //Not already past landframe?
                {
                    if(self->animation->landframe.ent >= 0)
                    {
                        dust = spawn(self->position.x, self->position.z, self->position.y, self->direction, NULL, self->animation->landframe.ent, NULL);
                        if(dust)
                        {
                            dust->base = self->position.y;
                            dust->autokill = 2;
                            execute_onspawn_script(dust);
                        }
                    }
                    update_frame(self, self->animation->landframe.frame);
                }

                // takedamage if thrown or basted
                if(self->damage_on_landing > 0 && !self->dead)
                {
                    if(self->takedamage)

                    {
                        attack              = emptyattack;
                        attack.attack_force = self->damage_on_landing;
                        attack.attack_type  = ATK_LAND;
                        self->takedamage(self, &attack);
                    }
                    else
                    {

                        self->health -= (self->damage_on_landing * self->defense[ATK_LAND].factor);
                        if(self->health <= 0 )
                        {
                            kill(self);
                        }
                        self->damage_on_landing = 0;
                    }
                }
                // in case landing, set hithead to NULL
                self->hithead = NULL;
            }// end of if - land checking
        }// end of if  - in-air checking
        if(self->toss_time <= time)
        {
            self->toss_time = time + 1;
        }

    }//end of if

    self->update_mark |= 8;

    self = tempself;
}

*Edit*: Found the method to retrieve gravity. See above.
 
Thanks, DC!

By looking at the manual, I got the SET method

gravity {value}

~This sets gravity or falling speed in the level.
~It should use negative value. Defaults to -10
~Setting -5 makes characters fall like in water.

I didn't find a GET method, but, for now, the bold part will get the intended results.

*Edit*: Thanks for finding it! Now, gotta go back to work!
 
Don Drago said:

NP, but the actual default is -0.1, not -10.

Fair warning, that's pretty common. The manual says "use some whole number" and when loading, OpenBOR reads the text value and corrects it before populating the variable. The idea was to "sanitize" floats into whole numbers for users, in theory making module authoring more user friendly.

I don't agree with the practice and put a stop to it when I took over because because it creates a ton of confusion, but there's a lot grandfathered in. Not a huge thing, just keep in mind what the manual says and the true values you see when scripting can often differ. If that happens it's almost always <real value> = <text value> / 100.

DC
 
@ Don Drago: For that purpose, I usually use these script combination:

@cmd targetL (Vy )(x) (z) (Turn)
@leap (Vy)

Here are the functions:
Code:
void targetL(float Vy, float dx, float dz, int Flip)
{// Targetting opponent before performing targetted leap attack
// Vy = y Velocity
// dx = x added distance
// dz = z added distance

    void self = getlocalvar("self");
    int dir = getentityproperty(self, "direction");
    float x = getentityproperty(self, "x");
    float z = getentityproperty(self, "z");

    if (dir == 0){ //Is entity facing left? 
      dx = -dx; //Reverse X direction to match facing
    }

    setlocalvar("T"+self, findtarget(self)); //Get nearest player

    if( getlocalvar("T"+self) != NULL()){
      void target = getlocalvar("T"+self);
      float Tx = getentityproperty(target, "x");
      float Tz = getentityproperty(target, "z");

      if(Flip == 1){
        if(Tx < x){
          changeentityproperty(self, "direction", 0);
        } else {
          changeentityproperty(self, "direction", 1);
        }
      }

      x = x+dx;
      z = z+dz;
      setlocalvar("x"+self, (Tx-x)/(22*Vy));
      setlocalvar("z"+self, (Tz-z)/(22*Vy));

    } else {
      setlocalvar("z"+self, 0);
      setlocalvar("x"+self, 0);
    }

    setlocalvar("T"+self, NULL()); //Clears variable
}

void leap(float Vely)
{// Leap with previously attained speed!
    void self = getlocalvar("self");
    float Vx = getlocalvar("x"+self);
    float Vz = getlocalvar("z"+self);
    if( Vx!=NULL() && Vz!=NULL() ){
      tossentity(self, Vely, Vx, Vz); //Leap towards target!
    }
}

With those functions, entity will leap with certain velocity toward nearest opponent. There's no Time parameter, but you can calculate it from Vy which is : Time = Vy*20 centiseconds

Though I have to say that those method above isn't 100% accurate (not a big deal for non 2D mods) about 95% accurate
I'm going to see if knowing gravity value could improve this function :)
 
@ Bloodbane: I needed a different code on SFFGoldPLUS. Sometimes I need to be high over the opponent (see Vega's Flying Barcelona Attack, Bison's Devil Reverse), while sometimes I need tojump at opponent's head (Bison's Head Press), sometimes I need a fixed height, while being able to target the oppoent (Retu, Bratken, Freddie). Lastly, I needed a "chasing jump" (Won Won). This code has everything, but needs to be perfected using Physics and openBOR's gravity:
Code:
/* 
 * guided jump to the nearest opponent, with desired time (reachAt) to reach it
 * and position adjusts(X, Y and Z). If there's no opponent, uses whiff* values
 * to jump. Use flipMe = 1 to face the target, if desired you may use this
 * with ajustY=NULL() and whiffY=NULL() while jumping, to make a "chasing jump"
 * (look at Super Final Fight Gold PLUS: Won Won has a chasing jump attack)
 * created by Don Drago
 */
void guidedJump(int reachAt, int adjustX, int adjustY, int adjustZ, float whiffX, float whiffY, float whiffZ, int flipMe) {
	void self = getlocalvar("self");
	void opponent = findtarget(self);
	int facing = (getentityproperty(self,"direction")==0) ? (-1) : (1);

	float pX = getentityproperty(self, "x");
	float pY = getentityproperty(self, "y");
	float pZ = getentityproperty(self, "z");
	float x, y, z;

	if(opponent!= NULL()) {
		float eX = getentityproperty(opponent, "x");
		float eY = getentityproperty(opponent, "y");
		float eZ = getentityproperty(opponent, "z");
		
		adjustX *= (eX < pX) ?(-1) : (1);
		
		x = (eX-pX+adjustX)*facing;
		y = eY-pY+adjustY;
		z = eZ-pZ+adjustZ;

		x=(x/reachAt)*facing;
		y=(y+50)/reachAt;// needs openBOR gravity AND some Physics class. works fine with reachAt around 60
		z=z/reachAt;
		
		if(eX < pX) {
			if(flipMe != 0){ changeentityproperty(self, "direction", 0); }
		}
		else {
			if(flipMe != 0){ changeentityproperty(self, "direction", 1); }
		}			
	}
	else {
		x = whiffX*facing;
		y = whiffY;
		z = whiffZ;
	}
    // FINALLY!!!	 
    tossentity(self, y, x, z);
}
 
I know you mean well to help, magggas, but y is an updated version of a. According to the updated manual now, a is deprecated, along with a few others. But I think it can be used too. DC or WD made the updates on the engine for it since. Don Drago is using one of the most updated/recent versions I believe. Also...

O Ilusionista said:
Drago made an updated version of that code, which has some improvements, like not letting the attacker going offscreen, calculate the screen center, etc.
 
magggas said:
This is a nice script version for this, but let me clear up some things. There is not any use of "OpenBOR gravity" or any "time calculation" in this code. And "getentityproperty(self, "y");" is wrong. It must be "getentityproperty(self, "a");" instead.

I hope that helps.

Sorry magggas, but that's not correct. A is depreciated. Always use Y for the vertical axis.
 
magggas said:
This is a nice script version for this, but let me clear up some things. There is not any use of "OpenBOR gravity" or any "time calculation" in this code. And "getentityproperty(self, "y");" is wrong. It must be "getentityproperty(self, "a");" instead.

I hope that helps.
magggas , the parte about Y vs A was already explained by Damon Caskey. About...

magggas said:
(...) There is not any use of "OpenBOR gravity" or any "time calculation" in this code. (...)
... well, that's why I requested help. Look again at the code, this line:
Code:
		y=(y+50)/reachAt;// needs openBOR gravity AND some Physics class. works fine with reachAt around 60

It states that it needs the code I requested. I'll implement right after I get to understand this - I'll just need to replace g with getlevelproperty("gravity").
 
Maggas, I think you need to chill out a bit. Maybe its a language barrier, but your answers seemed very bitter.
There is no use for:
There is not any use of "OpenBOR gravity" or any "time calculation" in this code
I'm trying to clear up some confusion here and you are making things more confusing. Because you don't known what are you talking about about "a",

Both were very uncalled for. Chill out :)
 
I think this is the finished code. Thanks for all involved. I attached a PNG showing why reachAt (AKA time to reach destination) is important, showing different trajectories based on different time frame. Feel free to change the code, making it simpler and more reliable if possible.
Code:
void guidedJump(int reachAt, int adjustX, int adjustY, int adjustZ, float whiffX, float whiffY, float whiffZ, int flipMe) {
	void self = getlocalvar("self");
	void opponent = findtarget(self);
	int facing = (getentityproperty(self,"direction")==0) ? (-1) : (1);

	float gravity = -(getlevelproperty("gravity")*(1.0-getentityproperty(self,"antigravity")));
	float pX = getentityproperty(self, "x");
	float pY = getentityproperty(self, "y");
	float pZ = getentityproperty(self, "z");
	float x, y, z;
	
	reachAt--;

	if(opponent!= NULL()) {
		float eX = getentityproperty(opponent, "x");
		float eY = getentityproperty(opponent, "y");
		float eZ = getentityproperty(opponent, "z");
		
		adjustX *= (eX < pX) ?(-1) : (1);
		
		if(adjustX !=NULL()) {
			x = (eX-pX+adjustX)*facing;
			x = (x/reachAt)*facing;			
		}
		else { x = NULL(); }
		
		if(adjustY !=NULL()) {
			y = eY-pY+adjustY;
			y = ((reachAt*gravity/2)+(y/reachAt));
		}
		else { y = NULL(); }
		
		if(adjustZ !=NULL()) {
			z = eZ-pZ+adjustZ;
			z = z/reachAt;
		}
		else { z = NULL(); }
		
		if(eX < pX) {
			if(flipMe != 0){ changeentityproperty(self, "direction", 0); }
		}
		else {
			if(flipMe != 0){ changeentityproperty(self, "direction", 1); }
		}			
	}
	else {
		x = whiffX*facing;
		y = whiffY;
		z = whiffZ;
	}
	
	 
    tossentity(self, y, x, z);
}

[attachment deleted by admin]
 
Back
Top Bottom