• Уважаемые гости и новички, приветствуем Вас на нашем форуме
    Здесь вы можете найти ответы практически на все свои вопросы о серии игр «Готика» (в том числе различных модах на нее), «Ведьмак», «Ризен», «Древние свитки», «Эра дракона» и о многих других играх. Можете также узнать свежие новости о разработке новых проектов, восхититься творчеством наших форумчан, либо самим показать, что вы умеете. Ну и наконец, можете обсудить общие увлечения или просто весело пообщаться с посетителями «Таверны».

    Чтобы получить возможность писать на форуме, оставьте сообщение в этой теме.
    Удачи!

Вопросы по скриптингу

MaGoth

★★★★★★★★★★★
Администратор
Регистрация
7 Янв 2003
Сообщения
19.367
Благодарности
7.815
Баллы
995
  • Первое сообщение
  • #1
Прежде чем задавать вопросы, ознакомьтесь с документацией..
1) Читать онлайн
2) Архив с офлайн-версией(chm) во вложении
 

Вложения

  • Vam_tutor.rar
    171,6 KB · Просмотры: 573
Последнее редактирование модератором:

Diego1987

★★★★★★★★★★★
Администратор
Регистрация
7 Апр 2008
Сообщения
17.134
Благодарности
7.554
Баллы
1.950
Уведомление
vadymg

Сообщение удалено из-за нарушения п.4.18 правил форума. На первый раз получаешь устное предупреждение.
 

vadymg

Участник форума
Регистрация
1 Мар 2013
Сообщения
11
Благодарности
0
Баллы
155
Всем привет!
Есть несколько вопросов по модостоению. Буду рад помощи ;)
1) Как поменять цену на конкретный товар у конкретного торговца? Например, чтобы в разных тавернах цена на пиво была разная.
2) Можно ли динамически менять TRADE_VALUE_MULTIPLIER?
3) Как пометить предмет, чтобы он оставался в инвентаре у торговца, но не отображался на панели торговли?
4) Как мне грамотно "отделить" zen файлы от оригинальной игры и запускать только в рамках мода?
5)После компиляции проекта в .mod, размещении его в \Data\ModVDF, создании mod.ini через Gothic Ini Writer, и попытке запуска мода через \System\GothicStarter_mod.exe запускается оригинальная Готика. Подозреваю, что проблема в mod.ini. Решил проблему копированием файлов Gothic.dat и ou.bin вместо оригинальных, но, понятно, это решение временное. Хотел бы попросить знатоков просмотреть мой ini файл.
[INFO]
Title=G2RM
Version=0.0.0.1
Authors=vadymg
Webpage=
Description=
Icon=
[FILES]
VDF=G2RM.mod
Game=Content\Gothic
FightAI=Content\Fight
Menu=System\Menu
Camera=System\Camera
Music=System\Music
SoundEffects=System\Sfx
ParticleEffects=System\ParticleFx
VisualEffects=System\VisualFx
OutputUnits=OU
[SETTINGS]
Player=PC_Hero
World=
[OPTIONS]
show_Info=0
show_InfoX=800
show_InfoY=7200
show_Version=1
show_VersionX=6500
show_VersionY=7200
show_Focus=1
show_FocusItm=1
show_FocusMob=0
show_FocusNpc=1
show_FocusBar=1
force_Subtitles=1
force_Parameters=
[OVERRIDES]
INTERNAL.extendedMenu=1
6) После попытки изменить отображаемую цену предмета, по-прежнему продолжает отображаться его фактическая цена. Т.е. вот такой вот вариант не работает. Почему?
instance ItMw_1h_Vlk_Dagger(C_Item)
{
name = "Кинжал";
mainflag = ITEM_KAT_NF;
flags = ITEM_SWD;
material = MAT_METAL;
value = Value_VLKDolch; //5
damageTotal = Damage_VLKDolch;
damagetype = DAM_EDGE; //Режущий
range = Range_VLKDolch;
cond_atr[2] = ATR_STRENGTH;
cond_value[2] = Condition_VLKDolch;
visual = "Itmw_005_1h_dagger_01.3DS";
description = "Обычное оружие простых горожан";
text[0] = name;
text[1] = NAME_Dam_Edge;
count[1] = damageTotal;
text[2] = NAME_Range;
count[2] = range;
text[3] = NAME_Str_needed;
count[3] = cond_value[2];
text[4] = NAME_OneHanded;
text[5] = NAME_Value;
count[5] = 100;
};
7) Подскажите, пожалуйста, наилучшую стратегию для реализации следующего сценария:
Все НПС, до знакомства с ГГ, именуются "Незнакомец", "Горожанин", "Торговец" и т.п. После знакомства отображается его нормальное имя.
8) В чем ошибка синтаксиса, не могу понять:
var_int = FloatToInt(IntToFloat(const_int) / const_float);
Пишет
Ошибка: Ожидается ')'
9) Как изменить логику сна? Не могу найти соответствующих функций...
10) Как сделать доступным инвентарь во время TA_Sit_Chair?

