Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
198 changes: 93 additions & 105 deletions Source.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,170 +4,158 @@
#include <iostream>
#include <sstream>
#include <iomanip>

UInt32 SkillCheckVar = 0;
char newSkillString[516];
char customOffset[8] = "%s[%s] ";
char customOffset1[7] = "%s%s";
char MWString[14] = "Melee Weapons";
char EWString[15] = "Energy Weapons";
#include <cstring> // For std::memset

namespace DiaCondExtended
{
// Constants for the various actor value strings
const char MWString[] = "Melee Weapons";
const char EWString[] = "Energy Weapons";
const char unknown[] = "unknown";

UInt32 SkillCheckVar = 0; // Actor Value Code (AV Code)
char newSkillString[516]; // Buffer for formatted skill check string
char customOffset[8] = "%s[%s] ";
char customOffset1[7] = "%s%s"; // Format string for success case

//Takes the Actor Value Code stored in SkillCheckVar and converts it to a string
// Returns a string representation of the Actor Value (AV) code
const char* GetSkillCheckString()
{
const char* name = nullptr;
if (SkillCheckVar <= eActorVal_FalloutMax)
{
//I'm so, so sorry if you speak another language, I'm lazy AF
//If either MeleeWeapons or EnergyWeapons, changes the string to have a space
if (SkillCheckVar == 0x26)
{
name = MWString;
}
else if (SkillCheckVar == 0x22)
{
name = EWString;
}

else
{
name = GetActorValueString(SkillCheckVar);
}
}
else
{
name = "unknown";
}
return name;
if (SkillCheckVar == 0x26) { return MWString; }
if (SkillCheckVar == 0x22) { return EWString; }

return GetActorValueString(SkillCheckVar); // Fetch the Actor Value string
}
return unknown;
}

//Grabs the AVcode from the ECX register at this address and stores it in SkillCheckVar
// Hook to grab the AV code from the ECX register and store it in SkillCheckVar
_declspec(naked) void __fastcall GetAvCodeHook()
{
static const UInt32 returnAddr = 0x763C40;

_asm
{
mov[ebp - 0x23C], ecx //Rewriting Overwritten Address
mov SkillCheckVar, ecx //ECX = AvCode --> SkillCheckVar
jmp returnAddr
mov[ebp - 0x23C], ecx // Save ECX value
mov SkillCheckVar, ecx // Store ECX value as the AV code
jmp returnAddr // Return to original function
}
}

//Wipes the string buffer before the loop starts, so that the 'AV/Perk' category in the GECK is irrelevant
// Clears the string buffer at the start of processing
_declspec(naked) void __fastcall WipeBuffer()
{
static const UInt32 FormatString = 0x406D00;
static const UInt32 returnAddr = 0x763BD9;

_asm
{
mov[ebp - 0x230], eax //Rewriting Overwritten Address
lea edi, [ebp - 0x208]
mov ecx, 0x200
xor eax, eax
rep stosb //Cleared StringBuffer
jmp returnAddr
lea edi, [ebp - 0x208] // Load address of string buffer
mov ecx, 0x200 // Set buffer size
xor eax, eax // Clear eax register (used by rep stosb)
rep stosb // Fill string buffer with zeros
jmp returnAddr // Return to original function
}
}

//Modifies the construction of the failure string.
// Modifies the failure string construction
_declspec(naked) void __stdcall StringModFail()
{
static const UInt32 FormatString = 0x406D00;
static const UInt32 offsetAddr = 0x01072850;
static const UInt32 returnAddr = 0x763CB7;
static const UInt32 offsetAddr = 0x01072850;

_asm
{
call GetSkillCheckString
push eax //eax = AvCode
push offsetAddr //"%s %d/%d"
push 0x200
lea eax, newSkillString
push eax
call FormatString //FormatString(newSkillString, 512, "%s %d/%d", AvCode, ClampedActorValueI, ComparisonValue)
add esp, 0x18 //2 arguments before jump + 4 new arguments = 6 arguments = 24 bits

lea eax, newSkillString //Concatenated String
push eax
lea edx, [ebp - 0x208] //StringBuffer
push edx
push offset customOffset //"%s[%s] "
push 0x200
lea eax, [ebp - 0x208]
push eax
call FormatString //FormatString(StringBuffer, 512, "%s[%s] ", StringBuffer, newSkillString)
add esp, 0x14 //Need to clean 20 bits for 5 arguments

jmp returnAddr
call GetSkillCheckString // Get AV code string
push eax // Push AV code string to the stack
push offsetAddr // Push format string for failure
push 0x200 // Buffer size for formatted string
lea eax, newSkillString // Load address of newSkillString
push eax // Push buffer for formatted string
call FormatString // Format the failure string

add esp, 0x18 // Clean up the stack (4 arguments)
lea eax, newSkillString // Load the concatenated failure string
push eax // Push formatted string
lea edx, [ebp - 0x208] // Load address of string buffer
push edx // Push string buffer to the stack
push offset customOffset // Push format string for success message
push 0x200 // Buffer size for formatted string
lea eax, [ebp - 0x208] // Load address of string buffer
push eax // Push string buffer
call FormatString // Format the success string

add esp, 0x14 // Clean up the stack
jmp returnAddr // Return to the original function
}
}

