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 * Based on the original sources
23 * Faery Tale II -- The Halls of the Dead
24 * (c) 1993-1996 The Wyrmkeep Entertainment Co.
25 */
26
27 #ifndef SAGA2_OBJECTS_H
28 #define SAGA2_OBJECTS_H
29
30 #include "saga2/objproto.h"
31 #include "saga2/property.h"
32
33 namespace Saga2 {
34
35 /* ======================================================================= *
36 GameObject: Describes an instance of an object
37 * ======================================================================= */
38
39 class GameWorld;
40
41 const uint16 unlimitedCapacity = maxuint16;
42
43 enum ActorManaID {
44 manaIDRed = 0,
45 manaIDOrange,
46 manaIDYellow,
47 manaIDGreen,
48 manaIDBlue,
49 manaIDViolet,
50
51 numManas
52 };
53
54 // Used to indicate if objects can be stacked or merged
55 enum {
56 cannotStackOrMerge = 0,
57 canStack,
58 canMerge
59 };
60
61 // The ResourceGameObject structure represents the game object data as
62 // it is structured in the resource file.
63
64 struct ResourceGameObject {
65 int16 protoIndex;
66 TilePoint location;
67 uint16 nameIndex;
68 ObjectID parentID;
69 uint16 script;
70 uint16 objectFlags;
71 uint8 hitPoints;
72 uint16 misc;
73
74 ResourceGameObject(Common::SeekableReadStream *stream);
75 };
76
77 // Base class of all objects
78 //
79 // Unlike the object prototypes, the only subclass of GameObject is
80 // the actor subclass, which is kept in an entirely seperate table.
81 // This allows all objects to be kept in an array (indexed by ID number)
82
83 #include "common/pack-start.h"
84
85 struct ObjectData {
86 uint32 projectDummy;
87 TilePoint location; // where object is located.
88 uint16 nameIndex; // object's proper name, if any
89 ObjectID parentID, // ID of parent object
90 siblingID, // ID of next in chain
91 childID; // ID of 1st child
92 uint16 script; // script attached to this object
93 uint16 objectFlags; // various flags
94 uint8 hitPoints; // object hit points
95 uint8 bParam; // number of spell charges an object has
96 // (also generator radius in metatiles)
97 union {
98 uint16 massCount; // for mergeables, object count
99 uint16 textStringID; // inscription for documents
100 uint16 enchantmentType; // for enchantments
101 uint16 generatorFrequency; // for encounter and mission generators
102 };
103
104 uint8 missileFacing;
105 ActiveItemID currentTAG; // ActiveItem object is on
106 uint8 sightCtr; // Line of sight counter
107
108 uint8 reserved[2];
109
110 GameObject *obj;
111 } PACKED_STRUCT;
112
113 #include "common/pack-end.h"
114
115 void initActors(void);
116 void saveActors(Common::OutSaveFile *outS);
117 void loadActors(Common::InSaveFile *in);
118 void cleanupActors(void);
119 class GameObject {
120
121 friend void initWorlds(void);
122 friend void cleanupWorlds(void);
123
124 friend void initObjects(void);
125 friend void saveObjects(Common::OutSaveFile *out);
126 friend void loadObjects(Common::InSaveFile *in);
127 friend void cleanupObjects(void);
128
129 friend void buildDisplayList(void);
130 friend void drawDisplayList(void);
131 friend void setMindContainer(int NewContainerClass, IntangibleContainerWindow &cw);
132 friend class EnchantmentContainerWindow;
133 friend bool Enchantment(ObjectID, ObjectID);
134 friend class ProtoObj;
135 friend class PhysicalContainerProto;
136 friend class IntangibleContainerProto;
137 friend class KeyProto;
138 friend class BottleProto;
139 friend class SkillProto;
140 friend class ActorProto;
141 friend class MotionTask;
142 friend class MotionTaskList;
143 friend class ObjectIterator;
144 friend class ContainerIterator;
145 friend class RecursiveContainerIterator;
146 friend class ShopMode;
147
148
149
150 private:
151
152 // container info
153 enum {
154 maxRow = 20,
155 maxCol = 4
156 };
157
158 public:
159
160 ObjectID thisID(void); // calculate our own ID value
161
162 static const char *nameText(uint16 index);
163
164 protected:
165 // get address of head-of-chain id.
166 static ObjectID *getHeadPtr(ObjectID parentID, TilePoint &l);
167
168 // Object list management functions
169 void remove(void); // removes from old list
170 void append(ObjectID newParent); // adds to new list (no remove)
171 void insert(ObjectID newPrev); // inserts after this item (no remove)
172
173 ProtoObj *prototype; // object that defines our behavior
174 public:
175 ObjectData _data;
176 uint _index;
177 bool _godmode;
178 // Default constructor
179 GameObject(void);
180
181 // Constructor -- initial construction
182 GameObject(const ResourceGameObject &res);
183
184 GameObject(Common::InSaveFile *in);
185
186 void read(Common::InSaveFile *in, bool expandProto);
187
188 // Return the number of bytes needed to archive this object in
189 // a buffer
190 int32 archiveSize(void);
191
192 void write(Common::MemoryWriteStreamDynamic *out, bool expandProto);
193
194 // returns the address of the object based on the ID, and this
195 // includes accounting for actors.
196 static GameObject *objectAddress(ObjectID id);
197
198 // Converts object ID into prototype address...
199 static ProtoObj *protoAddress(ObjectID id);
200
201 // Returns first object id found associate with the given name index
202 static int32 nameIndexToID(uint16 ind);
203
204 // Returns first object id found assciated with the given name
205 static Common::Array<ObjectID> nameToID(Common::String name);
206
207 // object creation and deletion
208 static GameObject *newObject(void); // get a newly created object
209 void deleteObject(void); // delete this object and remove
210 void deleteObjectRecursive(void); // delete this object and every
211 // object it contains
212
213 // Return pointer to parent/child/next sibling object, if any
parent(void)214 GameObject *parent(void) {
215 return _data.parentID == Nothing ? NULL : objectAddress(_data.parentID);
216 }
next(void)217 GameObject *next(void) {
218 return _data.siblingID == Nothing ? NULL : objectAddress(_data.siblingID);
219 }
child(void)220 GameObject *child(void) {
221 return _data.childID == Nothing ? NULL : objectAddress(_data.childID);
222 }
223
224 // Return ID of parent/child/next sibling object, if any
IDParent(void)225 ObjectID IDParent(void) {
226 return _data.parentID ;
227 }
IDNext(void)228 ObjectID IDNext(void) {
229 return _data.siblingID;
230 }
IDChild(void)231 ObjectID IDChild(void) {
232 return _data.childID ;
233 }
234
235 // Return a pointer to the world on which this object resides
236 GameWorld *world(void);
237
238 // Return the number of the map of the world on which this object
239 // resides
240 int16 getMapNum(void);
241
242 // graphics functions
243 int16 sprNum(int16 state); // returns current sprite number
244
245 // gets the offset to the spr image according to masscount for mergeables
246 int32 getSprOffset(int16 num = -1);
247
248 // completely restore the magical energy of a magical object
249 void recharge(void);
250
251 // returns the type of charge an object has
252 // be it none, red, violet, etc...
253 int16 getChargeType(void);
254
255 // use charge of this object
256 bool deductCharge(ActorManaID manaID, uint16 manaCost);
257
258 // check charge of this object
259 bool hasCharge(ActorManaID manaID, uint16 manaCost);
260
261 // context-changing functions
262 void setLocation(const Location &loc); // move to new location in world
263 void setLocation(const TilePoint &tp); // move to new location in world
264 void move(const Location &loc); // move to new location in world
265 void move(const Location &loc, int16 num); // move to new location in world
266 void move(const TilePoint &tp); // move to new location in world
267 void updateImage(ObjectID); // move to new location in world,
268 // (assumes setLocation has been called)
269
270 // Remove an object from a stack of objects. Returns true if it was in a stack.
271 bool unstack(void);
272
273 // this correctly moves merged or stacked objects
274 bool moveMerged(const Location &loc);
275 bool moveMerged(const Location &loc, int16 num = 1);
276 bool moveMerged(const TilePoint &tp);
277
278 // Extract a merged object with specified merge number from another
279 // merged object and return its ID
280 ObjectID extractMerged(const Location &loc, int16 num);
281 GameObject *extractMerged(int16 num);
282
283 void moveRandom(const TilePoint &minLoc, const TilePoint &maxLoc); //move to random location Between Two Points
284
285 ObjectID copy(const Location &loc); // copy item to new context
286 ObjectID copy(const Location &loc, int16 num); // copy item to new context
287
288 // Create an alias of this object
289 ObjectID makeAlias(const Location &loc);
290
291 // move the item with a given context
292 void move(int16 slot); // move to new slot in container
293
294 // Activate the object
295 void activate(void);
296
297 // Deactivate this object
298 void deactivate(void);
299
300 // Determine if this object is an alias for another object
isAlias()301 bool isAlias() {
302 return (_data.objectFlags & objectAlias) != 0;
303 }
304
305 // check to see if item can be contained by this object
canContain(ObjectID item)306 bool canContain(ObjectID item) {
307 return prototype->canContain(thisID(), item);
308 }
309
310 // check to see if item is contained by the object
311 bool isContaining(GameObject *item);
312
313 // check if an instance of the specified target is contained in
314 // this object
315 bool isContaining(ObjectTarget *objTarget);
316
317 // determine wether this object has a specified property
hasProperty(const ObjectProperty & objProp)318 bool hasProperty(const ObjectProperty &objProp) {
319 return objProp.operator()(this);
320 }
321
322 // Return the location of the first empty slot
323 TilePoint getFirstEmptySlot(GameObject *obj);
324
325 // Return the location of the first available slot within this object
326 // in which to place the specified object
327 bool getAvailableSlot(
328 GameObject *obj,
329 TilePoint *slot,
330 bool canMerge = false,
331 GameObject **mergeObj = NULL);
332
333 // Find a slot to place the specified object within this object and
334 // drop it in that slot
335 // If merge count == 0, then no auto-merging allowed
336 bool placeObject(
337 ObjectID enactor,
338 ObjectID objID,
339 bool canMerge = false,
340 int16 num = 1);
341
342 // Drop the specified object on the ground in a semi-random location
343 void dropInventoryObject(GameObject *obj, int16 count = 1);
344
345 //Get Specific Container From Object
346 GameObject *getIntangibleContainer(int containerType);
347
348 // generic actions
use(ObjectID enactor)349 bool use(ObjectID enactor) {
350 return prototype->use(thisID(), enactor);
351 }
useOn(ObjectID enactor,ObjectID item)352 bool useOn(ObjectID enactor, ObjectID item) {
353 return prototype->useOn(thisID(), enactor, item);
354 }
355
useOn(ObjectID enactor,ActiveItem * item)356 bool useOn(ObjectID enactor, ActiveItem *item) {
357 return prototype->useOn(thisID(), enactor, item);
358 }
359
useOn(ObjectID enactor,Location & loc)360 bool useOn(ObjectID enactor, Location &loc) {
361 return prototype->useOn(thisID(), enactor, loc);
362 }
363
364 // various verb actions that can take place
365 bool take(ObjectID enactor, int16 num = 1) {
366 return prototype->take(thisID(), enactor, num);
367 }
368 bool drop(ObjectID enactor, const Location &l, int16 num = 1) {
369 return prototype->drop(thisID(), enactor, l, num);
370 }
371 // drop an object onto another object and handle the result.
372 bool dropOn(ObjectID enactor, ObjectID target, int16 num = 1) {
373 return prototype->dropOn(thisID(), enactor, target, num);
374 }
375 // drop this object on a TAG
376 bool dropOn(ObjectID enactor, ActiveItem *target, const Location &loc, int16 num = 1) {
377 return prototype->dropOn(thisID(), enactor, target, loc, num);
378 }
open(ObjectID enactor)379 bool open(ObjectID enactor) {
380 return prototype->open(thisID(), enactor);
381 }
close(ObjectID enactor)382 bool close(ObjectID enactor) {
383 return prototype->close(thisID(), enactor);
384 }
strike(ObjectID enactor,ObjectID item)385 bool strike(ObjectID enactor, ObjectID item) {
386 return prototype->strike(thisID(), enactor, item);
387 }
damage(ObjectID enactor,ObjectID target)388 bool damage(ObjectID enactor, ObjectID target) {
389 return prototype->damage(thisID(), enactor, target);
390 }
eat(ObjectID enactor)391 bool eat(ObjectID enactor) {
392 return prototype->eat(thisID(), enactor);
393 }
insert(ObjectID enactor,ObjectID item)394 bool insert(ObjectID enactor, ObjectID item) {
395 return prototype->insert(thisID(), enactor, item);
396 }
remove(ObjectID enactor)397 bool remove(ObjectID enactor) {
398 return prototype->remove(thisID(), enactor);
399 }
acceptDrop(ObjectID enactor,ObjectID droppedObj,int count)400 bool acceptDrop(ObjectID enactor, ObjectID droppedObj, int count) {
401 return prototype->acceptDrop(thisID(), enactor, droppedObj, count);
402 }
403 bool acceptDamage(
404 ObjectID enactor,
405 int8 absDamage,
406 effectDamageTypes dType = kDamageOther,
407 int8 dice = 0,
408 uint8 sides = 1,
409 int8 perDieMod = 0) {
410 if (_godmode)
411 return false;
412
413 return prototype->acceptDamage(
414 thisID(),
415 enactor,
416 absDamage,
417 dType,
418 dice,
419 sides,
420 perDieMod);
421 }
422 bool acceptHealing(ObjectID enactor, int8 absDamage, int8 dice = 0, uint8 sides = 1, int8 perDieMod = 0) {
423 return prototype->acceptHealing(thisID(), enactor, absDamage, dice, sides, perDieMod);
424 }
acceptStrike(ObjectID enactor,ObjectID strikingObj,uint8 skillIndex)425 bool acceptStrike(
426 ObjectID enactor,
427 ObjectID strikingObj,
428 uint8 skillIndex) {
429 return prototype->acceptStrike(
430 thisID(),
431 enactor,
432 strikingObj,
433 skillIndex);
434 }
acceptLockToggle(ObjectID enactor,uint8 keyCode)435 bool acceptLockToggle(ObjectID enactor, uint8 keyCode) {
436 return prototype->acceptLockToggle(thisID(), enactor, keyCode);
437 }
acceptMix(ObjectID enactor,ObjectID mixObj)438 bool acceptMix(ObjectID enactor, ObjectID mixObj) {
439 return prototype->acceptMix(thisID(), enactor, mixObj);
440 }
acceptInsertion(ObjectID enactor,ObjectID item,int16 count)441 bool acceptInsertion(ObjectID enactor, ObjectID item, int16 count) {
442 return prototype->acceptInsertion(thisID(), enactor, item, count);
443 }
444 bool acceptInsertionAt(ObjectID enactor, ObjectID item, const TilePoint &where, int16 num = 1) {
445 return prototype->acceptInsertionAt(thisID(), enactor, item, where, num);
446 }
447
448 // query functions:
449 ObjectID possessor(void); // return actor posessing this object
450
451 // Access functions
proto(void)452 ProtoObj *proto(void) {
453 return prototype;
454 }
getLocation(void)455 TilePoint getLocation(void) const {
456 return _data.location;
457 }
458 TilePoint getWorldLocation(void);
459 bool getWorldLocation(Location &loc);
460 Location notGetLocation(void);
461 Location notGetWorldLocation(void);
462
463 // Return the name of this object (proper noun if it has one)
objName(void)464 const char *objName(void) {
465 if (_data.nameIndex > 0)
466 return nameText((int16)_data.nameIndex);
467 else if (prototype)
468 return nameText((int16)prototype->nameIndex);
469
470 return nameText(0);
471 }
472
473 // return name of object, and it's quantity if merged
474 void objCursorText(char nameBuf[], const int8 size, int16 count = -1);
475
476 // find out if this is a trueskill
477 bool isTrueSkill(void);
478
479 // Access functions for name index
getNameIndex(void)480 uint16 getNameIndex(void) {
481 return _data.nameIndex;
482 }
setNameIndex(uint16 n)483 void setNameIndex(uint16 n) {
484 _data.nameIndex = n;
485 }
486
487 // Return the name of this type of object
protoName(void)488 const char *protoName(void) {
489 return nameText(prototype->nameIndex);
490 }
491
492 // Update the state of this object. This function is called every
493 // frame for every active object.
494 void updateState(void);
495
496 // Flag test functions
isOpen(void)497 bool isOpen(void) {
498 return (int16)(_data.objectFlags & objectOpen);
499 }
isLocked(void)500 bool isLocked(void) {
501 return (int16)(_data.objectFlags & objectLocked);
502 }
isImportant(void)503 bool isImportant(void) {
504 return (int16)(_data.objectFlags & objectImportant);
505 }
isGhosted(void)506 bool isGhosted(void) {
507 return (_data.objectFlags & objectGhosted)
508 || (prototype->flags & ResourceObjectPrototype::objPropGhosted);
509 }
isInvisible(void)510 bool isInvisible(void) {
511 return (_data.objectFlags & objectInvisible)
512 || (prototype->flags & ResourceObjectPrototype::objPropHidden);
513 }
isMoving(void)514 bool isMoving(void) {
515 return (int16)(_data.objectFlags & objectMoving);
516 }
isActivated(void)517 bool isActivated(void) {
518 return (int16)(_data.objectFlags & objectActivated);
519 }
520
setScavengable(bool val)521 void setScavengable(bool val) {
522 if (val)
523 _data.objectFlags |= objectScavengable;
524 else
525 _data.objectFlags &= ~objectScavengable;
526 }
isScavengable(void)527 bool isScavengable(void) {
528 return (_data.objectFlags & objectScavengable) != 0;
529 }
530
setObscured(bool val)531 void setObscured(bool val) {
532 if (val)
533 _data.objectFlags |= objectObscured;
534 else
535 _data.objectFlags &= ~objectObscured;
536 }
isObscured(void)537 bool isObscured(void) {
538 return (_data.objectFlags & objectObscured) != 0;
539 }
540
setTriggeringTAG(bool val)541 void setTriggeringTAG(bool val) {
542 if (val)
543 _data.objectFlags |= objectTriggeringTAG;
544 else
545 _data.objectFlags &= ~objectTriggeringTAG;
546 }
isTriggeringTAG(void)547 bool isTriggeringTAG(void) {
548 return (_data.objectFlags & objectTriggeringTAG) != 0;
549 }
550
setOnScreen(bool val)551 void setOnScreen(bool val) {
552 if (val)
553 _data.objectFlags |= objectOnScreen;
554 else
555 _data.objectFlags &= ~objectOnScreen;
556 }
isOnScreen(void)557 bool isOnScreen(void) {
558 return (_data.objectFlags & objectOnScreen) != 0;
559 }
560
setSightedByCenter(bool val)561 void setSightedByCenter(bool val) {
562 if (val)
563 _data.objectFlags |= objectSightedByCenter;
564 else
565 _data.objectFlags &= ~objectSightedByCenter;
566 }
isSightedByCenter(void)567 bool isSightedByCenter(void) {
568 return (_data.objectFlags & objectSightedByCenter) != 0;
569 }
570
isMissile(void)571 bool isMissile(void) {
572 return prototype->isMissile();
573 }
574
575 // image data
576 Sprite *getIconSprite(void); // sprite when in inventory + cursor
577 Sprite *getGroundSprite(void); // sprite when on ground
578
579 // world interaction type flags
580 uint16 containmentSet(void);
581
scriptClass(void)582 uint16 scriptClass(void) {
583 if (_data.script)
584 return _data.script;
585 if (prototype)
586 return prototype->script;
587 return 0;
588 }
589
590 // General access functions
591
592 // Script access functions
getScript(void)593 uint16 getScript(void) {
594 return _data.script;
595 }
setScript(uint16 scr)596 void setScript(uint16 scr) {
597 _data.script = scr;
598 }
599
600 // access function to set object flags
setFlags(uint8 newval,uint8 changeMask)601 void setFlags(uint8 newval, uint8 changeMask) {
602 // Only change the flags spec'd by changeFlags
603 _data.objectFlags = (newval & changeMask)
604 | (_data.objectFlags & ~changeMask);
605 }
606
607 // Access functions for hit points
getHitPoints(void)608 uint8 getHitPoints(void) {
609 return _data.hitPoints;
610 }
setHitPoints(uint8 hp)611 void setHitPoints(uint8 hp) {
612 _data.hitPoints = hp;
613 }
614
615 // Builds the color remapping for this object based on the
616 // prototype's color map
getColorTranslation(ColorTable map)617 void getColorTranslation(ColorTable map) {
618 prototype->getColorTranslation(map);
619 }
620
621 // Functions to get and set prototype (used by scripts)
622 int32 getProtoNum(void);
623 void setProtoNum(int32 nProto);
624
625 // Acess functions for extra data
getExtra(void)626 uint16 getExtra(void) {
627 return _data.massCount;
628 }
setExtra(uint16 x)629 void setExtra(uint16 x) {
630 _data.massCount = x;
631 }
632
633 // Function to evaluate the effects of all enchantments
634 void evalEnchantments(void);
635
makeSavingThrow(void)636 bool makeSavingThrow(void) {
637 return prototype->makeSavingThrow();
638 }
639
640 // Generic range checking function
641 bool inRange(const TilePoint &tp, uint16 range);
642
643 // Generic function to test if object can be picked up
isCarryable(void)644 bool isCarryable(void) {
645 return prototype->mass <= 200 && prototype->bulk <= 200;
646 }
647
isMergeable(void)648 bool isMergeable(void) {
649 return (prototype->flags & ResourceObjectPrototype::objPropMergeable) != 0;
650 }
651
652 // A timer for this object has ticked
653 void timerTick(TimerID timer);
654
655 // A sensor for this object has sensed an object
656 void senseObject(SensorID sensor, ObjectID sensedObj);
657
658 // A sensor for this object has sensed an event
659 void senseEvent(
660 SensorID sensor,
661 int16 type,
662 ObjectID directObject,
663 ObjectID indirectObject);
664
665 // Timer related member functions
666 bool addTimer(TimerID id);
667 bool addTimer(TimerID id, int16 frameInterval);
668 void removeTimer(TimerID id);
669 void removeAllTimers(void);
670
671 // Sensor related member functions
672 private:
673 bool addSensor(Sensor *newSensor);
674 public:
675 bool addProtaganistSensor(SensorID id, int16 range);
676 bool addSpecificActorSensor(SensorID id, int16 range, Actor *a);
677 bool addSpecificObjectSensor(SensorID id, int16 range, ObjectID obj);
678 bool addActorPropertySensor(
679 SensorID id,
680 int16 range,
681 ActorPropertyID prop);
682 bool addObjectPropertySensor(
683 SensorID id,
684 int16 range,
685 ObjectPropertyID prop);
686 bool addEventSensor(SensorID id, int16 range, int16 eventType);
687 void removeSensor(SensorID id);
688 void removeAllSensors(void);
689
690 bool canSenseProtaganist(SenseInfo &info, int16 range);
691 bool canSenseSpecificActor(SenseInfo &info, int16 range, Actor *a);
692 bool canSenseSpecificObject(SenseInfo &info, int16 range, ObjectID obj);
693 bool canSenseActorProperty(
694 SenseInfo &info,
695 int16 range,
696 ActorPropertyID prop);
697 bool canSenseObjectProperty(
698 SenseInfo &info,
699 int16 range,
700 ObjectPropertyID prop);
701
702 static int32 canStackOrMerge(GameObject *dropObj, GameObject *target);
703 static void mergeWith(GameObject *dropObj, GameObject *target, int16 count);
704
705 bool merge(ObjectID enactor, ObjectID objToMergeID, int16 count);
706 bool stack(ObjectID enactor, ObjectID objToStackID);
707
canFitBulkwise(GameObject * obj)708 bool canFitBulkwise(GameObject *obj) {
709 return prototype->canFitBulkwise(this, obj);
710 }
canFitMasswise(GameObject * obj)711 bool canFitMasswise(GameObject *obj) {
712 return prototype->canFitMasswise(this, obj);
713 }
714
715 uint16 totalContainedMass(void);
716 uint16 totalContainedBulk(void);
717
totalMass(void)718 uint16 totalMass(void) {
719 return prototype->mass * (isMergeable() ? getExtra() : 1)
720 + totalContainedMass();
721 }
totalBulk(void)722 uint16 totalBulk(void) {
723 return prototype->bulk * (isMergeable() ? getExtra() : 1);
724 }
725
massCapacity(void)726 uint16 massCapacity(void) {
727 return prototype->massCapacity(this);
728 }
bulkCapacity(void)729 uint16 bulkCapacity(void) {
730 return prototype->bulkCapacity(this);
731 }
732 };
733
734 /* ===================================================================== *
735 Sector struct
736 * ===================================================================== */
737
738 class Sector {
739 public:
740 uint16 activationCount;
741 ObjectID childID;
742
Sector(void)743 Sector(void) :
744 activationCount(0),
745 childID(Nothing) {
746 }
747
isActivated(void)748 bool isActivated(void) {
749 return activationCount != 0;
750 }
751
752 void activate(void);
753 void deactivate(void);
754
755 void write(Common::MemoryWriteStreamDynamic *out);
756 void read(Common::InSaveFile *in);
757 };
758
759 /* ======================================================================= *
760 GameWorld: Describes a world within the game
761 * ======================================================================= */
762
763 // Terminology note: A "sector" is a small portion of a map.
764 // All objects within a sector are stored on a single list.
765
766 // The size of a sector (length of side) in UV coodinates.
767 // A sector is an area of about 4x4 metatiles.
768
769 class GameWorld : public GameObject {
770
771 friend void initWorlds(void);
772 friend void cleanupWorlds(void);
773 friend void buildDisplayList(void);
774
775 friend class ProtoObj;
776 friend class GameObject;
777 friend class ObjectIterator;
778
779 public:
780 TilePoint size; // size of world in U/V coords
781 int16 sectorArraySize; // size of sector array
782 Sector *sectorArray; // array of sectors
783 int16 mapNum; // map number for this world.
784
785 // Default constructor
GameWorld(void)786 GameWorld(void) : sectorArraySize(0), sectorArray(nullptr), mapNum(0) {}
787
788 // Initial constructor
789 GameWorld(int16 map);
790
791 GameWorld(Common::SeekableReadStream *stream);
792
793 ~GameWorld();
794
795 int32 archiveSize(void);
796
797 void cleanup(void);
798
getSector(int16 u,int16 v)799 Sector *getSector(int16 u, int16 v) {
800 if (u == -1 && v == -1)
801 return nullptr;
802
803 if (v * sectorArraySize + u >= sectorArraySize * sectorArraySize ||
804 v * sectorArraySize + u < 0) {
805 warning("Sector::getSector: Invalid sector: (%d, %d) (sectorArraySize = %d)", u, v, sectorArraySize);
806 return nullptr;
807 }
808
809 return &(sectorArray)[v * sectorArraySize + u];
810 }
811
sectorSize(void)812 TilePoint sectorSize(void) { // size of map in sectors
813 return TilePoint(sectorArraySize, sectorArraySize, 0);
814 }
815
IDtoMapNum(ObjectID id)816 static uint32 IDtoMapNum(ObjectID id) {
817 assert(isWorld(id));
818 return ((GameWorld *)GameObject::objectAddress(id))->mapNum;
819 }
820 };
821
822 void setCurrentWorld(ObjectID worldID);
823
824 extern GameWorld *currentWorld;
825
826 /* ======================================================================= *
827 GameObject inline member function
828 * ======================================================================= */
829
830 //------------------------------------------------------------------------
831 // Return the number of the map of the world on which this object resides.
832
getMapNum(void)833 inline int16 GameObject::getMapNum(void) {
834 if (world())
835 return world()->mapNum;
836 else if (_data.siblingID) {
837 GameObject *sibling = GameObject::objectAddress(_data.siblingID);
838 return sibling->getMapNum();
839 } else
840 return currentWorld->mapNum;
841 }
842
843 /* ======================================================================= *
844 Enchantment Class
845 * ======================================================================= */
846 //class Enchantment {
847 //
848 //public:
849 // Enchantment(ObjectID Skill,ObjectID Obj);
850 // ~Enchantment();
851 //
852 //};
853
854 /* ===================================================================== *
855 ActiveRegion class
856 * ===================================================================== */
857
858 class ActiveRegion {
859
860 friend void initActiveRegions(void);
861 friend void cleanupActiveRegions(void);
862
863 friend class ActiveRegionObjectIterator;
864
865 ObjectID anchor; // ID of object this region is attached to
866 TilePoint anchorLoc; // Location of anchor
867 ObjectID worldID;
868 TileRegion region; // Region coords ( in sectors )
869
870 public:
871
872 enum {
873 kActiveRegionSize = 22
874 };
875
ActiveRegion()876 ActiveRegion() : anchor(0), worldID(0) {}
877 void update(void);
878
879 void read(Common::InSaveFile *in);
880 void write(Common::MemoryWriteStreamDynamic *out);
881
882 // Return the current region in tile point coords
getRegion(void)883 TileRegion getRegion(void) {
884 TileRegion tReg;
885
886 tReg.min.u = region.min.u << kSectorShift;
887 tReg.min.v = region.min.v << kSectorShift;
888 tReg.max.u = region.max.u << kSectorShift;
889 tReg.max.v = region.max.v << kSectorShift;
890 tReg.min.z = tReg.max.z = 0;
891
892 return tReg;
893 }
894
895 // Return the region world
getWorld(void)896 GameWorld *getWorld(void) {
897 return (GameWorld *)GameObject::objectAddress(worldID);
898 }
899 };
900
901 void updateActiveRegions(void);
902
903 // Return a pointer to an active region given its PlayerActor's ID
904 ActiveRegion *getActiveRegion(PlayerActorID id);
905
906 void initActiveRegions(void);
907 void saveActiveRegions(Common::OutSaveFile *outS);
908 void loadActiveRegions(Common::InSaveFile *in);
cleanupActiveRegions(void)909 inline void cleanupActiveRegions(void) {}
910
911 /* ======================================================================= *
912 ObjectIterator Class
913 * ======================================================================= */
914
915 // This class simply defines a standard interface for all derived
916 // object iterator classes.
917
918 class ObjectIterator {
919 public:
920 // Virtual destructor
~ObjectIterator(void)921 virtual ~ObjectIterator(void) {}
922
923 // Iteration functions
924 virtual ObjectID first(GameObject **obj) = 0;
925 virtual ObjectID next(GameObject **obj) = 0;
926 };
927
928 /* ======================================================================= *
929 SectorRegionObjectIterator Class
930 * ======================================================================= */
931
932 // This class iterates through every object within a given region of
933 // sectors.
934
935 class SectorRegionObjectIterator : public ObjectIterator {
936
937 TilePoint minSector,
938 maxSector,
939 sectorCoords;
940 GameWorld *searchWorld;
941 GameObject *_currentObject;
942
943 public:
944 // Constructor
945 SectorRegionObjectIterator(GameWorld *world);
946
947 // Constructor
SectorRegionObjectIterator(GameWorld * world,const TileRegion & sectorRegion)948 SectorRegionObjectIterator(
949 GameWorld *world,
950 const TileRegion §orRegion) :
951 searchWorld(world),
952 minSector(sectorRegion.min),
953 maxSector(sectorRegion.max),
954 _currentObject(nullptr) {
955 assert(searchWorld != NULL);
956 assert(isWorld(searchWorld));
957 }
958
959 protected:
getSearchWorld(void)960 GameWorld *getSearchWorld(void) {
961 return searchWorld;
962 }
963
964 public:
965 // Iteration functions
966 ObjectID first(GameObject **obj);
967 ObjectID next(GameObject **obj);
968 };
969
970 /* ======================================================================= *
971 RadialObjectIterator Class
972 * ======================================================================= */
973
974 // This class will iterate through all objects within a given radius of
975 // a given center point.
976
977 class RadialObjectIterator : public SectorRegionObjectIterator {
978 private:
979
980 TilePoint center;
981 int16 radius;
982
983 // Compute the region of sectors to pass to the ObjectIterator
984 // constructor
985 static TileRegion computeSectorRegion(
986 const TilePoint §ors,
987 const TilePoint ¢er,
988 int16 radius);
989
990 // Compute the distance to the specified point from the search
991 // center
992 virtual int16 computeDist(const TilePoint &tp) = 0;
993
994 protected:
995
996 // Simply return the center coordinates
getCenter(void)997 TilePoint getCenter(void) {
998 return center;
999 }
1000
1001 public:
1002
1003 // Constructor
RadialObjectIterator(GameWorld * world,const TilePoint & searchCenter,int16 distance)1004 RadialObjectIterator(
1005 GameWorld *world,
1006 const TilePoint &searchCenter,
1007 int16 distance) :
1008 SectorRegionObjectIterator(
1009 world,
1010 computeSectorRegion(
1011 world->sectorSize(),
1012 searchCenter,
1013 distance)),
1014 center(searchCenter),
1015 radius(distance) {
1016 }
1017
1018 // Return the first object found
1019 ObjectID first(GameObject **obj, int16 *dist);
1020 // Return the next object found
1021 ObjectID next(GameObject **obj, int16 *dist);
1022
1023 // Return the first object found
first(GameObject ** obj)1024 ObjectID first(GameObject **obj) {
1025 return first(obj, NULL);
1026 }
1027 // Return the next object found
next(GameObject ** obj)1028 ObjectID next(GameObject **obj) {
1029 return next(obj, NULL);
1030 }
1031 };
1032
1033 /* ======================================================================= *
1034 CircularObjectIterator Class
1035 * ======================================================================= */
1036
1037 // Iterate through all objects within a circular region
1038
1039 class CircularObjectIterator : public RadialObjectIterator {
1040 protected:
1041
1042 // Compute the distance to the specified point from the center
1043 int16 computeDist(const TilePoint &tp);
1044
1045 public:
1046 // Constructor
CircularObjectIterator(GameWorld * world,const TilePoint & searchCenter,int16 distance)1047 CircularObjectIterator(
1048 GameWorld *world,
1049 const TilePoint &searchCenter,
1050 int16 distance) :
1051 RadialObjectIterator(world, searchCenter, distance) {
1052 }
1053 };
1054
1055 /* ======================================================================= *
1056 RingObjectIterator Class
1057 * ======================================================================= */
1058
1059 // Iterate through all objects within a circular region
1060
1061 class RingObjectIterator : public CircularObjectIterator {
1062 private:
1063
1064 int16 innerDist;
1065
1066 public:
1067 // Constructor
RingObjectIterator(GameWorld * world,const TilePoint & searchCenter,int16 outerDistance,int16 innerDistance)1068 RingObjectIterator(
1069 GameWorld *world,
1070 const TilePoint &searchCenter,
1071 int16 outerDistance,
1072 int16 innerDistance) :
1073 CircularObjectIterator(world, searchCenter, outerDistance) {
1074 innerDist = innerDistance;
1075 }
1076
1077 ObjectID first(GameObject **obj);
1078 ObjectID next(GameObject **obj);
1079 };
1080
1081 /* ======================================================================= *
1082 DispRegionObjectIterator Class
1083 * ======================================================================= */
1084
1085 // Iterate through all objects within a region parallel to the display
1086 // area
1087
1088 class DispRegionObjectIterator : public RadialObjectIterator {
1089 private:
1090
1091 // Compute the distance to the specified point from the center
1092 int16 computeDist(const TilePoint &tp);
1093
1094 public:
1095 // Constructor
DispRegionObjectIterator(GameWorld * world,const TilePoint & searchCenter,int16 distance)1096 DispRegionObjectIterator(
1097 GameWorld *world,
1098 const TilePoint &searchCenter,
1099 int16 distance) :
1100 RadialObjectIterator(world, searchCenter, distance) {
1101 }
1102 };
1103
1104 /* ======================================================================= *
1105 RegionalObjectIterator Class
1106 * ======================================================================= */
1107
1108 // Iterate through all objects within a rectangular region
1109
1110 class RegionalObjectIterator : public SectorRegionObjectIterator {
1111
1112 TilePoint minCoords,
1113 maxCoords;
1114
1115 // Calculate the sector region to pass to the ObjectIterator
1116 // constructor
1117 static TileRegion computeSectorRegion(
1118 const TilePoint §ors,
1119 const TilePoint &min,
1120 const TilePoint &max);
1121
1122 // Test to see if the specified point is within the region
1123 bool inRegion(const TilePoint &tp);
1124
1125 public:
1126 // Constructor
RegionalObjectIterator(GameWorld * world,const TilePoint & min,const TilePoint & max)1127 RegionalObjectIterator(
1128 GameWorld *world,
1129 const TilePoint &min,
1130 const TilePoint &max) :
1131 SectorRegionObjectIterator(
1132 world,
1133 computeSectorRegion(world->sectorSize(), min, max)),
1134 minCoords(min),
1135 maxCoords(max) {
1136 }
1137
1138 // Iteration functions
1139 virtual ObjectID first(GameObject **obj);
1140 virtual ObjectID next(GameObject **obj);
1141 };
1142
1143 /* ======================================================================= *
1144 RectangularObjectIterator Class
1145 * ======================================================================= */
1146
1147 // Iterate through all objects within a rectangular region
1148
1149 class RectangularObjectIterator : public RegionalObjectIterator {
1150
1151 TilePoint center,
1152 coords1,
1153 coords2,
1154 coords3,
1155 coords4;
1156
1157 // Test to see if the specified point is within the region
1158 bool inRegion(const TilePoint &tp);
1159
1160 public:
1161 // Constructor
1162 RectangularObjectIterator(
1163 GameWorld *world,
1164 const TilePoint &c,
1165 const TilePoint &cdelta1,
1166 const TilePoint &cdelta2);
1167
1168 virtual ObjectID first(GameObject **obj);
1169 virtual ObjectID next(GameObject **obj);
1170
1171 };
1172
1173 /* ======================================================================= *
1174 TriangularObjectIterator Class
1175 * ======================================================================= */
1176
1177 // Iterate through all objects within a rectangular region
1178
1179 class TriangularObjectIterator : public RegionalObjectIterator {
1180
1181 TilePoint coords1,
1182 coords2,
1183 coords3;
1184
1185 // Test to see if the specified point is within the region
1186 bool inRegion(const TilePoint &tp);
1187
1188 public:
1189 // Constructor
1190 TriangularObjectIterator(
1191 GameWorld *world,
1192 const TilePoint &c1,
1193 const TilePoint &c2,
1194 const TilePoint &c3);
1195
1196 // Iteration functions
1197 ObjectID first(GameObject **obj);
1198 ObjectID next(GameObject **obj);
1199 };
1200
1201 /* ======================================================================= *
1202 CenterRegionObjectIterator Class
1203 * ======================================================================= */
1204
1205 class CenterRegionObjectIterator : public RegionalObjectIterator {
1206
1207 static GameWorld *CenterWorld(void);
1208 static TilePoint MinCenterRegion(void);
1209 static TilePoint MaxCenterRegion(void);
1210
1211 public:
1212 // Constructor
CenterRegionObjectIterator(void)1213 CenterRegionObjectIterator(void) :
1214 RegionalObjectIterator(CenterWorld(),
1215 MinCenterRegion(),
1216 MaxCenterRegion()) {}
1217
1218 };
1219
1220 /* ======================================================================= *
1221 ActiveRegionObjectIterator Class
1222 * ======================================================================= */
1223
1224 class ActiveRegionObjectIterator : public ObjectIterator {
1225
1226 int16 activeRegionIndex;
1227 TilePoint baseSectorCoords,
1228 size,
1229 sectorCoords;
1230 uint8 sectorBitMask;
1231 GameWorld *currentWorld;
1232 GameObject *_currentObject;
1233
1234 bool firstActiveRegion(void);
1235 bool nextActiveRegion(void);
1236 bool firstSector(void);
1237 bool nextSector(void);
1238
1239 public:
1240 // Constructor
ActiveRegionObjectIterator(void)1241 ActiveRegionObjectIterator(void) : activeRegionIndex(-1), sectorBitMask(0), currentWorld(nullptr), _currentObject(nullptr) {}
1242
1243 // Iteration functions
1244 ObjectID first(GameObject **obj);
1245 ObjectID next(GameObject **obj);
1246 };
1247
1248 /* ============================================================================ *
1249 Container Iterator Class
1250 * ============================================================================ */
1251
1252 // This class iterates through every object within a container
1253
1254 class ContainerIterator {
1255 ObjectID nextID;
1256
1257 public:
1258 GameObject *object;
1259
1260 // Constructor
1261 ContainerIterator(GameObject *container);
1262
1263 // Iteration function
1264 ObjectID next(GameObject **obj);
1265 };
1266
1267 /* ============================================================================ *
1268 Recursive Container iterator Class
1269 * ============================================================================ */
1270
1271 // This class iterates through every object within a container and
1272 // all of the containers within the container
1273
1274 #if 0
1275 class RecursiveContainerIterator {
1276 ObjectID id;
1277 RecursiveContainerIterator *subIter;
1278
1279 public:
1280 // Constructor
1281 RecursiveContainerIterator(GameObject *container) :
1282 id(container->IDChild()),
1283 subIter(NULL) {
1284 }
1285 ~RecursiveContainerIterator(void);
1286
1287 // Iteration functions
1288 ObjectID first(GameObject **obj);
1289 ObjectID next(GameObject **obj);
1290 };
1291 #else
1292
1293 class RecursiveContainerIterator {
1294 ObjectID id,
1295 root;
1296
1297 public:
1298 // Constructor
RecursiveContainerIterator(GameObject * container)1299 RecursiveContainerIterator(GameObject *container) :
1300 root(container->thisID()), id(0) {}
1301
1302 // Iteration functions
1303 ObjectID first(GameObject **obj);
1304 ObjectID next(GameObject **obj);
1305 };
1306
1307 #endif
1308
1309 /* ============================================================================ *
1310 Object sound effect struct
1311 * ============================================================================ */
1312
1313 struct ObjectSoundFXs {
1314 uint8 soundFXHitFlesh,
1315 soundFXHitHard,
1316 soundFXParried,
1317 soundFXMissed;
1318 };
1319
1320 /* ======================================================================= *
1321 Misc Prototypes
1322 * ======================================================================= */
1323
1324
1325 // Defines values for sixteen missile facings, plus a value for no
1326 // missile facing.
1327 enum MissileFacings {
1328 missileUp,
1329 missileUpUpLf,
1330 missileUpLf,
1331 missileUpLfLf,
1332 missileLf,
1333 missileDnLfLf,
1334 missileDnLf,
1335 missileDnDnLf,
1336 missileDn,
1337 missileDnDnRt,
1338 missileDnRt,
1339 missileDnRtRt,
1340 missileRt,
1341 missileUpRtRt,
1342 missileUpRt,
1343 missileUpUpRt,
1344 missileNoFacing
1345 };
1346
1347 enum blockageType {
1348 blockageNone = 0,
1349 blockageTerrain,
1350 blockageObject
1351 };
1352
1353 uint32 objectTerrain(GameObject *obj);
1354
1355 // Return an object which is in collision with another object.
1356 GameObject *objectCollision(GameObject *obj, GameWorld *world, const TilePoint &loc);
1357
1358 // Test for line of sight between two objects
1359 bool lineOfSight(GameObject *obj1, GameObject *obj2, uint32 terrainMask);
1360 bool lineOfSight(GameObject *obj, const TilePoint &loc, uint32 terrainMask);
1361 bool lineOfSight(
1362 GameWorld *world,
1363 const TilePoint &loc1,
1364 const TilePoint &loc2,
1365 uint32 terrainMask);
1366
1367 // Test if object is obscured by terrain
1368 bool objObscured(GameObject *testObj);
1369
1370 // Determine which object mouse pointer is picking
1371 ObjectID pickObject(const StaticPoint32 &mouse, StaticTilePoint &objPos);
1372
1373 // Create enchantment attach it to object
1374 ObjectID EnchantObject(
1375 ObjectID target,
1376 int enchantmentType,
1377 int duration);
1378
1379 // Find an enchantment of a particular type
1380 ObjectID FindObjectEnchantment(
1381 ObjectID target,
1382 int enchantmentType);
1383
1384 // Remove an enchantment of a particular type
1385 bool DispelObjectEnchantment(
1386 ObjectID target,
1387 int enchantmentType);
1388
1389 // Function to eval the enchantments on an actor
1390 void evalActorEnchantments(Actor *a);
1391
1392 // Function to eval the enchantments on an actor
1393 void evalObjectEnchantments(GameObject *obj);
1394
1395 // Load prototypes from resource file
1396 void initPrototypes(void);
1397
1398 // Cleanup the prototype lists
1399 void cleanupPrototypes(void);
1400
1401 // Load the sound effects table
1402 void initObjectSoundFXTable(void);
1403
1404 // Cleanup the sound effects table
1405 void cleanupObjectSoundFXTable(void);
1406
1407 // Allocate array to hold the counts of the temp actors
1408 void initTempActorCount(void);
1409
1410 // Save the array of temp actor counts
1411 void saveTempActorCount(Common::OutSaveFile *outS);
1412
1413 // Load the array of temp actor counts
1414 void loadTempActorCount(Common::InSaveFile *in, int32 chunkSize);
1415
1416 // Cleanup the array to temp actor counts
1417 void cleanupTempActorCount(void);
1418
1419 // Increment the temporary actor count for the specified prototype
1420 void incTempActorCount(uint16 protoNum);
1421
1422 // Decrement the temporary actor count for the specified prototype
1423 void decTempActorCount(uint16 protoNum);
1424
1425 // Return the number of temporary actors for the specified prototype
1426 uint16 getTempActorCount(uint16 protoNum);
1427
1428 // Init game worlds
1429 void initWorlds(void);
1430
1431 // Save worlds to the save file
1432 void saveWorlds(Common::OutSaveFile *outS);
1433
1434 // Load worlds from the save file
1435 void loadWorlds(Common::InSaveFile *in);
1436
1437 // Cleanup game worlds
1438 void cleanupWorlds(void);
1439
1440 // Initialize object list
1441 void initObjects(void);
1442
1443 // Save the objects to the save file
1444 void saveObjects(Common::OutSaveFile *outS);
1445
1446 // Load the objects from the save file
1447 void loadObjects(Common::InSaveFile *in);
1448
1449 // Cleanup object list
1450 void cleanupObjects(void);
1451
1452 // Do background processing for objects
1453 void doBackgroundSimulation(void);
1454
1455 void pauseBackgroundSimulation(void);
1456 void resumeBackgroundSimulation(void);
1457
1458 // cleanup the ready container stuff
1459 void cleanupReadyContainers(void);
1460
1461 // This function simply calls the GameObject::updateState() method
1462 // for all active objects directly within a world.
1463 void updateObjectStates(void);
1464
1465 void pauseObjectStates(void);
1466 void resumeObjectStates(void);
1467
1468 void readyContainerSetup(void);
1469 void cleanupReadyContainers(void);
1470
1471 } // end of namespace Saga2
1472
1473 #endif
1474