Как я искал (и нашёл! =) рецепт секретного поушена))

Поведайте, какие тайны вы раскрыли в Кирандии.

Как я искал (и нашёл! =) рецепт секретного поушена))

Сообщение Малкольмович » 23 дек 2011, 20:59

Тем, кому не интересно, каковы внутренности кирандийских скриптов и их интерпретатора, могут не читать этот большой блок текста и сразу промотать в конец)

Intro.

Итак, Кирандия снова в опасности, и без секретного поушена Занция не будет настолько вдохновлена на борьбу с Рукой. =)
Поищем же его! В игре оно работает, и говорят, даже наливается в котел и во флакончики, но вот как его получить безо всяких редакторов и дебаггеров?
Во-первых, первое, что мне пришло в голову, это ухватиться за первую, просто-таки лежащую на виду зацепку: на сообщение о том, что мы-де, мол, нашли этот поушен и теперь наша клава - не что иное, как magical sound toy. =) Оно лежит в файле MYSTRM.PAK, а распаковав его WestPak-ом, мы увидим заветную фразу в MYSTRM.EMC. Поскольку этот пак отвечает за радужную комнату, отсюда сразу понятно, что эти пертурбации с клавой могут происходить только в радужной комнате.

Location 1: Darkmoor Script.

Итак, полезем в скрипт. Нам превратить его в текстовый вид поможет распаковщик EMC-скриптов dekyra из scummvm-tools.
Распакованный скрипт в аттаче к сообщению (для тех, кто желает в нём поразбираться), тут же я приведу участок кода с этим сообщением, облагороженный мной и немного протрассированный с этого псевдоассемблера на язык, подобный C:

Код: Выделить всё
// начало "облагороженного" участка кода:

// function_2():
// var[4] - по всей видимости, то, что в руках
// Похоже, что эта функция выполняется при изменении содержимого мышки (т.е. рук Занции).

// {
0x1710: 0x00 0x00 // это нечто типа разделителя функций nop-ами, как в х86-executable. Тут это заголовок функции №2.
0x1712: 0x0D c1_subSP 0

// if (-1 < var[4]) goto 0x172A; - проверка, вообще есть ли у нас в руках что-то (-1 - это пустая мышка)
0x1714: 0x05 c1_pushVar 4
0x1716: 0x04 c1_push -1
0x1718: 0x11 c1_eval 5 ; '(val1 >= val2)'
0x171A: 0x0F c1_ifNotJmp 0x172A

// randomSceneChat();
0x171E: 0x0E c1_execOpcode o2_randomSceneChat // по всей видимости, если в руках ничего - то говорить что-нибудь

// var[3]=1;
0x1720: 0x04 c1_push 1
0x1722: 0x09 c1_popVar 3

// retval=var[3];
0x1724: 0x05 c1_pushVar 3
0x1726: 0x08 c1_popRetOrPos 0

// return retval;
0x1728: 0x08 c1_popRetOrPos 1 // pop bp; ret;

// if (149 != var[4]) goto 0x17A8;
// это точно сравнение с номером айтема, ибо give 149 в скумме даёт Занции именно сикрет поушен
0x172A: 0x05 c1_pushVar 4   
0x172C: 0x03 c1_push 149
0x1730: 0x11 c1_eval 2
0x1732: 0x0F c1_ifNotJmp 0x17A8 // если там не сикрет поушен, тогда к дальнейшим проверкам.

// getCharacterX(0);
0x1736: 0x04 c1_push 0
0x1738: 0x0E c1_execOpcode o2_getCharacterX
0x173A: 0x0C c1_addSP 1

// if (160 < retval) goto 0x1756; - проверка позиции Занции?
0x173C: 0x02 c1_pushRetOrPos 0
0x173E: 0x03 c1_push 160
0x1742: 0x11 c1_eval 5 ; '(val1 >= val2)'
0x1744: 0x0F c1_ifNotJmp 0x1756

// refreshCharacter(0, 18, 3, 1); - видимо, если она стоит где-то не там, то пусть выйдет поближе
0x1748: 0x04 c1_push 1
0x174A: 0x04 c1_push 3
0x174C: 0x04 c1_push 18
0x174E: 0x04 c1_push 0
0x1750: 0x0E c1_exec o2_refreshCharacter
0x1752: 0x0C c1_addSP 4

// goto(0x1762);
0x1754: 0x00 c1_jumpTo 0x1762

// refreshCharacter(0, 18, 5, 1);
0x1756: 0x04 c1_push 1
0x1758: 0x04 c1_push 5
0x175A: 0x04 c1_push 18
0x175C: 0x04 c1_push 0
0x175E: 0x0E c1_exec o2_refreshCharacter
0x1760: 0x0C c1_addSP 4

// 0x1762: setHandItem(18);
0x1762: 0x04 c1_push 18 // 18 - это пустой флакон. Занция опустошает флакон с сикрет поушеном - даём пустой в мышку
0x1764: 0x0E c1_exec o1_setHandItem
0x1766: 0x0C c1_addSP 1

// Помимо этого, делаются вещи:
// включается клава в этот самый sound toy-режим
// меняется музыка (до всех текстовых сообщений)

// soundFadeOut(); - выключить старую музыку, видимо
0x1768: 0x0E c1_exec o2_soundFadeOut // Sound-toy режим? Больше нигде в скрипте не встречается

// playSoundEffect(178); - бабах?
0x176A: 0x03 c1_push 178
0x176E: 0x0E c1_execOpcode o1_playSoundEffect
0x1770: 0x0C c1_addSP 1

// Дальше тупо вывод строк.

// objectChat(0, 'Congratulations!');
0x1772: 0x04 c1_push 0
0x1774: 0x04 c1_push 31 ; string 'Congratulations!'
0x1776: 0x0E c1_exec o2_objectChat;
0x1778: 0x0C c1_addSP 2

// o1_playWanderScoreViaMap(87, 1); - запуск бодрой музычки?
0x177A: 0x04 c1_push 1
0x177C: 0x04 c1_push 87
0x177E: 0x0E c1_exec o1_playWanderScoreViaMap;
0x1780: 0x0C c1_addSP 2

// objectChat(0, 'You have found the secret potion!');
0x1782: 0x04 c1_push 0
0x1784: 0x04 c1_push 32 ; string 'You have found the secret potion!'
0x1786: 0x0E c1_exec o2_objectChat;
0x1788: 0x0C c1_addSP 2

// objectChat(0, 'Your keyboard has now become a magical sound toy...');
0x178A: 0x04 c1_push 0
0x178C: 0x04 c1_push 33 ; string 'Your keyboard has now become a magical sound toy...'
0x178E: 0x0E c1_exec o2_objectChat;
0x1790: 0x0C c1_addSP 2

