Как читать AI.obj от C1?

space2pacman

Постоялец
Местный
Сообщения
303
Розыгрыши
0
Репутация
252
Реакции
239
Баллы
1 038
Привет

Декомпилировал ai.obj от C1 этим инструментом

Правильно ли я понимаю

gremlin наследует warrior_passive
C-подобный:
class gremlin : warrior_passive
{
}

warrior_passive наследует warrior
C-подобный:
class warrior_passive : warrior
{
}

И сам warrior
C-подобный:
class warrior : default_npc
{
parameter:
    float Attack_DecayRatio = 6.6;
    float UseSkill_DecayRatio = 66000.0;
    float Attack_BoostValue = 300.0;
    float UseSkill_BoostValue = 100000.0;
    int MoveAroundSocial = 0;
    int ShoutMsg1 = 0;
    int ShoutMsg2 = 0;
    int ShoutMsg3 = 0;
    int ShoutMsg4 = 0;

handler:
    EventHandler NO_DESIRE()
    {
        AddMoveAroundDesire(5, 5);
    }

    EventHandler CREATED()
    {
        if (ShoutMsg1 > 0)
        {
            Shout(MakeFString(ShoutMsg1, "", "", "", "", ""));
        }

        if (MoveAroundSocial > 0 || ShoutMsg2 > 0 || ShoutMsg3 > 0)
        {
            AddTimerEx(1001, 10000);
        }
    }

    EventHandler TIMER_FIRED_EX(timer_id)
    {
        if (timer_id == 1001)
        {
            if (myself.p_state == PSTATE_MOVE_AROUND || myself.p_state == PSTATE_DO_NOTHING || myself.p_state == PSTATE_MOVE_TO_WAY_POINT)
            {
                if (MoveAroundSocial > 0 && Rand(100) < 20)
                {
                    AddEffectActionDesire(myself.sm, 1, MoveAroundSocial * 1000 / 30, 50);
                }

                if (ShoutMsg2 > 0 && Rand(1000) < 17)
                {
                    Shout(MakeFString(ShoutMsg2, "", "", "", "", ""));
                }
            }
            else if (myself.p_state == PSTATE_ATTACK)
            {
                if (ShoutMsg3 > 0 && Rand(100) < 10)
                {
                    Shout(MakeFString(ShoutMsg3, "", "", "", "", ""));
                }
            }

            AddTimerEx(1001, 10000);
        }

        super;
    }

    EventHandler ATTACKED(attacker, damage)
    {
        if (attacker.is_pc != 0 || IsInCategory(@summon_npc_group, attacker.class_id))
        {
            AddAttackDesire(attacker, @AMT_MOVE_TO_TARGET, damage / myself.sm.max_hp / 0.05 * 100);
        }
    }

    EventHandler CLAN_ATTACKED(attacker, damage)
    {
        if (GetLifeTime() > 7)
        {
            if (attacker.is_pc != 0 || IsInCategory(@summon_npc_group, attacker.class_id))
            {
                AddAttackDesire(attacker, @AMT_MOVE_TO_TARGET, damage / myself.sm.max_hp / 0.05 * 30);
            }
        }
    }

    EventHandler SEE_SPELL(speller, skill_name_id)
    {
        if (Skill_GetEffectPoint(skill_name_id) > 0)
        {
            AddAttackDesire(speller, @AMT_MOVE_TO_TARGET, Skill_GetEffectPoint(skill_name_id) / myself.sm.max_hp / 0.05 * 150);
        }
    }

    EventHandler DESIRE_MANIPULATION(speller, desire)
    {
        MakeAttackEvent(speller, desire, 0);
    }

    EventHandler MY_DYING()
    {
        if (ShoutMsg4 > 0 && Rand(100) < 30)
        {
            Shout(MakeFString(ShoutMsg4, "", "", "", "", ""));
        }
    }
}

Откуда берутся AddMoveAroundDesire и прочее? И есть ли какой-то AI Viewer для C1?
 

Привет

Декомпилировал ai.obj от C1 этим инструментом

Правильно ли я понимаю

gremlin наследует warrior_passive
C-подобный:
class gremlin : warrior_passive
{
}

