1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23 #include "ultima/nuvie/core/nuvie_defs.h"
24 #include "ultima/nuvie/core/obj_manager.h"
25 #include "ultima/nuvie/core/game.h"
26 #include "ultima/nuvie/core/u6_objects.h"
27
28 namespace Ultima {
29 namespace Nuvie {
30
Obj()31 Obj::Obj() {
32 obj_n = 0;
33 status = 0;
34 nuvie_status = 0;
35 frame_n = 0;
36 qty = 0;
37 quality = 0;
38 parent = NULL;
39 container = NULL;
40 x = 0;
41 y = 0;
42 z = 0;
43 }
44
Obj(Obj * sobj)45 Obj::Obj(Obj *sobj) {
46 memcpy(this, sobj, sizeof(Obj));
47
48 parent = NULL;
49 container = NULL;
50 }
51
make_container()52 void Obj::make_container() {
53 if (container == NULL)
54 container = new U6LList();
55
56 return;
57 }
58
get_container_obj(bool recursive)59 Obj *Obj::get_container_obj(bool recursive) {
60 Obj *obj = (is_in_container() ? (Obj *)parent : NULL);
61
62 if (recursive) {
63 while (obj && obj->is_in_container())
64 obj = (Obj *)obj->parent;
65 }
66
67 return obj;
68 }
69
set_on_map(U6LList * map_list)70 void Obj::set_on_map(U6LList *map_list) {
71 parent = map_list;
72 nuvie_status &= NUVIE_OBJ_STATUS_LOC_MASK_SET;
73 nuvie_status |= OBJ_LOC_MAP;
74
75 return;
76 }
77
set_in_container(Obj * container_obj)78 void Obj::set_in_container(Obj *container_obj) {
79 parent = (void *)container_obj;
80 nuvie_status &= NUVIE_OBJ_STATUS_LOC_MASK_SET;
81 nuvie_status |= OBJ_LOC_CONT;
82
83 return;
84 }
85
set_invisible(bool flag)86 void Obj::set_invisible(bool flag) {
87 if (flag)
88 status |= OBJ_STATUS_INVISIBLE;
89 else if (is_invisible())
90 status ^= OBJ_STATUS_INVISIBLE;
91
92 return;
93 }
94
set_temporary(bool flag)95 void Obj::set_temporary(bool flag) {
96 if (flag)
97 status |= OBJ_STATUS_TEMPORARY;
98 else if (is_temporary())
99 status ^= OBJ_STATUS_TEMPORARY;
100
101 return;
102 }
103
set_ok_to_take(bool flag,bool recursive)104 void Obj::set_ok_to_take(bool flag, bool recursive) {
105 if (flag)
106 status |= OBJ_STATUS_OK_TO_TAKE;
107 else if (is_ok_to_take())
108 status ^= OBJ_STATUS_OK_TO_TAKE;
109
110 if (recursive && container) {
111 for (U6Link *link = container->start(); link != NULL; link = link->next) {
112 Obj *obj = (Obj *)link->data;
113 obj->set_ok_to_take(flag, recursive);
114 }
115 }
116 }
117
set_in_inventory()118 void Obj::set_in_inventory() {
119 nuvie_status &= NUVIE_OBJ_STATUS_LOC_MASK_SET;
120 nuvie_status |= OBJ_LOC_INV;
121
122 return;
123 }
124
readied()125 void Obj::readied() { //set_readied() ??
126 nuvie_status &= NUVIE_OBJ_STATUS_LOC_MASK_SET;
127 nuvie_status |= OBJ_LOC_READIED;
128
129 return;
130 }
131
set_noloc()132 void Obj::set_noloc() {
133 parent = NULL;
134 nuvie_status &= NUVIE_OBJ_STATUS_LOC_MASK_SET; //clear location bits 0 = no loc
135
136 return;
137 }
138
set_in_script(bool flag)139 void Obj::set_in_script(bool flag) {
140 if (flag)
141 nuvie_status |= NUVIE_OBJ_STATUS_SCRIPTING;
142 else if (is_script_obj())
143 nuvie_status ^= NUVIE_OBJ_STATUS_SCRIPTING;
144
145 return;
146 }
147
set_actor_obj(bool flag)148 void Obj::set_actor_obj(bool flag) {
149 if (flag)
150 nuvie_status |= NUVIE_OBJ_STATUS_ACTOR_OBJ;
151 else if (is_actor_obj())
152 nuvie_status ^= NUVIE_OBJ_STATUS_ACTOR_OBJ;
153
154 return;
155 }
156
157 /* Returns true if an object is in an actor inventory, including containers and readied items. */
158
is_in_inventory(bool check_parent)159 bool Obj::is_in_inventory(bool check_parent) {
160 switch (get_engine_loc()) {
161 case OBJ_LOC_INV :
162 case OBJ_LOC_READIED :
163 return true;
164 case OBJ_LOC_CONT :
165 if (check_parent)
166 return ((Obj *)parent)->is_in_inventory(check_parent);
167 break;
168 default :
169 break;
170 }
171
172 return false;
173 }
174
get_engine_loc()175 uint8 Obj::get_engine_loc() {
176 return (nuvie_status & NUVIE_OBJ_STATUS_LOC_MASK_GET);
177 }
178
get_actor_holding_obj()179 Actor *Obj::get_actor_holding_obj() {
180 switch (get_engine_loc()) {
181 case OBJ_LOC_INV :
182 case OBJ_LOC_READIED :
183 return (Actor *)this->parent;
184
185 case OBJ_LOC_CONT :
186 return ((Obj *)parent)->get_actor_holding_obj();
187
188 default :
189 break;
190 }
191
192 return NULL;
193 }
194
195 //Add child object into container, stacking if required
add(Obj * obj,bool stack)196 void Obj::add(Obj *obj, bool stack) {
197 if (container == NULL)
198 make_container();
199
200 if (stack && Game::get_game()->get_obj_manager()->is_stackable(obj))
201 add_and_stack(obj);
202 else
203 container->addAtPos(0, obj);
204
205 obj->set_in_container(this);
206
207 return;
208 }
209
add_and_stack(Obj * obj)210 void Obj::add_and_stack(Obj *obj) {
211 U6Link *link;
212 Obj *cont_obj;
213
214 //should we recurse through nested containers?
215 for (link = container->start(); link != NULL;) {
216 cont_obj = (Obj *)link->data;
217 link = link->next;
218 //match on obj_n, frame_n and quality.
219 if (obj->obj_n == cont_obj->obj_n && obj->frame_n == cont_obj->frame_n && obj->quality == cont_obj->quality) {
220 obj->qty += cont_obj->qty;
221 container->replace(cont_obj, obj); //replace cont_obj with obj in container list. should we do this to link->data directly?
222 delete_obj(cont_obj);
223
224 return;
225 }
226 }
227
228 container->addAtPos(0, obj); // add the object as we couldn't find another object to stack with.
229
230 return;
231 }
232
233 //Remove child object from container.
remove(Obj * obj)234 bool Obj::remove(Obj *obj) {
235 if (container == NULL)
236 return false;
237
238 if (container->remove(obj) == false)
239 return false;
240 if (Game::get_game()->get_game_type() == NUVIE_GAME_SE) {
241 if (obj_n == OBJ_SE_JAR)
242 frame_n = 0; // empty jar frame
243 }
244 obj->x = 0;
245 obj->y = 0;
246 obj->z = 0;
247
248 obj->set_noloc();
249
250 return true;
251 }
252
find_in_container(uint16 objN,uint8 quality_,bool match_quality,uint8 frameN,bool match_frame_n,Obj ** prev_obj)253 Obj *Obj::find_in_container(uint16 objN, uint8 quality_, bool match_quality, uint8 frameN, bool match_frame_n, Obj **prev_obj) {
254 U6Link *link;
255 Obj *obj;
256
257 if (container == NULL)
258 return NULL;
259
260 for (link = container->start(); link != NULL; link = link->next) {
261 obj = (Obj *)link->data;
262 if (obj) {
263 if (obj->obj_n == objN && (match_quality == false || obj->quality == quality_) && (match_frame_n == false || obj->frame_n == frameN)) {
264 if (prev_obj != NULL && obj == *prev_obj)
265 prev_obj = NULL;
266 else {
267 if (prev_obj == NULL || *prev_obj == NULL)
268 return obj;
269 }
270 }
271
272 if (obj->container) {
273 obj = obj->find_in_container(objN, quality_, match_quality, frameN, match_frame_n, prev_obj);
274 if (obj)
275 return obj;
276 }
277 }
278 }
279
280 return NULL;
281 }
282
get_total_qty(uint16 match_obj_n)283 uint32 Obj::get_total_qty(uint16 match_obj_n) {
284 U6Link *link;
285 Obj *obj;
286 uint16 total_qty = 0;
287
288 if (obj_n == match_obj_n) {
289 if (qty == 0)
290 total_qty += 1;
291 else
292 total_qty += qty;
293 }
294
295 if (container != NULL) {
296 for (link = container->start(); link != NULL; link = link->next) {
297 obj = (Obj *)link->data;
298 if (obj) {
299 if (obj->container)
300 total_qty += obj->get_total_qty(match_obj_n);
301 else if (obj->obj_n == match_obj_n) {
302 if (obj->qty == 0)
303 total_qty += 1;
304 else
305 total_qty += obj->qty;
306 }
307 }
308 }
309 }
310
311 return total_qty;
312 }
313
container_count_objects()314 uint32 Obj::container_count_objects() {
315 uint32 count = 0;
316 U6Link *link;
317
318 if (container != NULL) {
319 for (link = container->start(); link != NULL; link = link->next) {
320 ++count;
321 }
322 }
323 return count;
324 }
325
is_ok_to_take()326 bool Obj::is_ok_to_take() {
327 return ((status & OBJ_STATUS_OK_TO_TAKE) || Game::get_game()->using_hackmove());
328 }
329
330 } // End of namespace Nuvie
331 } // End of namespace Ultima
332