Настройка инишек (user.ini, ut2004.ini) -> ut.dp.ua

Сообщение agressor » 13 ноя 2006, 09:02

ufaset писал(а):как лучше всего использовать кнопку на некоторых мышах 3x-Fire? первое что приходит на ум - додж. может есть более эффективные способы?
кстати, есть где-нибудь подобный FAQ для UT99?

Энциклопедия UT
Unreal Tournament FAQ#1
Unreal Tournament FAQ#2
Последний раз редактировалось agressor 15 ноя 2006, 18:52, всего редактировалось 2 раз(а).
AKA zd.Insider
Аватара пользователя
agressor
Путешественник
Путешественник
 
Автор темы
Сообщения: 362
Зарегистрирован:
07 фев 2002, 02:00
Откуда: Днепропетровск
Has thanked: 0 time
Have thanks: 0 time

Сообщение agressor » 13 ноя 2006, 09:10

Cobalt писал(а):Сделал как посаветовал agressor все получилось но появилась другая штука начал пропалать мутатор No adrenaline, попробовал прописать его в [Engine.GameEngine] но сервер воопще не запустился и еще хотелосьбы отметить сервер мы запускаем из игры т.к комп стоит на работе и желательно чтоб он весел возле часов , а не болтался на экране или был просто свернут как быть.


попробуй прописать в батнике:
?mutator=XGame.MutNoAdrenaline,XWeapons.MutNoSuperWeapon
AKA zd.Insider
Аватара пользователя
agressor
Путешественник
Путешественник
 
Автор темы
Сообщения: 362
Зарегистрирован:
07 фев 2002, 02:00
Откуда: Днепропетровск
Has thanked: 0 time
Have thanks: 0 time

Сообщение agressor » 13 ноя 2006, 09:30

lexa!! писал(а):

у мну проблема. он сначал прыгает а потом щит отпускает :-(
и получается что бы сделать шилд-джамп приходиться зажать кнопку - ты прыгаеш, набираеш щит, а потом только отпустить её и при этом нажать прыжок. вообщем или чот не так или я дет протупил. :)

Alt=Axis aLookUp Speed=-300.0|Jump|Button bFire|Button bSnapLevel|OnRelease aLookUp Speed=+300.0

предварительно нужно выбрать шилд (кнопки у него не должны быть переназначены)
1. Axis aLookUp Speed=-300.0 - смотрит вниз
2. Jump - прыгает
3. Button bFire - стреляет (левая кнопка мыши)
4. Button bSnapLevel - выравнивается в горизонтальное положение

после отпрускания кнопки (необязательно):
5. aLookUp Speed=+300.0 - смотрит вверх

З.Ы.
попробуй на дефолтных инишках
AKA zd.Insider
Аватара пользователя
agressor
Путешественник
Путешественник
 
Автор темы
Сообщения: 362
Зарегистрирован:
07 фев 2002, 02:00
Откуда: Днепропетровск
Has thanked: 0 time
Have thanks: 0 time

Сообщение Cobalt » 15 ноя 2006, 06:39

agressor спасибо все получилось
Аватара пользователя
Cobalt
Школота
Школота
 
Сообщения: 4
Зарегистрирован:
09 ноя 2006, 22:28
Откуда: Тул.обл. Алексин
Has thanked: 0 time
Have thanks: 0 time

Сообщение agressor » 17 ноя 2006, 18:04

lexa!! писал(а):2 agressor
сенкс. получилось.
а можно сделать чтобы он ешо немного щит накоплял ?


нет...
AKA zd.Insider
Аватара пользователя
agressor
Путешественник
Путешественник
 
Автор темы
Сообщения: 362
Зарегистрирован:
07 фев 2002, 02:00
Откуда: Днепропетровск
Has thanked: 0 time
Have thanks: 0 time

Сообщение agressor » 11 дек 2006, 16:25

Запуск от 1 до 9 выделенных серверов на одном ini-файле с выбором типа игры

1.Каталоге игры System Создаем файл Dedicated_Servers.cmd и прописываем в нем:

@echo off

if "%2" equ "Duel" (goto Duel)
if "%2" equ "DM" (goto DM)
if "%2" equ "TDM" (goto TDM)
if "%2" equ "CTF" (goto CTF)
if "%2" equ "ONS" (goto ONS)
if "%2" equ "AS" (goto AS)
if "%2" equ "BR" (goto BR)


:Duel
set Map=DM-DE-Ironic-FE.ut2
set Mutator=XWeapons.MutNoSuperWeapon,XGame.MutNoAdrenaline,utcompv16a.MutUTComp,TA100.MutTalkingIcon
set Game=XGame.xDeathMatch
set timelimit=15
set MinPlayers=2
set MaxPlayers=2
set MaxSpectators=2
set weaponstay=False
set MaxLives=0
set GoalScore=0
set Translocator=False
set ForceRespawn=True
set PlayersMustBeReady=True
set Tournament=1
set GameSpeed=1.00
set NumBots=1
set Difficulty=6
set FriendlyFireScale=0
goto Start

:DM
set Map=DM-DE-Grendelkeep.ut2
set Mutator=XWeapons.MutNoSuperWeapon,utcompv16a.MutUTComp,TA100.MutTalkingIcon
set Game=XGame.xDeathMatch
set timelimit=20
set MinPlayers=2
set MaxPlayers=10
set MaxSpectators=2
set weaponstay=True
set MaxLives=0
set GoalScore=0
set Translocator=False
set ForceRespawn=False
set PlayersMustBeReady=False
set Tournament=1
set GameSpeed=1.00
set NumBots=2
set Difficulty=6
set FriendlyFireScale=100
goto Start

:TDM
set Map=DM-DE-Grendelkeep.ut2
set Mutator=XWeapons.MutNoSuperWeapon,utcompv16a.MutUTComp,TA100.MutTalkingIcon
set Game=XGame.xTeamGame
set timelimit=20
set MinPlayers=2
set MaxPlayers=4
set MaxSpectators=2
set weaponstay=False
set MaxLives=0
set GoalScore=0
set Translocator=False
set ForceRespawn=True
set PlayersMustBeReady=True
set Tournament=1
set GameSpeed=1.00
set NumBots=0
set Difficulty=6
set FriendlyFireScale=100
goto Start

:CTF
set Map=CTF-Citadel.ut2
set Mutator=XWeapons.MutNoSuperWeapon,utcompv16a.MutUTComp,TA100.MutTalkingIcon,NoSpdCombo.MutNoSpeed
set Game=XGame.xCTFGame
set timelimit=20
set MinPlayers=2
set MaxPlayers=10
set MaxSpectators=2
set weaponstay=True
set MaxLives=0
set GoalScore=0
set Translocator=True
set ForceRespawn=False
set PlayersMustBeReady=True
set Tournament=1
set GameSpeed=1.00
set NumBots=0
set Difficulty=6
set FriendlyFireScale=0
goto Start

:ONS
set Map=ONS-CBP2-Yorda.ut2
set Mutator=XWeapons.MutNoSuperWeapon,utcompv16a.MutUTComp,TA100.MutTalkingIcon
set Game=Onslaught.ONSOnslaughtGame
set timelimit=20
set MinPlayers=2
set MaxPlayers=12
set MaxSpectators=2
set weaponstay=True
set MaxLives=0
set GoalScore=0
set Translocator=True
set ForceRespawn=False
set PlayersMustBeReady=True
set Tournament=1
set GameSpeed=1.00
set NumBots=0
set Difficulty=6
set FriendlyFireScale=0
goto Start

:AS
set Map=AS-CBP2-Thrust.ut2
set Mutator=XWeapons.MutNoSuperWeapon,utcompv16a.MutUTComp,TA100.MutTalkingIcon
set Game=UT2k4Assault.ASGameInfo
set timelimit=20
set MinPlayers=2
set MaxPlayers=10
set MaxSpectators=2
set weaponstay=True
set MaxLives=0
set GoalScore=0
set Translocator=True
set ForceRespawn=False
set PlayersMustBeReady=True
set Tournament=1
set GameSpeed=1.00
set NumBots=0
set Difficulty=6
set FriendlyFireScale=100
goto Start

:BR
set Map=BR-CBP2-Aquarius.ut2
set Mutator=XWeapons.MutNoSuperWeapon,utcompv16a.MutUTComp,TA100.MutTalkingIcon
set Game=XGame.xBombingRun
set timelimit=20
set MinPlayers=2
set MaxPlayers=10
set MaxSpectators=2
set weaponstay=True
set MaxLives=0
set GoalScore=0
set Translocator=True
set ForceRespawn=False
set PlayersMustBeReady=True
set Tournament=1
set GameSpeed=1.00
set NumBots=0
set Difficulty=6
set FriendlyFireScale=0
goto Start


:Start
if "%1" equ "" (set Servers=1) else (set Servers=%1)
if %Servers% gtr 9 (set Servers=1) else (if %Servers% equ 0 (set Servers=1))
title Start %Servers% server(s) (c) Agressor AKA zd.Insider
for /l %%A in (1, 1, %Servers%) do start "UT2004-Server #"%%A" Game:"%Game%" Players:"%MaxPlayers% /high ucc server %Map%?Game=%Game%?mutator=%Mutator%?MaxLives=%MaxLives%?GoalScore=%GoalScore%?TimeLimit=%TimeLimit%?MinPlayers=%MinPlayers%?MaxPlayers=%MaxPlayers%?MaxSpectators=%MaxSpectators%?Translocator=%Translocator%?WeaponStay=%WeaponStay%?FriendlyFireScale=%FriendlyFireScale%?ForceRespawn=%ForceRespawn%?PlayersMustBeReady=%PlayersMustBeReady%?Tournament=%Tournament%?GameSpeed=%GameSpeed%?NumBots=%NumBots%?Difficulty=6?port=7%%A77 -ini=Dedicated_Servers.ini -lanplay -log=..\UserLogs\Dedicated_Server%%A.log



2.Копируем файл ut2004.ini и и переименовываем его в Dedicated_Servers.ini, настраиваем его под свои потребности.

3.Кроме того в этом каталоге должны находиться мутаторы которые использованы в командной строке (в данном случае TA100, utcompv16a, NoSpdCombo).

ИСПОЛЬЗОВАНИЕ:
Dedicated_Servers.cmd [Количество серверов] [Тип игры]

[Количество серверов] - от 1 до 9
[Тип игры] - Duel, DM, TDM, CTF, ONS, AS, BR


Запуск без параметров, стартует 1 дуэльный сервер
пример: Dedicated_Servers.cmd

Запуск с "левым" первым параметром (отличным от 1, 2, 3, 4, 5, 6, 7, 8, 9), стартует 1 сервер, иначе стартует указанное к-во серверов
Запуск с "левым" вторым параметром (отличным от Duel, DM, TDM, CTF, ONS, AS, BR), стартует дуэльный сервер, иначе стартует указанный тип игры.

примеры:
Dedicated_Servers.cmd 2 CTF - запустится 2 CTF сервера
Dedicated_Servers.cmd 3 Duel - запустится 3 дуэльных сервера
Dedicated_Servers.cmd 10 Duel - запустится 1 дуэльный сервер
Dedicated_Servers.cmd A - запустится 1 дуэльный сервер

P.S.
В связи с тем что конфиг для серверов используется один, имена серверов в LAN-браузере будут одинаковыми...


Скачать готовые выделенные сервера можно здесь

Инфу предоставил: Agressor AKA zd.Insider
Последний раз редактировалось agressor 12 дек 2006, 15:51, всего редактировалось 5 раз(а).
AKA zd.Insider
Аватара пользователя
agressor
Путешественник
Путешественник
 
Автор темы
Сообщения: 362
Зарегистрирован:
07 фев 2002, 02:00
Откуда: Днепропетровск
Has thanked: 0 time
Have thanks: 0 time

Сообщение agressor » 11 дек 2006, 17:02

Подборка по редактору, мапингу и скриптингу:

Editing

Official
Technology from U (builds 200 - 226a) & UT (builds 400 - 436).
Unreal Developer Network: tech from U2, UT2003, & UC (builds 600 and up).
Creators of very good UT2003/4 editing video tutorials.
Creators of very good UT2003/4 editing video tutorials.
The people that make up 3D Buzz.
Designers of UDN''s video tutorials.
Designers of UDN''s video tutorials.
Technology for the PS2 and GC (builds 690 and up).
Psyonix ONS tutorial.
Articles by Matthias Worch.
Setting up navigation networks and AI actors.
Chris Hargrove''s courses on U2''s animation creation.