warrior_passive наследует warrior
C-подобный:
class warrior_passive : warrior
{
}

И сам warrior
C-подобный:
class warrior : default_npc
{
parameter:
    float Attack_DecayRatio = 6.6;
    float UseSkill_DecayRatio = 66000.0;
    float Attack_BoostValue = 300.0;
    float UseSkill_BoostValue = 100000.0;
    int MoveAroundSocial = 0;
    int ShoutMsg1 = 0;
    int ShoutMsg2 = 0;
    int ShoutMsg3 = 0;
    int ShoutMsg4 = 0;

handler:
    EventHandler NO_DESIRE()
    {
        AddMoveAroundDesire(5, 5);
    }

    EventHandler CREATED()
    {
        if (ShoutMsg1 > 0)
        {
            Shout(MakeFString(ShoutMsg1, "", "", "", "", ""));
        }

        if (MoveAroundSocial > 0 || ShoutMsg2 > 0 || ShoutMsg3 > 0)
        {
            AddTimerEx(1001, 10000);
        }
    }

    EventHandler TIMER_FIRED_EX(timer_id)
    {
        if (timer_id == 1001)
        {
            if (myself.p_state == PSTATE_MOVE_AROUND || myself.p_state == PSTATE_DO_NOTHING || myself.p_state == PSTATE_MOVE_TO_WAY_POINT)
            {
                if (MoveAroundSocial > 0 && Rand(100) < 20)
                {
                    AddEffectActionDesire(myself.sm, 1, MoveAroundSocial * 1000 / 30, 50);
                }

                if (ShoutMsg2 > 0 && Rand(1000) < 17)
                {
                    Shout(MakeFString(ShoutMsg2, "", "", "", "", ""));
                }
            }
            else if (myself.p_state == PSTATE_ATTACK)
            {
                if (ShoutMsg3 > 0 && Rand(100) < 10)
                {
                    Shout(MakeFString(ShoutMsg3, "", "", "", "", ""));
                }
            }

            AddTimerEx(1001, 10000);
        }

        super;
    }

    EventHandler ATTACKED(attacker, damage)
    {
        if (attacker.is_pc != 0 || IsInCategory(@summon_npc_group, attacker.class_id))
        {
            AddAttackDesire(attacker, @AMT_MOVE_TO_TARGET, damage / myself.sm.max_hp / 0.05 * 100);
        }
    }

    EventHandler CLAN_ATTACKED(attacker, damage)
    {
        if (GetLifeTime() > 7)
        {
            if (attacker.is_pc != 0 || IsInCategory(@summon_npc_group, attacker.class_id))
            {
                AddAttackDesire(attacker, @AMT_MOVE_TO_TARGET, damage / myself.sm.max_hp / 0.05 * 30);
            }
        }
    }

    EventHandler SEE_SPELL(speller, skill_name_id)
    {
        if (Skill_GetEffectPoint(skill_name_id) > 0)
        {
            AddAttackDesire(speller, @AMT_MOVE_TO_TARGET, Skill_GetEffectPoint(skill_name_id) / myself.sm.max_hp / 0.05 * 150);
        }
    }

    EventHandler DESIRE_MANIPULATION(speller, desire)
    {
        MakeAttackEvent(speller, desire, 0);
    }

    EventHandler MY_DYING()
    {
        if (ShoutMsg4 > 0 && Rand(100) < 30)
        {
            Shout(MakeFString(ShoutMsg4, "", "", "", "", ""));
        }
    }
}

Откуда берутся AddMoveAroundDesire и прочее? И есть ли какой-то AI Viewer для C1?
они дальше в NASC обращаются.

Если по простому - NASC это java ядро (gameserver.jar), а .obj это папка /scripts/ в датапаке
 
А есть какой-то гайд по методом, какие есть, как работаю?
Я не думаю, что кто-то когда-то документировал NASC. Там только функций для скриптов более 1000(в ХФ), + еще огромный массив кода, связывающего эти функции с остальным сервером.

В слитых данных можно найти pdb для NASC64.exe, и часть функций отреверсить.
 
