Merhabalar,
Aranızda ROK Projesini bilenler vardır. Yaratık & npc hızlarını ve yapay zekasını bu proje için geliştirmiştik. ICE ve lighting işlemeleri, sorunsuz takip sistemi vs.. sizlerle paylaşıyorum.
%100 ÇÖZÜMDÜR.!
[HIDE-REPLY]
Öncelikle AI Server içerisinde, Npc.h eklemeniz gerekenler;
Kod:
void NpcCalling(float fDis,float fDistance, __Vector3 oPos, __Vector3 cPost);
Unit.h eklemeniz gereken;
Unit.cpp Initialize() içerisinde varsayılan olarak 100 değeri vermeyi unutmayın.
AI > Npc.cpp içerisindeki IsNoPathFind fonksiyonunu bununla değişin;
Kod:
void CNpc::IsNoPathFind(float fDistance){
ClearPathFindData();
m_bPathFlag = true;
int nX = 0, nZ = 0;
__Vector3 vStart, vEnd, vDis, vOldDis;
float fDis = 0.0f;
vStart.Set(m_fStartPoint_X, 0, m_fStartPoint_Y);
vEnd.Set(m_fEndPoint_X, 0, m_fEndPoint_Y);
vDis.Set(m_fStartPoint_X, 0, m_fStartPoint_Y);
int count = 0;
int nError = 0;
fDis = GetDistance(vStart, vEnd);
if (fDis > NPC_MAX_MOVE_RANGE) {
ClearPathFindData();
TRACE("#### Npc-IsNoPathFind Fail : NPC_MAX_MOVE_RANGE overflow .. [nid = %d, name=%s], cur_x=%.2f, z=%.2f, dest_x=%.2f, dest_z=%.2f, fDis=%.2f#####\n",
GetID(), GetName().c_str(), m_fStartPoint_X, m_fStartPoint_Y, m_fEndPoint_X, m_fEndPoint_Y, fDis);
return;
}
if (GetMap() == nullptr)
{
ClearPathFindData();
TRACE("#### Npc-IsNoPathFind No map : [nid=%d, name=%s], zone=%d #####\n", GetID(), GetName().c_str(), GetZoneID());
return;
}
MAP* pMap = GetMap();
vOldDis.Set(vDis.x, 0, vDis.z);
fDis = GetDistance(vOldDis, vEnd);
if (count < 0 || count >= MAX_PATH_LINE) {
count = 0;
}
GetVectorPosition(vDis, vEnd, fDistance, &vDis);
NpcCalling(fDis,fDistance, vOldDis, vDis);
if (count <= 0 || count >= MAX_PATH_LINE) {
ClearPathFindData();
TRACE("#### IsNoPtahfind Fail : nid=%d,%s, count=%d ####\n", GetID(), GetName().c_str(), count);
return;
}
m_iAniFrameIndex = count;
}
Eksik fonksiyonumuz bunu da altına ekleyin;
Kod:
void CNpc::NpcCalling(float fDis,float fDistance, __Vector3 oPos, __Vector3 cPost){
float bChamber = TILE_SIZE + 3;
if (m_bSpeedAmount > 0 && m_bSpeedAmount < 100) {
float pTile = (float)(10 - (m_bSpeedAmount / 10) - TILE_SIZE);
bChamber -= (pTile >= 1 ? pTile + 2 : 0);
}
else if (m_bSpeedAmount > 100) {
float pTile = (float)(10 - (m_bSpeedAmount / 10) - TILE_SIZE);
bChamber += (pTile >= 1 ? pTile + 2 : 0);
}
bChamber = fDis / bChamber;
if (bChamber > 15)bChamber = 15;
m_curx = (cPost.x / bChamber) + oPos.x;
m_curz = (cPost.z / bChamber) + oPos.z;
float tempSpeed = m_fSecForRealMoveMetor;
if (tempSpeed == 0)
tempSpeed = m_fSpeed_1;
float nMoveSpeed = (float)(tempSpeed / ((float)m_sSpeed / 1000));
if (nMoveSpeed != 0) {
SendMoveResult(m_curx, m_fPrevY, m_curz, (float)(nMoveSpeed));
}
}
Hareket hızlarımız yazılımsal olarak düzelmiştir. Şimdide takip olayındaki hataları fixleyelim.
Yine Npc.cpp içindeki NpcTracing fonksiyonunda aşağıdaki return değerlerini güncelleyin.
Kod:
if (isNonAttackingObject()) {
InitTarget();
m_NpcState = NPC_STANDING;
return 0;
}
Kod:
if (m_byMoveType == 4) {
m_NpcState = NPC_FIGHTING;
return 0;
}
Kod:
if (result == CloseTargetInGeneralRange) {
NpcMoveEnd();
m_NpcState = NPC_FIGHTING;
return 0;
}
else if (result == CloseTargetInvalid)
{
InitTarget();
NpcMoveEnd();
m_NpcState = NPC_STANDING;
return 0;
}
else if (result == CloseTargetInAttackRange && GetProto()->m_byDirectAttack == 2)
{
NpcMoveEnd();
m_NpcState = NPC_FIGHTING;
return 0;
}
Kod:
if (m_bStopFollowingTarget) {
if (!ResetPath())// && !m_tNpcTraceType)
{
InitTarget();
NpcMoveEnd();
m_NpcState = NPC_STANDING;
return 0;
}
}
Kod:
if ( (!m_bPathFlag && !StepMove()) || (m_bPathFlag && !StepNoPathMove()))
{
m_NpcState = NPC_STANDING;
return 0;
}
Fonksiyonun en son ki return değeri ;
Yine aynı şekilde NpcAttacking fonksiyonun return değerleri aşağıdaki gibi olmalı;
Kod:
if (isNonAttackingObject()) {
m_NpcState = NPC_STANDING;
return 0;
}
Kod:
if (result == CloseTargetInGeneralRange) {
m_NpcState = NPC_FIGHTING;
return m_sAttackDelay;
}
Kod:
int nValue = GetTargetPath(); if (nValue == -1)
{
if (!RandomMove())
{
InitTarget();
m_NpcState = NPC_STANDING;
return m_sStandTime;
}
InitTarget();
m_NpcState = NPC_MOVING;
return 0;
}
else if (nValue == 0)
{
m_fSecForMetor = m_fSpeed_2;
IsNoPathFind(m_fSecForMetor);
}
m_NpcState = NPC_TRACING;
return m_sStandTime;
Sıradaki fonksiyon : NpcMoving aynı işlemi uygulayın;
Kod:
NpcMoveEnd(); m_NpcState = NPC_ATTACKING;
return 0;
Kod:
if (IsMovingEnd()) {
m_curx = m_fPrevX;
m_curz = m_fPrevZ;
if (GetX() < 0 || GetZ() < 0)
TRACE("Npc-NpcMoving-2 : nid=(%d, %s), x=%.2f, z=%.2f\n", GetID(), GetName().c_str(), GetX(), GetZ());
m_NpcState = NPC_STANDING;
return m_sStandTime;
}
Kod:
if ( (!m_bPathFlag && !StepMove()) || (m_bPathFlag && !StepNoPathMove()))
{
m_NpcState = NPC_STANDING;
return 0;
}
SendMoveResult(m_fPrevX, m_fPrevY, m_fPrevZ, (float)((m_fSecForRealMoveMetor) / ((double)m_sSpeed / 1000)));
return m_fSpeed_1;
Sıradaki fonksiyon, NpcStanding aynı işlemi uygulayın;
Kod:
if (pRoom != nullptr && pRoom->m_byStatus == 1)
{
m_NpcState = NPC_STANDING;
return m_sStandTime;
}
Kod:
if (RandomMove()) {
m_iAniFrameCount = 0;
m_NpcState = NPC_MOVING;
return m_sStandTime;
}
Fonksiyonun en sonki return değeri;
Sıradaki fonksiyon, Attack() aynı işlemi uygulayın; direk tüm fonksiyonu veriyorum. sizdekiyle return değerlerini güncelleyin yeter.
Kod:
try { if (isDead())
return -1;
int nRandom = 0, nPercent = 1000;
bool bTeleport = false;
if (isNonAttackingObject())
{
m_NpcState = NPC_STANDING;
InitTarget();
return 0;
}
if (GetProto()->m_byDirectAttack == 1)
return LongAndMagicAttack();
int nStandingTime = m_sStandTime;
auto result = IsCloseTarget(m_byAttackRange, AttackTypeMagic);
if (result == CloseTargetNotInRange)
{
m_sStepCount = 0;
m_byActionFlag = ATTACK_TO_TRACE;
m_NpcState = NPC_TRACING;
return m_sAttackDelay;
}
else if (result == CloseTargetInAttackRange)
{
if (GetProto()->m_byDirectAttack == 2)
return LongAndMagicAttack();
m_sStepCount = 0;
m_byActionFlag = ATTACK_TO_TRACE;
m_NpcState = NPC_TRACING;
return m_sAttackDelay;
}
else if (result == CloseTargetInvalid)
{
m_NpcState = NPC_STANDING;
InitTarget();
return 0;
}
int nDamage = 0;
uint16 nID = m_Target.id; // Target ì„ êµ¬í•œë‹¤.
// Targeting player
if (nID < NPC_BAND)
{
CUser * pUser = g_pMain->GetUserPtr(nID);
if (pUser == nullptr
|| pUser->isDead()
|| pUser->m_bInvisibilityType)
{
InitTarget();
m_NpcState = NPC_STANDING;
return 0;
}
// Don't attack GMs.
if (pUser->isGM())
{
InitTarget();
m_NpcState = NPC_MOVING;
return 0;
}
if (GetProto()->m_byMagicAttack == 4 || GetProto()->m_byMagicAttack == 5)
{
nRandom = myrand(1, 10000);
if (nRandom < nPercent)
{
CNpcMagicProcess::MagicPacket(MAGIC_EFFECTING, m_proto->m_iMagic1, GetID(), -1, int16(pUser->GetX()), int16(pUser->GetY()), int16(pUser->GetZ()));
//printf("AreaMagicAttack --- sid=%d, magicid=%d, name=%s\n", GetID(), m_proto->m_iMagic1, m_proto->m_strName.c_str());
return m_sAttackDelay + 1000;
}
}
else if (GetProto()->m_byMagicAttack == 2)
{
nRandom = myrand(1, 10000);
if (nRandom < nPercent)
{
CNpcMagicProcess::MagicPacket(MAGIC_EFFECTING, m_proto->m_iMagic1, GetID(), pUser->GetID());
// printf("LongAndMagicAttack --- sid=%d, tid=%d, magicid=%d, name=%s\n", GetID(), pUser->GetID(), m_proto->m_iMagic1, m_proto->m_strName.c_str());
return m_sAttackDelay;
}
}
SendAttackRequest(pUser->GetID());
}
else // Targeting NPC
{
CNpc * pNpc = g_pMain->GetNpcPtr(nID);
if (pNpc == nullptr
|| pNpc->isDead())
{
InitTarget();
m_NpcState = NPC_STANDING;
return 0;
}
if (isHealer()
&& !isHostileTo(pNpc))
{
m_NpcState = NPC_HEALING;
return 0;
}
SendAttackRequest(pNpc->GetID());
}
return m_sAttackDelay;
}
catch (...) {
GlobalError(__FILE__, __LINE__);
return 0;
}
}
Bunlarıda uyguladıktan sonra tıpki 1299 daki gibi hareket olayları çalışacaktır. Slot bozulamaları, donmaları vs durumlar ortadan kalkıyor.
Veritabanı kısmında yapacağınız işlem ise hız ve range olaylarını ayarlamak.
AttackRange : 2 - 5 arası olmalı. yaratığa göre ayarlamalısınız.
TrackingRange: 45 civarı
m_speed : 1300-1600 civarı ayarlarsanız sorun çıkmayacaktır. Bu değerleri sizlere vermiyorum. Kendiniz ayarlayın.
Yapmanız gereken son bir şey ise m_bSpeedAmount değeri Ai server de tutulmamakta. Bu yüzden aisocket aracılığı ile gameserver den m_bSpeedAmount bilgisini ai servere göndermeniz gerekiyor. Yoksa ice & lighting işlemi gerçekleşmez. Bu fonksiyonuda size bırakıyorum. 95% kısmını paylaşmış oldum. Gerisini getirirsiniz.
[/HIDE-REPLY]
İyi çalışmalar...