Объявления
Поздравляем
VDV_forever


Друзья, если не получается зарегистрироваться, напишите на почту vdv_forever@bk.ru.
Я оторву свою задницу от всех дел и обязательно Вас активирую! :smile10:
Добро пожаловать на геройский форум! :smile25:

Как создать плагин для HD мода

Герои Меча и Магии III: Возрождение Эрафии, Герои Меча и Магии III Дыхание Смерти, Герои Меча и Магии III Клинок Армагеддона, Герои Меча и Магии III Хроники Героев
offlineBen80  
имя: Сергей
Эксперт
Эксперт
 
Сообщения: 1315
Зарегистрирован: 18 июн 2017, 06:49
Пол: Не указан
Поблагодарили: 336 раз.

Re: Как создать плагин для HD мода

Сообщение Ben80 » 06 ноя 2017, 07:04

Simple procedure for Star Axis:

Код: Выделить всё
//----- (0052A860) --------------------------------------------------------
int __fastcall sub_0052A860(int a1, int a2)
{
  int result; // eax@2

  if ( (1 << *(_DWORD *)a2) & *(_DWORD *)(a1 + 103) )
    result = 0;
  else
    result = *(_DWORD *)(a1 + 1150);
  return result;
}


It is checked visited object or not. If not, some hero field used. Instead of
Код: Выделить всё
result = *(_DWORD *)(a1 + 1150);

you can use your own algorithm. Quite simple algorithm :smile1:

BTW, now I don't understand how Heroes's _dword_ visited[10] can store information about all map obects, even if bites are used actually.

Also, you need somehow associate new number for your new object.
http://www.wakeofgods.com/erm_help/
Objects, alphabetical List of
Вернуться к началу

offlineBen80  
имя: Сергей
Эксперт
Эксперт
 
Сообщения: 1315
Зарегистрирован: 18 июн 2017, 06:49
Пол: Не указан
Поблагодарили: 336 раз.

Re: Как создать плагин для HD мода

Сообщение Ben80 » 06 ноя 2017, 13:15

I have seen weight corresponding Garden of Revelation (it depends on current value of Hero Knowledge)
and I can propose some value for Market of time:

Код: Выделить всё
int __stdcall setMarketOfTimeWeight(LoHook* h, HookContext* c)
{
   if (getWorstSecSkill(c->ebx) == 29)
      c->eax = 0;
   else
   {
   if (*(int*)(c->ebx + 0x55)<=10)
      c->eax = 20 * 1;
   if (*(int*)(c->ebx + 0x55)<=20 && *(int*)(c->ebx + 0x55)>10)
      c->eax = 20 * 2;
   if (*(int*)(c->ebx + 0x55)<=30 && *(int*)(c->ebx + 0x55)>20)
      c->eax = 20 * 3;
   if (*(int*)(c->ebx + 0x55)>30)
      c->eax = 20 * 4;
   }

    return EXEC_DEFAULT;            
}


In principle you can use this code almost directly. I can propose procedure, which can be used directly, but not tested :smile1: (777 is number of your object):

Код: Выделить всё
int __stdcall setMarketOfTownWeight(LoHook* h, HookContext* c)
{
   if(c->eax != 777)
      return EXEC_DEFAULT;

   if (getWorstSecSkill(c->ebx) == 29)
      c->eax = 0;
   else
   {
   if (*(int*)(c->ebx + 0x55)<=10)
      c->eax = 20 * 1;
   if (*(int*)(c->ebx + 0x55)<=20 && *(int*)(c->ebx + 0x55)>10)
      c->eax = 20 * 2;
   if (*(int*)(c->ebx + 0x55)<=30 && *(int*)(c->ebx + 0x55)>20)
      c->eax = 20 * 3;
   if (*(int*)(c->ebx + 0x55)>30)
      c->eax = 20 * 4;
   }

   c->return_address = 0x528667;
    return NO_EXEC_DEFAULT;            
}

...
_PI->WriteLoHook(0x528553, setMarketOfTimeWeight);
Вернуться к началу

offlineRoseKavalier  
Мастер
Мастер
 
Сообщения: 331
Зарегистрирован: 23 сен 2017, 17:00
Пол: Не указан
Поблагодарили: 234 раз.

Re: Как создать плагин для HD мода

Сообщение RoseKavalier » 06 ноя 2017, 14:03

Ben80 писал(а):

Simple procedure for Star Axis:

