/* Rose Online Server Emulator Copyright (C) 2006,2007 OSRose Team http://www.osrose.net This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. depeloped with Main erose/hrose source server + some change from the original eich source */ #include "worldmap.h" // convert a monster to other CMonster* CMap::ConverToMonster( CMonster* monster, UINT newmontype, bool heal ) { CNPCData* thisnpc = GServer->GetNPCDataByID( newmontype ); if(thisnpc == NULL)// invalid type return NULL; monster->montype = newmontype; monster->thisnpc = thisnpc; monster->monAI = monster->thisnpc->AI; monster->SetStats( ); monster->Stats->MaxHP = monster->GetMaxHP( ); monster->Stats->HP = monster->Stats->MaxHP; monster->Stats->MaxMP = monster->GetMaxMP( ); monster->Stats->MP = monster->Stats->MaxMP; if(heal) monster->Stats->HP = monster->Stats->MaxHP; if(monster->owner == 0) { monster->MonsterDrop->mobdrop = GServer->GetDropData( monster->thisnpc->dropid ); monster->MonsterDrop->mapdrop = GServer->GetDropData( id ); } BEGINPACKET( pak, 0x774 ); ADDWORD ( pak, monster->clientid ); ADDWORD ( pak, newmontype ); GServer->SendToVisible( &pak, monster ); //monster->OnSpawn( false ); return monster; } // convert a npc to other [not working] CMonster* CMap::ConverToMonster( CNPC* npc, UINT newmontype ) { CMonster* monster = AddMonster( newmontype, npc->pos, 0, 0, 1 ); if(monster == NULL) // invalid montype return NULL; GServer->ClearClientID( monster->clientid ); monster->clientid = npc->clientid; for(UINT i=0;iclientid ); ADDWORD ( pak, newmontype ); GServer->SendToVisible( &pak, monster ); return monster; } // 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; Log(MSG_DEBUG,"(TeleportPlayer) Destiny set to target position X: %f Y: %f.",player->Position->current.x,player->Position->current.y); 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; } bool CMap::pakTeleport( CPlayer* player, unsigned int Map, fPoint coord, bool TelePassenger ) { GServer->MapList.Index[player->Position->Map]->RemovePlayer( player, false ); player->Position->Map = Map; player->Position->current = coord; player->Position->destiny = coord; Log(MSG_DEBUG,"(pakTeleport) Destiny set to target position X: %f Y: %f.",player->Position->current.x,player->Position->current.y); 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) ); 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; } // return near respawn [NULL if there are no respawn] CRespawnPoint* CMap::GetNearRespawn( CPlayer* player ) { CRespawnPoint* respawn = NULL; float distance = 0xffff; for(UINT i=0;idistance( player->Position->current, RespawnList.at(i)->dest ); if( resdist < distance ) { respawn = RespawnList.at(i); distance = resdist; } } return respawn; } // Return "start" respawn CRespawnPoint* CMap::GetStartRespawn( ) { for( UINT i = 0; i < RespawnList.size(); i++ ) { if( RespawnList.at(i)->masterdest ) return RespawnList.at(i); } return NULL; } // Return first respawn CRespawnPoint* CMap::GetFirstRespawn( ) { CRespawnPoint* respawn = NULL; for(UINT i=0;iclientid == id ) return PlayerList.at(i); } return NULL; } // Search a client by charid CPlayer* CMap::GetCharIDInMap( UINT id ) { for(UINT i=0;iCharInfo->charid == id ) return PlayerList.at(i); } return NULL; } // Search a monster by clientid CMonster* CMap::GetMonsterInMap( UINT id ) { for(UINT i=0;iclientid == id ) return MonsterList.at(i); } return NULL; } CDrop* CMap::GetDropInMap( UINT id ) { for(UINT i=0;iclientid == id ) return DropsList.at(i); } return NULL; } CNPC* CMap::GetNPCInMap( UINT id ) { for(UINT i=0;iclientid == id ) return NPCList.at(i); } return NULL; } void CMap::UpdateTime( ) { if(id == 0) return; UINT etime = (UINT)GServer->round((clock() - LastUpdate)/1000); if(etime < 10)return; MapTime += (UINT)floor((double)(etime/10)); int Hourlength = int(0xffffffff / 24); int Minutelength = int(Hourlength / 60); if(MapTime == 0xffffffff) { MapTime = 0; Date ++; } ZoneTime = int(MapTime / 17895697); if(dayperiod == 0) dayperiod = 1; UINT ctime = MapTime%dayperiod; if(ctime >= morningtime && ctime < daytime) { CurrentTime = MORNING; } else if(ctime >= daytime && ctime < eveningtime) { CurrentTime = DAY; } else if(ctime >= eveningtime && ctime < nighttime) { CurrentTime = EVENING; } else if(ctime >= nighttime) { CurrentTime = NIGHT; } hour = int(MapTime / Hourlength); minute = int((MapTime - (hour * Hourlength)) / Minutelength); LastUpdate = clock(); } // Clean Drops void CMap::CleanDrops( ) { for(UINT j=0;jdroptime >= 50 ) DeleteDrop( thisdrop ); // erases this element, so don't advance j - the next drop just shifted into position j else j++; } } // Respawn a Monster void CMap::RespawnMonster( ) { if(GServer->Config.SpawnType == 1) { /*for(UINT k=0;krespawntime<2)thisspawn->respawntime=2; time_t rtime = time(NULL) - thisspawn->lastRespawnTime; if((rtime > thisspawn->respawntime && thisspawn->amonmax)|| thisspawn->amonmin ) { fPoint position = GServer->RandInPoly( thisspawn->points, thisspawn->pcount ); AddMonster( thisspawn->montype, position, 0, thisspawn->mobdrop, thisspawn->mapdrop, thisspawn->id ); thisspawn->lastRespawnTime = time(NULL); } }*/ //PY new spawn code for(UINT k=0;klastRespawnTime; if(thisspawn->limit == 1 && IsNight()) //spawn limit is set to day only continue; if(thisspawn->RefVar != 0 && thisspawn->RefVal != 0) //only allow this spawn if the correct ObjVar is set to non zero { if(GServer->ObjVar[thisspawn->RefVar][0] == thisspawn->RefVal) continue; } if(thisspawn->limit == 2 && !IsNight()) //spawn limit is set to night only continue; switch (thisspawn->type) { case 0: // no spawn. this spawn area is inactive break; case 1: //normal spawn if(rtime > (thisspawn->respawntime) && thisspawn->amon < thisspawn->max) { fPoint position = GServer->RandInCircle( thisspawn->point, thisspawn->radius ); UINT aggro = thisspawn->aggressive; AddMonster( thisspawn->montype, position, 0, thisspawn->id, aggro, false, thisspawn->limit ); thisspawn->lastRespawnTime = time(NULL); UpdateSpawnCounter( thisspawn->montype, thisspawn->id, 1); // update the counters thisspawn->triggercount = 0; } break; case 2: //normal but fill the spawn if(rtime > (thisspawn->respawntime) && thisspawn->amon < thisspawn->max) { for(int i=1;imax;i++) { fPoint position = GServer->RandInCircle( thisspawn->point, thisspawn->radius ); UINT aggro = thisspawn->aggressive; AddMonster( thisspawn->montype, position, 0, thisspawn->id, aggro, false, thisspawn->limit ); UpdateSpawnCounter( thisspawn->montype, thisspawn->id, 1); // update the counters } thisspawn->lastRespawnTime = time(NULL); } break; case 3: //cascade spawn if(thisspawn->triggercount > thisspawn->triggeramount && thisspawn->amon < thisspawn->max) { fPoint position = GServer->RandInCircle( thisspawn->point, thisspawn->radius ); UINT aggro = thisspawn->aggressive; AddMonster( thisspawn->montype, position, 0, thisspawn->id, aggro, false, thisspawn->limit ); thisspawn->lastRespawnTime = time(NULL); UpdateSpawnCounter( thisspawn->montype, thisspawn->id, 1); // update the counters thisspawn->triggercount = 0; } break; case 4: //cascade to max if(thisspawn->triggercount > thisspawn->triggeramount && thisspawn->amon < thisspawn->max) { for(int i=1;imax;i++) { fPoint position = GServer->RandInCircle( thisspawn->point, thisspawn->radius ); UINT aggro = thisspawn->aggressive; AddMonster( thisspawn->montype, position, 0, thisspawn->id, aggro, false, thisspawn->limit ); UpdateSpawnCounter( thisspawn->montype, thisspawn->id, 1); // update the counters } thisspawn->lastRespawnTime = time(NULL); thisspawn->triggercount = 0; } break; case 5: //sub spawns. needs to trigger from a specific montype if(rtime > (thisspawn->respawntime) && thisspawn->amon < thisspawn->max) { //find if any of the trigger mobs exist for(UINT j=0;jmontype == thisspawn->triggertype && (thisspawn->spawnkey == 4 || thisspawn->triggercount >= thisspawn->triggeramount)) if(monster->montype == thisspawn->triggertype) { //found the right monster. now spawn the servant mob in a circle around it fPoint position = GServer->RandInCircle(monster->Position->current,5); UINT aggro = thisspawn->aggressive; AddMonster( thisspawn->montype, position, 0, thisspawn->id, aggro, false, thisspawn->limit ); UpdateSpawnCounter( thisspawn->montype, thisspawn->id, 1); // update the counters thisspawn->triggercount = 0; thisspawn->lastRespawnTime = time(NULL); } } } break; case 6: if(rtime > (thisspawn->respawntime) && thisspawn->amon < thisspawn->max) { //find if any of the trigger mobs exist for(UINT j=0;jmontype == thisspawn->triggertype && (thisspawn->spawnkey == 4 || thisspawn->triggercount >= thisspawn->triggeramount)) if(monster->montype == thisspawn->triggertype) { //found the right monster. now spawn the servant mobs around it up to the spawn max for(int i=thisspawn->amon;imax;i++) { fPoint position = GServer->RandInCircle(monster->Position->current,5); UINT aggro = thisspawn->aggressive; AddMonster( thisspawn->montype, position, 0, thisspawn->id, aggro, false, thisspawn->limit ); UpdateSpawnCounter( thisspawn->montype, thisspawn->id, 1); // update the counters } thisspawn->lastRespawnTime = time(NULL); thisspawn->triggercount = 0; } } } break; case 7: //TDEF spawn. Spawns thisspawn->max monsters one by one using triggercount to track them if(rtime > (thisspawn->respawntime) && thisspawn->triggercount < thisspawn->max) { fPoint position = GServer->RandInCircle( thisspawn->point, thisspawn->radius ); AddMonster( thisspawn->montype, position, 0, thisspawn->id, 0, true, 0 ); UpdateSpawnCounter( thisspawn->montype, thisspawn->id, 3); // update the counters thisspawn->lastRespawnTime = time(NULL); } break; default: break; } } } if(GServer->Config.SpawnType == 0) { for (UINT j = 0; j < MobGroupList.size(); j++) { CMobGroup* thisgroup = MobGroupList.at(j); time_t rtime = time(NULL) - thisgroup->lastRespawnTime; if (rtime < thisgroup->respawntime || thisgroup->active >= thisgroup->limit) continue; for (UINT k = thisgroup->active; k < thisgroup->limit; k++) { CMob *thismob; if (thisgroup->tacMobs.size() > 0 && thisgroup->basicKills >= thisgroup->tacticalpoints) { thismob = thisgroup->tacMobs.at(thisgroup->curTac); thisgroup->basicKills = 0; thisgroup->curTac++; if (thisgroup->curTac >= thisgroup->tacMobs.size()) thisgroup->curTac = 0; } else { thismob = thisgroup->basicMobs.at(thisgroup->curBasic); thisgroup->curBasic++; if (thisgroup->curBasic >= thisgroup->basicMobs.size()) thisgroup->curBasic = 0; } for (UINT i = 0; i < thismob->amount; i++) { fPoint position = GServer->RandInCircle( thisgroup->point, thisgroup->range ); AddMonster( thismob->mobId, position, 0, thisgroup->id, 1 ); } } } } } //update the trigger counts in cascade spawns void CMap::UpdateSpawnCounter( UINT montype, UINT spawnid, UINT key ) { if(key != 0) //kick back if key is undefined { for(UINT k=0;ktypeoftrigger) { case 0: //no trigger continue; break; case 1: //at any location //specific monster spawns or dies or is attacked anywhere in the current map if(thisspawn->triggertype == montype && thisspawn->spawnkey == key) { thisspawn->triggercount++; } case 2: //at a specific spawn id //specific monster spawns or dies or is attacked at this specific spawn area if(thisspawn->triggertype == spawnid && thisspawn->spawnkey == key) { thisspawn->triggercount++; } break; case 3: //towerdef thisspawn->triggercount++; break; default: break; } } } } // Return true if is night bool CMap::IsNight( ) { if(CurrentTime==NIGHT) return true; return false; } CCharacter* CMap::GetCharInMap( unsigned int id ) { CMonster* monster = GetMonsterInMap( id ); //Log(MSG_DEBUG, "getcharinmap %i", id); if(monster != NULL) { //Log(MSG_DEBUG, "Monster found type = %i", monster->montype); return (CCharacter*) monster; } CPlayer* player = GetPlayerInMap( id ); if(player != NULL) return (CCharacter*) player; return NULL; }