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

    Чтобы получить возможность писать на форуме, оставьте сообщение в этой теме.
    Удачи!
  • Друзья, доброго времени суток!
    Стартовал новый литературный конкурс от "Ордена Хранителей" - "Пираты Миртанского моря".
    Каждый может принять в нём участие и снискать славу и уважение, а в случае занятия призового места ещё и получить награду. Дерзайте
  • Дорогие друзья, год подходит к концу, и пришло время подвести его итоги и наградить достойных

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

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

DocNight

Участник форума
Регистрация
6 Июн 2020
Сообщения
32
Благодарности
1
Баллы
100
А по какой формуле они маштабируются, в зависимости от разрешения экрана?
 

Gratt


Модостроитель
Регистрация
14 Ноя 2014
Сообщения
3.301
Благодарности
4.641
Баллы
625
Если отбросить ту деталь, что размер каждого объекта интерфейса зависит друг от друга по уровню вложенности, то
* virtualX = 8192 / resX * pixelX
* virtualY = 8192 / resY * pixelY
Где
- virtualX/Y - виртуальные размеры объекта на экране
- 8192 - виртуальный размер экрана по x и y
- resX/Y - разрешение игры и соответственно игрового окна
- pixelX/Y - требуемые размеры объекта в пикселях. Для статус баров 180х20 пикселей.
 

DocNight

Участник форума
Регистрация
6 Июн 2020
Сообщения
32
Благодарности
1
Баллы
100
Это и хотел получить, благодарю.
Пост автоматически объединён:

Ох, и еще. Текст также располагается, в зависимости от разрешения экрана?
 
Последнее редактирование:

Gratt


Модостроитель
Регистрация
14 Ноя 2014
Сообщения
3.301
Благодарности
4.641
Баллы
625
Текст тоже является набором двумерных полигонов с натянутыми на них текстурами букв. Положение текста задаётся в виртуальных координатах, а вот размер этих самых букв определяется в пикселях.
Без вмешательства извне его размер изменить нельзя. То есть если высота шрифта 10 пикселей, то независимо от разрешения оно и останется 10 пикселей.
 

DocNight

Участник форума
Регистрация
6 Июн 2020
Сообщения
32
Благодарности
1
Баллы
100
Ну типо представим такое, что мне надо подогнать все это под меню. На уровне движка все это просчитывается, где должен быть размещен текст. Если это не будет просчитываться, то оно будет просто располагаться по виртуальным коор-дам. Например выставил место 2000 на 4000, он будет располагаться именно на этих координатах. Однако движок, как я знаю, умеет просчитывать координаты, и по задумке разработчика, ставить текст например в левую часть экрана. Например те же менюшки из глав. меню, которые подстраиваются под разрешение экрана.
 

N1kX


Модостроитель
Регистрация
13 Ноя 2009
Сообщения
6.179
Благодарности
5.706
Баллы
910
Продолжая делать TexturesAI я заметил, что много эффектов просто не юзается, как-нибудь сделаю весь список (пока что лишь веду только по текстурам)
Например,
В PARTICLEFX.DAT
есть три инстанции GROUNDFOGNIGHT_OUTDOOR_LOW/GROUNDFOGNIGHT_OUTDOOR_MID/GROUNDFOGNIGHT_OUTDOOR_HIGH (В Г1 его нет)
Это эффект дыма разный по размеру, но он работает только ночью.
Я так понимаю, что включает и выключает его движок по названию в имени NIGHT? Круто ведь, даже всякие приколюхи колхозить не надо :)

Типо его вид (GROUNDFOGNIGHT_OUTDOOR_LOW - маленький)
1608215038457.png
 
Последнее редактирование:

ElderGamer


Модостроитель
Регистрация
16 Апр 2008
Сообщения
4.411
Благодарности
3.242
Баллы
525
Я так понимаю, что включает и выключает его движок по названию в имени NIGHT?
Нет. В свойствах эффекта есть строковый параметр, в котором задаётся время старта эффекта и окончания генерации частиц.

Daedalus:
instance GROUNDFOGNIGHT_OUTDOOR_LOW(C_PARTICLEFX)
{
    ...
    timestartend_s = "23 9";
};
 

N1kX


