2022-05-19 01:51:26 -07:00
|
|
|
#include "interface.h"
|
|
|
|
|
2022-09-15 02:38:23 -07:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
2022-05-19 01:51:26 -07:00
|
|
|
#include "animation.h"
|
2022-06-18 07:39:55 -07:00
|
|
|
#include "art.h"
|
2022-05-19 01:51:26 -07:00
|
|
|
#include "color.h"
|
|
|
|
#include "combat.h"
|
|
|
|
#include "config.h"
|
|
|
|
#include "core.h"
|
|
|
|
#include "critter.h"
|
|
|
|
#include "cycle.h"
|
|
|
|
#include "debug.h"
|
|
|
|
#include "display_monitor.h"
|
|
|
|
#include "draw.h"
|
|
|
|
#include "endgame.h"
|
|
|
|
#include "game.h"
|
|
|
|
#include "game_config.h"
|
|
|
|
#include "game_mouse.h"
|
|
|
|
#include "game_sound.h"
|
2022-06-18 07:39:55 -07:00
|
|
|
#include "geometry.h"
|
2022-05-19 01:51:26 -07:00
|
|
|
#include "item.h"
|
|
|
|
#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-05-28 02:34:49 -07:00
|
|
|
#include "platform_compat.h"
|
2022-05-19 01:51:26 -07:00
|
|
|
#include "proto.h"
|
|
|
|
#include "proto_instance.h"
|
|
|
|
#include "proto_types.h"
|
|
|
|
#include "skill.h"
|
|
|
|
#include "stat.h"
|
|
|
|
#include "text_font.h"
|
|
|
|
#include "tile.h"
|
|
|
|
#include "window_manager.h"
|
|
|
|
|
2022-09-23 05:43:44 -07:00
|
|
|
namespace fallout {
|
|
|
|
|
2022-05-19 01:51:26 -07:00
|
|
|
// The width of connectors in the indicator box.
|
|
|
|
//
|
|
|
|
// There are male connectors on the left, and female connectors on the right.
|
|
|
|
// When displaying series of boxes they appear to be plugged into a chain.
|
|
|
|
#define INDICATOR_BOX_CONNECTOR_WIDTH 3
|
|
|
|
|
|
|
|
// Minimum radiation amount to display RADIATED indicator.
|
|
|
|
#define RADATION_INDICATOR_THRESHOLD 65
|
|
|
|
|
|
|
|
// Minimum poison amount to display POISONED indicator.
|
|
|
|
#define POISON_INDICATOR_THRESHOLD 0
|
|
|
|
|
2022-06-18 07:39:55 -07:00
|
|
|
// The maximum number of indicator boxes the indicator bar can display.
|
|
|
|
//
|
|
|
|
// For unknown reason this number is 6, even though there are only 5 different
|
|
|
|
// indicator types. In addition to that, default screen width 640px cannot hold
|
|
|
|
// 6 boxes 130px each.
|
|
|
|
#define INDICATOR_SLOTS_COUNT (6)
|
|
|
|
|
|
|
|
// The values of it's members are offsets to beginning of numbers in
|
|
|
|
// numbers.frm.
|
|
|
|
typedef enum InterfaceNumbersColor {
|
|
|
|
INTERFACE_NUMBERS_COLOR_WHITE = 0,
|
|
|
|
INTERFACE_NUMBERS_COLOR_YELLOW = 120,
|
|
|
|
INTERFACE_NUMBERS_COLOR_RED = 240,
|
|
|
|
} InterfaceNumbersColor;
|
|
|
|
|
|
|
|
// Available indicators.
|
|
|
|
//
|
|
|
|
// Indicator boxes in the bar are displayed according to the order of this enum.
|
|
|
|
typedef enum Indicator {
|
|
|
|
INDICATOR_ADDICT,
|
|
|
|
INDICATOR_SNEAK,
|
|
|
|
INDICATOR_LEVEL,
|
|
|
|
INDICATOR_POISONED,
|
|
|
|
INDICATOR_RADIATED,
|
|
|
|
INDICATOR_COUNT,
|
|
|
|
} Indicator;
|
|
|
|
|
|
|
|
// Provides metadata about indicator boxes.
|
|
|
|
typedef struct IndicatorDescription {
|
|
|
|
// An identifier of title in `intrface.msg`.
|
|
|
|
int title;
|
|
|
|
|
|
|
|
// A flag denoting this box represents something harmful to the player. It
|
|
|
|
// affects color of the title.
|
|
|
|
bool isBad;
|
|
|
|
|
|
|
|
// Prerendered indicator data.
|
|
|
|
//
|
|
|
|
// This value is provided at runtime during indicator box initialization.
|
|
|
|
// It includes indicator box background with it's title positioned in the
|
|
|
|
// center and is green colored if indicator is good, or red otherwise, as
|
|
|
|
// denoted by [isBad] property.
|
|
|
|
unsigned char* data;
|
|
|
|
} IndicatorDescription;
|
|
|
|
|
|
|
|
typedef struct InterfaceItemState {
|
|
|
|
Object* item;
|
|
|
|
unsigned char isDisabled;
|
|
|
|
unsigned char isWeapon;
|
|
|
|
int primaryHitMode;
|
|
|
|
int secondaryHitMode;
|
|
|
|
int action;
|
|
|
|
int itemFid;
|
|
|
|
} InterfaceItemState;
|
|
|
|
|
|
|
|
static int _intface_redraw_items_callback(Object* a1, Object* a2);
|
|
|
|
static int _intface_change_fid_callback(Object* a1, Object* a2);
|
|
|
|
static void interfaceBarSwapHandsAnimatePutAwayTakeOutSequence(int previousWeaponAnimationCode, int weaponAnimationCode);
|
2022-09-01 08:41:37 -07:00
|
|
|
static int intface_init_items();
|
2022-06-18 07:39:55 -07:00
|
|
|
static int interfaceBarRefreshMainAction();
|
|
|
|
static int endTurnButtonInit();
|
|
|
|
static int endTurnButtonFree();
|
|
|
|
static int endCombatButtonInit();
|
|
|
|
static int endCombatButtonFree();
|
|
|
|
static void interfaceUpdateAmmoBar(int x, int ratio);
|
|
|
|
static int _intface_item_reload();
|
|
|
|
static void interfaceRenderCounter(int x, int y, int previousValue, int value, int offset, int delay);
|
2022-09-01 08:41:37 -07:00
|
|
|
static int intface_fatal_error(int rc);
|
2022-06-18 07:39:55 -07:00
|
|
|
static int indicatorBarInit();
|
|
|
|
static void interfaceBarFree();
|
|
|
|
static void indicatorBarReset();
|
|
|
|
static int indicatorBoxCompareByPosition(const void* a, const void* b);
|
|
|
|
static void indicatorBarRender(int count);
|
|
|
|
static bool indicatorBarAdd(int indicator);
|
|
|
|
|
2022-05-19 01:51:26 -07:00
|
|
|
// 0x518F08
|
2022-06-18 07:39:55 -07:00
|
|
|
static bool gInterfaceBarInitialized = false;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
// 0x518F0C
|
2022-06-18 07:39:55 -07:00
|
|
|
static bool gInterfaceBarSwapHandsInProgress = false;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
// 0x518F10
|
2022-06-18 07:39:55 -07:00
|
|
|
static bool gInterfaceBarEnabled = false;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
// 0x518F14
|
2022-06-18 07:39:55 -07:00
|
|
|
static bool _intfaceHidden = false;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
// 0x518F18
|
2022-06-18 07:39:55 -07:00
|
|
|
static int gInventoryButton = -1;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
// 0x518F24
|
2022-06-18 07:39:55 -07:00
|
|
|
static int gOptionsButton = -1;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
// 0x518F30
|
2022-06-18 07:39:55 -07:00
|
|
|
static int gSkilldexButton = -1;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
// 0x518F40
|
2022-06-18 07:39:55 -07:00
|
|
|
static int gMapButton = -1;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
// 0x518F50
|
2022-06-18 07:39:55 -07:00
|
|
|
static int gPipboyButton = -1;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
// 0x518F5C
|
2022-06-18 07:39:55 -07:00
|
|
|
static int gCharacterButton = -1;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
// 0x518F68
|
2022-06-18 07:39:55 -07:00
|
|
|
static int gSingleAttackButton = -1;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
// 0x518F78
|
2022-06-18 07:39:55 -07:00
|
|
|
static int gInterfaceCurrentHand = HAND_LEFT;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
// 0x518F7C
|
2022-06-18 07:39:55 -07:00
|
|
|
static const Rect gInterfaceBarMainActionRect = { 267, 26, 455, 93 };
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
// 0x518F8C
|
2022-06-18 07:39:55 -07:00
|
|
|
static int gChangeHandsButton = -1;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
// 0x518F9C
|
2022-06-18 07:39:55 -07:00
|
|
|
static bool gInterfaceBarEndButtonsIsVisible = false;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
// Combat mode curtains rect.
|
|
|
|
//
|
|
|
|
// 0x518FA0
|
2022-06-18 07:39:55 -07:00
|
|
|
static const Rect gInterfaceBarEndButtonsRect = { 580, 38, 637, 96 };
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
// 0x518FB0
|
2022-06-18 07:39:55 -07:00
|
|
|
static int gEndTurnButton = -1;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
// 0x518FBC
|
2022-06-18 07:39:55 -07:00
|
|
|
static int gEndCombatButton = -1;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
// 0x518FD4
|
2022-06-18 07:39:55 -07:00
|
|
|
static const Rect gInterfaceBarActionPointsBarRect = { 316, 14, 406, 19 };
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
// 0x518FE8
|
2022-06-18 07:39:55 -07:00
|
|
|
static IndicatorDescription gIndicatorDescriptions[INDICATOR_COUNT] = {
|
2022-05-19 01:51:26 -07:00
|
|
|
{ 102, true, NULL }, // ADDICT
|
|
|
|
{ 100, false, NULL }, // SNEAK
|
|
|
|
{ 101, false, NULL }, // LEVEL
|
|
|
|
{ 103, true, NULL }, // POISONED
|
|
|
|
{ 104, true, NULL }, // RADIATED
|
|
|
|
};
|
|
|
|
|
|
|
|
// 0x519024
|
|
|
|
int gInterfaceBarWindow = -1;
|
|
|
|
|
|
|
|
// 0x519028
|
2022-06-18 07:39:55 -07:00
|
|
|
static int gIndicatorBarWindow = -1;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
// Last hit points rendered in interface.
|
|
|
|
//
|
|
|
|
// Used to animate changes.
|
|
|
|
//
|
|
|
|
// 0x51902C
|
2022-06-18 07:39:55 -07:00
|
|
|
static int gInterfaceLastRenderedHitPoints = 0;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
// Last color used to render hit points in interface.
|
|
|
|
//
|
|
|
|
// Used to animate changes.
|
|
|
|
//
|
|
|
|
// 0x519030
|
2022-06-18 07:39:55 -07:00
|
|
|
static int gInterfaceLastRenderedHitPointsColor = INTERFACE_NUMBERS_COLOR_RED;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
// Last armor class rendered in interface.
|
|
|
|
//
|
|
|
|
// Used to animate changes.
|
|
|
|
//
|
|
|
|
// 0x519034
|
2022-06-18 07:39:55 -07:00
|
|
|
static int gInterfaceLastRenderedArmorClass = 0;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
// Each slot contains one of indicators or -1 if slot is empty.
|
|
|
|
//
|
|
|
|
// 0x5970E0
|
2022-06-18 07:39:55 -07:00
|
|
|
static int gIndicatorSlots[INDICATOR_SLOTS_COUNT];
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
// 0x5970F8
|
2022-06-18 07:39:55 -07:00
|
|
|
static InterfaceItemState gInterfaceItemStates[HAND_COUNT];
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
// 0x597138
|
2022-06-18 07:39:55 -07:00
|
|
|
static bool gIndicatorBarIsVisible;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
// 0x597154
|
2022-06-18 07:39:55 -07:00
|
|
|
static unsigned char _itemButtonDown[188 * 67];
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
// 0x59A2B4
|
2022-06-18 07:39:55 -07:00
|
|
|
static unsigned char _itemButtonUp[188 * 67];
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
// 0x59D3F4
|
2022-06-18 07:39:55 -07:00
|
|
|
static unsigned char* gInterfaceWindowBuffer;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
// A slice of main interface background containing 10 shadowed action point
|
|
|
|
// dots. In combat mode individual colored dots are rendered on top of this
|
|
|
|
// background.
|
|
|
|
//
|
|
|
|
// This buffer is initialized once and does not change throughout the game.
|
|
|
|
//
|
|
|
|
// 0x59D40C
|
2022-06-18 07:39:55 -07:00
|
|
|
static unsigned char gInterfaceActionPointsBarBackground[90 * 5];
|
2022-05-19 01:51:26 -07:00
|
|
|
|
2022-05-21 11:30:25 -07:00
|
|
|
// Should the game window stretch all the way to the bottom or sit at the top of the interface bar (default)
|
|
|
|
bool gInterfaceBarMode = false;
|
|
|
|
|
2022-09-24 11:04:32 -07:00
|
|
|
static FrmImage _inventoryButtonNormalFrmImage;
|
|
|
|
static FrmImage _inventoryButtonPressedFrmImage;
|
|
|
|
static FrmImage _optionsButtonNormalFrmImage;
|
|
|
|
static FrmImage _optionsButtonPressedFrmImage;
|
|
|
|
static FrmImage _skilldexButtonNormalFrmImage;
|
|
|
|
static FrmImage _skilldexButtonPressedFrmImage;
|
|
|
|
static FrmImage _skilldexButtonMaskFrmImage;
|
|
|
|
static FrmImage _mapButtonNormalFrmImage;
|
|
|
|
static FrmImage _mapButtonPressedFrmImage;
|
|
|
|
static FrmImage _mapButtonMaskFrmImage;
|
|
|
|
static FrmImage _pipboyButtonNormalFrmImage;
|
|
|
|
static FrmImage _pipboyButtonPressedFrmImage;
|
|
|
|
static FrmImage _characterButtonNormalFrmImage;
|
|
|
|
static FrmImage _characterButtonPressedFrmImage;
|
|
|
|
static FrmImage _changeHandsButtonNormalFrmImage;
|
|
|
|
static FrmImage _changeHandsButtonPressedFrmImage;
|
|
|
|
static FrmImage _changeHandsButtonMaskFrmImage;
|
|
|
|
static FrmImage _itemButtonNormalFrmImage;
|
|
|
|
static FrmImage _itemButtonPressedFrmImage;
|
|
|
|
static FrmImage _itemButtonDisabledFrmImage;
|
|
|
|
static FrmImage _endTurnButtonNormalFrmImage;
|
|
|
|
static FrmImage _endTurnButtonPressedFrmImage;
|
|
|
|
static FrmImage _endCombatButtonNormalFrmImage;
|
|
|
|
static FrmImage _endCombatButtonPressedFrmImage;
|
|
|
|
static FrmImage _numbersFrmImage;
|
|
|
|
static FrmImage _greenLightFrmImage;
|
|
|
|
static FrmImage _yellowLightFrmImage;
|
|
|
|
static FrmImage _redLightFrmImage;
|
|
|
|
|
2022-05-19 01:51:26 -07:00
|
|
|
// intface_init
|
|
|
|
// 0x45D880
|
|
|
|
int interfaceInit()
|
|
|
|
{
|
|
|
|
int fid;
|
|
|
|
|
|
|
|
if (gInterfaceBarWindow != -1) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
gInterfaceBarInitialized = 1;
|
|
|
|
|
2022-05-21 04:00:30 -07:00
|
|
|
int interfaceBarWindowX = (screenGetWidth() - INTERFACE_BAR_WIDTH) / 2;
|
2022-05-21 11:30:25 -07:00
|
|
|
int interfaceBarWindowY = screenGetHeight() - INTERFACE_BAR_HEIGHT;
|
2022-05-20 15:37:05 -07:00
|
|
|
|
2022-05-21 04:00:30 -07:00
|
|
|
gInterfaceBarWindow = windowCreate(interfaceBarWindowX, interfaceBarWindowY, INTERFACE_BAR_WIDTH, INTERFACE_BAR_HEIGHT, _colorTable[0], WINDOW_HIDDEN);
|
2022-05-19 01:51:26 -07:00
|
|
|
if (gInterfaceBarWindow == -1) {
|
2022-09-01 08:41:37 -07:00
|
|
|
// NOTE: Uninline.
|
|
|
|
return intface_fatal_error(-1);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
gInterfaceWindowBuffer = windowGetBuffer(gInterfaceBarWindow);
|
|
|
|
if (gInterfaceWindowBuffer == NULL) {
|
2022-09-01 08:41:37 -07:00
|
|
|
// NOTE: Uninline.
|
|
|
|
return intface_fatal_error(-1);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
2022-09-24 11:04:32 -07:00
|
|
|
FrmImage backgroundFrmImage;
|
2022-07-29 06:04:05 -07:00
|
|
|
fid = buildFid(OBJ_TYPE_INTERFACE, 16, 0, 0, 0);
|
2022-09-24 11:04:32 -07:00
|
|
|
if (!backgroundFrmImage.lock(fid)) {
|
2022-09-01 08:41:37 -07:00
|
|
|
// NOTE: Uninline.
|
|
|
|
return intface_fatal_error(-1);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
2022-09-24 11:04:32 -07:00
|
|
|
blitBufferToBuffer(backgroundFrmImage.getData(), INTERFACE_BAR_WIDTH, INTERFACE_BAR_HEIGHT - 1, INTERFACE_BAR_WIDTH, gInterfaceWindowBuffer, 640);
|
|
|
|
backgroundFrmImage.unlock();
|
2022-05-19 01:51:26 -07:00
|
|
|
|
2022-07-29 06:04:05 -07:00
|
|
|
fid = buildFid(OBJ_TYPE_INTERFACE, 47, 0, 0, 0);
|
2022-09-24 11:04:32 -07:00
|
|
|
if (!_inventoryButtonNormalFrmImage.lock(fid)) {
|
2022-09-01 08:41:37 -07:00
|
|
|
// NOTE: Uninline.
|
|
|
|
return intface_fatal_error(-1);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
2022-07-29 06:04:05 -07:00
|
|
|
fid = buildFid(OBJ_TYPE_INTERFACE, 46, 0, 0, 0);
|
2022-09-24 11:04:32 -07:00
|
|
|
if (!_inventoryButtonPressedFrmImage.lock(fid)) {
|
2022-09-01 08:41:37 -07:00
|
|
|
// NOTE: Uninline.
|
|
|
|
return intface_fatal_error(-1);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
2022-09-24 11:04:32 -07:00
|
|
|
gInventoryButton = buttonCreate(gInterfaceBarWindow, 211, 40, 32, 21, -1, -1, -1, KEY_LOWERCASE_I, _inventoryButtonNormalFrmImage.getData(), _inventoryButtonPressedFrmImage.getData(), NULL, 0);
|
2022-05-19 01:51:26 -07:00
|
|
|
if (gInventoryButton == -1) {
|
2022-09-01 08:41:37 -07:00
|
|
|
// NOTE: Uninline.
|
|
|
|
return intface_fatal_error(-1);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
buttonSetCallbacks(gInventoryButton, _gsound_med_butt_press, _gsound_med_butt_release);
|
|
|
|
|
2022-07-29 06:04:05 -07:00
|
|
|
fid = buildFid(OBJ_TYPE_INTERFACE, 18, 0, 0, 0);
|
2022-09-24 11:04:32 -07:00
|
|
|
if (!_optionsButtonNormalFrmImage.lock(fid)) {
|
2022-09-01 08:41:37 -07:00
|
|
|
// NOTE: Uninline.
|
|
|
|
return intface_fatal_error(-1);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
2022-07-29 06:04:05 -07:00
|
|
|
fid = buildFid(OBJ_TYPE_INTERFACE, 17, 0, 0, 0);
|
2022-09-24 11:04:32 -07:00
|
|
|
if (!_optionsButtonPressedFrmImage.lock(fid)) {
|
2022-09-01 08:41:37 -07:00
|
|
|
// NOTE: Uninline.
|
|
|
|
return intface_fatal_error(-1);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
2022-09-24 11:04:32 -07:00
|
|
|
gOptionsButton = buttonCreate(gInterfaceBarWindow, 210, 61, 34, 34, -1, -1, -1, KEY_LOWERCASE_O, _optionsButtonNormalFrmImage.getData(), _optionsButtonPressedFrmImage.getData(), NULL, 0);
|
2022-05-19 01:51:26 -07:00
|
|
|
if (gOptionsButton == -1) {
|
2022-09-01 08:41:37 -07:00
|
|
|
// NOTE: Uninline.
|
|
|
|
return intface_fatal_error(-1);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
buttonSetCallbacks(gOptionsButton, _gsound_med_butt_press, _gsound_med_butt_release);
|
|
|
|
|
2022-07-29 06:04:05 -07:00
|
|
|
fid = buildFid(OBJ_TYPE_INTERFACE, 6, 0, 0, 0);
|
2022-09-24 11:04:32 -07:00
|
|
|
if (!_skilldexButtonNormalFrmImage.lock(fid)) {
|
2022-09-01 08:41:37 -07:00
|
|
|
// NOTE: Uninline.
|
|
|
|
return intface_fatal_error(-1);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
2022-07-29 06:04:05 -07:00
|
|
|
fid = buildFid(OBJ_TYPE_INTERFACE, 7, 0, 0, 0);
|
2022-09-24 11:04:32 -07:00
|
|
|
if (!_skilldexButtonPressedFrmImage.lock(fid)) {
|
2022-09-01 08:41:37 -07:00
|
|
|
// NOTE: Uninline.
|
|
|
|
return intface_fatal_error(-1);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
2022-07-29 06:04:05 -07:00
|
|
|
fid = buildFid(OBJ_TYPE_INTERFACE, 6, 0, 0, 0);
|
2022-09-24 11:04:32 -07:00
|
|
|
if (!_skilldexButtonMaskFrmImage.lock(fid)) {
|
2022-09-01 08:41:37 -07:00
|
|
|
// NOTE: Uninline.
|
|
|
|
return intface_fatal_error(-1);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
2022-09-24 11:04:32 -07:00
|
|
|
gSkilldexButton = buttonCreate(gInterfaceBarWindow, 523, 6, 22, 21, -1, -1, -1, KEY_LOWERCASE_S, _skilldexButtonNormalFrmImage.getData(), _skilldexButtonPressedFrmImage.getData(), NULL, BUTTON_FLAG_TRANSPARENT);
|
2022-05-19 01:51:26 -07:00
|
|
|
if (gSkilldexButton == -1) {
|
2022-09-01 08:41:37 -07:00
|
|
|
// NOTE: Uninline.
|
|
|
|
return intface_fatal_error(-1);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
2022-09-24 11:04:32 -07:00
|
|
|
buttonSetMask(gSkilldexButton, _skilldexButtonMaskFrmImage.getData());
|
2022-05-19 01:51:26 -07:00
|
|
|
buttonSetCallbacks(gSkilldexButton, _gsound_med_butt_press, _gsound_med_butt_release);
|
|
|
|
|
2022-07-29 06:04:05 -07:00
|
|
|
fid = buildFid(OBJ_TYPE_INTERFACE, 13, 0, 0, 0);
|
2022-09-24 11:04:32 -07:00
|
|
|
if (!_mapButtonNormalFrmImage.lock(fid)) {
|
2022-09-01 08:41:37 -07:00
|
|
|
// NOTE: Uninline.
|
|
|
|
return intface_fatal_error(-1);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
2022-07-29 06:04:05 -07:00
|
|
|
fid = buildFid(OBJ_TYPE_INTERFACE, 10, 0, 0, 0);
|
2022-09-24 11:04:32 -07:00
|
|
|
if (!_mapButtonPressedFrmImage.lock(fid)) {
|
2022-09-01 08:41:37 -07:00
|
|
|
// NOTE: Uninline.
|
|
|
|
return intface_fatal_error(-1);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
2022-07-29 06:04:05 -07:00
|
|
|
fid = buildFid(OBJ_TYPE_INTERFACE, 13, 0, 0, 0);
|
2022-09-24 11:04:32 -07:00
|
|
|
if (!_mapButtonMaskFrmImage.lock(fid)) {
|
2022-09-01 08:41:37 -07:00
|
|
|
// NOTE: Uninline.
|
|
|
|
return intface_fatal_error(-1);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
2022-09-24 11:04:32 -07:00
|
|
|
gMapButton = buttonCreate(gInterfaceBarWindow, 526, 39, 41, 19, -1, -1, -1, KEY_TAB, _mapButtonNormalFrmImage.getData(), _mapButtonPressedFrmImage.getData(), NULL, BUTTON_FLAG_TRANSPARENT);
|
2022-05-19 01:51:26 -07:00
|
|
|
if (gMapButton == -1) {
|
2022-09-01 08:41:37 -07:00
|
|
|
// NOTE: Uninline.
|
|
|
|
return intface_fatal_error(-1);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
2022-09-24 11:04:32 -07:00
|
|
|
buttonSetMask(gMapButton, _mapButtonMaskFrmImage.getData());
|
2022-05-19 01:51:26 -07:00
|
|
|
buttonSetCallbacks(gMapButton, _gsound_med_butt_press, _gsound_med_butt_release);
|
|
|
|
|
2022-07-29 06:04:05 -07:00
|
|
|
fid = buildFid(OBJ_TYPE_INTERFACE, 59, 0, 0, 0);
|
2022-09-24 11:04:32 -07:00
|
|
|
if (!_pipboyButtonNormalFrmImage.lock(fid)) {
|
2022-09-01 08:41:37 -07:00
|
|
|
// NOTE: Uninline.
|
|
|
|
return intface_fatal_error(-1);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
2022-07-29 06:04:05 -07:00
|
|
|
fid = buildFid(OBJ_TYPE_INTERFACE, 58, 0, 0, 0);
|
2022-09-24 11:04:32 -07:00
|
|
|
if (!_pipboyButtonPressedFrmImage.lock(fid)) {
|
2022-09-01 08:41:37 -07:00
|
|
|
// NOTE: Uninline.
|
|
|
|
return intface_fatal_error(-1);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
2022-09-24 11:04:32 -07:00
|
|
|
gPipboyButton = buttonCreate(gInterfaceBarWindow, 526, 77, 41, 19, -1, -1, -1, KEY_LOWERCASE_P, _pipboyButtonNormalFrmImage.getData(), _pipboyButtonPressedFrmImage.getData(), NULL, 0);
|
2022-05-19 01:51:26 -07:00
|
|
|
if (gPipboyButton == -1) {
|
2022-09-01 08:41:37 -07:00
|
|
|
// NOTE: Uninline.
|
|
|
|
return intface_fatal_error(-1);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
2022-09-24 11:04:32 -07:00
|
|
|
buttonSetMask(gPipboyButton, _mapButtonMaskFrmImage.getData());
|
2022-05-19 01:51:26 -07:00
|
|
|
buttonSetCallbacks(gPipboyButton, _gsound_med_butt_press, _gsound_med_butt_release);
|
|
|
|
|
2022-07-29 06:04:05 -07:00
|
|
|
fid = buildFid(OBJ_TYPE_INTERFACE, 57, 0, 0, 0);
|
2022-09-24 11:04:32 -07:00
|
|
|
if (!_characterButtonNormalFrmImage.lock(fid)) {
|
2022-09-01 08:41:37 -07:00
|
|
|
// NOTE: Uninline.
|
|
|
|
return intface_fatal_error(-1);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
2022-07-29 06:04:05 -07:00
|
|
|
fid = buildFid(OBJ_TYPE_INTERFACE, 56, 0, 0, 0);
|
2022-09-24 11:04:32 -07:00
|
|
|
if (!_characterButtonPressedFrmImage.lock(fid)) {
|
2022-09-01 08:41:37 -07:00
|
|
|
// NOTE: Uninline.
|
|
|
|
return intface_fatal_error(-1);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
2022-09-24 11:04:32 -07:00
|
|
|
gCharacterButton = buttonCreate(gInterfaceBarWindow, 526, 58, 41, 19, -1, -1, -1, KEY_LOWERCASE_C, _characterButtonNormalFrmImage.getData(), _characterButtonPressedFrmImage.getData(), NULL, 0);
|
2022-05-19 01:51:26 -07:00
|
|
|
if (gCharacterButton == -1) {
|
2022-09-01 08:41:37 -07:00
|
|
|
// NOTE: Uninline.
|
|
|
|
return intface_fatal_error(-1);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
2022-09-24 11:04:32 -07:00
|
|
|
buttonSetMask(gCharacterButton, _mapButtonMaskFrmImage.getData());
|
2022-05-19 01:51:26 -07:00
|
|
|
buttonSetCallbacks(gCharacterButton, _gsound_med_butt_press, _gsound_med_butt_release);
|
|
|
|
|
2022-07-29 06:04:05 -07:00
|
|
|
fid = buildFid(OBJ_TYPE_INTERFACE, 32, 0, 0, 0);
|
2022-09-24 11:04:32 -07:00
|
|
|
if (!_itemButtonNormalFrmImage.lock(fid)) {
|
2022-09-01 08:41:37 -07:00
|
|
|
// NOTE: Uninline.
|
|
|
|
return intface_fatal_error(-1);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
2022-07-29 06:04:05 -07:00
|
|
|
fid = buildFid(OBJ_TYPE_INTERFACE, 31, 0, 0, 0);
|
2022-09-24 11:04:32 -07:00
|
|
|
if (!_itemButtonPressedFrmImage.lock(fid)) {
|
2022-09-01 08:41:37 -07:00
|
|
|
// NOTE: Uninline.
|
|
|
|
return intface_fatal_error(-1);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
2022-07-29 06:04:05 -07:00
|
|
|
fid = buildFid(OBJ_TYPE_INTERFACE, 73, 0, 0, 0);
|
2022-09-24 11:04:32 -07:00
|
|
|
if (!_itemButtonDisabledFrmImage.lock(fid)) {
|
2022-09-01 08:41:37 -07:00
|
|
|
// NOTE: Uninline.
|
|
|
|
return intface_fatal_error(-1);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
2022-09-24 11:04:32 -07:00
|
|
|
memcpy(_itemButtonUp, _itemButtonNormalFrmImage.getData(), sizeof(_itemButtonUp));
|
|
|
|
memcpy(_itemButtonDown, _itemButtonPressedFrmImage.getData(), sizeof(_itemButtonDown));
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
gSingleAttackButton = buttonCreate(gInterfaceBarWindow, 267, 26, 188, 67, -1, -1, -1, -20, _itemButtonUp, _itemButtonDown, NULL, BUTTON_FLAG_TRANSPARENT);
|
|
|
|
if (gSingleAttackButton == -1) {
|
2022-09-01 08:41:37 -07:00
|
|
|
// NOTE: Uninline.
|
|
|
|
return intface_fatal_error(-1);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
buttonSetRightMouseCallbacks(gSingleAttackButton, -1, KEY_LOWERCASE_N, NULL, NULL);
|
|
|
|
buttonSetCallbacks(gSingleAttackButton, _gsound_lrg_butt_press, _gsound_lrg_butt_release);
|
|
|
|
|
2022-07-29 06:04:05 -07:00
|
|
|
fid = buildFid(OBJ_TYPE_INTERFACE, 6, 0, 0, 0);
|
2022-09-24 11:04:32 -07:00
|
|
|
if (!_changeHandsButtonNormalFrmImage.lock(fid)) {
|
2022-09-01 08:41:37 -07:00
|
|
|
// NOTE: Uninline.
|
|
|
|
return intface_fatal_error(-1);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
2022-07-29 06:04:05 -07:00
|
|
|
fid = buildFid(OBJ_TYPE_INTERFACE, 7, 0, 0, 0);
|
2022-09-24 11:04:32 -07:00
|
|
|
if (!_changeHandsButtonPressedFrmImage.lock(fid)) {
|
2022-09-01 08:41:37 -07:00
|
|
|
// NOTE: Uninline.
|
|
|
|
return intface_fatal_error(-1);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
2022-07-29 06:04:05 -07:00
|
|
|
fid = buildFid(OBJ_TYPE_INTERFACE, 6, 0, 0, 0);
|
2022-09-24 11:04:32 -07:00
|
|
|
if (!_changeHandsButtonMaskFrmImage.lock(fid)) {
|
2022-09-01 08:41:37 -07:00
|
|
|
// NOTE: Uninline.
|
|
|
|
return intface_fatal_error(-1);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Swap hands button
|
2022-09-24 11:04:32 -07:00
|
|
|
gChangeHandsButton = buttonCreate(gInterfaceBarWindow, 218, 6, 22, 21, -1, -1, -1, KEY_LOWERCASE_B, _changeHandsButtonNormalFrmImage.getData(), _changeHandsButtonPressedFrmImage.getData(), NULL, BUTTON_FLAG_TRANSPARENT);
|
2022-05-19 01:51:26 -07:00
|
|
|
if (gChangeHandsButton == -1) {
|
2022-09-01 08:41:37 -07:00
|
|
|
// NOTE: Uninline.
|
|
|
|
return intface_fatal_error(-1);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
2022-09-24 11:04:32 -07:00
|
|
|
buttonSetMask(gChangeHandsButton, _changeHandsButtonMaskFrmImage.getData());
|
2022-05-19 01:51:26 -07:00
|
|
|
buttonSetCallbacks(gChangeHandsButton, _gsound_med_butt_press, _gsound_med_butt_release);
|
|
|
|
|
2022-07-29 06:04:05 -07:00
|
|
|
fid = buildFid(OBJ_TYPE_INTERFACE, 82, 0, 0, 0);
|
2022-09-24 11:04:32 -07:00
|
|
|
if (!_numbersFrmImage.lock(fid)) {
|
2022-09-01 08:41:37 -07:00
|
|
|
// NOTE: Uninline.
|
|
|
|
return intface_fatal_error(-1);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
2022-07-29 06:04:05 -07:00
|
|
|
fid = buildFid(OBJ_TYPE_INTERFACE, 83, 0, 0, 0);
|
2022-09-24 11:04:32 -07:00
|
|
|
if (!_greenLightFrmImage.lock(fid)) {
|
2022-09-01 08:41:37 -07:00
|
|
|
// NOTE: Uninline.
|
|
|
|
return intface_fatal_error(-1);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
2022-07-29 06:04:05 -07:00
|
|
|
fid = buildFid(OBJ_TYPE_INTERFACE, 84, 0, 0, 0);
|
2022-09-24 11:04:32 -07:00
|
|
|
if (!_yellowLightFrmImage.lock(fid)) {
|
2022-09-01 08:41:37 -07:00
|
|
|
// NOTE: Uninline.
|
|
|
|
return intface_fatal_error(-1);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
2022-07-29 06:04:05 -07:00
|
|
|
fid = buildFid(OBJ_TYPE_INTERFACE, 85, 0, 0, 0);
|
2022-09-24 11:04:32 -07:00
|
|
|
if (!_redLightFrmImage.lock(fid)) {
|
2022-09-01 08:41:37 -07:00
|
|
|
// NOTE: Uninline.
|
|
|
|
return intface_fatal_error(-1);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
blitBufferToBuffer(gInterfaceWindowBuffer + 640 * 14 + 316, 90, 5, 640, gInterfaceActionPointsBarBackground, 90);
|
|
|
|
|
|
|
|
if (indicatorBarInit() == -1) {
|
2022-09-01 08:41:37 -07:00
|
|
|
// NOTE: Uninline.
|
|
|
|
return intface_fatal_error(-1);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
gInterfaceCurrentHand = HAND_LEFT;
|
|
|
|
|
2022-09-01 08:41:37 -07:00
|
|
|
// NOTE: Uninline.
|
|
|
|
intface_init_items();
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
displayMonitorInit();
|
|
|
|
|
|
|
|
gInterfaceBarEnabled = true;
|
|
|
|
gInterfaceBarInitialized = false;
|
|
|
|
_intfaceHidden = 1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x45E3D0
|
|
|
|
void interfaceReset()
|
|
|
|
{
|
|
|
|
interfaceBarEnable();
|
|
|
|
|
2022-09-01 08:41:37 -07:00
|
|
|
// NOTE: Uninline.
|
|
|
|
intface_hide();
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
indicatorBarRefresh();
|
|
|
|
displayMonitorReset();
|
|
|
|
|
|
|
|
// NOTE: Uninline a seemingly inlined routine.
|
|
|
|
indicatorBarReset();
|
|
|
|
|
|
|
|
gInterfaceCurrentHand = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x45E440
|
|
|
|
void interfaceFree()
|
|
|
|
{
|
|
|
|
if (gInterfaceBarWindow != -1) {
|
|
|
|
displayMonitorExit();
|
|
|
|
|
2022-09-24 11:04:32 -07:00
|
|
|
_redLightFrmImage.unlock();
|
|
|
|
_yellowLightFrmImage.unlock();
|
|
|
|
_greenLightFrmImage.unlock();
|
2022-05-19 01:51:26 -07:00
|
|
|
|
2022-09-24 11:04:32 -07:00
|
|
|
_numbersFrmImage.unlock();
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
if (gChangeHandsButton != -1) {
|
|
|
|
buttonDestroy(gChangeHandsButton);
|
|
|
|
gChangeHandsButton = -1;
|
|
|
|
}
|
|
|
|
|
2022-09-24 11:04:32 -07:00
|
|
|
_changeHandsButtonMaskFrmImage.unlock();
|
|
|
|
_changeHandsButtonPressedFrmImage.unlock();
|
|
|
|
_changeHandsButtonNormalFrmImage.unlock();
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
if (gSingleAttackButton != -1) {
|
|
|
|
buttonDestroy(gSingleAttackButton);
|
|
|
|
gSingleAttackButton = -1;
|
|
|
|
}
|
|
|
|
|
2022-09-24 11:04:32 -07:00
|
|
|
_itemButtonDisabledFrmImage.unlock();
|
|
|
|
_itemButtonPressedFrmImage.unlock();
|
|
|
|
_itemButtonNormalFrmImage.unlock();
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
if (gCharacterButton != -1) {
|
|
|
|
buttonDestroy(gCharacterButton);
|
|
|
|
gCharacterButton = -1;
|
|
|
|
}
|
|
|
|
|
2022-09-24 11:04:32 -07:00
|
|
|
_characterButtonPressedFrmImage.unlock();
|
|
|
|
_characterButtonNormalFrmImage.unlock();
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
if (gPipboyButton != -1) {
|
|
|
|
buttonDestroy(gPipboyButton);
|
|
|
|
gPipboyButton = -1;
|
|
|
|
}
|
|
|
|
|
2022-09-24 11:04:32 -07:00
|
|
|
_pipboyButtonPressedFrmImage.unlock();
|
|
|
|
_pipboyButtonNormalFrmImage.unlock();
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
if (gMapButton != -1) {
|
|
|
|
buttonDestroy(gMapButton);
|
|
|
|
gMapButton = -1;
|
|
|
|
}
|
|
|
|
|
2022-09-24 11:04:32 -07:00
|
|
|
_mapButtonMaskFrmImage.unlock();
|
|
|
|
_mapButtonPressedFrmImage.unlock();
|
|
|
|
_mapButtonNormalFrmImage.unlock();
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
if (gSkilldexButton != -1) {
|
|
|
|
buttonDestroy(gSkilldexButton);
|
|
|
|
gSkilldexButton = -1;
|
|
|
|
}
|
|
|
|
|
2022-09-24 11:04:32 -07:00
|
|
|
_skilldexButtonMaskFrmImage.unlock();
|
|
|
|
_skilldexButtonPressedFrmImage.unlock();
|
|
|
|
_skilldexButtonNormalFrmImage.unlock();
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
if (gOptionsButton != -1) {
|
|
|
|
buttonDestroy(gOptionsButton);
|
|
|
|
gOptionsButton = -1;
|
|
|
|
}
|
|
|
|
|
2022-09-24 11:04:32 -07:00
|
|
|
_optionsButtonPressedFrmImage.unlock();
|
|
|
|
_optionsButtonNormalFrmImage.unlock();
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
if (gInventoryButton != -1) {
|
|
|
|
buttonDestroy(gInventoryButton);
|
|
|
|
gInventoryButton = -1;
|
|
|
|
}
|
|
|
|
|
2022-09-24 11:04:32 -07:00
|
|
|
_inventoryButtonPressedFrmImage.unlock();
|
|
|
|
_inventoryButtonNormalFrmImage.unlock();
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
if (gInterfaceBarWindow != -1) {
|
|
|
|
windowDestroy(gInterfaceBarWindow);
|
|
|
|
gInterfaceBarWindow = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
interfaceBarFree();
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x45E860
|
|
|
|
int interfaceLoad(File* stream)
|
|
|
|
{
|
|
|
|
if (gInterfaceBarWindow == -1) {
|
|
|
|
if (interfaceInit() == -1) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int interfaceBarEnabled;
|
|
|
|
if (fileReadInt32(stream, &interfaceBarEnabled) == -1) return -1;
|
|
|
|
|
|
|
|
int v2;
|
|
|
|
if (fileReadInt32(stream, &v2) == -1) return -1;
|
|
|
|
|
|
|
|
int interfaceCurrentHand;
|
|
|
|
if (fileReadInt32(stream, &interfaceCurrentHand) == -1) return -1;
|
|
|
|
|
2022-07-07 00:52:54 -07:00
|
|
|
bool interfaceBarEndButtonsIsVisible;
|
|
|
|
if (fileReadBool(stream, &interfaceBarEndButtonsIsVisible) == -1) return -1;
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
if (!gInterfaceBarEnabled) {
|
|
|
|
interfaceBarEnable();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (v2) {
|
2022-09-01 08:41:37 -07:00
|
|
|
// NOTE: Uninline.
|
|
|
|
intface_hide();
|
2022-05-19 01:51:26 -07:00
|
|
|
} else {
|
|
|
|
_intface_show();
|
|
|
|
}
|
|
|
|
|
|
|
|
interfaceRenderHitPoints(false);
|
|
|
|
interfaceRenderArmorClass(false);
|
|
|
|
|
|
|
|
gInterfaceCurrentHand = interfaceCurrentHand;
|
|
|
|
|
|
|
|
interfaceUpdateItems(false, INTERFACE_ITEM_ACTION_DEFAULT, INTERFACE_ITEM_ACTION_DEFAULT);
|
|
|
|
|
|
|
|
if (interfaceBarEndButtonsIsVisible != gInterfaceBarEndButtonsIsVisible) {
|
|
|
|
if (interfaceBarEndButtonsIsVisible) {
|
|
|
|
interfaceBarEndButtonsShow(false);
|
|
|
|
} else {
|
|
|
|
interfaceBarEndButtonsHide(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!interfaceBarEnabled) {
|
|
|
|
interfaceBarDisable();
|
|
|
|
}
|
|
|
|
|
|
|
|
indicatorBarRefresh();
|
|
|
|
|
|
|
|
windowRefresh(gInterfaceBarWindow);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x45E988
|
|
|
|
int interfaceSave(File* stream)
|
|
|
|
{
|
|
|
|
if (gInterfaceBarWindow == -1) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fileWriteInt32(stream, gInterfaceBarEnabled) == -1) return -1;
|
|
|
|
if (fileWriteInt32(stream, _intfaceHidden) == -1) return -1;
|
|
|
|
if (fileWriteInt32(stream, gInterfaceCurrentHand) == -1) return -1;
|
|
|
|
if (fileWriteInt32(stream, gInterfaceBarEndButtonsIsVisible) == -1) return -1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-09-01 08:41:37 -07:00
|
|
|
// NOTE: Inlined.
|
|
|
|
//
|
|
|
|
// 0x45E9E0
|
|
|
|
void intface_hide()
|
|
|
|
{
|
|
|
|
if (gInterfaceBarWindow != -1) {
|
|
|
|
if (!_intfaceHidden) {
|
|
|
|
windowHide(gInterfaceBarWindow);
|
|
|
|
_intfaceHidden = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
indicatorBarRefresh();
|
|
|
|
}
|
|
|
|
|
2022-05-19 01:51:26 -07:00
|
|
|
// 0x45EA10
|
|
|
|
void _intface_show()
|
|
|
|
{
|
|
|
|
if (gInterfaceBarWindow != -1) {
|
|
|
|
if (_intfaceHidden) {
|
|
|
|
interfaceUpdateItems(false, INTERFACE_ITEM_ACTION_DEFAULT, INTERFACE_ITEM_ACTION_DEFAULT);
|
|
|
|
interfaceRenderHitPoints(false);
|
|
|
|
interfaceRenderArmorClass(false);
|
|
|
|
windowUnhide(gInterfaceBarWindow);
|
|
|
|
_intfaceHidden = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
indicatorBarRefresh();
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x45EA64
|
|
|
|
void interfaceBarEnable()
|
|
|
|
{
|
|
|
|
if (!gInterfaceBarEnabled) {
|
|
|
|
buttonEnable(gInventoryButton);
|
|
|
|
buttonEnable(gOptionsButton);
|
|
|
|
buttonEnable(gSkilldexButton);
|
|
|
|
buttonEnable(gMapButton);
|
|
|
|
buttonEnable(gPipboyButton);
|
|
|
|
buttonEnable(gCharacterButton);
|
|
|
|
|
|
|
|
if (gInterfaceItemStates[gInterfaceCurrentHand].isDisabled == 0) {
|
|
|
|
buttonEnable(gSingleAttackButton);
|
|
|
|
}
|
|
|
|
|
|
|
|
buttonEnable(gEndTurnButton);
|
|
|
|
buttonEnable(gEndCombatButton);
|
|
|
|
displayMonitorEnable();
|
|
|
|
|
|
|
|
gInterfaceBarEnabled = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x45EAFC
|
|
|
|
void interfaceBarDisable()
|
|
|
|
{
|
|
|
|
if (gInterfaceBarEnabled) {
|
|
|
|
displayMonitorDisable();
|
|
|
|
buttonDisable(gInventoryButton);
|
|
|
|
buttonDisable(gOptionsButton);
|
|
|
|
buttonDisable(gSkilldexButton);
|
|
|
|
buttonDisable(gMapButton);
|
|
|
|
buttonDisable(gPipboyButton);
|
|
|
|
buttonDisable(gCharacterButton);
|
|
|
|
if (gInterfaceItemStates[gInterfaceCurrentHand].isDisabled == 0) {
|
|
|
|
buttonDisable(gSingleAttackButton);
|
|
|
|
}
|
|
|
|
buttonDisable(gEndTurnButton);
|
|
|
|
buttonDisable(gEndCombatButton);
|
|
|
|
gInterfaceBarEnabled = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x45EB90
|
|
|
|
bool interfaceBarEnabled()
|
|
|
|
{
|
|
|
|
return gInterfaceBarEnabled;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x45EB98
|
|
|
|
void interfaceBarRefresh()
|
|
|
|
{
|
|
|
|
if (gInterfaceBarWindow != -1) {
|
|
|
|
interfaceUpdateItems(false, INTERFACE_ITEM_ACTION_DEFAULT, INTERFACE_ITEM_ACTION_DEFAULT);
|
|
|
|
interfaceRenderHitPoints(false);
|
|
|
|
interfaceRenderArmorClass(false);
|
|
|
|
indicatorBarRefresh();
|
|
|
|
windowRefresh(gInterfaceBarWindow);
|
|
|
|
}
|
|
|
|
indicatorBarRefresh();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Render hit points.
|
|
|
|
//
|
|
|
|
// 0x45EBD8
|
|
|
|
void interfaceRenderHitPoints(bool animate)
|
|
|
|
{
|
|
|
|
if (gInterfaceBarWindow == -1) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
int hp = critterGetHitPoints(gDude);
|
|
|
|
int maxHp = critterGetStat(gDude, STAT_MAXIMUM_HIT_POINTS);
|
|
|
|
|
|
|
|
int red = (int)((double)maxHp * 0.25);
|
|
|
|
int yellow = (int)((double)maxHp * 0.5);
|
|
|
|
|
|
|
|
int color;
|
|
|
|
if (hp < red) {
|
|
|
|
color = INTERFACE_NUMBERS_COLOR_RED;
|
|
|
|
} else if (hp < yellow) {
|
|
|
|
color = INTERFACE_NUMBERS_COLOR_YELLOW;
|
|
|
|
} else {
|
|
|
|
color = INTERFACE_NUMBERS_COLOR_WHITE;
|
|
|
|
}
|
|
|
|
|
|
|
|
int v1[4];
|
|
|
|
int v2[3];
|
|
|
|
int count = 1;
|
|
|
|
|
|
|
|
v1[0] = gInterfaceLastRenderedHitPoints;
|
|
|
|
v2[0] = gInterfaceLastRenderedHitPointsColor;
|
|
|
|
|
|
|
|
if (gInterfaceLastRenderedHitPointsColor != color) {
|
|
|
|
if (hp >= gInterfaceLastRenderedHitPoints) {
|
|
|
|
if (gInterfaceLastRenderedHitPoints < red && hp >= red) {
|
|
|
|
v1[count] = red;
|
|
|
|
v2[count] = INTERFACE_NUMBERS_COLOR_YELLOW;
|
|
|
|
count += 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (gInterfaceLastRenderedHitPoints < yellow && hp >= yellow) {
|
|
|
|
v1[count] = yellow;
|
|
|
|
v2[count] = INTERFACE_NUMBERS_COLOR_WHITE;
|
|
|
|
count += 1;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (gInterfaceLastRenderedHitPoints >= yellow && hp < yellow) {
|
|
|
|
v1[count] = yellow;
|
|
|
|
v2[count] = INTERFACE_NUMBERS_COLOR_YELLOW;
|
|
|
|
count += 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (gInterfaceLastRenderedHitPoints >= red && hp < red) {
|
|
|
|
v1[count] = red;
|
|
|
|
v2[count] = INTERFACE_NUMBERS_COLOR_RED;
|
|
|
|
count += 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
v1[count] = hp;
|
|
|
|
|
|
|
|
if (animate) {
|
|
|
|
int delay = 250 / (abs(gInterfaceLastRenderedHitPoints - hp) + 1);
|
|
|
|
for (int index = 0; index < count; index++) {
|
|
|
|
interfaceRenderCounter(473, 40, v1[index], v1[index + 1], v2[index], delay);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
interfaceRenderCounter(473, 40, gInterfaceLastRenderedHitPoints, hp, color, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
gInterfaceLastRenderedHitPoints = hp;
|
|
|
|
gInterfaceLastRenderedHitPointsColor = color;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Render armor class.
|
|
|
|
//
|
|
|
|
// 0x45EDA8
|
|
|
|
void interfaceRenderArmorClass(bool animate)
|
|
|
|
{
|
|
|
|
int armorClass = critterGetStat(gDude, STAT_ARMOR_CLASS);
|
|
|
|
|
|
|
|
int delay = 0;
|
|
|
|
if (animate) {
|
|
|
|
delay = 250 / (abs(gInterfaceLastRenderedArmorClass - armorClass) + 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
interfaceRenderCounter(473, 75, gInterfaceLastRenderedArmorClass, armorClass, 0, delay);
|
|
|
|
|
|
|
|
gInterfaceLastRenderedArmorClass = armorClass;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x45EE0C
|
|
|
|
void interfaceRenderActionPoints(int actionPointsLeft, int bonusActionPoints)
|
|
|
|
{
|
|
|
|
unsigned char* frmData;
|
|
|
|
|
|
|
|
if (gInterfaceBarWindow == -1) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
blitBufferToBuffer(gInterfaceActionPointsBarBackground, 90, 5, 90, gInterfaceWindowBuffer + 14 * 640 + 316, 640);
|
|
|
|
|
|
|
|
if (actionPointsLeft == -1) {
|
2022-09-24 11:04:32 -07:00
|
|
|
frmData = _redLightFrmImage.getData();
|
2022-05-19 01:51:26 -07:00
|
|
|
actionPointsLeft = 10;
|
|
|
|
bonusActionPoints = 0;
|
|
|
|
} else {
|
2022-09-24 11:04:32 -07:00
|
|
|
frmData = _greenLightFrmImage.getData();
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
if (actionPointsLeft < 0) {
|
|
|
|
actionPointsLeft = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (actionPointsLeft > 10) {
|
|
|
|
actionPointsLeft = 10;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bonusActionPoints >= 0) {
|
|
|
|
if (actionPointsLeft + bonusActionPoints > 10) {
|
|
|
|
bonusActionPoints = 10 - actionPointsLeft;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
bonusActionPoints = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int index;
|
|
|
|
for (index = 0; index < actionPointsLeft; index++) {
|
|
|
|
blitBufferToBuffer(frmData, 5, 5, 5, gInterfaceWindowBuffer + 14 * 640 + 316 + index * 9, 640);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (; index < (actionPointsLeft + bonusActionPoints); index++) {
|
2022-09-24 11:04:32 -07:00
|
|
|
blitBufferToBuffer(_yellowLightFrmImage.getData(), 5, 5, 5, gInterfaceWindowBuffer + 14 * 640 + 316 + index * 9, 640);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!gInterfaceBarInitialized) {
|
|
|
|
windowRefreshRect(gInterfaceBarWindow, &gInterfaceBarActionPointsBarRect);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x45EF6C
|
|
|
|
int interfaceGetCurrentHitMode(int* hitMode, bool* aiming)
|
|
|
|
{
|
|
|
|
if (gInterfaceBarWindow == -1) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
*aiming = false;
|
|
|
|
|
|
|
|
switch (gInterfaceItemStates[gInterfaceCurrentHand].action) {
|
|
|
|
case INTERFACE_ITEM_ACTION_PRIMARY_AIMING:
|
|
|
|
*aiming = true;
|
|
|
|
// FALLTHROUGH
|
|
|
|
case INTERFACE_ITEM_ACTION_PRIMARY:
|
|
|
|
*hitMode = gInterfaceItemStates[gInterfaceCurrentHand].primaryHitMode;
|
|
|
|
return 0;
|
|
|
|
case INTERFACE_ITEM_ACTION_SECONDARY_AIMING:
|
|
|
|
*aiming = true;
|
|
|
|
// FALLTHROUGH
|
|
|
|
case INTERFACE_ITEM_ACTION_SECONDARY:
|
|
|
|
*hitMode = gInterfaceItemStates[gInterfaceCurrentHand].secondaryHitMode;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x45EFEC
|
|
|
|
int interfaceUpdateItems(bool animated, int leftItemAction, int rightItemAction)
|
|
|
|
{
|
|
|
|
if (isoIsDisabled()) {
|
|
|
|
animated = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (gInterfaceBarWindow == -1) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
Object* oldCurrentItem = gInterfaceItemStates[gInterfaceCurrentHand].item;
|
|
|
|
|
|
|
|
InterfaceItemState* leftItemState = &(gInterfaceItemStates[HAND_LEFT]);
|
|
|
|
Object* item1 = critterGetItem1(gDude);
|
|
|
|
if (item1 == leftItemState->item && leftItemState->item != NULL) {
|
|
|
|
if (leftItemState->item != NULL) {
|
2022-08-17 22:41:15 -07:00
|
|
|
leftItemState->isDisabled = dudeIsWeaponDisabled(item1);
|
2022-05-19 01:51:26 -07:00
|
|
|
leftItemState->itemFid = itemGetInventoryFid(item1);
|
|
|
|
}
|
|
|
|
} else {
|
2022-08-11 04:12:29 -07:00
|
|
|
Object* oldItem = leftItemState->item;
|
|
|
|
int oldAction = leftItemState->action;
|
|
|
|
|
2022-05-19 01:51:26 -07:00
|
|
|
leftItemState->item = item1;
|
2022-08-11 04:12:29 -07:00
|
|
|
|
2022-05-19 01:51:26 -07:00
|
|
|
if (item1 != NULL) {
|
2022-08-17 22:41:15 -07:00
|
|
|
leftItemState->isDisabled = dudeIsWeaponDisabled(item1);
|
2022-05-19 01:51:26 -07:00
|
|
|
leftItemState->primaryHitMode = HIT_MODE_LEFT_WEAPON_PRIMARY;
|
|
|
|
leftItemState->secondaryHitMode = HIT_MODE_LEFT_WEAPON_SECONDARY;
|
|
|
|
leftItemState->isWeapon = itemGetType(item1) == ITEM_TYPE_WEAPON;
|
|
|
|
|
|
|
|
if (leftItemAction == INTERFACE_ITEM_ACTION_DEFAULT) {
|
|
|
|
if (leftItemState->isWeapon != 0) {
|
|
|
|
leftItemState->action = INTERFACE_ITEM_ACTION_PRIMARY;
|
|
|
|
} else {
|
|
|
|
leftItemState->action = INTERFACE_ITEM_ACTION_USE;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
leftItemState->action = leftItemAction;
|
|
|
|
}
|
|
|
|
|
|
|
|
leftItemState->itemFid = itemGetInventoryFid(item1);
|
|
|
|
} else {
|
|
|
|
leftItemState->isDisabled = 0;
|
|
|
|
leftItemState->isWeapon = 1;
|
|
|
|
leftItemState->action = INTERFACE_ITEM_ACTION_PRIMARY;
|
|
|
|
leftItemState->itemFid = -1;
|
|
|
|
|
2022-08-10 10:46:09 -07:00
|
|
|
// SFALL
|
|
|
|
leftItemState->primaryHitMode = unarmedGetPunchHitMode(false);
|
|
|
|
leftItemState->secondaryHitMode = unarmedGetPunchHitMode(true);
|
2022-08-11 04:12:29 -07:00
|
|
|
|
|
|
|
// SFALL: Keep selected attack mode.
|
|
|
|
// CE: Implementation is different.
|
|
|
|
if (oldItem == NULL) {
|
|
|
|
leftItemState->action = oldAction;
|
|
|
|
}
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
InterfaceItemState* rightItemState = &(gInterfaceItemStates[HAND_RIGHT]);
|
|
|
|
|
|
|
|
Object* item2 = critterGetItem2(gDude);
|
|
|
|
if (item2 == rightItemState->item && rightItemState->item != NULL) {
|
|
|
|
if (rightItemState->item != NULL) {
|
2022-08-17 22:41:15 -07:00
|
|
|
rightItemState->isDisabled = dudeIsWeaponDisabled(rightItemState->item);
|
2022-05-19 01:51:26 -07:00
|
|
|
rightItemState->itemFid = itemGetInventoryFid(rightItemState->item);
|
|
|
|
}
|
|
|
|
} else {
|
2022-08-11 04:12:29 -07:00
|
|
|
Object* oldItem = rightItemState->item;
|
|
|
|
int oldAction = rightItemState->action;
|
|
|
|
|
2022-05-19 01:51:26 -07:00
|
|
|
rightItemState->item = item2;
|
|
|
|
|
|
|
|
if (item2 != NULL) {
|
2022-08-17 22:41:15 -07:00
|
|
|
rightItemState->isDisabled = dudeIsWeaponDisabled(item2);
|
2022-05-19 01:51:26 -07:00
|
|
|
rightItemState->primaryHitMode = HIT_MODE_RIGHT_WEAPON_PRIMARY;
|
|
|
|
rightItemState->secondaryHitMode = HIT_MODE_RIGHT_WEAPON_SECONDARY;
|
|
|
|
rightItemState->isWeapon = itemGetType(item2) == ITEM_TYPE_WEAPON;
|
|
|
|
|
|
|
|
if (rightItemAction == INTERFACE_ITEM_ACTION_DEFAULT) {
|
|
|
|
if (rightItemState->isWeapon != 0) {
|
|
|
|
rightItemState->action = INTERFACE_ITEM_ACTION_PRIMARY;
|
|
|
|
} else {
|
|
|
|
rightItemState->action = INTERFACE_ITEM_ACTION_USE;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
rightItemState->action = rightItemAction;
|
|
|
|
}
|
|
|
|
rightItemState->itemFid = itemGetInventoryFid(item2);
|
|
|
|
} else {
|
|
|
|
rightItemState->isDisabled = 0;
|
|
|
|
rightItemState->isWeapon = 1;
|
|
|
|
rightItemState->action = INTERFACE_ITEM_ACTION_PRIMARY;
|
|
|
|
rightItemState->itemFid = -1;
|
|
|
|
|
2022-08-10 10:46:09 -07:00
|
|
|
// SFALL
|
|
|
|
rightItemState->primaryHitMode = unarmedGetKickHitMode(false);
|
|
|
|
rightItemState->secondaryHitMode = unarmedGetKickHitMode(true);
|
2022-08-11 04:12:29 -07:00
|
|
|
|
|
|
|
// SFALL: Keep selected attack mode.
|
|
|
|
// CE: Implementation is different.
|
|
|
|
if (oldItem == NULL) {
|
|
|
|
rightItemState->action = oldAction;
|
|
|
|
}
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (animated) {
|
|
|
|
Object* newCurrentItem = gInterfaceItemStates[gInterfaceCurrentHand].item;
|
|
|
|
if (newCurrentItem != oldCurrentItem) {
|
|
|
|
int animationCode = 0;
|
|
|
|
if (newCurrentItem != NULL) {
|
|
|
|
if (itemGetType(newCurrentItem) == ITEM_TYPE_WEAPON) {
|
|
|
|
animationCode = weaponGetAnimationCode(newCurrentItem);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
interfaceBarSwapHandsAnimatePutAwayTakeOutSequence((gDude->fid & 0xF000) >> 12, animationCode);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
interfaceBarRefreshMainAction();
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x45F404
|
|
|
|
int interfaceBarSwapHands(bool animated)
|
|
|
|
{
|
|
|
|
if (gInterfaceBarWindow == -1) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
gInterfaceCurrentHand = 1 - gInterfaceCurrentHand;
|
|
|
|
|
|
|
|
if (animated) {
|
|
|
|
Object* item = gInterfaceItemStates[gInterfaceCurrentHand].item;
|
|
|
|
int animationCode = 0;
|
|
|
|
if (item != NULL) {
|
|
|
|
if (itemGetType(item) == ITEM_TYPE_WEAPON) {
|
|
|
|
animationCode = weaponGetAnimationCode(item);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
interfaceBarSwapHandsAnimatePutAwayTakeOutSequence((gDude->fid & 0xF000) >> 12, animationCode);
|
|
|
|
} else {
|
|
|
|
interfaceBarRefreshMainAction();
|
|
|
|
}
|
|
|
|
|
|
|
|
int mode = gameMouseGetMode();
|
|
|
|
if (mode == GAME_MOUSE_MODE_CROSSHAIR || mode == GAME_MOUSE_MODE_USE_CROSSHAIR) {
|
|
|
|
gameMouseSetMode(GAME_MOUSE_MODE_MOVE);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x45F4B4
|
|
|
|
int interfaceGetItemActions(int* leftItemAction, int* rightItemAction)
|
|
|
|
{
|
|
|
|
*leftItemAction = gInterfaceItemStates[HAND_LEFT].action;
|
|
|
|
*rightItemAction = gInterfaceItemStates[HAND_RIGHT].action;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x45F4E0
|
|
|
|
int interfaceCycleItemAction()
|
|
|
|
{
|
|
|
|
if (gInterfaceBarWindow == -1) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
InterfaceItemState* itemState = &(gInterfaceItemStates[gInterfaceCurrentHand]);
|
|
|
|
|
|
|
|
int oldAction = itemState->action;
|
|
|
|
if (itemState->isWeapon != 0) {
|
|
|
|
bool done = false;
|
|
|
|
while (!done) {
|
|
|
|
itemState->action++;
|
|
|
|
switch (itemState->action) {
|
|
|
|
case INTERFACE_ITEM_ACTION_PRIMARY:
|
|
|
|
done = true;
|
|
|
|
break;
|
|
|
|
case INTERFACE_ITEM_ACTION_PRIMARY_AIMING:
|
2022-08-17 22:41:15 -07:00
|
|
|
if (critterCanAim(gDude, itemState->primaryHitMode)) {
|
2022-05-19 01:51:26 -07:00
|
|
|
done = true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case INTERFACE_ITEM_ACTION_SECONDARY:
|
|
|
|
if (itemState->secondaryHitMode != HIT_MODE_PUNCH
|
|
|
|
&& itemState->secondaryHitMode != HIT_MODE_KICK
|
|
|
|
&& weaponGetAttackTypeForHitMode(itemState->item, itemState->secondaryHitMode) != ATTACK_TYPE_NONE) {
|
|
|
|
done = true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case INTERFACE_ITEM_ACTION_SECONDARY_AIMING:
|
|
|
|
if (itemState->secondaryHitMode != HIT_MODE_PUNCH
|
|
|
|
&& itemState->secondaryHitMode != HIT_MODE_KICK
|
|
|
|
&& weaponGetAttackTypeForHitMode(itemState->item, itemState->secondaryHitMode) != ATTACK_TYPE_NONE
|
2022-08-17 22:41:15 -07:00
|
|
|
&& critterCanAim(gDude, itemState->secondaryHitMode)) {
|
2022-05-19 01:51:26 -07:00
|
|
|
done = true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case INTERFACE_ITEM_ACTION_RELOAD:
|
|
|
|
if (ammoGetCapacity(itemState->item) != ammoGetQuantity(itemState->item)) {
|
|
|
|
done = true;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case INTERFACE_ITEM_ACTION_COUNT:
|
|
|
|
itemState->action = INTERFACE_ITEM_ACTION_USE;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (oldAction != itemState->action) {
|
|
|
|
interfaceBarRefreshMainAction();
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x45F5EC
|
|
|
|
void _intface_use_item()
|
|
|
|
{
|
|
|
|
if (gInterfaceBarWindow == -1) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
InterfaceItemState* ptr = &(gInterfaceItemStates[gInterfaceCurrentHand]);
|
|
|
|
|
|
|
|
if (ptr->isWeapon != 0) {
|
|
|
|
if (ptr->action == INTERFACE_ITEM_ACTION_RELOAD) {
|
|
|
|
if (isInCombat()) {
|
|
|
|
int hitMode = gInterfaceCurrentHand == HAND_LEFT
|
|
|
|
? HIT_MODE_LEFT_WEAPON_RELOAD
|
|
|
|
: HIT_MODE_RIGHT_WEAPON_RELOAD;
|
|
|
|
|
2022-08-17 22:41:15 -07:00
|
|
|
int actionPointsRequired = itemGetActionPointCost(gDude, hitMode, false);
|
2022-05-19 01:51:26 -07:00
|
|
|
if (actionPointsRequired <= gDude->data.critter.combat.ap) {
|
|
|
|
if (_intface_item_reload() == 0) {
|
|
|
|
if (actionPointsRequired > gDude->data.critter.combat.ap) {
|
|
|
|
gDude->data.critter.combat.ap = 0;
|
|
|
|
} else {
|
|
|
|
gDude->data.critter.combat.ap -= actionPointsRequired;
|
|
|
|
}
|
|
|
|
interfaceRenderActionPoints(gDude->data.critter.combat.ap, _combat_free_move);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
_intface_item_reload();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
gameMouseSetCursor(MOUSE_CURSOR_CROSSHAIR);
|
|
|
|
gameMouseSetMode(GAME_MOUSE_MODE_CROSSHAIR);
|
|
|
|
if (!isInCombat()) {
|
|
|
|
_combat(NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (_proto_action_can_use_on(ptr->item->pid)) {
|
|
|
|
gameMouseSetCursor(MOUSE_CURSOR_USE_CROSSHAIR);
|
|
|
|
gameMouseSetMode(GAME_MOUSE_MODE_USE_CROSSHAIR);
|
|
|
|
} else if (_obj_action_can_use(ptr->item)) {
|
|
|
|
if (isInCombat()) {
|
2022-08-17 22:41:15 -07:00
|
|
|
int actionPointsRequired = itemGetActionPointCost(gDude, ptr->secondaryHitMode, false);
|
2022-05-19 01:51:26 -07:00
|
|
|
if (actionPointsRequired <= gDude->data.critter.combat.ap) {
|
|
|
|
_obj_use_item(gDude, ptr->item);
|
|
|
|
interfaceUpdateItems(false, INTERFACE_ITEM_ACTION_DEFAULT, INTERFACE_ITEM_ACTION_DEFAULT);
|
|
|
|
if (actionPointsRequired > gDude->data.critter.combat.ap) {
|
|
|
|
gDude->data.critter.combat.ap = 0;
|
|
|
|
} else {
|
|
|
|
gDude->data.critter.combat.ap -= actionPointsRequired;
|
|
|
|
}
|
|
|
|
|
|
|
|
interfaceRenderActionPoints(gDude->data.critter.combat.ap, _combat_free_move);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
_obj_use_item(gDude, ptr->item);
|
|
|
|
interfaceUpdateItems(false, INTERFACE_ITEM_ACTION_DEFAULT, INTERFACE_ITEM_ACTION_DEFAULT);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x45F7FC
|
|
|
|
int interfaceGetCurrentHand()
|
|
|
|
{
|
|
|
|
return gInterfaceCurrentHand;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x45F804
|
|
|
|
int interfaceGetActiveItem(Object** itemPtr)
|
|
|
|
{
|
|
|
|
if (gInterfaceBarWindow == -1) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
*itemPtr = gInterfaceItemStates[gInterfaceCurrentHand].item;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x45F838
|
|
|
|
int _intface_update_ammo_lights()
|
|
|
|
{
|
|
|
|
if (gInterfaceBarWindow == -1) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
InterfaceItemState* p = &(gInterfaceItemStates[gInterfaceCurrentHand]);
|
|
|
|
|
|
|
|
int ratio = 0;
|
|
|
|
|
|
|
|
if (p->isWeapon != 0) {
|
|
|
|
// calls sub_478674 twice, probably because if min/max kind macro
|
|
|
|
int maximum = ammoGetCapacity(p->item);
|
|
|
|
if (maximum > 0) {
|
|
|
|
int current = ammoGetQuantity(p->item);
|
|
|
|
ratio = (int)((double)current / (double)maximum * 70.0);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (itemGetType(p->item) == ITEM_TYPE_MISC) {
|
|
|
|
// calls sub_4793D0 twice, probably because if min/max kind macro
|
|
|
|
int maximum = miscItemGetMaxCharges(p->item);
|
|
|
|
if (maximum > 0) {
|
|
|
|
int current = miscItemGetCharges(p->item);
|
|
|
|
ratio = (int)((double)current / (double)maximum * 70.0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
interfaceUpdateAmmoBar(463, ratio);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x45F96C
|
|
|
|
void interfaceBarEndButtonsShow(bool animated)
|
|
|
|
{
|
|
|
|
if (gInterfaceBarWindow == -1) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (gInterfaceBarEndButtonsIsVisible) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-07-29 06:04:05 -07:00
|
|
|
int fid = buildFid(OBJ_TYPE_INTERFACE, 104, 0, 0, 0);
|
2022-05-19 01:51:26 -07:00
|
|
|
CacheEntry* handle;
|
|
|
|
Art* art = artLock(fid, &handle);
|
|
|
|
if (art == NULL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
int frameCount = artGetFrameCount(art);
|
|
|
|
soundPlayFile("iciboxx1");
|
|
|
|
|
|
|
|
if (animated) {
|
|
|
|
unsigned int delay = 1000 / artGetFramesPerSecond(art);
|
|
|
|
int time = 0;
|
|
|
|
int frame = 0;
|
|
|
|
while (frame < frameCount) {
|
|
|
|
if (getTicksSince(time) >= delay) {
|
|
|
|
unsigned char* src = artGetFrameData(art, frame, 0);
|
|
|
|
if (src != NULL) {
|
|
|
|
blitBufferToBuffer(src, 57, 58, 57, gInterfaceWindowBuffer + 640 * 38 + 580, 640);
|
|
|
|
windowRefreshRect(gInterfaceBarWindow, &gInterfaceBarEndButtonsRect);
|
|
|
|
}
|
|
|
|
|
|
|
|
time = _get_time();
|
|
|
|
frame++;
|
|
|
|
}
|
|
|
|
gameMouseRefresh();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
unsigned char* src = artGetFrameData(art, frameCount - 1, 0);
|
|
|
|
blitBufferToBuffer(src, 57, 58, 57, gInterfaceWindowBuffer + 640 * 38 + 580, 640);
|
|
|
|
windowRefreshRect(gInterfaceBarWindow, &gInterfaceBarEndButtonsRect);
|
|
|
|
}
|
|
|
|
|
|
|
|
artUnlock(handle);
|
|
|
|
|
|
|
|
gInterfaceBarEndButtonsIsVisible = true;
|
|
|
|
endTurnButtonInit();
|
|
|
|
endCombatButtonInit();
|
|
|
|
interfaceBarEndButtonsRenderRedLights();
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x45FAC0
|
|
|
|
void interfaceBarEndButtonsHide(bool animated)
|
|
|
|
{
|
|
|
|
if (gInterfaceBarWindow == -1) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!gInterfaceBarEndButtonsIsVisible) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2022-07-29 06:04:05 -07:00
|
|
|
int fid = buildFid(OBJ_TYPE_INTERFACE, 104, 0, 0, 0);
|
2022-05-19 01:51:26 -07:00
|
|
|
CacheEntry* handle;
|
|
|
|
Art* art = artLock(fid, &handle);
|
|
|
|
if (art == NULL) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
endTurnButtonFree();
|
|
|
|
endCombatButtonFree();
|
|
|
|
soundPlayFile("icibcxx1");
|
|
|
|
|
|
|
|
if (animated) {
|
|
|
|
unsigned int delay = 1000 / artGetFramesPerSecond(art);
|
|
|
|
unsigned int time = 0;
|
|
|
|
int frame = artGetFrameCount(art);
|
|
|
|
|
|
|
|
while (frame != 0) {
|
|
|
|
if (getTicksSince(time) >= delay) {
|
|
|
|
unsigned char* src = artGetFrameData(art, frame - 1, 0);
|
|
|
|
unsigned char* dest = gInterfaceWindowBuffer + 640 * 38 + 580;
|
|
|
|
if (src != NULL) {
|
|
|
|
blitBufferToBuffer(src, 57, 58, 57, dest, 640);
|
|
|
|
windowRefreshRect(gInterfaceBarWindow, &gInterfaceBarEndButtonsRect);
|
|
|
|
}
|
|
|
|
|
|
|
|
time = _get_time();
|
|
|
|
frame--;
|
|
|
|
}
|
|
|
|
gameMouseRefresh();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
unsigned char* dest = gInterfaceWindowBuffer + 640 * 38 + 580;
|
|
|
|
unsigned char* src = artGetFrameData(art, 0, 0);
|
|
|
|
blitBufferToBuffer(src, 57, 58, 57, dest, 640);
|
|
|
|
windowRefreshRect(gInterfaceBarWindow, &gInterfaceBarEndButtonsRect);
|
|
|
|
}
|
|
|
|
|
|
|
|
artUnlock(handle);
|
|
|
|
gInterfaceBarEndButtonsIsVisible = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x45FC04
|
|
|
|
void interfaceBarEndButtonsRenderGreenLights()
|
|
|
|
{
|
|
|
|
if (gInterfaceBarEndButtonsIsVisible) {
|
|
|
|
buttonEnable(gEndTurnButton);
|
|
|
|
buttonEnable(gEndCombatButton);
|
|
|
|
|
2022-09-24 11:04:32 -07:00
|
|
|
FrmImage lightsFrmImage;
|
2022-05-19 01:51:26 -07:00
|
|
|
// endltgrn.frm - green lights around end turn/combat window
|
2022-07-29 06:04:05 -07:00
|
|
|
int lightsFid = buildFid(OBJ_TYPE_INTERFACE, 109, 0, 0, 0);
|
2022-09-24 11:04:32 -07:00
|
|
|
if (!lightsFrmImage.lock(lightsFid)) {
|
2022-05-19 01:51:26 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
soundPlayFile("icombat2");
|
2022-09-24 11:04:32 -07:00
|
|
|
blitBufferToBufferTrans(lightsFrmImage.getData(), 57, 58, 57, gInterfaceWindowBuffer + 38 * 640 + 580, 640);
|
2022-05-19 01:51:26 -07:00
|
|
|
windowRefreshRect(gInterfaceBarWindow, &gInterfaceBarEndButtonsRect);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x45FC98
|
|
|
|
void interfaceBarEndButtonsRenderRedLights()
|
|
|
|
{
|
|
|
|
if (gInterfaceBarEndButtonsIsVisible) {
|
|
|
|
buttonDisable(gEndTurnButton);
|
|
|
|
buttonDisable(gEndCombatButton);
|
|
|
|
|
2022-09-24 11:04:32 -07:00
|
|
|
FrmImage lightsFrmImage;
|
2022-05-19 01:51:26 -07:00
|
|
|
// endltred.frm - red lights around end turn/combat window
|
2022-07-29 06:04:05 -07:00
|
|
|
int lightsFid = buildFid(OBJ_TYPE_INTERFACE, 110, 0, 0, 0);
|
2022-09-24 11:04:32 -07:00
|
|
|
if (!lightsFrmImage.lock(lightsFid)) {
|
2022-05-19 01:51:26 -07:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
soundPlayFile("icombat1");
|
2022-09-24 11:04:32 -07:00
|
|
|
blitBufferToBufferTrans(lightsFrmImage.getData(), 57, 58, 57, gInterfaceWindowBuffer + 38 * 640 + 580, 640);
|
2022-05-19 01:51:26 -07:00
|
|
|
windowRefreshRect(gInterfaceBarWindow, &gInterfaceBarEndButtonsRect);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-01 08:41:37 -07:00
|
|
|
// NOTE: Inlined.
|
|
|
|
//
|
|
|
|
// 0x45FD2C
|
|
|
|
static int intface_init_items()
|
|
|
|
{
|
|
|
|
// FIXME: For unknown reason these values initialized with -1. It's never
|
|
|
|
// checked for -1, so I have no explanation for this.
|
|
|
|
gInterfaceItemStates[HAND_LEFT].item = (Object*)-1;
|
|
|
|
gInterfaceItemStates[HAND_RIGHT].item = (Object*)-1;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2022-05-19 01:51:26 -07:00
|
|
|
// 0x45FD88
|
2022-06-18 07:39:55 -07:00
|
|
|
static int interfaceBarRefreshMainAction()
|
2022-05-19 01:51:26 -07:00
|
|
|
{
|
|
|
|
if (gInterfaceBarWindow == -1) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
buttonEnable(gSingleAttackButton);
|
|
|
|
|
|
|
|
InterfaceItemState* itemState = &(gInterfaceItemStates[gInterfaceCurrentHand]);
|
|
|
|
int actionPoints = -1;
|
|
|
|
|
|
|
|
if (itemState->isDisabled == 0) {
|
2022-09-24 11:04:32 -07:00
|
|
|
memcpy(_itemButtonUp, _itemButtonNormalFrmImage.getData(), sizeof(_itemButtonUp));
|
|
|
|
memcpy(_itemButtonDown, _itemButtonPressedFrmImage.getData(), sizeof(_itemButtonDown));
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
if (itemState->isWeapon == 0) {
|
|
|
|
int fid;
|
|
|
|
if (_proto_action_can_use_on(itemState->item->pid)) {
|
|
|
|
// USE ON
|
2022-07-29 06:04:05 -07:00
|
|
|
fid = buildFid(OBJ_TYPE_INTERFACE, 294, 0, 0, 0);
|
2022-05-19 01:51:26 -07:00
|
|
|
} else if (_obj_action_can_use(itemState->item)) {
|
|
|
|
// USE
|
2022-07-29 06:04:05 -07:00
|
|
|
fid = buildFid(OBJ_TYPE_INTERFACE, 292, 0, 0, 0);
|
2022-05-19 01:51:26 -07:00
|
|
|
} else {
|
|
|
|
fid = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fid != -1) {
|
2022-09-24 11:04:32 -07:00
|
|
|
FrmImage useTextFrmImage;
|
|
|
|
if (useTextFrmImage.lock(fid)) {
|
|
|
|
int width = useTextFrmImage.getWidth();
|
|
|
|
int height = useTextFrmImage.getHeight();
|
|
|
|
unsigned char* data = useTextFrmImage.getData();
|
2022-05-19 01:51:26 -07:00
|
|
|
blitBufferToBufferTrans(data, width, height, width, _itemButtonUp + 188 * 7 + 181 - width, 188);
|
|
|
|
_dark_trans_buf_to_buf(data, width, height, width, _itemButtonDown, 181 - width + 1, 5, 188, 59641);
|
|
|
|
}
|
|
|
|
|
2022-08-17 22:41:15 -07:00
|
|
|
actionPoints = itemGetActionPointCost(gDude, itemState->primaryHitMode, false);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
int primaryFid = -1;
|
|
|
|
int bullseyeFid = -1;
|
|
|
|
int hitMode = -1;
|
|
|
|
|
|
|
|
// NOTE: This value is decremented at 0x45FEAC, probably to build
|
|
|
|
// jump table.
|
|
|
|
switch (itemState->action) {
|
|
|
|
case INTERFACE_ITEM_ACTION_PRIMARY_AIMING:
|
2022-07-29 06:04:05 -07:00
|
|
|
bullseyeFid = buildFid(OBJ_TYPE_INTERFACE, 288, 0, 0, 0);
|
2022-05-19 01:51:26 -07:00
|
|
|
// FALLTHROUGH
|
|
|
|
case INTERFACE_ITEM_ACTION_PRIMARY:
|
|
|
|
hitMode = itemState->primaryHitMode;
|
|
|
|
break;
|
|
|
|
case INTERFACE_ITEM_ACTION_SECONDARY_AIMING:
|
2022-07-29 06:04:05 -07:00
|
|
|
bullseyeFid = buildFid(OBJ_TYPE_INTERFACE, 288, 0, 0, 0);
|
2022-05-19 01:51:26 -07:00
|
|
|
// FALLTHROUGH
|
|
|
|
case INTERFACE_ITEM_ACTION_SECONDARY:
|
|
|
|
hitMode = itemState->secondaryHitMode;
|
|
|
|
break;
|
|
|
|
case INTERFACE_ITEM_ACTION_RELOAD:
|
2022-08-17 22:41:15 -07:00
|
|
|
actionPoints = itemGetActionPointCost(gDude, gInterfaceCurrentHand == HAND_LEFT ? HIT_MODE_LEFT_WEAPON_RELOAD : HIT_MODE_RIGHT_WEAPON_RELOAD, false);
|
2022-07-29 06:04:05 -07:00
|
|
|
primaryFid = buildFid(OBJ_TYPE_INTERFACE, 291, 0, 0, 0);
|
2022-05-19 01:51:26 -07:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bullseyeFid != -1) {
|
2022-09-24 11:04:32 -07:00
|
|
|
FrmImage bullseyeFrmImage;
|
|
|
|
if (bullseyeFrmImage.lock(bullseyeFid)) {
|
|
|
|
int width = bullseyeFrmImage.getWidth();
|
|
|
|
int height = bullseyeFrmImage.getHeight();
|
|
|
|
unsigned char* data = bullseyeFrmImage.getData();
|
2022-05-19 01:51:26 -07:00
|
|
|
blitBufferToBufferTrans(data, width, height, width, _itemButtonUp + 188 * (60 - height) + (181 - width), 188);
|
|
|
|
|
|
|
|
int v9 = 60 - height - 2;
|
|
|
|
if (v9 < 0) {
|
|
|
|
v9 = 0;
|
|
|
|
height -= 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
_dark_trans_buf_to_buf(data, width, height, width, _itemButtonDown, 181 - width + 1, v9, 188, 59641);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (hitMode != -1) {
|
2022-08-17 22:41:15 -07:00
|
|
|
actionPoints = weaponGetActionPointCost(gDude, hitMode, bullseyeFid != -1);
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
int id;
|
|
|
|
int anim = critterGetAnimationForHitMode(gDude, hitMode);
|
|
|
|
switch (anim) {
|
|
|
|
case ANIM_THROW_PUNCH:
|
|
|
|
switch (hitMode) {
|
|
|
|
case HIT_MODE_STRONG_PUNCH:
|
|
|
|
id = 432; // strong punch
|
|
|
|
break;
|
|
|
|
case HIT_MODE_HAMMER_PUNCH:
|
|
|
|
id = 425; // hammer punch
|
|
|
|
break;
|
|
|
|
case HIT_MODE_HAYMAKER:
|
|
|
|
id = 428; // lightning punch
|
|
|
|
break;
|
|
|
|
case HIT_MODE_JAB:
|
|
|
|
id = 421; // chop punch
|
|
|
|
break;
|
|
|
|
case HIT_MODE_PALM_STRIKE:
|
|
|
|
id = 423; // dragon punch
|
|
|
|
break;
|
|
|
|
case HIT_MODE_PIERCING_STRIKE:
|
|
|
|
id = 424; // force punch
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
id = 42; // punch
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case ANIM_KICK_LEG:
|
|
|
|
switch (hitMode) {
|
|
|
|
case HIT_MODE_STRONG_KICK:
|
|
|
|
id = 430; // skick.frm - strong kick text
|
|
|
|
break;
|
|
|
|
case HIT_MODE_SNAP_KICK:
|
|
|
|
id = 431; // snapkick.frm - snap kick text
|
|
|
|
break;
|
|
|
|
case HIT_MODE_POWER_KICK:
|
|
|
|
id = 429; // cm_pwkck.frm - roundhouse kick text
|
|
|
|
break;
|
|
|
|
case HIT_MODE_HIP_KICK:
|
|
|
|
id = 426; // hipk.frm - kip kick text
|
|
|
|
break;
|
|
|
|
case HIT_MODE_HOOK_KICK:
|
|
|
|
id = 427; // cm_hookk.frm - jump kick text
|
|
|
|
break;
|
|
|
|
case HIT_MODE_PIERCING_KICK: // cm_prckk.frm - death blossom kick text
|
|
|
|
id = 422;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
id = 41; // kick.frm - kick text
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case ANIM_THROW_ANIM:
|
|
|
|
id = 117; // throw
|
|
|
|
break;
|
|
|
|
case ANIM_THRUST_ANIM:
|
|
|
|
id = 45; // thrust
|
|
|
|
break;
|
|
|
|
case ANIM_SWING_ANIM:
|
|
|
|
id = 44; // swing
|
|
|
|
break;
|
|
|
|
case ANIM_FIRE_SINGLE:
|
|
|
|
id = 43; // single
|
|
|
|
break;
|
|
|
|
case ANIM_FIRE_BURST:
|
|
|
|
case ANIM_FIRE_CONTINUOUS:
|
|
|
|
id = 40; // burst
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2022-07-29 06:04:05 -07:00
|
|
|
primaryFid = buildFid(OBJ_TYPE_INTERFACE, id, 0, 0, 0);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (primaryFid != -1) {
|
2022-09-24 11:04:32 -07:00
|
|
|
FrmImage primaryFrmImage;
|
|
|
|
if (primaryFrmImage.lock(primaryFid)) {
|
|
|
|
int width = primaryFrmImage.getWidth();
|
|
|
|
int height = primaryFrmImage.getHeight();
|
|
|
|
unsigned char* data = primaryFrmImage.getData();
|
2022-05-19 01:51:26 -07:00
|
|
|
blitBufferToBufferTrans(data, width, height, width, _itemButtonUp + 188 * 7 + 181 - width, 188);
|
|
|
|
_dark_trans_buf_to_buf(data, width, height, width, _itemButtonDown, 181 - width + 1, 5, 188, 59641);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (actionPoints >= 0 && actionPoints < 10) {
|
|
|
|
// movement point text
|
2022-09-24 11:04:32 -07:00
|
|
|
int apFid = buildFid(OBJ_TYPE_INTERFACE, 289, 0, 0, 0);
|
2022-05-19 01:51:26 -07:00
|
|
|
|
2022-09-24 11:04:32 -07:00
|
|
|
FrmImage apFrmImage;
|
|
|
|
if (apFrmImage.lock(apFid)) {
|
|
|
|
int width = apFrmImage.getWidth();
|
|
|
|
int height = apFrmImage.getHeight();
|
|
|
|
unsigned char* data = apFrmImage.getData();
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
blitBufferToBufferTrans(data, width, height, width, _itemButtonUp + 188 * (60 - height) + 7, 188);
|
|
|
|
|
|
|
|
int v29 = 60 - height - 2;
|
|
|
|
if (v29 < 0) {
|
|
|
|
v29 = 0;
|
|
|
|
height -= 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
_dark_trans_buf_to_buf(data, width, height, width, _itemButtonDown, 7 + 1, v29, 188, 59641);
|
|
|
|
|
|
|
|
int offset = width + 7;
|
|
|
|
|
2022-09-24 11:04:32 -07:00
|
|
|
FrmImage apNumbersFrmImage;
|
2022-05-19 01:51:26 -07:00
|
|
|
// movement point numbers - ten numbers 0 to 9, each 10 pixels wide.
|
2022-09-24 11:04:32 -07:00
|
|
|
int apNumbersFid = buildFid(OBJ_TYPE_INTERFACE, 290, 0, 0, 0);
|
|
|
|
if (apNumbersFrmImage.lock(apNumbersFid)) {
|
|
|
|
int width = apNumbersFrmImage.getWidth();
|
|
|
|
int height = apNumbersFrmImage.getHeight();
|
|
|
|
unsigned char* data = apNumbersFrmImage.getData();
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
blitBufferToBufferTrans(data + actionPoints * 10, 10, height, width, _itemButtonUp + 188 * (60 - height) + 7 + offset, 188);
|
|
|
|
|
|
|
|
int v40 = 60 - height - 2;
|
|
|
|
if (v40 < 0) {
|
|
|
|
v40 = 0;
|
|
|
|
height -= 2;
|
|
|
|
}
|
|
|
|
_dark_trans_buf_to_buf(data + actionPoints * 10, 10, height, width, _itemButtonDown, offset + 7 + 1, v40, 188, 59641);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2022-09-24 11:04:32 -07:00
|
|
|
memcpy(_itemButtonUp, _itemButtonDisabledFrmImage.getData(), sizeof(_itemButtonUp));
|
|
|
|
memcpy(_itemButtonDown, _itemButtonDisabledFrmImage.getData(), sizeof(_itemButtonDown));
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (itemState->itemFid != -1) {
|
2022-09-24 11:04:32 -07:00
|
|
|
FrmImage itemFrmImage;
|
|
|
|
if (itemFrmImage.lock(itemState->itemFid)) {
|
|
|
|
int width = itemFrmImage.getWidth();
|
|
|
|
int height = itemFrmImage.getHeight();
|
|
|
|
unsigned char* data = itemFrmImage.getData();
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
int v46 = (188 - width) / 2;
|
|
|
|
int v47 = (67 - height) / 2 - 2;
|
|
|
|
|
|
|
|
blitBufferToBufferTrans(data, width, height, width, _itemButtonUp + 188 * ((67 - height) / 2) + v46, 188);
|
|
|
|
|
|
|
|
if (v47 < 0) {
|
|
|
|
v47 = 0;
|
|
|
|
height -= 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
_dark_trans_buf_to_buf(data, width, height, width, _itemButtonDown, v46 + 1, v47, 188, 63571);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!gInterfaceBarInitialized) {
|
|
|
|
_intface_update_ammo_lights();
|
|
|
|
|
|
|
|
windowRefreshRect(gInterfaceBarWindow, &gInterfaceBarMainActionRect);
|
|
|
|
|
|
|
|
if (itemState->isDisabled != 0) {
|
|
|
|
buttonDisable(gSingleAttackButton);
|
|
|
|
} else {
|
|
|
|
buttonEnable(gSingleAttackButton);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x460658
|
2022-06-18 07:39:55 -07:00
|
|
|
static int _intface_redraw_items_callback(Object* a1, Object* a2)
|
2022-05-19 01:51:26 -07:00
|
|
|
{
|
|
|
|
interfaceBarRefreshMainAction();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x460660
|
2022-06-18 07:39:55 -07:00
|
|
|
static int _intface_change_fid_callback(Object* a1, Object* a2)
|
2022-05-19 01:51:26 -07:00
|
|
|
{
|
|
|
|
gInterfaceBarSwapHandsInProgress = false;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x46066C
|
2022-06-18 07:39:55 -07:00
|
|
|
static void interfaceBarSwapHandsAnimatePutAwayTakeOutSequence(int previousWeaponAnimationCode, int weaponAnimationCode)
|
2022-05-19 01:51:26 -07:00
|
|
|
{
|
|
|
|
gInterfaceBarSwapHandsInProgress = true;
|
|
|
|
|
|
|
|
reg_anim_clear(gDude);
|
2022-07-29 06:04:05 -07:00
|
|
|
reg_anim_begin(ANIMATION_REQUEST_RESERVED);
|
|
|
|
animationRegisterSetLightDistance(gDude, 4, 0);
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
if (previousWeaponAnimationCode != 0) {
|
|
|
|
const char* sfx = sfxBuildCharName(gDude, ANIM_PUT_AWAY, CHARACTER_SOUND_EFFECT_UNUSED);
|
2022-07-29 06:04:05 -07:00
|
|
|
animationRegisterPlaySoundEffect(gDude, sfx, 0);
|
|
|
|
animationRegisterAnimate(gDude, ANIM_PUT_AWAY, 0);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
2022-07-29 06:04:05 -07:00
|
|
|
// TODO: Get rid of cast.
|
|
|
|
animationRegisterCallbackForced(NULL, NULL, (AnimationCallback*)_intface_redraw_items_callback, -1);
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
Object* item = gInterfaceItemStates[gInterfaceCurrentHand].item;
|
|
|
|
if (item != NULL && item->lightDistance > 4) {
|
2022-07-29 06:04:05 -07:00
|
|
|
animationRegisterSetLightDistance(gDude, item->lightDistance, 0);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
if (weaponAnimationCode != 0) {
|
2022-07-29 06:04:05 -07:00
|
|
|
animationRegisterTakeOutWeapon(gDude, weaponAnimationCode, -1);
|
2022-05-19 01:51:26 -07:00
|
|
|
} else {
|
2022-07-29 06:04:05 -07:00
|
|
|
int fid = buildFid(OBJ_TYPE_CRITTER, gDude->fid & 0xFFF, ANIM_STAND, 0, gDude->rotation + 1);
|
|
|
|
animationRegisterSetFid(gDude, fid, -1);
|
2022-05-19 01:51:26 -07:00
|
|
|
}
|
|
|
|
|
2022-07-29 06:04:05 -07:00
|
|
|
// TODO: Get rid of cast.
|
|
|
|
animationRegisterCallbackForced(NULL, NULL, (AnimationCallback*)_intface_change_fid_callback, -1);
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
if (reg_anim_end() == -1) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool interfaceBarWasEnabled = gInterfaceBarEnabled;
|
|
|
|
|
|
|
|
interfaceBarDisable();
|
|
|
|
_gmouse_disable(0);
|
|
|
|
|
|
|
|
gameMouseSetCursor(MOUSE_CURSOR_WAIT_WATCH);
|
|
|
|
|
|
|
|
while (gInterfaceBarSwapHandsInProgress) {
|
|
|
|
if (_game_user_wants_to_quit) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
_get_input();
|
|
|
|
}
|
|
|
|
|
|
|
|
gameMouseSetCursor(MOUSE_CURSOR_NONE);
|
|
|
|
|
|
|
|
_gmouse_enable();
|
|
|
|
|
|
|
|
if (interfaceBarWasEnabled) {
|
|
|
|
interfaceBarEnable();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x4607E0
|
2022-06-18 07:39:55 -07:00
|
|
|
static int endTurnButtonInit()
|
2022-05-19 01:51:26 -07:00
|
|
|
{
|
|
|
|
int fid;
|
|
|
|
|
|
|
|
if (gInterfaceBarWindow == -1) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!gInterfaceBarEndButtonsIsVisible) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2022-07-29 06:04:05 -07:00
|
|
|
fid = buildFid(OBJ_TYPE_INTERFACE, 105, 0, 0, 0);
|
2022-09-24 11:04:32 -07:00
|
|
|
if (!_endTurnButtonNormalFrmImage.lock(fid)) {
|
2022-05-19 01:51:26 -07:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2022-07-29 06:04:05 -07:00
|
|
|
fid = buildFid(OBJ_TYPE_INTERFACE, 106, 0, 0, 0);
|
2022-09-24 11:04:32 -07:00
|
|
|
if (!_endTurnButtonPressedFrmImage.lock(fid)) {
|
2022-05-19 01:51:26 -07:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2022-09-24 11:04:32 -07:00
|
|
|
gEndTurnButton = buttonCreate(gInterfaceBarWindow, 590, 43, 38, 22, -1, -1, -1, 32, _endTurnButtonNormalFrmImage.getData(), _endTurnButtonPressedFrmImage.getData(), NULL, 0);
|
2022-05-19 01:51:26 -07:00
|
|
|
if (gEndTurnButton == -1) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2022-09-24 11:04:32 -07:00
|
|
|
_win_register_button_disable(gEndTurnButton, _endTurnButtonNormalFrmImage.getData(), _endTurnButtonNormalFrmImage.getData(), _endTurnButtonNormalFrmImage.getData());
|
2022-05-19 01:51:26 -07:00
|
|
|
buttonSetCallbacks(gEndTurnButton, _gsound_med_butt_press, _gsound_med_butt_release);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x4608C4
|
2022-06-18 07:39:55 -07:00
|
|
|
static int endTurnButtonFree()
|
2022-05-19 01:51:26 -07:00
|
|
|
{
|
|
|
|
if (gInterfaceBarWindow == -1) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (gEndTurnButton != -1) {
|
|
|
|
buttonDestroy(gEndTurnButton);
|
|
|
|
gEndTurnButton = -1;
|
|
|
|
}
|
|
|
|
|
2022-09-24 11:04:32 -07:00
|
|
|
_endTurnButtonNormalFrmImage.unlock();
|
|
|
|
_endTurnButtonPressedFrmImage.unlock();
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x460940
|
2022-06-18 07:39:55 -07:00
|
|
|
static int endCombatButtonInit()
|
2022-05-19 01:51:26 -07:00
|
|
|
{
|
|
|
|
int fid;
|
|
|
|
|
|
|
|
if (gInterfaceBarWindow == -1) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!gInterfaceBarEndButtonsIsVisible) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2022-07-29 06:04:05 -07:00
|
|
|
fid = buildFid(OBJ_TYPE_INTERFACE, 107, 0, 0, 0);
|
2022-09-24 11:04:32 -07:00
|
|
|
if (!_endCombatButtonNormalFrmImage.lock(fid)) {
|
2022-05-19 01:51:26 -07:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2022-07-29 06:04:05 -07:00
|
|
|
fid = buildFid(OBJ_TYPE_INTERFACE, 108, 0, 0, 0);
|
2022-09-24 11:04:32 -07:00
|
|
|
if (!_endCombatButtonPressedFrmImage.lock(fid)) {
|
2022-05-19 01:51:26 -07:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2022-09-24 11:04:32 -07:00
|
|
|
gEndCombatButton = buttonCreate(gInterfaceBarWindow, 590, 65, 38, 22, -1, -1, -1, 13, _endCombatButtonNormalFrmImage.getData(), _endCombatButtonPressedFrmImage.getData(), NULL, 0);
|
2022-05-19 01:51:26 -07:00
|
|
|
if (gEndCombatButton == -1) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2022-09-24 11:04:32 -07:00
|
|
|
_win_register_button_disable(gEndCombatButton, _endCombatButtonNormalFrmImage.getData(), _endCombatButtonNormalFrmImage.getData(), _endCombatButtonNormalFrmImage.getData());
|
2022-05-19 01:51:26 -07:00
|
|
|
buttonSetCallbacks(gEndCombatButton, _gsound_med_butt_press, _gsound_med_butt_release);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x460A24
|
2022-06-18 07:39:55 -07:00
|
|
|
static int endCombatButtonFree()
|
2022-05-19 01:51:26 -07:00
|
|
|
{
|
|
|
|
if (gInterfaceBarWindow == -1) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (gEndCombatButton != -1) {
|
|
|
|
buttonDestroy(gEndCombatButton);
|
|
|
|
gEndCombatButton = -1;
|
|
|
|
}
|
|
|
|
|
2022-09-24 11:04:32 -07:00
|
|
|
_endCombatButtonNormalFrmImage.unlock();
|
|
|
|
_endCombatButtonPressedFrmImage.unlock();
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x460AA0
|
2022-06-18 07:39:55 -07:00
|
|
|
static void interfaceUpdateAmmoBar(int x, int ratio)
|
2022-05-19 01:51:26 -07:00
|
|
|
{
|
|
|
|
if ((ratio & 1) != 0) {
|
|
|
|
ratio -= 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned char* dest = gInterfaceWindowBuffer + 640 * 26 + x;
|
|
|
|
|
|
|
|
for (int index = 70; index > ratio; index--) {
|
|
|
|
*dest = 14;
|
|
|
|
dest += 640;
|
|
|
|
}
|
|
|
|
|
|
|
|
while (ratio > 0) {
|
|
|
|
*dest = 196;
|
|
|
|
dest += 640;
|
|
|
|
|
|
|
|
*dest = 14;
|
|
|
|
dest += 640;
|
|
|
|
|
|
|
|
ratio -= 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!gInterfaceBarInitialized) {
|
|
|
|
Rect rect;
|
|
|
|
rect.left = x;
|
|
|
|
rect.top = 26;
|
|
|
|
rect.right = x + 1;
|
|
|
|
rect.bottom = 26 + 70;
|
|
|
|
windowRefreshRect(gInterfaceBarWindow, &rect);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x460B20
|
2022-06-18 07:39:55 -07:00
|
|
|
static int _intface_item_reload()
|
2022-05-19 01:51:26 -07:00
|
|
|
{
|
|
|
|
if (gInterfaceBarWindow == -1) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool v0 = false;
|
2022-08-17 22:41:15 -07:00
|
|
|
while (weaponAttemptReload(gDude, gInterfaceItemStates[gInterfaceCurrentHand].item) != -1) {
|
2022-05-19 01:51:26 -07:00
|
|
|
v0 = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
interfaceCycleItemAction();
|
|
|
|
interfaceUpdateItems(false, INTERFACE_ITEM_ACTION_DEFAULT, INTERFACE_ITEM_ACTION_DEFAULT);
|
|
|
|
|
|
|
|
if (!v0) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char* sfx = sfxBuildWeaponName(WEAPON_SOUND_EFFECT_READY, gInterfaceItemStates[gInterfaceCurrentHand].item, HIT_MODE_RIGHT_WEAPON_PRIMARY, NULL);
|
|
|
|
soundPlayFile(sfx);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Renders hit points.
|
|
|
|
//
|
|
|
|
// [delay] is an animation delay.
|
|
|
|
// [previousValue] is only meaningful for animation.
|
|
|
|
// [offset] = 0 - grey, 120 - yellow, 240 - red.
|
|
|
|
//
|
|
|
|
// 0x460BA0
|
2022-06-18 07:39:55 -07:00
|
|
|
static void interfaceRenderCounter(int x, int y, int previousValue, int value, int offset, int delay)
|
2022-05-19 01:51:26 -07:00
|
|
|
{
|
|
|
|
if (value > 999) {
|
|
|
|
value = 999;
|
|
|
|
} else if (value < -999) {
|
|
|
|
value = -999;
|
|
|
|
}
|
|
|
|
|
2022-09-24 11:04:32 -07:00
|
|
|
unsigned char* numbers = _numbersFrmImage.getData() + offset;
|
2022-05-19 01:51:26 -07:00
|
|
|
unsigned char* dest = gInterfaceWindowBuffer + 640 * y;
|
|
|
|
|
|
|
|
unsigned char* downSrc = numbers + 90;
|
|
|
|
unsigned char* upSrc = numbers + 99;
|
|
|
|
unsigned char* minusSrc = numbers + 108;
|
|
|
|
unsigned char* plusSrc = numbers + 114;
|
|
|
|
|
|
|
|
unsigned char* signDest = dest + x;
|
|
|
|
unsigned char* hundredsDest = dest + x + 6;
|
|
|
|
unsigned char* tensDest = dest + x + 6 + 9;
|
|
|
|
unsigned char* onesDest = dest + x + 6 + 9 * 2;
|
|
|
|
|
|
|
|
int normalizedSign;
|
|
|
|
int normalizedValue;
|
|
|
|
if (gInterfaceBarInitialized || delay == 0) {
|
|
|
|
normalizedSign = value >= 0 ? 1 : -1;
|
|
|
|
normalizedValue = abs(value);
|
|
|
|
} else {
|
|
|
|
normalizedSign = previousValue >= 0 ? 1 : -1;
|
|
|
|
normalizedValue = previousValue;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ones = normalizedValue % 10;
|
|
|
|
int tens = (normalizedValue / 10) % 10;
|
|
|
|
int hundreds = normalizedValue / 100;
|
|
|
|
|
|
|
|
blitBufferToBuffer(numbers + 9 * hundreds, 9, 17, 360, hundredsDest, 640);
|
|
|
|
blitBufferToBuffer(numbers + 9 * tens, 9, 17, 360, tensDest, 640);
|
|
|
|
blitBufferToBuffer(numbers + 9 * ones, 9, 17, 360, onesDest, 640);
|
|
|
|
blitBufferToBuffer(normalizedSign >= 0 ? plusSrc : minusSrc, 6, 17, 360, signDest, 640);
|
|
|
|
|
|
|
|
if (!gInterfaceBarInitialized) {
|
|
|
|
Rect numbersRect = { x, y, x + 33, y + 17 };
|
|
|
|
windowRefreshRect(gInterfaceBarWindow, &numbersRect);
|
|
|
|
if (delay != 0) {
|
|
|
|
int change = value - previousValue >= 0 ? 1 : -1;
|
|
|
|
int v14 = previousValue >= 0 ? 1 : -1;
|
|
|
|
int v49 = change * v14;
|
|
|
|
while (previousValue != value) {
|
|
|
|
if ((hundreds | tens | ones) == 0) {
|
|
|
|
v49 = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
blitBufferToBuffer(upSrc, 9, 17, 360, onesDest, 640);
|
|
|
|
_mouse_info();
|
|
|
|
gameMouseRefresh();
|
|
|
|
coreDelay(delay);
|
|
|
|
windowRefreshRect(gInterfaceBarWindow, &numbersRect);
|
|
|
|
|
|
|
|
ones += v49;
|
|
|
|
|
|
|
|
if (ones > 9 || ones < 0) {
|
|
|
|
blitBufferToBuffer(upSrc, 9, 17, 360, tensDest, 640);
|
|
|
|
_mouse_info();
|
|
|
|
gameMouseRefresh();
|
|
|
|
coreDelay(delay);
|
|
|
|
windowRefreshRect(gInterfaceBarWindow, &numbersRect);
|
|
|
|
|
|
|
|
tens += v49;
|
|
|
|
ones -= 10 * v49;
|
|
|
|
if (tens == 10 || tens == -1) {
|
|
|
|
blitBufferToBuffer(upSrc, 9, 17, 360, hundredsDest, 640);
|
|
|
|
_mouse_info();
|
|
|
|
gameMouseRefresh();
|
|
|
|
coreDelay(delay);
|
|
|
|
windowRefreshRect(gInterfaceBarWindow, &numbersRect);
|
|
|
|
|
|
|
|
hundreds += v49;
|
|
|
|
tens -= 10 * v49;
|
|
|
|
if (hundreds == 10 || hundreds == -1) {
|
|
|
|
hundreds -= 10 * v49;
|
|
|
|
}
|
|
|
|
|
|
|
|
blitBufferToBuffer(downSrc, 9, 17, 360, hundredsDest, 640);
|
|
|
|
_mouse_info();
|
|
|
|
gameMouseRefresh();
|
|
|
|
coreDelay(delay);
|
|
|
|
windowRefreshRect(gInterfaceBarWindow, &numbersRect);
|
|
|
|
}
|
|
|
|
|
|
|
|
blitBufferToBuffer(downSrc, 9, 17, 360, tensDest, 640);
|
|
|
|
coreDelay(delay);
|
|
|
|
windowRefreshRect(gInterfaceBarWindow, &numbersRect);
|
|
|
|
}
|
|
|
|
|
|
|
|
blitBufferToBuffer(downSrc, 9, 17, 360, onesDest, 640);
|
|
|
|
_mouse_info();
|
|
|
|
gameMouseRefresh();
|
|
|
|
coreDelay(delay);
|
|
|
|
windowRefreshRect(gInterfaceBarWindow, &numbersRect);
|
|
|
|
|
|
|
|
previousValue += change;
|
|
|
|
|
|
|
|
blitBufferToBuffer(numbers + 9 * hundreds, 9, 17, 360, hundredsDest, 640);
|
|
|
|
blitBufferToBuffer(numbers + 9 * tens, 9, 17, 360, tensDest, 640);
|
|
|
|
blitBufferToBuffer(numbers + 9 * ones, 9, 17, 360, onesDest, 640);
|
|
|
|
|
|
|
|
blitBufferToBuffer(previousValue >= 0 ? plusSrc : minusSrc, 6, 17, 360, signDest, 640);
|
|
|
|
_mouse_info();
|
|
|
|
gameMouseRefresh();
|
|
|
|
coreDelay(delay);
|
|
|
|
windowRefreshRect(gInterfaceBarWindow, &numbersRect);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-09-01 08:41:37 -07:00
|
|
|
// NOTE: Inlined.
|
|
|
|
//
|
|
|
|
// 0x461128
|
|
|
|
static int intface_fatal_error(int rc)
|
|
|
|
{
|
|
|
|
interfaceFree();
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2022-05-19 01:51:26 -07:00
|
|
|
// 0x461134
|
2022-06-18 07:39:55 -07:00
|
|
|
static int indicatorBarInit()
|
2022-05-19 01:51:26 -07:00
|
|
|
{
|
|
|
|
int oldFont = fontGetCurrent();
|
|
|
|
|
|
|
|
if (gIndicatorBarWindow != -1) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
MessageList messageList;
|
|
|
|
MessageListItem messageListItem;
|
|
|
|
int rc = 0;
|
|
|
|
if (!messageListInit(&messageList)) {
|
|
|
|
rc = -1;
|
|
|
|
}
|
|
|
|
|
2022-05-28 02:34:49 -07:00
|
|
|
char path[COMPAT_MAX_PATH];
|
2022-05-19 01:51:26 -07:00
|
|
|
sprintf(path, "%s%s", asc_5186C8, "intrface.msg");
|
|
|
|
|
|
|
|
if (rc != -1) {
|
|
|
|
if (!messageListLoad(&messageList, path)) {
|
|
|
|
rc = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (rc == -1) {
|
|
|
|
debugPrint("\nINTRFACE: Error indicator box messages! **\n");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2022-09-24 11:04:32 -07:00
|
|
|
FrmImage indicatorBoxFrmImage;
|
2022-07-29 06:04:05 -07:00
|
|
|
int indicatorBoxFid = buildFid(OBJ_TYPE_INTERFACE, 126, 0, 0, 0);
|
2022-09-24 11:04:32 -07:00
|
|
|
if (!indicatorBoxFrmImage.lock(indicatorBoxFid)) {
|
2022-05-19 01:51:26 -07:00
|
|
|
debugPrint("\nINTRFACE: Error initializing indicator box graphics! **\n");
|
|
|
|
messageListFree(&messageList);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int index = 0; index < INDICATOR_COUNT; index++) {
|
|
|
|
IndicatorDescription* indicatorDescription = &(gIndicatorDescriptions[index]);
|
|
|
|
|
2022-05-21 08:22:03 -07:00
|
|
|
indicatorDescription->data = (unsigned char*)internal_malloc(INDICATOR_BOX_WIDTH * INDICATOR_BOX_HEIGHT);
|
2022-05-19 01:51:26 -07:00
|
|
|
if (indicatorDescription->data == NULL) {
|
|
|
|
debugPrint("\nINTRFACE: Error initializing indicator box graphics! **");
|
|
|
|
|
|
|
|
while (--index >= 0) {
|
|
|
|
internal_free(gIndicatorDescriptions[index].data);
|
|
|
|
}
|
|
|
|
|
|
|
|
messageListFree(&messageList);
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fontSetCurrent(101);
|
|
|
|
|
|
|
|
for (int index = 0; index < INDICATOR_COUNT; index++) {
|
|
|
|
IndicatorDescription* indicator = &(gIndicatorDescriptions[index]);
|
|
|
|
|
|
|
|
char text[1024];
|
|
|
|
strcpy(text, getmsg(&messageList, &messageListItem, indicator->title));
|
|
|
|
|
|
|
|
int color = indicator->isBad ? _colorTable[31744] : _colorTable[992];
|
|
|
|
|
2022-09-24 11:04:32 -07:00
|
|
|
memcpy(indicator->data, indicatorBoxFrmImage.getData(), INDICATOR_BOX_WIDTH * INDICATOR_BOX_HEIGHT);
|
2022-05-19 01:51:26 -07:00
|
|
|
|
|
|
|
// NOTE: For unknown reason it uses 24 as a height of the box to center
|
|
|
|
// the title. One explanation is that these boxes were redesigned, but
|
|
|
|
// this value was not changed. On the other hand 24 is
|
|
|
|
// [INDICATOR_BOX_HEIGHT] + [INDICATOR_BOX_CONNECTOR_WIDTH]. Maybe just
|
|
|
|
// a coincidence. I guess we'll never find out.
|
|
|
|
int y = (24 - fontGetLineHeight()) / 2;
|
|
|
|
int x = (INDICATOR_BOX_WIDTH - fontGetStringWidth(text)) / 2;
|
|
|
|
fontDrawText(indicator->data + INDICATOR_BOX_WIDTH * y + x, text, INDICATOR_BOX_WIDTH, INDICATOR_BOX_WIDTH, color);
|
|
|
|
}
|
|
|
|
|
|
|
|
gIndicatorBarIsVisible = true;
|
|
|
|
indicatorBarRefresh();
|
|
|
|
|
|
|
|
messageListFree(&messageList);
|
|
|
|
fontSetCurrent(oldFont);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x461454
|
2022-06-18 07:39:55 -07:00
|
|
|
static void interfaceBarFree()
|
2022-05-19 01:51:26 -07:00
|
|
|
{
|
|
|
|
if (gIndicatorBarWindow != -1) {
|
|
|
|
windowDestroy(gIndicatorBarWindow);
|
|
|
|
gIndicatorBarWindow = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (int index = 0; index < INDICATOR_COUNT; index++) {
|
|
|
|
IndicatorDescription* indicatorBoxDescription = &(gIndicatorDescriptions[index]);
|
|
|
|
if (indicatorBoxDescription->data != NULL) {
|
|
|
|
internal_free(indicatorBoxDescription->data);
|
|
|
|
indicatorBoxDescription->data = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// NOTE: This function is not referenced in the original code.
|
|
|
|
//
|
|
|
|
// 0x4614A0
|
2022-06-18 07:39:55 -07:00
|
|
|
static void indicatorBarReset()
|
2022-05-19 01:51:26 -07:00
|
|
|
{
|
|
|
|
if (gIndicatorBarWindow != -1) {
|
|
|
|
windowDestroy(gIndicatorBarWindow);
|
|
|
|
gIndicatorBarWindow = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
gIndicatorBarIsVisible = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Updates indicator bar.
|
|
|
|
//
|
|
|
|
// 0x4614CC
|
|
|
|
int indicatorBarRefresh()
|
|
|
|
{
|
|
|
|
if (gInterfaceBarWindow != -1 && gIndicatorBarIsVisible && !_intfaceHidden) {
|
|
|
|
for (int index = 0; index < INDICATOR_SLOTS_COUNT; index++) {
|
|
|
|
gIndicatorSlots[index] = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int count = 0;
|
|
|
|
|
|
|
|
if (dudeHasState(DUDE_STATE_SNEAKING)) {
|
|
|
|
if (indicatorBarAdd(INDICATOR_SNEAK)) {
|
|
|
|
++count;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dudeHasState(DUDE_STATE_LEVEL_UP_AVAILABLE)) {
|
|
|
|
if (indicatorBarAdd(INDICATOR_LEVEL)) {
|
|
|
|
++count;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dudeHasState(DUDE_STATE_ADDICTED)) {
|
|
|
|
if (indicatorBarAdd(INDICATOR_ADDICT)) {
|
|
|
|
++count;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (critterGetPoison(gDude) > POISON_INDICATOR_THRESHOLD) {
|
|
|
|
if (indicatorBarAdd(INDICATOR_POISONED)) {
|
|
|
|
++count;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (critterGetRadiation(gDude) > RADATION_INDICATOR_THRESHOLD) {
|
|
|
|
if (indicatorBarAdd(INDICATOR_RADIATED)) {
|
|
|
|
++count;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (count > 1) {
|
|
|
|
qsort(gIndicatorSlots, count, sizeof(*gIndicatorSlots), indicatorBoxCompareByPosition);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (gIndicatorBarWindow != -1) {
|
|
|
|
windowDestroy(gIndicatorBarWindow);
|
|
|
|
gIndicatorBarWindow = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (count != 0) {
|
2022-05-22 03:55:49 -07:00
|
|
|
Rect interfaceBarWindowRect;
|
|
|
|
windowGetRect(gInterfaceBarWindow, &interfaceBarWindowRect);
|
|
|
|
|
|
|
|
gIndicatorBarWindow = windowCreate(interfaceBarWindowRect.left,
|
|
|
|
screenGetHeight() - INTERFACE_BAR_HEIGHT - INDICATOR_BOX_HEIGHT,
|
2022-05-19 01:51:26 -07:00
|
|
|
(INDICATOR_BOX_WIDTH - INDICATOR_BOX_CONNECTOR_WIDTH) * count,
|
|
|
|
INDICATOR_BOX_HEIGHT,
|
|
|
|
_colorTable[0],
|
|
|
|
0);
|
|
|
|
indicatorBarRender(count);
|
|
|
|
windowRefresh(gIndicatorBarWindow);
|
|
|
|
}
|
|
|
|
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (gIndicatorBarWindow != -1) {
|
|
|
|
windowDestroy(gIndicatorBarWindow);
|
|
|
|
gIndicatorBarWindow = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x461624
|
2022-06-18 07:39:55 -07:00
|
|
|
static int indicatorBoxCompareByPosition(const void* a, const void* b)
|
2022-05-19 01:51:26 -07:00
|
|
|
{
|
|
|
|
int indicatorBox1 = *(int*)a;
|
|
|
|
int indicatorBox2 = *(int*)b;
|
|
|
|
|
|
|
|
if (indicatorBox1 == indicatorBox2) {
|
|
|
|
return 0;
|
|
|
|
} else if (indicatorBox1 < indicatorBox2) {
|
|
|
|
return -1;
|
|
|
|
} else {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Renders indicator boxes into the indicator bar window.
|
|
|
|
//
|
|
|
|
// 0x461648
|
2022-06-18 07:39:55 -07:00
|
|
|
static void indicatorBarRender(int count)
|
2022-05-19 01:51:26 -07:00
|
|
|
{
|
|
|
|
if (gIndicatorBarWindow == -1) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (count == 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
int windowWidth = windowGetWidth(gIndicatorBarWindow);
|
|
|
|
unsigned char* windowBuffer = windowGetBuffer(gIndicatorBarWindow);
|
|
|
|
|
|
|
|
// The initial number of connections is 2 - one is first box to the screen
|
|
|
|
// boundary, the other is female socket (initially empty). Every displayed
|
|
|
|
// box adds one more connection (it is "plugged" into previous box and
|
|
|
|
// exposes it's own empty female socket).
|
|
|
|
int connections = 2;
|
|
|
|
|
|
|
|
// The width of displayed indicator boxes as if there were no connections.
|
|
|
|
int unconnectedIndicatorsWidth = 0;
|
|
|
|
|
|
|
|
// The X offset to display next box.
|
|
|
|
int x = 0;
|
|
|
|
|
|
|
|
// The first box is connected to the screen boundary, so we have to clamp
|
|
|
|
// male connectors on the left.
|
|
|
|
int connectorWidthCompensation = INDICATOR_BOX_CONNECTOR_WIDTH;
|
|
|
|
|
|
|
|
for (int index = 0; index < count; index++) {
|
|
|
|
int indicator = gIndicatorSlots[index];
|
|
|
|
IndicatorDescription* indicatorDescription = &(gIndicatorDescriptions[indicator]);
|
|
|
|
|
|
|
|
blitBufferToBufferTrans(indicatorDescription->data + connectorWidthCompensation,
|
|
|
|
INDICATOR_BOX_WIDTH - connectorWidthCompensation,
|
|
|
|
INDICATOR_BOX_HEIGHT,
|
|
|
|
INDICATOR_BOX_WIDTH,
|
|
|
|
windowBuffer + x, windowWidth);
|
|
|
|
|
|
|
|
connectorWidthCompensation = 0;
|
|
|
|
|
|
|
|
unconnectedIndicatorsWidth += INDICATOR_BOX_WIDTH;
|
|
|
|
x = unconnectedIndicatorsWidth - INDICATOR_BOX_CONNECTOR_WIDTH * connections;
|
|
|
|
connections++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Adds indicator to the indicator bar.
|
|
|
|
//
|
|
|
|
// Returns `true` if indicator was added, or `false` if there is no available
|
|
|
|
// space in the indicator bar.
|
|
|
|
//
|
|
|
|
// 0x4616F0
|
2022-06-18 07:39:55 -07:00
|
|
|
static bool indicatorBarAdd(int indicator)
|
2022-05-19 01:51:26 -07:00
|
|
|
{
|
|
|
|
for (int index = 0; index < INDICATOR_SLOTS_COUNT; index++) {
|
|
|
|
if (gIndicatorSlots[index] == -1) {
|
|
|
|
gIndicatorSlots[index] = indicator;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
debugPrint("\nINTRFACE: no free bar box slots!\n");
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x461740
|
|
|
|
bool indicatorBarShow()
|
|
|
|
{
|
|
|
|
bool oldIsVisible = gIndicatorBarIsVisible;
|
|
|
|
gIndicatorBarIsVisible = true;
|
|
|
|
|
|
|
|
indicatorBarRefresh();
|
|
|
|
|
|
|
|
return oldIsVisible;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 0x461760
|
|
|
|
bool indicatorBarHide()
|
|
|
|
{
|
|
|
|
bool oldIsVisible = gIndicatorBarIsVisible;
|
|
|
|
gIndicatorBarIsVisible = false;
|
|
|
|
|
|
|
|
indicatorBarRefresh();
|
|
|
|
|
|
|
|
return oldIsVisible;
|
|
|
|
}
|
2022-09-23 05:43:44 -07:00
|
|
|
|
|
|
|
} // namespace fallout
|