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

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

Не стесняюсь спросить....

N1kX


Модостроитель
Регистрация
13 Ноя 2009
Сообщения
6.129
Благодарности
5.626
Баллы
910
Это все хорошо, но меня интересовал вопрос, как быстро сделать хороший альфа-канал (сам нашел ответ)
Photoshop
Создаем пустой альфа-канал в channels
Выбираем из 3-х цветов тот, где лучше всего видно очертания (R/G/B)
Дальше select-color range
Выделяем нужный цвет, настраивая Fuzziness
Выделяем созданный альфа-канал в channels
Берем кисть белого цвета-макс радиус и жесткость, окрашиваем
Если окрасилось то что нужно, сохраняем картинку
Если есть ихлишки
select-inversed
кисть черного цвета по другой выделенной области, сохраняем картинку с норм альфа-каналом.
 

nameluxor

Участник форума
Регистрация
19 Янв 2019
Сообщения
13
Благодарности
2
Баллы
100
Сам ответа не нашел, по этому пишу сюда. В стандартных скриптах используются две ф-ции Npc_GetBodyState и с битными флагами c_bodystatecontains. В туторе по скриптам написано что Npc_GetBodyState всегда дает отрицательный результат. Я решил протестировать и в циклическом триггере приписал проверки с выводом на экран,
проверял я состояния BS_DIVE, BS_SWIM, BS_HIT, BS_PARADE.
Daedalus:
if(Npc_GetBodyState(hero) == BS_PARADE)

{

    PrintScreen(" == BS_PARADE",-1,10,FONT_SCREEN,2);

};

if((Npc_GetBodyState(hero) & BS_PARADE) == BS_PARADE)

{

    PrintScreen(" & BS_PARADE",-1,20,FONT_SCREEN,2);

};

if(c_bodystatecontains(hero,BS_PARADE))

{

    PrintScreen("(hero,BS_PARADE)",-1,30,FONT_SCREEN,2);

};
Ну или как-то так(я точно не помню). Суть в том, что отрабатывало все одинаково, по крайней мере с BS_DIVE, BS_SWIM, BS_HIT, BS_PARADE. Не пойму в чем подвох, почему в скриптах не рекомендуют стандартную ф-цию Npc_GetBodyState?
 
Последнее редактирование модератором:

MEG@VOLT

★★★★★★★★★
ТехАдмин
Регистрация
24 Мар 2006
Сообщения
9.860
Благодарности
6.740
Баллы
1.625
nameluxor,
В туторе по скриптам написано что Npc_GetBodyState всегда дает отрицательный результат
Где?
Не пойму в чем подвох
ответ
Ну или как-то так(я точно не помню)
почему в скриптах не рекомендуют стандартную ф-цию Npc_GetBodyState?
Кто?
ЗЫ. в следующий раз, пожалуйста, обрамляй код,
1587217453327.png
 

nameluxor

Участник форума
Регистрация
19 Янв 2019
Сообщения
13
Благодарности
2
Баллы
100
C++:
func int C_BodyStateContains(var c_npc slf,var int bodystate)
{
// Примечание автора: Руки прочь от этой формулы!!! Я знаю точно что я делаю! (Мое примечание: с точки зрения логического анализа формула неправильна).
// если фактическое состояние тела НПС без учета допфлагов равно запрошенному состоянию без учета допфлагов
if((Npc_GetBodyState(slf)&(BS_MAX|BS_FLAG_INTERRUPTABLE|BS_FLAG_FREEHANDS)) == (bodystate&(BS_MAX|BS_FLAG_INTERRUPTABLE|BS_FLAG_FREEHANDS)))
{
return TRUE;
};
return FALSE;
};
Вот ссылка Важно - Уроки скриптологии by VAM - 13. Вспомогательные С_ функции для людей (compare функции).
Пост автоматически объединён:

Каюсь =) был невнимателен, не прочитал про доп флаги) благодарю за внимание, вопрос снят
 
Последнее редактирование:

N1kX