Модостроитель
Регистрация
13 Ноя 2009
Сообщения
6.179
Благодарности
5.706
Баллы
910
Даже не посмотрел :)
Добавили видимо в Готике 2 (Может уже было в сиквеле)
Daedalus:
// необязательный, вы можете установить допустимый временной период, в котором этот pfx должен быть отрисован (например, "8 22": должен быть отрисован с 08 до 22 часов")
var string timeStartEnd_S;
 

N1kX


Модостроитель
Регистрация
13 Ноя 2009
Сообщения
6.179
Благодарности
5.706
Баллы
910
Кто поможет для познания расшифровать некоторые моменты?
Примерный список того, что движок вызывает из скриптов (Лень расписывать для всего :) )
Актуально для 2.6а
//Движок вызывает функцию Player_Hotkey_Lame_Potion, при условии, что включена тестовая функция быстрых зелий в gothic.ini
CGameManager::HandleEvent
{
SELF = <oCNpc>Player
OTHER = <oCNpc>Player
CallFunc("Player_Hotkey_Lame_Potion")
}
//Движок вызывает функцию Player_Hotkey_Lame_Heal, при условии, что включена тестовая функция быстрых зелий в gothic.ini
CGameManager::HandleEvent
{
SELF = <oCNpc>Player
OTHER = <oCNpc>Player
CallFunc("Player_Hotkey_Lame_Heal")
}
//Движок вызывает функцию Init_Zenname, чтобы выполнить инициализацию игрового мира
oCGame::CallScriptInit
{
CallFunc("Init_Global")
CallFunc("Init_" + WorldName)
}
//Движок вызывает функцию Startup_Zenname, чтобы выполнить инициализацию игрового мира
oCGame::CallScriptStartup
{
CallFunc("Startup_Global")
CallFunc("Startup_" + WorldName)
}
//Движок вызывает функцию Player_Hotkey_Screen_Map, чтобы выполнить получить инстанцию последней использованной карты
oCGame::HandleEvent
{
MapInstance = <int>CallFunc("Player_Hotkey_Screen_Map")
}
oCInfo::Info
{
SELF = <oCNpc>Respondent
OTHER = <oCNpc>Questioner
CallFunc(Information)
}
oCInfo::InfoConditions
{
SELF = <oCNpc>Respondent
OTHER = <oCNpc>Questioner
Fulfilled = <int>CallFunc(Condition)
}
oCInformationManager::OnChoice
{
SELF = <oCNpc>Npc
OTHER = <oCNpc>Player
CallFunc(Function)
}
oCItemReactModule::StartReaction
{
Exchange = <int>CallFunc(Reaction)
}

oCMag_Book::Spell_Cast
{
SELF = <oCNpc>SpellCaster
OTHER = <oCNpc>SpellTarget
CallFunc("Spell_Cast_" + SpellName, SpellLevel)
}
oCMission::Failure
{
SELF = <oCNpc>Npc
OTHER = <oCNpc>Player
CallFunc(FailureFunction)
}
oCMission::FailureConditions
{
SELF = <oCNpc>Npc
OTHER = <oCNpc>Player
Fulfilled = <int>CallFunc(FailureCondition)
}
oCMission::Obsolete
{
SELF = <oCNpc>Npc
OTHER = <oCNpc>Player
CallFunc(ObsoleteFunction)
}
oCMission::ObsoleteConditions
{
SELF = <oCNpc>Npc
OTHER = <oCNpc>Player
Fulfilled = <int>CallFunc(ObsoleteCondition)
}
oCMission::Offer
{
SELF = <oCNpc>Npc
OTHER = <oCNpc>Player
CallFunc(OfferFunction)
}
oCMission::OfferConditions
{
SELF = <oCNpc>Npc
OTHER = <oCNpc>Player
Fulfilled = <int>CallFunc(OfferCondition)
}
oCMission::Running
{
SELF = <oCNpc>Npc
OTHER = <oCNpc>Player
CallFunc(RunningFunction)
}
oCMission::Success
{
SELF = <oCNpc>Npc
OTHER = <oCNpc>Player
CallFunc(SuccessFunction)
}
oCMission::SuccessConditions
{
SELF = <oCNpc>Npc
OTHER = <oCNpc>Player
Fulfilled = <int>CallFunc(SuccessCondition)
}
oCMob::OnAction
{
TARGET = <oCNpc>Player
OBJECT = <oCMob>this
CallFunc(OnAction, ActionCounter)
}
oCMob::OnSpotted
{
CallFunc(OnSpotted, SpottedCounter)
}
oCMobInter::CallOnStateFunc
{
SELF = <oCNpc>Npc
ITEM = <oCItem>InteractItem
CallFunc(OnStateFunc + "_S" + State)
}
oCMobInter::CanInteractWith
{
SELF = <oCNpc>Npc
CanUse = <int>CallFunc(ConditionFunc)
}
//Движок вызывает функцию Player_Mob_Another_Is_Using, когда игрок хочет использовать oCMob, который использует НПС
oCMobInter::CanInteractWith
{
SELF = <oCNpc>Player
OTHER = <oCNpc>Player
CallFunc("Player_Mob_Another_Is_Using")
}
//Движок вызывает функцию Player_Mob_Missing_Item, когда у Игрока нет определенного предмета, прописанного в useWithItem, или в каком-нибудь скрипте
oCMobInter::CanInteractWith
{
SELF = <oCNpc>Player
OTHER = <oCNpc>Player
CallFunc("Player_Mob_Missing_Item")
}