// objectChat(0, '...Have fun!');
0x1792: 0x04 c1_push 0
0x1794: 0x04 c1_push 34 ; string '...Have fun!'
0x1796: 0x0E c1_exec o2_objectChat;
0x1798: 0x0C c1_addSP 2

// setGameFlag(494); - по-любому включение в sound-toy режим
0x179A: 0x03 c1_push 494
0x179E: 0x0E c1_exec o1_setGameFlag
0x17A0: 0x0C c1_addSP 1

// var[3] = 1;
0x17A2: 0x04 c1_push 1
0x17A4: 0x09 c1_popVar 3

// return retval;
0x17A6: 0x08 c1_popRetOrPos 1 // pop bp; ret; - очевидно, конец функции.

// дальнейшие проверки
// if (3 != var[4]) goto 0x17С0;
0x17A8: 0x05 c1_pushVar 4
0x17AA: 0x04 c1_push 3
0x17AC: 0x11 c1_eval 2 ; (C syntax): '(val1 == val2)'
0x17AE: 0x0F c1_ifNotJmp 0x17C0

// Ага! вывод этой строки происходит, когда она показывает себе блуберрю, значит var[4] - то, что в руках, а функция вызывается при показывании себе предмета из рук)

// objectChat(0, 'I bet this would make a lovely indigo potion.');
0x17B2: 0x04 c1_push 0
0x17B4: 0x04 c1_push 35 ; string 'I bet this would make a lovely indigo potion.'
0x17B6: 0x0E c1_execOpcode 128 ; functionname: 'o2_unk0x80'
0x17B8: 0x0C c1_addSP 2

// var[3] = 1;
0x17BA: 0x04 c1_push 1
0x17BC: 0x09 c1_popVar 3

// return retval;
0x17BE: 0x08 c1_popRetOrPos 1

// конец "облагороженного" участка кода

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

Однако, это нам дало только то, что сикретпоушен корректно обрабатывается только в радужной комнате, но может свариться не только в ней, ибо в скрипте упоминаний о каком-то хитром поведении cauldron-а нет.
Значит, это нечто, закоденное не в скрипте, а в самом коде игрушки, и придется обратиться к исходникам, а поскольку оригинальные исходники HOF нам недоступны, то полезем препарировать модуль 'kyra' из ScummVM.

Location 2: Morningmist Sources.

Первое же, что напоминает нам работу с котлом, мы находим в engines/kyra/staticres.cpp:

Код: Выделить всё
const int16 KyraEngine_HoF::_cauldronMagicTable[] = {
   0x0, 0x16, 0x2, 0x1A,
   0x7, 0xA4, 0x5, 0x4D,
   0x1, 0xA5, 0x3, 0xA6,
   0x6, 0x6D, 0x4, 0x91,
   0xA, 0x99, 0xC, 0x95,
   0x9, 0xAC, -1, -1
};

const int16 KyraEngine_HoF::_cauldronMagicTableScene77[] = {
   0x0, 0x16, 0x2, 0x1A,
   0x7, 0xAB, 0x5, 0x4D,
   0x1, 0xAE, 0x3, 0xAF,
   0x6, 0x6D, 0x4, 0x91,
   0xA, 0x99, 0xC, 0x95,
   0x9, 0xAC, -1, -1
};

Это похоже на пары цифр, маленькая, затем большая.
Обратившись к списку номеров айтемов (либо пропарсив соответствующую WSA-шку, либо пройдя give-ом по всем указанным тут номерам), увидим, что:
16 - теплая вода, набираемая из котла сразу
1A - зелье болотной змеи,
A4 - зелье бутерброда, AB - его рэйнбоурумная версия
и т.п.

Непонятно, однако, что значат цифры в самом начале? Есть в диапазонах 0-7, затем 9-A, затем C (у сикрет-поушена).
Что это такое? Видимо, номер какой-то последовательности.

Попробуем найти, где вообще упоминаются эти мэйджик-тейблы. Лезем в gui_hof.cpp, видим (комментарии мои):

Код: Выделить всё
   // если в руке пустой стакан, то...
   if (_itemInHand == 18) {
       // Ага, вот обращение к этим таблицам (в зависимости от номера комнаты)
      const int16 *magicTable = (_mainCharacter.sceneId == 77) ? _cauldronMagicTableScene77 : _cauldronMagicTable;
      while (magicTable[0] != -1) {
         if (_cauldronState == magicTable[0]) { // отсюда видим, что каждый четный элемент таблицы (считая с нуля) - это _cauldronState.
            setHandItem(magicTable[1]); // это каждый нечетный элемент: именно это (номер айтема - проверяется через give в скумме, также номер кадра в соответствующей WSA)
            snd_playSoundEffect(0x6C);
            ++_cauldronUseCount;
            if (_cauldronStateTable[_cauldronState] <= _cauldronUseCount && _cauldronUseCount) {
               showMessage(0, 0xCF);
               setCauldronState(0, true);
               clearCauldronTable();
            }
            return 0;
         }
         magicTable += 2;
      }
   } else if (_itemInHand >= 0) {
      int item = _itemInHand;
      cauldronItemAnim(item);
      addFrontCauldronTable(item);
      if (!updateCauldron()) { // ага!!! вот эта функция, видимо, просчитывает, не запихнуть ли нам зелье в котел, если там определенная последовательность
         _cauldronState = 0;
         cauldronRndPaletteFade(); // ведь иначе (судя по названию функции) это просто обычное изменение палитры на пару секунд, как при кидании туда любой штуки
      }
   }

Таким образом, нам нужно найти место, в котором _cauldronState становится равным 0xC.

Ищем присваивания этой переменной любых значений и находим, что единственное достойное внимания присвоение происходит в kyra_hof.cpp, в функции setCauldronState (капитан очевидность просто пляшет от радости).
Ищем обращения к этой функции и - пути сходятся! - находим как раз ту упомянутую раньше функцию updateCauldron!

Код: Выделить всё
bool KyraEngine_HoF::updateCauldron() {
   for (int i = 0; i < 23; ++i) {
      const int16 *curStateTable = _cauldronStateTables[i];
      if (*curStateTable == -2)
         continue;

      int cauldronState = i;
      int16 cauldronTable[25];
      memcpy(cauldronTable, _cauldronTable, sizeof(cauldronTable));

      while (*curStateTable != -2) {
         int stateValue = *curStateTable++;
         int j = 0;
         for (; j < 25; ++j) {
            int val = cauldronTable[j];

            switch (val) {
            case 68:
               val = 70;
               break;

            case 133:
            case 167:
               val = 119;
               break;

            case 130:
            case 143:
            case 100:
               val = 12;
               break;

            case 132:
            case 65:
            case 69:
            case 74:
               val = 137;
               break;

            case 157:
               val = 134;
               break;

            default:
               break;
            }

            if (val == stateValue) {
               cauldronTable[j] = -1;
               j = 26;
            }
         }

         if (j == 25)
            cauldronState = -1;
      }

      if (cauldronState >= 0) {
         showMessage(0, 0xCF);
         setCauldronState(cauldronState, true);
         if (cauldronState == 7)
            objectChat(getTableString(0xF2, _cCodeBuffer, 1), 0, 0x83, 0xF2);
         clearCauldronTable();
         return true;
      }
   }

   return false;
}