Diego1987,
Прошу прощения, я не знаю что это за кубики и зачем они нужны. Нажал из любопытства, а как удалить - тоже не знаю. Между прочим, Вы, как администратор, могли бы удалить только кубики, а не всё сообщение. Как-никак, я его долго писал и жду помощи.
 

ElderGamer


Модостроитель
Регистрация
16 Апр 2008
Сообщения
4.407
Благодарности
3.232
Баллы
525
1) Как поменять цену на конкретный товар у конкретного торговца? Например, чтобы в разных тавернах цена на пиво была разная.
2) Можно ли динамически менять TRADE_VALUE_MULTIPLIER?

Могу ошибаться, но, думаю, что нельзя так делать. Если только использовать костыли с разными инстанциями предметов одного вида (с разной ценой) и динамически их подменять в инвентаре.

3) Как пометить предмет, чтобы он оставался в инвентаре у торговца, но не отображался на панели торговли?

При торговле не отображается экипированное оружие, руны и доспехи. Но конкретные предметы можно на время торговли изымать из инвентаря торговца и возвращать их при выходе из режима диалога.

7) Подскажите, пожалуйста, наилучшую стратегию для реализации следующего сценария:
Все НПС, до знакомства с ГГ, именуются "Незнакомец", "Горожанин", "Торговец" и т.п. После знакомства отображается его нормальное имя.

Имя непися, прописанное в его инстанции, будет возвращаться каждый раз при инициализации локации (загрузка сохранения или вход в локацию). Для одного конкретного непися можно запомнить факт знакомства и подменять его имя в функции инициализации локации при состоявшемся знакомстве. Также можно создать непися-дублёра с другим именем в инстанции и подменять непися в после знакомства путём смены распорядка. Но оба этих способа вряд ли подойдут для массового применения. :confused:
 

Dimus

★★★★★★★★★
Супермодератор
Регистрация
19 Июл 2010
Сообщения
5.574
Благодарности
4.168
Баллы
915
Вопрос по реализации очистки инвентаря мага от рун в случае смерти от заморозки. Сейчас это происходит в функции ZS_MagicFreeze_Loop():
Код:
func int ZS_MagicFreeze_Loop()
{
    if(Npc_GetStateTime(self) > SPL_TIME_FREEZE)
    {
        B_StopMagicFreeze();
        return LOOP_END;
    };
    if(Npc_GetStateTime(self) != self.aivar[AIV_FreezeStateTime])
    {
        self.aivar[AIV_FreezeStateTime] = Npc_GetStateTime(self);
        if(self.attribute[ATR_HITPOINTS] > (self.attribute[ATR_HITPOINTS] - SPL_FREEZE_DAMAGE))
        {
            if((self.guild == GIL_FIREGOLEM) || (self.aivar[AIV_MM_REAL_ID] == ID_FIREWARAN) || (self.aivar[AIV_MM_REAL_ID] == ID_DRAGON_FIRE))
            {
                B_MagicHurtNpc(other,self,SPL_FREEZE_DAMAGE * 2);
                return LOOP_CONTINUE;
            };
            if((self.guild == GIL_ICEGOLEM) || (self.aivar[AIV_MM_REAL_ID] == ID_DRAGON_ICE))
            {
                B_MagicHurtNpc(other,self,SPL_FREEZE_DAMAGE / 2);
                return LOOP_CONTINUE;
            };
            B_MagicHurtNpc(other,self,SPL_FREEZE_DAMAGE);
        };
    };
    if(self.attribute[ATR_HITPOINTS] == 0)
    {
        B_ClearRuneInv(self);
    };
    return LOOP_CONTINUE;
};
Очистка от рун при выходе из цикла заморозки в функции ZS_MagicFreeze_End() не работает. Решение оказалось гораздо проще - досрочное прерывание цикла заморозки в случае смерти жертвы, тогда все очистки инвентаря отработают в функции ZS_Dead():
Код:
func int ZS_MagicFreeze_Loop()
{
    if((Npc_GetStateTime(self) > SPL_TIME_FREEZE) || (self.attribute[ATR_HITPOINTS] <= 0))
    {
        B_StopMagicFreeze();
        return LOOP_END;
    };
    if(Npc_GetStateTime(self) != self.aivar[AIV_FreezeStateTime])
    {
        self.aivar[AIV_FreezeStateTime] = Npc_GetStateTime(self);
        if(self.attribute[ATR_HITPOINTS] > (self.attribute[ATR_HITPOINTS] - SPL_FREEZE_DAMAGE))
        {
            if((self.guild == GIL_FIREGOLEM) || (self.aivar[AIV_MM_REAL_ID] == ID_FIREWARAN) || (self.aivar[AIV_MM_REAL_ID] == ID_DRAGON_FIRE))
            {
                B_MagicHurtNpc(other,self,SPL_FREEZE_DAMAGE * 2);
                return LOOP_CONTINUE;
            };
            if((self.guild == GIL_ICEGOLEM) || (self.aivar[AIV_MM_REAL_ID] == ID_DRAGON_ICE))
            {
                B_MagicHurtNpc(other,self,SPL_FREEZE_DAMAGE / 2);
                return LOOP_CONTINUE;
            };
            B_MagicHurtNpc(other,self,SPL_FREEZE_DAMAGE);
        };
    };
    return LOOP_CONTINUE;
};
 