Код: Выделить всё
//----- (0052A860) --------------------------------------------------------
int __fastcall sub_0052A860(int a1, int a2)
{
  int result; // eax@2

  if ( (1 << *(_DWORD *)a2) & *(_DWORD *)(a1 + 103) )
    result = 0;
  else
    result = *(_DWORD *)(a1 + 1150);
  return result;
}


It is checked visited object or not. If not, some hero field used. Instead of
Код: Выделить всё
result = *(_DWORD *)(a1 + 1150);

you can use your own algorithm. Quite simple algorithm :smile1:

BTW, now I don't understand how Heroes's _dword_ visited[10] can store information about all map obects, even if bites are used actually.

Also, you need somehow associate new number for your new object.
http://www.wakeofgods.com/erm_help/
Objects, alphabetical List of

Good, simpler than expected. I like simple weight procedure, we also need to add a check for sufficient gold based on getWorstSecSkill() so AI doesn't mindlessly go there. Or we could make it free for AI :smile36:

Market of Time ID is already set to 50 by all game assets, but the procedure for #50 was never implemented so code goes to default switch. That's why I have used this and that.
Изображение

Most hero-related objects that can be visited are capped at 32, some others like Stables only have 1. Hero visited objects are bitfields, that means 32 objects per dword.
Код: Выделить всё
1 -> 0x01
10 -> 0x02
100 -> 0x04
1000 -> 0x08
10000 -> 0x10
...

That's why even if you place 33 Star Axis, the 33rd is a copy of the 1st, since game performs % 32 on index to make sure you don't overflow on other item.

OTOH, non-hero-related objects (like mine, waterwheel, windmill) are instead player-related and have their visited bits set directly in _MapItem_->setup.
e.g.
Код: Выделить всё
struct _CreatureBank_{ // type 16
   unsigned _u1 : 5; //
   unsigned  visited : 8;
   unsigned  Ind : 12; // index
   unsigned  Taken : 1;
   unsigned _u2 : 6;
};
Вернуться к началу

offlineBen80  
имя: Сергей
Эксперт
Эксперт
 
Сообщения: 1315
Зарегистрирован: 18 июн 2017, 06:49
Пол: Не указан
Поблагодарили: 336 раз.

Re: Как создать плагин для HD мода

Сообщение Ben80 » 06 ноя 2017, 15:56

I have decided to propose you other algorithm for weighting, more correct :smile1: :

Код: Выделить всё
int __stdcall setMarketOfTownWeight(LoHook* h, HookContext* c)
{
    if(c->eax != 777)
        return EXEC_DEFAULT;

    _Hero_* hero = c->ebx;
    int skill = getWorstSecSkill(hero);
    if (skill == 29)
        c->eax = 0;
    else
    {
        c->eax = 0;
        if(hero->level < 20)
        {
            if(hero->second_skill[skill] == 1)
                c->eax = 40;
            if(hero->second_skill[skill] == 2)
                c->eax = 30;
            if(hero->second_skill[skill] == 3)
                c->eax = 20;
        }
        else
            c->eax = 40;
    }
    /*
    if (*(int*)(c->ebx + 0x55)<=10)
        c->eax = 20 * 1;
    if (*(int*)(c->ebx + 0x55)<=20 && *(int*)(c->ebx + 0x55)>10)
        c->eax = 20 * 2;
    if (*(int*)(c->ebx + 0x55)<=30 && *(int*)(c->ebx + 0x55)>20)
        c->eax = 20 * 3;
    if (*(int*)(c->ebx + 0x55)>30)
        c->eax = 20 * 4;
    */

    c->return_address = 0x528667;
    return NO_EXEC_DEFAULT;             
}
Вернуться к началу

offlineRoseKavalier  
Мастер
Мастер
 
Сообщения: 331
Зарегистрирован: 23 сен 2017, 17:00
Пол: Не указан
Поблагодарили: 234 раз.

Re: Как создать плагин для HD мода

Сообщение RoseKavalier » 07 ноя 2017, 02:27

We're getting there :smile11:
 screenshots
AI screen (I was red)
Изображение
Orrin steps on Market, getWorstSecSkill = 5 (Navigation)
Изображение
With enough gold, the bad skill is gone next day.
Изображение


Made some modifications to code, still at Github. [removed some files per request]
For translation, just skip down here and change the text.

