mirror of
https://github.com/fallout2-ce/fallout2-ce.git
synced 2026-07-27 16:47:11 -07:00
Compare commits
9
Commits
main
...
windows-opcodes
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
07939225c6 | ||
|
|
b10526330c | ||
|
|
4c1cad7122 | ||
|
|
b76ff8257e | ||
|
|
6edbd70d60 | ||
|
|
15917dccb3 | ||
|
|
33aae49066 | ||
|
|
bfd41bb40c | ||
|
|
0ccaef5ef0 |
@@ -75,10 +75,10 @@ See [`https://sfall-team.github.io/sfall/`](https://sfall-team.github.io/sfall/)
|
||||
| Global scripts / Global script functions | set_global_script_repeat<br>set_global_script_type<br>available_global_script_types | âś… except available_global_script_types | - |
|
||||
| Combat | attack_is_aimed<br>block_combat<br>force_aimed_shots<br>disable_aimed_shots<br>get_attack_type<br>get/set_bodypart_hit_modifier<br>combat_data<br>get/set/reset_critical_table<br>get_last_target<br>get_last_attacker<br>set_critter_burst_disable<br>get/set_critter_current_ap<br>set_spray_settings<br>get/set_combat_free_move | âś… except block_combat, force_aimed_shots, disable_aimed_shots, get_last_target, get_last_attacker, set_spray_settings | - |
|
||||
| Car | set_car_current_town<br>car_gas_amount<br>set_car_intface_art | implemented: all except set_car_intface_art | - |
|
||||
| Interface / Windows and images | art_frame_data<br>interface_art_draw<br>interface_print<br>draw_image<br>draw_image_scaled<br>get_window_under_mouse<br>create_win<br>get_window_attribute<br>message_box<br>set_window_flag<br>win_fill_color<br>interface_overlay<br>dialog_message<br>get_text_width<br>hide_window<br>show_window<br>create_message_window | implemented: only message_box, get_text_width, show_window, create_message_window | - |
|
||||
| Interface / Windows and images | art_frame_data<br>interface_art_draw<br>interface_print<br>draw_image<br>draw_image_scaled<br>get_window_under_mouse<br>create_win<br>get_window_attribute<br>message_box<br>set_window_flag<br>win_fill_color<br>interface_overlay<br>dialog_message<br>get_text_width<br>hide_window<br>show_window<br>create_message_window | âś… except interface_print, draw_image, draw_image_scaled, interface_overlay | - |
|
||||
| Interface / Outline | outlined_object<br>get_outline<br>set_outline | âś… | - |
|
||||
| Interface / Main interface | intface_is_hidden<br>intface_redraw<br>intface_hide<br>intface_show<br>set_quest_failure_value | implemented: only intface_redraw | `intface_redraw` only supports the zero-argument form; the optional-argument path is explicitly unimplemented. |
|
||||
| Interface / Inventory | display_stats<br>inventory_redraw<br>critter_inven_obj2<br>get_current_inven_size<br>item_weight | implemented: critter_inven_obj2, item_weight | - |
|
||||
| Interface / Inventory | display_stats<br>inventory_redraw<br>critter_inven_obj2<br>get_current_inven_size<br>item_weight | âś… except get_current_inven_size | - |
|
||||
| Interface / Cursor | get/set_cursor_mode | âś… | - |
|
||||
| Locks | lock_is_jammed<br>unjam_lock<br>set_unjam_locks_time | not implemented | - |
|
||||
| INI settings | get_ini_setting<br>get_ini_string<br>get_ini_section<br>get_ini_sections<br>get_ini_config<br>get_ini_config_db<br>set_ini_setting | âś… | `modified_ini` is intentionally omitted as deprecated. |
|
||||
|
||||
+141
-79
@@ -10,6 +10,7 @@
|
||||
|
||||
#include "animation.h"
|
||||
#include "content_config.h"
|
||||
#include "datafile.h"
|
||||
#include "debug.h"
|
||||
#include "draw.h"
|
||||
#include "game.h"
|
||||
@@ -524,34 +525,6 @@ unsigned char* artLockFrameData(int fid, int frame, int direction, CacheEntry**
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// 0x4191CC
|
||||
unsigned char* artLockFrameDataReturningSize(int fid, CacheEntry** handlePtr, int* widthPtr, int* heightPtr)
|
||||
{
|
||||
*handlePtr = nullptr;
|
||||
|
||||
Art* art = nullptr;
|
||||
cacheLock(&gArtCache, fid, (void**)&art, handlePtr);
|
||||
|
||||
if (art == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// NOTE: Uninline.
|
||||
*widthPtr = artGetWidth(art, 0, 0);
|
||||
if (*widthPtr == -1) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// NOTE: Uninline.
|
||||
*heightPtr = artGetHeight(art, 0, 0);
|
||||
if (*heightPtr == -1) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// NOTE: Uninline.
|
||||
return artGetFrameData(art, 0, 0);
|
||||
}
|
||||
|
||||
// 0x419260
|
||||
int artUnlock(CacheEntry* handle)
|
||||
{
|
||||
@@ -1221,6 +1194,51 @@ static bool artIndexedPngHasSupportedTransparency(const LodePNGColorMode& color)
|
||||
return true;
|
||||
}
|
||||
|
||||
static Art* artAllocateSingleFrame(int width, int height, unsigned char** frameDataPtr)
|
||||
{
|
||||
if (width <= 0 || height <= 0 || width > SHRT_MAX || height > SHRT_MAX) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
size_t pixelCount = static_cast<size_t>(width) * static_cast<size_t>(height);
|
||||
if (pixelCount > kMaxNamedPngPixels || pixelCount > INT_MAX) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Art header = {};
|
||||
header.version = 4;
|
||||
header.framesPerSecond = 10;
|
||||
header.actionFrame = 0;
|
||||
header.frameCount = 1;
|
||||
header.dataSize = sizeof(ArtFrame) + static_cast<int>(pixelCount);
|
||||
|
||||
int currentPadding = paddingForSize(sizeof(Art));
|
||||
for (int rotation = 0; rotation < ROTATION_COUNT; rotation++) {
|
||||
header.dataOffsets[rotation] = 0;
|
||||
header.padding[rotation] = currentPadding;
|
||||
}
|
||||
|
||||
int dataSize = artGetDataSize(&header);
|
||||
unsigned char* data = reinterpret_cast<unsigned char*>(internal_malloc(dataSize));
|
||||
if (data == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
memset(data, 0, dataSize);
|
||||
Art* art = reinterpret_cast<Art*>(data);
|
||||
*art = header;
|
||||
|
||||
ArtFrame* frame = reinterpret_cast<ArtFrame*>(data + sizeof(Art) + art->padding[0]);
|
||||
frame->width = static_cast<short>(width);
|
||||
frame->height = static_cast<short>(height);
|
||||
frame->size = static_cast<int>(pixelCount);
|
||||
frame->x = 0;
|
||||
frame->y = 0;
|
||||
|
||||
*frameDataPtr = reinterpret_cast<unsigned char*>(frame) + sizeof(ArtFrame);
|
||||
return art;
|
||||
}
|
||||
|
||||
static Art* artLoadIndexedPng(const char* path)
|
||||
{
|
||||
std::vector<unsigned char> encoded;
|
||||
@@ -1255,47 +1273,44 @@ static Art* artLoadIndexedPng(const char* path)
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
size_t pixelCount = static_cast<size_t>(width) * static_cast<size_t>(height);
|
||||
|
||||
Art header = {};
|
||||
header.version = 4;
|
||||
header.framesPerSecond = 10;
|
||||
header.actionFrame = 0;
|
||||
header.frameCount = 1;
|
||||
header.dataSize = sizeof(ArtFrame) + static_cast<int>(pixelCount);
|
||||
|
||||
int currentPadding = paddingForSize(sizeof(Art));
|
||||
for (int rotation = 0; rotation < ROTATION_COUNT; rotation++) {
|
||||
header.dataOffsets[rotation] = 0;
|
||||
header.padding[rotation] = currentPadding;
|
||||
}
|
||||
|
||||
int dataSize = artGetDataSize(&header);
|
||||
unsigned char* data = reinterpret_cast<unsigned char*>(internal_malloc(dataSize));
|
||||
if (data == nullptr) {
|
||||
unsigned char* frameData = nullptr;
|
||||
Art* art = artAllocateSingleFrame(static_cast<int>(width), static_cast<int>(height), &frameData);
|
||||
if (art == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
memset(data, 0, dataSize);
|
||||
Art* art = reinterpret_cast<Art*>(data);
|
||||
*art = header;
|
||||
|
||||
ArtFrame* frame = reinterpret_cast<ArtFrame*>(data + sizeof(Art) + art->padding[0]);
|
||||
frame->width = static_cast<short>(width);
|
||||
frame->height = static_cast<short>(height);
|
||||
frame->size = static_cast<int>(pixelCount);
|
||||
frame->x = 0;
|
||||
frame->y = 0;
|
||||
|
||||
if (!artUnpackIndexedPngPixels(indexedData, width, height, state.info_png.color.bitdepth, reinterpret_cast<unsigned char*>(frame) + sizeof(ArtFrame))) {
|
||||
if (!artUnpackIndexedPngPixels(indexedData, width, height, state.info_png.color.bitdepth, frameData)) {
|
||||
debugPrint("ART: failed to read indexed PNG pixels: %s\n", path);
|
||||
internal_free(data);
|
||||
internal_free(art);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return art;
|
||||
}
|
||||
|
||||
static Art* artLoadPcx(const char* path)
|
||||
{
|
||||
char mutablePath[COMPAT_MAX_PATH];
|
||||
strncpy(mutablePath, path, sizeof(mutablePath));
|
||||
mutablePath[sizeof(mutablePath) - 1] = '\0';
|
||||
|
||||
int width = 0;
|
||||
int height = 0;
|
||||
unsigned char* pcxData = datafileRead(mutablePath, &width, &height);
|
||||
if (pcxData == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
unsigned char* frameData = nullptr;
|
||||
Art* art = artAllocateSingleFrame(width, height, &frameData);
|
||||
if (art != nullptr) {
|
||||
memcpy(frameData, pcxData, static_cast<size_t>(width) * static_cast<size_t>(height));
|
||||
}
|
||||
|
||||
internal_free(pcxData);
|
||||
return art;
|
||||
}
|
||||
|
||||
static Art* artLoadFrm(const char* path)
|
||||
{
|
||||
File* stream = fileOpen(path, "rb");
|
||||
@@ -1340,6 +1355,10 @@ Art* artLoad(const char* path)
|
||||
return artLoadIndexedPng(path);
|
||||
}
|
||||
|
||||
if (artPathHasExtension(path, ".pcx")) {
|
||||
return artLoadPcx(path);
|
||||
}
|
||||
|
||||
Art* art = artLoadFrm(path);
|
||||
if (art != nullptr) {
|
||||
return art;
|
||||
@@ -1491,7 +1510,7 @@ public:
|
||||
|
||||
const Art* art() const { return _art.get(); }
|
||||
|
||||
unsigned char* frameData(int frame, int direction, int& outWidth, int& outHeight) const;
|
||||
ArtFrame* frame(int frame, int direction) const;
|
||||
|
||||
unsigned int mru = 0;
|
||||
|
||||
@@ -1504,17 +1523,9 @@ NamedCacheEntry::NamedCacheEntry(ArtPtr&& art)
|
||||
{
|
||||
}
|
||||
|
||||
unsigned char* NamedCacheEntry::frameData(int frame, int direction, int& outWidth, int& outHeight) const
|
||||
ArtFrame* NamedCacheEntry::frame(int frame, int direction) const
|
||||
{
|
||||
unsigned char* data = artGetFrameData(_art.get(), frame, direction);
|
||||
if (!data) {
|
||||
outWidth = 0;
|
||||
outHeight = 0;
|
||||
return nullptr;
|
||||
}
|
||||
outWidth = artGetWidth(_art.get(), frame, direction);
|
||||
outHeight = artGetHeight(_art.get(), frame, direction);
|
||||
return data;
|
||||
return artGetFrame(_art.get(), frame, direction);
|
||||
}
|
||||
|
||||
std::shared_ptr<NamedCacheEntry> artLockNamedFrameData(const char* path)
|
||||
@@ -1597,9 +1608,12 @@ ObjectType FrmId::objectType() const
|
||||
FrmImage::FrmImage()
|
||||
{
|
||||
_key = nullptr;
|
||||
_frame = nullptr;
|
||||
_data = nullptr;
|
||||
_width = 0;
|
||||
_height = 0;
|
||||
_xOffset = 0;
|
||||
_yOffset = 0;
|
||||
}
|
||||
|
||||
FrmImage::~FrmImage()
|
||||
@@ -1610,9 +1624,12 @@ FrmImage::~FrmImage()
|
||||
FrmImage::FrmImage(FrmImage&& other) noexcept
|
||||
: _namedKey(std::move(other._namedKey))
|
||||
, _key(other._key)
|
||||
, _frame(other._frame)
|
||||
, _data(other._data)
|
||||
, _width(other._width)
|
||||
, _height(other._height)
|
||||
, _xOffset(other._xOffset)
|
||||
, _yOffset(other._yOffset)
|
||||
{
|
||||
other.resetInternal();
|
||||
}
|
||||
@@ -1623,9 +1640,12 @@ FrmImage& FrmImage::operator=(FrmImage&& other) noexcept
|
||||
unlock();
|
||||
_namedKey = std::move(other._namedKey);
|
||||
_key = other._key;
|
||||
_frame = other._frame;
|
||||
_data = other._data;
|
||||
_width = other._width;
|
||||
_height = other._height;
|
||||
_xOffset = other._xOffset;
|
||||
_yOffset = other._yOffset;
|
||||
|
||||
other.resetInternal();
|
||||
}
|
||||
@@ -1633,33 +1653,60 @@ FrmImage& FrmImage::operator=(FrmImage&& other) noexcept
|
||||
}
|
||||
|
||||
bool FrmImage::lock(const FrmId& frmId)
|
||||
{
|
||||
return lock(frmId, 0, 0);
|
||||
}
|
||||
|
||||
bool FrmImage::lock(const FrmId& frmId, int frame, int direction)
|
||||
{
|
||||
if (frmId.fid() >= 0) {
|
||||
return lock(frmId.fid());
|
||||
return lock(frmId.fid(), frame, direction);
|
||||
}
|
||||
if (frmId.filePath() != nullptr) {
|
||||
return frmId.hasObjectType()
|
||||
? lock(frmId.objectType(), frmId.filePath())
|
||||
: lock(frmId.filePath());
|
||||
? lock(frmId.objectType(), frmId.filePath(), frame, direction)
|
||||
: lock(frmId.filePath(), frame, direction);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool FrmImage::lock(unsigned int fid)
|
||||
{
|
||||
return lock(fid, 0, 0);
|
||||
}
|
||||
|
||||
bool FrmImage::lock(unsigned int fid, int frame, int direction)
|
||||
{
|
||||
if (isLocked()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_data = artLockFrameDataReturningSize(fid, &_key, &_width, &_height);
|
||||
if (!_data) {
|
||||
Art* art = artLock(fid, &_key);
|
||||
if (art == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_frame = artGetFrame(art, frame, direction);
|
||||
if (_frame == nullptr) {
|
||||
unlock();
|
||||
return false;
|
||||
}
|
||||
|
||||
_data = reinterpret_cast<unsigned char*>(_frame) + sizeof(ArtFrame);
|
||||
_width = _frame->width;
|
||||
_height = _frame->height;
|
||||
_xOffset = _frame->x;
|
||||
_yOffset = _frame->y;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FrmImage::lock(const char* frmPath)
|
||||
{
|
||||
return lock(frmPath, 0, 0);
|
||||
}
|
||||
|
||||
bool FrmImage::lock(const char* frmPath, int frame, int direction)
|
||||
{
|
||||
if (isLocked()) {
|
||||
return false;
|
||||
@@ -1668,21 +1715,33 @@ bool FrmImage::lock(const char* frmPath)
|
||||
_namedKey = artLockNamedFrameData(frmPath);
|
||||
if (!_namedKey) return false;
|
||||
|
||||
_data = _namedKey->frameData(0, 0, _width, _height);
|
||||
if (_data == nullptr) {
|
||||
_namedKey = nullptr;
|
||||
_frame = _namedKey->frame(frame, direction);
|
||||
if (_frame == nullptr) {
|
||||
unlock();
|
||||
return false;
|
||||
}
|
||||
|
||||
_data = reinterpret_cast<unsigned char*>(_frame) + sizeof(ArtFrame);
|
||||
_width = _frame->width;
|
||||
_height = _frame->height;
|
||||
_xOffset = _frame->x;
|
||||
_yOffset = _frame->y;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FrmImage::lock(ObjectType objType, const char* frmRelativePath)
|
||||
{
|
||||
return lock(objType, frmRelativePath, 0, 0);
|
||||
}
|
||||
|
||||
bool FrmImage::lock(ObjectType objType, const char* frmRelativePath, int frame, int direction)
|
||||
{
|
||||
if (objType < OBJ_TYPE_ITEM || objType >= OBJ_TYPE_COUNT) {
|
||||
return false;
|
||||
}
|
||||
snprintf(_art_name, sizeof(_art_name), "%s%s%s\\%s", _cd_path_base, "art\\", gArtListDescriptions[objType].name, frmRelativePath);
|
||||
return lock(_art_name);
|
||||
return lock(_art_name, frame, direction);
|
||||
}
|
||||
|
||||
void FrmImage::unlock()
|
||||
@@ -1697,9 +1756,12 @@ void FrmImage::resetInternal()
|
||||
{
|
||||
_namedKey = nullptr;
|
||||
_key = nullptr;
|
||||
_frame = nullptr;
|
||||
_data = nullptr;
|
||||
_width = 0;
|
||||
_height = 0;
|
||||
_xOffset = 0;
|
||||
_yOffset = 0;
|
||||
}
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
@@ -128,7 +128,6 @@ void artRender(int fid, unsigned char* dest, int width, int height, int pitch);
|
||||
int art_list_str(int fid, char* name);
|
||||
Art* artLock(int fid, CacheEntry** cache_entry);
|
||||
unsigned char* artLockFrameData(int fid, int frame, int direction, CacheEntry** out_cache_entry);
|
||||
unsigned char* artLockFrameDataReturningSize(int fid, CacheEntry** out_cache_entry, int* widthPtr, int* heightPtr);
|
||||
int artUnlock(CacheEntry* cache_entry);
|
||||
int artCacheFlush();
|
||||
int artCopyFileName(int objectType, int id, char* dest);
|
||||
@@ -185,8 +184,8 @@ private:
|
||||
const char* _path = nullptr;
|
||||
};
|
||||
|
||||
// A helper for using RAII to read single-frame FRM's.
|
||||
// lock/unlock use the art-cache instead of just loading/unloading directly.
|
||||
// RAII helper for locking one selected frame from FID-backed or path-backed art.
|
||||
// lock/unlock use caches instead of just loading/unloading directly.
|
||||
class FrmImage {
|
||||
public:
|
||||
FrmImage();
|
||||
@@ -201,13 +200,19 @@ public:
|
||||
|
||||
bool isLocked() const { return _key != nullptr || _namedKey; }
|
||||
bool lock(const FrmId& frmId);
|
||||
bool lock(const FrmId& frmId, int frame, int direction);
|
||||
bool lock(unsigned int fid);
|
||||
bool lock(unsigned int fid, int frame, int direction);
|
||||
bool lock(const char* frmPath);
|
||||
bool lock(const char* frmPath, int frame, int direction);
|
||||
bool lock(ObjectType objType, const char* frmRelativePath);
|
||||
bool lock(ObjectType objType, const char* frmRelativePath, int frame, int direction);
|
||||
void unlock();
|
||||
|
||||
int getWidth() const { return _width; }
|
||||
int getHeight() const { return _height; }
|
||||
int getXOffset() const { return _xOffset; }
|
||||
int getYOffset() const { return _yOffset; }
|
||||
// Returns FRM frame data if locked, nullptr otherwise.
|
||||
unsigned char* getData() const { return _data; }
|
||||
|
||||
@@ -218,9 +223,12 @@ private:
|
||||
|
||||
std::shared_ptr<NamedCacheEntry> _namedKey;
|
||||
CacheEntry* _key = nullptr;
|
||||
ArtFrame* _frame = nullptr;
|
||||
unsigned char* _data = nullptr;
|
||||
int _width = 0;
|
||||
int _height = 0;
|
||||
int _xOffset = 0;
|
||||
int _yOffset = 0;
|
||||
};
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
@@ -46,6 +46,8 @@ static void _decode_map_data(int elevation);
|
||||
static int automapCreate();
|
||||
static int _copy_file_data(File* stream1, File* stream2, int length);
|
||||
|
||||
static int gAutomapWindow = -1;
|
||||
|
||||
typedef enum AutomapFrm {
|
||||
AUTOMAP_FRM_BACKGROUND,
|
||||
AUTOMAP_FRM_BUTTON_UP,
|
||||
@@ -326,6 +328,7 @@ void automapShow(bool isInGame, bool isUsingScanner)
|
||||
int automapWindowY = (screenGetHeight() - AUTOMAP_WINDOW_HEIGHT) / 2;
|
||||
// adding WINDOW_TRANSPARENT and WINDOW_DRAGGABLE_BY_BACKGROUND for testing temporarily
|
||||
int window = windowCreate(automapWindowX, automapWindowY, AUTOMAP_WINDOW_WIDTH, AUTOMAP_WINDOW_HEIGHT, color, WINDOW_MODAL | WINDOW_MOVE_ON_TOP | WINDOW_TRANSPARENT | WINDOW_DRAGGABLE_BY_BACKGROUND);
|
||||
gAutomapWindow = window;
|
||||
|
||||
int scannerBtn = buttonCreate(window,
|
||||
111,
|
||||
@@ -493,10 +496,16 @@ void automapShow(bool isInGame, bool isUsingScanner)
|
||||
}
|
||||
|
||||
windowDestroy(window);
|
||||
gAutomapWindow = -1;
|
||||
fontSetCurrent(oldFont);
|
||||
touch_set_touchscreen_mode(false);
|
||||
}
|
||||
|
||||
int automapGetWindow()
|
||||
{
|
||||
return windowGetWindow(gAutomapWindow) != nullptr ? gAutomapWindow : -1;
|
||||
}
|
||||
|
||||
// Renders automap in Map window.
|
||||
//
|
||||
// 0x41BD1C draw_top_down_map
|
||||
|
||||
@@ -55,6 +55,7 @@ void automapShow(bool isInGame, bool isUsingScanner);
|
||||
int automapRenderInPipboyWindow(int win, int map, int elevation);
|
||||
int automapSaveCurrent();
|
||||
int automapGetHeader(AutomapHeader** automapHeaderPtr);
|
||||
int automapGetWindow();
|
||||
|
||||
void automapSetDisplayMap(int map, bool available);
|
||||
|
||||
|
||||
@@ -5680,6 +5680,29 @@ void characterEditorReset()
|
||||
gCharacterEditorLastLevel = 1;
|
||||
}
|
||||
|
||||
int characterEditorGetWindow()
|
||||
{
|
||||
return windowGetWindow(gCharacterEditorWindow) != nullptr ? gCharacterEditorWindow : -1;
|
||||
}
|
||||
|
||||
void characterEditorDisplayStats()
|
||||
{
|
||||
if (windowGetWindow(gCharacterEditorWindow) == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
critterUpdateDerivedStats(gDude);
|
||||
critterAdjustHitPoints(gDude, 0);
|
||||
|
||||
characterEditorDrawSkills(0);
|
||||
characterEditorDrawPrimaryStat(RENDER_ALL_STATS, 0, 0);
|
||||
characterEditorDrawPcStats();
|
||||
characterEditorDrawDerivedStats();
|
||||
characterEditorDrawFolders();
|
||||
characterEditorDrawCard();
|
||||
windowRefresh(gCharacterEditorWindow);
|
||||
}
|
||||
|
||||
// level up if needed
|
||||
//
|
||||
// 0x43C228 UpdateLevel
|
||||
|
||||
@@ -14,6 +14,8 @@ char* _strmfe(char* dest, const char* name, const char* ext);
|
||||
int characterEditorSave(File* stream);
|
||||
int characterEditorLoad(File* stream);
|
||||
void characterEditorReset();
|
||||
int characterEditorGetWindow();
|
||||
void characterEditorDisplayStats();
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
|
||||
@@ -3495,6 +3495,11 @@ bool gameDialogIsBarterWindowExpanded()
|
||||
return gBarterWindowExpanded;
|
||||
}
|
||||
|
||||
int gameDialogGetWindow()
|
||||
{
|
||||
return windowGetWindow(gGameDialogWindow) != nullptr ? gGameDialogWindow : -1;
|
||||
}
|
||||
|
||||
// 0x448660 gdialog_barter_cleanup_tables
|
||||
void gameDialogBarterCleanupTables()
|
||||
{
|
||||
|
||||
@@ -40,6 +40,7 @@ void gameDialogSetBarterModifier(int modifier);
|
||||
int gameDialogBarter(int modifier);
|
||||
void gameDialogEndBarter();
|
||||
bool gameDialogIsBarterWindowExpanded();
|
||||
int gameDialogGetWindow();
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
|
||||
+72
-20
@@ -352,6 +352,7 @@ static void inventoryNormalLayoutUpdate();
|
||||
static bool inventoryBackgroundLoad(FrmImage& image, int col1FrmId, const char* col2Name, int columns);
|
||||
static int inventoryChooseColumns(FrmImage& image, int expandedWidth, int col1FrmId, const char* col2Name);
|
||||
static void inventoryCreateSlotButtons(int baseKeyCode, int scrollerX, int scrollerY, int columns);
|
||||
static bool inventoryGetCurrentWindowType(InventoryWindowType* inventoryWindowTypePtr);
|
||||
static int inventoryGetWindowWidth(int inventoryWindowType);
|
||||
static int inventoryGetWindowHeight(int inventoryWindowType);
|
||||
static void inventoryNormalClampStackOffset();
|
||||
@@ -695,6 +696,31 @@ static void inventoryCreateSlotButtons(int baseKeyCode, int scrollerX, int scrol
|
||||
}
|
||||
}
|
||||
|
||||
static bool inventoryGetCurrentWindowType(InventoryWindowType* inventoryWindowTypePtr)
|
||||
{
|
||||
if (GameMode::isInGameMode(GameMode::kBarter)) {
|
||||
*inventoryWindowTypePtr = INVENTORY_WINDOW_TYPE_TRADE;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (GameMode::isInGameMode(GameMode::kLoot)) {
|
||||
*inventoryWindowTypePtr = INVENTORY_WINDOW_TYPE_LOOT;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (GameMode::isInGameMode(GameMode::kUseOn)) {
|
||||
*inventoryWindowTypePtr = INVENTORY_WINDOW_TYPE_USE_ITEM_ON;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (GameMode::isInGameMode(GameMode::kInventory)) {
|
||||
*inventoryWindowTypePtr = INVENTORY_WINDOW_TYPE_NORMAL;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static int inventoryGetWindowWidth(int inventoryWindowType)
|
||||
{
|
||||
if (inventoryWindowType == INVENTORY_WINDOW_TYPE_NORMAL) return inventoryLayout.windowWidth;
|
||||
@@ -957,8 +983,6 @@ void inventoryOpen()
|
||||
}
|
||||
}
|
||||
|
||||
ScopedGameMode gm(GameMode::kInventory);
|
||||
|
||||
if (inventoryCommonInit() == -1) {
|
||||
return;
|
||||
}
|
||||
@@ -997,6 +1021,7 @@ void inventoryOpen()
|
||||
inventoryRenderSummary();
|
||||
_display_inventory(_stack_offset[_curr_stack], -1, INVENTORY_WINDOW_TYPE_NORMAL);
|
||||
inventorySetCursor(INVENTORY_WINDOW_CURSOR_HAND);
|
||||
ScopedGameMode gm(GameMode::kInventory);
|
||||
|
||||
for (;;) {
|
||||
sharedFpsLimiter.mark();
|
||||
@@ -2743,8 +2768,6 @@ static void _adjust_fid()
|
||||
// 0x4717E4
|
||||
void inventoryOpenUseItemOn(Object* targetObj)
|
||||
{
|
||||
ScopedGameMode gm(GameMode::kUseOn);
|
||||
|
||||
if (inventoryCommonInit() == -1) {
|
||||
return;
|
||||
}
|
||||
@@ -2752,6 +2775,7 @@ void inventoryOpenUseItemOn(Object* targetObj)
|
||||
bool isoWasEnabled = _setup_inventory(INVENTORY_WINDOW_TYPE_USE_ITEM_ON);
|
||||
_display_inventory(_stack_offset[_curr_stack], -1, INVENTORY_WINDOW_TYPE_USE_ITEM_ON);
|
||||
inventorySetCursor(INVENTORY_WINDOW_CURSOR_HAND);
|
||||
ScopedGameMode gm(GameMode::kUseOn);
|
||||
for (;;) {
|
||||
sharedFpsLimiter.mark();
|
||||
|
||||
@@ -3088,7 +3112,7 @@ int objectGetCarriedQuantityByPid(Object* object, int pid)
|
||||
// Renders character's summary of SPECIAL stats, equipped armor bonuses,
|
||||
// and weapon's damage/range.
|
||||
//
|
||||
// 0x471D5C
|
||||
// 0x471D5C display_stats
|
||||
static void inventoryRenderSummary()
|
||||
{
|
||||
int summaryStats[7];
|
||||
@@ -4350,8 +4374,6 @@ int inventoryOpenLooting(Object* looter, Object* target)
|
||||
return 0;
|
||||
}
|
||||
|
||||
ScopedGameMode gm(GameMode::kLoot);
|
||||
|
||||
if (FID_TYPE(target->fid) == OBJ_TYPE_CRITTER) {
|
||||
if (critterFlagCheck(target->pid, CRITTER_NO_STEAL)) {
|
||||
// You can't find anything to take from that.
|
||||
@@ -4417,6 +4439,7 @@ int inventoryOpenLooting(Object* looter, Object* target)
|
||||
}
|
||||
|
||||
bool isoWasEnabled = _setup_inventory(INVENTORY_WINDOW_TYPE_LOOT);
|
||||
ScopedGameMode gm(GameMode::kLoot);
|
||||
|
||||
Object** critters = nullptr;
|
||||
int critterCount = 0;
|
||||
@@ -6338,6 +6361,46 @@ int inventorySetTimer(Object* item)
|
||||
return seconds;
|
||||
}
|
||||
|
||||
int inventoryGetWindow()
|
||||
{
|
||||
return windowGetWindow(gInventoryWindow) != nullptr ? gInventoryWindow : -1;
|
||||
}
|
||||
|
||||
void inventoryDisplayStats()
|
||||
{
|
||||
if (windowGetWindow(gInventoryWindow) == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
inventoryRenderSummary();
|
||||
windowRefresh(gInventoryWindow);
|
||||
}
|
||||
|
||||
void inventoryRedraw(int redrawSide)
|
||||
{
|
||||
if (windowGetWindow(gInventoryWindow) == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
InventoryWindowType inventoryWindowType;
|
||||
if (!inventoryGetCurrentWindowType(&inventoryWindowType)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (redrawSide <= 0) {
|
||||
_stack_offset[_curr_stack] = 0;
|
||||
_display_inventory(0, -1, inventoryWindowType);
|
||||
}
|
||||
|
||||
if (redrawSide != 0
|
||||
&& (inventoryWindowType == INVENTORY_WINDOW_TYPE_LOOT
|
||||
|| inventoryWindowType == INVENTORY_WINDOW_TYPE_TRADE)) {
|
||||
_target_stack_offset[_target_curr_stack] = 0;
|
||||
_display_target_inventory(0, -1, _target_pud, inventoryWindowType);
|
||||
windowRefresh(gInventoryWindow);
|
||||
}
|
||||
}
|
||||
|
||||
Object* inventoryGetTargetObject()
|
||||
{
|
||||
return _target_stack[_target_curr_stack];
|
||||
@@ -6350,10 +6413,8 @@ int inventoryUnwieldSlot(Object* critter, InvenSlot slot)
|
||||
}
|
||||
|
||||
bool isDude = critter == gDude;
|
||||
bool uiModeActive = GameMode::isInGameMode(GameMode::kInventory)
|
||||
|| GameMode::isInGameMode(GameMode::kUseOn)
|
||||
|| GameMode::isInGameMode(GameMode::kLoot)
|
||||
|| GameMode::isInGameMode(GameMode::kBarter);
|
||||
InventoryWindowType inventoryWindowType;
|
||||
bool uiModeActive = inventoryGetCurrentWindowType(&inventoryWindowType);
|
||||
bool update = false;
|
||||
|
||||
if (slot != InvenSlot::Armor && !uiModeActive) {
|
||||
@@ -6443,15 +6504,6 @@ int inventoryUnwieldSlot(Object* critter, InvenSlot slot)
|
||||
return 0;
|
||||
}
|
||||
|
||||
InventoryWindowType inventoryWindowType = INVENTORY_WINDOW_TYPE_NORMAL;
|
||||
if (GameMode::isInGameMode(GameMode::kBarter)) {
|
||||
inventoryWindowType = INVENTORY_WINDOW_TYPE_TRADE;
|
||||
} else if (GameMode::isInGameMode(GameMode::kLoot)) {
|
||||
inventoryWindowType = INVENTORY_WINDOW_TYPE_LOOT;
|
||||
} else if (GameMode::isInGameMode(GameMode::kUseOn)) {
|
||||
inventoryWindowType = INVENTORY_WINDOW_TYPE_USE_ITEM_ON;
|
||||
}
|
||||
|
||||
if (inventoryWindowType == INVENTORY_WINDOW_TYPE_NORMAL) {
|
||||
inventoryRenderSummary();
|
||||
}
|
||||
|
||||
@@ -62,6 +62,9 @@ int inventoryOpenLooting(Object* looter, Object* target);
|
||||
int inventoryOpenStealing(Object* thief, Object* target);
|
||||
void barterProcessUI(int win, Object* barterer, Object* playerTable, Object* bartererTable, int barterMod);
|
||||
int inventorySetTimer(Object* item);
|
||||
int inventoryGetWindow();
|
||||
void inventoryDisplayStats();
|
||||
void inventoryRedraw(int redrawSide);
|
||||
Object* inventoryGetTargetObject();
|
||||
int inventoryUnwieldSlot(Object* critter, InvenSlot slot);
|
||||
|
||||
|
||||
@@ -74,6 +74,8 @@ static bool gOptionsWindowGameMouseObjectsWasVisible;
|
||||
// 0x663900 optnwin
|
||||
static int gOptionsWindow;
|
||||
|
||||
static int gPauseWindow = -1;
|
||||
|
||||
// 0x663908 winbuf
|
||||
static unsigned char* gOptionsWindowBuffer;
|
||||
|
||||
@@ -303,6 +305,7 @@ static int optionsWindowInit()
|
||||
static int optionsWindowFree()
|
||||
{
|
||||
windowDestroy(gOptionsWindow);
|
||||
gOptionsWindow = -1;
|
||||
fontSetCurrent(gOptionsWindowOldFont);
|
||||
messageListFree(&gPreferencesMessageList);
|
||||
|
||||
@@ -389,6 +392,8 @@ int showPause(bool preserveWorldState)
|
||||
return -1;
|
||||
}
|
||||
|
||||
gPauseWindow = window;
|
||||
|
||||
unsigned char* windowBuffer = windowGetBuffer(window);
|
||||
memcpy(windowBuffer,
|
||||
frmImages[PAUSE_WINDOW_FRM_BACKGROUND].getData(),
|
||||
@@ -477,6 +482,7 @@ int showPause(bool preserveWorldState)
|
||||
}
|
||||
|
||||
windowDestroy(window);
|
||||
gPauseWindow = -1;
|
||||
messageListFree(&gPreferencesMessageList);
|
||||
|
||||
if (!preserveWorldState) {
|
||||
@@ -529,4 +535,17 @@ int _init_options_menu()
|
||||
return 0;
|
||||
}
|
||||
|
||||
int optionsGetWindow()
|
||||
{
|
||||
if (windowGetWindow(gOptionsWindow) != nullptr) {
|
||||
return gOptionsWindow;
|
||||
}
|
||||
|
||||
if (windowGetWindow(gPauseWindow) != nullptr) {
|
||||
return gPauseWindow;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
@@ -6,6 +6,7 @@ namespace fallout {
|
||||
int showOptions();
|
||||
int showPause(bool preserveWorldState);
|
||||
int _init_options_menu();
|
||||
int optionsGetWindow();
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
|
||||
@@ -1014,6 +1014,11 @@ int pipboyLoad(File* stream)
|
||||
return _save_pipboy(stream);
|
||||
}
|
||||
|
||||
int pipboyGetWindow()
|
||||
{
|
||||
return windowGetWindow(gPipboyWindow) != nullptr ? gPipboyWindow : -1;
|
||||
}
|
||||
|
||||
// 0x497BD8
|
||||
static void pipboyWindowHandleStatus(int userInput)
|
||||
{
|
||||
|
||||
@@ -16,6 +16,7 @@ void pipboyInit();
|
||||
void pipboyReset();
|
||||
int pipboySave(File* stream);
|
||||
int pipboyLoad(File* stream);
|
||||
int pipboyGetWindow();
|
||||
|
||||
extern MessageList gPipboyMessageList;
|
||||
int pipboyMessageListInit();
|
||||
|
||||
+483
-12
File diff suppressed because it is too large
Load Diff
@@ -42,6 +42,7 @@
|
||||
#include "stat.h"
|
||||
#include "svga.h"
|
||||
#include "tile.h"
|
||||
#include "window_manager.h"
|
||||
#include "worldmap.h"
|
||||
|
||||
namespace fallout {
|
||||
@@ -899,6 +900,11 @@ static void op_get_mouse_buttons(Program* program)
|
||||
programStackPushInteger(program, mouse_get_last_buttons());
|
||||
}
|
||||
|
||||
static void op_get_window_under_mouse(Program* program)
|
||||
{
|
||||
programStackPushInteger(program, _win_last_button_winID());
|
||||
}
|
||||
|
||||
// get_screen_width
|
||||
static void op_get_screen_width(Program* program)
|
||||
{
|
||||
@@ -1873,6 +1879,7 @@ void sfallOpcodesInit()
|
||||
// 0x821e - int get_mouse_buttons()
|
||||
interpreterRegisterOpcode(0x821E, op_get_mouse_buttons);
|
||||
// 0x821f - int get_window_under_mouse()
|
||||
interpreterRegisterOpcode(0x821F, op_get_window_under_mouse);
|
||||
|
||||
// 0x8163 - int get_year()
|
||||
interpreterRegisterOpcode(0x8163, op_get_year);
|
||||
|
||||
@@ -147,6 +147,11 @@ int skilldexOpen()
|
||||
return rc;
|
||||
}
|
||||
|
||||
int skilldexGetWindow()
|
||||
{
|
||||
return windowGetWindow(gSkilldexWindow) != nullptr ? gSkilldexWindow : -1;
|
||||
}
|
||||
|
||||
// 0x4AC054 skilldex_start
|
||||
static int skilldexWindowInit()
|
||||
{
|
||||
|
||||
@@ -17,6 +17,7 @@ typedef enum SkilldexRC {
|
||||
} SkilldexRC;
|
||||
|
||||
int skilldexOpen();
|
||||
int skilldexGetWindow();
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
|
||||
+79
-18
@@ -158,9 +158,6 @@ static ManagedWindow gManagedWindows[MANAGED_WINDOW_COUNT];
|
||||
// 0x672D70 inputFunc
|
||||
static WindowInputHandler** gWindowInputHandlers;
|
||||
|
||||
// 0x672D74 createWindowFunc
|
||||
static ManagedWindowCreateCallback* off_672D74;
|
||||
|
||||
// NOTE: This value is never set.
|
||||
//
|
||||
// 0x672D78 selectWindowFunc
|
||||
@@ -704,6 +701,21 @@ bool scriptWindowShow()
|
||||
return true;
|
||||
}
|
||||
|
||||
bool scriptWindowHideNamed(const char* windowName)
|
||||
{
|
||||
for (int index = 0; index < MANAGED_WINDOW_COUNT; index++) {
|
||||
ManagedWindow* managedWindow = &(gManagedWindows[index]);
|
||||
if (managedWindow->window != -1) {
|
||||
if (compat_stricmp(managedWindow->name, windowName) == 0) {
|
||||
windowHide(managedWindow->window);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// 0x4B7734
|
||||
int scriptWindowWidth()
|
||||
{
|
||||
@@ -843,9 +855,6 @@ int scriptWindowCreate(const char* windowName, int x, int y, int width, int heig
|
||||
managedWindow->buttonsLength = 0;
|
||||
|
||||
flags |= WINDOW_MANAGED | WINDOW_USE_DEFAULTS;
|
||||
if (off_672D74 != nullptr) {
|
||||
off_672D74(windowIndex, managedWindow->name, &flags);
|
||||
}
|
||||
|
||||
managedWindow->window = windowCreate(x, y, width, height, a6, flags);
|
||||
managedWindow->cursorY = 0;
|
||||
@@ -909,6 +918,20 @@ bool scriptWindowSelectId(int index)
|
||||
return true;
|
||||
}
|
||||
|
||||
int scriptWindowGetWindow(int index)
|
||||
{
|
||||
if (index < 0 || index >= MANAGED_WINDOW_COUNT) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
ManagedWindow* managedWindow = &(gManagedWindows[index]);
|
||||
if (managedWindow->window == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return windowGetWindow(managedWindow->window) != nullptr ? managedWindow->window : -1;
|
||||
}
|
||||
|
||||
// 0x4B821C
|
||||
int scriptWindowSelect(const char* windowName)
|
||||
{
|
||||
@@ -950,23 +973,30 @@ unsigned char* scriptWindowGetBuffer()
|
||||
// 0x4B8330
|
||||
int scriptWindowPush(const char* windowName)
|
||||
{
|
||||
if (_winTOS >= MANAGED_WINDOW_COUNT) {
|
||||
return -1;
|
||||
int oldCurrentWindowIndex = gCurrentManagedWindowIndex;
|
||||
|
||||
int existingIndex = -1;
|
||||
for (int index = 0; index <= _winTOS; index++) {
|
||||
if (_winStack[index] == oldCurrentWindowIndex) {
|
||||
existingIndex = index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int oldCurrentWindowIndex = gCurrentManagedWindowIndex;
|
||||
// CE: check duplicates before checking capacity; removing one frees a stack slot.
|
||||
int newTopIndex = existingIndex == -1 ? _winTOS + 1 : _winTOS;
|
||||
if (newTopIndex >= MANAGED_WINDOW_COUNT) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int windowIndex = scriptWindowSelect(windowName);
|
||||
if (windowIndex == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// TODO: Check.
|
||||
for (int index = 0; index < _winTOS; index++) {
|
||||
if (_winStack[index] == oldCurrentWindowIndex) {
|
||||
memcpy(&(_winStack[index]), &(_winStack[index + 1]), sizeof(*_winStack) * (_winTOS - index));
|
||||
break;
|
||||
}
|
||||
if (existingIndex != -1) {
|
||||
memmove(&(_winStack[existingIndex]), &(_winStack[existingIndex + 1]), sizeof(*_winStack) * (_winTOS - existingIndex));
|
||||
_winTOS--;
|
||||
}
|
||||
|
||||
_winTOS++;
|
||||
@@ -983,9 +1013,15 @@ int _popWindow()
|
||||
}
|
||||
|
||||
int windowIndex = _winStack[_winTOS];
|
||||
ManagedWindow* managedWindow = &(gManagedWindows[windowIndex]);
|
||||
_winTOS--;
|
||||
|
||||
if (windowIndex < 0 || windowIndex >= MANAGED_WINDOW_COUNT) {
|
||||
gCurrentManagedWindowIndex = -1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
ManagedWindow* managedWindow = &(gManagedWindows[windowIndex]);
|
||||
|
||||
return scriptWindowSelect(managedWindow->name);
|
||||
}
|
||||
|
||||
@@ -1745,8 +1781,7 @@ bool scriptWindowAddButtonGfx(const char* buttonName, char* pressedFileName, cha
|
||||
}
|
||||
|
||||
if (hoverFileName != nullptr) {
|
||||
// TODO: this almost certainly should be hoverFileName
|
||||
unsigned char* hover = datafileRead(normalFileName, &width, &height);
|
||||
unsigned char* hover = datafileRead(hoverFileName, &width, &height);
|
||||
if (hover != nullptr) {
|
||||
if (managedButton->hover == nullptr) {
|
||||
managedButton->hover = (unsigned char*)internal_malloc_safe(managedButton->height * managedButton->width, __FILE__, __LINE__); // "..\\int\\WINDOW.C, 1849
|
||||
@@ -2657,4 +2692,30 @@ bool scriptWindowShowNamed(const char* windowName)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool scriptWindowSetNamedFlag(const char* windowName, int bitFlag, bool enabled)
|
||||
{
|
||||
for (int index = 0; index < MANAGED_WINDOW_COUNT; index++) {
|
||||
ManagedWindow* managedWindow = &(gManagedWindows[index]);
|
||||
if (managedWindow->window != -1) {
|
||||
if (compat_stricmp(managedWindow->name, windowName) == 0) {
|
||||
Window* window = windowGetWindow(managedWindow->window);
|
||||
if (window == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// note: Sfall also updates managedWindow->flags, but that is unused
|
||||
if (enabled) {
|
||||
window->flags |= bitFlag;
|
||||
} else {
|
||||
window->flags &= ~bitFlag;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace fallout
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user