Последнее редактирование:

Jr13San


Модостроитель
Регистрация
1 Апр 2010
Сообщения
449
Благодарности
266
Баллы
230
Подскажите, пожалуйста, наилучшую стратегию для реализации следующего сценария:
Все НПС, до знакомства с ГГ, именуются "Незнакомец", "Горожанин", "Торговец" и т.п. После знакомства отображается его нормальное имя.


Вот тебе небольшой примерчик в качестве подсказки:
Код:
func void rename_Gorn()
{
    //если ГГ познакомился с текущим персонажем, узнав его имя в одной из реплик диалога, то
    if (Npc_KnowsInfo(hero, DIA_Gorn_First) == TRUE)
    {
        //присваиваем НПС оригинальное имя
        self.name[0] = "Горн";
    }
    else//иначе, если ГГ не знаком с персонажем, то
    {
        //присваиваем НПС обобщённое имя
        self.name[0] = "Наёмник";
    };
};

//функция окончания диалога
func void ZS_Talk_End()
{
    //если персонаж, участвовавший в диалоге - это наёмник Горн, то
    if(Hlp_GetInstanceID(self) == Hlp_GetInstanceID(PC_Fighter))
    {
        rename_Gorn();//производим переименовку персонажа
    };
};


instance PC_Fighter(Npc_Default)
{
    rename_Gorn();//вызываем функцию переименовки персонажа
    npcType = npctype_friend;
    guild = GIL_SLD;
    level = 999;
    voice = 9;
    id = 3;
    flags = NPC_FLAG_IMMORTAL;
    attribute[ATR_STRENGTH] = 80;
    attribute[ATR_DEXTERITY] = 40;
    attribute[ATR_MANA_MAX] = 20;
    attribute[ATR_MANA] = 20;
    attribute[ATR_HITPOINTS_MAX] = 22;
    attribute[ATR_HITPOINTS] = 22;
    protection[PROT_FIRE] = 1000;
    Mdl_SetVisual (self, "HUMANS.MDS");
    Mdl_SetVisualBody (self, "hum_body_Naked0", 0, 3, "Hum_Head_Fighter", 13, 0, sld_armor_m);
    Mdl_ApplyOverlayMds (self, "Humans_Relaxed.mds");
    Npc_SetTalentSkill (self, NPC_TALENT_PICKPOCKET, 1);
    Npc_SetTalentValue (self, NPC_TALENT_PICKPOCKET, 60);
    Npc_SetTalentSkill (self, NPC_TALENT_SNEAK, 1);
    Npc_SetTalentSkill (self, NPC_TALENT_PICKLOCK, 1);
    Npc_SetTalentValue (self, NPC_TALENT_PICKLOCK, 60);
    Npc_SetTalentSkill (self, NPC_TALENT_1H, 2);
    Npc_SetTalentSkill (self, NPC_TALENT_2H, 2);
    fight_tactic = FAI_HUMAN_Strong;
    aivar[AIV_IMPORTANT] = TRUE;
    EquipItem (self, Gorns_Rache);
    CreateInvItems (self, ItFoWine, 5);
    CreateInvItems (self, ItFo_Potion_Health_03, 10);
    CreateInvItems (self, ItFo_Potion_Mana_01, 5);
    daily_routine = Rtn_Start_3;
};




