Skip to content

Commit af35f04

Browse files
committed
Improved implementation of the clearing move path algorithm for AI.
Added an additional argument to the Tilemap::make_path_func() function to build an array path with tile numbers.
1 parent ce33690 commit af35f04

8 files changed

Lines changed: 283 additions & 178 deletions

File tree

sfall/FalloutEngine/Functions_def.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ WRAP_WATCOM_FFUNC3(void, check_for_death, fo::GameObject*, critter, long, amount
3737
WRAP_WATCOM_FFUNC4(long, combat_check_bad_shot, fo::GameObject*, source, fo::GameObject*, target, long, hitMode, long, isSecondary)
3838
WRAP_WATCOM_FFUNC5(bool, combat_is_shot_blocked, fo::GameObject*, source, DWORD, tileSource, DWORD, tileTarget, fo::GameObject*, target, long*, accumulator)
3939
WRAP_WATCOM_FFUNC6(long, combat_safety_invalidate_weapon_func, fo::GameObject*, source, fo::GameObject*, weapon, long, hitMode, fo::GameObject*, targetA, DWORD*, outSafeRange, fo::GameObject*, targetB)
40+
WRAP_WATCOM_FFUNC4(long, combatai_msg, fo::GameObject*, source, fo::ComputeAttackResult*, ctd, long, action, long, delay)
4041
WRAP_WATCOM_FFUNC3(void, correctFidForRemovedItem, fo::GameObject*, critter, fo::GameObject*, item, long, slotFlag)
4142
WRAP_WATCOM_FFUNC7(long, createWindow, const char*, winName, DWORD, x, DWORD, y, DWORD, width, DWORD, height, long, color, long, flags)
4243
WRAP_WATCOM_FFUNC4(long, determine_to_hit, fo::GameObject*, source, fo::GameObject*, target, long, bodyPart, long, hitMode)

sfall/Game/ImprovedAI/AI.Behavior.cpp

Lines changed: 202 additions & 123 deletions
Large diffs are not rendered by default.

sfall/Game/ImprovedAI/AI.Behavior.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ class AIBehavior {
3939
};
4040

4141
static long __fastcall AICheckBeforeWeaponSwitch(fo::GameObject* target, long &hitMode, fo::GameObject* source, fo::GameObject* weapon);
42+
static long __fastcall AIMoveStepsCloser(long flags, fo::GameObject* target, fo::GameObject* source, long distance);
4243
};
4344

4445
constexpr int pickupCostAP = 3; // engine default cost

