#include "map.h" #include "animation.h" #include "automap.h" #include "character_editor.h" #include "color.h" #include "combat.h" #include "core.h" #include "critter.h" #include "cycle.h" #include "debug.h" #include "draw.h" #include "game.h" #include "game_config.h" #include "game_mouse.h" #include "game_movie.h" #include "game_sound.h" #include "interface.h" #include "item.h" #include "light.h" #include "loadsave.h" #include "memory.h" #include "object.h" #include "palette.h" #include "pipboy.h" #include "proto.h" #include "proto_instance.h" #include "queue.h" #include "random.h" #include "scripts.h" #include "text_object.h" #include "tile.h" #include "window_manager.h" #include "world_map.h" #include // 0x50B058 char byte_50B058[] = ""; // 0x50B30C char _aErrorF2[] = "ERROR! F2"; // 0x519540 IsoWindowRefreshProc* _map_scroll_refresh = isoWindowRefreshRectGame; // 0x519544 const int _map_data_elev_flags[ELEVATION_COUNT] = { 2, 4, 8, }; // 0x519550 unsigned int gIsoWindowScrollTimestamp = 0; // 0x519554 bool gIsoEnabled = false; // 0x519558 int gEnteringElevation = 0; // 0x51955C int gEnteringTile = -1; // 0x519560 int gEnteringRotation = ROTATION_NE; // 0x519564 int gMapSid = -1; // local_vars // 0x519568 int* gMapLocalVars = NULL; // map_vars // 0x51956C int* gMapGlobalVars = NULL; // local_vars_num // 0x519570 int gMapLocalVarsLength = 0; // map_vars_num // 0x519574 int gMapGlobalVarsLength = 0; // Current elevation. // // 0x519578 int gElevation = 0; // 0x51957C char* _errMapName = byte_50B058; // 0x519584 int _wmMapIdx = -1; // 0x614868 TileData _square_data[ELEVATION_COUNT]; // 0x631D28 MapTransition gMapTransition; // 0x631D38 Rect gIsoWindowRect; // map.msg // // map_msg_file // 0x631D48 MessageList gMapMessageList; // 0x631D50 unsigned char* gIsoWindowBuffer; // 0x631D54 MapHeader gMapHeader; // 0x631E40 TileData* _square[ELEVATION_COUNT]; // 0x631E4C int gIsoWindow; // 0x631E50 char _scratchStr[40]; // Last map file name. // // 0x631E78 char _map_path[COMPAT_MAX_PATH]; // iso_init // 0x481CA0 int isoInit() { tileScrollLimitingDisable(); tileScrollBlockingDisable(); for (int elevation = 0; elevation < ELEVATION_COUNT; elevation++) { _square[elevation] = &(_square_data[elevation]); } gIsoWindow = windowCreate(0, 0, screenGetWidth(), screenGetVisibleHeight(), 256, 10); 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) { debugPrint("tile_init failed in iso_init\n"); return -1; } debugPrint(">tile_init\t\t"); if (objectsInit(gIsoWindowBuffer, screenGetWidth(), screenGetVisibleHeight(), screenGetWidth()) != 0) { debugPrint("obj_init failed in iso_init\n"); return -1; } debugPrint(">obj_init\t\t"); colorCycleInit(); debugPrint(">cycle_init\t\t"); tileScrollBlockingEnable(); tileScrollLimitingEnable(); if (interfaceInit() != 0) { debugPrint("intface_init failed in iso_init\n"); return -1; } debugPrint(">intface_init\t\t"); mapMakeMapsDirectory(); gEnteringElevation = -1; gEnteringTile = -1; gEnteringRotation = -1; return 0; } // 0x481ED4 void isoReset() { if (gMapGlobalVars != NULL) { internal_free(gMapGlobalVars); gMapGlobalVars = NULL; gMapGlobalVarsLength = 0; } if (gMapLocalVars != NULL) { internal_free(gMapLocalVars); gMapLocalVars = NULL; gMapLocalVarsLength = 0; } artReset(); tileReset(); objectsReset(); colorCycleReset(); interfaceReset(); gEnteringElevation = -1; gEnteringTile = -1; gEnteringRotation = -1; } // 0x481F48 void isoExit() { interfaceFree(); colorCycleFree(); objectsExit(); tileExit(); artExit(); if (gMapGlobalVars != NULL) { internal_free(gMapGlobalVars); gMapGlobalVars = NULL; gMapGlobalVarsLength = 0; } if (gMapLocalVars != NULL) { internal_free(gMapLocalVars); gMapLocalVars = NULL; gMapLocalVarsLength = 0; } } // 0x481FB4 void _map_init() { char* executable; configGetString(&gGameConfig, GAME_CONFIG_SYSTEM_KEY, "executable", &executable); if (compat_stricmp(executable, "mapper") == 0) { _map_scroll_refresh = isoWindowRefreshRectMapper; } if (messageListInit(&gMapMessageList)) { char path[COMPAT_MAX_PATH]; sprintf(path, "%smap.msg", asc_5186C8); if (!messageListLoad(&gMapMessageList, path)) { debugPrint("\nError loading map_msg_file!"); } } else { debugPrint("\nError initing map_msg_file!"); } _map_new_map(); 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) { _wmMapMarkMapEntranceState(gMapHeader.field_34, elevation, 1); } 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, int value) { if (var < 0 || var >= gMapLocalVarsLength) { debugPrint("ERROR: attempt to reference local var out of range: %d", var); return -1; } gMapLocalVars[var] = value; return 0; } // 0x4822B0 int mapGetLocalVar(int var) { if (var < 0 || var >= gMapLocalVarsLength) { debugPrint("ERROR: attempt to reference local var out of range: %d", var); return 0; } return gMapLocalVars[var]; } // Make a room to store more local variables. // // 0x4822E0 int _map_malloc_local_var(int a1) { int oldMapLocalVarsLength = gMapLocalVarsLength; gMapLocalVarsLength += a1; int* vars = (int*)internal_realloc(gMapLocalVars, sizeof(*vars) * gMapLocalVarsLength); if (vars == NULL) { debugPrint("\nError: Ran out of memory!"); } gMapLocalVars = vars; memset((unsigned char*)vars + sizeof(*vars) * oldMapLocalVarsLength, 0, sizeof(*vars) * a1); 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) { if (map < 0 || map >= mapGetCount()) { 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) { if (map1 < 0 || map1 >= mapGetCount()) { return 0; } if (map2 < 0 || map2 >= mapGetCount()) { return 0; } if (!_wmMapIdxIsSaveable(map1)) { return 0; } if (!_wmMapIdxIsSaveable(map2)) { return 0; } int city1; if (_wmMatchAreaContainingMapIdx(map1, &city1) == -1) { return 0; } int city2; if (_wmMatchAreaContainingMapIdx(map2, &city2) == -1) { return 0; } return city1 == city2; } // 0x4825CC int _get_map_idx_same(int map1, int map2) { int city1 = -1; if (_wmMatchAreaContainingMapIdx(map1, &city1) == -1) { return -1; } int city2 = -2; if (_wmMatchAreaContainingMapIdx(map2, &city2) == -1) { return -1; } if (city1 != city2) { return -1; } return city1; } // 0x48261C char* mapGetCityName(int map) { int city; if (_wmMatchAreaContainingMapIdx(map, &city) == -1) { return _aErrorF2; } MessageListItem messageListItem; char* name = getmsg(&gMapMessageList, &messageListItem, 1500 + city); return name; } // 0x48268C char* _map_get_description_idx_(int map) { int city; if (_wmMatchAreaContainingMapIdx(map, &city) == 0) { _wmGetAreaIdxName(city, _scratchStr); } 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; } gIsoWindowScrollTimestamp = _get_time(); int screenDx = dx * 32; int screenDy = dy * 24; if (screenDx == 0 && screenDy == 0) { return -1; } gameMouseObjectsHide(); int centerScreenX; int centerScreenY; tileToScreenXY(gCenterTile, ¢erScreenX, ¢erScreenY, 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(); int pitch = width; int height = screenGetVisibleHeight(); 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); 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 char* mapBuildPath(char* name) { if (*name != '\\') { sprintf(_map_path, "maps\\%s", name); 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 void _map_new_map() { 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(); _anim_stop(); if (gMapGlobalVars != NULL) { internal_free(gMapGlobalVars); gMapGlobalVars = NULL; gMapGlobalVarsLength = 0; } if (gMapLocalVars != NULL) { internal_free(gMapLocalVars); gMapLocalVars = NULL; gMapLocalVarsLength = 0; } _square_reset(); _map_place_dude_and_mouse(); tileWindowRefresh(); } // 0x482A68 int mapLoadByName(char* fileName) { int rc; compat_strupr(fileName); 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); worldmapStartMapMusic(); } } 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]; if (mapGetFileName(map, name) == -1) { return -1; } _wmMapIdx = map; int rc = mapLoadByName(name); worldmapStartMapMusic(); return rc; } // 0x482B74 int mapLoad(File* stream) { _map_save_in_game(true); backgroundSoundLoad("wind2", 12, 13, 16); isoDisable(); _partyMemberPrepLoad(); _gmouse_disable_scrolling(); int savedMouseCursorId = gameMouseGetCursor(); gameMouseSetCursor(MOUSE_CURSOR_WAIT_PLANET); fileSetReadProgressHandler(gameMouseRefresh, 32768); 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); _anim_stop(); 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) { gEnteringElevation = gMapHeader.enteringElevation; gEnteringTile = gMapHeader.enteringTile; gEnteringRotation = gMapHeader.enteringRotation; } _obj_remove_all(); if (gMapHeader.globalVariablesCount < 0) { gMapHeader.globalVariablesCount = 0; } if (gMapHeader.localVariablesCount < 0) { gMapHeader.localVariablesCount = 0; } error = "Error loading global vars"; mapGlobalVariablesFree(); if (gMapHeader.globalVariablesCount != 0) { gMapGlobalVars = (int*)internal_malloc(sizeof(*gMapGlobalVars) * gMapHeader.globalVariablesCount); if (gMapGlobalVars == NULL) { goto err; } gMapGlobalVarsLength = gMapHeader.globalVariablesCount; } if (fileReadInt32List(stream, gMapGlobalVars, gMapGlobalVarsLength) != 0) { goto err; } error = "Error loading local vars"; mapLocalVariablesFree(); if (gMapHeader.localVariablesCount != 0) { gMapLocalVars = (int*)internal_malloc(sizeof(*gMapLocalVars) * gMapHeader.localVariablesCount); if (gMapLocalVars == NULL) { goto err; } gMapLocalVarsLength = gMapHeader.localVariablesCount; } if (fileReadInt32List(stream, gMapLocalVars, gMapLocalVarsLength) != 0) { 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); gMapHeader.field_34 = mapGetIndexByFileName(gMapHeader.name); if ((gMapHeader.flags & 1) == 0) { char path[COMPAT_MAX_PATH]; 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(5, 12, 0, 0, 0); objectCreateWithFidPid(&object, fid, -1); object->flags |= (OBJECT_FLAG_0x20000000 | OBJECT_TEMPORARY | OBJECT_HIDDEN); 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"; if (worldmapSetupRandomEncounter() == -1) { 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); _map_new_map(); 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; } _wmMapMarkVisited(gMapHeader.field_34); _wmMapMarkMapEntranceState(gMapHeader.field_34, gElevation, 1); if (_wmCheckGameAreaEvents() != 0) { rc = -1; } fileSetReadProgressHandler(NULL, 0); if (gameUiIsDisabled() == 0) { _gmouse_enable_scrolling(); } gameMouseSetCursor(savedMouseCursorId); gEnteringElevation = -1; gEnteringTile = -1; gEnteringRotation = -1; 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.field_38) { if (((gameTimeGetTime() - gMapHeader.field_38) / 36000) >= 24) { objectUnjamAll(); } if (_map_age_dead_critters() == -1) { debugPrint("\nError: Critter aging failed on map load!"); return -1; } } if (!_wmMapIsSaveable()) { 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 int _map_age_dead_critters() { if (!_wmMapDeadBodiesAge()) { return 0; } int v4 = (gameTimeGetTime() - gMapHeader.field_38) / 36000; if (v4 == 0) { return 0; } Object* obj = objectFindFirst(); while (obj != NULL) { if (obj->pid >> 24 == OBJ_TYPE_CRITTER && obj != gDude && !objectIsPartyMember(obj) && !critterIsDead(obj)) { obj->data.critter.combat.maneuver &= 0x04; if (critterGetKillType(obj) != KILL_TYPE_ROBOT && _critter_flag_check(obj->pid, 512) == 0) { _critter_heal_hours(obj, v4); } } obj = objectFindNext(); } int v20; if (v4 <= 336) { if (v4 > 144) { v20 = 1; } else { v20 = 0; } } else { v20 = 2; } if (v20 == 0) { return 0; } int capacity = 100; int count = 0; Object** objects = (Object**)internal_malloc(sizeof(*objects) * capacity); obj = objectFindFirst(); while (obj != NULL) { int type = obj->pid >> 24; if (type == OBJ_TYPE_CRITTER) { if (obj != gDude && critterIsDead(obj)) { if (critterGetKillType(obj) != KILL_TYPE_ROBOT && _critter_flag_check(obj->pid, 512) == 0) { objects[count++] = obj; if (count >= capacity) { capacity *= 2; objects = (Object**)internal_realloc(objects, sizeof(*objects) * capacity); if (objects == NULL) { debugPrint("\nError: Out of Memory!"); return -1; } } } } } else if (v20 == 2 && type == OBJ_TYPE_MISC && obj->pid == 0x500000B) { objects[count++] = obj; if (count >= capacity) { capacity *= 2; objects = (Object**)internal_realloc(objects, sizeof(*objects) * capacity); 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 (obj->pid >> 24 == OBJ_TYPE_CRITTER) { if (_critter_flag_check(obj->pid, 64) == 0) { _item_drop_all(obj, obj->tile); } Object* a1; if (objectCreateWithPid(&a1, 0x5000004) == -1) { rc = -1; break; } objectSetLocation(a1, obj->tile, obj->elevation, NULL); Proto* proto; protoGetProto(obj->pid, &proto); int frame = randomBetween(0, 3); if ((proto->critter.flags & 0x800)) { frame += 6; } else { if (critterGetKillType(obj) != KILL_TYPE_RAT && critterGetKillType(obj) != KILL_TYPE_MANTIS) { frame += 3; } } objectSetFrame(a1, frame, NULL); } reg_anim_clear(obj); objectDestroy(obj, NULL); } internal_free(objects); return rc; } // 0x48358C int _map_target_load_area() { int city = -1; if (_wmMatchAreaContainingMapIdx(gMapHeader.field_34, &city) == -1) { 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()) { _anim_stop(); _wmTownMap(); memset(&gMapTransition, 0, sizeof(gMapTransition)); } } else if (gMapTransition.map == -2) { if (!isInCombat()) { _anim_stop(); _wmWorldMap(); 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; _wmMatchAreaContainingMapIdx(gMapHeader.field_34, &city); if (_wmTeleportToArea(city) == -1) { debugPrint("\nError: couldn't make jump on worldmap for map jump!"); } } } return 0; } // 0x483784 void _map_fix_critter_combat_data() { for (Object* object = objectFindFirst(); object != NULL; object = objectFindNext()) { if (object->pid == -1) { continue; } if ((object->pid >> 24) != OBJ_TYPE_CRITTER) { continue; } if (object->data.critter.combat.whoHitMeCid == -1) { object->data.critter.combat.whoHitMe = NULL; } } } // map_save // 0x483850 int _map_save() { char temp[80]; temp[0] = '\0'; char* masterPatchesPath; if (configGetString(&gGameConfig, GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_MASTER_PATCHES_KEY, &masterPatchesPath)) { strcat(temp, masterPatchesPath); compat_mkdir(temp); strcat(temp, "\\MAPS"); compat_mkdir(temp); } 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 int _map_save_file(File* stream) { 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(4, _square[elevation]->field_0[tile] & 0xFFF, 0, 0, 0); if (fid != buildFid(4, 1, 0, 0, 0)) { break; } fid = buildFid(4, (_square[elevation]->field_0[tile] >> 16) & 0xFFF, 0, 0, 0); if (fid != buildFid(4, 1, 0, 0, 0)) { 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); // TODO: Incomplete. // _win_msg(err, 80, 80, _colorTable[31744]); } if (objectSaveAll(stream) == -1) { sprintf(err, "Error saving objects in %s", gMapHeader.name); // TODO: Incomplete. // _win_msg(err, 80, 80, _colorTable[31744]); } scriptsEnable(); return 0; } // 0x483C98 int _map_save_in_game(bool a1) { if (gMapHeader.name[0] == '\0') { return 0; } _anim_stop(); _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.field_38 = gameTimeGetTime(); char name[16]; if (a1 && !_wmMapIsSaveable()) { 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 void mapMakeMapsDirectory() { char path[COMPAT_MAX_PATH]; char* masterPatchesPath; if (configGetString(&gGameConfig, GAME_CONFIG_SYSTEM_KEY, GAME_CONFIG_MASTER_PATCHES_KEY, &masterPatchesPath)) { strcpy(path, masterPatchesPath); } else { strcpy(path, "DATA"); } compat_mkdir(path); strcat(path, "\\MAPS"); compat_mkdir(path); } // 0x483ED0 void isoWindowRefreshRect(Rect* rect) { windowRefreshRect(gIsoWindow, rect); } // 0x483EE4 void isoWindowRefreshRectGame(Rect* rect) { 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 void isoWindowRefreshRectMapper(Rect* rect) { 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); } // 0x484038 void mapGlobalVariablesFree() { if (gMapGlobalVars != NULL) { internal_free(gMapGlobalVars); gMapGlobalVars = NULL; gMapGlobalVarsLength = 0; } } // 0x4840D4 void mapLocalVariablesFree() { if (gMapLocalVars != NULL) { internal_free(gMapLocalVars); gMapLocalVars = NULL; gMapLocalVarsLength = 0; } } // 0x48411C void _map_place_dude_and_mouse() { _obj_clear_seen(); if (gDude != NULL) { if (((gDude->fid & 0xFF0000) >> 16) != 0) { objectSetFrame(gDude, 0, 0); gDude->fid = buildFid(1, gDude->fid & 0xFFF, ANIM_STAND, (gDude->fid & 0xF000) >> 12, gDude->rotation + 1); } 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(); } // 0x484210 void _square_reset() { 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; *p = ((buildFid(4, 1, 0, 0, 0) & 0xFFF | (((fid >> 16) & 0xF000) >> 12)) << 16) | (fid & 0xFFFF); fid = *p; int v3 = (fid & 0xF000) >> 12; int v4 = (buildFid(4, 1, 0, 0, 0) & 0xFFF) | v3; fid &= ~0xFFFF; *p = v4 | ((fid >> 16) << 16); p++; } } } } // 0x48431C int _square_load(File* stream, int flags) { 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 int mapHeaderWrite(MapHeader* ptr, File* stream) { 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->field_38) == -1) return -1; if (fileWriteInt32List(stream, ptr->field_3C, 44) == -1) return -1; return 0; } // 0x4844B4 int mapHeaderRead(MapHeader* ptr, File* stream) { 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->field_38)) == -1) return -1; if (fileReadInt32List(stream, ptr->field_3C, 44) == -1) return -1; return 0; }