A.I.M. Jagged Alliance2

Добро пожаловать, Гость. Пожалуйста, выберите:
Вход || Регистрация.
18.04.2024 в 17:57:21

Главная Главная Помощь Помощь Поиск Поиск Участники Участники Вход Вход Регистрация Регистрация
A.I.M. « [Уголок багодела] Расширение структур OBJECTTYPE и »
   A.I.M.
   Обсуждаем игры
   Гробокопатели
(Модераторы: Терапевт, ThunderBird)
   [Уголок багодела] Расширение структур OBJECTTYPE и
« Предыдущая Тема | Следующая Тема »
  Тема:  [Уголок багодела] Расширение структур OBJECTTYPE и             Страниц: 1 Прочитано 4473 раз
bugmonster
[Баги! Баги везде!]
Source

ПРОГРАММИРЫ НЕ УЧИТЫВАЛИ ЭТУ СИТУАЦИЮ




Пол:
Репутация: +1337
[Уголок багодела] Расширение структур OBJECTTYPE и
« от 20.09.2006 в 11:22:57 »

Здравствуйте, почтенные гробокопатели и прочие интересующиеся.
 
Представляю на суд моё начинание под кодовым названием "Уголок багодела". Уголок багодела планируется как цикл статей, посвящённых доработке исходников JA2. Этот цикл статей будет интересен тем, кто занимается правкой исходников и созданием собственных модификаций JA2. Первую статью старался писать так, что бы было понятно начинающему, однако указанное усовершенствование должно быть полезно даже для опытных модостроителей. Для чтения очень желательно знание языка С.
Каждая статья построена как мануал, поэтому выполнив все описанные шаги вы получите требуемый результат, но для понимания сути изменений нужно читать и пояснения ;)
 
 
Расширение структур OBJECTTYPE и SOLDIERTYPE.
 
 
1. Что такое OBJECTTYPE и SOLDIERTYPE и зачем их "расширять"?
2. Ковыряем.
3. Что это было.
 
 
1. Что такое OBJECTTYPE и SOLDIERTYPE и зачем их "расширять"?
 
Это две из множества структур, используемых в Джа2 для хранения информации об объектах игры. В структурах типа OBJECTTYPE хранится информация о каждом предмете, существующем в игре. Важно понимать, что если в игре есть конкретная аптечка, которую можно взять, использовать, продать, то информация о ней будет храниться в OBJECTTYPE. Там хранится, например, статус аптечки, т.е. сколько процентов "бинтов" в ней осталось.
А каждый солдат, наёмник (и даже корова с вороной :) ) хранится в своём SOLDIERTYPE. В каждом SOLDIERTYPE есть место для информации об инвентаре солдата. Инвентарь - это массив из предметов OBJECTTYPE. Если увеличить размер структуры OBJECTTYPE, то изменится и размер структуры SOLDIERTYPE - именно поэтому в статье две этих структуры рассматриваются вместе.
А зачем вообще увеличивать их размеры? Дело в том, что множество нововведений ("фич"), требуют место для хранения новых данных в этих структурах, а свободного места - нет.
Например увеличение количества слотов под аттачи к оружию потребует в структуре OBJECTTYPE увеличить длину массивов
UINT16 usAttachItem[MAX_ATTACHMENTS];
INT8 bAttachStatus[MAX_ATTACHMENTS];

, но разработчики не оставили в структуре OBJECTTYPE свободного места
Увеличение количества "карманов" в инвентаре солдата потребует в структуре SOLDIERTYPE увеличить длину массива
OBJECTTYPE inv[ NUM_INV_SLOTS ];.
Здесь разработчики предусмотрели в конце структуры свободное место в виде
UINT8 bFiller[ 39 ];,
и его можно использовать для добавления небольших новых полей, но расширить или перенести на его место инвентарь не получится.
 
 
2.  Ковыряем.
 
