-
RoseKavalier
- Мастер
-
- Сообщения: 331
- Зарегистрирован: 23 сен 2017, 17:00
- Пол:
- Поблагодарили: 234 раз.
|
RoseKavalier » 07 ноя 2017, 02:27
We're getting there 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 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 КБ) Скачиваний: 198
Последний раз редактировалось RoseKavalier 04 дек 2017, 17:26, всего редактировалось 1 раз.
|