fallout2-ce/src/map.cc

1738 lines
42 KiB
C++
Raw Normal View History

2022-05-19 01:51:26 -07:00
#include "map.h"
2022-09-15 02:38:23 -07:00
#include <stdio.h>
#include <string.h>
#include <vector>
2022-05-19 01:51:26 -07:00
#include "animation.h"
2022-06-19 04:27:29 -07:00
#include "art.h"
2022-05-19 01:51:26 -07:00
#include "automap.h"
#include "character_editor.h"
#include "color.h"
#include "combat.h"
#include "critter.h"
#include "cycle.h"
#include "debug.h"
#include "draw.h"
2022-08-03 02:34:13 -07:00
#include "elevator.h"
2022-05-19 01:51:26 -07:00
#include "game.h"
#include "game_mouse.h"
#include "game_movie.h"
#include "game_sound.h"
2022-10-04 23:23:27 -07:00
#include "input.h"
2022-05-19 01:51:26 -07:00
#include "interface.h"
#include "item.h"
#include "light.h"
#include "loadsave.h"
#include "memory.h"
#include "object.h"
#include "palette.h"
2022-06-19 02:00:14 -07:00
#include "party_member.h"
2022-05-19 01:51:26 -07:00
#include "pipboy.h"
#include "proto.h"
#include "proto_instance.h"
#include "queue.h"
#include "random.h"
#include "scripts.h"
#include "settings.h"
2022-10-05 00:35:05 -07:00
#include "svga.h"
2022-05-19 01:51:26 -07:00
#include "text_object.h"
#include "tile.h"
#include "window_manager.h"
#include "window_manager_private.h"
2022-09-14 23:00:11 -07:00
#include "worldmap.h"
2022-05-19 01:51:26 -07:00
2022-09-23 05:43:44 -07:00
namespace fallout {
2022-06-19 10:14:17 -07:00
static char* mapBuildPath(char* name);
static int mapLoad(File* stream);
static int _map_age_dead_critters();
static void _map_fix_critter_combat_data();
static int _map_save();
static int _map_save_file(File* stream);
static void mapMakeMapsDirectory();
static void isoWindowRefreshRect(Rect* rect);
static void isoWindowRefreshRectGame(Rect* rect);
static void isoWindowRefreshRectMapper(Rect* rect);
2022-09-15 08:16:46 -07:00
static int mapGlobalVariablesInit(int count);
2022-06-19 10:14:17 -07:00
static void mapGlobalVariablesFree();
2022-09-15 08:17:16 -07:00
static int mapGlobalVariablesLoad(File* stream);
2022-09-15 08:19:50 -07:00
static int mapLocalVariablesInit(int count);
2022-06-19 10:14:17 -07:00
static void mapLocalVariablesFree();
2022-09-15 08:22:27 -07:00
static int mapLocalVariablesLoad(File* stream);
2022-06-19 10:14:17 -07:00
static void _map_place_dude_and_mouse();
2022-09-15 08:25:48 -07:00
static void square_init();
2022-06-19 10:14:17 -07:00
static void _square_reset();
static int _square_load(File* stream, int a2);
static int mapHeaderWrite(MapHeader* ptr, File* stream);
static int mapHeaderRead(MapHeader* ptr, File* stream);
2022-05-19 01:51:26 -07:00
// 0x50B058
2022-06-19 10:14:17 -07:00
static char byte_50B058[] = "";
2022-05-19 01:51:26 -07:00
// 0x50B30C
2022-06-19 10:14:17 -07:00
static char _aErrorF2[] = "ERROR! F2";
2022-05-19 01:51:26 -07:00
// 0x519540
2022-06-19 10:14:17 -07:00
static IsoWindowRefreshProc* _map_scroll_refresh = isoWindowRefreshRectGame;
2022-05-19 01:51:26 -07:00
// 0x519544
2022-06-19 10:14:17 -07:00
static const int _map_data_elev_flags[ELEVATION_COUNT] = {
2022-05-19 01:51:26 -07:00
2,
4,
8,
};
// 0x519550
2022-06-19 10:14:17 -07:00
static unsigned int gIsoWindowScrollTimestamp = 0;
2022-05-19 01:51:26 -07:00
// 0x519554
2022-06-19 10:14:17 -07:00
static bool gIsoEnabled = false;
2022-05-19 01:51:26 -07:00
// 0x519558
2022-06-19 10:14:17 -07:00
static int gEnteringElevation = 0;
2022-05-19 01:51:26 -07:00
// 0x51955C
2022-06-19 10:14:17 -07:00
static int gEnteringTile = -1;
2022-05-19 01:51:26 -07:00
// 0x519560
2022-06-19 10:14:17 -07:00
static int gEnteringRotation = ROTATION_NE;
2022-05-19 01:51:26 -07:00
// 0x519564
int gMapSid = -1;
// local_vars
// 0x519568
int* gMapLocalVars = NULL;
// map_vars
// 0x51956C
2022-06-19 10:14:17 -07:00
static int* gMapGlobalVars = NULL;
2022-05-19 01:51:26 -07:00
// local_vars_num
// 0x519570
int gMapLocalVarsLength = 0;
// map_vars_num
// 0x519574
2022-06-19 10:14:17 -07:00
static int gMapGlobalVarsLength = 0;
2022-05-19 01:51:26 -07:00
// Current elevation.
//
// 0x519578
int gElevation = 0;
// 0x51957C
2022-06-19 10:14:17 -07:00
static char* _errMapName = byte_50B058;
2022-05-19 01:51:26 -07:00
// 0x519584
2022-06-19 10:14:17 -07:00
static int _wmMapIdx = -1;
2022-05-19 01:51:26 -07:00
// 0x614868
2022-06-19 10:14:17 -07:00
static TileData _square_data[ELEVATION_COUNT];
2022-05-19 01:51:26 -07:00
// 0x631D28
2022-06-19 10:14:17 -07:00
static MapTransition gMapTransition;
2022-05-19 01:51:26 -07:00
// 0x631D38
2022-06-19 10:14:17 -07:00
static Rect gIsoWindowRect;
2022-05-19 01:51:26 -07:00
// map.msg
//
// map_msg_file
// 0x631D48
MessageList gMapMessageList;
// 0x631D50
2022-06-19 10:14:17 -07:00
static unsigned char* gIsoWindowBuffer;
2022-05-19 01:51:26 -07:00
// 0x631D54
MapHeader gMapHeader;
// 0x631E40
TileData* _square[ELEVATION_COUNT];
// 0x631E4C
int gIsoWindow;
// 0x631E50
2022-06-19 10:14:17 -07:00
static char _scratchStr[40];
2022-05-19 01:51:26 -07:00
// Last map file name.
//
// 0x631E78
2022-06-19 10:14:17 -07:00
static char _map_path[COMPAT_MAX_PATH];
2022-05-19 01:51:26 -07:00
// CE: There is a bug in the user-space scripting where they want to store
// pointers to |Object| instances in local vars. This is obviously wrong as it's
// meaningless to save these pointers in file. As a workaround use second array
// to store these pointers.
static std::vector<void*> gMapLocalPointers;
2022-05-19 01:51:26 -07:00
// iso_init
// 0x481CA0
int isoInit()
{
2022-05-23 15:37:46 -07:00
tileScrollLimitingDisable();
tileScrollBlockingDisable();
2022-05-19 01:51:26 -07:00
2022-09-15 08:25:48 -07:00
// NOTE: Uninline.
square_init();
2022-05-19 01:51:26 -07:00
gIsoWindow = windowCreate(0, 0, screenGetWidth(), screenGetVisibleHeight(), 256, 10);
2022-05-19 01:51:26 -07:00
if (gIsoWindow == -1) {
debugPrint("win_add failed in iso_init\n");
return -1;
}
gIsoWindowBuffer = windowGetBuffer(gIsoWindow);
if (gIsoWindowBuffer == NULL) {
debugPrint("win_get_buf failed in iso_init\n");
return -1;
}
if (windowGetRect(gIsoWindow, &gIsoWindowRect) != 0) {
debugPrint("win_get_rect failed in iso_init\n");
return -1;
}
if (artInit() != 0) {
debugPrint("art_init failed in iso_init\n");
return -1;
}
debugPrint(">art_init\t\t");
if (tileInit(_square, SQUARE_GRID_WIDTH, SQUARE_GRID_HEIGHT, HEX_GRID_WIDTH, HEX_GRID_HEIGHT, gIsoWindowBuffer, screenGetWidth(), screenGetVisibleHeight(), screenGetWidth(), isoWindowRefreshRect) != 0) {
2022-05-19 01:51:26 -07:00
debugPrint("tile_init failed in iso_init\n");
return -1;
}
debugPrint(">tile_init\t\t");
if (objectsInit(gIsoWindowBuffer, screenGetWidth(), screenGetVisibleHeight(), screenGetWidth()) != 0) {
2022-05-19 01:51:26 -07:00
debugPrint("obj_init failed in iso_init\n");
return -1;
}
debugPrint(">obj_init\t\t");
colorCycleInit();
debugPrint(">cycle_init\t\t");
2022-05-23 15:37:46 -07:00
tileScrollBlockingEnable();
tileScrollLimitingEnable();
2022-05-19 01:51:26 -07:00
if (interfaceInit() != 0) {
debugPrint("intface_init failed in iso_init\n");
return -1;
}
debugPrint(">intface_init\t\t");
2022-08-03 02:34:13 -07:00
// SFALL
elevatorsInit();
2022-05-19 01:51:26 -07:00
mapMakeMapsDirectory();
2022-09-15 09:59:16 -07:00
// NOTE: Uninline.
mapSetEnteringLocation(-1, -1, -1);
2022-05-19 01:51:26 -07:00
return 0;
}
// 0x481ED4
void isoReset()
{
2022-09-15 07:43:33 -07:00
// NOTE: Uninline.
mapGlobalVariablesFree();
2022-05-19 01:51:26 -07:00
2022-09-15 07:43:33 -07:00
// NOTE: Uninline.
mapLocalVariablesFree();
2022-05-19 01:51:26 -07:00
artReset();
tileReset();
objectsReset();
colorCycleReset();
interfaceReset();
2022-09-15 07:43:33 -07:00
// NOTE: Uninline.
mapSetEnteringLocation(-1, -1, -1);
2022-05-19 01:51:26 -07:00
}
// 0x481F48
void isoExit()
{
interfaceFree();
colorCycleFree();
objectsExit();
tileExit();
artExit();
2022-09-15 07:45:35 -07:00
windowDestroy(gIsoWindow);
2022-05-19 01:51:26 -07:00
2022-09-15 07:45:35 -07:00
// NOTE: Uninline.
mapGlobalVariablesFree();
// NOTE: Uninline.
mapLocalVariablesFree();
2022-05-19 01:51:26 -07:00
}
// 0x481FB4
void _map_init()
{
if (compat_stricmp(settings.system.executable.c_str(), "mapper") == 0) {
2022-05-19 01:51:26 -07:00
_map_scroll_refresh = isoWindowRefreshRectMapper;
}
if (messageListInit(&gMapMessageList)) {
2022-05-28 02:34:49 -07:00
char path[COMPAT_MAX_PATH];
2022-05-19 01:51:26 -07:00
sprintf(path, "%smap.msg", asc_5186C8);
if (!messageListLoad(&gMapMessageList, path)) {
debugPrint("\nError loading map_msg_file!");
}
} else {
debugPrint("\nError initing map_msg_file!");
}
2022-09-15 07:49:40 -07:00
mapNewMap();
2022-05-19 01:51:26 -07:00
tickersAdd(gameMouseRefresh);
_gmouse_disable(0);
windowUnhide(gIsoWindow);
}
// 0x482084
void _map_exit()
{
windowHide(gIsoWindow);
gameMouseSetCursor(MOUSE_CURSOR_ARROW);
tickersRemove(gameMouseRefresh);
if (!messageListFree(&gMapMessageList)) {
debugPrint("\nError exiting map_msg_file!");
}
}
// 0x4820C0
void isoEnable()
{
if (!gIsoEnabled) {
textObjectsEnable();
if (!gameUiIsDisabled()) {
_gmouse_enable();
}
tickersAdd(_object_animate);
tickersAdd(_dude_fidget);
_scr_enable_critters();
gIsoEnabled = true;
}
}
// 0x482104
bool isoDisable()
{
if (!gIsoEnabled) {
return false;
}
_scr_disable_critters();
tickersRemove(_dude_fidget);
tickersRemove(_object_animate);
_gmouse_disable(0);
textObjectsDisable();
gIsoEnabled = false;
return true;
}
// 0x482148
bool isoIsDisabled()
{
return gIsoEnabled == false;
}
// map_set_elevation
// 0x482158
int mapSetElevation(int elevation)
{
if (!elevationIsValid(elevation)) {
return -1;
}
bool gameMouseWasVisible = false;
if (gameMouseGetCursor() != MOUSE_CURSOR_WAIT_PLANET) {
gameMouseWasVisible = gameMouseObjectsIsVisible();
gameMouseObjectsHide();
gameMouseSetCursor(MOUSE_CURSOR_NONE);
}
if (elevation != gElevation) {
2022-09-15 01:42:02 -07:00
wmMapMarkMapEntranceState(gMapHeader.field_34, elevation, 1);
2022-05-19 01:51:26 -07:00
}
gElevation = elevation;
reg_anim_clear(gDude);
_dude_stand(gDude, gDude->rotation, gDude->fid);
_partyMemberSyncPosition();
if (gMapSid != -1) {
scriptsExecMapUpdateProc();
}
if (gameMouseWasVisible) {
gameMouseObjectsShow();
}
return 0;
}
// 0x482220
int mapSetGlobalVar(int var, int value)
{
if (var < 0 || var >= gMapGlobalVarsLength) {
debugPrint("ERROR: attempt to reference map var out of range: %d", var);
return -1;
}
gMapGlobalVars[var] = value;
return 0;
}
// 0x482250
int mapGetGlobalVar(int var)
{
if (var < 0 || var >= gMapGlobalVarsLength) {
debugPrint("ERROR: attempt to reference map var out of range: %d", var);
return 0;
}
return gMapGlobalVars[var];
}
// 0x482280
int mapSetLocalVar(int var, ProgramValue& value)
2022-05-19 01:51:26 -07:00
{
if (var < 0 || var >= gMapLocalVarsLength) {
debugPrint("ERROR: attempt to reference local var out of range: %d", var);
return -1;
}
if (value.opcode == VALUE_TYPE_PTR) {
gMapLocalVars[var] = 0;
gMapLocalPointers[var] = value.pointerValue;
} else {
gMapLocalVars[var] = value.integerValue;
gMapLocalPointers[var] = nullptr;
}
2022-05-19 01:51:26 -07:00
return 0;
}
// 0x4822B0
int mapGetLocalVar(int var, ProgramValue& value)
2022-05-19 01:51:26 -07:00
{
if (var < 0 || var >= gMapLocalVarsLength) {
debugPrint("ERROR: attempt to reference local var out of range: %d", var);
return -1;
2022-05-19 01:51:26 -07:00
}
if (gMapLocalPointers[var] != nullptr) {
value.opcode = VALUE_TYPE_PTR;
value.pointerValue = gMapLocalPointers[var];
} else {
value.opcode = VALUE_TYPE_INT;
value.integerValue = gMapLocalVars[var];
}
return 0;
2022-05-19 01:51:26 -07:00
}
// Make a room to store more local variables.
//
// 0x4822E0
int _map_malloc_local_var(int a1)
{
int oldMapLocalVarsLength = gMapLocalVarsLength;
gMapLocalVarsLength += a1;
2022-05-21 08:22:03 -07:00
int* vars = (int*)internal_realloc(gMapLocalVars, sizeof(*vars) * gMapLocalVarsLength);
2022-05-19 01:51:26 -07:00
if (vars == NULL) {
debugPrint("\nError: Ran out of memory!");
}
gMapLocalVars = vars;
memset((unsigned char*)vars + sizeof(*vars) * oldMapLocalVarsLength, 0, sizeof(*vars) * a1);
gMapLocalPointers.resize(gMapLocalVarsLength);
2022-05-19 01:51:26 -07:00
return oldMapLocalVarsLength;
}
// 0x48234C
void mapSetStart(int tile, int elevation, int rotation)
{
gMapHeader.enteringTile = tile;
gMapHeader.enteringElevation = elevation;
gMapHeader.enteringRotation = rotation;
}
// 0x4824CC
char* mapGetName(int map, int elevation)
{
2022-09-15 01:42:02 -07:00
if (map < 0 || map >= wmMapMaxCount()) {
2022-05-19 01:51:26 -07:00
return NULL;
}
if (!elevationIsValid(elevation)) {
return NULL;
}
MessageListItem messageListItem;
return getmsg(&gMapMessageList, &messageListItem, map * 3 + elevation + 200);
}
// TODO: Check, probably returns true if map1 and map2 represents the same city.
//
// 0x482528
bool _is_map_idx_same(int map1, int map2)
{
2022-09-15 01:42:02 -07:00
if (map1 < 0 || map1 >= wmMapMaxCount()) {
2022-05-19 01:51:26 -07:00
return 0;
}
2022-09-15 01:42:02 -07:00
if (map2 < 0 || map2 >= wmMapMaxCount()) {
2022-05-19 01:51:26 -07:00
return 0;
}
2022-09-15 01:42:02 -07:00
if (!wmMapIdxIsSaveable(map1)) {
2022-05-19 01:51:26 -07:00
return 0;
}
2022-09-15 01:42:02 -07:00
if (!wmMapIdxIsSaveable(map2)) {
2022-05-19 01:51:26 -07:00
return 0;
}
int city1;
2022-09-15 01:42:02 -07:00
if (wmMatchAreaContainingMapIdx(map1, &city1) == -1) {
2022-05-19 01:51:26 -07:00
return 0;
}
int city2;
2022-09-15 01:42:02 -07:00
if (wmMatchAreaContainingMapIdx(map2, &city2) == -1) {
2022-05-19 01:51:26 -07:00
return 0;
}
return city1 == city2;
}
// 0x4825CC
int _get_map_idx_same(int map1, int map2)
{
int city1 = -1;
2022-09-15 01:42:02 -07:00
if (wmMatchAreaContainingMapIdx(map1, &city1) == -1) {
2022-05-19 01:51:26 -07:00
return -1;
}
int city2 = -2;
2022-09-15 01:42:02 -07:00
if (wmMatchAreaContainingMapIdx(map2, &city2) == -1) {
2022-05-19 01:51:26 -07:00
return -1;
}
if (city1 != city2) {
return -1;
}
return city1;
}
// 0x48261C
char* mapGetCityName(int map)
{
int city;
2022-09-15 01:42:02 -07:00
if (wmMatchAreaContainingMapIdx(map, &city) == -1) {
2022-05-19 01:51:26 -07:00
return _aErrorF2;
}
MessageListItem messageListItem;
char* name = getmsg(&gMapMessageList, &messageListItem, 1500 + city);
return name;
}
// 0x48268C
char* _map_get_description_idx_(int map)
{
int city;
2022-09-15 01:42:02 -07:00
if (wmMatchAreaContainingMapIdx(map, &city) == 0) {
wmGetAreaIdxName(city, _scratchStr);
2022-05-19 01:51:26 -07:00
} else {
strcpy(_scratchStr, _errMapName);
}
return _scratchStr;
}
// 0x4826B8
int mapGetCurrentMap()
{
return gMapHeader.field_34;
}
// 0x4826C0
int mapScroll(int dx, int dy)
{
if (getTicksSince(gIsoWindowScrollTimestamp) < 33) {
return -2;
}
2022-10-05 00:11:47 -07:00
gIsoWindowScrollTimestamp = getTicks();
2022-05-19 01:51:26 -07:00
int screenDx = dx * 32;
int screenDy = dy * 24;
if (screenDx == 0 && screenDy == 0) {
return -1;
}
gameMouseObjectsHide();
int centerScreenX;
int centerScreenY;
tileToScreenXY(gCenterTile, &centerScreenX, &centerScreenY, gElevation);
centerScreenX += screenDx + 16;
centerScreenY += screenDy + 8;
int newCenterTile = tileFromScreenXY(centerScreenX, centerScreenY, gElevation);
if (newCenterTile == -1) {
return -1;
}
if (tileSetCenter(newCenterTile, 0) == -1) {
return -1;
}
Rect r1;
rectCopy(&r1, &gIsoWindowRect);
Rect r2;
rectCopy(&r2, &r1);
int width = screenGetWidth();
2022-05-19 01:51:26 -07:00
int pitch = width;
int height = screenGetVisibleHeight();
2022-05-19 01:51:26 -07:00
if (screenDx != 0) {
width -= 32;
}
if (screenDy != 0) {
height -= 24;
}
if (screenDx < 0) {
r2.right = r2.left - screenDx;
} else {
r2.left = r2.right - screenDx;
}
unsigned char* src;
unsigned char* dest;
int step;
if (screenDy < 0) {
r1.bottom = r1.top - screenDy;
src = gIsoWindowBuffer + pitch * (height - 1);
dest = gIsoWindowBuffer + pitch * (screenGetVisibleHeight() - 1);
2022-05-19 01:51:26 -07:00
if (screenDx < 0) {
dest -= screenDx;
} else {
src += screenDx;
}
step = -pitch;
} else {
r1.top = r1.bottom - screenDy;
dest = gIsoWindowBuffer;
src = gIsoWindowBuffer + pitch * screenDy;
if (screenDx < 0) {
dest -= screenDx;
} else {
src += screenDx;
}
step = pitch;
}
for (int y = 0; y < height; y++) {
memmove(dest, src, width);
dest += step;
src += step;
}
if (screenDx != 0) {
_map_scroll_refresh(&r2);
}
if (screenDy != 0) {
_map_scroll_refresh(&r1);
}
windowRefresh(gIsoWindow);
return 0;
}
// 0x482900
2022-06-19 10:14:17 -07:00
static char* mapBuildPath(char* name)
2022-05-19 01:51:26 -07:00
{
if (*name != '\\') {
// NOTE: Uppercased from "maps".
sprintf(_map_path, "MAPS\\%s", name);
2022-05-19 01:51:26 -07:00
return _map_path;
}
return name;
}
// 0x482924
int mapSetEnteringLocation(int elevation, int tile_num, int orientation)
{
gEnteringElevation = elevation;
gEnteringTile = tile_num;
gEnteringRotation = orientation;
return 0;
}
// 0x482938
2022-09-15 07:49:40 -07:00
void mapNewMap()
2022-05-19 01:51:26 -07:00
{
mapSetElevation(0);
tileSetCenter(20100, TILE_SET_CENTER_FLAG_0x02);
memset(&gMapTransition, 0, sizeof(gMapTransition));
gMapHeader.enteringElevation = 0;
gMapHeader.enteringRotation = 0;
gMapHeader.localVariablesCount = 0;
gMapHeader.version = 20;
gMapHeader.name[0] = '\0';
gMapHeader.enteringTile = 20100;
_obj_remove_all();
2022-07-07 01:28:21 -07:00
animationStop();
2022-05-19 01:51:26 -07:00
2022-09-15 07:49:40 -07:00
// NOTE: Uninline.
mapGlobalVariablesFree();
2022-05-19 01:51:26 -07:00
2022-09-15 07:49:40 -07:00
// NOTE: Uninline.
mapLocalVariablesFree();
2022-05-19 01:51:26 -07:00
_square_reset();
_map_place_dude_and_mouse();
tileWindowRefresh();
}
// 0x482A68
int mapLoadByName(char* fileName)
{
int rc;
compat_strupr(fileName);
2022-05-19 01:51:26 -07:00
rc = -1;
char* extension = strstr(fileName, ".MAP");
if (extension != NULL) {
strcpy(extension, ".SAV");
const char* filePath = mapBuildPath(fileName);
File* stream = fileOpen(filePath, "rb");
strcpy(extension, ".MAP");
if (stream != NULL) {
fileClose(stream);
rc = mapLoadSaved(fileName);
2022-09-15 01:42:02 -07:00
wmMapMusicStart();
2022-05-19 01:51:26 -07:00
}
}
if (rc == -1) {
const char* filePath = mapBuildPath(fileName);
File* stream = fileOpen(filePath, "rb");
if (stream != NULL) {
rc = mapLoad(stream);
fileClose(stream);
}
if (rc == 0) {
strcpy(gMapHeader.name, fileName);
gDude->data.critter.combat.whoHitMe = NULL;
}
}
return rc;
}
// 0x482B34
int mapLoadById(int map)
{
scriptSetFixedParam(gMapSid, map);
char name[16];
2022-09-15 01:42:02 -07:00
if (wmMapIdxToName(map, name) == -1) {
2022-05-19 01:51:26 -07:00
return -1;
}
_wmMapIdx = map;
int rc = mapLoadByName(name);
2022-09-15 01:42:02 -07:00
wmMapMusicStart();
2022-05-19 01:51:26 -07:00
return rc;
}
// 0x482B74
2022-06-19 10:14:17 -07:00
static int mapLoad(File* stream)
2022-05-19 01:51:26 -07:00
{
_map_save_in_game(true);
backgroundSoundLoad("wind2", 12, 13, 16);
isoDisable();
_partyMemberPrepLoad();
_gmouse_disable_scrolling();
int savedMouseCursorId = gameMouseGetCursor();
gameMouseSetCursor(MOUSE_CURSOR_WAIT_PLANET);
2022-10-07 14:54:27 -07:00
fileSetReadProgressHandler(gameMouseRefreshImmediately, 32768);
2022-05-19 01:51:26 -07:00
tileDisable();
int rc = 0;
windowFill(gIsoWindow, 0, 0, _scr_size.right - _scr_size.left + 1, _scr_size.bottom - _scr_size.top - 99, _colorTable[0]);
windowRefresh(gIsoWindow);
2022-07-07 01:28:21 -07:00
animationStop();
2022-05-19 01:51:26 -07:00
scriptsDisable();
gMapSid = -1;
const char* error = NULL;
error = "Invalid file handle";
if (stream == NULL) {
goto err;
}
error = "Error reading header";
if (mapHeaderRead(&gMapHeader, stream) != 0) {
goto err;
}
error = "Invalid map version";
if (gMapHeader.version != 19 && gMapHeader.version != 20) {
goto err;
}
if (gEnteringElevation == -1) {
2022-09-15 09:59:16 -07:00
// NOTE: Uninline.
mapSetEnteringLocation(gMapHeader.enteringElevation, gMapHeader.enteringTile, gMapHeader.enteringRotation);
2022-05-19 01:51:26 -07:00
}
_obj_remove_all();
if (gMapHeader.globalVariablesCount < 0) {
gMapHeader.globalVariablesCount = 0;
}
if (gMapHeader.localVariablesCount < 0) {
gMapHeader.localVariablesCount = 0;
}
2022-09-15 08:16:46 -07:00
error = "Error allocating global vars";
// NOTE: Uninline.
if (mapGlobalVariablesInit(gMapHeader.globalVariablesCount) != 0) {
goto err;
2022-05-19 01:51:26 -07:00
}
2022-09-15 08:16:46 -07:00
error = "Error loading global vars";
2022-09-15 08:17:16 -07:00
// NOTE: Uninline.
if (mapGlobalVariablesLoad(stream) != 0) {
2022-05-19 01:51:26 -07:00
goto err;
}
2022-09-15 08:19:50 -07:00
error = "Error allocating local vars";
// NOTE: Uninline.
if (mapLocalVariablesInit(gMapHeader.localVariablesCount) != 0) {
goto err;
2022-05-19 01:51:26 -07:00
}
2022-09-15 08:19:50 -07:00
error = "Error loading local vars";
2022-09-15 08:22:27 -07:00
// NOTE: Uninline.
if (mapLocalVariablesLoad(stream) != 0) {
2022-05-19 01:51:26 -07:00
goto err;
}
if (_square_load(stream, gMapHeader.flags) != 0) {
goto err;
}
error = "Error reading scripts";
if (scriptLoadAll(stream) != 0) {
goto err;
}
error = "Error reading objects";
if (objectLoadAll(stream) != 0) {
goto err;
}
if ((gMapHeader.flags & 1) == 0) {
_map_fix_critter_combat_data();
}
error = "Error setting map elevation";
if (mapSetElevation(gEnteringElevation) != 0) {
goto err;
}
error = "Error setting tile center";
if (tileSetCenter(gEnteringTile, TILE_SET_CENTER_FLAG_0x02) != 0) {
goto err;
}
lightSetLightLevel(LIGHT_LEVEL_MAX, false);
objectSetLocation(gDude, gCenterTile, gElevation, NULL);
objectSetRotation(gDude, gEnteringRotation, NULL);
2022-09-15 01:42:02 -07:00
gMapHeader.field_34 = wmMapMatchNameToIdx(gMapHeader.name);
2022-05-19 01:51:26 -07:00
if ((gMapHeader.flags & 1) == 0) {
2022-05-28 02:34:49 -07:00
char path[COMPAT_MAX_PATH];
2022-05-19 01:51:26 -07:00
sprintf(path, "maps\\%s", gMapHeader.name);
char* extension = strstr(path, ".MAP");
if (extension == NULL) {
extension = strstr(path, ".map");
}
if (extension != NULL) {
*extension = '\0';
}
strcat(path, ".GAM");
globalVarsRead(path, "MAP_GLOBAL_VARS:", &gMapGlobalVarsLength, &gMapGlobalVars);
gMapHeader.globalVariablesCount = gMapGlobalVarsLength;
}
scriptsEnable();
if (gMapHeader.scriptIndex > 0) {
error = "Error creating new map script";
if (scriptAdd(&gMapSid, SCRIPT_TYPE_SYSTEM) == -1) {
goto err;
}
Object* object;
int fid = buildFid(OBJ_TYPE_MISC, 12, 0, 0, 0);
2022-05-19 01:51:26 -07:00
objectCreateWithFidPid(&object, fid, -1);
object->flags |= (OBJECT_LIGHT_THRU | OBJECT_TEMPORARY | OBJECT_HIDDEN);
2022-05-19 01:51:26 -07:00
objectSetLocation(object, 1, 0, NULL);
object->sid = gMapSid;
scriptSetFixedParam(gMapSid, (gMapHeader.flags & 1) == 0);
Script* script;
scriptGetScript(gMapSid, &script);
script->field_14 = gMapHeader.scriptIndex - 1;
script->flags |= SCRIPT_FLAG_0x08;
object->id = scriptsNewObjectId();
script->field_1C = object->id;
script->owner = object;
_scr_spatials_disable();
scriptExecProc(gMapSid, SCRIPT_PROC_MAP_ENTER);
_scr_spatials_enable();
error = "Error Setting up random encounter";
2022-09-15 01:42:02 -07:00
if (wmSetupRandomEncounter() == -1) {
2022-05-19 01:51:26 -07:00
goto err;
}
}
error = NULL;
err:
if (error != NULL) {
char message[100]; // TODO: Size is probably wrong.
sprintf(message, "%s while loading map.", error);
debugPrint(message);
2022-09-15 07:49:40 -07:00
mapNewMap();
2022-05-19 01:51:26 -07:00
rc = -1;
} else {
_obj_preload_art_cache(gMapHeader.flags);
}
_partyMemberRecoverLoad();
_intface_show();
_proto_dude_update_gender();
_map_place_dude_and_mouse();
fileSetReadProgressHandler(NULL, 0);
isoEnable();
_gmouse_disable_scrolling();
gameMouseSetCursor(MOUSE_CURSOR_WAIT_PLANET);
if (scriptsExecStartProc() == -1) {
debugPrint("\n Error: scr_load_all_scripts failed!");
}
scriptsExecMapEnterProc();
scriptsExecMapUpdateProc();
tileEnable();
if (gMapTransition.map > 0) {
if (gMapTransition.rotation >= 0) {
objectSetRotation(gDude, gMapTransition.rotation, NULL);
}
} else {
tileWindowRefresh();
}
gameTimeScheduleUpdateEvent();
if (_gsound_sfx_q_start() == -1) {
rc = -1;
}
2022-09-15 01:42:02 -07:00
wmMapMarkVisited(gMapHeader.field_34);
wmMapMarkMapEntranceState(gMapHeader.field_34, gElevation, 1);
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
if (wmCheckGameAreaEvents() != 0) {
2022-05-19 01:51:26 -07:00
rc = -1;
}
fileSetReadProgressHandler(NULL, 0);
if (gameUiIsDisabled() == 0) {
_gmouse_enable_scrolling();
}
gameMouseSetCursor(savedMouseCursorId);
2022-09-15 09:59:16 -07:00
// NOTE: Uninline.
mapSetEnteringLocation(-1, -1, -1);
2022-05-19 01:51:26 -07:00
gameMovieFadeOut();
gMapHeader.version = 20;
return rc;
}
// 0x483188
int mapLoadSaved(char* fileName)
{
debugPrint("\nMAP: Loading SAVED map.");
char mapName[16]; // TODO: Size is probably wrong.
_strmfe(mapName, fileName, "SAV");
int rc = mapLoadByName(mapName);
if (gameTimeGetTime() >= gMapHeader.lastVisitTime) {
if (((gameTimeGetTime() - gMapHeader.lastVisitTime) / GAME_TIME_TICKS_PER_HOUR) >= 24) {
2022-05-19 01:51:26 -07:00
objectUnjamAll();
}
if (_map_age_dead_critters() == -1) {
debugPrint("\nError: Critter aging failed on map load!");
return -1;
}
}
2022-09-15 01:42:02 -07:00
if (!wmMapIsSaveable()) {
2022-05-19 01:51:26 -07:00
debugPrint("\nDestroying RANDOM encounter map.");
char v15[16];
strcpy(v15, gMapHeader.name);
_strmfe(gMapHeader.name, v15, "SAV");
_MapDirEraseFile_("MAPS\\", gMapHeader.name);
strcpy(gMapHeader.name, v15);
}
return rc;
}
// 0x48328C
2022-06-19 10:14:17 -07:00
static int _map_age_dead_critters()
2022-05-19 01:51:26 -07:00
{
2022-09-15 01:42:02 -07:00
if (!wmMapDeadBodiesAge()) {
2022-05-19 01:51:26 -07:00
return 0;
}
int hoursSinceLastVisit = (gameTimeGetTime() - gMapHeader.lastVisitTime) / GAME_TIME_TICKS_PER_HOUR;
if (hoursSinceLastVisit == 0) {
2022-05-19 01:51:26 -07:00
return 0;
}
Object* obj = objectFindFirst();
while (obj != NULL) {
if (PID_TYPE(obj->pid) == OBJ_TYPE_CRITTER
2022-05-19 01:51:26 -07:00
&& obj != gDude
&& !objectIsPartyMember(obj)
&& !critterIsDead(obj)) {
obj->data.critter.combat.maneuver &= ~CRITTER_MANUEVER_FLEEING;
2022-10-05 03:06:49 -07:00
if (critterGetKillType(obj) != KILL_TYPE_ROBOT && !_critter_flag_check(obj->pid, CRITTER_NO_HEAL)) {
_critter_heal_hours(obj, hoursSinceLastVisit);
2022-05-19 01:51:26 -07:00
}
}
obj = objectFindNext();
}
int agingType;
if (hoursSinceLastVisit > 6 * 24) {
agingType = 1;
} else if (hoursSinceLastVisit > 14 * 24) {
agingType = 2;
2022-05-19 01:51:26 -07:00
} else {
return 0;
}
int capacity = 100;
int count = 0;
2022-05-21 08:22:03 -07:00
Object** objects = (Object**)internal_malloc(sizeof(*objects) * capacity);
2022-05-19 01:51:26 -07:00
obj = objectFindFirst();
while (obj != NULL) {
int type = PID_TYPE(obj->pid);
2022-05-19 01:51:26 -07:00
if (type == OBJ_TYPE_CRITTER) {
if (obj != gDude && critterIsDead(obj)) {
2022-10-05 03:06:49 -07:00
if (critterGetKillType(obj) != KILL_TYPE_ROBOT && !_critter_flag_check(obj->pid, CRITTER_NO_HEAL)) {
2022-05-19 01:51:26 -07:00
objects[count++] = obj;
if (count >= capacity) {
capacity *= 2;
2022-05-21 08:22:03 -07:00
objects = (Object**)internal_realloc(objects, sizeof(*objects) * capacity);
2022-05-19 01:51:26 -07:00
if (objects == NULL) {
debugPrint("\nError: Out of Memory!");
return -1;
}
}
}
}
} else if (agingType == 2 && type == OBJ_TYPE_MISC && obj->pid == 0x500000B) {
2022-05-19 01:51:26 -07:00
objects[count++] = obj;
if (count >= capacity) {
capacity *= 2;
2022-05-21 08:22:03 -07:00
objects = (Object**)internal_realloc(objects, sizeof(*objects) * capacity);
2022-05-19 01:51:26 -07:00
if (objects == NULL) {
debugPrint("\nError: Out of Memory!");
return -1;
}
}
}
obj = objectFindNext();
}
int rc = 0;
for (int index = 0; index < count; index++) {
Object* obj = objects[index];
if (PID_TYPE(obj->pid) == OBJ_TYPE_CRITTER) {
2022-10-05 03:06:49 -07:00
if (!_critter_flag_check(obj->pid, CRITTER_NO_DROP)) {
2022-08-17 22:41:15 -07:00
itemDropAll(obj, obj->tile);
2022-05-19 01:51:26 -07:00
}
Object* blood;
if (objectCreateWithPid(&blood, 0x5000004) == -1) {
2022-05-19 01:51:26 -07:00
rc = -1;
break;
}
objectSetLocation(blood, obj->tile, obj->elevation, NULL);
2022-05-19 01:51:26 -07:00
Proto* proto;
protoGetProto(obj->pid, &proto);
int frame = randomBetween(0, 3);
2022-10-05 03:06:49 -07:00
if ((proto->critter.flags & CRITTER_FLAT)) {
2022-05-19 01:51:26 -07:00
frame += 6;
} else {
if (critterGetKillType(obj) != KILL_TYPE_RAT
&& critterGetKillType(obj) != KILL_TYPE_MANTIS) {
frame += 3;
}
}
objectSetFrame(blood, frame, NULL);
2022-05-19 01:51:26 -07:00
}
reg_anim_clear(obj);
objectDestroy(obj, NULL);
}
internal_free(objects);
return rc;
}
// 0x48358C
int _map_target_load_area()
{
int city = -1;
2022-09-15 01:42:02 -07:00
if (wmMatchAreaContainingMapIdx(gMapHeader.field_34, &city) == -1) {
2022-05-19 01:51:26 -07:00
city = -1;
}
return city;
}
// 0x4835B4
int mapSetTransition(MapTransition* transition)
{
if (transition == NULL) {
return -1;
}
memcpy(&gMapTransition, transition, sizeof(gMapTransition));
if (gMapTransition.map == 0) {
gMapTransition.map = -2;
}
if (isInCombat()) {
_game_user_wants_to_quit = 1;
}
return 0;
}
// 0x4835F8
int mapHandleTransition()
{
if (gMapTransition.map == 0) {
return 0;
}
gameMouseObjectsHide();
gameMouseSetCursor(MOUSE_CURSOR_NONE);
if (gMapTransition.map == -1) {
if (!isInCombat()) {
2022-07-07 01:28:21 -07:00
animationStop();
2022-09-15 01:42:02 -07:00
wmTownMap();
2022-05-19 01:51:26 -07:00
memset(&gMapTransition, 0, sizeof(gMapTransition));
}
} else if (gMapTransition.map == -2) {
if (!isInCombat()) {
2022-07-07 01:28:21 -07:00
animationStop();
2022-09-15 01:42:02 -07:00
wmWorldMap();
2022-05-19 01:51:26 -07:00
memset(&gMapTransition, 0, sizeof(gMapTransition));
}
} else {
if (!isInCombat()) {
if (gMapTransition.map != gMapHeader.field_34 || gElevation == gMapTransition.elevation) {
mapLoadById(gMapTransition.map);
}
if (gMapTransition.tile != -1 && gMapTransition.tile != 0
&& gMapHeader.field_34 != MAP_MODOC_BEDNBREAKFAST && gMapHeader.field_34 != MAP_THE_SQUAT_A
&& elevationIsValid(gMapTransition.elevation)) {
objectSetLocation(gDude, gMapTransition.tile, gMapTransition.elevation, NULL);
mapSetElevation(gMapTransition.elevation);
objectSetRotation(gDude, gMapTransition.rotation, NULL);
}
if (tileSetCenter(gDude->tile, TILE_SET_CENTER_FLAG_0x01) == -1) {
debugPrint("\nError: map: attempt to center out-of-bounds!");
}
memset(&gMapTransition, 0, sizeof(gMapTransition));
int city;
2022-09-15 01:42:02 -07:00
wmMatchAreaContainingMapIdx(gMapHeader.field_34, &city);
if (wmTeleportToArea(city) == -1) {
2022-05-19 01:51:26 -07:00
debugPrint("\nError: couldn't make jump on worldmap for map jump!");
}
}
}
return 0;
}
// 0x483784
2022-06-19 10:14:17 -07:00
static void _map_fix_critter_combat_data()
2022-05-19 01:51:26 -07:00
{
for (Object* object = objectFindFirst(); object != NULL; object = objectFindNext()) {
if (object->pid == -1) {
continue;
}
if (PID_TYPE(object->pid) != OBJ_TYPE_CRITTER) {
2022-05-19 01:51:26 -07:00
continue;
}
if (object->data.critter.combat.whoHitMeCid == -1) {
object->data.critter.combat.whoHitMe = NULL;
}
}
}
// map_save
// 0x483850
2022-06-19 10:14:17 -07:00
static int _map_save()
2022-05-19 01:51:26 -07:00
{
char temp[80];
temp[0] = '\0';
strcat(temp, settings.system.master_patches_path.c_str());
compat_mkdir(temp);
2022-05-19 01:51:26 -07:00
strcat(temp, "\\MAPS");
compat_mkdir(temp);
2022-05-19 01:51:26 -07:00
int rc = -1;
if (gMapHeader.name[0] != '\0') {
char* mapFileName = mapBuildPath(gMapHeader.name);
File* stream = fileOpen(mapFileName, "wb");
if (stream != NULL) {
rc = _map_save_file(stream);
fileClose(stream);
} else {
sprintf(temp, "Unable to open %s to write!", gMapHeader.name);
debugPrint(temp);
}
if (rc == 0) {
sprintf(temp, "%s saved.", gMapHeader.name);
debugPrint(temp);
}
} else {
debugPrint("\nError: map_save: map header corrupt!");
}
return rc;
}
// 0x483980
2022-06-19 10:14:17 -07:00
static int _map_save_file(File* stream)
2022-05-19 01:51:26 -07:00
{
if (stream == NULL) {
return -1;
}
scriptsDisable();
for (int elevation = 0; elevation < ELEVATION_COUNT; elevation++) {
int tile;
for (tile = 0; tile < SQUARE_GRID_SIZE; tile++) {
int fid;
fid = buildFid(OBJ_TYPE_TILE, _square[elevation]->field_0[tile] & 0xFFF, 0, 0, 0);
if (fid != buildFid(OBJ_TYPE_TILE, 1, 0, 0, 0)) {
2022-05-19 01:51:26 -07:00
break;
}
fid = buildFid(OBJ_TYPE_TILE, (_square[elevation]->field_0[tile] >> 16) & 0xFFF, 0, 0, 0);
if (fid != buildFid(OBJ_TYPE_TILE, 1, 0, 0, 0)) {
2022-05-19 01:51:26 -07:00
break;
}
}
if (tile == SQUARE_GRID_SIZE) {
Object* object = objectFindFirstAtElevation(elevation);
if (object != NULL) {
// TODO: Implementation is slightly different, check in debugger.
while (object != NULL && (object->flags & OBJECT_TEMPORARY)) {
object = objectFindNextAtElevation();
}
if (object != NULL) {
gMapHeader.flags &= ~_map_data_elev_flags[elevation];
} else {
gMapHeader.flags |= _map_data_elev_flags[elevation];
}
} else {
gMapHeader.flags |= _map_data_elev_flags[elevation];
}
} else {
gMapHeader.flags &= ~_map_data_elev_flags[elevation];
}
}
gMapHeader.localVariablesCount = gMapLocalVarsLength;
gMapHeader.globalVariablesCount = gMapGlobalVarsLength;
gMapHeader.darkness = 1;
mapHeaderWrite(&gMapHeader, stream);
if (gMapHeader.globalVariablesCount != 0) {
fileWriteInt32List(stream, gMapGlobalVars, gMapHeader.globalVariablesCount);
}
if (gMapHeader.localVariablesCount != 0) {
fileWriteInt32List(stream, gMapLocalVars, gMapHeader.localVariablesCount);
}
for (int elevation = 0; elevation < ELEVATION_COUNT; elevation++) {
if ((gMapHeader.flags & _map_data_elev_flags[elevation]) == 0) {
_db_fwriteLongCount(stream, _square[elevation]->field_0, SQUARE_GRID_SIZE);
}
}
char err[80];
if (scriptSaveAll(stream) == -1) {
sprintf(err, "Error saving scripts in %s", gMapHeader.name);
_win_msg(err, 80, 80, _colorTable[31744]);
2022-05-19 01:51:26 -07:00
}
if (objectSaveAll(stream) == -1) {
sprintf(err, "Error saving objects in %s", gMapHeader.name);
_win_msg(err, 80, 80, _colorTable[31744]);
2022-05-19 01:51:26 -07:00
}
scriptsEnable();
return 0;
}
// 0x483C98
int _map_save_in_game(bool a1)
{
if (gMapHeader.name[0] == '\0') {
return 0;
}
2022-07-07 01:28:21 -07:00
animationStop();
2022-05-19 01:51:26 -07:00
_partyMemberSaveProtos();
if (a1) {
_queue_leaving_map();
_partyMemberPrepLoad();
_partyMemberPrepItemSaveAll();
scriptsExecMapExitProc();
if (gMapSid != -1) {
Script* script;
scriptGetScript(gMapSid, &script);
}
gameTimeScheduleUpdateEvent();
_obj_reset_roof();
}
gMapHeader.flags |= 0x01;
gMapHeader.lastVisitTime = gameTimeGetTime();
2022-05-19 01:51:26 -07:00
char name[16];
2022-09-15 01:42:02 -07:00
if (a1 && !wmMapIsSaveable()) {
2022-05-19 01:51:26 -07:00
debugPrint("\nNot saving RANDOM encounter map.");
strcpy(name, gMapHeader.name);
_strmfe(gMapHeader.name, name, "SAV");
_MapDirEraseFile_("MAPS\\", gMapHeader.name);
strcpy(gMapHeader.name, name);
} else {
debugPrint("\n Saving \".SAV\" map.");
strcpy(name, gMapHeader.name);
_strmfe(gMapHeader.name, name, "SAV");
if (_map_save() == -1) {
return -1;
}
strcpy(gMapHeader.name, name);
automapSaveCurrent();
if (a1) {
gMapHeader.name[0] = '\0';
_obj_remove_all();
_proto_remove_all();
_square_reset();
gameTimeScheduleUpdateEvent();
}
}
return 0;
}
// 0x483E28
2022-06-19 10:14:17 -07:00
static void mapMakeMapsDirectory()
2022-05-19 01:51:26 -07:00
{
2022-05-28 02:34:49 -07:00
char path[COMPAT_MAX_PATH];
2022-05-19 01:51:26 -07:00
strcpy(path, settings.system.master_patches_path.c_str());
compat_mkdir(path);
2022-05-19 01:51:26 -07:00
strcat(path, "\\MAPS");
compat_mkdir(path);
2022-05-19 01:51:26 -07:00
}
// 0x483ED0
2022-06-19 10:14:17 -07:00
static void isoWindowRefreshRect(Rect* rect)
2022-05-19 01:51:26 -07:00
{
windowRefreshRect(gIsoWindow, rect);
}
// 0x483EE4
2022-06-19 10:14:17 -07:00
static void isoWindowRefreshRectGame(Rect* rect)
2022-05-19 01:51:26 -07:00
{
Rect clampedDirtyRect;
if (rectIntersection(rect, &gIsoWindowRect, &clampedDirtyRect) == -1) {
return;
}
tileRenderFloorsInRect(&clampedDirtyRect, gElevation);
_grid_render(&clampedDirtyRect, gElevation);
_obj_render_pre_roof(&clampedDirtyRect, gElevation);
tileRenderRoofsInRect(&clampedDirtyRect, gElevation);
_obj_render_post_roof(&clampedDirtyRect, gElevation);
}
// 0x483F44
2022-06-19 10:14:17 -07:00
static void isoWindowRefreshRectMapper(Rect* rect)
2022-05-19 01:51:26 -07:00
{
Rect clampedDirtyRect;
if (rectIntersection(rect, &gIsoWindowRect, &clampedDirtyRect) == -1) {
return;
}
bufferFill(gIsoWindowBuffer + clampedDirtyRect.top * (_scr_size.right - _scr_size.left + 1) + clampedDirtyRect.left,
clampedDirtyRect.right - clampedDirtyRect.left + 1,
clampedDirtyRect.bottom - clampedDirtyRect.top + 1,
_scr_size.right - _scr_size.left + 1,
0);
tileRenderFloorsInRect(&clampedDirtyRect, gElevation);
_grid_render(&clampedDirtyRect, gElevation);
_obj_render_pre_roof(&clampedDirtyRect, gElevation);
tileRenderRoofsInRect(&clampedDirtyRect, gElevation);
_obj_render_post_roof(&clampedDirtyRect, gElevation);
}
2022-09-15 08:16:46 -07:00
// NOTE: Inlined.
//
// 0x483FE4
static int mapGlobalVariablesInit(int count)
{
mapGlobalVariablesFree();
if (count != 0) {
gMapGlobalVars = (int*)internal_malloc(sizeof(*gMapGlobalVars) * count);
if (gMapGlobalVars == NULL) {
return -1;
}
}
gMapGlobalVarsLength = count;
return 0;
}
2022-05-19 01:51:26 -07:00
// 0x484038
2022-06-19 10:14:17 -07:00
static void mapGlobalVariablesFree()
2022-05-19 01:51:26 -07:00
{
if (gMapGlobalVars != NULL) {
internal_free(gMapGlobalVars);
gMapGlobalVars = NULL;
gMapGlobalVarsLength = 0;
}
}
2022-09-15 08:17:16 -07:00
// NOTE: Inlined.
//
// 0x48405C
static int mapGlobalVariablesLoad(File* stream)
{
if (fileReadInt32List(stream, gMapGlobalVars, gMapGlobalVarsLength) != 0) {
return -1;
}
return 0;
}
2022-09-15 08:19:50 -07:00
// NOTE: Inlined.
//
// 0x484080
static int mapLocalVariablesInit(int count)
{
mapLocalVariablesFree();
if (count != 0) {
gMapLocalVars = (int*)internal_malloc(sizeof(*gMapLocalVars) * count);
if (gMapLocalVars == NULL) {
return -1;
}
gMapLocalPointers.resize(count);
2022-09-15 08:19:50 -07:00
}
gMapLocalVarsLength = count;
return 0;
}
2022-05-19 01:51:26 -07:00
// 0x4840D4
2022-06-19 10:14:17 -07:00
static void mapLocalVariablesFree()
2022-05-19 01:51:26 -07:00
{
if (gMapLocalVars != NULL) {
internal_free(gMapLocalVars);
gMapLocalVars = NULL;
gMapLocalVarsLength = 0;
}
gMapLocalPointers.clear();
2022-05-19 01:51:26 -07:00
}
2022-09-15 08:22:27 -07:00
// NOTE: Inlined.
//
// 0x4840F8
static int mapLocalVariablesLoad(File* stream)
{
if (fileReadInt32List(stream, gMapLocalVars, gMapLocalVarsLength) != 0) {
return -1;
}
return 0;
}
2022-05-19 01:51:26 -07:00
// 0x48411C
2022-06-19 10:14:17 -07:00
static void _map_place_dude_and_mouse()
2022-05-19 01:51:26 -07:00
{
_obj_clear_seen();
if (gDude != NULL) {
if (FID_ANIM_TYPE(gDude->fid) != ANIM_STAND) {
2022-05-19 01:51:26 -07:00
objectSetFrame(gDude, 0, 0);
gDude->fid = buildFid(OBJ_TYPE_CRITTER, gDude->fid & 0xFFF, ANIM_STAND, (gDude->fid & 0xF000) >> 12, gDude->rotation + 1);
2022-05-19 01:51:26 -07:00
}
if (gDude->tile == -1) {
objectSetLocation(gDude, gCenterTile, gElevation, NULL);
objectSetRotation(gDude, gMapHeader.enteringRotation, 0);
}
objectSetLight(gDude, 4, 0x10000, 0);
gDude->flags |= OBJECT_TEMPORARY;
_dude_stand(gDude, gDude->rotation, gDude->fid);
_partyMemberSyncPosition();
}
gameMouseResetBouncingCursorFid();
gameMouseObjectsShow();
}
2022-09-15 08:25:48 -07:00
// NOTE: Inlined.
//
// 0x4841F0
static void square_init()
{
for (int elevation = 0; elevation < ELEVATION_COUNT; elevation++) {
_square[elevation] = &(_square_data[elevation]);
}
}
2022-05-19 01:51:26 -07:00
// 0x484210
2022-06-19 10:14:17 -07:00
static void _square_reset()
2022-05-19 01:51:26 -07:00
{
for (int elevation = 0; elevation < ELEVATION_COUNT; elevation++) {
int* p = _square[elevation]->field_0;
for (int y = 0; y < SQUARE_GRID_HEIGHT; y++) {
for (int x = 0; x < SQUARE_GRID_WIDTH; x++) {
// TODO: Strange math, initially right, but need to figure it out and
// check subsequent calls.
int fid = *p;
fid &= ~0xFFFF;
2022-08-01 09:47:09 -07:00
*p = (((buildFid(OBJ_TYPE_TILE, 1, 0, 0, 0) & 0xFFF) | (((fid >> 16) & 0xF000) >> 12)) << 16) | (fid & 0xFFFF);
2022-05-19 01:51:26 -07:00
fid = *p;
int v3 = (fid & 0xF000) >> 12;
int v4 = (buildFid(OBJ_TYPE_TILE, 1, 0, 0, 0) & 0xFFF) | v3;
2022-05-19 01:51:26 -07:00
fid &= ~0xFFFF;
*p = v4 | ((fid >> 16) << 16);
p++;
}
}
}
}
// 0x48431C
2022-06-19 10:14:17 -07:00
static int _square_load(File* stream, int flags)
2022-05-19 01:51:26 -07:00
{
int v6;
int v7;
int v8;
int v9;
_square_reset();
for (int elevation = 0; elevation < ELEVATION_COUNT; elevation++) {
if ((flags & _map_data_elev_flags[elevation]) == 0) {
int* arr = _square[elevation]->field_0;
if (_db_freadIntCount(stream, arr, SQUARE_GRID_SIZE) != 0) {
return -1;
}
for (int tile = 0; tile < SQUARE_GRID_SIZE; tile++) {
v6 = arr[tile];
v6 &= ~(0xFFFF);
v6 >>= 16;
v7 = (v6 & 0xF000) >> 12;
v7 &= ~(0x01);
v8 = v6 & 0xFFF;
v9 = arr[tile] & 0xFFFF;
arr[tile] = ((v8 | (v7 << 12)) << 16) | v9;
}
}
}
return 0;
}
// 0x4843B8
2022-06-19 10:14:17 -07:00
static int mapHeaderWrite(MapHeader* ptr, File* stream)
2022-05-19 01:51:26 -07:00
{
if (fileWriteInt32(stream, ptr->version) == -1) return -1;
if (fileWriteFixedLengthString(stream, ptr->name, 16) == -1) return -1;
if (fileWriteInt32(stream, ptr->enteringTile) == -1) return -1;
if (fileWriteInt32(stream, ptr->enteringElevation) == -1) return -1;
if (fileWriteInt32(stream, ptr->enteringRotation) == -1) return -1;
if (fileWriteInt32(stream, ptr->localVariablesCount) == -1) return -1;
if (fileWriteInt32(stream, ptr->scriptIndex) == -1) return -1;
if (fileWriteInt32(stream, ptr->flags) == -1) return -1;
if (fileWriteInt32(stream, ptr->darkness) == -1) return -1;
if (fileWriteInt32(stream, ptr->globalVariablesCount) == -1) return -1;
if (fileWriteInt32(stream, ptr->field_34) == -1) return -1;
if (fileWriteInt32(stream, ptr->lastVisitTime) == -1) return -1;
2022-05-19 01:51:26 -07:00
if (fileWriteInt32List(stream, ptr->field_3C, 44) == -1) return -1;
return 0;
}
// 0x4844B4
2022-06-19 10:14:17 -07:00
static int mapHeaderRead(MapHeader* ptr, File* stream)
2022-05-19 01:51:26 -07:00
{
if (fileReadInt32(stream, &(ptr->version)) == -1) return -1;
if (fileReadFixedLengthString(stream, ptr->name, 16) == -1) return -1;
if (fileReadInt32(stream, &(ptr->enteringTile)) == -1) return -1;
if (fileReadInt32(stream, &(ptr->enteringElevation)) == -1) return -1;
if (fileReadInt32(stream, &(ptr->enteringRotation)) == -1) return -1;
if (fileReadInt32(stream, &(ptr->localVariablesCount)) == -1) return -1;
if (fileReadInt32(stream, &(ptr->scriptIndex)) == -1) return -1;
if (fileReadInt32(stream, &(ptr->flags)) == -1) return -1;
if (fileReadInt32(stream, &(ptr->darkness)) == -1) return -1;
if (fileReadInt32(stream, &(ptr->globalVariablesCount)) == -1) return -1;
if (fileReadInt32(stream, &(ptr->field_34)) == -1) return -1;
if (fileReadInt32(stream, &(ptr->lastVisitTime)) == -1) return -1;
2022-05-19 01:51:26 -07:00
if (fileReadInt32List(stream, ptr->field_3C, 44) == -1) return -1;
return 0;
}
2022-09-23 05:43:44 -07:00
} // namespace fallout