Грубо говоря, мы перебираем все 23 (!!! зачем столько?) возможных таблиц-рецептов зелий _cauldronStateTables[i]. Неиспользуемые таблицы начинаются с -2.

_cauldronTable - это список того, что находится в котле (максимум 25 элементов), с возможными поправками:
68 -> 70, то есть отпечаток ноги на глине приравнивается к отпечатку на пастиле;
133, 167 -> 119, то есть сосульки (кстати, вторая в игре вроде не используется) - к снегу;
130, 143, 100 -> 12, то есть перьевой пылеочиститель, перья из подушки снежного человека и "промо-ручка" из вулкании - к перу из гнезда;
132, 65, 69, 74 -> 137, то есть леденец, пиво в кружке (но не в миске), пастила и пастила в миске - к конфетам снежного человека;
и 157 -> 134, то есть одеколон - к мускусу.

Потом до конца рецепта-таблицы (который кончается элементом -2) мы проверяем соответствие, и если все элементы есть, меняем статус котла на соответствующий данному поушену.

Стоп... что это значит?! То есть я могу варить поушен даже если у меня в котле другой мусор?! Проверим-ка... запустим hof, загрузим сейв радужной комнаты, кинем в котел обложку, горяячий воздух, теперь луковицу (например) и засыпем сверху пером... ДА!!! Поушен сварился. (это происходит как в скумме, так и в оригинальной версии). А вы знали, что вовсе не обязательно соблюдать рецептуру? Главное кинуть нужные компоненты, а остальные - пофиг =)
Крутяк, значит, побросав в котел все имеющиеся у нас предметы, мы можем сварить нужный поушен, не заботясь о его чистоте)
А интересно, что будет, если мы будем кидать последним элемент, необходимый для двух поушенов? Например снег, имея в котле все остальные компоненты как для снеговика, так и для снежного человека? Или крокодиловы слезы для зелья сомнения и для болотной змеи... Интересно =)

В общем, это все неимоверно интересно, но как же заполняются таблицы? А функцией

Код: Выделить всё
bool KyraEngine_HoF::addToCauldronStateTable(int data, int idx) {
   for (int i = 0; i < 7; ++i) {
      if (_cauldronStateTables[idx][i] == -2) {
         _cauldronStateTables[idx][i] = data;
         return true;
      }
   }
   return false;
}

Которая в свою очередь, вызывается скриптовой функцией addCauldronStateTableEntry с опкодом 0х7A (смотрим в script_hof.cpp)

Код: Выделить всё
int KyraEngine_HoF::o2_addCauldronStateTableEntry(EMCState *script) {
   debugC(3, kDebugLevelScriptFuncs, "KyraEngine_HoF::o2_addCauldronStateTableEntry(%p) (%d, %d)", (const void *)script, stackPos(0), stackPos(1));
   return addToCauldronStateTable(stackPos(0), stackPos(1)) ? 1 : 0;
}

bool KyraEngine_HoF::addToCauldronStateTable(int data, int idx) {
   for (int i = 0; i < 7; ++i) {
      if (_cauldronStateTables[idx][i] == -2) {
         _cauldronStateTables[idx][i] = data;
         return true;
      }
   }
   return false;
}

Значит, постановка задачи такая. Надо найти скрипт EMC, в котором выполняется эта функция, т.е. есть строчка типа

Код: Выделить всё
0x0E c1_execOpcode 122 ; functionname: 'o2_unk0x7A'.

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

Location 3. The Enchanted MISC_EMC.

Путем копания в PAK-ах и EMC-шках (а точнее, поиска последовательности 0x4E 0x7A: опкод 0x0E or-ится с 0x40, это видимо флаг длины команды - однобайтной, т.к. у двухбаййтных, например, там не 0x40, а 0x20 =) было выяснено, что соответствующая EMC-шка содержится в MISC_EMC.PAK (кэп опять настороже =), в скрипте _START_01.EMC (кэп ликует).

Вот выдержка оттуда:

Код: Выделить всё
0x110E: 0x04 c1_push 2 ; could be string 'DOCK'
0x1110: 0x04 c1_push 6 ; could be string 'NEST'
0x1112: 0x0E c1_execOpcode 122 ; functionname: 'o2_unk0x7A'
0x1114: 0x0C c1_addSP 2
0x1116: 0x04 c1_push 2 ; could be string 'DOCK'
0x1118: 0x04 c1_push 1 ; could be string 'OUTHOME'
0x111A: 0x0E c1_execOpcode 122 ; functionname: 'o2_unk0x7A'
0x111C: 0x0C c1_addSP 2
0x111E: 0x04 c1_push 2 ; could be string 'DOCK'
0x1120: 0x04 c1_push 0
0x1122: 0x0E c1_execOpcode 122 ; functionname: 'o2_unk0x7A'
0x1124: 0x0C c1_addSP 2
0x1126: 0x04 c1_push 2 ; could be string 'DOCK'
0x1128: 0x04 c1_push 25 ; could be string 'ALLEY'
0x112A: 0x0E c1_execOpcode 122 ; functionname: 'o2_unk0x7A'
0x112C: 0x0C c1_addSP 2
0x112E: 0x04 c1_push 2 ; could be string 'DOCK'
0x1130: 0x04 c1_push 5 ; could be string 'FERRY'
0x1132: 0x0E c1_execOpcode 122 ; functionname: 'o2_unk0x7A'
0x1134: 0x0C c1_addSP 2
0x1136: 0x04 c1_push 2 ; could be string 'DOCK'
0x1138: 0x04 c1_push 23 ; could be string 'CELLAR'
0x113A: 0x0E c1_execOpcode 122 ; functionname: 'o2_unk0x7A'
0x113C: 0x0C c1_addSP 2
0x113E: 0x04 c1_push 7 ; could be string 'OUTHERB'
0x1140: 0x04 c1_push 51 ; could be string 'VOLC_G'
0x1142: 0x0E c1_execOpcode 122 ; functionname: 'o2_unk0x7A'
0x1144: 0x0C c1_addSP 2
0x1146: 0x04 c1_push 7 ; could be string 'OUTHERB'
0x1148: 0x04 c1_push 40 ; could be string 'ANCHOR'
0x114A: 0x0E c1_execOpcode 122 ; functionname: 'o2_unk0x7A'
0x114C: 0x0C c1_addSP 2
0x114E: 0x04 c1_push 7 ; could be string 'OUTHERB'
0x1150: 0x04 c1_push 33 ; could be string 'WHARF'
0x1152: 0x0E c1_execOpcode 122 ; functionname: 'o2_unk0x7A'
0x1154: 0x0C c1_addSP 2
0x1156: 0x04 c1_push 7 ; could be string 'OUTHERB'
0x1158: 0x04 c1_push 29 ; could be string 'STREET'
0x115A: 0x0E c1_execOpcode 122 ; functionname: 'o2_unk0x7A'
0x115C: 0x0C c1_addSP 2
0x115E: 0x04 c1_push 5 ; could be string 'FERRY'
0x1160: 0x04 c1_push 36 ; could be string 'JUNGLE'
0x1162: 0x0E c1_execOpcode 122 ; functionname: 'o2_unk0x7A'
0x1164: 0x0C c1_addSP 2
0x1166: 0x04 c1_push 5 ; could be string 'FERRY'
0x1168: 0x04 c1_push 70 ; could be string 'FIGHT'
0x116A: 0x0E c1_execOpcode 122 ; functionname: 'o2_unk0x7A'
0x116C: 0x0C c1_addSP 2
0x116E: 0x04 c1_push 5 ; could be string 'FERRY'
0x1170: 0x04 c1_push 59 ; could be string 'VOLC_O'
0x1172: 0x0E c1_execOpcode 122 ; functionname: 'o2_unk0x7A'
0x1174: 0x0C c1_addSP 2
0x1176: 0x04 c1_push 5 ; could be string 'FERRY'
0x1178: 0x04 c1_push 25 ; could be string 'ALLEY'
0x117A: 0x0E c1_execOpcode 122 ; functionname: 'o2_unk0x7A'
0x117C: 0x0C c1_addSP 2
0x117E: 0x04 c1_push 1 ; could be string 'OUTHOME'
0x1180: 0x04 c1_push 114 ; could be string 'SLR1'
0x1182: 0x0E c1_execOpcode 122 ; functionname: 'o2_unk0x7A'
0x1184: 0x0C c1_addSP 2
0x1186: 0x04 c1_push 1 ; could be string 'OUTHOME'
0x1188: 0x04 c1_push 99 ; could be string '----'
0x118A: 0x0E c1_execOpcode 122 ; functionname: 'o2_unk0x7A'
0x118C: 0x0C c1_addSP 2
0x118E: 0x04 c1_push 1 ; could be string 'OUTHOME'
0x1190: 0x04 c1_push 12 ; could be string 'FISHER'
0x1192: 0x0E c1_execOpcode 122 ; functionname: 'o2_unk0x7A'
0x1194: 0x0C c1_addSP 2
0x1196: 0x04 c1_push 3 ; could be string 'FLYTRAP'
0x1198: 0x04 c1_push 113 ; could be string 'CPTN'
0x119A: 0x0E c1_execOpcode 122 ; functionname: 'o2_unk0x7A'
0x119C: 0x0C c1_addSP 2
0x119E: 0x04 c1_push 3 ; could be string 'FLYTRAP'
0x11A0: 0x04 c1_push 102 ; could be string 'FAU4'
0x11A2: 0x0E c1_execOpcode 122 ; functionname: 'o2_unk0x7A'
0x11A4: 0x0C c1_addSP 2
0x11A6: 0x04 c1_push 3 ; could be string 'FLYTRAP'
0x11A8: 0x04 c1_push 104 ; could be string 'GRD1'
0x11AA: 0x0E c1_execOpcode 122 ; functionname: 'o2_unk0x7A'
0x11AC: 0x0C c1_addSP 2
0x11AE: 0x04 c1_push 6 ; could be string 'NEST'
0x11B0: 0x04 c1_push 119 ; could be string 'CBL3'
0x11B2: 0x0E c1_execOpcode 122 ; functionname: 'o2_unk0x7A'
0x11B4: 0x0C c1_addSP 2
0x11B6: 0x04 c1_push 6 ; could be string 'NEST'
0x11B8: 0x04 c1_push 118 ; could be string 'CBL2'
0x11BA: 0x0E c1_execOpcode 122 ; functionname: 'o2_unk0x7A'
0x11BC: 0x0C c1_addSP 2
0x11BE: 0x04 c1_push 6 ; could be string 'NEST'
0x11C0: 0x04 c1_push 120 ; could be string 'SCRB'
0x11C2: 0x0E c1_execOpcode 122 ; functionname: 'o2_unk0x7A'
0x11C4: 0x0C c1_addSP 2
0x11C6: 0x04 c1_push 4 ; could be string 'GNARL'
0x11C8: 0x04 c1_push 119 ; could be string 'CBL3'
0x11CA: 0x0E c1_execOpcode 122 ; functionname: 'o2_unk0x7A'
0x11CC: 0x0C c1_addSP 2
0x11CE: 0x04 c1_push 4 ; could be string 'GNARL'
0x11D0: 0x03 c1_push 134 ; could be string 'JESC'
0x11D4: 0x0E c1_execOpcode 122 ; functionname: 'o2_unk0x7A'
0x11D6: 0x0C c1_addSP 2
0x11D8: 0x04 c1_push 4 ; could be string 'GNARL'
0x11DA: 0x04 c1_push 12 ; could be string 'FISHER'
0x11DC: 0x0E c1_execOpcode 122 ; functionname: 'o2_unk0x7A'
0x11DE: 0x0C c1_addSP 2
0x11E0: 0x04 c1_push 4 ; could be string 'GNARL'
0x11E2: 0x03 c1_push 137 ; could be string 'JESM'
0x11E6: 0x0E c1_execOpcode 122 ; functionname: 'o2_unk0x7A'
0x11E8: 0x0C c1_addSP 2
0x11EA: 0x04 c1_push 10 ; could be string 'CROC'
0x11EC: 0x03 c1_push 158
0x11F0: 0x0E c1_execOpcode 122 ; functionname: 'o2_unk0x7A'
0x11F2: 0x0C c1_addSP 2
0x11F4: 0x04 c1_push 10 ; could be string 'CROC'
0x11F6: 0x03 c1_push 159
0x11FA: 0x0E c1_execOpcode 122 ; functionname: 'o2_unk0x7A'
0x11FC: 0x0C c1_addSP 2
0x11FE: 0x04 c1_push 10 ; could be string 'CROC'
0x1200: 0x03 c1_push 160
0x1204: 0x0E c1_execOpcode 122 ; functionname: 'o2_unk0x7A'
0x1206: 0x0C c1_addSP 2
0x1208: 0x04 c1_push 12 ; could be string 'FISHER'
0x120A: 0x03 c1_push 137 ; could be string 'JESM'
0x120E: 0x0E c1_execOpcode 122 ; functionname: 'o2_unk0x7A'
0x1210: 0x0C c1_addSP 2
0x1212: 0x04 c1_push 12 ; could be string 'FISHER'
0x1214: 0x04 c1_push 12 ; could be string 'FISHER'
0x1216: 0x0E c1_execOpcode 122 ; functionname: 'o2_unk0x7A'
0x1218: 0x0C c1_addSP 2
0x121A: 0x04 c1_push 12 ; could be string 'FISHER'
0x121C: 0x03 c1_push 144 ; could be string 'POPP'
0x1220: 0x0E c1_execOpcode 122 ; functionname: 'o2_unk0x7A'
0x1222: 0x0C c1_addSP 2
0x1224: 0x04 c1_push 12 ; could be string 'FISHER'
0x1226: 0x04 c1_push 115 ; could be string 'SLR2'
0x1228: 0x0E c1_execOpcode 122 ; functionname: 'o2_unk0x7A'
0x122A: 0x0C c1_addSP 2
0x122C: 0x04 c1_push 9 ; could be string 'QUICK'
0x122E: 0x04 c1_push 3 ; could be string 'FLYTRAP'
0x1230: 0x0E c1_execOpcode 122 ; functionname: 'o2_unk0x7A'
0x1232: 0x0C c1_addSP 2
0x1234: 0x04 c1_push 9 ; could be string 'QUICK'
0x1236: 0x03 c1_push 173
0x123A: 0x0E c1_execOpcode 122 ; functionname: 'o2_unk0x7A'
0x123C: 0x0C c1_addSP 2