А что нам мешает просто изменить OBJECTTYPE и SOLDIERTYPE, добавив в них новые поля по своему вкусу? Ничего. Все сохраняемые файлы игры, в т.ч. карты будут иметь новую структуру. Однако, загрузить существующие карты игра не сможет. Дело в том, что в файлах карт хранятся структуры OBJECTTYPE и SOLDIERTYPE (на самом деле информация о солдатах хранится в файле карты в виде структуры SOLDIERCREATE_STRUCT, но это дела не меняет). Хранятся они в "старом" виде, а игра теперь думает, что в "новом". Но мы - модостроители, зачем нам старые карты? Но ведь не все моды используют только новые карты, да и для сохранения переделанной карты в редакторе нужно сначала загрузить исходную в старом формате.
Есть простое решение - при загрузке карты читать OBJECTTYPE и SOLDIERTYPE старого типа и тут же в памяти преобразовывать их в новый вид.
 
Для начала откроем файл Tactical\Item types.h и скопипастим объявление структуры OBJECTTYPE. Старое объявление не трогая переименуем в OBJECTTYPE_OLD, а скопированное изменим по вкусу - это и будет наш новый OBJECTTYPE. В результате получится код вроде такого (избыточное цитирование не изменённого кода опущено под знаками " ...", изменённый код выделен жирным):

typedef struct
{
 UINT16 usItem;
 UINT8  ubNumberOfObjects;
 ...
  // attached objects
 UINT16 usAttachItem[MAX_ATTACHMENTS];
 INT8  bAttachStatus[MAX_ATTACHMENTS];
 ...
} OBJECTTYPE_OLD;
 
typedef struct
{
 UINT16 usItem;
 UINT8  ubNumberOfObjects;
 ...
  // attached objects
   // MAX_ATTACHMENTS*4 - это неправильный способ увеличить количество аттачей, зато наглядный :)
 UINT16 usAttachItem[MAX_ATTACHMENTS*4];
 INT8  bAttachStatus[MAX_ATTACHMENTS*4];
 
   // а тут я зарезервировал 256 байт прозапас
 union
 {
  UINT8 bChunk[256];
 };

 
 INT8  fFlags;
 UINT8  ubMission;
 INT8  bTrap;   // 1-10 exp_lvl to detect
 UINT8  ubImprintID; // ID of merc that item is imprinted on
 UINT8  ubWeight;
 UINT8  fUsed;    // flags for whether the item is used or not
} OBJECTTYPE;

 
OBJECTTYPE на картах используется как часть двух структур -  WORLDITEM и SOLDIERCREATE_STRUCT, значит нужно создать для этих структур прототипы старого размера и функции превращения (или переноса данных) из старого формата структуры в новый.
Открываем файл Tactical\World Items.h и копипастим объявление структуры WORLDITEM. В неё мы не планируем ничего добавлять, но так как членом этой структуры является OBJECTTYPE, нужно создать "старую версию" WORLDITEM для загрузки карт. Ещё нужно объявить функции переноса данных для OBJECTTYPE и WORLDITEM:

typedef struct
{
 ...
   OBJECTTYPE o;
 ...
} WORLDITEM;
 
typedef struct
{
 ...
 OBJECTTYPE_OLD  o;
 ...
} WORLDITEM_OLD;
 
void RenovateObjectype(OBJECTTYPE * pNew, OBJECTTYPE_OLD * pOld);
void RenovateWorldItem(WORLDITEM * pNew, WORLDITEM_OLD * pOld);


Открываем файл Tactical\World Items.c и добавляем в него реализацию функций:

