Basic Scar and Marker Tutorial


Contents Содержание
Introduction (Введение)
Markers and Scar (Маркеры и Скар)
Creating Makers (Создание маркеров)
Creating your First Script (Создание твоего первого скрипта)
Setting it all up (Настройка всего)
Rule_SetResearchLevel (Уровень технологий)
Rule_SetupMusicPlaylist (Список музыки)
Rule_PresetAI (Искуственый Интелект)
Gamestart and objectives (Начало игры и цели)
Script (Скрипты)
Setting up the AI (Настройки ИИ)
Setup Wins & Loses (Настройка условий победы и поражения)
Setup Rules (Настройка правил)
Setup Autosave (Создание автосохранения)
Conclusion (Заключение)

Введение

В прошлых туториалах мы создали файл кампании и карту, которая будет первым сценарием нашей кампании. В этом руководстве мы пройдемся по основам СКАР скриптования и расскажем как использовать его в маркерах, объектах и группах объектов. На данный момент мы имеет карту с пирамидой, где расположен и укреплен Космодесант. Сейчас мы добавим эльдаров (игрока) и сделаем все немножко интереснее.

Первая вещь, которую ты должен сделать перед чтением этого руководства, это посмотреть шаблоны Скар документов и попробовать понять их. Эти шаблоны опишут основу структуры, которую должны иметь твои миссии. Хотя ты и не обязан делать это, но это было бы полезным для тебя и для других, если ты будешь пояснять свои функции, чтобы каждый легко мог найти необходимую функцию ему и понять механизм твоего скрипта. Ты так же можешь поискать необходимый тебе скрипт в Scar Doc библиотеке, это очень полезный инструмент, который включает в себя все возможные СКАР функции.

Маркеры и Скар


Creating Makers (Создание маркеров)


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

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

После размещения наш маркер выглядит:

 



Имя маркеру ты можешь выбрать любое, но в общем-то гораздо удобнее иметь определеные условия названия для того чтобы не путать группы, маркеры и т.д. Мы будем использовать приставки mk_ с mk_squad, sg_ с sg_squad и т.д. Предлагаю следовать этому условию.

Другое использование маркеров эти NIS'ы и IE' ы. Мы установим маркер рядом с реликтовой точкой, располагающейся на вершине холма, который мы будем использовать для открытия этого места для игрока. Мы можем настроить это так:

 



Это показывает реликт и территорию рядом видимой нам, но вражеские здания и юниты остаются невидимыми

Создание твоего первого скрипта


С установкой всех маркеров, мы можем создать ядро нашей миссии - Скар скрипт, который определит когда мы выиграем миссию, года запустятся NIS'ы и другие события. Если ты не смотрел СКАР шаблоны и документацию, то лучше сделать это сейчас. Ты можешь также закачать SCiTE, это замечательный текстовой редактор с поддержкой синтасиса языка Скар, который использовался при создании компании в Dawn of War.

Создай Скар скрипт в твой SP папке с таким же названием как и миссия (например, для нашей первой миссии ME01.scar)

Есть несколько вещей, которые обязательно должны входить в состав скрипта, что-бы он нормально работал. Эти функции обязательны и должны иметь обозначеные ниже имена или игра выдаст сообщение “Fatal Scar Error”:

В следующих функциях нет обязательной необходимости, но они желательны:

Setting it all up (Настройка всего)


Хорошо, сейчас мы знаем, что СКАР файл должен содержать, и ты видел файл шаблона СКАР, давай двигаться дальше и начнем создание нашей миссии.

Первая вещь, которую тебе нужно сделать, это определить игроков и расы, которые они контролируют. Компьютерный ли это игрок, либо Человек - его определение имеет существенное значение. Это делается в OnGameSetup функции. В ней мы будем использовать Setup_Player переменную, чтобы определить расы каждого игрока: Элдары у человека и Космодесант у компьютера. Это просто сделать следующими командами:

g_Player1 = Setup_Player(0, "Eldar ", "eldar_race", 1)
g_Player2 = Setup_Player(1, "7th Assault Division", "space_marine_race", 2)