What remains? I think mostly balance, I only did a single test with AI.
Maybe we can also add Market of Time to random map generator, I'm not familiar with that part of the code.
I would also like to eliminate global variables but I have not found a good way to do so yet, proc function can only take 2 arguments :smile5:

For good measure, here is code so far in main.cpp.
Код: Выделить всё
#include "includes\HoMM3_Extra.h"
#include "getWorstSecSkill.h"

Patcher* _P;
PatcherInstance* _PI;

#pragma pack(push, 1)
struct _SSkillInfo_
{
   char* name;
   char* desc[3];
};

struct _MarketText_
{
   char* description;
   char* hint;
   char* confirm;
};
#pragma pack(pop)

#define BID_MARKET_OF_TIME 50
#define o_SSkillInfo (*(_SSkillInfo_**)0x67DCF0)
#define o_SkillLevel(level) (*(char**)(0x6A75D4 + 4 * skill_level))
#define GOLD_NAME (*(char**)0x6A5EE4)
#define MARKET_OF_TIME_NAME (*(char**)0x6A7B1C)

#define COST1 2000
#define COST2 3500
#define COST3 5000

#define ENOUGH_GOLD 0
#define NOT_ENOUGH_GOLD 1

_Hero_ *global_hero;
_Player_ *global_me;
_MarketText_ market;

bool isWaterMap = false;


int skeletsAISum(_Hero_* hero)
{
   int sum = 0;
   for (int i = 0; i < 7; i++)
      if (hero->army.type[i] == CID_SKELETON || hero->army.type[i] == CID_SKELETON_WARRIOR)
         sum = sum + o_CreatureInfo[hero->army.type[i]].AI_value * hero->army.count[i];
   return sum;
}

int armyAISum(_Hero_* hero)
{
   int sum = 0;
   for (int i = 0; i < 7; i++)
      sum = sum + o_CreatureInfo[hero->army.type[i]].AI_value * hero->army.count[i];
   return sum;
}

int undeadsAISum(_Hero_* hero)
{
   int sum = 0;
   for (int i = 0; i < 7; i++)
      if (hero->army.type[i] >= CID_SKELETON && hero->army.type[i] <= CID_GHOST_DRAGON)
         sum = sum + o_CreatureInfo[hero->army.type[i]].AI_value * hero->army.count[i];
   return sum;
}

int numberOfNecroTowns(_Hero_* hero)
{
   int sum = 0;
   _Player_* player1 = o_GameMgr->GetPlayer(hero->owner_id);
   for (int i = 0; i < player1->towns_count; i++)
      if (o_GameMgr->GetTown(player1->towns_ids[i])->type == TID_NECROPOLIS)
         sum = sum + 1;
   return sum;
}

int __stdcall setIsWaterMap(LoHook* h, HookContext* c)
{
   int mapSize = o_GameMgr->GetMapWidth();
   int mapDepth = o_GameMgr->GetMapDepth();
   int waterSize = 0;
   int rockSize = 0;

   for (int k = 0; k <= mapDepth; k++)
   {
      for (int i = 0; i < mapSize; i++)
      {
         for (int j = 0; j < mapSize; j++)
         {
            _MapItem_ *item = o_GameMgr->Map.GetItem(i, j, 0);
            if (item->land == H3M_TERRAIN_WATER)
               waterSize++;
            else if (item->land == H3M_TERRAIN_ROCK)
               rockSize++;
         }
      }
   }
   mapSize *= mapSize; // square size
   if (mapDepth)
      mapSize += mapSize; // double for underground

   if ((double)waterSize / (double)(mapSize - rockSize) > 0.1)
      isWaterMap = true;
   else
      isWaterMap = false;
   return EXEC_DEFAULT;
}

bool isNecromancyNeeded(_Hero_* ourHero)
{
   int numberOfAllTowns = o_GameMgr->GetPlayer(ourHero->owner_id)->towns_count;

   if (CALL_2(double, __thiscall, 0x4E3F40, ourHero, 0) < 0.25 && numberOfNecroTowns(ourHero) / numberOfAllTowns < 0.3
      && undeadsAISum(ourHero) < 10000)
      return false;
   return true;
}

int getWorstSecSkill(_Hero_* ourHero)
{
   int attack = ourHero->attack;

   if (ourHero->second_skill[HSS_NAVIGATION] > 0 && !isWaterMap)
      return HSS_NAVIGATION;

   if (ourHero->second_skill[HSS_NECROMANCY] > 0 && !isNecromancyNeeded(ourHero))
      return HSS_NECROMANCY;

   if (ourHero->level >= 10 && ourHero->level < 20)
   {
      if (ourHero->second_skill[HSS_EAGLE_EYE] == 1)
         return HSS_EAGLE_EYE;

      if (ourHero->second_skill[HSS_SCOUTING] == 1)
         return HSS_SCOUTING;

      if (ourHero->second_skill[HSS_FIRST_AID] == 1 && !ourHero->DoesHasArtifact(AID_FIRST_AID_TENT))
         if (armyAISum(ourHero) / ourHero->second_skill[HSS_FIRST_AID] > 15000)
            return HSS_FIRST_AID;

      if (ourHero->second_skill[HSS_ARTILLERY] == 1 && !ourHero->DoesHasArtifact(AID_BALLISTA))
         if ((double)armyAISum(ourHero) / pow((double)(ourHero->second_skill[HSS_ARTILLERY] * attack), 0.8) > 4000.0)
            return HSS_ARTILLERY;

      if (ourHero->second_skill[HSS_PATHFINDING] == 1)
         return HSS_PATHFINDING;

      if (ourHero->second_skill[HSS_MYSTICISM] == 1)
         return HSS_MYSTICISM;

      if (ourHero->second_skill[HSS_FIRST_AID] == 1)
         if (armyAISum(ourHero) / ourHero->second_skill[HSS_FIRST_AID] > 30000)
            return HSS_FIRST_AID;

      if (ourHero->second_skill[HSS_ARTILLERY] == 1)
         if ((double)armyAISum(ourHero) / pow((double)(ourHero->second_skill[HSS_ARTILLERY] * attack), 0.8) > 8000.0)
            return HSS_ARTILLERY;
   }

   else if (ourHero->level >= 20 && ourHero->level < 30)
   {
      if (ourHero->second_skill[HSS_EAGLE_EYE] > 0)
         if (ourHero->second_skill[HSS_EAGLE_EYE] < 3)
            return HSS_EAGLE_EYE;

      if (ourHero->second_skill[HSS_SCOUTING] > 0)
         if (ourHero->second_skill[HSS_SCOUTING] < 3)
            return HSS_SCOUTING;

      if (ourHero->second_skill[HSS_FIRST_AID] > 0)
         if (ourHero->second_skill[HSS_FIRST_AID] < 3 && !ourHero->DoesHasArtifact(AID_FIRST_AID_TENT))
            if (armyAISum(ourHero) / ourHero->second_skill[HSS_FIRST_AID] > 12500)
               return HSS_FIRST_AID;

      if (ourHero->second_skill[HSS_ARTILLERY] > 0)
         if (ourHero->second_skill[HSS_ARTILLERY] < 3 && !ourHero->DoesHasArtifact(AID_BALLISTA))
            if ((double)armyAISum(ourHero) / pow((double)(ourHero->second_skill[HSS_ARTILLERY] * attack), 0.8) > 3000.0)
               return HSS_ARTILLERY;

      if (ourHero->second_skill[HSS_PATHFINDING] > 0)
         if (ourHero->second_skill[HSS_PATHFINDING] < 3)
            return HSS_PATHFINDING;

      if (ourHero->second_skill[HSS_MYSTICISM] > 0)
         if (ourHero->second_skill[HSS_MYSTICISM] < 3)
            return HSS_MYSTICISM;

      if (ourHero->second_skill[HSS_FIRST_AID] > 0)
         if (ourHero->second_skill[HSS_FIRST_AID] < 3)
            if (armyAISum(ourHero) / ourHero->second_skill[HSS_FIRST_AID] > 25000)
               return HSS_FIRST_AID;

      if (ourHero->second_skill[HSS_ARTILLERY] > 0)
         if (ourHero->second_skill[HSS_ARTILLERY] < 3)
            if ((double)armyAISum(ourHero) / pow((double)(ourHero->second_skill[HSS_ARTILLERY] * attack), 0.8) > 6000.0)
               return HSS_ARTILLERY;
   }

   else if (ourHero->level >= 30)
   {
      if (ourHero->second_skill[HSS_EAGLE_EYE] >0)
         return HSS_EAGLE_EYE;

      if (ourHero->second_skill[HSS_SCOUTING] >0)
         return HSS_SCOUTING;

      if (ourHero->second_skill[HSS_FIRST_AID] > 0 && !ourHero->DoesHasArtifact(AID_FIRST_AID_TENT))
         if (armyAISum(ourHero) / ourHero->second_skill[HSS_FIRST_AID] > 10000)
            return HSS_FIRST_AID;

      if (ourHero->second_skill[HSS_ARTILLERY] > 0 && !ourHero->DoesHasArtifact(AID_BALLISTA))
         if ((double)armyAISum(ourHero) / pow((double)(ourHero->second_skill[HSS_ARTILLERY] * attack), 0.8) > 2000.0)
            return HSS_ARTILLERY;

      if (ourHero->second_skill[HSS_PATHFINDING] > 0)
         return HSS_PATHFINDING;

      if (ourHero->second_skill[HSS_MYSTICISM] > 0)
         return HSS_MYSTICISM;

      if (ourHero->second_skill[HSS_FIRST_AID] > 0)
         if (armyAISum(ourHero) / ourHero->second_skill[HSS_FIRST_AID] > 20000)
            return HSS_FIRST_AID;

      if (ourHero->second_skill[HSS_ARTILLERY] > 0)
         if ((double)armyAISum(ourHero) / pow((double)(ourHero->second_skill[HSS_ARTILLERY] * attack), 0.8) > 4000.0)
            return HSS_ARTILLERY;
   }
   return 29;
}

