Где и как считать информацию о карте?
Без варкрафта и без редактора карт.
Где хранится эта информация? Нужно ли распаковывать карту для считывания?
Название
Автор
Описание
Дополнение
Ландшафт
Размеры
Playable Area
Количество игроков
Картинка миникарты

Принятый ответ

vasya1, проблема знака '-' в том что не получится в пути написать пробелы, поэтому лучше путь пихать в кавычки "")
только нафиг '-' писать) Да и вообще никто так не делает вроде)

вроде решил проблему
Загруженные файлы
`
ОЖИДАНИЕ РЕКЛАМЫ...

Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
1
18
5 лет назад
1
это с гитхаба украл:
HANDLE SubFile;

if( SFileOpenFileEx( MapMPQ, "war3map.w3i", 0, &SubFile ) )
{
	uint32_t FileLength = SFileGetFileSize( SubFile, NULL );

	if( FileLength > 0 && FileLength != 0xFFFFFFFF )
	{
		char *SubFileData = new char[FileLength];
		DWORD BytesRead = 0;

		if( SFileReadFile( SubFile, SubFileData, FileLength, &BytesRead, NULL ) )
		{
			istringstream ISS( string( SubFileData, BytesRead ) );

			// war3map.w3i format found at http://www.wc3campaigns.net/tools/specs/index.html by Zepir/PitzerMike

			string GarbageString;
			uint32_t FileFormat;
			uint32_t RawMapWidth;
			uint32_t RawMapHeight;
			uint32_t RawMapFlags;
			uint32_t RawMapNumPlayers;
			uint32_t RawMapNumTeams;

			ISS.read( (char *)&FileFormat, 4 );				// file format (18 = ROC, 25 = TFT)

			if( FileFormat == 18 || FileFormat == 25 )
			{
				ISS.seekg( 4, ios :: cur );					// number of saves
				ISS.read( (char *)&EditorVersion, 4 );		// editor version
				getline( ISS, GarbageString, '\0' );		// map name
				getline( ISS, GarbageString, '\0' );		// map author
				getline( ISS, GarbageString, '\0' );		// map description
				getline( ISS, GarbageString, '\0' );		// players recommended
				ISS.seekg( 32, ios :: cur );				// camera bounds
				ISS.seekg( 16, ios :: cur );				// camera bounds complements
				ISS.read( (char *)&RawMapWidth, 4 );		// map width
				ISS.read( (char *)&RawMapHeight, 4 );		// map height
				ISS.read( (char *)&RawMapFlags, 4 );		// flags
				ISS.seekg( 1, ios :: cur );					// map main ground type

				if( FileFormat == 18 )
					ISS.seekg( 4, ios :: cur );				// campaign background number
				else if( FileFormat == 25 )
				{
					ISS.seekg( 4, ios :: cur );				// loading screen background number
					getline( ISS, GarbageString, '\0' );	// path of custom loading screen model
				}

				getline( ISS, GarbageString, '\0' );		// map loading screen text
				getline( ISS, GarbageString, '\0' );		// map loading screen title
				getline( ISS, GarbageString, '\0' );		// map loading screen subtitle

				if( FileFormat == 18 )
					ISS.seekg( 4, ios :: cur );				// map loading screen number
				else if( FileFormat == 25 )
				{
					ISS.seekg( 4, ios :: cur );				// used game data set
					getline( ISS, GarbageString, '\0' );	// prologue screen path
				}

				getline( ISS, GarbageString, '\0' );		// prologue screen text
				getline( ISS, GarbageString, '\0' );		// prologue screen title
				getline( ISS, GarbageString, '\0' );		// prologue screen subtitle

				if( FileFormat == 25 )
				{
					ISS.seekg( 4, ios :: cur );				// uses terrain fog
					ISS.seekg( 4, ios :: cur );				// fog start z height
					ISS.seekg( 4, ios :: cur );				// fog end z height
					ISS.seekg( 4, ios :: cur );				// fog density
					ISS.seekg( 1, ios :: cur );				// fog red value
					ISS.seekg( 1, ios :: cur );				// fog green value
					ISS.seekg( 1, ios :: cur );				// fog blue value
					ISS.seekg( 1, ios :: cur );				// fog alpha value
					ISS.seekg( 4, ios :: cur );				// global weather id
					getline( ISS, GarbageString, '\0' );	// custom sound environment
					ISS.seekg( 1, ios :: cur );				// tileset id of the used custom light environment
					ISS.seekg( 1, ios :: cur );				// custom water tinting red value
					ISS.seekg( 1, ios :: cur );				// custom water tinting green value
					ISS.seekg( 1, ios :: cur );				// custom water tinting blue value
					ISS.seekg( 1, ios :: cur );				// custom water tinting alpha value
				}

				ISS.read( (char *)&RawMapNumPlayers, 4 );	// number of players
				uint32_t ClosedSlots = 0;

				for( uint32_t i = 0; i < RawMapNumPlayers; ++i )
				{
					CGameSlot Slot( 0, 255, SLOTSTATUS_OPEN, 0, 0, 1, SLOTRACE_RANDOM );
					uint32_t Colour;
					uint32_t Status;
					uint32_t Race;

					ISS.read( (char *)&Colour, 4 );			// colour
					Slot.SetColour( Colour );
					ISS.read( (char *)&Status, 4 );			// status

					if( Status == 1 )
						Slot.SetSlotStatus( SLOTSTATUS_OPEN );
					else if( Status == 2 )
					{
						Slot.SetSlotStatus( SLOTSTATUS_OCCUPIED );
						Slot.SetComputer( 1 );
						Slot.SetComputerType( SLOTCOMP_NORMAL );
					}
					else
					{
						Slot.SetSlotStatus( SLOTSTATUS_CLOSED );
						++ClosedSlots;
					}

					ISS.read( (char *)&Race, 4 );			// race

					if( Race == 1 )
						Slot.SetRace( SLOTRACE_HUMAN );
					else if( Race == 2 )
						Slot.SetRace( SLOTRACE_ORC );
					else if( Race == 3 )
						Slot.SetRace( SLOTRACE_UNDEAD );
					else if( Race == 4 )
						Slot.SetRace( SLOTRACE_NIGHTELF );
					else
						Slot.SetRace( SLOTRACE_RANDOM );

					ISS.seekg( 4, ios :: cur );				// fixed start position
					getline( ISS, GarbageString, '\0' );	// player name
					ISS.seekg( 4, ios :: cur );				// start position x
					ISS.seekg( 4, ios :: cur );				// start position y
					ISS.seekg( 4, ios :: cur );				// ally low priorities
					ISS.seekg( 4, ios :: cur );				// ally high priorities

					if( Slot.GetSlotStatus( ) != SLOTSTATUS_CLOSED )
						Slots.push_back( Slot );
				}

				ISS.read( (char *)&RawMapNumTeams, 4 );		// number of teams

				for( uint32_t i = 0; i < RawMapNumTeams; ++i )
				{
					uint32_t Flags;
					uint32_t PlayerMask;

					ISS.read( (char *)&Flags, 4 );			// flags
					ISS.read( (char *)&PlayerMask, 4 );		// player mask

					for( unsigned char j = 0; j < MAX_SLOTS; ++j )
					{
						if( PlayerMask & 1 )
						{
							for( vector<CGameSlot> :: iterator k = Slots.begin( ); k != Slots.end( ); ++k )
							{
								if( (*k).GetColour( ) == j )
									(*k).SetTeam( i );
							}
						}

						PlayerMask >>= 1;
					}

					getline( ISS, GarbageString, '\0' );	// team name
				}

				// the bot only cares about the following options: melee, fixed player settings, custom forces
				// let's not confuse the user by displaying erroneous map options so zero them out now

				MapOptions = RawMapFlags & ( MAPOPT_MELEE | MAPOPT_FIXEDPLAYERSETTINGS | MAPOPT_CUSTOMFORCES );
				CONSOLE_Print( "[MAP] calculated map_options = " + UTIL_ToString( MapOptions ) );
				MapWidth = UTIL_CreateByteArray( (uint16_t)RawMapWidth, false );
				CONSOLE_Print( "[MAP] calculated map_width = " + UTIL_ByteArrayToDecString( MapWidth ) );
				MapHeight = UTIL_CreateByteArray( (uint16_t)RawMapHeight, false );
				CONSOLE_Print( "[MAP] calculated map_height = " + UTIL_ByteArrayToDecString( MapHeight ) );
				MapNumPlayers = RawMapNumPlayers - ClosedSlots;
				CONSOLE_Print( "[MAP] calculated map_numplayers = " + UTIL_ToString( MapNumPlayers ) );
				MapNumTeams = RawMapNumTeams;
				CONSOLE_Print( "[MAP] calculated map_numteams = " + UTIL_ToString( MapNumTeams ) );

				uint32_t SlotNum = 1;

				for( vector<CGameSlot> :: iterator i = Slots.begin( ); i != Slots.end( ); ++i )
				{
					CONSOLE_Print( "[MAP] calculated map_slot" + UTIL_ToString( SlotNum ) + " = " + UTIL_ByteArrayToDecString( (*i).GetByteArray( ) ) );
					++SlotNum;
				}

				if( MapOptions & MAPOPT_MELEE )
				{
					CONSOLE_Print( "[MAP] found melee map, initializing slots" );

					// give each slot a different team and set the race to random

					unsigned char Team = 0;

					for( vector<CGameSlot> :: iterator i = Slots.begin( ); i != Slots.end( ); ++i )
					{
						(*i).SetTeam( Team++ );
						(*i).SetRace( SLOTRACE_RANDOM );
					}

					MapFilterType = MAPFILTER_TYPE_MELEE;
				}

				if( !( MapOptions & MAPOPT_FIXEDPLAYERSETTINGS ) )
				{
					// make races selectable

					for( vector<CGameSlot> :: iterator i = Slots.begin( ); i != Slots.end( ); ++i )
						(*i).SetRace( (*i).GetRace( ) | SLOTRACE_SELECTABLE );
				}
			}
		}
		else
			CONSOLE_Print( "[MAP] unable to calculate map_options, map_width, map_height, map_slot<x>, map_numplayers, map_numteams - unable to extract war3map.w3i from MPQ file" );

		delete [] SubFileData;
	}

	SFileCloseFile( SubFile );
}
и ещё есть тоже самое, но я переделывал под 1.31 (надо поискать у себя)
0
27
5 лет назад
Отредактирован MpW
0
файл хороший, его зарелизили в отдельную статью тут? релизьте уже
я не могу точно обещать. к тому смущает меня кол-во дыр в информации (у меня) и неточностей, и перевод не полный. как это может потянуть на статью. у меня нет никаких навыков программирования =), могу даже что то не так перевести или понять. хотя это желание разобраться и перевести возникает не всегда, от альтруизма и пр. но с картинками и прочее понятнее
0
5
5 лет назад
0
Hodor:
это с гитхаба украл:
это на крестах? exe скомпилировать сможешь? чтобы запускать типа "Hodor.exe map.w3x" с экспортом в txt, а то он там в CONSOLE_Print печатает. это чтобы этим скриптом попользоваться, надо устанавливать C
1
18
5 лет назад
1
vasya1,
нуууу, это не совсем скрипт, это считай кусок кода из хостбота
Экспорт в .txt можно сделать, но не раньше чем завтра (мб к вечеру освобожусь)
0
5
5 лет назад
Отредактирован vasya1
0
Steal nerves:
я не могу точно обещать. к тому смущает меня кол-во дыр в информации (у меня) и неточностей, и перевод не полный. как это может потянуть на статью.
чувак,
wowa это ты?
я прогуглил, этот текст не гуглится. дата создания обнулилась при скачивании файла.
когда ты писал этот перевод? сколько лет он у тебя в загашнике лежит? пусть будет в любом виде в интернете. русский текст и картинки есть + цветовые маркеры. допиливать или нет, это вопрос десятый. хотя бы то, что уже есть - не выложено в паблик. это законно?
как тут статьи писать? только с одобрения модераторов? да ты хотя бы в блог на xgm выложи, пусть гугл кеширует, хватит солить инфу
Hodor:
Экспорт в .txt можно сделать
тогда буду ждать и держать руку на пульсе
0
27
5 лет назад
0
vasya1,
wowa это ты?
wowa - это не мое настоящее имя. =)
я прогуглил, этот текст не гуглится. дата создания обнулилась при скачивании файла.
когда ты писал этот перевод? сколько лет он у тебя в загашнике лежит? пусть будет в любом виде в интернете. русский текст и картинки есть + цветовые маркеры. допиливать или нет, это вопрос десятый. хотя бы то, что уже есть - не выложено в паблик. это законно?
я начал переводить и писать недавно. 2-3 месяца назад.
я текст писал в Word 2010, поэтому мб гугл и не берет
1
18
5 лет назад
1
Steal nerves, да ладно фиг с этой статьей, в ней есть неточности
в основном это перепутаны флаги
пруф
в .w3i лежит инфа о кланах, в том числе их флаги
чтобы проще понять - эти флаги идут как набор единиц и нулей (да/нет), читаются справа налево и у кланов их пять
От "Союзник" до "Общие войска: все"
Так вот
Я собрал карту, взял флаг и там написано 11000, т.е если исходить из той статьи
раскрыть
0x00000001: allied (force 1)
0x00000002: allied victory
0x00000004: share vision
0x00000010: share unit control
0x00000020: share advanced unit control
у меня должны стоять галки на "Общие войска" и "Общие войска: все"
но проблема вот в чем:
я конечно сразу посчитал это тем что я не выспался, поэтому вручную каждый флаг перепроверял и всё равно не совпадает со статьей
Вот правильный список составил:
0x00000001 Allied
0x00000002 Share victory
0x00000004 Share advanced unit control
0x00000008 Share vision
0x00000010 Share unit control

В общем собрал парсер, инструкция в архиве
Точность не гарантирую, но вроде все пункты правильно парсятся)
P.S. Технологии/Способности/Улучшения/Случайные предметы/Таблицы предметов не стал делать, т.к это геморройно и долго очень
Загруженные файлы
0
5
5 лет назад
Отредактирован vasya1
0
Технологии/Способности/Улучшения/Случайные предметы/Таблицы предметов не стал делать
так это и не нужно, перегружать только лишней инфой
В общем собрал парсер, инструкция в архиве
потестил, хороший получился, а можно его в консольный превратить?:
  1. самая жесть это ручной ввод количества игроков 12-24, учитывая что он парсит это значение сам. ты же можешь это спарсенное значение использовать, без надобности мучить пользователя. во-первых пользователь не знает 12 там или 24, а во-вторых весь смысл парсера зарубается на корню, потому что нельзя в пакетном режиме им пользоваться. значение лежит примерно на 80-90 строке в отчёте - "Number of players = "
  2. можно ли добавить всё-таки обращение к файлу не через фиксированный input.mpq, а через параметр?
    pw3i.exe -filepath или pw3i.exe /filepath
  3. ну и сюда же если ему прямо количество надо обязательно вводить от пользователя, то добавить параметр /12 или /24 и всё. и не надо вручную вбивать, но всё же брать это значение из самого парса - лучше
тогда будет вообще зачётный
1
26
5 лет назад
1
Такую штуку хочешь запилить?
3
18
5 лет назад
Отредактирован Hodor
3
vasya1, number of players это кол-во игроков заданное редактором
к примеру ты сделал в игре 5 игроков, остальные 7 выключены и num of players будет стоять на пяти.
Да, я накосячил, указывать игроков и так и так не нужно.
Мне во время парса игроков надо запомнить какие в игре, а какие нет (долго объяснять почему, просто лишние 12 игроков прилипали к первому клану при 24 игроках)

8gabriel8:
Такую штуку хочешь запилить?
я подумаю)

vasya1,

и ещё кое что хотел сказать:
.w3i может ссылаться на строки из war3map.wts
у меня есть парсер который составляет таблицу строк из .wts
но одно большое но
раскрыть
.wts должен быть строго по шаблону:
STRING 123
{
text
}
просто иногда есть люди которые ради незначительной экономии размера или красоты сокращают .wts до такого шаблона:
STRING 123
{text}
и ещё есть туча способов и варкрафт их прочитает
WorldEditor собирает .wts по первому шаблону
а точить парсер .wts под все случаи и ошибки в .wts - такое себе
поэтому я в output.txt добавил отображение номера TRIGSTR (если он конечно используется, т.к в .w3i можно писать строки не ссылась в .wts)
Загруженные файлы
0
5
5 лет назад
Отредактирован vasya1
0
8gabriel8:
Такую штуку хочешь запилить?
классный аддон, но глючный и не работает. (отписал в той теме со скрином ошибки)
есть ещё рабочий аналог такого аддона?
pw3i_1.01.zip
никак не заводится, сделай поддержку mpq w3x w3m
ещё можно выдрать минимальные данные из w3n (банально название кампании и автора), war3campaign.w3f - первые четыре TRIGSTR
.w3i может ссылаться на строки из war3map.wts
даже скорее ссылается в 99% случаях. надо постараться, чтобы найти w3i без TRIGSTR
поэтому я в output.txt добавил отображение номера TRIGSTR
да, я тоже подметил сразу, что это супер удобно сделано у тебя - вставка в отчёте помимо значения TRIGSTR ещё и имя переменной
vasya1:
ещё можно выдрать минимальные данные из w3n
war3campaign.w3f
по порядку TRIGSTR - название, сложность, автор, описание
количество глав - начало пятого TRIGSTR минус 8 ячеек смещение влево
итого 5 значений в свойствах кампании
Загруженные файлы
Показан только небольшой набор комментариев вокруг указанного. Перейти к актуальным.
Чтобы оставить комментарий, пожалуйста, войдите на сайт.