Модостроитель
Регистрация
13 Ноя 2009
Сообщения
6.129
Благодарности
5.626
Баллы
910
Проблема в движке или в скриптах?
Есть такая проблема.
НПС имеет следующие характеристики
Daedalus:
instance PC_Hero(Npc_Default)
{
   name[0] = "Ja";
   guild = GIL_NONE;
   id = 0;
   voice = 15;
   level = 0;
   npcType = npctype_main;
   bodyStateInterruptableOverride = TRUE;
   exp = 0;
   exp_next = 700;
   lp = 0;
   attribute[ATR_STRENGTH] = 25;
   attribute[ATR_DEXTERITY] = 25;
   attribute[ATR_MANA_MAX] = 25;
   attribute[ATR_MANA] = 25;
   attribute[ATR_HITPOINTS_MAX] = 120;
   attribute[ATR_HITPOINTS] = 120;
   Npc_SetTalentSkill(self,NPC_TALENT_MAGE,3);
   Npc_SetTalentSkill(self,NPC_TALENT_SNEAK,1);
   Npc_SetTalentSkill(self,NPC_TALENT_SMITH,1);
   PLAYER_TALENT_TAKEANIMALTROPHY[TROPHY_Fur] = TRUE;
   PLAYER_TALENT_TAKEANIMALTROPHY[TROPHY_Teeth] = TRUE;
   PLAYER_TALENT_TAKEANIMALTROPHY[TROPHY_Claws] = TRUE;
   PLAYER_TALENT_TAKEANIMALTROPHY[TROPHY_BFSting] = TRUE;
   PLAYER_TALENT_TAKEANIMALTROPHY[TROPHY_BFWing] = TRUE;
   PLAYER_TALENT_TAKEANIMALTROPHY[TROPHY_ReptileSkin] = TRUE;
   PLAYER_TALENT_TAKEANIMALTROPHY[TROPHY_Mandibles] = TRUE;
   /*B_AddFightSkill(self,NPC_TALENT_1H,12);
   B_AddFightSkill(self,NPC_TALENT_2H,12);
   B_AddFightSkill(self,NPC_TALENT_BOW,20);
   B_AddFightSkill(self,NPC_TALENT_CROSSBOW,20);*/
   Mdl_SetVisual(self,"HUMANS.MDS");
   Mdl_SetVisualBody(self,"hum_body_Naked0",9,0,"Hum_Head_Pony",Face_N_Player,0,ITAR_Vlk_NEW1);
   //B_SetFightSkills(self,22); //B_SetFightSkills(self,10);
   B_SetFightSkills1H(self,22);
   B_SetFightSkills2H(self,22);
   B_SetFightSkillsBow(self,30); //B_SetFightSkillsBow(self,29);
   B_SetFightSkillsCrossBow(self,30); //B_SetFightSkillsCrossBow(self,29);
};
Как видно, у игрока на старте уровни владения следующие
одноручное 22 - новичок
двуручное 22 - новичок
лук 30 - новичок
арбалет 30 - новичок
Функция B_AddFightSkill имеет вид, который ещё когда-то предлагал Myxomor
Код:
//new
func void B_AddFightSkill(var C_Npc slf,var int talent,var int percent)
{
    if(talent == NPC_TALENT_1H)
    {
        slf.HitChance[NPC_TALENT_1H] += percent;
        if(slf.HitChance[NPC_TALENT_1H] > 100)
        {
            slf.HitChance[NPC_TALENT_1H] = 100;
        };
        if(slf.HitChance[NPC_TALENT_1H] < 0)
        {
            slf.HitChance[NPC_TALENT_1H] = 0;
        };
        if(slf.HitChance[NPC_TALENT_1H] >= 60)
        {
            Npc_SetTalentSkill(slf,NPC_TALENT_1H,2);
            Mdl_ApplyOverlayMds(slf,"humans_1hST2.mds");
        }
        else if(slf.HitChance[NPC_TALENT_1H] >= 30)
        {
            Npc_SetTalentSkill(slf,NPC_TALENT_1H,1);
            Mdl_ApplyOverlayMds(slf,"humans_1hST1.mds");
        }
        else
        {
            Npc_SetTalentSkill(slf,NPC_TALENT_1H,0);
            Mdl_RemoveOverlayMds(slf,"humans_1hST1.MDS");
            Mdl_RemoveOverlayMds(slf,"humans_1hST2.MDS");
        };
    };
    if(talent == NPC_TALENT_2H)
    {
        slf.HitChance[NPC_TALENT_2H] += percent;
        if(slf.HitChance[NPC_TALENT_2H] > 100)
        {
            slf.HitChance[NPC_TALENT_2H] = 100;
        };
        if(slf.HitChance[NPC_TALENT_2H] < 0)
        {
            slf.HitChance[NPC_TALENT_2H] = 0;
        };
        if(slf.HitChance[NPC_TALENT_2H] >= 60)
        {
            Npc_SetTalentSkill(slf,NPC_TALENT_2H,2);
            Mdl_ApplyOverlayMds(slf,"humans_2hST2.mds");
        }
        else if(slf.HitChance[NPC_TALENT_2H] >= 30)
        {
            Npc_SetTalentSkill(slf,NPC_TALENT_2H,1);
            Mdl_ApplyOverlayMds(slf,"humans_2hST1.mds");
        }
        else
        {
            Npc_SetTalentSkill(slf,NPC_TALENT_2H,0);
            Mdl_RemoveOverlayMds(slf,"humans_2hST1.MDS");
            Mdl_RemoveOverlayMds(slf,"humans_2hST2.MDS");
        };
    };
    if(talent == NPC_TALENT_BOW)
    {
        slf.HitChance[NPC_TALENT_BOW] += percent;
        if(slf.HitChance[NPC_TALENT_BOW] > 100)
        {
            slf.HitChance[NPC_TALENT_BOW] = 100;
        };
        if(slf.HitChance[NPC_TALENT_BOW] >= 60)
        {
            Npc_SetTalentSkill(slf,NPC_TALENT_BOW,2);
            Mdl_ApplyOverlayMds(slf,"humans_bowT2.mds");
        }
        else if(slf.HitChance[NPC_TALENT_BOW] >= 30)
        {
            Npc_SetTalentSkill(slf,NPC_TALENT_BOW,1);
            Mdl_ApplyOverlayMds(slf,"humans_bowT1.mds");
        }
        else
        {
            Npc_SetTalentSkill(slf,NPC_TALENT_BOW,0);
            Mdl_RemoveOverlayMds(slf,"humans_bowT1.MDS");
            Mdl_RemoveOverlayMds(slf,"humans_bowT2.MDS");
        };
    };
    if(talent == NPC_TALENT_CROSSBOW)
    {
        slf.HitChance[NPC_TALENT_CROSSBOW] += percent;
        if(slf.HitChance[NPC_TALENT_CROSSBOW] > 100)
        {
            slf.HitChance[NPC_TALENT_CROSSBOW] = 100;
        };
        if(slf.HitChance[NPC_TALENT_CROSSBOW] >= 60)
        {
            Npc_SetTalentSkill(slf,NPC_TALENT_CROSSBOW,2);
            Mdl_ApplyOverlayMds(slf,"humans_cbowT2.mds");
        }
        else if(slf.HitChance[NPC_TALENT_CROSSBOW] >= 30)
        {
            Npc_SetTalentSkill(slf,NPC_TALENT_CROSSBOW,1);
            Mdl_ApplyOverlayMds(slf,"humans_cbowT1.mds");
        }
        else
        {
            Npc_SetTalentSkill(slf,NPC_TALENT_CROSSBOW,0);
            Mdl_RemoveOverlayMds(slf,"humans_cbowT1.MDS");
            Mdl_RemoveOverlayMds(slf,"humans_cbowT2.MDS");
        };
    };
};