void UpdateMarket(_Dlg_ *dlg, int gold)
{
   int cost[3] = { COST1, COST2, COST3 };
   _DlgStaticDef_ *SSkill;
   int skill_level;

   for (int i = 0; i < 8; i++)
   {
      if (SSkill = (_DlgStaticDef_*)dlg->GetItem(101 + i))
      {
         if (SSkill->def_frame_index >= 3)
         {
            skill_level = SSkill->def_frame_index % 3 + 1;
            if (gold < cost[skill_level - 1])
            {
               ((_DlgStaticDef_*)(dlg->GetItem(201 + i)))->def_frame_index = NOT_ENOUGH_GOLD;
               ((_DlgStaticDef_*)(dlg->GetItem(301 + i)))->def_frame_index = NOT_ENOUGH_GOLD;
            } // not enough gold
         } // if this skill still exists on hero
      } // if SSkill
   } // loop
}

int __stdcall MarketOfTimeProc(_Dlg_* dlg, _EventMsg_* msg)
{
   int r = dlg->DefProc(msg);
   char text[100];
   _DlgStaticDef_ *SSkill;
   int skill_id, skill_level;
   int cost[3] = { COST1, COST2, COST3 };
   text[0] = 0;
   if (msg->type == MT_MOUSEOVER) // update text of status bar
   {
      _DlgItem_* it = dlg->FindItem(msg->x_abs, msg->y_abs);
      if (it)
      {
         switch (it->id)
         {
         case 101:
         case 102:
         case 103:
         case 104:
         case 105:
         case 106:
         case 107:
         case 108:
            SSkill = (_DlgStaticDef_*)it;
            if (SSkill->def_frame_index >= 3)
            {
               skill_level = SSkill->def_frame_index % 3 + 1;
               skill_id = SSkill->def_frame_index / 3 - 1;
               sprintf(text, market.hint, o_SkillLevel(skill_level), o_SSkillInfo[skill_id].name, cost[skill_level - 1], GOLD_NAME);
            }
            break;
         case DIID_OK:
            sprintf(text, "%s", o_GENRLTXT_TXT->GetString(602-1));
            break;
         default:
            break;
         }
      }
      // Update status bar text
      _DlgStaticTextPcx8ed_* market_of_time_statbar =   (_DlgStaticTextPcx8ed_*)(dlg->GetItem(4000));
      market_of_time_statbar->SetText(text);
      market_of_time_statbar->Draw();
      market_of_time_statbar->RedrawScreen();
   }
   if (msg->type == MT_MOUSEBUTTON) // handle left click of DEFs
   {
      if (msg->subtype == MST_LBUTTONCLICK)
      {
         _DlgItem_* it = dlg->FindItem(msg->x_abs, msg->y_abs);
         if (it)
         {
            switch (it->id)
            {
            case 101:
            case 102:
            case 103:
            case 104:
            case 105:
            case 106:
            case 107:
            case 108:
               SSkill = (_DlgStaticDef_*)it;
               if (SSkill->def_frame_index >= 3)
               {
                  skill_level = SSkill->def_frame_index % 3 + 1;
                  skill_id = SSkill->def_frame_index / 3 - 1;
                  if (global_me->resourses.gold >= cost[skill_level - 1])
                  {
                     e_ClickSound();
                     sprintf(o_TextBuffer, market.confirm, cost[skill_level - 1], GOLD_NAME);
                     CALL_12(void, __fastcall, 0x4F6C00, o_TextBuffer, MBX_OKCANCEL, -1, -1, 0x14, SSkill->def_frame_index, -1, 0, -1, 0, -1, 0);
                     if (o_WndMgr->result_dlg_item_id == DIID_OK)
                     {
                        global_me->resourses.gold -= cost[skill_level - 1];
                        global_hero->UnlearnSkill(skill_id);
                        SSkill->def_frame_index = 0;
                        dlg->GetItem(it->id + 100)->Hide(); // Hide top bar
                        dlg->GetItem(it->id + 200)->Hide(); // Hide bot bar
                        dlg->GetItem(it->id + 300)->Hide(); // Hide SSkill name
                        dlg->GetItem(it->id + 400)->Hide(); // Hide SSkill level
                        UpdateMarket(dlg, global_me->resourses.gold);
                        dlg->Redraw();
                     }
                  }
               }
               break;
            default:
               break;
            } // switch
         } // it
      } // MST_LBUTTONCLICK

      if (msg->subtype == MST_RBUTTONDOWN) // show SSkill information
      {
         _DlgItem_* it = dlg->FindItem(msg->x_abs, msg->y_abs);
         if (it)
         {
            switch (it->id)
            {
            case 101:
            case 102:
            case 103:
            case 104:
            case 105:
            case 106:
            case 107:
            case 108:
               SSkill = (_DlgStaticDef_*)it;
               if (SSkill->def_frame_index >= 3)
               {
                  skill_level = SSkill->def_frame_index % 3 + 1;
                  skill_id = SSkill->def_frame_index / 3 - 1;
                  CALL_12(void, __fastcall, 0x4F6C00, o_SSkillInfo[skill_id].desc[skill_level - 1], MBX_RMC, -1, -1, -1, 0, -1, 0, -1, 0, -1, 0);
               }
               break;
            default:
               break;
            } // switch
         } // it
      } // MT_RBUTTONDOWN
   } // MT_MOUSEBUTTON

   return r;
}

