Пример #1
0
// update position
void CCharacter::UpdatePosition( )
{
    if(IsOnBattle( ) && Battle->target!=0)
    {
        CCharacter* Target = GetCharTarget( );
        if(Target!=NULL)  
        {
            if(IsMonster())
            {
                float distance = GServer->distance( Position->current, Position->source );
                if(distance>50)//AI should take care of this
                {
                    OnFar( );
                }
                //else Position->destiny = Target->Position->current;
            }
            //else Position->destiny = Target->Position->current;
        }
        else ClearBattle( Battle );
    }
    if(!IsMoving()){
      /*  if(IsPlayer()) */ Position->lastMoveTime = clock();
        return;
        }
	float dx = Position->destiny.x - Position->current.x;
	float dy = Position->destiny.y - Position->current.y;
	float distance = sqrt( (dx*dx) + (dy*dy) );
    float ntime = ( distance / (float(Stats->Move_Speed)/100.f)) * CLOCKS_PER_SEC;// * 100000; 
    clock_t etime = clock() - Position->lastMoveTime;       	
	if (ntime<=etime || distance==0) 
    {		
		Position->current.x = Position->destiny.x;
		Position->current.y = Position->destiny.y;		
    }
	else 
    {
		Position->current.x = dx*(etime/ntime) + Position->current.x;
		Position->current.y = dy*(etime/ntime) + Position->current.y;
	}
	Position->lastMoveTime = clock();    
}
Пример #2
0
// update attack values and destiny  position
bool CMonster::UpdateValues( )
{       
    //LMA: Some special case where special monsters stay still (mc, bonfires and so on...)
    if(stay_still&&(!IsBonfire()))
       return true;
        
    if(IsSummon( ) && CanMove( ))
    {
        CPlayer* thisclient = GetOwner( );
        if(thisclient!=NULL)
        {               
            if(!IsBonfire())
            {
                if(!IsOnBattle( ) && thisclient->IsAttacking( ))
                {
                    Battle->target = thisclient->Battle->target;
                    Battle->atktarget = Battle->target;
                    Battle->atktype = NORMAL_ATTACK;
                    Battle->contatk = true;
                    CCharacter* Enemy = GetCharTarget( );
                    if(Enemy!=NULL)
                        StartAction( Enemy, NORMAL_ATTACK );
                }
                else
                if(!IsOnBattle( ))
                {
                    Position->source = thisclient->Position->current;
                    float distance = GServer->distance( Position->destiny , thisclient->Position->current );
                    if((distance>15 && !IsOnBattle()) || distance>50)
                        Move( );                
                }
            
            }
            else
            {
                //LMA: Let's kill bonfires if owner too far away :).
                float distance = GServer->distance( Position->current , thisclient->Position->current );
                if(distance>25)
                {
                   UnspawnMonster( );
                   return false;                
                }
                
                return true;
            }
            
        }
        else
        {
            UnspawnMonster( );
            return false;
        }
    }                           
    if(!IsMoving( ) && !IsOnBattle( ) && CanMove( ))        
    {         
        clock_t etime = clock() - Position->lastMoveTime;  
        if(etime > 20*CLOCKS_PER_SEC) 
            Move( );    
    }
    if(!IsSummon( ))
    {
        CPlayer* player = GetNearPlayer( 10 );
        if(player!=NULL)
            OnEnemyOnSight( player );
    } 
    return true;
}
Пример #3
0
// start action [attack]
void CCharacter::StartAction( CCharacter* Target, BYTE action, UINT skillid, bool restart, CCharacter* receiver )
{
    if(IsPlayer())
    {
        Log(MSG_INFO,"A Player does an action %i, skill %i",action,skillid);
    }
    else
    {
        Log(MSG_INFO,"A Monster does an action %i, skill %i",action,skillid);
    }

    BEGINPACKET( pak, 0 );
    if (restart)
    {
       Target=GetCharTarget( );
       action=Battle->atktype;
       skillid=Battle->skillid;
    }

    //Drakia: If the target is NULL, we should only do something that doesn't require a target.
    if (Target == NULL && (action != SKILL_AOE &&action != BUFF_SELF &&action != BUFF_AOE &&action != MONSTER_BUFF_SELF &&action != AOE_TARGET))
    {
        Log(MSG_WARNING,"We tried to start attack %i without a target",action);
        return;
    }

    //LMA: don't attack a dead or an offline player... It's stupid...
    if(Target!=NULL)
    {
        if(Target->IsPlayer())
        {
            CPlayer* thisplayer=reinterpret_cast<CPlayer*>(Target);
            if(!thisplayer->Session->inGame)
            {
                //Log(MSG_HACK,"We don't attack a player not in game yet..., %s",thisplayer->CharInfo->charname);
                return;
            }

        }

        if(Target->IsDead())
        {
            //but we can if it's a friendly (restore...).
            if(action!=SKILL_BUFF)
            {
                ClearBattle(Battle);
                return;
            }

        }

    }

    switch(action)
    {
        case NORMAL_ATTACK:
        {
            RESETPACKET( pak, 0x798 );
            ADDWORD    ( pak, clientid );
            ADDWORD    ( pak, Target->clientid );

            //ADDWORD    ( pak, Stats->Move_Speed );
            ADDWORD    ( pak, Stats->Base_Speed );
            //Log(MSG_INFO,"move speed %u, base speed %u",Stats->Move_Speed,Stats->Base_Speed);

            ADDFLOAT   ( pak, Target->Position->current.x*100 );
            ADDFLOAT   ( pak, Target->Position->current.y*100 );
            Battle->target = Target->clientid;
            Battle->atktarget = Target->clientid;
            Battle->atktype = action;
            Position->destiny  = Target->Position->current;
            Position->lastMoveTime = clock( );
        }
        break;
        case SKILL_ATTACK:
        case SKILL_BUFF:
        {
        	RESETPACKET( pak, 0x7b3 );
        	ADDWORD    ( pak, clientid );
        	ADDWORD    ( pak, Target->clientid );
        	ADDWORD    ( pak, skillid );
        	ADDWORD    ( pak, 50000 );
            ADDFLOAT   ( pak, Target->Position->current.x*100 );
            ADDFLOAT   ( pak, Target->Position->current.y*100 );
            ADDFLOAT   ( pak, Position->aoedestiny.x*100 );
            ADDFLOAT   ( pak, Position->aoedestiny.y*100 );
            Battle->target = Target->clientid;

            if(action==SKILL_ATTACK) Battle->skilltarget = Target->clientid;
            else Battle->bufftarget = Target->clientid;

            Battle->atktype = action;
            Position->destiny  = Target->Position->current;
            Battle->skillid = skillid;
            Position->lastMoveTime = clock( );
        }
        break;
        case MONSTER_SKILL_ATTACK:
        case MONSTER_SKILL_BUFF:
        {
        	RESETPACKET( pak, 0x7b3 );
        	ADDWORD    ( pak, clientid );
        	ADDWORD    ( pak, Target->clientid );
        	ADDWORD    ( pak, skillid );
            ADDBYTE (pak,0x2b);
            ADDBYTE (pak,0x01);
            ADDFLOAT   ( pak, Target->Position->current.x*100 );
            ADDFLOAT   ( pak, Target->Position->current.y*100 );
            ADDBYTE    ( pak, 0x06);
            Battle->target = Target->clientid;

            if(action==MONSTER_SKILL_ATTACK) Battle->skilltarget = Target->clientid;
            else Battle->bufftarget = Target->clientid;

            Battle->atktype = action;
            Position->destiny  = Target->Position->current;
            Battle->skillid = skillid;
            Position->lastMoveTime = clock( );
        }
        break;
        case SUMMON_BUFF:
        {
            //LMA: Special case for Support summons
        	RESETPACKET( pak, 0x7b3 );
        	ADDWORD    ( pak, clientid );
        	ADDWORD    ( pak, Target->clientid );
        	ADDWORD    ( pak, skillid );
            ADDBYTE (pak,0x2b);
            ADDBYTE (pak,0x01);
            ADDFLOAT   ( pak, Target->Position->current.x*100 );
            ADDFLOAT   ( pak, Target->Position->current.y*100 );
            /*
            ADDFLOAT   ( pak, Position->current.x*100 );
            ADDFLOAT   ( pak, Position->current.y*100 );
            */
            ADDBYTE    ( pak, 0x06);
            Battle->target = 0;
            //Battle->skilltarget = Target->clientid;
            Battle->bufftarget = Target->clientid;
            Battle->atktype = action;
            Position->destiny  = Target->Position->current;
            Battle->skillid = skillid;
            Position->lastMoveTime = clock( );
            GServer->SendToVisible( &pak, Target );
            return;

        }
        break;
        case SKILL_AOE:
        case BUFF_SELF:
        case BUFF_AOE:
        {
            RESETPACKET( pak, 0x7b2);
            ADDWORD    ( pak, clientid );
            ADDWORD    ( pak, skillid );
            Battle->atktype = action;
            Battle->skillid = skillid;
        }
        break;
        case MONSTER_BUFF_SELF:
        {
            RESETPACKET( pak, 0x7b2);
            ADDWORD    ( pak, clientid );
            ADDWORD    ( pak, skillid );
            Battle->atktype = action;
            Battle->skillid = skillid;
        }
        break;
        case AOE_TARGET:
        {
            //LMA 2008/09/02: new version, the target is a zone, not a monster... so we stick with aoedestiny ;)
            //PY mods
            //Target is NULL for this function when cast by a player
            //Target is NOT NULL when it comes from a monster
            if(Target != NULL) //monster attack
            {
                Position->aoedestiny.x = Target->Position->current.x;
                Position->aoedestiny.y = Target->Position->current.y;
            }
            RESETPACKET( pak, 0x7b4 );
            ADDWORD    ( pak, clientid );
            ADDWORD    ( pak, skillid );
            ADDFLOAT   ( pak, Position->aoedestiny.x*100 );
            ADDFLOAT   ( pak, Position->aoedestiny.y*100 );
            Battle->atktype = action;
            Battle->skillid = skillid;
            Battle->skilltarget = 0;
            Battle->target = Battle->atktarget;
            Position->destiny  = Position->aoedestiny;
            Position->lastMoveTime = clock( );
            Log(MSG_INFO,"StartAction, AOE_TARGET, target (%.2f,%.2f)",Position->aoedestiny.x,Position->aoedestiny.y);
        }
        break;
        case STAY_STILL_ATTACK:
        {
             //LMA: Very special case where the monster don't really attack (mc)
             Battle->atktype = action;
             Battle->skillid = skillid;
             Battle->skilltarget = Target->clientid;
             return;
         }
        default: return;
    }
    //if (getClient()==NULL)
       GServer->SendToVisible( &pak, this );
    /*else
        getClient();*/
}
Пример #4
0
// update position
void CCharacter::UpdatePosition( bool monster_stay_still )
{
    /* old version
    if(IsOnBattle( ) && Battle->target!=0)
    {
        CCharacter* Target = GetCharTarget( );
        if(Target!=NULL)
        {
            if(IsMonster())
            {
                float distance = GServer->distance( Position->current, Position->source );
                if(distance>30)
                {
                    if(Position->Map==8)
                        Log(MSG_INFO,"Update Position, OnFar");

                    OnFar( );
                }
                else
                {
                    if (!monster_stay_still)
                       Position->destiny = Target->Position->current; //MOBS ONLY
                    else
                        Log(MSG_INFO,"This one stays still");

                    if(Position->Map==8)
                        Log(MSG_INFO,"Update Position, destiny=Target->Position->current (%2.f:%.2f)",Position->destiny.x,Position->destiny.y);

                }

            }
            else
            {
                if(Position->Map==8)
                    Log(MSG_INFO,"Update Position Player, destiny=Target->Position->current (%2.f:%.2f)",Position->destiny.x,Position->destiny.y);

                Position->destiny = Target->Position->current; //ONLY IF NO TARGET ON BATTLE
            }

        }
        else
        {
            if(Position->Map==8)
                Log(MSG_INFO,"Update Position,no target, clear battle");

            ClearBattle( Battle );
        }

    }
    */

    //LMA: osprose.
    if(IsOnBattle( ) && Battle->target!=0)
    {
        CCharacter* Target = GetCharTarget( );

        if(Target == NULL)
        {
            ClearBattle( Battle );
        }
        else
        {
            Position->destiny=Target->Position->current;
        }

    }
	//osprose end.


    if(Position->Map==8)
    {
        float tempdist = GServer->distance(Position->current,Position->destiny);

        if(IsPlayer())
        {
            Log(MSG_INFO,"Player HP %I64i, (%.2f:%.2f)->(%.2f:%.2f)=%.2f speed %u",Stats->HP,Position->current.x,Position->current.y,Position->destiny.x,Position->destiny.y,tempdist,Stats->Move_Speed);
        }
        else
        {
            //Log(MSG_INFO,"Monster HP %I64i, (%.2f:%.2f)->(%.2f:%.2f)=%.2f speed %u",Stats->HP,Position->current.x,Position->current.y,Position->destiny.x,Position->destiny.y,tempdist,Stats->Move_Speed);
            //Log(MSG_LOAD,"Monster (%.2f:%.2f)->(%.2f:%.2f)",Position->current.x,Position->current.y,Position->destiny.x,Position->destiny.y);
        }

    }


    //LMA maps: special case (arrive in Game)
    //and he changed map (GM or scroll or teleporter or boat?)
    //2do: other cases too, all in fact...
    bool is_done=false;
    if (IsPlayer( )&&((last_map==-1&&last_coords==-1)||(last_map!=Position->Map)))
    {
      	//updating player's grid
    	int new_coords=0;
    	int new_map=0;
    	int grid_id=0;

      	//deleting previous presence...
      	if (last_map!=-1&&last_coords!=-1)
      	{
          	grid_id=GServer->allmaps[last_map].grid_id;
            if (grid_id!=-1&&!GServer->allmaps[last_map].always_on&&GServer->gridmaps[grid_id].coords[last_coords]>0)
               GServer->gridmaps[grid_id].coords[last_coords]--;
        }

        //New coordinates
    	new_map=Position->Map;
    	grid_id=GServer->allmaps[new_map].grid_id;
        new_coords=GServer->GetGridNumber(new_map,(UINT) floor(Position->current.x),(UINT) floor(Position->current.y));
    	last_map=new_map;
    	last_coords=new_coords;

    	if (grid_id!=-1||!GServer->allmaps[new_map].always_on)
           GServer->gridmaps[grid_id].coords[new_coords]++;

   	    is_done=true;
    }

    if(!IsMoving())
    {
        //osprose
        if(IsPlayer())Position->lastMoveTime = clock();
        //osprose end
        return;
    }

	float dx = Position->destiny.x - Position->current.x;
	float dy = Position->destiny.y - Position->current.y;
	float distance = sqrt( (dx*dx) + (dy*dy) );
    float ntime = ( distance / Stats->Move_Speed * GServer->MOVE_SPEED_MODIF );
    clock_t etime = clock() - Position->lastMoveTime;

    //LMA: bad, that's bad...
	//if (ntime<=etime || distance<1.0 )
	if (ntime<=etime || distance<0.01 )
    {
        // if (IsPlayer()) printf("Arrived! X: %i, Y: %i\n", (int)Position->current.x, (int)Position->current.y);
        if(Position->Map==8&&IsMonster())
            Log(MSG_INFO," Monster Arrived, J (%.2f:%.2f)->(%.2f:%.2f)",Position->current.x,Position->current.y,Position->destiny.x,Position->destiny.y);

		Position->current.x = Position->destiny.x;
		Position->current.y = Position->destiny.y;
    }
	else
    {
		Position->current.x += dx*(etime/ntime);
		Position->current.y += dy*(etime/ntime);
	}

	Position->lastMoveTime = clock( );

	//LMA: maps (for player)
	if(!IsPlayer()||is_done)
	   return;

	//updating player's grid
	int new_coords=0;
	int new_map=0;
	int grid_id=0;

	new_map=Position->Map;
	grid_id=GServer->allmaps[new_map].grid_id;
	new_coords=GServer->GetGridNumber(new_map,(UINT) floor(Position->current.x),(UINT) floor(Position->current.y));
	//changed?
    if (last_map==new_map&&new_coords==last_coords)
         return;

     //Let's update.
	if (grid_id!=-1||!GServer->allmaps[new_map].always_on)
	   GServer->gridmaps[grid_id].coords[new_coords]++;

   //deleting player from his previous map
   grid_id=GServer->allmaps[last_map].grid_id;
   if (grid_id!=-1&&!GServer->allmaps[last_map].always_on&&GServer->gridmaps[grid_id].coords[last_coords]>0)
      GServer->gridmaps[grid_id].coords[last_coords]--;

    //Log(MSG_INFO,"Now[%i,%i],Was[%i,%i]",new_map,new_coords,last_map,last_coords);
	last_map=new_map;
	last_coords=new_coords;
}
Пример #5
0
void CCharacter::DoAttack( )
{
    //if(Status->Sleep <= 0xff)
    //{
    //    ClearBattle( Battle );
    //    return; // can't take any action while we are asleep can we?
    //}
    //Log(MSG_INFO,"skill type %i selected. Chartype = %i",Battle->atktype, CharType);
    if(Battle->iscasting == 1) 
    {
        CCharacter* Enemy = GetCharTarget( );
        if(Enemy == NULL)
        {
            ClearBattle( Battle );
            return;
        }
        //Log(MSG_DEBUG,"Iscasting detected as true. Reset to false.");
        if(CanAttack())
        {
            //if(IsPlayer())
            //{
            //    Log(MSG_DEBUG,"Should reach here once on normal attack. iscasting state = %i",Battle->iscasting);
            //}
            ClearBattle( Battle );
            StartAction(Enemy, NORMAL_ATTACK, 0);
        }
        else
        {
            return;
        }
        return;
    }
    if(!CanAttack())
    {
        return;
    }
    if(IsSummon())
    {
        CCharacter* Enemy = GetCharTarget( );
        if(Enemy == NULL || (Battle->atktype != SKILL_AOE && Battle->atktype != BUFF_AOE))
        {
            //Log(MSG_DEBUG,"No Enemy found");
            ClearBattle( Battle );
            return;
        }
        if(this == Enemy) //summoned monster is attacking itself. It has been observed to happen
        {
            //Log(MSG_INFO,"Clearing Battle for this summon");
            ClearBattle( Battle );
            return;
        }
        if(Enemy->IsSummon())
        {
            CMonster* thisMonster = reinterpret_cast<CMonster*>(this);
            if(thisMonster == NULL)
            {
                ClearBattle( Battle );
                return;           
            }
            CMonster* otherMonster = reinterpret_cast<CMonster*>(Enemy);
            if(otherMonster == NULL)
            {
                ClearBattle( Battle );
                return;           
            }
            if(thisMonster->owner == otherMonster->owner)
            {
                //Log(MSG_INFO,"Clearing Battle for this summon");
                ClearBattle( Battle );
                return;                    
            }                
        }
    }
    CMap* map = GServer->MapList.Index[Position->Map];
    //Log(MSG_INFO,"DoAttack Battle Attack type = %i",Battle->atktype);
    switch(Battle->atktype)
    {
        case NORMAL_ATTACK://normal attack
        {
            //if(!Status->CanAttack)
            //    return; //can't attack right now.
            CCharacter* Enemy = GetCharTarget( );
            if(Enemy == NULL)
            {
                ClearBattle( Battle );
                return;
            }
            if(Enemy == this)
            {
                //Log(MSG_INFO,"WTF?? I AM trying to attack myself");
                ClearBattle( Battle );
            }
            if(IsTargetReached( Enemy ))
            {
                //if(IsMonster())
                //    Log(MSG_INFO,"Monster is trying to hit the player");
                NormalAttack( Enemy );
                if (Enemy->IsMonster()) // do monster AI script when monster is attacked.
                {
                    CMonster* monster = GServer->GetMonsterByID(Enemy->clientid, Enemy->Position->Map);
                    if(monster == NULL)return;
                    //monster->DoAi(monster->thisnpc->AI, 3);
                    monster->DoAi(monster->monAI, 3);
                }
            }
        }
        break;
        case SKILL_ATTACK://skill attack
        {
            CCharacter* Enemy = GetCharTarget( );
            if(Enemy == NULL)
            {
                ClearBattle( Battle );
                return;
            }
            CSkills* skill = GServer->GetSkillByID( Battle->skillid );
            if(skill == NULL)
            {
                //ClearBattle( Battle );
                return;
            }
            if(IsTargetReached( Enemy, skill )) 
            {
                SkillAttack( Enemy, skill );
                if (Enemy->IsMonster())
                {
                    CMonster* monster = GServer->GetMonsterByID(Enemy->clientid, Enemy->Position->Map);
                    if(monster == NULL)return;
                    monster->DoAi(monster->monAI, 3);
                }
            }
        }
        break;
        case SKILL_BUFF://buffs
        {


            CCharacter* Enemy = GetCharTarget( );
            if(Enemy == NULL)
            {
                //Log(MSG_DEBUG,"this target is NULL");
                ClearBattle( Battle );
                return;
            }
            CSkills* skill = GServer->GetSkillByID( Battle->skillid );
            if(skill == NULL)
            {
                //Log(MSG_DEBUG,"this skill is NULL");
                return;
            }

            if(IsTargetReached( Enemy, skill ))
            {
                //Log(MSG_DEBUG,"Skill successfully cast");
                BuffSkill( Enemy, skill );
            }
        }
        break;
        case SKILL_AOE:
        //case SKILL_SELF: //this is impossible. it can never be set
        case AOE_TARGET:
        {


            //Log(MSG_DEBUG,"Called skill type %i",Battle->atktype);
            CCharacter* Enemy = NULL;
            CSkills* skill = GServer->GetSkillByID( Battle->skillid );
            if(skill == NULL)
            {
                ClearBattle( Battle );
                return;
            }
            if(Battle->atktype == AOE_TARGET)
            {
                float distance = GServer->distance( Position->current, Position->destiny );
                if(distance <= skill->range)
                {
                    Position->destiny = Position->current;
                    AoeSkill( skill, Enemy );
                }
            }
            else
            {
                Position->skilltargetpos = Position->current;
                AoeSkill( skill, NULL );
            }
        }
        break;
        case BUFF_SELF:
        {

            //    return; // can't cast skills right now
            CSkills* skill = GServer->GetSkillByID( Battle->skillid );
            if(skill == NULL)
            {
                //ClearBattle( Battle );
                return;
            }
            BuffSkill( this, skill );
        }
        break;
        case BUFF_AOE:
        {
            //Log(MSG_INFO,"BUFF AOE selected");
            CSkills* skill = GServer->GetSkillByID( Battle->skillid );
            if(skill == NULL)
            {
                //ClearBattle( Battle );

                return;
            }
            AoeBuff( skill );
        }
        break;
        default:
            return;
        break;
    }
}
Пример #6
0
void CCharacter::UpdatePosition( bool monster_stay_still )
{
    //LMA: osprose.
    if(IsOnBattle( ) && Battle->target!=0)
    {
        CCharacter* Target = GetCharTarget( );

        if(Target == NULL)
        {
            ClearBattle( Battle );
        }
        else
        {
            //LMA: Don't need to move if the target is reached.
            //Bad idea since the monster can go away and it seems
            //player goes automatically after him client side...
            /*
            if (Battle->atktype==NORMAL_ATTACK)
            {
                if(!IsTargetReached( Target ))
                {
                    Position->destiny=Target->Position->current;
                }

            }
            else
            {
                Position->destiny=Target->Position->current;
            }
            */
            //So let's go back to the old way.
             //LMA: done in DoAttack...
            //Can be "dangerous" since it checks range for normal attack
            //and if we're with skills the range isn't the same so player changes
            //its destiny all the time from skill range to weapon range.
            /*if(!IsTargetReached( Target ))
            {
                Position->destiny=Target->Position->current;
            }*/

        }

    }
	//osprose end.

    //LMA: position in map 8
    /*if(Position->Map==8)
    {
        float tempdist = GServer->distance(Position->current,Position->destiny);

        if(IsPlayer())
        {
            Log(MSG_INFO,"Player HP %I64i, (%.2f:%.2f)->(%.2f:%.2f)=%.2f speed %u",Stats->HP,Position->current.x,Position->current.y,Position->destiny.x,Position->destiny.y,tempdist,Stats->Move_Speed);
        }
        else
        {
            Log(MSG_INFO,"Monster HP %I64i, (%.2f:%.2f)->(%.2f:%.2f)=%.2f speed %u",Stats->HP,Position->current.x,Position->current.y,Position->destiny.x,Position->destiny.y,tempdist,Stats->Move_Speed);
            //Log(MSG_LOAD,"Monster (%.2f:%.2f)->(%.2f:%.2f)",Position->current.x,Position->current.y,Position->destiny.x,Position->destiny.y);
        }

    }*/

    //LMA maps: special case (arrive in Game)
    //and he changed map (GM or scroll or teleporter or boat?)
    //2do: other cases too, all in fact...
    bool is_done=false;
    if (IsPlayer( )&&((last_map==-1&&last_coords==-1)||(last_map!=Position->Map)))
    {
      	//updating player's grid
    	int new_coords=0;
    	int new_map=0;
    	int grid_id=0;

      	//deleting previous presence...
      	if (last_map!=-1&&last_coords!=-1)
      	{
          	grid_id=GServer->allmaps[last_map].grid_id;
            if (grid_id!=-1&&!GServer->allmaps[last_map].always_on&&GServer->gridmaps[grid_id].coords[last_coords]>0)
               GServer->gridmaps[grid_id].coords[last_coords]--;
        }

        //New coordinates
    	new_map=Position->Map;
    	grid_id=GServer->allmaps[new_map].grid_id;

        if (grid_id==-1)
        {
            Log(MSG_WARNING,"It seems you forgot to declare map %i in map_grid.csv",new_map);
        }

        new_coords=GServer->GetGridNumber(new_map,(UINT) floor(Position->current.x),(UINT) floor(Position->current.y));
    	last_map=new_map;
    	last_coords=new_coords;

    	//if (grid_id!=-1||!GServer->allmaps[new_map].always_on)
    	if (grid_id!=-1&&!GServer->allmaps[new_map].always_on)
           GServer->gridmaps[grid_id].coords[new_coords]++;

   	    is_done=true;
    }

    if(!IsMoving())
    {
        //osprose
        if(IsPlayer())
        {
            Position->current.x = Position->destiny.x;
            Position->current.y = Position->destiny.y;
            Position->lastMoveTime = clock();
        }
        //osprose end
        return;
    }

	float dx = Position->destiny.x - Position->current.x;
	float dy = Position->destiny.y - Position->current.y;
	float distance = sqrt( (dx*dx) + (dy*dy) );
	float ntime = ( distance / (float(Stats->Move_Speed)/100)) * CLOCKS_PER_SEC;
    clock_t etime = clock() - Position->lastMoveTime;

    //LMA: bad, that's bad...
	//if (ntime<=etime || distance<1.0 )
	if (ntime<=etime || distance<0.01 )
    {
        // if (IsPlayer()) printf("Arrived! X: %i, Y: %i\n", (int)Position->current.x, (int)Position->current.y);
        if(Position->Map==8&&IsMonster())
        {
            Log(MSG_INFO," Monster Arrived, J (%.2f:%.2f)->(%.2f:%.2f)",Position->current.x,Position->current.y,Position->destiny.x,Position->destiny.y);
        }

		Position->current.x = Position->destiny.x;
		Position->current.y = Position->destiny.y;
    }
	else
    {
		Position->current.x = dx*(etime/ntime) + Position->current.x;
		Position->current.y = dy*(etime/ntime) + Position->current.y;
	}

	Position->lastMoveTime = clock( );

	//LMA: maps (for player)
	if(!IsPlayer()||is_done)
	   return;

	//updating player's grid
	int new_coords=0;
	int new_map=0;
	int grid_id=0;

	new_map=Position->Map;
	grid_id=GServer->allmaps[new_map].grid_id;

	if (grid_id==-1)
	{
	    Log(MSG_WARNING,"It seems you forgot to declare map %i in map_grid.csv",new_map);
	}

	new_coords=GServer->GetGridNumber(new_map,(UINT) floor(Position->current.x),(UINT) floor(Position->current.y));
	//changed?
    if (last_map==new_map&&new_coords==last_coords)
         return;

     //Let's update.
	//if (grid_id!=-1||!GServer->allmaps[new_map].always_on)
	if (grid_id!=-1&&!GServer->allmaps[new_map].always_on)
	   GServer->gridmaps[grid_id].coords[new_coords]++;

   //deleting player from his previous map
   grid_id=GServer->allmaps[last_map].grid_id;
   if (grid_id!=-1&&!GServer->allmaps[last_map].always_on&&GServer->gridmaps[grid_id].coords[last_coords]>0)
      GServer->gridmaps[grid_id].coords[last_coords]--;

    //Log(MSG_INFO,"Now[%i,%i],Was[%i,%i]",new_map,new_coords,last_map,last_coords);
	last_map=new_map;
	last_coords=new_coords;
}