//Modifies the construction of the success string.
// Modifies the success string construction
_declspec(naked) void __stdcall StringModPass()
{
static const UInt32 FormatString = 0x406D00;
static const UInt32 offsetAddr = 0x0104700C;
static const UInt32 returnAddr = 0x763CE4;
static const UInt32 offsetAddr = 0x0104700C;

_asm
{
call GetSkillCheckString
push eax //eax = AvCode
push offsetAddr //"%s %d"
push 0x200
lea eax, newSkillString
push eax
call FormatString //FormatString(newSkillString, 512, "%s %d", AvCode, ComparisonValue)
add esp, 0x14

lea eax, newSkillString //Concatenated String
push eax
lea edx, [ebp - 0x208] //StringBuffer
push edx
push offset customOffset //"%s[%s] "
push 0x200
lea eax, [ebp - 0x208]
push eax
call FormatString //FormatString(StringBuffer, 512, "%s[%s] ", StringBuffer, newSkillString)

jmp returnAddr
call GetSkillCheckString // Get AV code string
push eax // Push AV code string to the stack
push offsetAddr // Push format string for success
push 0x200 // Buffer size for formatted string
lea eax, newSkillString // Load address of newSkillString
push eax // Push buffer for formatted string
call FormatString // Format the success string

add esp, 0x14 // Clean up the stack
lea eax, newSkillString // Load the concatenated success string
push eax // Push formatted string
lea edx, [ebp - 0x208] // Load address of string buffer
push edx // Push string buffer to the stack
push offset customOffset // Push format string for success message
push 0x200 // Buffer size for formatted string
lea eax, [ebp - 0x208] // Load address of string buffer
push eax // Push string buffer
call FormatString // Format the string buffer

jmp returnAddr // Return to the original function
}
}

//Removes the appended ']' at the end of the skill tag
// Removes the appended ']' at the end of the skill tag
_declspec(naked) void __fastcall EndModString()
{
static const UInt32 returnAddr = 0x763D1E;
_asm
{
push offset customOffset1
jmp returnAddr
push offset customOffset1 // Push the modified format string
jmp returnAddr // Return to the original function
}
}

//Function to initialize hooks
// Initializes all hooks for modifying dialogue conditions
void InitHooks()
{
UInt32 avHookAddr = 0x763C3A; //This is an Address where the ECX Register = AvCode
UInt32 loopStartAddr = 0x763BD3; //This Address is the start of the For Loop
UInt32 failStrAddr = 0x763C97; //This Address is for the String Buffer right before the string is formatted (Failure Condition)
UInt32 passStrAddr = 0x763CC7; //This Address is for the String Buffer right before the string is formatted (Success Condition)
UInt32 endFormatAddr = 0x763D19; //THis Address pushes the string definition "%s] %s" as an offset to close the Skill Tag up; ']'

ULONG_PTR breakAddr1 = 0x763CE7; //breakAddr1 and 2 are responsible for the break at the end of the for loop
ULONG_PTR breakAddr2 = 0x763CE8;

//Extend Dialogue Conditions
// Memory addresses for hook locations
const UInt32 avHookAddr = 0x763C3A;
const UInt32 loopStartAddr = 0x763BD3;
const UInt32 failStrAddr = 0x763C97;
const UInt32 passStrAddr = 0x763CC7;
const UInt32 endFormatAddr = 0x763D19;

// Break addresses for loop control
const ULONG_PTR breakAddr1 = 0x763CE7;
const ULONG_PTR breakAddr2 = 0x763CE8;

// Write the hooks into the game code
WriteRelJump(avHookAddr, UInt32(GetAvCodeHook));
WriteRelJump(loopStartAddr, UInt32(WipeBuffer));
WriteRelJump(failStrAddr, UInt32(StringModFail));
WriteRelJump(passStrAddr, UInt32(StringModPass));
WriteRelJump(endFormatAddr, UInt32(EndModString));

//Remove loop break
// Remove the loop break instructions to modify loop behavior
PatchMemoryNop(breakAddr1, 1);
PatchMemoryNop(breakAddr2, 1);
}
}
}