Initial commit
This commit is contained in:
314
engines/ultima/nuvie/usecode/usecode.cpp
Normal file
314
engines/ultima/nuvie/usecode/usecode.cpp
Normal file
@@ -0,0 +1,314 @@
|
||||
/* 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/misc/u6_llist.h"
|
||||
#include "ultima/nuvie/gui/widgets/msg_scroll.h"
|
||||
#include "ultima/nuvie/actors/actor_manager.h"
|
||||
#include "ultima/nuvie/actors/actor.h"
|
||||
#include "ultima/nuvie/usecode/usecode.h"
|
||||
#include "ultima/nuvie/gui/widgets/map_window.h"
|
||||
#include "ultima/nuvie/script/script.h"
|
||||
#include "ultima/nuvie/core/events.h"
|
||||
|
||||
namespace Ultima {
|
||||
namespace Nuvie {
|
||||
|
||||
UseCode::UseCode(Game *g, const Configuration *cfg) : game(g), config(cfg),
|
||||
obj_manager(nullptr), map(nullptr), player(nullptr), scroll(nullptr),
|
||||
actor_manager(nullptr), party(nullptr), script(nullptr), script_thread(nullptr) {
|
||||
clear_items();
|
||||
}
|
||||
|
||||
UseCode::~UseCode() {
|
||||
if (script_thread) {
|
||||
delete script_thread;
|
||||
}
|
||||
}
|
||||
|
||||
bool UseCode::init(ObjManager *om, Map *m, Player *p, MsgScroll *ms) {
|
||||
obj_manager = om;
|
||||
map = m;
|
||||
player = p;
|
||||
scroll = ms;
|
||||
|
||||
actor_manager = game->get_actor_manager();
|
||||
party = player->get_party();
|
||||
script = game->get_script();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Clear items.
|
||||
*/
|
||||
void UseCode::clear_items() {
|
||||
memset(&items, 0, sizeof(items));
|
||||
/* items.uint_ref = nullptr;
|
||||
items.sint_ref = nullptr;
|
||||
items.obj_ref = nullptr;
|
||||
items.actor_ref = items.actor2_ref = nullptr;
|
||||
items.mapcoord_ref = nullptr;
|
||||
items.msg_ref = nullptr;
|
||||
items.string_ref = nullptr;
|
||||
items.ent_ref = nullptr;
|
||||
items.data_ref = nullptr; */
|
||||
}
|
||||
|
||||
ScriptThread *UseCode::get_running_script() {
|
||||
if (script_thread && script_thread->is_running())
|
||||
return script_thread;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool UseCode::is_script_running() {
|
||||
if (script_thread && script_thread->is_running())
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool UseCode::is_container(const Obj *obj) const {
|
||||
return script->call_is_container_obj(obj->obj_n);
|
||||
}
|
||||
|
||||
bool UseCode::has_usecode(Obj *obj, UseCodeEvent ev) {
|
||||
return script->call_has_usecode(obj, ev);
|
||||
}
|
||||
|
||||
bool UseCode::use_obj(Obj *obj, Actor *actor) {
|
||||
if (script_thread) {
|
||||
delete script_thread;
|
||||
script_thread = nullptr;
|
||||
}
|
||||
|
||||
script_thread = script->call_use_obj(obj, actor);
|
||||
|
||||
if (script_thread) {
|
||||
script_thread->start();
|
||||
if (script_thread->finished()) {
|
||||
delete script_thread;
|
||||
script_thread = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
return true;//script->call_use_obj(obj, actor);
|
||||
}
|
||||
|
||||
// use obj at location with src_obj as object_ref
|
||||
bool UseCode::use_obj(uint16 x, uint16 y, uint8 z, Obj *src_obj) {
|
||||
Obj *obj;
|
||||
|
||||
obj = obj_manager->get_obj(x, y, z, true);
|
||||
|
||||
if (obj == nullptr)
|
||||
return false;
|
||||
|
||||
return use_obj(obj, src_obj);
|
||||
}
|
||||
|
||||
bool UseCode::ready_obj(Obj *obj, Actor *actor) {
|
||||
return script->call_ready_obj(obj, actor);
|
||||
}
|
||||
|
||||
bool UseCode::move_obj(Obj *obj, sint16 rel_x, sint16 rel_y) {
|
||||
return script->call_move_obj(obj, rel_x, rel_y);
|
||||
}
|
||||
|
||||
void UseCode::toggle_frame(Obj *obj) {
|
||||
if (obj->frame_n > 0)
|
||||
obj->frame_n--;
|
||||
else
|
||||
obj->frame_n = 1;
|
||||
}
|
||||
|
||||
|
||||
/* Print container contents and dump them on top of the container.
|
||||
*/
|
||||
//FIXME! some of this logic should go elsewhere.
|
||||
bool UseCode::search_container(Obj *obj, bool show_string) {
|
||||
Obj *temp_obj;
|
||||
U6Link *obj_link;
|
||||
|
||||
/* Test whether this object has items inside it. */
|
||||
if ((obj->container != nullptr) &&
|
||||
((obj_link = obj->container->start()) != nullptr)) {
|
||||
/* Add objects to obj_list. */
|
||||
for (; obj_link != nullptr;) {
|
||||
temp_obj = (Obj *)obj_link->data;
|
||||
obj_link = obj_link->next;
|
||||
/*
|
||||
obj_list->add(temp_obj);
|
||||
temp_obj->status |= OBJ_STATUS_OK_TO_TAKE;
|
||||
temp_obj->set_on_map(obj_list); //ERIC temp_obj->status &= ~OBJ_STATUS_IN_CONTAINER;
|
||||
temp_obj->x = obj->x;
|
||||
temp_obj->y = obj->y;
|
||||
temp_obj->z = obj->z;
|
||||
*/
|
||||
obj_manager->moveto_map(temp_obj, obj->is_in_container() ? MapCoord(obj->get_container_obj(true)) : MapCoord(obj));
|
||||
if (show_string) {
|
||||
scroll->display_string(obj_manager->look_obj(temp_obj, true));
|
||||
if (obj_link) // more objects left
|
||||
scroll->display_string(obj_link->next ? ", " : ", and ");
|
||||
}
|
||||
}
|
||||
/* Remove objects from the container. */
|
||||
//obj->container->removeAll();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/* Remove last object in container and return a pointer to it.
|
||||
*/
|
||||
Obj *UseCode::get_obj_from_container(Obj *obj) {
|
||||
Obj *temp_obj;
|
||||
if (obj->container && obj->container->end()) {
|
||||
temp_obj = (Obj *)obj->container->end()->data;
|
||||
obj->container->remove(temp_obj); // a pop_back() may be more efficient
|
||||
return temp_obj;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
/* Print name of event being sent and the object receiving it.
|
||||
*/
|
||||
void UseCode::dbg_print_event(UseCodeEvent event, Obj *obj) {
|
||||
string do_string = "";
|
||||
switch (event) {
|
||||
case USE_EVENT_USE:
|
||||
do_string = "Use";
|
||||
break;
|
||||
case USE_EVENT_LOOK:
|
||||
do_string = "Look at";
|
||||
break;
|
||||
case USE_EVENT_PASS:
|
||||
do_string = "Pass";
|
||||
break;
|
||||
case USE_EVENT_SEARCH:
|
||||
do_string = "Search";
|
||||
break;
|
||||
case USE_EVENT_MOVE:
|
||||
do_string = "Move";
|
||||
break;
|
||||
case USE_EVENT_LOAD:
|
||||
do_string = "Load";
|
||||
break;
|
||||
case USE_EVENT_MESSAGE:
|
||||
do_string = "Message";
|
||||
break;
|
||||
case USE_EVENT_READY:
|
||||
do_string = "(Un)Equip";
|
||||
break;
|
||||
case USE_EVENT_GET:
|
||||
do_string = "Get";
|
||||
break;
|
||||
case USE_EVENT_DROP:
|
||||
do_string = "Drop";
|
||||
break;
|
||||
}
|
||||
if (do_string != "")
|
||||
DEBUG(0, LEVEL_DEBUGGING, "UseCode: %s object %d:%d (%03x,%03x,%x)\n", do_string.c_str(),
|
||||
obj->obj_n, obj->frame_n, obj->x, obj->y, obj->z);
|
||||
else
|
||||
DEBUG(0, LEVEL_DEBUGGING, "UseCode: Events 0x%04x sent to object %d:%d (%03x,%03x,%x)\n",
|
||||
event, obj->obj_n, obj->frame_n, obj->x, obj->y, obj->z);
|
||||
}
|
||||
|
||||
|
||||
/* Subtract `count' from object quantity. Destroy the object completely if all
|
||||
* stacked objects were removed, or the object is not stackable, or `count' is
|
||||
* 0. This means it will be removed from the world or an actor's inventory, and
|
||||
* deleted.
|
||||
* Returns the original object if it still exists, because the count was smaller
|
||||
* than the object stack, or it could not be completely destroyed for whatever
|
||||
* reason. Returns nullptr if the object was destroyed.
|
||||
*/
|
||||
Obj *UseCode::destroy_obj(Obj *obj, uint32 count, bool run_usecode) {
|
||||
//ActorManager *actor_manager = Game::get_game()->get_actor_manager();
|
||||
//bool removed = false;
|
||||
|
||||
// subtract
|
||||
if (count > 0 && obj_manager->is_stackable(obj) && obj->qty > count)
|
||||
obj->qty -= count;
|
||||
else { // destroy
|
||||
obj_manager->unlink_from_engine(obj, run_usecode);
|
||||
delete_obj(obj);
|
||||
obj = nullptr;
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
/*
|
||||
* don't autowalk long distances to objects when foes are nearby or select obj outside of range
|
||||
*/
|
||||
bool UseCode::out_of_use_range(Obj *obj, bool check_enemies) {
|
||||
if (!obj) // this should be checked before you get here
|
||||
return true;
|
||||
if (obj->is_in_inventory())
|
||||
return false;
|
||||
|
||||
MapCoord player_loc = player->get_actor()->get_location();
|
||||
MapCoord obj_loc = MapCoord(obj->x, obj->y, obj->z);
|
||||
|
||||
if (!check_enemies) {
|
||||
if (player_loc.distance(obj_loc) > 1
|
||||
&& game->get_map_window()->get_interface() == INTERFACE_NORMAL) {
|
||||
scroll->display_string("\nOut of range.\n");
|
||||
return true;
|
||||
} else if (!game->get_map_window()->can_get_obj(player->get_actor(), obj)) {
|
||||
scroll->display_string("\nBlocked.\n");
|
||||
return true;
|
||||
} else
|
||||
return false;
|
||||
} else if (player_loc.distance(obj_loc) > 1) { // only setup for objects that already checked range and blocking limit
|
||||
ActorList *enemies = nullptr;
|
||||
|
||||
if ((enemies = player->get_actor()->find_enemies())) {
|
||||
scroll->display_string("\nOut of range.\n");
|
||||
delete enemies;
|
||||
return true;
|
||||
}
|
||||
delete enemies;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *useCodeTypeToString(UseCodeType type) {
|
||||
switch (type) {
|
||||
case USE :
|
||||
return "use";
|
||||
case MOVE :
|
||||
return "move";
|
||||
case GET :
|
||||
return "get";
|
||||
default :
|
||||
return "other";
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Nuvie
|
||||
} // End of namespace Ultima
|
||||
Reference in New Issue
Block a user