Отсюда мы видим таблицы:

№2: 6, 1, 0, 25, 5, 23. Это зелье болотной змеи. Желающие могут проверить по номерам айтемов и номеру статуса котла (то самое мелкое число из пары в мэйджик-тэйбле).
№7: 51, 40, 33, 29. Бутерброд.
№5: 36, 70, 59, 25. Скептик серум (основа для зелья сомнения).
№1: 114, 99, 12. Башмачки.
№3: 113, 102, 104. Плюшевый медвед.
№6: 119, 118, 120. Снеговик.
№4: 119, 134, 12, 137. Снежный человек.
№10: 158, 159, 160. Радужное зелье.
№12: ... пропустим пока
№9: 3, 173. Синее зелье из первой Кирандии.

Кстати, хочу заметить, что зелья транса тут нет, а значит, его сварить невозможно.

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

Location 4. The Final Battle: Zanthia vs. Secret Potion.

Предупреждение PG-37!!!! Детям до 37 лет... ой... ну то есть, тем, кто хочет САМ открыть рецепт зелья, дальше НЕ ЧИТАТЬ!!!!

предпоследняя строчка такова:

№12: 137, 12, 144, 115. То есть (выделить для прочтения) (сладости, перо, свисток (из радужного зелья) и зелёные кристаллики). А статус №12 - ЭТО И ЕСТЬ СЕКРЕТНОЕ ЗЕЛЬЕ!

Итак, дрожащими руками загружаем сейв с радужной комнатой (не ScummVM, только оригинальный HOF, запущенный из-под DosBox-а или чистого DOS-а!). Убедившись, что звук включен (какой sound toy без звука?!), Занция кидает в котел радужный камень, доминошку, коня, тащит с полки флакон с горячей водой, обжигаясь, выпивает его (не время сейчас думать о комфорте), черпает из котла радужное зелье, вытаскивает из флакона свисток (он большой, поэтому флакон приходится разбить), кидает его без промедления обратно в котел, присыпает сверху зелеными кристаллами, конфеткой мальчика, пером, и жидкость в котле окрашивается в прозрачно-розовый цвет! Сетуя на себя за то, что разбила тот флакон со свистком, Занция глотает еще порцию кипятка и черпает освободившимся флаконом звездящуюся жидкость из котла (в котле она сразу обесцвечивается - зелья хватает лишь на один флакон). Хватает флакон в руки, дергает из него пробку - и - БАБАХ! - Congratulations!!! Заиграла бодрая музычка, и теперь, жмя на любую кнопку с буквой на клавиатуре (т.е. QWERTYUIOPASDFGHJKLZXCVBNM1234567890), а также точку, кнопки со стрелками и Ins/Home/PgUp/End/PgDn (но не Del), а также клавиши 0-4 и 6-9 на цифровой клавиатуре (знаки препинания и все остальные служебные клавиши молчат), мы можем послушать, возможно, все звуковые эффекты из игры!
Вдоволь наигравшись со звуками, конечно, Занция может пойти проходить игру дальше. =)

И да, как уже сказано выше, судя по скрипту MYSTRM.EMC, такой эффект достигается, только если это делать в радужной комнате. В любой другой локации выпивание этого зелья не принесет ничего, так что положите свои редакторы сейвов, где взяли. =)

Outro.

А сейчас на часах уже 6:17, и как бы ни хотелось почувствовать себя королевским мистиком, копающихся в книгах в надежде найти секретный рецепт, пойду лучше спать, яки Малколм, ибо Кирандия в очередной раз спасена =), а сюжет поисков секретного зелья для четвертой книги, увы, теперь неактуален. =)

P.S.

Итого на открытие рецепта было потрачено чуть менее 6 часов - примерно с 0:30 и до 6:17. Но оно того стоило! Ведь, насколько я знаю, эту загадку никто из кирандийцев еще не смог разгадать))
Аватара пользователя
Малкольмович
(4) помощник Мистика
 
Сообщения: 293
Зарегистрирован: 22 дек 2011, 22:09
Любимая часть Кирандии: Hand of Fate, а точнее, Darkmoor Swamp из неё =)
Любимые персонажи Кирандии: Занечка всех порулит =)
Почему Вы любите Легенду о Кирандии?: это мир, в котором можно жить, а не в который играть)

Re: Как я искал (и нашёл! =) рецепт секретного поушена))

Сообщение Малкольмович » 23 дек 2011, 21:08

А теперь для тех, кому вышеприведенное не очень интересно, подытожу то, что я выяснил:
- за чистотой зелий следить не обязательно, т.е. можно сваливать все в котел без разбору, главное, чтобы там оказались все нужные компоненты
- зелье транса сварить невозможно, ибо в игре нет ни его айтема, ни рецепта
- секретное зелье имеет эффект только в радужной комнате
- и наконец, оно состоит из (выделить для прочтения: сладостей, пера, свистка и зелёных кристалликов). =)
Вложения
MYSTRM.rar
Декомпилированный скрипт радужной комнаты
(21.44 КБ) Скачиваний: 185
Аватара пользователя
Малкольмович
(4) помощник Мистика
 