//old
/*func void B_AddFightSkill(var C_Npc slf,var int talent,var int percent)
{
    if(talent == NPC_TALENT_1H)
    {
        slf.HitChance[NPC_TALENT_1H] = slf.HitChance[NPC_TALENT_1H] + percent;
        if(slf.HitChance[NPC_TALENT_1H] >= 0)
        {
            Npc_SetTalentSkill(slf,NPC_TALENT_1H,0);
        };
        if(slf.HitChance[NPC_TALENT_1H] >= 30)
        {
            Npc_SetTalentSkill(slf,NPC_TALENT_1H,1);
        };
        if(slf.HitChance[NPC_TALENT_1H] >= 60)
        {
            Npc_SetTalentSkill(slf,NPC_TALENT_1H,2);
        };
    };
    if(talent == NPC_TALENT_2H)
    {
        slf.HitChance[NPC_TALENT_2H] = slf.HitChance[NPC_TALENT_2H] + percent;
        if(slf.HitChance[NPC_TALENT_1H] >= 0)
        {
            Npc_SetTalentSkill(slf,NPC_TALENT_2H,0);
        };
        if(slf.HitChance[NPC_TALENT_2H] >= 30)
        {
            Npc_SetTalentSkill(slf,NPC_TALENT_2H,1);
        };
        if(slf.HitChance[NPC_TALENT_2H] >= 60)
        {
            Npc_SetTalentSkill(slf,NPC_TALENT_2H,2);
        };
    };
    if(talent == NPC_TALENT_BOW)
    {
        slf.HitChance[NPC_TALENT_BOW] = slf.HitChance[NPC_TALENT_BOW] + percent;
        if(slf.HitChance[NPC_TALENT_BOW] >= 0)
        {
            Npc_SetTalentSkill(slf,NPC_TALENT_BOW,0);
        };
        if(slf.HitChance[NPC_TALENT_BOW] >= 30)
        {
            Npc_SetTalentSkill(slf,NPC_TALENT_BOW,1);
        };
        if(slf.HitChance[NPC_TALENT_BOW] >= 60)
        {
            Npc_SetTalentSkill(slf,NPC_TALENT_BOW,2);
        };
    };
    if(talent == NPC_TALENT_CROSSBOW)
    {
        slf.HitChance[NPC_TALENT_CROSSBOW] = slf.HitChance[NPC_TALENT_CROSSBOW] + percent;
        if(slf.HitChance[NPC_TALENT_CROSSBOW] >= 0)
        {
            Npc_SetTalentSkill(slf,NPC_TALENT_CROSSBOW,0);
        };
        if(slf.HitChance[NPC_TALENT_CROSSBOW] >= 30)
        {
            Npc_SetTalentSkill(slf,NPC_TALENT_CROSSBOW,1);
        };
        if(slf.HitChance[NPC_TALENT_CROSSBOW] >= 60)
        {
            Npc_SetTalentSkill(slf,NPC_TALENT_CROSSBOW,2);
        };
    };
};*/
Берем в руки оружие, которое доводит владение одноручником до 30 (Эль-Бастардо)
Daedalus:
instance ItMw_ElBastardo(C_Item)
{
    name = "Эль-Бастардо";
    mainflag = ITEM_KAT_NF;
    flags = ITEM_SWD;
    material = MAT_METAL;
    value = Value_ElBastardo;
    damageTotal = Damage_ElBastardo;
    damagetype = DAM_EDGE;
    range = Range_ElBastardo;
    on_equip = Equip_1H_08;
    on_unequip = UnEquip_1H_08;
    cond_atr[2] = ATR_STRENGTH;
    cond_value[2] = Condition_ElBastardo;
    visual = "ItMw_065_1h_sword_bastard_03.3DS";
    description = name;
    text[0] = NAME_RANGE;
    count[0] = range;
    text[1] = NAME_Damage;
    count[1] = damageTotal;
    text[2] = NAME_Str_needed;
    count[2] = cond_value[2];
    text[3] = NAME_ADDON_BONUS_1H;
    count[3] = Waffenbonus_08;
    text[4] = NAME_OneHanded;
    text[5] = NAME_Value;
    count[5] = value;
};
У оружия функция надевания и снятия переписана
Daedalus:
func void Equip_1H_08()
{
    if(Npc_IsPlayer(self) && (self.HitChance[NPC_TALENT_1H] < 100))
    {
        if((self.HitChance[NPC_TALENT_1H] + Waffenbonus_08) > 100)
        {
            hero_1h_max_bonus = 100 - self.HitChance[NPC_TALENT_1H];
            B_AddFightSkill(self,NPC_TALENT_1H,hero_1h_max_bonus);
            b_meleeweaponchange(hero_1h_max_bonus,0,0);
        }
        else
        {
            hero_1h_max_bonus = -1;
            B_AddFightSkill(self,NPC_TALENT_1H,Waffenbonus_08);
            b_meleeweaponchange(Waffenbonus_08,0,0);
        };
    };
};

func void UnEquip_1H_08()
{
    if(Npc_IsPlayer(self) && (MELEEWEAPONCHANGEDHERO || (SCRIPTPATCHWEAPONCHANGE == FALSE)))
    {
        if(hero_1h_max_bonus < 0)
        {
            B_AddFightSkill(self,NPC_TALENT_1H,-Waffenbonus_08);
            b_meleeweaponundochange();
        }
        else
        {
            B_AddFightSkill(self,NPC_TALENT_1H,-hero_1h_max_bonus);
            b_meleeweaponundochange();
        };
    };
};
Теперь внимание. Надеваю оружие, уровень 30% - анимация бойца, все хорошо, но делаем сейф/лоад и после загрузки, в окне статистики 30% боец, а анимация новичка.... Если перенадеть оружие, анимация возвращается, но это не дело.
Изменил начальное владение луком и арбалетом до 29% (новичок), добавил меч, надел меч, проверил анимацию - боец (30%), делаю сейф/лоад, анимация не спадает...
Даже не представляю, как уровни владения (тем более их оверлеи) могут перекрываться между собой.
Если сделать все навыки по 30% - боец, проблемы тоже нет.
Делал вывод значений навыков, NPC_TALENT_1H и REAL_TALENT_1H имеют правильные значения, что до сохранения, что после загрузки.
 
