#include "intrface.h"
#include "brender/brender.h"
#include "flicplay.h"
#include "globvars.h"
#include "grafdata.h"
#include "graphics.h"
#include "harness/trace.h"
#include "input.h"
#include "loading.h"
#include "main.h"
#include "pd/sys.h"
#include "sound.h"
#include <stdlib.h>
int gDisabled_choices[10];
int gCurrent_mode;
tU32 gStart_time;
int gCurrent_choice;
tInterface_spec* gSpec;
int gAlways_typing;
int gDisabled_count;
// IDA: void __cdecl SetAlwaysTyping()
void SetAlwaysTyping(void) {
LOG_TRACE("()");
gAlways_typing = 1;
}
// IDA: void __cdecl ClearAlwaysTyping()
void ClearAlwaysTyping(void) {
LOG_TRACE("()");
gAlways_typing = 0;
}
// IDA: int __usercall ChoiceDisabled@<EAX>(int pChoice@<EAX>)
int ChoiceDisabled(int pChoice) {
int i;
LOG_TRACE("(%d)", pChoice);
for (i = 0; i < gDisabled_count; ++i) {
if (gDisabled_choices[i] == pChoice) {
return 1;
}
}
return 0;
}
// IDA: void __cdecl ResetInterfaceTimeout()
void ResetInterfaceTimeout(void) {
LOG_TRACE("()");
gStart_time = PDGetTotalTime();
}
// IDA: void __usercall ChangeSelection(tInterface_spec *pSpec@<EAX>, int *pOld_selection@<EDX>, int *pNew_selection@<EBX>, int pMode@<ECX>, int pSkip_disabled)
void ChangeSelection(tInterface_spec* pSpec, int* pOld_selection, int* pNew_selection, int pMode, int pSkip_disabled) {
//int i; // Pierre-Marie Baty -- unused variable
LOG_TRACE("(%p, %p, %p, %d, %d)", pSpec, *pOld_selection, *pNew_selection, pMode, pSkip_disabled);
if (ChoiceDisabled(*pNew_selection)) {
if (!pSkip_disabled) {
*pNew_selection = *pOld_selection;
} else if (*pOld_selection < *pNew_selection) {
do {
*pNew_selection = *pNew_selection + 1;
if (*pNew_selection < pSpec->move_up_min[pMode]) {
*pNew_selection = pSpec->move_up_max[pMode];
}
if (*pNew_selection > pSpec->move_up_max[pMode]) {
*pNew_selection = pSpec->move_up_min[pMode];
}
} while (*pNew_selection != *pOld_selection && ChoiceDisabled(*pNew_selection));
} else {
do {
*pNew_selection = *pNew_selection - 1;
if (*pNew_selection < pSpec->move_up_min[pMode]) {
*pNew_selection = pSpec->move_up_max[pMode];
}
if (*pNew_selection > pSpec->move_up_max[pMode]) {
*pNew_selection = pSpec->move_up_min[pMode];
}
} while (*pNew_selection != *pOld_selection && ChoiceDisabled(*pNew_selection));
}
}
if (*pOld_selection != *pNew_selection) {
if (*pOld_selection >= 0 && *pOld_selection < pSpec->number_of_button_flics) {
if (pSpec->flicker_off_flics[*pOld_selection].flic_index >= 0) {
AddToFlicQueue(pSpec->flicker_off_flics[*pOld_selection].flic_index,
pSpec->flicker_off_flics[*pOld_selection].x[gGraf_data_index],
pSpec->flicker_off_flics[*pOld_selection].y[gGraf_data_index], 0);
}
}
if (*pNew_selection >= 0 && *pNew_selection < pSpec->number_of_button_flics) {
if (pSpec->flicker_on_flics[*pNew_selection].flic_index >= 0) {
AddToFlicQueue(pSpec->flicker_on_flics[*pNew_selection].flic_index,
pSpec->flicker_on_flics[*pNew_selection].x[gGraf_data_index],
pSpec->flicker_on_flics[*pNew_selection].y[gGraf_data_index], 0);
}
}
*pOld_selection = *pNew_selection;
}
}
// IDA: void __usercall RecopyAreas(tInterface_spec *pSpec@<EAX>, br_pixelmap **pCopy_areas@<EDX>)
void RecopyAreas(tInterface_spec* pSpec, br_pixelmap** pCopy_areas) {
int i;
LOG_TRACE8("(%p, %p)", pSpec, pCopy_areas);
for (i = 0; i < pSpec->number_of_recopy_areas; i++) {
BrPixelmapRectangleCopy(
gBack_screen,
pSpec->recopy_areas[i].left[gGraf_data_index],
pSpec->recopy_areas[i].top[gGraf_data_index],
pCopy_areas[i],
0,
0,
pSpec->recopy_areas[i].right[gGraf_data_index] - pSpec->recopy_areas[i].left[gGraf_data_index],
pSpec->recopy_areas[i].bottom[gGraf_data_index] - pSpec->recopy_areas[i].top[gGraf_data_index]);
}
}
// IDA: void __usercall DisableChoice(int pChoice@<EAX>)
void DisableChoice(int pChoice) {
int i;
LOG_TRACE("(%d)", pChoice);
for (i = 0; i < gDisabled_count; i++) {
if (gDisabled_choices[i] == pChoice) {
return;
}
}
gDisabled_choices[gDisabled_count] = pChoice;
gDisabled_count++;
}
// IDA: void __usercall EnableChoice(int pChoice@<EAX>)
void EnableChoice(int pChoice) {
int i;
LOG_TRACE("(%d)", pChoice);
for (i = 0; i < gDisabled_count; i++) {
if (gDisabled_choices[i] == pChoice) {
memmove(&gDisabled_choices
[i
], &gDisabled_choices
[i
+ 1], (gDisabled_count
- i
- 1) * sizeof(gDisabled_choices
[0]));
gDisabled_count--;
break;
}
}
}
// IDA: int __usercall DoInterfaceScreen@<EAX>(tInterface_spec *pSpec@<EAX>, int pOptions@<EDX>, int pCurrent_choice@<EBX>)
int DoInterfaceScreen(tInterface_spec* pSpec, int pOptions, int pCurrent_choice) {
tProg_status entry_status; //
int x_coord; //
int y_coord; //
int mouse_in_somewhere = 0;
int i; //
//int key2; // Pierre-Marie Baty -- unused variable
//int mouse_was_started; // Pierre-Marie Baty -- unused variable
int last_choice; //
int escaped; //
int timed_out; //
int go_ahead; //
//int last_mode; // Pierre-Marie Baty -- unused variable
int result; //
int the_key; //
int the_max;
int mouse_down; //
int new_mouse_down; //
int last_mouse_down = 0;
int defeat_mode_change; //
int selection_changed; //
char the_str[256];
tU32 last_press; //
//tU32 last_left_press; // Pierre-Marie Baty -- unused variable
//tU32 last_right_press; // Pierre-Marie Baty -- unused variable
//tU32 last_up_press; // Pierre-Marie Baty -- unused variable
//tU32 last_down_press; // Pierre-Marie Baty -- unused variable
br_pixelmap** copy_areas; //
br_pixelmap* old_current_splash; //
//void* pixels_copy; // Pierre-Marie Baty -- unused variable
//void* palette_copy; // Pierre-Marie Baty -- unused variable
LOG_TRACE("(%p, %d, %d)", pSpec, pOptions, pCurrent_choice);
#if defined(DETHRACE_FIX_BUGS)
mouse_down = 0;
#endif
entry_status = gProgram_state.prog_status;
gTyping_slot = -1;
EdgeTriggerModeOn();
gSpec = pSpec;
gDisabled_count = 0;
LoadInterfaceStuff(gProgram_state.racing);
gProgram_state.dont_save_or_load = pSpec->dont_save_or_load;
for (i = 0; i < pSpec->number_of_button_flics; i++) {
LoadFlic(pSpec->flicker_on_flics[i].flic_index);
LoadFlic(pSpec->flicker_off_flics[i].flic_index);
LoadFlic(pSpec->pushed_flics[i].flic_index);
}
InitFlicQueue();
ResetInterfaceTimeout();
gCurrent_choice = pCurrent_choice;
gCurrent_mode = pSpec->initial_imode;
StartMouseCursor();
if (pSpec->font_needed) {
InitRollingLetters();
LoadFont(FONT_TYPEABLE);
}
old_current_splash = gCurrent_splash;
KillSplashScreen();
if (pSpec->start_proc1 != NULL) {
pSpec->start_proc1();
}
if (!gFaded_palette && old_current_splash == NULL && !(pOptions & 2)) {
DRS3StartSound(gEffects_outlet, 3006);
}
if (pOptions & 1) {
if (pSpec->second_opening_flic > 0) {
RunFlic(pSpec->second_opening_flic);
}
} else if (pSpec->first_opening_flic > 0) {
RunFlic(pSpec->first_opening_flic);
}
if (pSpec->start_proc2 != NULL) {
pSpec->start_proc2();
}
copy_areas = NULL;
if (pSpec->number_of_recopy_areas != 0) {
copy_areas = BrMemAllocate(sizeof(void*) * pSpec->number_of_recopy_areas, kMem_intf_copy_areas);
for (i = 0; i < pSpec->number_of_recopy_areas; i++) {
copy_areas[i] = BrPixelmapAllocate(BR_MEMORY_PIXELS,
((pSpec->recopy_areas[i].right[gGraf_data_index] - pSpec->recopy_areas[i].left[gGraf_data_index]) + 3) & ~3,
pSpec->recopy_areas[i].bottom[gGraf_data_index] - pSpec->recopy_areas[i].top[gGraf_data_index],
NULL, 0);
}
}
last_choice = -1;
ChangeSelection(pSpec, &last_choice, &gCurrent_choice, gCurrent_mode, 0);
WaitForNoKeys();
for (i = 0; i < pSpec->number_of_recopy_areas; i++) {
BrPixelmapRectangleCopy(copy_areas[i], 0, 0, gBack_screen, pSpec->recopy_areas[i].left[gGraf_data_index], pSpec->recopy_areas[i].top[gGraf_data_index],
pSpec->recopy_areas[i].right[gGraf_data_index] - pSpec->recopy_areas[i].left[gGraf_data_index],
pSpec->recopy_areas[i].bottom[gGraf_data_index] - pSpec->recopy_areas[i].top[gGraf_data_index]);
}
timed_out = -1; /* Not sure this is right, timed_out looks like its used as a bool? */
last_choice = gCurrent_choice;
last_press = -1;
do {
if (last_choice != gCurrent_choice) {
ChangeSelection(pSpec, &last_choice, &gCurrent_choice, gCurrent_mode, 1);
}
last_choice = gCurrent_choice;
PollKeys();
EdgeTriggerModeOff();
the_key = PDAnyKeyDown();
if (the_key != -1 && the_key != KEY_CAPSLOCK) {
gMouse_in_use = 0;
ResetInterfaceTimeout();
}
EdgeTriggerModeOn();
if ((gTyping_slot < 0 || gAlways_typing) && (PDKeyDown(KEY_LEFT) || PDKeyDown(KEY_KP_4) || last_press == KEY_LEFT)) {
last_press = -1;
if (pSpec->move_left_delta[gCurrent_mode] != 0) {
gCurrent_choice += pSpec->move_left_delta[gCurrent_mode];
if (gCurrent_choice < pSpec->move_left_min[gCurrent_mode]) {
gCurrent_choice = pSpec->move_left_max[gCurrent_mode];
}
if (gCurrent_choice > pSpec->move_left_max[gCurrent_mode]) {
gCurrent_choice = pSpec->move_left_min[gCurrent_mode];
}
DRS3StartSound(gEffects_outlet, 3000);
}
if (pSpec->move_left_proc[gCurrent_mode] != NULL) {
defeat_mode_change = (pSpec->move_left_proc[gCurrent_mode])(&gCurrent_choice, &gCurrent_mode);
} else {
defeat_mode_change = 0;
}
if (pSpec->move_left_new_mode[gCurrent_mode] >= 0 && !defeat_mode_change) {
gCurrent_mode = pSpec->move_left_new_mode[gCurrent_mode];
}
}
if ((gTyping_slot < 0 || gAlways_typing) && (PDKeyDown(KEY_RIGHT) || PDKeyDown(KEY_KP_6) || last_press == KEY_RIGHT)) {
last_press = -1;
if (pSpec->move_right_delta[gCurrent_mode] != 0) {
gCurrent_choice += pSpec->move_right_delta[gCurrent_mode];
if (gCurrent_choice < pSpec->move_right_min[gCurrent_mode]) {
gCurrent_choice = pSpec->move_right_max[gCurrent_mode];
}
if (gCurrent_choice > pSpec->move_right_max[gCurrent_mode]) {
gCurrent_choice = pSpec->move_right_min[gCurrent_mode];
}
DRS3StartSound(gEffects_outlet, 3000);
}
if (pSpec->move_right_proc[gCurrent_mode] != NULL) {
defeat_mode_change = (pSpec->move_right_proc[gCurrent_mode])(&gCurrent_choice, &gCurrent_mode);
} else {
defeat_mode_change = 0;
}
if (pSpec->move_right_new_mode[gCurrent_mode] >= 0 && !defeat_mode_change) {
gCurrent_mode = pSpec->move_right_new_mode[gCurrent_mode];
}
}
if (PDKeyDown(KEY_UP) || PDKeyDown(KEY_KP_8) || last_press == KEY_UP) {
last_press = -1;
if (pSpec->move_up_delta[gCurrent_mode] != 0) {
gCurrent_choice += pSpec->move_up_delta[gCurrent_mode];
if (gCurrent_choice < pSpec->move_up_min[gCurrent_mode]) {
gCurrent_choice = pSpec->move_up_max[gCurrent_mode];
}
if (gCurrent_choice > pSpec->move_up_max[gCurrent_mode]) {
gCurrent_choice = pSpec->move_up_min[gCurrent_mode];
}
DRS3StartSound(gEffects_outlet, 3000);
}
if (pSpec->move_up_proc[gCurrent_mode] != NULL) {
defeat_mode_change = (pSpec->move_up_proc[gCurrent_mode])(&gCurrent_choice, &gCurrent_mode);
} else {
defeat_mode_change = 0;
}
if (pSpec->move_up_new_mode[gCurrent_mode] >= 0 && !defeat_mode_change) {
gCurrent_mode = pSpec->move_up_new_mode[gCurrent_mode];
}
}
if (PDKeyDown(KEY_DOWN) || PDKeyDown(KEY_KP_2) || last_press == KEY_DOWN) {
last_press = -1;
if (pSpec->move_down_delta[gCurrent_mode] != 0) {
gCurrent_choice += pSpec->move_down_delta[gCurrent_mode];
if (gCurrent_choice < pSpec->move_down_min[gCurrent_mode]) {
gCurrent_choice = pSpec->move_down_max[gCurrent_mode];
}
if (gCurrent_choice > pSpec->move_down_max[gCurrent_mode]) {
gCurrent_choice = pSpec->move_down_min[gCurrent_mode];
}
DRS3StartSound(gEffects_outlet, 3000);
}
if (pSpec->move_down_proc[gCurrent_mode] != NULL) {
defeat_mode_change = (pSpec->move_down_proc[gCurrent_mode])(&gCurrent_choice, &gCurrent_mode);
} else {
defeat_mode_change = 0;
}
if (pSpec->move_down_new_mode[gCurrent_mode] >= 0 && !defeat_mode_change) {
gCurrent_mode = pSpec->move_down_new_mode[gCurrent_mode];
}
}
if (gTyping_slot >= 0 && pSpec->typeable[gCurrent_mode] && gTyping_slot != gCurrent_choice && !gAlways_typing) {
gCurrent_choice = gTyping_slot;
}
if (last_choice == gCurrent_choice) {
selection_changed = 0;
} else {
ChangeSelection(pSpec, &last_choice, &gCurrent_choice, gCurrent_mode, 1);
selection_changed = 1;
}
timed_out = pSpec->time_out && ((tU32) PDGetTotalTime() >= pSpec->time_out + gStart_time); // Pierre-Marie Baty -- added type cast
RemoveTransientBitmaps(1);
RecopyAreas(pSpec, copy_areas);
if (pSpec->font_needed) {
RollLettersIn();
}
ServicePanelFlics(1);
if (pSpec->draw_proc != NULL) {
pSpec->draw_proc(gCurrent_choice, gCurrent_mode);
}
ProcessFlicQueue(gFrame_period);
if (DoMouseCursor() || EitherMouseButtonDown()) {
ResetInterfaceTimeout();
}
PDScreenBufferSwap(0);
if (gMouse_in_use && !selection_changed) {
GetMousePosition(&x_coord, &y_coord);
new_mouse_down = EitherMouseButtonDown();
mouse_down = new_mouse_down && !last_mouse_down;
last_mouse_down = new_mouse_down;
mouse_in_somewhere = 0;
for (i = 0; i < pSpec->number_of_mouse_areas; i++) {
if (x_coord >= pSpec->mouse_areas[i].left[gGraf_data_index]
&& y_coord >= pSpec->mouse_areas[i].top[gGraf_data_index]
&& x_coord <= pSpec->mouse_areas[i].right[gGraf_data_index]
&& y_coord <= pSpec->mouse_areas[i].bottom[gGraf_data_index]
&& (gTyping_slot < 0 || gAlways_typing || pSpec->mouse_areas[i].available_when_typing || gTyping_slot == pSpec->mouse_areas[i].new_choice)) {
if (pSpec->mouse_areas[i].new_choice >= 0 && pSpec->mouse_areas[i].new_choice != gCurrent_choice) {
gCurrent_choice = pSpec->mouse_areas[i].new_choice;
ChangeSelection(pSpec, &last_choice, &gCurrent_choice, gCurrent_mode, 0);
}
if (pSpec->mouse_areas[i].new_mode >= 0) {
gCurrent_mode = pSpec->mouse_areas[i].new_mode;
}
if (pSpec->mouse_areas[i].new_mode >= 0 || pSpec->mouse_areas[i].new_choice >= 0) {
mouse_in_somewhere = 1;
}
if (mouse_down) {
if (pSpec->mouse_areas[i].mouse_click != NULL) {
mouse_down = pSpec->mouse_areas[i].mouse_click(&gCurrent_choice, &gCurrent_mode,
x_coord - pSpec->mouse_areas[i].left[gGraf_data_index],
y_coord - pSpec->mouse_areas[i].top[gGraf_data_index]);
}
}
break;
}
}
}
if (PDKeyDown(KEY_RETURN) || PDKeyDown(KEY_KP_ENTER) || (gTyping_slot < 0 && PDKeyDown(KEY_SPACE)) || (gMouse_in_use && mouse_in_somewhere && mouse_down)) {
DRS3StartSound(gEffects_outlet, 3004);
go_ahead = pSpec->go_ahead_allowed[gCurrent_mode];
if (pSpec->go_ahead_proc[gCurrent_mode]) {
go_ahead = (pSpec->go_ahead_proc[gCurrent_mode])(&gCurrent_choice, &gCurrent_mode);
}
} else {
go_ahead = 0;
}
if (PDKeyDown(KEY_ESCAPE)) {
DRS3StartSound(gEffects_outlet, 3005);
escaped = pSpec->escape_allowed[gCurrent_mode];
if (pSpec->escape_proc[gCurrent_mode] != NULL) {
escaped = (pSpec->escape_proc[gCurrent_mode])(&gCurrent_choice, &gCurrent_mode);
}
} else {
escaped = 0;
}
if (escaped && gTyping_slot >= 0 && !gAlways_typing) {
pSpec->get_original_string(0, gTyping_slot, the_str, &the_max);
escaped = 0;
RevertTyping(gTyping_slot, the_str);
gTyping = 0;
gTyping_slot = -1;
}
if (go_ahead) {
if (gCurrent_choice >= 0 && gCurrent_choice < pSpec->number_of_button_flics) {
if (pSpec->pushed_flics[gCurrent_choice].flic_index >= 0) {
AddToFlicQueue(pSpec->pushed_flics[gCurrent_choice].flic_index, pSpec->pushed_flics[gCurrent_choice].x[gGraf_data_index], pSpec->pushed_flics[gCurrent_choice].y[gGraf_data_index], 1);
}
}
if (pSpec->typeable[gCurrent_mode]) {
if (gTyping_slot >= 0 || gAlways_typing) {
KillCursor(gCurrent_choice);
RecopyAreas(pSpec, copy_areas);
RollLettersIn();
PDScreenBufferSwap(0);
} else {
gTyping_slot = gCurrent_choice;
pSpec->get_original_string(1, gCurrent_choice, the_str, &the_max);
StartTyping(gTyping_slot, the_str, the_max);
go_ahead = 0;
gTyping = 1;
}
}
} else if (gTyping_slot >= 0 && !escaped) {
last_press = PDAnyKeyDown();
if (last_press != -1 && (!gAlways_typing || (last_press != KEY_LEFT && last_press != KEY_RIGHT && last_press != KEY_UP && last_press != KEY_DOWN))) {
if (gCurrent_choice != gTyping_slot && !gAlways_typing) {
ChangeSelection(pSpec, &gCurrent_choice, &gTyping_slot, gCurrent_mode, gAlways_typing);
for (i = 0; i < 2; i++) {
if (pSpec->typeable[i]) {
gCurrent_mode = i;
break;
}
}
}
TypeKey(gAlways_typing ? 0 : gCurrent_choice, last_press);
}
}
ServiceGame();
if (last_choice != gCurrent_choice) {
ChangeSelection(pSpec, &last_choice, &gCurrent_choice, gCurrent_mode, 1);
}
if (entry_status != eProg_idling && gProgram_state.prog_status == eProg_idling) {
escaped = 1;
}
} while ((pSpec->exit_proc == NULL || !(pSpec->exit_proc)(&gCurrent_choice, &gCurrent_mode)) && !go_ahead && !timed_out && !escaped);
gTyping = 0;
if (pSpec->font_needed) {
EndRollingLetters();
DisposeFont(FONT_TYPEABLE);
}
if (pSpec->number_of_recopy_areas > 0) {
for (i = 0; i < pSpec->number_of_recopy_areas; i++) {
BrPixelmapFree(copy_areas[i]);
}
BrMemFree(copy_areas);
}
RemoveTransientBitmaps(1);
FlushFlicQueue();
for (i = 0; i < pSpec->number_of_button_flics; i++) {
UnlockFlic(pSpec->flicker_on_flics[i].flic_index);
UnlockFlic(pSpec->flicker_off_flics[i].flic_index);
UnlockFlic(pSpec->pushed_flics[i].flic_index);
}
if (gCurrent_choice == pSpec->escape_code) {
escaped = 1;
go_ahead = 0;
}
if (escaped) {
gCurrent_choice = pSpec->escape_code;
}
if (pSpec->done_proc != NULL) {
result = (pSpec->done_proc)(gCurrent_choice, gCurrent_mode, go_ahead, escaped, timed_out);
} else {
result = gCurrent_choice;
}
if (go_ahead) {
if (pSpec->end_flic_go_ahead > 0) {
DRS3StartSound(gEffects_outlet, 3007);
RunFlic(pSpec->end_flic_go_ahead);
} else if (pSpec->end_flic_go_ahead < 0) {
FadePaletteDown();
}
} else if (escaped) {
if (pSpec->end_flic_escaped > 0) {
DRS3StartSound(gEffects_outlet, 3007);
RunFlic(pSpec->end_flic_escaped);
} else if (pSpec->end_flic_escaped < 0) {
FadePaletteDown();
}
} else {
if (pSpec->end_flic_otherwise > 0) {
DRS3StartSound(gEffects_outlet, 3007);
RunFlic(pSpec->end_flic_otherwise);
} else if (pSpec->end_flic_otherwise < 0) {
FadePaletteDown();
}
}
gProgram_state.dont_save_or_load = 0;
EndMouseCursor();
UnlockInterfaceStuff();
EdgeTriggerModeOff();
return result;
}
// IDA: void __usercall ChangeSelectionTo(int pNew_choice@<EAX>, int pNew_mode@<EDX>)
void ChangeSelectionTo(int pNew_choice, int pNew_mode) {
int last_choice;
LOG_TRACE("(%d, %d)", pNew_choice, pNew_mode);
last_choice = gCurrent_choice;
gCurrent_choice = pNew_choice;
gCurrent_mode = pNew_mode;
ChangeSelection(gSpec, &last_choice, &gCurrent_choice, pNew_mode, 1);
}