mirror of
https://github.com/sfall-team/sfall.git
synced 2026-07-27 16:52:34 -07:00
Added "set_quest_failure_value" script function
This commit is contained in:
@@ -377,6 +377,7 @@
|
|||||||
#define set_map_enter_position(tile, elev, rot) sfall_func3("set_map_enter_position", tile, elev, rot)
|
#define set_map_enter_position(tile, elev, rot) sfall_func3("set_map_enter_position", tile, elev, rot)
|
||||||
#define set_object_data(obj, offset, value) sfall_func3("set_object_data", obj, offset, value)
|
#define set_object_data(obj, offset, value) sfall_func3("set_object_data", obj, offset, value)
|
||||||
#define set_outline(obj, color) sfall_func2("set_outline", obj, color)
|
#define set_outline(obj, color) sfall_func2("set_outline", obj, color)
|
||||||
|
#define set_quest_failure_value(gvar, threshold) sfall_func2("set_quest_failure_value", gvar, threshold)
|
||||||
#define set_rest_heal_time(time) sfall_func1("set_rest_heal_time", time)
|
#define set_rest_heal_time(time) sfall_func1("set_rest_heal_time", time)
|
||||||
#define set_rest_mode(mode) sfall_func1("set_rest_mode", mode)
|
#define set_rest_mode(mode) sfall_func1("set_rest_mode", mode)
|
||||||
#define set_terrain_name(x, y, name) sfall_func3("set_terrain_name", x, y, name)
|
#define set_terrain_name(x, y, name) sfall_func3("set_terrain_name", x, y, name)
|
||||||
|
|||||||
@@ -791,6 +791,11 @@ optional arguments:
|
|||||||
2 - clears the overlay area or the specified rectangle defined by the x, y, width, height arguments
|
2 - clears the overlay area or the specified rectangle defined by the x, y, width, height arguments
|
||||||
0 - destroys the created overlay surface (frees up the memory allocated to the surface)
|
0 - destroys the created overlay surface (frees up the memory allocated to the surface)
|
||||||
|
|
||||||
|
> void sfall_func2("set_quest_failure_value", int gvarNumber, int thresholdValue)
|
||||||
|
- sets the threshold value (failure_threshold) for the quest at which the quest will be considered failed (its description in the pipboy will be crossed out and colored red)
|
||||||
|
- gvarNumber: the number of the global variable controlling the quest
|
||||||
|
- thresholdValue: the value of the global variable at which the quest is counted as a failure
|
||||||
|
|
||||||
------------------------
|
------------------------
|
||||||
------ MORE INFO -------
|
------ MORE INFO -------
|
||||||
------------------------
|
------------------------
|
||||||
|
|||||||
@@ -224,6 +224,7 @@
|
|||||||
#define FO_VAR_ptable 0x59E934
|
#define FO_VAR_ptable 0x59E934
|
||||||
#define FO_VAR_pud 0x59E960
|
#define FO_VAR_pud 0x59E960
|
||||||
#define FO_VAR_quest_count 0x51C12C
|
#define FO_VAR_quest_count 0x51C12C
|
||||||
|
#define FO_VAR_quests 0x51C128
|
||||||
#define FO_VAR_queue 0x6648C0
|
#define FO_VAR_queue 0x6648C0
|
||||||
#define FO_VAR_quick_done 0x5193BC
|
#define FO_VAR_quick_done 0x5193BC
|
||||||
#define FO_VAR_read_callback 0x51DEEC
|
#define FO_VAR_read_callback 0x51DEEC
|
||||||
|
|||||||
@@ -197,11 +197,13 @@ static void __fastcall game_init_databases_hook1() {
|
|||||||
|
|
||||||
static bool NormalizePath(std::string &path) {
|
static bool NormalizePath(std::string &path) {
|
||||||
if (path.find(':') != std::string::npos) return false;
|
if (path.find(':') != std::string::npos) return false;
|
||||||
|
|
||||||
int pos = 0;
|
int pos = 0;
|
||||||
do { // replace all '/' char to '\'
|
do { // replace all '/' char to '\'
|
||||||
pos = path.find('/', pos);
|
pos = path.find('/', pos);
|
||||||
if (pos != std::string::npos) path[pos] = '\\';
|
if (pos != std::string::npos) path[pos] = '\\';
|
||||||
} while (pos != std::string::npos);
|
} while (pos != std::string::npos);
|
||||||
|
|
||||||
if (path.find(".\\") != std::string::npos || path.find("..\\") != std::string::npos) return false;
|
if (path.find(".\\") != std::string::npos || path.find("..\\") != std::string::npos) return false;
|
||||||
while (path.front() == '\\') path.erase(0, 1); // remove firsts '\'
|
while (path.front() == '\\') path.erase(0, 1); // remove firsts '\'
|
||||||
return true;
|
return true;
|
||||||
@@ -434,18 +436,20 @@ artNotExist:
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void SfallResourceFile() {
|
static void SfallResourceFile() {
|
||||||
|
const char* sfallRes = "sfall.dat";
|
||||||
|
|
||||||
WIN32_FIND_DATA findData;
|
WIN32_FIND_DATA findData;
|
||||||
HANDLE hFind = FindFirstFile("sfall_???.dat", &findData); // example: sfall_ru.dat, sfall_cht.dat
|
HANDLE hFind = FindFirstFile("sfall_???.dat", &findData); // example: sfall_ru.dat, sfall_cht.dat
|
||||||
if (hFind != INVALID_HANDLE_VALUE) {
|
if (hFind != INVALID_HANDLE_VALUE) {
|
||||||
dlog_f("Loading a localized sfall resource file: %s\n", DL_MAIN, findData.cFileName);
|
|
||||||
patchFiles.push_back(findData.cFileName);
|
|
||||||
FindClose(hFind);
|
FindClose(hFind);
|
||||||
|
dlog_f("Loading a localized sfall resource file: %s\n", DL_MAIN, findData.cFileName);
|
||||||
|
sfallRes = findData.cFileName;
|
||||||
}
|
}
|
||||||
if (patchFiles.empty()) patchFiles.push_back("sfall.dat");
|
patchFiles.push_back(sfallRes);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoadOrder::init() {
|
void LoadOrder::init() {
|
||||||
SfallResourceFile(); // Load external sfall resource file (load order is before patchXXX.dat)
|
SfallResourceFile(); // Add external sfall resource file (load order is before patchXXX.dat)
|
||||||
GetExtraPatches();
|
GetExtraPatches();
|
||||||
MultiPatchesPatch();
|
MultiPatchesPatch();
|
||||||
|
|
||||||
|
|||||||
+71
-27
@@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
#include "..\main.h"
|
#include "..\main.h"
|
||||||
#include "..\FalloutEngine\Fallout2.h"
|
#include "..\FalloutEngine\Fallout2.h"
|
||||||
|
#include "LoadGameHook.h"
|
||||||
|
|
||||||
#include "QuestList.h"
|
#include "QuestList.h"
|
||||||
|
|
||||||
@@ -314,8 +315,8 @@ static DWORD __fastcall ActionButtons(DWORD key) {
|
|||||||
curent_quest_page++;
|
curent_quest_page++;
|
||||||
first_quest_page = pageQuest[curent_quest_page];
|
first_quest_page = pageQuest[curent_quest_page];
|
||||||
last_quest_page = ((pageQuest.size() - 1) > curent_quest_page)
|
last_quest_page = ((pageQuest.size() - 1) > curent_quest_page)
|
||||||
? pageQuest[curent_quest_page + 1] - 1
|
? pageQuest[curent_quest_page + 1] - 1
|
||||||
: INT_MAX;
|
: INT_MAX;
|
||||||
buttonsPressed = true;
|
buttonsPressed = true;
|
||||||
return called_quest_number;
|
return called_quest_number;
|
||||||
}
|
}
|
||||||
@@ -343,31 +344,17 @@ skip:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void RegisterButtonSoundFunc0() {
|
static void RegisterButtonSound() {
|
||||||
__asm {
|
__asm {
|
||||||
mov ebx, fo::funcoffs::gsound_red_butt_release_;
|
mov ebx, fo::funcoffs::gsound_red_butt_release_;
|
||||||
mov edx, fo::funcoffs::gsound_red_butt_press_;
|
mov edx, fo::funcoffs::gsound_red_butt_press_;
|
||||||
call fo::funcoffs::win_register_button_sound_func_;
|
call fo::funcoffs::win_register_button_sound_func_; // eax - register button
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void __stdcall ArtButtonFunc(DWORD buttonKey, DWORD buttonMem, DWORD indexArt) {
|
static void LoadArtButton(DWORD buttonKey, DWORD buttonMem, DWORD indexArt) { // indexArt - index from intrface.lst
|
||||||
using namespace fo;
|
long artId = fo::func::art_id(fo::ArtType::OBJ_TYPE_INTRFACE, indexArt, 0, 0, 0);
|
||||||
__asm {
|
*(BYTE**)buttonMem = fo::func::art_ptr_lock_data(artId, 0, 0, (DWORD*)buttonKey); // first texture memory address
|
||||||
xor ecx, ecx;
|
|
||||||
xor ebx, ebx;
|
|
||||||
mov edx, indexArt; // index from intrface.lst
|
|
||||||
mov eax, OBJ_TYPE_INTRFACE;
|
|
||||||
push ecx;
|
|
||||||
call fo::funcoffs::art_id_;
|
|
||||||
//
|
|
||||||
mov ecx, buttonKey;
|
|
||||||
xor ebx, ebx;
|
|
||||||
xor edx, edx;
|
|
||||||
call fo::funcoffs::art_ptr_lock_data_;
|
|
||||||
mov ecx, buttonMem;
|
|
||||||
mov dword ptr [ecx], eax; // first texture memory address
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create buttons
|
// Create buttons
|
||||||
@@ -407,11 +394,11 @@ static void __declspec(naked) StartPipboy_hack() {
|
|||||||
// Load new texture for first (up) button. I used memory address for texture from buttons at chracter screen.
|
// Load new texture for first (up) button. I used memory address for texture from buttons at chracter screen.
|
||||||
// Everything fine, because this buttons can't use in one time, and they everytime recreating.
|
// Everything fine, because this buttons can't use in one time, and they everytime recreating.
|
||||||
// Down
|
// Down
|
||||||
ArtButtonFunc(FO_VAR_optionsButtonUpKey, FO_VAR_optionsButtonUp, indexUpArt0);
|
LoadArtButton(FO_VAR_optionsButtonUpKey, FO_VAR_optionsButtonUp, indexUpArt0);
|
||||||
ArtButtonFunc(FO_VAR_optionsButtonDownKey, FO_VAR_optionsButtonDown, indexDownArt0);
|
LoadArtButton(FO_VAR_optionsButtonDownKey, FO_VAR_optionsButtonDown, indexDownArt0);
|
||||||
// Up
|
// Up
|
||||||
ArtButtonFunc(FO_VAR_optionsButtonUpKey, FO_VAR_optionsButtonUp1, indexUpArt1);
|
LoadArtButton(FO_VAR_optionsButtonUpKey, FO_VAR_optionsButtonUp1, indexUpArt1);
|
||||||
ArtButtonFunc(FO_VAR_optionsButtonDownKey, FO_VAR_optionsButtonDown1, indexDownArt1);
|
LoadArtButton(FO_VAR_optionsButtonDownKey, FO_VAR_optionsButtonDown1, indexDownArt1);
|
||||||
|
|
||||||
xPos = questsScrollButtonsX;
|
xPos = questsScrollButtonsX;
|
||||||
yPos = questsScrollButtonsY;
|
yPos = questsScrollButtonsY;
|
||||||
@@ -421,13 +408,13 @@ static void __declspec(naked) StartPipboy_hack() {
|
|||||||
picDown = (BYTE*)fo::var::optionsButtonDown1;
|
picDown = (BYTE*)fo::var::optionsButtonDown1;
|
||||||
picUp = (BYTE*)fo::var::optionsButtonUp1;
|
picUp = (BYTE*)fo::var::optionsButtonUp1;
|
||||||
if (fo::func::win_register_button(winRef, xPos, yPos, width, height, -1, -1, -1, 0x300, picUp, picDown, 0, 32) != -1) {
|
if (fo::func::win_register_button(winRef, xPos, yPos, width, height, -1, -1, -1, 0x300, picUp, picDown, 0, 32) != -1) {
|
||||||
RegisterButtonSoundFunc0();
|
RegisterButtonSound();
|
||||||
}
|
}
|
||||||
|
|
||||||
picDown = (BYTE*)fo::var::optionsButtonDown;
|
picDown = (BYTE*)fo::var::optionsButtonDown;
|
||||||
picUp = (BYTE*)fo::var::optionsButtonUp;
|
picUp = (BYTE*)fo::var::optionsButtonUp;
|
||||||
if (fo::func::win_register_button(winRef, xPos, yPos + height, width, height, -1, -1, -1, 0x301, picUp, picDown, 0, 32) != -1) {
|
if (fo::func::win_register_button(winRef, xPos, yPos + height, width, height, -1, -1, -1, 0x301, picUp, picDown, 0, 32) != -1) {
|
||||||
RegisterButtonSoundFunc0();
|
RegisterButtonSound();
|
||||||
}
|
}
|
||||||
|
|
||||||
__asm {
|
__asm {
|
||||||
@@ -504,7 +491,64 @@ void QuestListPatch() {
|
|||||||
MakeCall(0x497A7D, pip_print_hack);
|
MakeCall(0x497A7D, pip_print_hack);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
struct QuestFailure {
|
||||||
|
long gvarNum;
|
||||||
|
long failureVal;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<QuestFailure> questFailures;
|
||||||
|
|
||||||
|
static long FindGVarQuestFailure(long globalVarNum) {
|
||||||
|
for (size_t i = 0; i < questFailures.size(); i++) {
|
||||||
|
if (questFailures[i].gvarNum == globalVarNum) return i;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void QuestList::AddQuestFailureValue(long globalVarNum, long failureThreshold) {
|
||||||
|
long index = FindGVarQuestFailure(globalVarNum);
|
||||||
|
if (index == -1) {
|
||||||
|
questFailures.push_back({ globalVarNum, failureThreshold });
|
||||||
|
} else {
|
||||||
|
questFailures[index].failureVal = failureThreshold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static BYTE __fastcall CheckQuestFailureState(fo::QuestData* quest, BYTE completeColor) {
|
||||||
|
if (questFailures.empty()) return completeColor;
|
||||||
|
|
||||||
|
const BYTE failureColor = 136; // dark red
|
||||||
|
|
||||||
|
long index = FindGVarQuestFailure(quest->gvarIndex);
|
||||||
|
return (index != -1 && fo::var::game_global_vars[quest->gvarIndex] >= questFailures[index].failureVal) ? failureColor : completeColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void __declspec(naked) PipStatus_hack() {
|
||||||
|
__asm {
|
||||||
|
push eax;
|
||||||
|
push ecx;
|
||||||
|
mov dl, ds:[0x6A5B34]; // completeColor (dark green)
|
||||||
|
mov ecx, ds:[FO_VAR_quests];
|
||||||
|
add ecx, [esp + 0x4BC - 0x28 + 12];
|
||||||
|
call CheckQuestFailureState;
|
||||||
|
mov bl, al;
|
||||||
|
pop ecx;
|
||||||
|
pop eax;
|
||||||
|
retn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void ResetQuests() {
|
||||||
|
questFailures.clear();
|
||||||
|
}
|
||||||
|
|
||||||
void QuestList::init() {
|
void QuestList::init() {
|
||||||
|
LoadGameHook::OnGameReset() += ResetQuests;
|
||||||
|
|
||||||
|
MakeCall(0x498222, PipStatus_hack, 1);
|
||||||
|
|
||||||
questsButtonsType = GetConfigInt("Misc", "UseScrollingQuestsList", 0);
|
questsButtonsType = GetConfigInt("Misc", "UseScrollingQuestsList", 0);
|
||||||
if (questsButtonsType > 0) {
|
if (questsButtonsType > 0) {
|
||||||
dlog("Applying quests list patch.", DL_INIT);
|
dlog("Applying quests list patch.", DL_INIT);
|
||||||
|
|||||||
@@ -25,6 +25,8 @@ class QuestList : public Module {
|
|||||||
public:
|
public:
|
||||||
const char* name() { return "QuestList"; }
|
const char* name() { return "QuestList"; }
|
||||||
void init();
|
void init();
|
||||||
|
|
||||||
|
static void AddQuestFailureValue(long globalVarNum, long failureThreshold);
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -136,6 +136,7 @@ static const SfallMetarule metarules[] = {
|
|||||||
{"set_map_enter_position", mf_set_map_enter_position, 3, 3, -1, {ARG_INT, ARG_INT, ARG_INT}},
|
{"set_map_enter_position", mf_set_map_enter_position, 3, 3, -1, {ARG_INT, ARG_INT, ARG_INT}},
|
||||||
{"set_object_data", mf_set_object_data, 3, 3, -1, {ARG_OBJECT, ARG_INT, ARG_INT}},
|
{"set_object_data", mf_set_object_data, 3, 3, -1, {ARG_OBJECT, ARG_INT, ARG_INT}},
|
||||||
{"set_outline", mf_set_outline, 2, 2, -1, {ARG_OBJECT, ARG_INT}},
|
{"set_outline", mf_set_outline, 2, 2, -1, {ARG_OBJECT, ARG_INT}},
|
||||||
|
{"set_quest_failure_value", mf_set_quest_failure_value, 2, 2, -1, {ARG_INT, ARG_INT}},
|
||||||
{"set_rest_heal_time", mf_set_rest_heal_time, 1, 1, -1, {ARG_INT}},
|
{"set_rest_heal_time", mf_set_rest_heal_time, 1, 1, -1, {ARG_INT}},
|
||||||
{"set_rest_mode", mf_set_rest_mode, 1, 1, -1, {ARG_INT}},
|
{"set_rest_mode", mf_set_rest_mode, 1, 1, -1, {ARG_INT}},
|
||||||
{"set_selectable_perk_npc", mf_set_selectable_perk_npc, 5, 5, -1, {ARG_OBJECT, ARG_STRING, ARG_INT, ARG_INT, ARG_STRING}},
|
{"set_selectable_perk_npc", mf_set_selectable_perk_npc, 5, 5, -1, {ARG_OBJECT, ARG_STRING, ARG_INT, ARG_INT, ARG_STRING}},
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
//#include "..\..\MiscPatches.h"
|
//#include "..\..\MiscPatches.h"
|
||||||
#include "..\..\Movies.h"
|
#include "..\..\Movies.h"
|
||||||
#include "..\..\PlayerModel.h"
|
#include "..\..\PlayerModel.h"
|
||||||
|
#include "..\..\QuestList.h"
|
||||||
#include "..\..\ScriptExtender.h"
|
#include "..\..\ScriptExtender.h"
|
||||||
#include "..\..\Sound.h"
|
#include "..\..\Sound.h"
|
||||||
|
|
||||||
@@ -496,5 +497,9 @@ void mf_get_ini_section(OpcodeContext& ctx) {
|
|||||||
ctx.setReturn(arrayId);
|
ctx.setReturn(arrayId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void mf_set_quest_failure_value(OpcodeContext& ctx) {
|
||||||
|
QuestList::AddQuestFailureValue(ctx.arg(0).rawValue(), ctx.arg(1).rawValue());
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -102,5 +102,7 @@ void mf_get_ini_sections(OpcodeContext&);
|
|||||||
|
|
||||||
void mf_get_ini_section(OpcodeContext&);
|
void mf_get_ini_section(OpcodeContext&);
|
||||||
|
|
||||||
|
void mf_set_quest_failure_value(OpcodeContext&);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user