mirror of
https://github.com/aimrebirth/tools.git
synced 2026-04-15 01:43:25 +00:00
Improve mod library and example mod.
This commit is contained in:
parent
091dd3cbe9
commit
3d76460d56
7 changed files with 2833 additions and 144 deletions
381
examples/mods/aim1_community_fix/aim.exe.fixes.h
Normal file
381
examples/mods/aim1_community_fix/aim.exe.fixes.h
Normal file
|
|
@ -0,0 +1,381 @@
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
/*struct char20 {
|
||||||
|
char string[20];
|
||||||
|
};*/
|
||||||
|
|
||||||
|
#define _BYTE uint8_t
|
||||||
|
#define this
|
||||||
|
#define __unaligned
|
||||||
|
#include "aim.exe.h"
|
||||||
|
#undef this
|
||||||
|
#undef __unaligned
|
||||||
|
|
||||||
|
using namespace std::literals;
|
||||||
|
|
||||||
|
constexpr auto call_command_length = 5;
|
||||||
|
|
||||||
|
enum aim1_fix : uint32_t {
|
||||||
|
script_function__ISGLIDER = 0x0043A1F6,
|
||||||
|
trade_actions_weapon_checks = 0x004072FA,
|
||||||
|
setup_proper_weapon_slots_for_a_glider = 0x004D62E4,
|
||||||
|
put_weapon_into_the_right_slot_after_purchase = 0x00417A6D,
|
||||||
|
sell_correct_weapon = 0x004176BC,
|
||||||
|
empty_light_weapon_message = 0x004067C4,
|
||||||
|
empty_heavy_weapon_message = 0x0040688B,
|
||||||
|
};
|
||||||
|
uint32_t known_caller;
|
||||||
|
auto player_ptr = (Player **)0x005B7B38;
|
||||||
|
auto get_player_ptr() {
|
||||||
|
auto player_ptr2 = (Player *)0x00678FEC;
|
||||||
|
return player_ptr2;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class glider_id : uint32_t {
|
||||||
|
nargoon = 0x7,
|
||||||
|
eyedstone = 0xe,
|
||||||
|
finder1 = 0x19,
|
||||||
|
finder2 = 0x1A,
|
||||||
|
};
|
||||||
|
|
||||||
|
#define NOP1 __asm { nop }
|
||||||
|
#define NOP2 NOP1 NOP1
|
||||||
|
#define NOP4 NOP2 NOP2
|
||||||
|
#define NOP8 NOP4 NOP4
|
||||||
|
#define NOP16 NOP8 NOP8
|
||||||
|
#define NOP32 NOP16 NOP16
|
||||||
|
#define NOP64 NOP32 NOP32
|
||||||
|
#define NOP128 NOP64 NOP64
|
||||||
|
#define NOP256 NOP128 NOP128
|
||||||
|
#define NOP512 NOP256 NOP256
|
||||||
|
#define NOP1024 NOP512 NOP512
|
||||||
|
#define NOP4K NOP1024 NOP1024 NOP1024 NOP1024
|
||||||
|
|
||||||
|
bool __stdcall strequ(const char *s1, const char *s2) {
|
||||||
|
do {
|
||||||
|
if (*s1 != *s2) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} while (*s1++ && *s2++);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
__declspec(naked) void fix_script_function__ISGLIDER() {
|
||||||
|
__asm {
|
||||||
|
; restore values
|
||||||
|
popad
|
||||||
|
pushad
|
||||||
|
|
||||||
|
mov edi, eax ; my glider
|
||||||
|
mov esi, [esp+20h+4+8*4] ; arg
|
||||||
|
|
||||||
|
label_cmp:
|
||||||
|
mov al, [edi]
|
||||||
|
mov cl, [esi]
|
||||||
|
cmp al, cl
|
||||||
|
jne bad
|
||||||
|
cmp al, 0
|
||||||
|
je end
|
||||||
|
inc edi
|
||||||
|
inc esi
|
||||||
|
jmp label_cmp
|
||||||
|
end:
|
||||||
|
cmp al, cl
|
||||||
|
jne bad
|
||||||
|
popad
|
||||||
|
; push some regs as required by success branch
|
||||||
|
push ebx
|
||||||
|
push ebp
|
||||||
|
push esi
|
||||||
|
push edi
|
||||||
|
push 0x0043A2DA
|
||||||
|
ret
|
||||||
|
|
||||||
|
bad:
|
||||||
|
popad
|
||||||
|
; original thunk
|
||||||
|
copy:
|
||||||
|
mov cl, [eax]; injection point
|
||||||
|
inc eax
|
||||||
|
mov[edx], cl
|
||||||
|
inc edx
|
||||||
|
test cl, cl
|
||||||
|
jnz copy
|
||||||
|
|
||||||
|
; epilogue
|
||||||
|
push known_caller
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_double_light_weapons_glider() {
|
||||||
|
return false
|
||||||
|
|| get_player_ptr()->glider_name.idx == (int)glider_id::nargoon
|
||||||
|
|| get_player_ptr()->glider_name.idx == (int)glider_id::finder1
|
||||||
|
;
|
||||||
|
}
|
||||||
|
bool is_double_heavy_weapons_glider() {
|
||||||
|
return false
|
||||||
|
|| get_player_ptr()->glider_name.idx == (int)glider_id::eyedstone
|
||||||
|
|| get_player_ptr()->glider_name.idx == (int)glider_id::finder2
|
||||||
|
;
|
||||||
|
}
|
||||||
|
bool is_special_glider() {
|
||||||
|
return is_double_light_weapons_glider() || is_double_heavy_weapons_glider();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_double_light_weapons_glider(glider_id id) {
|
||||||
|
return false
|
||||||
|
|| id == glider_id::nargoon
|
||||||
|
|| id == glider_id::finder1
|
||||||
|
;
|
||||||
|
}
|
||||||
|
bool is_double_heavy_weapons_glider(glider_id id) {
|
||||||
|
return false
|
||||||
|
|| id == glider_id::eyedstone
|
||||||
|
|| id == glider_id::finder2
|
||||||
|
;
|
||||||
|
}
|
||||||
|
bool is_special_glider(glider_id id) {
|
||||||
|
return is_double_light_weapons_glider(id) || is_double_heavy_weapons_glider(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool __stdcall can_buy_weapon(int selected_weapon_type, int *canbuy) {
|
||||||
|
if (is_special_glider()) {
|
||||||
|
if (selected_weapon_type == light && is_double_heavy_weapons_glider()) {
|
||||||
|
*(uint8_t*)canbuy = 0;
|
||||||
|
}
|
||||||
|
if (selected_weapon_type == heavy && is_double_light_weapons_glider()) {
|
||||||
|
*(uint8_t *)canbuy = 0;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
__declspec(naked) void fix_trade_actions_weapon_checks() {
|
||||||
|
__asm {
|
||||||
|
; restore values
|
||||||
|
popad
|
||||||
|
pushad
|
||||||
|
|
||||||
|
; ebx = selected weapon type in the store
|
||||||
|
; esi = gun_desc
|
||||||
|
; [esp + 102h] bool is_buy_change
|
||||||
|
; [esp + 103h] bool can_buy
|
||||||
|
|
||||||
|
mov edx, esp
|
||||||
|
add edx, 123h
|
||||||
|
lea edx, [edx]
|
||||||
|
push edx
|
||||||
|
|
||||||
|
push ebx
|
||||||
|
call can_buy_weapon
|
||||||
|
test al, 1
|
||||||
|
jz epi
|
||||||
|
popad
|
||||||
|
push 0x00407308
|
||||||
|
ret
|
||||||
|
|
||||||
|
epi:
|
||||||
|
; epilogue
|
||||||
|
popad
|
||||||
|
mov eax, ebx
|
||||||
|
sub eax, 0
|
||||||
|
push known_caller
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool can_have_light_weapon_slot(glider *obj, glider_id id, int special) {
|
||||||
|
if (is_special_glider(id)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return ((special >> 1) & 0x1) == 0;
|
||||||
|
}
|
||||||
|
bool can_have_heavy_weapon_slot(glider *obj, glider_id id, int special) {
|
||||||
|
if (is_special_glider(id)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return obj->standard > 2 && (special & 0x1) == 0;
|
||||||
|
}
|
||||||
|
void __stdcall can_have_weapon_slots(glider *gliders, glider *obj, int special) {
|
||||||
|
auto id = obj - gliders;
|
||||||
|
obj->can_have_light_weap = can_have_light_weapon_slot(obj, (glider_id)id, special);
|
||||||
|
obj->can_have_heavy_weap = can_have_heavy_weapon_slot(obj, (glider_id)id, special);
|
||||||
|
}
|
||||||
|
__declspec(naked) void fix_can_have_weapon_slots_for_a_glider() {
|
||||||
|
__asm {
|
||||||
|
; restore values
|
||||||
|
popad
|
||||||
|
pushad
|
||||||
|
|
||||||
|
push eax; SPECIAL field value
|
||||||
|
mov ecx, edx;
|
||||||
|
add ecx, ebx;
|
||||||
|
push ecx ; glider*
|
||||||
|
push edx ; glider**
|
||||||
|
call can_have_weapon_slots
|
||||||
|
|
||||||
|
popad
|
||||||
|
push 0x004D6351
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool __stdcall put_purchased_weapon_into_light_slot(int purchased_weapon_type) {
|
||||||
|
if (is_special_glider()) {
|
||||||
|
return get_player_ptr()->glider_object->light_gun_id == -1;
|
||||||
|
}
|
||||||
|
return purchased_weapon_type == 0;
|
||||||
|
}
|
||||||
|
__declspec(naked) void fix_put_weapon_into_the_right_slot_after_purchase() {
|
||||||
|
__asm {
|
||||||
|
; restore values
|
||||||
|
popad
|
||||||
|
pushad
|
||||||
|
|
||||||
|
push eax ; purchased weapon type
|
||||||
|
|
||||||
|
call put_purchased_weapon_into_light_slot
|
||||||
|
cmp al, 1
|
||||||
|
jne heavy_exit
|
||||||
|
popad
|
||||||
|
push 0x00417AA1
|
||||||
|
ret
|
||||||
|
|
||||||
|
heavy_exit:
|
||||||
|
popad
|
||||||
|
push 0x00417A75
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool __stdcall sell_light_weapon(int sold_weapon_type) {
|
||||||
|
if (is_special_glider()) {
|
||||||
|
return get_player_ptr()->glider_object->light_gun_id != -1;
|
||||||
|
}
|
||||||
|
return sold_weapon_type == 0;
|
||||||
|
}
|
||||||
|
__declspec(naked) void fix_sell_correct_weapon() {
|
||||||
|
__asm {
|
||||||
|
; restore values
|
||||||
|
popad
|
||||||
|
pushad
|
||||||
|
|
||||||
|
push eax; purchased weapon type
|
||||||
|
|
||||||
|
call sell_light_weapon
|
||||||
|
cmp al, 1
|
||||||
|
jne heavy_exit
|
||||||
|
popad
|
||||||
|
push 0x004176F1
|
||||||
|
ret
|
||||||
|
|
||||||
|
heavy_exit:
|
||||||
|
popad
|
||||||
|
push 0x004176C4
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t empty_weapon_message;
|
||||||
|
void __stdcall fix_empty_weapon_message(int light_slot) {
|
||||||
|
constexpr auto INT_EMPTY_LIGHT_GUN = 0x00521AA8;
|
||||||
|
constexpr auto INT_EMPTY_HEAVY_GUN = 0x00521A94;
|
||||||
|
if (is_double_light_weapons_glider()) {
|
||||||
|
empty_weapon_message = INT_EMPTY_LIGHT_GUN;
|
||||||
|
} else if (is_double_heavy_weapons_glider()) {
|
||||||
|
empty_weapon_message = INT_EMPTY_HEAVY_GUN;
|
||||||
|
} else {
|
||||||
|
empty_weapon_message = light_slot ? INT_EMPTY_LIGHT_GUN : INT_EMPTY_HEAVY_GUN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
__declspec(naked) void fix_empty_light_weapon_message() {
|
||||||
|
__asm {
|
||||||
|
; restore values
|
||||||
|
popad
|
||||||
|
pushad
|
||||||
|
|
||||||
|
mov eax, 1
|
||||||
|
push eax
|
||||||
|
call fix_empty_weapon_message
|
||||||
|
|
||||||
|
popad
|
||||||
|
push empty_weapon_message
|
||||||
|
push known_caller
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
}
|
||||||
|
__declspec(naked) void fix_empty_heavy_weapon_message() {
|
||||||
|
__asm {
|
||||||
|
; restore values
|
||||||
|
popad
|
||||||
|
pushad
|
||||||
|
|
||||||
|
mov eax, 0
|
||||||
|
push eax
|
||||||
|
call fix_empty_weapon_message
|
||||||
|
|
||||||
|
popad
|
||||||
|
push empty_weapon_message
|
||||||
|
push known_caller
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" __declspec(dllexport) __declspec(naked) void dispatcher() {
|
||||||
|
__asm {
|
||||||
|
pop known_caller
|
||||||
|
pushad
|
||||||
|
}
|
||||||
|
switch (known_caller - call_command_length) {
|
||||||
|
case aim1_fix::script_function__ISGLIDER:
|
||||||
|
known_caller += 0xA - call_command_length; // make normal ret
|
||||||
|
__asm jmp fix_script_function__ISGLIDER
|
||||||
|
break;
|
||||||
|
case aim1_fix::trade_actions_weapon_checks:
|
||||||
|
__asm jmp fix_trade_actions_weapon_checks
|
||||||
|
break;
|
||||||
|
case aim1_fix::setup_proper_weapon_slots_for_a_glider:
|
||||||
|
__asm jmp fix_can_have_weapon_slots_for_a_glider
|
||||||
|
break;
|
||||||
|
case aim1_fix::put_weapon_into_the_right_slot_after_purchase:
|
||||||
|
__asm jmp fix_put_weapon_into_the_right_slot_after_purchase
|
||||||
|
break;
|
||||||
|
case aim1_fix::sell_correct_weapon:
|
||||||
|
__asm jmp fix_sell_correct_weapon
|
||||||
|
break;
|
||||||
|
case aim1_fix::empty_light_weapon_message:
|
||||||
|
__asm jmp fix_empty_light_weapon_message
|
||||||
|
break;
|
||||||
|
case aim1_fix::empty_heavy_weapon_message:
|
||||||
|
__asm jmp fix_empty_heavy_weapon_message
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// just return
|
||||||
|
__asm {
|
||||||
|
popad
|
||||||
|
push known_caller
|
||||||
|
ret
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
//constexpr uint32_t free_data_base = 0x006929C0;
|
||||||
|
constexpr uint32_t free_data_base = 0x00692FF0;
|
||||||
|
auto mem = (uint8_t *)free_data_base;
|
||||||
|
mem[0] = 0xE9;
|
||||||
|
*(uint32_t*)&mem[1] = (uint32_t)&dispatcher - free_data_base - call_command_length;
|
||||||
|
}
|
||||||
|
BOOL WINAPI DllMain(HINSTANCE, DWORD fdwReason, LPVOID) {
|
||||||
|
if (fdwReason == DLL_PROCESS_ATTACH) {
|
||||||
|
setup();
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
2323
examples/mods/aim1_community_fix/aim.exe.h
Normal file
2323
examples/mods/aim1_community_fix/aim.exe.h
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -12,6 +12,9 @@ deps: pub.lzwdgc.Polygon4.Tools.aim1_mod_maker-master
|
||||||
* You can also distribute mod archive (requires 7z program).
|
* You can also distribute mod archive (requires 7z program).
|
||||||
**/
|
**/
|
||||||
|
|
||||||
|
#define AIM_TYPES_FILE_NAME "aim.exe.h"
|
||||||
|
#define INJECTIONS_FILE_NAME "aim.exe.fixes.h"
|
||||||
|
|
||||||
#ifndef INJECTED_DLL
|
#ifndef INJECTED_DLL
|
||||||
#include "aim1_mod_maker.h"
|
#include "aim1_mod_maker.h"
|
||||||
|
|
||||||
|
|
@ -19,7 +22,7 @@ deps: pub.lzwdgc.Polygon4.Tools.aim1_mod_maker-master
|
||||||
// patch note: lz, Solant, Streef
|
// patch note: lz, Solant, Streef
|
||||||
// patch note:
|
// patch note:
|
||||||
// patch note: Description
|
// patch note: Description
|
||||||
// patch note: This mod fixes some issues with the original AIM v1.04 game.
|
// patch note: This mod fixes some issues with the original AIM v1.06 (DRM-free) (1.0.6.3) game.
|
||||||
// patch note:
|
// patch note:
|
||||||
// patch note: Installation
|
// patch note: Installation
|
||||||
// patch note: Unpack and drop all files near original aim.exe. Replace files if necessary.
|
// patch note: Unpack and drop all files near original aim.exe. Replace files if necessary.
|
||||||
|
|
@ -27,6 +30,16 @@ deps: pub.lzwdgc.Polygon4.Tools.aim1_mod_maker-master
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
mod_maker mod;
|
mod_maker mod;
|
||||||
|
mod.files_to_distribute.insert(INJECTIONS_FILE_NAME);
|
||||||
|
mod.files_to_distribute.insert(AIM_TYPES_FILE_NAME);
|
||||||
|
|
||||||
|
// patch note: enable double weap gliders (still have many bugs related)
|
||||||
|
mod.make_injection(0x004072FA); // can trade for buy purposes
|
||||||
|
mod.make_injection(0x004D62E4); // setup proper weapon slots for a glider
|
||||||
|
mod.make_injection(0x00417A6D); // put weapon into the right slot after purchase
|
||||||
|
mod.make_injection(0x004176BC); // sell correct weapon
|
||||||
|
mod.make_injection(0x004067C4); // empty light weap
|
||||||
|
mod.make_injection(0x0040688B); // empty heavy weap
|
||||||
|
|
||||||
// patch note: CHANGES
|
// patch note: CHANGES
|
||||||
// patch note:
|
// patch note:
|
||||||
|
|
@ -65,7 +78,6 @@ int main(int argc, char *argv[]) {
|
||||||
// patch note:
|
// patch note:
|
||||||
|
|
||||||
// patch note: Script Changes
|
// patch note: Script Changes
|
||||||
// patch note: _ISGLIDER() function can check exact glider name now, for example _ISGLIDER(GL_M3_A_FIRST1) (lz)
|
|
||||||
// patch note: fix joining First Ones having one of four required gliders (lz, Streef)
|
// patch note: fix joining First Ones having one of four required gliders (lz, Streef)
|
||||||
mod.replace("ORG_FIRST.scr",
|
mod.replace("ORG_FIRST.scr",
|
||||||
"IF(_PLAYERHAS(GL_M3_A_FIRST1)||_PLAYERHAS(GL_M3_A_FIRST1))",
|
"IF(_PLAYERHAS(GL_M3_A_FIRST1)||_PLAYERHAS(GL_M3_A_FIRST1))",
|
||||||
|
|
@ -77,24 +89,30 @@ int main(int argc, char *argv[]) {
|
||||||
mod.replace("ORG_SINIGR.scr",
|
mod.replace("ORG_SINIGR.scr",
|
||||||
"IF(_PLAYERHAS(GL_S2_PA_SINYGR)|_PLAYERHAS(GL_S4_S_SINYGR))",
|
"IF(_PLAYERHAS(GL_S2_PA_SINYGR)|_PLAYERHAS(GL_S4_S_SINYGR))",
|
||||||
"IF(_ISGLIDER(GL_S2_PA_SINYGR)|_ISGLIDER(GL_S4_S_SINYGR))");
|
"IF(_ISGLIDER(GL_S2_PA_SINYGR)|_ISGLIDER(GL_S4_S_SINYGR))");
|
||||||
|
|
||||||
|
// patch note: _ISGLIDER() function can check exact glider name now, for example _ISGLIDER(GL_M3_A_FIRST1) (lz)
|
||||||
|
mod.make_injection(0x0043A1F6, 10);
|
||||||
|
//
|
||||||
|
|
||||||
|
// end of scripts section
|
||||||
// patch note:
|
// patch note:
|
||||||
|
|
||||||
/*mod.replace("Script/bin/B_L1_BASE1.scr", "_ADDBALANCE(300)", R"(
|
mod.replace("Script/bin/B_L1_BASE1.scr", "_ADDBALANCE(300)", R"(
|
||||||
_ADDBALANCE(300 )
|
_ADDBALANCE(300 )
|
||||||
|
|
||||||
_ADDOBJECT(GL_M3_PA_EYEDSTONE)
|
_ADDOBJECT(GL_S3_PS_FINDER1)
|
||||||
_ADDOBJECT(EQP_VACUUM_DRIVE_S3)
|
_ADDOBJECT(EQP_VACUUM_DRIVE_S3)
|
||||||
_ADDOBJECT(EQP_ZERO_ARMOR_S3)
|
_ADDOBJECT(EQP_ZERO_ARMOR_S3)
|
||||||
_ADDOBJECT(EQP_SHIELD_GENERATOR4_S3)
|
_ADDOBJECT(EQP_SHIELD_GENERATOR4_S3)
|
||||||
|
|
||||||
_ADDOBJECT(GL_M4_S_FIRST2)
|
//_ADDOBJECT(GL_M4_S_FIRST2)
|
||||||
_ADDOBJECT(EQP_VACUUM_DRIVE_S4)
|
//_ADDOBJECT(EQP_VACUUM_DRIVE_S4)
|
||||||
//_ADDOBJECT(EQP_MEZON_REACTOR_S4)
|
//_ADDOBJECT(EQP_MEZON_REACTOR_S4)
|
||||||
//_ADDOBJECT(EQP_GLUON_REACTOR_S1)
|
//_ADDOBJECT(EQP_GLUON_REACTOR_S1)
|
||||||
_ADDOBJECT(EQP_ZERO_ARMOR_S4)
|
//_ADDOBJECT(EQP_ZERO_ARMOR_S4)
|
||||||
_ADDOBJECT(EQP_SHIELD_GENERATOR4_S4)
|
//_ADDOBJECT(EQP_SHIELD_GENERATOR4_S4)
|
||||||
_ADDOBJECT(GUN_MICROWAVE_OSCILLATOR)
|
//_ADDOBJECT(GUN_MICROWAVE_OSCILLATOR)
|
||||||
_ADDOBJECT(GUN_RAILGUN)
|
//_ADDOBJECT(GUN_RAILGUN)
|
||||||
|
|
||||||
_ADDRATING(300000000)
|
_ADDRATING(300000000)
|
||||||
_ADDBALANCE(30000000)
|
_ADDBALANCE(30000000)
|
||||||
|
|
@ -115,7 +133,7 @@ int main(int argc, char *argv[]) {
|
||||||
_SETEVENT(SECTOR7.ACCESS)
|
_SETEVENT(SECTOR7.ACCESS)
|
||||||
//_SETEVENT(SECTOR8.VISIT)
|
//_SETEVENT(SECTOR8.VISIT)
|
||||||
_SETEVENT(SECTOR8.ACCESS)
|
_SETEVENT(SECTOR8.ACCESS)
|
||||||
)");*/
|
)");
|
||||||
|
|
||||||
// patch note: Release Manager
|
// patch note: Release Manager
|
||||||
// patch note: lz
|
// patch note: lz
|
||||||
|
|
@ -144,100 +162,5 @@ int main(int argc, char *argv[]) {
|
||||||
}
|
}
|
||||||
|
|
||||||
#else // INJECTED_DLL
|
#else // INJECTED_DLL
|
||||||
|
#include INJECTIONS_FILE_NAME
|
||||||
#include <stdint.h>
|
|
||||||
#include <windows.h>
|
|
||||||
|
|
||||||
constexpr auto call_command_length = 5;
|
|
||||||
|
|
||||||
enum aim1_fix : uint32_t {
|
|
||||||
script_function__ISGLIDER = 0x0043A1F6,
|
|
||||||
};
|
|
||||||
uint32_t known_caller;
|
|
||||||
|
|
||||||
__declspec(naked) void fix_script_function__ISGLIDER() {
|
|
||||||
__asm {
|
|
||||||
; restore values
|
|
||||||
popad
|
|
||||||
pushad
|
|
||||||
|
|
||||||
mov edi, eax; my glider
|
|
||||||
mov esi, [esp + 20h + 4 + 8 * 4]; arg
|
|
||||||
|
|
||||||
label_cmp :
|
|
||||||
mov al, [edi]
|
|
||||||
mov cl, [esi]
|
|
||||||
cmp al, cl
|
|
||||||
jne bad
|
|
||||||
cmp al, 0
|
|
||||||
je end
|
|
||||||
cmp cl, 0
|
|
||||||
je end
|
|
||||||
inc edi
|
|
||||||
inc esi
|
|
||||||
jmp label_cmp
|
|
||||||
end :
|
|
||||||
cmp al, cl
|
|
||||||
jne bad
|
|
||||||
popad
|
|
||||||
; push some regs as required by success branch
|
|
||||||
push ebx
|
|
||||||
push ebp
|
|
||||||
push esi
|
|
||||||
push edi
|
|
||||||
push 0x0043A2DA
|
|
||||||
ret
|
|
||||||
|
|
||||||
bad :
|
|
||||||
popad
|
|
||||||
; popf
|
|
||||||
; original thunk
|
|
||||||
copy :
|
|
||||||
mov cl, [eax]; injection point
|
|
||||||
inc eax
|
|
||||||
mov[edx], cl
|
|
||||||
inc edx
|
|
||||||
test cl, cl
|
|
||||||
jnz copy
|
|
||||||
|
|
||||||
; epilogue
|
|
||||||
push known_caller
|
|
||||||
ret
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C" __declspec(dllexport) __declspec(naked) void dispatcher() {
|
|
||||||
__asm {
|
|
||||||
pop known_caller
|
|
||||||
pushad
|
|
||||||
}
|
|
||||||
switch (known_caller - call_command_length) {
|
|
||||||
case aim1_fix::script_function__ISGLIDER:
|
|
||||||
known_caller += 0xA - call_command_length; // make normal ret
|
|
||||||
__asm jmp fix_script_function__ISGLIDER
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// just return
|
|
||||||
__asm {
|
|
||||||
popa
|
|
||||||
push known_caller
|
|
||||||
ret
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void setup() {
|
|
||||||
constexpr uint32_t free_data_base = 0x006929C0;
|
|
||||||
auto mem = (uint8_t *)free_data_base;
|
|
||||||
mem[0] = 0xE9;
|
|
||||||
*(uint32_t *)&mem[1] = (uint32_t)&dispatcher - free_data_base - call_command_length;
|
|
||||||
}
|
|
||||||
BOOL WINAPI DllMain(HINSTANCE, DWORD fdwReason, LPVOID) {
|
|
||||||
if (fdwReason == DLL_PROCESS_ATTACH) {
|
|
||||||
setup();
|
|
||||||
}
|
|
||||||
return TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -51,6 +51,18 @@ auto operator""_bin(const char *ptr, uint64_t len) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct aim_exe_v1_06_constants {
|
||||||
|
enum : uint32_t {
|
||||||
|
trampoline_base_real = 0x00025100,
|
||||||
|
trampoline_target_real = 0x001207f0,
|
||||||
|
//code_base = 0x00401000,
|
||||||
|
//data_base = 0x00540000,
|
||||||
|
//free_data_base_virtual = 0x006929C0,
|
||||||
|
free_data_base_virtual = 0x00692FF0,
|
||||||
|
our_code_start_virtual = 0x005207F0, // place to put out dll load
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
struct mod_maker {
|
struct mod_maker {
|
||||||
enum class file_type {
|
enum class file_type {
|
||||||
unknown,
|
unknown,
|
||||||
|
|
@ -164,6 +176,24 @@ struct mod_maker {
|
||||||
return patch_raw(fn, offset, oldval, val);
|
return patch_raw(fn, offset, oldval, val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// all you need is to provide injection address (virtual) with size
|
||||||
|
// handle the call instruction in 'dispatcher' symbol (naked) of your dll
|
||||||
|
constexpr static inline auto call_command_length = 5;
|
||||||
|
void make_injection(uint32_t virtual_address, uint32_t size = call_command_length) {
|
||||||
|
uint32_t len = size;
|
||||||
|
if (len < call_command_length) {
|
||||||
|
throw std::runtime_error{"jumppad must be 5 bytes atleast"};
|
||||||
|
}
|
||||||
|
primitives::templates2::mmap_file<uint8_t> f{find_real_filename(aim_exe),
|
||||||
|
primitives::templates2::mmap_file<uint8_t>::rw{}};
|
||||||
|
auto ptr = f.p + virtual_address - aim_exe_v1_06_constants::our_code_start_virtual + aim_exe_v1_06_constants::trampoline_target_real;
|
||||||
|
memcpy(ptr, make_insn_with_address("e8"_bin, aim_exe_v1_06_constants::free_data_base_virtual -
|
||||||
|
(virtual_address + call_command_length)));
|
||||||
|
memcpy(ptr, make_nops(len - call_command_length));
|
||||||
|
std::println("making injection on the virtual address 0x{:0X} (real address 0x{:0X}), size {}", virtual_address, ptr - f.p,
|
||||||
|
size);
|
||||||
|
}
|
||||||
|
|
||||||
#define ENABLE_DISABLE_FUNC(name, enable, disable) \
|
#define ENABLE_DISABLE_FUNC(name, enable, disable) \
|
||||||
void enable_##name() { name(enable); } \
|
void enable_##name() { name(enable); } \
|
||||||
void disable_##name() { name(disable); }
|
void disable_##name() { name(disable); }
|
||||||
|
|
@ -226,7 +256,7 @@ private:
|
||||||
*(uint32_t *)(&arr[insn.size()]) = addr;
|
*(uint32_t *)(&arr[insn.size()]) = addr;
|
||||||
return arr;
|
return arr;
|
||||||
}
|
}
|
||||||
static auto make_nops(uint32_t len) {
|
static byte_array make_nops(uint32_t len) {
|
||||||
byte_array arr(len, 0x90);
|
byte_array arr(len, 0x90);
|
||||||
return arr;
|
return arr;
|
||||||
}
|
}
|
||||||
|
|
@ -279,28 +309,26 @@ private:
|
||||||
make_injected_dll();
|
make_injected_dll();
|
||||||
files_to_distribute.insert(aim_exe);
|
files_to_distribute.insert(aim_exe);
|
||||||
primitives::templates2::mmap_file<uint8_t> f{find_real_filename(aim_exe), primitives::templates2::mmap_file<uint8_t>::rw{}};
|
primitives::templates2::mmap_file<uint8_t> f{find_real_filename(aim_exe), primitives::templates2::mmap_file<uint8_t>::rw{}};
|
||||||
constexpr uint32_t trampoline_base = 0x00025100;
|
uint32_t our_data = aim_exe_v1_06_constants::our_code_start_virtual;
|
||||||
constexpr uint32_t trampoline_target = 0x001207f0;
|
|
||||||
constexpr uint32_t code_base = 0x00401000;
|
|
||||||
constexpr uint32_t data_base = 0x00540000;
|
|
||||||
constexpr uint32_t free_data_base = 0x006929C0;
|
|
||||||
//constexpr uint32_t our_data = 0x00550FD0;
|
|
||||||
const uint32_t our_data_start = 0x005207F0;
|
|
||||||
uint32_t our_data = 0x005207F0;
|
|
||||||
//constexpr uint32_t free_data_base_real = 0x140000 + our_data - 0x00540000;
|
|
||||||
|
|
||||||
auto ptr = f.p + trampoline_target;
|
auto ptr = f.p + aim_exe_v1_06_constants::trampoline_target_real;
|
||||||
//strcpy((char *)f.p + free_data_base_real, get_dll_name().c_str());
|
#ifdef NDEBUG
|
||||||
strcpy((char *)ptr, get_dll_name().c_str());
|
auto dllnamelen = get_sw_dll_name().size() + 1;
|
||||||
|
strcpy((char *)ptr, get_sw_dll_name().c_str());
|
||||||
|
#else
|
||||||
|
auto dllname = "h:\\Games\\AIM\\1\\.sw\\out\\d\\aim_fixes-0.0.1.dll"s;
|
||||||
|
auto dllnamelen = dllname.size() + 1;
|
||||||
|
strcpy((char *)ptr, dllname.c_str());
|
||||||
|
#endif
|
||||||
|
ptr += dllnamelen;
|
||||||
auto push_dll_name = make_insn_with_address("68"_bin, our_data); // push
|
auto push_dll_name = make_insn_with_address("68"_bin, our_data); // push
|
||||||
ptr += 0x20;
|
|
||||||
our_data += 0x20;
|
our_data += 0x20;
|
||||||
strcpy((char *)ptr, "dispatcher");
|
strcpy((char *)ptr, "dispatcher");
|
||||||
auto dispatcher_func_name = make_insn_with_address("68"_bin, our_data); // push
|
auto dispatcher_func_name = make_insn_with_address("68"_bin, our_data); // push
|
||||||
ptr += 0x20;
|
ptr += 0x20;
|
||||||
our_data += 0x20;
|
our_data += 0x20;
|
||||||
const auto jumppad = "68 30 B8 51 00"_bin; // push offset SEH_425100
|
const auto jumppad = "68 30 B8 51 00"_bin; // push offset SEH_425100
|
||||||
uint32_t jump_offset = ptr - f.p - trampoline_base - jumppad.size() * 2;
|
uint32_t jump_offset = ptr - f.p - aim_exe_v1_06_constants::trampoline_base_real - jumppad.size() * 2;
|
||||||
memreplace(f.p, f.sz, jumppad, make_insn_with_address("e9"_bin, jump_offset));
|
memreplace(f.p, f.sz, jumppad, make_insn_with_address("e9"_bin, jump_offset));
|
||||||
memcpy(ptr, jumppad); // put our removed insn
|
memcpy(ptr, jumppad); // put our removed insn
|
||||||
memcpy(ptr, R"(
|
memcpy(ptr, R"(
|
||||||
|
|
@ -331,15 +359,7 @@ FF D7 ; call edi
|
||||||
memcpy(ptr, R"(
|
memcpy(ptr, R"(
|
||||||
61 ; popa
|
61 ; popa
|
||||||
)"_bin);
|
)"_bin);
|
||||||
memcpy(ptr, make_insn_with_address("e9"_bin, -(ptr - f.p - trampoline_base - jumppad.size())));
|
memcpy(ptr, make_insn_with_address("e9"_bin, -(ptr - f.p - aim_exe_v1_06_constants::trampoline_base_real - jumppad.size())));
|
||||||
|
|
||||||
// E8 C5 87 25 00
|
|
||||||
constexpr auto call_command_length = 5;
|
|
||||||
uint32_t start_addr = 0x0043A1F6;
|
|
||||||
uint32_t len = 10;
|
|
||||||
ptr = f.p + start_addr - our_data_start + trampoline_target;
|
|
||||||
memcpy(ptr, make_insn_with_address("e8"_bin, free_data_base - (start_addr + call_command_length)));
|
|
||||||
memcpy(ptr, make_nops(len - call_command_length));
|
|
||||||
}
|
}
|
||||||
path find_real_filename(path fn) const {
|
path find_real_filename(path fn) const {
|
||||||
auto s = fn.wstring();
|
auto s = fn.wstring();
|
||||||
|
|
|
||||||
|
|
@ -22,4 +22,43 @@
|
||||||
</DisplayString>
|
</DisplayString>
|
||||||
</Type>
|
</Type>
|
||||||
|
|
||||||
|
<Type Name="db2::tab">
|
||||||
|
<Expand>
|
||||||
|
<Item Name="[number of tables]" ExcludeView="simple">n_tables</Item>
|
||||||
|
<Item Name="[number of fields]" ExcludeView="simple">n_fields</Item>
|
||||||
|
<ArrayItems>
|
||||||
|
<Size>n_tables</Size>
|
||||||
|
<ValuePointer>(db2::tab::table*)(&n_fields+1)</ValuePointer>
|
||||||
|
</ArrayItems>
|
||||||
|
<ArrayItems>
|
||||||
|
<Size>n_fields</Size>
|
||||||
|
<ValuePointer>(db2::tab::field*)((db2::tab::table*)(&n_fields+1)+n_tables)</ValuePointer>
|
||||||
|
</ArrayItems>
|
||||||
|
</Expand>
|
||||||
|
</Type>
|
||||||
|
<Type Name="db2::tab::table">
|
||||||
|
<DisplayString>
|
||||||
|
{id},{name,s}
|
||||||
|
</DisplayString>
|
||||||
|
</Type>
|
||||||
|
<Type Name="db2::tab::field">
|
||||||
|
<DisplayString>
|
||||||
|
{table_id},{id},{name,s},{type}
|
||||||
|
</DisplayString>
|
||||||
|
</Type>
|
||||||
|
<Type Name="db2::ind">
|
||||||
|
<Expand>
|
||||||
|
<Item Name="[number of values]" ExcludeView="simple">n_values</Item>
|
||||||
|
<ArrayItems>
|
||||||
|
<Size>n_values</Size>
|
||||||
|
<ValuePointer>(db2::value*)(&n_values+1)</ValuePointer>
|
||||||
|
</ArrayItems>
|
||||||
|
</Expand>
|
||||||
|
</Type>
|
||||||
|
<Type Name="db2::value">
|
||||||
|
<DisplayString>
|
||||||
|
{table_id},{name,s}
|
||||||
|
</DisplayString>
|
||||||
|
</Type>
|
||||||
|
|
||||||
</AutoVisualizer>
|
</AutoVisualizer>
|
||||||
|
|
|
||||||
|
|
@ -183,7 +183,7 @@ struct Good
|
||||||
};
|
};
|
||||||
|
|
||||||
std::string name;
|
std::string name;
|
||||||
char unk1[0x40];
|
char condition_variable[0x40]; // when this var is set, we can access the good
|
||||||
float unk1_2 = 0;
|
float unk1_2 = 0;
|
||||||
float price = 0; // unk, quantity?
|
float price = 0; // unk, quantity?
|
||||||
float unk2[10];
|
float unk2[10];
|
||||||
|
|
@ -199,7 +199,7 @@ struct Good
|
||||||
{
|
{
|
||||||
READ_STRING(b, name);
|
READ_STRING(b, name);
|
||||||
if (gameType == GameType::Aim1)
|
if (gameType == GameType::Aim1)
|
||||||
READ(b, unk1);
|
READ(b, condition_variable);
|
||||||
else
|
else
|
||||||
READ(b, unk1_2);
|
READ(b, unk1_2);
|
||||||
READ(b, price);
|
READ(b, price);
|
||||||
|
|
|
||||||
25
sw.cpp
25
sw.cpp
|
|
@ -8,10 +8,13 @@ void build(Solution &s)
|
||||||
auto cppstd = cpp23;
|
auto cppstd = cpp23;
|
||||||
|
|
||||||
auto &common = tools.addStaticLibrary("common");
|
auto &common = tools.addStaticLibrary("common");
|
||||||
common += cppstd;
|
{
|
||||||
common.setRootDirectory("src/common");
|
common += cppstd;
|
||||||
common.Public += "pub.egorpugin.primitives.filesystem"_dep;
|
common.setRootDirectory("src/common");
|
||||||
common.Public += "pub.egorpugin.primitives.templates2"_dep;
|
common += ".*"_rr;
|
||||||
|
common.Public += "pub.egorpugin.primitives.filesystem"_dep;
|
||||||
|
common.Public += "pub.egorpugin.primitives.templates2"_dep;
|
||||||
|
}
|
||||||
|
|
||||||
auto add_exe_base = [&](const String &name) -> decltype(auto)
|
auto add_exe_base = [&](const String &name) -> decltype(auto)
|
||||||
{
|
{
|
||||||
|
|
@ -73,16 +76,16 @@ void build(Solution &s)
|
||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto &aim1_mod_maker = tools.addStaticLibrary("aim1_mod_maker");
|
auto &aim1_mod_maker = add_exe_with_common("aim1_mod_maker"); // actually a library
|
||||||
|
aim1_mod_maker.Public += "pub.egorpugin.primitives.command"_dep;
|
||||||
|
|
||||||
|
auto &aim1_community_fix = tools.addExecutable("examples.mods.aim1_community_fix");
|
||||||
{
|
{
|
||||||
auto &t = aim1_mod_maker;
|
auto &t = aim1_community_fix;
|
||||||
auto name = "aim1_mod_maker";
|
|
||||||
t.PackageDefinitions = true;
|
t.PackageDefinitions = true;
|
||||||
t += cppstd;
|
t += cppstd;
|
||||||
t.setRootDirectory("src/"s + name);
|
t += "examples/mods/aim1_community_fix/.*"_rr;
|
||||||
//t.Public += "pub.egorpugin.primitives.sw.main"_dep;
|
t += aim1_mod_maker;
|
||||||
t.Public += "pub.egorpugin.primitives.command"_dep;
|
|
||||||
t.Public += common;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
add_exe("mod_reader") += model;
|
add_exe("mod_reader") += model;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue