Initial commit
This commit is contained in:
540
engines/ultima/nuvie/views/spell_view.cpp
Normal file
540
engines/ultima/nuvie/views/spell_view.cpp
Normal file
@@ -0,0 +1,540 @@
|
||||
/* 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/screen/screen.h"
|
||||
#include "ultima/nuvie/misc/u6_llist.h"
|
||||
#include "ultima/nuvie/misc/u6_misc.h"
|
||||
#include "ultima/nuvie/files/u6_bmp.h"
|
||||
#include "ultima/nuvie/gui/gui.h"
|
||||
#include "ultima/nuvie/gui/gui_button.h"
|
||||
#include "ultima/nuvie/views/doll_widget.h"
|
||||
#include "ultima/nuvie/views/inventory_widget.h"
|
||||
#include "ultima/nuvie/views/spell_view.h"
|
||||
#include "ultima/nuvie/core/party.h"
|
||||
#include "ultima/nuvie/fonts/font.h"
|
||||
#include "ultima/nuvie/actors/actor.h"
|
||||
#include "ultima/nuvie/core/events.h"
|
||||
#include "ultima/nuvie/gui/widgets/map_window.h"
|
||||
#include "ultima/nuvie/gui/widgets/msg_scroll.h"
|
||||
#include "ultima/nuvie/usecode/usecode.h"
|
||||
#include "ultima/nuvie/views/view_manager.h"
|
||||
#include "ultima/nuvie/script/script.h"
|
||||
#include "ultima/nuvie/core/u6_objects.h"
|
||||
#include "ultima/nuvie/core/magic.h"
|
||||
#include "ultima/nuvie/keybinding/keys.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Nuvie {
|
||||
|
||||
static const char circle_num_tbl[][8] = {"1ST", "2ND", "3RD", "4TH", "5TH", "6TH", "7TH", "8TH"};
|
||||
static const int obj_n_reagent[8] = {OBJ_U6_MANDRAKE_ROOT, OBJ_U6_NIGHTSHADE, OBJ_U6_BLACK_PEARL, OBJ_U6_BLOOD_MOSS, OBJ_U6_SPIDER_SILK, OBJ_U6_GARLIC, OBJ_U6_GINSENG, OBJ_U6_SULFUROUS_ASH};
|
||||
|
||||
static const int NEWMAGIC_BMP_W = 144;
|
||||
static const int NEWMAGIC_BMP_H = 82;
|
||||
|
||||
SpellView::SpellView(const Configuration *cfg) : DraggableView(cfg), spell_container(nullptr),
|
||||
background(nullptr), level(1), all_spells_mode(false), spell_num(0),
|
||||
event_mode(false), num_spells_per_page(8), caster(nullptr) {
|
||||
}
|
||||
|
||||
SpellView::~SpellView() {
|
||||
if (background) {
|
||||
delete background;
|
||||
}
|
||||
}
|
||||
|
||||
bool SpellView::init(Screen *tmp_screen, void *view_manager, uint16 x, uint16 y, Font *f, Party *p, TileManager *tm, ObjManager *om) {
|
||||
View::init(x, y, f, p, tm, om);
|
||||
|
||||
SetRect(area.left, area.top, NEWMAGIC_BMP_W, NEWMAGIC_BMP_H + 16);
|
||||
Common::Path filename;
|
||||
|
||||
config_get_path(config, "newmagic.bmp", filename);
|
||||
background = new U6Bmp();
|
||||
if (background->load(filename) == false)
|
||||
return false;
|
||||
|
||||
add_command_icons(tmp_screen, view_manager);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void SpellView::PlaceOnScreen(Screen *s, GUI_DragManager *dm, int x, int y) {
|
||||
GUI_Widget::PlaceOnScreen(s, dm, x, y);
|
||||
}
|
||||
|
||||
void SpellView::set_spell_caster(Actor *actor, Obj *s_container, bool eventMode) {
|
||||
caster = actor;
|
||||
spell_container = s_container;
|
||||
event_mode = eventMode;
|
||||
|
||||
for (int shift = 0; shift < 8; shift++) {
|
||||
caster_reagents[shift] = caster->inventory_count_object(obj_n_reagent[shift]);
|
||||
}
|
||||
|
||||
level = (spell_container->quality / 16) + 1;
|
||||
spell_num = spell_container->quality - (16 * level);
|
||||
|
||||
|
||||
if (Game::get_game()->has_unlimited_casting() || spell_container->find_in_container(OBJ_U6_SPELL, MAGIC_ALL_SPELLS, OBJ_MATCH_QUALITY))
|
||||
all_spells_mode = true;
|
||||
else
|
||||
all_spells_mode = false;
|
||||
|
||||
fill_cur_spell_list();
|
||||
update_buttons();
|
||||
Game::get_game()->set_mouse_pointer(1); // crosshairs
|
||||
}
|
||||
|
||||
void SpellView::Display(bool full_redraw) {
|
||||
if (full_redraw || update_display) {
|
||||
screen->fill(bg_color, area.left, area.top + NEWMAGIC_BMP_H, area.width(), area.height() - NEWMAGIC_BMP_H);
|
||||
|
||||
screen->blit(area.left, area.top, background->get_data(), 8, NEWMAGIC_BMP_W, NEWMAGIC_BMP_H, NEWMAGIC_BMP_W, true);
|
||||
}
|
||||
|
||||
display_level_text();
|
||||
display_spell_list_text();
|
||||
|
||||
DisplayChildren(full_redraw);
|
||||
#if 1 // FIXME: This shouldn't need to be in the loop
|
||||
update_buttons(); // It doesn't seem to hurt speed though
|
||||
screen->update(area.left, area.top, area.width(), area.height());
|
||||
#else
|
||||
if (full_redraw || update_display) {
|
||||
update_display = false;
|
||||
screen->update(area.left, area.top, area.width(), area.height());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
uint8 SpellView::fill_cur_spell_list() {
|
||||
Magic *m = Game::get_game()->get_magic();
|
||||
int j = 0;
|
||||
for (int i = 0; i < 16; i++) {
|
||||
cur_spells[i] = -1;
|
||||
|
||||
if (m->get_spell((level - 1) * 16 + i) != nullptr && (all_spells_mode || spell_container->find_in_container(OBJ_U6_SPELL, (level - 1) * 16 + i, OBJ_MATCH_QUALITY)))
|
||||
cur_spells[j++] = (level - 1) * 16 + i;
|
||||
}
|
||||
|
||||
return j;
|
||||
}
|
||||
|
||||
sint8 SpellView::get_selected_index() const {
|
||||
for (uint8 i = 0; i < 16; i++) {
|
||||
if (cur_spells[i] == spell_container->quality) {
|
||||
return (sint8)i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
void SpellView::set_prev_level() {
|
||||
if (level == 1)
|
||||
return;
|
||||
|
||||
uint8 old_level = level;
|
||||
|
||||
|
||||
uint8 num_spells = 0;
|
||||
for (; num_spells == 0;) {
|
||||
level--;
|
||||
|
||||
if (level == 0)
|
||||
break;
|
||||
|
||||
num_spells = fill_cur_spell_list();
|
||||
}
|
||||
|
||||
if (num_spells == 0) {
|
||||
level = old_level;
|
||||
fill_cur_spell_list();
|
||||
}
|
||||
|
||||
if (num_spells > num_spells_per_page)
|
||||
spell_container->quality = cur_spells[num_spells_per_page];
|
||||
else {
|
||||
spell_container->quality = cur_spells[0];
|
||||
}
|
||||
}
|
||||
|
||||
void SpellView::set_next_level() {
|
||||
if (level == 8)
|
||||
return;
|
||||
|
||||
uint8 old_level = level;
|
||||
|
||||
|
||||
uint8 num_spells = 0;
|
||||
for (; num_spells == 0;) {
|
||||
level++;
|
||||
|
||||
if (level == 9)
|
||||
break;
|
||||
|
||||
num_spells = fill_cur_spell_list();
|
||||
}
|
||||
|
||||
if (num_spells == 0) {
|
||||
level = old_level;
|
||||
fill_cur_spell_list();
|
||||
} else
|
||||
spell_container->quality = cur_spells[0];
|
||||
}
|
||||
|
||||
void SpellView::move_left() {
|
||||
sint8 index = get_selected_index();
|
||||
if (index < 0)
|
||||
index = 0;
|
||||
|
||||
if (index >= num_spells_per_page) {
|
||||
spell_container->quality = cur_spells[0];
|
||||
} else {
|
||||
set_prev_level();
|
||||
}
|
||||
|
||||
update_buttons();
|
||||
update_display = true;
|
||||
}
|
||||
|
||||
void SpellView::move_right() {
|
||||
sint8 index = get_selected_index();
|
||||
if (index < 0)
|
||||
index = 0;
|
||||
|
||||
if (index >= num_spells_per_page || cur_spells[num_spells_per_page] == -1) {
|
||||
set_next_level();
|
||||
} else {
|
||||
spell_container->quality = cur_spells[num_spells_per_page];
|
||||
}
|
||||
|
||||
update_buttons();
|
||||
update_display = true;
|
||||
}
|
||||
|
||||
GUI_status SpellView::move_up() {
|
||||
sint8 index = get_selected_index();
|
||||
|
||||
if (index > 0 && index != num_spells_per_page) {
|
||||
spell_container->quality = cur_spells[index - 1];
|
||||
update_display = true;
|
||||
} else
|
||||
move_left();
|
||||
return GUI_YUM;
|
||||
}
|
||||
|
||||
GUI_status SpellView::move_down() {
|
||||
sint8 index = get_selected_index();
|
||||
|
||||
if (index != -1 && index < 15 && index != (num_spells_per_page - 1)) {
|
||||
if (cur_spells[index + 1] != -1) {
|
||||
spell_container->quality = cur_spells[index + 1];
|
||||
update_display = true;
|
||||
} else
|
||||
move_right();
|
||||
} else
|
||||
move_right();
|
||||
return GUI_YUM;
|
||||
}
|
||||
|
||||
void SpellView::display_level_text() {
|
||||
font->drawString(screen, circle_num_tbl[level - 1], area.left + 96 + 8, area.top + NEWMAGIC_BMP_H);
|
||||
font->drawString(screen, "level", area.left + 96, area.top + NEWMAGIC_BMP_H + 8);
|
||||
return;
|
||||
}
|
||||
|
||||
void SpellView::display_spell_list_text() {
|
||||
Magic *m = Game::get_game()->get_magic();
|
||||
|
||||
sint8 index = get_selected_index();
|
||||
|
||||
if (index >= num_spells_per_page)
|
||||
index = num_spells_per_page;
|
||||
else
|
||||
index = 0;
|
||||
|
||||
for (uint8 i = 0; i < num_spells_per_page; i++) {
|
||||
sint16 spellNum = cur_spells[i + index];
|
||||
if (spellNum != -1) {
|
||||
Spell *spell = m->get_spell((uint8)spellNum);
|
||||
|
||||
display_spell_text(spell, i, spell_container->quality);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SpellView::display_spell_text(Spell *spell, uint16 line_num, uint8 selected_spell) {
|
||||
line_num++;
|
||||
|
||||
font->drawString(screen, spell->name, area.left + 16, area.top + (line_num * 8));
|
||||
font->drawString(screen, Common::String::format("%d", get_available_spell_count(spell)).c_str(), area.left + NEWMAGIC_BMP_W - 24, area.top + (line_num * 8));
|
||||
|
||||
if (spell->num == selected_spell)
|
||||
font->drawChar(screen, 26, area.left + 8, area.top + (line_num * 8));
|
||||
}
|
||||
|
||||
uint16 SpellView::get_available_spell_count(const Spell *s) const {
|
||||
if (s->reagents == 0) // Help and Armageddon
|
||||
return 1;
|
||||
if (Game::get_game()->has_unlimited_casting())
|
||||
return 99;
|
||||
sint32 min_reagents = -1;
|
||||
for (int shift = 0; shift < 8; shift++) {
|
||||
if (1 << shift & s->reagents) {
|
||||
if (min_reagents == -1 || caster_reagents[shift] < min_reagents)
|
||||
min_reagents = caster_reagents[shift];
|
||||
}
|
||||
}
|
||||
|
||||
if (min_reagents == -1)
|
||||
min_reagents = 0;
|
||||
|
||||
return (uint16)min_reagents;
|
||||
}
|
||||
|
||||
void SpellView::add_command_icons(Screen *tmp_screen, void *view_manager) {
|
||||
Tile *tile;
|
||||
Graphics::ManagedSurface *button_image;
|
||||
Graphics::ManagedSurface *button_image2;
|
||||
|
||||
tile = tile_manager->get_tile(412); //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, 2 * 16, NEWMAGIC_BMP_H, button_image, button_image2, this);
|
||||
this->AddWidget(left_button);
|
||||
|
||||
tile = tile_manager->get_tile(413); //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, NEWMAGIC_BMP_H, button_image, button_image2, this);
|
||||
this->AddWidget(right_button);
|
||||
}
|
||||
|
||||
void SpellView::event_mode_select_spell() {
|
||||
sint16 spellNum = get_selected_spell();
|
||||
Game::get_game()->get_event()->select_spell_num(spellNum);
|
||||
release_focus();
|
||||
}
|
||||
|
||||
/* Move the cursor around
|
||||
*/
|
||||
GUI_status SpellView::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:
|
||||
return move_up();
|
||||
case SOUTH_KEY:
|
||||
return move_down();
|
||||
case WEST_KEY:
|
||||
case PREVIOUS_PARTY_MEMBER_KEY:
|
||||
move_left();
|
||||
break;
|
||||
case EAST_KEY:
|
||||
case NEXT_PARTY_MEMBER_KEY:
|
||||
move_right();
|
||||
break;
|
||||
case HOME_KEY:
|
||||
// TODO - add going to first viable page
|
||||
break;
|
||||
case END_KEY:
|
||||
// TODO - add going to last viable page
|
||||
break;
|
||||
case DO_ACTION_KEY:
|
||||
if (Game::get_game()->get_event()->is_looking_at_spellbook()) {
|
||||
show_spell_description();
|
||||
return GUI_YUM;
|
||||
}
|
||||
if (event_mode) {
|
||||
event_mode_select_spell();
|
||||
return GUI_YUM;
|
||||
}
|
||||
|
||||
return GUI_PASS;
|
||||
case CANCEL_ACTION_KEY:
|
||||
return cancel_spell();
|
||||
case TOGGLE_CURSOR_KEY :
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
return GUI_PASS;
|
||||
}
|
||||
return GUI_YUM;
|
||||
}
|
||||
|
||||
GUI_status SpellView::cancel_spell() {
|
||||
Events *event = Game::get_game()->get_event();
|
||||
if (event->is_looking_at_spellbook()) {
|
||||
close_look();
|
||||
return GUI_YUM;
|
||||
} else if (event_mode) {
|
||||
event->select_spell_num(-1);
|
||||
release_focus();
|
||||
return GUI_YUM;
|
||||
}
|
||||
event->set_mode(CAST_MODE);
|
||||
event->cancelAction();
|
||||
return GUI_YUM;
|
||||
}
|
||||
|
||||
GUI_status SpellView::MouseWheel(sint32 x, sint32 y) {
|
||||
if (y > 0)
|
||||
return move_up();
|
||||
if (y < 0)
|
||||
return move_down();
|
||||
|
||||
return GUI_YUM;
|
||||
}
|
||||
|
||||
GUI_status SpellView::MouseDown(int x, int y, Events::MouseButton button) {
|
||||
y -= area.top;
|
||||
x -= area.left;
|
||||
Events *event = Game::get_game()->get_event();
|
||||
bool selecting_spell_target, canceling_spell, doing_nothing;
|
||||
if (Game::get_game()->is_original_plus()) {
|
||||
if (Game::get_game()->is_original_plus_full_map())
|
||||
selecting_spell_target = (x < -7 || y > 194);
|
||||
else
|
||||
selecting_spell_target = (x < -7);
|
||||
canceling_spell = (x > 1 && (y > 101 || x > 137));
|
||||
doing_nothing = ((x > -8 && x < 16) || (x > -8 && (y < 8 || (y > 71 && y < 195))));
|
||||
} else {
|
||||
selecting_spell_target = (x < 0 && y > 0 && y < 162);
|
||||
canceling_spell = (x > 1 && (y > 101 || x > 137));
|
||||
doing_nothing = (y < 8 || y > 71 || x < 16 || x > 134);
|
||||
}
|
||||
|
||||
if (button == Events::BUTTON_RIGHT)
|
||||
return cancel_spell();
|
||||
|
||||
if (selecting_spell_target && !event_mode) { // cast selected spell on the map
|
||||
if (event->is_looking_at_spellbook()) {
|
||||
close_look();
|
||||
return GUI_YUM;
|
||||
}
|
||||
|
||||
event->target_spell();
|
||||
if (event->get_mode() == INPUT_MODE) {
|
||||
y += area.top;
|
||||
x += area.left;
|
||||
Game::get_game()->get_map_window()->select_target(x, y);
|
||||
}
|
||||
return GUI_YUM;
|
||||
}
|
||||
if (canceling_spell) // cancel spell
|
||||
return cancel_spell();
|
||||
if (doing_nothing) // do nothing
|
||||
return GUI_YUM;
|
||||
// selecting spell index
|
||||
|
||||
sint8 index = get_selected_index();
|
||||
|
||||
if (index >= num_spells_per_page)
|
||||
index = num_spells_per_page;
|
||||
else
|
||||
index = 0;
|
||||
y = (y / num_spells_per_page) - 1;
|
||||
//printf("x = %d, y = %d index=%d\n", x, y, index);
|
||||
|
||||
if (cur_spells[index + y] != -1) {
|
||||
spell_container->quality = cur_spells[index + y];
|
||||
update_display = true;
|
||||
if (event->is_looking_at_spellbook())
|
||||
show_spell_description();
|
||||
else if (event_mode)
|
||||
event_mode_select_spell();
|
||||
else
|
||||
Game::get_game()->get_event()->target_spell();
|
||||
}
|
||||
|
||||
return GUI_YUM;
|
||||
}
|
||||
|
||||
void SpellView::hide_buttons() {
|
||||
if (left_button) left_button->Hide();
|
||||
if (right_button) right_button->Hide();
|
||||
}
|
||||
|
||||
void SpellView::show_buttons() {
|
||||
if (left_button) left_button->Show();
|
||||
if (right_button) right_button->Show();
|
||||
}
|
||||
|
||||
void SpellView::update_buttons() {
|
||||
show_buttons();
|
||||
sint8 index = get_selected_index();
|
||||
|
||||
if (level == 1 && index <= (num_spells_per_page - 1) && left_button)
|
||||
left_button->Hide();
|
||||
|
||||
uint8 old_level = level;
|
||||
uint8 num_spells = 0;
|
||||
for (; num_spells == 0;) {
|
||||
level++;
|
||||
if (level == 9)
|
||||
break;
|
||||
num_spells = fill_cur_spell_list();
|
||||
}
|
||||
level = old_level;
|
||||
fill_cur_spell_list();
|
||||
|
||||
if (right_button && ((level < 8 && num_spells == 0) || level == 8)
|
||||
&& cur_spells[num_spells_per_page * (1 + index / num_spells_per_page)] == -1)
|
||||
right_button->Hide();
|
||||
}
|
||||
|
||||
void SpellView::close_look() {
|
||||
Game::get_game()->get_event()->set_looking_at_spellbook(false);
|
||||
Game::get_game()->get_scroll()->display_prompt();
|
||||
Game::get_game()->get_view_manager()->close_spell_mode();
|
||||
Game::get_game()->get_event()->endAction();
|
||||
}
|
||||
|
||||
void SpellView::show_spell_description() {
|
||||
if (get_selected_index() != -1) {
|
||||
sint16 index = get_selected_spell();
|
||||
if (index < 256 && index > -1)
|
||||
Game::get_game()->get_magic()->show_spell_description((uint8)index);
|
||||
}
|
||||
close_look();
|
||||
}
|
||||
|
||||
GUI_status SpellView::callback(uint16 msg, GUI_CallBack *caller, void *data) {
|
||||
|
||||
if (caller == left_button) {
|
||||
move_left();
|
||||
return GUI_YUM;
|
||||
} else if (caller == right_button) {
|
||||
move_right();
|
||||
return GUI_YUM;
|
||||
}
|
||||
|
||||
return GUI_PASS;
|
||||
}
|
||||
|
||||
} // End of namespace Nuvie
|
||||
} // End of namespace Ultima
|
||||
Reference in New Issue
Block a user