Initial commit

This commit is contained in:
2026-02-02 04:50:13 +01:00
commit 5b11698731
22592 changed files with 7677434 additions and 0 deletions

View File

@@ -0,0 +1,162 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "ultima/shared/std/string.h"
#include "ultima/nuvie/core/nuvie_defs.h"
#include "ultima/nuvie/conf/configuration.h"
#include "ultima/nuvie/misc/u6_misc.h"
#include "ultima/nuvie/files/u6_lib_n.h"
#include "ultima/nuvie/files/u6_bmp.h"
#include "ultima/nuvie/screen/dither.h"
#include "ultima/nuvie/gui/widgets/background.h"
#include "ultima/nuvie/gui/widgets/map_window.h"
#include "ultima/nuvie/gui/gui.h"
namespace Ultima {
namespace Nuvie {
Background::Background(const Configuration *cfg) : GUI_Widget(nullptr), config(cfg),
bg_w(0), bg_h(0), border_width(0), background(nullptr), right_bg_x_off(0),
left_bg_x_off(0) {
config->value("config/GameType", game_type);
x_off = Game::get_game()->get_game_x_offset();
y_off = Game::get_game()->get_game_y_offset();
Init(nullptr, 0, 0, Game::get_game()->get_screen()->get_width(), Game::get_game()->get_screen()->get_height());
}
Background::~Background() {
if (background)
delete background;
}
bool Background::init() {
Common::Path filename;
if (!Game::get_game()->is_new_style()) {
switch (game_type) {
case NUVIE_GAME_U6 :
config_get_path(config, "paper.bmp", filename);
background = (U6Shape *) new U6Bmp();
if (background->load(filename) == false)
return false;
if (Game::get_game()->is_original_plus()) {
border_width = 158;
right_bg_x_off = x_off + Game::get_game()->get_game_width() - 152;
left_bg_x_off = x_off + Game::get_game()->get_game_width() - border_width;
}
break;
case NUVIE_GAME_MD :
background = new U6Shape();
background->load_WoU_background(config, game_type);
if (Game::get_game()->is_original_plus()) {
border_width = 144;
left_bg_x_off = x_off + Game::get_game()->get_game_width() - border_width;
}
break;
case NUVIE_GAME_SE :
background = new U6Shape();
background->load_WoU_background(config, game_type);
if (Game::get_game()->is_original_plus()) {
border_width = 142;
left_bg_x_off = x_off + Game::get_game()->get_game_width() - border_width;
}
break;
}
background->get_size(&bg_w, &bg_h);
Game::get_game()->get_dither()->dither_bitmap(background->get_data(), bg_w, bg_h, DITHER_NO_TRANSPARENCY);
}
return true;
}
void Background::Display(bool full_redraw) {
if (full_redraw || update_display || Game::get_game()->is_original_plus_full_map()) {
if (Game::get_game()->is_original_plus()) {
if (Game::get_game()->is_original_plus_cutoff_map())
screen->clear(area.left, area.top, area.width(), area.height(), nullptr);
else if (full_redraw || update_display) { // need to clear null background when we have a game size smaller than the screen
uint16 game_width = Game::get_game()->get_game_width();
uint16 game_height = Game::get_game()->get_game_height();
if (x_off > 0) { // centered
screen->clear(area.left, area.top, x_off, area.height(), nullptr); // left side
screen->clear(x_off + game_width, area.top, x_off, area.height(), nullptr); // right side
} else if (area.width() > game_width) { // upper_left position
screen->clear(game_width, area.top, area.width() - game_width, area.height(), nullptr); // right side
}
if (y_off > 0) { // centered
screen->clear(area.left, area.top, area.width(), y_off, nullptr); // top
screen->clear(area.left, y_off + game_height, area.width(), y_off, nullptr); // bottom
} else if (area.height() > game_height) { // upper_left position
screen->clear(area.left, game_height, area.width(), area.height() - game_height, nullptr); // bottom
}
}
const unsigned char *ptr = background->get_data();
if (game_type == NUVIE_GAME_U6) {
ptr += (bg_w - 152);
screen->blit(right_bg_x_off, y_off, ptr, 8, 152, bg_h, bg_w, true);
screen->blit(left_bg_x_off, y_off, background->get_data(), 8, 6, bg_h, bg_w, true);
} else {
if (game_type == NUVIE_GAME_MD)
screen->fill(0, left_bg_x_off, y_off, border_width, bg_h); // background has transparent parts that should be black
ptr += (bg_w - border_width);
screen->blit(left_bg_x_off, y_off, ptr, 8, border_width, bg_h, bg_w, true);
}
} else {
screen->clear(area.left, area.top, area.width(), area.height(), nullptr);
if (Game::get_game()->is_orig_style())
screen->blit(x_off, y_off, background->get_data(), 8, bg_w, bg_h, bg_w, true);
}
update_display = false;
screen->update(0, 0, area.width(), area.height());
}
return;
}
bool Background::drag_accept_drop(int x, int y, int message, void *data) {
GUI::get_gui()->force_full_redraw();
DEBUG(0, LEVEL_DEBUGGING, "Background::drag_accept_drop()\n");
if (Game::get_game()->is_original_plus_full_map() && message == GUI_DRAG_OBJ) { // added to gui before the map window so we need to redirect
MapWindow *map_window = Game::get_game()->get_map_window();
if (!map_window) // should be initialized before drops occur but we will play it safe
return false;
if (Game::get_game()->get_game_width() > x - x_off && x >= x_off // make sure we are on the map window
&& Game::get_game()->get_game_height() > y - y_off && y >= y_off) {
if (x >= left_bg_x_off && y <= 200 + y_off) // over background image
return false;
return map_window->drag_accept_drop(x, y, message, data);
}
}
return false;
}
void Background::drag_perform_drop(int x, int y, int message, void *data) {
DEBUG(0, LEVEL_DEBUGGING, "Background::drag_perform_drop()\n");
if (message == GUI_DRAG_OBJ) // should only happen with original_plus_full_map
Game::get_game()->get_map_window()->drag_perform_drop(x, y, message, data);
}
} // End of namespace Nuvie
} // End of namespace Ultima

View File

@@ -0,0 +1,64 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef NUVIE_CORE_BACKGROUND_H
#define NUVIE_CORE_BACKGROUND_H
#include "ultima/nuvie/gui/widgets/gui_widget.h"
namespace Ultima {
namespace Nuvie {
class Configuration;
class U6Shape;
class Background: public GUI_Widget {
const Configuration *config;
int game_type;
U6Shape *background;
uint16 bg_w, bg_h;
uint16 x_off, y_off, right_bg_x_off, left_bg_x_off, border_width;
public:
Background(const Configuration *cfg);
~Background() override;
bool init();
uint16 get_border_width() const {
return border_width;
}
void Display(bool full_redraw) override;
bool drag_accept_drop(int x, int y, int message, void *data) override; // needed for original+_full_map
void drag_perform_drop(int x, int y, int message, void *data) override; // needed for original+_full_map
U6Shape *get_bg_shape() {
return background;
}
uint16 get_bg_w() const {
return bg_w;
}
};
} // End of namespace Nuvie
} // End of namespace Ultima
#endif

View File

@@ -0,0 +1,520 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "ultima/nuvie/conf/configuration.h"
#include "ultima/nuvie/core/nuvie_defs.h"
#include "ultima/nuvie/misc/u6_misc.h"
#include "ultima/nuvie/core/game.h"
#include "ultima/nuvie/screen/screen.h"
#include "ultima/nuvie/core/events.h"
#include "ultima/nuvie/core/tile_manager.h"
#include "ultima/nuvie/fonts/font.h"
#include "ultima/nuvie/fonts/font_manager.h"
#include "ultima/nuvie/core/game_clock.h"
#include "ultima/nuvie/screen/game_palette.h"
#include "ultima/nuvie/gui/widgets/command_bar.h"
#include "ultima/nuvie/core/weather.h"
#include "ultima/nuvie/core/party.h"
#include "ultima/nuvie/core/player.h"
#include "ultima/nuvie/save/obj_list.h"
#include "ultima/nuvie/files/nuvie_io.h"
#include "ultima/nuvie/files/u6_shape.h"
#include "ultima/nuvie/gui/widgets/map_window.h"
#include "ultima/nuvie/gui/gui.h"
#include "ultima/nuvie/nuvie.h"
namespace Ultima {
namespace Nuvie {
using Std::string;
static const Tile placeholder_tile = {
0,
false,
false,
false,
false,
false,
true,
false,
false,
0,
//uint8 qty;
//uint8 flags;
0,
0,
0,
{
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15
}
};
CommandBar::CommandBar() : GUI_Widget(nullptr), game(nullptr), event(nullptr),
background(nullptr), font(nullptr), selected_action(-1), offset(0),
combat_mode(false), bg_color(0), font_color(0), active_action_num(-1),
lever_up(nullptr), lever_down(nullptr) {
for (int i = 0; i < ARRAYSIZE(icon); i++)
icon[i] = nullptr;
}
CommandBar::CommandBar(Game *g) : GUI_Widget(nullptr), game(g),
background(nullptr), combat_mode(false), bg_color(0), active_action_num(-1),
font_color(0), lever_up(nullptr), lever_down(nullptr) {
Weather *weather;
uint16 x_off = game->get_game_x_offset();
uint16 y_off = game->get_game_y_offset();
bool right_pos_cb = false;
const Configuration *cfg = nullptr;
if (!game->is_orig_style()) {
cfg = game->get_config();
Std::string pos_str;
cfg->value(config_get_game_key(cfg) + "/cb_position", pos_str, "default");
if (pos_str == "default")
right_pos_cb = !game->is_new_style();
else
right_pos_cb = pos_str != "left";
}
if (game->get_game_type() == NUVIE_GAME_U6) {
offset = OBJLIST_OFFSET_U6_COMMAND_BAR;
if (!game->is_orig_style()) {
int value;
cfg->value(config_get_game_key(cfg) + "/cb_text_color", value, 115); // light blue so that it stands out most of the time and isn't too bold
font_color = value;
y_off += game->get_game_height() - 29;
if (right_pos_cb && (game->get_game_height() > 228 || game->is_new_style())) // bottom right
Init(nullptr, x_off + 159 + game->get_game_width() - 320, y_off, 0, 0);
else // bottom left
Init(nullptr, x_off, y_off, 0, 0);
} else {
font_color = FONT_COLOR_U6_NORMAL;
Init(nullptr, 8 + x_off, 168 + y_off, 0, 0);
}
area.setWidth(16 * 10); // space for 10 icons
area.setHeight(24 + 1); // extra space for the underlined default action
} else if (game->get_game_type() == NUVIE_GAME_MD) {
if (!game->is_orig_style()) {
background = new U6Shape();
background->load_WoU_background(game->get_config(), game->get_game_type());
y_off += game->get_game_height() - 34;
if (right_pos_cb && (game->get_game_height() > 233 || game->is_new_style()))
Init(nullptr, x_off + game->get_game_width() - 320 + 174, y_off, 146, 34);
else
Init(nullptr, 16 + x_off, y_off - 3, 146, 34);
} else
Init(nullptr, 16 + x_off, 163 + y_off, 146, 34);
offset = OBJLIST_OFFSET_MD_COMMAND_BAR;
} else { // SE
if (!game->is_orig_style()) {
background = new U6Shape();
background->load_WoU_background(game->get_config(), game->get_game_type());
y_off += game->get_game_height() - 22;
if (right_pos_cb && (game->get_game_height() > 221 || game->is_new_style())) // bottom right
Init(nullptr, x_off + 156 + game->get_game_width() - 320, y_off, 163, 19);
else
Init(nullptr, 8 + x_off, y_off, 1643, 19);
} else
Init(nullptr, 8 + x_off, 178 + y_off, 163, 19);
offset = OBJLIST_OFFSET_SE_COMMAND_BAR;
}
event = nullptr; // it's not set yet
font = game->get_font_manager()->get_font(0);
weather = game->get_weather();
selected_action = -1;
combat_mode = false;
wind = "?";
bg_color = game->get_palette()->get_bg_color();
init_buttons();
weather->add_wind_change_notification_callback((CallBack *)this); //we want to know when the wind direction changes.
}
CommandBar::~CommandBar() {
if (background)
delete background;
if (lever_up)
delete lever_up;
if (lever_down)
delete lever_down;
}
bool CommandBar::init_buttons() {
if (game->get_game_type() == NUVIE_GAME_U6) {
TileManager *tile_man = game->get_tile_manager();
for (uint32 i = 0; i < 9; i++)
icon[i] = tile_man->get_tile(i + 400);
// NOTE: combat button has two states
icon[9] = tile_man->get_tile(combat_mode ? 415 : 414);
icon[10] = tile_man->get_tile(409); //save icon used by CommandBarNewUI
icon[11] = tile_man->get_tile(409); // quick save
icon[12] = tile_man->get_tile(409); // quick load
} else if (game->get_game_type() == NUVIE_GAME_MD) {
icon[0] = &placeholder_tile; // attack
icon[1] = &placeholder_tile; // talk
icon[2] = &placeholder_tile; // look
icon[3] = &placeholder_tile; // get
icon[4] = &placeholder_tile; // drop
icon[5] = &placeholder_tile; // move
icon[6] = &placeholder_tile; // use
icon[7] = &placeholder_tile; // combat mode
icon[8] = &placeholder_tile; // load/save
icon[9] = &placeholder_tile; // quick save
icon[10] = &placeholder_tile; // quick load
Common::Path filename;
Configuration *config = Game::get_game()->get_config();
config_get_path(config, "mdscreen.lzc", filename);
lever_up = new U6Shape();
lever_down = new U6Shape();
lever_up->load_from_lzc(filename, 2, 1);
lever_down->load_from_lzc(filename, 2, 0);
} else { // SE
icon[0] = &placeholder_tile; // move
icon[1] = &placeholder_tile; // get
icon[2] = &placeholder_tile; // drop
icon[3] = &placeholder_tile; // use
icon[4] = &placeholder_tile; // talk
icon[5] = &placeholder_tile; // look
icon[6] = &placeholder_tile; // attack
icon[7] = &placeholder_tile; // rest
icon[8] = &placeholder_tile; // combat mode
icon[9] = &placeholder_tile; // load/save
icon[10] = &placeholder_tile; // quick save
icon[11] = &placeholder_tile; // quick load
}
return true;
}
bool CommandBar::load(NuvieIO *objlist) {
objlist->seek(offset);
uint8 action = objlist->read1();
selected_action = (action == 0xff ? -1 : action - 0x81);
sint8 max_action;
if (game->get_game_type() == NUVIE_GAME_U6)
max_action = 9;
else if (game->get_game_type() == NUVIE_GAME_SE)
max_action = 8;
else // MD
max_action = 7;
if (selected_action > max_action || selected_action < 0)
selected_action = -1;
return true;
}
bool CommandBar::save(NuvieIO *objlist) {
objlist->seek(offset);
objlist->write1(selected_action > 0 ? selected_action + 0x81 : 0xff);
return true;
}
void CommandBar::fill_square(uint8 pal_index) {
screen->fill(pal_index, area.left + selected_action * 18, area.top, 19, 1); // top row
screen->fill(pal_index, area.left + selected_action * 18, area.top + 18, 19, 1); // bottom row
screen->fill(pal_index, area.left + selected_action * 18, area.top + 1, 1, 17); // left side
screen->fill(pal_index, area.left + selected_action * 18 + 18, area.top + 1, 1, 17); // right side
}
void CommandBar::select_action(sint8 activate) {
if (!game->is_new_style() && game->get_game_type() == NUVIE_GAME_SE) // black out previous setting
fill_square(0);
if (selected_action == activate) // clear if already selected
set_selected_action(-1);
else
set_selected_action(activate);
}
GUI_status CommandBar::MouseDown(int x, int y, Events::MouseButton button) {
x -= area.left;
y -= area.top;
if (game->get_game_type() != NUVIE_GAME_U6 ||
(y >= 8 && y <= 24)) {
uint8 activate = x / 16; // icon selected
if (game->get_game_type() == NUVIE_GAME_SE)
activate = x / 18;
else if (game->get_game_type() == NUVIE_GAME_MD) {
activate = (x) / 18;
if (activate > 7)
activate = 7;
}
if (button == COMMANDBAR_USE_BUTTON)
return hit(activate);
else if (button == COMMANDBAR_ACTION_BUTTON) {
select_action(activate);
}
} else if (!game->is_orig_style())
return GUI_PASS;
return GUI_YUM;
}
GUI_status CommandBar::hit(uint8 num) {
if (!event) event = game->get_event();
if (event->get_mode() != MOVE_MODE && event->get_mode() != EQUIP_MODE)
return GUI_PASS;
try_selected_action(num);
return GUI_YUM;
}
static const EventMode U6_mode_tbl[] = { ATTACK_MODE, CAST_MODE, TALK_MODE, LOOK_MODE, GET_MODE,
DROP_MODE, PUSH_MODE, USE_MODE, REST_MODE, COMBAT_MODE
};
static const EventMode MD_mode_tbl[] = { ATTACK_MODE, TALK_MODE, LOOK_MODE, GET_MODE,
DROP_MODE, PUSH_MODE, USE_MODE, COMBAT_MODE
};
static const EventMode SE_mode_tbl[] = { PUSH_MODE, GET_MODE, DROP_MODE, USE_MODE, TALK_MODE,
LOOK_MODE, ATTACK_MODE, REST_MODE, COMBAT_MODE
};
/*
* return true if target is needed (only used for original CommandBar commands)
*/
bool CommandBar::try_selected_action(sint8 command_num) {
if (!event) event = game->get_event();
if (command_num == -1)
command_num = selected_action;
if (command_num == -1) // might happen if changing selected action when in EQUIP_MODE
return false;
EventMode mode;
sint8 save_num, quick_save_num, quick_load_num;
if (game->get_game_type() == NUVIE_GAME_U6) {
save_num = 10;
quick_save_num = 11;
quick_load_num = 12;
} else if (game->get_game_type() == NUVIE_GAME_MD) {
save_num = 8;
quick_save_num = 9;
quick_load_num = 10;
} else { // SE
save_num = 9;
quick_save_num = 10;
quick_load_num = 11;
}
// CommandBarNewUI only commands
if (command_num == save_num) {
g_engine->openMainMenuDialog();
return false;
} else if (command_num == quick_save_num)
return g_engine->quickSave(0, true);
else if (command_num == quick_load_num)
return g_engine->quickSave(0, false);
else if (command_num >= save_num)
return false;
// original CommandBar commands (also used in CommandBarNewUI)
if (game->get_game_type() == NUVIE_GAME_U6)
mode = U6_mode_tbl[command_num];
else if (game->get_game_type() == NUVIE_GAME_MD)
mode = MD_mode_tbl[command_num];
else // SE
mode = SE_mode_tbl[command_num];
switch (mode) {
case CAST_MODE:
case GET_MODE:
case DROP_MODE:
case PUSH_MODE:
if (game->get_player()->is_in_vehicle()) {
event->display_not_aboard_vehicle();
return false;
}
break;
default:
break;
}
event->newAction(mode);
if (mode < REST_MODE) // needs target
return true;
else
return false;
}
void CommandBar::set_combat_mode(bool mode) {
TileManager *tile_man = game->get_tile_manager();
if (combat_mode != mode) {
combat_mode = mode;
if (game->get_game_type() == NUVIE_GAME_U6) {
icon[9] = tile_man->get_tile(combat_mode ? 415 : 414);
update_display = true;
}
}
//FIXME this probably should be moved else where. I think this was added to get party to fight first. It may not be needed now.
if (combat_mode) { // make sure party attacks
Player *player = game->get_player();
Party *party = player->get_party();
party->follow(0, 0);
}
}
void CommandBar::Display(bool full_redraw) {
Screen *scr = game->get_screen();
if (full_redraw || update_display || !game->is_orig_style()) {
update_display = false;
if (game->get_game_type() == NUVIE_GAME_U6) {
if (game->is_orig_style())
scr->fill(bg_color, area.left, area.top, area.width(), area.height());
else if (game->is_original_plus_cutoff_map() && area.left != game->get_game_x_offset()) // over null background so clear area where text is displayed
scr->clear(area.left + 2, area.top, area.width() - 2, area.height() - 16, nullptr);
display_information();
for (uint32 i = 0; i < 10; i++)
scr->blit(area.left + i * 16, area.top + 8, icon[i]->data, 8, 16, 16, 16);
if (selected_action >= 0 && selected_action <= 9)
scr->fill(9, area.left + selected_action * 16, area.top + 24, 16, 1);
} else if (game->get_game_type() == NUVIE_GAME_SE) {
if (!game->is_orig_style()) {
const unsigned char *se_ptr = background->get_data();
se_ptr += ((320 * 178) + 8); // ((bg_w * image_y_off) + image_x_off)
scr->blit(area.left, area.top, se_ptr, 8, 163, 19, 320, true); // drawing command bar icons from background
}
if (selected_action >= 0 && selected_action <= 8)
fill_square(6);
} else { // MD
if (!game->is_orig_style()) {
const unsigned char *md_bg_ptr = background->get_data();
md_bg_ptr += ((320 * 163) + 15); // ((bg_w * image_y_off) + image_x_off)
scr->fill(0, area.left, area.top, area.width(), area.height()); // lever slots, text, top, and bottom have transparency so we need to fill in black first
scr->blit(area.left, area.top, md_bg_ptr, 8, area.width(), area.height(), 320, true); // drawing command bar icons from background
scr->fill(0, area.left, area.top, 1, area.height()); // make left black so it looks better
scr->fill(0, area.left + area.width() - 1, area.top, 1, area.height()); // make right black so it looks better
}
//
// Display the switched levers. Original MD has lever down for:
// * the right-click action (left click is move)
// * a current action pressed via lever or keyboard (eg, drop)
// * combat lever if in combat mode
//
// TODO: Switch the right-click action down to match original.
//
const U6Shape *lever;
uint16 w, h;
lever_up->get_size(&w, &h);
for (int i = 0; i < 7; i++) {
lever = (i == active_action_num) ? lever_down : lever_up;
scr->blit(area.left + 18 * i + 6, area.top + 6, lever->get_data(), 8, w, h, w);
}
lever = (combat_mode ? lever_down : lever_up);
scr->blit(area.left + 18 * 7 + 6, area.top + 6, lever->get_data(), 8, w, h, w);
}
scr->update(area.left, area.top, area.width(), area.height());
}
}
void CommandBar::display_information() {
string infostring(game->get_clock()->get_date_string());
infostring += " Wind:";
infostring += wind;
font->drawString(screen, infostring.c_str(), area.left + 8, area.top, font_color, font_color);
}
void CommandBar::on_new_action(EventMode action) {
// This is only really needed on MD, but keep track on others too.
const EventMode *modetbl;
int modetblsz;
if (game->get_game_type() == NUVIE_GAME_U6) {
modetbl = U6_mode_tbl;
modetblsz = ARRAYSIZE(U6_mode_tbl);
} else if (game->get_game_type() == NUVIE_GAME_MD) {
modetbl = MD_mode_tbl;
modetblsz = ARRAYSIZE(MD_mode_tbl);
} else { // SE
modetbl = SE_mode_tbl;
modetblsz = ARRAYSIZE(SE_mode_tbl);
}
active_action_num = -1;
for (int i = 0; i < modetblsz; i++) {
if (action == modetbl[i])
active_action_num = i;
}
update_display = true;
}
uint16 CommandBar::callback(uint16 msg, CallBack *caller, void *data) {
Weather *weather = game->get_weather();
if (caller == (CallBack *)weather && msg == WEATHER_CB_CHANGE_WIND_DIR) {
wind = weather->get_wind_dir_str();
update_display = true;
}
return 1;
}
bool CommandBar::drag_accept_drop(int x, int y, int message, void *data) {
GUI::get_gui()->force_full_redraw();
DEBUG(0, LEVEL_DEBUGGING, "CommandBar::drag_accept_drop()\n");
if (game->get_game_type() == NUVIE_GAME_U6 && !Game::get_game()->is_orig_style()
&& message == GUI_DRAG_OBJ) {
if (y < area.top + 8) // over text
return Game::get_game()->get_map_window()->drag_accept_drop(x, y, message, data);
}
return false;
}
void CommandBar::drag_perform_drop(int x, int y, int message, void *data) {
DEBUG(0, LEVEL_DEBUGGING, "CommandBar::drag_perform_drop()\n");
if (message == GUI_DRAG_OBJ) // should only happen with !orig_style in U6
Game::get_game()->get_map_window()->drag_perform_drop(x, y, message, data);
}
} // End of namespace Nuvie
} // End of namespace Ultima