void RenovateObjectype(OBJECTTYPE * pNew, OBJECTTYPE_OLD * pOld)
{
 pNew->usItem = pOld->usItem;
 pNew->ubNumberOfObjects = pOld->ubNumberOfObjects;
 memcpy( &(pNew->bStatus), &(pOld->bStatus), MAX_OBJECTS_PER_SLOT);
   // заполняем нулями массив
 memset( &(pNew->usAttachItem), 0, sizeof(pNew->usAttachItem));
   // копируем старый массив в начало большого нового
 memcpy( &(pNew->usAttachItem), &(pOld->usAttachItem), MAX_ATTACHMENTS*2 );
 memset( &(pNew->bAttachStatus), 0, sizeof(pNew->bAttachStatus));
 memcpy( &(pNew->bAttachStatus), &(pOld->bAttachStatus), MAX_ATTACHMENTS );
 pNew->fFlags = pOld->fFlags;
 pNew->ubMission = pOld->ubMission;
 pNew->bTrap = pOld->bTrap;
 pNew->ubImprintID = pOld->ubImprintID;
 pNew->ubWeight = pOld->ubWeight;
 pNew->fUsed = pOld->fUsed;
}
 
void RenovateWorldItem(WORLDITEM * pNew, WORLDITEM_OLD * pOld)
{
 pNew->fExists = pOld->fExists;
 pNew->sGridNo = pOld->sGridNo;
 pNew->ubLevel = pOld->ubLevel;
 RenovateObjectype( &(pNew->o), &(pOld->o) );
 pNew->usFlags = pOld->usFlags;
 pNew->bRenderZHeightAboveLevel = pOld->bRenderZHeightAboveLevel;
 pNew->bVisible = pOld->bVisible;
 pNew->ubNonExistChance = pOld->ubNonExistChance;
}

Открываем файл Tactical\Soldier Create.h и делаем с SOLDIERCREATE_STRUCT то же самое.

typedef struct
{
 ...
 //Inventory
 OBJECTTYPE_OLD  Inv[ NUM_INV_SLOTS ];  
 ...  
} SOLDIERCREATE_STRUCT_OLD;
 
typedef struct
{
 ...
 //Inventory
 OBJECTTYPE  Inv[ NUM_INV_SLOTS ];  
 ...  
} SOLDIERCREATE_STRUCT;
 
void RenovateSoldierCreateStruct(SOLDIERCREATE_STRUCT * pNew, SOLDIERCREATE_STRUCT_OLD * pOld);

 
Открываем файл Tactical\Soldier Create.c и добавляем в него реализацию RenovateSoldierCreateStruct

void RenovateSoldierCreateStruct(SOLDIERCREATE_STRUCT * pNew, SOLDIERCREATE_STRUCT_OLD * pOld)
{
 int i;
   // просто копирую часть структуры до инвентаря
 memcpy( pNew, pOld, (char*)&(pNew->Inv)-(char*)pNew );
   // конвертирую инвентарь по предметам один за одним
 for( i=0; i<NUM_INV_SLOTS; i++ )
  RenovateObjectype( pNew->Inv+i, pOld->Inv+i );
   // копирую оставшуюся после инвентаря часть структуры
 memcpy( &(pNew->HeadPal),&(pOld->HeadPal), sizeof(SOLDIERCREATE_STRUCT)-((char*)&(pNew->HeadPal)-(char*)pNew) );
}

Теперь сама загрузка. Загрузка карты происходит в TileEngine\worlddef.c в функции
BOOLEAN LoadWorld( UINT8 *puiFilename )
 
добавим к переменным (строка ~2630) флажок, означающий загрузку старой карты.
BOOLEAN fLegacyMap;
 
после загрузки записанного в файл размера структуры SOLDIERTYPE (строка ~2714) сравним его с используемым, и в случае несовпадения установим флажок загрузки старой карты.

// Load soldier size
LOADDATA( &uiSoldierSize, pBuffer, sizeof( INT32 ) );
 
fLegacyMap = uiSoldierSize!=sizeof(SOLDIERTYPE);

добавляем данный флажок как параметр к функциям загрузки предметов (строка ~3009)

LoadWorldItemsFromMap( &pBuffer, fLegacyMap );

и солдат (строка ~3062)