Сообщения: 293
Зарегистрирован: 22 дек 2011, 22:09
Любимая часть Кирандии: Hand of Fate, а точнее, Darkmoor Swamp из неё =)
Любимые персонажи Кирандии: Занечка всех порулит =)
Почему Вы любите Легенду о Кирандии?: это мир, в котором можно жить, а не в который играть)

Re: Как я искал (и нашёл! =) рецепт секретного поушена))

Сообщение Milena » 24 дек 2011, 13:36

Малкольмович писал(а):Стоп... что это значит?! То есть я могу варить поушен даже если у меня в котле другой мусор?! Проверим-ка... запустим hof, загрузим сейв радужной комнаты, кинем в котел обложку, горяячий воздух, теперь луковицу (например) и засыпем сверху пером... ДА!!! Поушен сварился. (это происходит как в скумме, так и в оригинальной версии). А вы знали, что вовсе не обязательно соблюдать рецептуру? Главное кинуть нужные компоненты, а остальные - пофиг =)
Крутяк, значит, побросав в котел все имеющиеся у нас предметы, мы можем сварить нужный поушен, не заботясь о его чистоте)
А интересно, что будет, если мы будем кидать последним элемент, необходимый для двух поушенов? Например снег, имея в котле все остальные компоненты как для снеговика, так и для снежного человека? Или крокодиловы слезы для зелья сомнения и для болотной змеи... Интересно =)


Я, кстати, давным-давно открыла, что вместе с мусором зелья тоже варятся - когда я мне было 4 или 5 лет и я играла в кирандию впервые, не зная английского, и мы с братом вместе составляли рецепты, просто добавляя все что можно ) Не уверена, что мы прошли дальше второго зелья, но точно помню, что "НАШ" рецепт зеленого зелья включал в себя гриб-мухомор, который мы добавляли сразу после срывания)

СПАСИБО ВАМ ОГРОМНОЕ! Это неоценимый вклад!! :D :D :D :D :D :D

П.с. Собственно, зелье болотной змеи "бьет" зелье сомнения, а зелье отвратительного снеговика "бьет" обычное - только что проверила 8*)
Я безнадежно влюблена в пещеры и запах дорог...
Аватара пользователя
Milena
Шериф Высокой Луны (модератор)
 
Сообщения: 551
Зарегистрирован: 30 ноя 2005, 02:29
Откуда: г. Москва
Любимая часть Кирандии: Первые две
Любимые персонажи Кирандии: Почтовый дракончик, Херман, Флаффи, Малкольм, Нолби, Дарм.
Почему Вы любите Легенду о Кирандии?: Она живая. И она оживляет.

Re: Как я искал (и нашёл! =) рецепт секретного поушена))

Сообщение Sonoko » 25 дек 2011, 10:03

Зелье транса - рецепт есть. Компонентов нет. Кажется, тут дообсуждались до того, что рецепт дан, чтобы игрок сообразил "ага! все ребята в трансе, надо варить зелье сомнения!" :)
Be careful, boy. Do not insult a man with knives.
---
Так надоел бой с тенью...
Аватара пользователя
Sonoko
(5) Мистик
 
Сообщения: 505
Зарегистрирован: 26 июн 2005, 10:09
Откуда: Томск
Любимая часть Кирандии: Рука Судьбы
Любимые персонажи Кирандии: Занция, Малькольм
Почему Вы любите Легенду о Кирандии?: це невыразимо=)))

Re: Как я искал (и нашёл! =) рецепт секретного поушена))

Сообщение Lunyavaya » 26 дек 2011, 14:09

Ооооо...))))) Спасииибо)) щас дойду о5 до радужной и буду радоваться)))))
Изображение
Аватара пользователя
Lunyavaya
(4) помощник Мистика
 
Сообщения: 319
Зарегистрирован: 30 ноя 2011, 19:17
Откуда: Высокая Луна
Любимая часть Кирандии: The Hand of Fate
Любимые персонажи Кирандии: Занция, Малколм и Дарм, конечно же)
Почему Вы любите Легенду о Кирандии?: За право играть в Кирандию мы с братом и мамой(!) почти дрались..))))
Такой волшебной и атмосферной игры я больше не видела..) Люблю, в общем)

Re: Как я искал (и нашёл! =) рецепт секретного поушена))

Сообщение Lunyavaya » 26 дек 2011, 14:22

Ураааа!!!)
Вложения
Безимени-2.jpg
Безимени-2.jpg (42.3 КБ) Просмотров: 7727
Изображение
Аватара пользователя
Lunyavaya
(4) помощник Мистика
 
Сообщения: 319
Зарегистрирован: 30 ноя 2011, 19:17
Откуда: Высокая Луна
Любимая часть Кирандии: The Hand of Fate
Любимые персонажи Кирандии: Занция, Малколм и Дарм, конечно же)
Почему Вы любите Легенду о Кирандии?: За право играть в Кирандию мы с братом и мамой(!) почти дрались..))))
Такой волшебной и атмосферной игры я больше не видела..) Люблю, в общем)

Re: Как я искал (и нашёл! =) рецепт секретного поушена))

Сообщение Малкольмович » 26 дек 2011, 19:56

Sonoko, именно так оно и есть) просто я видел треды (что тут, что в контактике) на тему "ну может все-таки зелье транса можно изготовить?.."

Lunyavaya, поздравляю)) клавиатурка превратилась в magical sound toy?)
Аватара пользователя
Малкольмович
(4) помощник Мистика
 
Сообщения: 293
Зарегистрирован: 22 дек 2011, 22:09
Любимая часть Кирандии: Hand of Fate, а точнее, Darkmoor Swamp из неё =)
Любимые персонажи Кирандии: Занечка всех порулит =)
Почему Вы любите Легенду о Кирандии?: это мир, в котором можно жить, а не в который играть)

Re: Как я искал (и нашёл! =) рецепт секретного поушена))

Сообщение Lunyavaya » 26 дек 2011, 21:59

отож)) конечно, превратилась) Очень порадовало)
Изображение
Аватара пользователя
Lunyavaya
(4) помощник Мистика
 
Сообщения: 319
Зарегистрирован: 30 ноя 2011, 19:17
Откуда: Высокая Луна
Любимая часть Кирандии: The Hand of Fate
Любимые персонажи Кирандии: Занция, Малколм и Дарм, конечно же)
Почему Вы любите Легенду о Кирандии?: За право играть в Кирандию мы с братом и мамой(!) почти дрались..))))
Такой волшебной и атмосферной игры я больше не видела..) Люблю, в общем)

Re: Как я искал (и нашёл! =) рецепт секретного поушена))