View File

@@ -0,0 +1,113 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef NUVIE_CORE_COMMAND_BAR_H
#define NUVIE_CORE_COMMAND_BAR_H
#include "ultima/shared/std/string.h"
#include "ultima/nuvie/gui/widgets/gui_widget.h"
#include "ultima/nuvie/misc/call_back.h"
namespace Ultima {
namespace Nuvie {
class NuvieIO;
class Events;
class Game;
class GUI_Button;
class GUI_CallBack;
class Font;
class U6Shape;
#define COMMANDBAR_USE_BUTTON 1
#define COMMANDBAR_ACTION_BUTTON 3
/* U6 command buttons.
* [Attack][Cast][Talk][Look][Get][Drop][Move][Use][Rest][Combat]
* Left click: New action if none is pending.
* Right click: Set default action.
* Information: [A]M-DD-YYYY Wind: W[B]
*/
class CommandBar: public GUI_Widget, public CallBack {
protected:
Game *game;
Events *event;
Font *font;
const Tile *icon[13];
U6Shape *background; // used to display the WoU command bar backgrounds
U6Shape *lever_up; // The lever in the up state (MD only)
U6Shape *lever_down; // The lever in the down state (MD only)
sint8 selected_action; // underlined icon (-1 = none)
sint8 active_action_num; // the last action that was activated (for MD levers)
bool combat_mode; // state of combat icon
Std::string wind; // wind direction
void fill_square(uint8 pal_index);
uint8 bg_color, font_color;
uint16 offset;
virtual void display_information();
virtual GUI_status hit(uint8 num);
public:
CommandBar();
CommandBar(Game *g);
~CommandBar() override;
virtual bool init_buttons();
void Display(bool full_redraw) override;
GUI_status MouseDown(int x, int y, Events::MouseButton button) override;
void update() {
update_display = true;
}
void select_action(sint8 activate);
void set_combat_mode(bool mode);
// void set_wind(Std::string dir) { wind = dir; update_display = true; }
void set_selected_action(sint8 action) {
selected_action = action;
update_display = true;
}
bool try_selected_action(sint8 command_num = -1);
sint8 get_selected_action() const {
return selected_action;
}
// Called when a mode is being changed from here
// *or* keyboard - so MD can update levers
void on_new_action(EventMode action);
GUI_status callback(uint16 msg, GUI_CallBack *caller, void *data) override {
return GUI_PASS;
}
uint16 callback(uint16 msg, CallBack *caller, void *data) override;
bool load(NuvieIO *objlist);
bool save(NuvieIO *objlist);
bool drag_accept_drop(int x, int y, int message, void *data) override; // needed for !orig_style
void drag_perform_drop(int x, int y, int message, void *data) override; // needed for !orig_style
};
} // End of namespace Nuvie
} // End of namespace Ultima
#endif

View File

@@ -0,0 +1,284 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "ultima/nuvie/conf/configuration.h"
#include "ultima/nuvie/core/nuvie_defs.h"
#include "ultima/nuvie/misc/u6_misc.h"
#include "ultima/nuvie/core/game.h"
#include "ultima/nuvie/screen/screen.h"
#include "ultima/nuvie/core/events.h"
#include "ultima/nuvie/core/tile_manager.h"
#include "ultima/nuvie/fonts/font.h"
#include "ultima/nuvie/fonts/font_manager.h"
#include "ultima/nuvie/core/game_clock.h"
#include "ultima/nuvie/screen/game_palette.h"
#include "ultima/nuvie/gui/widgets/command_bar_new_ui.h"
#include "ultima/nuvie/core/weather.h"
#include "ultima/nuvie/core/party.h"
#include "ultima/nuvie/core/player.h"
#include "ultima/nuvie/save/obj_list.h"
#include "ultima/nuvie/files/nuvie_io.h"
#include "ultima/nuvie/gui/widgets/background.h"
#include "ultima/nuvie/keybinding/keys.h"
#include "common/events.h"
namespace Ultima {
namespace Nuvie {
using Std::string;
#define btn_size 17
#define SELECTED_COLOR 248
#define table_size_U6 13
#define table_size_SE 12
#define table_size_MD 11
static const char *U6_mode_name_tbl[table_size_U6] = {"Attack", "Cast", "Talk", "Look", "Get", "Drop", "Move", "Use", "Rest", "Combat mode", "Load/Save", "Quick save", "Quick load"};
static const char *SE_mode_name_tbl[table_size_SE] = {"Move", "Get", "Drop", "Use", "Talk", "Look", "Attack", "Rest", "Combat mode", "Load/Save", "Quick save", "Quick load"};
static const char *MD_mode_name_tbl[table_size_MD] = {"Attack", "Talk", "Look", "Get", "Drop", "Move", "Use", "Combat mode", "Load/Save", "Quick save", "Quick load"};
static const char *mode_name_tbl[table_size_U6];
CommandBarNewUI::CommandBarNewUI(Game *g) : CommandBar() {
game = g;
background = nullptr;
Weather *weather;
uint16 x_off = game->get_game_x_offset();
uint16 y_off = game->get_game_y_offset();
icon_w = 5;
icon_h = 3;
uint8 text_height;
uint16 map_width;
uint16 map_height;
offset = OBJLIST_OFFSET_U6_COMMAND_BAR;
if (game->get_game_type() == NUVIE_GAME_U6) {
num_icons = table_size_U6;
for (uint8 i = 0; i < table_size_U6; i++)
mode_name_tbl[i] = U6_mode_name_tbl[i];
} else if (game->get_game_type() == NUVIE_GAME_SE) {
num_icons = table_size_SE;
for (uint8 i = 0; i < table_size_SE; i++)
mode_name_tbl[i] = SE_mode_name_tbl[i];
} else { // MD
num_icons = table_size_MD;
for (uint8 i = 0; i < table_size_MD; i++)
mode_name_tbl[i] = MD_mode_name_tbl[i];
}
if (game->is_orig_style()) {
text_height = 8;
icon_y_offset = 0;
map_width = 176;
map_height = 176;
} else {
if (game->get_game_type() == NUVIE_GAME_U6) {
text_height = 17;
icon_y_offset = 9;
} else {
text_height = 8;
icon_y_offset = 0;
}
if (game->is_original_plus())
map_width = game->get_game_width() - game->get_background()->get_border_width();
else
map_width = game->get_game_width();
map_height = game->get_game_height();
}
uint8 command_width = btn_size * icon_w;
uint8 command_height = btn_size * icon_h + text_height;
Init(nullptr, (map_width - command_width) / 2 + x_off, (map_height - command_height) / 2 + y_off, 0, 0);
area.setWidth(command_width); // space for 5x3 icons
area.setHeight(command_height);
event = nullptr; // it's not set yet
weather = game->get_weather();
selected_action = -1;
combat_mode = false;
wind = weather->get_wind_dir_str();
bg_color = game->get_palette()->get_bg_color();
init_buttons();
if (game->get_game_type() == NUVIE_GAME_U6 && !game->is_orig_style())
weather->add_wind_change_notification_callback((CallBack *)this); //we want to know when the wind direction changes.
cur_pos = 0;
font = game->get_font_manager()->get_conv_font();
}
CommandBarNewUI::~CommandBarNewUI() {
}
GUI_status CommandBarNewUI::MouseDown(int x, int y, Events::MouseButton button) {
if (HitRect(x, y)) {
x -= area.left;
y -= area.right;
if (y >= icon_y_offset) {
uint8 pos = ((y - icon_y_offset) / btn_size) * icon_w;
pos += x / btn_size;
if (pos < num_icons) {
cur_pos = pos;
hit((sint8)cur_pos);
Game::get_game()->get_keybinder()->set_enable_joy_repeat(true);
Hide();
}
}
}
return GUI_YUM;
}
GUI_status CommandBarNewUI::MouseUp(int x, int y, Events::MouseButton button) {
/*
if(HitRect(x, y))
{
x -= area.left;
y -= area.top;
if(y >= icon_y_offset && y < icon_y_offset + icon_h * btn_size)
{
hit((sint8)cur_pos);
Hide();
}
}
*/
return GUI_YUM;
}
GUI_status CommandBarNewUI::KeyDown(const Common::KeyState &key) {
KeyBinder *keybinder = Game::get_game()->get_keybinder();
ActionType a = keybinder->get_ActionType(key);
switch (keybinder->GetActionKeyType(a)) {
case NORTH_KEY:
do {
if (cur_pos - icon_w < 0)
cur_pos = icon_w * icon_h - (icon_w - cur_pos % icon_w);
else
cur_pos -= icon_w;
} while (cur_pos >= num_icons);
break;
case SOUTH_KEY:
do {
cur_pos = (cur_pos + icon_w) % (icon_w * icon_h);
} while (cur_pos >= num_icons);
break;
case WEST_KEY:
do {
if (cur_pos % icon_w == 0)
cur_pos = (cur_pos / icon_w) * icon_w + icon_w - 1;
else
cur_pos--;
} while (cur_pos >= num_icons);
break;
case EAST_KEY:
do {
cur_pos = (cur_pos / icon_w) * icon_w + (cur_pos + 1) % icon_w;
} while (cur_pos >= num_icons);
break;
case DO_ACTION_KEY:
if (cur_pos < num_icons) {
hit((sint8)cur_pos);
keybinder->set_enable_joy_repeat(true);
Hide();
}
break;
case CANCEL_ACTION_KEY:
case NEW_COMMAND_BAR_KEY:
keybinder->set_enable_joy_repeat(true);
Hide();
break;
default :
keybinder->handle_always_available_keys(a);
break;
}
return GUI_YUM;
}
void CommandBarNewUI::Display(bool full_redraw) {
Screen *scr = game->get_screen();
//if(full_redraw || update_display)
// {
update_display = false;
if (game->get_game_type() == NUVIE_GAME_U6) {
//scr->fill(bg_color, area.left, area.top, area.width(), area.height());
if (!game->is_orig_style()) {
//display_information();
string infostring(game->get_clock()->get_date_string());
infostring += " Wind:";
infostring += wind;
font->drawString(scr, infostring.c_str(), area.left - 13, area.top); // sort of center
}
}
uint8 i = 0;
for (uint8 y = 0; y < icon_h; y++) {
for (uint8 x = 0; x < icon_w && i < num_icons; x++, i++) {
scr->blit(area.left + x * btn_size, icon_y_offset + area.top + y * btn_size, icon[i]->data, 8, 16, 16, 16);
if (i == cur_pos) {
scr->stipple_8bit(SELECTED_COLOR, area.left + x * btn_size, icon_y_offset + area.top + y * btn_size, 16, 16);
}
}
}
if (game->get_game_type() == NUVIE_GAME_U6) { // FIXME use new icon instead
font->drawString(scr, "QS", area.left + 2 + btn_size, icon_y_offset + area.top + 2 * btn_size + 4);
font->drawString(scr, "QL", area.left + 2 + 2 * btn_size, icon_y_offset + area.top + 2 * btn_size + 4);
}
font->drawString(scr, get_command_name(cur_pos), area.left, area.top + icon_y_offset + icon_h * btn_size);
if (game->get_game_type() == NUVIE_GAME_U6 && !game->is_orig_style())
scr->update(area.left - 13, area.top, area.width() + 26, area.height()); // need to have edges of text update
else
scr->update(area.left, area.top, area.width(), area.height());
// }
}
const char *CommandBarNewUI::get_command_name(sint8 command_num) const {
if (command_num < 0 || command_num >= num_icons)
return "";
return mode_name_tbl[command_num];
}
/*
void CommandBarNewUI::display_information()
{
string infostring(game->get_clock()->get_date_string());
infostring += " Wind:";
infostring += wind;
text->drawString(screen, infostring.c_str(), area.left + 8, area.top, 0);
}
*/
} // End of namespace Nuvie
} // End of namespace Ultima

