fallout2-ce/src/display_monitor.cc

366 lines
9.8 KiB
C++

#include "display_monitor.h"
#include "art.h"
#include "color.h"
#include "combat.h"
#include "core.h"
#include "draw.h"
#include "game_mouse.h"
#include "game_sound.h"
#include "interface.h"
#include "memory.h"
#include "text_font.h"
#include "window_manager.h"
#include <string.h>
// 0x51850C
bool gDisplayMonitorInitialized = false;
// The rectangle that display monitor occupies in the main interface window.
//
// 0x518510
const Rect gDisplayMonitorRect = {
DISPLAY_MONITOR_X,
DISPLAY_MONITOR_Y,
DISPLAY_MONITOR_X + DISPLAY_MONITOR_WIDTH - 1,
DISPLAY_MONITOR_Y + DISPLAY_MONITOR_HEIGHT - 1,
};
// 0x518520
int gDisplayMonitorScrollDownButton = -1;
// 0x518524
int gDisplayMonitorScrollUpButton = -1;
// 0x56DBFC
char gDisplayMonitorLines[DISPLAY_MONITOR_LINES_CAPACITY][DISPLAY_MONITOR_LINE_LENGTH];
// 0x56FB3C
unsigned char* gDisplayMonitorBackgroundFrmData;
// 0x56FB40
int _max_disp;
// 0x56FB44
bool gDisplayMonitorEnabled;
// 0x56FB48
int _disp_curr;
// 0x56FB4C
int _intface_full_width;
// 0x56FB50
int gDisplayMonitorLinesCapacity;
// 0x56FB54
int _disp_start;
// 0x56FB58
unsigned int gDisplayMonitorLastBeepTimestamp;
// 0x431610
int displayMonitorInit()
{
if (!gDisplayMonitorInitialized) {
int oldFont = fontGetCurrent();
fontSetCurrent(DISPLAY_MONITOR_FONT);
gDisplayMonitorLinesCapacity = DISPLAY_MONITOR_LINES_CAPACITY;
_max_disp = DISPLAY_MONITOR_HEIGHT / fontGetLineHeight();
_disp_start = 0;
_disp_curr = 0;
fontSetCurrent(oldFont);
gDisplayMonitorBackgroundFrmData = (unsigned char*)internal_malloc(DISPLAY_MONITOR_WIDTH * DISPLAY_MONITOR_HEIGHT);
if (gDisplayMonitorBackgroundFrmData == NULL) {
return -1;
}
CacheEntry* backgroundFrmHandle;
int backgroundFid = buildFid(6, 16, 0, 0, 0);
Art* backgroundFrm = artLock(backgroundFid, &backgroundFrmHandle);
if (backgroundFrm == NULL) {
internal_free(gDisplayMonitorBackgroundFrmData);
return -1;
}
unsigned char* backgroundFrmData = artGetFrameData(backgroundFrm, 0, 0);
_intface_full_width = artGetWidth(backgroundFrm, 0, 0);
blitBufferToBuffer(backgroundFrmData + _intface_full_width * DISPLAY_MONITOR_Y + DISPLAY_MONITOR_X,
DISPLAY_MONITOR_WIDTH,
DISPLAY_MONITOR_HEIGHT,
_intface_full_width,
gDisplayMonitorBackgroundFrmData,
DISPLAY_MONITOR_WIDTH);
artUnlock(backgroundFrmHandle);
gDisplayMonitorScrollUpButton = buttonCreate(gInterfaceBarWindow,
DISPLAY_MONITOR_X,
DISPLAY_MONITOR_Y,
DISPLAY_MONITOR_WIDTH,
DISPLAY_MONITOR_HALF_HEIGHT,
-1,
-1,
-1,
-1,
NULL,
NULL,
NULL,
0);
if (gDisplayMonitorScrollUpButton != -1) {
buttonSetMouseCallbacks(gDisplayMonitorScrollUpButton,
displayMonitorScrollUpOnMouseEnter,
displayMonitorOnMouseExit,
displayMonitorScrollUpOnMouseDown,
NULL);
}
gDisplayMonitorScrollDownButton = buttonCreate(gInterfaceBarWindow,
DISPLAY_MONITOR_X,
DISPLAY_MONITOR_Y + DISPLAY_MONITOR_HALF_HEIGHT,
DISPLAY_MONITOR_WIDTH,
DISPLAY_MONITOR_HEIGHT - DISPLAY_MONITOR_HALF_HEIGHT,
-1,
-1,
-1,
-1,
NULL,
NULL,
NULL,
0);
if (gDisplayMonitorScrollDownButton != -1) {
buttonSetMouseCallbacks(gDisplayMonitorScrollDownButton,
displayMonitorScrollDownOnMouseEnter,
displayMonitorOnMouseExit,
displayMonitorScrollDownOnMouseDown,
NULL);
}
gDisplayMonitorEnabled = true;
gDisplayMonitorInitialized = true;
for (int index = 0; index < gDisplayMonitorLinesCapacity; index++) {
gDisplayMonitorLines[index][0] = '\0';
}
_disp_start = 0;
_disp_curr = 0;
displayMonitorRefresh();
}
return 0;
}
// 0x431800
int displayMonitorReset()
{
if (gDisplayMonitorInitialized) {
for (int index = 0; index < gDisplayMonitorLinesCapacity; index++) {
gDisplayMonitorLines[index][0] = '\0';
}
_disp_start = 0;
_disp_curr = 0;
displayMonitorRefresh();
}
return 0;
}
// 0x43184C
void displayMonitorExit()
{
if (gDisplayMonitorInitialized) {
internal_free(gDisplayMonitorBackgroundFrmData);
gDisplayMonitorInitialized = false;
}
}
// 0x43186C
void displayMonitorAddMessage(char* str)
{
if (!gDisplayMonitorInitialized) {
return;
}
int oldFont = fontGetCurrent();
fontSetCurrent(DISPLAY_MONITOR_FONT);
char knob = '\x95';
char knobString[2];
knobString[0] = knob;
knobString[1] = '\0';
int knobWidth = fontGetStringWidth(knobString);
if (!isInCombat()) {
unsigned int now = _get_bk_time();
if (getTicksBetween(now, gDisplayMonitorLastBeepTimestamp) >= DISPLAY_MONITOR_BEEP_DELAY) {
gDisplayMonitorLastBeepTimestamp = now;
soundPlayFile("monitor");
}
}
// TODO: Refactor these two loops.
char* v1 = NULL;
while (true) {
while (fontGetStringWidth(str) < DISPLAY_MONITOR_WIDTH - _max_disp - knobWidth) {
char* temp = gDisplayMonitorLines[_disp_start];
int length;
if (knob != '\0') {
*temp++ = knob;
length = DISPLAY_MONITOR_LINE_LENGTH - 2;
knob = '\0';
knobWidth = 0;
} else {
length = DISPLAY_MONITOR_LINE_LENGTH - 1;
}
strncpy(temp, str, length);
gDisplayMonitorLines[_disp_start][DISPLAY_MONITOR_LINE_LENGTH - 1] = '\0';
_disp_start = (_disp_start + 1) % gDisplayMonitorLinesCapacity;
if (v1 == NULL) {
fontSetCurrent(oldFont);
_disp_curr = _disp_start;
displayMonitorRefresh();
return;
}
str = v1 + 1;
*v1 = ' ';
v1 = NULL;
}
char* space = strrchr(str, ' ');
if (space == NULL) {
break;
}
if (v1 != NULL) {
*v1 = ' ';
}
v1 = space;
if (space != NULL) {
*space = '\0';
}
}
char* temp = gDisplayMonitorLines[_disp_start];
int length;
if (knob != '\0') {
temp++;
gDisplayMonitorLines[_disp_start][0] = knob;
length = DISPLAY_MONITOR_LINE_LENGTH - 2;
knob = '\0';
} else {
length = DISPLAY_MONITOR_LINE_LENGTH - 1;
}
strncpy(temp, str, length);
gDisplayMonitorLines[_disp_start][DISPLAY_MONITOR_LINE_LENGTH - 1] = '\0';
_disp_start = (_disp_start + 1) % gDisplayMonitorLinesCapacity;
fontSetCurrent(oldFont);
_disp_curr = _disp_start;
displayMonitorRefresh();
}
// 0x431A78
void displayMonitorRefresh()
{
if (!gDisplayMonitorInitialized) {
return;
}
unsigned char* buf = windowGetBuffer(gInterfaceBarWindow);
if (buf == NULL) {
return;
}
buf += _intface_full_width * DISPLAY_MONITOR_Y + DISPLAY_MONITOR_X;
blitBufferToBuffer(gDisplayMonitorBackgroundFrmData,
DISPLAY_MONITOR_WIDTH,
DISPLAY_MONITOR_HEIGHT,
DISPLAY_MONITOR_WIDTH,
buf,
_intface_full_width);
int oldFont = fontGetCurrent();
fontSetCurrent(DISPLAY_MONITOR_FONT);
for (int index = 0; index < _max_disp; index++) {
int stringIndex = (_disp_curr + gDisplayMonitorLinesCapacity + index - _max_disp) % gDisplayMonitorLinesCapacity;
fontDrawText(buf + index * _intface_full_width * fontGetLineHeight(), gDisplayMonitorLines[stringIndex], DISPLAY_MONITOR_WIDTH, _intface_full_width, _colorTable[992]);
// Even though the display monitor is rectangular, it's graphic is not.
// To give a feel of depth it's covered by some metal canopy and
// considered inclined outwards. This way earlier messages appear a
// little bit far from player's perspective. To implement this small
// detail the destination buffer is incremented by 1.
buf++;
}
windowRefreshRect(gInterfaceBarWindow, &gDisplayMonitorRect);
fontSetCurrent(oldFont);
}
// 0x431B70
void displayMonitorScrollUpOnMouseDown(int btn, int keyCode)
{
if ((gDisplayMonitorLinesCapacity + _disp_curr - 1) % gDisplayMonitorLinesCapacity != _disp_start) {
_disp_curr = (gDisplayMonitorLinesCapacity + _disp_curr - 1) % gDisplayMonitorLinesCapacity;
displayMonitorRefresh();
}
}
// 0x431B9C
void displayMonitorScrollDownOnMouseDown(int btn, int keyCode)
{
if (_disp_curr != _disp_start) {
_disp_curr = (_disp_curr + 1) % gDisplayMonitorLinesCapacity;
displayMonitorRefresh();
}
}
// 0x431BC8
void displayMonitorScrollUpOnMouseEnter(int btn, int keyCode)
{
gameMouseSetCursor(MOUSE_CURSOR_SMALL_ARROW_UP);
}
// 0x431BD4
void displayMonitorScrollDownOnMouseEnter(int btn, int keyCode)
{
gameMouseSetCursor(MOUSE_CURSOR_SMALL_ARROW_DOWN);
}
// 0x431BE0
void displayMonitorOnMouseExit(int btn, int keyCode)
{
gameMouseSetCursor(MOUSE_CURSOR_ARROW);
}
// 0x431BEC
void displayMonitorDisable()
{
if (gDisplayMonitorEnabled) {
buttonDisable(gDisplayMonitorScrollDownButton);
buttonDisable(gDisplayMonitorScrollUpButton);
gDisplayMonitorEnabled = false;
}
}
// 0x431C14
void displayMonitorEnable()
{
if (!gDisplayMonitorEnabled) {
buttonEnable(gDisplayMonitorScrollDownButton);
buttonEnable(gDisplayMonitorScrollUpButton);
gDisplayMonitorEnabled = true;
}
}