Последнее редактирование:

Myxomop

Почетный форумчанин
Регистрация
28 Май 2005
Сообщения
3.239
Благодарности
2.581
Баллы
455
N1kX,
На основе функции B_AddFightSkill сделай отдельную функцию, которая будет проверять навык владения и выставлять оверлей, пропиши в файле Startup.d в Init_Global и(или) в каждый локации init_world и прочее. Если используется зацикленные функции Триггер-Скрипт, Икарус или Union, можно и туда.
 

ElderGamer


Модостроитель
Регистрация
16 Апр 2008
Сообщения
4.407
Благодарности
3.232
Баллы
525
делаем сейф/лоад и после загрузки, в окне статистики 30% боец, а анимация новичка....
Проверь, какие из этих функций выполняются при загрузке сохранения и, что важно, в какой последовательности. Включая чтение информации из инстанции ГГ. Добавь для теста вывод названия функций на экран. Вертикальная позиция для вывода надписи должна получаться инкрементом. Таким образом ты определишь, что выполняется раньше, а что позже.
 

N1kX


Модостроитель
Регистрация
13 Ноя 2009
Сообщения
6.129
Благодарности
5.626
Баллы
910
Проверь, какие из этих функций выполняются при загрузке сохранения и, что важно, в какой последовательности. Включая чтение информации из инстанции ГГ. Добавь для теста вывод названия функций на экран. Вертикальная позиция для вывода надписи должна получаться инкрементом. Таким образом ты определишь, что выполняется раньше, а что позже.
Это при значениях 22/22/30/30
Новая игра
1587614711194.png
До сохранения/загрузки - надеваем меч
1587614768409.png
После загрузки сохранения с надетым мечом
1587614822408.png
Выполняется как в коде.
Daedalus:
func void B_AddFightSkill(var C_Npc slf,var int talent,var int percent)
{
    if(talent == NPC_TALENT_1H)
    {
        if(slf.id == 0)
        {
            PrintScreen("1H + Bonus",-1,26,FONT_ScreenSmall,10);
        };
        slf.HitChance[NPC_TALENT_1H] += percent;
        if(slf.HitChance[NPC_TALENT_1H] > 100)
        {
            slf.HitChance[NPC_TALENT_1H] = 100;
        };
        if(slf.HitChance[NPC_TALENT_1H] < 0)
        {
            slf.HitChance[NPC_TALENT_1H] = 0;
        };
        if(slf.HitChance[NPC_TALENT_1H] >= 60)
        {
            if(slf.id == 0)
            {
                PrintScreen("1H - add overlay master",-1,28,FONT_ScreenSmall,10);
            };
            Npc_SetTalentSkill(slf,NPC_TALENT_1H,2);
            Mdl_ApplyOverlayMds(slf,"humans_1hST2.mds");
        }
        else if(slf.HitChance[NPC_TALENT_1H] >= 30)
        {
            if(slf.id == 0)
            {
                PrintScreen("1H - add overlay fighter",-1,30,FONT_ScreenSmall,10);
            };
            Npc_SetTalentSkill(slf,NPC_TALENT_1H,1);
            Mdl_ApplyOverlayMds(slf,"humans_1hST1.mds");
        }
        else
        {
            if(slf.id == 0)
            {
                PrintScreen("1H - remove overlay",-1,32,FONT_ScreenSmall,10);
            };
            Npc_SetTalentSkill(slf,NPC_TALENT_1H,0);
            Mdl_RemoveOverlayMds(slf,"humans_1hST1.MDS");
            Mdl_RemoveOverlayMds(slf,"humans_1hST2.MDS");
        };
    };
    if(talent == NPC_TALENT_2H)
    {
        if(slf.id == 0)
        {
            PrintScreen("2H + Bonus",-1,34,FONT_ScreenSmall,10);
        };
        slf.HitChance[NPC_TALENT_2H] += percent;
        if(slf.HitChance[NPC_TALENT_2H] > 100)
        {
            slf.HitChance[NPC_TALENT_2H] = 100;
        };
        if(slf.HitChance[NPC_TALENT_2H] < 0)
        {
            slf.HitChance[NPC_TALENT_2H] = 0;
        };
        if(slf.HitChance[NPC_TALENT_2H] >= 60)
        {
            if(slf.id == 0)
            {
                PrintScreen("2H + add overlay master",-1,36,FONT_ScreenSmall,10);
            };
            Npc_SetTalentSkill(slf,NPC_TALENT_2H,2);
            Mdl_ApplyOverlayMds(slf,"humans_2hST2.mds");
        }
        else if(slf.HitChance[NPC_TALENT_2H] >= 30)
        {
            if(slf.id == 0)
            {
                PrintScreen("2H - add overlay fighter",-1,38,FONT_ScreenSmall,10);
            };
            Npc_SetTalentSkill(slf,NPC_TALENT_2H,1);
            Mdl_ApplyOverlayMds(slf,"humans_2hST1.mds");
        }
        else
        {
            if(slf.id == 0)
            {
                PrintScreen("2H - remove overlay",-1,40,FONT_ScreenSmall,10);
            };
            Npc_SetTalentSkill(slf,NPC_TALENT_2H,0);
            Mdl_RemoveOverlayMds(slf,"humans_2hST1.MDS");
            Mdl_RemoveOverlayMds(slf,"humans_2hST2.MDS");
        };
    };
    if(talent == NPC_TALENT_BOW)
    {
        if(slf.id == 0)
        {
            PrintScreen("Bow + Bonus",-1,42,FONT_ScreenSmall,10);
        };
        slf.HitChance[NPC_TALENT_BOW] += percent;
        if(slf.HitChance[NPC_TALENT_BOW] > 100)
        {
            slf.HitChance[NPC_TALENT_BOW] = 100;
        };
        if(slf.HitChance[NPC_TALENT_BOW] >= 60)
        {
            if(slf.id == 0)
            {
                PrintScreen("Bow + add overlay master",-1,44,FONT_ScreenSmall,10);
            };
            Npc_SetTalentSkill(slf,NPC_TALENT_BOW,2);
            Mdl_ApplyOverlayMds(slf,"humans_bowT2.mds");
        }
        else if(slf.HitChance[NPC_TALENT_BOW] >= 30)
        {
            if(slf.id == 0)
            {
                PrintScreen("Bow + add overlay fighter",-1,46,FONT_ScreenSmall,10);
            };
            Npc_SetTalentSkill(slf,NPC_TALENT_BOW,1);
            Mdl_ApplyOverlayMds(slf,"humans_bowT1.mds");
        }
        else
        {
            if(slf.id == 0)
            {
                PrintScreen("Bow - remove overlay",-1,48,FONT_ScreenSmall,10);
            };
            Npc_SetTalentSkill(slf,NPC_TALENT_BOW,0);
            Mdl_RemoveOverlayMds(slf,"humans_bowT1.MDS");
            Mdl_RemoveOverlayMds(slf,"humans_bowT2.MDS");
        };
    };
    if(talent == NPC_TALENT_CROSSBOW)
    {
        if(slf.id == 0)
        {
            PrintScreen("CrossBow + Bonus",-1,50,FONT_ScreenSmall,10);
        };
        slf.HitChance[NPC_TALENT_CROSSBOW] += percent;
        if(slf.HitChance[NPC_TALENT_CROSSBOW] > 100)
        {
            slf.HitChance[NPC_TALENT_CROSSBOW] = 100;
        };
        if(slf.HitChance[NPC_TALENT_CROSSBOW] >= 60)
        {
            if(slf.id == 0)
            {
                PrintScreen("CrossBow + add overlay master",-1,52,FONT_ScreenSmall,10);
            };
            Npc_SetTalentSkill(slf,NPC_TALENT_CROSSBOW,2);
            Mdl_ApplyOverlayMds(slf,"humans_cbowT2.mds");
        }
        else if(slf.HitChance[NPC_TALENT_CROSSBOW] >= 30)
        {
            if(slf.id == 0)
            {
                PrintScreen("CrossBow + add overlay fighter",-1,54,FONT_ScreenSmall,10);
            };
            Npc_SetTalentSkill(slf,NPC_TALENT_CROSSBOW,1);
            Mdl_ApplyOverlayMds(slf,"humans_cbowT1.mds");
        }
        else
        {
            if(slf.id == 0)
            {
                PrintScreen("Crossbow - remove overlay",-1,56,FONT_ScreenSmall,10);
            };
            Npc_SetTalentSkill(slf,NPC_TALENT_CROSSBOW,0);
            Mdl_RemoveOverlayMds(slf,"humans_cbowT1.MDS");
            Mdl_RemoveOverlayMds(slf,"humans_cbowT2.MDS");
        };
    };
};
 