Первый аргумент - это индекс игрока. В одиночной игре 0 означает человека, все остальные значения - это комп. игроки, второй аргумент - это название которым будет обозначаться игрок, третий аргумент - это раса игрока. Вот какие значения бывают: space_marine_race, elder_race, ork_race, chaos_race, guard_race, 4-ый аргумент означает команду к которой принадлежит данный игрок.

Законченая OnGameSetup функция выглядит так:

function OnGameSetup()

g_Player1 = Setup_Player (0, "Eldar ", "eldar_race", 1)
g_Player2 = Setup_Player (1, "7th Assault Division", "space_marine_race", 2)
end


После этого, дела становятся немного сложнее. После функции OnGameSetup идет OnInit функция, которая разветвляется на варианты других функций (многие из которых разветвляются в большинстве своем на один-два уровня). Мы разберем каждый шаг OnInit функции в свое время. Если тебе интересна эта часть создания миссии, ты можешь пропустить эту секцию документа. Хочу заметить, что некоторые функции будут описаны в следущем руководстве (особенно IE часть), но ты можешь поэксперементировать

Rule_SetResearchLevel


Функция Rule_SetResearchLevel используется, что бы дать игрокам исследования и установить глобальный уровень технологии в миссии. В нашем случае, мы должны дать Эльдарским рейнджерам технологию невидимости. Мы используем Player_GrantResarch функцию чтобы сделать это. Назания технологий для функции это названия файлов (разумеется без расширения Lua) могут быть найдены в папке Data\Attrib\Research. Пишется это так Rule_SetResearchLevel( уровень технологии)

--[[ DoW Specific!!
Restrict_SpaceMarines( g_Player1, resLevel )
Unrestrict_ResearchWithAlerts( g_Player1, "marine_requisition_research_2", "none", "none" )
Unrestrict_ResearchWithAlerts( g_Player1, "marine_power_research_2", "none", "none" )
]]

--[[ note: not using resLevel]]

Player_GrantResearch(g_Player1, "eldar_ranger_infiltration_research")
end

Есть несколько функций, которые используется вместе с OnInit. Вот они:


Эти функции будут описаны в следующем руководстве, чувствуй себя свободным играя с значениями этих функциями сам.

Rule_SetupMusicPlaylist


Правило настройки плейлиста для миссии. Хотя это и не обязательно, музыка добавит больше атмосферы в миссию и ты должен вставить её. Перед добавлением композиций нужно очистить существующий плейлист, это делается с помощью оператора Sound_PlaylistClear. А аргументами для этой функции являются PC_Music и PC_Ambient. Для очистки списка композиций у нас должно получится что-то в этом роде:

 Sound_PlaylistClear( PC_Music )


Теперь мы добавим несколько треков с помощью функции Sound_PlaylistAddTrack, установим их порядок в плейлисте с помощью функции Sound_PlaylistSetOrder и установим тишину между треками от 20 до 70 секунд используя функцию Sound_PlaylistSetSilence. Наша функция Rule_SetupMusicPlaylist в завершённом виде будет выглядить примерно вот так:

function Rule_SetupMusicPlaylist()

    --[[ clear the current playlist ]]
    Sound_PlaylistClear( PC_Music )
    --[[ add tracks to the playlist ]]
    Sound_PlaylistAddTrack( PC_Music, "music_ork_theme" )
Sound_PlaylistAddTrack( PC_Music, "music_invasion_theme" )
Sound_PlaylistAddTrack( PC_Music, "music_force_commander_theme" )
Sound_PlaylistAddTrack( PC_Music, "music_theme_spacemarines_01" )
Sound_PlaylistAddTrack( PC_Music, "battle_ingame_01" )
Sound_PlaylistAddTrack( PC_Music, "ambient_ingame_02" )
    --[[ mark these tracks to play randomly ]]
    Sound_PlaylistSetorder( PC_Music, true )
    --[[ add 5 to 10 seconds silence between tracks ]]
    Sound_PlaylistSetSilence( PC_Music, 20, 70 )