oCMobInter::SearchFreePosition
{
SELF = <oCNpc>Player
OTHER = <oCNpc>Player
CallFunc("Player_Mob_Too_Far_Away")
}

oCMobInter::SearchFreePosition
{
SELF = <oCNpc>Player
OTHER = <oCNpc>Player
CallFunc("Player_Mob_Wrong_Side")
}

oCMobLockable::CanOpen
{
SELF = <oCNpc>Player
OTHER = <oCNpc>Player
CallFunc("Player_Mob_Missing_Key")
}

oCMobLockable::CanOpen
{
SELF = <oCNpc>Player
OTHER = <oCNpc>Player
CallFunc("Player_Mob_Missing_Key_Or_Lockpick")
}

oCMobLockable::CanOpen
{
SELF = <oCNpc>Player
OTHER = <oCNpc>Player
CallFunc("Player_Mob_Missing_Lockpick")
}

oCMobLockable::CanOpen
{
SELF = <oCNpc>Player
OTHER = <oCNpc>Player
CallFunc("Player_Mob_Never_Open")
}

oCMobLockable::Interact
{
SELF = <oCMobLockable>this
CallFunc("G_Picklock", Success, Lockpick)
}

oCMobLockable::Unlock
{
CallFunc("G_NoKey")
}

oCMobLockable::Unlock
{
SELF = <oCMobLockable>this
CallFunc("G_Picklock", Success, LockpickOrOpened)
}

oCNewsManager::CreateNews
{
SELF = = <oCNpc>Witness
OTHER = <oCNpc>Offender
VICTIM = <oCNpc>Victim
SpreadType = <int>CallFunc("C_CanNewsBeSpread")
}

oCNewsManager::SpreadNews
{
SELF = <oCNpc>Npc
OTHER = <oCNpc>Offender
VICTIM = <oCNpc>Victim
CallFunc("B_SpreadAndMemorize", NewsId, TRUE)
}

oCNpc::AddItemEffects
{
SELF = <oCNpc>this
CallFunc(Item.OnEquip)
}

oCNpc::CanUse
{
SELF = <oCNpc>this
ITEM = <oCItem>Item
CallFunc("G_CannotCast", IsPlayer, ItemMagicCircle, MagicCircle)
}

oCNpc::CanUse
{
SELF = <oCNpc>this
ITEM = <oCItem>Item
CallFunc("G_CannotUse", IsPlayer, ItemConditionAttribute, ItemConditionValue)
}

oCNpc::EV_UseItemToState
{
SELF = <oCNpc>this
ITEM = <oCItem>InteractItem
CallFunc(InteractItem.OnState[InteractItem.CurrentState])
}

oCNpc::EV_WaitForQuestion
{
SELF = <oCNpc>this
CallFunc("B_NpcBye")
}

oCNpc::Enable
{
SELF = <oCNpc>this
CallFunc("B_RefreshAtInsert")
}
//Движок вызывает функцию InitPerceptions чтобы установить для класса NPC и его инстанции восприятия
oCNpc::InitStatics
{
CallFunc("InitPerceptions")
}