ElderGamer


Модостроитель
Регистрация
16 Апр 2008
Сообщения
4.407
Благодарности
3.232
Баллы
525
PrintScreen("1H + Bonus",-1,26,FONT_ScreenSmall,10);
Ты выводишь надпись на строго определённое место. Это сообщает о том, что функция была вызвана, но не сообщает, в какой последовательности вызывались функции.

Нужно:
- объявить глобальную переменную, которая будет использована в качестве вертикальной позиции для вывода надписи (можно использовать одну из аиварин ГГ);
- задать начальное значение переменной, например, 10;
- при каждом выводе надписи увеличивать значение переменной, скажем, на 3 или 4.

Можно также организовать возврат значения переменной к начальному, если это значение превысило некоторую величину, например, 80.
 

N1kX


Модостроитель
Регистрация
13 Ноя 2009
Сообщения
6.129
Благодарности
5.626
Баллы
910
Извини, спать хотел :)
После сохранения/загрузки без меча
1587628924971.png
Надел меч
1587629123434.png
Сейф/лоад - слет оверлея
1587629149605.png
Снял надел меч
1587629414345.png
Я прочитал у немцев, что есть такое, когда таланты вкачаны последние, а первые без талантов, оверлей может слетать, бред
Так же NicoDE переписал эту функцию, которую не включил в G2MDK
Из поста NicoDE
Ja. Ursprung des Problems ist, dass die Implementierung von Npc_SetTalentSkill die Animations-Overlays automatisch hinzufügt, aber davon ausgeht, dass die Kampftalente im Spiel nur größer werden.

Konkret macht Npc_SetTalentSkill folgendes:
  • wenn die Talentstufe größer wird:
    • NPC_TALENT_1H, NPC_TALENT_2H, NPC_TALENT_BOW, NPC_TALENT_CROSSBOW
      • wenn die Talentstufe größer oder gleich 2 ist, dann wird Overlay "<Modell>_<1HS|2HS|BOW|CBOW>T<Stufe - 1>.MDS" entfernt
      • Overlay "<Modell>_<1HS|2HS|BOW|CBOW>T<Stufe>.MDS" wird aktiviert
    • NPC_TALENT_ACROBAT
      • Overlay "HUMANS_ACROBATIC.MDS" wird aktiviert
      • die mögliche Fallhöhe wird verdoppelt
    • ansonsten keine weiteren Aktionen
    • beim Spieler wird danach das Jingle "JINGLELEARNTALENT" abgespielt
  • wenn die Talentstufe kleiner wird:
    • NPC_TALENT_ACROBAT
      • Overlay "HUMANS_ACROBATIC.MDS" wird entfernt
      • die mögliche Fallhöhe wird halbiert
    • ansonsten keine weiteren Aktionen (Kampf-Overlays bleiben also aktiv)
  • ansonsten keine weiteren Aktionen
ps: <Modell> ist in G1 fest kodiert als "HUMANS"
Daedalus:
var int Y_LOGENTRY;
const int _YPOS_MESSAGE = 20;