View File

@@ -0,0 +1,66 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef NUVIE_CORE_COMMAND_BAR_NEW_UI_H
#define NUVIE_CORE_COMMAND_BAR_NEW_UI_H
#include "ultima/shared/std/string.h"
#include "ultima/nuvie/gui/widgets/gui_widget.h"
#include "ultima/nuvie/misc/call_back.h"
#include "ultima/nuvie/gui/widgets/command_bar.h"
namespace Ultima {
namespace Nuvie {
class NuvieIO;
class Events;
class Game;
class GUI_Button;
class GUI_CallBack;
class Text;
class Font;
class CommandBarNewUI: public CommandBar {
protected:
uint8 cur_pos;
uint8 icon_w;
uint8 icon_h;
uint8 icon_y_offset;
uint16 num_icons;
Font *font;
public:
CommandBarNewUI(Game *g);
~CommandBarNewUI() override;
void Display(bool full_redraw) override;
GUI_status KeyDown(const Common::KeyState &key) override;
GUI_status MouseDown(int x, int y, Events::MouseButton button) override;
GUI_status MouseUp(int x, int y, Events::MouseButton button) override;
private:
const char *get_command_name(sint8 command_num) const;
};
} // End of namespace Nuvie
} // End of namespace Ultima
#endif

View File

@@ -0,0 +1,129 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "ultima/shared/std/string.h"
#include "ultima/nuvie/core/nuvie_defs.h"
#include "ultima/nuvie/misc/u6_misc.h"
#include "ultima/nuvie/gui/gui.h"
#include "ultima/nuvie/gui/widgets/console.h"
namespace Ultima {
namespace Nuvie {
static Console *g_console = nullptr;
Console::Console(const Configuration *c, Screen *s, GUI *g, uint16 x, uint16 y, uint16 w, uint16 h)
: GUI_Console(x, y, w, h), config(c), screen(s), gui(g), displayConsole(true) {
config->value("config/general/show_console", displayConsole, true);
if (displayConsole == false)
Hide();
gui->AddWidget(this);
}
Console::~Console() {
}
void Console::AddLine(const Std::string &line) {
GUI_Console::AddLine(line);
if (status == WIDGET_VISIBLE) {
gui->Display();
screen->performUpdate();
}
}
void ConsoleInit(const Configuration *c, Screen *s, GUI *gui, uint16 w, uint16 h) {
assert(g_console == nullptr);
//uint16 x_off = config_get_video_x_offset(c);
//uint16 y_off = config_get_video_y_offset(c);
g_console = new Console(c, s, gui, 0, 0, s->get_width(), s->get_height());//x_off, y_off, w, h);
}
void ConsoleDelete() {
if (g_console != nullptr) {
g_console->Delete();
g_console = nullptr;
}
}
void ConsoleAddInfo(const char *format, ...) {
char buf[1024];
memset(buf, 0, 1024);
va_list args;
va_start(args, format);
vsnprintf(buf, 1024, format, args);
va_end(args);
if (g_console != nullptr) {
DEBUG(0, LEVEL_INFORMATIONAL, "%s\n", buf);
g_console->AddLine(buf);
}
}
void ConsoleAddError(const Std::string &s) {
if (g_console != nullptr) {
DEBUG(0, LEVEL_ERROR, "%s\n", s.c_str());
g_console->Show();
g_console->AddLine("Error: " + s);
}
}
void ConsoleAddWarning(const Std::string &s) {
if (g_console != nullptr) {
DEBUG(0, LEVEL_WARNING, "%s\n", s.c_str());
g_console->AddLine("Warning: " + s);
}
}
void ConsolePause() {
if (g_console == nullptr)
return;
//pause here.
Common::Event event;
bool waiting = true;
for (; waiting;) {
while (!Events::get()->pollEvent(event)) {
if (event.type == Common::EVENT_KEYDOWN || event.type == Common::EVENT_QUIT) {
waiting = false;
break;
}
}
}
}
void ConsoleShow() {
if (g_console)
g_console->Show();
}
void ConsoleHide() {
if (g_console)
g_console->Hide();
}
} // End of namespace Nuvie
} // End of namespace Ultima

View File

@@ -0,0 +1,60 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef NUVIE_CORE_CONSOLE_H
#define NUVIE_CORE_CONSOLE_H
#include "ultima/nuvie/gui/gui_console.h"
#include "ultima/nuvie/screen/screen.h"
#include "ultima/nuvie/conf/configuration.h"
namespace Ultima {
namespace Nuvie {
class Console : public GUI_Console {
protected:
GUI *gui;
Screen *screen;
const Configuration *config;
bool displayConsole;
public:
Console(const Configuration *c, Screen *s, GUI *g, uint16 x, uint16 y, uint16 w, uint16 h);
~Console() override;
void AddLine(const Std::string &line) override;
};
void ConsoleInit(const Configuration *c, Screen *s, GUI *gui, uint16 w, uint16 h);
void ConsoleDelete();
void ConsoleAddInfo(const char *s, ...);
void ConsoleAddError(const Std::string &s);
void ConsoleAddWarning(const Std::string &s);
void ConsolePause();
void ConsoleShow();
void ConsoleHide();
} // End of namespace Nuvie
} // End of namespace Ultima
#endif

View File

