Merge branch 'main' into InterfaceBar

This commit is contained in:
Alexander Batalov 2022-11-07 11:52:38 +03:00
commit 7ce28efb61
26 changed files with 301 additions and 249 deletions

View File

@ -1396,7 +1396,7 @@ int actionUseSkill(Object* a1, Object* a2, int skill)
return -1;
case SKILL_SNEAK:
dudeToggleState(0);
dudeToggleState(DUDE_STATE_SNEAKING);
return 0;
default:
debugPrint("\nskill_use: invalid skill used.");

View File

@ -690,7 +690,7 @@ int animationRegisterRunToObject(Object* owner, Object* destination, int actionP
animationDescription->destination = destination;
if ((FID_TYPE(owner->fid) == OBJ_TYPE_CRITTER && (owner->data.critter.combat.results & DAM_CRIP_LEG_ANY) != 0)
|| (owner == gDude && dudeHasState(0) && !perkGetRank(gDude, PERK_SILENT_RUNNING))
|| (owner == gDude && dudeHasState(DUDE_STATE_SNEAKING) && !perkGetRank(gDude, PERK_SILENT_RUNNING))
|| !artExists(buildFid(FID_TYPE(owner->fid), owner->fid & 0xFFF, ANIM_RUNNING, 0, owner->rotation + 1))) {
animationDescription->anim = ANIM_WALK;
} else {
@ -786,7 +786,7 @@ int animationRegisterRunToTile(Object* owner, int tile, int elevation, int actio
animationDescription->elevation = elevation;
if ((FID_TYPE(owner->fid) == OBJ_TYPE_CRITTER && (owner->data.critter.combat.results & DAM_CRIP_LEG_ANY) != 0)
|| (owner == gDude && dudeHasState(0) && !perkGetRank(gDude, PERK_SILENT_RUNNING))
|| (owner == gDude && dudeHasState(DUDE_STATE_SNEAKING) && !perkGetRank(gDude, PERK_SILENT_RUNNING))
|| !artExists(buildFid(FID_TYPE(owner->fid), owner->fid & 0xFFF, ANIM_RUNNING, 0, owner->rotation + 1))) {
animationDescription->anim = ANIM_WALK;
} else {
@ -3043,7 +3043,7 @@ int _dude_run(int a1)
}
if (!perkGetRank(gDude, PERK_SILENT_RUNNING)) {
dudeDisableState(0);
dudeDisableState(DUDE_STATE_SNEAKING);
}
reg_anim_begin(ANIMATION_REQUEST_RESERVED);

View File

@ -1186,8 +1186,8 @@ int characterEditorShow(bool isCreationMode)
characterEditorRestorePlayer();
}
if (dudeHasState(0x03)) {
dudeDisableState(0x03);
if (dudeHasState(DUDE_STATE_LEVEL_UP_AVAILABLE)) {
dudeDisableState(DUDE_STATE_LEVEL_UP_AVAILABLE);
}
interfaceRenderHitPoints(false);

View File

@ -338,7 +338,7 @@ int fileReadInt32(File* stream, int* valuePtr)
return -1;
}
*valuePtr = ((value >> 24) & 0xFF) | ((value >> 8) & 0xFF00) | ((value << 8) & 0xFF0000) | ((value << 24) & 0xFF000000);
*valuePtr = ((value & 0xFF000000) >> 24) | ((value & 0xFF0000) >> 8) | ((value & 0xFF00) << 8) | ((value & 0xFF) << 24);
return 0;
}
@ -511,7 +511,7 @@ int fileReadInt32List(File* stream, int* arr, int count)
for (int index = 0; index < count; index++) {
int value = arr[index];
arr[index] = ((value >> 24) & 0xFF) | ((value >> 8) & 0xFF00) | ((value << 8) & 0xFF0000) | ((value << 24) & 0xFF000000);
arr[index] = ((value & 0xFF000000) >> 24) | ((value & 0xFF0000) >> 8) | ((value & 0xFF00) << 8) | ((value & 0xFF) << 24);
}
return 0;

View File

@ -5,10 +5,7 @@
#include <stdlib.h>
#include <string.h>
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#endif
#include <SDL.h>
#include "memory.h"
#include "platform_compat.h"
@ -148,13 +145,7 @@ int debugPrint(const char* format, ...)
rc = gDebugPrintProc(string);
} else {
#ifdef _DEBUG
char string[260];
vsprintf(string, format, args);
#ifdef _WIN32
OutputDebugStringA(string);
#else
printf("%s", string);
#endif
SDL_LogMessageV(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, format, args);
#endif
rc = -1;
}

View File

@ -123,60 +123,85 @@ static int interfaceFontLoad(int font_index)
File* stream = fileOpen(path, "rb");
if (stream == NULL) {
return false;
return -1;
}
int fileSize = fileGetSize(stream);
int sig;
if (fileRead(&sig, 4, 1, stream) != 1) goto err;
if (fileRead(&sig, 4, 1, stream) != 1) {
fileClose(stream);
return -1;
}
interfaceFontByteSwapInt32(&sig);
if (sig != 0x41414646) goto err;
if (sig != 0x41414646) {
fileClose(stream);
return -1;
}
if (fileRead(&(fontDescriptor->maxHeight), 2, 1, stream) != 1) goto err;
if (fileRead(&(fontDescriptor->maxHeight), 2, 1, stream) != 1) {
fileClose(stream);
return -1;
}
interfaceFontByteSwapInt16(&(fontDescriptor->maxHeight));
if (fileRead(&(fontDescriptor->letterSpacing), 2, 1, stream) != 1) goto err;
if (fileRead(&(fontDescriptor->letterSpacing), 2, 1, stream) != 1) {
fileClose(stream);
return -1;
}
interfaceFontByteSwapInt16(&(fontDescriptor->letterSpacing));
if (fileRead(&(fontDescriptor->wordSpacing), 2, 1, stream) != 1) goto err;
if (fileRead(&(fontDescriptor->wordSpacing), 2, 1, stream) != 1) {
fileClose(stream);
return -1;
}
interfaceFontByteSwapInt16(&(fontDescriptor->wordSpacing));
if (fileRead(&(fontDescriptor->lineSpacing), 2, 1, stream) != 1) goto err;
if (fileRead(&(fontDescriptor->lineSpacing), 2, 1, stream) != 1) {
fileClose(stream);
return -1;
}
interfaceFontByteSwapInt16(&(fontDescriptor->lineSpacing));
for (int index = 0; index < 256; index++) {
InterfaceFontGlyph* glyph = &(fontDescriptor->glyphs[index]);
if (fileRead(&(glyph->width), 2, 1, stream) != 1) goto err;
if (fileRead(&(glyph->width), 2, 1, stream) != 1) {
fileClose(stream);
return -1;
}
interfaceFontByteSwapInt16(&(glyph->width));
if (fileRead(&(glyph->height), 2, 1, stream) != 1) goto err;
if (fileRead(&(glyph->height), 2, 1, stream) != 1) {
fileClose(stream);
return -1;
}
interfaceFontByteSwapInt16(&(glyph->height));
if (fileRead(&(glyph->offset), 4, 1, stream) != 1) goto err;
if (fileRead(&(glyph->offset), 4, 1, stream) != 1) {
fileClose(stream);
return -1;
}
interfaceFontByteSwapInt32(&(glyph->offset));
}
fileSize -= sizeof(InterfaceFontDescriptor);
int glyphDataSize = fileSize - 2060;
fontDescriptor->data = (unsigned char*)internal_malloc_safe(fileSize, __FILE__, __LINE__); // FONTMGR.C, 259
if (fontDescriptor->data == NULL) goto err;
fontDescriptor->data = (unsigned char*)internal_malloc_safe(glyphDataSize, __FILE__, __LINE__); // FONTMGR.C, 259
if (fontDescriptor->data == NULL) {
fileClose(stream);
return -1;
}
if (fileRead(fontDescriptor->data, fileSize, 1, stream) != 1) {
if (fileRead(fontDescriptor->data, glyphDataSize, 1, stream) != 1) {
internal_free_safe(fontDescriptor->data, __FILE__, __LINE__); // FONTMGR.C, 268
goto err;
fileClose(stream);
return -1;
}
fileClose(stream);
return 0;
err:
fileClose(stream);
return -1;
}
// 0x442120
@ -211,26 +236,22 @@ static int interfaceFontGetStringWidthImpl(const char* string)
return 0;
}
const char* pch = string;
int width = 0;
int stringWidth = 0;
while (*pch != '\0') {
int v3;
int v4;
while (*string != '\0') {
unsigned char ch = static_cast<unsigned char>(*string++);
if (*pch == ' ') {
v3 = gCurrentInterfaceFontDescriptor->letterSpacing;
v4 = gCurrentInterfaceFontDescriptor->wordSpacing;
int characterWidth;
if (ch == ' ') {
characterWidth = gCurrentInterfaceFontDescriptor->wordSpacing;
} else {
v3 = gCurrentInterfaceFontDescriptor->glyphs[*pch & 0xFF].width;
v4 = gCurrentInterfaceFontDescriptor->letterSpacing;
characterWidth = gCurrentInterfaceFontDescriptor->glyphs[ch].width;
}
width += v3 + v4;
pch++;
stringWidth += characterWidth + gCurrentInterfaceFontDescriptor->letterSpacing;
}
return width;
return stringWidth;
}
// 0x4421DC
@ -322,13 +343,13 @@ static void interfaceFontDrawImpl(unsigned char* buf, const char* string, int le
unsigned char* ptr = buf;
while (*string != '\0') {
char ch = *string++;
unsigned char ch = static_cast<unsigned char>(*string++);
int characterWidth;
if (ch == ' ') {
characterWidth = gCurrentInterfaceFontDescriptor->wordSpacing;
} else {
characterWidth = gCurrentInterfaceFontDescriptor->glyphs[ch & 0xFF].width;
characterWidth = gCurrentInterfaceFontDescriptor->glyphs[ch].width;
}
unsigned char* end;
@ -343,7 +364,7 @@ static void interfaceFontDrawImpl(unsigned char* buf, const char* string, int le
break;
}
InterfaceFontGlyph* glyph = &(gCurrentInterfaceFontDescriptor->glyphs[ch & 0xFF]);
InterfaceFontGlyph* glyph = &(gCurrentInterfaceFontDescriptor->glyphs[ch]);
unsigned char* glyphDataPtr = gCurrentInterfaceFontDescriptor->data + glyph->offset;
// Skip blank pixels (difference between font's line height and glyph height).

View File

@ -693,7 +693,7 @@ int gameHandleKey(int eventCode, bool isInCombatMode)
}
if (gIsMapper) {
tileSetCenter(gDude->tile, TILE_SET_CENTER_FLAG_0x01);
tileSetCenter(gDude->tile, TILE_SET_CENTER_REFRESH_WINDOW);
} else {
_tile_scroll_to(gDude->tile, 2);
}

View File

@ -3498,7 +3498,7 @@ void partyMemberControlWindowUpdate()
FrmImage backgroundFrmImage;
int backgroundFid = buildFid(OBJ_TYPE_INTERFACE, 390, 0, 0, 0);
if (!backgroundFrmImage.lock(backgroundFid)) {
if (backgroundFrmImage.lock(backgroundFid)) {
int width = backgroundFrmImage.getWidth();
unsigned char* buffer = backgroundFrmImage.getData();
@ -4104,86 +4104,78 @@ int _gdCustomSelect(int a1)
sharedFpsLimiter.mark();
int keyCode = inputGetInput();
if (keyCode == -1) {
continue;
}
if (keyCode == KEY_CTRL_Q || keyCode == KEY_CTRL_X || keyCode == KEY_F10) {
showQuitConfirmationDialog();
}
if (_game_user_wants_to_quit != 0) {
break;
}
if (keyCode == KEY_RETURN) {
STRUCT_5189E4* ptr = &(_custom_settings[a1][value]);
_custom_current_selected[a1] = value;
_gdCustomUpdateSetting(a1, ptr->value);
done = true;
} else if (keyCode == KEY_ESCAPE) {
done = true;
} else if (keyCode == -2) {
if ((mouseGetEvent() & MOUSE_EVENT_LEFT_BUTTON_UP) == 0) {
continue;
if (keyCode != -1) {
if (keyCode == KEY_CTRL_Q || keyCode == KEY_CTRL_X || keyCode == KEY_F10) {
showQuitConfirmationDialog();
}
// No need to use mouseHitTestInWindow as these values are already
// in screen coordinates.
if (!_mouse_click_in(minX, minY, maxX, maxY)) {
continue;
if (_game_user_wants_to_quit != 0) {
break;
}
int mouseX;
int mouseY;
mouseGetPosition(&mouseX, &mouseY);
if (keyCode == KEY_RETURN) {
STRUCT_5189E4* ptr = &(_custom_settings[a1][value]);
_custom_current_selected[a1] = value;
_gdCustomUpdateSetting(a1, ptr->value);
done = true;
} else if (keyCode == KEY_ESCAPE) {
done = true;
} else if (keyCode == -2) {
if ((mouseGetEvent() & MOUSE_EVENT_LEFT_BUTTON_UP) != 0) {
// No need to use mouseHitTestInWindow as these values are already
// in screen coordinates.
if (_mouse_click_in(minX, minY, maxX, maxY)) {
int mouseX;
int mouseY;
mouseGetPosition(&mouseX, &mouseY);
int lineHeight = fontGetLineHeight();
int newValue = (mouseY - minY) / lineHeight;
if (newValue >= 6) {
continue;
}
int lineHeight = fontGetLineHeight();
int newValue = (mouseY - minY) / lineHeight;
if (newValue < 6) {
unsigned int timestamp = getTicks();
if (newValue == value) {
if (getTicksBetween(timestamp, v53) < 250) {
_custom_current_selected[a1] = newValue;
_gdCustomUpdateSetting(a1, newValue);
done = true;
}
} else {
STRUCT_5189E4* ptr = &(_custom_settings[a1][newValue]);
if (ptr->messageId != -1) {
bool enabled = false;
switch (a1) {
case PARTY_MEMBER_CUSTOMIZATION_OPTION_AREA_ATTACK_MODE:
enabled = partyMemberSupportsAreaAttackMode(gGameDialogSpeaker, ptr->value);
break;
case PARTY_MEMBER_CUSTOMIZATION_OPTION_RUN_AWAY_MODE:
enabled = partyMemberSupportsRunAwayMode(gGameDialogSpeaker, ptr->value);
break;
case PARTY_MEMBER_CUSTOMIZATION_OPTION_BEST_WEAPON:
enabled = partyMemberSupportsBestWeapon(gGameDialogSpeaker, ptr->value);
break;
case PARTY_MEMBER_CUSTOMIZATION_OPTION_DISTANCE:
enabled = partyMemberSupportsDistance(gGameDialogSpeaker, ptr->value);
break;
case PARTY_MEMBER_CUSTOMIZATION_OPTION_ATTACK_WHO:
enabled = partyMemberSupportsAttackWho(gGameDialogSpeaker, ptr->value);
break;
case PARTY_MEMBER_CUSTOMIZATION_OPTION_CHEM_USE:
enabled = partyMemberSupportsChemUse(gGameDialogSpeaker, ptr->value);
break;
}
unsigned int timestamp = getTicks();
if (newValue == value) {
if (getTicksBetween(timestamp, v53) < 250) {
_custom_current_selected[a1] = newValue;
_gdCustomUpdateSetting(a1, newValue);
done = true;
}
} else {
STRUCT_5189E4* ptr = &(_custom_settings[a1][newValue]);
if (ptr->messageId != -1) {
bool enabled = false;
switch (a1) {
case PARTY_MEMBER_CUSTOMIZATION_OPTION_AREA_ATTACK_MODE:
enabled = partyMemberSupportsAreaAttackMode(gGameDialogSpeaker, ptr->value);
break;
case PARTY_MEMBER_CUSTOMIZATION_OPTION_RUN_AWAY_MODE:
enabled = partyMemberSupportsRunAwayMode(gGameDialogSpeaker, ptr->value);
break;
case PARTY_MEMBER_CUSTOMIZATION_OPTION_BEST_WEAPON:
enabled = partyMemberSupportsBestWeapon(gGameDialogSpeaker, ptr->value);
break;
case PARTY_MEMBER_CUSTOMIZATION_OPTION_DISTANCE:
enabled = partyMemberSupportsDistance(gGameDialogSpeaker, ptr->value);
break;
case PARTY_MEMBER_CUSTOMIZATION_OPTION_ATTACK_WHO:
enabled = partyMemberSupportsAttackWho(gGameDialogSpeaker, ptr->value);
break;
case PARTY_MEMBER_CUSTOMIZATION_OPTION_CHEM_USE:
enabled = partyMemberSupportsChemUse(gGameDialogSpeaker, ptr->value);
break;
}
if (enabled) {
value = newValue;
_gdCustomSelectRedraw(windowBuffer, backgroundFrmWidth, a1, newValue);
windowRefresh(win);
if (enabled) {
value = newValue;
_gdCustomSelectRedraw(windowBuffer, backgroundFrmWidth, a1, newValue);
windowRefresh(win);
}
}
}
v53 = timestamp;
}
}
}
}
v53 = timestamp;
}
renderPresent();

View File

@ -284,6 +284,10 @@ int gameMoviePlay(int movie, int flags)
windowDestroy(win);
// CE: Destroying a window redraws only content it was covering (centered
// 640x480). This leads to everything outside this rect to remain black.
windowRefreshAll(&_scr_size);
if ((flags & GAME_MOVIE_PAUSE_MUSIC) != 0) {
backgroundSoundResume();
}

View File

@ -307,6 +307,8 @@ bool heapBlockAllocate(Heap* heap, int* handleIndexPtr, int size, int a4)
int blockSize;
HeapHandle* handle;
size += 4 - size % 4;
if (heap == NULL || handleIndexPtr == NULL || size == 0) {
goto err;
}

View File

@ -1127,6 +1127,16 @@ static void opConditionalOperatorLessThanEquals(Program* program)
assert(false && "Should be unreachable");
}
break;
// Nevada folks tend to use "object <= 0" to test objects for nulls.
case VALUE_TYPE_PTR:
switch (value[0].opcode) {
case VALUE_TYPE_INT:
result = (intptr_t)value[1].pointerValue <= (intptr_t)value[0].integerValue;
break;
default:
assert(false && "Should be unreachable");
}
break;
default:
assert(false && "Should be unreachable");
}

View File

@ -545,7 +545,7 @@ static void opSetMapStart(Program* program)
}
int tile = 200 * y + x;
if (tileSetCenter(tile, TILE_SET_CENTER_FLAG_0x01 | TILE_SET_CENTER_FLAG_0x02) != 0) {
if (tileSetCenter(tile, TILE_SET_CENTER_REFRESH_WINDOW | TILE_SET_CENTER_FLAG_IGNORE_SCROLL_RESTRICTIONS) != 0) {
scriptError("\nScript Error: %s: op_set_map_start: tile_set_center failed", program->name);
return;
}
@ -584,7 +584,7 @@ static void opOverrideMapStart(Program* program)
}
}
tileSetCenter(tile, TILE_SET_CENTER_FLAG_0x01);
tileSetCenter(tile, TILE_SET_CENTER_REFRESH_WINDOW);
tileWindowRefresh();
}
@ -866,7 +866,7 @@ static void opMoveTo(Program* program)
Rect rect;
newTile = objectSetLocation(object, tile, elevation, &rect);
if (newTile != -1) {
tileSetCenter(object->tile, TILE_SET_CENTER_FLAG_0x01);
tileSetCenter(object->tile, TILE_SET_CENTER_REFRESH_WINDOW);
}
if (tileLimitingEnabled) {
@ -2061,7 +2061,7 @@ static void opMetarule3(Program* program)
}
break;
case METARULE3_TILE_SET_CENTER:
result.integerValue = tileSetCenter(param1.integerValue, TILE_SET_CENTER_FLAG_0x01);
result.integerValue = tileSetCenter(param1.integerValue, TILE_SET_CENTER_REFRESH_WINDOW);
break;
case METARULE3_109:
result.integerValue = aiGetChemUse(static_cast<Object*>(param1.pointerValue));
@ -3158,7 +3158,7 @@ static void opFloatMessage(Program* program)
color = _colorTable[31744];
a5 = _colorTable[0];
font = 103;
tileSetCenter(gDude->tile, TILE_SET_CENTER_FLAG_0x01);
tileSetCenter(gDude->tile, TILE_SET_CENTER_REFRESH_WINDOW);
break;
case FLOATING_MESSAGE_TYPE_NORMAL:
case FLOATING_MESSAGE_TYPE_YELLOW:

View File

@ -1465,8 +1465,9 @@ static void opSetTextColor(Program* program)
}
for (int arg = 0; arg < 3; arg++) {
if (((value[arg].opcode & VALUE_TYPE_MASK) != VALUE_TYPE_FLOAT && (value[arg].opcode & VALUE_TYPE_MASK) != VALUE_TYPE_INT)
|| value[arg].floatValue == 0.0) {
if ((value[arg].opcode & VALUE_TYPE_MASK) != VALUE_TYPE_FLOAT
&& (value[arg].opcode & VALUE_TYPE_MASK) == VALUE_TYPE_INT
&& value[arg].integerValue != 0) {
programFatalError("Invalid type given to settextcolor");
}
}
@ -1492,8 +1493,9 @@ static void opSayOptionColor(Program* program)
}
for (int arg = 0; arg < 3; arg++) {
if (((value[arg].opcode & VALUE_TYPE_MASK) != VALUE_TYPE_FLOAT && (value[arg].opcode & VALUE_TYPE_MASK) != VALUE_TYPE_INT)
|| value[arg].floatValue == 0.0) {
if ((value[arg].opcode & VALUE_TYPE_MASK) != VALUE_TYPE_FLOAT
&& (value[arg].opcode & VALUE_TYPE_MASK) == VALUE_TYPE_INT
&& value[arg].integerValue != 0) {
programFatalError("Invalid type given to sayoptioncolor");
}
}
@ -1519,8 +1521,9 @@ static void opSayReplyColor(Program* program)
}
for (int arg = 0; arg < 3; arg++) {
if (((value[arg].opcode & VALUE_TYPE_MASK) != VALUE_TYPE_FLOAT && (value[arg].opcode & VALUE_TYPE_MASK) != VALUE_TYPE_INT)
|| value[arg].floatValue == 0.0) {
if ((value[arg].opcode & VALUE_TYPE_MASK) != VALUE_TYPE_FLOAT
&& (value[arg].opcode & VALUE_TYPE_MASK) == VALUE_TYPE_INT
&& value[arg].integerValue != 0) {
programFatalError("Invalid type given to sayreplycolor");
}
}
@ -1546,8 +1549,9 @@ static void opSetHighlightColor(Program* program)
}
for (int arg = 0; arg < 3; arg++) {
if (((value[arg].opcode & VALUE_TYPE_MASK) != VALUE_TYPE_FLOAT && (value[arg].opcode & VALUE_TYPE_MASK) != VALUE_TYPE_INT)
|| value[arg].floatValue == 0.0) {
if ((value[arg].opcode & VALUE_TYPE_MASK) != VALUE_TYPE_FLOAT
&& (value[arg].opcode & VALUE_TYPE_MASK) == VALUE_TYPE_INT
&& value[arg].integerValue != 0) {
programFatalError("Invalid type given to sayreplycolor");
}
}

View File

@ -2434,13 +2434,13 @@ static int _SlotMap2Game(File* stream)
{
debugPrint("LOADSAVE: in SlotMap2Game\n");
int v2;
if (fileReadInt32(stream, &v2) == 1) {
int fileNameListLength;
if (fileReadInt32(stream, &fileNameListLength) == -1) {
debugPrint("LOADSAVE: returning 1\n");
return -1;
}
if (v2 == 0) {
if (fileNameListLength == 0) {
debugPrint("LOADSAVE: returning 2\n");
return -1;
}
@ -2467,46 +2467,42 @@ static int _SlotMap2Game(File* stream)
sprintf(_str0, "%s\\%s\\%s", _patches, "MAPS", "AUTOMAP.DB");
compat_remove(_str0);
if (gPartyMemberDescriptionsLength > 1) {
for (int index = 1; index < gPartyMemberDescriptionsLength; index += 1) {
int pid = gPartyMemberPids[index];
if (pid != -2) {
char protoPath[COMPAT_MAX_PATH];
if (_proto_list_str(pid, protoPath) == 0) {
const char* basePath = pid >> 24 == OBJ_TYPE_CRITTER
? PROTO_DIR_NAME "\\" CRITTERS_DIR_NAME
: PROTO_DIR_NAME "\\" ITEMS_DIR_NAME;
sprintf(_str0, "%s\\%s\\%s", _patches, basePath, protoPath);
sprintf(_str1, "%s\\%s\\%s%.2d\\%s\\%s", _patches, "SAVEGAME", "SLOT", _slot_cursor + 1, basePath, protoPath);
for (int index = 1; index < gPartyMemberDescriptionsLength; index += 1) {
int pid = gPartyMemberPids[index];
if (pid != -2) {
char protoPath[COMPAT_MAX_PATH];
if (_proto_list_str(pid, protoPath) == 0) {
const char* basePath = PID_TYPE(pid) == OBJ_TYPE_CRITTER
? PROTO_DIR_NAME "\\" CRITTERS_DIR_NAME
: PROTO_DIR_NAME "\\" ITEMS_DIR_NAME;
sprintf(_str0, "%s\\%s\\%s", _patches, basePath, protoPath);
sprintf(_str1, "%s\\%s\\%s%.2d\\%s\\%s", _patches, "SAVEGAME", "SLOT", _slot_cursor + 1, basePath, protoPath);
if (_gzdecompress_file(_str1, _str0) == -1) {
debugPrint("LOADSAVE: returning 6\n");
return -1;
}
if (_gzdecompress_file(_str1, _str0) == -1) {
debugPrint("LOADSAVE: returning 6\n");
return -1;
}
}
}
}
if (v2 > 0) {
for (int index = 0; index < v2; index += 1) {
char v11[64]; // TODO: Size is probably wrong.
if (_mygets(v11, stream) == -1) {
break;
}
for (int index = 0; index < fileNameListLength; index += 1) {
char fileName[COMPAT_MAX_PATH];
if (_mygets(fileName, stream) == -1) {
break;
}
sprintf(_str0, "%s\\%s\\%s%.2d\\%s", _patches, "SAVEGAME", "SLOT", _slot_cursor + 1, v11);
sprintf(_str1, "%s\\%s\\%s", _patches, "MAPS", v11);
sprintf(_str0, "%s\\%s\\%s%.2d\\%s", _patches, "SAVEGAME", "SLOT", _slot_cursor + 1, fileName);
sprintf(_str1, "%s\\%s\\%s", _patches, "MAPS", fileName);
if (_gzdecompress_file(_str0, _str1) == -1) {
debugPrint("LOADSAVE: returning 7\n");
return -1;
}
if (_gzdecompress_file(_str0, _str1) == -1) {
debugPrint("LOADSAVE: returning 7\n");
return -1;
}
}
const char* v9 = _strmfe(_str1, "AUTOMAP.DB", "SAV");
sprintf(_str0, "%s\\%s\\%s%.2d\\%s", _patches, "SAVEGAME", "SLOT", _slot_cursor + 1, v9);
const char* automapFileName = _strmfe(_str1, "AUTOMAP.DB", "SAV");
sprintf(_str0, "%s\\%s\\%s%.2d\\%s", _patches, "SAVEGAME", "SLOT", _slot_cursor + 1, automapFileName);
sprintf(_str1, "%s\\%s\\%s", _patches, "MAPS", "AUTOMAP.DB");
if (fileCopyDecompressed(_str0, _str1) == -1) {
debugPrint("LOADSAVE: returning 8\n");

View File

@ -707,7 +707,7 @@ int mapSetEnteringLocation(int elevation, int tile_num, int orientation)
void mapNewMap()
{
mapSetElevation(0);
tileSetCenter(20100, TILE_SET_CENTER_FLAG_0x02);
tileSetCenter(20100, TILE_SET_CENTER_FLAG_IGNORE_SCROLL_RESTRICTIONS);
memset(&gMapTransition, 0, sizeof(gMapTransition));
gMapHeader.enteringElevation = 0;
gMapHeader.enteringRotation = 0;
@ -894,7 +894,7 @@ static int mapLoad(File* stream)
}
error = "Error setting tile center";
if (tileSetCenter(gEnteringTile, TILE_SET_CENTER_FLAG_0x02) != 0) {
if (tileSetCenter(gEnteringTile, TILE_SET_CENTER_FLAG_IGNORE_SCROLL_RESTRICTIONS) != 0) {
goto err;
}
@ -1240,7 +1240,7 @@ int mapHandleTransition()
objectSetRotation(gDude, gMapTransition.rotation, NULL);
}
if (tileSetCenter(gDude->tile, TILE_SET_CENTER_FLAG_0x01) == -1) {
if (tileSetCenter(gDude->tile, TILE_SET_CENTER_REFRESH_WINDOW) == -1) {
debugPrint("\nError: map: attempt to center out-of-bounds!");
}

View File

@ -81,6 +81,7 @@ static void* memoryBlockMallocImpl(size_t size)
if (size != 0) {
size += sizeof(MemoryBlockHeader) + sizeof(MemoryBlockFooter);
size += sizeof(int) - size % sizeof(int);
unsigned char* block = (unsigned char*)malloc(size);
if (block != NULL) {
@ -123,6 +124,7 @@ static void* memoryBlockReallocImpl(void* ptr, size_t size)
if (size != 0) {
size += sizeof(MemoryBlockHeader) + sizeof(MemoryBlockFooter);
size += sizeof(int) - size % sizeof(int);
}
unsigned char* newBlock = (unsigned char*)realloc(block, size);

View File

@ -185,7 +185,7 @@ static int _obj_last_roof_y = -1;
static int _obj_last_elev = -1;
// 0x51977C
static int _obj_last_is_empty = 1;
static bool _obj_last_is_empty = true;
// 0x519780
unsigned char* _wallBlendTable = NULL;
@ -1492,21 +1492,24 @@ int objectSetLocation(Object* obj, int tile, int elevation, Rect* rect)
// NOTE: Uninline.
obj_set_seen(tile);
int v14 = tile % 200 / 2;
int v15 = tile / 200 / 2;
if (v14 != _obj_last_roof_x || v15 != _obj_last_roof_y || elevation != _obj_last_elev) {
int v16 = _square[elevation]->field_0[v14 + 100 * v15];
int v31 = buildFid(OBJ_TYPE_TILE, (v16 >> 16) & 0xFFF, 0, 0, 0);
int v32 = _square[elevation]->field_0[_obj_last_roof_x + 100 * _obj_last_roof_y];
int v34 = buildFid(OBJ_TYPE_TILE, 1, 0, 0, 0) == v31;
int roofX = tile % 200 / 2;
int roofY = tile / 200 / 2;
if (roofX != _obj_last_roof_x || roofY != _obj_last_roof_y || elevation != _obj_last_elev) {
int currentSquare = _square[elevation]->field_0[roofX + 100 * roofY];
int currentSquareFid = buildFid(OBJ_TYPE_TILE, (currentSquare >> 16) & 0xFFF, 0, 0, 0);
// CE: Add additional checks for -1 to prevent array lookup at index -101.
int previousSquare = _obj_last_roof_x != -1 && _obj_last_roof_y != -1
? _square[elevation]->field_0[_obj_last_roof_x + 100 * _obj_last_roof_y]
: 0;
bool isEmpty = buildFid(OBJ_TYPE_TILE, 1, 0, 0, 0) == currentSquareFid;
if (v34 != _obj_last_is_empty || (((v16 >> 16) & 0xF000) >> 12) != (((v32 >> 16) & 0xF000) >> 12)) {
if (_obj_last_is_empty == 0) {
if (isEmpty != _obj_last_is_empty || (((currentSquare >> 16) & 0xF000) >> 12) != (((previousSquare >> 16) & 0xF000) >> 12)) {
if (!_obj_last_is_empty) {
_tile_fill_roof(_obj_last_roof_x, _obj_last_roof_y, elevation, 1);
}
if (v34 == 0) {
_tile_fill_roof(v14, v15, elevation, 0);
if (!isEmpty) {
_tile_fill_roof(roofX, roofY, elevation, 0);
}
if (rect != NULL) {
@ -1514,10 +1517,10 @@ int objectSetLocation(Object* obj, int tile, int elevation, Rect* rect)
}
}
_obj_last_roof_x = v14;
_obj_last_roof_y = v15;
_obj_last_roof_x = roofX;
_obj_last_roof_y = roofY;
_obj_last_elev = elevation;
_obj_last_is_empty = v34;
_obj_last_is_empty = isEmpty;
}
if (rect != NULL) {
@ -1530,7 +1533,7 @@ int objectSetLocation(Object* obj, int tile, int elevation, Rect* rect)
if (elevation != oldElevation) {
mapSetElevation(elevation);
tileSetCenter(tile, TILE_SET_CENTER_FLAG_0x01 | TILE_SET_CENTER_FLAG_0x02);
tileSetCenter(tile, TILE_SET_CENTER_REFRESH_WINDOW | TILE_SET_CENTER_FLAG_IGNORE_SCROLL_RESTRICTIONS);
if (isInCombat()) {
_game_user_wants_to_quit = 1;
}
@ -2183,7 +2186,7 @@ void _obj_remove_all()
_obj_last_roof_y = -1;
_obj_last_elev = -1;
_obj_last_is_empty = 1;
_obj_last_is_empty = true;
_obj_last_roof_x = -1;
}
@ -3335,7 +3338,7 @@ static int _obj_offset_table_init()
}
}
if (tileSetCenter(gCenterTile + 1, 2) == -1) {
if (tileSetCenter(gCenterTile + 1, TILE_SET_CENTER_FLAG_IGNORE_SCROLL_RESTRICTIONS) == -1) {
goto err;
}
}
@ -3753,7 +3756,7 @@ int _obj_load_dude(File* stream)
return -1;
}
tileSetCenter(tile, TILE_SET_CENTER_FLAG_0x01 | TILE_SET_CENTER_FLAG_0x02);
tileSetCenter(tile, TILE_SET_CENTER_REFRESH_WINDOW | TILE_SET_CENTER_FLAG_IGNORE_SCROLL_RESTRICTIONS);
return rc;
}

View File

@ -107,7 +107,6 @@ typedef enum PreferencesWindowFrm {
PREFERENCES_WINDOW_FRM_COUNT,
} PreferencesWindowFrm;
#pragma pack(2)
typedef struct PreferenceDescription {
// The number of options.
short valuesCount;
@ -129,7 +128,6 @@ typedef struct PreferenceDescription {
double maxValue;
int* valuePtr;
} PreferenceDescription;
#pragma pack()
static int optionsWindowInit();
static int optionsWindowFree();
@ -496,7 +494,7 @@ int showOptionsWithInitialKeyCode(int initialKeyCode)
case KEY_UPPERCASE_S:
case KEY_LOWERCASE_S:
case 500:
if (lsgSaveGame(1) != 1) {
if (lsgSaveGame(LOAD_SAVE_MODE_NORMAL) == 1) {
rc = 1;
}
break;

View File

@ -239,7 +239,7 @@ int _proto_list_str(int pid, char* proto_path)
*pch = '\0';
}
pch = strchr(string, '\n');
pch = strpbrk(string, "\r\n");
if (pch != NULL) {
*pch = '\0';
}

View File

@ -3,6 +3,8 @@
#include <limits.h>
#include <stdlib.h>
#include <random>
#include "debug.h"
#include "platform_compat.h"
#include "scripts.h"
@ -37,7 +39,7 @@ static int _idum;
void randomInit()
{
unsigned int randomSeed = randomGetSeed();
srand(randomSeed);
std::srand(randomSeed);
int pseudorandomSeed = randomInt32();
randomSeedPrerandomInternal(pseudorandomSeed);
@ -183,10 +185,7 @@ void randomSeedPrerandom(int seed)
// 0x4A31C4
static int randomInt32()
{
int high = rand() << 16;
int low = rand();
return (high + low) & INT_MAX;
return std::rand();
}
// 0x4A31E0

View File

@ -2354,6 +2354,11 @@ int _scr_remove_all()
} else {
next = scriptListExtent->next;
scriptRemove(script->sid);
// CE: Current extent is freed in |scriptRemove|. Break
// to prevent next iteration which needs to dereference
// extent to obtain it's length.
break;
}
}
}

View File

@ -58,7 +58,7 @@ namespace fallout {
#define SFALL_CONFIG_GAME_DIALOG_FIX_KEY "DialogueFix"
#define SFALL_CONFIG_TWEAKS_FILE_KEY "TweaksFile"
#define SFALL_CONFIG_GAME_DIALOG_GENDER_WORDS_KEY "DialogGenderWords"
#define SFALL_CONFIG_TOWN_MAP_HOTKEYS_FIX "TownMapHotkeysFix"
#define SFALL_CONFIG_TOWN_MAP_HOTKEYS_FIX_KEY "TownMapHotkeysFix"
#define SFALL_CONFIG_BURST_MOD_DEFAULT_CENTER_MULTIPLIER 1
#define SFALL_CONFIG_BURST_MOD_DEFAULT_CENTER_DIVISOR 3

View File

@ -207,7 +207,7 @@ static Rect gTileWindowRect;
static unsigned char _tile_grid[32 * 16];
// 0x66BDE4
static int _square_rect;
static int _square_y;
// 0x66BDE8
static int _square_x;
@ -433,7 +433,7 @@ int tileInit(TileData** a1, int squareGridWidth, int squareGridHeight, int hexGr
gTileWindowWidth = ORIGINAL_ISO_WINDOW_WIDTH;
gTileWindowHeight = ORIGINAL_ISO_WINDOW_HEIGHT;
tileSetCenter(hexGridWidth * (hexGridHeight / 2) + hexGridWidth / 2, 2);
tileSetCenter(hexGridWidth * (hexGridHeight / 2) + hexGridWidth / 2, TILE_SET_CENTER_FLAG_IGNORE_SCROLL_RESTRICTIONS);
tileSetBorder(windowWidth, windowHeight, hexGridWidth, hexGridHeight);
// Restore actual window size and set center one more time to calculate
@ -442,7 +442,7 @@ int tileInit(TileData** a1, int squareGridWidth, int squareGridHeight, int hexGr
gTileWindowWidth = windowWidth;
gTileWindowHeight = windowHeight;
tileSetCenter(hexGridWidth * (hexGridHeight / 2) + hexGridWidth / 2, 2);
tileSetCenter(hexGridWidth * (hexGridHeight / 2) + hexGridWidth / 2, TILE_SET_CENTER_FLAG_IGNORE_SCROLL_RESTRICTIONS);
if (compat_stricmp(settings.system.executable.c_str(), "mapper") == 0) {
gTileWindowRefreshElevationProc = tileRefreshMapper;
@ -533,29 +533,31 @@ int tileSetCenter(int tile, int flags)
return -1;
}
if ((gTileScrollLimitingEnabled & ((flags & TILE_SET_CENTER_FLAG_0x02) == 0)) != 0) {
int tileScreenX;
int tileScreenY;
tileToScreenXY(tile, &tileScreenX, &tileScreenY, gElevation);
if ((flags & TILE_SET_CENTER_FLAG_IGNORE_SCROLL_RESTRICTIONS) == 0) {
if (gTileScrollLimitingEnabled) {
int tileScreenX;
int tileScreenY;
tileToScreenXY(tile, &tileScreenX, &tileScreenY, gElevation);
int dudeScreenX;
int dudeScreenY;
tileToScreenXY(gDude->tile, &dudeScreenX, &dudeScreenY, gElevation);
int dudeScreenX;
int dudeScreenY;
tileToScreenXY(gDude->tile, &dudeScreenX, &dudeScreenY, gElevation);
int dx = abs(dudeScreenX - tileScreenX);
int dy = abs(dudeScreenY - tileScreenY);
int dx = abs(dudeScreenX - tileScreenX);
int dy = abs(dudeScreenY - tileScreenY);
if (dx > abs(dudeScreenX - _tile_offx)
|| dy > abs(dudeScreenY - _tile_offy)) {
if (dx >= 480 || dy >= 400) {
return -1;
if (dx > abs(dudeScreenX - _tile_offx)
|| dy > abs(dudeScreenY - _tile_offy)) {
if (dx >= 480 || dy >= 400) {
return -1;
}
}
}
}
if ((gTileScrollBlockingEnabled & ((flags & TILE_SET_CENTER_FLAG_0x02) == 0)) != 0) {
if (_obj_scroll_blocking_at(tile, gElevation) == 0) {
return -1;
if (gTileScrollBlockingEnabled) {
if (_obj_scroll_blocking_at(tile, gElevation) == 0) {
return -1;
}
}
}
@ -579,7 +581,7 @@ int tileSetCenter(int tile, int flags)
}
_square_x = _tile_x / 2;
_square_rect = _tile_y / 2;
_square_y = _tile_y / 2;
_square_offx = _tile_offx - 16;
_square_offy = _tile_offy - 2;
@ -590,7 +592,7 @@ int tileSetCenter(int tile, int flags)
gCenterTile = tile;
if (flags & TILE_SET_CENTER_FLAG_0x01) {
if ((flags & TILE_SET_CENTER_REFRESH_WINDOW) != 0) {
// NOTE: Uninline.
tileWindowRefresh();
}
@ -1080,7 +1082,7 @@ int squareTileToScreenXY(int squareTile, int* coordX, int* coordY, int elevation
*coordX += 48 * v8;
*coordY -= 12 * v8;
v9 = v6 - _square_rect;
v9 = v6 - _square_y;
*coordX += 32 * v9;
*coordY += 24 * v9;
@ -1111,7 +1113,7 @@ int squareTileToRoofScreenXY(int squareTile, int* screenX, int* screenY, int ele
*screenX += 48 * v8;
*screenY -= 12 * v8;
v9 = v6 - _square_rect;
v9 = v6 - _square_y;
*screenX += 32 * v9;
v10 = 24 * v9 + *screenY;
*screenY = v10;
@ -1149,12 +1151,10 @@ void squareTileScreenToCoord(int screenX, int screenY, int elevation, int* coord
*coordX = v6 >= 0 ? (v6 / 192) : ((v6 + 1) / 192 - 1);
v8 = 4 * v5 + v4;
*coordY = v8 >= 0
? ((v8 - ((v8 >> 31) << 7)) >> 7)
: ((((v8 + 1) - (((v8 + 1) >> 31) << 7)) >> 7) - 1);
*coordY = v8 >= 0 ? (v8 / 128) : ((v8 + 1) / 128 - 1);
*coordX += _square_x;
*coordY += _square_rect;
*coordY += _square_y;
*coordX = gSquareGridWidth - 1 - *coordX;
}
@ -1174,12 +1174,10 @@ void squareTileScreenToCoordRoof(int screenX, int screenY, int elevation, int* c
*coordX = (v6 >= 0) ? (v6 / 192) : ((v6 + 1) / 192 - 1);
v8 = 4 * v5 + v4;
*coordY = (v8 >= 0)
? ((v8 - ((v8 >> 31) << 7)) >> 7)
: ((((v8 + 1) - (((v8 + 1) >> 31) << 7)) >> 7) - 1);
*coordY = v8 >= 0 ? (v8 / 128) : ((v8 + 1) / 128 - 1);
*coordX += _square_x;
*coordY += _square_rect;
*coordY += _square_y;
*coordX = gSquareGridWidth - 1 - *coordX;
}

View File

@ -6,8 +6,8 @@
namespace fallout {
#define TILE_SET_CENTER_FLAG_0x01 0x01
#define TILE_SET_CENTER_FLAG_0x02 0x02
#define TILE_SET_CENTER_REFRESH_WINDOW 0x01
#define TILE_SET_CENTER_FLAG_IGNORE_SCROLL_RESTRICTIONS 0x02
typedef void(TileWindowRefreshProc)(Rect* rect);
typedef void(TileWindowRefreshElevationProc)(Rect* rect, int elevation);

View File

@ -887,7 +887,7 @@ int _selectWindow(const char* windowName)
}
}
if (!_selectWindowID(index)) {
if (_selectWindowID(index)) {
return index;
}
@ -1725,7 +1725,7 @@ bool _windowAddButtonGfx(const char* buttonName, char* pressedFileName, char* no
// 0x4BA11C
bool _windowAddButtonProc(const char* buttonName, Program* program, int mouseEnterProc, int mouseExitProc, int mouseDownProc, int mouseUpProc)
{
if (gCurrentManagedWindowIndex != -1) {
if (gCurrentManagedWindowIndex == -1) {
return false;
}

View File

@ -847,7 +847,16 @@ int wmWorldMap_init()
// SFALL
gTownMapHotkeysFix = true;
configGetBool(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_TOWN_MAP_HOTKEYS_FIX, &gTownMapHotkeysFix);
configGetBool(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_TOWN_MAP_HOTKEYS_FIX_KEY, &gTownMapHotkeysFix);
// CE: City size fids should be initialized during startup. They are used
// during |wmTeleportToArea| to calculate worldmap position when jumping
// from Temple to Arroyo - before giving a chance to |wmInterfaceInit| to
// initialize it.
for (int citySize = 0; citySize < CITY_SIZE_COUNT; citySize++) {
CitySizeDescription* citySizeDescription = &(wmSphereData[citySize]);
citySizeDescription->fid = buildFid(OBJ_TYPE_INTERFACE, 336 + citySize, 0, 0, 0);
}
return 0;
}
@ -1397,7 +1406,17 @@ static int wmParseEncounterTableIndex(EncounterEntry* entry, char* string)
if (strstr(string, "special")) {
entry->flags |= ENCOUNTER_ENTRY_SPECIAL;
string += 8;
// CE: Original code unconditionally consumes 8 characters, which is
// right when "special" is followed by conditions (separated with
// comma). However when "special" is the last keyword (which I guess
// is wrong, but present in worldmap.txt), consuming 8 characters
// sets pointer past NULL terminator, which can lead to many bad
// things (UB).
string += 7;
if (*string != '\0') {
string++;
}
}
if (string != NULL) {
@ -4459,11 +4478,7 @@ static int wmInterfaceInit()
for (int citySize = 0; citySize < CITY_SIZE_COUNT; citySize++) {
CitySizeDescription* citySizeDescription = &(wmSphereData[citySize]);
fid = buildFid(OBJ_TYPE_INTERFACE, 336 + citySize, 0, 0, 0);
citySizeDescription->fid = fid;
if (!citySizeDescription->frmImage.lock(fid)) {
if (!citySizeDescription->frmImage.lock(citySizeDescription->fid)) {
return -1;
}
}
@ -6530,9 +6545,21 @@ int wmTeleportToArea(int areaIdx)
// locations.
// CE: See `wmWorldMapFunc` for explanation.
CitySizeDescription* citySizeDescription = &(wmSphereData[city->size]);
// CE: This function might be called outside |wmWorldmapFunc|, so it's
// image might not be locked.
bool wasLocked = citySizeDescription->frmImage.isLocked();
if (!wasLocked) {
citySizeDescription->frmImage.lock(citySizeDescription->fid);
}
wmGenData.worldPosX = city->x + citySizeDescription->frmImage.getWidth() / 2 - WM_VIEW_X;
wmGenData.worldPosY = city->y + citySizeDescription->frmImage.getHeight() / 2 - WM_VIEW_Y;
if (!wasLocked) {
citySizeDescription->frmImage.unlock();
}
return 0;
}