Откуда берутся AddMoveAroundDesire и прочее? И есть ли какой-то AI Viewer для C1?
Метод cnpc класса (L2Npc) как пример от грации финал (список)

А есть какой-то гайд по методом, какие есть, как работаю?
Такая вот статейка попадалась, может будет полезна
 
Привет

Декомпилировал ai.obj от C1 этим инструментом

Правильно ли я понимаю

gremlin наследует warrior_passive
C-подобный:
class gremlin : warrior_passive
{
}

warrior_passive наследует warrior
C-подобный:
class warrior_passive : warrior
{
}

И сам warrior
C-подобный:
class warrior : default_npc
{
parameter:
    float Attack_DecayRatio = 6.6;
    float UseSkill_DecayRatio = 66000.0;
    float Attack_BoostValue = 300.0;
    float UseSkill_BoostValue = 100000.0;
    int MoveAroundSocial = 0;
    int ShoutMsg1 = 0;
    int ShoutMsg2 = 0;
    int ShoutMsg3 = 0;
    int ShoutMsg4 = 0;

handler:
    EventHandler NO_DESIRE()
    {
        AddMoveAroundDesire(5, 5);
    }

    EventHandler CREATED()
    {
        if (ShoutMsg1 > 0)
        {
            Shout(MakeFString(ShoutMsg1, "", "", "", "", ""));
        }

        if (MoveAroundSocial > 0 || ShoutMsg2 > 0 || ShoutMsg3 > 0)
        {
            AddTimerEx(1001, 10000);
        }
    }

    EventHandler TIMER_FIRED_EX(timer_id)
    {
        if (timer_id == 1001)
        {
            if (myself.p_state == PSTATE_MOVE_AROUND || myself.p_state == PSTATE_DO_NOTHING || myself.p_state == PSTATE_MOVE_TO_WAY_POINT)
            {
                if (MoveAroundSocial > 0 && Rand(100) < 20)
                {
                    AddEffectActionDesire(myself.sm, 1, MoveAroundSocial * 1000 / 30, 50);
                }

                if (ShoutMsg2 > 0 && Rand(1000) < 17)
                {
                    Shout(MakeFString(ShoutMsg2, "", "", "", "", ""));
                }
            }
            else if (myself.p_state == PSTATE_ATTACK)
            {
                if (ShoutMsg3 > 0 && Rand(100) < 10)
                {
                    Shout(MakeFString(ShoutMsg3, "", "", "", "", ""));
                }
            }

            AddTimerEx(1001, 10000);
        }

        super;
    }

    EventHandler ATTACKED(attacker, damage)
    {
        if (attacker.is_pc != 0 || IsInCategory(@summon_npc_group, attacker.class_id))
        {
            AddAttackDesire(attacker, @AMT_MOVE_TO_TARGET, damage / myself.sm.max_hp / 0.05 * 100);
        }
    }

    EventHandler CLAN_ATTACKED(attacker, damage)
    {
        if (GetLifeTime() > 7)
        {
            if (attacker.is_pc != 0 || IsInCategory(@summon_npc_group, attacker.class_id))
            {
                AddAttackDesire(attacker, @AMT_MOVE_TO_TARGET, damage / myself.sm.max_hp / 0.05 * 30);
            }
        }
    }

    EventHandler SEE_SPELL(speller, skill_name_id)
    {
        if (Skill_GetEffectPoint(skill_name_id) > 0)
        {
            AddAttackDesire(speller, @AMT_MOVE_TO_TARGET, Skill_GetEffectPoint(skill_name_id) / myself.sm.max_hp / 0.05 * 150);
        }
    }

    EventHandler DESIRE_MANIPULATION(speller, desire)
    {
        MakeAttackEvent(speller, desire, 0);
    }

    EventHandler MY_DYING()
    {
        if (ShoutMsg4 > 0 && Rand(100) < 30)
        {
            Shout(MakeFString(ShoutMsg4, "", "", "", "", ""));
        }
    }
}

Откуда берутся AddMoveAroundDesire и прочее? И есть ли какой-то AI Viewer для C1?
В l2npc.exe сервере все эти функции реализованы. Можете взять nasc64.pdb и посмотреть их(от 162 протокола)
 
Назад
Сверху