Merge pull request #531 from sfall-team/feature/inventory-slot-extensions

Added inventory/barter slot extensions
This commit is contained in:
NovaRain
2024-05-10 23:32:26 +08:00
committed by GitHub
32 changed files with 615 additions and 313 deletions
+9
View File
@@ -133,6 +133,15 @@ WorldMapTravelMarkers=0
;Set to 1 to display terrain types when hovering the cursor over the player's marker on the world map ;Set to 1 to display terrain types when hovering the cursor over the player's marker on the world map
WorldMapTerrainInfo=0 WorldMapTerrainInfo=0
;Set to 1 to enable tall trade/barter window with 4 item slots per table instead of 3
;Requires the high-res mode with resolution of at least 640x528
;Requires new frm files in art\intrface\: barter_e.frm (640x239), trade_e.frm (640x238) (included in sfall.dat)
ExpandedBarter=0
;Set to 1 to enable tall inventory/loot/item select windows with 8 vertical slots instead of 6
;Requires new frm files in art\intrface\: invbox_e.frm (499x467), loot_e.frm (537x464) and use_e.frm (292x464) files (included in sfall.dat)
ExpandedInventory=0
;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX ;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
[Sound] [Sound]
;Sets the number of allowed simultaneous sound effects ;Sets the number of allowed simultaneous sound effects
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+1 -101
View File
@@ -409,7 +409,7 @@ fo::GameObject* __fastcall MultiHexMoveIsBlocking(fo::GameObject* source, long d
// Returns the terrain type of the sub-tile at the specified coordinates on the world map // Returns the terrain type of the sub-tile at the specified coordinates on the world map
long wmGetTerrainType(long xPos, long yPos) { long wmGetTerrainType(long xPos, long yPos) {
long* terrainId; long* terrainId{};
__asm { __asm {
lea ebx, terrainId; lea ebx, terrainId;
mov edx, yPos; mov edx, yPos;
@@ -667,105 +667,5 @@ void RefreshGNW(bool skipOwner) {
fo::var::setInt(FO_VAR_doing_refresh_all) = 0; fo::var::setInt(FO_VAR_doing_refresh_all) = 0;
} }
//////////////////////////// UNLISTED FRM FUNCTIONS ////////////////////////////
static bool LoadFrmHeader(fo::UnlistedFrm *frmHeader, fo::DbFile* frmStream) {
if (fo::func::db_freadInt(frmStream, &frmHeader->version) == -1)
return false;
else if (fo::func::db_freadShort(frmStream, &frmHeader->FPS) == -1)
return false;
else if (fo::func::db_freadShort(frmStream, &frmHeader->actionFrame) == -1)
return false;
else if (fo::func::db_freadShort(frmStream, &frmHeader->numFrames) == -1)
return false;
else if (fo::func::db_freadShortCount(frmStream, frmHeader->xCentreShift, 6) == -1)
return false;
else if (fo::func::db_freadShortCount(frmStream, frmHeader->yCentreShift, 6) == -1)
return false;
else if (fo::func::db_freadIntCount(frmStream, frmHeader->oriOffset, 6) == -1)
return false;
else if (fo::func::db_freadInt(frmStream, &frmHeader->frameAreaSize) == -1)
return false;
return true;
}
static bool LoadFrmFrame(fo::UnlistedFrm::Frame *frame, fo::DbFile* frmStream) {
//FRMframe *frameHeader = (FRMframe*)frameMEM;
//BYTE* frameBuff = frame + sizeof(FRMframe);
if (fo::func::db_freadShort(frmStream, &frame->width) == -1)
return false;
else if (fo::func::db_freadShort(frmStream, &frame->height) == -1)
return false;
else if (fo::func::db_freadInt(frmStream, &frame->size) == -1)
return false;
else if (fo::func::db_freadShort(frmStream, &frame->x) == -1)
return false;
else if (fo::func::db_freadShort(frmStream, &frame->y) == -1)
return false;
frame->indexBuff = new BYTE[frame->size];
if (fo::func::db_fread(frame->indexBuff, 1, frame->size, frmStream) != frame->size)
return false;
return true;
}
fo::UnlistedFrm *LoadUnlistedFrm(char *frmName, unsigned int folderRef) {
if (folderRef > fo::OBJ_TYPE_SKILLDEX) return nullptr;
const char *artfolder = fo::var::art[folderRef].path; // address of art type name
char frmPath[MAX_PATH];
if (fo::var::use_language) {
sprintf_s(frmPath, MAX_PATH, "art\\%s\\%s\\%s", (const char*)fo::var::language, artfolder, frmName);
} else {
sprintf_s(frmPath, MAX_PATH, "art\\%s\\%s", artfolder, frmName);
}
fo::UnlistedFrm *frm = new fo::UnlistedFrm;
auto frmStream = fo::func::db_fopen(frmPath, "rb");
if (!frmStream && fo::var::use_language) {
sprintf_s(frmPath, MAX_PATH, "art\\%s\\%s", artfolder, frmName);
frmStream = fo::func::db_fopen(frmPath, "rb");
}
if (frmStream != nullptr) {
if (!LoadFrmHeader(frm, frmStream)) {
fo::func::db_fclose(frmStream);
delete frm;
return nullptr;
}
DWORD oriOffset_1st = frm->oriOffset[0];
DWORD oriOffset_new = 0;
frm->frames = new fo::UnlistedFrm::Frame[6 * frm->numFrames];
for (int ori = 0; ori < 6; ori++) {
if (ori == 0 || frm->oriOffset[ori] != oriOffset_1st) {
frm->oriOffset[ori] = oriOffset_new;
for (int fNum = 0; fNum < frm->numFrames; fNum++) {
if (!LoadFrmFrame(&frm->frames[oriOffset_new + fNum], frmStream)) {
fo::func::db_fclose(frmStream);
delete frm;
return nullptr;
}
}
oriOffset_new += frm->numFrames;
} else {
frm->oriOffset[ori] = 0;
}
}
fo::func::db_fclose(frmStream);
} else {
delete frm;
return nullptr;
}
return frm;
}
} }
} }
+14 -2
View File
@@ -33,6 +33,20 @@ namespace fo
namespace util namespace util
{ {
// To safely unlock cache entries after using art_ptr_lock and similar functions
struct ArtCacheLock {
DWORD entryPtr = 0;
ArtCacheLock() { }
ArtCacheLock(DWORD _lock) : entryPtr(_lock) { }
~ArtCacheLock() {
if (entryPtr != 0) {
fo::func::art_ptr_unlock(entryPtr);
entryPtr = 0;
}
}
};
__inline void DisplayPrint(const std::string& str) { __inline void DisplayPrint(const std::string& str) {
fo::func::display_print(str.c_str()); fo::func::display_print(str.c_str());
} }
@@ -191,7 +205,5 @@ void RedrawObject(fo::GameObject* obj);
// Redraws all windows // Redraws all windows
void RefreshGNW(bool skipOwner = false); void RefreshGNW(bool skipOwner = false);
fo::UnlistedFrm *LoadUnlistedFrm(char *frmName, unsigned int folderRef);
} }
} }
+27
View File
@@ -927,4 +927,31 @@ enum DialogOutFlags : long
DIALOGOUT_CLEAN = 0x20 // no buttons DIALOGOUT_CLEAN = 0x20 // no buttons
}; };
enum InventoryWindowType : unsigned long
{
// Normal inventory window with quick character sheet.
INVENTORY_WINDOW_TYPE_NORMAL,
// Narrow inventory window with just an item scroller that's shown when
// a "Use item on" is selected from context menu.
INVENTORY_WINDOW_TYPE_USE_ITEM_ON,
// Looting/strealing interface.
INVENTORY_WINDOW_TYPE_LOOT,
// Barter interface.
INVENTORY_WINDOW_TYPE_TRADE,
// Supplementary "Move items" window. Used to set quantity of items when
// moving items between inventories.
INVENTORY_WINDOW_TYPE_MOVE_ITEMS,
// Supplementary "Set timer" window. Internally it's implemented as "Move
// items" window but with timer overlay and slightly different adjustment
// mechanics.
INVENTORY_WINDOW_TYPE_SET_TIMER,
INVENTORY_WINDOW_TYPE_COUNT,
};
} }
+15 -67
View File
@@ -29,8 +29,8 @@ namespace sfall
struct Rectangle { struct Rectangle {
long x, y, width, height; long x, y, width, height;
long right() { return x + (width - 1); } long right() const { return x + (width - 1); }
long bottom() { return y + (height - 1); } long bottom() const { return y + (height - 1); }
}; };
} }
@@ -208,25 +208,25 @@ struct GameObject {
long rads; long rads;
long poison; long poison;
inline bool IsDead() { inline bool IsDead() const {
return ((damageFlags & DamageFlag::DAM_DEAD) != 0); return ((damageFlags & DamageFlag::DAM_DEAD) != 0);
} }
inline bool IsNotDead() { inline bool IsNotDead() const {
return ((damageFlags & DamageFlag::DAM_DEAD) == 0); return ((damageFlags & DamageFlag::DAM_DEAD) == 0);
} }
inline bool IsActive() { inline bool IsActive() const {
return ((damageFlags & (DamageFlag::DAM_KNOCKED_OUT | DamageFlag::DAM_LOSE_TURN)) == 0); return ((damageFlags & (DamageFlag::DAM_KNOCKED_OUT | DamageFlag::DAM_LOSE_TURN)) == 0);
} }
inline bool IsNotActive() { inline bool IsNotActive() const {
return ((damageFlags & (DamageFlag::DAM_KNOCKED_OUT | DamageFlag::DAM_LOSE_TURN)) != 0); return ((damageFlags & (DamageFlag::DAM_KNOCKED_OUT | DamageFlag::DAM_LOSE_TURN)) != 0);
} }
inline bool IsActiveNotDead() { inline bool IsActiveNotDead() const {
return ((damageFlags & (DamageFlag::DAM_DEAD | DamageFlag::DAM_KNOCKED_OUT | DamageFlag::DAM_LOSE_TURN)) == 0); return ((damageFlags & (DamageFlag::DAM_DEAD | DamageFlag::DAM_KNOCKED_OUT | DamageFlag::DAM_LOSE_TURN)) == 0);
} }
inline bool IsNotActiveOrDead() { inline bool IsNotActiveOrDead() const {
return ((damageFlags & (DamageFlag::DAM_DEAD | DamageFlag::DAM_KNOCKED_OUT | DamageFlag::DAM_LOSE_TURN)) != 0); return ((damageFlags & (DamageFlag::DAM_DEAD | DamageFlag::DAM_KNOCKED_OUT | DamageFlag::DAM_LOSE_TURN)) != 0);
} }
inline bool IsFleeing() { inline bool IsFleeing() const {
return ((combatState & CombatStateFlag::InFlee) != 0); return ((combatState & CombatStateFlag::InFlee) != 0);
} }
@@ -255,23 +255,23 @@ struct GameObject {
GameObject* owner; // not saved GameObject* owner; // not saved
long scriptIndex; long scriptIndex;
inline char Type() { inline char Type() const {
return (protoId >> 24); return (protoId >> 24);
} }
inline char TypeFid() { inline char TypeFid() const {
return ((artFid >> 24) & 0x0F); return ((artFid >> 24) & 0x0F);
} }
inline bool IsCritter() { inline bool IsCritter() const {
return (Type() == fo::ObjType::OBJ_TYPE_CRITTER); return (Type() == fo::ObjType::OBJ_TYPE_CRITTER);
} }
inline bool IsNotCritter() { inline bool IsNotCritter() const {
return (Type() != fo::ObjType::OBJ_TYPE_CRITTER); return (Type() != fo::ObjType::OBJ_TYPE_CRITTER);
} }
inline bool IsItem() { inline bool IsItem() const {
return (Type() == fo::ObjType::OBJ_TYPE_ITEM); return (Type() == fo::ObjType::OBJ_TYPE_ITEM);
} }
inline bool IsNotItem() { inline bool IsNotItem() const {
return (Type() != fo::ObjType::OBJ_TYPE_ITEM); return (Type() != fo::ObjType::OBJ_TYPE_ITEM);
} }
}; };
@@ -498,58 +498,6 @@ struct TileFrmFile : public FrmHeaderData {
static_assert(sizeof(TileFrmFile) == 2954, "Incorrect TileFrmFile definition."); static_assert(sizeof(TileFrmFile) == 2954, "Incorrect TileFrmFile definition.");
// structures for loading unlisted frms
struct UnlistedFrm {
DWORD version;
WORD FPS;
WORD actionFrame;
WORD numFrames;
WORD xCentreShift[6];
WORD yCentreShift[6];
DWORD oriOffset[6];
DWORD frameAreaSize;
struct Frame {
WORD width;
WORD height;
DWORD size;
WORD x;
WORD y;
BYTE *indexBuff;
Frame() {
width = 0;
height = 0;
size = 0;
x = 0;
y = 0;
indexBuff = nullptr;
}
~Frame() {
if (indexBuff != nullptr)
delete[] indexBuff;
}
} *frames;
UnlistedFrm() {
version = 0;
FPS = 0;
actionFrame = 0;
numFrames = 0;
for (int i = 0; i < 6; i++) {
xCentreShift[i] = 0;
yCentreShift[i] = 0;
oriOffset[i] = 0;
}
frameAreaSize = 0;
frames = nullptr;
}
~UnlistedFrm() {
if (frames != nullptr) delete[] frames;
}
};
//for holding a message //for holding a message
struct MessageNode { struct MessageNode {
long number; long number;
+1
View File
@@ -169,6 +169,7 @@
#define FO_VAR_intface_full_width 0x56FB4C #define FO_VAR_intface_full_width 0x56FB4C
#define FO_VAR_intfaceEnabled 0x518F10 #define FO_VAR_intfaceEnabled 0x518F10
#define FO_VAR_intotal 0x43E95C #define FO_VAR_intotal 0x43E95C
#define FO_VAR_inven_cur_disp 0x519054
#define FO_VAR_inven_dude 0x519058 #define FO_VAR_inven_dude 0x519058
#define FO_VAR_inven_pid 0x51905C #define FO_VAR_inven_pid 0x51905C
#define FO_VAR_inven_scroll_dn_bid 0x5190E8 #define FO_VAR_inven_scroll_dn_bid 0x5190E8
+1
View File
@@ -18,6 +18,7 @@ VAR_(BlueColor, BYTE)
VAR_(bottom_line, DWORD) VAR_(bottom_line, DWORD)
VAR_(btable, DWORD) VAR_(btable, DWORD)
VAR_(btncnt, DWORD) VAR_(btncnt, DWORD)
VAR_(buf_length_2, long)
VARD(cap, fo::AIcap) // dynamic array VARD(cap, fo::AIcap) // dynamic array
VAR_(carCurrentArea, DWORD) VAR_(carCurrentArea, DWORD)
VAR_(carGasAmount, long) // from 0 to 80000 VAR_(carGasAmount, long) // from 0 to 80000
+6 -9
View File
@@ -6,6 +6,7 @@
#include "..\main.h" #include "..\main.h"
#include "..\FalloutEngine\Fallout2.h" #include "..\FalloutEngine\Fallout2.h"
#include "..\Modules\ExtraArt.h"
#include "..\Modules\LoadGameHook.h" #include "..\Modules\LoadGameHook.h"
#include "Init.h" #include "Init.h"
@@ -22,7 +23,7 @@ namespace sf = sfall;
static const long width = 640; // art static const long width = 640; // art
static long scr_width = 639; static long scr_width = 639;
static fo::UnlistedFrm* altDialogArt; static fo::FrmFile* altDialogArt;
bool Dialog::DIALOG_SCRN_ART_FIX = true; bool Dialog::DIALOG_SCRN_ART_FIX = true;
bool Dialog::DIALOG_SCRN_BACKGROUND = false; bool Dialog::DIALOG_SCRN_BACKGROUND = false;
@@ -172,20 +173,16 @@ static bool loadAltDialogArt = false;
static void __cdecl talk_to_refresh_background_window_hook_buf_to_buf(BYTE* src, long w, long h, long srcWidth, BYTE* dst, long dstWidth) { static void __cdecl talk_to_refresh_background_window_hook_buf_to_buf(BYTE* src, long w, long h, long srcWidth, BYTE* dst, long dstWidth) {
if (!loadAltDialogArt) { if (!loadAltDialogArt) {
loadAltDialogArt = true; loadAltDialogArt = true;
altDialogArt = fo::util::LoadUnlistedFrm("HR_ALLTLK.frm", fo::ArtType::OBJ_TYPE_INTRFACE); altDialogArt = sf::LoadUnlistedFrmCached("HR_ALLTLK.frm", fo::ArtType::OBJ_TYPE_INTRFACE);
} }
if (altDialogArt) { if (altDialogArt) {
src = altDialogArt->frames->indexBuff; src = altDialogArt->frameData[0].data;
srcWidth = altDialogArt->frames->width; srcWidth = altDialogArt->frameData[0].width;
} }
fo::func::buf_to_buf(src, w, h, srcWidth, dst, dstWidth); fo::func::buf_to_buf(src, w, h, srcWidth, dst, dstWidth);
} }
static void UnloadDialogArt() { static void UnloadDialogArt() {
if (altDialogArt) {
delete altDialogArt;
altDialogArt = nullptr;
}
loadAltDialogArt = false; loadAltDialogArt = false;
} }
@@ -273,7 +270,7 @@ void Dialog::init() {
fo::var::backgrndRects[i].offy += 5; fo::var::backgrndRects[i].offy += 5;
} }
sf::LoadGameHook::OnGameExit() += UnloadDialogArt; sf::LoadGameHook::OnGameReset() += UnloadDialogArt;
} }
} }
+15 -19
View File
@@ -6,6 +6,7 @@
#include "..\main.h" #include "..\main.h"
#include "..\FalloutEngine\Fallout2.h" #include "..\FalloutEngine\Fallout2.h"
#include "..\Modules\ExtraArt.h"
#include "..\Modules\LoadGameHook.h" #include "..\Modules\LoadGameHook.h"
#include "Init.h" #include "Init.h"
@@ -45,22 +46,20 @@ static class Panels {
long rightBarID; long rightBarID;
void LoadFRMImage(char* name, long winId) { void LoadFRMImage(char* name, long winId) {
auto* frm = fo::util::LoadUnlistedFrm(name, fo::ArtType::OBJ_TYPE_INTRFACE); fo::FrmFile* frm = sf::LoadUnlistedFrmCached(name, fo::ArtType::OBJ_TYPE_INTRFACE);
if (!frm) return; if (frm == nullptr) return;
fo::Window* win = fo::func::GNW_find(winId); fo::Window* win = fo::func::GNW_find(winId);
long width = win->width; long width = win->width;
if (width > frm->frames->width) width = frm->frames->width; if (width > frm->frameData[0].width) width = frm->frameData[0].width;
BYTE* scr = frm->frames->indexBuff; BYTE* scr = frm->frameData[0].data;
// set the position to the right side // set the position to the right side
if (!IFaceBar::IFACE_BAR_SIDES_ORI && win->wRect.left <= 0) scr += (frm->frames->width - win->width); if (!IFaceBar::IFACE_BAR_SIDES_ORI && win->wRect.left <= 0) scr += (frm->frameData[0].width - win->width);
if (IFaceBar::IFACE_BAR_SIDES_ORI && win->wRect.left > xPosition) scr += (frm->frames->width - win->width); if (IFaceBar::IFACE_BAR_SIDES_ORI && win->wRect.left > xPosition) scr += (frm->frameData[0].width - win->width);
fo::func::cscale(scr, width, frm->frames->height, frm->frames->width, win->surface, win->width, win->height, win->width); fo::func::cscale(scr, width, frm->frameData[0].height, frm->frameData[0].width, win->surface, win->width, win->height, win->width);
delete frm;
} }
public: public:
@@ -205,24 +204,21 @@ static long __cdecl InterfaceArt(BYTE* scr, long w, long h, long srcWidth, BYTE*
char file[33]; char file[33];
std::sprintf(file, "HR_IFACE_%i%s.frm", IFaceBar::IFACE_BAR_WIDTH, ((expandAPBar) ? "E" : "")); std::sprintf(file, "HR_IFACE_%i%s.frm", IFaceBar::IFACE_BAR_WIDTH, ((expandAPBar) ? "E" : ""));
auto* frm = fo::util::LoadUnlistedFrm(file, fo::ArtType::OBJ_TYPE_INTRFACE); fo::FrmFile* frm = sf::LoadUnlistedFrmCached(file, fo::ArtType::OBJ_TYPE_INTRFACE);
if (frm && frm->frames->width == IFaceBar::IFACE_BAR_WIDTH) { if (frm != nullptr && frm->frameData[0].width == IFaceBar::IFACE_BAR_WIDTH) {
h = frm->frames->height; h = frm->frameData[0].height;
if (h > 100) h = 100; if (h > 100) h = 100;
fo::func::buf_to_buf(frm->frames->indexBuff, frm->frames->width, h, frm->frames->width, dst, IFaceBar::IFACE_BAR_WIDTH); fo::func::buf_to_buf(frm->frameData[0].data, frm->frameData[0].width, h, frm->frameData[0].width, dst, IFaceBar::IFACE_BAR_WIDTH);
delete frm;
return 0; return 0;
} }
// no required file, use the default one provided by HRP // no required file, use the default one provided by HRP
if (!frm) frm = fo::util::LoadUnlistedFrm(((expandAPBar) ? "HR_IFACE_800E.frm" : "HR_IFACE_800.frm"), fo::ArtType::OBJ_TYPE_INTRFACE); if (frm == nullptr) frm = sf::LoadUnlistedFrmCached(((expandAPBar) ? "HR_IFACE_800E.frm" : "HR_IFACE_800.frm"), fo::ArtType::OBJ_TYPE_INTRFACE);
if (frm) { if (frm != nullptr) {
// scale the 800px wide interface to the width of IFACE_BAR_WIDTH // scale the 800px wide interface to the width of IFACE_BAR_WIDTH
InterfaceArtScale(frm->frames->indexBuff, frm->frames->width, frm->frames->height, dst, h); InterfaceArtScale(frm->frameData[0].data, frm->frameData[0].width, frm->frameData[0].height, dst, h);
delete frm;
} else { } else {
// scale the vanilla interface to 640px wide (640-460=180) // scale the vanilla interface to 640px wide (640-460=180)
InterfaceArtScale(scr, w, h, dst, h); InterfaceArtScale(scr, w, h, dst, h);
+2 -1
View File
@@ -24,7 +24,8 @@ static long __fastcall CreateWin(long height, long yPos, long xPos, long width,
if (!setPosition[mode]) { if (!setPosition[mode]) {
setPosition[mode] = true; setPosition[mode] = true;
long x = (Setting::ScreenWidth() - width) / 2; long x = (Setting::ScreenWidth() - width) / 2;
long y = (fo::var::getInt(FO_VAR_buf_length_2) - height) / 2; long y = (fo::var::buf_length_2 - height) / 2;
if (y < 0) y = 0;
fo::var::iscr_data[mode].x = x; fo::var::iscr_data[mode].x = x;
fo::var::iscr_data[mode].y = y; fo::var::iscr_data[mode].y = y;
} }

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