--[[ clear the ambient playlist ]]
Sound_PlaylistClear( PC_Ambient )
    --[[ add tracks to the playlist ]]
    Sound_PlaylistAddTrack( PC_Ambient, "ambient_wind" )
    --[[ mark these tracks to play randomly ]]
    Sound_PlaylistSetorder( PC_Ambient, false )
    --[[ add 5 to 10 seconds silence between tracks ]]
    Sound_PlaylistSetSilence( PC_Ambient, 5, 10 )

end

Rule_PresetAI

Функция Rule_PresetAI используется, как и следует из названия, для предварительной настройки ИИ. Это сделано для того, чтобы включать/выключать какую-нибудь функцию ИИ в определеный момент времени, или удеживать группы от управления ИИ, или для других целей. Эта проблема возникает в течении создания миссии, когда юниты находящиеся под контролем, будут выполнять команды отданые посредством скриптов, они также будут выполнять любую команду отданую им компом. Это приводит к некоторым нежелательным ситуациям, таким как ИИ "переписывает" команды дизайнера миссии и начинают заниматься "своими делами", таким образом потенциально возможно нарушение любой скриптовой команды и соответствующего поведения юнитов. Для решения этой проблемы в Скар имеется набор команд для ИИ, которая оградит компьютер от контроля над любым юнитом, который выберет дизайнер миссии. Это позволяет дизайнеру иметь полный контроль над вражеским ИИ и писание команд для юнитов без боязни "переписания" комманд компьютером.

Хотя это и отличная идея ограничить контроль ИИ над юнитами в одиночной миссии, ты конечно не хочешь управлять вражеской армией полностью через Скар скрипты, поэтому это было бы неплохо создать дополнительный ИИ, которой возьмет некоторую часть твоих обязаностей в свои руки, например такую часть как битва. Примером этого была бы миссия с 2 ИИ, один из которых выключен, а другой ИИ используется как боевой ИИ, юниты давались бы ему временно и ты бы мог сказать ему атаковать когда нужно (возможно через команду CPU_ForceAttack())

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

Следуя этому мы заблокируем sg_SpaceMarines1 группу, так что бы ИИ не контролировал его полностью и так чтобы они пробовали атаковать Эльдарскую Видящюю (Farseer). Что бы сделать это мы используем Rule_PresetAI() функцую, которую ты возможно видел в примере Скар файла. Мы заберем контроль у компа нп Космодесантской группой следующим образом:

Cpu_LockSGroupAcrossPlayers( "sg_SpaceMarineSquad1")

Это не даст ИИ перезаписать приказ атаки, которую ты дашь Форсе командеру и присоединеному отряду. Так наша Rule_StartAI() функция выглядит так:

function Rule_PresetAI()

Cpu_EnableAll(true)
-- prevent the AI from control the space marine squad + force commander
-- as we want them to be constantly attacking.
Cpu_LockSGroupAcrossPlayers( "sg_SpaceMarineSquad1" )

end

Gamestart and objectives

В конце определяются правила (Gamestart) игры и объявляются цели миссии. Для запуска правил игры просто добавь следущую функцию к OnInit:

Rule_Add( Rule_GameStart )

А наши цели объявляются так:

Objective_KillSpaceMarines = {title_id = 200000, short_desc_id = 200001, help_tip_id = 200002 }
Objective_CaptureRelic = {title_id = 300000, short_desc_id = 300001, help_tip_id = 300002 }


Структура этой функции следующая: title_id - текст который появится в меню задач миссии, short_desc_id - короткое описание, которое появится на странице, help_tip_id - подсказка которая покажется когда задачи появятся.)

Script

До сюда мы базово настроили и запустили скриптовую систему и миссия может запускаться. Нам просто надо настроить несколько частей для запуска ИИ и все будет настроено.

Setting up the AI  (Настройка компа)


Сейчас мы собираемся установить ИИ, мы настроим уровень сложности и включим его. Также мы настроем уровень сложности на основе выбора сделаного игроком на экране выбора миссии. Сделаем мы это через функцию Rule_SetDifficultyLevel, которая выглядит так:

function Rule_SetDifficultyLevel( difficultyLevel )
Difficulty_SetForAll( difficultyLevel )
end

