@@ -89,7 +89,8 @@ static long __fastcall AIPickupWeaponFix(fo::GameObject* critter, long distance
8989 fo::GameObject* item = fo::func::inven_right_hand (critter);
9090 if (item && AIHelpers::IsGunOrThrowingWeapon (item)) return 1 ; // allow pickup
9191 }
92- return (allowPickUp) ? 1 : 0 ; // false - next item
92+ DEV_PRINTF1 (" \n ai_search_environ: ItemPickUpFix is allow: %d\n " , allowPickUp);
93+ return 0 | allowPickUp; // false - next item
9394}
9495
9596static void __declspec (naked) ai_search_environ_hook() {
@@ -380,7 +381,7 @@ static fo::GameObject* AISearchBestWeaponInCorpses(fo::GameObject* source, fo::G
380381 if (!game::CombatAI::ai_can_use_weapon (source, itemGround, fo::AttackType::ATKTYPE_RWEAPON_PRIMARY )) continue ;
381382
382383 // проверяем наличее и количество имеющихся патронов
383- if (!AIInventory::AICheckAmmo (itemGround, source) && Combat::check_item_ammo_cost (itemGround, fo::AttackType::ATKTYPE_RWEAPON_PRIMARY ) <= 0 ) {
384+ if (itemGround-> item . ammoPid != - 1 && !AIInventory::AICheckAmmo (itemGround, source) && Combat::check_item_ammo_cost (itemGround, fo::AttackType::ATKTYPE_RWEAPON_PRIMARY ) <= 0 ) {
384385 continue ;
385386 }
386387
@@ -438,7 +439,7 @@ static fo::GameObject* AISearchBestWeaponOnGround(fo::GameObject* source, fo::Ga
438439
439440 if (game::CombatAI::ai_can_use_weapon (source, itemGround, fo::AttackType::ATKTYPE_RWEAPON_PRIMARY ) &&
440441 // проверяем наличее и количество имеющихся патронов
441- AIInventory::AICheckAmmo (itemGround, source) && Combat::check_item_ammo_cost (itemGround, fo::AttackType::ATKTYPE_RWEAPON_PRIMARY ) > 0 )
442+ itemGround-> item . ammoPid == - 1 || AIInventory::AICheckAmmo (itemGround, source) && Combat::check_item_ammo_cost (itemGround, fo::AttackType::ATKTYPE_RWEAPON_PRIMARY ) > 0 )
442443 {
443444 if (AIInventory::BestWeapon (source, item, itemGround, target) == itemGround) {
444445 DEV_PRINTF2 (" \n [AI] SearchBestWeaponOnGround: %d (%s)" , itemGround->protoId , fo::func::critter_name (itemGround));
@@ -935,23 +936,24 @@ static void __declspec(naked) ai_try_attack_hack_after_attack() {
935936
936937// Событие перед атакой, когда шанс поразить цель является минимальным установленному значению 'min_to_hit' в AI.txt
937938static fo::GameObject* __fastcall AIBadToHit (fo::GameObject* source, fo::GameObject* target, fo::AttackType hitMode) {
938- DEV_PRINTF2 (" \n [AI] AIBadToHit : %s attack bad to hit my target (%s)\n " , fo::func::critter_name (source), fo::func::critter_name (target));
939+ DEV_PRINTF2 (" \n [AI] BadToHit : %s attack bad to hit my (%s) target. \n " , fo::func::critter_name (source), fo::func::critter_name (target));
939940
940- // TODO: попробовать сменить оружие?
941+ // TODO: попробовать сменить оружие
941942
942943 AICombat::AttackerSetHitMode (hitMode);
943944
944945 fo::GameObject* newTarget = AISearchTarget::AIDangerSource (source, 8 ); // попробовать найти другую цель со значеннием шанса выше 'min_to_hit'
945946 if (!newTarget || newTarget == target) {
946947 // новая цель не была найдена, проверяем боевой рейтинг цели
947- if (fo::func::combatai_rating (target) > (fo::func::combatai_rating (source) * 2 )) {
948+ fo::GameObject* lastTarget = fo::func::combatAIInfoGetLastTarget (target);
949+ if (lastTarget == source && fo::func::combatai_rating (target) > (fo::func::combatai_rating (source) * 2 )) {
948950 source->critter .combatState |= fo::CombatStateFlag::ReTarget;
949951 return nullptr ; // цель сильна - убегаем
950952 }
951- DEV_PRINTF (" \n [AI] AIBadToHit : No alternative target. Attack my target with bad to hit.\n " );
953+ DEV_PRINTF (" \n [AI] BadToHit : No alternative target. Attack my target with bad to hit.\n " );
952954 return (fo::GameObject*)-1 ; // продолжаем атаковать цель несмотря на низкий шанс
953955 }
954- DEV_PRINTF1 (" \n [AI] AIBadToHit : Found alternative (%s) target.\n " , fo::func::critter_name (newTarget));
956+ DEV_PRINTF1 (" \n [AI] BadToHit : Found alternative (%s) target.\n " , fo::func::critter_name (newTarget));
955957 return newTarget;
956958}
957959
@@ -995,16 +997,18 @@ static void ClearWalkThru() {
995997static fo::GameObject* AIClearMovePath (fo::GameObject* source, fo::GameObject* target) {
996998 fo::var::moveBlockObj = 0 ; // всегда содержит криттер или null
997999
1000+ __asm call fo::funcoffs::gmouse_bk_process_;
1001+
9981002 // check the path is clear
9991003 if (fo::func::make_path_func (source, source->tile , target->tile , 0 , 0 , AIHelpers::obj_ai_move_blocking_at_) > 0 ) {
1000- DEV_PRINTF (" \n [AI] AIClearMovePath : free." );
1004+ DEV_PRINTF (" \n [AI] ClearMovePath : free." );
10011005 // TODO: найти причину по которой путь строится для obj_ai_move_blocking_at_ но для obj_blocking_at_ это блокировано
10021006 if (fo::func::make_path_func (source, source->tile , target->tile , 0 , 0 , (void *)fo::funcoffs::obj_blocking_at_) > 0 ) {
10031007 return target;
10041008 }
10051009 if (++recursiveDepth > 10 ) return nullptr ;
10061010
1007- DEV_PRINTF (" \n [AI] AIClearMovePath : ClearWalkThru." );
1011+ DEV_PRINTF (" \n [AI] ClearMovePath : ClearWalkThru." );
10081012 ClearWalkThru ();
10091013 // BREAKPOINT;
10101014 return AIClearMovePath (source, target);
@@ -1023,7 +1027,7 @@ static fo::GameObject* AIClearMovePath(fo::GameObject* source, fo::GameObject* t
10231027 #endif
10241028 if (fo::var::moveBlockObj) {
10251029 fo::GameObject* blockCritter = fo::var::moveBlockObj;
1026- DEV_PRINTF1 (" \n [AI] AIClearMovePath : Blocked: %s" , fo::func::critter_name (blockCritter));
1030+ DEV_PRINTF2 (" \n [AI] ClearMovePath : Blocked: %s ID: %d " , fo::func::critter_name (blockCritter), blockCritter-> id );
10271031
10281032 if (!(blockCritter->flags & fo::ObjectFlag::WalkThru)) {
10291033 blockCritter->flags |= fo::ObjectFlag::WalkThru; // устанавливаем флаг для obj_ai_move_blocking_at_
@@ -1043,7 +1047,7 @@ static fo::GameObject* AIClearMovePath(fo::GameObject* source, fo::GameObject* t
10431047 char rotation[800 ];
10441048 len = fo::func::make_path_func (source, source->tile , blockCritter->tile , rotation, 0 , (void *)fo::funcoffs::obj_blocking_at_);
10451049 if (len == 0 ) {
1046- DEV_PRINTF (" \n [AI] AIClearMovePath : don't make path from source to block critter." );
1050+ DEV_PRINTF (" \n [AI] ClearMovePath : don't make path from source to block critter." );
10471051 return nullptr ; // нельзя!!!
10481052 }
10491053 if (len > source->critter .getMoveAP ()) return blockCritter;
@@ -1065,11 +1069,13 @@ static fo::GameObject* AIClearMovePath(fo::GameObject* source, fo::GameObject* t
10651069 // recursively calling functions until the path is freed or completely blocked
10661070 return AIClearMovePath (source, target);
10671071 }
1068- DEV_PRINTF (" \n [AI] AIClearMovePath : null." );
1072+ DEV_PRINTF (" \n [AI] ClearMovePath : null." );
10691073 return nullptr ;
10701074}
10711075
1072- static void __fastcall GetMoveObject (fo::GameObject* source, fo::GameObject* target, fo::GameObject* nearCritter) {
1076+ static void __fastcall GetMoveObject (fo::GameObject* source, fo::GameObject* target, fo::GameObject* nearCritter, long isMouse3d) {
1077+ if (isMouse3d) target->flags &= ~fo::ObjectFlag::Mouse_3d;
1078+
10731079 recursiveDepth = 0 ;
10741080 DEV_PRINTF2 (" \n [AI] TargetСritter: %s / NearСritter: %s" , fo::func::critter_name (target), fo::func::critter_name (nearCritter));
10751081 fo::GameObject* blockObject = AIClearMovePath (source, target);
@@ -1082,13 +1088,14 @@ static void __fastcall GetMoveObject(fo::GameObject* source, fo::GameObject* tar
10821088 ? blockObject
10831089 : nearCritter;
10841090
1085- DEV_PRINTF1 (" \n [AI] MoveToСritter: %s\n " , fo::func::critter_name (fo::var::moveBlockObj));
1091+ DEV_PRINTF2 (" \n [AI] MoveToСritter: %s ID:%d \n " , fo::func::critter_name (fo::var::moveBlockObj), fo::var::moveBlockObj-> id );
10861092
10871093 fo::func::register_begin (fo::RB_RESERVED );
10881094}
10891095
10901096static void __declspec (naked) ai_move_steps_closer_hack() {
10911097 __asm {
1098+ push [esp + 0x1C - 0x10 + 4 ]; // multiHexIsMouse3d
10921099 push edx; // block critter to move
10931100 mov ecx, esi; // source
10941101 mov edx, edi; // target
@@ -1124,7 +1131,7 @@ void AIBehavior::init(bool smartBehavior) {
11241131
11251132 // Реализация функции освобождения пути криттера блокирующего путь к цели
11261133 MakeCall (0x42A0D6 , ai_move_steps_closer_hack, 5 );
1127- BlockCall ( 0x42A06A ); // unused code
1134+ SafeWrite16 ( 0x42A0BF , 0x9090 );
11281135
11291136 // ////////////////// Combat AI improved behavior //////////////////////////
11301137
@@ -1133,7 +1140,7 @@ void AIBehavior::init(bool smartBehavior) {
11331140
11341141 if (smartBehavior) {
11351142 // Before starting his turn npc will always check if it has better weapons in inventory, than there is a current weapon
1136- LookupOnGround = (IniReader::GetConfigInt (" CombatAI" , " TakeBetterWeapons" , 1 ) > 1 ); // always check the items available on the ground
1143+ LookupOnGround = (IniReader::GetConfigInt (" CombatAI" , " TakeBetterWeapons" , 0 ) > 0 ); // always check the items available on the ground
11371144
11381145 HookCall (0x42A6BF , ai_called_shot_hook);
11391146
0 commit comments