В исходнике довольно близко к синтаксису DECORATE, где-то на forum.zdoom.org даже конвертер валялся.
Для начала нам надо найти код монстра в исходнике. Можно воспользоваться поиском APig (в коде к имени класса в начале всегда добавляется A). Но можно попробовать и другой способ, монстр из Hexen, поэтому смотрим содержимое g_hexen. В данном случае повезло и есть файл a_pig.cpp, но бывает что несколько подобных по назначению классов записаны в файл с более общим названием (например, некоторые предметы инвентаря и оружие). Дальше все равно придется искать APig, но текстовым поиском внутри файла может воспользоваться каждый.
class APig : public AMorphedMonster
{
DECLARE_ACTOR (APig, AMorphedMonster)
};
FState APig::States[] =
{
#define S_PIG_LOOK1 0
S_NORMAL (PIGY, 'B', 10, A_Look , &States[S_PIG_LOOK1]),
#define S_PIG_WALK1 (S_PIG_LOOK1+1)
S_NORMAL (PIGY, 'A', 3, A_Chase , &States[S_PIG_WALK1+1]),
S_NORMAL (PIGY, 'B', 3, A_Chase , &States[S_PIG_WALK1+2]),
S_NORMAL (PIGY, 'C', 3, A_Chase , &States[S_PIG_WALK1+3]),
S_NORMAL (PIGY, 'D', 3, A_Chase , &States[S_PIG_WALK1]),
#define S_PIG_PAIN (S_PIG_WALK1+4)
S_NORMAL (PIGY, 'D', 4, A_PigPain , &States[S_PIG_WALK1]),
#define S_PIG_ATK1 (S_PIG_PAIN+1)
S_NORMAL (PIGY, 'A', 5, A_FaceTarget , &States[S_PIG_ATK1+1]),
S_NORMAL (PIGY, 'A', 10, A_PigAttack , &States[S_PIG_WALK1]),
#define S_PIG_DIE1 (S_PIG_ATK1+2)
S_NORMAL (PIGY, 'E', 4, A_Scream , &States[S_PIG_DIE1+1]),
S_NORMAL (PIGY, 'F', 3, A_NoBlocking , &States[S_PIG_DIE1+2]),
S_NORMAL (PIGY, 'G', 4, A_QueueCorpse , &States[S_PIG_DIE1+3]),
S_NORMAL (PIGY, 'H', 3, NULL , &States[S_PIG_DIE1+4]),
S_NORMAL (PIGY, 'I', 4, NULL , &States[S_PIG_DIE1+5]),
S_NORMAL (PIGY, 'J', 4, NULL , &States[S_PIG_DIE1+6]),
S_NORMAL (PIGY, 'K', 4, NULL , &States[S_PIG_DIE1+7]),
S_NORMAL (PIGY, 'L', -1, NULL , NULL),
#define S_PIG_ICE (S_PIG_DIE1+8)
S_NORMAL (PIGY, 'M', 5, A_FreezeDeath , &States[S_PIG_ICE+1]),
S_NORMAL (PIGY, 'M', 1, A_FreezeDeathChunks , &States[S_PIG_ICE+1]),
};
IMPLEMENT_ACTOR (APig, Hexen, -1, 0)
PROP_SpawnHealth (25)
PROP_PainChance (128)
PROP_SpeedFixed (10)
PROP_RadiusFixed (12)
PROP_HeightFixed (22)
PROP_Mass (60)
PROP_Flags (MF_SOLID|MF_SHOOTABLE)
PROP_Flags2 (MF2_WINDTHRUST|MF2_FLOORCLIP|MF2_PASSMOBJ|MF2_TELESTOMP|MF2_PUSHWALL)
PROP_Flags3 (MF3_DONTMORPH|MF3_ISMONSTER)
PROP_SpawnState (S_PIG_LOOK1)
PROP_SeeState (S_PIG_WALK1)
PROP_PainState (S_PIG_PAIN)
PROP_MeleeState (S_PIG_ATK1)
PROP_DeathState (S_PIG_DIE1)
PROP_IDeathState (S_PIG_ICE)
PROP_SeeSound ("PigActive1")
PROP_PainSound ("PigPain")
PROP_DeathSound ("PigDeath")
PROP_ActiveSound ("PigActive1")
END_DEFAULTS Собственно приступаем к переводу:
//APig наследуется от AMorphedMonster, что и пишем (префикс A у классов используется только внутри движка)
//DoomEdNum здесь не используется, если бы он был, он бы был записан в строке IMPLEMENT_ACTOR, кажется третий параметр.
actor Pig : MorphedMonster {
//здесь просто переписываем внутренности IMPLEMENT_ACTOR, убирая PROP_, ну и некоторые дополнительные небольшие правки. В крайнем случае можно сверяться с викой
Health 25
PainChance 128
Speed 10
Radius 12
Height 22
Mass 60
//Анимации (они же States) запишем позже. Я предпочитаю записывать их в самом конце. Точно так же пока пропущу флаги и допишу остальные свойства
SeeSound "PigActive1"
PainSound "PigPain"
DeathSound "PigDeath"
ActiveSound "PigActive1"
//Теперь флаги. Записываем содежимое PROP_Flags, убирая само PROP_Flags, MF#_ и вертикальные черты (на самом деле это побитовый ИЛИ). При сомнениях лучше свериться со справочником, некоторые флаги в исходнике названы по-другому
+SOLID
+SHOOTABLE
+WINDTHRUST
+FLOORCLIP
+CANPASS //в исходнике называется PASSMOBJ
+TELESTOMP
+CANPUSHWALLS //было PUSHWALL
+DONTMORPH
+ISMONSTER
//Теперь самая "веселая" часть, анимации. Как видим из записанных свойств, названия последовательностей довольно удобные и с этой частью кода сверяться уже не понадобится. Переходим к части FState
States {
//#define здесь заменяют метки. S_NORMAL/S_BRIGHT соответственно определяют является ли кадр BRIGHT. Все остальное в принципе достаточно соответствует DECORATE с одним исключением, последний параметр кадра - следующий кадр.
Spawn:
PIGY B 10 A_Look
Loop //следующий кадр - начало той же анимации, поэтому пишем просто цикл
See:
PIGY ABCD 3 A_Chase //здесь кадры отличаются только субспрайтом, поэтому используем короткую запись. К тому же вручную рассчитывать сдвиги Goto нам точно не понадобится (даже если бы пришлось использовать Goto со смещением)
Loop //та же причина
Pain:
PIGY D 4 A_PigPain
Goto See //переход в другую анимацию, то есть Goto
Melee: //все-таки пришлось возвращаться к IMPLEMENT_ACTOR, ATK могло означать как ближнюю, так и дальнюю атаку
PIGY A 5 A_FaceTarget
PIGY A 10 A_PigAttack
Goto See //то же
Death:
PIGY E 4 A_Scream
PIGY F 3 A_NoBlocking
PIGY G 4 A_QueueCorpse
PIGY H 3
PIGY IJK 4
PIGY L -1 //на самом деле это бесконечное ожидание, но все-таки добавим нормальное завершение анимации
Stop //если следующий кадр NULL, значит мы в конце анимации
Ice:
PIGY M 5 A_FreezeDeath
PIGY M 1 A_FreezeDeathChunks
Wait //не спешим использовать Goto ) . В DECORATE есть более наглядные команды. Wait = повторять последний кадр
}
}
Я не гарантирую правильность этого кода, я пытался именно продемонстрировать принцип перевода. К примеру Pig уже определен в ZDoom, поэтому перед использованием этого кода в ваде точно придется переименовывать класс. Кроме того, для практического применения возможно вообще хватит "actor DoomPig : Pig {}". |