Moved code from main.cpp to new LoadOrder/Karma.cpp

Slightly refactored list_* functions with 4.x codebase.

Changed the initialization order in main.cpp to 4.x's.
This commit is contained in:
NovaRain
2019-10-18 11:15:10 +08:00
parent 6780a21b07
commit ac10bce231
25 changed files with 679 additions and 553 deletions
+4 -13
View File
@@ -97,21 +97,12 @@ static void RunEditorInternal(SOCKET &s) {
std::vector<DWORD*> vec = std::vector<DWORD*>();
for (int elv = 0; elv < 3; elv++) {
for (int tile = 0; tile < 40000; tile++) {
DWORD* obj;
__asm {
mov edx, tile;
mov eax, elv;
call obj_find_first_at_tile_;
mov obj, eax;
}
TGameObj* obj = ObjFindFirstAtTile(elv, tile);
while (obj) {
DWORD otype = obj[25];
otype = (otype & 0xFF000000) >> 24;
if (otype == 1) vec.push_back(obj);
__asm {
call obj_find_next_at_tile_;
mov obj, eax;
if (obj->pid >> 24 == OBJ_TYPE_CRITTER) {
vec.push_back(reinterpret_cast<DWORD*>(obj));
}
obj = ObjFindNextAtTile();
}
}
}
+12
View File
@@ -1083,10 +1083,22 @@ TGameObj* __stdcall ObjFindFirst() {
__asm call obj_find_first_;
}
TGameObj* __stdcall ObjFindFirstAtTile(long elevation, long tileNum) {
__asm {
mov edx, tileNum;
mov eax, elevation;
call obj_find_first_at_tile_;
}
}
TGameObj* __stdcall ObjFindNext() {
__asm call obj_find_next_;
}
TGameObj* __stdcall ObjFindNextAtTile() {
__asm call obj_find_next_at_tile_;
}
long __stdcall NewObjId() {
__asm call new_obj_id_;
}
+4
View File
@@ -1073,8 +1073,12 @@ long __stdcall QueueFindFirst(TGameObj* object, long qType);
TGameObj* __stdcall ObjFindFirst();
TGameObj* __stdcall ObjFindFirstAtTile(long elevation, long tileNum);
TGameObj* __stdcall ObjFindNext();
TGameObj* __stdcall ObjFindNextAtTile();
long __stdcall NewObjId();
FrmFrameData* __fastcall FramePtr(FrmHeaderData* frm, long frame, long direction);
+121
View File
@@ -0,0 +1,121 @@
/*
* sfall
* Copyright (C) 2008-2017 The sfall team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <math.h>
#include <stdio.h>
#include <string>
#include <vector>
#include "main.h"
#include "FalloutEngine.h"
struct KarmaFrmSetting {
DWORD frm;
int points;
};
static std::vector<KarmaFrmSetting> karmaFrms;
static char KarmaGainMsg[128];
static char KarmaLossMsg[128];
static DWORD _stdcall DrawCard() {
int reputation = **(int**)_game_global_vars;
for (std::vector<KarmaFrmSetting>::const_iterator it = karmaFrms.begin(); it != karmaFrms.end(); ++it) {
if (reputation < it->points) {
return it->frm;
}
}
return karmaFrms.end()->frm;
}
static void __declspec(naked) DrawInfoWin_hook() {
__asm {
cmp ds:[_info_line], 10;
jne skip;
cmp eax, 0x30;
jne skip;
push ecx;
push edx;
call DrawCard;
pop edx;
pop ecx;
skip:
jmp DrawCard_;
}
}
static void _stdcall SetKarma(int value) {
int old;
__asm {
xor eax, eax;
call game_get_global_var_;
mov old, eax;
}
old = value - old;
char buf[128];
if (old == 0) return;
if (old > 0) {
sprintf_s(buf, KarmaGainMsg, old);
} else {
sprintf_s(buf, KarmaLossMsg, -old);
}
DisplayConsoleMessage(buf);
}
static void __declspec(naked) SetGlobalVarWrapper() {
__asm {
test eax, eax; // GVar number
jnz end;
pushadc;
push edx;
call SetKarma;
popadc;
end:
jmp game_set_global_var_;
}
}
void KarmaInit() {
if (GetConfigInt("Misc", "DisplayKarmaChanges", 0)) {
dlog("Applying display karma changes patch.", DL_INIT);
Translate("sfall", "KarmaGain", "You gained %d karma.", KarmaGainMsg);
Translate("sfall", "KarmaLoss", "You lost %d karma.", KarmaLossMsg);
HookCall(0x455A6D, SetGlobalVarWrapper);
dlogr(" Done", DL_INIT);
}
std::vector<std::string> karmaFrmList = GetConfigList("Misc", "KarmaFRMs", "", 512);
size_t countFrm = karmaFrmList.size();
if (countFrm) {
dlog("Applying karma FRM patch.", DL_INIT);
std::vector<std::string> karmaPointsList = GetConfigList("Misc", "KarmaPoints", "", 512);
karmaFrms.resize(countFrm);
size_t countPoints = karmaPointsList.size();
for (size_t i = 0; i < countFrm; i++) {
karmaFrms[i].frm = atoi(karmaFrmList[i].c_str());
karmaFrms[i].points = (countPoints > i)
? atoi(karmaPointsList[i].c_str())
: INT_MAX;
}
HookCall(0x4367A9, DrawInfoWin_hook);
dlogr(" Done", DL_INIT);
}
}
+21
View File
@@ -0,0 +1,21 @@
/*
* sfall
* Copyright (C) 2008-2017 The sfall team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
void KarmaInit();
+5 -4
View File
@@ -33,15 +33,16 @@
#include "input.h"
#include "Inventory.h"
#include "LoadGameHook.h"
#include "LoadOrder.h"
#include "Logging.h"
#include "Message.h"
#include "movies.h"
#include "Movies.h"
#include "Objects.h"
#include "PartyControl.h"
#include "perks.h"
#include "Perks.h"
#include "ScriptExtender.h"
#include "skills.h"
#include "sound.h"
#include "Skills.h"
#include "Sound.h"
#include "SuperSave.h"
#include "TalkingHeads.h"
#include "version.h"
+253
View File
@@ -0,0 +1,253 @@
/*
* sfall
* Copyright (C) 2008-2017 The sfall team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "main.h"
#include "FalloutEngine.h"
static std::vector<int> savPrototypes;
static void __declspec(naked) RemoveDatabase() {
__asm {
cmp eax, -1;
je end;
mov ebx, ds:[_paths];
mov ecx, ebx;
nextPath:
mov edx, [esp + 0x104 + 4 + 4]; // path_patches
mov eax, [ebx]; // database.path
call stricmp_;
test eax, eax; // found path?
jz skip; // Yes
mov ecx, ebx;
mov ebx, [ebx + 0xC]; // database.next
jmp nextPath;
skip:
mov eax, [ebx + 0xC]; // database.next
mov [ecx + 0xC], eax; // database.next
xchg ebx, eax;
cmp eax, ecx;
jne end;
mov ds:[_paths], ebx;
end:
retn;
}
}
// Remove master_patches from the chain
static void __declspec(naked) game_init_databases_hack1() {
__asm {
call RemoveDatabase;
mov ds:[_master_db_handle], eax; // the pointer of master_patches node will be saved here
retn;
}
}
// Remove critter_patches from the chain
static void __declspec(naked) game_init_databases_hack2() {
__asm {
cmp eax, -1;
je end;
mov eax, ds:[_master_db_handle]; // pointer to master_patches node
mov eax, [eax]; // eax = master_patches.path
call xremovepath_;
dec eax; // remove path (critter_patches == master_patches)?
jz end; // Yes (jump if 0)
inc eax;
call RemoveDatabase;
end:
mov ds:[_critter_db_handle], eax; // the pointer of critter_patches node will be saved here
retn;
}
}
static void __declspec(naked) game_init_databases_hook() {
// eax = _master_db_handle
__asm {
mov ecx, ds:[_critter_db_handle];
mov edx, ds:[_paths];
test ecx, ecx;
jz skip;
mov [ecx + 0xC], edx; // critter_patches.next->_paths
mov edx, ecx;
skip:
mov [eax + 0xC], edx; // master_patches.next
mov ds:[_paths], eax;
retn;
}
}
////////////////////////////// SAVE PARTY MEMBER PROTOTYPES //////////////////////////////
static void __fastcall AddSavPrototype(long pid) {
for (std::vector<int>::const_iterator it = savPrototypes.begin(); it != savPrototypes.end(); ++it) {
if (*it == pid) return;
}
savPrototypes.push_back(pid);
}
static long ChangePrototypeExt(char* path) {
long len = strlen(path);
if (len) {
len -= 4;
if (path[len] == '.') {
path[++len] = 's';
path[++len] = 'a';
path[++len] = 'v';
} else {
len = 0;
}
}
return len;
}
static void __fastcall ExistSavPrototype(long pid, char* path) {
if (savPrototypes.empty()) return;
for (std::vector<int>::const_iterator it = savPrototypes.begin(); it != savPrototypes.end(); ++it) {
if (*it == pid) {
ChangePrototypeExt(path);
break;
}
}
}
static long __fastcall CheckProtoType(long pid, char* path) {
if (pid >> 24 != OBJ_TYPE_CRITTER) return 0;
return ChangePrototypeExt(path);
}
// saves prototypes (all party members) before saving game or exiting the map
static void __declspec(naked) proto_save_pid_hook() {
__asm {
push ecx;
call proto_list_str_;
test eax, eax;
jnz end;
mov ecx, ebx; // party pid
mov edx, edi; // path buffer
call CheckProtoType;
test eax, eax;
jz end;
mov ecx, ebx; // party pid
call AddSavPrototype;
end:
pop ecx;
retn;
}
}
#define _F_PATHFILE 0x6143F4
static void __declspec(naked) GameMap2Slot_hack() { // save party pids
__asm {
push ecx;
mov edx, _F_PATHFILE; // path buffer
call CheckProtoType; // ecx - party pid
pop ecx;
lea eax, [esp + 0x14 + 4];
retn 0x14;
}
}
static void __declspec(naked) SlotMap2Game_hack() { // load party pids
__asm {
push edx;
mov ecx, edi; // party pid
mov edx, _F_PATHFILE; // path buffer
call CheckProtoType;
test eax, eax;
jz end;
mov ecx, edi;
call AddSavPrototype;
end:
pop edx;
lea eax, [esp + 0x14 + 4];
retn 0x14;
}
}
static void __declspec(naked) proto_load_pid_hook() {
__asm { // eax - party pid
push ecx;
mov ecx, eax;
call proto_list_str_;
test eax, eax;
jnz end;
// check pid type
mov edx, ecx;
shr edx, 24;
cmp edx, OBJ_TYPE_CRITTER;
jnz end;
mov edx, edi; // path buffer
call ExistSavPrototype; // ecx - party pid
xor eax, eax;
end:
pop ecx;
retn;
}
}
static void ResetReadOnlyAttr() {
DWORD attr = GetFileAttributesA((const char*)_F_PATHFILE);
if (attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_READONLY)) {
SetFileAttributesA((const char*)_F_PATHFILE, (attr & ~FILE_ATTRIBUTE_READONLY));
}
}
static void __declspec(naked) SlotMap2Game_hack_attr() {
__asm {
cmp eax, -1;
je end;
cmp ebx, OBJ_TYPE_CRITTER;
jne end;
call ResetReadOnlyAttr;
or eax, 1; // reset ZF
end:
retn 0x8;
}
}
#define _F_SAV (const char*)0x50A480
#define _F_PROTO_CRITTERS (const char*)0x50A490
void RemoveSavFiles() {
MapDirErase(_F_PROTO_CRITTERS, _F_SAV);
}
void ClearSavPrototypes() {
savPrototypes.clear();
RemoveSavFiles();
}
void LoadOrderInit() {
if (GetConfigInt("Misc", "DataLoadOrderPatch", 1)) {
dlog("Applying data load order patch.", DL_INIT);
MakeCall(0x444259, game_init_databases_hack1);
MakeCall(0x4442F1, game_init_databases_hack2);
HookCall(0x44436D, game_init_databases_hook);
SafeWrite8(0x4DFAEC, 0x1D); // error correction (ecx > ebx)
dlogr(" Done", DL_INIT);
}
dlog("Applying party member protos save/load patch.", DL_INIT);
savPrototypes.reserve(25);
HookCall(0x4A1CF2, proto_load_pid_hook);
HookCall(0x4A1BEE, proto_save_pid_hook);
MakeCall(0x47F5A5, GameMap2Slot_hack); // save game
MakeCall(0x47FB80, SlotMap2Game_hack); // load game
MakeCall(0x47FBBF, SlotMap2Game_hack_attr, 1);
dlogr(" Done", DL_INIT);
}
+23
View File
@@ -0,0 +1,23 @@
/*
* sfall
* Copyright (C) 2008-2017 The sfall team
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
void LoadOrderInit();
void RemoveSavFiles();
void ClearSavPrototypes();
+1 -1
View File
@@ -27,7 +27,7 @@
#include "Graphics.h"
#include "Logging.h"
#include "movies.h"
#include "Movies.h"
static DWORD MoviePtrs[MaxMovies];
char MoviePaths[MaxMovies * 65];
View File
+1 -1
View File
@@ -1205,7 +1205,7 @@ static void _stdcall ClearEventsOnMapExit() {
}
}
void ScriptExtenderSetup() {
void ScriptExtenderInit() {
toggleHighlightsKey = GetConfigInt("Input", "ToggleItemHighlightsKey", 0);
if (toggleHighlightsKey) {
MotionSensorMode = GetConfigInt("Misc", "MotionScannerFlags", 1);
+1 -1
View File
@@ -43,7 +43,7 @@ typedef struct {
char initialized;
} sScriptProgram;
void ScriptExtenderSetup();
void ScriptExtenderInit();
bool _stdcall IsGameScript(const char* filename);
void LoadGlobalScripts();
void ClearGlobalScripts();
+1 -1
View File
@@ -24,7 +24,7 @@
#include "Combat.h"
#include "HeroAppearance.h"
#include "KillCounter.h"
#include "movies.h"
#include "Movies.h"
#include "PartyControl.h"
#include "ScriptExtender.h"
+4 -13
View File
@@ -447,21 +447,12 @@ static void __declspec(naked) op_obj_blocking_at() {
static void _stdcall op_tile_get_objects2() {
DWORD tile = opHandler.arg(0).asInt(),
elevation = opHandler.arg(1).asInt(),
obj;
elevation = opHandler.arg(1).asInt();
DWORD arrayId = TempArray(0, 4);
__asm {
mov eax, elevation;
mov edx, tile;
call obj_find_first_at_tile_;
mov obj, eax;
}
TGameObj* obj = ObjFindFirstAtTile(elevation, tile);
while (obj) {
arrays[arrayId].push_back((long)obj);
__asm {
call obj_find_next_at_tile_;
mov obj, eax;
}
arrays[arrayId].push_back(reinterpret_cast<long>(obj));
obj = ObjFindNextAtTile();
}
opHandler.setReturn(arrayId, DATATYPE_INT);
}
+53 -46
View File
@@ -482,6 +482,18 @@ struct sList {
}
};
static DWORD listID = 0xCCCCCC;
struct ListId {
sList* list;
DWORD id;
ListId(sList* lst) : list(lst) {
id = ++listID;
}
};
static std::vector<ListId> mList;
static void FillListVector(DWORD type, std::vector<TGameObj*>& vec) {
vec.reserve(100);
if (type == 6) {
@@ -522,36 +534,28 @@ static void FillListVector(DWORD type, std::vector<TGameObj*>& vec) {
} else if (type != 4) {
for (int elv = 0; elv < 3; elv++) {
for (int tile = 0; tile < 40000; tile++) {
TGameObj* obj;
__asm {
mov edx, tile;
mov eax, elv;
call obj_find_first_at_tile_;
mov obj, eax;
}
TGameObj* obj = ObjFindFirstAtTile(elv, tile);
while (obj) {
DWORD otype = obj->pid >> 24;
if (type == 9 || (type == 0 && otype == 1) || (type == 1 && otype == 0) || (type >= 2 && type <= 5 && type == otype)) {
vec.push_back(obj);
}
__asm {
call obj_find_next_at_tile_;
mov obj, eax;
}
obj = ObjFindNextAtTile();
}
}
}
}
}
static void* _stdcall list_begin2(DWORD type) {
static DWORD _stdcall ListBegin(DWORD type) {
std::vector<TGameObj*> vec = std::vector<TGameObj*>();
FillListVector(type, vec);
sList* list = new sList(&vec);
return list;
mList.push_back(list);
return listID;
}
static DWORD _stdcall list_as_array2(DWORD type) {
static DWORD _stdcall ListAsArray(DWORD type) {
std::vector<TGameObj*> vec = std::vector<TGameObj*>();
FillListVector(type, vec);
size_t sz = vec.size();
@@ -562,14 +566,20 @@ static DWORD _stdcall list_as_array2(DWORD type) {
return id;
}
static TGameObj* _stdcall list_next2(sList* list) {
static TGameObj* _stdcall ListNext(sList* list) {
if (!list || list->pos == list->len) return 0;
else return list->obj[list->pos++];
}
static void _stdcall list_end2(sList* list) {
delete[] list->obj;
delete list;
static void _stdcall ListEnd(DWORD id) {
for (std::vector<ListId>::const_iterator it = mList.cbegin(), it_end = mList.cend(); it != it_end; ++it) {
if (it->id == id) {
delete[] it->list->obj;
delete it->list;
mList.erase(it);
break;
}
}
}
static void __declspec(naked) list_begin() {
@@ -583,7 +593,7 @@ static void __declspec(naked) list_begin() {
cmp di, VAR_TYPE_INT;
jnz fail;
push eax;
call list_begin2;
call ListBegin;
mov edx, eax;
jmp end;
fail:
@@ -599,6 +609,7 @@ end:
retn;
}
}
static void __declspec(naked) list_as_array() {
__asm {
pushad;
@@ -610,7 +621,7 @@ static void __declspec(naked) list_as_array() {
cmp di, VAR_TYPE_INT;
jnz fail;
push eax;
call list_as_array2;
call ListAsArray;
mov edx, eax;
jmp end;
fail:
@@ -626,33 +637,29 @@ end:
retn;
}
}
static void _stdcall list_next2() {
const ScriptValue &idArg = opHandler.arg(0);
if (idArg.isInt()) {
DWORD id = idArg.rawValue();
sList* list = nullptr;
for (std::vector<ListId>::const_iterator it = mList.cbegin(), it_end = mList.cend(); it != it_end; ++it) {
if (it->id == id) {
list = it->list;
break;
}
}
opHandler.setReturn(ListNext(list));
} else {
OpcodeInvalidArgs("list_next");
opHandler.setReturn(-1);
}
}
static void __declspec(naked) list_next() {
__asm {
pushad;
mov ebp, eax;
call interpretPopShort_;
mov edi, eax;
mov eax, ebp;
call interpretPopLong_;
cmp di, VAR_TYPE_INT;
jnz fail;
push eax;
call list_next2;
mov edx, eax;
jmp end;
fail:
xor edx, edx;
dec edx;
end:
mov eax, ebp;
call interpretPushLong_;
mov eax, ebp;
mov edx, VAR_TYPE_INT;
call interpretPushShort_;
popad;
retn;
}
_WRAP_OPCODE(list_next2, 1, 1)
}
static void __declspec(naked) list_end() {
__asm {
pushad;
@@ -664,7 +671,7 @@ static void __declspec(naked) list_end() {
cmp di, VAR_TYPE_INT;
jnz end;
push eax;
call list_end2;
call ListEnd;
end:
popad;
retn;
+1 -1
View File
@@ -23,7 +23,7 @@
#include "Combat.h"
#include "Criticals.h"
#include "ScriptExtender.h"
#include "skills.h"
#include "Skills.h"
#include "Stats.h"
const char* invalidStat = "%s() - stat number out of range.";
View File
View File
View File

Some files were not shown because too many files have changed in this diff Show More