После танца с бубном вокруг компьютера и установки самой распоследней версии 7-Zip (http://7-zip.en.softonic.com/download) открыть архив с третьего раза (!!!) удалось!
Почему такая фигня приключилось - не знаю. Вчерашний твой архив раскрылся старым архиватором без проблем и с первого раза. Впрочем, неважно. Бубен я повесил пока на стенку рядом с компом.![]()
Помогло! Кнопку "AvoidGrowth" удалось убрать. Но в данном случае я этим трюком пока не пользовался, и в дальнейшем использовал твой CvMainInterface.py файл без всяких изменений.
Скомпилировал со второй попытки. Первая не удалась, поскольку в файле CvGlobals.cpp было дважды прописано одно и то же.
а должно быть, как я понимаю, так:Код://VET BirthPoints - begin 3/4 int CvGlobals::getBASE_BIRTH_POINTS_THRESHOLD() {return m_iBASE_BIRTH_POINTS_THRESHOLD;} int CvGlobals::getBASE_BIRTH_POINTS_THRESHOLD() {return m_iBASE_BIRTH_POINTS_THRESHOLD;} //VET BirthPoints - end 3/4
После этого скомпилировать удалось без проблем, но при входе в город выскакивает этот экран и .....Код://VET BirthPoints - begin 3/4 int CvGlobals::getBASE_BIRTH_POINTS_THRESHOLD() {return m_iBASE_BIRTH_POINTS_THRESHOLD;} int CvGlobals::getTURNS_FOR_FOOD() {return m_iTURNS_FOR_FOOD;} //VET BirthPoints - end 3/4
![]()
Пишет что в питон не выведена функция getTotalYieldStored
Я эту функцию в питон выводил, так что надо перекомпилировать заново DLL используя все файлы SDK, которые идут с моим модом. (эта функция выводится в питон через файлы CyCity.h, CyCity.cpp, CyCityInterface1.cpp)
Если новые технологии позволяют обходится без услуг простых людей - это прогресс, а если новые технологии позволяют обходится без услуг миллионеров и крупных компаний - это нарушение авторских прав.
Мой мод
Сейчас повторю компиляцию, но прошлый раз я в директорию с исходные кодами перенес все твои 12 файлов.
Минуточку....
Опаньки, получилось! Большое спасибо!
Не иначе как исправляя опечатку в CvGlobals.cpp я забыл забыл выполнить команду "Clean GameCore.dll", а тупо продолжил компиляцию.
Очень разумно. Это получается нечто НЗ - неприкосновенного запаса. Поскольку этот параметр задается в GlobalDefinesAlt.xml то его, равно как и BASE_BIRTH_POINTS_THRESHOLD, надо будет подбирать экспериментально.
Тоже верно. В приведенном выше случае жители не голодали. Это я снова лопухнулся. Они просто съедали все производимое за ход.
А при настоящем голоде, когда еды нет вообще, а потребление еды за ход больше, чем ее производство, происходит выброс жителя на глобальную карту. Я попробовал такой вариант и kirgre был абсолютно прав, когда писал
Вообще, насколько я помню, в оригинальной кол2 жители не умирают, а уезжают из города на глобальную карту.
Я почему-то был твердо уверен, что они вымирают. Да, наверное надо хоть иногда запускать игру для игры, а не для моддинга.![]()
В самой последней версии, скомпилированной вчера, нашел довольно странное поведение при переполнении городского склада.
Начальная логика при переполненном складе случае была понятна:
Поэтому когда еда стала обычным ресурсом, то именно она и терялась.Если склад переполнен, то теряются наиболее дешевые товары.
Затем был введен TURNS_FOR_FOOD или количество ходов, на которое будет накапливатся еда в городе (учитывая ее потребление всеми жителями города) вне зависмости от заполнености склада другими ресурсами при включеном NEW_CAPACITY.
Тоже все совершенно логично. Таким образом создавался некий городской "неприкосновенный запас" еды.
Однако в реальности почему-то получается по другому. Вот пример:
Город 4 человека. Запас еды 62. Это значение, равно как и население, по ходу игры не меняются.
TURNS_FOR_FOOD = 12.
Таким образом можно вычислить "неприкосновенный запас" еды для города. Он равен
Это значение больше, чем то количество еды, что есть в городе (62).Код:2 еды х 4 человека х 12 ходов = 96 еды
Из этого следует, что еда не будет исчезать при переполнении склада. Прекрасно!
Теперь смотрим что есть на складе. На городском складе есть древесина (самый дешевый товар, цена продажи 1 монета), шкуры, табак (продается за 3 монеты) и сигары (самый дорогой товар, 6 монет за штуку).
При переполнении склада по логике должны были исчезать доски (древесина), как самый дешевый товар. Не еда, поскольку ее запас меньше критического (62<96), а именно древесина.
Реально же исчезают только (!!!) сигары или табак. Странно?
Я провел дополнительный тест, подселяя в город по очереди пионера (на складе появилось +150 инструментов), затем ветерана (+150 оружия) и наконец скаута (+150 лошадей).
После каждого такого подселения на следующий ход из склада исчезали по очереди 150 инструментов, 150 ружей, 150 лошадей. При этом количество древесины, как самого дешевого товара, оставалось неизменным.
Другими словами всегда исчезает не самый дешевый, а самый крайний справа товар. Почему не работает старая логика, когда исчезать должен самый дешевый товар, совершенно непонятно?
Вечером попробую разобратся.
Если новые технологии позволяют обходится без услуг простых людей - это прогресс, а если новые технологии позволяют обходится без услуг миллионеров и крупных компаний - это нарушение авторских прав.
Мой мод
В файле CvCity.cpp найди строчку номер 6095:
if ((iYieldStored != 0) && (!bBIRTH_POINTS || ((iYield != YIELD_FOOD) || (iYieldStored > iMinFood))))
и измени ее так чтоб получилось
((iYieldStored != 0) && (aiPrices[iYield] < iMinPrice) && (!bBIRTH_POINTS || ((iYield != YIELD_FOOD) || (iYieldStored > iMinFood))))
Случайно удалил нужное условие (которое и находило минимальную цену) при редактировании![]()
Если новые технологии позволяют обходится без услуг простых людей - это прогресс, а если новые технологии позволяют обходится без услуг миллионеров и крупных компаний - это нарушение авторских прав.
Мой мод
Проверь на нормальное удаление еды. Сделай чтоб еды было болше необходимого минимума, а потом переполняй склад.
Если новые технологии позволяют обходится без услуг простых людей - это прогресс, а если новые технологии позволяют обходится без услуг миллионеров и крупных компаний - это нарушение авторских прав.
Мой мод
Привет, NeseryozniyVET!
Все эксперименты я проводил с учетом твоей последней корректировки:
Вот результаты тестов.
При переполнении склада (в том числе и едой сверх "неприкосновенного запаса") первой исчезает избыточная еда. Когда запас еды оказывается равным неприкосновенному запасу, то еда больше не удаляется.
Для города с населением 2 человека мы имеем
Это для нормальной скорости. Если игра идет на марафоне, то 48 надо умножить на коэффициент 3, будет 144. Именно это я и наблюдаю.2 еды х 2 человека х 12 ходов = 48 еды
Таким образом, данная часть мода работает совершенно правильно.
Однако затем возникает ошибка. Если до твоей последней корректировки с переполненного склада удалялся не самый дешевый, а самый крайний справа товар, то сейчас удаление идет в обратном порядке начиная с древесины и далее слева направо.
Для того, чтобы наверняка поймать эту ошибку я специально подредактировал CIV4YieldInfos.xml, задав новые цены при продаже:
По логике должно бытьдревесина (2 монеты), хлопок (5), шкуры (6), сахар (7), табак (4), руда (3)
После того, как запас еды стал равен неприкосновенному запасу, первой с переполненного склада исчезает древесина, что правильно, ибо она самый дешевый товар (2 монеты). Следующим кандидатом на удаление должна быть руда (3 монеты), поскольку после того, как вся древесина исчезла, именно она оказывается самым дешевым товаром. Однако вместо нее первым со склада исчезает хлопок (5 монет).Если склад переполнен, то теряются наиболее дешевые товары.
Если хлопка нет, то первыми исчезают шкуры (6 монет), затем более дешевый табак (4 монеты). До удаления железной руды, как самого дешевого товара дело не доходит.
Таким образом, в данном варианте программа не может найти самый дешевый товар, а удаляет самый первый из списка после еды:
CvEnums.h:
Код:YIELD_FOOD, YIELD_LUMBER, YIELD_SILVER, YIELD_COTTON, YIELD_FUR, YIELD_SUGAR, YIELD_TOBACCO, YIELD_ORE, YIELD_CLOTH, YIELD_COATS, YIELD_RUM, YIELD_CIGARS, YIELD_TOOLS, YIELD_MUSKETS, YIELD_HORSES, YIELD_TRADE_GOODS,
Просмотрел алгоритм, вроде, все правильно.
Может дело в том, что используется не цена в CIV4YieldInfos.xml, а цена в Европе, причем, если в товар в Европе продавать нельзя, то цена считается 0.
Если новые технологии позволяют обходится без услуг простых людей - это прогресс, а если новые технологии позволяют обходится без услуг миллионеров и крупных компаний - это нарушение авторских прав.
Мой мод
Странно....
Да нет, не похоже. Я тестирование проводил на примере города, который стоил через WorldBuilder, размещая нужное количество поселенцев на какой-то определенной клетке. Корабль с поселенцами я останавливал на первом ходу и он оставался в начальной точке все время. Это означает, что с Европой я не торговал вообще, а следовательно король не мог вводить мне налоги, а я от этого предложения соответственно отказываться. Другими словами, ни один из моих товаров не подпадал под запрет на продажу в Европе.
Относительно цены я не совсем понял твою мысль. Все цены на торговлю с Европой и туземцами прописаны в CIV4YieldInfos.xml. В этом файле есть целый букет тегов, связанных с ценами. Для хлопка к примеру это выглядит так:
Европейская цена находится в пределах от 3 до 5 монет.Код:<iBuyPriceLow>3</iBuyPriceLow> <iBuyPriceHigh>5</iBuyPriceHigh> <iSellPriceDifference>2</iSellPriceDifference> <iPriceChangeThreshold>800</iPriceChangeThreshold> <iPriceCorrectionPercent>2</iPriceCorrectionPercent> <iNativeBuyPrice>-1</iNativeBuyPrice> <iNativeSellPrice>5</iNativeSellPrice>
Именно одно из этих значений - 3, 4 или 5 - мы видим, когда наводим курсор на значок хлопка на экране города. Естественно можно пойти на экран Европы, но и там мы увидем ту же самую цену. Поэтому европейские цены, действующие в данный момент, проще смотреть прямо на городском экране.Код:<iBuyPriceLow>3</iBuyPriceLow> <iBuyPriceHigh>5</iBuyPriceHigh>
Однако эти цены, во-первых, колеблются в неких пределах (<iSellPriceDifference>), во-вторых, в оригинальной версии игры они очень близки или даже равны друг к другу.
Поэтому для прояснения ситуации я при тестировании твоего мода подредактировал CIV4YieldInfos.xml, задав новые цены при продаже:
При этом оба значения <iBuyPriceLow> и <iBuyPriceHigh> были одними и теми же для данного товара. Это позволило мне избавиться от колебания европейских цен. Причем, обрати внимание на порядок цен. После дешевой древесины (2 монеты) я специально поставил более дорогие хлопок (5), шкуры (6), сахар (7), а лишь потом более дешевые табак (4) и руду (3). Однако при переполнении городского склада почему-то сперва исчезали более дорогие хлопок (5), шкуры (6), сахар (7), а лишь потом более дешевые табак (4) и руда (3). Причем, что самое важное - удаление излишков шло совершенно четко слева направо.древесина (2 монеты), хлопок (5), шкуры (6), сахар (7), табак (4), руда (3)
Возможно именно этот ньюанс позволит понять логику принятия решения какой товар удалять.
Будем искать ошибку так
Добавь новые строчки (отмечени красным) в алгоритм поиска самого дешевого ресурса
доведи склад до переполнения и смотри на сообщенияКод:if (GC.getYieldInfo((YieldTypes)iYield).isCargo()) { iYieldStored = getYieldStored((YieldTypes)iYield); CvWString szBuffer = CvWString::format(L"/t%c, Stored%d, Price%d", GC.getYieldInfo((YieldTypes)iYield).getChar(), iYieldStored, aiPrices[iYield]); gDLL->getInterfaceIFace()->addMessage(getOwnerINLINE(), false, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_DEAL_CANCELLED", MESSAGE_TYPE_MINOR_EVENT, GC.getYieldInfo((YieldTypes)iLossYield).getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_BLUE"), getX_INLINE(), getY_INLINE(), true, true); //VET BirthPoints - begin 11/16 /*if ((iYieldStored > 0) && (aiPrices[iYield] < iMinPrice)) { iLossYieldStored = iYieldStored;*/ if ((iYieldStored != 0) && (aiPrices[iYield] < iMinPrice) && (!bBIRTH_POINTS || ((iYield != YIELD_FOOD) || (iYieldStored > iMinFood))))//iYieldStored отрицательным быть не может { CvWString szBuffer = CvWString::format(L"/t/t%c, Stored%d, PriceNew%d, PriceOld%d", GC.getYieldInfo((YieldTypes)iYield).getChar(), iYieldStored, aiPrices[iYield], iLossYield == -1 ? -1 : aiPrices[iLossYield]); gDLL->getInterfaceIFace()->addMessage(getOwnerINLINE(), false, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_DEAL_CANCELLED", MESSAGE_TYPE_MINOR_EVENT, GC.getYieldInfo((YieldTypes)iLossYield).getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_GREEN"), getX_INLINE(), getY_INLINE(), true, true); iLossYieldStored = iYieldStored; if (iYield == YIELD_FOOD)//это возможно только когда (GC.getBASE_BIRTH_POINTS_THRESHOLD() != 0) {iLossYieldStored -= iMinFood;} //VET BirthPoints - end 11/16 iMinPrice = aiPrices[iYield]; iLossYield = iYield; } }
Синее сообщение - проверяемый ресурс, его количество на складе и цена продажи (проверить эти значения с значениями в городском экране)
Зеленое сообщение - прошедший проверку ресурс. Ресурс цена которого ниже цены ресурса в прошлом (нижнем) зеленом сообщении. В сообщении будет цена нового и старого ресурса для сравнения.
Проанализируй сообщения и определи какой ресурс и по каким причинам не прошол правильную проверку
Если новые технологии позволяют обходится без услуг простых людей - это прогресс, а если новые технологии позволяют обходится без услуг миллионеров и крупных компаний - это нарушение авторских прав.
Мой мод
Итак, начинаем искать. Вот отчет о том, что получилось и что я увидел на экране.
Твой вариант с новыми строчками я скомпилировал без проблем. Более того можно даже запустить игру без каких-либо сообщений об ошибке. Но, в конце самого первого хода при нажатии кнопки окончания хода происходит сбой и выброс на основной экран виндовса.
К счастью, я проводил тестирование на том же компе, где и компилировал CvGameCoreDLL.dll, поэтому нажав на экране об ошибке на кнопку "Debug", я сразу же увидел строку, из-за которой происходил сбой.
Далее уже моя "самодеятельность". Я посмотрел как пишутся такого рода строки в исходных файлах и что им предшествует. После этого я внес небольшое изменение. Вместо "iLossYield" я записал "iYield".Код:gDLL->getInterfaceIFace()->addMessage(getOwnerINLINE(), false, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_DEAL_CANCELLED", MESSAGE_TYPE_MINOR_EVENT, GC.getYieldInfo((YieldTypes)iLossYield).getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_BLUE"), getX_INLINE(), getY_INLINE(), true, true);
В итоге конечная строка выглядела так:
Аналогичный трюк с заменой "iLossYield" на "iYield" я проделал и для следующей строки.Код:gDLL->getInterfaceIFace()->addMessage(getOwnerINLINE(), false, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_DEAL_CANCELLED", MESSAGE_TYPE_MINOR_EVENT, GC.getYieldInfo((YieldTypes)iYield).getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_BLUE"), getX_INLINE(), getY_INLINE(), true, true);
В итоге твой код получился в таком виде:
Я не специалист по С++ и поэтому возможно сделанные мной изменения неверны в принципе, однако после них я смог без труда запустить игру и увидеть синие и зеленые сообщения на экране. Насколько они достоверны зависит от того, насколько правильны были внесенные мной изменения. Если они неверны, то дальнейшее можно не читать, ибо это писано "вилами по воде".Код:if (GC.getYieldInfo((YieldTypes)iYield).isCargo()) { iYieldStored = getYieldStored((YieldTypes)iYield); CvWString szBuffer = CvWString::format(L"/t%c, Stored%d, Price%d", GC.getYieldInfo((YieldTypes)iYield).getChar(), iYieldStored, aiPrices[iYield]); gDLL->getInterfaceIFace()->addMessage(getOwnerINLINE(), false, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_DEAL_CANCELLED", MESSAGE_TYPE_MINOR_EVENT, GC.getYieldInfo((YieldTypes)iYield).getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_BLUE"), getX_INLINE(), getY_INLINE(), true, true); //VET BirthPoints - begin 11/16 /*if ((iYieldStored > 0) && (aiPrices[iYield] < iMinPrice)) { iLossYieldStored = iYieldStored;*/ if ((iYieldStored != 0) && (aiPrices[iYield] < iMinPrice) && (!bBIRTH_POINTS || ((iYield != YIELD_FOOD) || (iYieldStored > iMinFood))))//iYieldStored отрицательным быть не может { CvWString szBuffer = CvWString::format(L"/t/t%c, Stored%d, PriceNew%d, PriceOld%d", GC.getYieldInfo((YieldTypes)iYield).getChar(), iYieldStored, aiPrices[iYield], iLossYield == -1 ? -1 : aiPrices[iLossYield]); gDLL->getInterfaceIFace()->addMessage(getOwnerINLINE(), false, GC.getEVENT_MESSAGE_TIME(), szBuffer, "AS2D_DEAL_CANCELLED", MESSAGE_TYPE_MINOR_EVENT, GC.getYieldInfo((YieldTypes)iYield).getButton(), (ColorTypes)GC.getInfoTypeForString("COLOR_GREEN"), getX_INLINE(), getY_INLINE(), true, true); iLossYieldStored = iYieldStored; if (iYield == YIELD_FOOD)//это возможно только когда (GC.getBASE_BIRTH_POINTS_THRESHOLD() != 0) {iLossYieldStored -= iMinFood;} //VET BirthPoints - end 11/16 iMinPrice = aiPrices[iYield]; iLossYield = iYield; } }
Итак, город на два жителя, скорость игры нормальная, запас еды чуть больше "неприкосновенного" (48 еды), поэтому сначала удаляется небольшой избыток еды. На экране я вижу:
Количество хранящихся ресурсов (Stored) верно по всем позициям. Цена для еды -2147483648 довольно "странная", но "PricеOld -1" кажется правильной, так как еда действительно самый дешевый ресурс и стОит она именно 1 монету.
Далее постепенно опорожняем склад и наконец доходим до следующего варианта.
До удаления избытков:
Стоимость табака 4 монеты, железной руды 3. Поэтому по идее должна удаляться железная руда. Однако почему-то удаляется табак.
На экране мы видим сообщение об этом:
И опять те же странные значения по ценам: "2147483648" и "PricеOld -1". В данном случае "PricеOld -1" уже неверно, поскольку табак стоит 4 монеты, а не одну. А следовательно и в первом случае с едой этому значению верить нельзя.
Что в данном случае смущает меня больше всего?
Это одно и то же значение для цены на все без исключения товары. Я еще могу допустить, что на экране мы видим некое "внутреннее значение", которое программа использует для расчетов цен, но по логике оно должно быть разным для различных товаров. Тут же оно почему-то одно и то же по всем товарам.
В общем, получилось пока так.....
Решение проблемы я ему отправил личным сообщением несколько дней назад. Но, видимо, он опять в командировке.
Нет, напротив ко мне гости приехали и мы неделю из-за стола не поднимались.А в командировку я уеду на несколько дней в самом конце этой недели.
Итак, что получилось в последнем варианте, когда вводится
Компиляция и запуск игры - без проблем.Код:if (!GET_PLAYER(getOwnerINLINE()).isYieldEuropeTradable(eYield))// непродоваемые в европе
Набор городом "очков рождаемости" и поддержание "неприкосновенного запаса" еды в переполненном городском складе тоже все работает правильно.
Затем идет та же самая ошибка.
Вот город на 2 жителя. Скорость нормальная, вместимость склада 100, "неприкосновенный запас" еды равен 48. Остальное при переполнении должно удаляться.
И тут снова, как и раньше удаление излишков идет строго слева направо, причем совершенно независимо от стоимость удаляемого товара. Я даже оставил на складе 100 единиц серебра, то есть товара следующего по списку после древесины (если идти слева направо).
На следующий ход серебро было удалено, несмотря на то, что его цена была 19 монет и оно было самым дорогим товаром на переполненном складе.
Так же были удалены излишки хлопка (3 монеты) и шкур (5 монет). Самая крайняя справа и при этом дешевая же железная руда (3 монеты) осталась нетронутой.
Вот сообщения с экранаю Они не влезли в один снимок, поэтому я сделал три снимка по каждой позиции.
Сначала исчезло серебро:
Затем хлопок
И наконец самыми последними были удалены шкуры:
![]()