LoadSoldiersFromMap( &pBuffer, fLegacyMap );

 
Теперь модифицируем сами функции.
Tactical\Soldier Init List.h (строка ~25):
BOOLEAN LoadSoldiersFromMap( INT8 **hBuffer, BOOLEAN fLegacyMap );
Tactical\Soldier Init List.c (строка ~279):

BOOLEAN LoadSoldiersFromMap( INT8 **hBuffer, BOOLEAN fLegacyMap )
{
 ...
      if( tempBasicPlacement.fDetailedPlacement )
  { //Add the static detailed placement information in the same newly created node as the basic placement.
   //read static detailed placement from file
   
   if( fLegacyMap )
   {
       // загружаем старую структуру
    LOADDATA( &tempDetailedPlacementOld, *hBuffer, sizeof( SOLDIERCREATE_STRUCT_OLD ) );
       // переконвертируем её в новую
    RenovateSoldierCreateStruct(&tempDetailedPlacement, &tempDetailedPlacementOld);
   }
   else
   { // хотя на первый взгляд скобки здесь не нужны, LOADDATA - это макрос, развертывающийся в несколько комманд

    LOADDATA( &tempDetailedPlacement, *hBuffer, sizeof( SOLDIERCREATE_STRUCT ) );
   }
 
   //allocate memory for new static detailed placement
   pNode->pDetailedPlacement = (SOLDIERCREATE_STRUCT*)MemAlloc( sizeof( SOLDIERCREATE_STRUCT ) );
   if( !pNode->pDetailedPlacement )
   {
    AssertMsg( 0, "Failed to allocate memory for new detailed placement in LoadSoldiersFromMap." );
    return FALSE;
   }
 ...
 return TRUE;
}

Tactical\World Items.h (строка ~43):
void LoadWorldItemsFromMap( INT8 **hBuffer, BOOLEAN fLegacyMap );
Tactical\World Items.c (строка ~446):

void LoadWorldItemsFromMap( INT8 **hBuffer, BOOLEAN fLegacyMap )
{
 ...
 if( gTacticalStatus.uiFlags & LOADING_SAVED_GAME && !gfEditMode )
 { //The sector has already been visited.  The items are saved in a different format that will be  
  //loaded later on.  So, all we need to do is skip the data entirely.
 
  if( fLegacyMap )
   *hBuffer += sizeof( WORLDITEM_OLD ) * uiNumWorldItems;
  else
 

   *hBuffer += sizeof( WORLDITEM ) * uiNumWorldItems;
  return;
 }
 else for ( i = 0; i < uiNumWorldItems; i++ )
 { //Add all of the items to the world indirectly through AddItemToPool, but only if the chance
  //associated with them succeed.
 
  if( fLegacyMap )
  {
   LOADDATA( &dummyItemOld, *hBuffer, sizeof( WORLDITEM_OLD ) );
   RenovateWorldItem(&dummyItem, &dummyItemOld );
  }
  else
  {

   LOADDATA( &dummyItem, *hBuffer, sizeof( WORLDITEM ) );
  }
 ...
}

Вот и всё.
 
 
3. Что это было.
 
Исходников готовых не прилагаю, так как эта инструкция больше руководство к действию, чем готовое решение, т.к. сама по себе такая модификация не добавляет в игру новых возможностей. Для тех, кто не понимает как распорядиться полученным добром - в следующих статьях я (а может и кто другой) расскажу как расширить инвентарь наёмника или как сделать оружие с двумя калибрами и двумя магазинами. Хотя в структуру SOLDIERTYPE не добавлялись новые поля, это можно сделать на основе полученных данных.
« Изменён в : 20.09.2006 в 11:28:06 пользователем: bugmonster » Зарегистрирован

Восславим же радость и мужество,
Труда и науки содружество
Восславим мудрую партию,
Помолимся за неё.

А Пентагон в свои руки поганые,
Пусть возьмёт свои доллары сраные
И в ж... себе затолкает

Farah_Aydid
[Блэк Хок Даун]
Полный псих

Доктор Джекил и мистер Хайд - кем я буду сегодня?




Пол:
Репутация: +128
Re: [Уголок багодела] Расширение структур OBJECTTY
« Ответ #1 от 14.11.2009 в 08:39:02 »

(2009 год)
Наткнулся на эту тему в поисках информации об особых функциях предметов. Конкретно, меня интересуют эффекты наркотиков, алкоголя и прочих медикаментов.
В каких файлах хранится инфа для этих особых предметов? И насколько они функциональны для редактирования и создания новых предметов такого класса? Возможно ли, например, ввести зависимость от наркотиков? Возможно ли добавить абсолютно новые медикаменты с другими эффектами? Как и где вообще можно управлять настройкой этих эффектов?
 
Ковыряюсь в обычных ХМЛ-файлах для мода 113, но простыми средствами редактора новых предметов с необходимыми эффектами создать не получается. Видимо, инфа о наркоте хранится в каком-то особом файле, потому что даже обычным дупликатом старого предмета эффекты не переносятся на новый. Наверное, должен совпадать индекс предмета, с индексом, указанным в том самом загадочном файле, который я ищу.))
 
