mirror of
https://github.com/sfall-team/sfall.git
synced 2026-07-27 16:52:34 -07:00
Added CorpseDeleteTime option (from Mr.Stalin)
Fixed some functionality issues of fake perks.
This commit is contained in:
@@ -8,7 +8,7 @@
|
||||
; be used to remove their hardcoded effects, and add new stat/skill effects
|
||||
|
||||
;Name=The name of the perk (max 63 characters)
|
||||
;Desc=The description of the perk (max 1023 characters)
|
||||
;Desc=The description of the perk (max 255 characters)
|
||||
;Image=The line number (0-indexed) of the corresponding FRM in skilldex.lst
|
||||
;Ranks=The number of perk levels
|
||||
;Level=The minimum required level
|
||||
|
||||
@@ -357,6 +357,11 @@ PlayIdleAnimOnReload=0
|
||||
;Set to 1 to prevent corpses from blocking line of fire
|
||||
CorpseLineOfFireFix=0
|
||||
|
||||
;Changes the timer (in days) for deleting corpses on a map after you leave (valid range: 0..13)
|
||||
;Default is 6. Set to 0 for a 12-hour timer
|
||||
;The corpses of critters with 'Ages' flag or on maps with 'dead_bodies_age=No' set in maps.txt will not disappear
|
||||
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
|
||||
|
||||
@@ -1925,6 +1925,7 @@ isDead:
|
||||
cmp eax, -1;
|
||||
je noBlood;
|
||||
mov eax, [esp - 4]; // object
|
||||
// mov [eax + 0x18], 3; // set frame
|
||||
mov ebx, [esi + 0x28]; // critter.elev
|
||||
mov edx, [esi + 0x04]; // critter.tile
|
||||
xor ecx, ecx;
|
||||
|
||||
+80
-64
@@ -25,19 +25,21 @@
|
||||
#include "Perks.h"
|
||||
|
||||
static const int maxNameLen = 64; // don't change size
|
||||
static const int maxDescLen = 1024; // don't change size
|
||||
static const int maxDescLen = 512; // don't change size
|
||||
static const int descLen = 256; // maximum text length for interface
|
||||
|
||||
static char perksFile[MAX_PATH] = {0};
|
||||
|
||||
static char Name[maxNameLen * PERK_count] = {0};
|
||||
static char Desc[maxDescLen * PERK_count] = {0};
|
||||
static char Desc[descLen * PERK_count] = {0};
|
||||
static char tName[maxNameLen * TRAIT_count] = {0};
|
||||
static char tDesc[maxDescLen * TRAIT_count] = {0};
|
||||
static char tDesc[descLen * TRAIT_count] = {0};
|
||||
static char PerkBoxTitle[33];
|
||||
|
||||
#define check_trait(id) !disableTraits[id] && (pc_trait[0] == id || pc_trait[1] == id)
|
||||
|
||||
static DWORD addPerkMode = 2;
|
||||
static bool perksReInit = false;
|
||||
|
||||
struct TraitStruct {
|
||||
char* Name;
|
||||
@@ -76,15 +78,16 @@ struct FakePerk {
|
||||
int Image;
|
||||
char Name[maxNameLen];
|
||||
char Desc[maxDescLen];
|
||||
char reserve[512]; // empty block
|
||||
};
|
||||
|
||||
std::vector<FakePerk> fakeTraits;
|
||||
std::vector<FakePerk> fakePerks;
|
||||
std::vector<FakePerk> fakeSelectablePerks;
|
||||
|
||||
static DWORD RemoveTraitID;
|
||||
static DWORD RemovePerkID;
|
||||
static DWORD RemoveSelectableID;
|
||||
static std::list<int> RemoveTraitID;
|
||||
static std::list<int> RemovePerkID;
|
||||
static std::list<int> RemoveSelectableID;
|
||||
|
||||
static DWORD TraitSkillBonuses[TRAIT_count * 18] = {0};
|
||||
static DWORD TraitStatBonuses[TRAIT_count * (STAT_max_derived + 1)] = {0};
|
||||
@@ -186,7 +189,8 @@ void _stdcall SetSelectablePerk(char* name, int active, int image, char* desc) {
|
||||
if (!strcmp(name, fakeSelectablePerks[i].Name)) {
|
||||
fakeSelectablePerks[i].Level = active;
|
||||
fakeSelectablePerks[i].Image = image;
|
||||
strncpy_s(fakeSelectablePerks[i].Desc, desc, _TRUNCATE);
|
||||
strncpy(fakeSelectablePerks[i].Desc, desc, descLen - 1);
|
||||
fakeSelectablePerks[i].Desc[descLen - 1] = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -215,7 +219,8 @@ void _stdcall SetFakePerk(char* name, int level, int image, char* desc) {
|
||||
if (!strcmp(name, fakePerks[i].Name)) {
|
||||
fakePerks[i].Level = level;
|
||||
fakePerks[i].Image = image;
|
||||
strncpy_s(fakePerks[i].Desc, desc, _TRUNCATE);
|
||||
strncpy(fakePerks[i].Desc, desc, descLen - 1);
|
||||
fakePerks[i].Desc[descLen - 1] = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -244,7 +249,8 @@ void _stdcall SetFakeTrait(char* name, int active, int image, char* desc) {
|
||||
if (!strcmp(name, fakeTraits[i].Name)) {
|
||||
fakeTraits[i].Level = active;
|
||||
fakeTraits[i].Image = image;
|
||||
strncpy_s(fakeTraits[i].Desc, desc, _TRUNCATE);
|
||||
strncpy(fakeTraits[i].Desc, desc, descLen - 1);
|
||||
fakeTraits[i].Desc[descLen - 1] = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -343,7 +349,7 @@ static void __declspec(naked) GetFakeSPerkLevel() {
|
||||
}
|
||||
}
|
||||
|
||||
static DWORD _stdcall HandleFakeTraits(int id) {
|
||||
static DWORD _stdcall HandleFakeTraits(int isSelect) {
|
||||
for (DWORD i = 0; i < fakeTraits.size(); i++) {
|
||||
DWORD a = (DWORD)fakeTraits[i].Name;
|
||||
__asm {
|
||||
@@ -351,15 +357,15 @@ static DWORD _stdcall HandleFakeTraits(int id) {
|
||||
call folder_print_line_;
|
||||
mov a, eax;
|
||||
}
|
||||
if (a && !id) {
|
||||
id = 1;
|
||||
if (a && !isSelect) {
|
||||
isSelect = 1;
|
||||
*(DWORD*)_folder_card_fid = fakeTraits[i].Image;
|
||||
*(DWORD*)_folder_card_title = (DWORD)fakeTraits[i].Name;
|
||||
*(DWORD*)_folder_card_title2 = 0;
|
||||
*(DWORD*)_folder_card_desc = (DWORD)fakeTraits[i].Desc;
|
||||
}
|
||||
}
|
||||
return id;
|
||||
return isSelect;
|
||||
}
|
||||
|
||||
static void __declspec(naked) PlayerHasPerkHack() {
|
||||
@@ -468,12 +474,14 @@ cLoop:
|
||||
}
|
||||
}
|
||||
|
||||
static DWORD _stdcall HandleExtraSelectablePerks(DWORD offset, DWORD* data) {
|
||||
// Build a table of perks ID numbers available for selection
|
||||
// data buffer has limited size for 119 perks
|
||||
static DWORD _stdcall HandleExtraSelectablePerks(DWORD available, DWORD* data) {
|
||||
for (DWORD i = 0; i < fakeSelectablePerks.size(); i++) {
|
||||
//*(WORD*)(_name_sort_list + (offset+i)*8)=(WORD)(PERK_count+i);
|
||||
data[offset + i] = PERK_count + i;
|
||||
if (available >= 119) break; // exit if the buffer is overfull
|
||||
data[available++] = PERK_count + i; //*(WORD*)(_name_sort_list + (offset+i)*8)=(WORD)(PERK_count+i);
|
||||
}
|
||||
return offset + fakeSelectablePerks.size();
|
||||
return available; // total number of perks available for selection
|
||||
}
|
||||
|
||||
static void __declspec(naked) GetAvailablePerksHook() {
|
||||
@@ -546,6 +554,7 @@ end:
|
||||
}
|
||||
}
|
||||
|
||||
// Adds the selected perk to the player
|
||||
static void _stdcall AddFakePerk(DWORD perkID) {
|
||||
perkID -= PERK_count;
|
||||
if (addPerkMode & 1) {
|
||||
@@ -553,10 +562,11 @@ static void _stdcall AddFakePerk(DWORD perkID) {
|
||||
for (DWORD d = 0; d < fakeTraits.size(); d++) {
|
||||
if (!strcmp(fakeTraits[d].Name, fakeSelectablePerks[perkID].Name)) {
|
||||
matched = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!matched) {
|
||||
RemoveTraitID = fakeTraits.size();
|
||||
RemoveTraitID.push_back(fakeTraits.size());
|
||||
fakeTraits.push_back(fakeSelectablePerks[perkID]);
|
||||
}
|
||||
}
|
||||
@@ -564,22 +574,24 @@ static void _stdcall AddFakePerk(DWORD perkID) {
|
||||
bool matched = false;
|
||||
for (DWORD d = 0; d < fakePerks.size(); d++) {
|
||||
if (!strcmp(fakePerks[d].Name, fakeSelectablePerks[perkID].Name)) {
|
||||
RemovePerkID = d;
|
||||
RemovePerkID.push_back(d);
|
||||
fakePerks[d].Level++;
|
||||
matched = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!matched) {
|
||||
RemovePerkID = fakePerks.size();
|
||||
RemovePerkID.push_back(fakePerks.size());
|
||||
fakePerks.push_back(fakeSelectablePerks[perkID]);
|
||||
}
|
||||
}
|
||||
if (addPerkMode & 4) {
|
||||
RemoveSelectableID = perkID;
|
||||
RemoveSelectableID.push_back(perkID);
|
||||
//fakeSelectablePerks.remove_at(perkID);
|
||||
}
|
||||
}
|
||||
|
||||
// Adds perk from selection window to player
|
||||
static void __declspec(naked) AddPerkHook() {
|
||||
__asm {
|
||||
cmp edx, PERK_count;
|
||||
@@ -638,7 +650,7 @@ void _stdcall ApplyHeaveHoFix() { // not really a fix
|
||||
perkHeaveHoModFix = true;
|
||||
}
|
||||
|
||||
static void PerkSetup() {
|
||||
static void PerkEngineInit() {
|
||||
// Character screen (list_perks_)
|
||||
HookCall(0x434256, PlayerHasTraitHook); // jz func
|
||||
MakeJump(0x43436B, PlayerHasPerkHack);
|
||||
@@ -679,8 +691,15 @@ static void PerkSetup() {
|
||||
MakeCall(0x4AFB2F, LevelUpHack, 1); // replaces 'mov edx, ds:[PlayerLevel]'
|
||||
SafeWrite8(0x43C2EC, 0xEB); // skip the block of code which checks if the player has gained a perk (now handled in level up code)
|
||||
|
||||
memcpy(Perks, (void*)_perk_data, sizeof(PerkStruct) * PERK_count);
|
||||
// Disable losing unused perks
|
||||
SafeWrite16(0x43C369, 0x0DFE); // dec byte ptr ds:_free_perk
|
||||
SafeWrite8(0x43C370, 0xB1); // jmp 0x43C322
|
||||
}
|
||||
|
||||
static void PerkSetup() {
|
||||
memcpy(Perks, (void*)_perk_data, sizeof(PerkStruct) * PERK_count); // copy vanilla data
|
||||
|
||||
if (!perksReInit) {
|
||||
// _perk_data
|
||||
SafeWrite32(0x496669, (DWORD)Perks);
|
||||
SafeWrite32(0x496837, (DWORD)Perks);
|
||||
@@ -691,7 +710,7 @@ static void PerkSetup() {
|
||||
SafeWrite32(0x496BD1, (DWORD)Perks + 4);
|
||||
SafeWrite32(0x496BF5, (DWORD)Perks + 8);
|
||||
SafeWrite32(0x496AD4, (DWORD)Perks + 12);
|
||||
|
||||
}
|
||||
if (perksFile[0] != '\0') {
|
||||
char num[4];
|
||||
for (int i = 0; i < PERK_count; i++) {
|
||||
@@ -699,8 +718,8 @@ static void PerkSetup() {
|
||||
if (GetPrivateProfileString(num, "Name", "", &Name[i * maxNameLen], maxNameLen - 1, perksFile)) {
|
||||
Perks[i].Name = &Name[i * maxNameLen];
|
||||
}
|
||||
if (GetPrivateProfileString(num, "Desc", "", &Desc[i * maxDescLen], maxDescLen - 1, perksFile)) {
|
||||
Perks[i].Desc = &Desc[i * maxDescLen];
|
||||
if (GetPrivateProfileString(num, "Desc", "", &Desc[i * descLen], descLen - 1, perksFile)) {
|
||||
Perks[i].Desc = &Desc[i * descLen];
|
||||
}
|
||||
int value;
|
||||
value = GetPrivateProfileInt(num, "Image", -99999, perksFile);
|
||||
@@ -739,21 +758,7 @@ static void PerkSetup() {
|
||||
if (value != -99999) Perks[i].Lck = value;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < PERK_count; i++) {
|
||||
if (Perks[i].Name != &Name[maxNameLen * i]) {
|
||||
strcpy_s(&Name[maxNameLen * i], maxNameLen, Perks[i].Name);
|
||||
Perks[i].Name = &Name[maxNameLen * i];
|
||||
}
|
||||
if (Perks[i].Desc && Perks[i].Desc != &Desc[maxDescLen * i]) {
|
||||
strcpy_s(&Desc[maxDescLen * i], maxDescLen, Perks[i].Desc);
|
||||
Perks[i].Desc = &Desc[maxDescLen * i];
|
||||
}
|
||||
}
|
||||
|
||||
// Disable losing unused perks
|
||||
SafeWrite16(0x43C369, 0x0DFE); // dec byte ptr ds:_free_perk
|
||||
SafeWrite8(0x43C370, 0xB1); // jmp 0x43C322
|
||||
perksReInit = false;
|
||||
}
|
||||
|
||||
static __declspec(naked) void PerkInitWrapper() {
|
||||
@@ -768,6 +773,8 @@ static __declspec(naked) void PerkInitWrapper() {
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////// TRAIT FUNCTIONS ///////////////////////////////////
|
||||
|
||||
static int _stdcall stat_get_base_direct(DWORD statID) {
|
||||
DWORD result;
|
||||
__asm {
|
||||
@@ -921,8 +928,8 @@ static void TraitSetup() {
|
||||
if (GetPrivateProfileString(num, "Name", "", &tName[i * maxNameLen], maxNameLen - 1, perksFile)) {
|
||||
Traits[i].Name = &tName[i * maxNameLen];
|
||||
}
|
||||
if (GetPrivateProfileString(num, "Desc", "", &tDesc[i * maxDescLen], maxDescLen - 1, perksFile)) {
|
||||
Traits[i].Desc = &tDesc[i * maxDescLen];
|
||||
if (GetPrivateProfileString(num, "Desc", "", &tDesc[i * descLen], descLen - 1, perksFile)) {
|
||||
Traits[i].Desc = &tDesc[i * descLen];
|
||||
}
|
||||
int value;
|
||||
value = GetPrivateProfileInt(num, "Image", -99999, perksFile);
|
||||
@@ -990,17 +997,6 @@ static void TraitSetup() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < TRAIT_count; i++) {
|
||||
if (Traits[i].Name != &tName[maxNameLen * i]) {
|
||||
strcpy_s(&tName[maxNameLen * i], maxNameLen, Traits[i].Name);
|
||||
Traits[i].Name = &tName[maxNameLen * i];
|
||||
}
|
||||
if (Traits[i].Desc && Traits[i].Desc != &tDesc[maxDescLen * i]) {
|
||||
strcpy_s(&tDesc[maxDescLen * i], maxDescLen, Traits[i].Desc);
|
||||
Traits[i].Desc = &tDesc[maxDescLen * i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static __declspec(naked) void TraitInitWrapper() {
|
||||
@@ -1015,20 +1011,26 @@ static __declspec(naked) void TraitInitWrapper() {
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void _stdcall SetPerkValue(int id, int value, DWORD offset) {
|
||||
if (id < 0 || id >= PERK_count) return;
|
||||
*(DWORD*)((DWORD)(&Perks[id]) + offset) = value;
|
||||
perksReInit = true;
|
||||
}
|
||||
|
||||
void _stdcall SetPerkName(int id, char* value) {
|
||||
if (id < 0 || id >= PERK_count) return;
|
||||
strncpy_s(&Name[id * maxNameLen], maxNameLen, value, _TRUNCATE);
|
||||
Perks[id].Name = &Name[maxNameLen * id];
|
||||
perksReInit = true;
|
||||
}
|
||||
|
||||
void _stdcall SetPerkDesc(int id, char* value) {
|
||||
if (id < 0 || id >= PERK_count) return;
|
||||
strncpy_s(&Desc[id * maxDescLen], maxDescLen, value, _TRUNCATE);
|
||||
Perks[id].Desc = &Desc[maxDescLen * id];
|
||||
strncpy_s(&Desc[id * descLen], descLen, value, _TRUNCATE);
|
||||
Perks[id].Desc = &Desc[descLen * id];
|
||||
perksReInit = true;
|
||||
}
|
||||
|
||||
void PerksReset() {
|
||||
@@ -1055,6 +1057,7 @@ void PerksReset() {
|
||||
SafeWrite32(0x478AC5, 0x23);
|
||||
perkHeaveHoModFix = false;
|
||||
}
|
||||
if (perksReInit) PerkSetup(); // restore perk data
|
||||
}
|
||||
|
||||
void PerksSave(HANDLE file) {
|
||||
@@ -1131,27 +1134,40 @@ void _stdcall ClearSelectablePerks() {
|
||||
}
|
||||
|
||||
void PerksEnterCharScreen() {
|
||||
RemoveTraitID = -1;
|
||||
RemovePerkID = -1;
|
||||
RemoveSelectableID = -1;
|
||||
RemoveTraitID.clear();
|
||||
RemovePerkID.clear();
|
||||
RemoveSelectableID.clear();
|
||||
}
|
||||
|
||||
void PerksCancelCharScreen() {
|
||||
if (RemoveTraitID != -1) {
|
||||
fakeTraits.erase(fakeTraits.begin() + RemoveTraitID);
|
||||
if (RemoveTraitID.size() > 1) RemoveTraitID.sort();
|
||||
while (!RemoveTraitID.empty()) {
|
||||
fakeTraits.erase(fakeTraits.begin() + RemoveTraitID.back());
|
||||
RemoveTraitID.pop_back();
|
||||
}
|
||||
if (RemovePerkID != -1) {
|
||||
if (!--fakePerks[RemovePerkID].Level) fakePerks.erase(fakePerks.begin() + RemovePerkID);
|
||||
if (RemovePerkID.size() > 1) RemovePerkID.sort(); // sorting to correctly remove from the end
|
||||
while (!RemovePerkID.empty()) {
|
||||
int index = RemovePerkID.back();
|
||||
if (!--fakePerks[index].Level) fakePerks.erase(fakePerks.begin() + index);
|
||||
RemovePerkID.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
void PerksAcceptCharScreen() {
|
||||
if (RemoveSelectableID != -1) fakeSelectablePerks.erase(fakeSelectablePerks.begin() + RemoveSelectableID);
|
||||
if (RemoveSelectableID.size() > 1) {
|
||||
RemoveSelectableID.sort();
|
||||
RemoveSelectableID.unique();
|
||||
}
|
||||
while (!RemoveSelectableID.empty()) {
|
||||
fakeSelectablePerks.erase(fakeSelectablePerks.begin() + RemoveSelectableID.back());
|
||||
RemoveSelectableID.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
void PerksInit() {
|
||||
for (int i = STAT_st; i <= STAT_lu; i++) SafeWrite8(GainStatPerks[i][0], (BYTE)GainStatPerks[i][1]);
|
||||
|
||||
PerkEngineInit();
|
||||
HookCall(0x442729, PerkInitWrapper); // game_init_
|
||||
if (GetPrivateProfileString("Misc", "PerksFile", "", &perksFile[2], MAX_PATH - 3, ini)) {
|
||||
perksFile[0] = '.';
|
||||
|
||||
+15
-1
@@ -734,7 +734,7 @@ fail:
|
||||
static void __declspec(naked) op_obj_can_see_obj_hook() {
|
||||
__asm {
|
||||
push obj_shoot_blocking_at_; // check hex objects func pointer
|
||||
push 0x20; // flags, 0x20 = check shootthru
|
||||
push 0x20; // flags, 0x20 = check ShootThru
|
||||
mov ecx, dword ptr [esp + 0x0C]; // buf **ret_objStruct
|
||||
push ecx;
|
||||
xor ecx, ecx;
|
||||
@@ -1519,6 +1519,20 @@ static void DllMain2() {
|
||||
dlogr(" Done", DL_INIT);
|
||||
}
|
||||
|
||||
int time = GetPrivateProfileIntA("Misc", "CorpseDeleteTime", 6, ini); // time in days
|
||||
if (time != 6) {
|
||||
dlog("Applying corpse deletion time patch.", DL_INIT);
|
||||
if (time <= 0) {
|
||||
time = 12; // hours
|
||||
} else if (time > 13) {
|
||||
time = 13 * 24;
|
||||
} else {
|
||||
time *= 24;
|
||||
}
|
||||
SafeWrite32(0x483348, time);
|
||||
dlogr(" Done", DL_INIT);
|
||||
}
|
||||
|
||||
dlogr("Leave DllMain2", DL_MAIN);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user