//Диалог из Г1

instance DIA_Gorn_First(C_Info)
{
    npc = PC_Fighter;
    nr = 1;
    condition = Dia_Gorn_First_Condition;
    information = Dia_Gorn_First_Info;
    permanent = 0;
    important = 1;
};


func int Dia_Gorn_First_Condition()
{
    if (Kapitel < 3)
    {
        return 1;
    };
};

func void Dia_Gorn_First_Info()
{
    AI_Output (self, other, "DIA_Gorn_First_09_00");    //Эй. Новые лица.
    AI_Output (other, self, "DIA_Gorn_First_15_01");    //Ты кто?
    AI_Output (self, other, "DIA_Gorn_First_09_02");    //Я - Горн, наемник на службе у магов.
};

Написано в разброс, но если расставишь всё на свои места, то должно получится как надо.
Принцип прост. Как видим, наёмник-Горн начинает диалог с ГГ при их первой встрече, поэтому его имя поменяется сразу же после выхода из диалога с ним (см. изменённую функцию "ZS_Talk_End()").
Дальше, если сохраниться и вновь загрузить игру, то при загрузке сэйва произойдёт загрузка инстанции "PC_Fighter" и сработает функция "rename_Gorn()", поэтому имя персонажа будет изменено и присвоено по условиям этой функции.

Всё тоже самое можно сделать с помощью этих двух функций:
"Npc_SetKnowsPlayer()"
"Npc_KnowsPlayer()"
Подробности см. в справочнике по скриптам.

8) В чем ошибка синтаксиса, не могу понять:
var_int = FloatToInt(IntToFloat(const_int) / const_float);
Пишет
Ошибка: Ожидается ')'
Видимо такие вот вычисления с переменными типа float не поддерживаются скриптовой системой.

5) Отсутствует запись стартового Zen-уровня.
[SETTINGS]
Player=PC_Hero
World=
[OPTIONS]
 

ElderGamer


Модостроитель
Регистрация
16 Апр 2008
Сообщения
4.407
Благодарности
3.232
Баллы
525
Известный факт, что перемещение в домах неписей (Г1, Г2) с помощью прыжков или стрейфинга не вызывает пробуждения спящих неписей. Это же справедливо и для движения задом-наперёд. Причина в том, что в этих случаях движок не гененрирует посылку восприятия "тихих звуков" PERC_ASSESSQUIETSOUND. В случае прыжков и движения задом-наперёд можно отследить состояния тела (BS_WALK, BS_RUN и BS_JUMP) и производить посылку восприятия из циклической функции. Но в случае стрейфинга этот способ не помогает. Состояние тела в режиме стрейфинга определяется, как стояние (BS_STAND). Есть ли у кого идеи, как можно отследить режим стрейфинга?

Также есть такое дело, что избитый в чужом доме ГГ перестаёт интересовать окружающих неписей. Хозяин помещения спокойно ложится спать или идёт по своим делам, забывая, что вор остался в его доме. Возможно, кто-то пытался уже это исправить. Есть ли в каких-то модах готовые решения этой недоработки?
 
Последнее редактирование:

Dimus

★★★★★★★★★
Супермодератор
Регистрация
19 Июл 2010
Сообщения
5.574
Благодарности
4.168
Баллы
915
Также хотелось бы исправить и следующие недоработки ИИ:
- Все NPC (даже побитый) не считают преступлением избиение NPC, находящегося в состоянии заморозки. В лучшем случае они требуют от ГГ убрать оружие или магию. Следовательно, за это не надо платить штрафы.
- Возможность безнаказанно избивать дружественных NPC по методу: удар - предупреждение "Эй! Осторожнее!" - обращение ГГ к NPC (оба убирают оружие). Можно повторять этот цикл до отправки NPC в нокаут.
 

Хелдар

Участник форума
Регистрация
3 Июл 2012
Сообщения
2.450
Благодарности
780
Баллы
375
- Возможность безнаказанно избивать дружественных NPC по методу: удар - предупреждение "Эй! Осторожнее!" - обращение ГГ к NPC (оба убирают оружие). Можно повторять этот цикл до отправки NPC в нокаут.
Это ж каким, черт возьми, нужно быть жутким манчкином, чтобы таким маяться - я б вот в жизни не додумался...
 

