327 lines
7.3 KiB
C++
327 lines
7.3 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/core/obj_manager.h"
|
|
#include "ultima/nuvie/core/game.h"
|
|
#include "ultima/nuvie/core/u6_objects.h"
|
|
|
|
namespace Ultima {
|
|
namespace Nuvie {
|
|
|
|
Obj::Obj() : obj_n(0), status(0), nuvie_status(0), frame_n(0), qty(0),
|
|
quality(0), parent(nullptr), container(nullptr), x(0), y(0), z(0) {
|
|
}
|
|
|
|
Obj::Obj(Obj *sobj) {
|
|
memcpy(this, sobj, sizeof(Obj));
|
|
|
|
parent = nullptr;
|
|
container = nullptr;
|
|
}
|
|
|
|
void Obj::make_container() {
|
|
if (container == nullptr)
|
|
container = new U6LList();
|
|
|
|
return;
|
|
}
|
|
|
|
Obj *Obj::get_container_obj(bool recursive) {
|
|
Obj *obj = (is_in_container() ? (Obj *)parent : nullptr);
|
|
|
|
if (recursive) {
|
|
while (obj && obj->is_in_container())
|
|
obj = (Obj *)obj->parent;
|
|
}
|
|
|
|
return obj;
|
|
}
|
|
|
|
void Obj::set_on_map(U6LList *map_list) {
|
|
parent = map_list;
|
|
nuvie_status &= NUVIE_OBJ_STATUS_LOC_MASK_SET;
|
|
nuvie_status |= OBJ_LOC_MAP;
|
|
|
|
return;
|
|
}
|
|
|
|
void Obj::set_in_container(Obj *container_obj) {
|
|
parent = (void *)container_obj;
|
|
nuvie_status &= NUVIE_OBJ_STATUS_LOC_MASK_SET;
|
|
nuvie_status |= OBJ_LOC_CONT;
|
|
|
|
return;
|
|
}
|
|
|
|
void Obj::set_invisible(bool flag) {
|
|
if (flag)
|
|
status |= OBJ_STATUS_INVISIBLE;
|
|
else if (is_invisible())
|
|
status ^= OBJ_STATUS_INVISIBLE;
|
|
|
|
return;
|
|
}
|
|
|
|
void Obj::set_temporary(bool flag) {
|
|
if (flag)
|
|
status |= OBJ_STATUS_TEMPORARY;
|
|
else if (is_temporary())
|
|
status ^= OBJ_STATUS_TEMPORARY;
|
|
|
|
return;
|
|
}
|
|
|
|
void Obj::set_ok_to_take(bool flag, bool recursive) {
|
|
if (flag)
|
|
status |= OBJ_STATUS_OK_TO_TAKE;
|
|
else if (is_ok_to_take())
|
|
status ^= OBJ_STATUS_OK_TO_TAKE;
|
|
|
|
if (recursive && container) {
|
|
for (U6Link *link = container->start(); link != nullptr; link = link->next) {
|
|
Obj *obj = (Obj *)link->data;
|
|
obj->set_ok_to_take(flag, recursive);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Obj::set_in_inventory() {
|
|
nuvie_status &= NUVIE_OBJ_STATUS_LOC_MASK_SET;
|
|
nuvie_status |= OBJ_LOC_INV;
|
|
|
|
return;
|
|
}
|
|
|
|
void Obj::readied() { //set_readied() ??
|
|
nuvie_status &= NUVIE_OBJ_STATUS_LOC_MASK_SET;
|
|
nuvie_status |= OBJ_LOC_READIED;
|
|
|
|
return;
|
|
}
|
|
|
|
void Obj::set_noloc() {
|
|
parent = nullptr;
|
|
nuvie_status &= NUVIE_OBJ_STATUS_LOC_MASK_SET; //clear location bits 0 = no loc
|
|
|
|
return;
|
|
}
|
|
|
|
void Obj::set_in_script(bool flag) {
|
|
if (flag)
|
|
nuvie_status |= NUVIE_OBJ_STATUS_SCRIPTING;
|
|
else if (is_script_obj())
|
|
nuvie_status ^= NUVIE_OBJ_STATUS_SCRIPTING;
|
|
|
|
return;
|
|
}
|
|
|
|
void Obj::set_actor_obj(bool flag) {
|
|
if (flag)
|
|
nuvie_status |= NUVIE_OBJ_STATUS_ACTOR_OBJ;
|
|
else if (is_actor_obj())
|
|
nuvie_status ^= NUVIE_OBJ_STATUS_ACTOR_OBJ;
|
|
|
|
return;
|
|
}
|
|
|
|
/* Returns true if an object is in an actor inventory, including containers and readied items. */
|
|
|
|
bool Obj::is_in_inventory(bool check_parent) const {
|
|
switch (get_engine_loc()) {
|
|
case OBJ_LOC_INV :
|
|
case OBJ_LOC_READIED :
|
|
return true;
|
|
case OBJ_LOC_CONT :
|
|
if (check_parent)
|
|
return ((Obj *)parent)->is_in_inventory(check_parent);
|
|
break;
|
|
default :
|
|
break;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
uint8 Obj::get_engine_loc() const {
|
|
return (nuvie_status & NUVIE_OBJ_STATUS_LOC_MASK_GET);
|
|
}
|
|
|
|
Actor *Obj::get_actor_holding_obj() {
|
|
switch (get_engine_loc()) {
|
|
case OBJ_LOC_INV :
|
|
case OBJ_LOC_READIED :
|
|
return (Actor *)this->parent;
|
|
|
|
case OBJ_LOC_CONT :
|
|
return ((Obj *)parent)->get_actor_holding_obj();
|
|
|
|
default :
|
|
break;
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
//Add child object into container, stacking if required
|
|
void Obj::add(Obj *obj, bool stack, bool addAtTail) {
|
|
if (container == nullptr)
|
|
make_container();
|
|
|
|
if (stack && Game::get_game()->get_obj_manager()->is_stackable(obj))
|
|
add_and_stack(obj, addAtTail);
|
|
else
|
|
if (!addAtTail)
|
|
container->addAtPos(0, obj);
|
|
else
|
|
container->add(obj);
|
|
|
|
obj->set_in_container(this);
|
|
|
|
return;
|
|
}
|
|
|
|
void Obj::add_and_stack(Obj *obj, bool addAtTail) {
|
|
U6Link *link;
|
|
Obj *cont_obj;
|
|
|
|
//should we recurse through nested containers?
|
|
for (link = container->start(); link != nullptr;) {
|
|
cont_obj = (Obj *)link->data;
|
|
link = link->next;
|
|
//match on obj_n, frame_n and quality.
|
|
if (obj->obj_n == cont_obj->obj_n && obj->frame_n == cont_obj->frame_n && obj->quality == cont_obj->quality) {
|
|
obj->qty += cont_obj->qty;
|
|
container->replace(cont_obj, obj); //replace cont_obj with obj in container list. should we do this to link->data directly?
|
|
delete_obj(cont_obj);
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
if (!addAtTail)
|
|
container->addAtPos(0, obj); // add the object as we couldn't find another object to stack with.
|
|
else
|
|
container->add(obj);
|
|
|
|
return;
|
|
}
|
|
|
|
//Remove child object from container.
|
|
bool Obj::remove(Obj *obj) {
|
|
if (container == nullptr)
|
|
return false;
|
|
|
|
if (container->remove(obj) == false)
|
|
return false;
|
|
if (Game::get_game()->get_game_type() == NUVIE_GAME_SE) {
|
|
if (obj_n == OBJ_SE_JAR)
|
|
frame_n = 0; // empty jar frame
|
|
}
|
|
obj->x = 0;
|
|
obj->y = 0;
|
|
obj->z = 0;
|
|
|
|
obj->set_noloc();
|
|
|
|
return true;
|
|
}
|
|
|
|
Obj *Obj::find_in_container(uint16 objN, uint8 quality_, bool match_quality, uint8 frameN, bool match_frame_n, Obj **prev_obj) const {
|
|
U6Link *link;
|
|
Obj *obj;
|
|
|
|
if (container == nullptr)
|
|
return nullptr;
|
|
|
|
for (link = container->start(); link != nullptr; link = link->next) {
|
|
obj = (Obj *)link->data;
|
|
if (obj) {
|
|
if (obj->obj_n == objN && (match_quality == false || obj->quality == quality_) && (match_frame_n == false || obj->frame_n == frameN)) {
|
|
if (prev_obj != nullptr && obj == *prev_obj)
|
|
prev_obj = nullptr;
|
|
else {
|
|
if (prev_obj == nullptr || *prev_obj == nullptr)
|
|
return obj;
|
|
}
|
|
}
|
|
|
|
if (obj->container) {
|
|
obj = obj->find_in_container(objN, quality_, match_quality, frameN, match_frame_n, prev_obj);
|
|
if (obj)
|
|
return obj;
|
|
}
|
|
}
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
uint32 Obj::get_total_qty(uint16 match_obj_n) {
|
|
U6Link *link;
|
|
Obj *obj;
|
|
uint16 total_qty = 0;
|
|
|
|
if (obj_n == match_obj_n) {
|
|
if (qty == 0)
|
|
total_qty += 1;
|
|
else
|
|
total_qty += qty;
|
|
}
|
|
|
|
if (container != nullptr) {
|
|
for (link = container->start(); link != nullptr; link = link->next) {
|
|
obj = (Obj *)link->data;
|
|
if (obj) {
|
|
if (obj->container)
|
|
total_qty += obj->get_total_qty(match_obj_n);
|
|
else if (obj->obj_n == match_obj_n) {
|
|
if (obj->qty == 0)
|
|
total_qty += 1;
|
|
else
|
|
total_qty += obj->qty;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return total_qty;
|
|
}
|
|
|
|
uint32 Obj::container_count_objects() const {
|
|
uint32 count = 0;
|
|
U6Link *link;
|
|
|
|
if (container != nullptr) {
|
|
for (link = container->start(); link != nullptr; link = link->next) {
|
|
++count;
|
|
}
|
|
}
|
|
return count;
|
|
}
|
|
|
|
bool Obj::is_ok_to_take() const {
|
|
return ((status & OBJ_STATUS_OK_TO_TAKE) || Game::get_game()->using_hackmove());
|
|
}
|
|
|
|
} // End of namespace Nuvie
|
|
} // End of namespace Ultima
|