General
Mapping information.
Unreal engine documentation.
Info on UnrealEd, and general game info.
Info on UnrealEd, and general game info.
Wizard for creating Unreal content installers.
Download Toolbar Creator for UnrealEd and UMod tools here.
Unwrapping, Uvmapping and Muiltiple Texture assignment using 3dS 5.0.
UT2003 character animation.
Thread on animating and ragdoll effects.
Download the DDS Photoshop Plug-in here.
How to create a ragdoll.
Shane Caudle''s skinning help.
Loric''s tutorial.
chiQ.Net tutorial.
How to create a Voice Pack for UT2003 using Unreal Editor 3.0.
MP3 to Ogg Vorbis tutorial.
Change your crosshairs clientside.

Mapping
Level designing for different games.
Unreal Ops'' collection of map editing tutorials.
Incl. terrain.
Incl. terrain.
Incl. terrain.
Editing U games help.
Site on UT level editing.
A UT and UT2003 level editing site.
U editing basics.
UT and UT2003/4 mapping site.
Corsix'' mapping tutorials.
Information on UT2003 level editing.
By Rachel "Angel Mapper" Cordone. Ons TUT
By Rachel "Angel Mapper" Cordone. As TUT
Convert models to static meshes for scale reference.
A good read if you want your U games bots to be smart.
Tools for advanced map builders.
Tools for advanced map builders.
Custom brushes for different games.
More, free static meshes.
A tutorial. 3D Studio Max 5 to Unreal Tournament 2K3
Importing models using 3ds max.
Tutorial for LW 3D.
Textures, prefabs and tutorials.

UnrealScript
Information, tutorials about UnrealScript.
Community of UnrealScripters.
Creates API documentation for UnrealScript code.

Maps

General
Read reviews then and download maps for the U games.
UT & UT2003 maps and reviews.
UT & UT2003 maps and reviews.
UT2003 maps and map reviews.
Written by a 10 yr old, but has a nice map collection.
Maps for other games as well.
Download maps and a whole lot more from this database.
Maps for UT2004.
More map downloading and review reading. (No longer updated.)
Map reviews and downloads. (No longer updated.)
More map reviews. (No longer updated.)
UT2003 maps Clare "Webette" Doney likes.
Maps for UT.
Maps for UT.
Maps for UT.

Personal
Eric "zwarts" Evans.
Lasse "Dubbilan" Kolding.
A couple of level designers.
A bunch of Australian level designers.
U Maps made by Mick "VerMoord" Beard, the creator of DS9: The Fallen levels.
Norbert "Beppo" Bogenrieder worked on Infiltration.
Anthony "Bean" Nichols.
Mike "Bastard''O" Young.
Adam W. "Muad''dib" Stiles.
Nick_C.
Squacky.
Gary Blauvelt.
Arjan "Evil Atje" Vroegop.
AKA zd.Insider
Аватара пользователя
agressor
Путешественник
Путешественник
 
Автор темы
Сообщения: 362
Зарегистрирован:
07 фев 2002, 02:00
Откуда: Днепропетровск
Has thanked: 0 time
Have thanks: 0 time

Сообщение agressor » 11 дек 2006, 18:24

Running a Server as a Windows Service (UT2004)

From UnrealAdminWiki
Taken, in part from, Microsoft Support

This procedure uses the registry editor, use at your own risk!!!

To use as a server, make sure the computer you choose will boot with only a network cable and power cable attatched. Some BIOS changes may have to be made.

Make sure that ut2004 server runs correctly from a shortcut on the desktop and/or a *.bat file before using this procedure. You will need this later.

Obtain these files: Instsrv.exe and Srvany.exe from Microsoft.

Copy them into a directory that has NO SPACES IN THE PATH. I recommend the root of a drive.

Open a Command Window.

Execute the following: PATH_TO\Instsrv.exe NameOfService PATH_TO\Srvany.exe

Open regedit and navigate to HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\NameOfService to verify the service was created.

Right click on the new service and add a new "Key" named "Parameters"

Now, right click "Parameters" and add the following "String Value"s: AppDirectory, Application, and AppParameters.

Right click each "String Value" and "Modify" them as follows:

AppDirectory: The full path to the application's directory. Copy and paste from the shortcut/.bat file.

Example: C:\Games\ut2004\system

Application: The full path to the UCC.exe. Copy and paste from the shortcut/.bat file.

Example: C:\Games\ut2004\system\UCC.exe

AppParameters: Any parameters required to start the application to your specifications. Copy and paste from the shortcut/.bat file.

Example: server ONS-Torlan?game=Onslaught.ONSOnslaughtGame ini=UT2004.ini log=ons.log

Exit the registry editor.

Go to Start>Run>services.msc, select the new service and restart.

A simple test is to see if the Web Admin is available, if enabled. Otherwise, check the Task Manager to see if UCC.exe is running.

By default the new service will automatically start at Windows startup. Always reboot when you have toggled the service during testing.

http://wiki.unrealadmin.org
AKA zd.Insider
Аватара пользователя
agressor
Путешественник
Путешественник
 
Автор темы
Сообщения: 362
Зарегистрирован:
07 фев 2002, 02:00
Откуда: Днепропетровск
Has thanked: 0 time
Have thanks: 0 time

Сообщение agressor » 12 дек 2006, 20:46

Создание простого мутатора на примере Vampire

Эта статья в первой своей части повторяет статью "Основы работы с Unreal Script" (или наоборот)

Основная идея
В данной статье нами будет рассмотрен процесс создания простого мутатора Vampire. Идея мутатора состоит в том, что игрок, который наносит урон другому игроку, получает количество единиц здоровья равное нанесённому урону. Таким образом мы имеем что-то вроде вампиризма. Эта идея была выдвинута на одном из англоязычных сайтов по программированию на UnrealScript. Мы же пойдём дальше и введём также поддержку конфигурационных файлов, окон настройки мутатора и введём несложный графический эффект, показывающий, что игрок в данный момент крадёт жизнь у другого.

Подготовка к работе
Компилятор UCC.exe для UnrealScript устроен таким образом, что принимает только определённую структуру расположения папок со скриптами. Дело в том, что для начала вам необходимо создать все условия для того что бы компилятор нашёл ваш исходный код и создал U-файл (такие файлы называются Packages, но для простоты далее мы будем употреблять слово пакаджи) с определённым именем. Делается это так:

1. В папке UnrealTournament (там где находятся папки System, Maps, Textures и т.д.) создаём свою папку с названием нашего мутатора. Именно с таким названием будет создан наш U-файл или по-другому пакадж. В нашем случае имя папки будет, например, Vampire.

2. В папке Vampire создаём папку Classes. В этой папке будут храниться наши файлы скриптов (UC-файлы).

3. Теперь необходимо сообщить UCC.exe, что скрипты, лежащие в папке Vampire должны быть скомпилированы. Для этого в файле UnrealTournament.ini, находящемся в UnrealTournament/System, нужно дописать строчку EditPackages=Vampire после других строчек, начинающихся с EditPackages, в конце секции [Editor.EditorEngine].

В принципе больше ничего не нужно. Теперь достаточно запустить UCC.exe с параметром Make и все скрипты из папки Vampire будут скомпилированы. Как результат в папке UnrealTournament/System появится пакадж Vampire.u (если не возникнет никаких ошибок в процессе трейсинга и компиляции скриптов). Понятно, что папка Classes сейчас пуста и при компиляции у нас возникнет ошибка.
Я предлагаю упростить процесс отладки и последующей компиляции нашего мутатора. Не всем удобно постоянно запускать UCC.exe из командной строки с каким-либо параметром. Также для проверки мутатора нам необходимо постоянно запускать игру, создавать новый сервер и выбирать из списка мутаторов наш Vampire. Что бы сократить время отладки сделайте следующее:

1. В папке Vampire создайте папку General (это может быть любое название, но пусть это будет General - общая).

2. В папке General создайте BAT-файл с именем compile.bat, откройте его и впишите такие строки:
cd ..
cd ..
cd System
del Vampire.u
ucc make
Это обеспечит нам переход в папку UnrealTournament/System, удаление старой версии нашего мутатора и запуск UCC.exe с параметром Make. Рекомендую в свойствах нашего BAT-файла убрать флажок «Закрывать окно по завершении сеанса работы», так как нам нужно видеть какие ошибки возникли в процессе компиляции.
3. В папке Vampire создайте ярлык на наш BAT-файл. Это просто для

удобства. Советую назвать ярлык COMPILE и поставить ему какую-нибудь приметную иконку.

