// Move a mob (specified point) void CMonster::MoveTo( fPoint nPos, bool randcircle ) { if(randcircle) Position->destiny = GServer->RandInCircle( nPos, 5 ); else Position->destiny = nPos; // Position->lastMoveTime = clock(); BEGINPACKET( pak, 0x797 ); ADDWORD ( pak, clientid ); ADDWORD ( pak, 0x0000 ); // ??? ADDWORD ( pak, Stats->Move_Speed ); ADDFLOAT ( pak, Position->destiny.x*100 ); ADDFLOAT ( pak, Position->destiny.y*100 ); ADDWORD ( pak, 0xcdcd ); ADDBYTE ( pak, 0x01 ); GServer->SendToVisible(&pak, this ); }
// Move a mob (random place) void CMonster::Move( ) { Position->destiny = GServer->RandInCircle( Position->source, 10 ); // Position->lastMoveTime = clock(); ClearBattle( Battle ); BEGINPACKET( pak, 0x797 ); ADDWORD ( pak, clientid ); ADDWORD ( pak, 0x0000 );//??? ADDWORD ( pak, Stats->Move_Speed ); //speed ADDFLOAT ( pak, Position->destiny.x*100 ); ADDFLOAT ( pak, Position->destiny.y*100 ); ADDWORD ( pak, 0xcdcd ); ADDBYTE ( pak, 0x01 ); GServer->SendToVisible(&pak, this); }
// Teleport player to this map and this coord. bool CMap::TeleportPlayer( CPlayer* player, fPoint coord, bool TelePassenger ) { GServer->MapList.Index[player->Position->Map]->RemovePlayer( player, false ); player->Position->Map = id; player->Position->current = coord; player->Position->destiny = coord; player->Session->inGame = false; player->Position->lastMoveTime = clock(); if(player->Stats->HP<1)player->Stats->HP=player->Stats->MaxHP * 10 / 100; if(!allowpat || !TelePassenger) { if(!allowpat) player->Status->Stance=0x03; player->Ride->Drive = false; player->Ride->charid= 0; player->Ride->Ride = false; } AddPlayer( player ); BEGINPACKET( pak, 0x07a8 ); ADDWORD ( pak, player->clientid ); ADDWORD ( pak, player->Position->Map ); ADDFLOAT ( pak, player->Position->current.x*100 ); ADDFLOAT ( pak, player->Position->current.y*100 ); ADDWORD ( pak, (player->Status->Stance==0x04?0x0201:0x0001) ); player->client->SendPacket( &pak ); if( player->Ride->Drive && player->Ride->charid!=0 ) { CPlayer* otherclient = GServer->GetClientByCID( player->Ride->charid ); if( otherclient!=NULL ) { if(TelePassenger) { TeleportPlayer( otherclient, coord ); } else { otherclient->Ride->Drive = false; otherclient->Ride->charid= 0; otherclient->Ride->Ride = false; } } } GServer->pakClearUser( player ); GServer->ClearClientID( player->clientid ); player->RestartPlayerVal( ); return true; }
// Move a mob (random place) void CMonster::Move( ) { Position->destiny = GServer->RandInCircle( Position->source, 10 ); // Position->lastMoveTime = clock(); ClearBattle( Battle ); BEGINPACKET( pak, 0x797 ); ADDWORD ( pak, clientid ); ADDWORD ( pak, 0x0000 );//??? ADDWORD ( pak, Stats->Move_Speed ); //speed ADDFLOAT ( pak, Position->destiny.x*100 ); ADDFLOAT ( pak, Position->destiny.y*100 ); ADDWORD ( pak, 0xcdcd ); //ADDBYTE ( pak, 0x01 ); ADDBYTE ( pak, thisnpc->stance ); //AIP GServer->SendToVisible(&pak, this); if(Position->Map==8) Log(MSG_INFO,"Move (%.2f;%.2f) to (%.2f;%.2f)",Position->current.x,Position->current.y,Position->destiny.x,Position->destiny.y); }
// Move a mob (specified point) void CMonster::MoveTo( fPoint nPos, bool randcircle ) { if(randcircle) Position->destiny = GServer->RandInCircle( nPos, 5 ); else Position->destiny = nPos; // Position->lastMoveTime = clock(); BEGINPACKET( pak, 0x797 ); ADDWORD ( pak, clientid ); ADDWORD ( pak, 0x0000 ); // ??? ADDWORD ( pak, Stats->Move_Speed ); ADDFLOAT ( pak, Position->destiny.x*100 ); ADDFLOAT ( pak, Position->destiny.y*100 ); ADDWORD ( pak, 0xcdcd ); //ADDBYTE ( pak, 0x01 ); ADDBYTE ( pak, thisnpc->stance); //AIP GServer->SendToVisible(&pak, this ); if(Position->Map==8) Log(MSG_INFO,"MoveTo (%.2f;%.2f) to (%.2f;%.2f)",Position->current.x,Position->current.y,Position->destiny.x,Position->destiny.y); }
// Spawn a monster //LMA: added handling of skill summons. void CMonster::SpawnMonster( CPlayer* player, CMonster* thismon ) { BEGINPACKET( pak, 0x792 ); //struct tag_ADD_CHAR ADDWORD ( pak, clientid ); ADDFLOAT ( pak, Position->current.x*100 ); ADDFLOAT ( pak, Position->current.y*100 ); //current X and Y position if((thismon->bonushp > 0 || thismon->bonusmp > 0) && (thismon->skillid > 0)) //What is this? It seems to be sending this in place of destination if the monster is not able to move. Bonfires and so on { ADDFLOAT ( pak, 0xcdcdcdcd ); ADDFLOAT ( pak, 0xcdcdcdcd ); } else { ADDFLOAT ( pak, Position->destiny.x*100 ); //Destination position. This should always follow current position ADDFLOAT ( pak, Position->destiny.y*100 ); } // next 2 WORDS are m_wCommand and m_wTargetOBJ if(IsDead( )) { ADDWORD ( pak, 0x0003 ); ADDWORD ( pak, 0x0000 ); } else if(IsOnBattle( )) { //LMA: for supportive summons (lucky ghost...) if(Battle->bufftarget == Battle->target) { ADDWORD ( pak, 0x0002 ); ADDWORD ( pak, 0x0000 ); } else { ADDWORD ( pak, 0x0002 ); ADDWORD ( pak, Battle->target ); } } else if(IsMoving( )) { ADDWORD ( pak, 0x0001 ); ADDWORD ( pak, 0x0000 ); } else { ADDWORD ( pak, 0x0000 ); ADDWORD ( pak, 0x0000 ); } ADDBYTE ( pak, thisnpc->stance ); ADDWORD ( pak, Stats->HP ); ADDWORD ( pak, 0x0000 ); // now Team Number if(thismon->owner != player->clientid) { CMap* map = GServer->MapList.Index[Position->Map]; //LMA: adding team... if (thismon->team!=0) { ADDWORD( pak,thismon->team); } else { if(IsSummon( ) && map->allowpvp!=0) { //Hostil ADDWORD( pak, 0x0064 ); } else if (IsSummon( ) && map->allowpvp==0) { //Friendly ADDWORD ( pak, 0x0000 ); } else { //Hostil ADDWORD( pak, 0x0064 ); } } } else { //Friendly ADDWORD( pak, 0x0000 ); } ADDWORD ( pak, 0x0000 ); //and finally DWORD StatusFlag ADDDWORD( pak, GServer->BuildBuffs( this ) ); //struct gsv_MOB_CHAR ADDWORD ( pak, montype ); ADDWORD ( pak, 0x0000 ); ADDWORD ( pak, thismon->Stats->Level ); ADDWORD ( pak, thismon->Stats->Size ); player->client->SendPacket( &pak ); //LMA: supportive summons (lucky ghost) //PY: Another special case. Will probably need to remove this later if(IsSummon() && buffid > 0 && (player == GetOwner())) { Log(MSG_INFO,"The summon is spawned"); /*CPlayer* player = GetOwner( ); if (ownplayer==NULL) return true;*/ StartAction( player,SUMMON_BUFF,buffid); Log(MSG_INFO,"completly"); buffid=0; //only one buff } }
// Spawn a monster //LMA: added handling of skill summons. void CMonster::SpawnMonster( CPlayer* player, CMonster* thismon ) { BEGINPACKET( pak, 0x792 ); ADDWORD ( pak, clientid ); ADDFLOAT ( pak, Position->current.x*100 ); ADDFLOAT ( pak, Position->current.y*100 ); ADDDWORD ( pak, 0xcdcdcdcd ); ADDDWORD ( pak, 0xcdcdcdcd ); if(IsDead( )) { ADDWORD ( pak, 0x0003 ); ADDWORD ( pak, 0x0000 ); } else if(IsOnBattle( )) { //LMA: for supportive summons (lucky ghost...) if(Battle->bufftarget==Battle->target) { ADDWORD ( pak, 0x0002 ); ADDWORD ( pak, 0x0000 ); } else { ADDWORD ( pak, 0x0002 ); ADDWORD ( pak, Battle->target ); } } else if(IsMoving( )) { ADDWORD ( pak, 0x0001 ); ADDWORD ( pak, 0x0000 ); } else { ADDWORD ( pak, 0x0000 ); ADDWORD ( pak, 0x0000 ); } if(IsSummon( ) ) { ADDBYTE ( pak, 0x01 ); } else { ADDBYTE ( pak, 0x00 ); } ADDWORD(pak, 0x0000); if(Stats->HP > MAXHPMOB) { Stats->HP = (long long) MAXHPMOB; } ADDDWORD ( pak, Stats->HP ); if(thismon->owner != player->clientid) { CMap* map = GServer->MapList.Index[Position->Map]; if (thismon->team!=0) { ADDDWORD( pak,thismon->team); } else { if(IsSummon( ) && map->allowpvp!=0) { //Hostil ADDDWORD( pak, 0x00000064 ); } else if (IsSummon( ) && map->allowpvp==0) { //Friendly ADDDWORD ( pak, 2 ); } else { //Hostil ADDDWORD( pak, 0x00000064 ); } } } else { //Friendly ADDDWORD( pak, 2 ); } ADDDWORD( pak, GServer->BuildBuffs( this ) ); ADDDWORD ( pak, montype ); if(IsSummon( )) { ADDWORD( pak, owner ); if (thismon->skillid>0) { ADDWORD( pak, thismon->skillid ); //id del skill (si es summon de skill) } else { ADDWORD( pak, 0x0000 ); //id del skill (si es summon de skill) } } player->client->SendPacket( &pak ); //LMA: supportive summons (lucky ghost) if(IsSummon()&&buffid>0&&(player==GetOwner())) { Log(MSG_INFO,"The summon is spawned"); StartAction( player,SUMMON_BUFF,buffid); Log(MSG_INFO,"completly"); buffid=0; //only one buff } }
// Teleport player to this map and this coord. bool CMap::TeleportPlayer( CPlayer* player, fPoint coordold, bool TelePassenger ) { fPoint coord; coord=coordold; if(id==9&&player->UWPosition->source.x>0&&player->UWPosition->source.y>0) { coord.x = player->UWPosition->source.x; coord.y = player->UWPosition->source.y; } GServer->MapList.Index[player->Position->Map]->RemovePlayer( player, false ); player->Position->Map = id; player->Position->current = coord; //TELEPORT ONLY player->Position->destiny = coord; //TELEPORT ONLY player->Session->inGame = false; player->Position->lastMoveTime = clock(); if(!allowpat || !TelePassenger) { if(!allowpat) player->Status->Stance=0x03; player->Ride->Drive = false; player->Ride->charid= 0; player->Ride->Ride = false; } AddPlayer( player ); BEGINPACKET( pak, 0x07a8 ); ADDWORD ( pak, player->clientid ); ADDDWORD ( pak, player->Position->Map ); ADDFLOAT ( pak, player->Position->current.x*100 ); ADDFLOAT ( pak, player->Position->current.y*100 ); ADDBYTE ( pak, (player->Status->Stance==0x04?0x0201:0x0001) ); for(int i=0; i<14; i++) ADDBYTE ( pak, 0 ); //move speed. ADDWORD( pak,player->Stats->Base_Speed ); for(int i=0; i<38; i++) ADDBYTE ( pak, 0 ); player->client->SendPacket( &pak ); if( player->Ride->Drive && player->Ride->charid!=0 ) { CPlayer* otherclient = GServer->GetClientByCID( player->Ride->charid ); if( otherclient!=NULL ) { if(TelePassenger) { TeleportPlayer( otherclient, coord ); } else { otherclient->Ride->Drive = false; otherclient->Ride->charid= 0; otherclient->Ride->Ride = false; } } } GServer->pakClearUser( player ); GServer->ClearClientID( player->clientid ); player->RestartPlayerVal( ); return true; }
// start action [attack] void CCharacter::StartAction( CCharacter* Target, BYTE action, UINT skillid) { BEGINPACKET( pak, 0 ); switch(action) { case NORMAL_ATTACK: { //Log( MSG_INFO, "case NORMAL_ATTACK"); RESETPACKET( pak, 0x798 ); ADDWORD ( pak, clientid ); ADDWORD ( pak, Target->clientid ); ADDWORD ( pak, Stats->Move_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: //Log( MSG_INFO, "case SKILL_ATTACK"); case SKILL_BUFF: { //Log( MSG_INFO, "case SKILL_BUFF"); //Log( MSG_INFO, "clientid :%i Target id :%i skillid :%i", clientid, Target->clientid, skillid); RESETPACKET( pak, 0x7b3 ); ADDWORD ( pak, clientid ); ADDWORD ( pak, Target->clientid ); ADDWORD ( pak, skillid ); if (clientid==Target->clientid) { ADDWORD( pak, 0x0000 ); } else { ADDWORD (pak, Stats->Move_Speed); } ADDFLOAT ( pak, Target->Position->current.x*100 ); ADDFLOAT ( pak, Target->Position->current.y*100 ); if (CharType==2&&action==SKILL_ATTACK) ADDBYTE ( pak, 0x08);//8 monster skill attack nMotion ? 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 SKILL_AOE://Log( MSG_INFO, "case SKILL_AOE"); case BUFF_SELF://Log( MSG_INFO, "case BUFF_SELF"); case BUFF_AOE: { //Log( MSG_INFO, "case BUFF_AOE"); RESETPACKET( pak, 0x7b2); ADDWORD ( pak, clientid ); ADDWORD ( pak, skillid ); Battle->atktype = action; Battle->skillid = skillid; } break; case AOE_TARGET: { //Log( MSG_INFO, "case AOE_TARGET"); RESETPACKET( pak, 0x7b4 ); ADDWORD ( pak, clientid ); ADDWORD ( pak, skillid ); ADDFLOAT ( pak, Position->skilltargetpos.x*100 ); ADDFLOAT ( pak, Position->skilltargetpos.y*100 ); Battle->atktype = action; Battle->skillid = skillid; Battle->skilltarget = 0; } break; default: return; } GServer->SendToVisible( &pak, this ); Battle->contatk = true; }
// Spawn Another User on the Screen bool CPlayer::SpawnToPlayer( CPlayer* player, CPlayer* otherclient ) { /* if( Party->party!=NULL && Party->party == player->Party->party) { BEGINPACKET( pak, 0x7d5 ); ADDDWORD ( pak, CharInfo->charid ); ADDWORD ( pak, clientid ); ADDWORD ( pak, GetMaxHP( ) ); ADDWORD ( pak, Stats->HP ); ADDDWORD ( pak, 0x01000000 ); ADDDWORD ( pak, 0x0000000f ); ADDWORD ( pak, 0x1388 ); player->client->SendPacket( &pak ); } */ /* if( Ride->Ride ) { CPlayer* rideclient = GServer->GetClientByCID( Ride->charid, Position->Map ); if(rideclient==NULL) { Ride->Ride = false; Ride->Drive= false; Ride->charid = 0; return true; } if( GServer->IsVisible( player, rideclient ) || player->CharInfo->charid == rideclient->CharInfo->charid ) { BEGINPACKET( pak, 0x796 ); if( Ride->Drive ) { ADDWORD ( pak, rideclient->clientid ); ADDFLOAT ( pak, rideclient->Position->current.x*100 ); ADDFLOAT ( pak, rideclient->Position->current.y*100 ); } else { ADDWORD ( pak, clientid ); ADDFLOAT ( pak, Position->current.x*100 ); ADDFLOAT ( pak, Position->current.y*100 ); } ADDWORD ( pak, 0x0000 ); player->client->SendPacket( &pak ); RESETPACKET( pak, 0x7dd ); ADDBYTE ( pak, 0x02 ); if( rideclient->Ride->Drive ) { ADDWORD ( pak, rideclient->clientid ); ADDWORD ( pak, clientid ); } else { ADDWORD ( pak, clientid ); ADDWORD ( pak, rideclient->clientid ); } player->client->SendPacket( &pak ); } } return true; */ CMap* map = GServer->MapList.Index[otherclient->Position->Map]; BEGINPACKET( pak, 0x793 ); ADDWORD( pak, clientid); // USER ID ADDFLOAT( pak, Position->current.x*100 ); // POS X ADDFLOAT( pak, Position->current.y*100 ); // POS Y ADDFLOAT( pak, Position->destiny.x*100 ); // GOING TO X ADDFLOAT( pak, Position->destiny.y*100 ); // GOINT TO Y if(Shop->open) { ADDWORD( pak, 0x000b ); ADDWORD( pak, 0x0000 ); } else if(Stats->HP <= 0) { ADDWORD( pak, 0x0003 ); ADDWORD( pak, 0x0000 ); } else if(Status->Stance == SITTING) { ADDWORD( pak, 0x000a ); ADDWORD( pak, 0x0000 ); } else if (Battle->atktarget!=0) { ADDWORD( pak, 0x0002 ); ADDWORD( pak, Battle->atktarget ); } else if(Position->destiny.x != Position->current.x || Position->destiny.y != Position->current.y) { ADDWORD( pak, 0x0001 ); ADDWORD( pak, 0x0000 ); } else { ADDWORD( pak, 0x0000 ); ADDWORD( pak, 0x0000 ); } ADDBYTE( pak, Ride->Drive==true?2:1); ADDWORD( pak, Stats->HP); ADDWORD( pak, 0x0000); if(map->allowpvp==1)//clan v clan map { ADDWORD(pak, otherclient->Clan->clanid );//?? ADDWORD(pak, 0x0005 );//red icon (map) } else if(map->allowpvp==2) // pvp { ADDWORD(pak, otherclient->clientid); ADDWORD(pak, 0x0000 ); } else { ADDWORD(pak, 0x0002 );//white icon (map) ADDWORD(pak, 0x0000 );//white icon (map) } //ADDWORD( pak, 0x00 ); ADDDWORD( pak, GServer->BuildBuffs( this ) ); // BUFFS ADDBYTE( pak, CharInfo->Sex ); // GENDER ADDWORD( pak, Stats->Move_Speed ); // WALK SPEED MAYBE? ADDBYTE( pak, 0x00 ); // ?? ADDBYTE( pak, 0x00 ); // ?? ADDBYTE( pak, 0x01 ); // ?? ADDDWORD( pak, CharInfo->Face ); // FACE TYPE ADDDWORD( pak, CharInfo->Hair ); // HAIR TYPE ADDDWORD( pak, GServer->BuildItemShow( items[2] )); // CAP ADDDWORD( pak, GServer->BuildItemShow( items[3] )); // BODY ADDDWORD( pak, GServer->BuildItemShow( items[5] )); // GLOVES ADDDWORD( pak, GServer->BuildItemShow( items[6] )); // BOOTS ADDDWORD( pak, GServer->BuildItemShow( items[1] )); // FACE ADDDWORD( pak, GServer->BuildItemShow( items[4] )); // BACK ADDDWORD( pak, GServer->BuildItemShow( items[7] )); // WEAPON ADDDWORD( pak, GServer->BuildItemShow( items[8] )); // SUBWEAPON ADDWORD( pak, GServer->BuildItemHead(items[132] )); ADDWORD( pak, GServer->BuildItemHead(items[133] )); ADDWORD( pak, GServer->BuildItemHead(items[134] )); ADDWORD( pak, CharInfo->Job ); ADDBYTE( pak, Stats->Level); if(items[135].itemnum>0){ ADDWORD( pak, (items[135].itemnum +1024));} else{ ADDWORD( pak, 0x0000 );} ADDWORD( pak, 0x0000 ); if(items[136].itemnum>0){ ADDWORD( pak, (items[136].itemnum +1024));} else{ ADDWORD( pak, 0x0000 );} ADDWORD( pak, 0x0000 ); if(items[137].itemnum>0){ ADDWORD( pak, (items[137].itemnum +1024));} else{ ADDWORD( pak, 0x0000 );} ADDWORD( pak, 0x0000 ); if(items[138].itemnum>0){ ADDWORD( pak, (items[138].itemnum +1024));} else{ ADDWORD( pak, 0x0000 );} ADDWORD( pak, 0x0000 ); ADDWORD( pak, (Stats->HP<=0)?0x0:0xCDCD ); if(Shop->open) { ADDWORD( pak, 0x0002 ); } else { ADDWORD( pak, 0x0000 ); } ADDWORD( pak, 0x0000 ); ADDSTRING( pak, CharInfo->charname ); ADDBYTE( pak, 0x00 ); if(Status->Dash_up != 0xff) ADDWORD ( pak, (MagicStatus[Status->Dash_up].Value)); if(Status->Haste_up!= 0xff) ADDWORD ( pak, (MagicStatus[Status->Haste_up].Value)); if(Shop->open) { ADDBYTE( pak, Shop->ShopType); ADDBYTE( pak, 0x00); ADDSTRING(pak, Shop->name); ADDBYTE( pak, 0x00); } if(Clan->clanid!=0) { ADDWORD ( pak, Clan->clanid ); ADDWORD ( pak, 0x0000 ); ADDWORD ( pak, Clan->back ); ADDWORD ( pak, Clan->logo ); ADDBYTE ( pak, Clan->grade ); ADDBYTE ( pak, Clan->clanrank ); ADDSTRING ( pak, Clan->clanname ); } ADDWORD( pak, 0x0000 ); player->client->SendPacket(&pak); return true; }
bool CPlayer::SpawnToPlayer( CPlayer* player, CPlayer* otherclient ) { BEGINPACKET ( pak, 0x793 ); ADDWORD ( pak, clientid); // Client ID ADDFLOAT ( pak, Position->current.x*100 ); // Position X ADDFLOAT ( pak, Position->current.y*100 ); // Position Y ADDFLOAT ( pak, Position->destiny.x*100 ); // Position X ADDFLOAT ( pak, Position->destiny.y*100 ); // Position Y // Observe: 430 Extra Bytes ADDDWORD ( pak, 0 ); // ?? ADDWORD ( pak, 0 ); // ?? // End switch (Status->Stance) { case WALKING: ADDBYTE ( pak, 0x00 ); // Walking break; case RUNNING: ADDBYTE ( pak, 0x01 ); // Running break; case DRIVING: case MOUNTED: ADDBYTE ( pak, 0x02 ); // Driving // Observe: Mounts aswell break; default: ADDBYTE ( pak, 0x00 ); // Default: Running } if(Status->Stance == 0x01) { ADDWORD ( pak, 0x000a ); ADDWORD ( pak, 0x0000 ); } else if(IsDead()) { ADDWORD ( pak, 0x0003 ); ADDWORD ( pak, 0x0000 ); } else if(Position->destiny.x != Position->current.y || Position->destiny.y != Position->current.y) { ADDWORD ( pak, 0x0001 ); ADDWORD ( pak, Battle->atktarget ); } else if(Battle->atktarget != 0) { ADDWORD ( pak, 0x0002 ); ADDWORD ( pak, Battle->atktarget ); } else { ADDDWORD( pak, 0x00000000 ); } pvp_id = otherclient->ReturnPvp(player,otherclient); ADDDWORD (pak, pvp_id); ADDDWORD ( pak, GServer->BuildBuffs( this ) ); // Buffs ADDBYTE ( pak, CharInfo->Sex ); // Gender ADDDWORD ( pak, Stats->Move_Speed ); // Movement Speed ADDBYTE ( pak, CharInfo->HairColor ); // HairColor ADDDWORD ( pak, CharInfo->Face ); // Face Type ADDDWORD ( pak, CharInfo->Hair ); // Hair Type if(items[142].itemnum != 0) // Cap { ADDWORD ( pak, items[142].itemnum ); ADDWORD ( pak, GServer->BuildItemRefine( items[142])); } else { ADDWORD ( pak, items[2].itemnum ); ADDWORD ( pak, GServer->BuildItemRefine( items[2])); } if(items[143].itemnum != 0) // Body { ADDWORD ( pak, items[143].itemnum ); ADDWORD ( pak, GServer->BuildItemRefine( items[143])); } else { ADDWORD ( pak, items[3].itemnum ); ADDWORD ( pak, GServer->BuildItemRefine( items[3])); } if(items[144].itemnum != 0) // Gloves { ADDWORD ( pak, items[144].itemnum ); ADDWORD ( pak, GServer->BuildItemRefine( items[144])); } else { ADDWORD ( pak, items[5].itemnum ); ADDWORD ( pak, GServer->BuildItemRefine( items[5])); } if(items[145].itemnum != 0) // Shoes { ADDWORD ( pak, items[145].itemnum ); ADDWORD ( pak, GServer->BuildItemRefine( items[145])); } else { ADDWORD ( pak, items[6].itemnum ); ADDWORD ( pak, GServer->BuildItemRefine( items[6])); } if(items[146].itemnum != 0) // Mask { ADDWORD ( pak, items[146].itemnum ); ADDWORD ( pak, GServer->BuildItemRefine( items[146])); } else { ADDWORD ( pak, items[1].itemnum ); ADDWORD ( pak, GServer->BuildItemRefine( items[1])); } if(items[147].itemnum != 0) // Back { ADDWORD ( pak, items[147].itemnum ); ADDWORD ( pak, GServer->BuildItemRefine( items[147])); } else { ADDWORD ( pak, items[4].itemnum ); ADDWORD ( pak, GServer->BuildItemRefine( items[4])); } ADDWORD ( pak, items[7].itemnum ); // Weapon ADDWORD ( pak, GServer->BuildItemRefine( items[7] ) ); ADDWORD ( pak, items[8].itemnum ); // Sub-Weapon ADDWORD ( pak, GServer->BuildItemRefine( items[8] ) ); ADDWORD ( pak, (items[132].itemnum << 5)); // Arrows ADDWORD ( pak, (items[133].itemnum << 5)); // Bullets ADDWORD ( pak, (items[134].itemnum << 5)); // Cannons ADDWORD ( pak, CharInfo->Job ); // Class ADDBYTE ( pak, Stats->Level ); // Level ADDWORD ( pak, items[135].itemnum); // Frame ADDWORD ( pak, GServer->BuildItemRefine(items[135])); ADDWORD ( pak, items[136].itemnum ); // Engine ADDWORD ( pak, GServer->BuildItemRefine(items[136])); ADDWORD ( pak, items[137].itemnum ); // Wheels ADDWORD ( pak, GServer->BuildItemRefine(items[137])); ADDWORD ( pak, items[138].itemnum ); // Weapon ADDWORD ( pak, GServer->BuildItemRefine(items[138])); ADDWORD ( pak, items[139].itemnum ); // Ability ADDWORD ( pak, GServer->BuildItemRefine(items[139])); // Observe: 434 Extra Bytes if(Status->Stance != MOUNTED) { ADDDWORD ( pak, 0 ); // ?? ADDWORD ( pak, 0 ); // ?? } else { ADDBYTE ( pak, 1 ); ADDDWORD ( pak, CharInfo->Mount ); ADDBYTE ( pak, 0 ); } // End 434 ADDWORD ( pak, (Stats->HP <= 0)?0x00:0xea7b ); // HP if(Shop->open) { ADDWORD ( pak, 0x0002 ); // Shop } else if(otherclient->isInvisibleMode && !player->isInvisibleMode) { ADDWORD ( pak, 0x0001 ); // Invisible } else { ADDWORD ( pak, 0x0000 ); // Visible } ADDBYTE ( pak, 0x00 ); // Fairy? ADDBYTE ( pak, 0 ); ADDBYTE ( pak, CharInfo->HairColor ); // Another HairColor?? ADDSTRING ( pak, CharInfo->charname ); // Character Name ADDBYTE ( pak, 0x00 ); if(Shop->open) { ADDWORD ( pak, Shop->ShopType); // Shop Type ADDSTRING( pak, Shop->name); // Shopname ADDBYTE ( pak, 0x00); } if (!IsDead()) { if (Status->HP_up != 0xff) { ADDWORD ( pak, MagicStatus[Status->HP_up].Value ); } if (Status->Dash_up != 0xff) { ADDWORD ( pak, MagicStatus[Status->Dash_up].Value ); } if (Status->Haste_up != 0xff) { ADDWORD ( pak, MagicStatus[Status->Haste_up].Value ); } } if(Clan->clanid != 0) { ADDDWORD( pak, Clan->clanid ); ADDWORD ( pak, Clan->back ); ADDWORD ( pak, Clan->logo ); ADDBYTE ( pak, Clan->grade ); ADDBYTE ( pak, Clan->clanrank ); ADDSTRING( pak, Clan->clanname ); ADDBYTE ( pak, 0x00 ) }
// Spawn Another User on the Screen bool CPlayer::SpawnToPlayer( CPlayer* player, CPlayer* otherclient ) { BEGINPACKET( pak, 0x793 ); ADDWORD( pak, clientid); // USER ID ANYONE? ADDFLOAT( pak, Position->current.x*100 ); // POS X ADDFLOAT( pak, Position->current.y*100 ); // POS Y ADDFLOAT( pak, Position->destiny.x*100 ); // GOING TO X ADDFLOAT( pak, Position->destiny.y*100 ); // GOINT TO Y if(Status->Stance == 0x01) { ADDWORD( pak, 0x000a ); ADDWORD( pak, 0x0000 ); } else if(Stats->HP <= 0) { ADDWORD( pak, 0x0003 ); ADDWORD( pak, 0x0000 ); } else if(Position->destiny.x != Position->current.y || Position->destiny.y != Position->current.y) { ADDWORD( pak, 0x0001 ); ADDWORD( pak, Battle->atktarget ); } else if(Battle->atktarget!=0) { ADDWORD( pak, 0x0002 ); ADDWORD( pak, Battle->atktarget ); } else { ADDWORD( pak, 0x0001 ); ADDWORD( pak, 0x0000 ); } switch (Status->Stance) { case WALKING: ADDBYTE( pak, 0x00 ); break; case RUNNING: ADDBYTE( pak, 0x01 ); break; case DRIVING: ADDBYTE( pak, 0x02 ); break; default: ADDBYTE( pak, 0x0b ); } ADDWORD( pak, 0x0000 ); ADDWORD( pak, 0x0000 ); if(otherclient->Party->party==NULL || otherclient->Party->party != player->Party->party || otherclient->Party->party == player->Party->party) { CMap* map = GServer->MapList.Index[player->Position->Map]; if(map->allowpvp==1){ADDDWORD(pak, 0x00000051 );} // pvp all vs all else if(map->allowpvp==2) // pvp group vs group { if((player->Clan->clanid != otherclient->Clan->clanid) && ((map->id>0) && (map->id<121))) { ADDDWORD(pak, 0x00000051 ); }//Clan War map (pedion) else if((player->Clan->clanid == otherclient->Clan->clanid) && ((map->id>0) && (map->id<=100))) { ADDDWORD(pak, 0x00000051 ); }//other pvp group vs group map else { ADDDWORD(pak, 0x00000000 ); } } else { ADDDWORD(pak, 0x00000000 ); } } else {ADDDWORD(pak, 0x00000000 );} ADDDWORD( pak, GServer->BuildBuffs( this ) );//BUFFS ADDBYTE( pak, CharInfo->Sex ); // GENDER ADDWORD( pak, Stats->Move_Speed ); // WALK SPEED MAYBE? ADDWORD( pak, 0 ); // ?? ADDBYTE( pak, 0x01 ); // ?? ADDDWORD( pak, CharInfo->Face ); // FACE TYPE ADDDWORD( pak, CharInfo->Hair ); // HAIR TYPE ADDWORD( pak, items[2].itemnum ); // CAP ADDWORD( pak, GServer->BuildItemRefine( items[2] ) ); // CAP REFINE ADDWORD( pak, items[3].itemnum ); // BODY ADDWORD( pak, GServer->BuildItemRefine( items[3] ) ); // BODY REFINE ADDWORD( pak, items[5].itemnum ); // GLOVES ADDWORD( pak, GServer->BuildItemRefine( items[5] ) ); // GLOVES REFINE ADDWORD( pak, items[6].itemnum ); // BOOTS ADDWORD( pak, GServer->BuildItemRefine( items[6] ) ); // BOOTS REFINE ADDWORD( pak, items[1].itemnum ); // FACE ADDWORD( pak, GServer->BuildItemRefine( items[1] ) ); // FACE REFINE ADDWORD( pak, items[4].itemnum ); // BACK ADDWORD( pak, GServer->BuildItemRefine( items[4] ) ); // BACK REFINE ADDWORD( pak, items[7].itemnum ); // WEAPON ADDWORD( pak, GServer->BuildItemRefine( items[7] ) ); // WEAPON REFINE ADDWORD( pak, items[8].itemnum ); // SUBWEAPON ADDWORD( pak, GServer->BuildItemRefine( items[8] ) ); // SUBWEAPON REFINE /* ADDWORD( pak, ((items[132].itemnum << 5) & 0x3ff) );//arrows ADDWORD( pak, ((items[133].itemnum << 5) & 0x3ff) );//bullets ADDWORD( pak, ((items[134].itemnum << 5) & 0x3ff) );//cannons */ //Fix from maximz ADDWORD( pak, ((items[132].itemnum << 5) ));//arrows ADDWORD( pak, ((items[133].itemnum << 5) ));//bullets ADDWORD( pak, ((items[134].itemnum << 5) ));//cannons ADDWORD( pak, CharInfo->Job ); ADDBYTE( pak, Stats->Level ); ADDWORD( pak, items[135].itemnum); // CART FRAME ADDWORD( pak, GServer->BuildItemRefine( items[135] ) ); ADDWORD( pak, items[136].itemnum ); // CART ENGINE ADDWORD( pak, GServer->BuildItemRefine( items[136] ) ); ADDWORD( pak, items[137].itemnum ); // CART WHEELS ADDWORD( pak, GServer->BuildItemRefine( items[137] ) ); ADDWORD( pak, items[138].itemnum ); // CART WEAPON ADDWORD( pak, GServer->BuildItemRefine( items[138] ) ); ADDWORD( pak, items[139].itemnum ); // CART ABILITY ADDWORD( pak, GServer->BuildItemRefine( items[139] ) ); ADDWORD( pak, (Stats->HP<=0)?0x0:0xea7b ); if(Shop->open) { ADDBYTE( pak, 0x02 ); } else { ADDBYTE( pak, 0x00 ); } ADDBYTE( pak, 0x00); ADDBYTE( pak, 0x00); if( Fairy ) { ADDBYTE( pak, 0x61); } else { ADDBYTE( pak, 0x00); } ADDSTRING( pak, CharInfo->charname ); ADDBYTE( pak, 0x00); if(Shop->open) { ADDBYTE( pak, Shop->ShopType); ADDBYTE( pak, 0x00); ADDSTRING(pak, Shop->name); ADDBYTE( pak, 0x00); //LMA 139+ } if(Clan->clanid!=0) { ADDDWORD( pak, Clan->clanid ); ADDWORD( pak, Clan->back); ADDWORD( pak, Clan->logo); ADDBYTE( pak, Clan->grade); ADDBYTE( pak, 0x00); ADDSTRING( pak, Clan->clanname); Log(MSG_INFO,"[WS] Clan info in player packet 0x793"); } ADDWORD( pak, 0x0000 ); player->client->SendPacket(&pak); if( Party->party!=NULL && Party->party == player->Party->party) { BEGINPACKET( pak, 0x7d5 ); ADDDWORD ( pak, CharInfo->charid ); ADDWORD ( pak, clientid ); ADDWORD ( pak, GetMaxHP( ) ); ADDWORD ( pak, Stats->HP ); ADDDWORD ( pak, 0x01000000 ); ADDDWORD ( pak, 0x0000000f ); ADDWORD ( pak, 0x1388 ); player->client->SendPacket( &pak ); } if( Ride->Ride ) { CPlayer* rideclient = GServer->GetClientByCID( Ride->charid, Position->Map ); if(rideclient==NULL) { Ride->Ride = false; Ride->Drive= false; Ride->charid = 0; return true; } if( GServer->IsVisible( player, rideclient ) || player->CharInfo->charid == rideclient->CharInfo->charid ) { BEGINPACKET( pak, 0x796 ); if( Ride->Drive ) { ADDWORD ( pak, rideclient->clientid ); ADDFLOAT ( pak, rideclient->Position->current.x*100 ); ADDFLOAT ( pak, rideclient->Position->current.y*100 ); } else { ADDWORD ( pak, clientid ); ADDFLOAT ( pak, Position->current.x*100 ); ADDFLOAT ( pak, Position->current.y*100 ); } ADDWORD ( pak, 0x0000 ); player->client->SendPacket( &pak ); RESETPACKET( pak, 0x7dd ); ADDBYTE ( pak, 0x02 ); if( rideclient->Ride->Drive ) { ADDWORD ( pak, rideclient->clientid ); ADDWORD ( pak, clientid ); } else { ADDWORD ( pak, clientid ); ADDWORD ( pak, rideclient->clientid ); } player->client->SendPacket( &pak ); } } //Little addition till the nonsense in server sync is fixed. //StartAction(NULL, 0, 0, true); return true; }
// Map Process PVOID MapProcess( PVOID TS ) { bool ok_cont=false; UINT loopcount=0; clock_t time_skill=0; bool only_npc=false; //LMA: AIP is done by NPC even when no player in map. bool only_summon=false; //LMA: test for summons when no one's around (sad is a summon's life ^_^). UINT nb_summons_map=0; //LMA: test for summons when no one's around (sad is a summon's life ^_^). //LMA: temp monster used for NPCs. fPoint tempPos; tempPos.x=0; tempPos.y=0; tempPos.z=0; CMonster* NPCmonster = new (nothrow) CMonster( tempPos, 0, 0, 0, 0 ); while(GServer->ServerOnline) { loopcount++; //geobot: refresh only every 100 cycles if (loopcount < 100) { continue; } loopcount = 0; pthread_mutex_lock( &GServer->PlayerMutex ); pthread_mutex_lock( &GServer->MapMutex ); for(UINT i=0;i<GServer->MapList.Map.size();i++) { CMap* map = GServer->MapList.Map.at(i); //LMA: test for Union. only_npc=false; only_summon=false; //LMA: test for summons when no one's around (sad is a summon's life ^_^). nb_summons_map=0; if( map->PlayerList.size()<1 ) { only_npc = true; //LMA: AIP is done by NPC even when no player in map. //LMA: doing summons too if there are any in map. if(map->nb_summons > 0) { only_summon = true; } //continue; } if (!only_npc||only_summon) { // Player update //------------------------ for(UINT j=0;j<map->PlayerList.size();j++) { CPlayer* player = map->PlayerList.at(j); //check for delayed trigger if(player->TriggerDelay != 0 ) //only one problem. If the player logs out before the delayed action trigger is executed than it never will be. Oh Dear! The missing children will really be missing. lol. It's fine though because they never truly despawn. they just disappear from the player's visibility list. { clock_t etime = clock() - player->DelayStartTime; if( etime >= player->TriggerDelay ) { player->ExecuteQuestTrigger(player->TriggerHash,true); player->TriggerDelay = 0; //reset delays and stuff player->TriggerHash = 0; } } if(!player->Session->inGame) continue; if(player->IsDead( )) { player->lastRegenTime = 0; player->lastShowTime = 0; continue; } player->RefreshHPMP(); //LMA HP / MP Jumping if(player->UpdateValues( )) //Does nothing except for rides... equals to true if player isn't on the back seat player->UpdatePosition(false); if(player->IsOnBattle( )) player->DoAttack( ); player->RefreshBuff( ); player->PlayerHeal( ); player->Regeneration( ); player->CheckPlayerLevelUP( ); player->CheckDoubleEquip(); //LMA: Core fix for double weapon and shield player->CheckZulies( ); //Fuel handling. if (player->Status->Stance == DRIVING && (player->last_fuel>0) && (clock()-player->last_fuel > 60000)) { //We kill some fuel every now and then :) player->TakeFuel(); player->last_fuel=clock(); } //LMA: mileage coupon checks. time_t etime=time(NULL); if(player->no_exp&&(etime>=player->timer_no_exp)) { BEGINPACKET( pak, 0x702 ); ADDSTRING( pak, "[Mileage] Null Xp vanished."); ADDBYTE( pak, 0 ); player->client->SendPacket(&pak); player->timer_no_exp=0; player->no_exp=false; } if(player->bonusxp>1&&(etime>=player->timerxp)) { BEGINPACKET( pak, 0x702 ); ADDSTRING( pak, "[Mileage] Bonus Xp vanished."); ADDBYTE( pak, 0 ); player->client->SendPacket(&pak); player->bonusxp=1; player->timerxp=0; player->wait_validation=0; } if(player->bonusddrop>1&&(etime>=player->timerddrop)) { BEGINPACKET( pak, 0x702 ); ADDSTRING( pak, "[Mileage] Medal of Fortune vanished."); ADDBYTE( pak, 0 ); player->client->SendPacket(&pak); player->bonusddrop=1; player->timerddrop=0; player->wait_validation_ddrop=0; } if(player->bonusstatdrop>1&&(etime>=player->timerstatdrop)) { BEGINPACKET( pak, 0x702 ); ADDSTRING( pak, "[Mileage] Medal of Excellence vanished."); ADDBYTE( pak, 0 ); player->client->SendPacket(&pak); player->bonusstatdrop=1; player->timerstatdrop=0; player->wait_validation_statdrop=0; } if(player->bonusgraydrop>0&&(etime>=player->timergraydrop)) { BEGINPACKET( pak, 0x702 ); ADDSTRING( pak, "[Mileage] Medal of Retrieval vanished."); ADDBYTE( pak, 0 ); player->client->SendPacket(&pak); player->bonusgraydrop=0; player->timergraydrop=0; player->wait_validation_graydrop=0; } if(player->Shop->ShopType>0&&(etime>=player->Shop->mil_shop_time)) { BEGINPACKET( pak, 0x702 ); ADDSTRING( pak, "[Mileage] Mileage shop expired !"); ADDBYTE( pak, 0 ); player->client->SendPacket(&pak); player->Shop->ShopType=0; player->Shop->mil_shop_time=0; } if(player->Shop->ShopType>0&&(etime>=player->Shop->mil_shop_time)) { BEGINPACKET( pak, 0x702 ); ADDSTRING( pak, "[Mileage] Mileage shop expired !"); ADDBYTE( pak, 0 ); player->client->SendPacket(&pak); player->Shop->ShopType=0; player->Shop->mil_shop_time=0; } } // Monster update //------------------------ pthread_mutex_lock( &map->MonsterMutex ); //spawn TD monsters unsigned nextmon = map->TDMobList[map->TDNextSpawn]; if(nextmon != 0) { //Log(MSG_DEBUG,"Spawning TD mobs"); clock_t etime = clock() - map->lastTDSpawnTime; if(etime >= map->TDMobDelay) // check if elapsed time is greater than spawn delay { //spawn the next monster on the list //Log(MSG_DEBUG,"Spawning TD mob of type %i at position %i in the list for map %i",nextmon, map->TDNextSpawn, map->id); map->AddMonster(nextmon, GServer->WPList[map->id][1].pos, 0, 0, 0, 1, 0, 999 ); //spawn a TD mob with no AI //Log(MSG_DEBUG,"Spawned mob in addmonster"); map->TDMobList[map->TDNextSpawn] = 0; //clear the spawn //Log(MSG_DEBUG,"cleared the spawn"); map->TDNextSpawn++; //move the pointer //Log(MSG_DEBUG,"moved the pointer"); if(map->TDNextSpawn > 100)map->TDNextSpawn = 0; map->lastTDSpawnTime = clock(); } } //TD spawn end for(UINT j=0;j<map->MonsterList.size();j++) { CMonster* monster = map->MonsterList.at(j); //UINT thistimer = monster->AItimer; clock_t etime = clock() - monster->lastAiUpdate; //LMA: only summon ? if (only_summon&&!monster->IsSummon()) { continue; } else if(only_summon) { nb_summons_map++; } if(monster->hitcount == 0xFF)//this is a delay for new monster spawns this might olso fix invisible monsters(if they attack directly on spawning the client dosn't get the attack packet(its not in it's visible list yet)) { monster->hitcount = 0; //monster->DoAi(monster->thisnpc->AI, 0); monster->DoAi(monster->MonAI, 0); //AI on spawn monster->lastAiUpdate=clock(); } //PY handling day only or night only monsters. if(!map->IsNight( ) && monster->Status->nightonly)// if day, delete all night time monsters { //Log( MSG_INFO, "Night Only monster deleted. Type %i", monster->montype); map->DeleteMonster( monster, true, j ); continue; } if(map->IsNight() && monster->Status->dayonly) { //Log( MSG_INFO, "Day Only monster deleted. Type %i", monster->montype); map->DeleteMonster( monster, true, j ); continue; } //Do TD stuff if(monster->MonAI == 999 && etime >= monster->AITimer) //It's a TD mob { monster->UpdatePosition(monster->stay_still ); float distance = GServer->distance( monster->Position->current, monster->Position->destiny ); //Log( MSG_INFO, "Found a TD monster %f from target. Waypoint type = %i stance %i speed %i", distance,GServer->WPList[map->id][monster->NextWayPoint].WPType,monster->Stats->stance, monster->Stats->Move_Speed); //Log( MSG_INFO, "monster location X: %f Y: %f",monster->Position->current.x, monster->Position->current.y); //Log( MSG_INFO, "WP location X: %f Y: %f ", GServer->WPList[map->id][monster->NextWayPoint].pos.x,GServer->WPList[map->id][monster->NextWayPoint].pos.y); if(distance < 1) //monster has reached it's destination { switch(GServer->WPList[map->id][monster->NextWayPoint].WPType) { case 1: //Start waypoint case 2: //regular waypoint. Increment waypoint counter. Set detiny to next waypoint { //Log( MSG_INFO, "Monster reached waypoint %i type: %i", monster->NextWayPoint,GServer->WPList[map->id][monster->NextWayPoint].WPType); monster->NextWayPoint++; monster->Position->destiny.x = GServer->WPList[map->id][monster->NextWayPoint].pos.x; monster->Position->destiny.y = GServer->WPList[map->id][monster->NextWayPoint].pos.y; BEGINPACKET( pak, 0x797 ); ADDWORD ( pak, monster->clientid ); ADDWORD ( pak, 0x0000 ); ADDWORD ( pak, monster->Stats->Move_Speed ); //speed ADDFLOAT ( pak, monster->Position->destiny.x * 100 ); ADDFLOAT ( pak, monster->Position->destiny.y * 100 ); ADDWORD ( pak, 0xcdcd ); ADDBYTE ( pak, monster->Stats->stance ); //should be walking GServer->SendToVisible(&pak, monster); } break; case 3: //Final waypoint. do stuff. suicide { //Log( MSG_INFO, "Reached final waypoint"); //monster->Stats->HP = 0; map->DeleteMonster( monster, true, j ); //Log( MSG_INFO, "monster successfully deleted"); continue; } break; default: Log( MSG_INFO, "WPType %i not recognized",GServer->WPList[map->id][monster->NextWayPoint].WPType); break; } } else { //send move packet again to try to synchronise the monster movement BEGINPACKET( pak, 0x797 ); ADDWORD ( pak, monster->clientid ); ADDWORD ( pak, 0x0000 ); ADDWORD ( pak, monster->Stats->Move_Speed ); //speed ADDFLOAT ( pak, monster->Position->destiny.x * 100 ); ADDFLOAT ( pak, monster->Position->destiny.y * 100 ); ADDWORD ( pak, 0xcdcd ); ADDBYTE ( pak, monster->Stats->stance ); //should be walking GServer->SendToVisible(&pak, monster); } monster->lastAiUpdate = clock(); } //End TD stuff //if(!monster->PlayerInRange( )) continue; if(!monster->UpdateValues( )) continue; monster->UpdatePosition( true ); if(monster->IsOnBattle( )) { monster->DoAttack( ); // why was this commented? Monsters were not attacking //monster->DoAi(monster->thisnpc->AI, 2); //don't use thisnpc->AI any more. if(etime >= monster->AITimer) { monster->DoAi(monster->MonAI, 2); monster->lastAiUpdate = clock(); } //Log(MSG_INFO,"Monster type: %i current HP: %i",monster->montype, monster->Stats->HP); } else { //monster->DoAi(monster->thisnpc->AI, 1); if(etime >= monster->AITimer) { monster->DoAi(monster->MonAI, 1); monster->lastAiUpdate = clock(); } } monster->RefreshBuff( ); if (monster->IsSummon()) { monster->SummonUpdate(monster,map, j); continue; } if(monster->IsDead()) { if(clock() - monster->DeathDelayTimer > GServer->Config.DeathDelay) { //Log(MSG_DEBUG,"Found dead monster montype %i",monster->montype); monster->OnDie( ); //all this does is give exp //Log(MSG_DEBUG,"back from giving exp"); monster->DoAi(monster->MonAI, 5); //Log(MSG_DEBUG,"ran AI"); map->DeleteMonster( monster, true, j ); //Log(MSG_DEBUG,"deleted monster"); continue; } else { //Log(MSG_DEBUG,"Dead monster found. waiting for death delay timer"); } } } //LMA: was there any summons in this map? if(only_summon&&nb_summons_map==0) { map->nb_summons=0; } } if(only_npc&&!only_summon) { pthread_mutex_lock( &map->MonsterMutex ); } //LMA: AIP for NPC. for(UINT j=0;j<map->NPCList.size();j++) { CNPC* npc = map->NPCList.at(j); //LMA: We don't worry about IFO Objects... if(npc->npctype>10000) { continue; } if(npc->thisnpc->AI != 0 && npc->thisnpc->AI != 30) { //check every minute. Conditions seem to be based on 6 minute segments //LMA: untrue for some NPCs, special case for UW... //PY: NO we don't check every minute. We check whatever interval the AIP file asks for bool is_time_ok=false; // int delay=60000; //each AIP 60 seconds. //LMA: AIP Timer. //delay = npc->thisnpc->AiTimer; if(npc->thisnpc->AiTimer == 0) { //npc->thisnpc->AiTimer = 60000; //Log(MSG_WARNING,"NPC %i hadn't timer, file AI=%i",npc->npctype,npc->thisnpc->AI); //PY: If the NPC doesn't have a timer then let's give it one CAip* script = NULL; for(unsigned k=0; k < GServer->AipList.size(); k++) { if (GServer->AipList.at(k)->AInumber == npc->thisnpc->AI) { script = GServer->AipList.at(k); break; } } if(script == NULL) { Log( MSG_WARNING, "Invalid AI script for AI %i Setting AI to 30 (blank)", npc->thisnpc->AI ); npc->thisnpc->AI = 30; continue; } //Set the timer npc->thisnpc->AiTimer = script->minTime; } //PY: Any npc reaching this point has a valid timer. It has either been set or removed //PY MORE Bloody lmame special cases //If he had just set the frickin timer correctly like i did above, all this crap would be un-necessary //Leum, for Union War (no need to do his stuff always). //PY: NO this is BS //if(npc->npctype==1113&&GServer->ObjVar[1113][1]>0) //{ //LogDebug("Doing an update for Leum each 10 seconds since UW is on"); // delay=10000; //} //PY: What the hell is this shit? commenting it out //Walls for map 66 (no need to do his stuff always) //if(npc->npctype>=1024&&npc->npctype<=1027&&GServer->ObjVar[1249][2]>0&&GServer->ObjVar[1249][2]<=90) //{ //LogDebug("Doing an update for Wall %i each second quest from Hope is on",npc->npctype); // delay=1000; //} //PY: Seriously?? //Hope map 66 (no need to do his stuff always) //if(npc->npctype==1249&&GServer->ObjVar[1249][2]>0&&GServer->ObjVar[1249][2]<=90) //{ //LogDebug("Doing an update for Hope each 10 seconds quest from Hope is on",npc->npctype); // delay=10000; //} //PY and more special cases........ //Williams //if(npc->npctype==1075) //{ //Each 5 minutes // delay=300000; //} //LMA END //if(60000<(UINT)GServer->round((clock( ) - npc->lastAiUpdate))) //if(is_time_ok) //if(delay<(UINT)GServer->round((clock( ) - npc->lastAiUpdate))) //PY NOPE!! How about we do it right UINT thistimer = npc->thisnpc->AiTimer * 1000; //this is always set in seconds in AIP if(thistimer<(UINT)GServer->round((clock( ) - npc->lastAiUpdate))) //check AIP conditions when the timer calls for it { CNPCData* thisnpc = GServer->GetNPCDataByID( npc->npctype ); if(thisnpc == NULL) { Log( MSG_WARNING, "Invalid montype %i", npc->npctype ); continue; } //LMA: before this temp monster was created and deleted every time, now we only do it once... //new code, we overwrite the temp monster each time rather than creating / deleting him each time. NPCmonster->Position->source = npc->pos; NPCmonster->Position->current = npc->pos; NPCmonster->Position->destiny = npc->pos; NPCmonster->montype=npc->npctype; NPCmonster->Position->Map=map->id; NPCmonster->Position->lastMoveTime = clock( ); NPCmonster->SpawnTime = clock( ); NPCmonster->lastSighCheck = clock( ); NPCmonster->lastLifeUpdate = time(NULL); //old code: //CMonster* NPCmonster = new (nothrow) CMonster( npc->pos, npc->npctype, map->id, 0, 0 ); NPCmonster->aip_npctype=npc->npctype; NPCmonster->aip_clientid=npc->clientid; NPCmonster->thisnpc = thisnpc; int lma_previous_eventID = npc->thisnpc->eventid; //Log(MSG_INFO,"XCIDAIBEGIN NPC %i map %i cid %i",npc->npctype,map->id,npc->clientid); NPCmonster->DoAi(NPCmonster->MonAI, 1); //Log(MSG_INFO,"XCIDAIEND NPC %i map %i cid %i",npc->npctype,map->id,npc->clientid); //PY: AAAAAAAAAGGGGGGGGGGHHHHHHHHHH. NO! just NO!!. Stop with the bloody special cases. Fix the damn core code already!!!!!!! //Williams (temple of Oblivion) /*if(npc->npctype == 1075) { //each 5 minutes //saving values for him if(GServer->LastTempleAccess[0]!=GServer->ObjVar[npc->npctype][0]||GServer->LastTempleAccess[1]!=GServer->ObjVar[npc->npctype][1]) { GServer->DB->QExecute("UPDATE list_npcs SET eventid=%i, extra_param=%i WHERE type=1075",GServer->ObjVar[1075][0],GServer->ObjVar[1075][1]); /*Log(MSG_WARNING,"Doing an update for Williams each 5 minutes, values changed (%i->%i, %i->%i)", GServer->LastTempleAccess[0],GServer->ObjVar[npc->npctype][0], GServer->LastTempleAccess[1],GServer->ObjVar[npc->npctype][1]); }*/ /*else { Log(MSG_WARNING,"Doing an update for Williams each 5 minutes."); }*/ /* GServer->LastTempleAccess[0]=GServer->ObjVar[npc->npctype][0]; GServer->LastTempleAccess[1]=GServer->ObjVar[npc->npctype][1]; }*/ //PY: I have absolutely no idea what this bit does. I suspuct it's also a load of bollux but I'm leaving it in for now //ToDo Figure this out and tidy it up //LMA: check if eventID changed, if we do it in AIP conditions / actions, it just fails... if (lma_previous_eventID!=NPCmonster->thisnpc->eventid) { //Log(MSG_WARNING,"(1)Event ID not the same NPC %i from %i to %i in map %i, npc->thisnpc->eventid=%i !",npc->npctype,lma_previous_eventID,NPCmonster->thisnpc->eventid,map->id,npc->thisnpc->eventid); LogDebugPriority(3); LogDebug("(1)Event ID not the same NPC %i from %i to %i in map %i, npc->thisnpc->eventid=%i !",npc->npctype,lma_previous_eventID,NPCmonster->thisnpc->eventid,map->id,npc->thisnpc->eventid); LogDebugPriority(4); npc->thisnpc->eventid=NPCmonster->thisnpc->eventid; npc->event=npc->thisnpc->eventid; //LMA: We have to change the event ID here since we didn't send the clientID :( BEGINPACKET( pak, 0x790 ); ADDWORD ( pak, npc->clientid ); ADDWORD ( pak, npc->thisnpc->eventid ); GServer->SendToAllInMap(&pak,map->id); } //LMA: We don't clear anymore, too much hassle :( //We declare the temporary monster just once... /*GServer->ClearClientID(NPCmonster->clientid); delete NPCmonster;*/ npc->lastAiUpdate = clock(); } } //LMA: Sometimes another NPC does the job for you. if(npc->thisnpc->eventid!=GServer->ObjVar[npc->npctype][0]) { int new_event_id=GServer->ObjVar[npc->npctype][0]; LogDebugPriority(3); //Log(MSG_WARNING,"(2)Event ID not the same NPC %i from %i to %i in map %i, npc->thisnpc->eventid=%i !",npc->npctype,npc->thisnpc->eventid,new_event_id,map->id,npc->thisnpc->eventid); LogDebug("(2)Event ID not the same NPC %i from %i to %i in map %i, npc->thisnpc->eventid=%i !",npc->npctype,npc->thisnpc->eventid,new_event_id,map->id,npc->thisnpc->eventid); LogDebugPriority(4); npc->thisnpc->eventid=new_event_id; npc->event=new_event_id; //LMA: We have to change the event ID here since we didn't send the clientID :( BEGINPACKET( pak, 0x790 ); ADDWORD ( pak, npc->clientid ); ADDWORD ( pak, npc->thisnpc->eventid ); GServer->SendToAllInMap(&pak,map->id); } } pthread_mutex_unlock( &map->MonsterMutex ); } pthread_mutex_unlock( &GServer->MapMutex ); pthread_mutex_unlock( &GServer->PlayerMutex ); #ifdef _WIN32 Sleep(GServer->Config.MapDelay); #else usleep(GServer->Config.MapDelay); #endif } pthread_exit( NULL ); //LMA: we delete the temporary monster. GServer->ClearClientID(NPCmonster->clientid); delete NPCmonster; return 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();*/ }
// start action [attack] void CCharacter::StartAction( CCharacter* Target, BYTE action, UINT skillid) { BEGINPACKET( pak, 0 ); switch(action) { case NORMAL_ATTACK: { //Log( MSG_INFO, "case NORMAL_ATTACK"); if(Target == NULL)return; RESETPACKET( pak, 0x798 ); ADDWORD ( pak, clientid ); ADDWORD ( pak, Target->clientid ); ADDWORD ( pak, Stats->Move_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; Battle->skilltarget = 0; Battle->bufftarget = 0; Battle->skillid = 0; Position->destiny = Target->Position->current; Position->lastMoveTime = clock(); } break; case SKILL_ATTACK: //Log( MSG_INFO, "case SKILL_ATTACK"); case SKILL_BUFF: { if(Target == NULL)return; RESETPACKET( pak, 0x7b3 ); ADDWORD ( pak, clientid ); ADDWORD ( pak, Target->clientid ); ADDWORD ( pak, skillid ); ADDWORD ( pak, 0x0000 ); ADDFLOAT ( pak, Target->Position->current.x * 100 ); ADDFLOAT ( pak, Target->Position->current.y * 100 ); Battle->target = Target->clientid; if(action == SKILL_ATTACK) { //Log( MSG_INFO, "case SKILL_ATTACK"); Battle->skilltarget = Target->clientid; Battle->bufftarget = 0; } else { //Log( MSG_INFO, "case SKILL_BUFF"); Battle->bufftarget = Target->clientid; Battle->skilltarget = 0; } Battle->atktype = action; Position->destiny = Target->Position->current; Battle->skillid = skillid; Position->lastMoveTime = clock(); } break; case SKILL_AOE://Log( MSG_INFO, "case SKILL_AOE"); case BUFF_SELF://Log( MSG_INFO, "case BUFF_SELF"); case BUFF_AOE: { //Log( MSG_INFO, "case BUFF_AOE"); RESETPACKET( pak, 0x7b2); ADDWORD ( pak, clientid ); ADDWORD ( pak, skillid ); Battle->atktype = action; Battle->skillid = skillid; //Log( MSG_INFO, "BUFF_AOE packet sent"); } break; case AOE_TARGET: { //Log( MSG_INFO, "case AOE_TARGET"); //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->skilltargetpos.x = Target->Position->current.x; Position->skilltargetpos.y = Target->Position->current.y; } RESETPACKET( pak, 0x7b4 ); ADDWORD ( pak, clientid ); ADDWORD ( pak, skillid ); ADDFLOAT ( pak, Position->skilltargetpos.x * 100 ); ADDFLOAT ( pak, Position->skilltargetpos.y * 100 ); Battle->atktype = action; Battle->skillid = skillid; Battle->skilltarget = 0; Battle->bufftarget = 0; } break; default: return; break; } GServer->SendToVisible( &pak, this ); Battle->contatk = true; //Log(MSG_INFO,"Battle Attacktype = %i",Battle->atktype); return; }
// Check For Debuffs void CCharacter::RefreshBuff( ) { bool bflag = false; for( UINT i=0; i<30; i++) { if(MagicStatus[i].Buff==0) continue; clock_t etime = clock() - MagicStatus[i].BuffTime; if( etime >= MagicStatus[i].Duration * CLOCKS_PER_SEC ) { switch(MagicStatus[i].Buff) { case A_ATTACK: if(i<15) Status->Attack_up = 0xff; else Status->Attack_down = 0xff; Stats->Attack_Power = GetAttackPower( ); break; case A_DEFENSE: if(i<15) Status->Defense_up= 0xff; else Status->Defense_down = 0xff; Stats->Defense = GetDefense( ); break; case A_ACCUR: if(i<15) Status->Accury_up= 0xff; else Status->Accury_down = 0xff; Stats->Accury = GetAccury( ); break; case A_MRESIST: if(i<15) Status->Magic_Defense_up = 0xff; else Status->Magic_Defense_down = 0xff; Stats->Magic_Defense = GetMagicDefense( ); break; case A_DODGE: if(i<15) Status->Dodge_up = 0xff; else Status->Dodge_down = 0xff; Stats->Dodge = GetDodge( ); break; case A_DASH: if(i<15) Status->Dash_up = 0xff; else Status->Dash_down = 0xff; Stats->Move_Speed = GetMoveSpeed( ); break; case A_HASTE: if(i < 15) { Status->Haste_up = 0xff; } else { Status->Haste_down = 0xff; } Stats->Attack_Speed = GetAttackSpeed(); break; case A_CRITICAL: if(i<15) Status->Critical_up = 0xff; else Status->Critical_down = 0xff; Stats->Critical = GetCritical( ); break; case A_MAX_HP: if(i<15) Status->HP_up = 0xff; else Status->HP_down = 0xff; Stats->MaxHP = GetMaxHP( ); break; case A_MAX_MP: if(i<15) Status->MP_up = 0xff; else Status->MP_down = 0xff; Stats->MaxMP = GetMaxMP( ); break; case A_STUN: Status->Stuned = 0xff; printf("removing stun\n"); //StartAction2(NULL, 0, 0, true); break; case A_POISON: Status->Poisoned = 0xff; printf("removing poison\n"); break; case A_MUTE: Status->Muted = 0xff; break; case A_GMExtra_Damage: case A_Extra_Damage: if(i<15) { Status->ExtraDamage_up = 0xff; Stats->ExtraDamage = 0; } else Status->ExtraDamage_down = 0xff; break; } MagicStatus[i].Buff = 0; MagicStatus[i].BuffTime = 0; MagicStatus[i].Duration = 0; MagicStatus[i].Value = 0; bflag = true; } else if (MagicStatus[i].Buff == A_POISON && etime > 1*CLOCKS_PER_SEC) //Do poison dmg every 1.5 seconds { Stats->HP -= MagicStatus[i].Value; MagicStatus[i].BuffTime+= 1*CLOCKS_PER_SEC; MagicStatus[i].Duration-=1; printf("did %i poison dmg to the player, still %i seconds and %i HP remain \n", MagicStatus[i].Value, MagicStatus[i].Duration, Stats->HP); //A bunch of messy code to send dmg packet BEGINPACKET( pak, 0x7b6 ); ADDWORD ( pak, clientid ); ADDWORD ( pak, 0 ); ADDDWORD ( pak, 0x000007f8 ); ADDBYTE ( pak, 0x00 ); ADDDWORD ( pak, MagicStatus[i].Value ); //If Enemy is killed if( IsDead()) { printf("char died\n"); CDrop* thisdrop = NULL; //ADDDWORD ( pak, 16 );//i don't think this one belongs in irose if( !IsSummon( ) && !IsPlayer( )) { thisdrop = GetDrop( ); if( thisdrop!=NULL) { ADDFLOAT ( pak, thisdrop->pos.x*100 ); ADDFLOAT ( pak, thisdrop->pos.y*100 ); if( thisdrop->type==1) { ADDDWORD( pak, 0xccdf );//0xccccccdf ); ADDDWORD( pak, thisdrop->amount ); } else { ADDDWORD ( pak, GServer->BuildItemHead( thisdrop->item ) ); ADDDWORD ( pak, GServer->BuildItemData( thisdrop->item ) ); } ADDWORD ( pak, thisdrop->clientid ); ADDWORD ( pak, thisdrop->owner ); CMap* map = GServer->MapList.Index[thisdrop->posMap]; map->AddDrop( thisdrop ); } } GServer->SendToVisible( &pak, this, thisdrop ); } //If enemy is still alive else { ADDDWORD ( pak, 4 ); GServer->SendToVisible( &pak, this ); } } } if(bflag) { BEGINPACKET( pak,0x7b7 ); ADDWORD ( pak, clientid ); ADDDWORD ( pak, GServer->BuildBuffs( this ) ); GServer->SendToVisible( &pak, this ); } }
// Spawn a monster //LMA: added handling of skill summons. void CMonster::SpawnMonster( CPlayer* player, CMonster* thismon ) { BEGINPACKET( pak, 0x792 ); ADDWORD ( pak, clientid ); ADDFLOAT ( pak, Position->current.x*100 ); ADDFLOAT ( pak, Position->current.y*100 ); if((thismon->bonushp>0||thismon->bonusmp>0)&&(thismon->skillid>0)) { ADDFLOAT ( pak, 0xcdcdcdcd ); ADDFLOAT ( pak, 0xcdcdcdcd ); } else { ADDFLOAT ( pak, Position->destiny.x*100 ); ADDFLOAT ( pak, Position->destiny.y*100 ); } if(IsDead( )) { ADDWORD ( pak, 0x0003 ); ADDWORD ( pak, 0x0000 ); } else if(IsOnBattle( )) { //LMA: for supportive summons (lucky ghost...) if(Battle->bufftarget==Battle->target) { ADDWORD ( pak, 0x0002 ); ADDWORD ( pak, 0x0000 ); } else { ADDWORD ( pak, 0x0002 ); ADDWORD ( pak, Battle->target ); } } else if(IsMoving( )) { ADDWORD ( pak, 0x0001 ); ADDWORD ( pak, 0x0000 ); } else { ADDWORD ( pak, 0x0000 ); ADDWORD ( pak, 0x0000 ); } if(IsSummon( ) ) { ADDBYTE ( pak, 0x01 ); } else { ADDBYTE ( pak, 0x00 ); } //LMA: Little check, for now we "only" have a DWORD for monster's HP so there is a limit //broken by some monsters (Turak boss) if(Stats->HP>MAXHPMOB) { LogDebugPriority(3); LogDebug("Too much HP for monster %i (%I64i->%I64i)",thismon->montype,Stats->HP,MAXHPMOB); LogDebugPriority(4); Stats->HP=(long long) MAXHPMOB; } ADDDWORD ( pak, Stats->HP ); if(thismon->owner != player->clientid) { CMap* map = GServer->MapList.Index[Position->Map]; //LMA: adding team... if (thismon->team!=0) { ADDDWORD( pak,thismon->team); } else { if(IsSummon( ) && map->allowpvp!=0) { //Hostil ADDDWORD( pak, 0x00000064 ); } else if (IsSummon( ) && map->allowpvp==0) { //Friendly ADDDWORD ( pak, 0x00000000 ); } else { //Hostil ADDDWORD( pak, 0x00000064 ); } //TODO: LMA, test if necessary or not anymore... /* else if(thismon->montype>=1474&&thismon->montype<=1489) { //LMA: Xmas trees are friendly. ADDDWORD ( pak, 0x00000000 ); } */ } } else { //Friendly ADDDWORD( pak, 0x00000000 ); } ADDDWORD( pak, GServer->BuildBuffs( this ) ); ADDWORD ( pak, montype ); ADDWORD ( pak, 0x0000 ); if(IsSummon( )) { ADDWORD( pak, owner ); if (thismon->skillid>0) { ADDWORD( pak, thismon->skillid ); //id del skill (si es summon de skill) } else { ADDWORD( pak, 0x0000 ); //id del skill (si es summon de skill) } } player->client->SendPacket( &pak ); //LMA: supportive summons (lucky ghost) if(IsSummon()&&buffid>0&&(player==GetOwner())) { Log(MSG_INFO,"The summon is spawned"); /*CPlayer* player = GetOwner( ); if (ownplayer==NULL) return true;*/ StartAction( player,SUMMON_BUFF,buffid); Log(MSG_INFO,"completly"); buffid=0; //only one buff } }
// Teleport player to this map and this coord. bool CMap::TeleportPlayer( CPlayer* player, fPoint coordold, bool TelePassenger ) { fPoint coord; coord=coordold; if(id==9&&player->UWPosition->source.x>0&&player->UWPosition->source.y>0) { coord.x = player->UWPosition->source.x; coord.y = player->UWPosition->source.y; } GServer->MapList.Index[player->Position->Map]->RemovePlayer( player, false ); player->Position->Map = id; player->Position->current = coord; //TELEPORT ONLY player->Position->destiny = coord; //TELEPORT ONLY player->Session->inGame = false; player->Position->lastMoveTime = clock(); if(!allowpat || !TelePassenger) { if(!allowpat) player->Status->Stance=0x03; player->Ride->Drive = false; player->Ride->charid= 0; player->Ride->Ride = false; } AddPlayer( player ); BEGINPACKET( pak, 0x07a8 ); ADDWORD ( pak, player->clientid ); ADDWORD ( pak, player->Position->Map ); ADDFLOAT ( pak, player->Position->current.x*100 ); ADDFLOAT ( pak, player->Position->current.y*100 ); ADDWORD ( pak, (player->Status->Stance == 0x04? 0x0201: 0x0001) ); //PY: structure of WORD above should be //BYTE btRunMode //Byte btRideMode //+ 2 byte of a large byte array // See struct gsv_TELEPORT_REPLY in netPrototypes.h in client source //LMA: it seems they added some stuff... ADDDWORD(pak, 0x00); ADDDWORD(pak, 0x00); ADDDWORD(pak, 0x00); //move speed. ADDWORD(pak,player->Stats->Move_Speed); //this would appear to be in the right place though //0x00 ADDDWORD(pak, 0x00); ADDDWORD(pak, 0x00); ADDDWORD(pak, 0x00); ADDDWORD(pak, 0x00); ADDDWORD(pak, 0x00); ADDDWORD(pak, 0x00); ADDDWORD(pak, 0x00); ADDDWORD(pak, 0x00); ADDDWORD(pak, 0x00); ADDWORD(pak, 0x00); player->client->SendPacket( &pak ); if( player->Ride->Drive && player->Ride->charid!=0 ) { CPlayer* otherclient = GServer->GetClientByCID( player->Ride->charid ); if( otherclient!=NULL ) { if(TelePassenger) { TeleportPlayer( otherclient, coord ); } else { otherclient->Ride->Drive = false; otherclient->Ride->charid= 0; otherclient->Ride->Ride = false; } } } GServer->pakClearUser( player ); GServer->ClearClientID( player->clientid ); player->RestartPlayerVal( ); player->SetStats( ); return true; }