void MarketOfTime(_Hero_ *hero, _Player_ *me)
{
   // simple array that holds cost
   int cost[3] = { COST1, COST2, COST3 };

   //////////////////////
   //
   //   Creation
   //
   //////////////////////
   _Dlg_ *dlg;
   dlg = _CustomDlg_::Create(DLG_X_CENTER, DLG_Y_CENTER, 512, 450, DF_SCREENSHOT | DF_SHADOW, MarketOfTimeProc);

   // background
   dlg->AddItem(_DlgStaticDef_::Create(0, 0, 0, "MarketTime.def", 0, 0, 0));

   // color border to player's hue
   CALL_5(int, __thiscall, 0x5FF400, dlg, 512, 13, 0, me->id);

   // title
   dlg->AddItem(_DlgStaticText_::Create(0, 30, 512, 30, MARKET_OF_TIME_NAME, "bigfont.fnt", 2, 1, ALIGN_H_CENTER | ALIGN_V_CENTER, 0));

   // description
   dlg->AddItem(_DlgStaticText_::Create(50, 80, 405, 64, market.description, "smalfont.fnt", 1, 1, ALIGN_H_CENTER | ALIGN_V_CENTER, 0));

   //////////////////////
   //
   //   Secondary Skills
   //
   //////////////////////

   int sskill_y = 182;
   int sskill_x = 75;
   int dx = 104;
   int dy = 119;
   int bar_x = 47;
   int top_bar_y = 160;
   int bot_bar_y = 230;
   int sskill_count = hero->second_skill_count;

   for (int i = 0; i < sskill_count; i++)
   {
      int row = i / 4;
      int col = i % 4;
      int skill = hero->ShownSSkillPosition(i + 1);
      int skill_level = hero->second_skill[skill];
      int def_frame = 2 + 3 * skill + skill_level;

      // skill def
      dlg->AddItem(_DlgStaticDef_::Create(sskill_x + dx * col, sskill_y + dy * row, 101 + i, "Secskill.def", def_frame, 0, 0));

      // allowed/disallowed colors
      int allowed_disallowed = me->resourses.gold >= cost[skill_level - 1] ? ENOUGH_GOLD : NOT_ENOUGH_GOLD;
      dlg->AddItem(_DlgStaticDef_::Create(bar_x + dx * col, top_bar_y + dy * row, 201 + i, "MarketBars.def", allowed_disallowed, 0, 0));
      dlg->AddItem(_DlgStaticDef_::Create(bar_x + dx * col, bot_bar_y + dy * row, 301 + i, "MarketBars.def", allowed_disallowed, 0, 0));

      // skill name text
      dlg->AddItem(_DlgStaticText_::Create(bar_x + dx * col, top_bar_y + dy * row, 100, 18, o_SSkillInfo[skill].name, "smalfont.fnt", 1, 401 + i, ALIGN_H_CENTER | ALIGN_V_CENTER, 0));

      // skill level text
      dlg->AddItem(_DlgStaticText_::Create(bar_x + dx * col, bot_bar_y + dy * row, 100, 18, o_SkillLevel(skill_level), "smalfont.fnt", 1, 501 + i, ALIGN_H_CENTER | ALIGN_V_CENTER, 0));
   }

   //////////////////////
   //
   //   Status Bar
   //
   //////////////////////
   dlg->AddItem(_DlgStaticTextPcx8ed_::Create(8, 425, 512 - 16, 18, "", "smalfont.fnt", "HD_TStat.bmp", 1, 4000, ALIGN_H_CENTER | ALIGN_V_CENTER));

   //////////////////////
   //
   //   Exit Button
   //
   //////////////////////
   dlg->AddItem(_DlgStaticPcx8_::Create(512 / 2 - 33, 450 - 72, 1234, "Box64x30.pcx"));
   dlg->AddItem(_DlgButton_::Create(512 / 2 - 32, 450 - 71, 64, 30, DIID_OK, "iOkay.def", 0, 1, 1, 28, 2));

   //////////////////////
   //
   //   Finish up
   //
   //////////////////////
   o_SoundMgr->PlaySample("HASTE.wav");
   o_MouseMgr->ChangeCursor(0, 0);
   dlg->Run();
   dlg->Destroy(TRUE);
}

