Add op_force_encounter

This commit is contained in:
Alexander Batalov 2023-09-02 21:34:41 +03:00
parent 84aecfa823
commit bb3513956c
3 changed files with 76 additions and 0 deletions

View File

@ -138,6 +138,13 @@ static void op_in_world_map(Program* program)
programStackPushInteger(program, GameMode::isInGameMode(GameMode::kWorldmap) ? 1 : 0); programStackPushInteger(program, GameMode::isInGameMode(GameMode::kWorldmap) ? 1 : 0);
} }
// force_encounter
static void op_force_encounter(Program* program)
{
int map = programStackPopInteger(program);
wmForceEncounter(map, 0);
}
// set_world_map_pos // set_world_map_pos
static void op_set_world_map_pos(Program* program) static void op_set_world_map_pos(Program* program)
{ {
@ -541,6 +548,14 @@ static void op_get_attack_type(Program* program)
} }
} }
// force_encounter_with_flags
static void op_force_encounter_with_flags(Program* program)
{
unsigned int flags = programStackPopInteger(program);
int map = programStackPopInteger(program);
wmForceEncounter(map, flags);
}
// atoi // atoi
static void opParseInt(Program* program) static void opParseInt(Program* program)
{ {
@ -894,6 +909,7 @@ void sfallOpcodesInit()
interpreterRegisterOpcode(0x816A, op_set_global_script_repeat); interpreterRegisterOpcode(0x816A, op_set_global_script_repeat);
interpreterRegisterOpcode(0x816C, op_key_pressed); interpreterRegisterOpcode(0x816C, op_key_pressed);
interpreterRegisterOpcode(0x8170, op_in_world_map); interpreterRegisterOpcode(0x8170, op_in_world_map);
interpreterRegisterOpcode(0x8171, op_force_encounter);
interpreterRegisterOpcode(0x8172, op_set_world_map_pos); interpreterRegisterOpcode(0x8172, op_set_world_map_pos);
interpreterRegisterOpcode(0x8193, opGetCurrentHand); interpreterRegisterOpcode(0x8193, opGetCurrentHand);
interpreterRegisterOpcode(0x819B, op_set_global_script_type); interpreterRegisterOpcode(0x819B, op_set_global_script_type);
@ -927,6 +943,7 @@ void sfallOpcodesInit()
interpreterRegisterOpcode(0x8221, opGetScreenHeight); interpreterRegisterOpcode(0x8221, opGetScreenHeight);
interpreterRegisterOpcode(0x8224, op_create_message_window); interpreterRegisterOpcode(0x8224, op_create_message_window);
interpreterRegisterOpcode(0x8228, op_get_attack_type); interpreterRegisterOpcode(0x8228, op_get_attack_type);
interpreterRegisterOpcode(0x8229, op_force_encounter_with_flags);
interpreterRegisterOpcode(0x822D, opCreateArray); interpreterRegisterOpcode(0x822D, opCreateArray);
interpreterRegisterOpcode(0x822E, opSetArray); interpreterRegisterOpcode(0x822E, opSetArray);
interpreterRegisterOpcode(0x822F, opGetArray); interpreterRegisterOpcode(0x822F, opGetArray);

View File

@ -817,6 +817,8 @@ static double gGameTimeIncRemainder = 0.0;
static FrmImage _backgroundFrmImage; static FrmImage _backgroundFrmImage;
static FrmImage _townFrmImage; static FrmImage _townFrmImage;
static bool wmFaded = false; static bool wmFaded = false;
static int wmForceEncounterMapId = -1;
static unsigned int wmForceEncounterFlags = 0;
static inline bool cityIsValid(int city) static inline bool cityIsValid(int city)
{ {
@ -929,6 +931,9 @@ static int wmGenDataInit()
wmGenData.tabsScrollingDelta = 0; wmGenData.tabsScrollingDelta = 0;
wmGenData.viewportMaxX = 0; wmGenData.viewportMaxX = 0;
wmForceEncounterMapId = -1;
wmForceEncounterFlags = 0;
return 0; return 0;
} }
@ -979,6 +984,9 @@ static int wmGenDataReset()
wmMarkSubTileRadiusVisited(wmGenData.worldPosX, wmGenData.worldPosY); wmMarkSubTileRadiusVisited(wmGenData.worldPosX, wmGenData.worldPosY);
wmForceEncounterMapId = -1;
wmForceEncounterFlags = 0;
return 0; return 0;
} }
@ -3347,6 +3355,33 @@ static int wmRndEncounterOccurred()
} }
} }
// SFALL: Handle forced encounter.
// CE: In Sfall a check for forced encounter is inserted instead of check
// for Horrigan encounter (above). This implemenation gives Horrigan
// encounter a priority.
if (wmForceEncounterMapId != -1) {
if ((wmForceEncounterFlags & ENCOUNTER_FLAG_NO_CAR) != 0) {
if (wmGenData.isInCar) {
wmMatchAreaContainingMapIdx(wmForceEncounterMapId, &(wmGenData.currentCarAreaId));
}
}
// For unknown reason fadeout and blinking icon are mutually exclusive.
if ((wmForceEncounterFlags & ENCOUNTER_FLAG_FADEOUT) != 0) {
wmFadeOut();
} else if ((wmForceEncounterFlags & ENCOUNTER_FLAG_NO_ICON) == 0) {
bool special = (wmForceEncounterFlags & ENCOUNTER_FLAG_ICON_SP) != 0;
wmBlinkRndEncounterIcon(special);
}
mapLoadById(wmForceEncounterMapId);
wmForceEncounterMapId = -1;
wmForceEncounterFlags = 0;
return 1;
}
// NOTE: Uninline. // NOTE: Uninline.
wmPartyFindCurSubTile(); wmPartyFindCurSubTile();
@ -6608,4 +6643,21 @@ void wmCarSetCurrentArea(int area)
wmGenData.currentCarAreaId = area; wmGenData.currentCarAreaId = area;
} }
void wmForceEncounter(int map, unsigned int flags)
{
if ((wmForceEncounterFlags & (1 << 31)) != 0) {
return;
}
wmForceEncounterMapId = map;
wmForceEncounterFlags = flags;
// I don't quite understand the reason why locking needs one more flag.
if ((wmForceEncounterFlags & ENCOUNTER_FLAG_LOCK) != 0) {
wmForceEncounterFlags |= (1 << 31);
} else {
wmForceEncounterFlags &= ~(1 << 31);
}
}
} // namespace fallout } // namespace fallout

View File

@ -229,6 +229,12 @@ typedef enum Map {
MAP_IN_GAME_MOVIE1 = 149, MAP_IN_GAME_MOVIE1 = 149,
} Map; } Map;
#define ENCOUNTER_FLAG_NO_CAR 0x1
#define ENCOUNTER_FLAG_LOCK 0x2
#define ENCOUNTER_FLAG_NO_ICON 0x4
#define ENCOUNTER_FLAG_ICON_SP 0x8
#define ENCOUNTER_FLAG_FADEOUT 0x10
extern unsigned char* circleBlendTable; extern unsigned char* circleBlendTable;
int wmWorldMap_init(); int wmWorldMap_init();
@ -279,6 +285,7 @@ int wmTeleportToArea(int areaIdx);
void wmSetPartyWorldPos(int x, int y); void wmSetPartyWorldPos(int x, int y);
void wmCarSetCurrentArea(int area); void wmCarSetCurrentArea(int area);
void wmForceEncounter(int map, unsigned int flags);
} // namespace fallout } // namespace fallout