Для различных уровней сложности, выбраных игроком, настроим ИИ по разному. Так как мы вызвали
функцию Rule_SetDifficultyLevel, это позволит нам легко изменить её значения, так как имеется всего одна функция для настройки сложности ИИ.. Ты так же можешь использовать эту функцию для других задач, как, например, количество начальных ресурсов или начальных юнитов (например три отряда Космодесанта на легком против одного отряда на сложном) и всякого прочего. Может быть ты удивишся, почему мы не вызвали Difficult_SetForAll функцию. Объяснение кроется в количестве ИИ, которое мы имеем. Обычно в миссии имеется более чем один ИИ, и ты бы наверняка хотел бы установить уровень сложности для каждого отдельно, что выглядело-бы примерно так:

-- now if we wanted to further adjust the difficulty level for the cpu
-- we could do so by manually adjusting the difficulty level for each cpu player
-- based on the selected difficulty leve, like so:

-- easy
if difficultyLevel == DIFFICULTY_EASY then

Cpu_SetDifficulty( g_Player2, AD_Standard )
Cpu_SetDifficulty( g_Player3, AD_Easy )

-- medium
elseif difficultyLevel == DIFFICULTY_NORMAL then

Cpu_SetDifficulty( g_Player2, AD_Standard )
Cpu_SetDifficulty( g_Player3, AD_Standard )

-- hard
elseif difficultyLevel == DIFFICULTY_HARD then

Cpu_SetDifficulty( g_Player2, AD_Hard )
Cpu_SetDifficulty( g_Player3, AD_Standard )

end


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

function Rule_StartAI()
Cpu_EnableAll(true)
end

Setup Wins & Loses

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

function Rule_PlayerLoses()

if Event_IsAnyRunning() == false and SGroup_Count( SGroup_FromName("sg_Farseer")) == 0 
 then
Rule_RemoveAll()
Fade_Start(4, false)
World_SetTeamWin( g_Player2, "" )
Rule_AddIntervalEx( Rule_GameOver,5,1 )
Rule_Remove( Rule_EndGameLose )
end

end


В нашей миссии игрок не имеет зданий, поэтому он проигрывает когда его farseer (Видящяя) будет убита. Это простое правило проверяет количество объектов в группе farseer (Видящяя), когла количество единиц в нём упадет до нуля (farseer убит), ИИ команде будет отдана победа, правило победы будет вызвано и текущее правило, как всегда, будет убрано из "мира". Возникает вопрос, почему мы вызываем функцию Rule_AddIntervalEx? Просто она с красиво запускает конец миссии, так что это не кончается резким "обрывом" игры, когда farseer умирает, что смотрится просто никудышне - отстойно.

In our mission, since the player has no buildings to speak of, the player loses if his farseer gets killed. This rule simply keeps checking the number of entities that are in the farseer group, when the number drops to 0 (the farseer is dead), the AI team is given the win, the win rule is called and the current rule, like always, is removed from the world. You may be asking why we call Rule_AddIntervalEx, this is to slightly delay the end of the mission, so that it doesn't end abruptly when the Farseer dies as this just looks bad.


Правило победы похоже на правило поражения и может быть описано так:

function Rule_EndGameWin()

if Objective_Exists( Objective_KillSpaceMarines.title_id) and 
Objective_GetState( Objective_KillSpaceMarines.title_id ) == OS_Complete  and
Objective_Exists( Objective_CaptureRelic.title_id)  and 
Objective_GetState( Objective_CaptureRelic.title_id ) == OS_Complete  
then
Rule_RemoveAll()
Util_StartNIS(EVENTS.NIS_Closing)
end
end


Игрок выигрывает когда он захватит реликт, а так же, когда убьет отряд космодесанта. Ты может быть хочешь знать что случится триггер будет выполнен - игра просто закончится. В нашем случае, с вызовом функции происходит конец игры.

Setup Rules (Настройка правил)

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

--[[ Kill Marine Squad
]]
function Rule_KillSpaceMarineSquad()

if Event_IsAnyRunning() == false and SGroup_Count( SGroup_FromName("sg_SpaceMarineSquad1")) == 0 
then
Util_ObjectiveComplete( Objective_KillSpaceMarines.title_id )
Rule_Remove( Rule_KillSpaceMarineSquad )
Rule_AddOneShot( Rule_IE_CaptureRelic, 10 )