//Движок вызывает функцию Player_Victim_Is_Immortal, когда урон идет по врагу с флагом NPC_FLAG_IMMORTAL
oCNpc::OnDamage
{
CallFunc("Player_Victim_Is_Immortal")
}
oCNpc::OnDamage_Condition
{
SELF = <oCNpc>this
OTHER = <oCNpc>Attacker
UnconsciousnessAllowed = <int>CallFunc("C_DropUnconscious")
}
//Движок вызывает функцию B_SetCutscenePerceptions (Без понятия для чего)
oCNpc::OnMessage
{
SELF = <oCNpc>this
CallFunc("B_SetCutscenePerceptions")
}
//Движок вызывает функцию Player_Plunder_Is_Empty, чтобы НПС мог обшманать труп/побитого
oCNpc::OpenDeadNpc
{
SELF = <oCNpc>Player
OTHER = <oCNpc>Player
CallFunc("Player_Plunder_Is_Empty")
}
//Движок вызывает функцию G_CanSteal, чтобы проверить возможна ли кража (В готике 1 для кражи со спины, в готике 2 функция упрощена)
oCNpc::OpenSteal
{
SELF = <oCNpc>this
OTHER = <oCNpc>Victim
CanSteal = <int>CallFunc("G_CanSteal")
}

oCNpc::RefreshNpc
{
SELF = <oCNpc>this
CallFunc("B_RefreshArmor")
}

oCNpc::RemoveItemEffects
{
SELF = <oCNpc>this
CallFunc(Item.OnUnequip)
}
oCNpc::SetCurrentAnswer
{
SELF = <oCNpc>this
OTHER = <oCNpc>other
CallFunc(Function)
}
oCNpc_States:: DoAIState
{
SELF = <oCNpc>Npc
OTHER = <oCNpc>Other
VICTIM = <oCNpc>Victim
ITEM = <oCItem>Item
CallFunc(StateFunction)
}
oCNpc_States:: DoAIState
{
SELF = <oCNpc>Npc
OTHER = <oCNpc>Other
VICTIM = <oCNpc>Victim
ITEM = <oCItem>Item
End = <int>CallFunc(StateFunction + '_LOOP')
}
oCNpc_States:: DoAIState
{
SELF = <oCNpc>Npc
OTHER = <oCNpc>Other
VICTIM = <oCNpc>Victim
ITEM = <oCItem>Item
CallFunc(StateFunction + '_END')
}
//Движок вызывает выполнение расписания дня в классе oCNpc
oCNpc_States::InitRoutine
{
SELF = <oCNpc>Npc
CallFunc(Npc.DailyRoutine)
}
oCNpc_States::StartAIState
{
SELF = <oCNpc>Npc
CallFunc(AiState)
}
//Движок вызывает 2 скрипты для манипуляции с маной НПС/игрока
oCSpell::CallScriptInvestedMana
{
SELF = <oCNpc>SpellCaster
OTHER = <oCNpc>SpellTarget
SpellStatus = <int>CallFunc("Spell_ProcessMana", ManaInvested)
}
oCSpell::SetReleaseStatus
{
SELF = <oCNpc>SpellCaster
OTHER = <oCNpc>SpellTarget
SpellStatus = <int>CallFunc("Spell_ProcessMana_Release", ManaInvested)
}

oCTriggerScript::TriggerTarget
{
SELF = <oCNpc>Originator
OTHER = NULL
ITEM = NULL
CallFunc(ScriptFunc)
}
//Похоже на огрызок из Готики 1 с его бартером, движок вызывает скрипт Player_Trade_Not_Enough_Gold, чтобы вывести инфу, что у игрока недостаточно валюты для совершения торговли
oCViewDialogTrade::OnTransferRight
{
SELF = <oCNpc>Player
OTHER = <oCNpc>Player
CallFunc("Player_Trade_Not_Enough_Gold")
}
//движок вызывает скрипт C_CanNpcCollideWithSpell, чтобы определить что делать, после попадания заклинания в какую-то область (стена, нпс)
oCVisualFX:: ProcessCollision
{
SELF = <oCNpc>Target
OTHER = <oCNpc>Origin
CollideFlags = <int>CallFunc("C_CanNpcCollideWithSpell", SpellType)
}
zCCSCutsceneContext::Stop
{
SELF = <oCNpc>MainRole
OTHER = NULL
VICTIM = NULL
CallFunc(ScriptFuncOnStop, Name)
}
zCMenu::HandleAction
{
Leave = <int>CallFunc(MenuItem.OnEventAction[x])
}
zCMenu::HandleSelAction
{
Leave = <int>CallFunc(MenuItem.OnEventAction[x])
}
zCMenuItem::HandleEvent
{
Exit = <int>CallFunc(OnEventAction[MENU_EVENT_INIT])
}
zCMenuItemChoice::InsertInWin
{
CallFunc(OnEventAction[MENU_EVENT_INIT])
}
Я заметил, что есть функции, которых нет в скриптах. Для примера я попробовал добавить Player_Victim_Is_Immortal, но чет тестового сообщения не было, которое я прописал в нем, следовательно вызов функции может был отключен.
 