sfall/Game/ImprovedAI/AI.Combat.cpp

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -685,7 +685,7 @@ static void CombatAI_Extended(fo::GameObject* source, fo::GameObject* target) {
685685
{
686686
case AIBehavior::AttackResult::TargetDead:
687687
DEV_PRINTF("\n[AI] Attack result: TARGET DEAD!\n");
688-
if (target == fo::var::obj_dude) return;
688+
if (target->protoId == fo::PID_Player) return;
689689
findTargetAfterKill = true;
690690
goto ReFindNewTarget; // поиск новой цели, текущая была убита
691691

@@ -1015,24 +1015,24 @@ static void __declspec(naked) combat_attack_hook() {
10151015
*/
10161016
/////////////////////////////////////////////////////////////////////////////////////////
10171017

1018-
#ifndef NDEBUG
1019-
static void __declspec(naked) ai_move_steps_closer_debug() {
1020-
static const char* move_steps_closer_fail = "\nERROR: ai_move_steps_closer.";
1021-
__asm {
1022-
test eax, eax;
1023-
jns skip;
1024-
push move_steps_closer_fail;
1025-
call fo::funcoffs::debug_printf_;
1026-
add esp, 4;
1027-
skip:
1028-
add esp, 0x10;
1029-
pop ebp;
1030-
pop edi;
1031-
pop esi;
1032-
retn;
1033-
}
1034-
}
1035-
#endif
1018+
//#ifndef NDEBUG
1019+
//static void __declspec(naked) ai_move_steps_closer_debug() {
1020+
// static const char* move_steps_closer_fail = "\nERROR: ai_move_steps_closer.";
1021+
// __asm {
1022+
// test eax, eax;
1023+
// jns skip;
1024+
// push move_steps_closer_fail;
1025+
// call fo::funcoffs::debug_printf_;
1026+
// add esp, 4;
1027+
//skip:
1028+
// add esp, 0x10;
1029+
// pop ebp;
1030+
// pop edi;
1031+
// pop esi;
1032+
// retn;
1033+
// }
1034+
//}
1035+
//#endif
10361036

10371037
void AICombat::init(bool smartBehavior) {
10381038

@@ -1056,7 +1056,7 @@ void AICombat::init(bool smartBehavior) {
10561056

10571057
#ifndef NDEBUG
10581058
combatDebug = (sf::IniReader::GetConfigInt("CombatAI", "Debug", 0) != 0);
1059-
sf::MakeJump(0x42A1B6, ai_move_steps_closer_debug);
1059+
//sf::MakeJump(0x42A1B6, ai_move_steps_closer_debug);
10601060
#endif
10611061
}
10621062
}

sfall/Game/ImprovedAI/AI.FuncHelpers.cpp

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,11 @@
66

77
#include "..\..\FalloutEngine\Fallout2.h"
88
#include "..\..\Utils.h"
9-
//#include "..\..\Modules\AI.h"
109

1110
#include "..\AI\AIHelpers.h"
12-
1311
#include "..\items.h"
1412

13+
#include "AI.Behavior.h"
1514
#include "AI.FuncHelpers.h"
1615

1716
namespace game
@@ -68,13 +67,13 @@ long AIHelpersExt::CombatMoveToTile(fo::GameObject* source, long tile, long dist
6867
}
6968

7069
long AIHelpersExt::ForceMoveToTarget(fo::GameObject* source, fo::GameObject* target, long dist) {
71-
dist |= 0x02000000; // sfall force flag (stay and stay_close)
72-
return fo::func::ai_move_steps_closer(source, target, ~dist, 0); // 0 - ok, -1 - don't move
70+
// sfall force flag (stay and stay_close)
71+
return AIBehavior::AIMoveStepsCloser(0x02000000, target, source, dist); // 0 - ok, -1 - don't move
7372
}
7473

7574
long AIHelpersExt::MoveToTarget(fo::GameObject* source, fo::GameObject* target, long dist) {
76-
dist |= 0x01000000; // sfall force flag (stay_close)
77-
return fo::func::ai_move_steps_closer(source, target, ~dist, 0); // 0 - ok, -1 - don't move
75+
// sfall force flag (stay_close)
76+
return AIBehavior::AIMoveStepsCloser(0x01000000, target, source, dist); // 0 - ok, -1 - don't move
7877
}
7978

8079
fo::GameObject* AIHelpersExt::AICheckWeaponSkill(fo::GameObject* source, fo::GameObject* hWeapon, fo::GameObject* sWeapon) {
@@ -286,7 +285,7 @@ bool AIHelpersExt::CanSeeObject(fo::GameObject* source, fo::GameObject* target)
286285
// return fo::func::can_see(source, target) && AIHelpers::CanSeeObject(source, target);
287286
//}
288287

289-
static fo::GameObject* __fastcall obj_ai_move_blocking_at(fo::GameObject* source, long tile, long elev) {
288+
fo::GameObject* __fastcall AIHelpersExt::obj_ai_move_blocking_at(fo::GameObject* source, long tile, long elev) {
290289
if (tile < 0 || tile >= 40000) return nullptr;
291290

292291
fo::ObjectTable* obj = fo::var::objectTable[tile];
@@ -297,8 +296,9 @@ static fo::GameObject* __fastcall obj_ai_move_blocking_at(fo::GameObject* source
297296
long flags = object->flags;
298297
// не установлены флаги Mouse_3d, NoBlock и WalkThru
299298
if (!(flags & fo::ObjectFlag::Mouse_3d) && !(flags & fo::ObjectFlag::NoBlock) && !(flags & fo::ObjectFlag::WalkThru) && source != object) {
300-
if (object->TypeFid() == fo::ObjType::OBJ_TYPE_CRITTER) fo::var::moveBlockObj = object;
301-
return object;
299+
if (object->TypeFid() != fo::ObjType::OBJ_TYPE_CRITTER || object->critter.teamNum != source->critter.teamNum) {
300+
return object;
301+
};
302302
}
303303
}
304304
obj = obj->nextObject;
@@ -315,14 +315,16 @@ static fo::GameObject* __fastcall obj_ai_move_blocking_at(fo::GameObject* source
315315
fo::GameObject* object = obj->object;
316316
long flags = object->flags;
317317
if (flags & fo::ObjectFlag::MultiHex && !(flags & fo::ObjectFlag::Mouse_3d) && !(flags & fo::ObjectFlag::NoBlock) && !(flags & fo::ObjectFlag::WalkThru) && source != object) {
318-
if (object->TypeFid() == fo::ObjType::OBJ_TYPE_CRITTER) fo::var::moveBlockObj = object;
319-
return object;
318+
if (object->TypeFid() != fo::ObjType::OBJ_TYPE_CRITTER || object->critter.teamNum != source->critter.teamNum) {
319+
return object;
320+
};
320321
}
321322
}
322323
obj = obj->nextObject;
323324
}
324325
}
325326
} while (++direction < 6);
327+
326328
return nullptr;
327329
}
328330

sfall/Game/ImprovedAI/AI.FuncHelpers.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ class AIHelpersExt {
5656

5757
static bool CanSeeObject(fo::GameObject* source, fo::GameObject* target);
5858

59+
static fo::GameObject* __fastcall obj_ai_move_blocking_at(fo::GameObject* source, long tile, long elev);
60+
// wrapper
5961
static void obj_ai_move_blocking_at_();
6062
};
6163

sfall/Game/tilemap.cpp

Lines changed: 43 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/*
1+
/*
22
* sfall
33
* Copyright (C) 2008 - 2021 Timeslip and sfall team
44
*
@@ -180,7 +180,7 @@ long __fastcall Tilemap::tile_num_beyond(long sourceTile, long targetTile, long
180180
}
181181
}
182182

183-
static void __declspec(naked) tile_num_beyond_hack() {
183+
static void __declspec(naked) tile_num_beyond_replacement() {
184184
__asm { //push ecx;
185185
push ebx;
186186
mov ecx, eax;
@@ -214,16 +214,17 @@ static __forceinline fo::GameObject* CheckTileBlocking(void* blockFunc, long til
214214
//return object;
215215
}
216216

217-
// idist_
217+
// same as idist_
218218
static __inline long DistanceFromPositions(long sX, long sY, long tX, long tY) {
219219
long diffX = std::abs(tX - sX);
220220
long diffY = std::abs(tY - sY);
221221
long minDiff = (diffX <= diffY) ? diffX : diffY;
222222
return (diffX + diffY) - (minDiff >> 1);
223223
}
224224

225-
// optimized version
226-
long __fastcall Tilemap::make_path_func(fo::GameObject* srcObject, long sourceTile, long targetTile, uint8_t* arrayRotation, long checkTargetTile, void* blockFunc) {
225+
// optimized version with added 'type' arg
226+
// type: 1 - tile path, 0 - rotation path
227+
long __fastcall Tilemap::make_path_func(fo::GameObject* srcObject, long sourceTile, long targetTile, long type, void* arrayRef, long checkTargetTile, void* blockFunc) {
227228

228229
if (checkTargetTile && fo::func::obj_blocking_at_wrapper(srcObject, targetTile, srcObject->elevation, blockFunc)) return 0;
229230

@@ -281,7 +282,9 @@ long __fastcall Tilemap::make_path_func(fo::GameObject* srcObject, long sourceTi
281282
if (childData.tile == targetTile) break; // exit the loop path is built
282283

283284
*dadData = childData;
284-
if (++dadData == m_dadData.end()) return 0; // path can't be built reached the end of the array (limit the maximum path length)
285+
if (++dadData == m_dadData.end()) {
286+
return 0; // path can't be built reached the end of the array (limit the maximum path length)
287+
}
285288

286289
char rotation = 0;
287290
do {
@@ -295,17 +298,16 @@ long __fastcall Tilemap::make_path_func(fo::GameObject* srcObject, long sourceTi
295298
if (tile != targetTile) {
296299
fo::GameObject* objBlock = CheckTileBlocking(blockFunc, tile, srcObject);
297300
if (objBlock) {
298-
// Fix for building the path to the central hex of a multihex object (from BugFixes.cpp)
301+
// [FIX] Fixes building the path to the central hex of a multihex object (from BugFixes.cpp)
299302
if (objBlock->tile != targetTile) {
300303
if (!fo::func::anim_can_use_door(srcObject, objBlock)) continue; // block - next rotation
301304
} else {
302305
targetTile = tile; // replace the target tile (where the multihex object is located) with the current tile
303306
}
304307
}
305308
}
306-
if (++pathCounter >= 2000) {
307-
//BREAKPOINT
308-
return 0; // îãðàíè÷åíèå ìàêñèìàëüíîé äëèíû ïóòè?
309+
if (++pathCounter >= 2000) { // ограничение максимальной длины пути?
310+
return 0;
309311
}
310312

311313
pathData = m_pathData.begin();
@@ -338,32 +340,50 @@ long __fastcall Tilemap::make_path_func(fo::GameObject* srcObject, long sourceTi
338340
if (!pathCounter) return 0; // the path can't be built
339341
}
340342

343+
uint8_t* arrayR = reinterpret_cast<uint8_t*>(arrayRef);
344+
uint16_t* arrayT = reinterpret_cast<uint16_t*>(arrayRef);
341345
size_t pathLen = 0;
342-
uint8_t* array = arrayRotation;
346+
343347
// building and calculating the path length
344348
do {
345349
if (childData.tile == sourceTile) break; // reached the source tile
346-
if (array) *array++ = childData.rotation;
347-
350+
if (arrayRef) {
351+
if (type) {
352+
*arrayT++ = (uint16_t)childData.tile;
353+
} else {
354+
*arrayR++ = childData.rotation;
355+
}
356+
}
348357
while (childData.from_tile != dadData->tile) --dadData; // search a linked tile 'from -> tile'
349358
childData = *dadData;
350359
} while (++pathLen < 800);
351360

352-
if (arrayRotation && pathLen > 1) {
361+
if (arrayRef && pathLen > 1) {
353362
// reverse the array values
354363
size_t count = pathLen >> 1;
355-
do {
356-
uint8_t last = *--array;
357-
*array = *arrayRotation; // last < front
358-
*arrayRotation++ = last;
359-
} while (--count);
364+
if (type) {
365+
uint16_t* arrayFront = reinterpret_cast<uint16_t*>(arrayRef);;
366+
do {
367+
uint16_t last = *--arrayT;
368+
*arrayT = *arrayFront; // last < front
369+
*arrayFront++ = last;
370+
} while (--count);
371+
} else {
372+
uint8_t* arrayFront = reinterpret_cast<uint8_t*>(arrayRef);;
373+
do {
374+
uint8_t last = *--arrayR;
375+
*arrayR = *arrayFront; // last < front
376+
*arrayFront++ = last;
377+
} while (--count);
378+
}
360379
}
361380
return pathLen;
362381
}
363382

364-
//static void __declspec(naked) make_path_func_hack() {
383+
//static void __declspec(naked) make_path_func_replacement() {
365384
// __asm {
366385
// xchg [esp], ecx; // ret addr <> array
386+
// push 0; // type
367387
// push ebx; // target tile
368388
// push ecx; // ret addr
369389
// mov ecx, eax;
@@ -372,10 +392,10 @@ long __fastcall Tilemap::make_path_func(fo::GameObject* srcObject, long sourceTi
372392
//}
373393

374394
void Tilemap::init() {
375-
sf::MakeJump(fo::funcoffs::tile_num_beyond_ + 1, tile_num_beyond_hack); // 0x4B1B84
395+
sf::MakeJump(fo::funcoffs::tile_num_beyond_ + 1, tile_num_beyond_replacement); // 0x4B1B84
376396

377-
// test
378-
//sf::MakeJump(fo::funcoffs::make_path_func_, make_path_func_hack); // 0x415EFC
397+
// for test in game
398+
//sf::MakeJump(fo::funcoffs::make_path_func_, make_path_func_replacement); // 0x415EFC
379399
}
380400

381401
}

sfall/Game/tilemap.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ class Tilemap {
1717

1818
static long __fastcall tile_num_beyond(long sourceTile, long targetTile, long maxRange);
1919

20-
static long __fastcall make_path_func(fo::GameObject* srcObject, long sourceTile, long targetTile, uint8_t* arrayRotation, long checkTargetTile, void* blockFunc);
20+
static long __fastcall make_path_func(fo::GameObject* srcObject, long sourceTile, long targetTile, long type, void* arrayRef, long checkTargetTile, void* blockFunc);
2121
};
2222

2323
}

0 commit comments

Comments
 (0)