func void b_y_logentry()
{
    if(Y_LOGENTRY == 1)
    {
        Y_LOGENTRY = 2;
        _YPOS_MESSAGE = _YPOS_MESSAGE +2;
    }
    else if(Y_LOGENTRY == 2)
    {
        Y_LOGENTRY = 3;
        _YPOS_MESSAGE = _YPOS_MESSAGE +2;
    }
    else if(Y_LOGENTRY == 3)
    {
        Y_LOGENTRY = 4;
        _YPOS_MESSAGE = _YPOS_MESSAGE +2;
    }
    else if(Y_LOGENTRY == 4)
    {
        Y_LOGENTRY = 5;
        _YPOS_MESSAGE = _YPOS_MESSAGE +2;
    }
    else if(Y_LOGENTRY == 5)
    {
        Y_LOGENTRY = 6;
        _YPOS_MESSAGE = _YPOS_MESSAGE +2;
    }
    else if(Y_LOGENTRY == 6)
    {
        Y_LOGENTRY = 7;
        _YPOS_MESSAGE = _YPOS_MESSAGE +2;
    }
    else if(Y_LOGENTRY == 7)
    {
        Y_LOGENTRY = 8;
        _YPOS_MESSAGE = _YPOS_MESSAGE +2;
    }
    else if(Y_LOGENTRY == 9)
    {
        Y_LOGENTRY = 10;
        _YPOS_MESSAGE = _YPOS_MESSAGE +2;
    }
    else if(Y_LOGENTRY == 10)
    {
        Y_LOGENTRY = 11;
        _YPOS_MESSAGE = _YPOS_MESSAGE +2;
    }
    else if(Y_LOGENTRY == 11)
    {
        Y_LOGENTRY = 12;
        _YPOS_MESSAGE = _YPOS_MESSAGE +2;
    }
    else if(Y_LOGENTRY == 12)
    {
        Y_LOGENTRY = 13;
        _YPOS_MESSAGE = _YPOS_MESSAGE +2;
    }
    else
    {
        Y_LOGENTRY = 1;
        _YPOS_MESSAGE = 20;
    };
};