Сообщение The_Rover » 27 дек 2011, 00:57

Ого, ну вот и раскрыли секрет, который мне уже несколько лет покоя не давал)) Класс)
A rock and a hard place await for me
Between the devil and the deep blue sea
The_Rover
(0) Каннибал Горчичного острова
 
Сообщения: 9
Зарегистрирован: 11 янв 2009, 20:43
Откуда: Москва

Re: Как я искал (и нашёл! =) рецепт секретного поушена))

Сообщение Малкольмович » 28 дек 2011, 22:30

на здоровье)

кстати, я не думал, что все так быстро получится, или что я вообще разберусь в языке этих скриптов)
руки чешутся написать нормальный декомпилятор, ибо видно же, что компилилось с высокого уровня, и все это, в принципе, можно перевести в некое подобие сишника, только с goto и без select/for/while =) тогда все станет гораздо понятнее)
вот только кто бы мне сготовил зелье остановки времени или написал бы свиток удлинения суток еще часов эдак на десять?)
Аватара пользователя
Малкольмович
(4) помощник Мистика
 
Сообщения: 293
Зарегистрирован: 22 дек 2011, 22:09
Любимая часть Кирандии: Hand of Fate, а точнее, Darkmoor Swamp из неё =)
Любимые персонажи Кирандии: Занечка всех порулит =)
Почему Вы любите Легенду о Кирандии?: это мир, в котором можно жить, а не в который играть)

Re: Как я искал (и нашёл! =) рецепт секретного поушена))

Сообщение bckpkol » 05 фев 2012, 23:07

На самом деле вполне возможно сделать secret potion в ScummVM.
Бабах! Музыка играет! Вот только клавиатура не превращается в music toy.
Аватара пользователя
bckpkol
(3) Столичный горожанин
 
Сообщения: 223
Зарегистрирован: 02 янв 2011, 20:48
Откуда: город Бийск
Любимая часть Кирандии: Кирандия 3 и 4
Любимые персонажи Кирандии: Дарм, Зантия
Почему Вы любите Легенду о Кирандии?: За простоту, удобство интерфейса и лёгкую проходимость.

Re: Как я искал (и нашёл! =) рецепт секретного поушена))

Сообщение Малкольмович » 06 фев 2012, 19:38

Естественно, все можно сварить и в scumm-е - ведь я парсил именно его исходники, а не HoF.
Однако setGameFlag(494); в скумме не делает ничего - ведь скумм просто не знает, что можно делать с этим флагом.
Аватара пользователя
Малкольмович
(4) помощник Мистика
 
Сообщения: 293
Зарегистрирован: 22 дек 2011, 22:09
Любимая часть Кирандии: Hand of Fate, а точнее, Darkmoor Swamp из неё =)
Любимые персонажи Кирандии: Занечка всех порулит =)
Почему Вы любите Легенду о Кирандии?: это мир, в котором можно жить, а не в который играть)

Re: Как я искал (и нашёл! =) рецепт секретного поушена))

Сообщение Reflector » 21 фев 2012, 17:39

Малкольмович писал(а):на здоровье)

руки чешутся написать нормальный декомпилятор, ибо видно же, что компилилось с высокого уровня, и все это, в принципе, можно перевести в некое подобие сишника, только с goto и без select/for/while =) тогда все станет гораздо понятнее)

Я уже игрался с декомпиляцией, можешь глянуть тестовый билд моего экстрактора... Для сравнения, dekyra выдает такой листинг:
Код: Выделить всё
0x0040: 0x02 c1_pushRetOrPos 0
0x0042: 0x11 c1_eval 5 ; (C syntax): '(val1 >= val2)'
0x0044: 0x0F c1_ifNotJmp 0x0054
0x0048: 0x04 c1_push -1
0x004A: 0x04 c1_push 5 ; could be string 'Is it missing a piece?'
0x004C: 0x04 c1_push 0
0x004E: 0x0E c1_execOpcode 58 ; functionname: 'o1_changeCharactersFacing'
0x0050: 0x0C c1_addSP 3
0x0052: 0x00 c1_jumpTo 0x005E

А у меня такой:
Код: Выделить всё
0x0040:  4200   pushRet
0x0042:  5105   [SP] = (a < b)
0x0044:  2F00   ifNotJmp 0x0054
0x0046:  802A
0x0048:  44FF   push -1
0x004A:  4405   push 5
0x004C:  4400   push 0
0x004E:  4E3A   o1_changeCharactersFacing()
0x0050:  4C03   SP += 3
0x0052:  802F   goto 0x005e

А вот приведение к сишнику - это уже совершенно другой объем работ :)
Reflector
(2) Житель Милтонии
 
Сообщения: 163
Зарегистрирован: 11 сен 2010, 16:44
Любимая часть Кирандии: 2
Любимые персонажи Кирандии: Занция
Почему Вы любите Легенду о Кирандии?: Ностальгия...

Re: Как я искал (и нашёл! =) рецепт секретного поушена))

Сообщение Малкольмович » 21 фев 2012, 19:32

это уже, так сказать, шаг в будущее)

а моя идея была - покопаться с декомпилированными скриптами и все push/pop поперекидать в параметры, кроме спорных случаев)

в идеале, конечно, нужно сделать некий монитор стека, который бы собирал параметры функций и при вызове бы их подставлял (но тут надо забить в него все функции и их количество параметров, чтобы он правильно работал, а это (с проверками) не на день, и наверное, даже не на месяц работы))
Аватара пользователя
Малкольмович
(4) помощник Мистика
 
Сообщения: 293
Зарегистрирован: 22 дек 2011, 22:09
Любимая часть Кирандии: Hand of Fate, а точнее, Darkmoor Swamp из неё =)
Любимые персонажи Кирандии: Занечка всех порулит =)
Почему Вы любите Легенду о Кирандии?: это мир, в котором можно жить, а не в который играть)

Re: Как я искал (и нашёл! =) рецепт секретного поушена))

Сообщение Reflector » 21 фев 2012, 20:49

Малкольмович писал(а):в идеале, конечно, нужно сделать некий монитор стека, который бы собирал параметры функций и при вызове бы их подставлял (но тут надо забить в него все функции и их количество параметров, чтобы он правильно работал, а это (с проверками) не на день, и наверное, даже не на месяц работы))

Список функций уже есть, после вызова каждой к SP прибавляется число равное количеству параметров(надеюсь исключений нет), так что 5-ть строк из моего листинга можно легко свернуть до одной: o1_changeCharactersFacing(-1, 5, 0). Проблема в том, что аргументы не просто лежат на стеке, иногда сначала нужно выполнить серию арифметических операций и не всегда над константами. Компилятор был не очень умный, там встречаются даже выражения типа "0 + 0" :) Но это все реализуемо, я когда-то писал с-подобный компилятор для PIC18, вот там была жесть, а тут нужен лишь особый настрой :)
Reflector
(2) Житель Милтонии
 