int __stdcall EnterMarketTime(LoHook *h, HookContext *c)
{
   if (c->ebx == BID_MARKET_OF_TIME)
   {
      global_hero = (_Hero_*)c->arg_n(1);
      global_me = o_GameMgr->GetPlayer(global_hero->owner_id);
      if (c->arg_n(4)) // human
      {
         MarketOfTime(global_hero, global_me);
      }
      else // AI
      {
         int AI_cost[3] = { COST1, COST2, COST3 };
         int skill = getWorstSecSkill(global_hero);
         if (skill != 29 && global_me->resourses.gold >= AI_cost[global_hero->second_skill[skill]] + 1000) // second check necessary?
         {
            global_hero->UnlearnSkill(skill);
            global_me->resourses.gold -= AI_cost[global_hero->second_skill[skill]];
         }
      }
   }
   return EXEC_DEFAULT;
}

int __stdcall setMarketOfTownWeight(LoHook* h, HookContext* c)
{
   if (c->eax != BID_MARKET_OF_TIME)
      return EXEC_DEFAULT;
   int weight = 0;
   _Hero_* hero = (_Hero_*)c->ebx;
   _Player_ *me = o_GameMgr->GetPlayer(hero->owner_id);
   int skill = getWorstSecSkill(hero);
   if (skill != 29)
   {
      if (hero->level < 20)
      {
         if (hero->second_skill[skill] == 1)
            weight = 40;
         if (hero->second_skill[skill] == 2)
            weight = 30;
         if (hero->second_skill[skill] == 3)
            weight = 20;
      }
      else
         weight = 40;
      int AI_cost[3] = { COST1, COST2, COST3 };
      if (me->resourses.gold < AI_cost[hero->second_skill[skill]] + 1000) // let AI keep some spare change
         weight = 0;
   }
   c->return_address = 0x528667;
   c->eax = weight;
   return NO_EXEC_DEFAULT;
}

