fallout2-ce/src/worldmap.cc

6570 lines
180 KiB
C++
Raw Normal View History

2022-09-14 23:00:11 -07:00
#include "worldmap.h"
2022-05-19 01:51:26 -07:00
2022-09-15 02:38:23 -07:00
#include <assert.h>
#include <ctype.h>
#include <math.h>
#include <stdio.h>
#include <string.h>
2022-06-19 02:00:14 -07:00
#include "animation.h"
2022-06-19 03:32:42 -07:00
#include "art.h"
2022-08-29 06:07:34 -07:00
#include "automap.h"
2022-05-19 01:51:26 -07:00
#include "color.h"
#include "combat.h"
#include "combat_ai.h"
#include "critter.h"
#include "cycle.h"
2022-06-18 21:45:51 -07:00
#include "db.h"
2022-05-19 01:51:26 -07:00
#include "dbox.h"
#include "debug.h"
#include "display_monitor.h"
#include "draw.h"
#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"
2022-10-03 06:42:34 -07:00
#include "kb.h"
2022-05-19 01:51:26 -07:00
#include "memory.h"
2022-10-03 02:41:33 -07:00
#include "mouse.h"
2022-05-19 01:51:26 -07:00
#include "object.h"
2022-06-19 02:00:14 -07:00
#include "party_member.h"
2022-05-19 01:51:26 -07:00
#include "perk.h"
#include "proto_instance.h"
#include "queue.h"
#include "random.h"
#include "scripts.h"
#include "settings.h"
2022-08-14 14:16:36 -07:00
#include "sfall_config.h"
2022-05-19 01:51:26 -07:00
#include "skill.h"
#include "stat.h"
#include "string_parsers.h"
2022-10-05 00:35:05 -07:00
#include "svga.h"
2022-05-19 01:51:26 -07:00
#include "text_font.h"
#include "tile.h"
#include "window_manager.h"
2022-09-23 05:43:44 -07:00
namespace fallout {
2022-06-18 21:45:51 -07:00
#define CITY_NAME_SIZE (40)
#define TILE_WALK_MASK_NAME_SIZE (40)
#define ENTRANCE_LIST_CAPACITY (10)
#define MAP_AMBIENT_SOUND_EFFECTS_CAPACITY (6)
#define MAP_STARTING_POINTS_CAPACITY (15)
#define SUBTILE_GRID_WIDTH (7)
#define SUBTILE_GRID_HEIGHT (6)
#define ENCOUNTER_ENTRY_SPECIAL (0x01)
#define ENCOUNTER_SUBINFO_DEAD (0x01)
#define WM_WINDOW_DIAL_X (532)
#define WM_WINDOW_DIAL_Y (48)
#define WM_TOWN_LIST_SCROLL_UP_X (480)
#define WM_TOWN_LIST_SCROLL_UP_Y (137)
#define WM_TOWN_LIST_SCROLL_DOWN_X (WM_TOWN_LIST_SCROLL_UP_X)
#define WM_TOWN_LIST_SCROLL_DOWN_Y (152)
#define WM_WINDOW_GLOBE_OVERLAY_X (495)
#define WM_WINDOW_GLOBE_OVERLAY_Y (330)
#define WM_WINDOW_CAR_X (514)
#define WM_WINDOW_CAR_Y (336)
#define WM_WINDOW_CAR_OVERLAY_X (499)
#define WM_WINDOW_CAR_OVERLAY_Y (330)
#define WM_WINDOW_CAR_FUEL_BAR_X (500)
#define WM_WINDOW_CAR_FUEL_BAR_Y (339)
#define WM_WINDOW_CAR_FUEL_BAR_HEIGHT (70)
#define WM_TOWN_WORLD_SWITCH_X (519)
#define WM_TOWN_WORLD_SWITCH_Y (439)
2022-05-19 01:51:26 -07:00
#define WM_TILE_WIDTH (350)
#define WM_TILE_HEIGHT (300)
#define WM_SUBTILE_SIZE (50)
#define WM_WINDOW_WIDTH (640)
#define WM_WINDOW_HEIGHT (480)
#define WM_VIEW_X (22)
#define WM_VIEW_Y (21)
#define WM_VIEW_WIDTH (450)
#define WM_VIEW_HEIGHT (443)
2022-06-18 21:45:51 -07:00
typedef enum EncounterFormationType {
ENCOUNTER_FORMATION_TYPE_SURROUNDING,
ENCOUNTER_FORMATION_TYPE_STRAIGHT_LINE,
ENCOUNTER_FORMATION_TYPE_DOUBLE_LINE,
ENCOUNTER_FORMATION_TYPE_WEDGE,
ENCOUNTER_FORMATION_TYPE_CONE,
ENCOUNTER_FORMATION_TYPE_HUDDLE,
ENCOUNTER_FORMATION_TYPE_COUNT,
} EncounterFormationType;
typedef enum EncounterFrequencyType {
ENCOUNTER_FREQUENCY_TYPE_NONE,
ENCOUNTER_FREQUENCY_TYPE_RARE,
ENCOUNTER_FREQUENCY_TYPE_UNCOMMON,
ENCOUNTER_FREQUENCY_TYPE_COMMON,
ENCOUNTER_FREQUENCY_TYPE_FREQUENT,
ENCOUNTER_FREQUENCY_TYPE_FORCED,
ENCOUNTER_FREQUENCY_TYPE_COUNT,
} EncounterFrequencyType;
typedef enum EncounterSceneryType {
ENCOUNTER_SCENERY_TYPE_NONE,
ENCOUNTER_SCENERY_TYPE_LIGHT,
ENCOUNTER_SCENERY_TYPE_NORMAL,
ENCOUNTER_SCENERY_TYPE_HEAVY,
ENCOUNTER_SCENERY_TYPE_COUNT,
} EncounterSceneryType;
typedef enum EncounterSituation {
ENCOUNTER_SITUATION_NOTHING,
ENCOUNTER_SITUATION_AMBUSH,
ENCOUNTER_SITUATION_FIGHTING,
ENCOUNTER_SITUATION_AND,
ENCOUNTER_SITUATION_COUNT,
} EncounterSituation;
typedef enum EncounterLogicalOperator {
ENCOUNTER_LOGICAL_OPERATOR_NONE,
ENCOUNTER_LOGICAL_OPERATOR_AND,
ENCOUNTER_LOGICAL_OPERATOR_OR,
} EncounterLogicalOperator;
typedef enum EncounterConditionType {
ENCOUNTER_CONDITION_TYPE_NONE = 0,
ENCOUNTER_CONDITION_TYPE_GLOBAL = 1,
ENCOUNTER_CONDITION_TYPE_NUMBER_OF_CRITTERS = 2,
ENCOUNTER_CONDITION_TYPE_RANDOM = 3,
ENCOUNTER_CONDITION_TYPE_PLAYER = 4,
ENCOUNTER_CONDITION_TYPE_DAYS_PLAYED = 5,
ENCOUNTER_CONDITION_TYPE_TIME_OF_DAY = 6,
} EncounterConditionType;
typedef enum EncounterConditionalOperator {
ENCOUNTER_CONDITIONAL_OPERATOR_NONE,
ENCOUNTER_CONDITIONAL_OPERATOR_EQUAL,
ENCOUNTER_CONDITIONAL_OPERATOR_NOT_EQUAL,
ENCOUNTER_CONDITIONAL_OPERATOR_LESS_THAN,
ENCOUNTER_CONDITIONAL_OPERATOR_GREATER_THAN,
ENCOUNTER_CONDITIONAL_OPERATOR_COUNT,
} EncounterConditionalOperator;
typedef enum Daytime {
DAY_PART_MORNING,
DAY_PART_AFTERNOON,
DAY_PART_NIGHT,
DAY_PART_COUNT,
} Daytime;
2022-09-15 01:42:02 -07:00
typedef enum LockState {
LOCK_STATE_UNLOCKED,
LOCK_STATE_LOCKED,
} LockState;
2022-06-18 21:45:51 -07:00
typedef enum SubtileState {
SUBTILE_STATE_UNKNOWN,
SUBTILE_STATE_KNOWN,
SUBTILE_STATE_VISITED,
} SubtileState;
typedef enum WorldMapEncounterFrm {
WORLD_MAP_ENCOUNTER_FRM_RANDOM_BRIGHT,
WORLD_MAP_ENCOUNTER_FRM_RANDOM_DARK,
WORLD_MAP_ENCOUNTER_FRM_SPECIAL_BRIGHT,
WORLD_MAP_ENCOUNTER_FRM_SPECIAL_DARK,
WORLD_MAP_ENCOUNTER_FRM_COUNT,
} WorldMapEncounterFrm;
typedef enum WorldmapArrowFrm {
WORLDMAP_ARROW_FRM_NORMAL,
WORLDMAP_ARROW_FRM_PRESSED,
WORLDMAP_ARROW_FRM_COUNT,
} WorldmapArrowFrm;
2022-09-15 01:42:02 -07:00
typedef enum CitySize {
CITY_SIZE_SMALL,
CITY_SIZE_MEDIUM,
CITY_SIZE_LARGE,
CITY_SIZE_COUNT,
} CitySize;
2022-06-18 21:45:51 -07:00
typedef struct EntranceInfo {
int state;
int x;
int y;
int map;
int elevation;
int tile;
int rotation;
} EntranceInfo;
typedef struct CityInfo {
char name[CITY_NAME_SIZE];
2022-09-15 01:42:02 -07:00
int areaId;
2022-06-18 21:45:51 -07:00
int x;
int y;
int size;
int state;
2022-09-15 01:42:02 -07:00
int lockState;
int visitedState;
2022-06-18 21:45:51 -07:00
int mapFid;
int labelFid;
int entrancesLength;
EntranceInfo entrances[ENTRANCE_LIST_CAPACITY];
} CityInfo;
typedef struct MapAmbientSoundEffectInfo {
char name[40];
int chance;
} MapAmbientSoundEffectInfo;
typedef struct MapStartPointInfo {
int elevation;
int tile;
int field_8;
} MapStartPointInfo;
typedef struct MapInfo {
char lookupName[40];
int field_28;
int field_2C;
char mapFileName[40];
char music[40];
int flags;
int ambientSoundEffectsLength;
MapAmbientSoundEffectInfo ambientSoundEffects[MAP_AMBIENT_SOUND_EFFECTS_CAPACITY];
int startPointsLength;
MapStartPointInfo startPoints[MAP_STARTING_POINTS_CAPACITY];
} MapInfo;
typedef struct Terrain {
2022-09-15 01:42:02 -07:00
char lookupName[40];
2022-08-29 07:37:58 -07:00
int difficulty;
2022-06-18 21:45:51 -07:00
int mapsLength;
int maps[20];
} Terrain;
typedef struct EncounterConditionEntry {
int type;
int conditionalOperator;
int param;
int value;
} EncounterConditionEntry;
typedef struct EncounterCondition {
int entriesLength;
EncounterConditionEntry entries[3];
int logicalOperators[2];
} EncounterCondition;
typedef struct ENCOUNTER_ENTRY_ENC {
int minQuantity; // min
int maxQuantity; // max
int field_8;
int situation;
} ENCOUNTER_ENTRY_ENC;
typedef struct EncounterEntry {
int flags;
int map;
int scenery;
int chance;
int counter;
EncounterCondition condition;
int field_50;
ENCOUNTER_ENTRY_ENC field_54[6];
} EncounterEntry;
typedef struct EncounterTable {
char lookupName[40];
int field_28;
int mapsLength;
int maps[6];
int field_48;
int entriesLength;
EncounterEntry entries[41];
} EncounterTable;
typedef struct ENC_BASE_TYPE_38_48 {
int pid;
int minimumQuantity;
int maximumQuantity;
bool isEquipped;
} ENC_BASE_TYPE_38_48;
typedef struct ENC_BASE_TYPE_38 {
char field_0[40];
int field_28;
int field_2C;
int ratio;
int pid;
int flags;
int distance;
int tile;
int itemsLength;
ENC_BASE_TYPE_38_48 items[10];
int team;
int script;
EncounterCondition condition;
} ENC_BASE_TYPE_38;
typedef struct ENC_BASE_TYPE {
char name[40];
int position;
int spacing;
int distance;
int field_34;
ENC_BASE_TYPE_38 field_38[10];
} ENC_BASE_TYPE;
typedef struct SubtileInfo {
int terrain;
int field_4;
int encounterChance[DAY_PART_COUNT];
int encounterType;
int state;
} SubtileInfo;
// A worldmap tile is 7x6 area, thus consisting of 42 individual subtiles.
typedef struct TileInfo {
int fid;
CacheEntry* handle;
unsigned char* data;
char walkMaskName[TILE_WALK_MASK_NAME_SIZE];
unsigned char* walkMaskData;
int encounterDifficultyModifier;
SubtileInfo subtiles[SUBTILE_GRID_HEIGHT][SUBTILE_GRID_WIDTH];
} TileInfo;
typedef struct CitySizeDescription {
int fid;
FrmImage frmImage;
2022-06-18 21:45:51 -07:00
} CitySizeDescription;
2022-09-15 01:42:02 -07:00
typedef struct WmGenData {
bool mousePressed;
bool didMeetFrankHorrigan;
int currentAreaId;
int worldPosX;
int worldPosY;
SubtileInfo* currentSubtile;
int dword_672E18;
bool isWalking;
int walkDestinationX;
int walkDestinationY;
int walkDistance;
int walkLineDelta;
int walkLineDeltaMainAxisStep;
int walkLineDeltaCrossAxisStep;
int walkWorldPosMainAxisStepX;
int walkWorldPosCrossAxisStepX;
int walkWorldPosMainAxisStepY;
int walkWorldPosCrossAxisStepY;
int encounterIconIsVisible;
int encounterMapId;
int encounterTableId;
int encounterEntryId;
int encounterCursorId;
int oldWorldPosX;
int oldWorldPosY;
bool isInCar;
int currentCarAreaId;
int carFuel;
CacheEntry* carImageFrmHandle;
Art* carImageFrm;
int carImageFrmWidth;
int carImageFrmHeight;
int carImageCurrentFrameIndex;
FrmImage hotspotNormalFrmImage;
FrmImage hotspotPressedFrmImage;
2022-09-15 01:42:02 -07:00
FrmImage destinationMarkerFrmImage;
FrmImage locationMarkerFrmImage;
2022-09-15 01:42:02 -07:00
FrmImage encounterCursorFrmImages[WORLD_MAP_ENCOUNTER_FRM_COUNT];
2022-09-15 01:42:02 -07:00
int viewportMaxX;
int viewportMaxY;
FrmImage tabsBackgroundFrmImage;
2022-09-15 01:42:02 -07:00
int tabsOffsetY;
FrmImage tabsBorderFrmImage;
2022-09-15 01:42:02 -07:00
CacheEntry* dialFrmHandle;
int dialFrmWidth;
int dialFrmHeight;
int dialFrmCurrentFrameIndex;
Art* dialFrm;
FrmImage carOverlayFrmImage;
FrmImage globeOverlayFrmImage;
2022-09-15 01:42:02 -07:00
int oldTabsOffsetY;
int tabsScrollingDelta;
FrmImage redButtonNormalFrmImage;
FrmImage redButtonPressedFrmImage;
2022-09-15 01:42:02 -07:00
FrmImage scrollUpButtonFrmImages[WORLDMAP_ARROW_FRM_COUNT];
FrmImage scrollDownButtonFrmImages[WORLDMAP_ARROW_FRM_COUNT];
2022-09-15 01:42:02 -07:00
FrmImage monthsFrmImage;
FrmImage numbersFrmImage;
2022-09-15 01:42:02 -07:00
int oldFont;
} WmGenData;
static void wmSetFlags(int* flagsPtr, int flag, int value);
static int wmGenDataInit();
static int wmGenDataReset();
static int wmWorldMapSaveTempData();
static int wmWorldMapLoadTempData();
static int wmConfigInit();
static int wmReadEncounterType(Config* config, char* lookupName, char* sectionKey);
static int wmParseEncounterTableIndex(EncounterEntry* entry, char* string);
static int wmParseEncounterSubEncStr(EncounterEntry* encounterEntry, char** stringPtr);
static int wmParseFindSubEncTypeMatch(char* str, int* valuePtr);
static int wmFindEncBaseTypeMatch(char* str, int* valuePtr);
static int wmReadEncBaseType(char* name, int* valuePtr);
static int wmParseEncBaseSubTypeStr(ENC_BASE_TYPE_38* ptr, char** stringPtr);
static int wmEncBaseTypeSlotInit(ENC_BASE_TYPE* entry);
static int wmEncBaseSubTypeSlotInit(ENC_BASE_TYPE_38* entry);
static int wmEncounterSubEncSlotInit(ENCOUNTER_ENTRY_ENC* entry);
static int wmEncounterTypeSlotInit(EncounterEntry* entry);
static int wmEncounterTableSlotInit(EncounterTable* encounterTable);
static int wmTileSlotInit(TileInfo* tile);
static int wmTerrainTypeSlotInit(Terrain* terrain);
static int wmConditionalDataInit(EncounterCondition* condition);
static int wmParseTerrainTypes(Config* config, char* string);
static int wmParseTerrainRndMaps(Config* config, Terrain* terrain);
static int wmParseSubTileInfo(TileInfo* tile, int row, int column, char* string);
static int wmParseFindEncounterTypeMatch(char* string, int* valuePtr);
static int wmParseFindTerrainTypeMatch(char* string, int* valuePtr);
static int wmParseEncounterItemType(char** stringPtr, ENC_BASE_TYPE_38_48* a2, int* a3, const char* delim);
static int wmParseItemType(char* string, ENC_BASE_TYPE_38_48* ptr);
static int wmParseConditional(char** stringPtr, const char* a2, EncounterCondition* condition);
static int wmParseSubConditional(char** stringPtr, const char* a2, int* typePtr, int* operatorPtr, int* paramPtr, int* valuePtr);
static int wmParseConditionalEval(char** stringPtr, int* conditionalOperatorPtr);
static int wmAreaSlotInit(CityInfo* area);
static int wmAreaInit();
static int wmParseFindMapIdxMatch(char* string, int* valuePtr);
static int wmEntranceSlotInit(EntranceInfo* entrance);
static int wmMapSlotInit(MapInfo* map);
static int wmMapInit();
static int wmRStartSlotInit(MapStartPointInfo* rsp);
static int wmMatchEntranceFromMap(int areaIdx, int mapIdx, int* entranceIdxPtr);
static int wmMatchEntranceElevFromMap(int areaIdx, int mapIdx, int elevation, int* entranceIdxPtr);
static int wmMatchAreaFromMap(int mapIdx, int* areaIdxPtr);
static int wmWorldMapFunc(int a1);
static int wmInterfaceCenterOnParty();
static void wmCheckGameEvents();
static int wmRndEncounterOccurred();
static int wmPartyFindCurSubTile();
static int wmFindCurSubTileFromPos(int x, int y, SubtileInfo** subtilePtr);
static int wmFindCurTileFromPos(int x, int y, TileInfo** tilePtr);
static int wmRndEncounterPick();
static int wmSetupCritterObjs(int type_idx, Object** critterPtr, int critterCount);
static int wmSetupRndNextTileNumInit(ENC_BASE_TYPE* a1);
static int wmSetupRndNextTileNum(ENC_BASE_TYPE* a1, ENC_BASE_TYPE_38* a2, int* out_tile_num);
static bool wmEvalConditional(EncounterCondition* a1, int* a2);
static bool wmEvalSubConditional(int operand1, int condionalOperator, int operand2);
static bool wmGameTimeIncrement(int ticksToAdd);
static int wmGrabTileWalkMask(int tileIdx);
static bool wmWorldPosInvalid(int x, int y);
static void wmPartyInitWalking(int x, int y);
static void wmPartyWalkingStep();
static void wmInterfaceScrollTabsStart(int delta);
static void wmInterfaceScrollTabsStop();
static void wmInterfaceScrollTabsUpdate();
static int wmInterfaceInit();
static int wmInterfaceExit();
static int wmInterfaceScroll(int dx, int dy, bool* successPtr);
static int wmInterfaceScrollPixel(int stepX, int stepY, int dx, int dy, bool* success, bool shouldRefresh);
static void wmMouseBkProc();
static int wmMarkSubTileOffsetVisited(int tile, int subtileX, int subtileY, int offsetX, int offsetY);
static int wmMarkSubTileOffsetKnown(int tile, int subtileX, int subtileY, int offsetX, int offsetY);
static int wmMarkSubTileOffsetVisitedFunc(int tile, int subtileX, int subtileY, int offsetX, int offsetY, int subtileState);
static void wmMarkSubTileRadiusVisited(int x, int y);
static int wmTileGrabArt(int tileIdx);
static int wmInterfaceRefresh();
static void wmInterfaceRefreshDate(bool shouldRefreshWindow);
static int wmMatchWorldPosToArea(int x, int y, int* areaIdxPtr);
static int wmInterfaceDrawCircleOverlay(CityInfo* cityInfo, CitySizeDescription* citySizeInfo, unsigned char* buffer, int x, int y);
static void wmInterfaceDrawSubTileRectFogged(unsigned char* dest, int width, int height, int pitch);
static int wmInterfaceDrawSubTileList(TileInfo* tileInfo, int column, int row, int x, int y, int a6);
static int wmDrawCursorStopped();
static bool wmCursorIsVisible();
static int wmGetAreaName(CityInfo* city, char* name);
static void wmMarkAllSubTiles(int state);
static int wmTownMapFunc(int* mapIdxPtr);
static int wmTownMapInit();
static int wmTownMapRefresh();
static int wmTownMapExit();
static int wmRefreshInterfaceOverlay(bool shouldRefreshWindow);
static void wmInterfaceRefreshCarFuel();
static int wmRefreshTabs();
static int wmMakeTabsLabelList(int** quickDestinationsPtr, int* quickDestinationsLengthPtr);
static int wmTabsCompareNames(const void* a1, const void* a2);
static int wmFreeTabsLabelList(int** quickDestinationsListPtr, int* quickDestinationsLengthPtr);
static void wmRefreshInterfaceDial(bool shouldRefreshWindow);
static void wmInterfaceDialSyncTime(bool shouldRefreshWindow);
static int wmAreaFindFirstValidMap(int* mapIdxPtr);
2022-05-19 01:51:26 -07:00
// 0x4BC860
2022-06-18 21:45:51 -07:00
static const int _can_rest_here[ELEVATION_COUNT] = {
2022-05-19 01:51:26 -07:00
MAP_CAN_REST_ELEVATION_0,
MAP_CAN_REST_ELEVATION_1,
MAP_CAN_REST_ELEVATION_2,
};
// 0x4BC86C
2022-06-18 21:45:51 -07:00
static const int gDayPartEncounterFrequencyModifiers[DAY_PART_COUNT] = {
2022-05-19 01:51:26 -07:00
40,
30,
0,
};
// 0x4BC878
2022-09-15 01:42:02 -07:00
static const char* gWorldmapEncDefaultMsg[2] = {
2022-05-19 01:51:26 -07:00
"You detect something up ahead.",
"Do you wish to encounter it?",
};
// 0x4BC880
2022-09-15 01:42:02 -07:00
static MessageListItem gWorldmapMessageListItem;
2022-05-19 01:51:26 -07:00
// 0x50EE44
2022-06-18 21:45:51 -07:00
static char _aCricket[] = "cricket";
2022-05-19 01:51:26 -07:00
// 0x50EE4C
2022-06-18 21:45:51 -07:00
static char _aCricket1[] = "cricket1";
2022-05-19 01:51:26 -07:00
// 0x51DD88
2022-09-15 01:42:02 -07:00
static const char* wmStateStrs[2] = {
2022-05-19 01:51:26 -07:00
"off",
"on"
};
// 0x51DD90
2022-09-15 01:42:02 -07:00
static const char* wmYesNoStrs[2] = {
2022-05-19 01:51:26 -07:00
"no",
"yes",
};
// 0x51DD98
2022-09-15 01:42:02 -07:00
static const char* wmFreqStrs[ENCOUNTER_FREQUENCY_TYPE_COUNT] = {
2022-05-19 01:51:26 -07:00
"none",
"rare",
"uncommon",
"common",
"frequent",
"forced",
};
// 0x51DDB0
2022-09-15 01:42:02 -07:00
static const char* wmFillStrs[9] = {
2022-05-19 01:51:26 -07:00
"no_fill",
"fill_n",
"fill_s",
"fill_e",
"fill_w",
"fill_nw",
"fill_ne",
"fill_sw",
"fill_se",
};
// 0x51DDD4
2022-09-15 01:42:02 -07:00
static const char* wmSceneryStrs[ENCOUNTER_SCENERY_TYPE_COUNT] = {
2022-05-19 01:51:26 -07:00
"none",
"light",
"normal",
"heavy",
};
// 0x51DDE4
2022-09-15 01:42:02 -07:00
static Terrain* wmTerrainTypeList = NULL;
2022-05-19 01:51:26 -07:00
// 0x51DDE8
2022-09-15 01:42:02 -07:00
static int wmMaxTerrainTypes = 0;
2022-05-19 01:51:26 -07:00
// 0x51DDEC
2022-09-15 01:42:02 -07:00
static TileInfo* wmTileInfoList = NULL;
2022-05-19 01:51:26 -07:00
// 0x51DDF0
2022-09-15 01:42:02 -07:00
static int wmMaxTileNum = 0;
2022-05-19 01:51:26 -07:00
// The width of worldmap grid in tiles.
//
// There is no separate variable for grid height, instead its calculated as
2022-09-15 01:42:02 -07:00
// [wmMaxTileNum] / [gWorldmapTilesGridWidth].
2022-05-19 01:51:26 -07:00
//
// num_horizontal_tiles
// 0x51DDF4
2022-09-15 01:42:02 -07:00
static int wmNumHorizontalTiles = 0;
2022-05-19 01:51:26 -07:00
// 0x51DDF8
2022-09-15 01:42:02 -07:00
static CityInfo* wmAreaInfoList = NULL;
2022-05-19 01:51:26 -07:00
// 0x51DDFC
2022-09-15 01:42:02 -07:00
static int wmMaxAreaNum = 0;
2022-05-19 01:51:26 -07:00
// 0x51DE00
2022-09-15 01:42:02 -07:00
static const char* wmAreaSizeStrs[CITY_SIZE_COUNT] = {
2022-05-19 01:51:26 -07:00
"small",
"medium",
"large",
};
// 0x51DE0C
2022-09-15 01:42:02 -07:00
static MapInfo* wmMapInfoList = NULL;
2022-05-19 01:51:26 -07:00
// 0x51DE10
2022-09-15 01:42:02 -07:00
static int wmMaxMapNum = 0;
2022-05-19 01:51:26 -07:00
// 0x51DE14
2022-09-15 01:42:02 -07:00
static int wmBkWin = -1;
2022-05-19 01:51:26 -07:00
// 0x51DE24
2022-09-15 01:42:02 -07:00
static unsigned char* wmBkWinBuf = NULL;
2022-05-19 01:51:26 -07:00
// 0x51DE2C
2022-09-15 01:42:02 -07:00
static int wmWorldOffsetX = 0;
2022-05-19 01:51:26 -07:00
// 0x51DE30
2022-09-15 01:42:02 -07:00
static int wmWorldOffsetY = 0;
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
// 0x51DE34
unsigned char* circleBlendTable = NULL;
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
// 0x51DE38
static int wmInterfaceWasInitialized = 0;
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
// 0x51DE3C
static const char* wmEncOpStrs[ENCOUNTER_SITUATION_COUNT] = {
2022-05-19 01:51:26 -07:00
"nothing",
"ambush",
"fighting",
"and",
};
2022-09-15 01:42:02 -07:00
// 0x51DE4C
static const char* wmConditionalOpStrs[ENCOUNTER_CONDITIONAL_OPERATOR_COUNT] = {
2022-05-19 01:51:26 -07:00
"_",
"==",
"!=",
"<",
">",
};
2022-09-15 01:42:02 -07:00
// 0x51DE64
static const char* wmConditionalQualifierStrs[2] = {
"and",
"or",
};
2022-05-19 01:51:26 -07:00
// 0x51DE6C
2022-09-15 01:42:02 -07:00
static const char* wmFormationStrs[ENCOUNTER_FORMATION_TYPE_COUNT] = {
2022-05-19 01:51:26 -07:00
"surrounding",
"straight_line",
"double_line",
"wedge",
"cone",
"huddle",
};
// 0x51DE84
2022-09-15 01:42:02 -07:00
static const int wmRndCursorFids[WORLD_MAP_ENCOUNTER_FRM_COUNT] = {
2022-05-19 01:51:26 -07:00
154,
155,
438,
439,
};
// 0x51DE94
2022-09-15 01:42:02 -07:00
static int* wmLabelList = NULL;
2022-05-19 01:51:26 -07:00
// 0x51DE98
2022-09-15 01:42:02 -07:00
static int wmLabelCount = 0;
2022-05-19 01:51:26 -07:00
// 0x51DE9C
2022-09-15 01:42:02 -07:00
static int wmTownMapCurArea = -1;
2022-05-19 01:51:26 -07:00
// 0x51DEA0
2022-09-15 01:42:02 -07:00
static unsigned int wmLastRndTime = 0;
2022-05-19 01:51:26 -07:00
// 0x51DEA4
2022-09-15 01:42:02 -07:00
static int wmRndIndex = 0;
2022-05-19 01:51:26 -07:00
// 0x51DEA8
2022-09-15 01:42:02 -07:00
static int wmRndCallCount = 0;
2022-05-19 01:51:26 -07:00
// 0x51DEAC
2022-06-18 21:45:51 -07:00
static int _terrainCounter = 1;
2022-05-19 01:51:26 -07:00
// 0x51DEB0
2022-06-18 21:45:51 -07:00
static unsigned int _lastTime_2 = 0;
2022-05-19 01:51:26 -07:00
// 0x51DEB4
2022-06-18 21:45:51 -07:00
static bool _couldScroll = true;
2022-05-19 01:51:26 -07:00
// 0x51DEC8
2022-09-15 01:42:02 -07:00
static char* wmRemapSfxList[2] = {
2022-05-19 01:51:26 -07:00
_aCricket,
_aCricket1,
};
// 0x672DB8
2022-09-15 01:42:02 -07:00
static int wmRndTileDirs[2];
2022-05-19 01:51:26 -07:00
// 0x672DC0
2022-09-15 01:42:02 -07:00
static int wmRndCenterTiles[2];
2022-05-19 01:51:26 -07:00
// 0x672DC8
2022-09-15 01:42:02 -07:00
static int wmRndCenterRotations[2];
2022-05-19 01:51:26 -07:00
// 0x672DD0
2022-09-15 01:42:02 -07:00
static int wmRndRotOffsets[2];
2022-05-19 01:51:26 -07:00
// Buttons for city entrances.
//
// 0x672DD8
2022-09-15 01:42:02 -07:00
static int wmTownMapButtonId[ENTRANCE_LIST_CAPACITY];
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
// NOTE: There are no symbols in |mapper2.exe| for the range between |wmGenData|
// and |wmMsgFile| implying everything in between are fields of the large
// struct.
2022-05-19 01:51:26 -07:00
//
2022-09-15 01:42:02 -07:00
// 0x672E00
static WmGenData wmGenData;
2022-05-19 01:51:26 -07:00
// worldmap.msg
//
// 0x672FB0
2022-09-15 01:42:02 -07:00
static MessageList wmMsgFile;
2022-05-19 01:51:26 -07:00
// 0x672FB8
2022-09-15 01:42:02 -07:00
static int wmFreqValues[6];
2022-05-19 01:51:26 -07:00
// 0x672FD0
2022-09-15 01:42:02 -07:00
static int wmRndOriginalCenterTile;
2022-05-19 01:51:26 -07:00
// worldmap.txt
//
// 0x672FD4
2022-09-15 01:42:02 -07:00
static Config* pConfigCfg;
2022-05-19 01:51:26 -07:00
// 0x672FD8
2022-09-15 01:42:02 -07:00
static int wmTownMapSubButtonIds[7];
2022-05-19 01:51:26 -07:00
// 0x672FF4
2022-09-15 01:42:02 -07:00
static ENC_BASE_TYPE* wmEncBaseTypeList;
2022-05-19 01:51:26 -07:00
// 0x672FF8
2022-09-15 01:42:02 -07:00
static CitySizeDescription wmSphereData[CITY_SIZE_COUNT];
2022-05-19 01:51:26 -07:00
// 0x673034
2022-09-15 01:42:02 -07:00
static EncounterTable* wmEncounterTableList;
2022-05-19 01:51:26 -07:00
// Number of enc_base_types.
//
// 0x673038
2022-09-15 01:42:02 -07:00
static int wmMaxEncBaseTypes;
2022-05-19 01:51:26 -07:00
// 0x67303C
2022-09-15 01:42:02 -07:00
static int wmMaxEncounterInfoTables;
2022-06-18 21:45:51 -07:00
2022-08-14 14:16:36 -07:00
static bool gTownMapHotkeysFix;
2022-08-29 07:37:58 -07:00
static double gGameTimeIncRemainder = 0.0;
static FrmImage _backgroundFrmImage;
static FrmImage _townFrmImage;
2022-08-14 14:16:36 -07:00
2022-06-18 21:45:51 -07:00
static inline bool cityIsValid(int city)
{
2022-09-15 01:42:02 -07:00
return city >= 0 && city < wmMaxAreaNum;
2022-06-18 21:45:51 -07:00
}
2022-05-19 01:51:26 -07:00
2022-09-01 08:41:37 -07:00
// 0x4BC890
static void wmSetFlags(int* flagsPtr, int flag, int value)
{
if (value) {
*flagsPtr |= flag;
} else {
*flagsPtr &= ~flag;
}
}
2022-05-19 01:51:26 -07:00
// 0x4BC89C
2022-09-15 01:42:02 -07:00
int wmWorldMap_init()
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
2022-09-15 01:42:02 -07:00
if (wmGenDataInit() == -1) {
2022-05-19 01:51:26 -07:00
return -1;
}
2022-09-15 01:42:02 -07:00
if (!messageListInit(&wmMsgFile)) {
2022-05-19 01:51:26 -07:00
return -1;
}
sprintf(path, "%s%s", asc_5186C8, "worldmap.msg");
2022-09-15 01:42:02 -07:00
if (!messageListLoad(&wmMsgFile, path)) {
2022-05-19 01:51:26 -07:00
return -1;
}
2022-09-15 01:42:02 -07:00
if (wmConfigInit() == -1) {
2022-05-19 01:51:26 -07:00
return -1;
}
2022-09-15 01:42:02 -07:00
wmGenData.viewportMaxX = WM_TILE_WIDTH * wmNumHorizontalTiles - WM_VIEW_WIDTH;
wmGenData.viewportMaxY = WM_TILE_HEIGHT * (wmMaxTileNum / wmNumHorizontalTiles) - WM_VIEW_HEIGHT;
circleBlendTable = _getColorBlendTable(_colorTable[992]);
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
wmMarkSubTileRadiusVisited(wmGenData.worldPosX, wmGenData.worldPosY);
wmWorldMapSaveTempData();
2022-05-19 01:51:26 -07:00
2022-08-14 14:16:36 -07:00
// SFALL
gTownMapHotkeysFix = true;
configGetBool(&gSfallConfig, SFALL_CONFIG_MISC_KEY, SFALL_CONFIG_TOWN_MAP_HOTKEYS_FIX_KEY, &gTownMapHotkeysFix);
2022-08-14 14:16:36 -07:00
// 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);
}
messageListRepositorySetStandardMessageList(STANDARD_MESSAGE_LIST_WORLDMAP, &wmMsgFile);
2022-05-19 01:51:26 -07:00
return 0;
}
// 0x4BC984
2022-09-15 01:42:02 -07:00
static int wmGenDataInit()
{
wmGenData.didMeetFrankHorrigan = false;
wmGenData.currentAreaId = -1;
wmGenData.worldPosX = 173;
wmGenData.worldPosY = 122;
wmGenData.currentSubtile = NULL;
wmGenData.dword_672E18 = 0;
wmGenData.isWalking = false;
wmGenData.walkDestinationX = -1;
wmGenData.walkDestinationY = -1;
wmGenData.walkDistance = 0;
wmGenData.walkLineDelta = 0;
wmGenData.walkLineDeltaMainAxisStep = 0;
wmGenData.walkLineDeltaCrossAxisStep = 0;
wmGenData.walkWorldPosMainAxisStepX = 0;
wmGenData.walkWorldPosMainAxisStepY = 0;
wmGenData.walkWorldPosCrossAxisStepY = 0;
wmGenData.encounterIconIsVisible = 0;
wmGenData.encounterMapId = -1;
wmGenData.encounterTableId = -1;
wmGenData.encounterEntryId = -1;
wmGenData.encounterCursorId = -1;
wmGenData.oldWorldPosX = 0;
wmGenData.oldWorldPosY = 0;
wmGenData.isInCar = false;
wmGenData.currentCarAreaId = -1;
wmGenData.carFuel = CAR_FUEL_MAX;
wmGenData.carImageFrmHandle = INVALID_CACHE_ENTRY;
wmGenData.carImageFrmWidth = 0;
wmGenData.carImageFrmHeight = 0;
wmGenData.carImageCurrentFrameIndex = 0;
wmGenData.mousePressed = false;
wmGenData.walkWorldPosCrossAxisStepX = 0;
wmGenData.carImageFrm = NULL;
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
wmGenData.viewportMaxY = 0;
wmGenData.tabsOffsetY = 0;
wmGenData.dialFrmHandle = INVALID_CACHE_ENTRY;
wmGenData.dialFrm = NULL;
wmGenData.dialFrmWidth = 0;
wmGenData.dialFrmHeight = 0;
wmGenData.dialFrmCurrentFrameIndex = 0;
wmGenData.oldTabsOffsetY = 0;
wmGenData.tabsScrollingDelta = 0;
wmGenData.viewportMaxX = 0;
2022-05-19 01:51:26 -07:00
return 0;
}
// 0x4BCBFC
2022-09-15 01:42:02 -07:00
static int wmGenDataReset()
{
wmGenData.didMeetFrankHorrigan = false;
wmGenData.currentSubtile = NULL;
wmGenData.dword_672E18 = 0;
wmGenData.isWalking = false;
wmGenData.walkDistance = 0;
wmGenData.walkLineDelta = 0;
wmGenData.walkLineDeltaMainAxisStep = 0;
wmGenData.walkLineDeltaCrossAxisStep = 0;
wmGenData.walkWorldPosMainAxisStepX = 0;
wmGenData.walkWorldPosMainAxisStepY = 0;
wmGenData.walkWorldPosCrossAxisStepY = 0;
wmGenData.encounterIconIsVisible = 0;
wmGenData.mousePressed = false;
wmGenData.currentAreaId = -1;
wmGenData.worldPosX = 173;
wmGenData.worldPosY = 122;
wmGenData.walkDestinationX = -1;
wmGenData.walkDestinationY = -1;
wmGenData.encounterMapId = -1;
wmGenData.encounterTableId = -1;
wmGenData.encounterEntryId = -1;
wmGenData.encounterCursorId = -1;
wmGenData.currentCarAreaId = -1;
wmGenData.carFuel = CAR_FUEL_MAX;
wmGenData.carImageFrmHandle = INVALID_CACHE_ENTRY;
wmGenData.dialFrmHandle = INVALID_CACHE_ENTRY;
wmGenData.walkWorldPosCrossAxisStepX = 0;
wmGenData.oldWorldPosX = 0;
wmGenData.oldWorldPosY = 0;
wmGenData.isInCar = false;
wmGenData.carImageFrmWidth = 0;
wmGenData.carImageFrmHeight = 0;
wmGenData.carImageCurrentFrameIndex = 0;
wmGenData.tabsOffsetY = 0;
wmGenData.dialFrm = NULL;
wmGenData.dialFrmWidth = 0;
wmGenData.dialFrmHeight = 0;
wmGenData.dialFrmCurrentFrameIndex = 0;
wmGenData.oldTabsOffsetY = 0;
wmGenData.tabsScrollingDelta = 0;
wmGenData.carImageFrm = NULL;
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
wmMarkSubTileRadiusVisited(wmGenData.worldPosX, wmGenData.worldPosY);
2022-05-19 01:51:26 -07:00
return 0;
}
// 0x4BCE00
2022-09-15 01:42:02 -07:00
void wmWorldMap_exit()
2022-05-19 01:51:26 -07:00
{
2022-09-15 01:42:02 -07:00
if (wmTerrainTypeList != NULL) {
internal_free(wmTerrainTypeList);
wmTerrainTypeList = NULL;
2022-05-19 01:51:26 -07:00
}
2022-09-15 01:42:02 -07:00
if (wmTileInfoList) {
internal_free(wmTileInfoList);
wmTileInfoList = NULL;
2022-05-19 01:51:26 -07:00
}
2022-09-15 01:42:02 -07:00
wmNumHorizontalTiles = 0;
wmMaxTileNum = 0;
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
if (wmEncounterTableList != NULL) {
internal_free(wmEncounterTableList);
wmEncounterTableList = NULL;
2022-05-19 01:51:26 -07:00
}
2022-09-15 01:42:02 -07:00
wmMaxEncounterInfoTables = 0;
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
if (wmEncBaseTypeList != NULL) {
internal_free(wmEncBaseTypeList);
wmEncBaseTypeList = NULL;
2022-05-19 01:51:26 -07:00
}
2022-09-15 01:42:02 -07:00
wmMaxEncBaseTypes = 0;
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
if (wmAreaInfoList != NULL) {
internal_free(wmAreaInfoList);
wmAreaInfoList = NULL;
2022-05-19 01:51:26 -07:00
}
2022-09-15 01:42:02 -07:00
wmMaxAreaNum = 0;
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
if (wmMapInfoList != NULL) {
internal_free(wmMapInfoList);
2022-05-19 01:51:26 -07:00
}
2022-09-15 01:42:02 -07:00
wmMaxMapNum = 0;
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
if (circleBlendTable != NULL) {
2022-05-19 01:51:26 -07:00
_freeColorBlendTable(_colorTable[992]);
2022-09-15 01:42:02 -07:00
circleBlendTable = NULL;
2022-05-19 01:51:26 -07:00
}
messageListRepositorySetStandardMessageList(STANDARD_MESSAGE_LIST_WORLDMAP, nullptr);
2022-09-15 01:42:02 -07:00
messageListFree(&wmMsgFile);
2022-05-19 01:51:26 -07:00
}
// 0x4BCEF8
2022-09-15 01:42:02 -07:00
int wmWorldMap_reset()
2022-05-19 01:51:26 -07:00
{
2022-09-15 01:42:02 -07:00
wmWorldOffsetX = 0;
wmWorldOffsetY = 0;
2022-05-19 01:51:26 -07:00
2022-08-29 07:37:58 -07:00
// CE: Fix Pathfinder perk.
gGameTimeIncRemainder = 0.0;
2022-09-15 01:42:02 -07:00
wmWorldMapLoadTempData();
wmMarkAllSubTiles(0);
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
return wmGenDataReset();
2022-05-19 01:51:26 -07:00
}
// 0x4BCF28
2022-09-15 01:42:02 -07:00
int wmWorldMap_save(File* stream)
2022-05-19 01:51:26 -07:00
{
int i;
int j;
int k;
EncounterTable* encounter_table;
EncounterEntry* encounter_entry;
2022-09-15 01:42:02 -07:00
if (fileWriteBool(stream, wmGenData.didMeetFrankHorrigan) == -1) return -1;
if (fileWriteInt32(stream, wmGenData.currentAreaId) == -1) return -1;
if (fileWriteInt32(stream, wmGenData.worldPosX) == -1) return -1;
if (fileWriteInt32(stream, wmGenData.worldPosY) == -1) return -1;
if (fileWriteInt32(stream, wmGenData.encounterIconIsVisible) == -1) return -1;
if (fileWriteInt32(stream, wmGenData.encounterMapId) == -1) return -1;
if (fileWriteInt32(stream, wmGenData.encounterTableId) == -1) return -1;
if (fileWriteInt32(stream, wmGenData.encounterEntryId) == -1) return -1;
if (fileWriteBool(stream, wmGenData.isInCar) == -1) return -1;
if (fileWriteInt32(stream, wmGenData.currentCarAreaId) == -1) return -1;
if (fileWriteInt32(stream, wmGenData.carFuel) == -1) return -1;
if (fileWriteInt32(stream, wmMaxAreaNum) == -1) return -1;
for (int areaIdx = 0; areaIdx < wmMaxAreaNum; areaIdx++) {
CityInfo* cityInfo = &(wmAreaInfoList[areaIdx]);
2022-05-19 01:51:26 -07:00
if (fileWriteInt32(stream, cityInfo->x) == -1) return -1;
if (fileWriteInt32(stream, cityInfo->y) == -1) return -1;
if (fileWriteInt32(stream, cityInfo->state) == -1) return -1;
2022-09-15 01:42:02 -07:00
if (fileWriteInt32(stream, cityInfo->visitedState) == -1) return -1;
2022-05-19 01:51:26 -07:00
if (fileWriteInt32(stream, cityInfo->entrancesLength) == -1) return -1;
2022-09-15 01:42:02 -07:00
for (int entranceIdx = 0; entranceIdx < cityInfo->entrancesLength; entranceIdx++) {
EntranceInfo* entrance = &(cityInfo->entrances[entranceIdx]);
2022-05-19 01:51:26 -07:00
if (fileWriteInt32(stream, entrance->state) == -1) return -1;
}
}
2022-09-15 01:42:02 -07:00
if (fileWriteInt32(stream, wmMaxTileNum) == -1) return -1;
if (fileWriteInt32(stream, wmNumHorizontalTiles) == -1) return -1;
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
for (int tileIndex = 0; tileIndex < wmMaxTileNum; tileIndex++) {
TileInfo* tileInfo = &(wmTileInfoList[tileIndex]);
2022-05-19 01:51:26 -07:00
for (int column = 0; column < SUBTILE_GRID_HEIGHT; column++) {
for (int row = 0; row < SUBTILE_GRID_WIDTH; row++) {
SubtileInfo* subtile = &(tileInfo->subtiles[column][row]);
if (fileWriteInt32(stream, subtile->state) == -1) return -1;
}
}
}
k = 0;
2022-09-15 01:42:02 -07:00
for (i = 0; i < wmMaxEncounterInfoTables; i++) {
encounter_table = &(wmEncounterTableList[i]);
2022-05-19 01:51:26 -07:00
for (j = 0; j < encounter_table->entriesLength; j++) {
encounter_entry = &(encounter_table->entries[j]);
if (encounter_entry->counter != -1) {
k++;
}
}
}
if (fileWriteInt32(stream, k) == -1) return -1;
2022-09-15 01:42:02 -07:00
for (i = 0; i < wmMaxEncounterInfoTables; i++) {
encounter_table = &(wmEncounterTableList[i]);
2022-05-19 01:51:26 -07:00
for (j = 0; j < encounter_table->entriesLength; j++) {
encounter_entry = &(encounter_table->entries[j]);
if (encounter_entry->counter != -1) {
if (fileWriteInt32(stream, i) == -1) return -1;
if (fileWriteInt32(stream, j) == -1) return -1;
if (fileWriteInt32(stream, encounter_entry->counter) == -1) return -1;
}
}
}
return 0;
}
// 0x4BD28C
2022-09-15 01:42:02 -07:00
int wmWorldMap_load(File* stream)
2022-05-19 01:51:26 -07:00
{
int i;
int j;
int k;
int cities_count;
int v38;
int v39;
int v35;
EncounterTable* encounter_table;
EncounterEntry* encounter_entry;
2022-09-15 01:42:02 -07:00
if (fileReadBool(stream, &(wmGenData.didMeetFrankHorrigan)) == -1) return -1;
if (fileReadInt32(stream, &(wmGenData.currentAreaId)) == -1) return -1;
if (fileReadInt32(stream, &(wmGenData.worldPosX)) == -1) return -1;
if (fileReadInt32(stream, &(wmGenData.worldPosY)) == -1) return -1;
if (fileReadInt32(stream, &(wmGenData.encounterIconIsVisible)) == -1) return -1;
if (fileReadInt32(stream, &(wmGenData.encounterMapId)) == -1) return -1;
if (fileReadInt32(stream, &(wmGenData.encounterTableId)) == -1) return -1;
if (fileReadInt32(stream, &(wmGenData.encounterEntryId)) == -1) return -1;
if (fileReadBool(stream, &(wmGenData.isInCar)) == -1) return -1;
if (fileReadInt32(stream, &(wmGenData.currentCarAreaId)) == -1) return -1;
if (fileReadInt32(stream, &(wmGenData.carFuel)) == -1) return -1;
2022-05-19 01:51:26 -07:00
if (fileReadInt32(stream, &(cities_count)) == -1) return -1;
2022-09-15 01:42:02 -07:00
for (int areaIdx = 0; areaIdx < cities_count; areaIdx++) {
CityInfo* city = &(wmAreaInfoList[areaIdx]);
2022-05-19 01:51:26 -07:00
if (fileReadInt32(stream, &(city->x)) == -1) return -1;
if (fileReadInt32(stream, &(city->y)) == -1) return -1;
if (fileReadInt32(stream, &(city->state)) == -1) return -1;
2022-09-15 01:42:02 -07:00
if (fileReadInt32(stream, &(city->visitedState)) == -1) return -1;
2022-05-19 01:51:26 -07:00
int entranceCount;
if (fileReadInt32(stream, &(entranceCount)) == -1) {
return -1;
}
2022-09-15 01:42:02 -07:00
for (int entranceIdx = 0; entranceIdx < entranceCount; entranceIdx++) {
EntranceInfo* entrance = &(city->entrances[entranceIdx]);
2022-05-19 01:51:26 -07:00
if (fileReadInt32(stream, &(entrance->state)) == -1) {
return -1;
}
}
}
if (fileReadInt32(stream, &(v39)) == -1) return -1;
if (fileReadInt32(stream, &(v38)) == -1) return -1;
for (int tileIndex = 0; tileIndex < v39; tileIndex++) {
2022-09-15 01:42:02 -07:00
TileInfo* tile = &(wmTileInfoList[tileIndex]);
2022-05-19 01:51:26 -07:00
for (int column = 0; column < SUBTILE_GRID_HEIGHT; column++) {
for (int row = 0; row < SUBTILE_GRID_WIDTH; row++) {
SubtileInfo* subtile = &(tile->subtiles[column][row]);
if (fileReadInt32(stream, &(subtile->state)) == -1) return -1;
}
}
}
if (fileReadInt32(stream, &(v35)) == -1) return -1;
for (i = 0; i < v35; i++) {
if (fileReadInt32(stream, &(j)) == -1) return -1;
2022-09-15 01:42:02 -07:00
encounter_table = &(wmEncounterTableList[j]);
2022-05-19 01:51:26 -07:00
if (fileReadInt32(stream, &(k)) == -1) return -1;
encounter_entry = &(encounter_table->entries[k]);
if (fileReadInt32(stream, &(encounter_entry->counter)) == -1) return -1;
}
2022-09-15 01:42:02 -07:00
wmInterfaceCenterOnParty();
2022-05-19 01:51:26 -07:00
return 0;
}
// 0x4BD678
2022-09-15 01:42:02 -07:00
static int wmWorldMapSaveTempData()
2022-05-19 01:51:26 -07:00
{
File* stream = fileOpen("worldmap.dat", "wb");
if (stream == NULL) {
return -1;
}
int rc = 0;
2022-09-15 01:42:02 -07:00
if (wmWorldMap_save(stream) == -1) {
2022-05-19 01:51:26 -07:00
rc = -1;
}
fileClose(stream);
return rc;
}
// 0x4BD6B4
2022-09-15 01:42:02 -07:00
static int wmWorldMapLoadTempData()
2022-05-19 01:51:26 -07:00
{
File* stream = fileOpen("worldmap.dat", "rb");
if (stream == NULL) {
return -1;
}
int rc = 0;
2022-09-15 01:42:02 -07:00
if (wmWorldMap_load(stream) == -1) {
2022-05-19 01:51:26 -07:00
rc = -1;
}
fileClose(stream);
return rc;
}
// 0x4BD6F0
2022-09-15 01:42:02 -07:00
static int wmConfigInit()
2022-05-19 01:51:26 -07:00
{
2022-09-15 01:42:02 -07:00
if (wmAreaInit() == -1) {
2022-05-19 01:51:26 -07:00
return -1;
}
Config config;
if (!configInit(&config)) {
return -1;
}
if (configRead(&config, "data\\worldmap.txt", true)) {
for (int index = 0; index < ENCOUNTER_FREQUENCY_TYPE_COUNT; index++) {
2022-09-15 01:42:02 -07:00
if (!configGetInt(&config, "data", wmFreqStrs[index], &(wmFreqValues[index]))) {
2022-05-19 01:51:26 -07:00
break;
}
}
char* terrainTypes;
configGetString(&config, "data", "terrain_types", &terrainTypes);
2022-09-15 01:42:02 -07:00
wmParseTerrainTypes(&config, terrainTypes);
2022-05-19 01:51:26 -07:00
for (int index = 0;; index++) {
char section[40];
sprintf(section, "Encounter Table %d", index);
char* lookupName;
if (!configGetString(&config, section, "lookup_name", &lookupName)) {
break;
}
2022-09-15 01:42:02 -07:00
if (wmReadEncounterType(&config, lookupName, section) == -1) {
2022-05-19 01:51:26 -07:00
return -1;
}
}
2022-09-15 01:42:02 -07:00
if (!configGetInt(&config, "Tile Data", "num_horizontal_tiles", &wmNumHorizontalTiles)) {
2022-05-19 01:51:26 -07:00
showMesageBox("\nwmConfigInit::Error loading tile data!");
return -1;
}
for (int tileIndex = 0; tileIndex < 9999; tileIndex++) {
char section[40];
sprintf(section, "Tile %d", tileIndex);
int artIndex;
if (!configGetInt(&config, section, "art_idx", &artIndex)) {
break;
}
2022-09-15 01:42:02 -07:00
wmMaxTileNum++;
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
TileInfo* worldmapTiles = (TileInfo*)internal_realloc(wmTileInfoList, sizeof(*wmTileInfoList) * wmMaxTileNum);
2022-05-19 01:51:26 -07:00
if (worldmapTiles == NULL) {
showMesageBox("\nwmConfigInit::Error loading tiles!");
exit(1);
}
2022-09-15 01:42:02 -07:00
wmTileInfoList = worldmapTiles;
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
TileInfo* tile = &(worldmapTiles[wmMaxTileNum - 1]);
2022-05-19 01:51:26 -07:00
// NOTE: Uninline.
2022-09-15 01:42:02 -07:00
wmTileSlotInit(tile);
2022-05-19 01:51:26 -07:00
tile->fid = buildFid(OBJ_TYPE_INTERFACE, artIndex, 0, 0, 0);
2022-05-19 01:51:26 -07:00
int encounterDifficulty;
if (configGetInt(&config, section, "encounter_difficulty", &encounterDifficulty)) {
tile->encounterDifficultyModifier = encounterDifficulty;
}
char* walkMaskName;
if (configGetString(&config, section, "walk_mask_name", &walkMaskName)) {
strncpy(tile->walkMaskName, walkMaskName, TILE_WALK_MASK_NAME_SIZE);
}
for (int column = 0; column < SUBTILE_GRID_HEIGHT; column++) {
for (int row = 0; row < SUBTILE_GRID_WIDTH; row++) {
char key[40];
sprintf(key, "%d_%d", row, column);
char* subtileProps;
if (!configGetString(&config, section, key, &subtileProps)) {
showMesageBox("\nwmConfigInit::Error loading tiles!");
exit(1);
}
2022-09-15 01:42:02 -07:00
if (wmParseSubTileInfo(tile, row, column, subtileProps) == -1) {
2022-05-19 01:51:26 -07:00
showMesageBox("\nwmConfigInit::Error loading tiles!");
exit(1);
}
}
}
}
}
configFree(&config);
return 0;
}
// 0x4BD9F0
2022-09-15 01:42:02 -07:00
static int wmReadEncounterType(Config* config, char* lookupName, char* sectionKey)
2022-05-19 01:51:26 -07:00
{
2022-09-15 01:42:02 -07:00
wmMaxEncounterInfoTables++;
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
EncounterTable* encounterTables = (EncounterTable*)internal_realloc(wmEncounterTableList, sizeof(EncounterTable) * wmMaxEncounterInfoTables);
2022-05-19 01:51:26 -07:00
if (encounterTables == NULL) {
showMesageBox("\nwmConfigInit::Error loading Encounter Table!");
exit(1);
}
2022-09-15 01:42:02 -07:00
wmEncounterTableList = encounterTables;
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
EncounterTable* encounterTable = &(encounterTables[wmMaxEncounterInfoTables - 1]);
2022-05-19 01:51:26 -07:00
// NOTE: Uninline.
2022-09-15 01:42:02 -07:00
wmEncounterTableSlotInit(encounterTable);
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
encounterTable->field_28 = wmMaxEncounterInfoTables - 1;
2022-05-19 01:51:26 -07:00
strncpy(encounterTable->lookupName, lookupName, 40);
char* str;
if (configGetString(config, sectionKey, "maps", &str)) {
while (*str != '\0') {
if (encounterTable->mapsLength >= 6) {
break;
}
2022-09-15 01:42:02 -07:00
if (strParseStrFromFunc(&str, &(encounterTable->maps[encounterTable->mapsLength]), wmParseFindMapIdxMatch) == -1) {
2022-05-19 01:51:26 -07:00
break;
}
encounterTable->mapsLength++;
}
}
for (;;) {
char key[40];
sprintf(key, "enc_%02d", encounterTable->entriesLength);
char* str;
if (!configGetString(config, sectionKey, key, &str)) {
break;
}
if (encounterTable->entriesLength >= 40) {
showMesageBox("\nwmConfigInit::Error: Encounter Table: Too many table indexes!!");
exit(1);
}
2022-09-15 01:42:02 -07:00
pConfigCfg = config;
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
if (wmParseEncounterTableIndex(&(encounterTable->entries[encounterTable->entriesLength]), str) == -1) {
2022-05-19 01:51:26 -07:00
return -1;
}
encounterTable->entriesLength++;
}
return 0;
}
// 0x4BDB64
2022-09-15 01:42:02 -07:00
static int wmParseEncounterTableIndex(EncounterEntry* entry, char* string)
2022-05-19 01:51:26 -07:00
{
// NOTE: Uninline.
2022-09-15 01:42:02 -07:00
if (wmEncounterTypeSlotInit(entry) == -1) {
2022-05-19 01:51:26 -07:00
return -1;
}
while (string != NULL && *string != '\0') {
strParseIntWithKey(&string, "chance", &(entry->chance), ":");
strParseIntWithKey(&string, "counter", &(entry->counter), ":");
if (strstr(string, "special")) {
entry->flags |= ENCOUNTER_ENTRY_SPECIAL;
2022-10-29 08:14:49 -07:00
// 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++;
}
2022-05-19 01:51:26 -07:00
}
if (string != NULL) {
char* pch = strstr(string, "map:");
if (pch != NULL) {
string = pch + 4;
2022-09-15 01:42:02 -07:00
strParseStrFromFunc(&string, &(entry->map), wmParseFindMapIdxMatch);
2022-05-19 01:51:26 -07:00
}
}
2022-09-15 01:42:02 -07:00
if (wmParseEncounterSubEncStr(entry, &string) == -1) {
2022-05-19 01:51:26 -07:00
break;
}
if (string != NULL) {
char* pch = strstr(string, "scenery:");
if (pch != NULL) {
string = pch + 8;
2022-09-15 01:42:02 -07:00
strParseStrFromList(&string, &(entry->scenery), wmSceneryStrs, ENCOUNTER_SCENERY_TYPE_COUNT);
2022-05-19 01:51:26 -07:00
}
}
2022-09-15 01:42:02 -07:00
wmParseConditional(&string, "if", &(entry->condition));
2022-05-19 01:51:26 -07:00
}
return 0;
}
// 0x4BDCA8
2022-09-15 01:42:02 -07:00
static int wmParseEncounterSubEncStr(EncounterEntry* encounterEntry, char** stringPtr)
2022-05-19 01:51:26 -07:00
{
char* string = *stringPtr;
if (compat_strnicmp(string, "enc:", 4) != 0) {
2022-05-19 01:51:26 -07:00
return -1;
}
// Consume "enc:".
string += 4;
char* comma = strstr(string, ",");
if (comma != NULL) {
// Comma is present, position string pointer to the next chunk.
*stringPtr = comma + 1;
*comma = '\0';
} else {
// No comma, this chunk is the last one.
*stringPtr = NULL;
}
while (string != NULL) {
ENCOUNTER_ENTRY_ENC* entry = &(encounterEntry->field_54[encounterEntry->field_50]);
// NOTE: Uninline.
2022-09-15 01:42:02 -07:00
wmEncounterSubEncSlotInit(entry);
2022-05-19 01:51:26 -07:00
if (*string == '(') {
string++;
entry->minQuantity = atoi(string);
while (*string != '\0' && *string != '-') {
string++;
}
if (*string == '-') {
string++;
}
entry->maxQuantity = atoi(string);
while (*string != '\0' && *string != ')') {
string++;
}
if (*string == ')') {
string++;
}
}
while (*string == ' ') {
string++;
}
char* end = string;
while (*end != '\0' && *end != ' ') {
end++;
}
char ch = *end;
*end = '\0';
2022-09-15 01:42:02 -07:00
if (strParseStrFromFunc(&string, &(entry->field_8), wmParseFindSubEncTypeMatch) == -1) {
2022-05-19 01:51:26 -07:00
return -1;
}
*end = ch;
if (ch == ' ') {
string++;
}
end = string;
while (*end != '\0' && *end != ' ') {
end++;
}
ch = *end;
*end = '\0';
if (*string != '\0') {
2022-09-15 01:42:02 -07:00
strParseStrFromList(&string, &(entry->situation), wmEncOpStrs, ENCOUNTER_SITUATION_COUNT);
2022-05-19 01:51:26 -07:00
}
*end = ch;
encounterEntry->field_50++;
while (*string == ' ') {
string++;
}
if (*string == '\0') {
string = NULL;
}
}
if (comma != NULL) {
*comma = ',';
}
return 0;
}
// 0x4BDE94
2022-09-15 01:42:02 -07:00
static int wmParseFindSubEncTypeMatch(char* str, int* valuePtr)
2022-05-19 01:51:26 -07:00
{
*valuePtr = 0;
if (compat_stricmp(str, "player") == 0) {
2022-05-19 01:51:26 -07:00
*valuePtr = -1;
return 0;
}
2022-09-15 01:42:02 -07:00
if (wmFindEncBaseTypeMatch(str, valuePtr) == 0) {
2022-05-19 01:51:26 -07:00
return 0;
}
2022-09-15 01:42:02 -07:00
if (wmReadEncBaseType(str, valuePtr) == 0) {
2022-05-19 01:51:26 -07:00
return 0;
}
return -1;
}
// 0x4BDED8
2022-09-15 01:42:02 -07:00
static int wmFindEncBaseTypeMatch(char* str, int* valuePtr)
2022-05-19 01:51:26 -07:00
{
2022-09-15 01:42:02 -07:00
for (int index = 0; index < wmMaxEncBaseTypes; index++) {
if (compat_stricmp(wmEncBaseTypeList[index].name, str) == 0) {
2022-05-19 01:51:26 -07:00
*valuePtr = index;
return 0;
}
}
*valuePtr = -1;
return -1;
}
// 0x4BDF34
2022-09-15 01:42:02 -07:00
static int wmReadEncBaseType(char* name, int* valuePtr)
2022-05-19 01:51:26 -07:00
{
char section[40];
sprintf(section, "Encounter: %s", name);
char key[40];
sprintf(key, "type_00");
char* string;
2022-09-15 01:42:02 -07:00
if (!configGetString(pConfigCfg, section, key, &string)) {
2022-05-19 01:51:26 -07:00
return -1;
}
2022-09-15 01:42:02 -07:00
wmMaxEncBaseTypes++;
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
ENC_BASE_TYPE* arr = (ENC_BASE_TYPE*)internal_realloc(wmEncBaseTypeList, sizeof(*wmEncBaseTypeList) * wmMaxEncBaseTypes);
2022-05-19 01:51:26 -07:00
if (arr == NULL) {
showMesageBox("\nwmConfigInit::Error Reading EncBaseType!");
exit(1);
}
2022-09-15 01:42:02 -07:00
wmEncBaseTypeList = arr;
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
ENC_BASE_TYPE* entry = &(arr[wmMaxEncBaseTypes - 1]);
2022-05-19 01:51:26 -07:00
// NOTE: Uninline.
2022-09-15 01:42:02 -07:00
wmEncBaseTypeSlotInit(entry);
2022-05-19 01:51:26 -07:00
strncpy(entry->name, name, 40);
while (1) {
2022-09-15 01:42:02 -07:00
if (wmParseEncBaseSubTypeStr(&(entry->field_38[entry->field_34]), &string) == -1) {
2022-05-19 01:51:26 -07:00
return -1;
}
entry->field_34++;
sprintf(key, "type_%02d", entry->field_34);
2022-09-15 01:42:02 -07:00
if (!configGetString(pConfigCfg, section, key, &string)) {
2022-05-19 01:51:26 -07:00
int team;
2022-09-15 01:42:02 -07:00
configGetInt(pConfigCfg, section, "team_num", &team);
2022-05-19 01:51:26 -07:00
for (int index = 0; index < entry->field_34; index++) {
ENC_BASE_TYPE_38* ptr = &(entry->field_38[index]);
if (PID_TYPE(ptr->pid) == OBJ_TYPE_CRITTER) {
2022-05-19 01:51:26 -07:00
ptr->team = team;
}
}
2022-09-15 01:42:02 -07:00
if (configGetString(pConfigCfg, section, "position", &string)) {
strParseStrFromList(&string, &(entry->position), wmFormationStrs, ENCOUNTER_FORMATION_TYPE_COUNT);
2022-05-19 01:51:26 -07:00
strParseIntWithKey(&string, "spacing", &(entry->spacing), ":");
strParseIntWithKey(&string, "distance", &(entry->distance), ":");
}
2022-09-15 01:42:02 -07:00
*valuePtr = wmMaxEncBaseTypes - 1;
2022-05-19 01:51:26 -07:00
return 0;
}
}
return -1;
}
// 0x4BE140
2022-09-15 01:42:02 -07:00
static int wmParseEncBaseSubTypeStr(ENC_BASE_TYPE_38* ptr, char** stringPtr)
2022-05-19 01:51:26 -07:00
{
char* string = *stringPtr;
// NOTE: Uninline.
2022-09-15 01:42:02 -07:00
if (wmEncBaseSubTypeSlotInit(ptr) == -1) {
2022-05-19 01:51:26 -07:00
return -1;
}
if (strParseIntWithKey(&string, "ratio", &(ptr->ratio), ":") == 0) {
ptr->field_2C = 0;
}
if (strstr(string, "dead,") == string) {
ptr->flags |= ENCOUNTER_SUBINFO_DEAD;
string += 5;
}
strParseIntWithKey(&string, "pid", &(ptr->pid), ":");
if (ptr->pid == 0) {
ptr->pid = -1;
}
strParseIntWithKey(&string, "distance", &(ptr->distance), ":");
strParseIntWithKey(&string, "tilenum", &(ptr->tile), ":");
for (int index = 0; index < 10; index++) {
if (strstr(string, "item:") == NULL) {
break;
}
2022-09-15 01:42:02 -07:00
wmParseEncounterItemType(&string, &(ptr->items[ptr->itemsLength]), &(ptr->itemsLength), ":");
2022-05-19 01:51:26 -07:00
}
strParseIntWithKey(&string, "script", &(ptr->script), ":");
2022-09-15 01:42:02 -07:00
wmParseConditional(&string, "if", &(ptr->condition));
2022-05-19 01:51:26 -07:00
return 0;
}
// NOTE: Inlined.
//
// 0x4BE2A0
2022-09-15 01:42:02 -07:00
static int wmEncBaseTypeSlotInit(ENC_BASE_TYPE* entry)
2022-05-19 01:51:26 -07:00
{
entry->name[0] = '\0';
entry->position = ENCOUNTER_FORMATION_TYPE_SURROUNDING;
entry->spacing = 1;
entry->distance = -1;
entry->field_34 = 0;
return 0;
}
// NOTE: Inlined.
//
// 0x4BE2C4
2022-09-15 01:42:02 -07:00
static int wmEncBaseSubTypeSlotInit(ENC_BASE_TYPE_38* entry)
2022-05-19 01:51:26 -07:00
{
entry->field_28 = -1;
entry->field_2C = 1;
entry->ratio = 100;
entry->pid = -1;
entry->flags = 0;
entry->distance = 0;
entry->tile = -1;
entry->itemsLength = 0;
entry->script = -1;
entry->team = -1;
2022-09-15 01:42:02 -07:00
return wmConditionalDataInit(&(entry->condition));
2022-05-19 01:51:26 -07:00
}
// NOTE: Inlined.
//
// 0x4BE32C
2022-09-15 01:42:02 -07:00
static int wmEncounterSubEncSlotInit(ENCOUNTER_ENTRY_ENC* entry)
2022-05-19 01:51:26 -07:00
{
entry->minQuantity = 1;
entry->maxQuantity = 1;
entry->field_8 = -1;
entry->situation = ENCOUNTER_SITUATION_NOTHING;
return 0;
}
// NOTE: Inlined.
//
// 0x4BE34C
2022-09-15 01:42:02 -07:00
static int wmEncounterTypeSlotInit(EncounterEntry* entry)
2022-05-19 01:51:26 -07:00
{
entry->flags = 0;
entry->map = -1;
entry->scenery = ENCOUNTER_SCENERY_TYPE_NORMAL;
entry->chance = 0;
entry->counter = -1;
entry->field_50 = 0;
2022-09-15 01:42:02 -07:00
return wmConditionalDataInit(&(entry->condition));
2022-05-19 01:51:26 -07:00
}
// NOTE: Inlined.
//
// 0x4BE3B8
2022-09-15 01:42:02 -07:00
static int wmEncounterTableSlotInit(EncounterTable* encounterTable)
2022-05-19 01:51:26 -07:00
{
encounterTable->lookupName[0] = '\0';
encounterTable->mapsLength = 0;
encounterTable->field_48 = 0;
encounterTable->entriesLength = 0;
return 0;
}
// NOTE: Inlined.
//
// 0x4BE3D4
2022-09-15 01:42:02 -07:00
static int wmTileSlotInit(TileInfo* tile)
2022-05-19 01:51:26 -07:00
{
tile->fid = -1;
tile->handle = INVALID_CACHE_ENTRY;
tile->data = NULL;
tile->walkMaskName[0] = '\0';
tile->walkMaskData = NULL;
tile->encounterDifficultyModifier = 0;
return 0;
}
// NOTE: Inlined.
//
// 0x4BE400
2022-09-15 01:42:02 -07:00
static int wmTerrainTypeSlotInit(Terrain* terrain)
2022-05-19 01:51:26 -07:00
{
2022-09-15 01:42:02 -07:00
terrain->lookupName[0] = '\0';
2022-08-29 07:37:58 -07:00
terrain->difficulty = 0;
2022-05-19 01:51:26 -07:00
terrain->mapsLength = 0;
return 0;
}
// 0x4BE378
2022-09-15 01:42:02 -07:00
static int wmConditionalDataInit(EncounterCondition* condition)
2022-05-19 01:51:26 -07:00
{
condition->entriesLength = 0;
for (int index = 0; index < 3; index++) {
EncounterConditionEntry* conditionEntry = &(condition->entries[index]);
conditionEntry->type = ENCOUNTER_CONDITION_TYPE_NONE;
conditionEntry->conditionalOperator = ENCOUNTER_CONDITIONAL_OPERATOR_NONE;
conditionEntry->param = 0;
conditionEntry->value = 0;
}
for (int index = 0; index < 2; index++) {
condition->logicalOperators[index] = ENCOUNTER_LOGICAL_OPERATOR_NONE;
}
return 0;
}
// 0x4BE414
2022-09-15 01:42:02 -07:00
static int wmParseTerrainTypes(Config* config, char* string)
2022-05-19 01:51:26 -07:00
{
if (*string == '\0') {
return -1;
}
int terrainCount = 1;
char* pch = string;
while (*pch != '\0') {
if (*pch == ',') {
terrainCount++;
}
pch++;
}
2022-09-15 01:42:02 -07:00
wmMaxTerrainTypes = terrainCount;
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
wmTerrainTypeList = (Terrain*)internal_malloc(sizeof(*wmTerrainTypeList) * terrainCount);
if (wmTerrainTypeList == NULL) {
2022-05-19 01:51:26 -07:00
return -1;
}
2022-09-15 01:42:02 -07:00
for (int index = 0; index < wmMaxTerrainTypes; index++) {
Terrain* terrain = &(wmTerrainTypeList[index]);
2022-05-19 01:51:26 -07:00
// NOTE: Uninline.
2022-09-15 01:42:02 -07:00
wmTerrainTypeSlotInit(terrain);
2022-05-19 01:51:26 -07:00
}
compat_strlwr(string);
2022-05-19 01:51:26 -07:00
pch = string;
2022-09-15 01:42:02 -07:00
for (int index = 0; index < wmMaxTerrainTypes; index++) {
Terrain* terrain = &(wmTerrainTypeList[index]);
2022-05-19 01:51:26 -07:00
pch += strspn(pch, " ");
2022-08-29 13:58:03 -07:00
size_t endPos = strcspn(pch, ",");
2022-05-19 01:51:26 -07:00
char end = pch[endPos];
pch[endPos] = '\0';
2022-08-29 13:58:03 -07:00
size_t delimeterPos = strcspn(pch, ":");
2022-05-19 01:51:26 -07:00
char delimeter = pch[delimeterPos];
pch[delimeterPos] = '\0';
2022-09-15 01:42:02 -07:00
strncpy(terrain->lookupName, pch, 40);
2022-08-29 07:37:58 -07:00
terrain->difficulty = atoi(pch + delimeterPos + 1);
2022-05-19 01:51:26 -07:00
pch[delimeterPos] = delimeter;
pch[endPos] = end;
if (end == ',') {
pch += endPos + 1;
}
}
2022-09-15 01:42:02 -07:00
for (int index = 0; index < wmMaxTerrainTypes; index++) {
wmParseTerrainRndMaps(config, &(wmTerrainTypeList[index]));
2022-05-19 01:51:26 -07:00
}
return 0;
}
// 0x4BE598
2022-09-15 01:42:02 -07:00
static int wmParseTerrainRndMaps(Config* config, Terrain* terrain)
2022-05-19 01:51:26 -07:00
{
char section[40];
2022-09-15 01:42:02 -07:00
sprintf(section, "Random Maps: %s", terrain->lookupName);
2022-05-19 01:51:26 -07:00
for (;;) {
char key[40];
sprintf(key, "map_%02d", terrain->mapsLength);
char* string;
if (!configGetString(config, section, key, &string)) {
break;
}
2022-09-15 01:42:02 -07:00
if (strParseStrFromFunc(&string, &(terrain->maps[terrain->mapsLength]), wmParseFindMapIdxMatch) == -1) {
2022-05-19 01:51:26 -07:00
return -1;
}
terrain->mapsLength++;
if (terrain->mapsLength >= 20) {
return -1;
}
}
return 0;
}
// 0x4BE61C
2022-09-15 01:42:02 -07:00
static int wmParseSubTileInfo(TileInfo* tile, int row, int column, char* string)
2022-05-19 01:51:26 -07:00
{
SubtileInfo* subtile = &(tile->subtiles[column][row]);
subtile->state = SUBTILE_STATE_UNKNOWN;
2022-09-15 01:42:02 -07:00
if (strParseStrFromFunc(&string, &(subtile->terrain), wmParseFindTerrainTypeMatch) == -1) {
2022-05-19 01:51:26 -07:00
return -1;
}
2022-09-15 01:42:02 -07:00
if (strParseStrFromList(&string, &(subtile->field_4), wmFillStrs, 9) == -1) {
2022-05-19 01:51:26 -07:00
return -1;
}
for (int index = 0; index < DAY_PART_COUNT; index++) {
2022-09-15 01:42:02 -07:00
if (strParseStrFromList(&string, &(subtile->encounterChance[index]), wmFreqStrs, ENCOUNTER_FREQUENCY_TYPE_COUNT) == -1) {
2022-05-19 01:51:26 -07:00
return -1;
}
}
2022-09-15 01:42:02 -07:00
if (strParseStrFromFunc(&string, &(subtile->encounterType), wmParseFindEncounterTypeMatch) == -1) {
2022-05-19 01:51:26 -07:00
return -1;
}
return 0;
}
// 0x4BE6D4
2022-09-15 01:42:02 -07:00
static int wmParseFindEncounterTypeMatch(char* string, int* valuePtr)
2022-05-19 01:51:26 -07:00
{
2022-09-15 01:42:02 -07:00
for (int index = 0; index < wmMaxEncounterInfoTables; index++) {
if (compat_stricmp(string, wmEncounterTableList[index].lookupName) == 0) {
2022-05-19 01:51:26 -07:00
*valuePtr = index;
return 0;
}
}
debugPrint("WorldMap Error: Couldn't find match for Encounter Type!");
*valuePtr = -1;
return -1;
}
// 0x4BE73C
2022-09-15 01:42:02 -07:00
static int wmParseFindTerrainTypeMatch(char* string, int* valuePtr)
2022-05-19 01:51:26 -07:00
{
2022-09-15 01:42:02 -07:00
for (int index = 0; index < wmMaxTerrainTypes; index++) {
Terrain* terrain = &(wmTerrainTypeList[index]);
if (compat_stricmp(string, terrain->lookupName) == 0) {
2022-05-19 01:51:26 -07:00
*valuePtr = index;
return 0;
}
}
debugPrint("WorldMap Error: Couldn't find match for Terrain Type!");
*valuePtr = -1;
return -1;
}
// 0x4BE7A4
2022-09-15 01:42:02 -07:00
static int wmParseEncounterItemType(char** stringPtr, ENC_BASE_TYPE_38_48* a2, int* a3, const char* delim)
2022-05-19 01:51:26 -07:00
{
char* string;
2022-08-29 13:58:03 -07:00
size_t v2, v3;
2022-05-19 01:51:26 -07:00
char tmp, tmp2;
int v20;
string = *stringPtr;
v20 = 0;
if (*string == '\0') {
return -1;
}
compat_strlwr(string);
2022-05-19 01:51:26 -07:00
if (*string == ',') {
string++;
*stringPtr += 1;
}
string += strspn(string, " ");
v2 = strcspn(string, ",");
tmp = string[v2];
string[v2] = '\0';
v3 = strcspn(string, delim);
tmp2 = string[v3];
string[v3] = '\0';
if (strcmp(string, "item") == 0) {
*stringPtr += v2 + 1;
v20 = 1;
2022-09-15 01:42:02 -07:00
wmParseItemType(string + v3 + 1, a2);
2022-05-19 01:51:26 -07:00
*a3 = *a3 + 1;
}
string[v3] = tmp2;
string[v2] = tmp;
return v20 ? 0 : -1;
}
// 0x4BE888
2022-09-15 01:42:02 -07:00
static int wmParseItemType(char* string, ENC_BASE_TYPE_38_48* ptr)
2022-05-19 01:51:26 -07:00
{
while (*string == ' ') {
string++;
}
ptr->minimumQuantity = 1;
ptr->maximumQuantity = 1;
ptr->isEquipped = false;
if (*string == '(') {
string++;
ptr->minimumQuantity = atoi(string);
while (isdigit(*string)) {
string++;
}
if (*string == '-') {
string++;
ptr->maximumQuantity = atoi(string);
while (isdigit(*string)) {
string++;
}
} else {
ptr->maximumQuantity = ptr->minimumQuantity;
}
if (*string == ')') {
string++;
}
}
while (*string == ' ') {
string++;
}
ptr->pid = atoi(string);
while (isdigit(*string)) {
string++;
}
while (*string == ' ') {
string++;
}
if (strstr(string, "{wielded}") != NULL
|| strstr(string, "(wielded)") != NULL
|| strstr(string, "{worn}") != NULL
|| strstr(string, "(worn)") != NULL) {
ptr->isEquipped = true;
}
return 0;
}
// 0x4BE988
2022-09-15 01:42:02 -07:00
static int wmParseConditional(char** stringPtr, const char* a2, EncounterCondition* condition)
2022-05-19 01:51:26 -07:00
{
while (condition->entriesLength < 3) {
EncounterConditionEntry* conditionEntry = &(condition->entries[condition->entriesLength]);
2022-09-15 01:42:02 -07:00
if (wmParseSubConditional(stringPtr, a2, &(conditionEntry->type), &(conditionEntry->conditionalOperator), &(conditionEntry->param), &(conditionEntry->value)) == -1) {
2022-05-19 01:51:26 -07:00
return -1;
}
condition->entriesLength++;
char* andStatement = strstr(*stringPtr, "and");
if (andStatement != NULL) {
*stringPtr = andStatement + 3;
condition->logicalOperators[condition->entriesLength - 1] = ENCOUNTER_LOGICAL_OPERATOR_AND;
continue;
}
char* orStatement = strstr(*stringPtr, "or");
if (orStatement != NULL) {
*stringPtr = orStatement + 2;
condition->logicalOperators[condition->entriesLength - 1] = ENCOUNTER_LOGICAL_OPERATOR_OR;
continue;
}
break;
}
return 0;
}
// 0x4BEA24
2022-09-15 01:42:02 -07:00
static int wmParseSubConditional(char** stringPtr, const char* a2, int* typePtr, int* operatorPtr, int* paramPtr, int* valuePtr)
2022-05-19 01:51:26 -07:00
{
char* pch;
2022-08-29 13:58:03 -07:00
size_t v2;
size_t v3;
2022-05-19 01:51:26 -07:00
char tmp;
char tmp2;
int v57;
char* string = *stringPtr;
if (string == NULL) {
return -1;
}
if (*string == '\0') {
return -1;
}
compat_strlwr(string);
2022-05-19 01:51:26 -07:00
if (*string == ',') {
string++;
*stringPtr = string;
}
string += strspn(string, " ");
v2 = strcspn(string, ",");
tmp = *(string + v2);
*(string + v2) = '\0';
v3 = strcspn(string, "(");
tmp2 = *(string + v3);
*(string + v3) = '\0';
v57 = 0;
if (strstr(string, a2) == string) {
v57 = 1;
}
*(string + v3) = tmp2;
*(string + v2) = tmp;
if (v57 == 0) {
return -1;
}
string += v3 + 1;
if (strstr(string, "rand(") == string) {
string += 5;
*typePtr = ENCOUNTER_CONDITION_TYPE_RANDOM;
*operatorPtr = ENCOUNTER_CONDITIONAL_OPERATOR_NONE;
*paramPtr = atoi(string);
pch = strstr(string, ")");
if (pch != NULL) {
string = pch + 1;
}
pch = strstr(string, ")");
if (pch != NULL) {
string = pch + 1;
}
pch = strstr(string, ",");
if (pch != NULL) {
string = pch + 1;
}
*stringPtr = string;
return 0;
} else if (strstr(string, "global(") == string) {
string += 7;
*typePtr = ENCOUNTER_CONDITION_TYPE_GLOBAL;
*paramPtr = atoi(string);
pch = strstr(string, ")");
if (pch != NULL) {
string = pch + 1;
}
while (*string == ' ') {
string++;
}
2022-09-15 01:42:02 -07:00
if (wmParseConditionalEval(&string, operatorPtr) != -1) {
2022-05-19 01:51:26 -07:00
*valuePtr = atoi(string);
pch = strstr(string, ")");
if (pch != NULL) {
string = pch + 1;
}
pch = strstr(string, ",");
if (pch != NULL) {
string = pch + 1;
}
*stringPtr = string;
return 0;
}
} else if (strstr(string, "player(level)") == string) {
string += 13;
*typePtr = ENCOUNTER_CONDITION_TYPE_PLAYER;
while (*string == ' ') {
string++;
}
2022-09-15 01:42:02 -07:00
if (wmParseConditionalEval(&string, operatorPtr) != -1) {
2022-05-19 01:51:26 -07:00
*valuePtr = atoi(string);
pch = strstr(string, ")");
if (pch != NULL) {
string = pch + 1;
}
pch = strstr(string, ",");
if (pch != NULL) {
string = pch + 1;
}
*stringPtr = string;
return 0;
}
} else if (strstr(string, "days_played") == string) {
string += 11;
*typePtr = ENCOUNTER_CONDITION_TYPE_DAYS_PLAYED;
while (*string == ' ') {
string++;
}
2022-09-15 01:42:02 -07:00
if (wmParseConditionalEval(&string, operatorPtr) != -1) {
2022-05-19 01:51:26 -07:00
*valuePtr = atoi(string);
pch = strstr(string, ")");
if (pch != NULL) {
string = pch + 1;
}
pch = strstr(string, ",");
if (pch != NULL) {
string = pch + 1;
}
*stringPtr = string;
return 0;
}
} else if (strstr(string, "time_of_day") == string) {
string += 11;
*typePtr = ENCOUNTER_CONDITION_TYPE_TIME_OF_DAY;
while (*string == ' ') {
string++;
}
2022-09-15 01:42:02 -07:00
if (wmParseConditionalEval(&string, operatorPtr) != -1) {
2022-05-19 01:51:26 -07:00
*valuePtr = atoi(string);
pch = strstr(string, ")");
if (pch != NULL) {
string = pch + 1;
}
pch = strstr(string, ",");
if (pch != NULL) {
string = pch + 1;
}
*stringPtr = string;
return 0;
}
} else if (strstr(string, "enctr(num_critters)") == string) {
string += 19;
*typePtr = ENCOUNTER_CONDITION_TYPE_NUMBER_OF_CRITTERS;
while (*string == ' ') {
string++;
}
2022-09-15 01:42:02 -07:00
if (wmParseConditionalEval(&string, operatorPtr) != -1) {
2022-05-19 01:51:26 -07:00
*valuePtr = atoi(string);
pch = strstr(string, ")");
if (pch != NULL) {
string = pch + 1;
}
pch = strstr(string, ",");
if (pch != NULL) {
string = pch + 1;
}
*stringPtr = string;
return 0;
}
} else {
*stringPtr = string;
return 0;
}
return -1;
}
// 0x4BEEBC
2022-09-15 01:42:02 -07:00
static int wmParseConditionalEval(char** stringPtr, int* conditionalOperatorPtr)
2022-05-19 01:51:26 -07:00
{
char* string = *stringPtr;
*conditionalOperatorPtr = ENCOUNTER_CONDITIONAL_OPERATOR_NONE;
int index;
for (index = 0; index < ENCOUNTER_CONDITIONAL_OPERATOR_COUNT; index++) {
2022-09-15 01:42:02 -07:00
if (strstr(string, wmConditionalOpStrs[index]) == string) {
2022-05-19 01:51:26 -07:00
break;
}
}
if (index == ENCOUNTER_CONDITIONAL_OPERATOR_COUNT) {
return -1;
}
*conditionalOperatorPtr = index;
2022-09-15 01:42:02 -07:00
string += strlen(wmConditionalOpStrs[index]);
2022-05-19 01:51:26 -07:00
while (*string == ' ') {
string++;
}
*stringPtr = string;
return 0;
}
// NOTE: Inlined.
//
// 0x4BEF1C
2022-09-15 01:42:02 -07:00
static int wmAreaSlotInit(CityInfo* area)
2022-05-19 01:51:26 -07:00
{
area->name[0] = '\0';
2022-09-15 01:42:02 -07:00
area->areaId = -1;
2022-05-19 01:51:26 -07:00
area->x = 0;
area->y = 0;
area->size = CITY_SIZE_LARGE;
2022-09-15 01:42:02 -07:00
area->state = CITY_STATE_UNKNOWN;
area->lockState = LOCK_STATE_UNLOCKED;
area->visitedState = 0;
2022-05-19 01:51:26 -07:00
area->mapFid = -1;
area->labelFid = -1;
area->entrancesLength = 0;
return 0;
}
// 0x4BEF68
2022-09-15 01:42:02 -07:00
static int wmAreaInit()
2022-05-19 01:51:26 -07:00
{
Config cfg;
char section[40];
char key[40];
int area_idx;
int num;
char* str;
CityInfo* cities;
CityInfo* city;
EntranceInfo* entrance;
2022-09-15 01:42:02 -07:00
if (wmMapInit() == -1) {
2022-05-19 01:51:26 -07:00
return -1;
}
2022-07-06 05:05:32 -07:00
if (!configInit(&cfg)) {
2022-05-19 01:51:26 -07:00
return -1;
}
if (configRead(&cfg, "data\\city.txt", true)) {
area_idx = 0;
do {
sprintf(section, "Area %02d", area_idx);
if (!configGetInt(&cfg, section, "townmap_art_idx", &num)) {
break;
}
2022-09-15 01:42:02 -07:00
wmMaxAreaNum++;
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
cities = (CityInfo*)internal_realloc(wmAreaInfoList, sizeof(CityInfo) * wmMaxAreaNum);
2022-05-19 01:51:26 -07:00
if (cities == NULL) {
showMesageBox("\nwmConfigInit::Error loading areas!");
exit(1);
}
2022-09-15 01:42:02 -07:00
wmAreaInfoList = cities;
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
city = &(cities[wmMaxAreaNum - 1]);
2022-05-19 01:51:26 -07:00
// NOTE: Uninline.
2022-09-15 01:42:02 -07:00
wmAreaSlotInit(city);
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
city->areaId = area_idx;
2022-05-19 01:51:26 -07:00
if (num != -1) {
num = buildFid(OBJ_TYPE_INTERFACE, num, 0, 0, 0);
2022-05-19 01:51:26 -07:00
}
city->mapFid = num;
if (configGetInt(&cfg, section, "townmap_label_art_idx", &num)) {
if (num != -1) {
num = buildFid(OBJ_TYPE_INTERFACE, num, 0, 0, 0);
2022-05-19 01:51:26 -07:00
}
city->labelFid = num;
}
if (!configGetString(&cfg, section, "area_name", &str)) {
showMesageBox("\nwmConfigInit::Error loading areas!");
exit(1);
}
strncpy(city->name, str, 40);
if (!configGetString(&cfg, section, "world_pos", &str)) {
showMesageBox("\nwmConfigInit::Error loading areas!");
exit(1);
}
if (strParseInt(&str, &(city->x)) == -1) {
return -1;
}
if (strParseInt(&str, &(city->y)) == -1) {
return -1;
}
if (!configGetString(&cfg, section, "start_state", &str)) {
showMesageBox("\nwmConfigInit::Error loading areas!");
exit(1);
}
2022-09-15 01:42:02 -07:00
if (strParseStrFromList(&str, &(city->state), wmStateStrs, 2) == -1) {
2022-05-19 01:51:26 -07:00
return -1;
}
if (configGetString(&cfg, section, "lock_state", &str)) {
2022-09-15 01:42:02 -07:00
if (strParseStrFromList(&str, &(city->lockState), wmStateStrs, 2) == -1) {
2022-05-19 01:51:26 -07:00
return -1;
}
}
if (!configGetString(&cfg, section, "size", &str)) {
showMesageBox("\nwmConfigInit::Error loading areas!");
exit(1);
}
2022-09-15 01:42:02 -07:00
if (strParseStrFromList(&str, &(city->size), wmAreaSizeStrs, 3) == -1) {
2022-05-19 01:51:26 -07:00
return -1;
}
while (city->entrancesLength < ENTRANCE_LIST_CAPACITY) {
sprintf(key, "entrance_%d", city->entrancesLength);
if (!configGetString(&cfg, section, key, &str)) {
break;
}
entrance = &(city->entrances[city->entrancesLength]);
// NOTE: Uninline.
2022-09-15 01:42:02 -07:00
wmEntranceSlotInit(entrance);
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
if (strParseStrFromList(&str, &(entrance->state), wmStateStrs, 2) == -1) {
2022-05-19 01:51:26 -07:00
return -1;
}
if (strParseInt(&str, &(entrance->x)) == -1) {
return -1;
}
if (strParseInt(&str, &(entrance->y)) == -1) {
return -1;
}
2022-09-15 01:42:02 -07:00
if (strParseStrFromFunc(&str, &(entrance->map), &wmParseFindMapIdxMatch) == -1) {
2022-05-19 01:51:26 -07:00
return -1;
}
if (strParseInt(&str, &(entrance->elevation)) == -1) {
return -1;
}
if (strParseInt(&str, &(entrance->tile)) == -1) {
return -1;
}
if (strParseInt(&str, &(entrance->rotation)) == -1) {
return -1;
}
city->entrancesLength++;
}
area_idx++;
} while (area_idx < 5000);
}
configFree(&cfg);
2022-09-15 01:42:02 -07:00
if (wmMaxAreaNum != CITY_COUNT) {
2022-05-19 01:51:26 -07:00
showMesageBox("\nwmAreaInit::Error loading Cities!");
exit(1);
}
return 0;
}
// 0x4BF3E0
2022-09-15 01:42:02 -07:00
static int wmParseFindMapIdxMatch(char* string, int* valuePtr)
2022-05-19 01:51:26 -07:00
{
2022-09-15 01:42:02 -07:00
for (int index = 0; index < wmMaxMapNum; index++) {
MapInfo* map = &(wmMapInfoList[index]);
if (compat_stricmp(string, map->lookupName) == 0) {
2022-05-19 01:51:26 -07:00
*valuePtr = index;
return 0;
}
}
debugPrint("\nWorldMap Error: Couldn't find match for Map Index!");
*valuePtr = -1;
return -1;
}
// NOTE: Inlined.
//
// 0x4BF448
2022-09-15 01:42:02 -07:00
static int wmEntranceSlotInit(EntranceInfo* entrance)
2022-05-19 01:51:26 -07:00
{
entrance->state = 0;
entrance->x = 0;
entrance->y = 0;
entrance->map = -1;
entrance->elevation = 0;
entrance->tile = 0;
entrance->rotation = 0;
return 0;
}
// 0x4BF47C
2022-09-15 01:42:02 -07:00
static int wmMapSlotInit(MapInfo* map)
2022-05-19 01:51:26 -07:00
{
map->lookupName[0] = '\0';
map->field_28 = -1;
map->field_2C = -1;
map->mapFileName[0] = '\0';
map->music[0] = '\0';
map->flags = 0x3F;
map->ambientSoundEffectsLength = 0;
map->startPointsLength = 0;
return 0;
}
// 0x4BF4BC
2022-09-15 01:42:02 -07:00
static int wmMapInit()
2022-05-19 01:51:26 -07:00
{
char* str;
int num;
MapInfo* maps;
MapInfo* map;
int j;
MapAmbientSoundEffectInfo* sfx;
MapStartPointInfo* rsp;
Config config;
if (!configInit(&config)) {
return -1;
}
if (configRead(&config, "data\\maps.txt", true)) {
2022-09-15 01:42:02 -07:00
for (int mapIdx = 0;; mapIdx++) {
2022-05-19 01:51:26 -07:00
char section[40];
2022-09-15 01:42:02 -07:00
sprintf(section, "Map %03d", mapIdx);
2022-05-19 01:51:26 -07:00
if (!configGetString(&config, section, "lookup_name", &str)) {
break;
}
2022-09-15 01:42:02 -07:00
wmMaxMapNum++;
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
maps = (MapInfo*)internal_realloc(wmMapInfoList, sizeof(*wmMapInfoList) * wmMaxMapNum);
2022-05-19 01:51:26 -07:00
if (maps == NULL) {
showMesageBox("\nwmConfigInit::Error loading maps!");
exit(1);
}
2022-09-15 01:42:02 -07:00
wmMapInfoList = maps;
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
map = &(maps[wmMaxMapNum - 1]);
wmMapSlotInit(map);
2022-05-19 01:51:26 -07:00
strncpy(map->lookupName, str, 40);
if (!configGetString(&config, section, "map_name", &str)) {
showMesageBox("\nwmConfigInit::Error loading maps!");
exit(1);
}
compat_strlwr(str);
2022-05-19 01:51:26 -07:00
strncpy(map->mapFileName, str, 40);
if (configGetString(&config, section, "music", &str)) {
strncpy(map->music, str, 40);
}
if (configGetString(&config, section, "ambient_sfx", &str)) {
while (str) {
sfx = &(map->ambientSoundEffects[map->ambientSoundEffectsLength]);
if (strParseKeyValue(&str, sfx->name, &(sfx->chance), ":") == -1) {
return -1;
}
map->ambientSoundEffectsLength++;
if (*str == '\0') {
str = NULL;
}
if (map->ambientSoundEffectsLength >= MAP_AMBIENT_SOUND_EFFECTS_CAPACITY) {
if (str != NULL) {
2022-09-15 01:42:02 -07:00
debugPrint("\nwmMapInit::Error reading ambient sfx. Too many! Str: %s, MapIdx: %d", map->lookupName, mapIdx);
2022-05-19 01:51:26 -07:00
str = NULL;
}
}
}
}
if (configGetString(&config, section, "saved", &str)) {
2022-09-15 01:42:02 -07:00
if (strParseStrFromList(&str, &num, wmYesNoStrs, 2) == -1) {
2022-05-19 01:51:26 -07:00
return -1;
}
2022-09-01 08:41:37 -07:00
// NOTE: Uninline.
wmSetFlags(&(map->flags), MAP_SAVED, num);
2022-05-19 01:51:26 -07:00
}
if (configGetString(&config, section, "dead_bodies_age", &str)) {
2022-09-15 01:42:02 -07:00
if (strParseStrFromList(&str, &num, wmYesNoStrs, 2) == -1) {
2022-05-19 01:51:26 -07:00
return -1;
}
2022-09-01 08:41:37 -07:00
// NOTE: Uninline.
wmSetFlags(&(map->flags), MAP_DEAD_BODIES_AGE, num);
2022-05-19 01:51:26 -07:00
}
if (configGetString(&config, section, "can_rest_here", &str)) {
2022-09-15 01:42:02 -07:00
if (strParseStrFromList(&str, &num, wmYesNoStrs, 2) == -1) {
2022-05-19 01:51:26 -07:00
return -1;
}
2022-09-01 08:41:37 -07:00
// NOTE: Uninline.
wmSetFlags(&(map->flags), MAP_CAN_REST_ELEVATION_0, num);
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
if (strParseStrFromList(&str, &num, wmYesNoStrs, 2) == -1) {
2022-05-19 01:51:26 -07:00
return -1;
}
2022-09-01 08:41:37 -07:00
// NOTE: Uninline.
wmSetFlags(&(map->flags), MAP_CAN_REST_ELEVATION_1, num);
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
if (strParseStrFromList(&str, &num, wmYesNoStrs, 2) == -1) {
2022-05-19 01:51:26 -07:00
return -1;
}
2022-09-01 08:41:37 -07:00
// NOTE: Uninline.
wmSetFlags(&(map->flags), MAP_CAN_REST_ELEVATION_2, num);
2022-05-19 01:51:26 -07:00
}
2022-08-29 06:08:23 -07:00
if (configGetString(&config, section, "pipboy_active", &str)) {
2022-09-15 01:42:02 -07:00
if (strParseStrFromList(&str, &num, wmYesNoStrs, 2) == -1) {
2022-05-19 01:51:26 -07:00
return -1;
}
2022-09-01 08:41:37 -07:00
// NOTE: Uninline.
wmSetFlags(&(map->flags), MAP_PIPBOY_ACTIVE, num);
2022-05-19 01:51:26 -07:00
}
2022-08-29 06:07:34 -07:00
// SFALL: Pip-boy automaps patch.
if (configGetString(&config, section, "automap", &str)) {
2022-09-15 01:42:02 -07:00
if (strParseStrFromList(&str, &num, wmYesNoStrs, 2) == -1) {
2022-08-29 06:07:34 -07:00
return -1;
}
2022-09-15 01:42:02 -07:00
automapSetDisplayMap(mapIdx, num);
2022-08-29 06:07:34 -07:00
}
2022-05-19 01:51:26 -07:00
if (configGetString(&config, section, "random_start_point_0", &str)) {
j = 0;
while (str != NULL) {
while (*str != '\0') {
if (map->startPointsLength >= MAP_STARTING_POINTS_CAPACITY) {
break;
}
rsp = &(map->startPoints[map->startPointsLength]);
// NOTE: Uninline.
2022-09-15 01:42:02 -07:00
wmRStartSlotInit(rsp);
2022-05-19 01:51:26 -07:00
strParseIntWithKey(&str, "elev", &(rsp->elevation), ":");
strParseIntWithKey(&str, "tile_num", &(rsp->tile), ":");
map->startPointsLength++;
}
char key[40];
sprintf(key, "random_start_point_%1d", ++j);
if (!configGetString(&config, section, key, &str)) {
str = NULL;
}
}
}
}
}
configFree(&config);
return 0;
}
// NOTE: Inlined.
//
// 0x4BF954
2022-09-15 01:42:02 -07:00
static int wmRStartSlotInit(MapStartPointInfo* rsp)
2022-05-19 01:51:26 -07:00
{
rsp->elevation = 0;
rsp->tile = -1;
rsp->field_8 = -1;
return 0;
}
// 0x4BF96C
2022-09-15 01:42:02 -07:00
int wmMapMaxCount()
2022-05-19 01:51:26 -07:00
{
2022-09-15 01:42:02 -07:00
return wmMaxMapNum;
2022-05-19 01:51:26 -07:00
}
// 0x4BF974
2022-09-15 01:42:02 -07:00
int wmMapIdxToName(int mapIdx, char* dest)
2022-05-19 01:51:26 -07:00
{
2022-09-15 01:42:02 -07:00
if (mapIdx == -1 || mapIdx > wmMaxMapNum) {
2022-05-19 01:51:26 -07:00
dest[0] = '\0';
return -1;
}
2022-09-15 01:42:02 -07:00
sprintf(dest, "%s.MAP", wmMapInfoList[mapIdx].mapFileName);
2022-05-19 01:51:26 -07:00
return 0;
}
// 0x4BF9BC
2022-09-15 01:42:02 -07:00
int wmMapMatchNameToIdx(char* name)
2022-05-19 01:51:26 -07:00
{
compat_strlwr(name);
2022-05-19 01:51:26 -07:00
char* pch = name;
while (*pch != '\0' && *pch != '.') {
pch++;
}
bool truncated = false;
if (*pch != '\0') {
*pch = '\0';
truncated = true;
}
int map = -1;
2022-09-15 01:42:02 -07:00
for (int index = 0; index < wmMaxMapNum; index++) {
if (strcmp(wmMapInfoList[index].mapFileName, name) == 0) {
2022-05-19 01:51:26 -07:00
map = index;
break;
}
}
if (truncated) {
*pch = '.';
}
return map;
}
// 0x4BFA44
2022-09-15 01:42:02 -07:00
bool wmMapIdxIsSaveable(int mapIdx)
2022-05-19 01:51:26 -07:00
{
2022-09-15 01:42:02 -07:00
return (wmMapInfoList[mapIdx].flags & MAP_SAVED) != 0;
2022-05-19 01:51:26 -07:00
}
// 0x4BFA64
2022-09-15 01:42:02 -07:00
bool wmMapIsSaveable()
2022-05-19 01:51:26 -07:00
{
2022-09-15 01:42:02 -07:00
return (wmMapInfoList[gMapHeader.field_34].flags & MAP_SAVED) != 0;
2022-05-19 01:51:26 -07:00
}
// 0x4BFA90
2022-09-15 01:42:02 -07:00
bool wmMapDeadBodiesAge()
2022-05-19 01:51:26 -07:00
{
2022-09-15 01:42:02 -07:00
return (wmMapInfoList[gMapHeader.field_34].flags & MAP_DEAD_BODIES_AGE) != 0;
2022-05-19 01:51:26 -07:00
}
// 0x4BFABC
2022-09-15 01:42:02 -07:00
bool wmMapCanRestHere(int elevation)
2022-05-19 01:51:26 -07:00
{
int flags[3];
// NOTE: I'm not sure why they're copied.
memcpy(flags, _can_rest_here, sizeof(flags));
2022-09-15 01:42:02 -07:00
MapInfo* map = &(wmMapInfoList[gMapHeader.field_34]);
2022-05-19 01:51:26 -07:00
return (map->flags & flags[elevation]) != 0;
}
// 0x4BFAFC
2022-09-15 01:42:02 -07:00
bool wmMapPipboyActive()
2022-05-19 01:51:26 -07:00
{
return gameMovieIsSeen(MOVIE_VSUIT);
}
// 0x4BFB08
2022-09-15 01:42:02 -07:00
int wmMapMarkVisited(int mapIdx)
2022-05-19 01:51:26 -07:00
{
2022-09-15 01:42:02 -07:00
if (mapIdx < 0 || mapIdx >= wmMaxMapNum) {
2022-05-19 01:51:26 -07:00
return -1;
}
2022-09-15 01:42:02 -07:00
MapInfo* map = &(wmMapInfoList[mapIdx]);
2022-05-19 01:51:26 -07:00
if ((map->flags & MAP_SAVED) == 0) {
return 0;
}
2022-09-15 01:42:02 -07:00
int areaIdx;
if (wmMatchAreaContainingMapIdx(mapIdx, &areaIdx) == -1) {
2022-05-19 01:51:26 -07:00
return -1;
}
2022-09-01 08:41:37 -07:00
// NOTE: Uninline.
2022-09-15 01:42:02 -07:00
wmAreaMarkVisited(areaIdx);
2022-05-19 01:51:26 -07:00
return 0;
}
// 0x4BFB64
2022-09-15 01:42:02 -07:00
static int wmMatchEntranceFromMap(int areaIdx, int mapIdx, int* entranceIdxPtr)
2022-05-19 01:51:26 -07:00
{
2022-09-15 01:42:02 -07:00
CityInfo* city = &(wmAreaInfoList[areaIdx]);
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
for (int entranceIdx = 0; entranceIdx < city->entrancesLength; entranceIdx++) {
EntranceInfo* entrance = &(city->entrances[entranceIdx]);
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
if (mapIdx == entrance->map) {
*entranceIdxPtr = entranceIdx;
2022-05-19 01:51:26 -07:00
return 0;
}
}
2022-09-15 01:42:02 -07:00
*entranceIdxPtr = -1;
2022-05-19 01:51:26 -07:00
return -1;
}
// 0x4BFBE8
2022-09-15 01:42:02 -07:00
static int wmMatchEntranceElevFromMap(int areaIdx, int mapIdx, int elevation, int* entranceIdxPtr)
2022-05-19 01:51:26 -07:00
{
2022-09-15 01:42:02 -07:00
CityInfo* city = &(wmAreaInfoList[areaIdx]);
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
for (int entranceIdx = 0; entranceIdx < city->entrancesLength; entranceIdx++) {
EntranceInfo* entrance = &(city->entrances[entranceIdx]);
if (entrance->map == mapIdx) {
2022-05-19 01:51:26 -07:00
if (elevation == -1 || entrance->elevation == -1 || elevation == entrance->elevation) {
2022-09-15 01:42:02 -07:00
*entranceIdxPtr = entranceIdx;
2022-05-19 01:51:26 -07:00
return 0;
}
}
}
2022-09-15 01:42:02 -07:00
*entranceIdxPtr = -1;
2022-05-19 01:51:26 -07:00
return -1;
}
// 0x4BFC7C
2022-09-15 01:42:02 -07:00
static int wmMatchAreaFromMap(int mapIdx, int* areaIdxPtr)
2022-05-19 01:51:26 -07:00
{
2022-09-15 01:42:02 -07:00
for (int areaIdx = 0; areaIdx < wmMaxAreaNum; areaIdx++) {
CityInfo* city = &(wmAreaInfoList[areaIdx]);
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
for (int entranceIdx = 0; entranceIdx < city->entrancesLength; entranceIdx++) {
EntranceInfo* entrance = &(city->entrances[entranceIdx]);
if (mapIdx == entrance->map) {
*areaIdxPtr = areaIdx;
2022-05-19 01:51:26 -07:00
return 0;
}
}
}
2022-09-15 01:42:02 -07:00
*areaIdxPtr = -1;
2022-05-19 01:51:26 -07:00
return -1;
}
// Mark map entrance.
//
// 0x4BFD50
2022-09-15 01:42:02 -07:00
int wmMapMarkMapEntranceState(int mapIdx, int elevation, int state)
2022-05-19 01:51:26 -07:00
{
2022-09-15 01:42:02 -07:00
if (mapIdx < 0 || mapIdx >= wmMaxMapNum) {
2022-05-19 01:51:26 -07:00
return -1;
}
2022-09-15 01:42:02 -07:00
MapInfo* map = &(wmMapInfoList[mapIdx]);
2022-05-19 01:51:26 -07:00
if ((map->flags & MAP_SAVED) == 0) {
return -1;
}
2022-09-15 01:42:02 -07:00
int areaIdx;
if (wmMatchAreaContainingMapIdx(mapIdx, &areaIdx) == -1) {
2022-05-19 01:51:26 -07:00
return -1;
}
2022-09-15 01:42:02 -07:00
int entranceIdx;
if (wmMatchEntranceElevFromMap(areaIdx, mapIdx, elevation, &entranceIdx) == -1) {
2022-05-19 01:51:26 -07:00
return -1;
}
2022-09-15 01:42:02 -07:00
CityInfo* city = &(wmAreaInfoList[areaIdx]);
EntranceInfo* entrance = &(city->entrances[entranceIdx]);
2022-05-19 01:51:26 -07:00
entrance->state = state;
return 0;
}
// 0x4BFE0C
2022-09-15 01:42:02 -07:00
void wmWorldMap()
2022-05-19 01:51:26 -07:00
{
2022-09-15 01:42:02 -07:00
wmWorldMapFunc(0);
2022-05-19 01:51:26 -07:00
}
// 0x4BFE10
2022-09-15 01:42:02 -07:00
static int wmWorldMapFunc(int a1)
2022-05-19 01:51:26 -07:00
{
2022-09-15 01:42:02 -07:00
if (wmInterfaceInit() == -1) {
wmInterfaceExit();
2022-05-19 01:51:26 -07:00
return -1;
}
2022-09-15 01:42:02 -07:00
wmMatchWorldPosToArea(wmGenData.worldPosX, wmGenData.worldPosY, &(wmGenData.currentAreaId));
2022-05-19 01:51:26 -07:00
unsigned int v24 = 0;
int map = -1;
int v25 = 0;
int rc = 0;
for (;;) {
2022-10-07 14:54:27 -07:00
sharedFpsLimiter.mark();
2022-10-05 00:11:47 -07:00
int keyCode = inputGetInput();
unsigned int tick = getTicks();
2022-05-19 01:51:26 -07:00
int mouseX;
int mouseY;
2022-09-15 01:42:02 -07:00
mouseGetPositionInWindow(wmBkWin, &mouseX, &mouseY);
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
int v4 = wmWorldOffsetX + mouseX - WM_VIEW_X;
int v5 = wmWorldOffsetY + mouseY - WM_VIEW_Y;
2022-05-19 01:51:26 -07:00
if (keyCode == KEY_CTRL_Q || keyCode == KEY_CTRL_X || keyCode == KEY_F10) {
showQuitConfirmationDialog();
}
2022-09-01 08:41:37 -07:00
// NOTE: Uninline.
wmCheckGameEvents();
2022-05-19 01:51:26 -07:00
if (_game_user_wants_to_quit != 0) {
break;
}
int mouseEvent = mouseGetEvent();
2022-09-15 01:42:02 -07:00
if (wmGenData.isWalking) {
wmPartyWalkingStep();
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
if (wmGenData.isInCar) {
wmPartyWalkingStep();
wmPartyWalkingStep();
wmPartyWalkingStep();
2022-05-19 01:51:26 -07:00
if (gameGetGlobalVar(GVAR_CAR_BLOWER)) {
2022-09-15 01:42:02 -07:00
wmPartyWalkingStep();
2022-05-19 01:51:26 -07:00
}
if (gameGetGlobalVar(GVAR_NEW_RENO_CAR_UPGRADE)) {
2022-09-15 01:42:02 -07:00
wmPartyWalkingStep();
2022-05-19 01:51:26 -07:00
}
if (gameGetGlobalVar(GVAR_NEW_RENO_SUPER_CAR)) {
2022-09-15 01:42:02 -07:00
wmPartyWalkingStep();
wmPartyWalkingStep();
wmPartyWalkingStep();
2022-05-19 01:51:26 -07:00
}
2022-09-15 01:42:02 -07:00
wmGenData.carImageCurrentFrameIndex++;
if (wmGenData.carImageCurrentFrameIndex >= artGetFrameCount(wmGenData.carImageFrm)) {
wmGenData.carImageCurrentFrameIndex = 0;
2022-05-19 01:51:26 -07:00
}
2022-09-15 01:42:02 -07:00
wmCarUseGas(100);
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
if (wmGenData.carFuel <= 0) {
wmGenData.walkDestinationX = 0;
wmGenData.walkDestinationY = 0;
wmGenData.isWalking = false;
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
wmMatchWorldPosToArea(v4, v5, &(wmGenData.currentAreaId));
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
wmGenData.isInCar = false;
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
if (wmGenData.currentAreaId == -1) {
wmGenData.currentCarAreaId = CITY_CAR_OUT_OF_GAS;
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
CityInfo* city = &(wmAreaInfoList[CITY_CAR_OUT_OF_GAS]);
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
CitySizeDescription* citySizeDescription = &(wmSphereData[city->size]);
int worldmapX = wmGenData.worldPosX + wmGenData.hotspotNormalFrmImage.getWidth() / 2 + citySizeDescription->frmImage.getWidth() / 2;
int worldmapY = wmGenData.worldPosY + wmGenData.hotspotNormalFrmImage.getHeight() / 2 + citySizeDescription->frmImage.getHeight() / 2;
2022-09-15 01:42:02 -07:00
wmAreaSetWorldPos(CITY_CAR_OUT_OF_GAS, worldmapX, worldmapY);
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
city->state = CITY_STATE_KNOWN;
city->visitedState = 1;
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
wmGenData.currentAreaId = CITY_CAR_OUT_OF_GAS;
2022-05-19 01:51:26 -07:00
} else {
2022-09-15 01:42:02 -07:00
wmGenData.currentCarAreaId = wmGenData.currentAreaId;
2022-05-19 01:51:26 -07:00
}
debugPrint("\nRan outta gas!");
}
}
2022-09-15 01:42:02 -07:00
wmInterfaceRefresh();
2022-05-19 01:51:26 -07:00
if (getTicksBetween(tick, v24) > 1000) {
if (_partyMemberRestingHeal(3)) {
interfaceRenderHitPoints(false);
v24 = tick;
}
}
2022-09-15 01:42:02 -07:00
wmMarkSubTileRadiusVisited(wmGenData.worldPosX, wmGenData.worldPosY);
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
if (wmGenData.walkDistance <= 0) {
wmGenData.isWalking = false;
wmMatchWorldPosToArea(wmGenData.worldPosX, wmGenData.worldPosY, &(wmGenData.currentAreaId));
2022-05-19 01:51:26 -07:00
}
2022-09-15 01:42:02 -07:00
wmInterfaceRefresh();
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
if (wmGameTimeIncrement(18000)) {
2022-05-19 01:51:26 -07:00
if (_game_user_wants_to_quit != 0) {
break;
}
}
2022-09-15 01:42:02 -07:00
if (wmGenData.isWalking) {
if (wmRndEncounterOccurred()) {
if (wmGenData.encounterMapId != -1) {
if (wmGenData.isInCar) {
wmMatchAreaContainingMapIdx(wmGenData.encounterMapId, &(wmGenData.currentCarAreaId));
2022-05-19 01:51:26 -07:00
}
2022-09-15 01:42:02 -07:00
mapLoadById(wmGenData.encounterMapId);
2022-05-19 01:51:26 -07:00
}
break;
}
}
}
if ((mouseEvent & MOUSE_EVENT_LEFT_BUTTON_DOWN) != 0 && (mouseEvent & MOUSE_EVENT_LEFT_BUTTON_REPEAT) == 0) {
2022-09-15 01:42:02 -07:00
if (mouseHitTestInWindow(wmBkWin, WM_VIEW_X, WM_VIEW_Y, 472, 465)) {
if (!wmGenData.isWalking && !wmGenData.mousePressed && abs(wmGenData.worldPosX - v4) < 5 && abs(wmGenData.worldPosY - v5) < 5) {
wmGenData.mousePressed = true;
wmInterfaceRefresh();
2022-10-07 14:54:27 -07:00
renderPresent();
2022-05-19 01:51:26 -07:00
}
} else {
continue;
}
}
if ((mouseEvent & MOUSE_EVENT_LEFT_BUTTON_UP) != 0) {
2022-09-15 01:42:02 -07:00
if (wmGenData.mousePressed) {
wmGenData.mousePressed = false;
wmInterfaceRefresh();
if (abs(wmGenData.worldPosX - v4) < 5 && abs(wmGenData.worldPosY - v5) < 5) {
if (wmGenData.currentAreaId != -1) {
CityInfo* city = &(wmAreaInfoList[wmGenData.currentAreaId]);
if (city->visitedState == 2 && city->mapFid != -1) {
if (wmTownMapFunc(&map) == -1) {
2022-05-19 01:51:26 -07:00
v25 = -1;
break;
}
} else {
2022-09-15 01:42:02 -07:00
if (wmAreaFindFirstValidMap(&map) == -1) {
2022-05-19 01:51:26 -07:00
v25 = -1;
break;
}
2022-09-15 01:42:02 -07:00
city->visitedState = 2;
2022-05-19 01:51:26 -07:00
}
} else {
map = 0;
}
if (map != -1) {
2022-09-15 01:42:02 -07:00
if (wmGenData.isInCar) {
wmGenData.isInCar = false;
if (wmGenData.currentAreaId == -1) {
wmMatchAreaContainingMapIdx(map, &(wmGenData.currentCarAreaId));
2022-05-19 01:51:26 -07:00
} else {
2022-09-15 01:42:02 -07:00
wmGenData.currentCarAreaId = wmGenData.currentAreaId;
2022-05-19 01:51:26 -07:00
}
}
mapLoadById(map);
break;
}
}
} else {
2022-09-15 01:42:02 -07:00
if (mouseHitTestInWindow(wmBkWin, WM_VIEW_X, WM_VIEW_Y, 472, 465)) {
wmPartyInitWalking(v4, v5);
2022-05-19 01:51:26 -07:00
}
2022-09-15 01:42:02 -07:00
wmGenData.mousePressed = false;
2022-05-19 01:51:26 -07:00
}
}
2022-09-01 08:41:37 -07:00
// NOTE: Uninline.
wmInterfaceScrollTabsUpdate();
2022-05-19 01:51:26 -07:00
if (keyCode == KEY_UPPERCASE_T || keyCode == KEY_LOWERCASE_T) {
2022-09-15 01:42:02 -07:00
if (!wmGenData.isWalking && wmGenData.currentAreaId != -1) {
CityInfo* city = &(wmAreaInfoList[wmGenData.currentAreaId]);
if (city->visitedState == 2 && city->mapFid != -1) {
if (wmTownMapFunc(&map) == -1) {
2022-05-19 01:51:26 -07:00
rc = -1;
}
if (map != -1) {
2022-09-15 01:42:02 -07:00
if (wmGenData.isInCar) {
wmMatchAreaContainingMapIdx(map, &(wmGenData.currentCarAreaId));
2022-05-19 01:51:26 -07:00
}
mapLoadById(map);
}
}
}
} else if (keyCode == KEY_HOME) {
2022-09-15 01:42:02 -07:00
wmInterfaceCenterOnParty();
2022-05-19 01:51:26 -07:00
} else if (keyCode == KEY_ARROW_UP) {
2022-09-01 08:41:37 -07:00
// NOTE: Uninline.
wmInterfaceScroll(0, -1, NULL);
2022-05-19 01:51:26 -07:00
} else if (keyCode == KEY_ARROW_LEFT) {
2022-09-01 08:41:37 -07:00
// NOTE: Uninline.
wmInterfaceScroll(-1, 0, NULL);
2022-05-19 01:51:26 -07:00
} else if (keyCode == KEY_ARROW_DOWN) {
2022-09-01 08:41:37 -07:00
// NOTE: Uninline.
wmInterfaceScroll(0, 1, NULL);
2022-05-19 01:51:26 -07:00
} else if (keyCode == KEY_ARROW_RIGHT) {
2022-09-01 08:41:37 -07:00
// NOTE: Uninline.
wmInterfaceScroll(1, 0, NULL);
2022-05-19 01:51:26 -07:00
} else if (keyCode == KEY_CTRL_ARROW_UP) {
2022-09-15 01:42:02 -07:00
wmInterfaceScrollTabsStart(-27);
2022-05-19 01:51:26 -07:00
} else if (keyCode == KEY_CTRL_ARROW_DOWN) {
2022-09-15 01:42:02 -07:00
wmInterfaceScrollTabsStart(27);
2022-05-19 01:51:26 -07:00
} else if (keyCode >= KEY_CTRL_F1 && keyCode <= KEY_CTRL_F7) {
2022-09-15 01:42:02 -07:00
int quickDestinationIndex = wmGenData.tabsOffsetY / 27 + (keyCode - KEY_CTRL_F1);
if (quickDestinationIndex < wmLabelCount) {
int areaIdx = wmLabelList[quickDestinationIndex];
CityInfo* city = &(wmAreaInfoList[areaIdx]);
if (wmAreaIsKnown(city->areaId)) {
if (wmGenData.currentAreaId != areaIdx) {
2022-08-24 03:11:46 -07:00
// SFALL: Fix the position of the destination marker for
// small/medium location circles.
2022-09-15 01:42:02 -07:00
// CE: Fix is slightly different. `wmPartyInitWalking`
2022-08-24 03:11:46 -07:00
// assumes x/y are compensated for worldmap viewport
// offset (as can be seen earlier in this function).
2022-09-15 01:42:02 -07:00
CitySizeDescription* citySizeDescription = &(wmSphereData[city->size]);
int destX = city->x + citySizeDescription->frmImage.getWidth() / 2 - WM_VIEW_X;
int destY = city->y + citySizeDescription->frmImage.getHeight() / 2 - WM_VIEW_Y;
2022-09-15 01:42:02 -07:00
wmPartyInitWalking(destX, destY);
wmGenData.mousePressed = 0;
2022-05-19 01:51:26 -07:00
}
}
}
}
2022-08-07 04:52:44 -07:00
if ((mouseEvent & MOUSE_EVENT_WHEEL) != 0) {
int wheelX;
int wheelY;
mouseGetWheel(&wheelX, &wheelY);
2022-09-15 01:42:02 -07:00
if (mouseHitTestInWindow(wmBkWin, WM_VIEW_X, WM_VIEW_Y, 472, 465)) {
wmInterfaceScrollPixel(20, 20, wheelX, -wheelY, NULL, true);
} else if (mouseHitTestInWindow(wmBkWin, 501, 135, 501 + 119, 135 + 178)) {
2022-08-07 04:52:44 -07:00
if (wheelY != 0) {
2022-09-15 01:42:02 -07:00
wmInterfaceScrollTabsStart(wheelY > 0 ? 27 : -27);
2022-08-07 04:52:44 -07:00
}
}
}
2022-05-19 01:51:26 -07:00
if (map != -1 || v25 == -1) {
break;
}
2022-10-07 14:54:27 -07:00
renderPresent();
sharedFpsLimiter.throttle();
2022-05-19 01:51:26 -07:00
}
2022-09-15 01:42:02 -07:00
if (wmInterfaceExit() == -1) {
2022-05-19 01:51:26 -07:00
return -1;
}
return rc;
}
// 0x4C056C
2022-09-15 01:42:02 -07:00
int wmCheckGameAreaEvents()
2022-05-19 01:51:26 -07:00
{
2022-09-15 01:42:02 -07:00
if (wmGenData.currentAreaId == CITY_FAKE_VAULT_13_A) {
2022-09-15 04:25:21 -07:00
// NOTE: Uninline.
wmAreaSetVisibleState(CITY_FAKE_VAULT_13_A, CITY_STATE_UNKNOWN, true);
2022-05-19 01:51:26 -07:00
2022-09-15 04:25:21 -07:00
// NOTE: Uninline.
wmAreaSetVisibleState(CITY_FAKE_VAULT_13_B, CITY_STATE_KNOWN, true);
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
wmAreaMarkVisitedState(CITY_FAKE_VAULT_13_B, 2);
2022-05-19 01:51:26 -07:00
}
return 0;
}
// 0x4C05C4
2022-09-15 01:42:02 -07:00
static int wmInterfaceCenterOnParty()
2022-05-19 01:51:26 -07:00
{
int v0;
int v1;
2022-09-15 01:42:02 -07:00
v0 = wmGenData.worldPosX - 203;
2022-05-19 01:51:26 -07:00
if ((v0 & 0x80000000) == 0) {
2022-09-15 01:42:02 -07:00
if (v0 > wmGenData.viewportMaxX) {
v0 = wmGenData.viewportMaxX;
2022-05-19 01:51:26 -07:00
}
} else {
v0 = 0;
}
2022-09-15 01:42:02 -07:00
v1 = wmGenData.worldPosY - 200;
2022-05-19 01:51:26 -07:00
if ((v1 & 0x80000000) == 0) {
2022-09-15 01:42:02 -07:00
if (v1 > wmGenData.viewportMaxY) {
v1 = wmGenData.viewportMaxY;
2022-05-19 01:51:26 -07:00
}
} else {
v1 = 0;
}
2022-09-15 01:42:02 -07:00
wmWorldOffsetX = v0;
wmWorldOffsetY = v1;
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
wmInterfaceRefresh();
2022-05-19 01:51:26 -07:00
return 0;
}
2022-09-01 08:41:37 -07:00
// NOTE: Inlined.
//
// 0x4C0624
static void wmCheckGameEvents()
{
2022-09-15 01:42:02 -07:00
_scriptsCheckGameEvents(NULL, wmBkWin);
2022-09-01 08:41:37 -07:00
}
2022-05-19 01:51:26 -07:00
// 0x4C0634
2022-09-15 01:42:02 -07:00
static int wmRndEncounterOccurred()
2022-05-19 01:51:26 -07:00
{
2022-10-05 00:11:47 -07:00
unsigned int v0 = getTicks();
2022-09-15 01:42:02 -07:00
if (getTicksBetween(v0, wmLastRndTime) < 1500) {
2022-05-19 01:51:26 -07:00
return 0;
}
2022-09-15 01:42:02 -07:00
wmLastRndTime = v0;
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
if (abs(wmGenData.oldWorldPosX - wmGenData.worldPosX) < 3) {
2022-05-19 01:51:26 -07:00
return 0;
}
2022-09-15 01:42:02 -07:00
if (abs(wmGenData.oldWorldPosY - wmGenData.worldPosY) < 3) {
2022-05-19 01:51:26 -07:00
return 0;
}
int v26;
2022-09-15 01:42:02 -07:00
wmMatchWorldPosToArea(wmGenData.worldPosX, wmGenData.worldPosY, &v26);
2022-05-19 01:51:26 -07:00
if (v26 != -1) {
return 0;
}
2022-09-15 01:42:02 -07:00
if (!wmGenData.didMeetFrankHorrigan) {
2022-05-19 01:51:26 -07:00
unsigned int gameTime = gameTimeGetTime();
if (gameTime / GAME_TIME_TICKS_PER_DAY > 35) {
// SFALL: Add a flashing icon to the Horrigan encounter.
2022-09-15 01:42:02 -07:00
wmGenData.encounterIconIsVisible = 1;
for (int index = 0; index < 7; index++) {
2022-09-15 01:42:02 -07:00
wmGenData.encounterCursorId = index % 2 == 0
? WORLD_MAP_ENCOUNTER_FRM_SPECIAL_DARK
: WORLD_MAP_ENCOUNTER_FRM_SPECIAL_BRIGHT;
2022-09-15 01:42:02 -07:00
if (wmInterfaceRefresh() == -1) {
return -1;
}
2022-10-07 14:54:27 -07:00
renderPresent();
2022-10-05 00:11:47 -07:00
inputBlockForTocks(200);
}
2022-09-15 01:42:02 -07:00
wmGenData.encounterMapId = v26;
wmGenData.didMeetFrankHorrigan = true;
if (wmGenData.isInCar) {
wmMatchAreaContainingMapIdx(MAP_IN_GAME_MOVIE1, &(wmGenData.currentCarAreaId));
2022-05-19 01:51:26 -07:00
}
mapLoadById(MAP_IN_GAME_MOVIE1);
return 1;
}
}
// NOTE: Uninline.
2022-09-15 01:42:02 -07:00
wmPartyFindCurSubTile();
2022-05-19 01:51:26 -07:00
int dayPart;
int gameTimeHour = gameTimeGetHour();
if (gameTimeHour >= 1800 || gameTimeHour < 600) {
dayPart = DAY_PART_NIGHT;
} else if (gameTimeHour >= 1200) {
dayPart = DAY_PART_AFTERNOON;
} else {
dayPart = DAY_PART_MORNING;
}
2022-09-15 01:42:02 -07:00
int frequency = wmFreqValues[wmGenData.currentSubtile->encounterChance[dayPart]];
2022-05-19 01:51:26 -07:00
if (frequency > 0 && frequency < 100) {
int modifier = frequency / 15;
switch (settings.preferences.game_difficulty) {
case GAME_DIFFICULTY_EASY:
frequency -= modifier;
break;
case GAME_DIFFICULTY_HARD:
frequency += modifier;
break;
2022-05-19 01:51:26 -07:00
}
}
int chance = randomBetween(0, 100);
if (chance >= frequency) {
return 0;
}
2022-09-15 01:42:02 -07:00
wmRndEncounterPick();
2022-05-19 01:51:26 -07:00
int v8 = 1;
2022-09-15 01:42:02 -07:00
wmGenData.encounterIconIsVisible = 1;
wmGenData.encounterCursorId = 0;
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
EncounterTable* encounterTable = &(wmEncounterTableList[wmGenData.encounterTableId]);
EncounterEntry* encounter = &(encounterTable->entries[wmGenData.encounterEntryId]);
2022-05-19 01:51:26 -07:00
if ((encounter->flags & ENCOUNTER_ENTRY_SPECIAL) != 0) {
2022-09-15 01:42:02 -07:00
wmGenData.encounterCursorId = 2;
wmMatchAreaContainingMapIdx(wmGenData.encounterMapId, &v26);
CityInfo* city = &(wmAreaInfoList[v26]);
CitySizeDescription* citySizeDescription = &(wmSphereData[city->size]);
int worldmapX = wmGenData.worldPosX + wmGenData.hotspotNormalFrmImage.getWidth() / 2 + citySizeDescription->frmImage.getWidth() / 2;
int worldmapY = wmGenData.worldPosY + wmGenData.hotspotNormalFrmImage.getHeight() / 2 + citySizeDescription->frmImage.getHeight() / 2;
2022-09-15 01:42:02 -07:00
wmAreaSetWorldPos(v26, worldmapX, worldmapY);
2022-05-19 01:51:26 -07:00
v8 = 3;
2022-09-15 01:42:02 -07:00
if (v26 >= 0 && v26 < wmMaxAreaNum) {
CityInfo* city = &(wmAreaInfoList[v26]);
if (city->lockState != LOCK_STATE_LOCKED) {
city->state = CITY_STATE_KNOWN;
2022-05-19 01:51:26 -07:00
}
}
}
// Blinking.
for (int index = 0; index < 7; index++) {
2022-09-15 01:42:02 -07:00
wmGenData.encounterCursorId = v8 - wmGenData.encounterCursorId;
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
if (wmInterfaceRefresh() == -1) {
2022-05-19 01:51:26 -07:00
return -1;
}
2022-10-07 14:54:27 -07:00
renderPresent();
2022-10-05 00:11:47 -07:00
inputBlockForTocks(200);
2022-05-19 01:51:26 -07:00
}
2022-09-15 01:42:02 -07:00
if (wmGenData.isInCar) {
2022-05-19 01:51:26 -07:00
int modifiers[DAY_PART_COUNT];
// NOTE: I'm not sure why they're copied.
memcpy(modifiers, gDayPartEncounterFrequencyModifiers, sizeof(gDayPartEncounterFrequencyModifiers));
frequency -= modifiers[dayPart];
}
bool randomEncounterIsDetected = false;
if (frequency > chance) {
int outdoorsman = partyGetBestSkillValue(SKILL_OUTDOORSMAN);
Object* scanner = objectGetCarriedObjectByPid(gDude, PROTO_ID_MOTION_SENSOR);
if (scanner != NULL) {
if (gDude == scanner->owner) {
outdoorsman += 20;
}
}
if (outdoorsman > 95) {
outdoorsman = 95;
}
TileInfo* tile;
// NOTE: Uninline.
2022-09-15 01:42:02 -07:00
wmFindCurTileFromPos(wmGenData.worldPosX, wmGenData.worldPosY, &tile);
2022-05-19 01:51:26 -07:00
debugPrint("\nEncounter Difficulty Mod: %d", tile->encounterDifficultyModifier);
outdoorsman += tile->encounterDifficultyModifier;
if (randomBetween(1, 100) < outdoorsman) {
randomEncounterIsDetected = true;
int xp = 100 - outdoorsman;
if (xp > 0) {
// SFALL: Display actual xp received.
debugPrint("WorldMap: Giving Player [%d] Experience For Catching Rnd Encounter!", xp);
int xpGained;
pcAddExperience(xp, &xpGained);
2022-05-19 01:51:26 -07:00
MessageListItem messageListItem;
char* text = getmsg(&gMiscMessageList, &messageListItem, 8500);
if (strlen(text) < 110) {
char formattedText[120];
sprintf(formattedText, text, xpGained);
2022-05-19 01:51:26 -07:00
displayMonitorAddMessage(formattedText);
} else {
debugPrint("WorldMap: Error: Rnd Encounter string too long!");
}
}
}
} else {
randomEncounterIsDetected = true;
}
2022-09-15 01:42:02 -07:00
wmGenData.oldWorldPosX = wmGenData.worldPosX;
wmGenData.oldWorldPosY = wmGenData.worldPosY;
2022-05-19 01:51:26 -07:00
if (randomEncounterIsDetected) {
MessageListItem messageListItem;
2022-09-15 01:42:02 -07:00
const char* title = gWorldmapEncDefaultMsg[0];
const char* body = gWorldmapEncDefaultMsg[1];
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
title = getmsg(&wmMsgFile, &messageListItem, 2999);
body = getmsg(&wmMsgFile, &messageListItem, 3000 + 50 * wmGenData.encounterTableId + wmGenData.encounterEntryId);
2022-05-19 01:51:26 -07:00
if (showDialogBox(title, &body, 1, 169, 116, _colorTable[32328], NULL, _colorTable[32328], DIALOG_BOX_LARGE | DIALOG_BOX_YES_NO) == 0) {
2022-09-15 01:42:02 -07:00
wmGenData.encounterIconIsVisible = 0;
wmGenData.encounterMapId = -1;
wmGenData.encounterTableId = -1;
wmGenData.encounterEntryId = -1;
2022-05-19 01:51:26 -07:00
return 0;
}
}
return 1;
}
// NOTE: Inlined.
//
// 0x4C0BE4
2022-09-15 01:42:02 -07:00
static int wmPartyFindCurSubTile()
2022-05-19 01:51:26 -07:00
{
2022-09-15 01:42:02 -07:00
return wmFindCurSubTileFromPos(wmGenData.worldPosX, wmGenData.worldPosY, &(wmGenData.currentSubtile));
2022-05-19 01:51:26 -07:00
}
// 0x4C0C00
2022-09-15 01:42:02 -07:00
static int wmFindCurSubTileFromPos(int x, int y, SubtileInfo** subtilePtr)
2022-05-19 01:51:26 -07:00
{
2022-09-15 01:42:02 -07:00
int tileIndex = y / WM_TILE_HEIGHT * wmNumHorizontalTiles + x / WM_TILE_WIDTH % wmNumHorizontalTiles;
TileInfo* tile = &(wmTileInfoList[tileIndex]);
2022-05-19 01:51:26 -07:00
int column = y % WM_TILE_HEIGHT / WM_SUBTILE_SIZE;
int row = x % WM_TILE_WIDTH / WM_SUBTILE_SIZE;
2022-09-15 01:42:02 -07:00
*subtilePtr = &(tile->subtiles[column][row]);
2022-05-19 01:51:26 -07:00
return 0;
}
// NOTE: Inlined.
//
// 0x4C0CA8
2022-09-15 01:42:02 -07:00
static int wmFindCurTileFromPos(int x, int y, TileInfo** tilePtr)
2022-05-19 01:51:26 -07:00
{
2022-09-15 01:42:02 -07:00
int tileIndex = y / WM_TILE_HEIGHT * wmNumHorizontalTiles + x / WM_TILE_WIDTH % wmNumHorizontalTiles;
*tilePtr = &(wmTileInfoList[tileIndex]);
2022-05-19 01:51:26 -07:00
return 0;
}
// 0x4C0CF4
2022-09-15 01:42:02 -07:00
static int wmRndEncounterPick()
2022-05-19 01:51:26 -07:00
{
2022-09-15 01:42:02 -07:00
if (wmGenData.currentSubtile == NULL) {
2022-05-19 01:51:26 -07:00
// NOTE: Uninline.
2022-09-15 01:42:02 -07:00
wmPartyFindCurSubTile();
2022-05-19 01:51:26 -07:00
}
2022-09-15 01:42:02 -07:00
wmGenData.encounterTableId = wmGenData.currentSubtile->encounterType;
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
EncounterTable* encounterTable = &(wmEncounterTableList[wmGenData.encounterTableId]);
2022-05-19 01:51:26 -07:00
int candidates[41];
int candidatesLength = 0;
int totalChance = 0;
for (int index = 0; index < encounterTable->entriesLength; index++) {
EncounterEntry* encounterTableEntry = &(encounterTable->entries[index]);
bool selected = true;
2022-09-15 01:42:02 -07:00
if (wmEvalConditional(&(encounterTableEntry->condition), NULL) == 0) {
2022-05-19 01:51:26 -07:00
selected = false;
}
if (encounterTableEntry->counter == 0) {
selected = false;
}
if (selected) {
candidates[candidatesLength++] = index;
totalChance += encounterTableEntry->chance;
}
}
int v1 = critterGetStat(gDude, STAT_LUCK) - 5;
int v2 = randomBetween(0, totalChance) + v1;
if (perkHasRank(gDude, PERK_EXPLORER)) {
v2 += 2;
}
if (perkHasRank(gDude, PERK_RANGER)) {
v2++;
}
if (perkHasRank(gDude, PERK_SCOUT)) {
v2++;
}
switch (settings.preferences.game_difficulty) {
case GAME_DIFFICULTY_EASY:
v2 += 5;
if (v2 > totalChance) {
v2 = totalChance;
}
break;
case GAME_DIFFICULTY_HARD:
v2 -= 5;
if (v2 < 0) {
v2 = 0;
2022-05-19 01:51:26 -07:00
}
break;
2022-05-19 01:51:26 -07:00
}
int index;
for (index = 0; index < candidatesLength; index++) {
EncounterEntry* encounterTableEntry = &(encounterTable->entries[candidates[index]]);
if (v2 < encounterTableEntry->chance) {
break;
}
v2 -= encounterTableEntry->chance;
}
if (index == candidatesLength) {
index = candidatesLength - 1;
}
2022-09-15 01:42:02 -07:00
wmGenData.encounterEntryId = candidates[index];
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
EncounterEntry* encounterTableEntry = &(encounterTable->entries[wmGenData.encounterEntryId]);
2022-05-19 01:51:26 -07:00
if (encounterTableEntry->counter > 0) {
encounterTableEntry->counter--;
}
if (encounterTableEntry->map == -1) {
if (encounterTable->mapsLength <= 0) {
2022-09-15 01:42:02 -07:00
Terrain* terrain = &(wmTerrainTypeList[wmGenData.currentSubtile->terrain]);
int randommapIdx = randomBetween(0, terrain->mapsLength - 1);
wmGenData.encounterMapId = terrain->maps[randommapIdx];
2022-05-19 01:51:26 -07:00
} else {
2022-09-15 01:42:02 -07:00
int randommapIdx = randomBetween(0, encounterTable->mapsLength - 1);
wmGenData.encounterMapId = encounterTable->maps[randommapIdx];
2022-05-19 01:51:26 -07:00
}
} else {
2022-09-15 01:42:02 -07:00
wmGenData.encounterMapId = encounterTableEntry->map;
2022-05-19 01:51:26 -07:00
}
return 0;
}
// 0x4C0FA4
2022-09-15 01:42:02 -07:00
int wmSetupRandomEncounter()
2022-05-19 01:51:26 -07:00
{
MessageListItem messageListItem;
2022-09-15 01:42:02 -07:00
if (wmGenData.encounterMapId == -1) {
2022-05-19 01:51:26 -07:00
return 0;
}
2022-09-15 01:42:02 -07:00
EncounterTable* encounterTable = &(wmEncounterTableList[wmGenData.encounterTableId]);
EncounterEntry* encounterTableEntry = &(encounterTable->entries[wmGenData.encounterEntryId]);
2022-05-19 01:51:26 -07:00
// SFALL: Display encounter description in one line.
char formattedText[512];
sprintf(formattedText,
"%s %s",
getmsg(&wmMsgFile, &messageListItem, 2998),
getmsg(&wmMsgFile, &messageListItem, 3000 + 50 * wmGenData.encounterTableId + wmGenData.encounterEntryId));
displayMonitorAddMessage(formattedText);
2022-05-19 01:51:26 -07:00
int gameDifficulty = settings.preferences.game_difficulty;
2022-05-19 01:51:26 -07:00
switch (encounterTableEntry->scenery) {
case ENCOUNTER_SCENERY_TYPE_NONE:
case ENCOUNTER_SCENERY_TYPE_LIGHT:
case ENCOUNTER_SCENERY_TYPE_NORMAL:
case ENCOUNTER_SCENERY_TYPE_HEAVY:
2022-09-15 01:42:02 -07:00
debugPrint("\nwmSetupRandomEncounter: Scenery Type: %s", wmSceneryStrs[encounterTableEntry->scenery]);
2022-05-19 01:51:26 -07:00
break;
default:
debugPrint("\nERROR: wmSetupRandomEncounter: invalid Scenery Type!");
return -1;
}
Object* v0 = NULL;
for (int i = 0; i < encounterTableEntry->field_50; i++) {
ENCOUNTER_ENTRY_ENC* v3 = &(encounterTableEntry->field_54[i]);
int v9 = randomBetween(v3->minQuantity, v3->maxQuantity);
switch (gameDifficulty) {
case GAME_DIFFICULTY_EASY:
v9 -= 2;
if (v9 < v3->minQuantity) {
v9 = v3->minQuantity;
}
break;
case GAME_DIFFICULTY_HARD:
v9 += 2;
break;
}
int partyMemberCount = _getPartyMemberCount();
if (partyMemberCount > 2) {
v9 += 2;
}
if (v9 != 0) {
Object* v35;
2022-09-15 01:42:02 -07:00
if (wmSetupCritterObjs(v3->field_8, &v35, v9) == -1) {
2022-05-19 01:51:26 -07:00
scriptsRequestWorldMap();
return -1;
}
if (i > 0) {
if (v0 != NULL) {
if (v0 != v35) {
if (encounterTableEntry->field_50 != 1) {
if (encounterTableEntry->field_50 == 2 && !isInCombat()) {
v0->data.critter.combat.whoHitMe = v35;
v35->data.critter.combat.whoHitMe = v0;
STRUCT_664980 combat;
combat.attacker = v0;
combat.defender = v35;
combat.actionPointsBonus = 0;
combat.accuracyBonus = 0;
combat.damageBonus = 0;
combat.minDamage = 0;
combat.maxDamage = 500;
combat.field_1C = 0;
_caiSetupTeamCombat(v35, v0);
_scripts_request_combat_locked(&combat);
}
} else {
if (!isInCombat()) {
v0->data.critter.combat.whoHitMe = gDude;
STRUCT_664980 combat;
combat.attacker = v0;
combat.defender = gDude;
combat.actionPointsBonus = 0;
combat.accuracyBonus = 0;
combat.damageBonus = 0;
combat.minDamage = 0;
combat.maxDamage = 500;
combat.field_1C = 0;
_caiSetupTeamCombat(gDude, v0);
_scripts_request_combat_locked(&combat);
}
}
}
}
}
v0 = v35;
}
}
return 0;
}
// wmSetupCritterObjs
// 0x4C11FC
2022-09-15 01:42:02 -07:00
static int wmSetupCritterObjs(int type_idx, Object** critterPtr, int critterCount)
2022-05-19 01:51:26 -07:00
{
if (type_idx == -1) {
return 0;
}
*critterPtr = 0;
2022-09-15 01:42:02 -07:00
ENC_BASE_TYPE* v25 = &(wmEncBaseTypeList[type_idx]);
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
debugPrint("\nwmSetupCritterObjs: typeIdx: %d, Formation: %s", type_idx, wmFormationStrs[v25->position]);
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
if (wmSetupRndNextTileNumInit(v25) == -1) {
2022-05-19 01:51:26 -07:00
return -1;
}
for (int i = 0; i < v25->field_34; i++) {
ENC_BASE_TYPE_38* v5 = &(v25->field_38[i]);
if (v5->pid == -1) {
continue;
}
2022-09-15 01:42:02 -07:00
if (!wmEvalConditional(&(v5->condition), &critterCount)) {
2022-05-19 01:51:26 -07:00
continue;
}
int v23;
switch (v5->field_2C) {
case 0:
v23 = v5->ratio * critterCount / 100;
break;
case 1:
v23 = 1;
break;
default:
assert(false && "Should be unreachable");
}
if (v23 < 1) {
v23 = 1;
}
for (int j = 0; j < v23; j++) {
int tile;
2022-09-15 01:42:02 -07:00
if (wmSetupRndNextTileNum(v25, v5, &tile) == -1) {
2022-05-19 01:51:26 -07:00
debugPrint("\nERROR: wmSetupCritterObjs: wmSetupRndNextTileNum:");
continue;
}
if (v5->pid == -1) {
continue;
}
Object* object;
if (objectCreateWithPid(&object, v5->pid) == -1) {
return -1;
}
if (*critterPtr == NULL) {
if (PID_TYPE(v5->pid) == OBJ_TYPE_CRITTER) {
2022-05-19 01:51:26 -07:00
*critterPtr = object;
}
}
if (v5->team != -1) {
if (PID_TYPE(object->pid) == OBJ_TYPE_CRITTER) {
2022-05-19 01:51:26 -07:00
object->data.critter.combat.team = v5->team;
}
}
if (v5->script != -1) {
if (object->sid != -1) {
scriptRemove(object->sid);
object->sid = -1;
}
_obj_new_sid_inst(object, SCRIPT_TYPE_CRITTER, v5->script - 1);
}
if (v25->position != ENCOUNTER_FORMATION_TYPE_SURROUNDING) {
objectSetLocation(object, tile, gElevation, NULL);
} else {
_obj_attempt_placement(object, tile, 0, 0);
}
int direction = tileGetRotationTo(tile, gDude->tile);
objectSetRotation(object, direction, NULL);
for (int itemIndex = 0; itemIndex < v5->itemsLength; itemIndex++) {
ENC_BASE_TYPE_38_48* v10 = &(v5->items[itemIndex]);
int quantity;
if (v10->maximumQuantity == v10->minimumQuantity) {
quantity = v10->maximumQuantity;
} else {
quantity = randomBetween(v10->minimumQuantity, v10->maximumQuantity);
}
if (quantity == 0) {
continue;
}
Object* item;
if (objectCreateWithPid(&item, v10->pid) == -1) {
return -1;
}
if (v10->pid == PROTO_ID_MONEY) {
if (perkHasRank(gDude, PERK_FORTUNE_FINDER)) {
quantity *= 2;
}
}
if (itemAdd(object, item, quantity) == -1) {
return -1;
}
_obj_disconnect(item, NULL);
if (v10->isEquipped) {
if (_inven_wield(object, item, 1) == -1) {
debugPrint("\nERROR: wmSetupCritterObjs: Inven Wield Failed: %d on %s: Critter Fid: %d", item->pid, critterGetName(object), object->fid);
}
}
}
}
}
return 0;
}
// 0x4C155C
2022-09-15 01:42:02 -07:00
static int wmSetupRndNextTileNumInit(ENC_BASE_TYPE* a1)
2022-05-19 01:51:26 -07:00
{
for (int index = 0; index < 2; index++) {
2022-09-15 01:42:02 -07:00
wmRndCenterRotations[index] = 0;
wmRndTileDirs[index] = 0;
wmRndCenterTiles[index] = -1;
2022-05-19 01:51:26 -07:00
if (index & 1) {
2022-09-15 01:42:02 -07:00
wmRndRotOffsets[index] = 5;
2022-05-19 01:51:26 -07:00
} else {
2022-09-15 01:42:02 -07:00
wmRndRotOffsets[index] = 1;
2022-05-19 01:51:26 -07:00
}
}
2022-09-15 01:42:02 -07:00
wmRndCallCount = 0;
2022-05-19 01:51:26 -07:00
switch (a1->position) {
case ENCOUNTER_FORMATION_TYPE_SURROUNDING:
2022-09-15 01:42:02 -07:00
wmRndCenterTiles[0] = gDude->tile;
wmRndTileDirs[0] = randomBetween(0, ROTATION_COUNT - 1);
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
wmRndOriginalCenterTile = wmRndCenterTiles[0];
2022-05-19 01:51:26 -07:00
return 0;
case ENCOUNTER_FORMATION_TYPE_STRAIGHT_LINE:
case ENCOUNTER_FORMATION_TYPE_DOUBLE_LINE:
case ENCOUNTER_FORMATION_TYPE_WEDGE:
case ENCOUNTER_FORMATION_TYPE_CONE:
case ENCOUNTER_FORMATION_TYPE_HUDDLE:
if (1) {
2022-09-15 01:42:02 -07:00
MapInfo* map = &(wmMapInfoList[gMapHeader.field_34]);
2022-05-19 01:51:26 -07:00
if (map->startPointsLength != 0) {
int rspIndex = randomBetween(0, map->startPointsLength - 1);
MapStartPointInfo* rsp = &(map->startPoints[rspIndex]);
2022-09-15 01:42:02 -07:00
wmRndCenterTiles[0] = rsp->tile;
wmRndCenterTiles[1] = wmRndCenterTiles[0];
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
wmRndCenterRotations[0] = rsp->field_8;
wmRndCenterRotations[1] = wmRndCenterRotations[0];
2022-05-19 01:51:26 -07:00
} else {
2022-09-15 01:42:02 -07:00
wmRndCenterRotations[0] = 0;
wmRndCenterRotations[1] = 0;
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
wmRndCenterTiles[0] = gDude->tile;
wmRndCenterTiles[1] = gDude->tile;
2022-05-19 01:51:26 -07:00
}
2022-09-15 01:42:02 -07:00
wmRndTileDirs[0] = tileGetRotationTo(wmRndCenterTiles[0], gDude->tile);
wmRndTileDirs[1] = tileGetRotationTo(wmRndCenterTiles[1], gDude->tile);
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
wmRndOriginalCenterTile = wmRndCenterTiles[0];
2022-05-19 01:51:26 -07:00
return 0;
}
default:
debugPrint("\nERROR: wmSetupCritterObjs: invalid Formation Type!");
return -1;
}
}
// wmSetupRndNextTileNum
// 0x4C16F0
2022-09-15 01:42:02 -07:00
static int wmSetupRndNextTileNum(ENC_BASE_TYPE* a1, ENC_BASE_TYPE_38* a2, int* out_tile_num)
2022-05-19 01:51:26 -07:00
{
int tile_num;
int attempt = 0;
while (1) {
switch (a1->position) {
case ENCOUNTER_FORMATION_TYPE_SURROUNDING:
if (1) {
int distance;
if (a2->distance != 0) {
distance = a2->distance;
} else {
distance = randomBetween(-2, 2);
distance += critterGetStat(gDude, STAT_PERCEPTION);
if (perkHasRank(gDude, PERK_CAUTIOUS_NATURE)) {
distance += 3;
}
}
if (distance < 0) {
distance = 0;
}
int origin = a2->tile;
if (origin == -1) {
2022-09-15 01:42:02 -07:00
origin = tileGetTileInDirection(gDude->tile, wmRndTileDirs[0], distance);
2022-05-19 01:51:26 -07:00
}
2022-09-15 01:42:02 -07:00
if (++wmRndTileDirs[0] >= ROTATION_COUNT) {
wmRndTileDirs[0] = 0;
2022-05-19 01:51:26 -07:00
}
int randomizedDistance = randomBetween(0, distance / 2);
int randomizedRotation = randomBetween(0, ROTATION_COUNT - 1);
2022-09-15 01:42:02 -07:00
tile_num = tileGetTileInDirection(origin, (randomizedRotation + wmRndTileDirs[0]) % ROTATION_COUNT, randomizedDistance);
2022-05-19 01:51:26 -07:00
}
break;
case ENCOUNTER_FORMATION_TYPE_STRAIGHT_LINE:
2022-09-15 01:42:02 -07:00
tile_num = wmRndCenterTiles[wmRndIndex];
if (wmRndCallCount != 0) {
int rotation = (wmRndRotOffsets[wmRndIndex] + wmRndTileDirs[wmRndIndex]) % ROTATION_COUNT;
int origin = tileGetTileInDirection(wmRndCenterTiles[wmRndIndex], rotation, a1->spacing);
int v13 = tileGetTileInDirection(origin, (rotation + wmRndRotOffsets[wmRndIndex]) % ROTATION_COUNT, a1->spacing);
wmRndCenterTiles[wmRndIndex] = v13;
wmRndIndex = 1 - wmRndIndex;
2022-05-19 01:51:26 -07:00
tile_num = v13;
}
break;
case ENCOUNTER_FORMATION_TYPE_DOUBLE_LINE:
2022-09-15 01:42:02 -07:00
tile_num = wmRndCenterTiles[wmRndIndex];
if (wmRndCallCount != 0) {
int rotation = (wmRndRotOffsets[wmRndIndex] + wmRndTileDirs[wmRndIndex]) % ROTATION_COUNT;
int origin = tileGetTileInDirection(wmRndCenterTiles[wmRndIndex], rotation, a1->spacing);
int v17 = tileGetTileInDirection(origin, (rotation + wmRndRotOffsets[wmRndIndex]) % ROTATION_COUNT, a1->spacing);
wmRndCenterTiles[wmRndIndex] = v17;
wmRndIndex = 1 - wmRndIndex;
2022-05-19 01:51:26 -07:00
tile_num = v17;
}
break;
case ENCOUNTER_FORMATION_TYPE_WEDGE:
2022-09-15 01:42:02 -07:00
tile_num = wmRndCenterTiles[wmRndIndex];
if (wmRndCallCount != 0) {
tile_num = tileGetTileInDirection(wmRndCenterTiles[wmRndIndex], (wmRndRotOffsets[wmRndIndex] + wmRndTileDirs[wmRndIndex]) % ROTATION_COUNT, a1->spacing);
wmRndCenterTiles[wmRndIndex] = tile_num;
wmRndIndex = 1 - wmRndIndex;
2022-05-19 01:51:26 -07:00
}
break;
case ENCOUNTER_FORMATION_TYPE_CONE:
2022-09-15 01:42:02 -07:00
tile_num = wmRndCenterTiles[wmRndIndex];
if (wmRndCallCount != 0) {
tile_num = tileGetTileInDirection(wmRndCenterTiles[wmRndIndex], (wmRndTileDirs[wmRndIndex] + 3 + wmRndRotOffsets[wmRndIndex]) % ROTATION_COUNT, a1->spacing);
wmRndCenterTiles[wmRndIndex] = tile_num;
wmRndIndex = 1 - wmRndIndex;
2022-05-19 01:51:26 -07:00
}
break;
case ENCOUNTER_FORMATION_TYPE_HUDDLE:
2022-09-15 01:42:02 -07:00
tile_num = wmRndCenterTiles[0];
if (wmRndCallCount != 0) {
wmRndTileDirs[0] = (wmRndTileDirs[0] + 1) % ROTATION_COUNT;
tile_num = tileGetTileInDirection(wmRndCenterTiles[0], wmRndTileDirs[0], a1->spacing);
wmRndCenterTiles[0] = tile_num;
2022-05-19 01:51:26 -07:00
}
break;
default:
assert(false && "Should be unreachable");
}
++attempt;
2022-09-15 01:42:02 -07:00
++wmRndCallCount;
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
if (wmEvalTileNumForPlacement(tile_num)) {
2022-05-19 01:51:26 -07:00
break;
}
debugPrint("\nWARNING: EVAL-TILE-NUM FAILED!");
2022-09-15 01:42:02 -07:00
if (tileDistanceBetween(wmRndOriginalCenterTile, wmRndCenterTiles[wmRndIndex]) > 25) {
2022-05-19 01:51:26 -07:00
return -1;
}
if (attempt > 25) {
return -1;
}
}
debugPrint("\nwmSetupRndNextTileNum:TileNum: %d", tile_num);
*out_tile_num = tile_num;
return 0;
}
// 0x4C1A64
2022-09-15 01:42:02 -07:00
bool wmEvalTileNumForPlacement(int tile)
2022-05-19 01:51:26 -07:00
{
if (_obj_blocking_at(gDude, tile, gElevation) != NULL) {
return false;
}
if (pathfinderFindPath(gDude, gDude->tile, tile, NULL, 0, _obj_shoot_blocking_at) == 0) {
return false;
}
return true;
}
// 0x4C1AC8
2022-09-15 01:42:02 -07:00
static bool wmEvalConditional(EncounterCondition* a1, int* a2)
2022-05-19 01:51:26 -07:00
{
int value;
bool matches = true;
for (int index = 0; index < a1->entriesLength; index++) {
EncounterConditionEntry* ptr = &(a1->entries[index]);
matches = true;
switch (ptr->type) {
case ENCOUNTER_CONDITION_TYPE_GLOBAL:
value = gameGetGlobalVar(ptr->param);
2022-09-15 01:42:02 -07:00
if (!wmEvalSubConditional(value, ptr->conditionalOperator, ptr->value)) {
2022-05-19 01:51:26 -07:00
matches = false;
}
break;
case ENCOUNTER_CONDITION_TYPE_NUMBER_OF_CRITTERS:
2022-09-15 01:42:02 -07:00
if (!wmEvalSubConditional(*a2, ptr->conditionalOperator, ptr->value)) {
2022-05-19 01:51:26 -07:00
matches = false;
}
break;
case ENCOUNTER_CONDITION_TYPE_RANDOM:
value = randomBetween(0, 100);
if (value > ptr->param) {
matches = false;
}
break;
case ENCOUNTER_CONDITION_TYPE_PLAYER:
value = pcGetStat(PC_STAT_LEVEL);
2022-09-15 01:42:02 -07:00
if (!wmEvalSubConditional(value, ptr->conditionalOperator, ptr->value)) {
2022-05-19 01:51:26 -07:00
matches = false;
}
break;
case ENCOUNTER_CONDITION_TYPE_DAYS_PLAYED:
value = gameTimeGetTime();
2022-09-15 01:42:02 -07:00
if (!wmEvalSubConditional(value / GAME_TIME_TICKS_PER_DAY, ptr->conditionalOperator, ptr->value)) {
2022-05-19 01:51:26 -07:00
matches = false;
}
break;
case ENCOUNTER_CONDITION_TYPE_TIME_OF_DAY:
value = gameTimeGetHour();
2022-09-15 01:42:02 -07:00
if (!wmEvalSubConditional(value / 100, ptr->conditionalOperator, ptr->value)) {
2022-05-19 01:51:26 -07:00
matches = false;
}
break;
}
if (!matches) {
// FIXME: Can overflow with all 3 conditions specified.
if (a1->logicalOperators[index] == ENCOUNTER_LOGICAL_OPERATOR_AND) {
break;
}
}
}
return matches;
}
// 0x4C1C0C
2022-09-15 01:42:02 -07:00
static bool wmEvalSubConditional(int operand1, int condionalOperator, int operand2)
2022-05-19 01:51:26 -07:00
{
switch (condionalOperator) {
case ENCOUNTER_CONDITIONAL_OPERATOR_EQUAL:
return operand1 == operand2;
case ENCOUNTER_CONDITIONAL_OPERATOR_NOT_EQUAL:
return operand1 != operand2;
case ENCOUNTER_CONDITIONAL_OPERATOR_LESS_THAN:
return operand1 < operand2;
case ENCOUNTER_CONDITIONAL_OPERATOR_GREATER_THAN:
return operand1 > operand2;
}
return false;
}
// 0x4C1C50
2022-09-15 01:42:02 -07:00
static bool wmGameTimeIncrement(int ticksToAdd)
2022-05-19 01:51:26 -07:00
{
2022-08-29 07:37:58 -07:00
if (ticksToAdd == 0) {
2022-05-19 01:51:26 -07:00
return false;
}
2022-08-29 07:37:58 -07:00
// SFALL: Fix Pathfinder perk.
int pathfinderRank = perkGetRank(gDude, PERK_PATHFINDER);
double bonus = static_cast<double>(ticksToAdd) * static_cast<double>(pathfinderRank) * 0.25 + gGameTimeIncRemainder;
gGameTimeIncRemainder = modf(bonus, &bonus);
ticksToAdd -= static_cast<int>(bonus);
while (ticksToAdd != 0) {
2022-05-19 01:51:26 -07:00
unsigned int gameTime = gameTimeGetTime();
unsigned int nextEventTime = queueGetNextEventTime();
2022-08-29 07:37:58 -07:00
int v1 = nextEventTime >= gameTime ? ticksToAdd : nextEventTime - gameTime;
ticksToAdd -= v1;
2022-05-19 01:51:26 -07:00
gameTimeAddTicks(v1);
2022-09-01 08:41:37 -07:00
// NOTE: Uninline.
wmInterfaceDialSyncTime(true);
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
wmInterfaceRefreshDate(true);
2022-05-19 01:51:26 -07:00
if (queueProcessEvents()) {
break;
}
}
return true;
}
// Reads .msk file if needed.
//
// 0x4C1CE8
2022-09-15 01:42:02 -07:00
static int wmGrabTileWalkMask(int tileIdx)
2022-05-19 01:51:26 -07:00
{
2022-09-15 01:42:02 -07:00
TileInfo* tileInfo = &(wmTileInfoList[tileIdx]);
2022-05-19 01:51:26 -07:00
if (tileInfo->walkMaskData != NULL) {
return 0;
}
if (*tileInfo->walkMaskName == '\0') {
return 0;
}
2022-05-21 08:22:03 -07:00
tileInfo->walkMaskData = (unsigned char*)internal_malloc(13200);
2022-05-19 01:51:26 -07:00
if (tileInfo->walkMaskData == NULL) {
return -1;
}
2022-05-28 02:34:49 -07:00
char path[COMPAT_MAX_PATH];
2022-05-19 01:51:26 -07:00
sprintf(path, "data\\%s.msk", tileInfo->walkMaskName);
File* stream = fileOpen(path, "rb");
if (stream == NULL) {
return -1;
}
int rc = 0;
if (fileReadUInt8List(stream, tileInfo->walkMaskData, 13200) == -1) {
rc = -1;
}
fileClose(stream);
return rc;
}
// 0x4C1D9C
2022-09-15 01:42:02 -07:00
static bool wmWorldPosInvalid(int x, int y)
2022-05-19 01:51:26 -07:00
{
2022-09-15 01:42:02 -07:00
int tileIdx = y / WM_TILE_HEIGHT * wmNumHorizontalTiles + x / WM_TILE_WIDTH % wmNumHorizontalTiles;
if (wmGrabTileWalkMask(tileIdx) == -1) {
2022-05-19 01:51:26 -07:00
return false;
}
2022-09-15 01:42:02 -07:00
TileInfo* tileDescription = &(wmTileInfoList[tileIdx]);
2022-05-19 01:51:26 -07:00
unsigned char* mask = tileDescription->walkMaskData;
if (mask == NULL) {
return false;
}
// Mask length is 13200, which is 300 * 44
// 44 * 8 is 352, which is probably left 2 bytes intact
// TODO: Check math.
2022-09-15 01:42:02 -07:00
int pos = (y % WM_TILE_HEIGHT) * 44 + (x % WM_TILE_WIDTH) / 8;
int bit = 1 << (((x % WM_TILE_WIDTH) / 8) & 3);
2022-05-19 01:51:26 -07:00
return (mask[pos] & bit) != 0;
}
// 0x4C1E54
2022-09-15 01:42:02 -07:00
static void wmPartyInitWalking(int x, int y)
2022-05-19 01:51:26 -07:00
{
2022-09-15 01:42:02 -07:00
wmGenData.walkDestinationX = x;
wmGenData.walkDestinationY = y;
wmGenData.currentAreaId = -1;
wmGenData.isWalking = true;
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
int dx = abs(x - wmGenData.worldPosX);
int dy = abs(y - wmGenData.worldPosY);
2022-05-19 01:51:26 -07:00
if (dx < dy) {
2022-09-15 01:42:02 -07:00
wmGenData.walkDistance = dy;
wmGenData.walkLineDeltaMainAxisStep = 2 * dx;
wmGenData.walkWorldPosMainAxisStepX = 0;
wmGenData.walkLineDelta = 2 * dx - dy;
wmGenData.walkLineDeltaCrossAxisStep = 2 * (dx - dy);
wmGenData.walkWorldPosCrossAxisStepX = 1;
wmGenData.walkWorldPosMainAxisStepY = 1;
wmGenData.walkWorldPosCrossAxisStepY = 1;
2022-05-19 01:51:26 -07:00
} else {
2022-09-15 01:42:02 -07:00
wmGenData.walkDistance = dx;
wmGenData.walkLineDeltaMainAxisStep = 2 * dy;
wmGenData.walkWorldPosMainAxisStepY = 0;
wmGenData.walkLineDelta = 2 * dy - dx;
wmGenData.walkLineDeltaCrossAxisStep = 2 * (dy - dx);
wmGenData.walkWorldPosMainAxisStepX = 1;
wmGenData.walkWorldPosCrossAxisStepX = 1;
wmGenData.walkWorldPosCrossAxisStepY = 1;
2022-05-19 01:51:26 -07:00
}
2022-09-15 01:42:02 -07:00
if (wmGenData.walkDestinationX < wmGenData.worldPosX) {
wmGenData.walkWorldPosCrossAxisStepX = -wmGenData.walkWorldPosCrossAxisStepX;
wmGenData.walkWorldPosMainAxisStepX = -wmGenData.walkWorldPosMainAxisStepX;
2022-05-19 01:51:26 -07:00
}
2022-09-15 01:42:02 -07:00
if (wmGenData.walkDestinationY < wmGenData.worldPosY) {
wmGenData.walkWorldPosCrossAxisStepY = -wmGenData.walkWorldPosCrossAxisStepY;
wmGenData.walkWorldPosMainAxisStepY = -wmGenData.walkWorldPosMainAxisStepY;
2022-05-19 01:51:26 -07:00
}
2022-09-15 01:42:02 -07:00
if (!wmCursorIsVisible()) {
wmInterfaceCenterOnParty();
2022-05-19 01:51:26 -07:00
}
}
// 0x4C1F90
2022-09-15 01:42:02 -07:00
static void wmPartyWalkingStep()
2022-05-19 01:51:26 -07:00
{
2022-09-15 01:42:02 -07:00
if (wmGenData.walkDistance <= 0) {
2022-05-19 01:51:26 -07:00
return;
}
_terrainCounter++;
if (_terrainCounter > 4) {
_terrainCounter = 1;
}
// NOTE: Uninline.
2022-09-15 01:42:02 -07:00
wmPartyFindCurSubTile();
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
Terrain* terrain = &(wmTerrainTypeList[wmGenData.currentSubtile->terrain]);
2022-08-29 07:37:58 -07:00
// SFALL: Fix Pathfinder perk.
int terrainDifficulty = terrain->difficulty;
if (terrainDifficulty < 1) {
terrainDifficulty = 1;
2022-05-19 01:51:26 -07:00
}
2022-08-29 07:37:58 -07:00
if (_terrainCounter / terrainDifficulty >= 1) {
2022-05-19 01:51:26 -07:00
int v3;
int v4;
2022-09-15 01:42:02 -07:00
if (wmGenData.walkLineDelta >= 0) {
if (wmWorldPosInvalid(wmGenData.walkWorldPosCrossAxisStepX + wmGenData.worldPosX, wmGenData.walkWorldPosCrossAxisStepY + wmGenData.worldPosY)) {
wmGenData.walkDestinationX = 0;
wmGenData.walkDestinationY = 0;
wmGenData.isWalking = false;
wmMatchWorldPosToArea(wmGenData.worldPosX, wmGenData.worldPosX, &(wmGenData.currentAreaId));
wmGenData.walkDistance = 0;
2022-05-19 01:51:26 -07:00
return;
}
2022-09-15 01:42:02 -07:00
v3 = wmGenData.walkWorldPosCrossAxisStepX;
wmGenData.walkLineDelta += wmGenData.walkLineDeltaCrossAxisStep;
wmGenData.worldPosX += wmGenData.walkWorldPosCrossAxisStepX;
v4 = wmGenData.walkWorldPosCrossAxisStepY;
wmGenData.worldPosY += wmGenData.walkWorldPosCrossAxisStepY;
2022-05-19 01:51:26 -07:00
} else {
2022-09-15 01:42:02 -07:00
if (wmWorldPosInvalid(wmGenData.walkWorldPosMainAxisStepX + wmGenData.worldPosX, wmGenData.walkWorldPosMainAxisStepY + wmGenData.worldPosY) == 1) {
wmGenData.walkDestinationX = 0;
wmGenData.walkDestinationY = 0;
wmGenData.isWalking = false;
wmMatchWorldPosToArea(wmGenData.worldPosX, wmGenData.worldPosX, &(wmGenData.currentAreaId));
wmGenData.walkDistance = 0;
2022-05-19 01:51:26 -07:00
return;
}
2022-09-15 01:42:02 -07:00
v3 = wmGenData.walkWorldPosMainAxisStepX;
wmGenData.walkLineDelta += wmGenData.walkLineDeltaMainAxisStep;
wmGenData.worldPosY += wmGenData.walkWorldPosMainAxisStepY;
v4 = wmGenData.walkWorldPosMainAxisStepY;
wmGenData.worldPosX += wmGenData.walkWorldPosMainAxisStepX;
2022-05-19 01:51:26 -07:00
}
2022-09-15 01:42:02 -07:00
wmInterfaceScrollPixel(1, 1, v3, v4, NULL, false);
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
wmGenData.walkDistance -= 1;
if (wmGenData.walkDistance == 0) {
wmGenData.walkDestinationY = 0;
wmGenData.isWalking = false;
wmGenData.walkDestinationX = 0;
2022-05-19 01:51:26 -07:00
}
}
}
// 0x4C219C
2022-09-15 01:42:02 -07:00
static void wmInterfaceScrollTabsStart(int delta)
2022-05-19 01:51:26 -07:00
{
int i;
int v3;
for (i = 0; i < 7; i++) {
2022-09-15 01:42:02 -07:00
buttonDisable(wmTownMapSubButtonIds[i]);
2022-05-19 01:51:26 -07:00
}
2022-09-15 01:42:02 -07:00
wmGenData.oldTabsOffsetY = wmGenData.tabsOffsetY;
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
v3 = wmGenData.tabsOffsetY + 7 * delta;
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
if (delta >= 0) {
if (wmGenData.tabsBackgroundFrmImage.getHeight() - 230 <= wmGenData.oldTabsOffsetY) {
2022-05-19 01:51:26 -07:00
goto L11;
} else {
2022-09-15 01:42:02 -07:00
wmGenData.oldTabsOffsetY = wmGenData.tabsOffsetY + 7 * delta;
if (v3 > wmGenData.tabsBackgroundFrmImage.getHeight() - 230) {
2022-05-19 01:51:26 -07:00
}
}
} else {
2022-09-15 01:42:02 -07:00
if (wmGenData.tabsOffsetY <= 0) {
2022-05-19 01:51:26 -07:00
goto L11;
} else {
2022-09-15 01:42:02 -07:00
wmGenData.oldTabsOffsetY = wmGenData.tabsOffsetY + 7 * delta;
2022-05-19 01:51:26 -07:00
if (v3 < 0) {
2022-09-15 01:42:02 -07:00
wmGenData.oldTabsOffsetY = 0;
2022-05-19 01:51:26 -07:00
}
}
}
2022-09-15 01:42:02 -07:00
wmGenData.tabsScrollingDelta = delta;
2022-05-19 01:51:26 -07:00
L11:
2022-09-01 08:41:37 -07:00
// NOTE: Uninline.
wmInterfaceScrollTabsUpdate();
2022-05-19 01:51:26 -07:00
}
// 0x4C2270
2022-09-15 01:42:02 -07:00
static void wmInterfaceScrollTabsStop()
2022-05-19 01:51:26 -07:00
{
int i;
2022-09-15 01:42:02 -07:00
wmGenData.tabsScrollingDelta = 0;
2022-05-19 01:51:26 -07:00
for (i = 0; i < 7; i++) {
2022-09-15 01:42:02 -07:00
buttonEnable(wmTownMapSubButtonIds[i]);
2022-05-19 01:51:26 -07:00
}
}
2022-09-01 08:41:37 -07:00
// NOTE: Inlined.
//
// 0x4C2290
static void wmInterfaceScrollTabsUpdate()
{
2022-09-15 01:42:02 -07:00
if (wmGenData.tabsScrollingDelta != 0) {
wmGenData.tabsOffsetY += wmGenData.tabsScrollingDelta;
wmRefreshInterfaceOverlay(1);
2022-09-01 08:41:37 -07:00
2022-09-15 01:42:02 -07:00
if (wmGenData.tabsScrollingDelta >= 0) {
if (wmGenData.oldTabsOffsetY <= wmGenData.tabsOffsetY) {
2022-09-01 08:41:37 -07:00
// NOTE: Uninline.
2022-09-15 01:42:02 -07:00
wmInterfaceScrollTabsStop();
2022-09-01 08:41:37 -07:00
}
} else {
2022-09-15 01:42:02 -07:00
if (wmGenData.oldTabsOffsetY >= wmGenData.tabsOffsetY) {
2022-09-01 08:41:37 -07:00
// NOTE: Uninline.
2022-09-15 01:42:02 -07:00
wmInterfaceScrollTabsStop();
2022-09-01 08:41:37 -07:00
}
}
}
}
2022-05-19 01:51:26 -07:00
// 0x4C2324
2022-09-15 01:42:02 -07:00
static int wmInterfaceInit()
2022-05-19 01:51:26 -07:00
{
int fid;
2022-10-05 00:11:47 -07:00
wmLastRndTime = getTicks();
2022-08-29 13:33:03 -07:00
// SFALL: Fix default worldmap font.
// CE: This setting affects only city names. In Sfall it's configurable via
// WorldMapFontPatch and is turned off by default.
2022-09-15 01:42:02 -07:00
wmGenData.oldFont = fontGetCurrent();
2022-08-29 13:33:03 -07:00
fontSetCurrent(101);
2022-05-19 01:51:26 -07:00
_map_save_in_game(true);
2022-09-15 01:42:02 -07:00
const char* backgroundSoundFileName = wmGenData.isInCar ? "20car" : "23world";
2022-05-19 01:51:26 -07:00
_gsound_background_play_level_music(backgroundSoundFileName, 12);
indicatorBarHide();
isoDisable();
colorCycleDisable();
gameMouseSetCursor(MOUSE_CURSOR_ARROW);
2022-05-20 17:25:03 -07:00
int worldmapWindowX = (screenGetWidth() - WM_WINDOW_WIDTH) / 2;
int worldmapWindowY = (screenGetHeight() - WM_WINDOW_HEIGHT) / 2;
2022-09-15 01:42:02 -07:00
wmBkWin = windowCreate(worldmapWindowX, worldmapWindowY, WM_WINDOW_WIDTH, WM_WINDOW_HEIGHT, _colorTable[0], WINDOW_FLAG_0x04);
if (wmBkWin == -1) {
2022-05-19 01:51:26 -07:00
return -1;
}
fid = buildFid(OBJ_TYPE_INTERFACE, 136, 0, 0, 0);
if (!_backgroundFrmImage.lock(fid)) {
2022-05-19 01:51:26 -07:00
return -1;
}
2022-09-15 01:42:02 -07:00
wmBkWinBuf = windowGetBuffer(wmBkWin);
if (wmBkWinBuf == NULL) {
2022-05-19 01:51:26 -07:00
return -1;
}
blitBufferToBuffer(_backgroundFrmImage.getData(),
_backgroundFrmImage.getWidth(),
_backgroundFrmImage.getHeight(),
_backgroundFrmImage.getWidth(),
wmBkWinBuf,
WM_WINDOW_WIDTH);
2022-05-19 01:51:26 -07:00
for (int citySize = 0; citySize < CITY_SIZE_COUNT; citySize++) {
2022-09-15 01:42:02 -07:00
CitySizeDescription* citySizeDescription = &(wmSphereData[citySize]);
if (!citySizeDescription->frmImage.lock(citySizeDescription->fid)) {
2022-05-19 01:51:26 -07:00
return -1;
}
}
// hotspot1.frm - town map selector shape #1
fid = buildFid(OBJ_TYPE_INTERFACE, 168, 0, 0, 0);
if (!wmGenData.hotspotNormalFrmImage.lock(fid)) {
2022-05-19 01:51:26 -07:00
return -1;
}
// hotspot2.frm - town map selector shape #2
fid = buildFid(OBJ_TYPE_INTERFACE, 223, 0, 0, 0);
if (!wmGenData.hotspotPressedFrmImage.lock(fid)) {
2022-05-19 01:51:26 -07:00
return -1;
}
// wmaptarg.frm - world map move target maker #1
fid = buildFid(OBJ_TYPE_INTERFACE, 139, 0, 0, 0);
if (!wmGenData.destinationMarkerFrmImage.lock(fid)) {
2022-05-19 01:51:26 -07:00
return -1;
}
// wmaploc.frm - world map location marker
fid = buildFid(OBJ_TYPE_INTERFACE, 138, 0, 0, 0);
if (!wmGenData.locationMarkerFrmImage.lock(fid)) {
2022-05-19 01:51:26 -07:00
return -1;
}
for (int index = 0; index < WORLD_MAP_ENCOUNTER_FRM_COUNT; index++) {
2022-09-15 01:42:02 -07:00
fid = buildFid(OBJ_TYPE_INTERFACE, wmRndCursorFids[index], 0, 0, 0);
if (!wmGenData.encounterCursorFrmImages[index].lock(fid)) {
2022-05-19 01:51:26 -07:00
return -1;
}
}
2022-09-15 01:42:02 -07:00
for (int index = 0; index < wmMaxTileNum; index++) {
wmTileInfoList[index].handle = INVALID_CACHE_ENTRY;
2022-05-19 01:51:26 -07:00
}
// wmtabs.frm - worldmap town tabs underlay
fid = buildFid(OBJ_TYPE_INTERFACE, 364, 0, 0, 0);
if (!wmGenData.tabsBackgroundFrmImage.lock(fid)) {
2022-05-19 01:51:26 -07:00
return -1;
}
// wmtbedge.frm - worldmap town tabs edging overlay
fid = buildFid(OBJ_TYPE_INTERFACE, 367, 0, 0, 0);
if (!wmGenData.tabsBorderFrmImage.lock(fid)) {
2022-05-19 01:51:26 -07:00
return -1;
}
// wmdial.frm - worldmap night/day dial
fid = buildFid(OBJ_TYPE_INTERFACE, 365, 0, 0, 0);
2022-09-15 01:42:02 -07:00
wmGenData.dialFrm = artLock(fid, &(wmGenData.dialFrmHandle));
if (wmGenData.dialFrm == NULL) {
2022-05-19 01:51:26 -07:00
return -1;
}
2022-09-15 01:42:02 -07:00
wmGenData.dialFrmWidth = artGetWidth(wmGenData.dialFrm, 0, 0);
wmGenData.dialFrmHeight = artGetHeight(wmGenData.dialFrm, 0, 0);
2022-05-19 01:51:26 -07:00
// wmscreen - worldmap overlay screen
fid = buildFid(OBJ_TYPE_INTERFACE, 363, 0, 0, 0);
if (!wmGenData.carOverlayFrmImage.lock(fid)) {
2022-05-19 01:51:26 -07:00
return -1;
}
// wmglobe.frm - worldmap globe stamp overlay
fid = buildFid(OBJ_TYPE_INTERFACE, 366, 0, 0, 0);
if (!wmGenData.globeOverlayFrmImage.lock(fid)) {
2022-05-19 01:51:26 -07:00
return -1;
}
// lilredup.frm - little red button up
fid = buildFid(OBJ_TYPE_INTERFACE, 8, 0, 0, 0);
wmGenData.redButtonNormalFrmImage.lock(fid);
2022-05-19 01:51:26 -07:00
// lilreddn.frm - little red button down
fid = buildFid(OBJ_TYPE_INTERFACE, 9, 0, 0, 0);
wmGenData.redButtonPressedFrmImage.lock(fid);
2022-05-19 01:51:26 -07:00
// months.frm - month strings for pip boy
fid = buildFid(OBJ_TYPE_INTERFACE, 129, 0, 0, 0);
if (!wmGenData.monthsFrmImage.lock(fid)) {
2022-05-19 01:51:26 -07:00
return -1;
}
// numbers.frm - numbers for the hit points and fatigue counters
fid = buildFid(OBJ_TYPE_INTERFACE, 82, 0, 0, 0);
if (!wmGenData.numbersFrmImage.lock(fid)) {
2022-05-19 01:51:26 -07:00
return -1;
}
// create town/world switch button
2022-09-15 01:42:02 -07:00
int switchBtn = buttonCreate(wmBkWin,
2022-05-19 01:51:26 -07:00
WM_TOWN_WORLD_SWITCH_X,
WM_TOWN_WORLD_SWITCH_Y,
wmGenData.redButtonNormalFrmImage.getWidth(),
wmGenData.redButtonNormalFrmImage.getHeight(),
-1,
-1,
2022-05-19 01:51:26 -07:00
-1,
KEY_UPPERCASE_T,
wmGenData.redButtonNormalFrmImage.getData(),
wmGenData.redButtonPressedFrmImage.getData(),
NULL,
2022-05-19 01:51:26 -07:00
BUTTON_FLAG_TRANSPARENT);
2022-08-29 13:35:58 -07:00
// SFALL: Add missing button sounds.
if (switchBtn != -1) {
buttonSetCallbacks(switchBtn, _gsound_red_butt_press, _gsound_red_butt_release);
}
2022-05-19 01:51:26 -07:00
for (int index = 0; index < 7; index++) {
2022-09-15 01:42:02 -07:00
wmTownMapSubButtonIds[index] = buttonCreate(wmBkWin,
508,
2022-05-19 01:51:26 -07:00
138 + 27 * index,
wmGenData.redButtonNormalFrmImage.getWidth(),
wmGenData.redButtonNormalFrmImage.getHeight(),
-1,
2022-05-19 01:51:26 -07:00
-1,
-1,
KEY_CTRL_F1 + index,
wmGenData.redButtonNormalFrmImage.getData(),
wmGenData.redButtonPressedFrmImage.getData(),
NULL,
2022-05-19 01:51:26 -07:00
BUTTON_FLAG_TRANSPARENT);
2022-08-29 13:35:58 -07:00
// SFALL: Add missing button sounds.
2022-09-15 01:42:02 -07:00
if (wmTownMapSubButtonIds[index] != -1) {
buttonSetCallbacks(wmTownMapSubButtonIds[index], _gsound_red_butt_press, _gsound_red_butt_release);
2022-08-29 13:35:58 -07:00
}
2022-05-19 01:51:26 -07:00
}
for (int index = 0; index < WORLDMAP_ARROW_FRM_COUNT; index++) {
// 200 - uparwon.frm - character editor
// 199 - uparwoff.frm - character editor
2022-08-29 13:42:36 -07:00
// SFALL: Fix images for scroll buttons.
fid = buildFid(OBJ_TYPE_INTERFACE, 199 + index, 0, 0, 0);
if (!wmGenData.scrollUpButtonFrmImages[index].lock(fid)) {
2022-05-19 01:51:26 -07:00
return -1;
}
}
for (int index = 0; index < WORLDMAP_ARROW_FRM_COUNT; index++) {
// 182 - dnarwon.frm - character editor
// 181 - dnarwoff.frm - character editor
2022-08-29 13:42:36 -07:00
// SFALL: Fix images for scroll buttons.
fid = buildFid(OBJ_TYPE_INTERFACE, 181 + index, 0, 0, 0);
if (!wmGenData.scrollDownButtonFrmImages[index].lock(fid)) {
2022-05-19 01:51:26 -07:00
return -1;
}
}
// Scroll up button.
2022-09-15 01:42:02 -07:00
int scrollUpBtn = buttonCreate(wmBkWin,
2022-05-19 01:51:26 -07:00
WM_TOWN_LIST_SCROLL_UP_X,
WM_TOWN_LIST_SCROLL_UP_Y,
wmGenData.scrollUpButtonFrmImages[WORLDMAP_ARROW_FRM_NORMAL].getWidth(),
wmGenData.scrollUpButtonFrmImages[WORLDMAP_ARROW_FRM_NORMAL].getHeight(),
-1,
-1,
2022-05-19 01:51:26 -07:00
-1,
KEY_CTRL_ARROW_UP,
wmGenData.scrollUpButtonFrmImages[WORLDMAP_ARROW_FRM_NORMAL].getData(),
wmGenData.scrollUpButtonFrmImages[WORLDMAP_ARROW_FRM_PRESSED].getData(),
2022-05-19 01:51:26 -07:00
NULL,
BUTTON_FLAG_TRANSPARENT);
2022-08-29 13:35:58 -07:00
// SFALL: Add missing button sounds.
if (scrollUpBtn != -1) {
buttonSetCallbacks(scrollUpBtn, _gsound_red_butt_press, _gsound_red_butt_release);
}
2022-05-19 01:51:26 -07:00
// Scroll down button.
2022-09-15 01:42:02 -07:00
int scrollDownBtn = buttonCreate(wmBkWin,
WM_TOWN_LIST_SCROLL_DOWN_X,
WM_TOWN_LIST_SCROLL_DOWN_Y,
wmGenData.scrollDownButtonFrmImages[WORLDMAP_ARROW_FRM_NORMAL].getWidth(),
wmGenData.scrollDownButtonFrmImages[WORLDMAP_ARROW_FRM_NORMAL].getHeight(),
2022-05-19 01:51:26 -07:00
-1,
-1,
-1,
2022-05-19 01:51:26 -07:00
KEY_CTRL_ARROW_DOWN,
wmGenData.scrollUpButtonFrmImages[WORLDMAP_ARROW_FRM_NORMAL].getData(),
wmGenData.scrollUpButtonFrmImages[WORLDMAP_ARROW_FRM_PRESSED].getData(),
NULL,
2022-05-19 01:51:26 -07:00
BUTTON_FLAG_TRANSPARENT);
2022-08-29 13:35:58 -07:00
// SFALL: Add missing button sounds.
if (scrollDownBtn != -1) {
buttonSetCallbacks(scrollDownBtn, _gsound_red_butt_press, _gsound_red_butt_release);
}
2022-09-15 01:42:02 -07:00
if (wmGenData.isInCar) {
2022-05-19 01:51:26 -07:00
// wmcarmve.frm - worldmap car movie
fid = buildFid(OBJ_TYPE_INTERFACE, 433, 0, 0, 0);
2022-09-15 01:42:02 -07:00
wmGenData.carImageFrm = artLock(fid, &(wmGenData.carImageFrmHandle));
if (wmGenData.carImageFrm == NULL) {
2022-05-19 01:51:26 -07:00
return -1;
}
2022-09-15 01:42:02 -07:00
wmGenData.carImageFrmWidth = artGetWidth(wmGenData.carImageFrm, 0, 0);
wmGenData.carImageFrmHeight = artGetHeight(wmGenData.carImageFrm, 0, 0);
2022-05-19 01:51:26 -07:00
}
2022-09-15 01:42:02 -07:00
tickersAdd(wmMouseBkProc);
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
if (wmMakeTabsLabelList(&wmLabelList, &wmLabelCount) == -1) {
2022-05-19 01:51:26 -07:00
return -1;
}
2022-09-15 01:42:02 -07:00
wmInterfaceWasInitialized = 1;
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
if (wmInterfaceRefresh() == -1) {
2022-05-19 01:51:26 -07:00
return -1;
}
2022-09-15 01:42:02 -07:00
windowRefresh(wmBkWin);
2022-05-19 01:51:26 -07:00
scriptsDisable();
_scr_remove_all();
return 0;
}
// 0x4C2E44
2022-09-15 01:42:02 -07:00
static int wmInterfaceExit()
2022-05-19 01:51:26 -07:00
{
int i;
TileInfo* tile;
2022-09-15 01:42:02 -07:00
tickersRemove(wmMouseBkProc);
2022-05-19 01:51:26 -07:00
_backgroundFrmImage.unlock();
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
if (wmBkWin != -1) {
windowDestroy(wmBkWin);
wmBkWin = -1;
2022-05-19 01:51:26 -07:00
}
wmGenData.hotspotNormalFrmImage.unlock();
wmGenData.hotspotPressedFrmImage.unlock();
2022-05-19 01:51:26 -07:00
wmGenData.destinationMarkerFrmImage.unlock();
wmGenData.locationMarkerFrmImage.unlock();
2022-05-19 01:51:26 -07:00
for (i = 0; i < 4; i++) {
wmGenData.encounterCursorFrmImages[i].unlock();
2022-05-19 01:51:26 -07:00
}
for (i = 0; i < CITY_SIZE_COUNT; i++) {
2022-09-15 01:42:02 -07:00
CitySizeDescription* citySizeDescription = &(wmSphereData[i]);
citySizeDescription->frmImage.unlock();
2022-05-19 01:51:26 -07:00
}
2022-09-15 01:42:02 -07:00
for (i = 0; i < wmMaxTileNum; i++) {
tile = &(wmTileInfoList[i]);
2022-05-19 01:51:26 -07:00
if (tile->handle != INVALID_CACHE_ENTRY) {
artUnlock(tile->handle);
tile->handle = INVALID_CACHE_ENTRY;
tile->data = NULL;
if (tile->walkMaskData != NULL) {
internal_free(tile->walkMaskData);
tile->walkMaskData = NULL;
}
}
}
wmGenData.tabsBackgroundFrmImage.unlock();
wmGenData.tabsBorderFrmImage.unlock();
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
if (wmGenData.dialFrm != NULL) {
artUnlock(wmGenData.dialFrmHandle);
wmGenData.dialFrmHandle = INVALID_CACHE_ENTRY;
wmGenData.dialFrm = NULL;
2022-05-19 01:51:26 -07:00
}
wmGenData.carOverlayFrmImage.unlock();
wmGenData.globeOverlayFrmImage.unlock();
2022-05-19 01:51:26 -07:00
wmGenData.redButtonNormalFrmImage.unlock();
wmGenData.redButtonPressedFrmImage.unlock();
2022-05-19 01:51:26 -07:00
for (i = 0; i < 2; i++) {
wmGenData.scrollUpButtonFrmImages[i].unlock();
wmGenData.scrollDownButtonFrmImages[i].unlock();
2022-05-19 01:51:26 -07:00
}
wmGenData.monthsFrmImage.unlock();
wmGenData.numbersFrmImage.unlock();
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
if (wmGenData.carImageFrm != NULL) {
artUnlock(wmGenData.carImageFrmHandle);
wmGenData.carImageFrmHandle = INVALID_CACHE_ENTRY;
wmGenData.carImageFrm = NULL;
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
wmGenData.carImageFrmWidth = 0;
wmGenData.carImageFrmHeight = 0;
2022-05-19 01:51:26 -07:00
}
2022-09-15 01:42:02 -07:00
wmGenData.encounterIconIsVisible = 0;
wmGenData.encounterMapId = -1;
wmGenData.encounterTableId = -1;
wmGenData.encounterEntryId = -1;
2022-05-19 01:51:26 -07:00
indicatorBarShow();
isoEnable();
colorCycleEnable();
2022-09-15 01:42:02 -07:00
fontSetCurrent(wmGenData.oldFont);
2022-05-19 01:51:26 -07:00
2022-09-01 08:41:37 -07:00
// NOTE: Uninline.
2022-09-15 01:42:02 -07:00
wmFreeTabsLabelList(&wmLabelList, &wmLabelCount);
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
wmInterfaceWasInitialized = 0;
2022-05-19 01:51:26 -07:00
scriptsEnable();
return 0;
}
2022-09-01 08:41:37 -07:00
// NOTE: Inlined.
//
// 0x4C31E8
static int wmInterfaceScroll(int dx, int dy, bool* successPtr)
{
2022-09-15 01:42:02 -07:00
return wmInterfaceScrollPixel(20, 20, dx, dy, successPtr, 1);
2022-09-01 08:41:37 -07:00
}
2022-05-19 01:51:26 -07:00
// FIXME: There is small bug in this function. There is [success] flag returned
// by reference so that calling code can update scrolling mouse cursor to invalid
// range. It works OK on straight directions. But in diagonals when scrolling in
// one direction is possible (and in fact occured), it will still be reported as
// error.
//
// 0x4C3200
2022-09-15 01:42:02 -07:00
static int wmInterfaceScrollPixel(int stepX, int stepY, int dx, int dy, bool* success, bool shouldRefresh)
2022-05-19 01:51:26 -07:00
{
2022-09-15 01:42:02 -07:00
int v6 = wmWorldOffsetY;
int v7 = wmWorldOffsetX;
2022-05-19 01:51:26 -07:00
if (success != NULL) {
*success = true;
}
if (dy < 0) {
if (v6 > 0) {
v6 -= stepY;
if (v6 < 0) {
v6 = 0;
}
} else {
if (success != NULL) {
*success = false;
}
}
} else if (dy > 0) {
2022-09-15 01:42:02 -07:00
if (v6 < wmGenData.viewportMaxY) {
2022-05-19 01:51:26 -07:00
v6 += stepY;
2022-09-15 01:42:02 -07:00
if (v6 > wmGenData.viewportMaxY) {
v6 = wmGenData.viewportMaxY;
2022-05-19 01:51:26 -07:00
}
} else {
if (success != NULL) {
*success = false;
}
}
}
if (dx < 0) {
if (v7 > 0) {
v7 -= stepX;
if (v7 < 0) {
v7 = 0;
}
} else {
if (success != NULL) {
*success = false;
}
}
} else if (dx > 0) {
2022-09-15 01:42:02 -07:00
if (v7 < wmGenData.viewportMaxX) {
2022-05-19 01:51:26 -07:00
v7 += stepX;
2022-09-15 01:42:02 -07:00
if (v7 > wmGenData.viewportMaxX) {
v7 = wmGenData.viewportMaxX;
2022-05-19 01:51:26 -07:00
}
} else {
if (success != NULL) {
*success = false;
}
}
}
2022-09-15 01:42:02 -07:00
wmWorldOffsetY = v6;
wmWorldOffsetX = v7;
2022-05-19 01:51:26 -07:00
if (shouldRefresh) {
2022-09-15 01:42:02 -07:00
if (wmInterfaceRefresh() == -1) {
2022-05-19 01:51:26 -07:00
return -1;
}
}
return 0;
}
// 0x4C32EC
2022-09-15 01:42:02 -07:00
static void wmMouseBkProc()
2022-05-19 01:51:26 -07:00
{
int x;
int y;
2022-09-15 01:42:02 -07:00
mouseGetPositionInWindow(wmBkWin, &x, &y);
2022-05-19 01:51:26 -07:00
int dx = 0;
if (x == 639) {
dx = 1;
} else if (x == 0) {
dx = -1;
}
int dy = 0;
if (y == 479) {
dy = 1;
} else if (y == 0) {
dy = -1;
}
int oldMouseCursor = gameMouseGetCursor();
int newMouseCursor = oldMouseCursor;
if (dx != 0 || dy != 0) {
if (dx > 0) {
if (dy > 0) {
newMouseCursor = MOUSE_CURSOR_SCROLL_SE;
} else if (dy < 0) {
newMouseCursor = MOUSE_CURSOR_SCROLL_NE;
} else {
newMouseCursor = MOUSE_CURSOR_SCROLL_E;
}
} else if (dx < 0) {
if (dy > 0) {
newMouseCursor = MOUSE_CURSOR_SCROLL_SW;
} else if (dy < 0) {
newMouseCursor = MOUSE_CURSOR_SCROLL_NW;
} else {
newMouseCursor = MOUSE_CURSOR_SCROLL_W;
}
} else {
if (dy < 0) {
newMouseCursor = MOUSE_CURSOR_SCROLL_N;
} else if (dy > 0) {
newMouseCursor = MOUSE_CURSOR_SCROLL_S;
}
}
unsigned int tick = _get_bk_time();
if (getTicksBetween(tick, _lastTime_2) > 50) {
_lastTime_2 = _get_bk_time();
2022-09-01 08:41:37 -07:00
// NOTE: Uninline.
wmInterfaceScroll(dx, dy, &_couldScroll);
2022-05-19 01:51:26 -07:00
}
if (!_couldScroll) {
newMouseCursor += 8;
}
} else {
if (oldMouseCursor != MOUSE_CURSOR_ARROW) {
newMouseCursor = MOUSE_CURSOR_ARROW;
}
}
if (oldMouseCursor != newMouseCursor) {
gameMouseSetCursor(newMouseCursor);
}
}
2022-09-01 08:41:37 -07:00
// NOTE: Inlined.
//
// 0x4C340C
static int wmMarkSubTileOffsetVisited(int tile, int subtileX, int subtileY, int offsetX, int offsetY)
{
return wmMarkSubTileOffsetVisitedFunc(tile, subtileX, subtileY, offsetX, offsetY, SUBTILE_STATE_VISITED);
}
// NOTE: Inlined.
//
// 0x4C3420
static int wmMarkSubTileOffsetKnown(int tile, int subtileX, int subtileY, int offsetX, int offsetY)
{
return wmMarkSubTileOffsetVisitedFunc(tile, subtileX, subtileY, offsetX, offsetY, SUBTILE_STATE_KNOWN);
}
2022-05-19 01:51:26 -07:00
// 0x4C3434
2022-09-01 08:41:37 -07:00
static int wmMarkSubTileOffsetVisitedFunc(int tile, int subtileX, int subtileY, int offsetX, int offsetY, int subtileState)
2022-05-19 01:51:26 -07:00
{
2022-09-01 08:41:37 -07:00
int actualTile;
int actualSubtileX;
int actualSubtileY;
TileInfo* tileInfo;
SubtileInfo* subtileInfo;
2022-05-19 01:51:26 -07:00
2022-09-01 08:41:37 -07:00
actualSubtileX = subtileX + offsetX;
actualTile = tile;
actualSubtileY = subtileY + offsetY;
2022-05-19 01:51:26 -07:00
2022-09-01 08:41:37 -07:00
if (actualSubtileX >= 0) {
if (actualSubtileX >= SUBTILE_GRID_WIDTH) {
2022-09-15 01:42:02 -07:00
if (tile % wmNumHorizontalTiles == wmNumHorizontalTiles - 1) {
2022-05-19 01:51:26 -07:00
return -1;
}
2022-09-01 08:41:37 -07:00
actualTile = tile + 1;
actualSubtileX %= SUBTILE_GRID_WIDTH;
2022-05-19 01:51:26 -07:00
}
} else {
2022-09-15 01:42:02 -07:00
if (!(tile % wmNumHorizontalTiles)) {
2022-05-19 01:51:26 -07:00
return -1;
}
2022-09-01 08:41:37 -07:00
actualSubtileX += SUBTILE_GRID_WIDTH;
actualTile = tile - 1;
2022-05-19 01:51:26 -07:00
}
2022-09-01 08:41:37 -07:00
if (actualSubtileY >= 0) {
if (actualSubtileY >= SUBTILE_GRID_HEIGHT) {
2022-09-15 01:42:02 -07:00
if (actualTile > wmMaxTileNum - wmNumHorizontalTiles - 1) {
2022-05-19 01:51:26 -07:00
return -1;
}
2022-09-15 01:42:02 -07:00
actualTile += wmNumHorizontalTiles;
2022-09-01 08:41:37 -07:00
actualSubtileY %= SUBTILE_GRID_HEIGHT;
2022-05-19 01:51:26 -07:00
}
} else {
2022-09-15 01:42:02 -07:00
if (actualTile < wmNumHorizontalTiles) {
2022-05-19 01:51:26 -07:00
return -1;
}
2022-09-01 08:41:37 -07:00
actualSubtileY += SUBTILE_GRID_HEIGHT;
2022-09-15 01:42:02 -07:00
actualTile -= wmNumHorizontalTiles;
2022-05-19 01:51:26 -07:00
}
2022-09-15 01:42:02 -07:00
tileInfo = &(wmTileInfoList[actualTile]);
2022-09-01 08:41:37 -07:00
subtileInfo = &(tileInfo->subtiles[actualSubtileY][actualSubtileX]);
if (subtileState != SUBTILE_STATE_KNOWN || subtileInfo->state == SUBTILE_STATE_UNKNOWN) {
subtileInfo->state = subtileState;
2022-05-19 01:51:26 -07:00
}
return 0;
}
// 0x4C3550
2022-09-15 01:42:02 -07:00
static void wmMarkSubTileRadiusVisited(int x, int y)
2022-05-19 01:51:26 -07:00
{
int radius = 1;
if (perkHasRank(gDude, PERK_SCOUT)) {
radius = 2;
}
2022-09-01 08:41:37 -07:00
wmSubTileMarkRadiusVisited(x, y, radius);
2022-05-19 01:51:26 -07:00
}
// 0x4C35A8
2022-09-01 08:41:37 -07:00
int wmSubTileMarkRadiusVisited(int x, int y, int radius)
2022-05-19 01:51:26 -07:00
{
2022-09-01 08:41:37 -07:00
int tile;
int subtileX;
int subtileY;
int offsetX;
int offsetY;
SubtileInfo* subtile;
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
tile = x / WM_TILE_WIDTH % wmNumHorizontalTiles + y / WM_TILE_HEIGHT * wmNumHorizontalTiles;
2022-09-01 08:41:37 -07:00
subtileX = x % WM_TILE_WIDTH / WM_SUBTILE_SIZE;
subtileY = y % WM_TILE_HEIGHT / WM_SUBTILE_SIZE;
2022-05-19 01:51:26 -07:00
2022-09-01 08:41:37 -07:00
for (offsetY = -radius; offsetY <= radius; offsetY++) {
for (offsetX = -radius; offsetX <= radius; offsetX++) {
// NOTE: Uninline.
wmMarkSubTileOffsetKnown(tile, subtileX, subtileY, offsetX, offsetY);
2022-05-19 01:51:26 -07:00
}
}
2022-09-15 01:42:02 -07:00
subtile = &(wmTileInfoList[tile].subtiles[subtileY][subtileX]);
2022-05-19 01:51:26 -07:00
subtile->state = SUBTILE_STATE_VISITED;
switch (subtile->field_4) {
case 2:
2022-09-01 08:41:37 -07:00
while (subtileY-- > 0) {
// NOTE: Uninline.
wmMarkSubTileOffsetVisited(tile, subtileX, subtileY, 0, 0);
2022-05-19 01:51:26 -07:00
}
break;
case 4:
2022-09-01 08:41:37 -07:00
while (subtileX-- >= 0) {
// NOTE: Uninline.
wmMarkSubTileOffsetVisited(tile, subtileX, subtileY, 0, 0);
2022-05-19 01:51:26 -07:00
}
2022-09-15 01:42:02 -07:00
if (tile % wmNumHorizontalTiles > 0) {
2022-09-01 08:41:37 -07:00
for (subtileX = 0; subtileX < SUBTILE_GRID_WIDTH; subtileX++) {
// NOTE: Uninline.
wmMarkSubTileOffsetVisited(tile - 1, subtileX, subtileY, 0, 0);
2022-05-19 01:51:26 -07:00
}
}
break;
}
return 0;
}
// 0x4C3740
2022-09-15 01:42:02 -07:00
int wmSubTileGetVisitedState(int x, int y, int* statePtr)
2022-05-19 01:51:26 -07:00
{
TileInfo* tile;
2022-09-15 01:42:02 -07:00
SubtileInfo* subtile;
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
tile = &(wmTileInfoList[y / WM_TILE_HEIGHT * wmNumHorizontalTiles + x / WM_TILE_WIDTH % wmNumHorizontalTiles]);
subtile = &(tile->subtiles[y % WM_TILE_HEIGHT / WM_SUBTILE_SIZE][x % WM_TILE_WIDTH / WM_SUBTILE_SIZE]);
*statePtr = subtile->state;
2022-05-19 01:51:26 -07:00
return 0;
}
// Load tile art if needed.
//
// 0x4C37EC
2022-09-15 01:42:02 -07:00
static int wmTileGrabArt(int tileIdx)
2022-05-19 01:51:26 -07:00
{
2022-09-15 01:42:02 -07:00
TileInfo* tile = &(wmTileInfoList[tileIdx]);
2022-05-19 01:51:26 -07:00
if (tile->data != NULL) {
return 0;
}
tile->data = artLockFrameData(tile->fid, 0, 0, &(tile->handle));
if (tile->data != NULL) {
return 0;
}
2022-09-15 01:42:02 -07:00
wmInterfaceExit();
2022-05-19 01:51:26 -07:00
return -1;
}
// 0x4C3830
2022-09-15 01:42:02 -07:00
static int wmInterfaceRefresh()
2022-05-19 01:51:26 -07:00
{
2022-09-15 01:42:02 -07:00
if (wmInterfaceWasInitialized != 1) {
2022-05-19 01:51:26 -07:00
return 0;
}
2022-09-15 01:42:02 -07:00
int v17 = wmWorldOffsetX % WM_TILE_WIDTH;
int v18 = wmWorldOffsetY % WM_TILE_HEIGHT;
2022-05-19 01:51:26 -07:00
int v20 = WM_TILE_HEIGHT - v18;
int v21 = WM_TILE_WIDTH * v18;
int v19 = WM_TILE_WIDTH - v17;
// Render tiles.
int y = 0;
int x = 0;
2022-09-15 01:42:02 -07:00
int v0 = wmWorldOffsetY / WM_TILE_HEIGHT * wmNumHorizontalTiles + wmWorldOffsetX / WM_TILE_WIDTH % wmNumHorizontalTiles;
2022-05-19 01:51:26 -07:00
while (y < WM_VIEW_HEIGHT) {
x = 0;
int v23 = 0;
int height;
while (x < WM_VIEW_WIDTH) {
2022-09-15 01:42:02 -07:00
if (wmTileGrabArt(v0) == -1) {
2022-05-19 01:51:26 -07:00
return -1;
}
int width = WM_TILE_WIDTH;
int srcX = 0;
if (x == 0) {
srcX = v17;
width = v19;
}
if (width + x > WM_VIEW_WIDTH) {
width = WM_VIEW_WIDTH - x;
}
height = WM_TILE_HEIGHT;
if (y == 0) {
height = v20;
srcX += v21;
}
if (height + y > WM_VIEW_HEIGHT) {
height = WM_VIEW_HEIGHT - y;
}
2022-09-15 01:42:02 -07:00
TileInfo* tileInfo = &(wmTileInfoList[v0]);
2022-05-19 01:51:26 -07:00
blitBufferToBuffer(tileInfo->data + srcX,
width,
height,
WM_TILE_WIDTH,
2022-09-15 01:42:02 -07:00
wmBkWinBuf + WM_WINDOW_WIDTH * (y + WM_VIEW_Y) + WM_VIEW_X + x,
2022-05-19 01:51:26 -07:00
WM_WINDOW_WIDTH);
v0++;
x += width;
v23++;
}
2022-09-15 01:42:02 -07:00
v0 += wmNumHorizontalTiles - v23;
2022-05-19 01:51:26 -07:00
y += height;
}
// Render cities.
2022-09-15 01:42:02 -07:00
for (int index = 0; index < wmMaxAreaNum; index++) {
CityInfo* cityInfo = &(wmAreaInfoList[index]);
2022-05-19 01:51:26 -07:00
if (cityInfo->state != CITY_STATE_UNKNOWN) {
2022-09-15 01:42:02 -07:00
CitySizeDescription* citySizeDescription = &(wmSphereData[cityInfo->size]);
int cityX = cityInfo->x - wmWorldOffsetX;
int cityY = cityInfo->y - wmWorldOffsetY;
if (cityX >= 0 && cityX <= 472 - citySizeDescription->frmImage.getWidth()
&& cityY >= 0 && cityY <= 465 - citySizeDescription->frmImage.getHeight()) {
2022-09-15 01:42:02 -07:00
wmInterfaceDrawCircleOverlay(cityInfo, citySizeDescription, wmBkWinBuf, cityX, cityY);
2022-05-19 01:51:26 -07:00
}
}
}
// Hide unknown subtiles, dim unvisited.
2022-09-15 01:42:02 -07:00
int v25 = wmWorldOffsetX / WM_TILE_WIDTH % wmNumHorizontalTiles + wmWorldOffsetY / WM_TILE_HEIGHT * wmNumHorizontalTiles;
2022-05-19 01:51:26 -07:00
int v30 = 0;
while (v30 < WM_VIEW_HEIGHT) {
int v24 = 0;
int v33 = 0;
int v29;
while (v33 < WM_VIEW_WIDTH) {
int v31 = WM_TILE_WIDTH;
if (v33 == 0) {
v31 = WM_TILE_WIDTH - v17;
}
if (v33 + v31 > WM_VIEW_WIDTH) {
v31 = WM_VIEW_WIDTH - v33;
}
v29 = WM_TILE_HEIGHT;
if (v30 == 0) {
v29 -= v18;
}
if (v30 + v29 > WM_VIEW_HEIGHT) {
v29 = WM_VIEW_HEIGHT - v30;
}
int v32;
if (v30 != 0) {
v32 = WM_VIEW_Y;
} else {
v32 = WM_VIEW_Y - v18;
}
int v13 = 0;
int v34 = v30 + v32;
for (int row = 0; row < SUBTILE_GRID_HEIGHT; row++) {
int v35;
if (v33 != 0) {
v35 = WM_VIEW_X;
} else {
v35 = WM_VIEW_X - v17;
}
int v15 = v33 + v35;
for (int column = 0; column < SUBTILE_GRID_WIDTH; column++) {
2022-09-15 01:42:02 -07:00
TileInfo* tileInfo = &(wmTileInfoList[v25]);
wmInterfaceDrawSubTileList(tileInfo, column, row, v15, v34, 1);
2022-05-19 01:51:26 -07:00
v15 += WM_SUBTILE_SIZE;
v35 += WM_SUBTILE_SIZE;
}
v32 += WM_SUBTILE_SIZE;
v34 += WM_SUBTILE_SIZE;
}
v25++;
v24++;
v33 += v31;
}
2022-09-15 01:42:02 -07:00
v25 += wmNumHorizontalTiles - v24;
2022-05-19 01:51:26 -07:00
v30 += v29;
}
2022-09-15 01:42:02 -07:00
wmDrawCursorStopped();
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
wmRefreshInterfaceOverlay(true);
2022-05-19 01:51:26 -07:00
return 0;
}
// 0x4C3C9C
2022-09-15 01:42:02 -07:00
static void wmInterfaceRefreshDate(bool shouldRefreshWindow)
2022-05-19 01:51:26 -07:00
{
int month;
int day;
int year;
gameTimeGetDate(&month, &day, &year);
month--;
2022-09-15 01:42:02 -07:00
unsigned char* dest = wmBkWinBuf;
2022-05-19 01:51:26 -07:00
int numbersFrmWidth = wmGenData.numbersFrmImage.getWidth();
int numbersFrmHeight = wmGenData.numbersFrmImage.getHeight();
unsigned char* numbersFrmData = wmGenData.numbersFrmImage.getData();
2022-05-19 01:51:26 -07:00
dest += WM_WINDOW_WIDTH * 12 + 487;
blitBufferToBuffer(numbersFrmData + 9 * (day / 10), 9, numbersFrmHeight, numbersFrmWidth, dest, WM_WINDOW_WIDTH);
blitBufferToBuffer(numbersFrmData + 9 * (day % 10), 9, numbersFrmHeight, numbersFrmWidth, dest + 9, WM_WINDOW_WIDTH);
int monthsFrmWidth = wmGenData.monthsFrmImage.getWidth();
unsigned char* monthsFrmData = wmGenData.monthsFrmImage.getData();
2022-05-19 01:51:26 -07:00
blitBufferToBuffer(monthsFrmData + monthsFrmWidth * 15 * month, 29, 14, 29, dest + WM_WINDOW_WIDTH + 26, WM_WINDOW_WIDTH);
dest += 98;
for (int index = 0; index < 4; index++) {
dest -= 9;
blitBufferToBuffer(numbersFrmData + 9 * (year % 10), 9, numbersFrmHeight, numbersFrmWidth, dest, WM_WINDOW_WIDTH);
year /= 10;
}
int gameTimeHour = gameTimeGetHour();
dest += 72;
for (int index = 0; index < 4; index++) {
blitBufferToBuffer(numbersFrmData + 9 * (gameTimeHour % 10), 9, numbersFrmHeight, numbersFrmWidth, dest, WM_WINDOW_WIDTH);
dest -= 9;
gameTimeHour /= 10;
}
if (shouldRefreshWindow) {
Rect rect;
rect.left = 487;
rect.top = 12;
rect.bottom = numbersFrmHeight + 12;
rect.right = 630;
2022-09-15 01:42:02 -07:00
windowRefreshRect(wmBkWin, &rect);
2022-05-19 01:51:26 -07:00
}
}
// 0x4C3F00
2022-09-15 01:42:02 -07:00
static int wmMatchWorldPosToArea(int x, int y, int* areaIdxPtr)
2022-05-19 01:51:26 -07:00
{
2022-09-15 01:42:02 -07:00
int v3 = y + WM_VIEW_Y;
int v4 = x + WM_VIEW_X;
2022-05-19 01:51:26 -07:00
int index;
2022-09-15 01:42:02 -07:00
for (index = 0; index < wmMaxAreaNum; index++) {
CityInfo* city = &(wmAreaInfoList[index]);
2022-05-19 01:51:26 -07:00
if (city->state) {
if (v4 >= city->x && v3 >= city->y) {
2022-09-15 01:42:02 -07:00
CitySizeDescription* citySizeDescription = &(wmSphereData[city->size]);
if (v4 <= city->x + citySizeDescription->frmImage.getWidth() && v3 <= city->y + citySizeDescription->frmImage.getHeight()) {
2022-05-19 01:51:26 -07:00
break;
}
}
}
}
2022-09-15 01:42:02 -07:00
if (index == wmMaxAreaNum) {
*areaIdxPtr = -1;
2022-05-19 01:51:26 -07:00
} else {
2022-09-15 01:42:02 -07:00
*areaIdxPtr = index;
2022-05-19 01:51:26 -07:00
}
return 0;
}
// 0x4C3FA8
2022-09-15 01:42:02 -07:00
static int wmInterfaceDrawCircleOverlay(CityInfo* city, CitySizeDescription* citySizeDescription, unsigned char* dest, int x, int y)
2022-05-19 01:51:26 -07:00
{
_dark_translucent_trans_buf_to_buf(citySizeDescription->frmImage.getData(),
citySizeDescription->frmImage.getWidth(),
citySizeDescription->frmImage.getHeight(),
citySizeDescription->frmImage.getWidth(),
2022-05-19 01:51:26 -07:00
dest,
x,
y,
WM_WINDOW_WIDTH,
0x10000,
2022-09-15 01:42:02 -07:00
circleBlendTable,
2022-05-19 01:51:26 -07:00
_commonGrayTable);
2022-08-29 13:33:03 -07:00
// CE: Slightly increase whitespace between cirle and city name.
int nameY = y + citySizeDescription->frmImage.getHeight() + 3;
2022-05-19 01:51:26 -07:00
int maxY = 464 - fontGetLineHeight();
if (nameY < maxY) {
MessageListItem messageListItem;
2022-09-01 08:41:37 -07:00
char name[40];
2022-09-15 01:42:02 -07:00
if (wmAreaIsKnown(city->areaId)) {
2022-09-01 08:41:37 -07:00
// NOTE: Uninline.
wmGetAreaName(city, name);
2022-05-19 01:51:26 -07:00
} else {
2022-09-15 01:42:02 -07:00
strncpy(name, getmsg(&wmMsgFile, &messageListItem, 1004), 40);
2022-05-19 01:51:26 -07:00
}
2022-09-01 08:41:37 -07:00
int width = fontGetStringWidth(name);
fontDrawText(dest + WM_WINDOW_WIDTH * nameY + x + citySizeDescription->frmImage.getWidth() / 2 - width / 2,
2022-09-01 08:41:37 -07:00
name,
width,
WM_WINDOW_WIDTH,
_colorTable[992]);
2022-05-19 01:51:26 -07:00
}
return 0;
}
// Helper function that dims specified rectangle in given buffer. It's used to
// slightly darken subtile which is known, but not visited.
//
// 0x4C40A8
2022-09-15 01:42:02 -07:00
static void wmInterfaceDrawSubTileRectFogged(unsigned char* dest, int width, int height, int pitch)
2022-05-19 01:51:26 -07:00
{
int skipY = pitch - width;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
unsigned char byte = *dest;
unsigned int index = (byte << 8) + 75;
*dest++ = _intensityColorTable[index];
}
dest += skipY;
}
}
// 0x4C40E4
2022-09-15 01:42:02 -07:00
static int wmInterfaceDrawSubTileList(TileInfo* tileInfo, int column, int row, int x, int y, int a6)
2022-05-19 01:51:26 -07:00
{
SubtileInfo* subtileInfo = &(tileInfo->subtiles[row][column]);
int destY = y;
int destX = x;
int height = WM_SUBTILE_SIZE;
if (y < WM_VIEW_Y) {
if (y < 0) {
height = y + 29;
} else {
height = WM_SUBTILE_SIZE - (WM_VIEW_Y - y);
}
destY = WM_VIEW_Y;
}
if (height + y > 464) {
height -= height + y - 464;
}
int width = WM_SUBTILE_SIZE * a6;
if (x < WM_VIEW_X) {
destX = WM_VIEW_X;
width -= WM_VIEW_X - x;
}
if (width + x > 472) {
width -= width + x - 472;
}
if (width > 0 && height > 0) {
2022-09-15 01:42:02 -07:00
unsigned char* dest = wmBkWinBuf + WM_WINDOW_WIDTH * destY + destX;
2022-05-19 01:51:26 -07:00
switch (subtileInfo->state) {
case SUBTILE_STATE_UNKNOWN:
bufferFill(dest, width, height, WM_WINDOW_WIDTH, _colorTable[0]);
break;
case SUBTILE_STATE_KNOWN:
2022-09-15 01:42:02 -07:00
wmInterfaceDrawSubTileRectFogged(dest, width, height, WM_WINDOW_WIDTH);
2022-05-19 01:51:26 -07:00
break;
}
}
return 0;
}
// 0x4C41EC
2022-09-15 01:42:02 -07:00
static int wmDrawCursorStopped()
2022-05-19 01:51:26 -07:00
{
unsigned char* src;
int width;
int height;
2022-09-15 01:42:02 -07:00
if (wmGenData.walkDestinationX >= 1 || wmGenData.walkDestinationY >= 1) {
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
if (wmGenData.encounterIconIsVisible == 1) {
src = wmGenData.encounterCursorFrmImages[wmGenData.encounterCursorId].getData();
width = wmGenData.encounterCursorFrmImages[wmGenData.encounterCursorId].getWidth();
height = wmGenData.encounterCursorFrmImages[wmGenData.encounterCursorId].getHeight();
2022-05-19 01:51:26 -07:00
} else {
src = wmGenData.locationMarkerFrmImage.getData();
width = wmGenData.locationMarkerFrmImage.getWidth();
height = wmGenData.locationMarkerFrmImage.getHeight();
2022-05-19 01:51:26 -07:00
}
2022-09-15 01:42:02 -07:00
if (wmGenData.worldPosX >= wmWorldOffsetX && wmGenData.worldPosX < wmWorldOffsetX + WM_VIEW_WIDTH
&& wmGenData.worldPosY >= wmWorldOffsetY && wmGenData.worldPosY < wmWorldOffsetY + WM_VIEW_HEIGHT) {
blitBufferToBufferTrans(src, width, height, width, wmBkWinBuf + WM_WINDOW_WIDTH * (WM_VIEW_Y - wmWorldOffsetY + wmGenData.worldPosY - height / 2) + WM_VIEW_X - wmWorldOffsetX + wmGenData.worldPosX - width / 2, WM_WINDOW_WIDTH);
2022-05-19 01:51:26 -07:00
}
2022-09-15 01:42:02 -07:00
if (wmGenData.walkDestinationX >= wmWorldOffsetX && wmGenData.walkDestinationX < wmWorldOffsetX + WM_VIEW_WIDTH
&& wmGenData.walkDestinationY >= wmWorldOffsetY && wmGenData.walkDestinationY < wmWorldOffsetY + WM_VIEW_HEIGHT) {
blitBufferToBufferTrans(wmGenData.destinationMarkerFrmImage.getData(),
wmGenData.destinationMarkerFrmImage.getWidth(),
wmGenData.destinationMarkerFrmImage.getHeight(),
wmGenData.destinationMarkerFrmImage.getWidth(),
wmBkWinBuf + WM_WINDOW_WIDTH * (WM_VIEW_Y - wmWorldOffsetY + wmGenData.walkDestinationY - wmGenData.destinationMarkerFrmImage.getHeight() / 2) + WM_VIEW_X - wmWorldOffsetX + wmGenData.walkDestinationX - wmGenData.destinationMarkerFrmImage.getWidth() / 2,
WM_WINDOW_WIDTH);
2022-05-19 01:51:26 -07:00
}
} else {
2022-09-15 01:42:02 -07:00
if (wmGenData.encounterIconIsVisible == 1) {
src = wmGenData.encounterCursorFrmImages[wmGenData.encounterCursorId].getData();
width = wmGenData.encounterCursorFrmImages[wmGenData.encounterCursorId].getWidth();
height = wmGenData.encounterCursorFrmImages[wmGenData.encounterCursorId].getHeight();
2022-05-19 01:51:26 -07:00
} else {
src = wmGenData.mousePressed ? wmGenData.hotspotPressedFrmImage.getData() : wmGenData.hotspotNormalFrmImage.getData();
width = wmGenData.hotspotNormalFrmImage.getWidth();
height = wmGenData.hotspotNormalFrmImage.getHeight();
2022-05-19 01:51:26 -07:00
}
2022-09-15 01:42:02 -07:00
if (wmGenData.worldPosX >= wmWorldOffsetX && wmGenData.worldPosX < wmWorldOffsetX + WM_VIEW_WIDTH
&& wmGenData.worldPosY >= wmWorldOffsetY && wmGenData.worldPosY < wmWorldOffsetY + WM_VIEW_HEIGHT) {
blitBufferToBufferTrans(src, width, height, width, wmBkWinBuf + WM_WINDOW_WIDTH * (WM_VIEW_Y - wmWorldOffsetY + wmGenData.worldPosY - height / 2) + WM_VIEW_X - wmWorldOffsetX + wmGenData.worldPosX - width / 2, WM_WINDOW_WIDTH);
2022-05-19 01:51:26 -07:00
}
}
return 0;
}
// 0x4C4490
2022-09-15 01:42:02 -07:00
static bool wmCursorIsVisible()
2022-05-19 01:51:26 -07:00
{
2022-09-15 01:42:02 -07:00
return wmGenData.worldPosX >= wmWorldOffsetX
&& wmGenData.worldPosY >= wmWorldOffsetY
&& wmGenData.worldPosX < wmWorldOffsetX + WM_VIEW_WIDTH
&& wmGenData.worldPosY < wmWorldOffsetY + WM_VIEW_HEIGHT;
2022-05-19 01:51:26 -07:00
}
2022-09-01 08:41:37 -07:00
// NOTE: Inlined.
//
// 0x4C44D8
static int wmGetAreaName(CityInfo* city, char* name)
{
MessageListItem messageListItem;
2022-09-15 01:42:02 -07:00
getmsg(&gMapMessageList, &messageListItem, city->areaId + 1500);
2022-09-01 08:41:37 -07:00
strncpy(name, messageListItem.text, 40);
return 0;
}
2022-05-19 01:51:26 -07:00
// Copy city short name.
//
// 0x4C450C
2022-09-15 01:42:02 -07:00
int wmGetAreaIdxName(int areaIdx, char* name)
2022-05-19 01:51:26 -07:00
{
MessageListItem messageListItem;
2022-09-15 01:42:02 -07:00
getmsg(&gMapMessageList, &messageListItem, 1500 + areaIdx);
2022-05-19 01:51:26 -07:00
strncpy(name, messageListItem.text, 40);
return 0;
}
// Returns true if world area is known.
//
// 0x4C453C
2022-09-15 01:42:02 -07:00
bool wmAreaIsKnown(int areaIdx)
2022-05-19 01:51:26 -07:00
{
2022-09-15 01:42:02 -07:00
if (!cityIsValid(areaIdx)) {
2022-05-19 01:51:26 -07:00
return false;
}
2022-09-15 01:42:02 -07:00
CityInfo* city = &(wmAreaInfoList[areaIdx]);
if (city->visitedState) {
2022-05-19 01:51:26 -07:00
if (city->state == CITY_STATE_KNOWN) {
return true;
}
}
return false;
}
// 0x4C457C
2022-09-15 01:42:02 -07:00
int wmAreaVisitedState(int areaIdx)
2022-05-19 01:51:26 -07:00
{
2022-09-15 01:42:02 -07:00
if (!cityIsValid(areaIdx)) {
2022-05-19 01:51:26 -07:00
return 0;
}
2022-09-15 01:42:02 -07:00
CityInfo* city = &(wmAreaInfoList[areaIdx]);
if (city->visitedState && city->state == CITY_STATE_KNOWN) {
return city->visitedState;
2022-05-19 01:51:26 -07:00
}
return 0;
}
// 0x4C45BC
2022-09-15 01:42:02 -07:00
bool wmMapIsKnown(int mapIdx)
2022-05-19 01:51:26 -07:00
{
2022-09-15 01:42:02 -07:00
int areaIdx;
if (wmMatchAreaFromMap(mapIdx, &areaIdx) != 0) {
2022-05-19 01:51:26 -07:00
return false;
}
2022-09-15 01:42:02 -07:00
int entranceIdx;
if (wmMatchEntranceFromMap(areaIdx, mapIdx, &entranceIdx) != 0) {
2022-05-19 01:51:26 -07:00
return false;
}
2022-09-15 01:42:02 -07:00
CityInfo* city = &(wmAreaInfoList[areaIdx]);
EntranceInfo* entrance = &(city->entrances[entranceIdx]);
2022-05-19 01:51:26 -07:00
if (entrance->state != 1) {
return false;
}
return true;
}
2022-09-01 08:41:37 -07:00
// 0x4C4624
2022-09-15 01:42:02 -07:00
int wmAreaMarkVisited(int areaIdx)
2022-09-01 08:41:37 -07:00
{
2022-09-15 01:42:02 -07:00
return wmAreaMarkVisitedState(areaIdx, CITY_STATE_VISITED);
2022-09-01 08:41:37 -07:00
}
2022-05-19 01:51:26 -07:00
// 0x4C4634
2022-09-15 01:42:02 -07:00
bool wmAreaMarkVisitedState(int areaIdx, int state)
2022-05-19 01:51:26 -07:00
{
2022-09-15 01:42:02 -07:00
if (!cityIsValid(areaIdx)) {
2022-05-19 01:51:26 -07:00
return false;
}
2022-09-15 01:42:02 -07:00
CityInfo* city = &(wmAreaInfoList[areaIdx]);
int v5 = city->visitedState;
if (city->state == CITY_STATE_KNOWN && state != 0) {
wmMarkSubTileRadiusVisited(city->x, city->y);
2022-05-19 01:51:26 -07:00
}
2022-09-15 01:42:02 -07:00
city->visitedState = state;
2022-05-19 01:51:26 -07:00
SubtileInfo* subtile;
2022-09-15 01:42:02 -07:00
if (wmFindCurSubTileFromPos(city->x, city->y, &subtile) == -1) {
2022-05-19 01:51:26 -07:00
return false;
}
2022-09-15 01:42:02 -07:00
if (state == 1) {
2022-05-19 01:51:26 -07:00
subtile->state = SUBTILE_STATE_KNOWN;
2022-09-15 01:42:02 -07:00
} else if (state == 2 && v5 == 0) {
city->visitedState = 1;
2022-05-19 01:51:26 -07:00
}
return true;
}
// 0x4C46CC
2022-09-15 01:42:02 -07:00
bool wmAreaSetVisibleState(int areaIdx, int state, bool force)
2022-05-19 01:51:26 -07:00
{
2022-09-15 01:42:02 -07:00
if (!cityIsValid(areaIdx)) {
2022-05-19 01:51:26 -07:00
return false;
}
2022-09-15 01:42:02 -07:00
CityInfo* city = &(wmAreaInfoList[areaIdx]);
if (city->lockState != LOCK_STATE_LOCKED || force) {
city->state = state;
2022-05-19 01:51:26 -07:00
return true;
}
return false;
}
// 0x4C4710
2022-09-15 01:42:02 -07:00
int wmAreaSetWorldPos(int areaIdx, int x, int y)
2022-05-19 01:51:26 -07:00
{
2022-09-15 01:42:02 -07:00
if (!cityIsValid(areaIdx)) {
2022-05-19 01:51:26 -07:00
return -1;
}
2022-09-15 01:42:02 -07:00
if (x < 0 || x >= WM_TILE_WIDTH * wmNumHorizontalTiles) {
2022-05-19 01:51:26 -07:00
return -1;
}
2022-09-15 01:42:02 -07:00
if (y < 0 || y >= WM_TILE_HEIGHT * (wmMaxTileNum / wmNumHorizontalTiles)) {
2022-05-19 01:51:26 -07:00
return -1;
}
2022-09-15 01:42:02 -07:00
CityInfo* city = &(wmAreaInfoList[areaIdx]);
2022-05-19 01:51:26 -07:00
city->x = x;
city->y = y;
return 0;
}
// Returns current town x/y.
//
// 0x4C47A4
2022-09-15 01:42:02 -07:00
int wmGetPartyWorldPos(int* xPtr, int* yPtr)
2022-05-19 01:51:26 -07:00
{
2022-09-15 01:42:02 -07:00
if (xPtr != NULL) {
*xPtr = wmGenData.worldPosX;
2022-05-19 01:51:26 -07:00
}
2022-09-15 01:42:02 -07:00
if (yPtr != NULL) {
*yPtr = wmGenData.worldPosY;
2022-05-19 01:51:26 -07:00
}
return 0;
}
// Returns current town.
//
// 0x4C47C0
2022-09-15 01:42:02 -07:00
int wmGetPartyCurArea(int* areaIdxPtr)
2022-05-19 01:51:26 -07:00
{
2022-09-15 01:42:02 -07:00
if (areaIdxPtr != NULL) {
*areaIdxPtr = wmGenData.currentAreaId;
2022-05-19 01:51:26 -07:00
return 0;
}
return -1;
}
// 0x4C47D8
2022-09-15 01:42:02 -07:00
static void wmMarkAllSubTiles(int state)
2022-05-19 01:51:26 -07:00
{
2022-09-15 01:42:02 -07:00
for (int tileIndex = 0; tileIndex < wmMaxTileNum; tileIndex++) {
TileInfo* tile = &(wmTileInfoList[tileIndex]);
2022-05-19 01:51:26 -07:00
for (int column = 0; column < SUBTILE_GRID_HEIGHT; column++) {
for (int row = 0; row < SUBTILE_GRID_WIDTH; row++) {
SubtileInfo* subtile = &(tile->subtiles[column][row]);
2022-09-15 01:42:02 -07:00
subtile->state = state;
2022-05-19 01:51:26 -07:00
}
}
}
}
// 0x4C4850
2022-09-15 01:42:02 -07:00
void wmTownMap()
2022-05-19 01:51:26 -07:00
{
2022-09-15 01:42:02 -07:00
wmWorldMapFunc(1);
2022-05-19 01:51:26 -07:00
}
// 0x4C485C
2022-09-15 01:42:02 -07:00
static int wmTownMapFunc(int* mapIdxPtr)
2022-05-19 01:51:26 -07:00
{
2022-09-15 01:42:02 -07:00
*mapIdxPtr = -1;
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
if (wmTownMapInit() == -1) {
wmTownMapExit();
2022-05-19 01:51:26 -07:00
return -1;
}
2022-09-15 01:42:02 -07:00
if (wmGenData.currentAreaId == -1) {
2022-05-19 01:51:26 -07:00
return -1;
}
2022-09-15 01:42:02 -07:00
CityInfo* city = &(wmAreaInfoList[wmGenData.currentAreaId]);
2022-05-19 01:51:26 -07:00
for (;;) {
2022-10-07 14:54:27 -07:00
sharedFpsLimiter.mark();
2022-10-05 00:11:47 -07:00
int keyCode = inputGetInput();
2022-05-19 01:51:26 -07:00
if (keyCode == KEY_CTRL_Q || keyCode == KEY_CTRL_X || keyCode == KEY_F10) {
showQuitConfirmationDialog();
}
if (_game_user_wants_to_quit) {
break;
}
if (keyCode != -1) {
if (keyCode == KEY_ESCAPE) {
break;
}
if (keyCode >= KEY_1 && keyCode < KEY_1 + city->entrancesLength) {
EntranceInfo* entrance = &(city->entrances[keyCode - KEY_1]);
2022-08-14 14:16:36 -07:00
// SFALL: Prevent using number keys to enter unvisited areas on
// a town map.
if (gTownMapHotkeysFix) {
if (entrance->state == 0 || entrance->x == -1 || entrance->y == -1) {
continue;
}
}
2022-09-15 01:42:02 -07:00
*mapIdxPtr = entrance->map;
2022-05-19 01:51:26 -07:00
mapSetEnteringLocation(entrance->elevation, entrance->tile, entrance->rotation);
break;
}
if (keyCode >= KEY_CTRL_F1 && keyCode <= KEY_CTRL_F7) {
2022-09-15 01:42:02 -07:00
int quickDestinationIndex = wmGenData.tabsOffsetY / 27 + keyCode - KEY_CTRL_F1;
if (quickDestinationIndex < wmLabelCount) {
int areaIdx = wmLabelList[quickDestinationIndex];
CityInfo* city = &(wmAreaInfoList[areaIdx]);
if (!wmAreaIsKnown(city->areaId)) {
2022-05-19 01:51:26 -07:00
break;
}
2022-09-15 01:42:02 -07:00
if (areaIdx != wmGenData.currentAreaId) {
2022-08-24 03:11:46 -07:00
// CE: Fix incorrect destination positioning. See
2022-09-15 01:42:02 -07:00
// `wmWorldMapFunc` for explanation.
CitySizeDescription* citySizeDescription = &(wmSphereData[city->size]);
int destX = city->x + citySizeDescription->frmImage.getWidth() / 2 - WM_VIEW_X;
int destY = city->y + citySizeDescription->frmImage.getHeight() / 2 - WM_VIEW_Y;
2022-09-15 01:42:02 -07:00
wmPartyInitWalking(destX, destY);
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
wmGenData.mousePressed = false;
2022-05-19 01:51:26 -07:00
break;
}
}
} else {
if (keyCode == KEY_CTRL_ARROW_UP) {
2022-09-15 01:42:02 -07:00
wmInterfaceScrollTabsStart(-27);
2022-05-19 01:51:26 -07:00
} else if (keyCode == KEY_CTRL_ARROW_DOWN) {
2022-09-15 01:42:02 -07:00
wmInterfaceScrollTabsStart(27);
2022-05-19 01:51:26 -07:00
} else if (keyCode == 2069) {
2022-09-15 01:42:02 -07:00
if (wmTownMapRefresh() == -1) {
2022-05-19 01:51:26 -07:00
return -1;
}
}
if (keyCode == KEY_UPPERCASE_T || keyCode == KEY_LOWERCASE_T || keyCode == KEY_UPPERCASE_W || keyCode == KEY_LOWERCASE_W) {
keyCode = KEY_ESCAPE;
}
if (keyCode == KEY_ESCAPE) {
break;
}
}
}
2022-10-07 14:54:27 -07:00
renderPresent();
sharedFpsLimiter.throttle();
2022-05-19 01:51:26 -07:00
}
2022-09-15 01:42:02 -07:00
if (wmTownMapExit() == -1) {
2022-05-19 01:51:26 -07:00
return -1;
}
return 0;
}
// 0x4C4A6C
2022-09-15 01:42:02 -07:00
static int wmTownMapInit()
2022-05-19 01:51:26 -07:00
{
2022-09-15 01:42:02 -07:00
wmTownMapCurArea = wmGenData.currentAreaId;
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
CityInfo* city = &(wmAreaInfoList[wmGenData.currentAreaId]);
2022-05-19 01:51:26 -07:00
if (!_townFrmImage.lock(city->mapFid)) {
2022-05-19 01:51:26 -07:00
return -1;
}
for (int index = 0; index < city->entrancesLength; index++) {
2022-09-15 01:42:02 -07:00
wmTownMapButtonId[index] = -1;
2022-05-19 01:51:26 -07:00
}
for (int index = 0; index < city->entrancesLength; index++) {
EntranceInfo* entrance = &(city->entrances[index]);
if (entrance->state == 0) {
continue;
}
if (entrance->x == -1 || entrance->y == -1) {
continue;
}
2022-09-15 01:42:02 -07:00
wmTownMapButtonId[index] = buttonCreate(wmBkWin,
2022-05-19 01:51:26 -07:00
entrance->x,
entrance->y,
wmGenData.hotspotNormalFrmImage.getWidth(),
wmGenData.hotspotNormalFrmImage.getHeight(),
2022-05-19 01:51:26 -07:00
-1,
2069,
-1,
KEY_1 + index,
wmGenData.hotspotNormalFrmImage.getData(),
wmGenData.hotspotPressedFrmImage.getData(),
2022-05-19 01:51:26 -07:00
NULL,
BUTTON_FLAG_TRANSPARENT);
2022-09-15 01:42:02 -07:00
if (wmTownMapButtonId[index] == -1) {
2022-05-19 01:51:26 -07:00
return -1;
}
}
2022-09-15 01:42:02 -07:00
tickersRemove(wmMouseBkProc);
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
if (wmTownMapRefresh() == -1) {
2022-05-19 01:51:26 -07:00
return -1;
}
return 0;
}
// 0x4C4BD0
2022-09-15 01:42:02 -07:00
static int wmTownMapRefresh()
2022-05-19 01:51:26 -07:00
{
blitBufferToBuffer(_townFrmImage.getData(),
_townFrmImage.getWidth(),
_townFrmImage.getHeight(),
_townFrmImage.getWidth(),
2022-09-15 01:42:02 -07:00
wmBkWinBuf + WM_WINDOW_WIDTH * WM_VIEW_Y + WM_VIEW_X,
2022-05-19 01:51:26 -07:00
WM_WINDOW_WIDTH);
2022-09-15 01:42:02 -07:00
wmRefreshInterfaceOverlay(false);
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
CityInfo* city = &(wmAreaInfoList[wmGenData.currentAreaId]);
2022-05-19 01:51:26 -07:00
for (int index = 0; index < city->entrancesLength; index++) {
EntranceInfo* entrance = &(city->entrances[index]);
if (entrance->state == 0) {
continue;
}
if (entrance->x == -1 || entrance->y == -1) {
continue;
}
MessageListItem messageListItem;
2022-09-15 01:42:02 -07:00
messageListItem.num = 200 + 10 * wmTownMapCurArea + index;
if (messageListGetItem(&wmMsgFile, &messageListItem)) {
2022-05-19 01:51:26 -07:00
if (messageListItem.text != NULL) {
int width = fontGetStringWidth(messageListItem.text);
2022-08-29 13:33:03 -07:00
// CE: Slightly increase whitespace between marker and entrance name.
windowDrawText(wmBkWin, messageListItem.text, width, wmGenData.hotspotNormalFrmImage.getWidth() / 2 + entrance->x - width / 2, wmGenData.hotspotNormalFrmImage.getHeight() + entrance->y + 4, _colorTable[992] | 0x2010000);
2022-05-19 01:51:26 -07:00
}
}
}
2022-09-15 01:42:02 -07:00
windowRefresh(wmBkWin);
2022-05-19 01:51:26 -07:00
return 0;
}
// 0x4C4D00
2022-09-15 01:42:02 -07:00
static int wmTownMapExit()
2022-05-19 01:51:26 -07:00
{
_townFrmImage.unlock();
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
if (wmTownMapCurArea != -1) {
CityInfo* city = &(wmAreaInfoList[wmTownMapCurArea]);
2022-05-19 01:51:26 -07:00
for (int index = 0; index < city->entrancesLength; index++) {
2022-09-15 01:42:02 -07:00
if (wmTownMapButtonId[index] != -1) {
buttonDestroy(wmTownMapButtonId[index]);
wmTownMapButtonId[index] = -1;
2022-05-19 01:51:26 -07:00
}
}
}
2022-09-15 01:42:02 -07:00
if (wmInterfaceRefresh() == -1) {
2022-05-19 01:51:26 -07:00
return -1;
}
2022-09-15 01:42:02 -07:00
tickersAdd(wmMouseBkProc);
2022-05-19 01:51:26 -07:00
return 0;
}
// 0x4C4DA4
2022-09-15 01:42:02 -07:00
int wmCarUseGas(int amount)
2022-05-19 01:51:26 -07:00
{
if (gameGetGlobalVar(GVAR_NEW_RENO_SUPER_CAR) != 0) {
amount -= amount * 90 / 100;
}
if (gameGetGlobalVar(GVAR_NEW_RENO_CAR_UPGRADE) != 0) {
amount -= amount * 10 / 100;
}
if (gameGetGlobalVar(GVAR_CAR_UPGRADE_FUEL_CELL_REGULATOR) != 0) {
amount /= 2;
}
2022-09-15 01:42:02 -07:00
wmGenData.carFuel -= amount;
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
if (wmGenData.carFuel < 0) {
wmGenData.carFuel = 0;
2022-05-19 01:51:26 -07:00
}
return 0;
}
// Returns amount of fuel that does not fit into tank.
//
// 0x4C4E34
2022-09-15 01:42:02 -07:00
int wmCarFillGas(int amount)
2022-05-19 01:51:26 -07:00
{
2022-09-15 01:42:02 -07:00
if ((amount + wmGenData.carFuel) <= CAR_FUEL_MAX) {
wmGenData.carFuel += amount;
2022-05-19 01:51:26 -07:00
return 0;
}
2022-09-15 01:42:02 -07:00
int remaining = CAR_FUEL_MAX - wmGenData.carFuel;
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
wmGenData.carFuel = CAR_FUEL_MAX;
2022-05-19 01:51:26 -07:00
return remaining;
}
// 0x4C4E74
2022-09-15 01:42:02 -07:00
int wmCarGasAmount()
2022-05-19 01:51:26 -07:00
{
2022-09-15 01:42:02 -07:00
return wmGenData.carFuel;
2022-05-19 01:51:26 -07:00
}
// 0x4C4E7C
2022-09-15 01:42:02 -07:00
bool wmCarIsOutOfGas()
2022-05-19 01:51:26 -07:00
{
2022-09-15 01:42:02 -07:00
return wmGenData.carFuel <= 0;
2022-05-19 01:51:26 -07:00
}
// 0x4C4E8C
2022-09-15 01:42:02 -07:00
int wmCarCurrentArea()
2022-05-19 01:51:26 -07:00
{
2022-09-15 01:42:02 -07:00
return wmGenData.currentCarAreaId;
2022-05-19 01:51:26 -07:00
}
// 0x4C4E94
2022-09-15 01:42:02 -07:00
int wmCarGiveToParty()
2022-05-19 01:51:26 -07:00
{
MessageListItem messageListItem;
2022-09-15 01:42:02 -07:00
memcpy(&messageListItem, &gWorldmapMessageListItem, sizeof(MessageListItem));
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
if (wmGenData.carFuel <= 0) {
2022-05-19 01:51:26 -07:00
// The car is out of power.
2022-09-15 01:42:02 -07:00
char* msg = getmsg(&wmMsgFile, &messageListItem, 1502);
2022-05-19 01:51:26 -07:00
displayMonitorAddMessage(msg);
return -1;
}
2022-09-15 01:42:02 -07:00
wmGenData.isInCar = true;
2022-05-19 01:51:26 -07:00
MapTransition transition;
memset(&transition, 0, sizeof(transition));
transition.map = -2;
mapSetTransition(&transition);
2022-09-15 01:42:02 -07:00
CityInfo* city = &(wmAreaInfoList[CITY_CAR_OUT_OF_GAS]);
city->state = CITY_STATE_UNKNOWN;
city->visitedState = 0;
2022-05-19 01:51:26 -07:00
return 0;
}
// 0x4C4F28
2022-09-15 01:42:02 -07:00
int wmSfxMaxCount()
2022-05-19 01:51:26 -07:00
{
2022-09-15 01:42:02 -07:00
int mapIdx = mapGetCurrentMap();
if (mapIdx < 0 || mapIdx >= wmMaxMapNum) {
2022-05-19 01:51:26 -07:00
return -1;
}
2022-09-15 01:42:02 -07:00
MapInfo* map = &(wmMapInfoList[mapIdx]);
2022-05-19 01:51:26 -07:00
return map->ambientSoundEffectsLength;
}
// 0x4C4F5C
2022-09-15 01:42:02 -07:00
int wmSfxRollNextIdx()
2022-05-19 01:51:26 -07:00
{
2022-09-15 01:42:02 -07:00
int mapIdx = mapGetCurrentMap();
if (mapIdx < 0 || mapIdx >= wmMaxMapNum) {
2022-05-19 01:51:26 -07:00
return -1;
}
2022-09-15 01:42:02 -07:00
MapInfo* map = &(wmMapInfoList[mapIdx]);
2022-05-19 01:51:26 -07:00
int totalChances = 0;
for (int index = 0; index < map->ambientSoundEffectsLength; index++) {
MapAmbientSoundEffectInfo* sfx = &(map->ambientSoundEffects[index]);
totalChances += sfx->chance;
}
int chance = randomBetween(0, totalChances);
for (int index = 0; index < map->ambientSoundEffectsLength; index++) {
MapAmbientSoundEffectInfo* sfx = &(map->ambientSoundEffects[index]);
if (chance >= sfx->chance) {
chance -= sfx->chance;
continue;
}
return index;
}
return -1;
}
// 0x4C5004
2022-09-15 01:42:02 -07:00
int wmSfxIdxName(int sfxIdx, char** namePtr)
2022-05-19 01:51:26 -07:00
{
if (namePtr == NULL) {
return -1;
}
*namePtr = NULL;
2022-09-15 01:42:02 -07:00
int mapIdx = mapGetCurrentMap();
if (mapIdx < 0 || mapIdx >= wmMaxMapNum) {
2022-05-19 01:51:26 -07:00
return -1;
}
2022-09-15 01:42:02 -07:00
MapInfo* map = &(wmMapInfoList[mapIdx]);
if (sfxIdx < 0 || sfxIdx >= map->ambientSoundEffectsLength) {
2022-05-19 01:51:26 -07:00
return -1;
}
2022-09-15 01:42:02 -07:00
MapAmbientSoundEffectInfo* ambientSoundEffectInfo = &(map->ambientSoundEffects[sfxIdx]);
2022-05-19 01:51:26 -07:00
*namePtr = ambientSoundEffectInfo->name;
int v1 = 0;
if (strcmp(ambientSoundEffectInfo->name, "brdchir1") == 0) {
v1 = 1;
} else if (strcmp(ambientSoundEffectInfo->name, "brdchirp") == 0) {
v1 = 2;
}
if (v1 != 0) {
int dayPart;
int gameTimeHour = gameTimeGetHour();
if (gameTimeHour <= 600 || gameTimeHour >= 1800) {
dayPart = DAY_PART_NIGHT;
} else if (gameTimeHour >= 1200) {
dayPart = DAY_PART_AFTERNOON;
} else {
dayPart = DAY_PART_MORNING;
}
if (dayPart == DAY_PART_NIGHT) {
2022-09-15 01:42:02 -07:00
*namePtr = wmRemapSfxList[v1 - 1];
2022-05-19 01:51:26 -07:00
}
}
return 0;
}
// 0x4C50F4
2022-09-15 01:42:02 -07:00
static int wmRefreshInterfaceOverlay(bool shouldRefreshWindow)
2022-05-19 01:51:26 -07:00
{
blitBufferToBufferTrans(_backgroundFrmImage.getData(),
_backgroundFrmImage.getWidth(),
_backgroundFrmImage.getHeight(),
_backgroundFrmImage.getWidth(),
2022-09-15 01:42:02 -07:00
wmBkWinBuf,
2022-05-19 01:51:26 -07:00
WM_WINDOW_WIDTH);
2022-09-15 01:42:02 -07:00
wmRefreshTabs();
2022-05-19 01:51:26 -07:00
2022-09-01 08:41:37 -07:00
// NOTE: Uninline.
wmInterfaceDialSyncTime(false);
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
wmRefreshInterfaceDial(false);
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
if (wmGenData.isInCar) {
unsigned char* data = artGetFrameData(wmGenData.carImageFrm, wmGenData.carImageCurrentFrameIndex, 0);
2022-05-19 01:51:26 -07:00
if (data == NULL) {
return -1;
}
blitBufferToBuffer(data,
2022-09-15 01:42:02 -07:00
wmGenData.carImageFrmWidth,
wmGenData.carImageFrmHeight,
wmGenData.carImageFrmWidth,
wmBkWinBuf + WM_WINDOW_WIDTH * WM_WINDOW_CAR_Y + WM_WINDOW_CAR_X,
2022-05-19 01:51:26 -07:00
WM_WINDOW_WIDTH);
blitBufferToBufferTrans(wmGenData.carOverlayFrmImage.getData(),
wmGenData.carOverlayFrmImage.getWidth(),
wmGenData.carOverlayFrmImage.getHeight(),
wmGenData.carOverlayFrmImage.getWidth(),
2022-09-15 01:42:02 -07:00
wmBkWinBuf + WM_WINDOW_WIDTH * WM_WINDOW_CAR_OVERLAY_Y + WM_WINDOW_CAR_OVERLAY_X,
2022-05-19 01:51:26 -07:00
WM_WINDOW_WIDTH);
2022-09-15 01:42:02 -07:00
wmInterfaceRefreshCarFuel();
2022-05-19 01:51:26 -07:00
} else {
blitBufferToBufferTrans(wmGenData.globeOverlayFrmImage.getData(),
wmGenData.globeOverlayFrmImage.getWidth(),
wmGenData.globeOverlayFrmImage.getHeight(),
wmGenData.globeOverlayFrmImage.getWidth(),
2022-09-15 01:42:02 -07:00
wmBkWinBuf + WM_WINDOW_WIDTH * WM_WINDOW_GLOBE_OVERLAY_Y + WM_WINDOW_GLOBE_OVERLAY_X,
2022-05-19 01:51:26 -07:00
WM_WINDOW_WIDTH);
}
2022-09-15 01:42:02 -07:00
wmInterfaceRefreshDate(false);
2022-05-19 01:51:26 -07:00
if (shouldRefreshWindow) {
2022-09-15 01:42:02 -07:00
windowRefresh(wmBkWin);
2022-05-19 01:51:26 -07:00
}
return 0;
}
// 0x4C5244
2022-09-15 01:42:02 -07:00
static void wmInterfaceRefreshCarFuel()
2022-05-19 01:51:26 -07:00
{
2022-09-15 01:42:02 -07:00
int ratio = (WM_WINDOW_CAR_FUEL_BAR_HEIGHT * wmGenData.carFuel) / CAR_FUEL_MAX;
2022-05-19 01:51:26 -07:00
if ((ratio & 1) != 0) {
ratio -= 1;
}
2022-09-15 01:42:02 -07:00
unsigned char* dest = wmBkWinBuf + WM_WINDOW_WIDTH * WM_WINDOW_CAR_FUEL_BAR_Y + WM_WINDOW_CAR_FUEL_BAR_X;
2022-05-19 01:51:26 -07:00
for (int index = WM_WINDOW_CAR_FUEL_BAR_HEIGHT; index > ratio; index--) {
*dest = 14;
dest += 640;
}
while (ratio > 0) {
*dest = 196;
dest += WM_WINDOW_WIDTH;
*dest = 14;
dest += WM_WINDOW_WIDTH;
ratio -= 2;
}
}
// 0x4C52B0
2022-09-15 01:42:02 -07:00
static int wmRefreshTabs()
2022-05-19 01:51:26 -07:00
{
unsigned char* v30;
unsigned char* v0;
int v31;
CityInfo* city;
Art* art;
CacheEntry* cache_entry;
int width;
int height;
unsigned char* buf;
int v10;
unsigned char* v11;
unsigned char* v12;
int v32;
unsigned char* v13;
blitBufferToBufferTrans(wmGenData.tabsBackgroundFrmImage.getData() + wmGenData.tabsBackgroundFrmImage.getWidth() * wmGenData.tabsOffsetY + 9,
119,
178,
wmGenData.tabsBackgroundFrmImage.getWidth(),
wmBkWinBuf + WM_WINDOW_WIDTH * 135 + 501,
WM_WINDOW_WIDTH);
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
v30 = wmBkWinBuf + WM_WINDOW_WIDTH * 138 + 530;
v0 = wmBkWinBuf + WM_WINDOW_WIDTH * 138 + 530 - WM_WINDOW_WIDTH * (wmGenData.tabsOffsetY % 27);
v31 = wmGenData.tabsOffsetY / 27;
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
if (v31 < wmLabelCount) {
city = &(wmAreaInfoList[wmLabelList[v31]]);
2022-05-19 01:51:26 -07:00
if (city->labelFid != -1) {
art = artLock(city->labelFid, &cache_entry);
if (art == NULL) {
return -1;
}
width = artGetWidth(art, 0, 0);
height = artGetHeight(art, 0, 0);
buf = artGetFrameData(art, 0, 0);
if (buf == NULL) {
return -1;
}
2022-09-15 01:42:02 -07:00
v10 = height - wmGenData.tabsOffsetY % 27;
v11 = buf + width * (wmGenData.tabsOffsetY % 27);
2022-05-19 01:51:26 -07:00
v12 = v0;
if (v0 < v30 - WM_WINDOW_WIDTH) {
v12 = v30 - WM_WINDOW_WIDTH;
}
blitBufferToBuffer(v11, width, v10, width, v12, WM_WINDOW_WIDTH);
artUnlock(cache_entry);
cache_entry = INVALID_CACHE_ENTRY;
}
}
v13 = v0 + WM_WINDOW_WIDTH * 27;
v32 = v31 + 6;
for (int v14 = v31 + 1; v14 < v32; v14++) {
2022-09-15 01:42:02 -07:00
if (v14 < wmLabelCount) {
city = &(wmAreaInfoList[wmLabelList[v14]]);
2022-05-19 01:51:26 -07:00
if (city->labelFid != -1) {
art = artLock(city->labelFid, &cache_entry);
if (art == NULL) {
return -1;
}
width = artGetWidth(art, 0, 0);
height = artGetHeight(art, 0, 0);
buf = artGetFrameData(art, 0, 0);
if (buf == NULL) {
return -1;
}
blitBufferToBuffer(buf, width, height, width, v13, WM_WINDOW_WIDTH);
artUnlock(cache_entry);
cache_entry = INVALID_CACHE_ENTRY;
}
}
v13 += WM_WINDOW_WIDTH * 27;
}
2022-09-15 01:42:02 -07:00
if (v31 + 6 < wmLabelCount) {
city = &(wmAreaInfoList[wmLabelList[v31 + 6]]);
2022-05-19 01:51:26 -07:00
if (city->labelFid != -1) {
art = artLock(city->labelFid, &cache_entry);
if (art == NULL) {
return -1;
}
width = artGetWidth(art, 0, 0);
height = artGetHeight(art, 0, 0);
buf = artGetFrameData(art, 0, 0);
if (buf == NULL) {
return -1;
}
blitBufferToBuffer(buf, width, height, width, v13, WM_WINDOW_WIDTH);
artUnlock(cache_entry);
cache_entry = INVALID_CACHE_ENTRY;
}
}
blitBufferToBufferTrans(wmGenData.tabsBorderFrmImage.getData(), 119, 178, 119, wmBkWinBuf + WM_WINDOW_WIDTH * 135 + 501, WM_WINDOW_WIDTH);
2022-05-19 01:51:26 -07:00
return 0;
}
// Creates array of cities available as quick destinations.
//
// 0x4C55D4
2022-09-15 01:42:02 -07:00
static int wmMakeTabsLabelList(int** quickDestinationsPtr, int* quickDestinationsLengthPtr)
2022-05-19 01:51:26 -07:00
{
int* quickDestinations = *quickDestinationsPtr;
2022-09-01 08:41:37 -07:00
// NOTE: Uninline.
wmFreeTabsLabelList(quickDestinationsPtr, quickDestinationsLengthPtr);
2022-05-19 01:51:26 -07:00
int capacity = 10;
2022-05-21 08:22:03 -07:00
quickDestinations = (int*)internal_malloc(sizeof(*quickDestinations) * capacity);
2022-05-19 01:51:26 -07:00
*quickDestinationsPtr = quickDestinations;
if (quickDestinations == NULL) {
return -1;
}
int quickDestinationsLength = *quickDestinationsLengthPtr;
2022-09-15 01:42:02 -07:00
for (int index = 0; index < wmMaxAreaNum; index++) {
if (wmAreaIsKnown(index) && wmAreaInfoList[index].labelFid != -1) {
2022-05-19 01:51:26 -07:00
quickDestinationsLength++;
*quickDestinationsLengthPtr = quickDestinationsLength;
if (capacity <= quickDestinationsLength) {
capacity += 10;
2022-05-21 08:22:03 -07:00
quickDestinations = (int*)internal_realloc(quickDestinations, sizeof(*quickDestinations) * capacity);
2022-05-19 01:51:26 -07:00
if (quickDestinations == NULL) {
return -1;
}
*quickDestinationsPtr = quickDestinations;
}
quickDestinations[quickDestinationsLength - 1] = index;
}
}
2022-09-15 01:42:02 -07:00
qsort(quickDestinations, quickDestinationsLength, sizeof(*quickDestinations), wmTabsCompareNames);
2022-05-19 01:51:26 -07:00
return 0;
}
// 0x4C56C8
2022-09-15 01:42:02 -07:00
static int wmTabsCompareNames(const void* a1, const void* a2)
2022-05-19 01:51:26 -07:00
{
int v1 = *(int*)a1;
int v2 = *(int*)a2;
2022-09-15 01:42:02 -07:00
CityInfo* city1 = &(wmAreaInfoList[v1]);
CityInfo* city2 = &(wmAreaInfoList[v2]);
2022-05-19 01:51:26 -07:00
return compat_stricmp(city1->name, city2->name);
2022-05-19 01:51:26 -07:00
}
2022-09-01 08:41:37 -07:00
// NOTE: Inlined.
//
// 0x4C5710
static int wmFreeTabsLabelList(int** quickDestinationsListPtr, int* quickDestinationsLengthPtr)
{
if (*quickDestinationsListPtr != NULL) {
internal_free(*quickDestinationsListPtr);
*quickDestinationsListPtr = NULL;
}
*quickDestinationsLengthPtr = 0;
return 0;
}
2022-05-19 01:51:26 -07:00
// 0x4C5734
2022-09-15 01:42:02 -07:00
static void wmRefreshInterfaceDial(bool shouldRefreshWindow)
2022-05-19 01:51:26 -07:00
{
2022-09-15 01:42:02 -07:00
unsigned char* data = artGetFrameData(wmGenData.dialFrm, wmGenData.dialFrmCurrentFrameIndex, 0);
2022-05-19 01:51:26 -07:00
blitBufferToBufferTrans(data,
2022-09-15 01:42:02 -07:00
wmGenData.dialFrmWidth,
wmGenData.dialFrmHeight,
wmGenData.dialFrmWidth,
wmBkWinBuf + WM_WINDOW_WIDTH * WM_WINDOW_DIAL_Y + WM_WINDOW_DIAL_X,
2022-05-19 01:51:26 -07:00
WM_WINDOW_WIDTH);
if (shouldRefreshWindow) {
Rect rect;
rect.left = WM_WINDOW_DIAL_X;
rect.top = WM_WINDOW_DIAL_Y - 1;
2022-09-15 01:42:02 -07:00
rect.right = rect.left + wmGenData.dialFrmWidth;
rect.bottom = rect.top + wmGenData.dialFrmHeight;
windowRefreshRect(wmBkWin, &rect);
2022-05-19 01:51:26 -07:00
}
}
2022-09-01 08:41:37 -07:00
// NOTE: Inlined.
//
// 0x4C57BC
static void wmInterfaceDialSyncTime(bool shouldRefreshWindow)
{
int gameHour;
int frame;
gameHour = gameTimeGetHour();
2022-09-15 01:42:02 -07:00
frame = (gameHour / 100 + 12) % artGetFrameCount(wmGenData.dialFrm);
if (frame != wmGenData.dialFrmCurrentFrameIndex) {
wmGenData.dialFrmCurrentFrameIndex = frame;
wmRefreshInterfaceDial(shouldRefreshWindow);
2022-09-01 08:41:37 -07:00
}
}
2022-05-19 01:51:26 -07:00
// 0x4C5804
2022-09-15 01:42:02 -07:00
static int wmAreaFindFirstValidMap(int* mapIdxPtr)
2022-05-19 01:51:26 -07:00
{
2022-09-15 01:42:02 -07:00
*mapIdxPtr = -1;
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
if (wmGenData.currentAreaId == -1) {
2022-05-19 01:51:26 -07:00
return -1;
}
2022-09-15 01:42:02 -07:00
CityInfo* city = &(wmAreaInfoList[wmGenData.currentAreaId]);
2022-05-19 01:51:26 -07:00
if (city->entrancesLength == 0) {
return -1;
}
for (int index = 0; index < city->entrancesLength; index++) {
EntranceInfo* entrance = &(city->entrances[index]);
if (entrance->state != 0) {
2022-09-15 01:42:02 -07:00
*mapIdxPtr = entrance->map;
2022-05-19 01:51:26 -07:00
return 0;
}
}
EntranceInfo* entrance = &(city->entrances[0]);
entrance->state = 1;
2022-09-15 01:42:02 -07:00
*mapIdxPtr = entrance->map;
2022-05-19 01:51:26 -07:00
return 0;
}
// 0x4C58C0
2022-09-15 01:42:02 -07:00
int wmMapMusicStart()
2022-05-19 01:51:26 -07:00
{
do {
2022-09-15 01:42:02 -07:00
int mapIdx = mapGetCurrentMap();
if (mapIdx == -1 || mapIdx >= wmMaxMapNum) {
2022-05-19 01:51:26 -07:00
break;
}
2022-09-15 01:42:02 -07:00
MapInfo* map = &(wmMapInfoList[mapIdx]);
2022-05-19 01:51:26 -07:00
if (strlen(map->music) == 0) {
break;
}
if (_gsound_background_play_level_music(map->music, 12) == -1) {
break;
}
return 0;
} while (0);
debugPrint("\nWorldMap Error: Couldn't start map Music!");
return -1;
}
// 0x4C5928
2022-09-15 01:42:02 -07:00
int wmSetMapMusic(int mapIdx, const char* name)
2022-05-19 01:51:26 -07:00
{
2022-09-15 01:42:02 -07:00
if (mapIdx == -1 || mapIdx >= wmMaxMapNum) {
2022-05-19 01:51:26 -07:00
return -1;
}
if (name == NULL) {
return -1;
}
2022-09-15 01:42:02 -07:00
debugPrint("\nwmSetMapMusic: %d, %s", mapIdx, name);
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
MapInfo* map = &(wmMapInfoList[mapIdx]);
2022-05-19 01:51:26 -07:00
strncpy(map->music, name, 40);
map->music[39] = '\0';
2022-09-15 01:42:02 -07:00
if (mapGetCurrentMap() == mapIdx) {
2022-05-19 01:51:26 -07:00
backgroundSoundDelete();
2022-09-15 01:42:02 -07:00
wmMapMusicStart();
2022-05-19 01:51:26 -07:00
}
return 0;
}
// 0x4C59A4
2022-09-15 01:42:02 -07:00
int wmMatchAreaContainingMapIdx(int mapIdx, int* areaIdxPtr)
2022-05-19 01:51:26 -07:00
{
2022-09-15 01:42:02 -07:00
*areaIdxPtr = 0;
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
for (int areaIdx = 0; areaIdx < wmMaxAreaNum; areaIdx++) {
CityInfo* cityInfo = &(wmAreaInfoList[areaIdx]);
for (int entranceIdx = 0; entranceIdx < cityInfo->entrancesLength; entranceIdx++) {
EntranceInfo* entranceInfo = &(cityInfo->entrances[entranceIdx]);
if (entranceInfo->map == mapIdx) {
*areaIdxPtr = areaIdx;
2022-05-19 01:51:26 -07:00
return 0;
}
}
}
return -1;
}
// 0x4C5A1C
2022-09-15 01:42:02 -07:00
int wmTeleportToArea(int areaIdx)
2022-05-19 01:51:26 -07:00
{
2022-09-15 01:42:02 -07:00
if (!cityIsValid(areaIdx)) {
2022-05-19 01:51:26 -07:00
return -1;
}
2022-09-15 01:42:02 -07:00
wmGenData.currentAreaId = areaIdx;
wmGenData.walkDestinationX = 0;
wmGenData.walkDestinationY = 0;
wmGenData.isWalking = false;
2022-05-19 01:51:26 -07:00
2022-09-15 01:42:02 -07:00
CityInfo* city = &(wmAreaInfoList[areaIdx]);
2022-08-24 03:11:46 -07:00
// SFALL: Fix for incorrect positioning after exiting small/medium
// locations.
2022-09-15 01:42:02 -07:00
// 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;
2022-05-19 01:51:26 -07:00
if (!wasLocked) {
citySizeDescription->frmImage.unlock();
}
2022-05-19 01:51:26 -07:00
return 0;
}
2022-09-23 05:43:44 -07:00
} // namespace fallout