@@ -0,0 +1,757 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "ultima/shared/std/string.h"
#include "ultima/nuvie/core/nuvie_defs.h"
#include "ultima/nuvie/conf/configuration.h"
#include "ultima/nuvie/misc/u6_misc.h"
#include "ultima/nuvie/fonts/font_manager.h"
#include "ultima/nuvie/fonts/font.h"
#include "ultima/nuvie/screen/game_palette.h"
#include "ultima/nuvie/gui/gui.h"
#include "ultima/nuvie/gui/widgets/msg_scroll.h"
#include "ultima/nuvie/portraits/portrait.h"
#include "ultima/nuvie/core/player.h"
#include "ultima/nuvie/gui/widgets/converse_gump.h"
#include "ultima/nuvie/actors/actor_manager.h"
#include "ultima/nuvie/actors/actor.h"
#include "ultima/nuvie/keybinding/keys.h"
namespace Ultima {
namespace Nuvie {
static const int CURSOR_COLOR = 248;
// ConverseGump Class
ConverseGump::ConverseGump(const Configuration *cfg, Font *f, Screen *s) {
// uint16 x, y;
init(cfg, f);
Game *game = Game::get_game();
game_type = game->get_game_type();
scroll_width = 30;
scroll_height = 8;
// x = 8;
// y = 8;
int gump_h;
uint8 min_h, default_c;
Std::string height_str;
min_w = game->get_min_converse_gump_width();
uint16 x_off = game->get_game_x_offset();
uint16 y_off = game->get_game_y_offset();
int game_h = game->get_game_height();
if (game_type == NUVIE_GAME_SE) {
default_c = 216;
min_h = 185;
} else if (game_type == NUVIE_GAME_MD) {
default_c = 136;
min_h = 181;
} else {// U6
default_c = 218;
min_h = 152;
}
cfg->value(config_get_game_key(cfg) + "/converse_height", height_str, "default");
if (game->is_orig_style()) {
gump_h = game_h;
} else {
if (height_str == "default") {
if (game_h > min_h * 1.5) // big enough that we probably don't want to take up the whole screen
gump_h = min_h;
else
gump_h = game_h;
} else {
cfg->value(config_get_game_key(cfg) + "/converse_height", gump_h, game_h);
if (gump_h < min_h)
gump_h = min_h;
else if (gump_h > game_h)
gump_h = game_h;
}
}
GUI_Widget::Init(nullptr, x_off, y_off, game->get_converse_gump_width(), (uint16)gump_h);
npc_portrait = nullptr;
avatar_portrait = nullptr;
keyword_list = nullptr;
font = game->get_font_manager()->get_conv_font();
found_break_char = false;
cursor_wait = 0;
if (game->is_forcing_solid_converse_bg()) {
solid_bg = true;
force_solid_bg = true;
} else {
force_solid_bg = false;
cfg->value(config_get_game_key(config) + "/converse_solid_bg", solid_bg, false);
}
int c;
cfg->value(config_get_game_key(config) + "/converse_bg_color", c, default_c);
if (c < 256)
converse_bg_color = (uint8)c;
else
converse_bg_color = 0;
cursor_position = 0;
portrait_width = frame_w = game->get_portrait()->get_portrait_width();
portrait_height = frame_h = game->get_portrait()->get_portrait_height();
if (game_type == NUVIE_GAME_U6) {
frame_w = portrait_width + 8;
frame_h = portrait_height + 9;
}
//DEBUG(0, LEVEL_DEBUGGING, "\nMin w = %d\n", frame_w + 12 + 210);
}
ConverseGump::~ConverseGump() {
if (npc_portrait)
free(npc_portrait);
if (avatar_portrait)
free(avatar_portrait);
conv_keywords.clear();
permitted_input_keywords.clear();
}
void ConverseGump::set_talking(bool state, Actor *actor) {
if (state == true) {
Game::get_game()->get_keybinder()->set_enable_joy_repeat(false);
found_break_char = true;
conv_keywords.clear();
permitted_input_keywords.clear();
Show();
set_input_mode(false);
clear_scroll();
set_found_break_char(true);
bool altar = (game_type == NUVIE_GAME_U6 // Singularity is excluded on purpose
&& actor->get_actor_num() >= 192 && actor->get_actor_num() <= 199);
if (!altar) {
add_keyword("name");
add_keyword("job");
add_keyword("bye");
}
bool cant_join = (game_type == NUVIE_GAME_U6 // statues and altars
&& actor->get_actor_num() >= 189 && actor->get_actor_num() <= 200);
if (actor->is_in_party())
add_keyword("leave");
else if (!cant_join)
add_keyword("join");
if (game_type == NUVIE_GAME_U6 && !altar) {
add_keyword("rune");
add_keyword("mantra");
}
keyword_list = &conv_keywords;
if (avatar_portrait) {
free(avatar_portrait);
avatar_portrait = nullptr;
}
cursor_position = 0;
} else {
Game::get_game()->get_keybinder()->set_enable_joy_repeat(true);
}
MsgScroll::set_talking(state);
}
void ConverseGump::set_actor_portrait(Actor *a) {
if (npc_portrait)
free(npc_portrait);
if (Game::get_game()->get_portrait()->has_portrait(a))
npc_portrait = get_portrait_data(a);
else
npc_portrait = nullptr;
if (avatar_portrait == nullptr) {
Actor *p = Game::get_game()->get_player()->get_actor();
Actor *p1 = Game::get_game()->get_actor_manager()->get_actor(1);
avatar_portrait = get_portrait_data(p->get_actor_num() != 0 ? p : p1); // don't use portrait 0 when in a vehicle
}
}
unsigned char *ConverseGump::get_portrait_data(Actor *a) {
if (game_type == NUVIE_GAME_U6) {
return create_framed_portrait(a);
}
Portrait *p = Game::get_game()->get_portrait();
return p->get_portrait_data(a);
}
unsigned char *ConverseGump::create_framed_portrait(Actor *a) { //FIXME U6 specific.
//uint8 FRAME_W = portrait_width + 8;
uint16 i;
Portrait *p = Game::get_game()->get_portrait();
unsigned char *portrait_data = p->get_portrait_data(a);
unsigned char *framed_data = (unsigned char *)malloc(frame_w * frame_h);
memset(framed_data, 255, frame_w * frame_h);
memset(framed_data, 0, frame_w);
memset(framed_data + (frame_h - 1)*frame_w, 0, frame_w);
memset(framed_data + 1 * frame_w + 2, 53, 57);
memset(framed_data + 2 * frame_w + 2, 57, 59);
memset(framed_data + 3 * frame_w + 4, 0, 57);
//top left corner
framed_data[1 * frame_w] = 0;
framed_data[1 * frame_w + 1] = 138;
framed_data[2 * frame_w] = 0;
framed_data[2 * frame_w + 1] = 139;
framed_data[3 * frame_w] = 0;
framed_data[3 * frame_w + 1] = 139;
framed_data[3 * frame_w + 2] = 57;
framed_data[3 * frame_w + 3] = 143;
for (i = 0; i < portrait_height; i++) {
framed_data[(i + 4)*frame_w] = 0;
framed_data[(i + 4)*frame_w + 1] = 139;
framed_data[(i + 4)*frame_w + 2] = 57;
framed_data[(i + 4)*frame_w + 3] = 142;
memcpy(&framed_data[(i + 4)*frame_w + 4], &portrait_data[i * p->get_portrait_width()], portrait_width);
framed_data[(i + 4)*frame_w + 4 + portrait_width] = 0;
framed_data[(i + 4)*frame_w + 4 + portrait_width + 1] = 57;
framed_data[(i + 4)*frame_w + 4 + portrait_width + 2] = 53;
framed_data[(i + 4)*frame_w + 4 + portrait_width + 3] = 0;
}
memset(framed_data + (frame_h - 5)*frame_w + 3, 142, 57);
memset(framed_data + (frame_h - 4)*frame_w + 2, 57, 60);
memset(framed_data + (frame_h - 3)*frame_w + 1, 139, 61);
memset(framed_data + (frame_h - 2)*frame_w + 1, 142, 62);
//bottom left
framed_data[(frame_h - 5)*frame_w] = 0;
framed_data[(frame_h - 5)*frame_w + 1] = 139;
framed_data[(frame_h - 5)*frame_w + 2] = 57;
framed_data[(frame_h - 4)*frame_w] = 0;
framed_data[(frame_h - 4)*frame_w + 1] = 139;
framed_data[(frame_h - 3)*frame_w] = 0;
framed_data[(frame_h - 2)*frame_w] = 0;
//top right
framed_data[1 * frame_w + 59] = 50;
framed_data[1 * frame_w + 59 + 1] = 49;
framed_data[1 * frame_w + 59 + 2] = 49;
framed_data[1 * frame_w + 59 + 3] = 15;
framed_data[1 * frame_w + 59 + 4] = 0;
framed_data[2 * frame_w + 59 + 2] = 15;
framed_data[2 * frame_w + 59 + 3] = 49;
framed_data[2 * frame_w + 59 + 4] = 0;
framed_data[3 * frame_w + 59 + 2] = 57;
framed_data[3 * frame_w + 59 + 3] = 49;
framed_data[3 * frame_w + 59 + 4] = 0;
framed_data[4 * frame_w + 59 + 3] = 50;
//bottom right
framed_data[(frame_h - 5)*frame_w + 60] = 143;
framed_data[(frame_h - 5)*frame_w + 61] = 57;
framed_data[(frame_h - 5)*frame_w + 62] = 53;
framed_data[(frame_h - 5)*frame_w + 63] = 0;
framed_data[(frame_h - 4)*frame_w + 62] = 53;
framed_data[(frame_h - 4)*frame_w + 63] = 0;
framed_data[(frame_h - 3)*frame_w + 62] = 173;
framed_data[(frame_h - 3)*frame_w + 63] = 0;
framed_data[(frame_h - 2)*frame_w + 63] = 0;
free(portrait_data);
return framed_data;
}
void ConverseGump::set_permitted_input(const char *allowed) {
permitted_input_keywords.clear();
keyword_list = &permitted_input_keywords;
MsgScroll::set_permitted_input(allowed);
if (yes_no_only) {
add_keyword("yes");
add_keyword("no");
} else if (aye_nay_only) {
add_keyword("aye");
add_keyword("nay");
} else if (numbers_only) {
add_keyword("0");
add_keyword("1");
add_keyword("2");
add_keyword("3");
add_keyword("4");
add_keyword("5");
add_keyword("6");
add_keyword("7");
add_keyword("8");
add_keyword("9");
}
cursor_position = 0;
}
void ConverseGump::clear_permitted_input() {
keyword_list = &conv_keywords;
MsgScroll::clear_permitted_input();
}
/*
void ConverseGump::add_token(MsgText *token)
{
DEBUG(0,LEVEL_ALERT, "TOKEN: %s\n", token->s.c_str());
display_text.push_back(*token);
}
*/
void ConverseGump::display_string(const Std::string &s, Font *f, bool include_on_map_window) {
if (s.empty())
return;
MsgScroll::display_string(strip_whitespace_after_break(s), f, include_on_map_window);//, MSGSCROLL_NO_MAP_DISPLAY);
}
Std::string ConverseGump::strip_whitespace_after_break(Std::string s) {
Std::string::iterator iter;
for (iter = s.begin(); iter != s.end();) {
if (found_break_char == true) {
char c = *iter;
if (c == ' ' || c == '\t' || c == '\n' || c == '*') {
iter = s.erase(iter);
} else {
found_break_char = false;
iter++;
}
} else {
char c = *iter;
if (c == '*') {
found_break_char = true;
}
iter++;
}
}
return s;
}
bool ConverseGump::parse_token(MsgText *token) {
int at_idx = token->s.findFirstOf('@', 0);
int i = 0;
int len = (int)token->s.size();
while (at_idx != -1 && i < len) {
Std::string keyword = "";
for (i = at_idx + 1; i < len; i++) {
char c = token->s[i];
if (Common::isAlpha(c)) {
keyword.push_back(c);
}
if (!Common::isAlpha(c) || i == len - 1) {
token->s.erase(at_idx, 1);
i--;
at_idx = token->s.findFirstOf('@', i);
break;
}
}
DEBUG(0, LEVEL_WARNING, "%s", keyword.c_str());
add_keyword(keyword);
}
parse_fm_towns_token(token);
return MsgScroll::parse_token(token);
}
// Add FM-Towns keywords which take the form. +actor_numKeyword+ eg. +5runes+
// Only add keyword if the player has met the actor given by the actor_num
void ConverseGump::parse_fm_towns_token(MsgText *token) {
int at_idx = token->s.findFirstOf('+', 0);
int i = 0;
int len = (int)token->s.size();
bool has_met = false;
while (at_idx != -1 && i < len) {
i = at_idx + 1;
char c = token->s[i];
if (i < len && Common::isDigit(c)) {
const char *c_str = token->s.c_str();
uint16 actor_num = (int)strtol(&c_str[i], nullptr, 10);
if (actor_num < 256) {
Actor *actor = Game::get_game()->get_actor_manager()->get_actor(actor_num);
if (actor) {
has_met = actor->is_met();
}
}
for (; Common::isDigit(c_str[i]);)
i++;
}
Std::string keyword = "";
for (; i < len; i++) {
char ch = token->s[i];
if (Common::isAlpha(ch)) {
keyword.push_back(ch);
}
if (!Common::isAlpha(ch) || i == len - 1) {
token->s.erase(at_idx, (i - at_idx) + 1);
i -= i - at_idx;
at_idx = token->s.findFirstOf('+', i);
break;
}
}
DEBUG(0, LEVEL_WARNING, "%s", keyword.c_str());
if (has_met) { //only add keyword if the player has met the actor in question.
add_keyword(keyword);
has_met = false;
}
}
return;
}
void ConverseGump::add_keyword(const Std::string keyword_) {
string keyword = " *" + keyword_;
for (const MsgText &txt : *keyword_list) {
if (string_i_compare(txt.s, keyword)) {
return;
}
}
MsgText m_text;
m_text.s = keyword;
m_text.font = font;
keyword_list->push_back(m_text);
}
Std::string ConverseGump::get_token_string_at_pos(uint16 x, uint16 y) {
uint16 total_length = 0;
uint16 tmp_y = area.top + portrait_height + 8 + 3 + 4;
Std::list<MsgText>::iterator iter;
for (iter = keyword_list->begin(); iter != keyword_list->end(); iter++) {
MsgText t = *iter;
uint16 token_len = font->getStringWidth(t.s.c_str());
// if(token_len + total_length >= (26 * 8))
if (portrait_width / 2 + portrait_width + token_len + total_length + 8 >= min_w - 4) {
total_length = 0;
tmp_y += 10;
}
//t.font->drawString(screen, t.s.c_str(), area.left + portrait_width / 2 + portrait_width + 8 + total_length * 8, y + portrait_height + 8, 0);
if (x > area.left + portrait_width / 2 + portrait_width + 8 + total_length && x < area.left + portrait_width / 2 + portrait_width + 8 + total_length + token_len) {
if (y > tmp_y && y < tmp_y + 8) {
if (!is_permanent_keyword(t.s))
keyword_list->erase(iter);
return t.s;
}
}
total_length += token_len;
}
return "";
}
Std::string ConverseGump::get_token_at_cursor() {
uint16 i = 0;
Std::list<MsgText>::iterator iter;
for (iter = keyword_list->begin(); iter != keyword_list->end(); i++, iter++) {
if (i == cursor_position) {
Std::string keyword = (*iter).s;
if (!is_permanent_keyword(keyword)) {
keyword_list->erase(iter);
if (permit_input)
keyword = Std::string(keyword.at(2)); // only return first char after " *"
}
return keyword;
}
}
return "";
}
bool ConverseGump::input_buf_add_char(char c) {
input_char = 0;
if (permit_input != nullptr)
input_buf_remove_char();
input_buf.push_back(c);
return true;
}
bool ConverseGump::input_buf_remove_char() {
if (!input_buf.empty()) {
input_buf.deleteLastChar();
return true;
}
return false;
}
void ConverseGump::Display(bool full_redraw) {
uint16 total_length = 0;
uint16 y = area.top + portrait_height + 8 + 3;
if (converse_bg_color != 255 || force_solid_bg) {
if (solid_bg)
screen->fill(converse_bg_color, area.left, area.top, area.width(), area.height());
else
screen->stipple_8bit(converse_bg_color, area.left, area.top, area.width(), area.height());
}
bool use_transparency = (game_type == NUVIE_GAME_U6) ? false : true;
if (npc_portrait) {
screen->blit(area.left + 4, area.top + 4, npc_portrait, 8, frame_w, frame_h, frame_w, use_transparency);
}
if (!page_break && input_mode && avatar_portrait && is_talking()) {
screen->blit(area.left + portrait_width / 2 + 4, y, avatar_portrait, 8, frame_w, frame_h, frame_w, use_transparency);
sint16 i = 0;
for (const MsgText &t : *keyword_list) {
uint16 token_len = font->getStringWidth(t.s.c_str());
// if(token_len + total_length >= (26 * 8))
if (portrait_width / 2 + portrait_width + token_len + total_length + 8 >= min_w - 4) {
total_length = 0;
y += 10;
}
t.font->drawString(screen, t.s.c_str(), area.left + portrait_width / 2 + portrait_width + 8 + total_length, y + 4, 0, 0);
if (cursor_position == i) {
screen->fill(CURSOR_COLOR, area.left + portrait_width / 2 + portrait_width + 16 + total_length, y + 4 + 8, token_len - 8, 1);
}
total_length += token_len;
//total_length += t.s.size();
}
y += 16;
font->drawString(screen, " *", area.left + portrait_width / 2 + portrait_width + 8, y, 0, 0);
font->drawString(screen, input_buf.c_str(), area.left + portrait_width / 2 + portrait_width + 8 + font->getStringWidth(" *"), y, 0, 0);
drawCursor(area.left + portrait_width / 2 + portrait_width + 8 + font->getStringWidth(" *") + font->getStringWidth(input_buf.c_str()), y);
if (cursor_position == keyword_list->size()) {
screen->fill(CURSOR_COLOR, area.left + portrait_width / 2 + portrait_width + 16, y + 8, font->getStringWidth(input_buf.c_str()) + 8, 1);
}
}
y = area.top + 4;
total_length = 0;
for (const MsgLine *line : msg_buf) {
for (const MsgText *token : line->text) {
total_length += token->font->drawString(screen, token->s.c_str(), area.left + 4 + frame_w + 4 + total_length, y + 4, 0, 0); //FIX for hardcoded font height
//token->s.size();
//token->font->drawChar(screen, ' ', area.left + portrait_width + 8 + total_length * 8, y, 0);
//total_length += 1;
}
y += 10;
total_length = 0;
}
//font->drawString(screen, conv_str.c_str(), area.left, area.top);
screen->update(area.left, area.top, area.width(), area.height());
}
GUI_status ConverseGump::KeyDown(const Common::KeyState &keyState) {
Common::KeyState key = keyState;
char ascii = get_ascii_char_from_keysym(key);
if (page_break || !is_talking()) {
page_break = false;
just_finished_page_break = true;
if (!input_mode)
Game::get_game()->get_gui()->unlock_input();
if (!is_holding_buffer_empty() || !input_mode || !is_talking()) {
clear_scroll();
process_holding_buffer(); // Process any text in the holding buffer.
}
return GUI_YUM;
}
if (!input_mode || !Common::isPrint(ascii)) {
KeyBinder *keybinder = Game::get_game()->get_keybinder();
ActionType a = keybinder->get_ActionType(key);
switch (keybinder->GetActionKeyType(a)) {
case WEST_KEY:
key.keycode = Common::KEYCODE_LEFT;
break;
case EAST_KEY:
key.keycode = Common::KEYCODE_RIGHT;
break;
case SOUTH_KEY:
key.keycode = Common::KEYCODE_DOWN;
break;
case NORTH_KEY:
key.keycode = Common::KEYCODE_UP;
break;
case CANCEL_ACTION_KEY:
key.keycode = Common::KEYCODE_ESCAPE;
break;
case DO_ACTION_KEY:
key.keycode = Common::KEYCODE_RETURN;
break;
default:
if (keybinder->handle_always_available_keys(a)) return GUI_YUM;
break;
}
}
switch (key.keycode) {
case Common::KEYCODE_LEFT:
if (cursor_at_input_section() && input_char != 0)
input_char = 0;
else {
if (!cursor_at_input_section() || !input_buf_remove_char()) {
if (cursor_position == 0) {
cursor_position = keyword_list->size();
} else {
cursor_position--;
}
}
}
break;
case Common::KEYCODE_RIGHT:
if (cursor_at_input_section() && input_char != 0 && permit_input == nullptr)
input_buf_add_char(get_char_from_input_char());
else
cursor_position = (cursor_position + 1) % (keyword_list->size() + 1);
break;
case Common::KEYCODE_DOWN:
cursor_move_to_input();
increase_input_char();
break;
case Common::KEYCODE_UP:
cursor_move_to_input();
decrease_input_char();
break;
case Common::KEYCODE_ESCAPE:
if (permit_inputescape) {
// reset input buffer
permit_input = nullptr;
if (input_mode)
set_input_mode(false);
}
return GUI_YUM;
case Common::KEYCODE_KP_ENTER:
case Common::KEYCODE_RETURN:
if (permit_inputescape || !cursor_at_input_section()
|| input_char != 0) { // input_char should only be permit_input
if (!cursor_at_input_section())
input_add_string(get_token_at_cursor());
else {
if (input_char != 0)
input_buf_add_char(get_char_from_input_char());
}
//if(input_mode)
set_input_mode(false);
clear_scroll();
found_break_char = true; //strip leading whitespace.
cursor_reset();
}
return GUI_YUM;
case Common::KEYCODE_BACKSPACE :
if (input_mode)
input_buf_remove_char();
break;
default: // alphanumeric characters
if (input_mode && Common::isPrint(ascii)) {
cursor_move_to_input();
if (permit_input == nullptr) {
if (!numbers_only || Common::isDigit(ascii))
if (input_char != 0)
input_buf_add_char(get_char_from_input_char());
input_buf_add_char(ascii);
} else if (strchr(permit_input, ascii) || strchr(permit_input, tolower(ascii))) {
input_buf_add_char(toupper(ascii));
set_input_mode(false);
clear_scroll();
found_break_char = true;
}
}
break;
}
return GUI_YUM;
}
GUI_status ConverseGump::MouseUp(int x, int y, Events::MouseButton button) {
Std::string token_str;
if (page_break || !is_talking()) { // any click == scroll-to-end
page_break = false;
just_finished_page_break = true;
if (!input_mode)
Game::get_game()->get_gui()->unlock_input();
if (!is_holding_buffer_empty() || !input_mode || !is_talking()) {
clear_scroll();
process_holding_buffer(); // Process any text in the holding buffer.
}
return GUI_YUM;
} else if (button == 1) { // left click == select word
if (input_mode) {
token_str = get_token_string_at_pos(x, y);
if (!token_str.empty()) {
input_add_string(token_str);
set_input_mode(false);
clear_scroll();
found_break_char = true; //strip leading whitespace.
}
}
}
/*
else if(button == 3) // right click == send input
if(permit_inputescape && input_mode)
{
set_input_mode(false);
return(GUI_YUM);
}
*/
return GUI_YUM;
}
void ConverseGump::input_add_string(Std::string token_str) {
input_buf.clear();
for (uint16 i = 0; i < token_str.size(); i++) {
if (Common::isAlnum(token_str[i]) && (!permit_input || strchr(permit_input, token_str[i])
|| strchr(permit_input, tolower(token_str[i]))))
input_buf_add_char(token_str[i]);
}
}
bool ConverseGump::is_permanent_keyword(const Std::string &keyword) {
return (string_i_compare(keyword, " *buy") || string_i_compare(keyword, " *sell")
|| string_i_compare(keyword, " *bye") || string_i_compare(keyword, " *spells")
|| string_i_compare(keyword, " *reagents"));
}
void ConverseGump::drawCursor(uint16 x, uint16 y) {
if (input_char != 0) {
font->drawChar(screen, get_char_from_input_char(), x, y);
} else {
MsgScroll::drawCursor(x, y);
}
}
} // End of namespace Nuvie
} // End of namespace Ultima

View File