BOOL APIENTRY DllMain(HMODULE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)
{
   static _bool_ plugin_On = 0;
   switch (ul_reason_for_call)
   {
   case DLL_PROCESS_ATTACH:
      if (!plugin_On)
      {
         plugin_On = 1;
         _P = GetPatcher();
         _PI = _P->CreateInstance("MarketOfTime");

         // Hero steps on Market of Time
         _PI->WriteLoHook(0x4A8194, EnterMarketTime);
         // New game
         _PI->WriteLoHook(0x4FDF90, setIsWaterMap);
         // Load game
         _PI->WriteLoHook(0x4BD91F, setIsWaterMap);
         // AI value for building
         _PI->WriteLoHook(0x528546, setMarketOfTownWeight);

         market.confirm = "The old man asks: \"Are you sure you want to forget this skill? This cannot be undone.\"\n\nThe fee is %d %s.";
         market.description = "An old bearded man beckons you over to hear him out. After a few moments, you discover that this strange place \
         allows you to alter some of your past decisions. For a fee, you can forget any of the Secondary Skills you may have learned.";
         market.hint = "Forget %s %s for %d %s.";
      }
      break;

   case DLL_THREAD_ATTACH:
   case DLL_THREAD_DETACH:
   case DLL_PROCESS_DETACH:
      break;
   }
   return TRUE;
}
Вложения
MarketOfTime.zip
Beta 2 - AI works
(90.57 КБ) Скачиваний: 169
Последний раз редактировалось RoseKavalier 04 дек 2017, 17:26, всего редактировалось 1 раз.
Вернуться к началу

offlineBen80  
имя: Сергей
Эксперт
Эксперт
 
Сообщения: 1315
Зарегистрирован: 18 июн 2017, 06:49
Пол: Не указан
Поблагодарили: 336 раз.

Re: Как создать плагин для HD мода

Сообщение Ben80 » 07 ноя 2017, 03:28

Код: Выделить всё
_MapItem_ *item = o_GameMgr->Map.GetItem(i, j, 0);


Should be (i, j, k) ?

BTW, this code will be working correctly if map has only underground but have no main level ?
(k will be 0 for underground, not 1 ?)
Код: Выделить всё
for (int k = 0; k <= mapDepth; k++)
Вернуться к началу

offlineRoseKavalier  
Мастер
Мастер
 
Сообщения: 331
Зарегистрирован: 23 сен 2017, 17:00
Пол: Не указан
Поблагодарили: 234 раз.

Re: Как создать плагин для HD мода

Сообщение RoseKavalier » 07 ноя 2017, 05:49

Oops. Yes (i,j,k) - will fix links tomorrow; Git updated though.

Map with one level will always be above ground, unless I am very mistaken ?
Вернуться к началу

offlineНмеса  
 
Сообщения: 9
Зарегистрирован: 02 ноя 2017, 16:04
Пол: Не указан
Поблагодарили: 2 раз.

Re: Как создать плагин для HD мода

Сообщение Нмеса » 07 ноя 2017, 06:31

Крашится игра при столкновении с Мастер Джинами и плагином на новый Mirth. Сразу заподозрил его, джинов случаем не клинит, когда ранее точечный спелл стал массовым?

Сейв - http://rgho.st/7hPYBlfSx
Вернуться к началу

offlineBen80  
имя: Сергей
Эксперт
Эксперт
 
Сообщения: 1315
Зарегистрирован: 18 июн 2017, 06:49
Пол: Не указан
Поблагодарили: 336 раз.

Re: Как создать плагин для HD мода

Сообщение Ben80 » 07 ноя 2017, 15:09

Нмеса писал(а):

Крашится игра при столкновении с Мастер Джинами и плагином на новый Mirth. Сразу заподозрил его, джинов случаем не клинит, когда ранее точечный спелл стал массовым?

Сейв - http://rgho.st/7hPYBlfSx


Спасибо !

Посмотрю при случае, исправлю.
Вернуться к началу

offlineBen80  
имя: Сергей
Эксперт
Эксперт
 
Сообщения: 1315
Зарегистрирован: 18 июн 2017, 06:49
Пол: Не указан
Поблагодарили: 336 раз.

Re: Как создать плагин для HD мода

Сообщение Ben80 » 07 ноя 2017, 15:15

RoseKavalier писал(а):

Oops. Yes (i,j,k) - will fix links tomorrow; Git updated though.

Map with one level will always be above ground, unless I am very mistaken ?


As far as I remember in Heroes Chronicles, World of Tree were maps with one level - underground, without above ground.
Did you play in Heroes Chronicles ?
Вернуться к началу

Пред.След.

Вернуться в Общий раздел

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

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