Сообщения: 163
Зарегистрирован: 11 сен 2010, 16:44
Любимая часть Кирандии: 2
Любимые персонажи Кирандии: Занция
Почему Вы любите Легенду о Кирандии?: Ностальгия...

Re: Как я искал (и нашёл! =) рецепт секретного поушена))

Сообщение Малкольмович » 22 фев 2012, 17:35

Да, тут самое простое - полагаться на опкоды и на определенную последовательность команд, например, что после exec стоит add_sp, а перед exec чаще всего нужное количество push-ей; еще надо в некоторых функциях в зависимости от типа подставлять не числа, а строки; ну и конструкции типа if..goto тоже надо хитро парсить - тогда многое станет понятнее.

Проблема в том, что это не панацея, например, от функций, возвращающих значения на стеке (конкретно не смотрел, есть ли такие, но никто не запрещает их иметь), тогда, например, что-то типа

function get_A_and_B (out& A, out& B);
function make_something_with_B(in B);

...
get_A_and_B (a, b);
make_something_with_B(b);
...

превращалось бы в

call get_A_and_B
sub sp, 1
call make_something_with_B
sub sp, 1

и вся логика декомпилера летела бы далеко-далеко(
Аватара пользователя
Малкольмович
(4) помощник Мистика
 
Сообщения: 293
Зарегистрирован: 22 дек 2011, 22:09
Любимая часть Кирандии: Hand of Fate, а точнее, Darkmoor Swamp из неё =)
Любимые персонажи Кирандии: Занечка всех порулит =)
Почему Вы любите Легенду о Кирандии?: это мир, в котором можно жить, а не в который играть)

Re: Как я искал (и нашёл! =) рецепт секретного поушена))

Сообщение Reflector » 22 фев 2012, 18:52

По-моему ты все излишне драматизируешь :) Допустим у нас есть такой фрагмент листинга:
Код: Выделить всё
0x0038:  4501   pushGVar 1
0x003A:  4400   push 0
0x003C:  4E38   o1_getCharacterX()
0x003E:  4C01   SP += 1
0x0040:  4200   pushRet
0x0042:  5105   [SP] = (a < b)
0x0044:  2F00   ifNotJmp 0x0054

Вероятно o1_getCharacterX() возвращает позицию X для какого-то персонажа, но можно получить более подробную информацию из исходников скума, в котором реализованы все наши функции. Вот нужный фрагмент:
Код: Выделить всё
int KyraEngine_LoK::o1_getCharacterX(EMCState *script)
{
    debugC(3, kDebugLevelScriptFuncs, "KyraEngine_LoK::o1_getCharacterX(%p) (%d)",
        (const void *)script, stackPos(0));
    return _characterList[stackPos(0)].x1;
}

Из него видно, что функция принимает один аргумент(индекс персонажа) и возвращает для него X. Однако в листинге все равно написано SP += 1, т.к. аргумент был всего один, зато еще есть pushRet, которая кидает на стек наше возвращаемое значение. Насколько я понимаю возврат значений вообще не производится через стек, для этого есть специальная команда, такой подход позволяет упростить написание компилятора. В крайнем случае можно взять из скума количество аргументов для каждой функции, жестко их прописать и затем сравнивать с величиной приращения стека после возврата из функций.
Reflector
(2) Житель Милтонии
 
Сообщения: 163
Зарегистрирован: 11 сен 2010, 16:44
Любимая часть Кирандии: 2
Любимые персонажи Кирандии: Занция
Почему Вы любите Легенду о Кирандии?: Ностальгия...

Re: Как я искал (и нашёл! =) рецепт секретного поушена))

Сообщение Малкольмович » 27 фев 2012, 14:41

да, я действительно драматизирую, потому что такое возможно))
естественно, возвращать значение проще либо через зарезервированный глобал (например, pushRet именно его помещает на стек), регистр (например, AX/EАХ - так в х86-асме) или через стек (return x -> {pop eip; push x;} ), но когда речь идет не о возврате через return, а о передаче значений наверх по ссылке, такие махинации со стеком вполне могут быть)

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

а насчет взять количество (и формат!) параметров из исходников scumm - это первое, о чем я подумал, когда у меня возникла такая идея)))
Аватара пользователя
Малкольмович
(4) помощник Мистика
 
Сообщения: 293
Зарегистрирован: 22 дек 2011, 22:09
Любимая часть Кирандии: Hand of Fate, а точнее, Darkmoor Swamp из неё =)
Любимые персонажи Кирандии: Занечка всех порулит =)
Почему Вы любите Легенду о Кирандии?: это мир, в котором можно жить, а не в который играть)

Re: Как я искал (и нашёл! =) рецепт секретного поушена))

Сообщение Reflector » 27 фев 2012, 15:39

Малкольмович писал(а):впрочем, с языков высокого уровня entry/exit-код функций обычно фиксирован, и там эти параметры просто лишний раз гоняются по маршруту стек-память-стек, хоть этого можно было бы не делать, но ведь компилятор-то не знает, нужно ли оставить эти переменные на стеке.

Чем проще компилятор, тем больше в нем шаблонов, а в нашем случае он похоже вообще однопроходный :)

а насчет взять количество (и формат!) параметров из исходников scumm - это первое, о чем я подумал, когда у меня возникла такая идея)))

Вечером попробую прописать количество параметров и прогнать все скрипты...
Reflector
(2) Житель Милтонии
 
Сообщения: 163
Зарегистрирован: 11 сен 2010, 16:44
Любимая часть Кирандии: 2
Любимые персонажи Кирандии: Занция
Почему Вы любите Легенду о Кирандии?: Ностальгия...

Re: Как я искал (и нашёл! =) рецепт секретного поушена))

Сообщение Малкольмович » 28 фев 2012, 17:33

это будет хорошо))
и заодно надо сделать возможность подстановки названий функций-сисколлов MR, ибо оригинальная dekyra знает только LoK и HoF =)

интересно, а у бывших Westwood-овцев остались ли примеры исходников этих скриптов? Интересно было бы посмотреть, с чего все компилилось)
Аватара пользователя
Малкольмович
(4) помощник Мистика
 
Сообщения: 293
Зарегистрирован: 22 дек 2011, 22:09
Любимая часть Кирандии: Hand of Fate, а точнее, Darkmoor Swamp из неё =)
Любимые персонажи Кирандии: Занечка всех порулит =)
Почему Вы любите Легенду о Кирандии?: это мир, в котором можно жить, а не в который играть)

След.

Вернуться в Секреты Кирандии

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

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 1

cron