@@ -0,0 +1,156 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef NUVIE_CORE_CONVERSE_GUMP_H
#define NUVIE_CORE_CONVERSE_GUMP_H
#include "ultima/nuvie/misc/call_back.h"
#include "ultima/nuvie/gui/widgets/gui_widget.h"
#include "ultima/shared/std/containers.h"
#include "ultima/shared/std/string.h"
namespace Ultima {
namespace Nuvie {
using Std::list;
class Configuration;
class Font;
class MsgScroll;
class Actor;
class ConverseGump: public MsgScroll {
Std::list<MsgText> conv_keywords;
Std::list<MsgText> permitted_input_keywords;
Std::list<MsgText> *keyword_list;
unsigned char *npc_portrait;
unsigned char *avatar_portrait;
bool found_break_char;
bool solid_bg;
bool force_solid_bg;
uint8 converse_bg_color;
uint16 cursor_position;
uint8 portrait_width;
uint8 portrait_height;
uint8 frame_w;
uint8 frame_h;
uint16 min_w;
nuvie_game_t game_type;
public:
ConverseGump(const Configuration *cfg, Font *f, Screen *s);
~ConverseGump() override;
void set_actor_portrait(Actor *a);
unsigned char *create_framed_portrait(Actor *a);
bool parse_token(MsgText *token) override;
Std::string get_token_string_at_pos(uint16 x, uint16 y) override;
void display_string(const Std::string &s, Font *f, bool include_on_map_window) override;
void set_talking(bool state, Actor *actor = nullptr) override;
void set_font(uint8 font_type) override {}
//bool get_solid_bg() { return solid_bg; }
void set_solid_bg(bool val) {
solid_bg = val;
}
void Display(bool full_redraw) override;
GUI_status KeyDown(const Common::KeyState &key) override;
GUI_status MouseUp(int x, int y, Events::MouseButton button) override;
GUI_status MouseDown(int x, int y, Events::MouseButton button) override {
return GUI_YUM;
}
GUI_status MouseMotion(int x, int y, uint8 state) override {
return GUI_YUM;
}
GUI_status MouseEnter(uint8 state) override {
return GUI_YUM;
}
GUI_status MouseLeave(uint8 state) override {
return GUI_YUM;
}
GUI_status MouseClick(int x, int y, Events::MouseButton button) override {
return GUI_YUM;
}
GUI_status MouseDouble(int x, int y, Events::MouseButton button) override {
return GUI_YUM;
}
GUI_status MouseDelayed(int x, int y, Events::MouseButton button) override {
return GUI_YUM;
}
GUI_status MouseHeld(int x, int y, Events::MouseButton button) override {
return GUI_YUM;
}
void set_found_break_char(bool val) {
found_break_char = val;
}
bool input_buf_add_char(char c) override;
bool input_buf_remove_char() override;
bool is_converse_finished() override {
return (is_holding_buffer_empty() && msg_buf.size() == 1 && msg_buf.back()->total_length == 0);
}
void drawCursor(uint16 x, uint16 y) override;
protected:
Std::string strip_whitespace_after_break(Std::string s);
void add_keyword(Std::string keyword);
void set_permitted_input(const char *allowed) override;
void clear_permitted_input() override;
bool cursor_at_input_section() const {
return (keyword_list && cursor_position == keyword_list->size());
}
void cursor_reset() {
cursor_position = 0;
}
void cursor_move_to_input() {
cursor_position = keyword_list ? keyword_list->size() : 0;
}
void input_add_string(Std::string token_str);
Std::string get_token_at_cursor();
bool is_permanent_keyword(const Std::string &keyword);
void parse_fm_towns_token(MsgText *token);
private:
unsigned char *get_portrait_data(Actor *a);
};
} // End of namespace Nuvie
} // End of namespace Ultima
#endif

View File

@@ -0,0 +1,187 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "ultima/shared/std/string.h"
#include "ultima/nuvie/core/nuvie_defs.h"
#include "ultima/nuvie/conf/configuration.h"
#include "ultima/nuvie/misc/u6_misc.h"
#include "ultima/nuvie/fonts/font_manager.h"
#include "ultima/nuvie/fonts/font.h"
#include "ultima/nuvie/screen/game_palette.h"
#include "ultima/nuvie/gui/gui.h"
#include "ultima/nuvie/misc/sdl_compat.h"
#include "ultima/nuvie/gui/widgets/msg_scroll.h"
#include "ultima/nuvie/portraits/portrait.h"
#include "ultima/nuvie/core/player.h"
#include "ultima/nuvie/gui/widgets/converse_gump_wou.h"
#include "ultima/nuvie/actors/actor_manager.h"
#include "ultima/nuvie/keybinding/keys.h"
#include "ultima/nuvie/gui/widgets/map_window.h"
#include "ultima/nuvie/gui/widgets/background.h"
#include "ultima/nuvie/files/u6_shape.h"
#include "ultima/nuvie/files/nuvie_bmp_file.h"
#include "ultima/nuvie/views/view_manager.h"
#include "ultima/nuvie/views/md_sky_strip_widget.h"
namespace Ultima {
namespace Nuvie {
#define INPUT_FONT_COLOR 1
// ConverseGumpWOU Class
ConverseGumpWOU::ConverseGumpWOU(const Configuration *cfg, Font *f, Screen *s)
: found_break_char(false), frame_h(0), frame_w(0), min_w(0) {
// uint16 x, y;
init(cfg, f);
Game *game = Game::get_game();
game_type = game->get_game_type();
//scroll_width = 20;
//scroll_height = 18;
set_scroll_dimensions(18, 18);
Std::string height_str;
uint16 x_off = game->get_game_x_offset();
uint16 y_off = game->get_game_y_offset();
if (game_type == NUVIE_GAME_U6) {
GUI_Widget::Init(nullptr, x_off + 8, y_off + 8, 160, 160);
bg_color = converse_bg_color = 0x31; //17;
if (game->get_game_width() >= 335) {
Common::Path imagefile;
Common::Path datadir = GUI::get_gui()->get_data_dir();
build_path(datadir, "U6_WOU_Scroll_bg.bmp", imagefile);
NuvieBmpFile bmp;
bg_image = bmp.getSdlSurface32(imagefile);
} else
bg_image = nullptr;
} else { //MD and SE
bg_image = nullptr;
GUI_Widget::Init(nullptr, x_off + 8, y_off + 16, 160, 144);
bg_color = converse_bg_color = Game::get_game()->get_palette()->get_bg_color();
}
left_margin = 8;
add_new_line();
//DEBUG(0, LEVEL_DEBUGGING, "\nMin w = %d\n", frame_w + 12 + 210);
}
ConverseGumpWOU::~ConverseGumpWOU() {
if (bg_image)
delete bg_image;
}
void ConverseGumpWOU::set_talking(bool state, Actor *actor) {
if (state) {
found_break_char = true;
clear_scroll();
Show();
if (Game::get_game()->get_view_manager()->get_mdSkyWidget() && Game::get_game()->is_original_plus())
Game::get_game()->get_view_manager()->get_mdSkyWidget()->Show();
} else {
if (talking) {
MsgScroll::display_string("\nPress any key...*", MSGSCROLL_NO_MAP_DISPLAY);
} else {
if (Game::get_game()->get_view_manager()->get_mdSkyWidget() && Game::get_game()->is_original_plus())
Game::get_game()->get_view_manager()->get_mdSkyWidget()->Hide();
}
}
MsgScroll::set_talking(state);
}
void ConverseGumpWOU::process_page_break() {
page_break = false;
just_finished_page_break = true;
if (!input_mode)
Game::get_game()->get_gui()->unlock_input();
if (!input_mode) {
//clear_scroll();
process_holding_buffer(); // Process any text in the holding buffer.
}
}
void ConverseGumpWOU::display_converse_prompt() {
MsgScroll::display_string("\nyou say:", INPUT_FONT_COLOR, MSGSCROLL_NO_MAP_DISPLAY);
}
void ConverseGumpWOU::display_bg() {
Game *game = Game::get_game();
U6Shape *background = game->get_background()->get_bg_shape();
unsigned char *ptr = background->get_data();
uint16 bg_w = game->get_background()->get_bg_w();
uint16 x_off = game->get_game_x_offset();
uint16 y_off = game->get_game_y_offset();
uint16 game_w = game->get_game_width();
if (game_type == NUVIE_GAME_U6) {
if (game_w >= 335) { // get right size
Common::Rect dst;
dst.left = x_off;
dst.top = y_off;
dst.setWidth(176);
dst.setHeight(176);
SDL_BlitSurface(bg_image, nullptr, game->get_screen()->get_sdl_surface(), &dst);
screen->update(x_off, y_off, 176, 176);
} else {
screen->blit(x_off, y_off, ptr, 8, 171, 200, bg_w, true); // main bg
if (game_w > 323) { // add filler to the right
ptr += 5;
screen->blit(x_off + 171, y_off, ptr, 8, game_w - 323, 200, bg_w, true);
screen->fill(game->get_palette()->get_bg_color(), x_off + 171, y_off + 8, game_w - 323, 184); // ovewrite center
screen->update(x_off, y_off, 171 + game_w - 323, 200);
} else
screen->update(x_off, y_off, 171, 200);
}
} else if (game_type == NUVIE_GAME_SE) {
ptr += bg_w + 1;
screen->fill(0, x_off + 172, y_off, 4, 1); // upper right corner
screen->blit(x_off + 1, y_off + 1, ptr, 8, 176, 173, bg_w, true); // main bg
// FIXME: will need to add time strip to top once it is coded
screen->update(x_off + 1, y_off, 177, 174);
} else { // MD
screen->fill(0, x_off, y_off, 176, 164); // background has transparent parts that should be black - also adding border to bottom
if (game_w == 321)
screen->fill(4, x_off + 176, y_off, 1, 1); // overwrite black pixel on top that looks bad
else if (game_w > 321) // add right border
screen->fill(0, x_off + 176, y_off, 1, 164);
screen->blit(x_off, y_off, ptr, 8, 176, 163, bg_w, true); // main bg
if (game->get_view_manager()->get_mdSkyWidget())
game->get_view_manager()->get_mdSkyWidget()->Display(true);
screen->update(x_off, y_off, 177, 164);
}
}
void ConverseGumpWOU::Display(bool full_redraw) {
if (Game::get_game()->is_original_plus())
display_bg(); // do first so that the text will be displayed on top
MsgScroll::Display(true);
if (game_type == NUVIE_GAME_U6) {
Game::get_game()->get_map_window()->drawBorder();
screen->update(area.left, area.top, area.width(), area.height());
}
}
} // End of namespace Nuvie
} // End of namespace Ultima

View File

@@ -0,0 +1,112 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef NUVIE_CORE_CONVERSE_GUMP_WOU_H
#define NUVIE_CORE_CONVERSE_GUMP_WOU_H
#include "ultima/nuvie/misc/call_back.h"
#include "ultima/nuvie/gui/widgets/gui_widget.h"
#include "ultima/nuvie/fonts/font.h"
#include "ultima/shared/std/containers.h"
#include "ultima/shared/std/string.h"
namespace Ultima {
namespace Nuvie {
using Std::list;
class Configuration;
class Font;
class MsgScroll;
class Actor;
class ConverseGumpWOU: public MsgScroll {
uint8 converse_bg_color;
uint8 frame_w;
uint8 frame_h;
uint16 min_w;
nuvie_game_t game_type;
bool found_break_char;
public:
ConverseGumpWOU(const Configuration *cfg, Font *f, Screen *s);
~ConverseGumpWOU() override;
void set_talking(bool state, Actor *actor = nullptr) override;
void set_font(uint8 font_type) override {}
void display_converse_prompt() override;
void Display(bool full_redraw) override;
GUI_status MouseUp(int x, int y, Events::MouseButton button) override {
return GUI_YUM;
}
GUI_status MouseDown(int x, int y, Events::MouseButton button) override {
return GUI_YUM;
}
GUI_status MouseMotion(int x, int y, uint8 state) override {
return GUI_YUM;
}
GUI_status MouseEnter(uint8 state) override {
return GUI_YUM;
}
GUI_status MouseLeave(uint8 state) override {
return GUI_YUM;
}
GUI_status MouseClick(int x, int y, Events::MouseButton button) override {
return GUI_YUM;
}
GUI_status MouseDouble(int x, int y, Events::MouseButton button) override {
return GUI_YUM;
}
GUI_status MouseDelayed(int x, int y, Events::MouseButton button) override {
return GUI_YUM;
}
GUI_status MouseHeld(int x, int y, Events::MouseButton button) override {
return GUI_YUM;
}
bool is_converse_finished() override {
return (is_holding_buffer_empty() && !page_break);
}
protected:
void input_add_string(Std::string token_str);
void process_page_break() override;
uint8 get_input_font_color() const override {
return FONT_COLOR_WOU_CONVERSE_INPUT;
}
void display_bg();
private:
Graphics::ManagedSurface *bg_image;
};
} // End of namespace Nuvie
} // End of namespace Ultima
#endif

View File

@@ -0,0 +1,69 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "ultima/nuvie/conf/configuration.h"
#include "ultima/nuvie/core/nuvie_defs.h"
#include "ultima/nuvie/misc/u6_misc.h"
#include "ultima/nuvie/core/game.h"
#include "ultima/nuvie/screen/screen.h"
#include "ultima/nuvie/fonts/font_manager.h"
#include "ultima/nuvie/fonts/font.h"
#include "ultima/nuvie/gui/widgets/fps_counter.h"
namespace Ultima {
namespace Nuvie {
using Std::string;
FpsCounter::FpsCounter(Game *g) : GUI_Widget(nullptr) {
game = g;
font = game->get_font_manager()->get_conv_font();
uint16 x_off = game->get_game_x_offset();
uint16 y_off = game->get_game_y_offset();
Init(nullptr, x_off + 280, y_off, 40, 10);
Common::strcpy_s(fps_string, "000.00");
}
FpsCounter::~FpsCounter() {
}
void FpsCounter::setFps(float fps) {
snprintf(fps_string, sizeof(fps_string), "%3.02f", fps);
}
void FpsCounter::Display(bool full_redraw) {
Screen *scr = game->get_screen();
// if(full_redraw || update_display || game->is_new_style())
{
// update_display = false;
scr->fill(0, area.left, area.top, area.width(), area.height());
font->drawString(scr, fps_string, area.left, area.top);
scr->update(area.left, area.top, area.width(), area.height());
}
}
} // End of namespace Nuvie
} // End of namespace Ultima

View File

@@ -0,0 +1,57 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef NUVIE_CORE_FPS_COUNTER_H
#define NUVIE_CORE_FPS_COUNTER_H
#include "ultima/nuvie/gui/widgets/gui_widget.h"
#include "ultima/nuvie/fonts/font.h"
namespace Ultima {
namespace Nuvie {
class Game;
class FpsCounter: public GUI_Widget {
protected:
Game *game;
Font *font;
char fps_string[7]; // "000.00\0"
public:
FpsCounter(Game *g);
~FpsCounter() override;
void setFps(float fps);
void Display(bool full_redraw) override;
void update() {
update_display = true;
}
};
} // End of namespace Nuvie
} // End of namespace Ultima
#endif

View File