4. В папке Vampire создайте два ярлыка на UnrealTournament.exe и назовите
их, например, DM-Deck16][ и CTF-Face.
В свойствах ярлыка DM-Deck16][ в поле ввода “Обьект” после указанного
пути к программе введите следующее:
DM-Deck16][.unr?mutator=Vampire.Vampire
Это может, например, выглядеть так:
"C:\Program Files\GT Interactive\UnrealTournament\System\ UnrealTournament.exe" DM-Deck16][.unr?mutator=Vampire.Vampire
Примерно также поступим с ярлыком CTF-Face.
В свойствах ярлыка CTF-Face в поле ввода “Обьект” после указанного
пути к программе введите следующее:
CTF-Face.unr?game=Botpack.CTFGame?mutator=Vampire.Vampire
Это может, например, выглядеть так:
"C:\Program Files\GT Interactive\UnrealTournament\System\ UnrealTournament.exe" CTF-Face.unr?game=Botpack.CTFGame? mutator=Vampire.Vampire
Данные опирации дадут нам возможность быстро запускать игру на картах DM-Deck16][ и CTF-Face с нашим мутатором. Иногда необходимо проверять мутаторы на разных типах игры. Это два ярлыка позволяют это делать для DeathMatch и CaptureTheFlag.

Если вы проделали всё, что указано выше, то у вас должно выйти что-то подобное такому:

UnrealTournament (ПАПКА)
|
|- Vampire (ПАПКА)
|
|-COMPILE (ярлык на compile.bat)
|
|-DM-Deck16][ (ярлык)
|
|-CTF-Face (ярлык)
|
|-General (ПАПКА)
| |
| |-compile.bat (файл)
|
|-Classes (ПАПКА)

Теперь всё готово и мы можем переходить с самому процессу написания скриптов.

Основной код мутатора
Итак, приступим. Основой каждого мутатора, создаваемого пользователем, является класс, наследующий свойства и методы класса Mutator. Создайте в папке Vampire текстовый файл Vampire.uc и впишите в него следующие строки:

//===================================
// Vampire ; This is mutator script.
// Description: You gain life equal to the amount of damage you do to
// an enemy.
//===================================

class Vampire expands Mutator;

var bool Initialized;

var() float LifeStolenPerHit;
var() int MaxLife;
var() bool bInflictedDamageOnly;

function PostBeginPlay()
{
if (Initialized)
return;
Initialized = True;
Level.Game.RegisterDamageMutator( Self );
}

function MutatorTakeDamage( out int ActualDamage, Pawn Victim, Pawn InstigatedBy, out Vector HitLocation,
out Vector Momentum, name DamageType)
{
if ((InstigatedBy.IsA('Bot') || InstigatedBy.IsA('PlayerPawn')) && (Victim != InstigatedBy) && (InstigatedBy != None) && (Victim != None))
{
if ((Victim.Health < ActualDamage) && bInflictedDamageOnly)
ActualDamage = Victim.Health;
InstigatedBy.Health += ActualDamage * LifeStolenPerHit;

if ((InstigatedBy.Health > MaxLife) && (MaxLife != 0))
{
InstigatedBy.Health = MaxLife;
}
}

if ( NextDamageMutator != None )
NextDamageMutator.MutatorTakeDamage( ActualDamage, Victim, InstigatedBy, HitLocation, Momentum, DamageType );
}

defaultproperties
{
LifeStolenPerHit=1.000000
MaxLife=200
bInflictedDamageOnly=True
}

Теперь детально разберём этот текст.
Как видите в начале файла стоят строки:

//===================================
// Vampire ; This is mutator script.
// Description: You gain life equal to the amount of damage you do to
// an enemy.
//===================================

Всё, что стоит после символов //, считается комментарием. Этот комментарий является однострочным, то есть символами // можно закомментировать только тот участок текста, который стоит после этих символов и до конца строки. В UnrealScript есть также многострочный комментарий. Он начинается с символов /* и заканчивается соответственно символами */. Таким образом, весь текст, что стоит между этими символами будет закомментирован. Комментарии не обязательны, но иногда в процессе отладки нужно временно убрать некоторый участок текста. Также комментарии служат для упрощения понимания кода скрипта. В нашем случае в комментарии указано название класса и краткое описание.
Далее идёт описание класса мутатора:

class Vampire expands Mutator;

Описание начинается со слова class, после чего идёт название описываемого класса. В нашем случае это Vampire. После определения имени класса идёт слово expands, которое означает, что описываемый класс является наследником какого-либо другого класса. И, наконец, идёт имя родительского класса. Так как мы создаём мутатор, то родительским для нашего класса является класс Mutator. Иногда вы можете увидеть в описании других классов, что слово expands заменено на слово extends. С самого начала UnrealScript использовал слово expands, но довольно давно оно было заменено на слово extends, которое используется в Java. Компилятор принимает их обоих и понимает одинаково, но в следующих версиях движка слово expands может не работать. Поэтому всегда используйте слово extends когда у вас есть выбор. Пусть в нашем примере будет слово expands что бы вы видели, что бывают различные методы описания, но всё таки потом рекомендуется заменить его на слово extends. Как видите, в конце строчки ставится сивол ; (точка с запятой). Он является разделительным символом и ставится в конце строки после описания чего-либо или после выражений. Точка с запятой не ставится перед символом { и после символа }. Заметьте также, что имя описываемого класса должно совпадать с именем файла, в котором этот класс определён. Например у нас класс Vampire описан в файле Vampire.uc (это необходимо и в случае отличия будет ошибка). Также после имени родительского класса могут идти модификаторы:

Abstract – данный класс не может быть вызван (spawned), так как является базовым;
Config – значения переменных данного класса сохраняются во внешнем конфигурационном файле. Если после этого ключевого слова стоят скобки с каким либо текстом в них, то значения переменных будут сохраняться в INI-файле с именем, стоящим в скобках. В противном случае (если в скобках ничего нет) значения переменных будут сохраняться в файле UnrealTournament.ini, который используется для этого по умолчанию;
NoUserCreate – данный класс не может быть помещён на уровень с помощью UnrealEd;
Native – некоторые фрагменты данного класса описаны с использованием внешнего программирования (импорт функций из библиотек DLL);
NativeReplication – переменные данного класса полностью описаны с использованием внешнего программирования;
SafeReplace – означает, что ссылка на этот класс может быть изменена на Null (пустая ссылка) или на значение по умолчанию, если данный класс не найден ни в одном из пакаджей. Пакаджи сами по себе не имеют свойства SafeReplace. Например вы в редакторе сделали свою карту с применением двух текстур MyTex1 и MyTex2 из пакаджа MyTextures.utx, а потом сохранили.
Если теперь вы удалите из пакаджа MyTextures.utx текстуру MyTex1, то на вашей карте те грани, на которые была наложена текстура MyTex1, покроются другой текстурой (той, которая выбрана по умолчанию) и карта всё равно будет запускаться. Но если теперь удалить сам пакадж MyTextures.utx и запустить карту, то игра выдаст сообщение об ошибке: &laquo;Пакадж MyTextures.utx не найден&raquo;;
Within <Класс> - обьекты данного класса могут быть созданы только внутри указанного Класса (это не работает для UnrealTournament v 420);
PerObjectConfig – информация о каждом обьекте данного класса должна храниться в конфигурационном файле отдельно под секцией с названием, зависящим от его (обьекта) имени. Смотри описание ключевого слова Config;
Transient – данный класс не включается при сохранении игрового соcтояния (в Unreal);
NoExport – не экспортировать в заголовок C++. Исполнение через командную строчку "UCC.exe Make -h" не будет генерировать автоматически заголовок C++ для функций и событий, описанных с помощью внешнего программирования.

После описания класса обычно идёт описание переменных (свойств, параметров) класса:

var bool Initialized;

var() float LifeStolenPerHit;
var() int MaxLife;
var() bool bInflictedDamageOnly;

Описание переменной начинается со слова var (от англ. Variable - величина), после чего идёт тип переменной (например, float,bool,int,string и т.д.), а за ним имя переменной. Если за словом var стоят скобки, то это означает, что этот параметр помещается в каком-нибудь разделе. Пример: если в скобках указано название раздела Display, а переменная называется bUnlit, то в редакторе UnrealEd можно изменять значение данного параметра через окно Actor properties. В случае, когда в скобках не указано ничего, редактор UnrealEd не даёт возможности изменять значение параметра и единственный способ сделать это – редактировать раздел defaultproperties в скрипте класса (об этом ниже). Иногда вместо слова var вы можете встретить другие слова. Все они как и var обозначают характер описываемого свойства.
Они могут быть следующие:

var – переменная, может принимать различные значения в зависимости от типа;
const – константа. Не может быть изменена ни из UnrealScript, ни из вне (с помощью внешнего программирования);
local – используется только внутри функций. Данная переменная существует на этапе исполнения функции, в которой она описана, а потом её значение будет утеряно.

Описываемые переменные могут быть следующих типов:

bool – бинарная переменная для логических опираций. Значения: True/False (Правда/Ложь);
int – целое значение от –2147483648 до 2147483647 (включая пределы);
byte – целое значение от 0 до 255 (включая пределы). Значение, которое выходит за эти границы будет заворачиваться. Пример: число 256, введённое в переменную типа byte примет значение 0;
float – вещественное значение, десятичная дробь;
string – строка символов, заключённых в двойных кавычки;
name – идентификатор (имя), заключённый в одинарные кавычки. Имена могут содержать только буквы. Цифры и символ подчёркивания. Регистр букв в именах не имеет значения.

Иногда вы можете встретить переменные типов vector, rotator, color и другие. Дело в том, что это не предопределённые типы, а структуры. UnrealScript даёт нам возможность создавать свои типы используя ключевые слова struct и enum.
Переменные, описываемые после слова struct являются структурами. Описываются они так :

var struct <Имя_структуры> {
<Описание переменной 1>;
< Описание переменной 2>;

} <Имя_переменной 1>, <Имя_переменной 2>, …;

Таким образом структура представляет собой переменную, состоящую из набора других переменных (полей).
Служебное слово enum служит для определения перечисляемых типов. Описываются они подобно структурам:

var enum <Имя_типа> {
<Значение1>,
< Значение 2>,

} <Имя_переменной 1>, < Имя_переменной 2>, …;

Это как бы список значений, идущих по порядку. Если вам нужно узнать количество значений в этом списке, используйте функцию EnumCount(<Имя_типа>).

У нас описаны такие переменные класса:

- Булевская переменная Initialized – служебная переменная для проверки корректной работы мутатора (в принципе не обязательна);

- Вещественная переменная LifeStolenPerHit – указывает какой прцент от урона перейдёт в жизнь;

- Целая переменная MaxLife – определяет максимальное количество жизни, которое может быть у игрока (что-бы был лимит вампиризма);

- Булевская переменная bInflictedDamageOnly – если урон, нанесённый жертве больше её жизни и значение этого параметра равно True, то игрок, нанёсший урон получит количество жизни равное жизни жертвы, а если значение параметра равно False, то игрок, нанёсший урон получит количество жизни равное нанесённому урону как бы он ни был велик. В любом случае, после этого жертва умирает.

Теперь перейдём непосредственно к коду, описывающему методы нашего класса. Методы (функции) описываются так:

<Модификаторы_функции> function/event <Тип_функции> <Имя_функции> (<Модификаторы_параметра> <Тип_параметра> <Имя_параметра>, …)
{

}

Сначала идут модификаторы функции. Они могут быть такие:

final – данная функция не может быть перегружена (переопределена – override) в подклассах или состояниях (state) этого класса. Функции, определённые как статические (static) и финальные (final), автоматически считаются симулированными (simulated).
iterator – данная функция является итерационной функцией (итератором) для использования после ключевого слова foreach.
Итераторами могут быть только функции, определённые с помощью внешнего программирования (native).
latent – данная функция требует определённых затрат времени на выполнение. Латентные функции могут вызываться только из кода состояний (state) или из других латентных функций. Латентные функции должны быть внешними (native).
native (или intrinsic)– данная функция определена во внешнем С++ коде.
native(<Номер>) – данная функция находится под указанным номером в С++ коде.
simulated – данная функция вызывается на сервере и на клиенте при игре по сети. Функции, не определённые как симулированные игнорируются при работе скрипта у клиента.
singular – данная функция предотвращает самовызов.
static – данная функция может быть вызвана без экземпляра класса, в котором она описана.
exec – данная функция может быть вызвана через консоль.

После модификаторов функции идёт ключевое слово function или event. Слово event имеет такое же значение как и function, но при экспорте скриптов в С++ код имеет свои особенности.

Потом идёт тип функции, который определяет, данные какого типа возвращает функция. Типы функций могут быть такими же как и у переменных.

Далее идёт имя функции. Это просто идентификатор.

После имени между двух круглых скобок идёт список параметров, которые описываются подобно переменным, но без слова var. Описания параметров отделяются запятыми. Перед каждым из параметров может стоять модификатор параметра, определяющий его поведение.
Модификаторы параметров могут быть следующие:

out – значение переменной, которая будет подставлена в качестве данного параметра может быть изменено в теле функции. Если не ставить out перед описанием параметра и передать в качестве параметра переменную, то функция возмёт из данной переменной значение, обработает его и возвратит некоторое значение в то место кода, где она (функция) стоит. Если же слово out стоит перед описанием параметра и в качестве параметра передаётся некая переменная, то функция возмёт значение из этой переменной, запомнит имя переменной, обработает значение, а потом возвратит некоторое значение в то место кода, где она (функция) стоит, но также изменит значение переменной, подставленной в качестве параметра. Это можно использовать, когда требуется что бы функция возвращала более одного значения. Возможно моё обьяснение путанное и непонятное, но это довольно сложно обьяснить человеку, впервые столкнувшемуся с программированием. Для корректного обьяснения требуется вводить такие понятия как параметры-переменные и параметры-значения, а также понятие указателя на область памяти. Желательно всё таки знать основы программирования на языках С++ или Pascal;
optional – данный параметр может быть пропущен при вызове процедуры. Если вы хотите пропустить данный параметр, то запятые всё равно нужны. Просто межлу ними ничего не будет стоять;
coerce – значение, которое передаётся функции через данный параметр, будет автоматически приведено к указанному типу.

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

Первым идёт метод PostBeginPlay(), который у нас определяется так:

function PostBeginPlay()
{
if (Initialized)
return;
Initialized = True;
Level.Game.RegisterDamageMutator( Self );
}

Этот метод вызывается после создания экземпляра класса мутатора. Короче, почти в самом начале. Тут сначала с помощью служебной переменной Initialized мы проверяем мутатор на инициализацию. Если мутатор инициализирован, то выйти из данной функции (return – выйти из тела функции). В противном случае (мутатор не инициализирован) – функция выполняется дальше и вызывается метод RegisterDamageMutator с параметром Self, указывающим на данный мутатор. Метод RegisterDamageMutator необходимо вызывать в тех мутаторах, где нужно что-либо делать, когда живым обьектам (Pawn) наносится урон. Этот метод регистрирует наш мутатор как DamageMutator. Если мутатору не будет поставлен такой статус, то функция MutatorTakeDamage для обработки нанесённого урона вызываться не будет.

Далее описывается функция, которая и является костяком всего мутатора.

function MutatorTakeDamage( out int ActualDamage, Pawn Victim, Pawn InstigatedBy, out Vector HitLocation,
out Vector Momentum, name DamageType)
{
if ((InstigatedBy.IsA('Bot') || InstigatedBy.IsA('PlayerPawn')) && (Victim != InstigatedBy) && (InstigatedBy != None) && (Victim != None))
{
if ((Victim.Health < ActualDamage) && bInflictedDamageOnly)
ActualDamage = Victim.Health;
InstigatedBy.Health += ActualDamage * LifeStolenPerHit;

if ((InstigatedBy.Health > MaxLife) && (MaxLife != 0))
{
InstigatedBy.Health = MaxLife;
}
}

if ( NextDamageMutator != None )
NextDamageMutator.MutatorTakeDamage( ActualDamage, Victim, InstigatedBy, HitLocation, Momentum, DamageType );
}

Эта функция вызывается тогда, когда один живой обьект (Pawn) наносит урон другому. Она вызывается в методе TakeDamage живого обьекта, которому был нанесён урон, если мутатор зарегистрирован как DamageMutator. Если наш мутатор будет работать, то игра сначала определит какой урон наносит один игрок другому с помощью оружия и параметры попадания, затем идёт проверка инвентаря игрока на предмет наличия брони для уменьшения урона, а потом мы можем обработать это событие по-своему и изменить сам механизм нанесения урона. Как видите, процедура имеет некоторые параметры:

out int ActualDamage – параметр, определяющий величину нанесённого урона. Величина урона должна быть целым числом (int).Так как параметр описан со словом out, то это означает, что в процедуру через данный параметр будет передано некоторое значение, которое мы можем обработать и изменить, а затем уже оно будет возвращено обратно во внешний код;
Pawn Victim – параметр, указывающий на обьект, которому был нанесён урон. Это жертва;
Pawn InstigatedBy – параметр, указывающий на обьект, который нанёс урон жертве. Это подстрекатель;
out Vector HitLocation – параметр, содержащий вектор, координаты которого определяют координаты точки попадания. Именно в эту точку подстрекатель нанёс урон жертве. Так как параметр описан со словом out, то это означает, что в процедуру через данный параметр будет передано некоторое значение, которое мы можем обработать и изменить, а затем уже оно будет возвращено обратно во внешний код;
out Vector Momentum – параметр, определяющий вектор отдачи при получении урона жертвой. Так как параметр описан со словом out, то это означает, что в процедуру через данный параметр будет передано некоторое значение, которое мы можем обработать и изменить, а затем уже оно будет возвращено обратно во внешний код;
name DamageType – параметр, определяющий тип наносимого урона. В соответствии с различными типами урона можно описать различные методы его обработки.

Далее в теле функции идёт проверка:

if ((InstigatedBy.IsA('Bot') || InstigatedBy.IsA('PlayerPawn')) && (Victim != InstigatedBy) && (InstigatedBy != None) && (Victim != None))

Тут проверяется:
- Является ли подстрекатель ботом;
- Является ли подстрекатель игроком;
- Не совершила ли жертва суицид;
- Существует ли жертва как обьект;
- Существует ли подстрекатель как обьект.
Эти проверки нужны для корректной работы мутатора. Если данные условия выполняются, то выполняется следующий отрезок кода:

if ((Victim.Health < ActualDamage) && bInflictedDamageOnly)
ActualDamage = Victim.Health;
InstigatedBy.Health += ActualDamage * LifeStolenPerHit;

if ((InstigatedBy.Health > MaxLife) && (MaxLife != 0))
{
InstigatedBy.Health = MaxLife;
}

Его можно разбить на две части.
Первая часть:

if ((Victim.Health < ActualDamage) && bInflictedDamageOnly)
ActualDamage = Victim.Health;
InstigatedBy.Health += ActualDamage * LifeStolenPerHit;

Тут оценивается количество жизни у жертвы и в зависимости от параметров bInflictedDamageOnly и LifeStolenPerHit нашего мутатора начисляется определённое количество жизни подстрекателю.
Вторая часть:

if ((InstigatedBy.Health > MaxLife) && (MaxLife != 0))
{
InstigatedBy.Health = MaxLife;
}

Тут оценивается количество жизни подстрекателя после получения дополнительной жизни. В зависимости от параметра MaxLife нашего мутатора жизнь подстрекателя будет ограничена определённым числом или не будет ограничена вообще (кроме ограничения поставленного разработчиками в игре).

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

После всего этого (в конце функции) идут стандартные для DamageMutator’ов строки:

if ( NextDamageMutator != None )
NextDamageMutator.MutatorTakeDamage( ActualDamage, Victim, InstigatedBy, HitLocation, Momentum, DamageType );

Они отвечают за корректную работу механизма нанесения урона, который описан в нашем мутаторе в том случае, когда кроме нашего мутатора подключены другие мутаторы, которые имеют статус DamageMutator и определяют функцию MutatorTakeDamage по-своему.
Тут идёт проверка на наличие следующего DamageMutator’а. Если такой мутатор есть, то выполняется его метод MutatorTakeDamage. Таким образом после обработки урона нашим мутатором его обрабатывает следующий DamageMutator и так далее пока все DamageMutator’ы не обработают наносимый урон.

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

Вот и всё. Класс нашего мутатора описан. Теперь нужно скомпилировать текст скрипта в пакадж. Если вы всё делали в соответствии с действиями указанными в разделе &laquo;Подготовка к работе&raquo;, то вам нужно просто зайти в папку UnrealTournament/Vampire и запустить файл COMPILE (ярлык на файл compile.bat). Если в процессе компиляции будут возникать ошибки, то ещё раз прочитайте и проделайте указанные в данной статье действия по написанию кода скрипта. Если ошибка не устраняется, то пишите мне на E-mail: [email protected] и я попробую помочь. В результате правильной компиляции мы должны получит файл Vampire.u в папке UnrealTournament/System.
Осталось только присоединить наш пакадж к движку Unreal Tournament. Игра должна &laquo;увидеть&raquo; наш мутатор и поместить его в список рядом с другими мутаторами. Это делается с помощью INT-файлов.
Создайте в папке System текстовый файл, назовите его Vampire.int и откройте в каком-либо текстовом редакторе (Wordpad например).
Добавьте следующие строки:

[Public]
Object=(Name=Vampire.Vampire,Class=Class,MetaClass=
Engine.Mutator,Description="Vampire,You gain life equal to the amount of damage you do to an enemy.")

Это и есть привязка. Тут указывается имя мутатора как класса, тип обьекта, родительский класс и описание. Имя состоит из имени пакаджа и имени класса в нём, разделяющихся точкой. Тип нашего обьекта – Class, а не текстура или звук. Родительским является класс Mutator, описанный в пакадже Engine. Описание состоит из двух предложений, разделяемых запятой. Первое предложение определяет имя мутатора в списке мутаторов, а второе – строчку, которая будет показываться в стоке состояния снизу экрана.
Сохраните и закройте этот файл.
Теперь запускайте UnrealTournament, выбирайте ваш мутатор в списке и начинайте новую игру.

Добавляем эффекты
Допустим, что нам захотелось украсить наш мутатор некоторым эффектом. Мы хотим, что бы при получении игроком жизни от его жертвы, вокруг него создавалась красная оболочка. Сделаем это.
Создайте в папке Vampire/Classes текстовый файл и назовите его VampireShell.uc – это и будет файл, описывающий класс оболочки.
Откройте этот файл и впишите в него следующие строки:

//===================================
// VampireShell ; This is effect script.
// Description: Red shell around damage instigator.
//===================================

class VampireShell expands Effects;

defaultproperties
{
bAnimByOwner=True
bOwnerNoSee=True
bNetTemporary=False
bTrailerSameRotation=True
Physics=PHYS_Trailer
RemoteRole=ROLE_SimulatedProxy
LODBias=0.500000
DrawType=DT_Mesh
Style=STY_Translucent
Texture=None
ScaleGlow=0.500000
AmbientGlow=64
Fatness=157
bUnlit=True
bMeshEnviroMap=True
LifeSpan=0.500000
}

Разберём скрипт данного класса. Как видите, в начале поставлены комментарии для облегчения разбора кода (как это было со скриптом мутатора).
После комментария идёт описание класса нашей оболочки, которая является классом-наследником класса Effects.
Никаких методов и переменных нам не требуется, поэтому сразу идёт раздел defaultproperties. Переменные, указанные в данном разделе требуют более детального разбора так как описаны не нами, а разработчиками в классах, которые являются родительскими для нашего (Effects, Actor). Итак, мы имеем следующие переменные:

bAnimByOwner=True – анимировать в соответствии с
движениями владельца. Для того что бы наша оболочка повторяла движения модели игрока;
bOwnerNoSee=True – невидимый для владельца. Для того что бы игрок не видел оболочку перед глазами;
bNetTemporary=False – обьект и его переменные устанавливаются только в момент его создания и не подлежат дальнейшей обработке. Всё что обрабатывается клиентской частью не связано больше с сервером. Обычно это свойство устанавливается для классов, которые наследуются от класса Effects, а также других классов, которые существуют независимо (неуправляемые снаряды и т.п.). У нас оболочка как раз управляема (повторяет движения игрока), поэтому - False;
bTrailerSameRotation=True – поворот такой же как и у владельца. Для того что бы оболочка поворачивалась вместе с игроком;
Physics=PHYS_Trailer – тип физики. У нас оболочка прикреплена к игроку и её координаты меняются вместе с движением игрока (Trailer от англ. прицеп);
RemoteRole=ROLE_SimulatedProxy – роль данного обьекта в игровом мире. В данном случае мы ставим такое значение, которое применяется для обьектов, движение которых может быть предсказано;
LODBias=0.500000 – уровень детализации (LOD - Level of detail). По умолчанию в обьектах стоит 1;
DrawType=DT_Mesh – способ отрисовки обьекта. У нас трёхмерный обьёмный обьект;
Style=STY_Translucent – стиль наложения текстур. У нас прозрачная оболочка;
Texture=None – текстура обьекта. У нас ничего не стоит так как текстура выбирается в коде мутатора (смотрите далее);
ScaleGlow=0.500000 – в нашем случае прозрачной оболочки (Style=STY_Translucent) это степень прозрачности. Величина данного параметра меняется от 0 до 1. У нас 0.5 – полупрозрачная оболочка;
AmbientGlow=64 – яркость освещённости. Величина меняется от 0 до 255 (255 = пульсация);
Fatness=157 – ширина обьекта. По умолчанию 128 и меняется от 0 до 255.
bUnlit=True – не освещать обьект. У нас источники освещения не освещают, а тени не затеняют оболочку.
bMeshEnviroMap=True – хромовая поверхность. У нас оболочка с эффектом зеркальной поверхности.
LifeSpan=0.500000 – время жизни обьекта. Если это значение равно 0, то обьект существует до тех пор пока для него не будет вызван метод Destroy. Если значение отлично от нуля, то игра автоматически удалит обьект по истечении заданного времени в секундах. У нас стоит 0.5 – оболочка будет присутствовать на игроке пол-секунды, после чего исчезнет.

Оболочка описана. Теперь следует внести некоторые изменения в код мутатора. После добывления эффекта текст скрипта в файле Vampire.uc должен выглядеть так:

//===================================
// Vampire ; This is mutator script.
// Description: You gain life equal to the amount of damage you do to
// an enemy.
//===================================

class Vampire expands Mutator;

var bool Initialized;
var vector InstFog;
var float InstFlash;
var VampireShell VampireShellEffect;
var texture ShellSkin;
var class<VampireShell> ShellType;

var() float LifeStolenPerHit;
var() int MaxLife;
var() bool bInflictedDamageOnly;
var() bool bIsRegenEffect;

function PostBeginPlay()
{
if (Initialized)
return;
Initialized = True;
Level.Game.RegisterDamageMutator( Self );
}

function MutatorTakeDamage( out int ActualDamage, Pawn Victim, Pawn InstigatedBy, out Vector HitLocation,
out Vector Momentum, name DamageType)
{
if ((InstigatedBy.IsA('Bot') || InstigatedBy.IsA('PlayerPawn')) && (Victim != InstigatedBy) && (InstigatedBy != None) && (Victim != None))
{
if ((Victim.Health < ActualDamage) && bInflictedDamageOnly)
ActualDamage = Victim.Health;
InstigatedBy.Health += ActualDamage * LifeStolenPerHit;

if (bIsRegenEffect && (MaxLife != 0 ))
{
FlashShell(InstigatedBy);
if ( InstigatedBy.IsA('PlayerPawn') )
PlayerPawn(InstigatedBy).ClientInstantFlash(InstFlash, InstFog);
}

if ((InstigatedBy.Health > MaxLife) && (MaxLife != 0))
{
InstigatedBy.Health = MaxLife;
}
}

if ( NextDamageMutator != None )
NextDamageMutator.MutatorTakeDamage( ActualDamage, Victim, InstigatedBy, HitLocation, Momentum, DamageType );
}

function FlashShell(pawn Other)
{
if (VampireShellEffect == None)
{
VampireShellEffect = Spawn(ShellType, Other,,Other.Location, Other.Rotation);
}
if ( VampireShellEffect != None )
{
VampireShellEffect.Mesh = Other.Mesh;
VampireShellEffect.DrawScale = Other.Drawscale;
VampireShellEffect.Texture = ShellSkin;
}
}

defaultproperties
{
LifeStolenPerHit=1.000000
MaxLife=200
bInflictedDamageOnly=True
bIsRegenEffect=True
InstFog=(X=475.000000,Y=325.000000,Z=145.000000)
InstFlash=-0.400000
ShellSkin=FireTexture'UnrealShare.Belt_fx.ShieldBelt.RedShield'
ShellType=Class'Vampire.VampireShell'
}

Как видите, в начале файла добавились описания новых переменных:

var vector InstFog;
var float InstFlash;
var VampireShell VampireShellEffect;
var texture ShellSkin;
var class<VampireShell> ShellType;

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

var() bool bIsRegenEffect;

Вывод оболочки нужно производить в момент получения жизни игроком-подстрекателем. Это делается путём добавления нескольких строчек в тело функции MutatorTakeDamage, которая и вызывается в момент нанесения урона. Добавляются такие строки:

if (bIsRegenEffect && (MaxLife != 0 ))
{
FlashShell(InstigatedBy);
if ( InstigatedBy.IsA('PlayerPawn') )
PlayerPawn(InstigatedBy).ClientInstantFlash(InstFlash, InstFog);
}

Тут в условном операторе if проверяется состояние переменной bIsRegenEffect, а также оценивается текущие количество жизни игрока-подстрекателя. Далее следует вызов функции FlashShell, которая будет описана ниже. Ещё добавлены строки, отвечающие за вывод дополнительных графических эффектов.
Для создания оболочки вокруг игрока опишем функцию:

function FlashShell(pawn Other)
{
if (VampireShellEffect == None)
{
VampireShellEffect = Spawn(ShellType, Other,,Other.Location, Other.Rotation);
}
if ( VampireShellEffect != None )
{
VampireShellEffect.Mesh = Other.Mesh;
VampireShellEffect.DrawScale = Other.Drawscale;
VampireShellEffect.Texture = ShellSkin;
}
}

Эта функция принимает в качестве параметра обьект класса pawn. Передавая в качестве значения параметра Other экземпляр класса pawn, соответствующий игроку, вокруг которого необходимо вывести оболочку, мы можем управлять нашим эффектом. В теле функции производятся действия, связанные с созданием, формированием и выводом оболочки. Сначала идёт несколько строчек, отвечающих за создание самого экземпляра класса VampireShell в игровом мире. Это делается с помощью функции Spawn, которая довольно часто используется и требует более детального рассмотрения. Она имеет такой синтаксис:

function actor Spawn
(
class<actor> SpawnClass,
optional actor SpawnOwner,
optional name SpawnTag,
optional vector SpawnLocation,
optional rotator SpawnRotation
);

Параметры:

SpawnClass – класс, экземпляр которого должен быть вызван;
SpawnOwner – владелец вызываемого класса. Это значение, которое будет подставлено в свойство Owner вызванного обьекта;
SpawnTag – значение, которое будет присвоено свойству Tag при создании обьекта;
SpawnLocation – вектор, определяющий координаты в пространстве, в которые должен быть вызван обьект;
SpawnRotation – ротатор, который определяет поворот обьекта. Подобно вектору указывает &laquo;направление взгляда&raquo; обьекта.

Таким образом в строчке:

VampireShellEffect = Spawn(ShellType, Other,,Other.Location, Other.Rotation);

мы создаём экземпляр класса, который определён в переменной ShellType. Для данного обьекта поле Owner содержит указатель на экземпляр класса actor, определяющего игрока, для которого создана оболочка. Значения полей Location и Rotation (координаты и поворот) оболочки совпадают со значениями аналогичных полей для игрока, для которого создана оболочка. Поле Tag не заполняется так как в этом нет необходимости.

После вызова обьекта всегда следует проверять факт его существования. Если какие-либо из параметров функции Spawn заданы неправильно (например вы пытаетесь вызвать экземпляр класса не описанного нигде в UnrealScript), то обьект просто не создастся. Поэтому перед работой с выбранным обьектом следует проверять его на предмет существования. Делается у нас это следующим образом:

if ( VampireShellEffect != None )
{
VampireShellEffect.Mesh = Other.Mesh;
VampireShellEffect.DrawScale = Other.Drawscale;
VampireShellEffect.Texture = ShellSkin;
}

Тут проверяется создание оболочки и если она существует, то мы устанавливаем её форму (Mesh) подобно форме игрока, размер (Drawscale) подобно размеру игрока и устанавливается текстура, определённая в переменной ShellSkin.

Также в разделе defaultproperties добавились дополнительные строчки:

bIsRegenEffect=True
InstFog=(X=475.000000,Y=325.000000,Z=145.000000)
InstFlash=-0.400000
ShellSkin=FireTexture'UnrealShare.Belt_fx.ShieldBelt.RedShield'
ShellType=Class'Vampire.VampireShell'

Тут мы устанавливаем значение переменной bIsRegenEffect по-умолчанию равным True (показывать оболочку). Переменные InstFog и InstFlash отвечают за некоторые графические эффекты, а переменные ShellType и ShellSkin определяют тип класс оболочки и текстуру оболочки соответственно.

Подключаем конфигурационный файл
Иногда необходимо, чтобы ваши настройки для какого-либо мода сохранялись при выходе из Unreal Tournament в конфигурационном файле. Существует очень простой способ, позволяющий классам UnrealScript сохранять и загружать данные, используя при этом INI-файлы. Это очень удобно, так как вы можете конфигурировать ваш класс (например, менять значения некоторых полей и свойств) без повторной компиляции. Такой механизм обращения к INI-файлам реализуется с помощью ключевого слова Config, которое и указывает, какую переменную и в каком файле сохранять. Для подключения конфигурационного файла к нашему мутатору достаточно добавить несколько дополнительных слов в файл Vampire.uc в разделе описания класса и переменных:

//===================================
// Vampire ; This is mutator script.
// Description: You gain life equal to the amount of damage you do to
// an enemy.
//===================================

class Vampire expands Mutator config(Vampire);

var bool Initialized;
var vector InstFog;
var float InstFlash;
var VampireShell VampireShellEffect;
var texture ShellSkin;
var class<VampireShell> ShellType;

var() config float LifeStolenPerHit;
var() config int MaxLife;
var() config bool bInflictedDamageOnly;
var() config bool bIsRegenEffect;

Как видите, в строке описания класса добавилось слово config. Это же слово появилось и в описании некоторых переменных.
Ключевое слово config в описании класса означает, что значения по умолчанию полей данного класса будут сохраняться и загружаться из INI-файла. Если после слова config, которое стоит в строке определения класса вставлены скобки с каким-либо именем в них, то значения полей будут сохраняться в INI-файл с таким именем (в папке System), а если скобок нет, то данные будут автоматически сохраняться в файле UnrealTournament.ini в секции с именем, состоящим из названия вашего пакаджа и имени класса:

[<Имя пакаджа>.<Имя класса>]

Слово config, стоящее в описании переменной означает, что данная переменная класса будет сохраняться в конфигурационном файле.
Вот и всё, что необходимо было сделать.

Добавляем интерфейс
Что бы наш мутатор принял профессиональный вид и мог легко конфигурироваться, можно ввести также поддержку интерфейса пользователя. UnrealScript позволяет довольно быстро создавать окна настроек мутаторов и модов. Эти окна настроек вызываются из меню Mod игры. Мы рассмотрим этот процесс на примере небольшого окна с малым количеством элементов управления.
Для того что бы окно корректно работало необходимо описать как минимум 3 класса:
- новая единица в меню Mod;
- фрейм окна;
- клиентская область окна.
Для этого создайте в папке Vampire три текстовых файла и назовите их:
- VampireModMenuItem.uc
- VampireConfigWindow.uc
- VampireClientWindow.uc
Откройте эти файлы поочерёдно и вставьте в них следующие строки:

1. Текст файла VampireModMenuItem.uc:

//===================================
// VampireModMenuItem ; This is script for menu item
// "Vampire Configuration" in the Mod menu.
//===================================

class VampireModMenuItem expands UMenuModMenuItem;

function Execute()
{
MenuItem.Owner.Root.CreateWindow(class'
VampireConfigWindow',10,10,320,175);
}

Описание:
Этот класс описывает пункт меню, при нажатии на который будет вызвано окно нашего мутатора. Функция Execute обрабатывает нажатие на данный пункт и создаёт окно настроек с помощью функции CreateWindow.

2. Текст файла VampireConfigWindow.uc:

//===================================
// VampireConfigWindow ; This is frame for
// Vampire's configuration window.
//===================================

class VampireConfigWindow expands UWindowFramedWindow;

function BeginPlay()
{
Super.BeginPlay();

WindowTitle = "Vampire Configuration";

ClientClass = class'Vampire.VampireClientWindow';

bSizable = False;
}

function Created()
{
Super.Created();
SetSize(320, 175);
WinLeft = (Root.WinWidth - WinWidth) / 2;
WinTop = (Root.WinHeight - WinHeight) / 2;
}

Описание:
Данный класс отвечает за создание окна (прямоугольной области с заголовком). Тут устанавливается заголовок окна, его размеры, положение на экране и т.д.

3. Текст файла VampireClientWindow.uc:

//===================================
// VampireClientWindow ; This is client part of
// Vampire's configuration window.
//===================================

class VampireClientWindow expands UWindowDialogClientWindow;

var UWindowSmallCloseButton CloseButton;
var UWindowEditControl Edit[2];
var UWindowCheckbox OverDamage_Check,RegenEffect_Check;

var string EditBoxString[2];
var string OverDamageCheckString;
var string RegenEffectCheckString;
var string EditBoxHelpString[2];
var string OverDamageCheckHelpString;
var string RegenEffectCheckHelpString;

Var UWindowLabelControl TitleLabel;
Var UWindowLabelControl PermissionsLabel;
Var UWindowLabelControl CopyrightLabel;
Var UWindowLabelControl SplitLabel;

// called after object has been created...add content
function Created()
{
local int i,j,X,Y,Width;

EditBoxString[0] = "Life stolen per hit (%)";
EditBoxString[1] = "Maximum amount of hit points (0 = No limit)";
OverDamageCheckString = "Only inflicted damage comes to life";
RegenEffectCheckString = "Show regeneration effect";
EditBoxHelpString[0] = "Life stolen per hit (%)";
EditBoxHelpString[1] = "Max life";
OverDamageCheckHelpString = "Only inflicted damage
comes to life (Damage <= Victim's life)";
RegenEffectCheckHelpString = "Show regeneration effect";

CloseButton = UWindowSmallCloseButton(CreateControl(class
'UWindowSmallCloseButton', WinWidth-50, WinHeight-18, 48, 16));
CloseButton.SetHelpText("Close config window
and save your current settings!");

X = 10;
Y = 10;

for(i=0;i<2;i++)
{
Edit[i] = UWindowEditControl(CreateControl(class
'UWindowEditControl', X,Y, 300, 1));
Edit[i].SetText(EditBoxString[i]);
Edit[i].SetHelpText(EditBoxHelpString[i]);
Edit[i].SetFont(F_Normal);
Edit[i].SetNumericOnly(True);
Edit[i].SetMaxLength(3);
Edit[i].Align = TA_Left;
Edit[i].EditBoxWidth = 40;
Y += 20;
}
Edit[0].SetValue(string(int(100*class'Vampire'
.Default.LifeStolenPerHit)));
Edit[1].SetValue(string(class'Vampire'.Default.MaxLife));

OverDamage_Check = UWindowCheckbox(CreateControl
(class'UWindowCheckbox', X, Y, 300, 1));
if(class'Vampire'.default.bInflictedDamageOnly)
OverDamage_Check.bChecked = true; else OverDamage_Check.bChecked = false;
OverDamage_Check.SetText(OverDamageCheckString);
OverDamage_Check.SetHelpText(OverDamageCheckHelpString);
OverDamage_Check.SetFont(F_Normal);
OverDamage_Check.Align = TA_Left;
Y += 20;

RegenEffect_Check = UWindowCheckbox
(CreateControl(class'UWindowCheckbox', X, Y, 300, 1));
if(class'Vampire'.default.bIsRegenEffect)
RegenEffect_Check.bChecked = true; else
RegenEffect_Check.bChecked = false;
RegenEffect_Check.SetText(RegenEffectCheckString);
RegenEffect_Check.SetHelpText(RegenEffectCheckHelpString);
RegenEffect_Check.SetFont(F_Normal);
RegenEffect_Check.Align = TA_Left;
Y += 20;

SplitLabel = UWindowLabelControl(CreateControl
(class 'UWindowLabelControl', 10, Y, 300, 1));
SplitLabel.SetText("----------------------
-----------------------------------------------------");
SplitLabel.SetFont(F_Bold);
Y += 10;
TitleLabel = UWindowLabelControl(CreateControl
(class 'UWindowLabelControl', 20, Y, 300, 1));
TitleLabel.SetText("Vampire - Mutator V1.00");
TitleLabel.SetFont(F_Bold);
Y += 10;
PermissionsLabel = UWindowLabelControl
(CreateControl(class 'UWindowLabelControl', 20, Y, 300, 1));
PermissionsLabel.SetText("Free for noncommercial
use and distribution.");
Y += 10;
CopyrightLabel = UWindowLabelControl
(CreateControl(class 'UWindowLabelControl', 20, Y, 300, 1));
CopyrightLabel.SetText("Copyright 2002
by Your_Name 'Your_Nick' Your_SecondName.");
Y += 10;

Super.Created();
}

///////////////////////////////////////////////////
//when a control changes, Notify is called with the changed control
///////////////////////////////////////////////////
function Notify(UWindowDialogControl C, byte E)
{
local int i;
super.Notify(C, E);
if(E==DE_Change)
for (i=0;i < ArrayCount(Edit);i++)
{
if(C==Edit[i])
ApplyEdit(i);
}
switch(E)
{
case DE_Change:
switch(C)
{
case CloseButton: Close(); break;
case OverDamage_Check: ApplyOverDamage(); break;
case RegenEffect_Check: ApplyRegenEffect(); break;
}
}
}
function ApplyOverDamage()
{
class'Vampire'.default.bInflictedDamageOnly =
OverDamage_Check.bChecked;;
class'Vampire'.SaveConfig();
class'Vampire'.static.StaticSaveConfig();
}
function ApplyRegenEffect()
{
class'Vampire'.default.bIsRegenEffect = RegenEffect_
Check.bChecked;;
class'Vampire'.SaveConfig();
class'Vampire'.static.StaticSaveConfig();
}
function ApplyEdit(int i)
{
switch(i)
{
case 0: class'Vampire'.default.
LifeStolenPerHit = 0.01*float(int(Edit[i].GetValue())); break;
case 1: class'Vampire'.default.MaxLife = int
(Edit[i].GetValue()); break;
}
class'Vampire'.SaveConfig();
class'Vampire'.static.StaticSaveConfig();
}
///////////////////////////////////////////////////
function Close(optional bool bByParent)
{
Super.Close(bByParent);
}
///////////////////////////////////////////////////

defaultproperties
{
}

Описание:
Этот класс определяет клиентскую область окна, то есть область, на которой создаются все элементы управления. Также тут обрабатываются все события, которые вызывает пользователь при работе с элементами интерфейса. Сначала все элементы должны быть описаны подобно переменным. В функции Created элементы интерфейса создаются на клиентской области и инициализируются (устанавливаются координаты, индивидуальные свойства и т.д.)
В функции Notify происходит обработка событий вызываемых при нажатии на кнопку или изменении числа в поле ввода. На вход в качестве параметров эта функция принимает имя элемента интерфейса и число, которое определяет тип вызванного события. Также необходимо что бы игра &laquo;знала&raquo; о новом пункте в меню Mod. Для этого открываем наш Vampire.int файл и добавляем туда строчку, отвечающую за пункт меню. После изменения файл должен выглядеть следующим образом:

[Public]
Object=(Name=Vampire.Vampire,Class=Class,MetaClass=
Engine.Mutator,Description="Vampire,You gain life equal to
the amount of damage you do to an enemy.")
Object=(Name=Vampire.VampireModMenuItem,Class=Class,
MetaClass=UMenu.UMenuModMenuItem,Description="Vampire Configuration")

Как видите была добавлена ещё одна строчка, которая начинается так же как и первая со слова Object, но описывает не мутатор, а пункт меню.

Конечный результат
В конце мы должны получить пять файлов в папке Vampire:
1. Vampire.uc
2. VampireShell.uc
3. VampireModMenuItem.uc
4. VampireConfigWindow.uc
5. VampireClientWindow.uc
Эти файлы должны иметь такой вид:

1.) Текст файла Vampire.uc

//===================================
// Vampire ; This is mutator script.
// Description: You gain life equal to the amount of damage you do to
// an enemy.
//===================================

class Vampire expands Mutator config(Vampire);

var bool Initialized;
var vector InstFog;
var float InstFlash;
var VampireShell VampireShellEffect;
var texture ShellSkin;
var class<VampireShell> ShellType;

var() config float LifeStolenPerHit;
var() config int MaxLife;
var() config bool bInflictedDamageOnly;
var() config bool bIsRegenEffect;

function PostBeginPlay()
{
if (Initialized)
return;
Initialized = True;
Level.Game.RegisterDamageMutator( Self );
}

function MutatorTakeDamage( out int ActualDamage,
Pawn Victim, Pawn InstigatedBy, out Vector HitLocation,
out Vector Momentum, name DamageType)
{
if ((InstigatedBy.IsA('Bot') || InstigatedBy.IsA('PlayerPawn'))
&& (Victim != InstigatedBy) && (InstigatedBy != None) && (Victim != None))
{
if ((Victim.Health < ActualDamage) && bInflictedDamageOnly)
ActualDamage = Victim.Health;
InstigatedBy.Health += ActualDamage * LifeStolenPerHit;

if (bIsRegenEffect && (MaxLife != 0 ))
{
FlashShell(InstigatedBy);
if ( InstigatedBy.IsA('PlayerPawn') )
PlayerPawn(InstigatedBy).ClientInstantFlash(InstFlash, InstFog);
}

if ((InstigatedBy.Health > MaxLife) && (MaxLife != 0))
{
InstigatedBy.Health = MaxLife;
}
}

if ( NextDamageMutator != None )
NextDamageMutator.MutatorTakeDamage( ActualDamage,
Victim, InstigatedBy, HitLocation, Momentum, DamageType );
}

function FlashShell(pawn Other)
{
if (VampireShellEffect == None)
{
VampireShellEffect = Spawn(ShellType, Other,,Other.Location, Other.Rotation);
}
if ( VampireShellEffect != None )
{
VampireShellEffect.Mesh = Other.Mesh;
VampireShellEffect.DrawScale = Other.Drawscale;
VampireShellEffect.Texture = ShellSkin;
}
}

defaultproperties
{
LifeStolenPerHit=1.000000
MaxLife=200
bInflictedDamageOnly=True
bIsRegenEffect=True
InstFog=(X=475.000000,Y=325.000000,Z=145.000000)
InstFlash=-0.400000
ShellSkin=FireTexture'UnrealShare.Belt_fx.ShieldBelt.RedShield'
ShellType=Class'Vampire.VampireShell'
}

2.) Текст файла VampireShell.uc

//===================================
// VampireShell ; This is effect script.
// Description: Red shell around damage instigator.
//===================================

class VampireShell expands Effects;

defaultproperties
{
bAnimByOwner=True
bOwnerNoSee=True
bNetTemporary=False
bTrailerSameRotation=True
Physics=PHYS_Trailer
RemoteRole=ROLE_SimulatedProxy
LODBias=0.500000
DrawType=DT_Mesh
Style=STY_Translucent
Texture=None
ScaleGlow=0.500000
AmbientGlow=64
Fatness=157
bUnlit=True
bMeshEnviroMap=True
LifeSpan=0.500000
}

3.) Текст файла VampireModMenuItem.uc

//===================================
// VampireModMenuItem ; This is script for menu item
// "Vampire Configuration" in the Mod menu.
//===================================

class VampireModMenuItem expands UMenuModMenuItem;

function Execute()
{
MenuItem.Owner.Root.CreateWindow(class
'VampireConfigWindow',10,10,320,175);
}

4.) Текст файла VampireConfigWindow.uc

//===================================
// VampireConfigWindow ; This is frame for
// Vampire's configuration window.
//===================================

class VampireConfigWindow expands UWindowFramedWindow;

function BeginPlay()
{
Super.BeginPlay();

WindowTitle = "Vampire Configuration";

ClientClass = class'Vampire.VampireClientWindow';

bSizable = False;
}

function Created()
{
Super.Created();
SetSize(320, 175);
WinLeft = (Root.WinWidth - WinWidth) / 2;
WinTop = (Root.WinHeight - WinHeight) / 2;

5.) Текст файла VampireClientWindow.uc

//===================================
// VampireClientWindow ; This is client part of
// Vampire's configuration window.
//===================================

class VampireClientWindow expands UWindowDialogClientWindow;

var UWindowSmallCloseButton CloseButton;
var UWindowEditControl Edit[2];
var UWindowCheckbox OverDamage_Check,RegenEffect_Check;

var string EditBoxString[2];
var string OverDamageCheckString;
var string RegenEffectCheckString;
var string EditBoxHelpString[2];
var string OverDamageCheckHelpString;
var string RegenEffectCheckHelpString;

Var UWindowLabelControl TitleLabel;
Var UWindowLabelControl PermissionsLabel;
Var UWindowLabelControl CopyrightLabel;
Var UWindowLabelControl SplitLabel;

// called after object has been created...add content
function Created()
{
local int i,j,X,Y,Width;

EditBoxString[0] = "Life stolen per hit (%)";
EditBoxString[1] = "Maximum amount of hit points (0 = No limit)";
OverDamageCheckString = "Only inflicted damage comes to life";
RegenEffectCheckString = "Show regeneration effect";
EditBoxHelpString[0] = "Life stolen per hit (%)";
EditBoxHelpString[1] = "Max life";
OverDamageCheckHelpString = "Only inflicted damage comes to life
(Damage <= Victim's life)";
RegenEffectCheckHelpString = "Show regeneration effect";

CloseButton = UWindowSmallCloseButton
(CreateControl(class'UWindowSmallCloseButton',
WinWidth-50, WinHeight-18, 48, 16));
CloseButton.SetHelpText("Close config window
and save your current settings!");

X = 10;
Y = 10;

for(i=0;i<2;i++)
{
Edit[i] = UWindowEditControl(CreateControl
(class'UWindowEditControl', X,Y, 300, 1));
Edit[i].SetText(EditBoxString[i]);
Edit[i].SetHelpText(EditBoxHelpString[i]);
Edit[i].SetFont(F_Normal);
Edit[i].SetNumericOnly(True);
Edit[i].SetMaxLength(3);
Edit[i].Align = TA_Left;
Edit[i].EditBoxWidth = 40;
Y += 20;
}
Edit[0].SetValue(string(int(100*class'Vampire'
.Default.LifeStolenPerHit)));
Edit[1].SetValue(string(class'Vampire'.Default.MaxLife));

OverDamage_Check = UWindowCheckbox(CreateControl
(class'UWindowCheckbox', X, Y, 300, 1));
if(class'Vampire'.default.bInflictedDamageOnly)
OverDamage_Check.bChecked = true; else
OverDamage_Check.bChecked = false;
OverDamage_Check.SetText(OverDamageCheckString);
OverDamage_Check.SetHelpText(OverDamageCheckHelpString);
OverDamage_Check.SetFont(F_Normal);
OverDamage_Check.Align = TA_Left;
Y += 20;

RegenEffect_Check = UWindowCheckbox(CreateControl
(class'UWindowCheckbox', X, Y, 300, 1));
if(class'Vampire'.default.bIsRegenEffect)
RegenEffect_Check.bChecked = true;
else RegenEffect_Check.bChecked = false;
RegenEffect_Check.SetText(RegenEffectCheckString);
RegenEffect_Check.SetHelpText(RegenEffectCheckHelpString);
RegenEffect_Check.SetFont(F_Normal);
RegenEffect_Check.Align = TA_Left;
Y += 20;

SplitLabel = UWindowLabelControl(CreateControl
(class 'UWindowLabelControl', 10, Y, 300, 1));
SplitLabel.SetText
("--------------------------------------
-------------------------------------");
SplitLabel.SetFont(F_Bold);
Y += 10;
TitleLabel = UWindowLabelControl(CreateControl(class
'UWindowLabelControl', 20, Y, 300, 1));
TitleLabel.SetText("Vampire - Mutator V1.00");
TitleLabel.SetFont(F_Bold);
Y += 10;
PermissionsLabel = UWindowLabelControl(CreateControl
(class 'UWindowLabelControl', 20, Y, 300, 1));
PermissionsLabel.SetText("Free for noncommercial
use and distribution.");
Y += 10;
CopyrightLabel = UWindowLabelControl(CreateControl
(class 'UWindowLabelControl', 20, Y, 300, 1));
CopyrightLabel.SetText("Copyright 2002
by Your_Name 'Your_Nick' Your_SecondName.");
Y += 10;

Super.Created();
}

///////////////////////////////////////////////////
//when a control changes, Notify is called with the changed control
///////////////////////////////////////////////////
function Notify(UWindowDialogControl C, byte E)
{
local int i;
super.Notify(C, E);
if(E==DE_Change)
for (i=0;i < ArrayCount(Edit);i++)
{
if(C==Edit[i])
ApplyEdit(i);
}
switch(E)
{
case DE_Change:
switch(C)
{
case CloseButton: Close(); break;
case OverDamage_Check: ApplyOverDamage(); break;
case RegenEffect_Check: ApplyRegenEffect(); break;
}
}
}
function ApplyOverDamage()
{
class'Vampire'.default.bInflictedDamageOnly =
OverDamage_Check.bChecked;;
class'Vampire'.SaveConfig();
class'Vampire'.static.StaticSaveConfig();
}
function ApplyRegenEffect()
{
class'Vampire'.default.bIsRegenEffect = RegenEffect_Check.bChecked;;
class'Vampire'.SaveConfig();
class'Vampire'.static.StaticSaveConfig();
}
function ApplyEdit(int i)
{
switch(i)
{
case 0: class'Vampire'.default.LifeStolenPerHit = 0.01*float
(int(Edit[i].GetValue())); break;
case 1: class'Vampire'.default.MaxLife = int(Edit[i].GetValue());
break;
}
class'Vampire'.SaveConfig();
class'Vampire'.static.StaticSaveConfig();
}
///////////////////////////////////////////////////
function Close(optional bool bByParent)
{
Super.Close(bByParent);
}
///////////////////////////////////////////////////

defaultproperties
{
}

Также мы имеем файл Vampire.int в папке System, который должен выглядеть так:

[Public]
Object=(Name=Vampire.Vampire,Class=Class,MetaClass=Engine.
Mutator,Description="Vampire,You gain life equal to the
amount of damage you do to an enemy.")
Object=(Name=Vampire.VampireModMenuItem,Class=Class,
MetaClass=UMenu.UMenuModMenuItem,Description="Vampire Configuration")

Вот и всё – осталось только скомпилировать исходный код и начать играть.

Надеюсь вы узнали из этого гайда что-нибудь интересное для себя. Если у вас возникнут какие-либо вопросы – присылайте письма на мой E-Mail: [email protected].

http://sandmansvault.narod.ru
AKA zd.Insider
Аватара пользователя
agressor
Путешественник
Путешественник
 
Автор темы
Сообщения: 362
Зарегистрирован:
07 фев 2002, 02:00
Откуда: Днепропетровск
Has thanked: 0 time
Have thanks: 0 time

Сообщение agressor » 12 дек 2006, 20:48

Использование конфигурационных файлов в модах

Использование конфигурационных файлов в модах
Иногда необходимо, чтобы ваши настройки для какого-либо мода сохранялись при выходе из Unreal Tournament в конфигурационном файле. Существует очень простой способ, позволяющий классам UnrealScript сохранять и загружать данные, используя при этом INI-файлы. Это очень удобно, так как вы можете конфигурировать ваш класс (например, менять значения некоторых полей и свойств) без повторной компиляции. Такой механизм обращения к INI-файлам реализуется с помощью ключевого слова Config, которое и указывает, какую переменную и в каком файле сохранять. Итак, приступим.

Посмотрите на описание данного класса:

Class MyClass Extends Actor;

Var String MyString;
Var Int MyInt;
Var Float MyFloat;

DefaultProperties
{
}

Это достаточно простой класс без методов, содержащий только три переменных. Первая переменная MyString имеет тип String. Это означает, что эта переменная содержит строчку символов. Переменные MyInt и MyFloat имеют типы Int и Float соответственно. То есть они представляют собой целое и вещественное числа. Раздел DefaultProperties, как видите, пустой. Это означает, что переменным класса MyClass не будут присваиваться значения по умолчанию при создании экземпляра этого класса. Простота данного класса обусловлена тем, что на его примере легко показать механизм взаимодействия UnrealScript и INI-файлов.
Допустим, что нам необходимо сохранять содержимое переменной MyString в конфигурационном файле. Для этого нам нужно заменить текст скрипта на следующий:

Class MyClass Extends Actor Config;

Var Config String MyString;
Var Int MyInt;
Var Float MyFloat;

DefaultProperties
{
}

Как видите, нужно просто добавить ключевое слово Config после объявления класса (Class MyClass Extends Actor Config;) и перед указанием типа переменной (Var Config String MyString;). Добавлением этого слова, мы указали Unreal, что:
1. в этом классе содержатся данные, которые необходимо сохранить в конфигурационном файле;
2. мы хотим, чтобы содержимое переменной MyString сохранялось/загружалось.
Заметьте, что сохраняться будет только MyString. Вы должны поместить ключевое слово Config перед описанием каждой переменной, которую вы хотите сохранить.
Теперь вы можете открыть конфигурационный файл (в нашем случае UnrealTournament.ini – он ставится по умолчанию) и присвоить нашей переменной какое-либо значение:

[MyPackage.MyClass]
MyString="This is a test string"

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

Function SaveMyString(Coerce String NewString)
{
MyString = NewString;
SaveConfig();
}

Ключевое слово Coerce в описании параметров функции отвечает за передачу параметру NewString правильного типа. В общем случае ключевое слово Coerce служит для приведения вызванного параметра к заданному типу (даже если UnrealScript не производит этого автоматически). Это удобно для функций, которые используют строки в качестве параметров. Таким образом параметры будут автоматически переводится в строки.
Теперь при каждом вызове функции SaveMyString() значение переменной MyString меняется на новое и сохраняется в конфигурационном файле для последующего использования. За это отвечает функция SaveConfig(), описанная разработчиками и сохраняющая все переменные данного класса (те которые определяются со словом Config) в INI-файле.
Вы также можете задавать имя конфигурационного файла. Для этого нужно изменить строчку, в которой определяется ваш класс на подобную этой:

Class MyClass Extends Actor Config(Test);

Теперь ваш класс будет сохранять все свои конфигурируемые данные в файле Test.ini и таким же образом вы можете задавать любое имя конфигурационного файла. Если после ключевого слова Config в строке определения класса нет скобок с указанным в них именем конфигурационного файла, то ваши данные будут автоматически сохраняться в файле UnrealTournament.ini в секции с именем, состоящим из названия вашего пакаджа и имени класса:

[<Имя пакаджа>.<Имя класса>]

Также существует функция ResetConfig(), которая сбрасывает значения конфигурируемых переменных класса и присваивает им значения, указанные в INI-файле.

Теперь вы можете использовать конфигурационные INI-файлы для хранения любых настроек своих модов или мутаторов.

Надеюсь, вы узнали из этого гайда что-нибудь интересное для себя. Если у вас возникнут какие-либо вопросы – присылайте письма на мой E-Mail: [email protected].

http://sandmansvault.narod.ru
AKA zd.Insider
Аватара пользователя
agressor
Путешественник
Путешественник
 
Автор темы
Сообщения: 362
Зарегистрирован:
07 фев 2002, 02:00
Откуда: Днепропетровск
Has thanked: 0 time
Have thanks: 0 time

Сообщение agressor » 12 дек 2006, 20:49

Функции UCC.exe

Функции UCC.exe
Многие, кто пытался писать свои моды или мутаторы сталкивались с тем, что UnrealEd не мог обеспечить выполнение некоторых функций при написании скриптов и, возможно, даже не подозревали, что есть другой способ компилирования исходного кода модов.
Сначала давайте определимся с терминологией. Пакаджем (от англ. Package) будем называть файл, содержащий объекты каких-либо типов: текстуры, звуки, музыка, скрипты и т.д. Для Unreal Tournament они представлены U-файлами (*.u) и представляют собой скомпилированные скрипты, лежащие в файле вместе со своим текстовым представлением, а также сжатыми текстурами, звуками и другими объектами. Скриптом будем называть исходный текст программы, которую обрабатывает движок Unreal Tournament. Они представлены UC-файлами (*.uc) и имеют текстовый формат. В UC-файлах всегда описан какой-либо класс, который составляет часть дерева классов Unreal Tournament.
Итак, всё начинается с UCC.exe – маленького файлика, лежащего в директории System.
Многие люди не интересуются содержимым директорий вообще, некоторые интересуются, но не заходят слишком далеко, некоторые даже запускали UCC.exe но были испуганы результатом его работы – работает ведь он в консольном режиме. Дело в том, что при всей своей непритязательности и неприглядности этот файл является тем самым компилятором скриптов Анриала, с помощью которого и создаются всевозможные моды и мутаторы. Но этим его функции не ограничиваются. Не зря программа, скрывающаяся в файле UCC.exe, называется &laquo;UnrealOS execution environment&raquo; – &laquo;Исполнительная среда операционной системы Unreal&raquo;.
Для работы с этой программой лучше всего создать BAT-файл, так как надо будет часто запускать её с различными параметрами в командной строке. Следует также убрать флаг &laquo;Закрывать окно по завершении сеанса&raquo; в свойствах для этого BAT-файла. Так мы будем видеть, какие именно сообщения пишет программа. Если сообщений много и они не помещаются на экран или вы хотите просматривать сообщения программы в другом виде, то можете после выполнения каких-либо задач в UCC.exe просматривать файл UCC.log в той же папке. Иногда это бывает необходимым. Файл UCC.log содержит более полную информацию о работе программы.
Перейдём теперь непосредственно к запуску UCC.exe . При запуске программа пишет на экране сообщение:

=======================================
ucc.exe: UnrealOS execution environment
Copyright 1999 Epic Games Inc
=======================================
Use "ucc help" for help

Это название программы и руководство по использованию. Программа говорит нам запустить её с параметром Help. Следуем этому указанию и, запустив программу с параметром Help, получаем полный список параметров для командной строки, реализующих определённые функции, а также небольшое пояснение для каждого из параметров. Так выглядит список всех параметров UCC.exe:

ucc <command> <parameters>

Commands for "ucc":
ucc
ucc batchexport Export objects in bulk
ucc checksum Calculate package checksum for stat logging
ucc checksumpackage Display checksum for package file
ucc compress Compress an Unreal package for auto-downloading. A
file with extension .uz will be created.
ucc conform Generate conforming binary files
ucc datarip Create a package with Texture, Music and Sound data
ripped out.
ucc decompress Decompress a file compressed with ucc compress.
ucc HelloWorld Sample
ucc help <command> Get help on a command
ucc make Rebuild UnrealScript packages
ucc master Build master installer files
ucc masterserver Maintain master list of servers.
ucc mergedxt Merge DXT textures with standard textures
ucc packageflag Set package flags in package files
ucc server Network game server
ucc updateserver Service Unreal Engine auto update requests.
ucc updateumod Add, delete, replace or extract files from a umod

Я попробую описать некоторые из функций, которые позволят вам не только создавать собственные моды и мутаторы, но и анализировать чужие скрипты, а также доставать объекты ресурсов из чужих пакаджей, встраивать объекты ресурсов в свои моды и мутаторы. Большинство функций UCC.exe не нужны обычному пользователю, поэтому и мы рассмотрим только некоторые. Итак:

1. BatchExport – позволяет экспортировать различные объекты из заданного пакаджа и сохранять их в заданном формате.

Использование: UCC.exe BatchExport Package.ext ClassName Export_Ext Path

Параметры:
Package.ext – Пакадж, из которого вы собираетесь экспортировать объекты (с расширением).
ClassName – Класс объектов, которые будут экспортированы.
Export_ext – Расширение файлов, в которые будут экспортированы объекты из пакаджа.
Path – Путь к папке, куда будут экспортированы файлы.

Пример: UCC.exe BatchExport UWindow.u Texture pcx C:\UCC_Learn
Из пакаджа UWindow.u в папку C:\UCC_Learn будут экспортированы все, находящиеся в этом пакадже, текстуры. Причём текстуры будут сохранены в формате PCX. Если вам нужно экспортировать звуки, то параметр ClassName нужно изменить на Sound, а параметр Export_ext – на wav: UCC.exe BatchExport Botpack.u Sound wav C:\UCC_Learn.
Таким же образом из пакаджей экспортируются скрипты. Значения параметров ClassName и Export_ext в этом случае должны быть Class и uc соответственно:
UCC.exe BatchExport botpack.u Class uc C:\UCCLearn.

2. DataRip – Вырезает объекты из одного пакаджа и вставляет в другой, при этом компилируя этот второй пакадж для того, что бы все связи в объектах установились в соответствии с его именем.

Использование: UCC.exe DataRip SrcPackage.ext DstPackage.ext

Параметры:
SrcPackage.ext – Исходный пакадж.
DstPackage.ext – Новый пакадж.

Пример: UCC.exe DataRip DE.u DE1.u
Все данные из пакаджа DE.u будут перенесены в новый пакадж DE1.u, после чего DE1.u будет перекомпилирован. Таким образом, классы, описанные и скомпилированные в DE.u, будут функционировать и в DE1.u . Например, класс DE.TeamBeacon превратится в DE1.TeamBeacon и будет корректно работать.

3. Help – Выдаёт информацию о команде.

Использование: UCC.exe Help <Command>

Параметры:
<Command> - Команда, по которой нужна справка.

Пример: UCC.exe Help BatchExport
UCC.exe выдаст информацию о команде BatchExport, которая была рассмотрена выше. Результат будет такой:

=======================================
ucc.exe: UnrealOS execution environment
Copyright 1999 Epic Games Inc
=======================================

Использование:
ucc batchexport package.ext classname export_ext

Параметры:
package.ext Package whose objects you wish to export
classname Class of object to export
export_ext File extension to export to
path Path to export files to, like c:\MyPath
Как видите, идёт краткое описание команды и параметров для неё. Help – достаточно полезная команда. Пользуйтесь ею, если вы не помните, как что-то сделать или возникает какая-нибудь ошибка. Возможно, вы просто забыли порядок следования параметров или их количество.

4. Make – Компилирует пакаджи.

Использование: UCC.exe Make [-option...] [parm=value]...

Параметры:
Я не писал про параметр [-option...], так как он устанавливает различные режимы компилирования, которые обычно не используются рядовыми пользователями. Также все параметры этой команды не являются обязательными и чаще всего она используется без них.

Пример: UCC.exe Make
Программа проверит секцию [Editor.EditorEngine] файла UnrealTournament.ini на предмет наличия строк, начинающихся со слов EditPackages (вроде EditPackages=Core) и обозначающих пакаджи, которые должны быть скомпилированы, после чего начнёт искать папку с аналогичным именем в директории UnrealTournament (в нашем случае UnrealTournament\ Core). Если результат поиска окажется положительным, то последует следующая проверка содержимого папки пакаджа на предмет наличия в ней подпапок Classes, Textures, Sounds и т.д. Скрипты из папки Classes будут скомпилированы в новый пакадж, а объекты ресурсов из остальных папок – сжаты и добавлены туда же.

5. UpdateUMOD – Позволяет работать с архивами в формате UMOD.

Использование: UCC.exe UpdateUMOD UmodFile Command [FileName]

Параметры:
UmodFile – UMOD-файл, подлежащий изменению или просмотру.
Command - Параметр, определяющий режим работы с UMOD-файлом.
Может принимать одно из следующих значений:
EXTRACT – распаковать;
ADD – добавить;
DELETE – удалить;
REPLACE – заменить;
LIST – просмотреть.
FileName – Имя файла, в который распаковывается файл из UMOD-архива, который добавляется в UMOD-архив, который удаляется из UMOD-архива или на который заменяется файл в UMOD-архиве соответственно режимам работы с архивом.

Пример:
Допустим, что у нас есть файл-архив TestMod.umod, который нам требуется распаковать. Для начала нужно просмотреть содержимое архива. Это делается с помощью строки: UCC.exe UpdateUMOD TestMod.umod List
При этом на экран будет выведена информация о файлах, содержащихся в файле TestMod.umod . Предположим теперь, что среди запакованных файлов имеются файлы какого-либо мутатора. Например, Mutator.u и Mutator.int, которые мы хотим достать. Для этого нужно выполнить такие командные строчки:
UCC.exe UpdateUMOD TestMod.umod EXTRACT Mutator.u
UCC.exe UpdateUMOD TestMod.umod EXTRACT Mutator.int
Понятно, что UMOD-файл, с которым вы работаете, должен лежать в папке System.
Таким образом, можно устанавливать моды и мутаторы без применения программы-установщика Setup.exe в случае её некорректной работы. Часто моды и мутаторы, поставляемые в UMOD-файлах не могут установится из-за того, что версия Unreal Tournament, на которую их хотят установить, является пиратской или русифицированной. Это обусловлено тем, что пиратские версии игры не устанавливаются, а просто копируются на жёсткий диск, не создавая при этом необходимых переменных в системном реестре, отвечающих за рабочие папки Unreal Tournament. В таких случаях программа-установщик Setup.exe выдаёт ошибку
Setup: Unknown Disposition. Такой метод установки имеет ещё один недостаток кроме длительного времени инсталляции и большого числа операций, выполняемых вручную. Это недостаток заключается в том, что для корректной работы некоторых модов на сервере, необходимо, что бы в секции [Engine.GameEngine] файла UnrealTournament.ini была прописана строчка ServerPackages=. Установочная программа делает это автоматически, а пользователю необходимо самому позаботится про это.

Таким образом, мы рассмотрели некоторые функции программы UCC.exe, которые могут пригодится пользователю для создания своих модов и мутаторов. Все команды, которые вводятся в командной строчке, могут не иметь заглавных букв. Программа UCC.exe не различает регистры при интерпретации этих команд. Я писал в словах команд заглавные буквы для более лёгкого восприятия текста читателем.

Нестандартные методы установки модов

Выше мы рассмотрели метод установки модов из UMOD-файлов с помощью программы UCC.exe, которая представляет собой универсальную программу для работы с пакаджами и файлами-архивами UMOD. Как было сказано, описанный метод имеет много недостатков, но иногда является единственным возможным. Однако есть ещё один способ устанавливать моды, если Unreal Tournament не создал необходимых записей в системном реестре. Он заключается в том, что имя UMOD-файла, содержащего мод, подаётся на выполнение программе Setup.exe в командной строчке после параметра Install.
В общем виде это выглядит так: Setup.exe Install “Имя_UMOD_Файла.umod” .
Обратите внимание на то, что имя UMOD-файла пишется с расширением в двойных кавычках. Про это следует помнить, так как отсутствие кавычек или расширения может привести к неправильной трактовке вашего запроса программой Setup.exe .

Мутатор за 10 минут

Давайте рассмотрим технологию создания мутаторов на примере простого мутатора RedeemerArena. Чтение данного документа будет представлять интерес только для начинающих скриптеров или просто любопытных пользователей, которые ещё никогда не сталкивались с созданием собственных мутаторов.
Для этого желательно иметь некоторое представление о функциях UCC.exe, а также немного терпения.
Итак:

1. Зайдите в папку, куда вы инсталлировали Unreal Tournament.
Например: C:\Program Files\GT Interactive\UnrealTournament.

2. Создайте папку с названием своего мода. Имя папки в будущем станет именем пакаджа. В нашем случае будет рационально назвать её RedeemerArena. Таким образом мы получили папку: C:\Program Files\GT Interactive\UnrealTournament\RedeemerArena.
Зайдите внутрь этой папки.

3. Внутри папки RedeemerArena создайте подпапку Classes. В этой папке будут лежать исходные тексты скриптов. Так как нам не требуется встраивать в наш мутатор других объектов, наподобие звука или текстур, то нам не нужно создавать дополнительно папки Sounds и Textures. То есть на этом шаге мы получаем только папку:
C:\Program Files\GT Interactive\UnrealTournament\RedeemerArena\Classes.
Зайдите внутрь этой папки.

4. Создайте внутри этой папки текстовый файл и переименуйте его в RedeemerArena.uc и
откройте с помощью какого-либо текстового редактора.

5. Вставьте в этот файл (RedeemerArena.uc) следующие строчки:


//======================================
// RedeemerArena.
// Author: Alexei "Sandman" Goncharov.
// Permissions: Don't forget to give me credits .
//======================================

Class RedeemerArena Expands Arena;

function bool AlwaysKeep(Actor Other)
{
Local Bool bTemp;

If ( Other.IsA(WeaponName) )
{
Weapon(Other).PickupAmmoCount = 50;
Return True;
}

If ( NextMutator != None )
Return ( NextMutator.AlwaysKeep(Other) );
Return False;
}

DefaultProperties
{
WeaponName=WarheadLauncher
WeaponString="Botpack.WarheadLauncher"
DefaultWeapon=Class'Botpack.WarheadLauncher'
}

Сохраните и закройте файл.

6. Выйдите из текущей директории и зайдите в папку UnrealTournament\System.

7. Создайте в папке UnrealTournament\System текстовый файл и переименуйте его в RedeemerArena.int, после чего откройте его в каком-либо текстовом редакторе.

8. Вставьте в этот файл (RedeemerArena.int) следующие строчки:

[Public]
Object=(Name=RedeemerArena.RedeemerArena,Class=Class,MetaClass=
Engine.Mutator,Description="RedeemerArena,Only Redeemers!")

Сохраните и закройте файл.

9. Теперь найдите в папке UnrealTournament файл UnrealTournament.ini
и откройте его в каком-либо текстовым редакторе.

10. Найдите в этом файле секцию [Editor.EditorEngine] и добавьте в конце после строчек:

EditPackages=Core
EditPackages=Engine
EditPackages=Editor
EditPackages=UWindow
EditPackages=Fire
EditPackages=IpDrv
EditPackages=UWeb
EditPackages=UBrowser
EditPackages=UnrealShare
EditPackages=UnrealI
EditPackages=UMenu
EditPackages=IpServer
EditPackages=Botpack
EditPackages=UTServerAdmin
EditPackages=UTMenu
EditPackages=UTBrowser

Ещё одну строчку: EditPackages=RedeemerArena.
Сохраните и закройте файл.

11. Теперь запустите программу UCC.exe с параметром Make:
UCC.exe Make.

12. Если вы не сделали никаких ошибок, то в папке System должен появится файл RedeemerArena.u, но если он не появился, то нужно в первую очередь проверить корректность содержимого файла скриптов RedeemerArena.uc, а потом также проверить файл RedeemerArena.int .

Всё! Ваш мутатор готов! Теперь можете скопировать файлы RedeemerArena.u и RedeemerArena.int в отдельную папку и показывать друзьям. Именно эти два файла составляют ваш мутатор. Файл пакадж RedeemerArena.u – это сам скомпилированный скрипт, а RedeemerArena.int – связующий файл, который говорит игре, что название вашего мутатора нужно поместить в список выбора мутаторов.

Вот и всё пока что. Надеюсь, вы узнали из этого гайда что-нибудь интересное для себя. Если у вас возникнут какие-либо вопросы – присылайте письма на мой E-Mail: [email protected].

http://sandmansvault.narod.ru
AKA zd.Insider
Аватара пользователя
agressor
Путешественник
Путешественник
 
Автор темы
Сообщения: 362
Зарегистрирован:
07 фев 2002, 02:00
Откуда: Днепропетровск
Has thanked: 0 time
Have thanks: 0 time

Сообщение Maybe.Duo » 13 дек 2006, 09:39

Я проверил, на других серваках оно чето неработает (((, а на алькаре работает :o
Аватара пользователя
Maybe.Duo
Школота
Школота
 
Сообщения: 4
Зарегистрирован:
25 окт 2006, 18:41
Has thanked: 0 time
Have thanks: 0 time

Сообщение agressor » 13 дек 2006, 09:53

Maybe.Duo писал(а):Я проверил, на других серваках оно чето неработает (((, а на алькаре работает :o

О чем идет речь?
AKA zd.Insider
Аватара пользователя
agressor
Путешественник
Путешественник
 
Автор темы
Сообщения: 362
Зарегистрирован:
07 фев 2002, 02:00
Откуда: Днепропетровск
Has thanked: 0 time
Have thanks: 0 time

Сообщение agressor » 18 дек 2006, 19:39

Добавлен раздел UnrealED
Основы
Интерфейс UnrealED
AKA zd.Insider
Аватара пользователя
agressor
Путешественник
Путешественник
 
Автор темы
Сообщения: 362
Зарегистрирован:
07 фев 2002, 02:00
Откуда: Днепропетровск
Has thanked: 0 time
Have thanks: 0 time

Сообщение agressor » 21 фев 2007, 09:36

Скрипт для распаковки кэша

1. В каталоге игры есть каталог Cache, создаём в нём файл Cache.cmd (Cache.bat)
2. Пишем в нём:

md resolved
for /f "skip=1 delims== tokens=1,2" %%A in (cache.ini) do (copy /B %%A.uxx resolved\%%B)

3. Cохраняем и запускаем (жмём на нем Enter), в результате получим в каталоге resolved файлы загруженные в кэш.
AKA zd.Insider
Аватара пользователя
agressor
Путешественник
Путешественник
 
Автор темы
Сообщения: 362
Зарегистрирован:
07 фев 2002, 02:00
Откуда: Днепропетровск
Has thanked: 0 time
Have thanks: 0 time

Пред.След.

Вернуться в Unreal Tournament

Кто сейчас на конференции

Посетителей: 1, из них зарегистрированных: 0, скрытых: 0 и гостей: 1 (находятся на конференции)
Этот раздел просматривают: нет зарегистрированных пользователей и гости: 1

cron