func void B_AddFightSkill(var C_Npc slf,var int talent,var int percent)
{
    if(talent == NPC_TALENT_1H)
    {
        if(slf.id == 0)
        {
            b_y_logentry();
            PrintScreen("1H + Bonus",-1,_YPOS_MESSAGE,FONT_ScreenSmall,10);
        };
        slf.HitChance[NPC_TALENT_1H] += percent;
        if(slf.HitChance[NPC_TALENT_1H] > 100)
        {
            slf.HitChance[NPC_TALENT_1H] = 100;
        };
        if(slf.HitChance[NPC_TALENT_1H] < 0)
        {
            slf.HitChance[NPC_TALENT_1H] = 0;
        };
        if(slf.HitChance[NPC_TALENT_1H] >= 60)
        {
            if(slf.id == 0)
            {  
                b_y_logentry();
                PrintScreen("1H - add overlay master",-1,_YPOS_MESSAGE,FONT_ScreenSmall,10);
            };
            Npc_SetTalentSkill(slf,NPC_TALENT_1H,2);
            Mdl_ApplyOverlayMds(slf,"HUMANS_1HST2.mds");
        }
        else if(slf.HitChance[NPC_TALENT_1H] >= 30)
        {
            if(slf.id == 0)
            {
                b_y_logentry();
                PrintScreen("1H - add overlay fighter",-1,_YPOS_MESSAGE,FONT_ScreenSmall,10);
            };
            Npc_SetTalentSkill(slf,NPC_TALENT_1H,1);
            Mdl_ApplyOverlayMds(slf,"HUMANS_1HST1.mds");
        }
        else
        {
            if(slf.id == 0)
            {
                b_y_logentry();
                PrintScreen("1H - remove overlay",-1,_YPOS_MESSAGE,FONT_ScreenSmall,10);
            };
            Npc_SetTalentSkill(slf,NPC_TALENT_1H,0);
            Mdl_RemoveOverlayMds(slf,"HUMANS_1HST1.MDS");
            Mdl_RemoveOverlayMds(slf,"HUMANS_1HST2.MDS");
        };
    };
    if(talent == NPC_TALENT_2H)
    {
        if(slf.id == 0)
        {
            b_y_logentry();
            PrintScreen("2H + Bonus",-1,_YPOS_MESSAGE,FONT_ScreenSmall,10);
        };
        slf.HitChance[NPC_TALENT_2H] += percent;
        if(slf.HitChance[NPC_TALENT_2H] > 100)
        {
            slf.HitChance[NPC_TALENT_2H] = 100;
        };
        if(slf.HitChance[NPC_TALENT_2H] < 0)
        {
            slf.HitChance[NPC_TALENT_2H] = 0;
        };
        if(slf.HitChance[NPC_TALENT_2H] >= 60)
        {
            if(slf.id == 0)
            {
                b_y_logentry();
                PrintScreen("2H + add overlay master",-1,_YPOS_MESSAGE,FONT_ScreenSmall,10);
            };
            Npc_SetTalentSkill(slf,NPC_TALENT_2H,2);
            Mdl_ApplyOverlayMds(slf,"HUMANS_2HST2.mds");
        }
        else if(slf.HitChance[NPC_TALENT_2H] >= 30)
        {
            if(slf.id == 0)
            {
                b_y_logentry();
                PrintScreen("2H - add overlay fighter",-1,_YPOS_MESSAGE,FONT_ScreenSmall,10);
            };
            Npc_SetTalentSkill(slf,NPC_TALENT_2H,1);
            Mdl_ApplyOverlayMds(slf,"HUMANS_2HST1.mds");
        }
        else
        {
            if(slf.id == 0)
            {
                b_y_logentry();
                PrintScreen("2H - remove overlay",-1,_YPOS_MESSAGE,FONT_ScreenSmall,10);
            };
            Npc_SetTalentSkill(slf,NPC_TALENT_2H,0);
            Mdl_RemoveOverlayMds(slf,"HUMANS_2HST1.MDS");
            Mdl_RemoveOverlayMds(slf,"HUMANS_2HST2.MDS");
        };
    };
    if(talent == NPC_TALENT_BOW)
    {
        if(slf.id == 0)
        {
            b_y_logentry();
            PrintScreen("Bow + Bonus",-1,_YPOS_MESSAGE,FONT_ScreenSmall,10);
        };
        slf.HitChance[NPC_TALENT_BOW] += percent;
        if(slf.HitChance[NPC_TALENT_BOW] > 100)
        {
            slf.HitChance[NPC_TALENT_BOW] = 100;
        };
        if(slf.HitChance[NPC_TALENT_BOW] >= 60)
        {
            if(slf.id == 0)
            {  
                b_y_logentry();
                PrintScreen("Bow + add overlay master",-1,_YPOS_MESSAGE,FONT_ScreenSmall,10);
            };
            Npc_SetTalentSkill(slf,NPC_TALENT_BOW,2);
            Mdl_ApplyOverlayMds(slf,"HUMANS_BOWT2.mds");
        }
        else if(slf.HitChance[NPC_TALENT_BOW] >= 30)
        {
            if(slf.id == 0)
            {
                b_y_logentry();
                PrintScreen("Bow + add overlay fighter",-1,_YPOS_MESSAGE,FONT_ScreenSmall,10);
            };
            Npc_SetTalentSkill(slf,NPC_TALENT_BOW,1);
            Mdl_ApplyOverlayMds(slf,"HUMANS_BOWT1.mds");
        }
        else
        {
            if(slf.id == 0)
            {
                b_y_logentry();
                PrintScreen("Bow - remove overlay",-1,_YPOS_MESSAGE,FONT_ScreenSmall,10);
            };
            Npc_SetTalentSkill(slf,NPC_TALENT_BOW,0);
            Mdl_RemoveOverlayMds(slf,"HUMANS_BOWT1.MDS");
            Mdl_RemoveOverlayMds(slf,"HUMANS_BOWT2.MDS");
        };
    };
    if(talent == NPC_TALENT_CROSSBOW)
    {
        if(slf.id == 0)
        {
            b_y_logentry();
            PrintScreen("CrossBow + Bonus",-1,_YPOS_MESSAGE,FONT_ScreenSmall,10);
        };
        slf.HitChance[NPC_TALENT_CROSSBOW] += percent;
        if(slf.HitChance[NPC_TALENT_CROSSBOW] > 100)
        {
            slf.HitChance[NPC_TALENT_CROSSBOW] = 100;
        };
        if(slf.HitChance[NPC_TALENT_CROSSBOW] >= 60)
        {
            if(slf.id == 0)
            {
                b_y_logentry();
                PrintScreen("CrossBow + add overlay master",-1,_YPOS_MESSAGE,FONT_ScreenSmall,10);
            };
            Npc_SetTalentSkill(slf,NPC_TALENT_CROSSBOW,2);
            Mdl_ApplyOverlayMds(slf,"HUMANS_CBOWT2.mds");
        }
        else if(slf.HitChance[NPC_TALENT_CROSSBOW] >= 30)
        {
            if(slf.id == 0)
            {
                b_y_logentry();
                PrintScreen("CrossBow + add overlay fighter",-1,_YPOS_MESSAGE,FONT_ScreenSmall,10);
            };
            Npc_SetTalentSkill(slf,NPC_TALENT_CROSSBOW,1);
            Mdl_ApplyOverlayMds(slf,"HUMANS_CBOWT1.mds");
        }
        else
        {
            if(slf.id == 0)
            {
                b_y_logentry();
                PrintScreen("Crossbow - remove overlay",-1,_YPOS_MESSAGE,FONT_ScreenSmall,10);
            };
            Npc_SetTalentSkill(slf,NPC_TALENT_CROSSBOW,0);
            Mdl_RemoveOverlayMds(slf,"HUMANS_CBOWT1.MDS");
            Mdl_RemoveOverlayMds(slf,"HUMANS_CBOWT2.MDS");
        };
    };
};
Daedalus:
func void B_AddFightSkill(var C_NPC npc, var int tal, var int add)
{
    var int hit;
    var string mds;
    mds = "HUMANS";  //FIXME: NPCs mit anderem Modell als HUMANS.MDS
    if (tal == NPC_TALENT_1H) {
        npc.HitChance[NPC_TALENT_1H] += add;
        hit = npc.HitChance[NPC_TALENT_1H];
        mds = ConcatStrings(mds, "_1HST");
    } else if (tal == NPC_TALENT_2H) {
        npc.HitChance[NPC_TALENT_2H] += add;
        hit = npc.HitChance[NPC_TALENT_2H];
        mds = ConcatStrings(mds, "_2HST");
    } else if (tal == NPC_TALENT_BOW) {
        npc.HitChance[NPC_TALENT_BOW] += add;
        hit = npc.HitChance[NPC_TALENT_BOW];
        mds = ConcatStrings(mds, "_BOWT");
    } else if (tal == NPC_TALENT_CROSSBOW) {
        npc.HitChance[NPC_TALENT_CROSSBOW] += add;
        hit = npc.HitChance[NPC_TALENT_CROSSBOW];
        mds = ConcatStrings(mds, "_CBOWT");
    } else {
        return;
    };
    var int old;
    var int val;
    old = Npc_GetTalentSkill(npc, tal);
    if (hit >= 60) {
        val = 2;
    } else if (hit >= 30) {
        val = 1;
    } else {
        val = 0;
    };
    if (val < old) {
        // Beim Verlernen aktives Overlay entfernen.
        mds = ConcatStrings(mds, IntToString(old));
        mds = ConcatStrings(mds, ".MDS");
    //    PrintScreen(ConcatStrings("remove ", mds), -1, -1, "", 3);
        Mdl_RemoveOverlayMds(npc, mds);
    };
    Npc_SetTalentSkill(npc, tal, val);
};
Если все начальные навыки сделать одинаковыми проблемы нет, разные, проблемы есть.
 

ElderGamer