@@ -0,0 +1,578 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "ultima/nuvie/core/nuvie_defs.h"
#include "ultima/nuvie/gui/gui.h"
#include "ultima/nuvie/gui/widgets/gui_widget.h"
namespace Ultima {
namespace Nuvie {
/* Widget constructors */
GUI_Widget::GUI_Widget(void *data) {
Init(data, 0, 0, 0, 0);
}
GUI_Widget::GUI_Widget(void *data, int x, int y, int w, int h) {
Init(data, x, y, w, h);
}
GUI_Widget::~GUI_Widget() {
for (; !children.empty();) {
GUI_Widget *child = children.front();
children.pop_front();
delete child;
}
return;
}
void GUI_Widget::Init(void *data, int x, int y, int w, int h) {
focused = false;
gui_drag_manager = nullptr; //set from placeOnScreen method
widget_data = data;
screen = nullptr;
surface = nullptr;
SetRect(0, 0, w, h);
offset_x = x;
offset_y = y;
Show();
errorptr = nullptr;
for (int n = 0; n < 3; ++n) {
pressed[n] = 0;
}
parent = nullptr;
update_display = true;
set_accept_mouseclick(false); // initializes mouseclick time; SB-X
delayed_button = Events::BUTTON_NONE; // optional mouseclick-delay; SB-X
held_button = Events::BUTTON_NONE; // optional mousedown-delay; SB-X
mouse_moved = false;
int mx = 0, my = 0;
if (screen)
screen->get_mouse_location(&mx, &my);
mouse_over = HitRect(mx, my);
}
int GUI_Widget::AddWidget(GUI_Widget *widget) {
children.push_back(widget);
widget->setParent(this);
return 0; //success.
}
/* Mark the widget as visible -- this is the default state */
void GUI_Widget::Show(void) {
status = WIDGET_VISIBLE;
}
/* Mark the widget as hidden; no display, no events */
void GUI_Widget::Hide(void) {
if (has_focus()) {
release_focus();
}
status = WIDGET_HIDDEN;
}
/* Mark the widget as free, so it will be deleted by the GUI */
void GUI_Widget::Delete(void) {
status = WIDGET_DELETED;
}
void GUI_Widget::MoveRelative(int dx, int dy) {
area.translate(dx, dy);
for (GUI_Widget *child : children)
child->MoveRelative(dx, dy);
return;
}
void GUI_Widget::Move(int32 new_x, int32 new_y) {
area.moveTo(new_x + offset_x, new_y + offset_y);
for (GUI_Widget *child : children)
child->Move(area.left, area.top);
return;
}
void GUI_Widget::MoveRelativeToParent(int dx, int dy) {
area.left = (area.left - offset_x) + dx;
area.top = (area.top - offset_y) + dy;
offset_x = dx;
offset_y = dy;
for (GUI_Widget *child : children)
child->Move(area.left, area.top);
return;
}
void GUI_Widget::grab_focus() {
if (GUI::get_gui()->set_focus(this))
focused = true;
}
void GUI_Widget::release_focus() {
GUI::get_gui()->clear_focus();
focused = false;
}
void GUI_Widget::moveToFront() {
GUI *gui = GUI::get_gui();
if (gui) {
gui->removeWidget(this);
gui->AddWidget(this);
}
}
void GUI_Widget::PlaceOnScreen(Screen *s, GUI_DragManager *dm, int x, int y) {
if (screen != nullptr)
return;
area.moveTo(x + offset_x, y + offset_y);
gui_drag_manager = dm;
SetDisplay(s);
/* place our children relative to ourself */
for (GUI_Widget *child : children)
child->PlaceOnScreen(screen, dm, area.left, area.top);
return;
}
/* Report status to GUI */
WIDGET_status GUI_Widget::Status(void) const {
return status;
}
/* Set the bounds of the widget.
If 'w' or 'h' is -1, that parameter will not be changed.
*/
void GUI_Widget::SetRect(int x, int y, int w, int h) {
area = Common::Rect(x, y, x + w, y + h);
}
void GUI_Widget::SetRect(Common::Rect **bounds) {
int minx, maxx;
int miny, maxy;
int i, v;
maxx = 0;
maxy = 0;
for (i = 0; bounds[i]; ++i) {
v = (bounds[i]->right - 1);
if (maxx < v) {
maxx = v;
}
v = (bounds[i]->bottom - 1);
if (maxy < v) {
maxy = v;
}
}
minx = maxx;
miny = maxy;
for (i = 0; bounds[i]; ++i) {
v = bounds[i]->left;
if (minx > v) {
minx = v;
}
v = bounds[i]->top;
if (miny > v) {
miny = v;
}
}
SetRect(minx, miny, (maxx - minx + 1), (maxy - miny + 1));
}
/* Check to see if a point intersects the bounds of the widget.
*/
int GUI_Widget::HitRect(int x, int y) {
return HitRect(x, y, area);
}
int GUI_Widget::HitRect(int x, int y, const Common::Rect &rect) {
int hit;
hit = 1;
if ((x < rect.left) || (x >= rect.right) ||
(y < rect.top) || (y >= rect.bottom)) {
hit = 0;
}
return hit;
}
/* Set the display surface for this widget */
void GUI_Widget::SetDisplay(Screen *s) {
screen = s;
surface = screen->get_sdl_surface();
}
void GUI_Widget::setParent(GUI_Widget *widget) {
parent = widget;
}
/* Show the widget.
If the surface needs to be locked, it will be locked
before this call, and unlocked after it returns.
****************NO, NOT AT ALL IF I'M NOT TOO DUMB TO LOOK******
******OTHERWISE YOU COULDN'T FILLRECT in Display(), ETC!!!! ***********
*/
void GUI_Widget::Display(bool full_redraw) {
DisplayChildren(full_redraw);
}
void GUI_Widget::DisplayChildren(bool full_redraw) {
if (update_display)
full_redraw = true;
if (children.empty() == false) {
/* display our children */
for (GUI_Widget *child : children) {
if (child->Status() == WIDGET_VISIBLE)
child->Display(full_redraw);
}
}
return;
}
/* Redraw the widget and only the widget */
void GUI_Widget::Redraw(void) {
if (status == WIDGET_VISIBLE) {
update_display = true;
if (parent != nullptr)
parent->Redraw();
//Display();
//SDL_UpdateRects(screen,1,&area);
}
}
/* GUI idle function -- run when no events pending */
// Idle and HandleEvent produce delayed clicks. Don't override if using those. -- SB-X
GUI_status GUI_Widget::Idle(void) {
if (children.empty() == false) {
/* idle our children */
for (GUI_Widget *child : children) {
GUI_status idleStatus = child->Idle();
if (idleStatus != GUI_PASS)
return idleStatus;
}
}
if (delayed_button != 0 || held_button != 0)
return try_mouse_delayed();
return GUI_PASS;
}
/* Widget event handlers.
These functions should return a status telling the GUI whether
or not the event should be passed on to other widgets.
These are called by the default HandleEvent function.
*/
GUI_status GUI_Widget::KeyDown(const Common::KeyState &key) {
return GUI_PASS;
}
GUI_status GUI_Widget::KeyUp(Common::KeyState key) {
return GUI_PASS;
}
GUI_status GUI_Widget::MouseDown(int x, int y, Events::MouseButton button) {
return GUI_PASS;
}
GUI_status GUI_Widget::MouseUp(int x, int y, Events::MouseButton button) {
return GUI_PASS;
}
GUI_status GUI_Widget::MouseMotion(int x, int y, uint8 state) {
return GUI_PASS;
}
GUI_status GUI_Widget::MouseWheel(sint32 x, sint32 y) {
return GUI_PASS;
}
/* Main event handler function.
This function gets raw SDL events from the GUI.
*/
// Idle and HandleEvent produce delayed clicks. Don't override if using those. -- SB-X
GUI_status GUI_Widget::HandleEvent(const Common::Event *event) {
if (status == WIDGET_HIDDEN) //we don't care for events if we are hidden.
return GUI_PASS;
if (children.empty() == false) {
/* handle our children */
for (GUI_Widget *child : children) {
GUI_status status_ = child->HandleEvent(event);
if (status_ != GUI_PASS)
return status_;
}
}
if (delayed_button != 0 || held_button != 0) {
GUI_status status_ = try_mouse_delayed();
if (status_ != GUI_PASS)
return status_;
}
switch (event->type) {
case Common::EVENT_KEYDOWN:
return KeyDown(event->kbd.keycode);
break;
case Common::EVENT_KEYUP:
return KeyUp(event->kbd.keycode);
break;
case Common::EVENT_LBUTTONDOWN:
case Common::EVENT_RBUTTONDOWN:
case Common::EVENT_MBUTTONDOWN: {
int x, y;
Events::MouseButton button;
x = event->mouse.x;
y = event->mouse.y;
button = Events::whichButton(event->type);
if (focused || HitRect(x, y)) {
set_mousedown(SDL_GetTicks(), button);
return(MouseDown(x, y, button));
}
break;
}
case Common::EVENT_LBUTTONUP:
case Common::EVENT_RBUTTONUP:
case Common::EVENT_MBUTTONUP: {
int x, y;
Events::MouseButton button;
x = event->mouse.x;
y = event->mouse.y;
button = Events::whichButton(event->type);
if (focused || HitRect(x, y)) {
int rel_time = SDL_GetTicks();
int last_rel_time = get_mouseup(button);
bool do_mouseclick = get_mousedown(button);
set_mouseup(rel_time, button);
if (do_mouseclick && accept_mouseclick[button - 1] && (rel_time - last_rel_time < GUI::mouseclick_delay)) {
// before a Double or Delayed click, mouseup_time is reset so another click isn't possible
set_mouseup(0, button);
return MouseDouble(x, y, button);
} else if (do_mouseclick && accept_mouseclick[button - 1])
return MouseClick(x, y, button);
else
return MouseUp(x, y, button);
}
/* if widget was clicked before we must let it deactivate itself*/
else if (ClickState(1)) {
set_mouseup(0, button);
return MouseUp(-1, -1, button);
}
break;
}
case Common::EVENT_MOUSEMOVE: {
int x, y;
uint8 state;
x = event->mouse.x;
y = event->mouse.y;
state = Events::get()->getButtonState();
if (state > 0) // mousemotion resets Click
mouse_moved = true;
if (focused || HitRect(x, y)) {
if (!mouse_over) {
mouse_over = true;
MouseEnter(state);
}
return MouseMotion(x, y, state);
} else {
if (mouse_over) {
mouse_over = false;
MouseLeave(state);
}
/* if widget was clicked before we must let it react*/
if (ClickState(1))
return MouseMotion(-1, -1, state);
}
}
break;
case Common::EVENT_WHEELUP:
return MouseWheel(0, 1);
case Common::EVENT_WHEELDOWN:
return MouseWheel(0, -1);
default: {
/* Pass it along.. */;
}
break;
}
return GUI_PASS;
}
// iterate through children if present to hit the correct drag area.
bool GUI_Widget::drag_accept_drop(int x, int y, int message, void *data) {
if (children.empty() == false) {
for (GUI_Widget *child : children) {
if (child->HitRect(x, y)) {
if (child->drag_accept_drop(x, y, message, data))
return true;
}
}
}
GUI::get_gui()->force_full_redraw();
return false;
}
void GUI_Widget::drag_perform_drop(int x, int y, int message, void *data) {
if (children.empty() == false) {
for (GUI_Widget *child : children) {
if (child->HitRect(x, y)) {
child->drag_perform_drop(x, y, message, data);
break;
}
}
}
return;
}
/* Mouse button was pressed and released over the widget.
*/
GUI_status GUI_Widget::MouseClick(int x, int y, Events::MouseButton button) {
return GUI_PASS;
}
/* Mouse button was clicked twice over the widget, within a certain time period.
*/
GUI_status GUI_Widget::MouseDouble(int x, int y, Events::MouseButton button) {
return GUI_PASS;
}
/* Mouse cursor passed out of the widget area.
*/
GUI_status GUI_Widget::MouseEnter(uint8 state) {
return GUI_PASS;
}
/* Mouse cursor passed into the widget area.
*/
GUI_status GUI_Widget::MouseLeave(uint8 state) {
return GUI_PASS;
}
/* Returns false if any widget but this one is focused or locked.
*/
bool GUI_Widget::widget_has_focus() {
GUI_Widget *focused_widget = GUI::get_gui()->get_focused_widget();
GUI_Widget *locked_widget = GUI::get_gui()->get_locked_widget();
if (GUI::get_gui()->get_block_input())
return false;
if (locked_widget != nullptr && locked_widget != this)
return false;
if (focused_widget != nullptr && focused_widget != this)
return false;
return true;
}
// button 0 = all
void GUI_Widget::set_accept_mouseclick(bool set, int button) {
if (button <= 0)
accept_mouseclick[0] = accept_mouseclick[1] = accept_mouseclick[2] = set;
else if (button < 4)
accept_mouseclick[button - 1] = set;
set_mouseup(0, button);
set_mousedown(0, button);
}
// time 0 = reset; button 0 = all
// mousedown is always cleared
void GUI_Widget::set_mouseup(int set, int button) {
mouse_moved = false;
if (button <= 0) {
mouseup[0] = mouseup[1] = mouseup[2] = set;
mousedown[0] = mousedown[1] = mousedown[2] = 0;
} else if (button < 4) {
mouseup[button - 1] = set;
mousedown[button - 1] = 0;
}
}
// time 0 = reset; button 0 = all
// mouseup is not cleared because two mouseup times are compared for mouseclicks
void GUI_Widget::set_mousedown(int set, int button) {
if (button <= 0) {
// mouseup[0]=mouseup[1]=mouseup[2] = 0;
mousedown[0] = mousedown[1] = mousedown[2] = set;
} else if (button < 4) {
// mouseup[button-1] = 0;
mousedown[button - 1] = set;
}
}
// check to see if time has passed for a MouseDelayed or MouseHeld
GUI_status GUI_Widget::try_mouse_delayed() {
int mousedown_time = get_mousedown(held_button);
int mouseup_time = get_mouseup(delayed_button);
int time_to_hold = SDL_GetTicks() - mousedown_time;
int time_to_click = SDL_GetTicks() - mouseup_time;
if (mousedown_time != 0 && time_to_hold >= GUI::mouseclick_delay) {
Events::MouseButton button = held_button;
int x, y; // position isn't saved anywhere so we get it here
screen->get_mouse_location(&x, &y); // hopefully it hasn't changed since MouseDown
held_button = Events::BUTTON_NONE; // no need to clear mousedown time, MouseUp does that
return (MouseHeld(x, y, button));
}
if (mouseup_time != 0 && time_to_click >= GUI::mouseclick_delay) {
Events::MouseButton button = delayed_button;
int x, y; // position isn't saved anywhere so we get it here
screen->get_mouse_location(&x, &y); // hopefully it hasn't changed since MouseClick/MouseUp
delayed_button = Events::BUTTON_NONE;
// before a Double or Delayed click, mouseup time is reset
set_mouseup(0, button);
return (MouseDelayed(x, y, button));
}
return GUI_PASS;
}
// like a MouseClick but called only after waiting for MouseDouble, if
// wait_for_mouseclick(button) was called
GUI_status GUI_Widget::MouseDelayed(int x, int y, Events::MouseButton button) {
return GUI_PASS;
}
// like a MouseDown but called only after waiting for MouseUp, if
// wait_for_mousedown(button) was called
GUI_status GUI_Widget::MouseHeld(int x, int y, Events::MouseButton button) {
return GUI_PASS;
}
} // End of namespace Nuvie
} // End of namespace Ultima

View File