Beowulf

Участник форума
Регистрация
21 Ноя 2010
Сообщения
1.940
Благодарности
1.454
Баллы
465

Leonion

Участник форума
Регистрация
31 Мар 2008
Сообщения
249
Благодарности
154
Баллы
195
Мне кажется, или порой скрипты в готике ведут себя рандомным образом?

В b_enter_newworld в 2 разных местах прописано:

В первом месте:
Wld_InsertNpc(PC_Fighter_NW_nach_DJG,"BIGFARM");
if ((HurrayICanHire == TRUE) && (NOMORESPOILEDFOOD == TRUE) && (NiclasGoesHunting == TRUE) && (FarimRecruitedDT == TRUE))
{
B_StartOtherRoutine(PC_Fighter_NW_nach_DJG,"VisitsDTTower");
};
Вставили, поменяли рутину - и это работает.

Во втором месте (если кратко, просто такое расписано для 6 персонажей):
if((ThorusPartyInsertedNW == FALSE) && (ThorusPartyEscapesAW == TRUE))
{
Wld_InsertNpc(vlk_6026_miguel,"NW_TROLLAREA_PORTAL_KDWWAIT_06");
B_StartOtherRoutine(MIGUEL_NW,"NearPortal");
CreateInvItems(MIGUEL_NW,ItAr_BDT_M,1);
Npc_RemoveInvItems(MIGUEL_NW,ITAR_Vlk_M,1);
AI_EquipBestArmor(MIGUEL_NW);
ThorusPartyInsertedNW = TRUE;
};
То же самое - вставили, поменяли рутину, но в этот раз не работает.
Причем не работает абсолютно ничего, кроме вставление. НПС вставляется, но ни его рутина, ни его инвентарь не меняется.
Причем на "обрезание" скрипта не сослаться: вставление-смена рутины прописаны по очереди для 6 НПС, но все вставления работают, а все смены рутины - нет.
Правописание сверял, в нпс_глобалс неписи прописаны.

В одном и том же диалоге (с Бенгаром):
CreateInvItems(Pardos_NW,ItAr_SLD_M,1);
Npc_RemoveInvItems(Pardos_NW,ITAR_Prisoner,1);
AI_EquipBestArmor(Pardos_NW);
CreateInvItems(Pardos_NW,ItMw_SCHWERT4,1);
Npc_RemoveInvItems(Pardos_NW,ItMw_2H_Axe_L_01,1);
AI_EquipBestMeleeWeapon(Pardos_NW);

CreateInvItems(Bengar,ItAr_Sekbed,1);
Npc_RemoveInvItems(Bengar,ITAR_Bau_M,1);
AI_EquipBestArmor(Bengar);

Итог: Бенгар переодевается, а у Пардоса лишь вещи в ивентаре появляются, но не экипируются.
По статам проверял: экипироваться могут, требования соответствуют.

В одном и том же диалоге:

B_StartOtherRoutine(TalbinNW,"DTBeforeTrollHunt");
AI_Teleport(TalbinNW,"NW_DT_HUNT_TROLL_06");
CreateInvItems(TalbinNW,ItMw_Morgenstern,1);
AI_EquipBestMeleeWeapon(TalbinNW);
if (JanRecruitedDT == TRUE)
{
CreateInvItems(TalbinNW,ITAR_DJG_L,1);
AI_EquipBestArmor(TalbinNW);
};

Npc_ExchangeRoutine(self,"DTBeforeTrollHunt");
CreateInvItems(self,ItMw_Morgenstern,1);
AI_EquipBestMeleeWeapon(self);
if (JanRecruitedDT == TRUE)
{
CreateInvItems(self,ITAR_DJG_L,1);
AI_EquipBestArmor(self);
};

Итог: Тальбин переоделся, сменил оружие, сменил рутину, в то время как self (Никлас) не сделал ничего из этого. У него даже в инвентаре вещи не появились. Причем я могу понять, если вдруг не сработает ссылка на какого-то далекого НПС (мало ли, где-то с правописанием ошибся или что-то в этом роде), но чтобы не работала ссылка на self...