Последнее редактирование:

DocNight

Участник форума
Регистрация
6 Июн 2020
Сообщения
32
Благодарности
1
Баллы
100
Друзья, всем привет. Какая функция отвечает за размещение 3д текста, ака имя персонажа над его головой, и вообще моб объекты? И по какой формуле все это просчитывается?
 

WoOliN

Участник форума
Регистрация
13 Окт 2012
Сообщения
347
Благодарности
196
Баллы
210
Вопрос, возможно глупый, но всё же попробую сформулировать:
есть ли возможность в чистых скриптах, без расширителей (в том числе и Юниона) задать одну переменную типа var int, которая будет через скрипты изменяться индивидуально для каждого отдельного персонажа?
Нужно, чтобы эта переменная отсчитывала свой собственный таймер для каждого отдельного персонажа, если эффект активировался сразу на нескольких NPC.

Что-то вроде константы AI, например, как const int AIV_VictoryXPGiven (конкретно эта определяет, получен ли опыт за данного NPC),
но с возможностью изменяться в диапазоне от 0 до 10.
Надеюсь, более-менее понятно объяснил)

Достаточно близкий пример - это эффект движкового горения с постепенной потерей ХП. Если подожжены несколько целей, то каждая из них горит с отдельным таймером, который чётко останавливает эффект после определенного числа тиков. Единственное, что этот эффект контролируется движком, а мне бы хотелось нечто подобное через скрипты.
Основное здесь - эффект должен вовремя останавливаться и не мешать рутине NPC.
 
Последнее редактирование:

N1kX


Модостроитель
Регистрация
13 Ноя 2009
Сообщения
6.179
Благодарности
5.706
Баллы
910
Вопрос, возможно глупый, но всё же попробую сформулировать:
есть ли возможность в чистых скриптах, без расширителей (в том числе и Юниона) задать одну переменную типа var int, которая будет через скрипты изменяться индивидуально для каждого отдельного персонажа?
Нужно, чтобы эта переменная отсчитывала свой собственный таймер для каждого отдельного персонажа, если эффект активировался сразу на нескольких NPC.

Что-то вроде константы AI, например, как const int AIV_VictoryXPGiven (конкретно эта определяет, получен ли опыт за данного NPC),
но с возможностью изменяться в диапазоне от 0 до 10.
Надеюсь, более-менее понятно объяснил)
Самый простой путь через айвар. Свободный индекс айваров с 89 по 99.

Как пример, заклинание безумие
Ai_Constant.d
Daedalus:
const int AIV_RageStateTime = 89;
SPL_Victims_Rage = 2; (2 сек)
zs_rage.d
Daedalus:
func void ZS_Rage () {

    if (self.aivar[AIV_RageStateTime] == 0) {
        // ------ сброс состояния охраны ------
        self.aivar[AIV_Guardpassage_Status] = GP_NONE;

        Npc_SetRefuseTalk(self, 0);

        // ------ Temp_Att (отношение) "сброс" ------
        Npc_SetTempAttitude(self, Npc_GetPermAttitude(self, hero));

        // ------ Сброс оверлеев ------
        B_StopLookAt(self);
        AI_StopPointAt(self);

        Npc_ClearAIQueue(self);

        if (!Npc_HasBodyFlag(self, BS_FLAG_INTERRUPTABLE)) {
            AI_StandUp(self);
        } else {
            AI_StandUpQuick(self);
        };

        B_ClearPerceptions(self);
        Wld_PlayEffect("spellFX_Rage_TARGET", self, self, 0, 0, 0, 0);
        if (self.guild < GIL_SEPERATOR_HUM) {
            AI_Wait(self, 0.5);
            AI_TurnToNpc(self, hero); // Примечание: заклинание использует только Hero.
            AI_Wait(self, 0.5);
            AI_PlayAni(self, "T_GREETNOV");
            AI_Wait(self, 0.3);
        };
    };
};

