mirror of
https://github.com/sfall-team/sfall.git
synced 2026-07-27 16:52:34 -07:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ea921aabbd | ||
|
|
b263b69fa3 | ||
|
|
6bb56b0f95 | ||
|
|
9a4f0c7505 | ||
|
|
c89a18522d | ||
|
|
c7ccb7f2c2 | ||
|
|
b25ca683f3 | ||
|
|
e28b3a5796 | ||
|
|
a9c74501df | ||
|
|
b03b93d6fc | ||
|
|
1f696b9f12 | ||
|
|
3d2d1cdf2a | ||
|
|
42347ac062 | ||
|
|
007b415740 | ||
|
|
35d2491bcb | ||
|
|
ece76ee726 | ||
|
|
d6f4a23527 | ||
|
|
045ad2f5d7 | ||
|
|
13703f1a3b | ||
|
|
58bb77d79f | ||
|
|
229371e4ab | ||
|
|
1884e279c7 | ||
|
|
e81d79e43e | ||
|
|
f731de7a25 | ||
|
|
0d6bc33279 |
@@ -13,18 +13,25 @@ Count=0
|
||||
[1]
|
||||
; drug item PID
|
||||
PID=0
|
||||
|
||||
; set a limit on the count of first and second delayed effects when using the drug, i.e. if the queue has delayed effects from the drug,
|
||||
; and their count is greater or equal to NumEffects, it is not possible to obtain new effects from using the drug
|
||||
; this count is 4 for Buffout/Mentats/Psycho/Jet
|
||||
; e.g. this count is 4 for Buffout/Mentats/Psycho/Jet
|
||||
; set -1 to leave this parameter unchanged
|
||||
NumEffects=-1
|
||||
|
||||
; the duration of the addiction effect in game minutes (i.e. 1440 = 24 game hours)
|
||||
; set to 0 to use the default time (7 days for all drugs except Jet)
|
||||
; set to 0 to use the default time of 7 days (as all drugs except Jet)
|
||||
AddictTime=0
|
||||
|
||||
; the number of the global variable from vault13.gam responsible for displaying addiction in the character screen
|
||||
; if you set GvarID with numbers: 21-26, 295, 296, or variable numbers that have already been declared in previous sections,
|
||||
; the TextID and FrmID options in this section will be ignored
|
||||
; set to 0 if the addiction is not required
|
||||
GvarID=0
|
||||
|
||||
; the index number from editor.msg to display the title of the addiction (the description uses the index number of TextID + 100)
|
||||
TextID=-1
|
||||
|
||||
; the line number (0-indexed) of the corresponding FRM in skilldex.lst
|
||||
FrmID=-1
|
||||
|
||||
+10
-10
@@ -1,5 +1,5 @@
|
||||
;sfall configuration settings
|
||||
;v4.2.4
|
||||
;v4.2.5
|
||||
|
||||
[Main]
|
||||
;Change to 1 if you want to use command line args to tell sfall to use another ini file.
|
||||
@@ -18,9 +18,9 @@ UseCommandLine=0
|
||||
;The greater numbers take precedence over lesser numbers
|
||||
;PatchFile0=mods\RP_data
|
||||
|
||||
;Path to the folder in which the game will automatically search and load custom .dat files
|
||||
;The data load order of the .dat files in the folder will be in reverse alphabetical order of the filenames
|
||||
;The .dat files specified in the PatchFileXX options will have higher priority than others
|
||||
;Path to the folder in which the game will automatically search and load custom files (by *.dat mask, including folders)
|
||||
;The data load order of the files in the folder will be in reverse alphabetical order of the filenames
|
||||
;The files placed in this folder will have higher priority than the PatchFileXX options
|
||||
;Uncomment the option to specify a different folder path. The default path is <GameRoot>\mods\
|
||||
;AutoSearchPath=mods
|
||||
|
||||
@@ -121,7 +121,7 @@ WorldMapTerrainInfo=0
|
||||
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||||
[Sound]
|
||||
;Sets the number of allowed simultaneous sound effects
|
||||
;Set to 0 to leave the default unchanged (i.e. 4)
|
||||
;Set to 0 to leave the default unchanged (i.e. 4). The maximum is 32
|
||||
NumSoundBuffers=0
|
||||
|
||||
;Set to 1 to allow attaching sound files to combat float messages
|
||||
@@ -134,7 +134,7 @@ AllowDShowSound=0
|
||||
|
||||
;Set to 1 to override the music path used by default (i.e. data\sound\music\) if not present in the cfg
|
||||
;Set to 2 to overwrite all occurances of the music path
|
||||
OverrideMusicDir=2
|
||||
OverrideMusicDir=1
|
||||
|
||||
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
|
||||
[Input]
|
||||
@@ -193,7 +193,7 @@ SpeedKey9=0x00
|
||||
;Set to -1 for either ctrl key, -2 for either alt key or -3 for either shift key
|
||||
WindowScrollKey=0
|
||||
|
||||
;A key to press to reload your currently equipped weapon
|
||||
;A key to press to reload your currently equipped weapon or use the active item
|
||||
;Set to 0 if you don't want a reload key, or a DX scancode otherwise
|
||||
ReloadWeaponKey=0
|
||||
|
||||
@@ -361,7 +361,7 @@ SingleCore=1
|
||||
OverrideArtCacheSize=0
|
||||
|
||||
;Prevents you from saving in combat except at the start of your turn to avoid a few bugs
|
||||
;Note that even with this option enabled, it is still not advisable to save in combat at all.
|
||||
;Note that even with this option enabled, it is still not advisable to save in combat at all (obsolete information)
|
||||
;Set to 2 to block all saving in combat
|
||||
SaveInCombatFix=1
|
||||
|
||||
@@ -411,7 +411,7 @@ CorpseDeleteTime=6
|
||||
;Set a number of milliseconds to idle each input loop
|
||||
;Set to -1 to disable
|
||||
;Set to 0 to idle only if other processes are waiting for processor time (WinXP/2000: if processes have equal priority)
|
||||
;Set to 1 (or some higher number if needed, the maximum is 127) to prevent 100% CPU use
|
||||
;Set to 1 (or some higher number if needed) to prevent 100% CPU use. The maximum is 127
|
||||
ProcessorIdle=-1
|
||||
|
||||
;Set to 1 if using the hero appearance mod
|
||||
@@ -715,7 +715,7 @@ PartyMemberExtraInfo=0
|
||||
;that overrides First Aid/Doctor functions has very limited usefulness
|
||||
PartyMemberSkillFix=0
|
||||
|
||||
;Set to 1 to skip loading all game settings except the game/combat difficulty from a saved game
|
||||
;Set to 1 to skip loading all game settings except the game/combat difficulty from saved games
|
||||
;Set to 2 to also skip loading the game/combat difficulty settings
|
||||
SkipLoadingGameSettings=0
|
||||
|
||||
|
||||
@@ -266,6 +266,12 @@
|
||||
#define ADD_PERK_MODE_PERK (2) // add to the player's perks
|
||||
#define ADD_PERK_MODE_REMOVE (4) // remove from the list of selectable perks (after added to the player)
|
||||
|
||||
// instantly apply the item to dude_obj (w/o animation)
|
||||
#define use_item_on_dude(item) set_self(dude_obj); \
|
||||
set_self(dude_obj); \
|
||||
use_obj_on_obj(item, dude_obj); \
|
||||
set_self(0)
|
||||
|
||||
// sfall_funcX macros
|
||||
#define add_extra_msg_file(name) sfall_func1("add_extra_msg_file", name)
|
||||
#define add_global_timer_event(time, fixedParam) sfall_func2("add_g_timer_event", time, fixedParam)
|
||||
|
||||
@@ -10,7 +10,6 @@ namespace sfall
|
||||
std::multimap<long, long> writeAddress;
|
||||
|
||||
static std::vector<long> excludeAddr = {
|
||||
0x42A14F, 0x42A178,
|
||||
0x44E949, 0x44E94A, 0x44E937, 0x4F5F40, 0x4CB850, // from movies.cpp
|
||||
};
|
||||
|
||||
|
||||
@@ -166,7 +166,7 @@ void ToggleNpcFlag(fo::GameObject* npc, long flag, bool set) {
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the number of party members in the existing table (begins from 1)
|
||||
// Returns the position of party member in the existing table (begins from 1)
|
||||
long IsPartyMemberByPid(long pid) {
|
||||
size_t patryCount = fo::var::partyMemberMaxCount;
|
||||
if (patryCount) {
|
||||
@@ -178,6 +178,7 @@ long IsPartyMemberByPid(long pid) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Returns True if the NPC belongs to the player's potential (set in party.txt) party members (analog of broken isPotentialPartyMember_)
|
||||
bool IsPartyMember(fo::GameObject* critter) {
|
||||
if (critter->id < PLAYER_ID) return false;
|
||||
return (IsPartyMemberByPid(critter->protoId) > 0);
|
||||
@@ -251,7 +252,7 @@ fo::Window* GetWindow(long winType) {
|
||||
}
|
||||
|
||||
// Returns an array of objects within the specified radius from the source tile
|
||||
void GetObjectsTileRadius(std::vector<fo::GameObject*> &objs, long sourceTile, long radius, long elev, long type = -1) {
|
||||
void GetObjectsTileRadius(std::vector<fo::GameObject*> &objs, long sourceTile, long radius, long elev, long type) {
|
||||
for (long tile = 0; tile < 40000; tile++) {
|
||||
fo::GameObject* obj = fo::func::obj_find_first_at_tile(elev, tile);
|
||||
while (obj) {
|
||||
|
||||
@@ -72,9 +72,10 @@ long __fastcall IsRadInfluence();
|
||||
|
||||
void ToggleNpcFlag(fo::GameObject* npc, long flag, bool set);
|
||||
|
||||
// Returns the number of party members in the existing table (begins from 1)
|
||||
// Returns the position of party member in the existing table (begins from 1)
|
||||
long IsPartyMemberByPid(long pid);
|
||||
|
||||
// Returns True if the NPC belongs to the player's potential (set in party.txt) party members (analog of broken isPotentialPartyMember_)
|
||||
bool IsPartyMember(fo::GameObject* critter);
|
||||
|
||||
// Returns the number of local variables of the object script
|
||||
@@ -84,7 +85,7 @@ long __fastcall GetTopWindowID(long xPos, long yPos);
|
||||
|
||||
fo::Window* GetWindow(long winType);
|
||||
|
||||
void GetObjectsTileRadius(std::vector<fo::GameObject*> &objs, long sourceTile, long radius, long elev, long type);
|
||||
void GetObjectsTileRadius(std::vector<fo::GameObject*> &objs, long sourceTile, long radius, long elev, long type = -1);
|
||||
|
||||
long wmGetCurrentTerrainType();
|
||||
|
||||
|
||||
@@ -90,6 +90,15 @@ enum Animation : long
|
||||
ANIM_called_shot_pic = 64,
|
||||
};
|
||||
|
||||
enum AnimCommand : long
|
||||
{
|
||||
RB_UNRESERVED = 0x1,
|
||||
RB_RESERVED = 0x2,
|
||||
RB_DONTSTAND = 0x4,
|
||||
RB_UNKNOWN = 0x100,
|
||||
RB_END_ANIM = 0x200
|
||||
};
|
||||
|
||||
enum CritterFlags : long
|
||||
{
|
||||
Sneak = 0x01, // Can sneak ?
|
||||
@@ -244,7 +253,7 @@ enum ArtType : char
|
||||
// Some FO2 PIDs possibly used by engine
|
||||
enum ProtoId : long
|
||||
{
|
||||
PID_ROCK = 19,
|
||||
// PID_ROCK = 19,
|
||||
PID_SMALL_ENERGY_CELL = 38,
|
||||
PID_MICRO_FUSION_CELL = 39,
|
||||
PID_STIMPAK = 40,
|
||||
@@ -256,8 +265,8 @@ enum ProtoId : long
|
||||
PID_GEIGER_COUNTER = 52,
|
||||
PID_MENTATS = 53,
|
||||
PID_STEALTH_BOY = 54,
|
||||
PID_WATER_CHIP = 55,
|
||||
PID_HOLODISK = 58,
|
||||
// PID_WATER_CHIP = 55,
|
||||
// PID_HOLODISK = 58,
|
||||
PID_MOTION_SENSOR = 59,
|
||||
PID_MUTATED_FRUIT = 71,
|
||||
PID_BIG_BOOK_OF_SCIENCE = 73,
|
||||
@@ -268,7 +277,7 @@ enum ProtoId : long
|
||||
PID_SCOUT_HANDBOOK = 86,
|
||||
PID_BUFFOUT = 87,
|
||||
PID_DOCTORS_BAG = 91,
|
||||
PID_PUMP_PARTS = 98,
|
||||
// PID_PUMP_PARTS = 98,
|
||||
PID_GUNS_AND_BULLETS = 102,
|
||||
PID_NUKA_COLA = 106,
|
||||
PID_RAD_X = 109,
|
||||
@@ -287,7 +296,7 @@ enum ProtoId : long
|
||||
PID_JET = 259,
|
||||
PID_JET_ANTIDOTE = 260,
|
||||
PID_DECK_OF_TRAGIC_CARDS = 306,
|
||||
PID_GECK = 366,
|
||||
// PID_GECK = 366,
|
||||
PID_SOLAR_SCORCHER = 390,
|
||||
PID_CAR_TRUNK = 455,
|
||||
PID_JESSE_CONTAINER = 467,
|
||||
|
||||
@@ -21,12 +21,12 @@
|
||||
/*
|
||||
* HOW TO USE ENGINE FUNCTIONS:
|
||||
*
|
||||
* in ASM code, call offsets directly, don't call wrappers as they might not be _stdcall
|
||||
* in ASM code, call offsets directly, don't call wrappers as they might not be __stdcall
|
||||
* in C++ code, use wrappers (add new ones if the don't exist yet, see Wrappers_def.h)
|
||||
*
|
||||
* Note: USE C++!
|
||||
* 1) Place thin __declspec(naked) hooks, only use minimum ASM to pass values to/from C++
|
||||
* 2) Call _stdcall functions from (1), write those entirely in C++ (with little ASM blocks only to call engine functions, when you are too lazy to add wrapper)
|
||||
* 2) Call __stdcall functions from (1), write those entirely in C++ (with little ASM blocks only to call engine functions, when you are too lazy to add wrapper)
|
||||
*/
|
||||
|
||||
namespace fo
|
||||
|
||||
@@ -202,7 +202,7 @@ const char* __stdcall findCurrentProc(Program* program) {
|
||||
WRAP_WATCOM_CALL1(findCurrentProc_, program)
|
||||
}
|
||||
|
||||
const char* _stdcall getmsg(const MessageList* fileAddr, MessageNode* result, long messageId) {
|
||||
const char* __stdcall getmsg(const MessageList* fileAddr, MessageNode* result, long messageId) {
|
||||
WRAP_WATCOM_CALL3(getmsg_, fileAddr, result, messageId)
|
||||
}
|
||||
|
||||
@@ -273,7 +273,7 @@ void __declspec(naked) interpretError(const char* fmt, ...) {
|
||||
__asm jmp fo::funcoffs::interpretError_
|
||||
}
|
||||
|
||||
long _stdcall isPartyMember(GameObject* obj) {
|
||||
long __stdcall isPartyMember(GameObject* obj) {
|
||||
WRAP_WATCOM_CALL1(isPartyMember_, obj)
|
||||
}
|
||||
|
||||
@@ -358,11 +358,11 @@ GameObject* __stdcall obj_find_next_at_tile() {
|
||||
WRAP_WATCOM_CALL0(obj_find_next_at_tile_)
|
||||
}
|
||||
|
||||
long _stdcall partyMemberGetCurLevel(GameObject* obj) {
|
||||
long __stdcall partyMemberGetCurLevel(GameObject* obj) {
|
||||
WRAP_WATCOM_CALL1(partyMemberGetCurLevel_, obj)
|
||||
}
|
||||
|
||||
long _stdcall perk_level(GameObject* critter, long perkId) {
|
||||
long __stdcall perk_level(GameObject* critter, long perkId) {
|
||||
WRAP_WATCOM_CALL2(perk_level_, critter, perkId)
|
||||
}
|
||||
|
||||
|
||||
@@ -99,12 +99,12 @@ void executeProcedure(Program* sptr, long procNum);
|
||||
|
||||
long __stdcall get_input();
|
||||
|
||||
long _stdcall isPartyMember(GameObject* obj);
|
||||
long __stdcall isPartyMember(GameObject* obj);
|
||||
|
||||
long __stdcall item_get_type(GameObject* item);
|
||||
|
||||
// searches for message ID in given message file and places result in @result
|
||||
const char* _stdcall getmsg(const MessageList* fileAddr, MessageNode* result, long messageId);
|
||||
const char* __stdcall getmsg(const MessageList* fileAddr, MessageNode* result, long messageId);
|
||||
|
||||
// plays SFX sound with given name
|
||||
void __stdcall gsound_play_sfx_file(const char* name);
|
||||
@@ -173,9 +173,9 @@ GameObject* __stdcall obj_find_first_at_tile(long elevation, long tileNum);
|
||||
|
||||
GameObject* __stdcall obj_find_next_at_tile();
|
||||
|
||||
long _stdcall partyMemberGetCurLevel(GameObject* obj);
|
||||
long __stdcall partyMemberGetCurLevel(GameObject* obj);
|
||||
|
||||
long _stdcall perk_level(GameObject* critter, long perkId);
|
||||
long __stdcall perk_level(GameObject* critter, long perkId);
|
||||
|
||||
// places pointer to a prototype structure into ptrPtr and returns 0 on success or -1 on failure
|
||||
long proto_ptr(long pid, Proto* *ptrPtr);
|
||||
|
||||
@@ -19,12 +19,14 @@
|
||||
WRAP_WATCOM_FFUNC4(long, _word_wrap, const char*, text, int, maxWidth, DWORD*, buf, BYTE*, count)
|
||||
WRAP_WATCOM_FFUNC3(void, correctFidForRemovedItem, GameObject*, critter, GameObject*, item, long, slotFlag)
|
||||
WRAP_WATCOM_FFUNC7(long, createWindow, const char*, winName, DWORD, x, DWORD, y, DWORD, width, DWORD, height, long, color, long, flags)
|
||||
WRAP_WATCOM_FFUNC4(long, determine_to_hit, GameObject*, source, GameObject*, target, long, bodyPart, long, hitMode)
|
||||
WRAP_WATCOM_FFUNC3(void, display_inventory, long, inventoryOffset, long, visibleOffset, long, mode)
|
||||
WRAP_WATCOM_FFUNC4(void, display_target_inventory, long, inventoryOffset, long, visibleOffset, DWORD*, targetInventory, long, mode)
|
||||
WRAP_WATCOM_FFUNC3(FrmFrameData*, frame_ptr, FrmHeaderData*, frm, long, frame, long, direction)
|
||||
WRAP_WATCOM_FFUNC3(void, intface_update_items, long, animate, long, modeLeft,long, modeRight)
|
||||
WRAP_WATCOM_FFUNC3(GameObject*, inven_find_type, GameObject*, critter, long, itemType, DWORD*, buf)
|
||||
WRAP_WATCOM_FFUNC3(long, item_add_force, GameObject*, critter, GameObject*, item, long, count)
|
||||
WRAP_WATCOM_FFUNC3(long, item_w_mp_cost, GameObject*, source, long, hitMode, long, isCalled)
|
||||
WRAP_WATCOM_FFUNC7(void, make_straight_path_func, GameObject*, objFrom, DWORD, tileFrom, DWORD, tileTo, void*, rotationPtr, DWORD*, result, long, flags, void*, func)
|
||||
WRAP_WATCOM_FFUNC3(long, message_find, DWORD*, msgFile, long, msgNumber, DWORD*, outBuf)
|
||||
WRAP_WATCOM_FFUNC4(long, mouse_click_in, long, x, long, y, long, x_end, long, y_end)
|
||||
@@ -33,6 +35,8 @@ WRAP_WATCOM_FFUNC4(long, obj_move_to_tile, GameObject*, object, long, tile, long
|
||||
WRAP_WATCOM_FFUNC3(long, obj_new_sid_inst, GameObject*, object, long, sType, long, scriptIndex)
|
||||
WRAP_WATCOM_FFUNC3(long, object_under_mouse, long, crSwitch, long, inclDude, long, elevation)
|
||||
WRAP_WATCOM_FFUNC4(void, register_object_call, long*, target, long*, source, void*, func, long, delay)
|
||||
WRAP_WATCOM_FFUNC4(long, register_object_move_to_object, GameObject*, source, GameObject*, target, long, distance, long, delay)
|
||||
WRAP_WATCOM_FFUNC4(long, register_object_run_to_object, GameObject*, source, GameObject*, target, long, distance, long, delay)
|
||||
WRAP_WATCOM_FFUNC3(long, scr_get_local_var, long, sid, long, varId, long*, value)
|
||||
WRAP_WATCOM_FFUNC3(long, scr_set_local_var, long, sid, long, varId, long, value)
|
||||
WRAP_WATCOM_FFUNC3(long, tile_num_in_direction, long, tile, long, rotation,long, distance)
|
||||
@@ -84,8 +88,10 @@ WRAP_WATCOM_FUNC2(void, intface_update_move_points, long, ap, long, freeAP)
|
||||
WRAP_WATCOM_FUNC0(void, intface_use_item)
|
||||
WRAP_WATCOM_FUNC2(long, inven_unwield, GameObject*, critter, long, slot)
|
||||
WRAP_WATCOM_FUNC0(long, is_pc_sneak_working)
|
||||
WRAP_WATCOM_FUNC2(long, is_within_perception, GameObject*, source, GameObject*, target)
|
||||
WRAP_WATCOM_FUNC1(long, item_c_curr_size, GameObject*, critter)
|
||||
WRAP_WATCOM_FUNC1(long, item_caps_total, GameObject*, object)
|
||||
WRAP_WATCOM_FUNC2(GameObject*, item_hit_with, GameObject*, critter, long, hitMode)
|
||||
WRAP_WATCOM_FUNC1(long, item_size, GameObject*, item)
|
||||
WRAP_WATCOM_FUNC1(long, item_total_cost, GameObject*, object)
|
||||
WRAP_WATCOM_FUNC1(long, item_total_weight, GameObject*, object)
|
||||
@@ -98,8 +104,10 @@ WRAP_WATCOM_FUNC1(long, item_w_dam_div, GameObject*, item)
|
||||
WRAP_WATCOM_FUNC1(long, item_w_dam_mult, GameObject*, item)
|
||||
WRAP_WATCOM_FUNC1(long, item_w_dr_adjust, GameObject*, item)
|
||||
WRAP_WATCOM_FUNC1(long, item_w_max_ammo, GameObject*, item)
|
||||
WRAP_WATCOM_FUNC2(long, item_w_range, GameObject*, critter, long, hitMode)
|
||||
WRAP_WATCOM_FUNC2(long, item_w_reload, GameObject*, weapon, GameObject*, ammo)
|
||||
WRAP_WATCOM_FUNC1(long, item_w_rounds, GameObject*, item)
|
||||
WRAP_WATCOM_FUNC2(long, item_w_subtype, GameObject*, item, long, hitMode)
|
||||
WRAP_WATCOM_FUNC1(long, item_weight, GameObject*, item)
|
||||
// returns light level at given tile
|
||||
WRAP_WATCOM_FUNC2(long, light_get_tile, long, elevation, long, tileNum)
|
||||
@@ -114,6 +122,7 @@ WRAP_WATCOM_FUNC0(long, new_obj_id)
|
||||
// calculates bounding box (rectangle) for a given object
|
||||
WRAP_WATCOM_FUNC2(void, obj_bound, GameObject*, object, BoundRect*, boundRect)
|
||||
WRAP_WATCOM_FUNC1(long, obj_destroy, GameObject*, object)
|
||||
WRAP_WATCOM_FUNC2(long, obj_dist, GameObject*, source, GameObject*, target)
|
||||
WRAP_WATCOM_FUNC2(long, obj_erase_object, GameObject*, object, BoundRect*, boundRect)
|
||||
WRAP_WATCOM_FUNC0(GameObject*, obj_find_first)
|
||||
WRAP_WATCOM_FUNC0(GameObject*, obj_find_next)
|
||||
@@ -130,6 +139,8 @@ WRAP_WATCOM_FUNC0(void, process_bk)
|
||||
WRAP_WATCOM_FUNC0(void, proto_dude_update_gender)
|
||||
WRAP_WATCOM_FUNC2(long*, queue_find_first, GameObject*, object, long, qType)
|
||||
WRAP_WATCOM_FUNC2(long*, queue_find_next, GameObject*, object, long, qType)
|
||||
WRAP_WATCOM_FUNC1(long, register_begin, long, regType)
|
||||
WRAP_WATCOM_FUNC0(long, register_end)
|
||||
WRAP_WATCOM_FUNC3(long, register_object_animate, GameObject*, object, long, anim, long, delay)
|
||||
WRAP_WATCOM_FUNC3(long, register_object_animate_and_hide, GameObject*, object, long, anim, long, delay)
|
||||
// WRAP_WATCOM_FUNC3(long, register_object_animate_and_move_straight_, GameObject*, object;
|
||||
@@ -144,13 +155,11 @@ WRAP_WATCOM_FUNC1(long, register_object_inc_rotation, GameObject*, object)
|
||||
WRAP_WATCOM_FUNC3(long, register_object_light, GameObject*, object, long, lightRadius, long, delay)
|
||||
// WRAP_WATCOM_FUNC3(long, register_object_move_on_stairs_, GameObject*, object;
|
||||
// WRAP_WATCOM_FUNC3(long, register_object_move_straight_to_tile_, GameObject*, object;
|
||||
// WRAP_WATCOM_FUNC3(long, register_object_move_to_object_, GameObject*, object;
|
||||
// WRAP_WATCOM_FUNC3(long, register_object_move_to_tile_, GameObject*, object;
|
||||
// WRAP_WATCOM_FUNC3(long, register_object_must_call_, GameObject*, object;
|
||||
WRAP_WATCOM_FUNC1(long, register_object_must_erase, GameObject*, object)
|
||||
// WRAP_WATCOM_FUNC3(long, register_object_outline_, GameObject*, object;
|
||||
// WRAP_WATCOM_FUNC3(long, register_object_play_sfx_, GameObject*, object;
|
||||
// WRAP_WATCOM_FUNC3(long, register_object_run_to_object_, GameObject*, object;
|
||||
// WRAP_WATCOM_FUNC3(long, register_object_run_to_tile_, GameObject*, object;
|
||||
WRAP_WATCOM_FUNC3(long, register_object_take_out, GameObject*, object, long, holdFrameId, long, nothing)
|
||||
WRAP_WATCOM_FUNC3(long, register_object_turn_towards, GameObject*, object, long, tileNum, long, nothing)
|
||||
|
||||
@@ -373,6 +373,7 @@ struct UnlistedFrm {
|
||||
}
|
||||
};
|
||||
|
||||
//for holding a message
|
||||
#pragma pack(1)
|
||||
struct MessageNode {
|
||||
long number;
|
||||
@@ -424,8 +425,7 @@ struct CritInfo {
|
||||
};
|
||||
|
||||
#pragma pack(1)
|
||||
struct SkillInfo
|
||||
{
|
||||
struct SkillInfo {
|
||||
const char* name;
|
||||
const char* description;
|
||||
long attr;
|
||||
|
||||
@@ -277,6 +277,8 @@
|
||||
#define FO_VAR_DARK_GREY_Color 0x6A59D8
|
||||
#define FO_VAR_DarkGreenColor 0x6A3A90
|
||||
#define FO_VAR_DarkGreenGreyColor 0x6A3DF1
|
||||
#define FO_VAR_DarkRedColor 0x6AA8D0
|
||||
#define FO_VAR_DarkYellowColor 0x6AB472
|
||||
#define FO_VAR_DullPinkColor 0x6AB718
|
||||
#define FO_VAR_GoodColor 0x6AB4EF
|
||||
#define FO_VAR_GreenColor 0x6A3CB0
|
||||
@@ -285,4 +287,4 @@
|
||||
#define FO_VAR_PeanutButter 0x6A82F3
|
||||
#define FO_VAR_RedColor 0x6AB4D0
|
||||
#define FO_VAR_WhiteColor 0x6AB8CF
|
||||
#define FO_VAR_YellowColor 0x6AB8BB
|
||||
#define FO_VAR_YellowColor 0x6AB8BB // Light
|
||||
|
||||
+32
-31
@@ -17,6 +17,7 @@
|
||||
*/
|
||||
|
||||
#define DIRECTINPUT_VERSION 0x0700
|
||||
|
||||
#include <math.h>
|
||||
#include <dinput.h>
|
||||
#include <queue>
|
||||
@@ -56,7 +57,7 @@ static int mouseY;
|
||||
|
||||
static DWORD forcingGraphicsRefresh = 0;
|
||||
|
||||
void _stdcall ForceGraphicsRefresh(DWORD d) {
|
||||
void __stdcall ForceGraphicsRefresh(DWORD d) {
|
||||
forcingGraphicsRefresh = (d == 0) ? 0 : 1;
|
||||
}
|
||||
|
||||
@@ -107,7 +108,7 @@ void FlushInputBuffer() {
|
||||
__asm call fo::funcoffs::kb_clear_;
|
||||
}
|
||||
|
||||
DWORD _stdcall KeyDown(DWORD key) {
|
||||
DWORD __stdcall KeyDown(DWORD key) {
|
||||
if ((key & 0x80000000) > 0) { // special flag to check by VK code directly
|
||||
return GetAsyncKeyState(key & 0xFFFF) & 0x8000;
|
||||
}
|
||||
@@ -125,7 +126,7 @@ DWORD _stdcall KeyDown(DWORD key) {
|
||||
}
|
||||
}
|
||||
|
||||
void _stdcall TapKey(DWORD key) {
|
||||
void __stdcall TapKey(DWORD key) {
|
||||
DIDEVICEOBJECTDATA data;
|
||||
data.dwTimeStamp = 0;
|
||||
data.dwSequence = 0;
|
||||
@@ -155,15 +156,15 @@ public:
|
||||
}
|
||||
|
||||
/*** IUnknown methods ***/
|
||||
HRESULT _stdcall QueryInterface(REFIID riid, LPVOID * ppvObj) {
|
||||
HRESULT __stdcall QueryInterface(REFIID riid, LPVOID * ppvObj) {
|
||||
return RealDevice->QueryInterface(riid, ppvObj);
|
||||
}
|
||||
|
||||
ULONG _stdcall AddRef(void) {
|
||||
ULONG __stdcall AddRef(void) {
|
||||
return ++Refs;
|
||||
}
|
||||
|
||||
ULONG _stdcall Release(void) {
|
||||
ULONG __stdcall Release(void) {
|
||||
if (--Refs == 0) {
|
||||
RealDevice->Release();
|
||||
delete this;
|
||||
@@ -174,32 +175,32 @@ public:
|
||||
}
|
||||
|
||||
/*** IDirectInputDevice8A methods ***/
|
||||
HRESULT _stdcall GetCapabilities(LPDIDEVCAPS a) {
|
||||
HRESULT __stdcall GetCapabilities(LPDIDEVCAPS a) {
|
||||
return RealDevice->GetCapabilities(a);
|
||||
}
|
||||
|
||||
HRESULT _stdcall EnumObjects(LPDIENUMDEVICEOBJECTSCALLBACKA a, LPVOID b, DWORD c) {
|
||||
HRESULT __stdcall EnumObjects(LPDIENUMDEVICEOBJECTSCALLBACKA a, LPVOID b, DWORD c) {
|
||||
return RealDevice->EnumObjects(a, b, c);
|
||||
}
|
||||
|
||||
HRESULT _stdcall GetProperty(REFGUID a, DIPROPHEADER* b) {
|
||||
HRESULT __stdcall GetProperty(REFGUID a, DIPROPHEADER* b) {
|
||||
return RealDevice->GetProperty(a, b);
|
||||
}
|
||||
|
||||
HRESULT _stdcall SetProperty(REFGUID a, const DIPROPHEADER* b) {
|
||||
HRESULT __stdcall SetProperty(REFGUID a, const DIPROPHEADER* b) {
|
||||
return RealDevice->SetProperty(a, b);
|
||||
}
|
||||
|
||||
HRESULT _stdcall Acquire(void) {
|
||||
HRESULT __stdcall Acquire(void) {
|
||||
return RealDevice->Acquire();
|
||||
}
|
||||
|
||||
HRESULT _stdcall Unacquire(void) {
|
||||
HRESULT __stdcall Unacquire(void) {
|
||||
return RealDevice->Unacquire();
|
||||
}
|
||||
|
||||
// Only called for the mouse
|
||||
HRESULT _stdcall GetDeviceState(DWORD a, LPVOID b) {
|
||||
HRESULT __stdcall GetDeviceState(DWORD a, LPVOID b) {
|
||||
if (forcingGraphicsRefresh) RefreshGraphics();
|
||||
if (DeviceType != kDeviceType_MOUSE) {
|
||||
return RealDevice->GetDeviceState(a, b);
|
||||
@@ -269,7 +270,7 @@ public:
|
||||
}
|
||||
|
||||
// Only called for the keyboard (dxinput_read_keyboard_buffer_ called at 0x4E06AB)
|
||||
HRESULT _stdcall GetDeviceData(DWORD a, DIDEVICEOBJECTDATA* buf, DWORD* count, DWORD d) { // buf - DirectInputKeyboardBuffer (0x6B2560)
|
||||
HRESULT __stdcall GetDeviceData(DWORD a, DIDEVICEOBJECTDATA* buf, DWORD* count, DWORD d) { // buf - DirectInputKeyboardBuffer (0x6B2560)
|
||||
if (DeviceType != kDeviceType_KEYBOARD) {
|
||||
return RealDevice->GetDeviceData(a, buf, count, d);
|
||||
}
|
||||
@@ -304,35 +305,35 @@ public:
|
||||
return DI_OK;
|
||||
}
|
||||
|
||||
HRESULT _stdcall SetDataFormat(const DIDATAFORMAT* a) {
|
||||
HRESULT __stdcall SetDataFormat(const DIDATAFORMAT* a) {
|
||||
if (formatLock && oldFormat.dwSize) return RealDevice->SetDataFormat(&oldFormat);
|
||||
memcpy(&oldFormat, a, sizeof(DIDATAFORMAT));
|
||||
return RealDevice->SetDataFormat(a);
|
||||
}
|
||||
|
||||
HRESULT _stdcall SetEventNotification(HANDLE a) {
|
||||
HRESULT __stdcall SetEventNotification(HANDLE a) {
|
||||
return RealDevice->SetEventNotification(a);
|
||||
}
|
||||
|
||||
HRESULT _stdcall SetCooperativeLevel(HWND a, DWORD b) {
|
||||
HRESULT __stdcall SetCooperativeLevel(HWND a, DWORD b) {
|
||||
if (DeviceType == kDeviceType_KEYBOARD && backgroundKeyboard) b = DISCL_BACKGROUND | DISCL_NONEXCLUSIVE;
|
||||
if (DeviceType == kDeviceType_MOUSE && backgroundMouse) b = DISCL_BACKGROUND | DISCL_NONEXCLUSIVE;
|
||||
return RealDevice->SetCooperativeLevel(a, b);
|
||||
}
|
||||
|
||||
HRESULT _stdcall GetObjectInfo(LPDIDEVICEOBJECTINSTANCEA a, DWORD b, DWORD c) {
|
||||
HRESULT __stdcall GetObjectInfo(LPDIDEVICEOBJECTINSTANCEA a, DWORD b, DWORD c) {
|
||||
return RealDevice->GetObjectInfo(a, b, c);
|
||||
}
|
||||
|
||||
HRESULT _stdcall GetDeviceInfo(LPDIDEVICEINSTANCEA a) {
|
||||
HRESULT __stdcall GetDeviceInfo(LPDIDEVICEINSTANCEA a) {
|
||||
return RealDevice->GetDeviceInfo(a);
|
||||
}
|
||||
|
||||
HRESULT _stdcall RunControlPanel(HWND a, DWORD b) {
|
||||
HRESULT __stdcall RunControlPanel(HWND a, DWORD b) {
|
||||
return RealDevice->RunControlPanel(a, b);
|
||||
}
|
||||
|
||||
HRESULT _stdcall Initialize(HINSTANCE a, DWORD b, REFGUID c) {
|
||||
HRESULT __stdcall Initialize(HINSTANCE a, DWORD b, REFGUID c) {
|
||||
return RealDevice->Initialize(a, b, c);
|
||||
}
|
||||
|
||||
@@ -352,15 +353,15 @@ public:
|
||||
}
|
||||
|
||||
/*** IUnknown methods ***/
|
||||
HRESULT _stdcall QueryInterface(REFIID riid, LPVOID* ppvObj) {
|
||||
HRESULT __stdcall QueryInterface(REFIID riid, LPVOID* ppvObj) {
|
||||
return RealInput->QueryInterface(riid, ppvObj);
|
||||
}
|
||||
|
||||
ULONG _stdcall AddRef(void) {
|
||||
ULONG __stdcall AddRef(void) {
|
||||
return ++Refs;
|
||||
}
|
||||
|
||||
ULONG _stdcall Release(void) {
|
||||
ULONG __stdcall Release(void) {
|
||||
if (--Refs == 0) {
|
||||
RealInput->Release();
|
||||
delete this;
|
||||
@@ -371,7 +372,7 @@ public:
|
||||
}
|
||||
|
||||
/*** IDirectInput8A methods ***/
|
||||
HRESULT _stdcall CreateDevice(REFGUID r, IDirectInputDeviceA** device, IUnknown* unused) {
|
||||
HRESULT __stdcall CreateDevice(REFGUID r, IDirectInputDeviceA** device, IUnknown* unused) {
|
||||
GUID GUID_SysMouse = { 0x6F1D2B60, 0xD5A0, 0x11CF, { 0xBF, 0xC7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00} };
|
||||
GUID GUID_SysKeyboard = { 0x6F1D2B61, 0xD5A0, 0x11CF, { 0xBF, 0xC7, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00} };
|
||||
|
||||
@@ -398,19 +399,19 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT _stdcall EnumDevices(DWORD a, LPDIENUMDEVICESCALLBACKA b, void* c, DWORD d) {
|
||||
HRESULT __stdcall EnumDevices(DWORD a, LPDIENUMDEVICESCALLBACKA b, void* c, DWORD d) {
|
||||
return RealInput->EnumDevices(a, b, c, d);
|
||||
}
|
||||
|
||||
HRESULT _stdcall GetDeviceStatus(REFGUID r) {
|
||||
HRESULT __stdcall GetDeviceStatus(REFGUID r) {
|
||||
return RealInput->GetDeviceStatus(r);
|
||||
}
|
||||
|
||||
HRESULT _stdcall RunControlPanel(HWND a, DWORD b) {
|
||||
HRESULT __stdcall RunControlPanel(HWND a, DWORD b) {
|
||||
return RealInput->RunControlPanel(a, b);
|
||||
}
|
||||
|
||||
HRESULT _stdcall Initialize(HINSTANCE a, DWORD b) {
|
||||
HRESULT __stdcall Initialize(HINSTANCE a, DWORD b) {
|
||||
return RealInput->Initialize(a, b);
|
||||
}
|
||||
};
|
||||
@@ -439,10 +440,10 @@ inline void InitInputFeatures() {
|
||||
|
||||
}
|
||||
|
||||
typedef HRESULT (_stdcall *DInputCreateProc)(HINSTANCE a,DWORD b,IDirectInputA** c,IUnknown* d);
|
||||
typedef HRESULT (__stdcall *DInputCreateProc)(HINSTANCE a,DWORD b,IDirectInputA** c,IUnknown* d);
|
||||
|
||||
// This should be in global namespace
|
||||
HRESULT _stdcall FakeDirectInputCreate(HINSTANCE a, DWORD b, IDirectInputA** c, IUnknown* d) {
|
||||
HRESULT __stdcall FakeDirectInputCreate(HINSTANCE a, DWORD b, IDirectInputA** c, IUnknown* d) {
|
||||
HMODULE dinput = LoadLibraryA("dinput.dll");
|
||||
if (!dinput || dinput == INVALID_HANDLE_VALUE) return -1;
|
||||
DInputCreateProc proc = (DInputCreateProc)GetProcAddress(dinput, "DirectInputCreateA");
|
||||
|
||||
+3
-3
@@ -32,8 +32,8 @@ void SetMDown(bool down, bool right);
|
||||
void SetMPos(int x, int y);
|
||||
|
||||
void FlushInputBuffer();
|
||||
DWORD _stdcall KeyDown(DWORD key);
|
||||
void _stdcall TapKey(DWORD key);
|
||||
DWORD __stdcall KeyDown(DWORD key);
|
||||
void __stdcall TapKey(DWORD key);
|
||||
|
||||
typedef Delegate<DWORD, bool> KeyPressedDelegate;
|
||||
typedef Delegate<DWORD, bool> MouseClickedDelegate;
|
||||
@@ -44,7 +44,7 @@ Delegate<>& OnInputLoop();
|
||||
|
||||
void GetMouse(int* x, int* y);
|
||||
|
||||
void _stdcall ForceGraphicsRefresh(DWORD);
|
||||
void __stdcall ForceGraphicsRefresh(DWORD);
|
||||
|
||||
#define DIK_ESCAPE 0x01
|
||||
#define DIK_1 0x02
|
||||
|
||||
@@ -11,13 +11,13 @@ ModuleManager::ModuleManager() {
|
||||
}
|
||||
|
||||
ModuleManager::~ModuleManager() {
|
||||
for (auto it = _modules.cbegin(); it != _modules.cend(); it++) {
|
||||
for (auto it = _modules.cbegin(); it != _modules.cend(); ++it) {
|
||||
(*it)->exit();
|
||||
}
|
||||
}
|
||||
|
||||
void ModuleManager::initAll() {
|
||||
for (auto it = _modules.cbegin(); it != _modules.cend(); it++) {
|
||||
for (auto it = _modules.cbegin(); it != _modules.cend(); ++it) {
|
||||
dlog_f("Initializing module %s...\n", DL_INIT, (*it)->name());
|
||||
(*it)->init();
|
||||
}
|
||||
|
||||
+180
-8
@@ -21,6 +21,8 @@
|
||||
#include "..\main.h"
|
||||
#include "..\FalloutEngine\Fallout2.h"
|
||||
|
||||
#include "HookScripts\CombatHS.h"
|
||||
|
||||
#include "AI.h"
|
||||
|
||||
namespace sfall
|
||||
@@ -32,6 +34,24 @@ using namespace Fields;
|
||||
static std::unordered_map<fo::GameObject*, fo::GameObject*> targets;
|
||||
static std::unordered_map<fo::GameObject*, fo::GameObject*> sources;
|
||||
|
||||
fo::GameObject* AI::sf_check_critters_in_lof(fo::GameObject* object, DWORD checkTile, DWORD team) {
|
||||
if (object && object->Type() == ObjType::OBJ_TYPE_CRITTER && object->critter.teamNum != team) { // not friendly fire
|
||||
if (object->tile == checkTile) return nullptr;
|
||||
fo::GameObject* obj = nullptr; // continue checking the line of fire from object to checkTile
|
||||
fo::func::make_straight_path_func(object, object->tile, checkTile, 0, (DWORD*)&obj, 32, (void*)fo::funcoffs::obj_shoot_blocking_at_);
|
||||
if (!sf_check_critters_in_lof(obj, checkTile, team)) return nullptr;
|
||||
}
|
||||
return object;
|
||||
}
|
||||
|
||||
// Returns the friendly critter that is in the line of fire
|
||||
fo::GameObject* AI::CheckFriendlyFire(fo::GameObject* target, fo::GameObject* attacker) {
|
||||
fo::GameObject* object = nullptr;
|
||||
fo::func::make_straight_path_func(attacker, attacker->tile, target->tile, 0, (DWORD*)&object, 32, (void*)fo::funcoffs::obj_shoot_blocking_at_);
|
||||
object = sf_check_critters_in_lof(object, target->tile, attacker->critter.teamNum);
|
||||
return (!object || object->TypeFid() == fo::ObjType::OBJ_TYPE_CRITTER) ? object : nullptr; // 0 if there are no friendly critters
|
||||
}
|
||||
|
||||
static void __declspec(naked) ai_try_attack_hook_FleeFix() {
|
||||
__asm {
|
||||
or byte ptr [esi + combatState], 8; // set new 'ReTarget' flag
|
||||
@@ -40,7 +60,7 @@ static void __declspec(naked) ai_try_attack_hook_FleeFix() {
|
||||
}
|
||||
|
||||
static void __declspec(naked) combat_ai_hook_FleeFix() {
|
||||
static const DWORD combat_ai_hook_flee_Ret = 0x42B22F;
|
||||
static const DWORD combat_ai_hook_flee_Ret = 0x42B206;
|
||||
__asm {
|
||||
test byte ptr [ebp], 8; // 'ReTarget' flag (critter.combat_state)
|
||||
jnz reTarget;
|
||||
@@ -152,7 +172,23 @@ skip:
|
||||
}
|
||||
}
|
||||
|
||||
static DWORD RetryCombatMinAP;
|
||||
static void __declspec(naked) ai_danger_source_hack_pm_newfind() {
|
||||
__asm {
|
||||
mov ecx, [ebp + 0x18]; // source combat_data.who_hit_me
|
||||
test ecx, ecx;
|
||||
jnz hasTarget;
|
||||
retn;
|
||||
hasTarget:
|
||||
test [ecx + damageFlags], DAM_DEAD;
|
||||
jz isNotDead;
|
||||
xor ecx, ecx;
|
||||
isNotDead:
|
||||
mov dword ptr [ebp + 0x18], 0; // combat_data.who_hit_me (engine code)
|
||||
retn;
|
||||
}
|
||||
}
|
||||
|
||||
static long RetryCombatMinAP;
|
||||
|
||||
static void __declspec(naked) RetryCombatHook() {
|
||||
static DWORD RetryCombatLastAP = 0;
|
||||
@@ -189,7 +225,7 @@ static long __fastcall sf_ai_weapon_reload(fo::GameObject* weapon, fo::GameObjec
|
||||
|
||||
while (ammo) {
|
||||
result = fo::func::item_w_reload(weapon, ammo);
|
||||
if (result != 0) break; // 1 - reload done, -1 - can't reload
|
||||
if (result != 0) return result; // 1 - reload done, -1 - can't reload
|
||||
|
||||
if (!proto) {
|
||||
proto = fo::GetProto(weapon->protoId);
|
||||
@@ -209,7 +245,7 @@ static long __fastcall sf_ai_weapon_reload(fo::GameObject* weapon, fo::GameObjec
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!result && _ammo != ammo) {
|
||||
if (_ammo != ammo) {
|
||||
fo::func::obj_destroy(ammo);
|
||||
return 1; // notifies the engine that the ammo has already been destroyed
|
||||
}
|
||||
@@ -231,6 +267,112 @@ skip:
|
||||
}
|
||||
}
|
||||
|
||||
static long __fastcall CheckWeaponRangeAndApCost(fo::GameObject* source, fo::GameObject* target) {
|
||||
long weaponRange = fo::func::item_w_range(source, fo::ATKTYPE_RWEAPON_SECONDARY);
|
||||
long targetDist = fo::func::obj_dist(source, target);
|
||||
if (targetDist > weaponRange) return 0; // don't use secondary mode
|
||||
|
||||
return (source->critter.movePoints >= sf_item_w_mp_cost(source, fo::ATKTYPE_RWEAPON_SECONDARY, 0)); // 1 - allow secondary mode
|
||||
}
|
||||
|
||||
static void __declspec(naked) ai_pick_hit_mode_hook() {
|
||||
__asm {
|
||||
call fo::funcoffs::caiHasWeapPrefType_;
|
||||
test eax, eax;
|
||||
jnz evaluation;
|
||||
retn;
|
||||
evaluation:
|
||||
mov edx, edi;
|
||||
mov ecx, esi;
|
||||
jmp CheckWeaponRangeAndApCost;
|
||||
}
|
||||
}
|
||||
|
||||
static void __declspec(naked) ai_danger_source_hook() {
|
||||
__asm {
|
||||
call fo::funcoffs::combat_check_bad_shot_;
|
||||
cmp dword ptr [esp + 56], 0x42B235 + 5; // called from combat_ai_
|
||||
je fix;
|
||||
retn;
|
||||
fix: // check result
|
||||
cmp eax, 1; // exception: 1 - no ammo
|
||||
setg al; // set 0 for result OK
|
||||
retn;
|
||||
}
|
||||
}
|
||||
|
||||
static void __declspec(naked) cai_perform_distance_prefs_hack() {
|
||||
__asm {
|
||||
mov ebx, eax; // current distance to target
|
||||
mov ecx, esi;
|
||||
push 0; // no called shot
|
||||
mov edx, ATKTYPE_RWEAPON_PRIMARY;
|
||||
call sf_item_w_mp_cost;
|
||||
mov edx, [esi + movePoints];
|
||||
sub edx, eax; // ap - cost = free AP's
|
||||
jle moveAway; // <= 0
|
||||
lea edx, [edx + ebx - 1];
|
||||
cmp edx, 5; // minimum threshold distance
|
||||
jge skipMove; // distance >= 5?
|
||||
// check combat rating
|
||||
mov eax, esi;
|
||||
call fo::funcoffs::combatai_rating_;
|
||||
mov edx, eax; // source rating
|
||||
mov eax, edi;
|
||||
call fo::funcoffs::combatai_rating_;
|
||||
cmp eax, edx; // target vs source rating
|
||||
jl skipMove; // target rating is low
|
||||
moveAway:
|
||||
mov ebx, 10; // move away max distance
|
||||
retn;
|
||||
skipMove:
|
||||
xor ebx, ebx; // skip moving away at the beginning of the turn
|
||||
retn;
|
||||
}
|
||||
}
|
||||
|
||||
static void __declspec(naked) ai_move_away_hook() {
|
||||
static const DWORD ai_move_away_hook_Ret = 0x4289DA;
|
||||
__asm {
|
||||
test ebx, ebx;
|
||||
jl fix; // distance arg < 0
|
||||
jmp fo::funcoffs::ai_cap_;
|
||||
fix:
|
||||
neg ebx;
|
||||
mov eax, [esi + movePoints]; // Current Action Points
|
||||
cmp ebx, eax;
|
||||
cmovg ebx, eax; // if (distance > ap) dist = ap
|
||||
add esp, 4;
|
||||
jmp ai_move_away_hook_Ret;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static long __fastcall RollFriendlyFire(fo::GameObject* target, fo::GameObject* attacker) {
|
||||
if (AI::CheckFriendlyFire(target, attacker)) {
|
||||
long dice = fo::func::roll_random(1, 10);
|
||||
return (fo::func::stat_level(attacker, fo::STAT_iq) >= dice); // 1 - is friendly
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void __declspec(naked) combat_safety_invalidate_weapon_func_hook_check() {
|
||||
static const DWORD safety_invalidate_weapon_burst_friendly = 0x4216C9;
|
||||
__asm {
|
||||
pushadc;
|
||||
mov ecx, esi; // target
|
||||
call RollFriendlyFire;
|
||||
test eax, eax;
|
||||
jnz friendly;
|
||||
popadc;
|
||||
jmp fo::funcoffs::combat_ctd_init_;
|
||||
friendly:
|
||||
lea esp, [esp + 8 + 3 * 4];
|
||||
jmp safety_invalidate_weapon_burst_friendly; // "Friendly was in the way!"
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static void __fastcall CombatAttackHook(fo::GameObject* source, fo::GameObject* target) {
|
||||
@@ -271,8 +413,29 @@ void AI::init() {
|
||||
0x42A970, 0x42AA56, // ai_try_attack_
|
||||
});
|
||||
|
||||
// Adds a check for the weapon range and the AP cost when AI is choosing weapon attack modes
|
||||
HookCall(0x429F6D, ai_pick_hit_mode_hook);
|
||||
|
||||
/////////////////////// Combat AI behavior fixes ///////////////////////
|
||||
|
||||
// Fix to reduce friendly fire in burst attacks
|
||||
// Adds a check/roll for friendly critters in the line of fire when AI uses burst attacks
|
||||
HookCall(0x421666, combat_safety_invalidate_weapon_func_hook_check);
|
||||
|
||||
// Fix for duplicate critters being added to the list of potential targets for AI
|
||||
MakeCall(0x428E75, ai_find_attackers_hack_target2, 2);
|
||||
MakeCall(0x428EB5, ai_find_attackers_hack_target3);
|
||||
MakeCall(0x428EE5, ai_find_attackers_hack_target4, 1);
|
||||
|
||||
#ifndef NDEBUG
|
||||
if (iniGetInt("Debugging", "AIBugFixes", 1, ::sfall::ddrawIni) == 0) return;
|
||||
#endif
|
||||
|
||||
// Tweak for finding new targets for party members
|
||||
// Save the current target in the "target1" variable and find other potential targets
|
||||
MakeCall(0x429074, ai_danger_source_hack_pm_newfind);
|
||||
SafeWrite16(0x429074 + 5, 0x47EB); // jmp 0x4290C2
|
||||
|
||||
// Fix to allow fleeing NPC to use drugs
|
||||
MakeCall(0x42B1DC, combat_ai_hack);
|
||||
// Fix for AI not checking minimum hp properly for using stimpaks (prevents premature fleeing)
|
||||
@@ -284,10 +447,19 @@ void AI::init() {
|
||||
// Disable fleeing when NPC cannot move closer to target
|
||||
BlockCall(0x42ADF6); // ai_try_attack_
|
||||
|
||||
// Fix for duplicate critters being added to the list of potential targets for AI
|
||||
MakeCall(0x428E75, ai_find_attackers_hack_target2, 2);
|
||||
MakeCall(0x428EB5, ai_find_attackers_hack_target3);
|
||||
MakeCall(0x428EE5, ai_find_attackers_hack_target4, 1);
|
||||
// Fix AI target selection for combat_check_bad_shot_ function returning a no_ammo result
|
||||
HookCalls(ai_danger_source_hook, {0x42903A, 0x42918A});
|
||||
|
||||
// Fix AI behavior for "Snipe" distance preference
|
||||
// The attacker will try to shoot the target instead of always running away from it at the beginning of the turn
|
||||
MakeCall(0x42B086, cai_perform_distance_prefs_hack);
|
||||
|
||||
// Fix for ai_move_away_ engine function not working correctly in cases when needing to move a distance away from the target
|
||||
// now the function also takes the distance argument in a negative value for moving away at a distance
|
||||
HookCall(0x4289A7, ai_move_away_hook);
|
||||
// also patch combat_safety_invalidate_weapon_func_ for returning out_range argument in a negative value
|
||||
SafeWrite8(0x421628, 0xD0); // sub edx, eax > sub eax, edx
|
||||
SafeWrite16(0x42162A, 0xFF40); // lea eax, [edx+1] > lea eax, [eax-1]
|
||||
}
|
||||
|
||||
fo::GameObject* __stdcall AI::AIGetLastAttacker(fo::GameObject* target) {
|
||||
|
||||
@@ -30,6 +30,9 @@ public:
|
||||
const char* name() { return "AI"; }
|
||||
void init();
|
||||
|
||||
static fo::GameObject* sf_check_critters_in_lof(fo::GameObject* object, DWORD checkTile, DWORD team);
|
||||
static fo::GameObject* CheckFriendlyFire(fo::GameObject* target, fo::GameObject* attacker);
|
||||
|
||||
// TODO: use subscription instead
|
||||
static void __stdcall AICombatStart();
|
||||
static void __stdcall AICombatEnd();
|
||||
|
||||
@@ -191,9 +191,9 @@ static DWORD __fastcall CheckSetSad(BYTE openFlag, DWORD valueMul) {
|
||||
return result;
|
||||
}
|
||||
|
||||
static const DWORD object_move_back0 = 0x417611;
|
||||
static const DWORD object_move_back1 = 0x417616;
|
||||
static void __declspec(naked) object_move_hack() {
|
||||
static const DWORD object_move_back0 = 0x417611;
|
||||
static const DWORD object_move_back1 = 0x417616;
|
||||
__asm {
|
||||
mov ecx, ds:[ecx + 0x3C]; // openFlag
|
||||
mov edx, [esp + 0x4C - 0x20]; // valueMul
|
||||
|
||||
@@ -61,9 +61,9 @@ static const DWORD bboxSlotAddr[] = {
|
||||
0x4616F7, 0x46170F, 0x461736, 0x4616B1, 0x46151D, 0x4615B3
|
||||
};
|
||||
|
||||
static const DWORD DisplayBoxesRet1 = 0x4615A8;
|
||||
static const DWORD DisplayBoxesRet2 = 0x4615BE;
|
||||
static void __declspec(naked) DisplayBoxesHack() {
|
||||
static const DWORD DisplayBoxesRet1 = 0x4615A8;
|
||||
static const DWORD DisplayBoxesRet2 = 0x4615BE;
|
||||
__asm {
|
||||
mov edx, [boxText];
|
||||
xor ebx, ebx;
|
||||
@@ -115,8 +115,8 @@ skip:
|
||||
}
|
||||
}
|
||||
|
||||
static const DWORD SetIndexBoxRet = 0x4612E8;
|
||||
static void __declspec(naked) BarBoxesIndexHack() {
|
||||
static const DWORD SetIndexBoxRet = 0x4612E8;
|
||||
__asm {
|
||||
mov eax, ds:[0x4612E2]; // fontnum
|
||||
mov ecx, setBoxIndex; // start index
|
||||
@@ -125,9 +125,9 @@ static void __declspec(naked) BarBoxesIndexHack() {
|
||||
}
|
||||
}
|
||||
|
||||
static const DWORD SizeLoopBoxRet = 0x461477;
|
||||
static const DWORD ExitLoopBoxRet = 0x461498;
|
||||
static void __declspec(naked) BarBoxesSizeHack() {
|
||||
static const DWORD SizeLoopBoxRet = 0x461477;
|
||||
static const DWORD ExitLoopBoxRet = 0x461498;
|
||||
__asm {
|
||||
cmp edx, sizeBox;
|
||||
jz exitLoop;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user