Опять же сравнивая с предыдущими переодеваниями:
CreateInvItems(MIL_321_Rangar,ITAR_Bloodwyn_Addon,1);
AI_EquipBestArmor(Rangar);
- не работает (вставление работает, переодевание не работает), хотя по статам ITAR_Bloodwyn_Addon гораздо лучше доспехов ополчения (старой экипировки).
Точно такая же схема не работает больше нигде (переодевание у меня много где распихано, в т.ч. массовый скрипт на около 25 переодеваний, но везде работает лишь вставление предмета), кроме Тальбина из 3-го примера, который охотно переоделся и теперь щеголяет в новых доспехах.

Вот хоть убейте, не вижу разницы между
CreateInvItems(TalbinNW,ITAR_DJG_L,1);
AI_EquipBestArmor(TalbinNW);

и

CreateInvItems(Malak,ITAR_SLD_M_V5,1);
AI_EquipBestArmor(Malak);

Во всех тех случаях из скрипта статы позволяют и новые доспехи лучше старых.
Кроме того, там же рядышком идет смена оружия (чередуются: сменить доспехи НПС1, сменить оружие НПС1, сменить доспехи НПС2, сменить оружие НПС2) так вот смена оружия работает на отл. (т.е. функция отрабатывается игрой), а переодевание - кукиш.

Кто-нибудь может пояснить, откуда берутся такие чудеса и как от них можно избавиться?
 

Phantom95

Участник форума
Регистрация
31 Июл 2014
Сообщения
2.227
Благодарности
1.910
Баллы
370
Как открыть скрипты OU из папки Cutscene в первой готике?
 

Dimus

★★★★★★★★★
Супермодератор
Регистрация
19 Июл 2010
Сообщения
5.574
Благодарности
4.168
Баллы
915
@ Leonion:
Попробуй заменить функцию AI_EquipBestArmor(c_npc self) на AI_EquipArmor(c_npc self, int armor).

Чуть не забыл: у тебя в инстанциях доспехов не прописаны требования к силе / ловкости / выносливости / жизни / мане / интеллекту и т.п.?
 
Последнее редактирование:

Leonion

Участник форума
Регистрация
31 Мар 2008
Сообщения
249
Благодарности
154
Баллы
195
@ Leonion:
Попробуй заменить функцию AI_EquipBestArmor(c_npc self) на AI_EquipArmor(c_npc self, int armor).

Чуть не забыл: у тебя в инстанциях доспехов не прописаны требования к силе / ловкости / выносливости / жизни / мане / интеллекту и т.п.?

AI_EquipArmor пробовал, все так же не хотят переодеваться.
Требования должны быть ("Возвращение" мучаю), но у НПС достаточно статов.
Пробовал уже все и в разном порядке (дал-отнял-одел, отнял-дал-одел, дал-одел-отнял, раздел-отнял-дал-одел, раздел-дал-отнял-одел), все впустую.
Пробовал через стандартные идентификаторы НПС, пробовал через те, что в NPC_Globals - бестолку.
Единственное, что разобрался с переходом между мирами - оказалось, что там работают только стандартные идентификаторы, и что это из-за использования глобаловских у меня кроме вставки ничего не работало (в 1 примере).

В конечном итоге со стандартным (выдал новые доспехи, отнял старые, сделал AI_EquipBestArmor или AI_EquipArmor) сработало только так: выполнить функцию => перейти в другой мир => вернуться => сохраниться => загрузиться.
Жесть.

Попробовал еще прописать вместо AI_EquipBestArmor это:
B_SetNpcVisual(Mika,MALE,"Hum_Head_FatBald",Face_L_Scatty,BodyTex_L,ITAR_Bloodwyn_Addon);
Но оно срабатывает только после сохранения-загрузки.


В общем почти все осталось под вопросом: не понятно, почему Тальбин экипируется, а остальные нет, и почему Пардос не хочет брыть в руки оружие, в то время как во всех остальных местах функции по смене оружия работают, как конфетки.
 

Leonion

Участник форума
Регистрация
31 Мар 2008
Сообщения
249
Благодарности
154
Баллы
195
Кхм...
В общем, как я понял, неписи [обычно] не меняют броню, если чем-то заняты.
Сначала я пробовал вызывать функцию смены брони когда 2 нужных мне непися шли мимо меня или делали что-то еще - не работало.
Затем попробовал их остановить, обнажив оружие, а потом убрав, в рез-те чего оба встали и стали пялиться на меня: один с оружием в руках, другой без. Если вызывать функцию в этот момент, оба радостно переодеваются (причем обе функции смены брони работают - и AI_EquipBestArmor, и AI_EquipArmor).
Далее: когда функцию прописал следующим образом:
Npc_ClearAIQueue(Rangar);
Npc_RemoveInvItems(Rangar,ITAR_Mil_L,1);
CreateInvItems(Rangar,ITAR_DJG_L_V5,1);
AI_EquipArmor(Rangar,ITAR_DJG_L_V5);
....то неписи стали в любом случае менять броню, даже если в этот момент шли.