func int ZS_Rage_Loop () {
    // Выход из ZS
    if (self.aivar[AIV_RageStateTime] >= SPL_Victims_Rage) {
        Npc_ClearAIQueue(self);
        return LOOP_END;
    };

    self.aivar[AIV_RageStateTime] = self.aivar[AIV_RageStateTime]+1;

    Npc_PerceiveAll(self);

    if (Wld_DetectNpcEx(self, -1, NOFUNC, -1, 0) == TRUE) {
        if (self.guild < GIL_SEPERATOR_HUM) {
            var int rnd; rnd = Hlp_Random (100);
            if (rnd <= 40) {
                Snd_Play3D(self, "SVM_1_BERZERK");
            }
            else if (rnd <= 80) {
                Snd_Play3D(self, "SVM_2_BERZERK");
            }
            else if (rnd <= 99) {
                Snd_Play3D(self, "SVM_3_BERZERK");
            };
        };
        Npc_SetTarget(self, other);
        if (other.guild < GIL_SEPERATOR_HUM) {
            B_Attack(self, other, AR_NONE, 0);
        } else {
            AI_StartState(self, ZS_MM_Attack, 0, "");
        };
    };

    // никогда не достигается
    return LOOP_CONTINUE;
};

func void ZS_Rage_End() {
    AI_StandUp(self);
    if (self.guild < GIL_SEPERATOR_HUM) {
        AI_Dodge(self);
        AI_Dodge(self);
        AI_PlayAni(self, "T_SEARCH");
        B_Say_Overlay(self, self, "$WHATWASTHAT");
        AI_RemoveWeapon(self);
        AI_Wait(self, 1);
        AI_PlayAni(self, "T_DONTKNOW");
        AI_Wait(self, 0.5);
    };
    if (self.attribute[ATR_HITPOINTS] < (self.attribute[ATR_HITPOINTS_MAX]/2))
    {
        AI_StartState(self, ZS_HealSelf, 0, "");
        return;
    };
};
 

WoOliN

Участник форума
Регистрация
13 Окт 2012
Сообщения
347
Благодарности
196
Баллы
210
По-моему, это уже полноценное состояние со сбросом текущей очереди AI и запуском своего набора действий.
Как я понимаю, оно прервёт, например, состояние атаки и запустит свои эффекты.
Мне же нужен пример или совет, который позволит не прерывать возможность вести бой для NPC, а просто за 10 тиков снимет с NPC определенное число здоровья, пока он будет драться и корректно остановит эффект потери ХП через те самые 10 тиков. И если эффект активируется на нескольких NPC сразу, то каждый из них получит свои 10 тиков.

Пока, неким интуитивным и, как подозреваю, очень кривым образом я могу запустить состояние потери ХП одновременно у разных NPC, но я не могу его остановить и они просто умирают после исчерпания всего запаса здоровья)
Скорее всего для этого мне и нужна переменная, которая будет считать тики, но считать их отдельно для каждого персонажа.
Теоретически, я могу использовать обычный var int и плюсовать к нему единичку в каждом цикле, но активация эффекта на нескольких персонажах сразу просто остановит таймеры раньше времени у всех персонажей с активным эффектом.
Использование айвара вида self.aivar[AIV_...] почему-то не позволяет мне остановить эффект после достижения определенного значения ... либо не хватает соображалки для реализации)
 
Последнее редактирование:

Gratt


Модостроитель
Регистрация
14 Ноя 2014
Сообщения
3.301
Благодарности
4.641
Баллы
625
Она не в активном блоке препроцессора расположена. Не комиилится в ехешник и, соответственно, не вызывается.


Друзья, всем привет. Какая функция отвечает за размещение 3д текста, ака имя персонажа над его головой, и вообще моб объекты? И по какой формуле все это просчитывается?
Через проекцию 3D точки на вьюпорт. Метод zCCamera::Project. Игра выводит текст в точке, когда значение глубины проекции положительно, то бишь находится перед камерой, а не за ней.

WoOliN, циклический урон спокойно реализуется через VFX. Для кастомного цикла только костыли.
Напоминаю что такое чистые скрипты. Это простая математика + пачка внешних функций.
Внешние функции - это функции, которые пишутся на плюсах для решения задач, выходящих за рамки простой математики. Если задача модостроителя выходит за рамки математики и не имеет решения среди существующих внешних функций, значит нужно написать новую внешнюю функцию. Имха пусть лучше N1kX объяснит за триггер скрипты на экстендере.
 