ОООо! Эта инфа наверное в JSD хранится. И как же ее ковырять. О, ужас!  :-/
« Изменён в : 14.11.2009 в 08:46:53 пользователем: Farah_Aydid » Зарегистрирован

Всех джайцев сослать в страну Африканского Рога!!! =)
http://www.ja2.su/mods/Ja2v113/Farah_Aydid/JA2_113_HoA_in_progress.rar
Устарело. Обнова скоро будет.

http://kunt.mybrute.com
Воруй@Убивай

<<GEM>>
[Добрый волшебник]
Прирожденный Джаец

Иногда мне дико не хватает мозгов.


WWW Ё-мэйл

Пол:
Репутация: +675
Re: [Уголок багодела] Расширение структур OBJECTTY
« Ответ #2 от 14.11.2009 в 18:06:11 »

14.11.2009 в 08:39:02, Farah_Aydid писал(a):
Эта инфа наверное в JSD хранится.
- не думаю. Инфа эта строго в исходниках записана. В оригинальном Джа так.
Зарегистрирован

Модельки от меня.
bugmonster
[Баги! Баги везде!]
Source

ПРОГРАММИРЫ НЕ УЧИТЫВАЛИ ЭТУ СИТУАЦИЮ




Пол:
Репутация: +1337
Re: [Уголок багодела] Расширение структур OBJECTTY
« Ответ #3 от 15.11.2009 в 06:47:26 »

2Farah_Aydid: JSDшки это совсем из другой оперы, в Джа2 (в том числе и 1.13) свойства алкоголя и наркотиков жестко закодированы на номер предмета.
А вообще это оффтоп, ты ошибся темой.
Зарегистрирован

Восславим же радость и мужество,
Труда и науки содружество
Восславим мудрую партию,
Помолимся за неё.

А Пентагон в свои руки поганые,
Пусть возьмёт свои доллары сраные
И в ж... себе затолкает

Lion
[Lion. King Lion.]


Welcome to Metavira!




Пол:
Репутация: +362
Re: [Уголок багодела] Расширение структур OBJECTTY
« Ответ #4 от 25.03.2013 в 04:02:47 »

2bugmonster: В статье подробно описана возня с переделыванием карт из старого формата в новый с клонированием структур и прочими радостями жизни.
 
Меня больше интересует вопрос (можно, конечно, и в исходниках глянуть, но думаю, Вы знаете ответ), всегда ли в файле с картой хранятся эти структуры? Можно ли вольно править OBJECTTYPE и SOLDIERTYPE, а карты просто переносить, если на них нет ни одного персонажа и ни одного предмета?
 
Опять же можно ли приводить карты к новым структурам методом:
1) Удалить с карты в старом формате всех людей и все предметы.
2) Открыть карту как карту в новом формате, вернуть людей и предметы?
Зарегистрирован