Проблема в том, что мне надо заменить броню у пары десятков неписей, находящихся в момент диалога на другом конце карты. А если неписи вне зоны видимости, то вышеупомянутый трюк с Npc_ClearAIQueue уже не работает.

Может кто-нибудь знает, как можно (если вообще можно) сымитировать состояние пассивности у непися, находящегося на другом конце карты? :)
Мне пока идеи кроме двойного телепорта (телепортировать куда-нибудь поблизости от ГГ, но так чтоб он не видел, выполнить функцию смены брони, телепортировать назад) в голову не приходят...((

P.S. Сорри за даблпостинг, просто суть вопроса немного поменялась. посему решил не объединять.

P.S.2. Походу, идея с двойным телепортом не подходит, ибо неписи что-то не горят желанием повторно куда-то телепортироваться.
 
Последнее редактирование:

Myxomop

Почетный форумчанин
Регистрация
28 Май 2005
Сообщения
3.239
Благодарности
2.581
Баллы
455
Попробуй написать для нужных НПЦ собственные TA_ распорядки и в теле функции распорядка менять броню. В нужный момент выставь для всех нужных НПЦ распорядки со сменой брони.
 

Leonion

Участник форума
Регистрация
31 Мар 2008
Сообщения
249
Благодарности
154
Баллы
195
Попробуй написать для нужных НПЦ собственные TA_ распорядки и в теле функции распорядка менять броню. В нужный момент выставь для всех нужных НПЦ распорядки со сменой брони.

Спасибо за совет, помогло.)

И у меня, надеюсь, последний вопрос, с которым мне никак не удается разобраться.
Я попытался в скриптах создать еще одну руну телепорта в нужное мне место.
1) Instance скопировал с руны телепорта в таверну, только поменял названия руны и SPL_
2) В Spell_ProcessMana записи сделал по той же схеме.
3) Spell_Logic и Spell_Cast - то же самое. Менял лишь TeleportTaverne на TeleportDTower и координаты места телепортации.
4)В константах увеличил MAX_SPELL на 1 (со 103 до 104), прописал свое под номером 103.
Заменил spellFxInstanceNames[103] на spellFxInstanceNames[104], внизу массива добавил, соответственно, "Teleport".
Заменил spellFxAniLetters[103] на spellFxAniLetters[104], внизу добавил "HEA".

Больше не вижу, что еще можно добавить/заменить.
При этом игра вылетает при попытке взять в руки руну (т.е. я ей назначаю. скажем, клавишу 4, выхожу из инвентаря. жму на 4 - и игра крашится).
Может в каком-то еще файле нужно было что-то менять?
 

Myxomop

Почетный форумчанин
Регистрация
28 Май 2005
Сообщения
3.239
Благодарности
2.581
Баллы
455
На сколько я помню, количество спеллов наглухо зашито в движок и его нельзя увеличивать, то же самое касается массива aivar и гильдий.
Советую вернуть spellFxInstanceNames в прежнее количество 100 и использовать для собственных спеллов только зарезервированные константы. По крайней мере в своем моде для телепортов я использовал константы с 7 по 17 и все они работали.
 

Jr13San


Модостроитель
Регистрация
1 Апр 2010
Сообщения
449
Благодарности
266
Баллы
230
Известный факт, что перемещение в домах неписей (Г1, Г2) с помощью прыжков или стрейфинга не вызывает пробуждения спящих неписей. Это же справедливо и для движения задом-наперёд. Причина в том, что в этих случаях движок не гененрирует посылку восприятия "тихих звуков" PERC_ASSESSQUIETSOUND. В случае прыжков и движения задом-наперёд можно отследить состояния тела (BS_WALK, BS_RUN и BS_JUMP) и производить посылку восприятия из циклической функции. Но в случае стрейфинга этот способ не помогает. Состояние тела в режиме стрейфинга определяется, как стояние (BS_STAND). Есть ли у кого идеи, как можно отследить режим стрейфинга?