Модостроитель
Регистрация
16 Апр 2008
Сообщения
4.407
Благодарности
3.232
Баллы
525
Сейф/лоад - слет оверлея
Похоже, тут произошло считывание данных из инстанции ГГ, а функция, вызываемая при экипировке оружия, не вызывалась. Отсюда вывод: функция установки оверлеев, нормально работающая для неписей, не совсем подходит для ГГ. У неписей не меняются значения оружейных навыков. У ГГ они меняются. И, кстати, а зачем эта функция включена в инстанцию ГГ? Она там точно нужна? Начальные значения навыков ГГ можно выставить в стартапе, наверное. :oops:
 

N1kX


Модостроитель
Регистрация
13 Ноя 2009
Сообщения
6.129
Благодарности
5.626
Баллы
910
Она там и в оригинале Г2 НВ.
Daedalus:
instance PC_Hero (NPC_DEFAULT)
{
    // ------ SC ------
    name         = "Ich";
    guild        = GIL_NONE;
    id            = 0;
    voice        = 15;
    level        = 0;
    Npctype        = NPCTYPE_MAIN;
    
    //***************************************************
    bodyStateInterruptableOverride     = TRUE;
    //***************************************************
    
    // ------ XP Setup ------
    exp                = 0;
    exp_next        = 500;
    lp                = 0;
    
    // ------ Attribute ------
    attribute[ATR_STRENGTH]         = 10;
    attribute[ATR_DEXTERITY]         = 10;
    attribute[ATR_MANA_MAX]         = 10;
    attribute[ATR_MANA]             = 10;
    attribute[ATR_HITPOINTS_MAX]    = 40;
    attribute[ATR_HITPOINTS]         = 40;
    
    // ------ visuals ------
    //B_SetNpcVisual         (self, MALE, "Hum_Head_Pony", FACE_N_Player, BodyTex_N, NO_ARMOR);
    
    Mdl_SetVisual (self,"HUMANS.MDS");
    // ------ Visual ------ "body_Mesh",        bodyTex            SkinColor    headMesh,            faceTex,        teethTex,    armorInstance   
    Mdl_SetVisualBody (self, "hum_body_Naked0", 9,                0,            "Hum_Head_Pony",     FACE_N_Player,    0,             NO_ARMOR);
    
    // ------ Kampf-Talente ------
    B_SetFightSkills     (self, 10);
};

B_SetFightSkills вызывает B_RaiseFightTalent, который вызывает B_AddFightSkill и B_RaiseRealFightTalentPercent (нужен для правильной установке стоимости талантов)
 

ElderGamer


Модостроитель
Регистрация
16 Апр 2008
Сообщения
4.407
Благодарности
3.232
Баллы
525
Она там и в оригинале Г2 НВ.
B_SetFightSkills вызывает ...
И если эта функция не работает при каждой загрузке, значит она вызывается из инстанции однократно. Но в инстанции есть ряд позиций, которые считываются оттуда многократно. Могу предположить, что в движке имеется перечень того, что считывается из инстанции однократно, в том числе и названия функций. Функции с другими названиями могут запускаться из инстанции многократно. Твои функции установки навыков имеют особые названия. Нужно проверить, запускаются они из инстанции однократно или при каждой загрузке.
 

Slavemaster


Модостроитель
Регистрация
10 Июн 2019
Сообщения
1.082
Благодарности
1.901
Баллы
320
ElderGamer, наверняка при каждой загрузке весь конструктор выполняется. Потом поверх всего этого значения из сейва присваиваются.
 

N1kX


Модостроитель
Регистрация
13 Ноя 2009
Сообщения
6.129
Благодарности
5.626
Баллы
910
Так и есть, при каждой загрузке есть вывод, мои функции всего лишь производные от B_SetFightSkills для удобства назначения навыков, пробовал и просто hitchange с Real_ делать, результата нет. Как только лук/арбалет больше 1h/2h, при загрузке оверлеи 1h/2h сбрасываются. Делаешь навыки одинаковыми или наоборот, проблемы нет.
 

ElderGamer


Модостроитель
Регистрация
16 Апр 2008
Сообщения
4.407
Благодарности
3.232
Баллы
525
наверняка при каждой загрузке весь конструктор выполняется. Потом поверх всего этого значения из сейва присваиваются.
Возможно. Но в сейве сохраняется не вся информация. Например, там не сохраняются текстовые переменные. Отсюда невозможность простого (однократного) изменения имён персонажей по ходу игры. А сохраняется ли в сейве информация о назначенных оверлеях?

Так и есть, при каждой загрузке есть вывод,
Попробуй следующий подход. Назначь значения навыков ГГ в стартапе. А в инстанции ГГ в качестве аргументов функции установки оверлеев используй не конкретные числа, а текущие значения талантов. Это будет работать, если стартап выполняется раньше чтения данных из инстанции (скорее всего, так и есть). Или нужно как-то однократно назначить таланты ГГ в инстанции ДО вызова функции назначения оверлеев.
 

N1kX


Модостроитель
Регистрация
13 Ноя 2009
Сообщения
6.129
Благодарности
5.626
Баллы
910
В сохранение записываются оверлеи всех НПС
Например вот значения из сохранения одного мода
Сейф ISLAND.SAV
PC_HERO y ђґ ai oCAIHuman : o CAniCtrl_Human:zCAIPlayer ДьѕBДьѕBnDДьѕBЕ±ЃC АAC і aiNpc § 4 µ % zCEventManager emCutscene % яяPC_HERO fff? Ђ? Ђ? HUMANS_2HST1.MDS HUMANS_1HST1.MDS
 

Slavemaster


Модостроитель
Регистрация
10 Июн 2019
Сообщения
1.082
Благодарности
1.901
Баллы
320
А сохраняется ли в сейве информация о назначенных оверлеях?
При загрузке выполняется скриптовый конструктор НПС с деактивированным инвентарем. Потом активируются сохраненные оверлеи. Потом применяются сохраненные таланты, что тоже может привести к добавлению/удалению оверлеев.
 
Сверху Снизу