bugmonster
[Баги! Баги везде!]
Source

ПРОГРАММИРЫ НЕ УЧИТЫВАЛИ ЭТУ СИТУАЦИЮ




Пол:
Репутация: +1337
Re: [Уголок багодела] Расширение структур OBJECTTY
« Ответ #5 от 26.03.2013 в 01:22:27 »

2Lion:   Quote:
Можно ли вольно править OBJECTTYPE и SOLDIERTYPE, а карты просто переносить, если на них нет ни одного персонажа и ни одного предмета?  

Да, ЕМНИП.
 
Quote:
Опять же можно ли приводить карты к новым структурам методом:  
1) Удалить с карты в старом формате всех людей и все предметы.  
2) Открыть карту как карту в новом формате, вернуть людей и предметы?

 
Исходя из вышесказанного - можно. Но лучше дописать конвертацию в исходниках.
Зарегистрирован

Восславим же радость и мужество,
Труда и науки содружество
Восславим мудрую партию,
Помолимся за неё.

А Пентагон в свои руки поганые,
Пусть возьмёт свои доллары сраные
И в ж... себе затолкает

Lion
[Lion. King Lion.]


Welcome to Metavira!




Пол:
Репутация: +362
Re: [Уголок багодела] Расширение структур OBJECTTY
« Ответ #6 от 26.03.2013 в 01:46:39 »

26.03.2013 в 01:22:27, bugmonster писал(a):
Но лучше дописать конвертацию в исходниках.  
В каком отношении лучше?
При учёте того, что на картах, о которых идёт речь, предметов и людей просто нет. Т.е. удалять никого не надо.
 
Хотя можно и конвертацию написать.  : rolleyes :
Зарегистрирован

bugmonster
[Баги! Баги везде!]
Source

ПРОГРАММИРЫ НЕ УЧИТЫВАЛИ ЭТУ СИТУАЦИЮ




Пол:
Репутация: +1337
Re: [Уголок багодела] Расширение структур OBJECTTY
« Ответ #7 от 26.03.2013 в 02:11:14 »

26.03.2013 в 01:46:39, Lion писал(a):
В каком отношении лучше?  
При учёте того, что на картах, о которых идёт речь, предметов и людей просто нет. Т.е. удалять никого не надо.  

Лучше в общем случае.
Карты без предметов и людей это очень специфический случай.
Зарегистрирован

Восславим же радость и мужество,
Труда и науки содружество
Восславим мудрую партию,
Помолимся за неё.

А Пентагон в свои руки поганые,
Пусть возьмёт свои доллары сраные
И в ж... себе затолкает

Lion
[Lion. King Lion.]


Welcome to Metavira!




Пол:
Репутация: +362
Re: [Уголок багодела] Расширение структур OBJECTTY
« Ответ #8 от 26.03.2013 в 02:46:36 »

26.03.2013 в 02:11:14, bugmonster писал(a):
Карты без предметов и людей это очень специфический случай.  
Не согласен. Для определённого этапа создания проекта - вполне нормально. Какие карты - известно, а что конкретно на них будет - известно плохо, рисуется ландшафт, а положить предметы и людей - дело быстрое и нехитрое, к тому же лучше это делать на всех картах сразу.
 
Спасибо.
« Изменён в : 26.03.2013 в 02:46:50 пользователем: Lion » Зарегистрирован

MAn
[Человечище!!!]







Пол:
Репутация: +403
Re: [Уголок багодела] Расширение структур OBJECTTY
« Ответ #9 от 26.03.2013 в 02:54:37 »

Offtop:
Зарегистрирован

Страниц: 1  Послать Тему Послать Тему Печатать Печатать

« Предыдущая Тема | Следующая Тема »

Статистика. Размер данных: 50688 GZip: off
A.I.M. » Powered by YaBB Modification 4 (v.4.0.0-pre)!
YaBB © 2000-2003. All Rights Reserved.