Код:
func void B_AssessQuietSound()
{
    Print("AssessQuietSound");//вывод сообщения о реакции (в режиме теста)

    if(!Hlp_IsValidNpc(other))
    {
        return;
    };
    if(Npc_GetHeightToNpc(self,other) > PERC_DIST_HEIGHT)
    {
        return;
    };
    if((Wld_GetPlayerPortalGuild() >= GIL_NONE) && (Npc_GetHeightToNpc(self,other) > PERC_DIST_INDOOR_HEIGHT))
    {
        return;
    };
    if(B_AssessEnterRoom())
    {
        return;
    };
    if(C_NpcIsGateGuard(self))
    {
        return;
    };
    if((Npc_GetAttitude(self,other) != ATT_HOSTILE) && (Npc_CheckInfo(self,1) == FALSE))
    {
        return;
    };
    if((Npc_GetAttitude(self,other) == ATT_HOSTILE) && ((self.aivar[AIV_EnemyOverride] == TRUE) || (C_PlayerIsFakeBandit(self,other) && (self.guild == GIL_BDT))))
    {
        return;
    };
    if(Npc_CanSeeSource(self))
    {
        return;
    };
    Npc_ClearAIQueue(self);
    B_ClearPerceptions(self);
    AI_StartState(self,ZS_ObservePlayer,1,"");
};

Код:
func void B_AssessPortalCollision()
{
    //other - вошедший
    //self - свидетель
    //owner - владелец
  
    var C_NPC owner;
  
    //находим владельца помещения
    owner = Npc_GetPortalOwner(other);
  
    //и посылаем ему пассивное восприятие
    Npc_SendPassivePerc(self,PERC_ASSESSQUIETSOUND,owner,other);

  
    var int formerportalguild;
    formerportalguild = Wld_GetFormerPlayerPortalGuild();
    if(B_AssessEnterRoom())
    {
        return;
    };
    if(!Npc_CanSeeNpc(self,other) && (C_BodyStateContains(other,BS_SNEAK) || C_BodyStateContains(other,BS_STAND)))
    {
        return;
    };
    Npc_PerceiveAll(self);
    if(Wld_DetectNpcEx(self,-1,ZS_ClearRoom,-1,FALSE))
    {
        return;
    };
    if((self.guild == formerportalguild) || (Wld_GetGuildAttitude(self.guild,formerportalguild) == ATT_FRIENDLY))
    {
        if((Wld_GetGuildAttitude(self.guild,other.guild) == ATT_FRIENDLY) || (Npc_IsPlayer(other) && (self.npcType == NPCTYPE_FRIEND)))
        {
            return;
        };
        if(self.guild == GIL_NONE)
        {
            return;
        };
        if(((formerportalguild == GIL_MIL) || (formerportalguild == GIL_SLD)) && (Wld_GetGuildAttitude(self.guild,formerportalguild) == ATT_FRIENDLY))
        {
            B_Attack(self,other,AR_LeftPortalRoom,0);
            return;
        }
        else
        {
            self.aivar[AIV_SeenLeftRoom] = TRUE;
            Npc_ClearAIQueue(self);
            B_ClearPerceptions(self);
            AI_StartState(self,ZS_ObservePlayer,0,"");
            return;
        };
    };
};
 

Leonion

Участник форума
Регистрация
31 Мар 2008
Сообщения
249
Благодарности
154
Баллы
195
На сколько я помню, количество спеллов наглухо зашито в движок и его нельзя увеличивать, то же самое касается массива aivar и гильдий.
Советую вернуть spellFxInstanceNames в прежнее количество 100 и использовать для собственных спеллов только зарезервированные константы. По крайней мере в своем моде для телепортов я использовал константы с 7 по 17 и все они работали.

Точно?
Просто здесь писали, что спеллы лимитированы лишь числом 255:
https://worldofplayers.ru/threads/13198/page-32#post-540590

Попробовал сейчас предыд. спеллы.
102-ой (const int = 101) работает, 103-ий (бывший до меня) вылетает.
Там тоже xterm не мог дальше 102 спеллов уйти (собсно, я сейчас делаю мод поверх его).

/////
Ура, нашел решение.) Просто искал по 103, а оказалось, надо было искать по 102 (ибо пред. человек тоже не прописал нормально последний спелл).
Нужно еще в двух местах сделать замены:
1) var int player_talent_runes[102]; => var int player_talent_runes[104];
2) массив const string TXT_SPELLS[102] => const string TXT_SPELLS[104]
+ Вписать в массиве имена.

Теперь все работает.
Спасибо, что навели на мысль.)
 
Сверху Снизу