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 #ifndef ULTIMA8_WORLD_ITEM_H
24 #define ULTIMA8_WORLD_ITEM_H
25 
26 #include "ultima/ultima8/kernel/object.h"
27 #include "ultima/ultima8/graphics/shape_info.h"
28 
29 #include "ultima/ultima8/usecode/intrinsics.h"
30 #include "ultima/ultima8/misc/box.h"
31 #include "ultima/ultima8/misc/point3.h"
32 #include "ultima/ultima8/misc/direction.h"
33 
34 namespace Ultima {
35 namespace Ultima8 {
36 
37 class Container;
38 class ShapeInfo;
39 class Shape;
40 class Gump;
41 class GravityProcess;
42 
43 class Item : public Object {
44 	friend class ItemFactory;
45 
46 public:
47 	Item();
48 	~Item() override;
49 
ENABLE_RUNTIME_CLASSTYPE()50 	ENABLE_RUNTIME_CLASSTYPE()
51 
52 	//! Get the Container this Item is in, if any. (0 if not in a Container)
53 	ObjId getParent() const {
54 		return _parent;
55 	}
56 
57 	//! Set the parent container of this item.
setParent(ObjId p)58 	void setParent(ObjId p) {
59 		_parent = p;
60 	}
61 
62 	//! Get the Container this Item is in, if any. (NULL if not in a Container)
63 	Container *getParentAsContainer() const;
64 
65 	//! Get the top-most Container this Item is in, or the Item itself if not
66 	//! in a container
67 	Item *getTopItem();
68 
69 	//! Set item location. This strictly sets the location, and does not
70 	//! even update CurrentMap
71 	void setLocation(int32 x, int32 y, int32 z); // this only sets the loc.
72 
73 	//! Move an item. This moves an item to the new location, and updates
74 	//! CurrentMap and fastArea if necessary.
75 	virtual void move(int32 x, int32 y, int32 z);
76 
77 	//! Move, but with a point struct.
78 	void move(const Point3 &pt);
79 
80 	//! Move an item. This moves an item to a container and  updates
81 	//! CurrentMap and fastArea if necessary.
82 	//! \param container The container this item should be placed in
83 	//! \return true if item was moved, false if failed
84 	bool moveToContainer(Container *container, bool checkwghtvol = false);
85 
86 	//! Move an item to the Ethereal Void
87 	void moveToEtherealVoid();
88 
89 	//! Move an item out of the Ethereal Void to where it originally was
90 	void returnFromEtherealVoid();
91 
92 	//! Check if moving this item is stealing; call AvatarStoleSomething if so
93 	void movedByPlayer();
94 
95 	//! Get the location of the top-most container this Item is in, or
96 	//! this Item's location if not in a container.
97 	void getLocationAbsolute(int32 &x, int32 &y, int32 &z) const;
98 
99 	//! Get this Item's location. Note that this does not return
100 	//! 'usable' coordinates if the Item is contained or equipped.
101 	inline void getLocation(int32 &x, int32 &y, int32 &z) const;
102 
103 	//! Get the Item's location using a Point3 struct.
104 	inline void getLocation(Point3 &pt) const;
105 
106 	//! Get this Item's Z coordinate.
107 	int32 getZ() const;
108 
109 	//! Set this Item's Z coordinate
setZ(int32 z)110 	void setZ(int32 z) {
111 		_z = z;
112 	}
113 
114 	//! Get this Item's location in a ContainerGump. Undefined if the Item
115 	//! is not in a Container.
116 	void getGumpLocation(int32 &x, int32 &y) const;
117 
118 	//! Set the Item's location in a ContainerGump. NOP if the Item
119 	//! is not in a Container.
120 	void setGumpLocation(int32 x, int32 y);
121 
122 	//! Randomize the Item's location in a ContainerGump. Effectively
123 	//! this sets the coordinates to (255,255) and lets the ContainerGump
124 	//! randomize the position when it is next opened.
125 	void randomGumpLocation();
126 
127 	//! Get the world coordinates of the Item's centre. Undefined if the Item
128 	//! is contained or equipped.
129 	void getCentre(int32 &x, int32 &y, int32 &z) const;
130 
131 	//! Get the size of this item's 3D bounding box, in world coordinates.
132 	inline void getFootpadWorld(int32 &x, int32 &y, int32 &z) const;
133 
134 	//! Get the size of this item's 3D bounding box, scaled as in the datafiles
135 	//! (i.e., the dimensions are not in the same unit as world coordinates!)
136 	inline void getFootpadData(int32 &x, int32 &y, int32 &z) const;
137 
138 	//! Get the Box this item occupies in the world. Undef if item is contained
139 	Box getWorldBox() const;
140 
141 	//! Get all flags
getFlags()142 	inline uint16 getFlags() const {
143 		return _flags;
144 	}
145 
146 	//! Does this item have any of the given flags mask set
hasFlags(uint16 flags)147 	inline bool hasFlags(uint16 flags) const {
148 		return (_flags & flags) != 0;
149 	}
150 
151 	//! Set the flags set in the given mask.
setFlag(uint32 mask)152 	void setFlag(uint32 mask) {
153 		_flags |= mask;
154 	}
155 
setFlagRecursively(uint32 mask)156 	virtual void setFlagRecursively(uint32 mask) {
157 		setFlag(mask);
158 	}
159 
160 	//! Clear the flags set in the given mask.
clearFlag(uint32 mask)161 	void clearFlag(uint32 mask) {
162 		_flags &= ~mask;
163 	}
164 
165 	//! Set _extendedFlags
setExtFlags(uint32 f)166 	void setExtFlags(uint32 f) {
167 		_extendedFlags = f;
168 	}
169 
170 	//! Get _extendedFlags
getExtFlags()171 	inline uint32 getExtFlags() const {
172 		return _extendedFlags;
173 	}
174 
175 	//! Does item have any of the given extended flags
hasExtFlags(uint32 flags)176 	inline bool hasExtFlags(uint32 flags) const {
177 		return (_extendedFlags & flags) != 0;
178 	}
179 
180 	//! Set the _extendedFlags set in the given mask.
setExtFlag(uint32 mask)181 	void setExtFlag(uint32 mask) {
182 		_extendedFlags |= mask;
183 	}
184 
185 	//! Clear the _extendedFlags set in the given mask.
clearExtFlag(uint32 mask)186 	void clearExtFlag(uint32 mask) {
187 		_extendedFlags &= ~mask;
188 	}
189 
190 	//! Get this Item's shape number
getShape()191 	uint32 getShape() const {
192 		return _shape;
193 	}
194 
195 	//! Set this Item's shape number
196 	void setShape(uint32 shape);
197 
198 	//! Get this Item's frame number
getFrame()199 	uint32 getFrame() const {
200 		return _frame;
201 	}
202 
203 	//! Set this Item's frame number
setFrame(uint32 frame)204 	void setFrame(uint32 frame) {
205 		_frame = frame;
206 	}
207 
208 	//! Get this Item's quality (a.k.a. 'Q')
getQuality()209 	uint16 getQuality() const {
210 		return _quality;
211 	}
212 
213 	//! Set this Item's quality (a.k.a 'Q');
setQuality(uint16 quality)214 	void setQuality(uint16 quality) {
215 		_quality = quality;
216 	}
217 
218 	//! Get the 'NpcNum' of this Item. Note that this can represent various
219 	//! things depending on the family of this Item.
getNpcNum()220 	uint16 getNpcNum() const {
221 		return _npcNum;
222 	}
223 
224 	//! Set the 'NpcNum' of this Item. Note that this can represent various
225 	//! things depending on the family of this Item.
setNpcNum(uint16 npcnum)226 	void setNpcNum(uint16 npcnum) {
227 		_npcNum = npcnum;
228 	}
229 
230 	//! Get the 'MapNum' of this Item. Note that this can represent various
231 	//! things depending on the family of this Item.
getMapNum()232 	uint16 getMapNum() const {
233 		return _mapNum;
234 	}
235 
236 	//! Set the 'MapNum' of this Item. Note that this can represent various
237 	//! things depending on the family of this Item.
setMapNum(uint16 mapnum)238 	void setMapNum(uint16 mapnum) {
239 		_mapNum = mapnum;
240 	}
241 
242 	//! Get the ShapeInfo object for this Item. (The pointer will be cached.)
243 	inline const ShapeInfo *getShapeInfo() const;
244 
245 	//! Get the ShapeInfo object for this Item from the game instance.
246 	virtual const ShapeInfo *getShapeInfoFromGameInstance() const;
247 
248 	//! Get the Shape object for this Item. (The pointer will be cached.)
249 	const Shape *getShapeObject() const;
250 
251 	//! Get the family of the shape number of this Item. (This is a
252 	//! member of the ShapeInfo object.)
253 	uint16 getFamily() const;
254 
255 	//! Check if we can merge with another item.
256 	bool canMergeWith(Item *other);
257 
258 	//! Get the open ContainerGump for this Item, if any. (NULL if not open.)
getGump()259 	ObjId getGump() const {
260 		return _gump;
261 	}
262 	//! Call this to notify the Item's open Gump has closed.
263 	void clearGump(); // set gump to 0 and clear the GUMP_OPEN flag
264 	//! Open a gump with the given shape for this Item
265 	ObjId openGump(uint32 gumpshape);
266 	//! Close this Item's gump, if any
267 	void closeGump();
268 
269 	//! Destroy self.
270 	virtual void destroy(bool delnow = false);
271 
272 	//! Check if this item overlaps another item in 3D world-space
273 	bool overlaps(const Item &item2) const;
274 
275 	//! Check if this item overlaps another item in the xy dims in 3D space
276 	bool overlapsxy(const Item &item2) const;
277 
278 	//! Check if this item is on top of another item
279 	bool isOn(const Item &item2) const;
280 
281 	//! Check if this item is on completely on top of another item
282 	bool isCompletelyOn(const Item &item2) const;
283 
284 	//! Check if the centre of this item is on top of another item
285 	bool isCentreOn(const Item &item2) const;
286 
287 	//! Check if the item is currently entirely visible on screen
288 	bool isOnScreen() const;
289 
290 	//! Check if the item is currently partly visible on screen
291 	bool isPartlyOnScreen() const;
292 
293 	//! Check if this item can exist at the given coordinates
294 	bool canExistAt(int32 x, int32 y, int32 z, bool needsupport = false) const;
295 
296 	//! Get direction from centre to another item's centre.
297 	//! Undefined if either item is contained or equipped.
298 	Direction getDirToItemCentre(const Item &item2) const;
299 
300 	//! Same as above, but from a fixed point.
301 	Direction getDirToItemCentre(const Point3 &pt) const;
302 
303 	//! get 'distance' to other item. This is the maximum of the differences
304 	//! between the x, y (and possibly z) coordinates of the items.
305 	int getRange(const Item &item2, bool checkz = false) const;
306 
307 	//! get 'distance' to other item if it's visible (ie, there's nothing blocking the path)
308 	int getRangeIfVisible(const Item &item2) const;
309 
310 	//! Check if this item can reach another item. (This includes LoS.)
311 	//! \param other item to be reached
312 	//! \param range range
313 	//! \param x x coordinate of other to use, If zero, use real coords.
314 	//! \param y y coordinate of other to use
315 	//! \param z z coordinate of other to use.
316 	bool canReach(Item *other, int range, int32 x = 0, int32 y = 0, int32 z = 0);
317 
318 	//! Move the object to (x,y,z) colliding with objects in the way.
319 	//! \param teleport move without colliding with objects between source and
320 	//!        destination
321 	//! \param force force the object to get to the destination without being
322 	//!        blocked by solid objects
323 	//! \param hititem if non-NULL, this is set to (one of) the item(s)
324 	//!        blocking the movement, or to zero if nothing blocked it
325 	//! \param dirs if non-NULL, this is set to a bitmask of the x/y/z
326 	//         directions in which movement was blocked (bit 0=x,1=y,2=z)
327 	//! \returns 0-0x4000 representing how far it got.
328 	//!          0 = didn't move
329 	//!          0x4000 = reached destination
330 	//! \note This can destroy the object
331 	virtual int32 collideMove(int32 x, int32 y, int32 z, bool teleport, bool force,
332 	                  ObjId *hititem = 0, uint8 *dirs = 0);
333 
334 	//! Make the item move up (delta>0) or down (delta<0),
335 	//! including any items on top of it
336 	//! \param delta distance in Z-direction to move
337 	//! \returns 0-0x4000 representing how far it got.
338 	//!          0 = didn't move
339 	//!          0x4000 = reached destination
340 	int32 ascend(int delta);
341 
342 	//! Make the item fall down.
343 	//! This creates a GravityProcess to do the actual work if the Item
344 	//! doesn't already have one.
345 	void fall();
346 
347 	//! Make any items on top of this Item fall down and notify any supporting
348 	//! items that we're gone by calling the 'release' event.
349 	//! Note that this Item has to be moved away right after calling grab(),
350 	//! since otherwise the items will immediately hit this Item again.
351 	void grab();
352 
353 	//! Hurl the item in the given direction
354 	void hurl(int xs, int ys, int zs, int grav);
355 
356 	//! Set the PID of the GravityProcess for this Item.  There should be only one.
setGravityPID(ProcId pid)357 	void setGravityPID(ProcId pid) {
358 		assert(_gravityPid == 0 || pid == 0);
359 		_gravityPid = pid;
360 	}
361 
362 	//! Get the PID of the GravityProcess for this Item (or 0)
getGravityPID()363 	ProcId getGravityPID() const {
364 		return _gravityPid;
365 	}
366 
367 	//! Get the GravityProcess of this Item, creating it if necessary
368 	virtual GravityProcess *ensureGravityProcess();
369 
370 	//! Get the weight of this Item
371 	virtual uint32 getWeight() const;
372 
373 	//! Get the weight of this Item and its contents, if any
374 	virtual uint32 getTotalWeight() const;
375 
376 	//! Get the volume this item takes up in a container
377 	virtual uint32 getVolume() const;
378 
379 	//! explode with explosion type (0,1,2), whether to destroy the item,
380 	//! and whether to cause splash damage.
381 	void explode(int explosion_type, bool destroy_item, bool cause_damage = true);
382 
383 	//! get the damage type this object does when hitting something
384 	virtual uint16 getDamageType() const;
385 
386 	//! receive a hit
387 	//! \param other The item delivering the hit
388 	//! \param dir The direction the hit is coming from (or inverse? CHECKME!)
389 	//! \param damage The force of the hit. Zero for default
390 	//! \param type The type of damage done. Zero for default
391 	virtual void receiveHit(ObjId other, Direction dir, int damage, uint16 type);
392 
393 	//! fire the given weapon type in the given direction from location x, y, z.
394 	uint16 fireWeapon(int32 x, int32 y, int32 z, Direction dir, int firetype, bool findtarget);
395 
396 	//! get the distance (in map tiles) if we were to fire in this direction to "other"
397 	//! and could hit, otherwise return 0.
398 	uint16 fireDistance(const Item *other, Direction dir, int16 xoff, int16 yoff, int16 zoff) const;
399 
400 	//! get damage points, used in Crusader for item damage.
getDamagePoints()401 	uint8 getDamagePoints() const {
402 		return _damagePoints;
403 	}
404 
405 	//! set damage points, used in Crusader for item damage.
setDamagePoints(uint8 points)406 	void setDamagePoints(uint8 points) {
407 		_damagePoints = points;
408 	}
409 
410 	//! Get the right Z which an attacker should aim for, given the attacker's z.
411 	//! (Crusader only)
412 	int32 getTargetZRelativeToAttackerZ(int32 attackerz) const;
413 
414 	//! count nearby objects of a given shape
415 	unsigned int countNearby(uint32 shape, uint16 range);
416 
417 	//! can this item be dragged?
418 	bool canDrag();
419 
420 	//! how far can this item be thrown?
421 	//! \return range, or 0 if item can't be thrown
422 	int getThrowRange();
423 
424 	//! Check this Item against the given loopscript
425 	//! \param script The loopscript to run
426 	//! \param scriptsize The size (in bytes) of the loopscript
427 	//! \return true if the item matches, false otherwise
428 	bool checkLoopScript(const uint8 *script, uint32 scriptsize) const;
429 
430 	uint32 callUsecodeEvent_look();                             // event 0
431 	uint32 callUsecodeEvent_use();                              // event 1
432 	uint32 callUsecodeEvent_anim();                             // event 2
433 	uint32 callUsecodeEvent_cachein();                          // event 4
434 	uint32 callUsecodeEvent_hit(ObjId hitted, int16 hitforce);  // event 5
435 	uint32 callUsecodeEvent_gotHit(ObjId hitter, int16 hitforce);// event 6
436 	uint32 callUsecodeEvent_hatch();                            // event 7
437 	uint32 callUsecodeEvent_schedule(uint32 time);              // event 8
438 	uint32 callUsecodeEvent_release();                          // event 9
439 	uint32 callUsecodeEvent_equip();                            // event A
440 	uint32 callUsecodeEvent_equipWithParam(ObjId param);        // event A
441 	uint32 callUsecodeEvent_unequip();                          // event B
442 	uint32 callUsecodeEvent_unequipWithParam(ObjId param);      // event B
443 	uint32 callUsecodeEvent_combine();                          // event C
444 	uint32 callUsecodeEvent_calledFromAnim();                   // event E
445 	uint32 callUsecodeEvent_enterFastArea();                    // event F
446 	uint32 callUsecodeEvent_leaveFastArea();                    // event 10
447 	uint32 callUsecodeEvent_cast(uint16 unk);                   // event 11
448 	uint32 callUsecodeEvent_justMoved();                        // event 12
449 	uint32 callUsecodeEvent_AvatarStoleSomething(uint16 unk);   // event 14
450 	uint32 callUsecodeEvent_guardianBark(int16 unk);            // event 15 (Ultima)
451 	uint32 callUsecodeEvent_unhatch();							// event 15 (Crusader)
452 
453 	uint32 use();
454 
455 	//! Get lerped location.
getLerped(int32 & xp,int32 & yp,int32 & zp)456 	inline void getLerped(int32 &xp, int32 &yp, int32 &zp) const {
457 		xp = _ix;
458 		yp = _iy;
459 		zp = _iz;
460 	}
461 
462 	//! Do lerping for an in between frame (0-256)
463 	//! The result can be retrieved with getLerped(x,y,z)
464 	//! \param factor The lerp factor: 0 is start of move, 256 is end of move
doLerp(int32 factor)465 	inline void doLerp(int32 factor) {
466 		// Should be noted that this does indeed limit us to 'only' 24bit coords
467 		// not that it matters because on disk they are unsigned 16 bit
468 
469 		if (factor == 256) {
470 			_ix = _lNext._x;
471 			_iy = _lNext._y;
472 			_iz = _lNext._z;
473 		} else if (factor == 0) {
474 			_ix = _lPrev._x;
475 			_iy = _lPrev._y;
476 			_iz = _lPrev._z;
477 		} else {
478 #if 1
479 			// This way while possibly slower is more accurate
480 			_ix = ((_lPrev._x * (256 - factor) + _lNext._x * factor) >> 8);
481 			_iy = ((_lPrev._y * (256 - factor) + _lNext._y * factor) >> 8);
482 			_iz = ((_lPrev._z * (256 - factor) + _lNext._z * factor) >> 8);
483 #else
484 			_ix = _lPrev.x + (((_lNext.x - _lPrev.x) * factor) >> 8);
485 			_iy = _lPrev.y + (((_lNext.y - _lPrev.y) * factor) >> 8);
486 			_iz = _lPrev.z + (((_lNext.z - _lPrev.z) * factor) >> 8);
487 #endif
488 		}
489 	}
490 
491 	//! Setup the lerped info for this gametick and animate the item
492 	void setupLerp(int32 gametick);
493 
494 	//! The item has entered the fast area
495 	virtual uint32 enterFastArea();
496 
497 	//! The item has left the fast area
498 	//! \note This can destroy the object
499 	virtual void leaveFastArea();
500 
501 	//! dump some info about this item to pout
502 	void dumpInfo() const override;
503 
504 	bool loadData(Common::ReadStream *rs, uint32 version);
505 	void saveData(Common::WriteStream *ws) override;
506 
507 	// Intrinsics
508 	INTRINSIC(I_touch);
509 	INTRINSIC(I_getX);
510 	INTRINSIC(I_getY);
511 	INTRINSIC(I_getZ);
512 	INTRINSIC(I_getCX);
513 	INTRINSIC(I_getCY);
514 	INTRINSIC(I_getCZ);
515 	INTRINSIC(I_getPoint);
516 	INTRINSIC(I_getShape);
517 	INTRINSIC(I_setShape);
518 	INTRINSIC(I_getFrame);
519 	INTRINSIC(I_setFrame);
520 	INTRINSIC(I_getQuality);
521 	INTRINSIC(I_getUnkEggType);
522 	INTRINSIC(I_setUnkEggType);
523 	INTRINSIC(I_getQuantity);
524 	INTRINSIC(I_getContainer);
525 	INTRINSIC(I_getRootContainer);
526 	INTRINSIC(I_getQ);
527 	INTRINSIC(I_getQHi);
528 	INTRINSIC(I_getQLo);
529 	INTRINSIC(I_setQ);
530 	INTRINSIC(I_setQHi);
531 	INTRINSIC(I_setQLo);
532 	INTRINSIC(I_setQuality);
533 	INTRINSIC(I_setQuantity);
534 	INTRINSIC(I_setQAndCombine);
535 	INTRINSIC(I_getFamily);
536 	INTRINSIC(I_getTypeFlag);
537 	INTRINSIC(I_getStatus);
538 	INTRINSIC(I_orStatus);
539 	INTRINSIC(I_andStatus);
540 	INTRINSIC(I_getFootpadData);
541 	INTRINSIC(I_overlaps);
542 	INTRINSIC(I_overlapsXY);
543 	INTRINSIC(I_isOn);
544 	INTRINSIC(I_isCompletelyOn);
545 	INTRINSIC(I_isCentreOn);
546 	INTRINSIC(I_isInNpc);
547 	INTRINSIC(I_ascend);
548 	INTRINSIC(I_getWeight);
549 	INTRINSIC(I_getWeightIncludingContents);
550 	INTRINSIC(I_getVolume);
551 	INTRINSIC(I_bark);
552 	INTRINSIC(I_getMapArray);
553 	INTRINSIC(I_setMapArray);
554 	INTRINSIC(I_getNpcNum);
555 	INTRINSIC(I_setNpcNum);
556 	INTRINSIC(I_getDirToCoords);
557 	INTRINSIC(I_getDirFromCoords);
558 	INTRINSIC(I_getDirToItem);
559 	INTRINSIC(I_getDirFromItem);
560 	INTRINSIC(I_getDirFromTo16);
561 	INTRINSIC(I_getClosestDirectionInRange);
562 	INTRINSIC(I_look);
563 	INTRINSIC(I_use);
564 	INTRINSIC(I_gotHit);
565 	INTRINSIC(I_enterFastArea);
566 	INTRINSIC(I_cast);
567 	INTRINSIC(I_ask);
568 	INTRINSIC(I_getSliderInput);
569 	INTRINSIC(I_openGump);
570 	INTRINSIC(I_closeGump);
571 	INTRINSIC(I_create);
572 	INTRINSIC(I_legalCreateAtPoint);
573 	INTRINSIC(I_legalCreateAtCoords);
574 	INTRINSIC(I_legalCreateInCont);
575 	INTRINSIC(I_push);
576 	INTRINSIC(I_pop);
577 	INTRINSIC(I_popToCoords);
578 	INTRINSIC(I_popToContainer);
579 	INTRINSIC(I_popToEnd);
580 	INTRINSIC(I_destroy);
581 	INTRINSIC(I_move);
582 	INTRINSIC(I_legalMoveToPoint);
583 	INTRINSIC(I_legalMoveToContainer);
584 	INTRINSIC(I_hurl);
585 	INTRINSIC(I_shoot);
586 	INTRINSIC(I_fall);
587 	INTRINSIC(I_grab);
588 	INTRINSIC(I_igniteChaos);
589 	INTRINSIC(I_getFamilyOfType);
590 	INTRINSIC(I_getEtherealTop);
591 	INTRINSIC(I_guardianBark);
592 	INTRINSIC(I_getSurfaceWeight);
593 	INTRINSIC(I_isExplosive);
594 	INTRINSIC(I_receiveHit);
595 	INTRINSIC(I_explode);
596 	INTRINSIC(I_canReach);
597 	INTRINSIC(I_getRange);
598 	INTRINSIC(I_getRangeIfVisible);
599 	INTRINSIC(I_isCrusTypeNPC);
600 	INTRINSIC(I_setBroken);
601 	INTRINSIC(I_inFastArea);
602 	INTRINSIC(I_equip);
603 	INTRINSIC(I_unequip);
604 	INTRINSIC(I_avatarStoleSomething);
605 	INTRINSIC(I_isPartlyOnScreen);
606 	INTRINSIC(I_fireWeapon);
607 	INTRINSIC(I_fireDistance);
608 
609 private:
610 	uint32 _shape;   // DO NOT modify this directly! Always use setShape()!
611 
612 protected:
613 	uint32 _frame;
614 
615 	int32 _x, _y, _z; // world coordinates
616 	uint16 _flags;
617 	uint16 _quality;
618 	uint16 _npcNum;
619 	uint16 _mapNum;
620 
621 	uint32 _extendedFlags; // pentagram's own flags
622 
623 	ObjId _parent; // objid container this item is in (or 0 for top-level items)
624 
625 	mutable const Shape *_cachedShape;
626 	mutable const ShapeInfo *_cachedShapeInfo;
627 
628 	// This is stuff that is used for displaying and interpolation
629 	struct Lerped {
LerpedLerped630 		Lerped() : _x(0), _y(0), _z(0), _shape(0), _frame(0) {};
631 		int32 _x, _y, _z;
632 		uint32 _shape, _frame;
633 	};
634 
635 	Lerped  _lPrev;         // Previous state (relative to camera)
636 	Lerped  _lNext;         // Next (current) state (relative to camera)
637 	int32   _ix, _iy, _iz;  // Interpolated position in camera space
638 
639 	ObjId _gump;             // Item's gump
640 	ProcId _gravityPid;      // Item's GravityTracker (or 0)
641 
642 	uint8 _damagePoints;	// Damage points, used for item damage in Crusader
643 
644 	//! True if this is a Robot shape (in a fixed list)
645 	bool isRobotCru() const;
646 
647 	//! Scale a received damage value based on the current difficulty level
648 	//! and the type of object this is.
649 	int scaleReceivedDamageCru(int damage, uint16 type) const;
650 
651 private:
652 
653 	//! Call a Usecode Event. Use the separate functions instead!
654 	uint32 callUsecodeEvent(uint32 event, const uint8 *args = 0, int argsize = 0);
655 
656 	//! The gametick setupLerp was last called on
657 	int32 _lastSetup;
658 
659 	//! Animate the item (called by setupLerp)
660 	void animateItem();
661 
662 	//! The U8 version of receiveHit
663 	void receiveHitU8(ObjId other, Direction dir, int damage, uint16 type);
664 
665 	//! The Crusader version of receiveHit
666 	void receiveHitCru(ObjId other, Direction dir, int damage, uint16 type);
667 
668 public:
669 	enum statusflags {
670 		FLG_DISPOSABLE   = 0x0002,  //!< Item is discarded on map change
671 		FLG_OWNED        = 0x0004,  //!< Item is owned by avatar
672 		FLG_CONTAINED    = 0x0008,  //!< Item is in a container
673 		FLG_INVISIBLE    = 0x0010,  //!< Item is invisible
674 		FLG_FLIPPED      = 0x0020,  //!< Item is flipped horizontally
675 		FLG_IN_NPC_LIST  = 0x0040,  //!< Item is a NPC
676 		FLG_FAST_ONLY    = 0x0080,  //!< Item is discarded when leaving fast area
677 		FLG_GUMP_OPEN    = 0x0100,  //!< Item has a gump open
678 		FLG_EQUIPPED     = 0x0200,  //!< Item is equipped
679 		FLG_BOUNCING     = 0x0400,  //!< Item has bounced
680 		FLG_ETHEREAL     = 0x0800,  //!< Item is in the ethereal list - confirmed same meaning in crusader
681 		FLG_HANGING      = 0x1000,  //!< Item is suspended in the air
682 		FLG_FASTAREA     = 0x2000,  //!< Item is in the fast area
683 		FLG_LOW_FRICTION = 0x4000,  //!< Item has low friction
684 		FLG_BROKEN       = 0x8000   //!< Item is broken - Crusader only - broken items are not targetable.
685 	};
686 
687 	enum extflags {
688 		EXT_FIXED        = 0x0001,  //!< Item came from FIXED
689 		EXT_INCURMAP     = 0x0002,  //!< Item is in a CurrentMap display list
690 		EXT_LERP_NOPREV  = 0x0008,  //!< Item can't be lerped this frame
691 		EXT_HIGHLIGHT    = 0x0010,  //!< Item should be Painted highlighted
692 		EXT_CAMERA       = 0x0020,  //!< Item is being followed by the camera
693 		EXT_SPRITE       = 0x0040,  //!< Item is a sprite
694 		EXT_TRANSPARENT  = 0x0080,  //!< Item should be painted transparent
695 		EXT_PERMANENT_NPC = 0x0100, //!< Item is a permanent NPC
696 		EXT_TARGET 		 = 0x0200,  //!< Item is the current reticle target in Crusader
697 		EXT_FEMALE       = 0x8000	//!< Item is Crusader Female NPC (controls sfx)
698 	};
699 };
700 
getShapeInfo()701 inline const ShapeInfo *Item::getShapeInfo() const {
702 	if (!_cachedShapeInfo)
703 		_cachedShapeInfo = getShapeInfoFromGameInstance();
704 	return _cachedShapeInfo;
705 }
706 
getFootpadData(int32 & X,int32 & Y,int32 & Z)707 inline void Item::getFootpadData(int32 &X, int32 &Y, int32 &Z) const {
708 	const ShapeInfo *si = getShapeInfo();
709 	Z = si->_z;
710 
711 	if (_flags & Item::FLG_FLIPPED) {
712 		X = si->_y;
713 		Y = si->_x;
714 	} else {
715 		X = si->_x;
716 		Y = si->_y;
717 	}
718 }
719 
720 // like getFootpadData, but scaled to world coordinates
getFootpadWorld(int32 & X,int32 & Y,int32 & Z)721 inline void Item::getFootpadWorld(int32 &X, int32 &Y, int32 &Z) const {
722 	const ShapeInfo *si = getShapeInfo();
723 	si->getFootpadWorld(X, Y, Z, _flags & Item::FLG_FLIPPED);
724 }
725 
getLocation(int32 & X,int32 & Y,int32 & Z)726 inline void Item::getLocation(int32 &X, int32 &Y, int32 &Z) const {
727 	X = _x;
728 	Y = _y;
729 	Z = _z;
730 }
731 
getLocation(Point3 & pt)732 inline void Item::getLocation(Point3 &pt) const {
733 	pt.x = _x;
734 	pt.y = _y;
735 	pt.z = _z;
736 }
737 
738 } // End of namespace Ultima8
739 } // End of namespace Ultima
740 
741 #endif
742