void CZoneEntities::WideScan(CCharEntity* PChar, uint16 radius) { PChar->pushPacket(new CWideScanPacket(WIDESCAN_BEGIN)); for (EntityList_t::const_iterator it = m_npcList.begin(); it != m_npcList.end(); ++it) { CNpcEntity* PNpc = (CNpcEntity*)it->second; if (PNpc->status == STATUS_NORMAL && !PNpc->IsNameHidden() && !PNpc->IsUntargetable()) { if (distance(PChar->loc.p, PNpc->loc.p) < radius) { PChar->pushPacket(new CWideScanPacket(PChar, PNpc)); } } } for (EntityList_t::const_iterator it = m_mobList.begin(); it != m_mobList.end(); ++it) { CMobEntity* PMob = (CMobEntity*)it->second; if (PMob->status != STATUS_DISAPPEAR && !PMob->IsUntargetable()) { if (distance(PChar->loc.p, PMob->loc.p) < radius) { PChar->pushPacket(new CWideScanPacket(PChar, PMob)); } } } PChar->pushPacket(new CWideScanPacket(WIDESCAN_END)); }
void CZone::FindPartyForMob(CBaseEntity* PEntity) { DSP_DEBUG_BREAK_IF(PEntity == NULL); DSP_DEBUG_BREAK_IF(PEntity->objtype != TYPE_MOB); CMobEntity* PMob = (CMobEntity*)PEntity; // force all mobs in a burning circle to link bool forceLink = GetType() == ZONETYPE_BATTLEFIELD || GetType() == ZONETYPE_DYNAMIS || PMob->getMobMod(MOBMOD_SUPERLINK); if ((forceLink || PMob->m_Link) && PMob->PParty == NULL) { for (EntityList_t::const_iterator it = m_mobList.begin() ; it != m_mobList.end() ; ++it) { CMobEntity* PCurrentMob = (CMobEntity*)it->second; if(!forceLink && !PCurrentMob->m_Link) continue; int16 sublink = PMob->getMobMod(MOBMOD_SUBLINK); if (forceLink || PCurrentMob->m_Family == PMob->m_Family || sublink && sublink == PCurrentMob->getMobMod(MOBMOD_SUBLINK)) { if(PCurrentMob->PMaster == NULL || PCurrentMob->PMaster->objtype == TYPE_MOB) { PCurrentMob->PParty->AddMember(PMob); return; } } } PMob->PParty = new CParty(PMob); } }
/*************************************************************** Spawns monsters for the given BCNMID/Battlefield number by looking at bcnm_battlefield table for mob ids then spawning them and adding them to the monster list for the given battlefield. ****************************************************************/ bool spawnMonstersForBcnm(CBattlefield* battlefield) { DSP_DEBUG_BREAK_IF(battlefield == nullptr); //get ids from DB const char* fmtQuery = "SELECT monsterId, conditions \ FROM bcnm_battlefield \ WHERE bcnmId = %u AND battlefieldNumber = %u"; int32 ret = Sql_Query(SqlHandle, fmtQuery, battlefield->getID(), battlefield->getBattlefieldNumber()); if (ret == SQL_ERROR || Sql_NumRows(SqlHandle) == 0) { ShowError("spawnMonstersForBcnm : SQL error - Cannot find any monster IDs for BCNMID %i Battlefield %i \n", battlefield->getID(), battlefield->getBattlefieldNumber()); } else { while (Sql_NextRow(SqlHandle) == SQL_SUCCESS) { uint32 mobid = Sql_GetUIntData(SqlHandle, 0); uint8 condition = Sql_GetUIntData(SqlHandle, 1); CMobEntity* PMob = (CMobEntity*)zoneutils::GetEntity(mobid, TYPE_MOB); if (PMob != nullptr) { PMob->m_battlefieldID = battlefield->getBattlefieldNumber(); PMob->m_bcnmID = battlefield->getID(); if (condition & CONDITION_SPAWNED_AT_START) { if (!PMob->PAI->IsSpawned()) { PMob->Spawn(); //ShowDebug("Spawned %s (%u) id %i inst %i \n",PMob->GetName(),PMob->id,battlefield->getID(),battlefield->getBattlefieldNumber()); battlefield->addEnemy(PMob, condition); } else { ShowDebug(CL_CYAN"SpawnMobForBcnm: <%s> (%u) is already spawned\n" CL_RESET, PMob->GetName(), PMob->id); } } else { battlefield->addEnemy(PMob, condition); } } else { ShowDebug("SpawnMobForBcnm: mob %u not found\n", mobid); } } if (!(battlefield->m_RuleMask & RULES_ALLOW_SUBJOBS)) { // disable players subjob battlefield->disableSubJob(); } return true; } return false; }
void CZoneEntities::HealAllMobs() { for (EntityList_t::const_iterator it = m_mobList.begin(); it != m_mobList.end(); ++it) { CMobEntity* PCurrentMob = (CMobEntity*)it->second; // keep resting until i'm full PCurrentMob->Rest(1); } }
void CMobController::TryLink() { if (PTarget == nullptr) { return; } //handle pet behaviour on the targets behalf (faster than in ai_pet_dummy) // Avatars defend masters by attacking mobs if the avatar isn't attacking anything currently (bodyguard behaviour) if (PTarget->PPet != nullptr && PTarget->PPet->GetBattleTargetID() == 0) { if (PTarget->PPet->objtype == TYPE_PET && ((CPetEntity*)PTarget->PPet)->getPetType() == PETTYPE_AVATAR) { petutils::AttackTarget(PTarget, PMob); } } // my pet should help as well if (PMob->PPet != nullptr && PMob->PPet->PAI->IsRoaming()) { ((CMobEntity*)PMob->PPet)->PEnmityContainer->AddBaseEnmity(PTarget); } // Handle monster linking if they are close enough if (PMob->PParty != nullptr) { for (uint16 i = 0; i < PMob->PParty->members.size(); ++i) { CMobEntity* PPartyMember = (CMobEntity*)PMob->PParty->members[i]; if (PPartyMember->PAI->IsRoaming() && PPartyMember->CanLink(&PMob->loc.p, PMob->getMobMod(MOBMOD_SUPERLINK))) { PPartyMember->PEnmityContainer->AddBaseEnmity(PTarget); if (PPartyMember->m_roamFlags & ROAMFLAG_IGNORE) { // force into attack action //#TODO PPartyMember->PAI->Engage(PTarget->targid); } } } } // ask my master for help if (PMob->PMaster != nullptr && PMob->PMaster->PAI->IsRoaming()) { CMobEntity* PMaster = (CMobEntity*)PMob->PMaster; if (PMaster->PAI->IsRoaming() && PMaster->CanLink(&PMob->loc.p, PMob->getMobMod(MOBMOD_SUPERLINK))) { PMaster->PEnmityContainer->AddBaseEnmity(PTarget); } } }
void CMobEntity::Spawn() { CBattleEntity::Spawn(); m_giveExp = true; m_HiPCLvl = 0; m_THLvl = 0; m_ItemStolen = false; m_DropItemTime = 1000; animationsub = getMobMod(MOBMOD_SPAWN_ANIMATIONSUB); CallForHelp(false); PEnmityContainer->Clear(); uint8 level = m_minLevel; // Generate a random level between min and max level if (m_maxLevel != m_minLevel) { level += dsprand::GetRandomNumber(0, m_maxLevel - m_minLevel); } SetMLevel(level); SetSLevel(level);//calculated in function delRageMode(); mobutils::CalculateStats(this); mobutils::GetAvailableSpells(this); // spawn somewhere around my point loc.p = m_SpawnPoint; if (m_roamFlags & ROAMFLAG_STEALTH) { HideName(true); Untargetable(true); } // add people to my posse if (getMobMod(MOBMOD_ASSIST)) { for (int8 i = 1; i < getMobMod(MOBMOD_ASSIST) + 1; i++) { CMobEntity* PMob = (CMobEntity*)GetEntity(targid + i, TYPE_MOB); if (PMob != nullptr) { PMob->setMobMod(MOBMOD_SUPERLINK, targid); } } } m_DespawnTimer = time_point::min(); luautils::OnMobSpawn(this); }
void CZone::SpawnMOBs(CCharEntity* PChar) { for (EntityList_t::const_iterator it = m_mobList.begin() ; it != m_mobList.end() ; ++it) { CMobEntity* PCurrentMob = (CMobEntity*)it->second; SpawnIDList_t::iterator MOB = PChar->SpawnMOBList.lower_bound(PCurrentMob->id); float CurrentDistance = distance(PChar->loc.p, PCurrentMob->loc.p); if (PCurrentMob->status == STATUS_UPDATE && CurrentDistance < 50) { if( MOB == PChar->SpawnMOBList.end() || PChar->SpawnMOBList.key_comp()(PCurrentMob->id, MOB->first)) { PChar->SpawnMOBList.insert(MOB, SpawnIDList_t::value_type(PCurrentMob->id, PCurrentMob)); PChar->pushPacket(new CEntityUpdatePacket(PCurrentMob, ENTITY_SPAWN)); } if (PChar->isDead() || PChar->nameflags.flags & FLAG_GM || PCurrentMob->PMaster != NULL) continue; // проверка ночного/дневного сна монстров уже учтена в проверке CurrentAction, т.к. во сне монстры не ходят ^^ uint16 expGain = (uint16)charutils::GetRealExp(PChar->GetMLevel(),PCurrentMob->GetMLevel()); CAIMobDummy* PAIMob = (CAIMobDummy*)PCurrentMob->PBattleAI; bool validAggro = expGain > 50 || PChar->animation == ANIMATION_HEALING || PCurrentMob->getMobMod(MOBMOD_ALWAYS_AGGRO); if(validAggro && PAIMob->CanAggroTarget(PChar)) { PCurrentMob->PEnmityContainer->AddBaseEnmity(PChar); } } else { if( MOB != PChar->SpawnMOBList.end() && !(PChar->SpawnMOBList.key_comp()(PCurrentMob->id, MOB->first))) { PChar->SpawnMOBList.erase(MOB); PChar->pushPacket(new CEntityUpdatePacket(PCurrentMob,ENTITY_DESPAWN)); } } } }
void CZoneEntities::SpawnMOBs(CCharEntity* PChar) { for (EntityList_t::const_iterator it = m_mobList.begin(); it != m_mobList.end(); ++it) { CMobEntity* PCurrentMob = (CMobEntity*)it->second; SpawnIDList_t::iterator MOB = PChar->SpawnMOBList.lower_bound(PCurrentMob->id); float CurrentDistance = distance(PChar->loc.p, PCurrentMob->loc.p); if (PCurrentMob->status != STATUS_DISAPPEAR && CurrentDistance < 50) { if (MOB == PChar->SpawnMOBList.end() || PChar->SpawnMOBList.key_comp()(PCurrentMob->id, MOB->first)) { PChar->SpawnMOBList.insert(MOB, SpawnIDList_t::value_type(PCurrentMob->id, PCurrentMob)); PChar->pushPacket(new CEntityUpdatePacket(PCurrentMob, ENTITY_SPAWN, UPDATE_ALL_MOB)); } if (PChar->isDead() || PChar->nameflags.flags & FLAG_GM || PCurrentMob->PMaster != nullptr) continue; // проверка ночного/дневного сна монстров уже учтена в проверке CurrentAction, т.к. во сне монстры не ходят ^^ uint16 expGain = (uint16)charutils::GetRealExp(PChar->GetMLevel(), PCurrentMob->GetMLevel()); CMobController* PController = static_cast<CMobController*>(PCurrentMob->PAI->GetController()); bool validAggro = expGain > 50 || PChar->isSitting() || PCurrentMob->getMobMod(MOBMOD_ALWAYS_AGGRO); if (validAggro && PController->CanAggroTarget(PChar)) { PCurrentMob->PEnmityContainer->AddBaseEnmity(PChar); } } else { if (MOB != PChar->SpawnMOBList.end() && !(PChar->SpawnMOBList.key_comp()(PCurrentMob->id, MOB->first))) { PChar->SpawnMOBList.erase(MOB); PChar->pushPacket(new CEntityUpdatePacket(PCurrentMob, ENTITY_DESPAWN, UPDATE_NONE)); } } } }
bool spawnSecondPartDynamis(CBattlefield* battlefield) { DSP_DEBUG_BREAK_IF(battlefield == nullptr); //get ids from DB const int8* fmtQuery = "SELECT monsterId \ FROM bcnm_battlefield \ WHERE bcnmId = %u AND battlefieldNumber = 2"; int32 ret = Sql_Query(SqlHandle, fmtQuery, battlefield->getID()); if (ret == SQL_ERROR || Sql_NumRows(SqlHandle) == 0) { ShowError("spawnSecondPartDynamis : SQL error - Cannot find any monster IDs for Dynamis %i \n", battlefield->getID(), battlefield->getBattlefieldNumber()); } else { while (Sql_NextRow(SqlHandle) == SQL_SUCCESS) { uint32 mobid = Sql_GetUIntData(SqlHandle, 0); CMobEntity* PMob = (CMobEntity*)zoneutils::GetEntity(mobid, TYPE_MOB); if (PMob != nullptr) { if (!PMob->PAI->IsSpawned()) { PMob->Spawn(); PMob->m_battlefieldID = battlefield->getBattlefieldNumber(); ShowDebug("Spawned %s (%u) id %i inst %i \n", PMob->GetName(), PMob->id, battlefield->getID(), battlefield->getBattlefieldNumber()); battlefield->addEnemy(PMob, CONDITION_SPAWNED_AT_START & CONDITION_WIN_REQUIREMENT); } else { ShowDebug(CL_CYAN"spawnSecondPartDynamis: <%s> (%u) is already spawned\n" CL_RESET, PMob->GetName(), PMob->id); } } else { ShowDebug("spawnSecondPartDynamis: mob %u not found\n", mobid); } } return true; } return false; }
bool spawnSecondPartDynamis(CInstance* instance){ DSP_DEBUG_BREAK_IF(instance==NULL); //get ids from DB const int8* fmtQuery = "SELECT monsterId \ FROM bcnm_instance \ WHERE bcnmId = %u AND instanceNumber = 2"; int32 ret = Sql_Query(SqlHandle, fmtQuery, instance->getID()); if (ret == SQL_ERROR || Sql_NumRows(SqlHandle) == 0) { ShowError("spawnSecondPartDynamis : SQL error - Cannot find any monster IDs for Dynamis %i \n", instance->getID(), instance->getInstanceNumber()); } else{ while(Sql_NextRow(SqlHandle) == SQL_SUCCESS){ uint32 mobid = Sql_GetUIntData(SqlHandle,0); CMobEntity* PMob = (CMobEntity*)zoneutils::GetEntity(mobid, TYPE_MOB); if (PMob != NULL) { if (PMob->PBattleAI->GetCurrentAction() == ACTION_NONE || PMob->PBattleAI->GetCurrentAction() == ACTION_SPAWN) { PMob->PBattleAI->SetLastActionTime(0); PMob->PBattleAI->SetCurrentAction(ACTION_SPAWN); PMob->m_instanceID = instance->getInstanceNumber(); ShowDebug("Spawned %s (%u) id %i inst %i \n",PMob->GetName(),PMob->id,instance->getID(),instance->getInstanceNumber()); instance->addEnemy(PMob, CONDITION_SPAWNED_AT_START & CONDITION_WIN_REQUIREMENT); } else { ShowDebug(CL_CYAN"spawnSecondPartDynamis: <%s> (%u) is alredy spawned\n" CL_RESET, PMob->GetName(), PMob->id); } } else { ShowDebug("spawnSecondPartDynamis: mob %u not found\n", mobid); } } return true; } return false; }
void SpawnCatch(CCharEntity* PChar, uint32 mobid) { CBattleEntity* TargetID = (CBattleEntity*)PChar; CMobEntity* PMob = (CMobEntity*)zoneutils::GetEntity(mobid, TYPE_MOB); if (PMob->PBattleAI->GetCurrentAction() == ACTION_NONE) { PMob->SetDespawnTimer(3); PMob->m_AllowRespawn = false; PMob->m_Type = MOBTYPE_FISHED; PMob->CanDetectTarget(TargetID, true); PMob->m_Behaviour = BEHAVIOUR_NO_TURN; PMob->m_SpawnPoint = nearPosition(PChar->loc.p, 2.2f, M_PI); PMob->PBattleAI->SetLastActionTime(gettick()); PMob->PBattleAI->SetCurrentAction(ACTION_SPAWN); PMob->PBattleAI->CheckCurrentAction(gettick()); PMob->PEnmityContainer->AddBaseEnmity(TargetID); } }
void CZoneEntities::WeatherChange(WEATHER weather) { auto element = zoneutils::GetWeatherElement(weather); for (EntityList_t::const_iterator it = m_mobList.begin(); it != m_mobList.end(); ++it) { CMobEntity* PCurrentMob = (CMobEntity*)it->second; PCurrentMob->PAI->EventHandler.triggerListener("WEATHER_CHANGE", PCurrentMob, static_cast<int>(weather), element); // can't detect by scent in this weather if (PCurrentMob->m_Aggro & AGGRO_SCENT) { PCurrentMob->m_disableScent = (weather == WEATHER_RAIN || weather == WEATHER_SQUALL || weather == WEATHER_BLIZZARDS); } if (PCurrentMob->m_EcoSystem == SYSTEM_ELEMENTAL && PCurrentMob->PMaster == nullptr && PCurrentMob->m_SpawnType == SPAWNTYPE_WEATHER) { if (PCurrentMob->m_Element == element) { PCurrentMob->SetDespawnTime(0s); PCurrentMob->m_AllowRespawn = true; PCurrentMob->Spawn(); } else { PCurrentMob->SetDespawnTime(1s); PCurrentMob->m_AllowRespawn = false; } } else if (PCurrentMob->m_SpawnType == SPAWNTYPE_FOG) { if (weather == WEATHER_FOG) { PCurrentMob->SetDespawnTime(0s); PCurrentMob->m_AllowRespawn = true; PCurrentMob->Spawn(); } else { PCurrentMob->SetDespawnTime(1s); PCurrentMob->m_AllowRespawn = false; } } } for (EntityList_t::const_iterator it = m_charList.begin(); it != m_charList.end(); ++it) { CCharEntity* PChar = (CCharEntity*)it->second; PChar->PLatentEffectContainer->CheckLatentsZone(); PChar->PAI->EventHandler.triggerListener("WEATHER_CHANGE", PChar, static_cast<int>(weather), element); } }
void CZoneEntities::TOTDChange(TIMETYPE TOTD) { SCRIPTTYPE ScriptType = SCRIPT_NONE; switch (TOTD) { case TIME_MIDNIGHT: { } break; case TIME_NEWDAY: { for (EntityList_t::const_iterator it = m_mobList.begin(); it != m_mobList.end(); ++it) { CMobEntity* PMob = (CMobEntity*)it->second; if (PMob->m_SpawnType == SPAWNTYPE_ATNIGHT) { PMob->SetDespawnTimer(1); PMob->m_AllowRespawn = false; } } } break; case TIME_DAWN: { ScriptType = SCRIPT_TIME_DAWN; for (EntityList_t::const_iterator it = m_mobList.begin(); it != m_mobList.end(); ++it) { CMobEntity* PMob = (CMobEntity*)it->second; if (PMob->m_SpawnType == SPAWNTYPE_ATEVENING) { PMob->SetDespawnTimer(1); PMob->m_AllowRespawn = false; } } } break; case TIME_DAY: { ScriptType = SCRIPT_TIME_DAY; } break; case TIME_DUSK: { ScriptType = SCRIPT_TIME_DUSK; } break; case TIME_EVENING: { ScriptType = SCRIPT_TIME_EVENING; for (EntityList_t::const_iterator it = m_mobList.begin(); it != m_mobList.end(); ++it) { CMobEntity* PMob = (CMobEntity*)it->second; if (PMob->m_SpawnType == SPAWNTYPE_ATEVENING) { PMob->SetDespawnTimer(0); PMob->m_AllowRespawn = true; PMob->PBattleAI->SetCurrentAction(ACTION_SPAWN); } } } break; case TIME_NIGHT: { for (EntityList_t::const_iterator it = m_mobList.begin(); it != m_mobList.end(); ++it) { CMobEntity* PMob = (CMobEntity*)it->second; if (PMob->m_SpawnType == SPAWNTYPE_ATNIGHT) { PMob->SetDespawnTimer(0); PMob->m_AllowRespawn = true; PMob->PBattleAI->SetCurrentAction(ACTION_SPAWN); } } } break; } if (ScriptType != SCRIPT_NONE) { for (EntityList_t::const_iterator it = m_charList.begin(); it != m_charList.end(); ++it) { charutils::CheckEquipLogic((CCharEntity*)it->second, ScriptType, TOTD); } } }
void CZoneEntities::DecreaseZoneCounter(CCharEntity* PChar) { DSP_DEBUG_BREAK_IF(PChar == nullptr); DSP_DEBUG_BREAK_IF(PChar->loc.zone != m_zone); //remove pets if (PChar->PPet != nullptr) { charutils::BuildingCharPetAbilityTable(PChar, (CPetEntity*)PChar->PPet, 0);//blank the pet commands if (PChar->PPet->isCharmed) { petutils::DespawnPet(PChar); } else { PChar->PPet->status = STATUS_DISAPPEAR; if (((CPetEntity*)(PChar->PPet))->getPetType() == PETTYPE_AVATAR) PChar->setModifier(MOD_AVATAR_PERPETUATION, 0); } // It may have been nullptred by DespawnPet if (PChar->PPet != nullptr) { PChar->PPet->PAI->Disengage(); for (EntityList_t::const_iterator it = m_charList.begin(); it != m_charList.end(); ++it) { //inform other players of the pets removal CCharEntity* PCurrentChar = (CCharEntity*)it->second; SpawnIDList_t::iterator PET = PCurrentChar->SpawnPETList.find(PChar->PPet->id); if (PET != PCurrentChar->SpawnPETList.end()) { PCurrentChar->SpawnPETList.erase(PET); PCurrentChar->pushPacket(new CEntityUpdatePacket(PChar->PPet, ENTITY_DESPAWN, UPDATE_NONE)); } } PChar->PPet = nullptr; } } //remove bcnm status if (m_zone->m_BattlefieldHandler != nullptr && PChar->StatusEffectContainer->HasStatusEffect(EFFECT_BATTLEFIELD)) { if (m_zone->m_BattlefieldHandler->disconnectFromBcnm(PChar)) { ShowDebug("Removed %s from the BCNM they were in as they have left the zone.\n", PChar->GetName()); } if (PChar->loc.destination == 0) { //this player is disconnecting/logged out, so move them to the entrance //move depending on zone int pos[4] = {0, 0, 0, 0}; battlefieldutils::getStartPosition(m_zone->GetID(), pos); if (pos != nullptr) { PChar->loc.p.x = pos[0]; PChar->loc.p.y = pos[1]; PChar->loc.p.z = pos[2]; PChar->loc.p.rotation = pos[3]; PChar->updatemask |= UPDATE_POS; charutils::SaveCharPosition(PChar); } else { ShowWarning("%s has disconnected from the BCNM but cannot move them to the lobby as the lobby position is unknown!\n", PChar->GetName()); } } } else if (m_zone->m_BattlefieldHandler != nullptr && PChar->StatusEffectContainer->HasStatusEffect(EFFECT_DYNAMIS, 0)) { if (m_zone->m_BattlefieldHandler->disconnectFromDynamis(PChar)) { ShowDebug("Removed %s from the BCNM they were in as they have left the zone.\n", PChar->GetName()); } if (PChar->loc.destination == 0) { //this player is disconnecting/logged out, so move them to the entrance //move depending on zone int pos[4] = {0, 0, 0, 0}; battlefieldutils::getStartPosition(m_zone->GetID(), pos); if (!(pos[0] == 0 && pos[1] == 0 && pos[2] == 0 && pos[3] == 0)) { PChar->loc.p.x = pos[0]; PChar->loc.p.y = pos[1]; PChar->loc.p.z = pos[2]; PChar->loc.p.rotation = pos[3]; PChar->updatemask |= UPDATE_POS; charutils::SaveCharPosition(PChar); } else { ShowWarning("%s has disconnected from the BCNM but cannot move them to the lobby as the lobby position is unknown!\n", PChar->GetName()); } } } for (auto PMobIt : m_mobList) { CMobEntity* PCurrentMob = (CMobEntity*)PMobIt.second; PCurrentMob->PEnmityContainer->LogoutReset(PChar->id); if (PCurrentMob->m_OwnerID.id == PChar->id) { PCurrentMob->m_OwnerID.clean(); PCurrentMob->updatemask |= UPDATE_STATUS; } if (PCurrentMob->GetBattleTargetID() == PChar->targid) { PCurrentMob->SetBattleTargetID(0); } } if (PChar->animation == ANIMATION_SYNTH) { PChar->CraftContainer->setQuantity(0, synthutils::SYNTHESIS_FAIL); synthutils::sendSynthDone(PChar); } // TODO: могут возникать проблемы с переходом между одной и той же зоной (zone == prevzone) m_charList.erase(PChar->targid); ShowDebug(CL_CYAN"CZone:: %s DecreaseZoneCounter <%u> %s\n" CL_RESET, m_zone->GetName(), m_charList.size(), PChar->GetName()); }
void SpawnMobPet(CBattleEntity* PMaster, uint32 PetID) { // this is ONLY used for mob smn elementals / avatars /* This should eventually be merged into one big spawn pet method. At the moment player pets and mob pets are totally different. We need a central place to manage pet families and spawn them. */ // grab pet info Pet_t* petData = g_PPetList.at(PetID); CMobEntity* PPet = (CMobEntity*)PMaster->PPet; PPet->look = petData->look; PPet->name = petData->name; PPet->m_EcoSystem = petData->EcoSystem; PPet->m_Family = petData->m_Family; PPet->m_Element = petData->m_Element; PPet->HPscale = petData->HPscale; PPet->MPscale = petData->MPscale; PPet->m_HasSpellScript = petData->hasSpellScript; // assuming elemental spawn PPet->setModifier(MOD_DMGPHYS,-50); //-50% PDT PPet->m_SpellListContainer = mobSpellList::GetMobSpellList(petData->spellList); PPet->setModifier(MOD_SLASHRES, petData->slashres); PPet->setModifier(MOD_PIERCERES,petData->pierceres); PPet->setModifier(MOD_HTHRES, petData->hthres); PPet->setModifier(MOD_IMPACTRES, petData->impactres); PPet->setModifier(MOD_FIREDEF, petData->firedef); // These are stored as floating percentages PPet->setModifier(MOD_ICEDEF, petData->icedef); // and need to be adjusted into modifier units. PPet->setModifier(MOD_WINDDEF, petData->winddef); // Higher DEF = lower damage. PPet->setModifier(MOD_EARTHDEF, petData->earthdef); // Negatives signify increased damage. PPet->setModifier(MOD_THUNDERDEF, petData->thunderdef); // Positives signify reduced damage. PPet->setModifier(MOD_WATERDEF, petData->waterdef); // Ex: 125% damage would be 1.25, 50% damage would be 0.50 PPet->setModifier(MOD_LIGHTDEF, petData->lightdef); // (1.25 - 1) * -1000 = -250 DEF PPet->setModifier(MOD_DARKDEF, petData->darkdef); // (0.50 - 1) * -1000 = 500 DEF PPet->setModifier(MOD_FIRERES, petData->fireres); // These are stored as floating percentages PPet->setModifier(MOD_ICERES, petData->iceres); // and need to be adjusted into modifier units. PPet->setModifier(MOD_WINDRES, petData->windres); // Higher RES = lower damage. PPet->setModifier(MOD_EARTHRES, petData->earthres); // Negatives signify lower resist chance. PPet->setModifier(MOD_THUNDERRES, petData->thunderres); // Positives signify increased resist chance. PPet->setModifier(MOD_WATERRES, petData->waterres); PPet->setModifier(MOD_LIGHTRES, petData->lightres); PPet->setModifier(MOD_DARKRES, petData->darkres); }
CMobEntity* InstantiateAlly(uint32 groupid, uint16 zoneID, CInstance* instance) { const char* Query = "SELECT zoneid, name, \ respawntime, spawntype, dropid, mob_groups.HP, mob_groups.MP, minLevel, maxLevel, \ modelid, mJob, sJob, cmbSkill, cmbDmgMult, cmbDelay, behavior, links, mobType, immunity, \ systemid, mobsize, speed, \ STR, DEX, VIT, AGI, `INT`, MND, CHR, EVA, DEF, \ Slash, Pierce, H2H, Impact, \ Fire, Ice, Wind, Earth, Lightning, Water, Light, Dark, Element, \ mob_pools.familyid, name_prefix, entityFlags, animationsub, \ (mob_family_system.HP / 100), (mob_family_system.MP / 100), hasSpellScript, spellList, ATT, ACC, mob_groups.poolid, \ allegiance, namevis, aggro, mob_pools.skill_list_id, mob_pools.true_detection, mob_family_system.detects, packet_name \ FROM mob_groups INNER JOIN mob_pools ON mob_groups.poolid = mob_pools.poolid \ INNER JOIN mob_family_system ON mob_pools.familyid = mob_family_system.familyid \ WHERE mob_groups.groupid = %u"; int32 ret = Sql_Query(SqlHandle, Query, groupid); CMobEntity* PMob = nullptr; if (ret != SQL_ERROR && Sql_NumRows(SqlHandle) != 0) { if (Sql_NextRow(SqlHandle) == SQL_SUCCESS) { PMob = new CMobEntity; PMob->PInstance = instance; PMob->name.insert(0, (const char*)Sql_GetData(SqlHandle, 1)); PMob->packetName.insert(0, (const char*)Sql_GetData(SqlHandle, 61)); PMob->m_RespawnTime = Sql_GetUIntData(SqlHandle, 2) * 1000; PMob->m_SpawnType = (SPAWNTYPE)Sql_GetUIntData(SqlHandle, 3); PMob->m_DropID = Sql_GetUIntData(SqlHandle, 4); PMob->HPmodifier = (uint32)Sql_GetIntData(SqlHandle, 5); PMob->MPmodifier = (uint32)Sql_GetIntData(SqlHandle, 6); PMob->m_minLevel = (uint8)Sql_GetIntData(SqlHandle, 7); PMob->m_maxLevel = (uint8)Sql_GetIntData(SqlHandle, 8); memcpy(&PMob->look, Sql_GetData(SqlHandle, 9), 23); PMob->SetMJob(Sql_GetIntData(SqlHandle, 10)); PMob->SetSJob(Sql_GetIntData(SqlHandle, 11)); PMob->m_Weapons[SLOT_MAIN]->setMaxHit(1); PMob->m_Weapons[SLOT_MAIN]->setSkillType(Sql_GetIntData(SqlHandle, 12)); PMob->m_dmgMult = Sql_GetUIntData(SqlHandle, 13); PMob->m_Weapons[SLOT_MAIN]->setDelay((Sql_GetIntData(SqlHandle, 14) * 1000) / 60); PMob->m_Weapons[SLOT_MAIN]->setBaseDelay((Sql_GetIntData(SqlHandle, 14) * 1000) / 60); PMob->m_Behaviour = (uint16)Sql_GetIntData(SqlHandle, 15); PMob->m_Link = (uint8)Sql_GetIntData(SqlHandle, 16); PMob->m_Type = (uint8)Sql_GetIntData(SqlHandle, 17); PMob->m_Immunity = (IMMUNITY)Sql_GetIntData(SqlHandle, 18); PMob->m_EcoSystem = (ECOSYSTEM)Sql_GetIntData(SqlHandle, 19); PMob->m_ModelSize = (uint8)Sql_GetIntData(SqlHandle, 10); PMob->speed = (uint8)Sql_GetIntData(SqlHandle, 21); PMob->speedsub = (uint8)Sql_GetIntData(SqlHandle, 21); /*if(PMob->speed != 0) { PMob->speed += map_config.speed_mod; // whats this for? PMob->speedsub += map_config.speed_mod; }*/ PMob->strRank = (uint8)Sql_GetIntData(SqlHandle, 22); PMob->dexRank = (uint8)Sql_GetIntData(SqlHandle, 23); PMob->vitRank = (uint8)Sql_GetIntData(SqlHandle, 24); PMob->agiRank = (uint8)Sql_GetIntData(SqlHandle, 25); PMob->intRank = (uint8)Sql_GetIntData(SqlHandle, 26); PMob->mndRank = (uint8)Sql_GetIntData(SqlHandle, 27); PMob->chrRank = (uint8)Sql_GetIntData(SqlHandle, 28); PMob->evaRank = (uint8)Sql_GetIntData(SqlHandle, 29); PMob->defRank = (uint8)Sql_GetIntData(SqlHandle, 30); PMob->attRank = (uint8)Sql_GetIntData(SqlHandle, 52); PMob->accRank = (uint8)Sql_GetIntData(SqlHandle, 53); PMob->setModifier(Mod::SLASHRES, (uint16)(Sql_GetFloatData(SqlHandle, 31) * 1000)); PMob->setModifier(Mod::PIERCERES, (uint16)(Sql_GetFloatData(SqlHandle, 32) * 1000)); PMob->setModifier(Mod::HTHRES, (uint16)(Sql_GetFloatData(SqlHandle, 33) * 1000)); PMob->setModifier(Mod::IMPACTRES, (uint16)(Sql_GetFloatData(SqlHandle, 34) * 1000)); PMob->setModifier(Mod::FIRERES, (int16)((Sql_GetFloatData(SqlHandle, 35) - 1) * -100)); // These are stored as floating percentages PMob->setModifier(Mod::ICERES, (int16)((Sql_GetFloatData(SqlHandle, 36) - 1) * -100)); // and need to be adjusted into modifier units. PMob->setModifier(Mod::WINDRES, (int16)((Sql_GetFloatData(SqlHandle, 37) - 1) * -100)); // Higher RES = lower damage. PMob->setModifier(Mod::EARTHRES, (int16)((Sql_GetFloatData(SqlHandle, 38) - 1) * -100)); // Negatives signify lower resist chance. PMob->setModifier(Mod::THUNDERRES, (int16)((Sql_GetFloatData(SqlHandle, 39) - 1) * -100)); // Positives signify increased resist chance. PMob->setModifier(Mod::WATERRES, (int16)((Sql_GetFloatData(SqlHandle, 40) - 1) * -100)); PMob->setModifier(Mod::LIGHTRES, (int16)((Sql_GetFloatData(SqlHandle, 41) - 1) * -100)); PMob->setModifier(Mod::DARKRES, (int16)((Sql_GetFloatData(SqlHandle, 42) - 1) * -100)); PMob->m_Element = (uint8)Sql_GetIntData(SqlHandle, 43); PMob->m_Family = (uint16)Sql_GetIntData(SqlHandle, 44); PMob->m_name_prefix = (uint8)Sql_GetIntData(SqlHandle, 45); PMob->m_flags = (uint32)Sql_GetIntData(SqlHandle, 46); //Special sub animation for Mob (yovra, jailer of love, phuabo) // yovra 1: en hauteur, 2: en bas, 3: en haut // phuabo 1: sous l'eau, 2: sort de l'eau, 3: rentre dans l'eau PMob->animationsub = (uint32)Sql_GetIntData(SqlHandle, 47); // Setup HP / MP Stat Percentage Boost PMob->HPscale = Sql_GetFloatData(SqlHandle, 48); PMob->MPscale = Sql_GetFloatData(SqlHandle, 49); // Check if we should be looking up scripts for this mob PMob->m_HasSpellScript = (uint8)Sql_GetIntData(SqlHandle, 50); PMob->m_SpellListContainer = mobSpellList::GetMobSpellList(Sql_GetIntData(SqlHandle, 51)); PMob->m_Pool = Sql_GetUIntData(SqlHandle, 54); PMob->allegiance = Sql_GetUIntData(SqlHandle, 55); PMob->namevis = Sql_GetUIntData(SqlHandle, 56); PMob->m_Aggro = Sql_GetUIntData(SqlHandle, 57); PMob->m_MobSkillList = Sql_GetUIntData(SqlHandle, 58); PMob->m_TrueDetection = Sql_GetUIntData(SqlHandle, 59); PMob->m_Detects = Sql_GetUIntData(SqlHandle, 60); // must be here first to define mobmods mobutils::InitializeMob(PMob, zoneutils::GetZone(zoneID)); zoneutils::GetZone(zoneID)->InsertPET(PMob); luautils::OnMobInitialize(PMob); luautils::ApplyMixins(PMob); PMob->saveModifiers(); PMob->saveMobModifiers(); } } return PMob; }
CEntityUpdatePacket::CEntityUpdatePacket(CBaseEntity* PEntity, ENTITYUPDATE type, uint8 updatemask) { this->type = 0x0E; this->size = 0x1C; WBUFL(data,(0x04)-4) = PEntity->id; WBUFW(data,(0x08)-4) = PEntity->targid; WBUFB(data,(0x0A)-4) = updatemask; switch(type) { case ENTITY_DESPAWN: { WBUFB(data,(0x0A)-4) = 0x20; updatemask = UPDATE_ALL_MOB; } break; case ENTITY_SPAWN: { updatemask = UPDATE_ALL_MOB; if (PEntity->objtype == TYPE_PET) { WBUFB(data,(0x28)-4) = 0x04; } if (PEntity->look.size == MODEL_EQUIPED || PEntity->look.size == MODEL_CHOCOBO) { updatemask = 0x57; } WBUFB(data,(0x0A)-4) = updatemask; } break; } if (updatemask & UPDATE_POS){ WBUFB(data,(0x0B)-4) = PEntity->loc.p.rotation; WBUFF(data,(0x0C)-4) = PEntity->loc.p.x; WBUFF(data,(0x10)-4) = PEntity->loc.p.y; WBUFF(data,(0x14)-4) = PEntity->loc.p.z; WBUFW(data,(0x18)-4) = PEntity->loc.p.moving; WBUFW(data,(0x1A)-4) = PEntity->m_TargID << 1; WBUFB(data,(0x1C)-4) = PEntity->speed; WBUFB(data,(0x1D)-4) = PEntity->speedsub; } if (PEntity->allegiance == ALLEGIANCE_PLAYER && PEntity->status == STATUS_UPDATE) WBUFB(data, (0x20) - 4) = STATUS_NORMAL; else WBUFB(data, (0x20) - 4) = PEntity->status; switch(PEntity->objtype) { case TYPE_NPC: { if (updatemask & UPDATE_HP) { WBUFB(data,(0x1E)-4) = 0x64; WBUFB(data,(0x1F)-4) = PEntity->animation; WBUFB(data,(0x2A)-4) = PEntity->animationsub; WBUFL(data,(0x21)-4) = ((CNpcEntity*)PEntity)->unknown; WBUFB(data,(0x22)-4) |= (PEntity->untargetable ? 0x08 : 0x00); WBUFB(data,(0x22)-4) |= (PEntity->hpvis ? 0x00 : 0x01); WBUFB(data,(0x27)-4) = ((CNpcEntity*)PEntity)->name_prefix; // gender and something else WBUFB(data,(0x29)-4) = PEntity->allegiance; WBUFB(data,(0x2B)-4) = PEntity->namevis; } } break; case TYPE_MOB: { CMobEntity* PMob = (CMobEntity*)PEntity; if(PMob->PMaster != NULL && PMob->PMaster->objtype == TYPE_PC && PMob->PBattleAI->GetCurrentAction() == ACTION_FALL) { WBUFB(data,(0x21)-4) = 0x99; //WBUFB (data,(0x27)-4) = 0x28; WBUFB(data,(0x1E)-4) = 0x00; //0% HP WBUFB(data,(0x1F)-4) = ANIMATION_DEATH; //death anim WBUFB(data,(0x20)-4) = STATUS_NORMAL; WBUFB(data,(0x29)-4) = PEntity->allegiance; WBUFB(data,(0x2B)-4) = PEntity->namevis; } else { if (updatemask & UPDATE_HP) { WBUFB(data,(0x1E)-4) = PMob->GetHPP(); WBUFB(data,(0x1F)-4) = PEntity->animation; WBUFB(data,(0x2A)-4) = PEntity->animationsub; WBUFL(data,(0x21)-4) = PMob->m_unknown; WBUFB(data,(0x21)-4) |= PMob->m_CallForHelp; WBUFB(data,(0x22)-4) |= (PEntity->untargetable ? 0x08 : 0x00); WBUFB(data,(0x22)-4) |= (PEntity->hpvis ? 0x00 : 0x01); WBUFB(data,(0x27)-4) = PMob->m_name_prefix; if (PMob->PMaster != NULL && PMob->PMaster->objtype == TYPE_PC) WBUFB(data,(0x27)-4) |= 0x08; WBUFB(data,(0x28)-4) |= (PMob->StatusEffectContainer->HasStatusEffect(EFFECT_TERROR) ? 0x10 : 0x00); WBUFB(data,(0x29)-4) = PEntity->allegiance; WBUFB(data, (0x2B) - 4) = 0;//PEntity->namevis; } if (updatemask & UPDATE_STATUS) { WBUFL(data, (0x2C) - 4) = PMob->m_OwnerID.id; } } if (updatemask & UPDATE_NAME) { //depending on size of name, this can be 0x20, 0x22, or 0x24 this->size = 0x24; memcpy(data + (0x34) - 4, PEntity->GetName(), (PEntity->name.size() > 15 ? 15 : PEntity->name.size())); } } break; case TYPE_PET: { if(((CPetEntity*)PEntity)->PBattleAI->GetCurrentAction()==ACTION_FALL){ WBUFB(data,(0x21)-4) = 0x99; WBUFB(data,(0x25)-4) = 0x08; WBUFB(data,(0x27)-4) = 0x08 | ((CPetEntity*)PEntity)->m_name_prefix; WBUFB(data,(0x29)-4) = PEntity->allegiance; WBUFB(data,(0x28)-4) = (((CBattleEntity*)PEntity)->health.hp > 0 ? 0x08 : 0x00); WBUFB(data,(0x1E)-4) = 0x00; //0% HP WBUFB(data,(0x1F)-4) = ANIMATION_DEATH; WBUFB(data,(0x20)-4) = STATUS_NORMAL; } else{ if (updatemask & UPDATE_HP) { WBUFB(data,(0x1E)-4) = ((CPetEntity*)PEntity)->GetHPP(); WBUFB(data,(0x1F)-4) = PEntity->animation; WBUFB(data,(0x2A)-4) = PEntity->animationsub; WBUFB(data,(0x28)-4) |= (((CPetEntity*)PEntity)->StatusEffectContainer->HasStatusEffect(EFFECT_TERROR) ? 0x10 : 0x00); WBUFB(data,(0x29)-4) = PEntity->allegiance; } if (updatemask & UPDATE_STATUS) { WBUFB(data,(0x27)-4) = 0x08 | ((CPetEntity*)PEntity)->m_name_prefix; } if (updatemask & UPDATE_NAME) { this->size = 0x24; memcpy(data + (0x34) - 4, PEntity->GetName(), (PEntity->name.size() > 15 ? 15 : PEntity->name.size())); } } } break; } switch(PEntity->look.size) { case MODEL_STANDARD: case MODEL_UNK_5: case MODEL_AUTOMATON: { WBUFL(data,(0x30)-4) = RBUFL(&PEntity->look,0); } break; case MODEL_EQUIPED: case MODEL_CHOCOBO: { this->size = 0x24; memcpy(data + (0x30) - 4, &(PEntity->look), 20); } break; case MODEL_DOOR: case MODEL_ELEVATOR: case MODEL_SHIP: { this->size = 0x24; WBUFW (data,(0x30)-4) = PEntity->look.size; memcpy(data+(0x34)-4, PEntity->GetName(),(PEntity->name.size() > 12 ? 12 : PEntity->name.size())); } break; } }
void DespawnPet(CBattleEntity* PMaster) { DSP_DEBUG_BREAK_IF(PMaster->PPet == NULL); CBattleEntity* PPet = PMaster->PPet; // mob was not reset properly on death/uncharm // reset manually if (PPet->isCharmed && PMaster->objtype == TYPE_MOB) { PPet->isCharmed = false; PMaster->charmTime = 0; delete PPet->PBattleAI; PPet->PBattleAI = new CAIMobDummy((CMobEntity*)PMaster); PPet->PBattleAI->SetLastActionTime(gettick()); PPet->PBattleAI->SetCurrentAction(ACTION_FALL); ShowDebug("An ex charmed mob was not reset properly, Manually resetting it.\n"); return; } switch (PPet->objtype) { case TYPE_PET: { PPet->PBattleAI->SetCurrentAction(ACTION_FALL); if( ((CPetEntity*)PPet)->getPetType() == PETTYPE_AVATAR ) PMaster->setModifier(MOD_AVATAR_PERPETUATION, 0); if (PMaster->PParty != NULL) { for (uint8 i = 0; i < PMaster->PParty->members.size(); ++i) { CCharEntity* PMember = (CCharEntity*)PMaster->PParty->members.at(i); PMember->PLatentEffectContainer->CheckLatentsPartyAvatar(); } } CCharEntity* PChar = (CCharEntity*)PMaster; PChar->PLatentEffectContainer->CheckLatentsPartyAvatar(); } break; case TYPE_MOB: { if(PMaster->objtype == TYPE_PC) { CMobEntity* PMob = (CMobEntity*)PMaster->PPet; CCharEntity* PChar = (CCharEntity*)PMaster; // mobs charm wears off whist fighting another mob. Both mobs now attack player since mobs are no longer enemies if(PMob->PBattleAI != NULL && PMob->PBattleAI->GetBattleTarget() != NULL && PMob->PBattleAI->GetBattleTarget()->objtype == TYPE_MOB){ ((CMobEntity*)PMob->PBattleAI->GetBattleTarget())->PEnmityContainer->Clear(); ((CMobEntity*)PMob->PBattleAI->GetBattleTarget())->PEnmityContainer->UpdateEnmity(PChar, 0, 0); } //clear the ex-charmed mobs enmity PMob->PEnmityContainer->Clear(); // charm time is up, mob attacks player now if (PMob->GetHPP() != 0 && PMob->PMaster->GetHPP() != 0 && distance(PMob->loc.p, PMob->PMaster->loc.p) < 30) { PMob->PEnmityContainer->UpdateEnmity(PChar, 0, 0); } else { PMob->m_OwnerID.clean(); } // dirty exp if not full PMob->m_giveExp = PMob->GetHPP() == 100; //master using leave command if (PMaster->PBattleAI->GetCurrentAction() == ACTION_JOBABILITY_FINISH && PMaster->PBattleAI->GetCurrentJobAbility()->getID() == 55 || PChar->loc.zoning) { PMob->PEnmityContainer->Clear(); PMob->m_OwnerID.clean(); } PMob->isCharmed = false; PMob->charmTime = 0; PMob->PMaster = NULL; delete PMob->PBattleAI; PMob->PBattleAI = new CAIMobDummy(PMob); PMob->PBattleAI->SetLastActionTime(gettick()); if (PMob->GetHPP() == 0) PMob->PBattleAI->SetCurrentAction(ACTION_FALL); else PMob->PBattleAI->SetCurrentAction(ACTION_DISENGAGE); PChar->PPet = NULL; PChar->pushPacket(new CCharUpdatePacket(PChar)); PMob->loc.zone->PushPacket(PMob, CHAR_INRANGE, new CEntityUpdatePacket(PMob, ENTITY_UPDATE)); } } break; case TYPE_PC: { // освобождаем персонажа из под контроля } break; } }
CEntityUpdatePacket::CEntityUpdatePacket(CBaseEntity* PEntity, ENTITYUPDATE type, uint8 updatemask) { this->type = 0x0E; this->size = 0x1C; ref<uint32>(0x04) = PEntity->id; ref<uint16>(0x08) = PEntity->targid; ref<uint8>(0x0A) = updatemask; switch (type) { case ENTITY_DESPAWN: { ref<uint8>(0x0A) = 0x20; updatemask = UPDATE_ALL_MOB; } break; case ENTITY_SPAWN: { updatemask = UPDATE_ALL_MOB; if (PEntity->objtype == TYPE_PET) { ref<uint8>(0x28) = 0x04; } if (PEntity->look.size == MODEL_EQUIPED || PEntity->look.size == MODEL_CHOCOBO) { updatemask = 0x57; } ref<uint8>(0x0A) = updatemask; } break; default: { break; } } if (updatemask & UPDATE_POS) { ref<uint8>(0x0B) = PEntity->loc.p.rotation; ref<float>(0x0C) = PEntity->loc.p.x; ref<float>(0x10) = PEntity->loc.p.y; ref<float>(0x14) = PEntity->loc.p.z; ref<uint16>(0x18) = PEntity->loc.p.moving; ref<uint16>(0x1A) = PEntity->m_TargID << 1; ref<uint8>(0x1C) = PEntity->speed; ref<uint8>(0x1D) = PEntity->speedsub; } if (PEntity->allegiance == ALLEGIANCE_PLAYER && PEntity->status == STATUS_MOB) ref<uint8>(0x20) = STATUS_NORMAL; else ref<uint8>(0x20) = PEntity->status; switch (PEntity->objtype) { case TYPE_NPC: { if (updatemask & UPDATE_HP) { ref<uint8>(0x1E) = 0x64; ref<uint8>(0x1F) = PEntity->animation; ref<uint8>(0x2A) = PEntity->animationsub; ref<uint32>(0x21) = ((CNpcEntity*)PEntity)->m_flags; ref<uint8>(0x27) = ((CNpcEntity*)PEntity)->name_prefix; // gender and something else ref<uint8>(0x29) = PEntity->allegiance; ref<uint8>(0x2B) = PEntity->namevis; } } break; case TYPE_MOB: case TYPE_PET: { CMobEntity* PMob = (CMobEntity*)PEntity; //if(PMob->PMaster != nullptr && PMob->PMaster->objtype == TYPE_PC && // PMob->PBattleAI->GetCurrentAction() == ACTION_FALL) //{ // ref<uint8>(data,(0x21)) = 0x99; // //ref<uint8> (data,(0x27)) = 0x28; // ref<uint8>(data,(0x1E)) = 0x00; //0% HP // ref<uint8>(data,(0x1F)) = ANIMATION_DEATH; //death anim // ref<uint8>(data,(0x20)) = STATUS_NORMAL; // ref<uint8>(data,(0x29)) = PEntity->allegiance; // ref<uint8>(data,(0x2B)) = PEntity->namevis; //} //else { if (updatemask & UPDATE_HP) { ref<uint8>(0x1E) = PMob->GetHPP(); ref<uint8>(0x1F) = PEntity->animation; ref<uint8>(0x2A) = PEntity->animationsub; ref<uint32>(0x21) = PMob->m_flags; ref<uint8>(0x25) = PMob->health.hp > 0 ? 0x08 : 0; ref<uint8>(0x27) = PMob->m_name_prefix; if (PMob->PMaster != nullptr && PMob->PMaster->objtype == TYPE_PC) ref<uint8>(0x27) |= 0x08; ref<uint8>(0x28) |= (PMob->StatusEffectContainer->HasStatusEffect(EFFECT_TERROR) ? 0x10 : 0x00); ref<uint8>(0x28) |= PMob->health.hp > 0 && PMob->animation == ANIMATION_DEATH ? 0x08 : 0; ref<uint8>(0x29) = PEntity->allegiance; ref<uint8>(0x2B) = PEntity->namevis; } if (updatemask & UPDATE_STATUS) { ref<uint32>(0x2C) = PMob->m_OwnerID.id; } } if (updatemask & UPDATE_NAME) { //depending on size of name, this can be 0x20, 0x22, or 0x24 this->size = 0x24; if (PMob->packetName.empty()) memcpy(data + (0x34), PEntity->GetName(), (PEntity->name.size() > 15 ? 15 : PEntity->name.size())); else memcpy(data + (0x34), PMob->packetName.c_str(), (PMob->packetName.size() > 15 ? 15 : PMob->packetName.size())); } } break; default: { break; } } switch (PEntity->look.size) { case MODEL_STANDARD: case MODEL_UNK_5: case MODEL_AUTOMATON: { ref<uint32>(0x30) = ::ref<uint32>(&PEntity->look, 0); } break; case MODEL_EQUIPED: case MODEL_CHOCOBO: { this->size = 0x24; memcpy(data + (0x30), &(PEntity->look), 20); } break; case MODEL_DOOR: case MODEL_ELEVATOR: case MODEL_SHIP: { this->size = 0x24; ref<uint16>(0x30) = PEntity->look.size; memcpy(data + (0x34), PEntity->GetName(), (PEntity->name.size() > 12 ? 12 : PEntity->name.size())); } break; } }
/*************************************************************** Spawns monsters for the given BCNMID/Instance number by looking at bcnm_instance table for mob ids then spawning them and adding them to the monster list for the given instance. ****************************************************************/ bool spawnMonstersForBcnm(CInstance* instance){ DSP_DEBUG_BREAK_IF(instance==NULL); //get ids from DB const int8* fmtQuery = "SELECT monsterId, conditions \ FROM bcnm_instance \ WHERE bcnmId = %u AND instanceNumber = %u"; int32 ret = Sql_Query(SqlHandle, fmtQuery, instance->getID(), instance->getInstanceNumber()); if (ret == SQL_ERROR || Sql_NumRows(SqlHandle) == 0) { ShowError("spawnMonstersForBcnm : SQL error - Cannot find any monster IDs for BCNMID %i Instance %i \n", instance->getID(), instance->getInstanceNumber()); } else{ while(Sql_NextRow(SqlHandle) == SQL_SUCCESS){ uint32 mobid = Sql_GetUIntData(SqlHandle,0); uint8 condition = Sql_GetUIntData(SqlHandle,1); CMobEntity* PMob = (CMobEntity*)zoneutils::GetEntity(mobid, TYPE_MOB); if (PMob != NULL) { PMob->m_instanceID = instance->getInstanceNumber(); PMob->m_bcnmID = instance->getID(); if (condition & CONDITION_SPAWNED_AT_START) { // This condition is needed for some mob at dynamis, else he don't pop if(PMob->PBattleAI->GetCurrentAction() == ACTION_FADE_OUT){ PMob->PBattleAI->SetLastActionTime(0); PMob->PBattleAI->SetCurrentAction(ACTION_NONE); } if (PMob->PBattleAI->GetCurrentAction() == ACTION_NONE || PMob->PBattleAI->GetCurrentAction() == ACTION_SPAWN) { PMob->PBattleAI->SetLastActionTime(0); PMob->PBattleAI->SetCurrentAction(ACTION_SPAWN); if(strcmp(PMob->GetName(),"Maat")==0){ mobutils::SetupMaat(PMob, (JOBTYPE)instance->getPlayerMainJob()); PMob->m_DropID = 4485; //Give Maat his stealable Warp Scroll // disable players subjob instance->disableSubJob(); // disallow subjob, this will enable for later instance->m_RuleMask &= ~(1 << RULES_ALLOW_SUBJOBS); } //ShowDebug("Spawned %s (%u) id %i inst %i \n",PMob->GetName(),PMob->id,instance->getID(),instance->getInstanceNumber()); instance->addEnemy(PMob, condition); } else { ShowDebug(CL_CYAN"SpawnMobForBcnm: <%s> (%u) is alredy spawned\n" CL_RESET, PMob->GetName(), PMob->id); } } else { instance->addEnemy(PMob, condition); } } else { ShowDebug("SpawnMobForBcnm: mob %u not found\n", mobid); } } return true; } return false; }
void CAIPetDummy::ActionAbilityStart() { if (m_PPet->StatusEffectContainer->HasPreventActionEffect()) { return; } if (m_PPet->objtype == TYPE_MOB && m_PPet->PMaster->objtype == TYPE_PC) { if (m_MasterCommand == MASTERCOMMAND_SIC && m_PPet->health.tp >= 1000 && m_PBattleTarget != nullptr) { m_MasterCommand = MASTERCOMMAND_NONE; CMobEntity* PMob = (CMobEntity*)m_PPet->PMaster->PPet; std::vector<uint16> MobSkills = battleutils::GetMobSkillList(PMob->getMobMod(MOBMOD_SKILL_LIST)); if (MobSkills.size() > 0) { std::shuffle(MobSkills.begin(), MobSkills.end(), dsprand::mt()); for (auto&& skillid : MobSkills) { auto PMobSkill = battleutils::GetMobSkill(skillid); if (PMobSkill && luautils::OnMobSkillCheck(m_PBattleTarget, m_PPet, PMobSkill) == 0) { SetCurrentMobSkill(PMobSkill); break; } } // could not find skill if (!GetCurrentMobSkill()) { TransitionBack(true); return; } preparePetAbility(m_PBattleTarget); return; } return; } } if (m_PPet->getPetType() == PETTYPE_JUG_PET) { if (m_MasterCommand == MASTERCOMMAND_SIC && m_PPet->health.tp >= 1000 && m_PBattleTarget != nullptr) { //choose random tp move m_MasterCommand = MASTERCOMMAND_NONE; if (m_PPet->PetSkills.size() > 0) { auto PMobSkill = battleutils::GetMobSkill(m_PPet->PetSkills.at(dsprand::GetRandomNumber(m_PPet->PetSkills.size()))); if (PMobSkill) { SetCurrentMobSkill(PMobSkill); preparePetAbility(m_PBattleTarget); return; } } } } else if (m_PPet->getPetType() == PETTYPE_AVATAR) { for (int i = 0; i < m_PPet->PetSkills.size(); i++) { auto PMobSkill = battleutils::GetMobSkill(m_PPet->PetSkills.at(i)); if (PMobSkill && PMobSkill->getAnimationTime() == m_MasterCommand) { SetCurrentMobSkill(PMobSkill); m_MasterCommand = MASTERCOMMAND_NONE; preparePetAbility(m_PPet); return; } } m_MasterCommand = MASTERCOMMAND_NONE; } else if (m_PPet->getPetType() == PETTYPE_WYVERN) { WYVERNTYPE wyverntype = m_PPet->getWyvernType(); if (m_MasterCommand == MASTERCOMMAND_ELEMENTAL_BREATH && (wyverntype == WYVERNTYPE_MULTIPURPOSE || wyverntype == WYVERNTYPE_OFFENSIVE)) { m_MasterCommand = MASTERCOMMAND_NONE; //offensive or multipurpose wyvern if (m_PBattleTarget != nullptr) { //prepare elemental breaths int skip = dsprand::GetRandomNumber(6); int hasSkipped = 0; for (int i = 0; i < m_PPet->PetSkills.size(); i++) { auto PMobSkill = battleutils::GetMobSkill(m_PPet->PetSkills.at(i)); if (PMobSkill && PMobSkill->getValidTargets() == TARGET_ENEMY) { if (hasSkipped == skip) { SetCurrentMobSkill(PMobSkill); break; } else { hasSkipped++; } } } preparePetAbility(m_PBattleTarget); return; } } else if (m_MasterCommand == MASTERCOMMAND_HEALING_BREATH && (wyverntype == WYVERNTYPE_DEFENSIVE || wyverntype == WYVERNTYPE_MULTIPURPOSE)) { m_MasterCommand = MASTERCOMMAND_NONE; m_PBattleSubTarget = nullptr; //TODO: CHECK FOR STATUS EFFECTS FOR REMOVE- BREATH (higher priority than healing breaths) // if(m_PPet->PMaster->PParty==nullptr){//solo with master-kun CItemArmor* masterHeadItem = ((CCharEntity*)(m_PPet->PMaster))->getEquip(SLOT_HEAD); uint16 masterHead = masterHeadItem ? masterHeadItem->getID() : 0; // Determine what the required HP percentage will need to be // at or under in order for healing breath to activate. uint8 requiredHPP = 0; if (((CCharEntity*)(m_PPet->PMaster))->objtype == TYPE_PC && (masterHead == 12519 || masterHead == 15238)) { //Check for player & AF head, or +1 if (wyverntype == WYVERNTYPE_DEFENSIVE) { //healer wyvern requiredHPP = 50; } else if (wyverntype == WYVERNTYPE_MULTIPURPOSE) { //hybrid wyvern requiredHPP = 33; } } else { if (wyverntype == WYVERNTYPE_DEFENSIVE) { //healer wyvern requiredHPP = 33; } else if (wyverntype == WYVERNTYPE_MULTIPURPOSE) { //hybrid wyvern requiredHPP = 25; } } // Only attempt to find a target if there is an HP percentage to calculate. if (requiredHPP) { CBattleEntity* master = m_PPet->PMaster; // Check the master first. if (master->GetHPP() <= requiredHPP) { m_PBattleSubTarget = master; } // Otherwise if this is a healer wyvern, and the member is in a party // check all of the party members who qualify. else if (wyverntype == WYVERNTYPE_DEFENSIVE && master->PParty != nullptr) { master->ForParty([this, requiredHPP](CBattleEntity* PTarget) { if (PTarget->GetHPP() <= requiredHPP) { m_PBattleSubTarget = PTarget; } }); } } if (m_PBattleSubTarget != nullptr) { //target to heal //get highest breath for wyverns level m_PMobSkill = nullptr; for (int i = 0; i < m_PPet->PetSkills.size(); i++) { auto PMobSkill = battleutils::GetMobSkill(m_PPet->PetSkills.at(i)); if (PMobSkill && PMobSkill->getValidTargets() == TARGET_PLAYER_PARTY) { if (PMobSkill->getID() == 638 && m_PPet->PMaster->GetMLevel() < 20) { //can only using hb1 SetCurrentMobSkill(PMobSkill); break; } else if (PMobSkill->getID() == 639 && m_PPet->PMaster->GetMLevel() < 40) { //can only using hb2 SetCurrentMobSkill(PMobSkill); break; } else if (PMobSkill->getID() == 640 && m_PPet->PMaster->GetMLevel() >= 40) { //can only using hb3 SetCurrentMobSkill(PMobSkill); break; } } } preparePetAbility(m_PBattleSubTarget); return; } } } TransitionBack(true); }
void LoadMOBList() { const int8* Query = "SELECT zoneid, name, mobid, pos_rot, pos_x, pos_y, pos_z, \ respawntime, spawntype, dropid, mob_groups.HP, mob_groups.MP, minLevel, maxLevel, \ modelid, mJob, sJob, cmbSkill, cmbDmgMult, cmbDelay, behavior, links, mobType, immunity, \ systemid, mobsize, speed, \ STR, DEX, VIT, AGI, `INT`, MND, CHR, EVA, DEF, \ Slash, Pierce, H2H, Impact, \ Fire, Ice, Wind, Earth, Lightning, Water, Light, Dark, Element, \ mob_pools.familyid, name_prefix, unknown, animationsub, \ (mob_family_system.HP / 100), (mob_family_system.MP / 100), hasSpellScript, spellList, ATT, ACC, mob_groups.poolid \ FROM mob_groups INNER JOIN mob_pools ON mob_groups.poolid = mob_pools.poolid \ INNER JOIN mob_spawn_points ON mob_groups.groupid = mob_spawn_points.groupid \ INNER JOIN mob_family_system ON mob_pools.familyid = mob_family_system.familyid \ WHERE NOT (pos_x = 0 AND pos_y = 0 AND pos_z = 0);"; int32 ret = Sql_Query(SqlHandle, Query); if( ret != SQL_ERROR && Sql_NumRows(SqlHandle) != 0) { while(Sql_NextRow(SqlHandle) == SQL_SUCCESS) { uint16 ZoneID = (uint16)Sql_GetUIntData(SqlHandle, 0); CMobEntity* PMob = new CMobEntity; PMob->name.insert(0,Sql_GetData(SqlHandle,1)); PMob->id = (uint32)Sql_GetUIntData(SqlHandle,2); PMob->targid = (uint16)PMob->id & 0x0FFF; PMob->m_SpawnPoint.rotation = (uint8)Sql_GetIntData(SqlHandle,3); PMob->m_SpawnPoint.x = Sql_GetFloatData(SqlHandle,4); PMob->m_SpawnPoint.y = Sql_GetFloatData(SqlHandle,5); PMob->m_SpawnPoint.z = Sql_GetFloatData(SqlHandle,6); PMob->m_RespawnTime = Sql_GetUIntData(SqlHandle,7) * 1000; PMob->m_SpawnType = (SPAWNTYPE)Sql_GetUIntData(SqlHandle,8); PMob->m_DropID = Sql_GetUIntData(SqlHandle,9); PMob->HPmodifier = (uint32)Sql_GetIntData(SqlHandle,10); PMob->MPmodifier = (uint32)Sql_GetIntData(SqlHandle,11); PMob->m_minLevel = (uint8)Sql_GetIntData(SqlHandle,12); PMob->m_maxLevel = (uint8)Sql_GetIntData(SqlHandle,13); memcpy(&PMob->look,Sql_GetData(SqlHandle,14),23); PMob->SetMJob(Sql_GetIntData(SqlHandle,15)); PMob->SetSJob(Sql_GetIntData(SqlHandle,16)); PMob->m_Weapons[SLOT_MAIN]->setMaxHit(1); PMob->m_Weapons[SLOT_MAIN]->setSkillType(Sql_GetIntData(SqlHandle,17)); PMob->m_dmgMult = Sql_GetUIntData(SqlHandle, 18); PMob->m_Weapons[SLOT_MAIN]->setDelay((Sql_GetIntData(SqlHandle,19) * 1000)/60); PMob->m_Weapons[SLOT_MAIN]->setBaseDelay((Sql_GetIntData(SqlHandle,19) * 1000)/60); PMob->m_Behaviour = (uint16)Sql_GetIntData(SqlHandle,20); PMob->m_Link = (uint8)Sql_GetIntData(SqlHandle,21); PMob->m_Type = (uint8)Sql_GetIntData(SqlHandle,22); PMob->m_Immunity = (IMMUNITY)Sql_GetIntData(SqlHandle,23); PMob->m_EcoSystem = (ECOSYSTEM)Sql_GetIntData(SqlHandle,24); PMob->m_ModelSize += (uint8)Sql_GetIntData(SqlHandle,25); PMob->speed = (uint8)Sql_GetIntData(SqlHandle,26); PMob->speedsub = (uint8)Sql_GetIntData(SqlHandle,26); /*if(PMob->speed != 0) { PMob->speed += map_config.speed_mod; // whats this for? PMob->speedsub += map_config.speed_mod; }*/ PMob->strRank = (uint8)Sql_GetIntData(SqlHandle,27); PMob->dexRank = (uint8)Sql_GetIntData(SqlHandle,28); PMob->vitRank = (uint8)Sql_GetIntData(SqlHandle,29); PMob->agiRank = (uint8)Sql_GetIntData(SqlHandle,30); PMob->intRank = (uint8)Sql_GetIntData(SqlHandle,31); PMob->mndRank = (uint8)Sql_GetIntData(SqlHandle,32); PMob->chrRank = (uint8)Sql_GetIntData(SqlHandle,33); PMob->evaRank = (uint8)Sql_GetIntData(SqlHandle,34); PMob->defRank = (uint8)Sql_GetIntData(SqlHandle,35); PMob->attRank = (uint8)Sql_GetIntData(SqlHandle,57); PMob->accRank = (uint8)Sql_GetIntData(SqlHandle,58); PMob->setModifier(MOD_SLASHRES, (uint16)(Sql_GetFloatData(SqlHandle,36) * 1000)); PMob->setModifier(MOD_PIERCERES,(uint16)(Sql_GetFloatData(SqlHandle,37) * 1000)); PMob->setModifier(MOD_HTHRES, (uint16)(Sql_GetFloatData(SqlHandle,38) * 1000)); PMob->setModifier(MOD_IMPACTRES,(uint16)(Sql_GetFloatData(SqlHandle,39) * 1000)); PMob->setModifier(MOD_FIREDEF, (int16)((Sql_GetFloatData(SqlHandle, 40) - 1) * -1000)); // These are stored as floating percentages PMob->setModifier(MOD_ICEDEF, (int16)((Sql_GetFloatData(SqlHandle, 41) - 1) * -1000)); // and need to be adjusted into modifier units. PMob->setModifier(MOD_WINDDEF, (int16)((Sql_GetFloatData(SqlHandle, 42) - 1) * -1000)); // Higher DEF = lower damage. PMob->setModifier(MOD_EARTHDEF, (int16)((Sql_GetFloatData(SqlHandle, 43) - 1) * -1000)); // Negatives signify increased damage. PMob->setModifier(MOD_THUNDERDEF, (int16)((Sql_GetFloatData(SqlHandle, 44) - 1) * -1000)); // Positives signify reduced damage. PMob->setModifier(MOD_WATERDEF, (int16)((Sql_GetFloatData(SqlHandle, 45) - 1) * -1000)); // Ex: 125% damage would be 1.25, 50% damage would be 0.50 PMob->setModifier(MOD_LIGHTDEF, (int16)((Sql_GetFloatData(SqlHandle, 46) - 1) * -1000)); // (1.25 - 1) * -1000 = -250 DEF PMob->setModifier(MOD_DARKDEF, (int16)((Sql_GetFloatData(SqlHandle, 47) - 1) * -1000)); // (0.50 - 1) * -1000 = 500 DEF PMob->setModifier(MOD_FIRERES, (int16)((Sql_GetFloatData(SqlHandle, 40) - 1) * -100)); // These are stored as floating percentages PMob->setModifier(MOD_ICERES, (int16)((Sql_GetFloatData(SqlHandle, 41) - 1) * -100)); // and need to be adjusted into modifier units. PMob->setModifier(MOD_WINDRES, (int16)((Sql_GetFloatData(SqlHandle, 42) - 1) * -100)); // Higher RES = lower damage. PMob->setModifier(MOD_EARTHRES, (int16)((Sql_GetFloatData(SqlHandle, 43) - 1) * -100)); // Negatives signify lower resist chance. PMob->setModifier(MOD_THUNDERRES, (int16)((Sql_GetFloatData(SqlHandle, 44) - 1) * -100)); // Positives signify increased resist chance. PMob->setModifier(MOD_WATERRES, (int16)((Sql_GetFloatData(SqlHandle, 45) - 1) * -100)); PMob->setModifier(MOD_LIGHTRES, (int16)((Sql_GetFloatData(SqlHandle, 46) - 1) * -100)); PMob->setModifier(MOD_DARKRES, (int16)((Sql_GetFloatData(SqlHandle, 47) - 1) * -100)); PMob->m_Element = (uint8)Sql_GetIntData(SqlHandle,48); PMob->m_Family = (uint16)Sql_GetIntData(SqlHandle,49); PMob->m_name_prefix = (uint8)Sql_GetIntData(SqlHandle,50); PMob->m_unknown = (uint32)Sql_GetIntData(SqlHandle,51); //Special sub animation for Mob (yovra, jailer of love, phuabo) // yovra 1: en hauteur, 2: en bas, 3: en haut // phuabo 1: sous l'eau, 2: sort de l'eau, 3: rentre dans l'eau PMob->animationsub = (uint32)Sql_GetIntData(SqlHandle,52); // Setup HP / MP Stat Percentage Boost PMob->HPscale = Sql_GetFloatData(SqlHandle,53); PMob->MPscale = Sql_GetFloatData(SqlHandle,54); PMob->PBattleAI = new CAIMobDummy(PMob); if (PMob->m_AllowRespawn = PMob->m_SpawnType == SPAWNTYPE_NORMAL) { PMob->PBattleAI->SetCurrentAction(ACTION_SPAWN); } // Check if we should be looking up scripts for this mob PMob->m_HasSpellScript = (uint8)Sql_GetIntData(SqlHandle,55); PMob->m_SpellListContainer = mobSpellList::GetMobSpellList(Sql_GetIntData(SqlHandle,56)); PMob->m_Pool = Sql_GetUIntData(SqlHandle,59); // must be here first to define mobmods mobutils::InitializeMob(PMob, GetZone(ZoneID)); GetZone(ZoneID)->InsertMOB(PMob); luautils::OnMobInitialize(PMob); PMob->saveModifiers(); PMob->saveMobModifiers(); } } // attach pets to mobs const int8* PetQuery = "SELECT zoneid, mob_mobid, pet_offset \ FROM mob_pets \ LEFT JOIN mob_spawn_points ON mob_pets.mob_mobid = mob_spawn_points.mobid \ LEFT JOIN mob_groups ON mob_spawn_points.groupid = mob_groups.groupid;"; ret = Sql_Query(SqlHandle, PetQuery); if( ret != SQL_ERROR && Sql_NumRows(SqlHandle) != 0) { while(Sql_NextRow(SqlHandle) == SQL_SUCCESS) { uint16 ZoneID = (uint16)Sql_GetUIntData(SqlHandle, 0); uint32 masterid = (uint32)Sql_GetUIntData(SqlHandle,1); uint32 petid = masterid + (uint32)Sql_GetUIntData(SqlHandle,2); CMobEntity* PMaster = (CMobEntity*)GetZone(ZoneID)->GetEntity(masterid & 0x0FFF, TYPE_MOB); CMobEntity* PPet = (CMobEntity*)GetZone(ZoneID)->GetEntity(petid & 0x0FFF, TYPE_MOB); if(PMaster == NULL) { ShowError("zoneutils::loadMOBList PMaster is null. masterid: %d. Make sure x,y,z are not zeros, and that all entities are entered in the database!\n", masterid); } else if(PPet == NULL) { ShowError("zoneutils::loadMOBList PPet is null. petid: %d. Make sure x,y,z are not zeros!\n", petid); } else if(masterid == petid) { ShowError("zoneutils::loadMOBList Master and Pet are the same entity: %d\n", masterid); } else { // pet is always spawned by master PPet->m_AllowRespawn = false; PPet->m_SpawnType = SPAWNTYPE_SCRIPTED; PPet->PBattleAI->SetCurrentAction(ACTION_NONE); PPet->SetDespawnTimer(0); PMaster->PPet = PPet; PPet->PMaster = PMaster; } } } }
CEntityUpdatePacket::CEntityUpdatePacket(CBaseEntity* PEntity, ENTITYUPDATE type) { this->type = 0x0E; this->size = 0x1C; WBUFL(data,(0x04)-4) = PEntity->id; WBUFW(data,(0x08)-4) = PEntity->targid; switch(type) { case ENTITY_DESPAWN: { switch(PEntity->objtype) { case TYPE_NPC: { WBUFB(data,(0x0A)-4) = 0x20; } break; case TYPE_MOB: { WBUFB(data,(0x0A)-4) = 0x07; WBUFB(data,(0x20)-4) = 0x07; } break; case TYPE_PET: { WBUFB(data,(0x0A)-4) = 0x20; } break; } } break; case ENTITY_SPAWN: { switch(PEntity->objtype) { case TYPE_PET: { WBUFB(data,(0x28)-4) = 0x04; } break; } } case ENTITY_UPDATE: { WBUFB(data,(0x0B)-4) = PEntity->loc.p.rotation; WBUFF(data,(0x0C)-4) = PEntity->loc.p.x; WBUFF(data,(0x10)-4) = PEntity->loc.p.y; WBUFF(data,(0x14)-4) = PEntity->loc.p.z; WBUFW(data,(0x18)-4) = PEntity->loc.p.moving; WBUFW(data,(0x1A)-4) = PEntity->m_TargID << 1; WBUFB(data,(0x1C)-4) = PEntity->speed; WBUFB(data,(0x1D)-4) = PEntity->speedsub; WBUFB(data,(0x1F)-4) = PEntity->animation; WBUFB(data,(0x20)-4) = PEntity->status; WBUFB(data,(0x2A)-4) = PEntity->animationsub; WBUFB(data,(0x2B)-4) = PEntity->namevis; switch(PEntity->objtype) { case TYPE_NPC: { WBUFB(data,(0x1E)-4) = 0x64; WBUFL(data,(0x21)-4) = ((CNpcEntity*)PEntity)->unknown; WBUFB(data,(0x27)-4) = ((CNpcEntity*)PEntity)->name_prefix; // gender and something else } break; case TYPE_MOB: { CMobEntity* PMob = (CMobEntity*)PEntity; if(PMob->PMaster != NULL && PMob->PMaster->objtype == TYPE_PC) { //charmed mob if(PMob->PMaster->objtype = TYPE_PC) { if(PMob->PBattleAI->GetCurrentAction()==ACTION_FALL) { WBUFB(data,(0x0A)-4) = 0x07; WBUFB (data,(0x21)-4) = 0x99; //WBUFB (data,(0x27)-4) = 0x28; WBUFW(data,(0x1A)-4) = 0x00; WBUFW(data,(0x1B)-4) = 0x00; WBUFB (data,(0x1E)-4) = 0x00; //0% HP WBUFB (data,(0x1F)-4) = ANIMATION_DEATH; //death anim WBUFB (data,(0x20)-4) = STATUS_NORMAL; } else { this->size = 0x24; WBUFB (data,(0x1E)-4) = PMob->GetHPP(); WBUFB (data,(0x27)-4) = 0x08; memcpy(data+(0x34)-4, PEntity->GetName(),(PEntity->name.size() > 15 ? 15 : PEntity->name.size())); } } } else { WBUFB(data,(0x1E)-4) = PMob->GetHPP(); WBUFL(data,(0x21)-4) = PMob->m_unknown; WBUFB(data,(0x21)-4) |= PMob->m_CallForHelp; WBUFB(data,(0x27)-4) = PMob->m_name_prefix; WBUFL(data,(0x2C)-4) = PMob->m_OwnerID.id; //set bit0 to 1 to make HP bars invisible e.g. Yilgeban, another bit somewhere controls mob targetability //WBUFB(data,(0x22)-4) = 0; if (PMob->PMaster != NULL && PMob->PMaster->objtype == TYPE_PC) WBUFB(data,(0x27)-4) = 0x08; //todo: may need |= } } break; case TYPE_PET: { if(((CPetEntity*)PEntity)->PBattleAI->GetCurrentAction()==ACTION_FALL){ WBUFB(data,(0x0A)-4) = 0x07; WBUFB(data,(0x21)-4) = 0x99; //WBUFB(data,(0x27)-4) = 0x28; WBUFW(data,(0x1A)-4) = 0x00; WBUFB(data,(0x1E)-4) = 0x00; //0% HP WBUFB(data,(0x1F)-4) = ANIMATION_DEATH; WBUFB(data,(0x20)-4) = STATUS_NORMAL; } else{ this->size = 0x24; WBUFB (data,(0x1E)-4) = ((CPetEntity*)PEntity)->GetHPP(); WBUFB (data,(0x27)-4) = 0x08; memcpy(data+(0x34)-4, PEntity->GetName(),(PEntity->name.size() > 15 ? 15 : PEntity->name.size())); } } break; } switch(PEntity->look.size) { case MODEL_STANDARD: case MODEL_UNK_5: case MODEL_UNK_6: { WBUFB(data,(0x0A)-4) = 0x0F; WBUFL(data,(0x30)-4) = RBUFL(&PEntity->look,0); } break; case MODEL_EQUIPED: case MODEL_CHOCOBO: { this->size = 0x24; WBUFB (data,(0x0A)-4) = 0x57; memcpy(data+(0x30)-4, &(PEntity->look), 20); } break; case MODEL_DOOR: case MODEL_ELEVATOR: case MODEL_SHIP: { this->size = 0x24; WBUFB (data,(0x0A)-4) = 0x07; WBUFW (data,(0x30)-4) = PEntity->look.size; memcpy(data+(0x34)-4, PEntity->GetName(),(PEntity->name.size() > 12 ? 12 : PEntity->name.size())); } break; } } break; } }