@@ -0,0 +1,251 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
/* Base class for all widgets -- the GUI operates on this class */
#ifndef NUVIE_GUI_GUI_WIDGET_H
#define NUVIE_GUI_GUI_WIDGET_H
#include "ultima/nuvie/gui/gui_status.h"
#include "ultima/nuvie/gui/gui_drag_area.h"
#include "ultima/nuvie/gui/gui_drag_manager.h"
#include "ultima/nuvie/screen/screen.h"
#include "ultima/nuvie/core/events.h"
namespace Ultima {
namespace Nuvie {
typedef GUI_status(*GUI_CallbackProc)(void *data);
class GUI_Widget : public GUI_DragArea {
protected:
/* A generic pointer to user-specified data for the widget.
*/
void *widget_data;
Screen *screen;
/* The display surface for the widget */
Graphics::ManagedSurface *surface;
int offset_x, offset_y; /* original offsets to parent */
/* Flag -- whether or not the widget should be freed */
WIDGET_status status;
/* should we redraw this widget */
bool update_display;
/* the button states for theoretically 3 buttons */
int pressed[3];
bool focused;
Std::list<GUI_Widget *>children;
GUI_Widget *parent;
char *errorptr;
char errbuf[BUFSIZ];
GUI_DragManager *gui_drag_manager;
// SB-X
/* The time of the last mouse click (SDL_GetTicks()). */
unsigned int mouseup[3]; /* for 3 buttons */
unsigned int mousedown[3]; /* waiting for MouseUp */
bool accept_mouseclick[3]; /* which buttons can be [double]clicked */
Events::MouseButton delayed_button; /* a MouseClick can be delayed on one button; 0=none */
Events::MouseButton held_button; /* a MouseDown can be delayed on one button; 0=none */
bool mouse_moved; /* true if mouse moves while button is pressed */
bool mouse_over; // initialized here; toggled by GUI
public:
/* The area covered by the widget */
Common::Rect area;
GUI_Widget(void *data);
GUI_Widget(void *data, int x, int y, int w, int h);
~GUI_Widget() override;
int AddWidget(GUI_Widget *widget);
/* Mark the widget as visible -- this is the default state */
virtual void Show(void);
/* Mark the widget as hidden; no display, no events */
virtual void Hide(void);
/* Mark the widget as free, so it will be deleted by the GUI */
virtual void Delete(void);
virtual void MoveRelative(int dx, int dy);
virtual void Move(int32 new_x, int32 new_y);
void MoveRelativeToParent(int dx, int dy);
bool has_focus() const {
return focused;
}
void grab_focus();
virtual void release_focus();
void moveToFront();
virtual void PlaceOnScreen(Screen *s, GUI_DragManager *dm, int x, int y);
virtual WIDGET_status Status(void) const; /* Reports status to GUI */
/* Set the bounds of the widget.
If 'w' or 'h' is -1, that parameter will not be changed.
*/
virtual void SetRect(int x, int y, int w, int h);
virtual void SetRect(Common::Rect **bounds);
/* Return the whole area */
virtual Common::Rect GetRect() {
return area;
}
/* Return the bounds of the widget */
virtual int X() const {
return area.left;
}
virtual int Y() const {
return area.top;
}
virtual int W() const {
return area.width();
}
virtual int H() const {
return area.height();
}
/* Check to see if a point intersects the bounds of the widget.
*/
virtual int HitRect(int x, int y);
virtual int HitRect(int x, int y, const Common::Rect &rect);
/* Set the display surface for this widget */
virtual void SetDisplay(Screen *s);
/* Show the widget.
If the surface needs to be locked, it will be locked
before this call, and unlocked after it returns.
*/
virtual void Display(bool full_redraw = false);
void DisplayChildren(bool full_redraw = false);
/* Redraw the widget and only the widget */
virtual void Redraw(void);
/* should this widget be redrawn */
inline bool needs_redraw() const {
return update_display;
}
/* widget has focus or no widget is focused */
bool widget_has_focus(); // SB-X
/* GUI idle function -- run when no events pending */
virtual GUI_status Idle(void);
/* Widget event handlers.
These functions should return a status telling the GUI whether
or not the event should be passed on to other widgets.
These are called by the default HandleEvent function.
*/
virtual GUI_status KeyDown(const Common::KeyState &key);
virtual GUI_status KeyUp(Common::KeyState key);
virtual GUI_status MouseDown(int x, int y, Events::MouseButton button);
virtual GUI_status MouseUp(int x, int y, Events::MouseButton button);
virtual GUI_status MouseMotion(int x, int y, uint8 state);
virtual GUI_status MouseWheel(sint32 x, sint32 y);
// <SB-X>
virtual GUI_status MouseEnter(uint8 state);
virtual GUI_status MouseLeave(uint8 state);
virtual GUI_status MouseClick(int x, int y, Events::MouseButton button);
virtual GUI_status MouseDouble(int x, int y, Events::MouseButton button);
virtual GUI_status MouseDelayed(int x, int y, Events::MouseButton button);
virtual GUI_status MouseHeld(int x, int y, Events::MouseButton button);
// </SB-X>
bool drag_accept_drop(int x, int y, int message, void *data) override;
void drag_perform_drop(int x, int y, int message, void *data) override;
/* Main event handler function.
This function gets raw SDL events from the GUI.
*/
virtual GUI_status HandleEvent(const Common::Event *event);
/* Returns nullptr if everything is okay, or an error message if not */
char *Error(void) {
return errorptr;
}
/* yields click state: none, pressed, intermediate */
inline virtual int ClickState(int button) {
return pressed[button - 1];
}
/* set click state from remote */
inline virtual void SetClickState(int button, int value) {
if ((button > 0) && (button <= 3)) pressed[button - 1] = value;
}
protected:
/* The constructor, separated out for both access constructors */
void Init(void *data, int x, int y, int w, int h);
void setParent(GUI_Widget *widget);
/* Useful for getting error feedback */
void SetError(char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
Common::vsprintf_s(errbuf, fmt, ap);
va_end(ap);
errorptr = errbuf;
}
// SB-X
void set_accept_mouseclick(bool set, int button = 0);
void set_mouseup(int set, int button = 0);
void set_mousedown(int set, int button = 0);
int get_mouseup(int button) const {
if (button > 0 && button < 4) return (mouseup[button - 1]);
else return 0;
}
int get_mousedown(int button) const {
if (button > 0 && button < 4) return (mousedown[button - 1]);
else return 0;
}
void wait_for_mouseclick(int button) {
if (button >= Events::BUTTON_NONE && button < Events::BUTTON_MIDDLE)
delayed_button = (Events::MouseButton)button;
}
void wait_for_mousedown(int button) {
if (button >= Events::BUTTON_NONE && button <= Events::BUTTON_MIDDLE)
held_button = (Events::MouseButton)button;
}
virtual GUI_status try_mouse_delayed();
};
} // End of namespace Nuvie
} // End of namespace Ultima
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,383 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef NUVIE_CORE_MAP_WINDOW_H
#define NUVIE_CORE_MAP_WINDOW_H
#include "ultima/shared/std/containers.h"
#include "ultima/nuvie/core/nuvie_defs.h"
#include "ultima/nuvie/core/obj_manager.h"
#include "ultima/nuvie/gui/widgets/gui_widget.h"
#include "ultima/nuvie/core/map.h"
namespace Ultima {
namespace Nuvie {
class Configuration;
class TileManager;
class ActorManager;
class Actor;
class AnimManager;
class Map;
class MapCoord;
class Screen;
class CallBack;
class Game;
#define MAPWINDOW_THUMBNAIL_SIZE 52
#define MAPWINDOW_THUMBNAIL_SCALE 3
#define MAP_OVERLAY_DEFAULT 0 /* just below border */
#define MAP_OVERLAY_ONTOP 1 /* cover border */
#define MAPWINDOW_ROOFTILES_IMG_W 5
#define MAPWINDOW_ROOFTILES_IMG_H 204
typedef struct {
Tile *t;
uint16 x, y;
} TileInfo;
typedef struct {
Tile *eye_tile;
uint16 prev_x, prev_y;
uint16 moves_left;
CallBack *caller;
} WizardEye;
enum RoofDisplayType {ROOF_DISPLAY_OFF, ROOF_DISPLAY_NORMAL, ROOF_DISPLAY_FORCE_ON };
enum InterfaceType { INTERFACE_NORMAL, INTERFACE_FULLSCREEN, INTERFACE_IGNORE_BLOCK };
enum X_RayType { X_RAY_CHEAT_OFF = -1, X_RAY_OFF = 0, X_RAY_ON = 1, X_RAY_CHEAT_ON = 2};
enum CanDropOrMoveMsg { MSG_NOT_POSSIBLE, MSG_SUCCESS, MSG_BLOCKED, MSG_OUT_OF_RANGE, MSG_NO_TILE};
class MapWindow: public GUI_Widget {
friend class AnimManager;
friend class ConverseGumpWOU;
Game *game;
const Configuration *config;
int game_type;
bool enable_doubleclick;
bool walk_with_left_button;
uint8 walk_button_mask;
X_RayType x_ray_view;
InterfaceType interface;
bool custom_actor_tiles;
Map *map;
uint16 *tmp_map_buf; // tempory buffer for flood fill, hide rooms.
uint16 tmp_map_width, tmp_map_height;
Graphics::ManagedSurface *overlay; // used for visual effects
uint8 overlay_level; // where the overlay surface is placed
int min_brightness;
TileManager *tile_manager;
ObjManager *obj_manager;
ActorManager *actor_manager;
AnimManager *anim_manager;
sint16 cur_x, cur_y;
uint16 cursor_x, cursor_y, map_center_xoff;
sint16 mousecenter_x, mousecenter_y; // location mousecursor rotates around, relative to cur_x&cur_y
uint16 last_boundary_fill_x, last_boundary_fill_y; // start of boundary-fill in previous blacking update
Tile *cursor_tile;
Tile *use_tile;
bool show_cursor;
bool show_use_cursor;
bool show_grid;
unsigned char *thumbnail;
bool new_thumbnail;
uint16 win_width, win_height, border_width;
uint8 cur_level;
uint16 map_width;
uint8 cur_x_add, cur_y_add; // pixel offset from cur_x,cur_y (set by shiftMapRelative)
sint32 vel_x, vel_y; // velocity of automatic map movement (pixels per second)
Common::Rect clip_rect;
Graphics::ManagedSurface _mapWinSubSurf; // sub surface of the screen clipped to MapWindow's clip_rect
Obj *selected_obj;
Actor *look_actor;
Obj *look_obj;
bool hackmove;
bool walking;
bool look_on_left_click;
bool looking; // used to stop look_on_left_click from triggering during mouseup from left button walking, failed drag, or input mode
bool window_updated;
bool freeze_blacking_location;
bool enable_blacking;
bool roof_mode;
RoofDisplayType roof_display;
Graphics::ManagedSurface *roof_tiles;
WizardEye wizard_eye_info;
bool draw_brit_lens_anim;
bool draw_garg_lens_anim;
// Std::vector<TileInfo> m_ViewableObjTiles; // shouldn't need this for in_town checks
Std::vector<TileInfo> m_ViewableMapTiles;
bool lighting_update_required;
bool game_started;
public:
MapWindow(const Configuration *cfg, Map *m);
~MapWindow() override;
bool init(TileManager *tm, ObjManager *om, ActorManager *am);
sint16 get_cur_x() const {
return cur_x;
}
sint16 get_cur_y() const {
return cur_y;
}
bool set_windowSize(uint16 width, uint16 height);
void set_show_cursor(bool state);
void set_show_use_cursor(bool state);
void set_show_grid(bool state);
bool is_grid_showing() {
return show_grid;
}
void set_velocity(sint16 vx, sint16 vy) {
vel_x = vx;
vel_y = vy;
}
void set_overlay(Graphics::ManagedSurface *surfpt);
void set_overlay_level(int level = MAP_OVERLAY_DEFAULT) {
overlay_level = level;
}
void set_x_ray_view(X_RayType state, bool cheat_off = false);
X_RayType get_x_ray_view() {
return x_ray_view;
}
void set_freeze_blacking_location(bool state);
void set_enable_blacking(bool state);
void set_roof_mode(bool roofs);
void set_roof_display_mode(enum RoofDisplayType mode) {
roof_display = mode;
}
void set_walking(bool state);
void set_walk_button_mask();
bool will_walk_with_left_button() {
return walk_with_left_button;
}
void set_walk_with_left_button(bool val) {
walk_with_left_button = val;
set_walk_button_mask();
}
void set_looking(bool state) {
looking = state;
}
int get_min_brightness() {
return min_brightness;
}
void set_min_brightness(int brightness) {
min_brightness = brightness;
}
void moveLevel(uint8 new_level);
void moveMap(sint16 new_x, sint16 new_y, sint8 new_level, uint8 new_x_add = 0, uint8 new_y_add = 0);
void moveMapRelative(sint16 rel_x, sint16 rel_y);
void shiftMapRelative(sint16 rel_x, sint16 rel_y);
void set_mousecenter(sint16 new_x, sint16 new_y) {
mousecenter_x = new_x;
mousecenter_y = new_y;
}
void reset_mousecenter() {
mousecenter_x = win_width / 2;
mousecenter_y = win_height / 2;
}
uint16 get_win_area() {
return win_width * win_height;
}
void centerMapOnActor(Actor *actor);
void centerMap(uint16 x, uint16 y, uint8 z);
void centerCursor();
void moveCursor(sint16 new_x, sint16 new_y);
void moveCursorRelative(sint16 rel_x, sint16 rel_y);
bool is_doubleclick_enabled() {
return enable_doubleclick;
}
void set_enable_doubleclick(bool val) {
enable_doubleclick = val;
}
void set_look_on_left_click(bool val) {
look_on_left_click = val;
}
void set_use_left_clicks();
bool will_look_on_left_click() {
return look_on_left_click;
}
bool is_on_screen(uint16 x, uint16 y, uint8 z);
bool tile_is_black(uint16 x, uint16 y, const Obj *obj = nullptr) const; // subtracts cur_x and cur_y
const char *look(uint16 x, uint16 y, bool show_prefix = true);
const char *lookAtCursor(bool show_prefix = true) {
return (look(cursor_x, cursor_y, show_prefix));
}
Obj *get_objAtCursor(bool for_use = false);
Obj *get_objAtCoord(MapCoord coord, bool top_obj, bool include_ignored_objects, bool for_use = false);
Actor *get_actorAtCursor();
MapCoord get_cursorCoord();
Obj *get_objAtMousePos(int x, int y);
Actor *get_actorAtMousePos(int x, int y);
void teleport_to_cursor();
void select_target(int x, int y);
void mouseToWorldCoords(int mx, int my, int &wx, int &wy);
void get_movement_direction(uint16 mx, uint16 my, sint16 &rel_x, sint16 &rel_y, uint8 *mptr = nullptr);
TileManager *get_tile_manager() {
return tile_manager;
}
AnimManager *get_anim_manager() {
return anim_manager;
}
const Common::Rect *get_clip_rect() const {
return &clip_rect;
}
Graphics::ManagedSurface *get_overlay();
void get_level(uint8 *level) const;
void get_pos(uint16 *x, uint16 *y, uint8 *px = nullptr, uint8 *py = nullptr) const;
void get_velocity(sint16 *vx, sint16 *vy) const {
*vx = vel_x;
*vy = vel_y;
}
void get_windowSize(uint16 *width, uint16 *height) const;
bool in_window(uint16 x, uint16 y, uint8 z) const;
bool in_dungeon_level() const;
bool in_town() const;
// can put object at world location x,y?
CanDropOrMoveMsg can_drop_or_move_obj(uint16 x, uint16 y, Actor *actor, Obj *obj);
void display_can_drop_or_move_msg(CanDropOrMoveMsg msg, Std::string msg_text = "");
bool can_get_obj(const Actor *actor, Obj *obj);
bool blocked_by_wall(const Actor *actor, const Obj *obj);
MapCoord original_obj_loc;
void updateBlacking();
void updateAmbience();
void update();
void Display(bool full_redraw) override;
GUI_status MouseDown(int x, int y, Events::MouseButton button) override;
GUI_status MouseUp(int x, int y, Events::MouseButton button) override;
GUI_status MouseMotion(int x, int y, uint8 state) override;
GUI_status MouseDouble(int x, int y, Events::MouseButton button) override;
GUI_status MouseClick(int x, int y, Events::MouseButton button) override;
GUI_status Idle(void) override;
GUI_status MouseLeave(uint8 state) override;
GUI_status MouseDelayed(int x, int y, Events::MouseButton button) override;
GUI_status MouseHeld(int x, int y, Events::MouseButton button) override;
GUI_status KeyDown(const Common::KeyState &key) override;
GUI_status MouseWheel(sint32 x, sint32 y) override;
void drag_drop_success(int x, int y, int message, void *data) override;
void drag_drop_failed(int x, int y, int message, void *data) override;
bool drag_accept_drop(int x, int y, int message, void *data) override;
void drag_perform_drop(int x, int y, int message, void *data) override;
bool move_on_drop(Obj *obj);
void set_interface();
InterfaceType get_interface();
bool is_interface_fullscreen_in_combat();
void drag_draw(int x, int y, int message, void *data) override;
void update_mouse_cursor(uint32 mx, uint32 my);
unsigned char *make_thumbnail();
void free_thumbnail();
Graphics::ManagedSurface *get_sdl_surface();
Graphics::ManagedSurface *get_sdl_surface(uint16 x, uint16 y, uint16 w, uint16 h);
Graphics::ManagedSurface *get_roof_tiles() {
return roof_tiles;
}
Std::vector<const Obj *> m_ViewableObjects; //^^ dodgy public buffer
void wizard_eye_start(const MapCoord &location, uint16 duration, CallBack *caller);
bool using_map_tile_lighting;
protected:
void create_thumbnail();
void drawActors();
void drawAnims(bool top_anims);
void drawObjs();
void drawObjSuperBlock(bool draw_lowertiles, bool toptile);
inline void drawObj(const Obj *obj, bool draw_lowertiles, bool toptile);
inline void drawTile(const Tile *tile, uint16 x, uint16 y, bool toptile, bool use_tile_data = false);
inline void drawNewTile(const Tile *tile, uint16 x, uint16 y, bool toptile);
void drawBorder();
inline void drawTopTile(const Tile *tile, uint16 x, uint16 y, bool toptile);
inline void drawActor(const Actor *actor);
void drawRoofs();
void drawGrid();
void drawRain();
inline void drawLensAnim();
void updateLighting();
void generateTmpMap();
void boundaryFill(const byte *map_ptr, uint16 pitch, uint16 x, uint16 y);
bool floorTilesVisible();
bool boundaryLookThroughWindow(uint16 tile_num, uint16 x, uint16 y);
void reshapeBoundary();
inline bool tmpBufTileIsBlack(uint16 x, uint16 y) const;
bool tmpBufTileIsBoundary(uint16 x, uint16 y);
bool tmpBufTileIsWall(uint16 x, uint16 y, NuvieDir direction);
void wizard_eye_stop();
void wizard_eye_update();
bool is_wizard_eye_mode() {
if (wizard_eye_info.moves_left != 0) return true;
else return false;
}
void loadRoofTiles();
private:
void createLightOverlay();
void AddMapTileToVisibleList(uint16 tile_num, uint16 x, uint16 y);
bool can_display_obj(uint16 x, uint16 y, Obj *obj);
};
} // End of namespace Nuvie
} // End of namespace Ultima
#endif

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,304 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef NUVIE_CORE_MSG_SCROLL_H
#define NUVIE_CORE_MSG_SCROLL_H
#include "ultima/nuvie/misc/call_back.h"
#include "ultima/nuvie/gui/widgets/gui_widget.h"
#include "ultima/shared/std/containers.h"
#define MSGSCROLL_U6_WIDTH 17
#define MSGSCROLL_U6_HEIGHT 10
#define MSGSCROLL_MD_WIDTH 16
#define MSGSCROLL_MD_HEIGHT 8
#define MSGSCROLL_SE_WIDTH 16
#define MSGSCROLL_SE_HEIGHT 8
#define MSGSCROLL_CURSOR_DELAY 6 // used to slow down the animated cursor
#define MSGSCROLL_SCROLLBACK_HEIGHT 100
#define MSGSCROLL_NO_MAP_DISPLAY false
namespace Ultima {
namespace Nuvie {
using Std::list;
class Configuration;
class Font;
class Actor;
class MsgText {
public:
Font *font;
Std::string s;
uint8 color;
MsgText();
MsgText(const Std::string &new_string, Font *f);
~MsgText();
void append(const Std::string &new_string);
void copy(MsgText *msg_text);
uint32 length();
uint16 getDisplayWidth();
bool operator<(const MsgText &rhs) const {
return (s < rhs.s);
}
};
class MsgLine {
public:
Std::list<MsgText *> text;
uint32 total_length;
MsgLine() {
total_length = 0;
};
~MsgLine();
void append(MsgText *new_text);
void remove_char();
uint32 length();
MsgText *get_text_at_pos(uint16 pos);
uint16 get_display_width();
};
class MsgScroll: public GUI_Widget, public CallBack {
protected:
const Configuration *config;
int game_type;
Font *font;
uint8 font_color;
uint8 font_highlight_color;
uint16 scroll_height;
uint16 scroll_width;
uint8 left_margin; // margin width in pixels
// set by request_input()
CallBack *callback_target;
char *callback_user_data;
uint8 input_char;
bool input_mode;
const char *permit_input; // character list, or 0 = any string
bool yes_no_only, aye_nay_only, numbers_only; // limited input selection
bool page_break;
bool just_finished_page_break;
bool just_displayed_prompt;
virtual void process_page_break();
Std::list<MsgLine *> msg_buf;
Std::string input_buf;
bool permit_inputescape; // can RETURN or ESCAPE be used to escape input entry
uint16 cursor_wait;
uint16 scrollback_height;
bool discard_whitespace;
bool using_target_cursor;
uint8 bg_color;
bool talking;
private:
uint16 screen_x; //x offset to top left corner of MsgScroll
uint16 screen_y; //y offset to top left corner of MsgScroll
bool keyword_highlight;
MsgText prompt;
Std::list<MsgText *> holding_buffer;
bool show_cursor;
bool autobreak; // if true, a page break will be added when the scroll is full
bool scroll_updated;
uint8 cursor_char;
uint16 cursor_x, cursor_y;
uint16 line_count; // count the number of lines since last page break.
uint16 display_pos;
bool capitalise_next_letter;
public:
MsgScroll(const Configuration *cfg, Font *f);
MsgScroll() : GUI_Widget(nullptr, 0, 0, 0, 0),
config(nullptr), game_type(0), font(nullptr), scroll_height(0),
scroll_width(0), callback_target(nullptr), callback_user_data(nullptr),
input_mode(false), permit_input(nullptr), page_break(false),
just_finished_page_break(false), permit_inputescape(false),
cursor_wait(0), screen_x(0), screen_y(0), bg_color(0),
keyword_highlight(true), talking(false), show_cursor(false),
autobreak(false), scroll_updated(false), cursor_char(0),
cursor_x(0), cursor_y(0), line_count(0), display_pos(0),
capitalise_next_letter(false), just_displayed_prompt(false),
scrollback_height(MSGSCROLL_SCROLLBACK_HEIGHT), discard_whitespace(false),
left_margin(0), font_color(0), font_highlight_color(0), input_char(0),
yes_no_only(false), aye_nay_only(false), numbers_only(false),
using_target_cursor(false) {
}
~MsgScroll() override;
void init(const Configuration *cfg, Font *f);
bool init(const char *player_name);
void page_up();
void page_down();
virtual void move_scroll_down();
virtual void move_scroll_up();
void set_using_target_cursor(bool val) {
using_target_cursor = val;
}
void process_holding_buffer();
MsgText *holding_buffer_get_token();
bool is_holding_buffer_empty() const {
return holding_buffer.empty();
}
virtual bool can_display_prompt() const {
return !just_displayed_prompt;
}
virtual bool parse_token(MsgText *token);
void add_token(MsgText *token);
bool remove_char();
virtual void set_font(uint8 font_type);
virtual bool is_garg_font();
template<class... TParam>
int print(const Std::string &format, TParam... param);
virtual void display_string(const Std::string &s, Font *f, bool include_on_map_window);
void display_string(const Std::string &s, Font *f, uint8 color, bool include_on_map_window);
void display_string(const Std::string &s, uint16 length, uint8 lang_num);
void display_string(const Std::string &s, bool include_on_map_window = true);
void display_string(const Std::string &s, uint8 color, bool include_on_map_window);
void display_fmt_string(const char *format, ...);
void message(const char *string) {
display_string(string);
display_prompt();
}
bool set_prompt(const char *new_prompt, Font *f = nullptr);
virtual void display_prompt();
virtual void display_converse_prompt();
void set_keyword_highlight(bool state);
void set_input_mode(bool state, const char *allowed = nullptr,
bool can_escape = true, bool use_target_cursor = false,
bool set_numbers_only_to_true = false);
virtual void set_talking(bool state, Actor *actor = nullptr) {
talking = state;
input_char = 0;
}
bool is_talking() const {
return talking;
}
void set_show_cursor(bool state) {
show_cursor = state;
}
void set_autobreak(bool state) {
autobreak = state;
}
void set_discard_whitespace(bool discard) {
discard_whitespace = discard;
}
bool get_page_break() const {
return page_break;
}
GUI_status KeyDown(const Common::KeyState &key) override;
GUI_status MouseUp(int x, int y, Events::MouseButton button) override;
GUI_status MouseWheel(sint32 x, sint32 y) override;
virtual Std::string get_token_string_at_pos(uint16 x, uint16 y);
//void updateScroll();
void Display(bool full_redraw) override;
void clearCursor(uint16 x, uint16 y);
virtual void drawCursor(uint16 x, uint16 y);
void set_page_break();
virtual bool input_buf_add_char(char c);
virtual bool input_buf_remove_char();
/* Converse uses this to tell if the scroll has finished displaying the converse dialog */
virtual bool is_converse_finished() {
return true;
}
bool has_input();
Std::string get_input();
const char *peek_at_input();
void request_input(CallBack *caller, void *user_data);
void cancel_input_request() {
request_input(nullptr, nullptr);
}
void clear_scroll();
protected:
void set_scroll_dimensions(uint16 w, uint16 h);
void delete_front_line();
virtual MsgLine *add_new_line();
void drawLine(Screen *screen, MsgLine *msg_line, uint16 line_y);
inline void clear_page_break();
virtual void set_permitted_input(const char *allowed);
virtual void clear_permitted_input();
virtual bool can_fit_token_on_msgline(MsgLine *msg_line, MsgText *token);
void increase_input_char();
void decrease_input_char();
uint8 get_char_from_input_char();
virtual uint8 get_input_font_color() const {
return font_color;
}
private:
int print_internal(const Std::string *format, ...);
};
template<class... TParam>
inline int MsgScroll::print(const Std::string &format, TParam... param) {
return print_internal(&format, Common::forward<TParam>(param)...);
}
} // End of namespace Nuvie
} // End of namespace Ultima
#endif

