Автор перевода : ValleoИтак, продолжаю переводить функции тулсета...
Кстати, одно уточнение... В тулсете есть два вида функций - стандартные (script function) и определенные пользователем (user function). В игре существует довольно много user functions, созданных ребятами из BioWare для кампании, однако их с успехом можно использовать и в своих модулях. Я пока перевожу стандартные функции, которые вы можете видеть в Скрипт Эдиторе. Биоварские пользовательские функции находятся в инклудах.
Инклуды - своего рода библиотеки пользовательских функций. Обычно в них собраны функции по одному критерию (увидите ниже). Инклуды включаются в скрипт по средствам директивы #include. Обычно инклуды включают в самом начале скрипта, до первых инструкций, чтобы функции, определенные в инклудах можно было использовать в исполняемом скрипте. Инклуды не компилируются (т.к. нету исполняемой функции - main() или StartingCondition()). При компиляции неиспользуемые пользовательские функции пропускаются.
И еще - если вы хотите просмотреть содержимое инклудов, то выполните этот порядок действий:
Откройте Скрипт Эдитор (Script Editor);
Нажмите Ctrl+O - откроется окно, где вы можете выбрать скрипт для редактирования;
Установите радиофлажек в выборе ресурсов на самую верхнюю позицию (верхняя - все скрипты, средняя - только ваши, нижняя - скрипты хак-пака);
В поле Скрипт Нэйм (название скрипта) впишите "nw_i0_" (без кавычек) и выберите тот, который вам нужен.
P.S. Вы также можете создавать свои инклуды. Просто для их использования в самом начале вашего скрипта пропишите название вашей библиотеки функций:
#include "название_вашей_базы_функций"
Но это необходимо лишь в том случае, если вы написали около десятка (или больше) функций, которые можно логически объединить по одному критерию. Выносить две-три функции в инклуд не имеет смысла.
Note: Стандартные скрипты можно (а порой и нужно) изменять. Для этого просто сохраните измененный скрипт. Если изменения вам не понравились, а вы забыли что меняли - просто удалите этот скрипт (он будет удален только из вашего модуля). В этом случае снова будет использоваться стандартный скрипт (он берется напрямую из scripts.bif).
BeginConversation (Начать беседу)
int BeginConversation(string sResRef="", object oObjectToDialog=OBJECT_INVALID)
string sResRef - пропишите здесь в кавычках название вашего дерева разговора (если не написать - запустится дефаулт разговор... какой - не известно)
object oObjectToDialog - здесь указывается тот, с кем начинается разговор (если не указать - начнется разговор с тем, кто активировал скрипт)
BlackScreen (Черный Экран - это для ДМов извращенцев используется для пыток простых людей черным экраном за плохие поступки... хотя можно и использовать в синглах для эффектного телепорта (сначала темный экран, а когда он проявляется вы уже в другой части света... это можно увидеть в СоУ, когда выполняешь квест с кобольдами в таверне в самом первом городе, где нужно освободить повариху - там этот эффект хорошо можно разглядеть))
void BlackScreen(object oCreature)
object oCreature - бедный oCreature, на который будем юзать черный экран (кстати в комбинации с "открыть меню смерти" (где кнопки загрузить, выйти и респаун) получается интерестная вещь...)
BootPC (Забутить игрока - бутим, бутим, пока у того глаза на лоб не полезут... точнее выгоняем с сервера)
void BootPC(object oPlayer)
object oPlayer - бедный подопытный игрок...
Note: Эта функция работает только в мультиплеере. Чтобы завершить модуль в сигле используйте EndGame().
ChangeFaction (Присоединяет oObjectToChangeFaction к фракции, к которой принадлежит oMemberOfFactionToJoin)
void ChangeFaction(object oObjectToChangeFaction, object oMemberOfFactionToJoin)
object oObjectToChangeFaction - это тот, кто будет менять фракцию...
object oMemberOfFactionToJoin - а это тот, к кому будут присоеденяться (точнее к чьей фракции будут присоеденяться)
Note: Эта функция работает только между двумя NPC.
ChangeToStandardFaction (Сменить фракцию на стандартную - тоже, что и выше, только используются стандартные фракции)
void ChangeToStandardFaction(object oCreatureToChange, int nStandardFaction)
object oCreatureToChange - тот, кто будет менять фракцию
int nStandardFaction - одна из стандартных фракций (список ниже):
STANDARD_FACTION_COMMONER - коммонеры (или просто люди, которым на тебя параллельно)
STANDARD_FACTION_DEFENDER - дефендеры (фракция защитников)
STANDARD_FACTION_HOSTILE - хостайл (враждебная фракция)
STANDARD_FACTION_MERCHANT - мерчанты (торговцы иными словами)
ClearAllActions (Функция очищает все действия, которые выполнялись объектом - очень полезная функция, когда по скрипту надо срочно переменить деятельность персонажа, а не ожидать своей очереди)
void ClearAllActions(int nClearCombatState=FALSE)
int nClearCombatState - если FALSE, то ничего особенного, а если TRUE - то очищаются даже все действия во время битвы, сразу останавливается боевая музыка и появляется возможность отдыха
ClearPersonalReputation (очищает репутацию персонажа в глазах определенного персонажа)
void ClearPersonalReputation(object oTarget, object oSource=OBJECT_SELF)
object oTarget - тот, чью репутацию очищаем
object oSource - тот, в чьих глазах очищаем репутацию
CopyItem (Скопировать вещь в указанный инвентарь, копирует все, включая сумки, но чтобы те в свою очередь были пустые, иначе копирование выдаст ошибку)
object CopyItem(object oItem, object oTargetInventory=OBJECT_INVALID)
object oItem - вещь, которую надо скопировать
object oTargetInventory - объект, в инвентарь которого будет копироваться вещь... если это место оставить пустым, то вещь скопируется туда же, где находится первоисточник
CopyObject (Копировать обьект, любой, в том числе и вещь... может копировать все, включая вас самих... если это вещь, то копирует в определенный инвентарь, если что то иное - в определенную локацию... кстати, можно скопировать объект так, что он создастся с новым тэгом)
object CopyObject(object oSource, location locLocation, object oOwner = OBJECT_INVALID, string sNewTag = "")
object oSource - объект, который надо копировать
location locLocation - местоположение, куда объект копируется
object oOwner - владелец инвентаря(если копируемый объект - вещь), куда будет копироваться объект
string sNewTag - новый тэг (ярлык), который будет дан копированному объекту
cos (Извлекает косинус из числа)
float cos(float fValue)
float fValue - число, из которого извлекается косинус
CreateItemOnObject (Создает вещь в инвентаре объекта)
object CreateItemOnObject(string sItemTemplate, object oTarget=OBJECT_SELF, int nStackSize=1)
string sItemTemplate - тэг создаваемого объекта (ярлык)
object oTarget - объект, в инвентарь которого создается объект
int nStackSize - размер стэка (наверно это для стрел, болтов и т.п.)
CreateObject (Просто и со вкусом - создать объект...)
object CreateObject(int nObjectType, string sTemplate, location lLocation, int bUseAppearAnimation=FALSE, string sNewTag="")
int nObjectType - это определяет, чем является объект... выбираем из списка:
OBJECT_TYPE_ITEM - объект является вещью
OBJECT_TYPE_CREATURE - объектом является создание (живое существо)
OBJECT_TYPE_PLACEABLE - объектом является плесейбел (ящики, сундуки, столбы, стулья и т.д.)
OBJECT_TYPE_STORE - объектом является... является... является магазин (пока переводил написал три раза =) )
OBJECT_TYPE_WAYPOINT - объектом является вейпоинт (я например использую для пометки места смерти персонажа, чтобы при воскрешении его отправляло именно в то место)...
P.S. Обязательно правильно укажите тип объекта!!! Bначе функция просто напросто не сработает!!!
string sTemplate - тэг (ярлык) объекта, который мы хотим создать
location lLocation - место, где мы создаем объект
int bUseAppearAnimation - использование анимации... TRUE или FALSE
string sNewTag - задаем созданному объекту новый тэг, если это нужно (я например задаю для вейпоинта имя умершего)
//Далее в функциях мы наблюдаем странные строки d10, d100 и т.д.
//И так, представим "кубик" с 6 гранями. Это и будет d6.
//С 10ю гранями - d10, со 100та гранями - d100.
//Игра как бы "кидает кубик" с определенным числом граней, и возвращает то, что выпадет на "верхней" грани.
//Функция представляется как:
int d10(int nNumDice=1)
int nNumDice - это число раз, которое должен быть брошен кубик. Это НЕ умножение на выпавшее число на кубике.
ПРИМЕР:
int DC = d10(5);
В этом примере в переменную DC запишется сумма выпавших чисел на кубике, а бросков будет 5. Пр. первый бросок - 3, второй - 6, третий - 1, четвертый - 8, пятый - 4: функция вернет 3+6+1+8+4.
Прервемся и изучим еще несколько деталей из Тулсета.
Все уже наверняка знают такие проверялки, как if, while, switch - case?
Но некоторые не знают, как применять их в Тулсете...
И так, этот краткий курс поможет вам понять, что где и как работает.
Начнем с IF.
И так, для чего нужна эта проверка... А вот для чего. Иногда при создании квестов вам надо проверить, например, какой уровень у персонажа, или сколько у него золота, или вообще это воин или кто то еще? И если догадка подтверждается - выполняется то, что вам нужно, а если нет - или выполняется что то другое, или просто переходит к обработке след. функции... расмотрим на примере:
Код
void main()
{
object oPC = GetEnteringObject();
if (GetIsDM(oPC))
{
ActionSpeakString("ДМ на шарде, ура ура ура!!!", TALKVOLUME_SHOUT)
}
}
Этот скрипт скажет в шаут, что на сервер зашел ДМ - т.е. в шауте буквально будет "[SERVER] ДМ на шарде, ура ура ура!!!" Функция определяет, что если зашедший (object oPC - GetEnteringObject() игрок ДМ (GetIsDM(oPC)) - то он скажет что мы задали между фигурных скобок после if. Но если же это будет НЕ ДМ - скрипте ничего не предпримет.
Дополним скрипт:
Цитата
void main()
{
object oPC = GetEnteringObject();
if (GetIsDM(oPC))
{
ActionSpeakString("ДМ на шарде, ура ура ура!!!", TALKVOLUME_SHOUT)
}
else
ActionSpeakString("Опять простой игрок, ну надо же...", TALKVOLUME_SHOUT)
}
В этом случае если зашедший игрок НЕ ДМ скрипт скажет "Опять простой игрок, ну надо же..." в шаут.
Вообще это можно разобрать так: IF(если) then (то-то), else(иначе) then (то-то).
Заметьте, что фигурные скобки можно и не ставить. В этом случае выполнится одна следующая инструкция. В описанном случае - ActionSpeakString("Опять простой игрок...")
Дополним скрипт:
Код
void main()
{
object oPC = GetEnteringObject();
if (GetIsDM(oPC))
{
ActionSpeakString("ДМ на шарде, ура ура ура!!!", TALKVOLUME_SHOUT)
}
else if (GetIsPC(oPC))
{
ActionSpeakString("Опять простой игрок, ну надо же...", TALKVOLUME_SHOUT)
}
else
{
ActionSpeakString("Гадость, это уже и не игрок, и не ДМ... ЧИТО ЭТО???", TALKVOLUME_SHOUT)
}
}
Здесь мы использовали такую структуру: IF(если) then (то-то), else(иначе) IF(если) then (то-то), else(иначе) then (то-то)
Функция сначала смотри, зашел ли ДМ - если нет, смотрит, игрок ли это (GetIsPC(oPC)), и если и это неверно - говорит в шаут "Гадость, это уже и не игрок, и не ДМ... ЧИТО ЭТО???"
Этой проверкой можно проверить все, что может быть на персонаже, включая даже имя персонажа.
В Авроре существует один тернарный оператор (выполняет действия над 3 выражениями). Записывается он довольно просто, но с первого взгляда не понятно: (логическое_выражение) ? (выражение_1) : (выражение_2).
Эта запись эквивалентна следующей:
if (логическое_выражение == TRUE) { (выражение_1) }
else { выражение_2) }
Ну например, вот такое выражение:
string sDatabase = "mydb";
object oPlayer = GetEnteringObject();
int nHitPoints = (GetLocalInt(GetModule(), GetName(oPlayer) + ".HitPoints")) ? GetLocalInt(GetModule(), GetName(oPlayer) + ".HitPoints") : GetCampaignInt(sDatabase, "HitPoints", oPlayer);
Чтобы не сильно нагружать сервер, читая все время из базы данных, мы сначала проверяем, существует ли какое-нибудь значение в локальной переменной на уровне модуля. Если да - используем его, если нет - значит был рестарт, данные потерялись, используем информацию из базы данных. Это часть функции, которая восстанавливает ХП при перезаходе на сервер.
Далее while. Это цикл (loop) с начальным условием. Цикл будет выполняться до тех пор, пока условие истинно. Цикл может не выполнится ниразу.
И так, пример, и вы поймете что к чему:
Код
void main()
{
object oPC = GetEnteringObject();
object oLootItem=GetFirstItemInInventory(oPC);
while(GetIsObjectValid(oLootItem))
{
oLootItem=GetNextItemInInventory(oPC);
}
}
Что делает эта вещь... Короче, сначала берется самая первая вещь из инвентара (object oLootItem=GetFirstItemInInventory(oPC), потом функция while проверяет, находится ли эта вещь в инвентаре (while(GetIsObjectValid(oLootItem))), и если да, то выполняется то, что заключенно между фигурными скобками после while. Это зацилненная функция, так как она будет действовать, пока то что она проверяет будет верно (в конце она берет следуюoe. вещь из инвентаря oLootItem=GetNextItemInInventory(oPC); и опять идет проверка на ее наличие в инвентаре, и если она прошла успешно - опять выполняется то, что заключенно между фигурными скобками, и будет так до того момента, когда при проверке окажется, что вещи такой в инвентаре нет, и она прекратит работу). Кстати, эту функцию можно прервать насильно - в конце дописать "break;", и тогда эта функция напоминает что то типа IF.
Кроме того существует цикл с условием в конце тела. Разница в том, что этот цикл выполнится хотя бы один раз.
do
{
}
while (condition);
В инструкциях предусмотрены следующие операторы
&& - логическое "И"
|| - логическое "ИЛИ"
! - логическое "НЕ"
Код
// объект игрок и ДМ (GetisPC() возвращает, является ли объект клиентом)
if (GetIsPC(oPC) && GetIsDM(oPC))
{
ActionSpeakString("ДМ на шарде, ура ура ура!!!", TALKVOLUME_SHOUT)
}
// объект игрок, но не ДМ
else if (GetIsPC(oPC) && !GetIsDM(oPC)
{
<...>
}
Фух, case разберем потом =)
Следите за обновлениями! Мне кажется грядет полный туториал по тулсету на русском... =)))
Пока это все =)
И не забывайте при создании скрипта после каждой функции ставить ";"