ElderGamer


Модостроитель
Регистрация
16 Апр 2008
Сообщения
4.411
Благодарности
3.242
Баллы
525
Скорее всего для этого мне и нужна переменная, которая будет считать тики, но считать их отдельно для каждого персонажа.
Переменная нужна, но трудность здесь не в наличии самой переменной, а в том, как она будет изменяться. Вернее - ГДЕ. Мне видится пока только один путь - это введение во ВСЕ состояния ИИ, в которых может пребывать непись, контроль и изменение этой переменной. Но это тот ещё геморр. *around the head*
 

Gratt


Модостроитель
Регистрация
14 Ноя 2014
Сообщения
3.301
Благодарности
4.641
Баллы
625
ElderGamer, так у состояний ещё время отклика разное.
 

N1kX


Модостроитель
Регистрация
13 Ноя 2009
Сообщения
6.179
Благодарности
5.706
Баллы
910
Использование айвара вида self.aivar[AIV_...] почему-то не позволяет мне остановить эффект после достижения определенного значения ... либо не хватает соображалки для реализации)

Ну айвар же надо обнулять, когда его значение стало больше твоего

if self.aivar[AIV_Test1] > числа
запуск твоего кода (Снижение хп)
self.aivar[AIV_Test1] = 0


Она не в активном блоке препроцессора расположена. Не комиилится в ехешник и, соответственно, не вызывается.

А что по другим?
Например G_NoKey, B_SetCutscenePerceptions, B_NpcBye, B_SpreadAndMemorize, C_CanNewsBeSpread
Подозреваю, что это рудименты или скрипты Г1.
 

Gratt


Модостроитель
Регистрация
14 Ноя 2014
Сообщения
3.301
Благодарности
4.641
Баллы
625
Ну айвар же надо обнулять, когда его значение стало больше твоего
Эффективнее назначить аивару любое угодное значение и уменьшать, пока значение не будет равно нулю.


А что по другим?
Ну блин, если тебя интересует алгоритм вызова каждой, то это довольно трудоёмко :). Максимум могу потом сказать существует ли реализация вызова в принципе.
 

ElderGamer


Модостроитель
Регистрация
16 Апр 2008
Сообщения
4.411
Благодарности
3.242
Баллы
525
@ElderGamer, так у состояний ещё время отклика разное.
Согласен. Но камрада, как я понимаю, интересует нанесение растянутого во времени повреждения. И тут большее значение имеет не время нанесения этого урона, а его величина. Понятно, что в разных состояниях этот урон будет наноситься с разной скоростью. Частично, это можно учесть и скомпенсировать. Но идеального решения не выйдет.
 

Gratt


Модостроитель
Регистрация
14 Ноя 2014
Сообщения
3.301
Благодарности
4.641
Баллы
625
Нормальных решений на оригинальных скриптах нет и быть не может.

Экстендер. Независимая триггер функция, привязанная к конкретному нпс. Пол минуты кодинга.
Внизу по ссылке спойлер с примером https://worldofplayers.ru/threads/41999/
Daedalus:
// Вызвать эту функцию из любого удобного места программы
func void Test()
{
  var C_Trigger trigger;
  // Создать триггер на функцию TriggerTest с
  // задержкой 1000мс и привязкой в self персонажа hero
  trigger = AI_StartTriggerScriptEx("TriggerTest", 1000, hero, null, null);
  trigger.AIVariables[0] = 15; // Предположим это будет число повторов триггера
  trigger.AIVariables[1] = 5;  // Сколько HP будем отнимать у hero каждую секунду
};



// Тело триггера
func int TriggerTest()
{
  // Завершаем цикл, если количество доступных повторений равно нулю
  if (SelfTrigger.AIVariables[0] <= 0)
  {
    return Loop_end;
  };

  SelfTrigger.Delay             -= 20; // Ускоряем цикл на 20мс каждый последующий вызов функции
  SelfTrigger.AIVariables[0]    -= 1;  // Понижаем счетчик повторов
  Self.Attribute[ATR_HITPOINTS] -= SelfTrigger.AIVariables[1];  // Отнимаем здоровье привязанного к триггеру Npc

  // Продолжаем цикл
  return Loop_continue;
};
 
Сверху Снизу