elseif Event_IsAnyRunning() == false and Objective_Exists(Objective_KillSpaceMarines.title_id) == false then
Util_ObjectiveCreate(Objective_KillSpaceMarines, true)
end
end


Первое, функция проверяет, существует ли данная цель (убить космодесантников). Если не существует, мы её создаем. Если существует мы проверяем выполнено ли требуемое условие. Мы проверяем это с помощью проверки, пуста ли группа sg_SpaceMarines1. Мы также убеждаемся, что ни какое событие не запущено. Если эта цель выполнена, то помечает эта цель помечается как достигнутая и удаляется. В общем, таким способом ты можешь установить любое правило для нужного условия, которое ждёт пока не произойдёт определённое событие, и как только оно произошло - просто завершает его.

Цель захвата реликта выглядит похоже:

--[[ Capture Relic 
]]
function Rule_CaptureRelic()

--[[ Objective Successfull ]]
if Event_IsAnyRunning() == false and EGroup_IsCapturedByPlayer("eg_RelicPoint", g_Player1, false) then
Util_ObjectiveComplete( Objective_CaptureRelic.title_id )
Rule_Remove( Rule_CaptureRelic )

--[[Objective doesn't exist, create it ]]
elseif Event_IsAnyRunning() == false and Objective_Exists(Objective_CaptureRelic.title_id) == false then
Util_ObjectiveCreate(Objective_CaptureRelic, true)
end

end

Главным отличием между данной целью и целью KillSpaceMarines является то, что проверяется, захвачен ли Реликт нужным игроком. В нашем случае g_Player1. Если ты посмотришь описание EGroup_IsCapturedByPlayer команды, то увидишь, что первый аргумент это имя группы, которую мы хотим захватить, а второе - это имя игрока, который должен захватить её, ну а 3 - это логическое выражение охватывающее "все". Так как мы имеем только один объект в нашейгруппе, то установка его значения на правду или ложь не имеет особой разницы.

В самом конце мы настроим правило проверки пересечения моста игроком. Мы будем использовать предидущий маркер mk_ElminiateIncomingEldar и определим есть ли какой нибудь отряд игрока в его радиусе. Это может быть сделано с помощью функции Player_AreSquadronNearMarker, первым аргументом которой является требуемый игрок, а вторым - нужный маркер. Если это выполнится, то мы сделаем 2 вещи: запустим в игре очередь команд NIS (об этом в следующем туториале), а также прикажем Космодесанту атаковать Эльдаров с помощью функции Cmd_AttackSGroup. Первый её аргумент - это группа, которая должна атаковать, а второй - группа, которая должна быть атакована.

function Rule_WatchForEldarTransgression()
if Player_AreSquadsNearMarker(g_Player1, "mk_EliminateIncomingEldar") then

-- FADE BLACK
EventCue_Enable(false)
Fade_Start( 0, false )
W40k_Letterbox( true, 0 )

Util_StartIntel( EVENTS.NIS_FCAlive )

Cmd_AttackSGroup("sg_SpaceMarineSquad1", "sg_Farseer");
Rule_Remove( Rule_WatchForEldarTransgression)
end
end

Setup Autosave (Настройка автосохранения)

Одна из возможностей, которая тебе может понадобиться - это автосохранение. Это очень просто. Типичная функция автосохранения выглядит примерно так:

function Rule_AutosaveAfterFCDead()
if not Event_IsAnyRunning() then
Util_Autosave( "Eldar M1" )
Rule_Remove(Rule_AutosaveAfterFCDead)
end
end

Каждое автосохранение имеет сходную структуру. Для автосохранения просто вызываем Rule_AddRule(<functionName>) функции в требуемом месте. Мы будем иметь два автосохранения: одно после начала миссии (это хорощая идея для всех миссий), а второе - после уничтожение Космодесанта.

Conclusion (Заключение)


Ну так сейчас мы имеем простенькую миссию с базовыми NIS'ами. В следующем руководстве мы создадим настройки для NIS & IE, которые лучше расскажут историю связаную с нашей миссией.

 

Конец

Translate by GreatVV & TruMdz
Сайт управляется системой uCoz