View File

@@ -0,0 +1,297 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "ultima/shared/std/string.h"
#include "ultima/nuvie/core/nuvie_defs.h"
#include "ultima/nuvie/conf/configuration.h"
#include "ultima/nuvie/misc/u6_misc.h"
#include "ultima/nuvie/fonts/font_manager.h"
#include "ultima/nuvie/fonts/font.h"
#include "ultima/nuvie/screen/game_palette.h"
#include "ultima/nuvie/gui/gui.h"
#include "ultima/nuvie/gui/widgets/msg_scroll.h"
#include "ultima/nuvie/portraits/portrait.h"
#include "ultima/nuvie/core/player.h"
#include "ultima/nuvie/fonts/conv_font.h"
#include "ultima/nuvie/gui/widgets/msg_scroll_new_ui.h"
#include "ultima/nuvie/actors/actor_manager.h"
#include "ultima/nuvie/core/timed_event.h"
namespace Ultima {
namespace Nuvie {
// MsgScrollNewUI Class
MsgScrollNewUI::MsgScrollNewUI(const Configuration *cfg, Screen *s) {
drop_target = false; //we don't participate in drag and drop.
font_normal = Game::get_game()->get_font_manager()->get_conv_font();
font_garg = Game::get_game()->get_font_manager()->get_conv_garg_font();
init(cfg, font_normal);
Std::string new_scroll_cfg = config_get_game_key(config) + "/newscroll";
cfg->value(new_scroll_cfg + "/solid_bg", solid_bg, false);
int c;
if (Game::get_game()->get_game_type() == NUVIE_GAME_U6) {
bg_color = 218;
border_color = 220;
} else if (Game::get_game()->get_game_type() == NUVIE_GAME_SE) {
bg_color = 216;
border_color = 219;
} else { // MD
bg_color = 136;
border_color = 133;
}
cfg->value(new_scroll_cfg + "/bg_color", c, bg_color);
bg_color = clamp_max(c, 255);
cfg->value(new_scroll_cfg + "/border_color", c, border_color);
border_color = clamp_max(c, 255);
cfg->value(new_scroll_cfg + "/width", c, 18);
scroll_width = c;
cfg->value(new_scroll_cfg + "/height", c, 19);
scroll_height = clamp_max(c, scrollback_height);
uint16 x_off = Game::get_game()->get_game_x_offset();
uint16 y_off = Game::get_game()->get_game_y_offset();
// need to accept clicks on whole game area
GUI_Widget::Init(nullptr, x_off, y_off, Game::get_game()->get_game_width(), Game::get_game()->get_game_height());
cursor_wait = 0;
timer = nullptr;
position = 0;
}
MsgScrollNewUI::~MsgScrollNewUI() {
}
bool MsgScrollNewUI::can_fit_token_on_msgline(MsgLine *msg_line, MsgText *token) {
if (msg_line->get_display_width() + token->getDisplayWidth() > scroll_width * 7 - 8) {
return false; //token doesn't fit on the current line.
}
return true;
}
void MsgScrollNewUI::display_string(const Std::string &str, Font *f, bool include_on_map_window) {
if (str.empty())
return;
bool has_trailing_whitespace = (!trailing_whitespace.empty());
string s = trailing_whitespace + str;
trailing_whitespace.clear();
uint16 i, pos;
for (i = 0, pos = s.size(); pos >= 0; pos--, i++) {
char c = s[pos];
if (c != '\t' && c != '\n')
break;
}
if (i > 0) {
trailing_whitespace = s.substr(s.size() - i, i);
s = s.substr(0, s.size() - i);
}
if (!s.empty()) {
if (position > 0 && position == msg_buf.size()) {
if (!has_trailing_whitespace)
position--;
else {
position += count_empty_lines(s) - 1;
}
}
timer = new TimedCallback(this, nullptr, 2000);
MsgScroll::display_string(s, f, include_on_map_window);
}
}
uint16 MsgScrollNewUI::count_empty_lines(const Std::string &s) {
uint16 count = 0;
for (char c : s) {
if (c != ' ' && c != '\t' && c != '\n')
break;
if (c == '\n')
count++;
}
return count;
}
void MsgScrollNewUI::set_font(uint8 font_type) {
if (font_type == NUVIE_FONT_NORMAL) {
font = font_normal;
} else {
if (font_garg) {
font = font_garg;
}
}
}
bool MsgScrollNewUI::is_garg_font() {
return (font == font_garg);
}
uint16 MsgScrollNewUI::callback(uint16 msg, CallBack *caller, void *data) {
if (msg == CB_TIMED && (timer == nullptr || timer == caller)) {
timer = nullptr;
if (input_mode) {
new TimedCallback(this, nullptr, 100);
} else {
//roll up the message scroll so it's out of the way.
if (position < msg_buf.size()) {
if ((uint16)(position + 1) < msg_buf.size()
|| msg_buf.back()->total_length > 0) { //don't advance if on second last line and the last line is empty.
position++;
new TimedCallback(this, nullptr, 50);
}
}
}
}
return 1;
}
void MsgScrollNewUI::Display(bool full_redraw) {
MsgText *token;
uint16 y = area.top + 4;
uint16 total_length = 0;
Std::list<MsgLine *>::iterator iter;
iter = msg_buf.begin();
for (uint16 i = 0; i < position && iter != msg_buf.end(); i++)
iter++;
for (uint16 i = 0; i < scroll_height && iter != msg_buf.end(); i++, iter++) {
MsgLine *msg_line = *iter;
Std::list<MsgText *>::iterator iter1;
iter1 = msg_line->text.begin();
//if not last record or if last record is not an empty line.
if (i + position < ((int)msg_buf.size() - 1) || (iter1 != msg_line->text.end() && ((*iter)->total_length != 0))) {
if (bg_color != 255) {
if (solid_bg)
screen->fill(bg_color, area.left, y + (i == 0 ? -4 : 4), scroll_width * 7 + 8, (i == 0 ? 18 : 10));
else
screen->stipple_8bit(bg_color, area.left, y + (i == 0 ? -4 : 4), scroll_width * 7 + 8, (i == 0 ? 18 : 10));
}
if (border_color != 255) {
screen->fill(border_color, area.left, y + (i == 0 ? -4 : 4), 1, (i == 0 ? 18 : 10));
screen->fill(border_color, area.left + scroll_width * 7 + 7, y + (i == 0 ? -4 : 4), 1, (i == 0 ? 18 : 10));
}
for (total_length = 0; iter1 != msg_line->text.end() ; iter1++) {
token = *iter1;
total_length += token->font->drawString(screen, token->s.c_str(), area.left + 4 + 4 + total_length, y + 4, 0, 0); //FIX for hardcoded font height
}
y += 10;
}
}
if (input_char != 0)
font->drawChar(screen, get_char_from_input_char(), total_length + 8, y - 6);
if (border_color != 255 && y != area.top + 4) {
screen->fill(border_color, area.left, y + 4, scroll_width * 7 + 8, 1); //draw bottom border
}
/* Debug
char buf[10];
snprintf(buf, 10, "%d", position);
font_normal->drawString(screen, buf, 160, 10);
snprintf(buf, 10, "%d", (int)msg_buf.size());
font_normal->drawString(screen, buf, 160, 20);
*/
screen->update(area.left, area.top, scroll_width * 7 + 8, scroll_height * 10 + 8);
}
GUI_status MsgScrollNewUI::KeyDown(const Common::KeyState &key) {
MsgScrollEventType event = SCROLL_ESCAPE;
/*
switch(key.keycode)
{
case Common::KEYCODE_PAGEDOWN: if(input_mode) event = SCROLL_DOWN; break;
case Common::KEYCODE_PAGEUP: if(input_mode) event = SCROLL_UP; break;
default : break;
}
*/
if (scroll_movement_event(event) == GUI_YUM)
return GUI_YUM;
return MsgScroll::KeyDown(key);
}
GUI_status MsgScrollNewUI::MouseDown(int x, int y, Events::MouseButton button) {
MsgScrollEventType event = SCROLL_ESCAPE;
return scroll_movement_event(event);
}
GUI_status MsgScrollNewUI::scroll_movement_event(MsgScrollEventType event) {
switch (event) {
case SCROLL_UP :
if (position > 0) {
timer = new TimedCallback(this, nullptr, 2000);
position--;
grab_focus();
}
return GUI_YUM;
case SCROLL_DOWN :
timer = new TimedCallback(this, nullptr, 2000);
if (position < msg_buf.size())
position++;
return GUI_YUM;
default :
release_focus();
new TimedCallback(this, nullptr, 50);
break;
}
return GUI_PASS;
}
MsgLine *MsgScrollNewUI::add_new_line() {
MsgLine *line = MsgScroll::add_new_line();
if (position + scroll_height < (uint16)msg_buf.size()) {
position++;
} else if (position + scroll_height > scrollback_height) {
position--;
}
return line;
}
} // End of namespace Nuvie
} // End of namespace Ultima

View File

@@ -0,0 +1,109 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#ifndef NUVIE_CORE_MSG_SCROLL_NEW_UI_H
#define NUVIE_CORE_MSG_SCROLL_NEW_UI_H
#include "ultima/nuvie/misc/call_back.h"
#include "ultima/nuvie/gui/widgets/gui_widget.h"
#include "ultima/shared/std/containers.h"
#include "ultima/shared/std/string.h"
namespace Ultima {
namespace Nuvie {
using Std::list;
class Configuration;
class Font;
class MsgScroll;
class Actor;
class CallBack;
typedef enum {
SCROLL_UP,
SCROLL_DOWN,
SCROLL_ESCAPE
} MsgScrollEventType;
class MsgScrollNewUI: public MsgScroll {
CallBack *timer;
Font *font_normal;
Font *font_garg;
bool solid_bg;
uint8 bg_color;
uint8 border_color;
uint16 position;
Std::string trailing_whitespace;
public:
MsgScrollNewUI(const Configuration *cfg, Screen *s);
~MsgScrollNewUI() override;
GUI_status callback(uint16 msg, GUI_CallBack *caller, void *data) override {
return GUI_PASS;
}
uint16 callback(uint16 msg, CallBack *caller, void *data) override;
bool can_display_prompt() const override {
return false;
}
bool can_fit_token_on_msgline(MsgLine *msg_line, MsgText *token) override;
void Display(bool full_redraw) override;
void display_prompt() override {}
void display_string(const Std::string &s, Font *f, bool include_on_map_window) override;
void set_font(uint8 font_type) override;
bool is_garg_font() override;
GUI_status KeyDown(const Common::KeyState &key) override;
GUI_status MouseDown(int x, int y, Events::MouseButton button) override;
void move_scroll_down() override {
scroll_movement_event(SCROLL_DOWN);
}
void move_scroll_up() override {
scroll_movement_event(SCROLL_UP);
}
protected:
MsgLine *add_new_line() override;
private:
GUI_status scroll_movement_event(MsgScrollEventType event);
uint16 count_empty_lines(const Std::string &s);
};
} // End of namespace Nuvie
} // End of namespace Ultima
#endif