Files
2026-02-02 04:50:13 +01:00

347 lines
12 KiB
C++

/* 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_button.h"
#include "ultima/nuvie/script/script.h"
#include "ultima/nuvie/views/view.h"
#include "ultima/nuvie/actors/actor.h"
#include "ultima/nuvie/core/party.h"
#include "ultima/nuvie/portraits/portrait.h"
#include "ultima/nuvie/views/actor_view.h"
#include "ultima/nuvie/fonts/font.h"
#include "ultima/nuvie/core/player.h"
#include "ultima/nuvie/core/events.h"
#include "ultima/nuvie/keybinding/keys.h"
namespace Ultima {
namespace Nuvie {
extern GUI_status inventoryViewButtonCallback(void *data);
extern GUI_status partyViewButtonCallback(void *data);
#define MD Game::get_game()->get_game_type()==NUVIE_GAME_MD
ActorView::ActorView(const Configuration *cfg) : View(cfg), portrait(nullptr),
portrait_data(nullptr), in_party(false), cursor_tile(nullptr),
show_cursor(false) {
cursor_pos.x = 2;
cursor_pos.px = cursor_pos.py = 0;
}
ActorView::~ActorView() {
if (portrait_data != nullptr)
free(portrait_data);
}
bool ActorView::init(Screen *tmp_screen, void *view_manager, uint16 x, uint16 y, Font *f, Party *p, TileManager *tm, ObjManager *om, Portrait *port) {
if (Game::get_game()->get_game_type() == NUVIE_GAME_U6)
View::init(x, y, f, p, tm, om);
else
View::init(x, y - 2, f, p, tm, om);
portrait = port;
add_command_icons(tmp_screen, view_manager);
set_party_member(0);
cursor_tile = tile_manager->get_cursor_tile();
return true;
}
bool ActorView::set_party_member(uint8 party_member) {
in_party = false;
if (View::set_party_member(party_member)
&& !Game::get_game()->get_event()->using_control_cheat()) {
in_party = true;
if (party_button) party_button->Show();
} else {
if (left_button) left_button->Hide();
if (right_button) right_button->Hide();
if (party_button) party_button->Hide();
}
if (portrait) { // this might not be set yet. if called from View::init()
if (portrait_data)
free(portrait_data);
if (in_party)
portrait_data = portrait->get_portrait_data(party->get_actor(cur_party_member));
else {
Player *player = Game::get_game()->get_player();
portrait_data = portrait->get_portrait_data(player->get_actor());
}
if (portrait_data == nullptr)
return false;
}
return true;
}
void ActorView::Display(bool full_redraw) {
if (portrait_data != nullptr && (full_redraw || update_display || Game::get_game()->is_original_plus_full_map())) {
update_display = false;
if (MD) {
fill_md_background(bg_color, area);
screen->blit(area.left + 1, area.top + 16, portrait_data, 8, portrait->get_portrait_width(), portrait->get_portrait_height(), portrait->get_portrait_width(), true);
} else {
screen->fill(bg_color, area.left, area.top, area.width(), area.height());
screen->blit(area.left, area.top + 8, portrait_data, 8, portrait->get_portrait_width(), portrait->get_portrait_height(), portrait->get_portrait_width(), false);
}
display_name();
display_actor_stats();
DisplayChildren(); //draw buttons
screen->update(area.left, area.top, area.width(), area.height());
}
if (show_cursor && cursor_tile != nullptr) {
screen->blit(cursor_pos.px, cursor_pos.py, (unsigned char *)cursor_tile->data,
8, 16, 16, 16, true, nullptr);
screen->update(cursor_pos.px, cursor_pos.py, 16, 16);
}
}
void ActorView::add_command_icons(Screen *tmp_screen, void *view_manager) {
int x_off = 0; // U6 and MD
int y = 80; // U6
Tile *tile;
Graphics::ManagedSurface *button_image;
Graphics::ManagedSurface *button_image2;
if (Game::get_game()->get_game_type() == NUVIE_GAME_SE) {
x_off = 1;
y = 96;
} else if (MD)
y = 100;
//FIX need to handle clicked button image, check image free on destruct.
tile = tile_manager->get_tile(MD ? 282 : 387); //left arrow icon
button_image = tmp_screen->create_sdl_surface_from(tile->data, 8, 16, 16, 16);
button_image2 = tmp_screen->create_sdl_surface_from(tile->data, 8, 16, 16, 16);
left_button = new GUI_Button(this, x_off, y, button_image, button_image2, this);
this->AddWidget(left_button);
tile = tile_manager->get_tile(MD ? 279 : 384); //party view icon
button_image = tmp_screen->create_sdl_surface_from(tile->data, 8, 16, 16, 16);
button_image2 = tmp_screen->create_sdl_surface_from(tile->data, 8, 16, 16, 16);
party_button = new GUI_Button(view_manager, 16 + x_off, y, button_image, button_image2, this);
this->AddWidget(party_button);
tile = tile_manager->get_tile(MD ? 281 : 386); //inventory view icon
button_image = tmp_screen->create_sdl_surface_from(tile->data, 8, 16, 16, 16);
button_image2 = tmp_screen->create_sdl_surface_from(tile->data, 8, 16, 16, 16);
inventory_button = new GUI_Button(view_manager, 2 * 16 + x_off, y, button_image, button_image2, this);
this->AddWidget(inventory_button);
tile = tile_manager->get_tile(MD ? 283 : 388); //right arrow icon
button_image = tmp_screen->create_sdl_surface_from(tile->data, 8, 16, 16, 16);
button_image2 = tmp_screen->create_sdl_surface_from(tile->data, 8, 16, 16, 16);
right_button = new GUI_Button(this, 3 * 16 + x_off, y, button_image, button_image2, this);
this->AddWidget(right_button);
return;
}
void ActorView::display_name() {
const char *name;
int y_off = 0;
if (MD)
y_off = 4;
else if (Game::get_game()->get_game_type() == NUVIE_GAME_SE)
y_off = 1;
if (in_party)
name = party->get_actor_name(cur_party_member);
else
name = Game::get_game()->get_player()->get_actor()->get_name(true);
if (name == nullptr)
return;
font->drawString(screen, name, area.left + ((136) - strlen(name) * 8) / 2, area.top + y_off);
return;
}
void ActorView::display_actor_stats() {
Actor *actor;
char buf[10];
int x_off = 0;
int y_off = 0;
uint8 hp_text_color = 0; //standard text color
if (in_party)
actor = party->get_actor(cur_party_member);
else
actor = Game::get_game()->get_player()->get_actor();
if (MD) {
x_off = -1;
} else if (Game::get_game()->get_game_type() == NUVIE_GAME_SE) {
x_off = 2;
y_off = - 6;
}
hp_text_color = actor->get_hp_text_color();
Common::sprintf_s(buf, "%d", Game::get_game()->get_script()->call_actor_str_adj(actor)); //actor->get_strength());
uint8 str_len = font->drawString(screen, "STR:", area.left + 5 * 16 + x_off, area.top + y_off + 16);
font->drawString(screen, buf, area.left + 5 * 16 + x_off + str_len, area.top + y_off + 16, actor->get_str_text_color(), 0);
Common::sprintf_s(buf, "%d", Game::get_game()->get_script()->call_actor_dex_adj(actor));
str_len = font->drawString(screen, "DEX:", area.left + 5 * 16 + x_off, area.top + y_off + 16 + 8);
font->drawString(screen, buf, area.left + 5 * 16 + x_off + str_len, area.top + y_off + 16 + 8, actor->get_dex_text_color(), 0);
Common::sprintf_s(buf, "INT:%d", Game::get_game()->get_script()->call_actor_int_adj(actor));
font->drawString(screen, buf, area.left + 5 * 16 + x_off, area.top + y_off + 16 + 2 * 8);
if (MD || Game::get_game()->get_game_type() == NUVIE_GAME_SE) {
Common::sprintf_s(buf, "%3d", actor->get_hp());
str_len = font->drawString(screen, "HP:", area.left + 5 * 16 + x_off, area.top + y_off + 16 + 3 * 8);
font->drawString(screen, buf, strlen(buf), area.left + 5 * 16 + x_off + str_len, area.top + y_off + 16 + 3 * 8, hp_text_color, 0);
Common::sprintf_s(buf, "HM:%3d", actor->get_maxhp());
font->drawString(screen, buf, area.left + 5 * 16 + x_off, area.top + y_off + 16 + 4 * 8);
Common::sprintf_s(buf, "Lev:%2d", actor->get_level());
font->drawString(screen, buf, area.left + 5 * 16 + x_off, area.top + y_off + 16 + 5 * 8);
font->drawString(screen, "Exper:", area.left + 5 * 16 + x_off, area.top + y_off + 16 + 6 * 8);
Common::sprintf_s(buf, "%6d", actor->get_exp());
font->drawString(screen, buf, area.left + 5 * 16 + x_off, area.top + y_off + 16 + 7 * 8);
return;
}
font->drawString(screen, "Magic", area.left + 5 * 16, area.top + 16 + 4 * 8);
Common::sprintf_s(buf, "%d/%d", actor->get_magic(), actor->get_maxmagic());
font->drawString(screen, buf, area.left + 5 * 16, area.top + 16 + 5 * 8);
font->drawString(screen, "Health", area.left + 5 * 16, area.top + 16 + 6 * 8);
Common::sprintf_s(buf, "%3d", actor->get_hp());
font->drawString(screen, buf, strlen(buf), area.left + 5 * 16, area.top + 16 + 7 * 8, hp_text_color, 0);
Common::sprintf_s(buf, " /%d", actor->get_maxhp());
font->drawString(screen, buf, area.left + 5 * 16, area.top + 16 + 7 * 8);
font->drawString(screen, "Lev/Exp", area.left + 5 * 16, area.top + 16 + 8 * 8);
Common::sprintf_s(buf, "%d/%d", actor->get_level(), actor->get_exp());
font->drawString(screen, buf, area.left + 5 * 16, area.top + 16 + 9 * 8);
return;
}
GUI_status ActorView::MouseWheel(sint32 x, sint32 y) {
int xpos, ypos;
screen->get_mouse_location(&xpos, &ypos);
xpos -= area.left;
ypos -= area.top;
if (xpos < 0 || ypos > area.top + area.height() - 7)
return GUI_PASS; // goes to MsgScroll
if (y > 0) {
View::callback(BUTTON_CB, left_button, Game::get_game()->get_view_manager());
} else if (y < 0) {
View::callback(BUTTON_CB, right_button, Game::get_game()->get_view_manager());
}
return GUI_YUM;
}
GUI_status ActorView::MouseDown(int x, int y, Events::MouseButton button) {
return GUI_PASS;
}
/* Move the cursor around and use command icons.
*/
GUI_status ActorView::KeyDown(const Common::KeyState &key) {
if (!show_cursor) // FIXME: don't rely on show_cursor to get/pass focus
return GUI_PASS;
KeyBinder *keybinder = Game::get_game()->get_keybinder();
ActionType a = keybinder->get_ActionType(key);
switch (keybinder->GetActionKeyType(a)) {
case SOUTH_WEST_KEY:
case NORTH_WEST_KEY:
case WEST_KEY:
moveCursorToButton(cursor_pos.x - 1);
break;
case NORTH_EAST_KEY:
case SOUTH_EAST_KEY:
case EAST_KEY:
moveCursorToButton(cursor_pos.x + 1);
break;
case DO_ACTION_KEY:
select_button();
break;
case NORTH_KEY: // would otherwise move invisible mapwindow cursor
case SOUTH_KEY:
break;
default:
// set_show_cursor(false); // newAction() can move cursor here
return GUI_PASS;
}
return GUI_YUM;
}
/* Put cursor over one of the command icons. */
void ActorView::moveCursorToButton(sint8 button_num) {
if (button_num < 0 || button_num > 3)
return;
cursor_pos.x = button_num;
update_cursor();
update_display = true;
}
/* Update on-screen location (px,py) of cursor.
*/
void ActorView::update_cursor() {
cursor_pos.px = ((cursor_pos.x + 1) * 16) - 16;
cursor_pos.py = party_button->area.top;
cursor_pos.px += area.left;
//cursor_pos.py += area.top;
}
void ActorView::set_show_cursor(bool state) {
show_cursor = state;
update_display = true;
}
void ActorView::select_button() {
ViewManager *view_manager = Game::get_game()->get_view_manager();
if (cursor_pos.x == 0) // left
View::callback(BUTTON_CB, left_button, view_manager);
if (cursor_pos.x == 1) // party
View::callback(BUTTON_CB, party_button, view_manager);
if (cursor_pos.x == 2) // inventory
View::callback(BUTTON_CB, inventory_button, view_manager);
if (cursor_pos.x == 3) // right
View::callback(BUTTON_CB, right_button, view_manager);
}
} // End of namespace Nuvie
} // End of namespace Ultima