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_MOTION_H
28 #define SAGA2_MOTION_H
29
30 #include "saga2/actor.h"
31
32 namespace Saga2 {
33
34 class PathRequest;
35 struct StandingTileInfo;
36
37 extern const StaticTilePoint dirTable[];
38 extern const StaticTilePoint incDirTable[];
39
40
41 const int gravity = 2;
42 const int walkSpeed = 4;
43 const int slowWalkSpeed = 2;
44 const int runSpeed = 8;
45 const int walkSpeedDiag = 3;
46 const int runSpeedDiag = 6;
47 const int angleThresh = 24;
48
49 enum MotionThreadReturnValues {
50 motionInterrupted, // MotionTask has been rudely
51 // interrupted and recycled for a new
52 // motion.
53
54 motionStarted, // The actor started moving.
55 motionCompleted, // The actor motion completed
56 // successfully.
57 motionWalkBlocked // The walk motion failed.
58 };
59
60 enum {
61 moveWait = (1 << 0),
62 moveRun = (1 << 1)
63 };
64
65 /* ===================================================================== *
66 Utility Motion Functions
67 * ===================================================================== */
68
69 void setObjectSurface(GameObject *obj, StandingTileInfo &sti);
70
71 /* ===================================================================== *
72 Motion Task Class
73 * ===================================================================== */
74
75 // This class handles the movement of objects. It includes things like
76 // thrown rocks, cast spells, and actors walking.
77 //
78 // Since most things in the game aren't moving at a given point, the
79 // variables for simulating motion don't need to always be present.
80
81 // Also need to handle explosion on impact for projectiles
82 // Or other special action.
83 // an object can hit a regular surface
84 // can hit a trip plate
85 // can hit another object
86 // can hit an actor
87 //
88 // can damage actor
89 // can break
90 // can set off trap
91 // can explode
92
93 class MotionTask {
94 friend class MotionTaskList;
95 friend class PathRequest;
96 friend class DestinationPathRequest;
97 friend class WanderPathRequest;
98 friend class Actor;
99 friend void RequestPath(MotionTask *mTask, int16 smartness);
100 friend void RequestWanderPath(MotionTask *mTask, int16 smartness);
101 friend void abortPathFind(MotionTask *mTask);
102
103 GameObject *object; // the object to move
104 TilePoint velocity; // object velocity for ballistic flight
105 TilePoint immediateLocation, // where we are trying to get to
106 finalTarget; // where we eventually want to get to
107 int16 tetherMinU,
108 tetherMinV,
109 tetherMaxU,
110 tetherMaxV;
111 uint8 motionType, // thrown or shot.
112 prevMotionType; // motion type before interruption
113
114 ThreadID thread; // SAGA thread to wake up when
115 // motion is done
116
117 uint16 flags; // various flags
118
119 enum motionFlags {
120 pathFind = (1 << 0), // walk is using path finding
121 finalPath = (1 << 1), // current path is final
122 inWater = (1 << 2), // handle motion as in water
123 reset = (1 << 3), // target has been reset
124 blocked = (1 << 4), // target was blocked
125 requestRun = (1 << 5), // caller has requested running
126 wandering = (1 << 6), // wander
127 tethered = (1 << 7), // stay within tether
128 nextAnim = (1 << 8), // update animation for this frame
129 turnDelay = (1 << 9), // Delay While Turning
130 TAGTarg = (1 << 10), // The target is not an object but a TAG
131 LocTarg = (1 << 11), // The target is not an object but a TAG
132 agitated = (1 << 12), // Walking around blockage
133 agitatable = (1 << 13), // Will agitate when blocked
134 onStairs = (1 << 14), // actor is climbing stairs
135 privledged = (1 << 15) // don't let AI interrupt this
136 };
137
138 Direction direction; // direction of movement
139 TilePoint pathList[16]; // intermediate motion targets
140 int16 pathCount, // number of points in path
141 pathIndex, // number of points so far
142 runCount; // used for run requests.
143 PathRequest *pathFindTask; // request to find the path
144 int16 steps, // number of steps in ballistic motion
145 uFrac, // remainder in U direction
146 vFrac, // remainder in V direction
147 uErrorTerm, // used to adjust for rounding errors
148 vErrorTerm; // used to adjust for rounding errors
149
150 // Data used in combat motion
151 uint8 combatMotionType; // combat sub motion type
152
153 // Spell casting stuff
154 GameObject *targetObj; // target of attack or defense (object)
155 ActiveItem *targetTAG; // target of attack or defense (TAG)
156 Location targetLoc; // target of attack or defense (Location)
157 SkillProto *spellObj; // spell being cast
158
159 union {
160 int16 actionCounter; // counter used in some motion
161 int16 moveCount; // counter used when moving mergeable objects around
162 };
163
164 enum defenseMotionFlags {
165 blocking = (1 << 0) // actor is blocking an attack
166 };
167
168 union {
169 // Object interaction stuff
170 struct {
171 GameObject *directObject, // object directly being acted
172 // upon.
173 *indirectObject; // object idirectly being acted
174 // upon.
175 Actor *enactor;
176 ActiveItem *TAI; // TAI involved in interation
177 } o;
178
179 // Defensive motion stuff
180 struct {
181 Actor *attacker; // attacking actor
182 GameObject *defensiveObj; // shield or parrying weapon
183 uint8 defenseFlags; // various combat flags
184 } d;
185 };
186
187 public:
188 // Combat specific motion sub-types
189 enum TwoHandedSwingTypes {
190 twoHandedSwingHigh,
191 twoHandedSwingLow,
192 twoHandedSwingLeftHigh,
193 twoHandedSwingLeftLow,
194 twoHandedSwingRightHigh,
195 twoHandedSwingRightLow
196 };
197
198 enum OneHandedSwingTypes {
199 oneHandedSwingHigh,
200 oneHandedSwingLow,
201 oneHandedThrust
202 };
203
204 enum OneHandedParryTypes {
205 oneHandedParryHigh,
206 oneHandedParryLow
207 };
208
209 private:
210
211 enum motionTypes {
212 motionTypeNone, // no motion
213
214 motionTypeThrown, // thrown in an arc
215 motionTypeShot, // shot in very shallow arc w/ cheat
216 motionTypeFall, // fall from a height
217 motionTypeWalk, // walk to a point
218 motionTypeStagger, // stagger to a point
219 motionTypeClimbUp, // climb up ladder to a point
220 motionTypeClimbDown, // climb dowb ladder
221 motionTypeTalk, // talk and gesture
222 motionTypeLand, // land after falling
223 motionTypeLandBadly, // land badly after falling
224 motionTypeJump, // get ready for jump
225 motionTypeTurn, // Turn Object
226 motionTypeGive, // Extend arm to give object
227 motionTypeRise, // Rise slowly in water
228 motionTypeHit, // For simple animations
229
230 // Immobile motions
231 motionTypeWait, // Don't move, simply eat some time
232 motionTypeUseObject, // Use an object
233 motionTypeUseObjectOnObject, // Use one object on another
234 motionTypeUseObjectOnTAI, // Use an object on a TAI
235 motionTypeUseObjectOnLocation, // Use an object on a TilePoint
236 motionTypeUseTAI, // Use a TAI
237 motionTypeDropObject, // Drop an object at a location
238 motionTypeDropObjectOnObject, // Drop one object on another
239 motionTypeDropObjectOnTAI, // Drop an object on a TAI
240
241 // Offensive combat actions
242 motionTypeTwoHandedSwing, // swing two-handed weapon
243 motionTypeOneHandedSwing, // swing one-handed weapon
244 motionTypeFireBow, // fire bow
245 motionTypeCastSpell, // cast spell
246 motionTypeUseWand, // cast spell with wand
247
248 // Defensive combat actions
249 motionTypeTwoHandedParry, // parry with two-handed weapon
250 motionTypeOneHandedParry, // parry with one-handed weapon
251 motionTypeShieldParry, // parry with shield
252 motionTypeDodge, // dodge blow
253
254 // Other combat actions
255 motionTypeAcceptHit, // show effect of hit
256 motionTypeFallDown, // be knocked off feet
257 motionTypeDie // self-explanatory
258
259 };
260
261 void read(Common::InSaveFile *in);
262
263 // Return the number of bytes needed to archive this MotionTask
264 int32 archiveSize(void);
265
266 void write(Common::MemoryWriteStreamDynamic *out);
267
268 // motion task is finished.
269 void remove(int16 returnVal = motionInterrupted);
270
271 TilePoint getImmediateTarget(void); // determine immediate target
272 // location
273
274 // Routines to handle updating of specific motion types
turnAction(void)275 void turnAction(void) {
276 Actor *a = (Actor *)object;
277
278 if (flags & reset) {
279 a->setAction(actionStand, 0);
280 flags &= ~reset;
281 }
282
283 if (a->_currentFacing != direction)
284 a->turn(direction);
285 else
286 remove(motionCompleted);
287 }
288
289 void ballisticAction(void);
290 void walkAction(void);
291 void giveAction(void);
292
293 void upLadderAction(void);
294 void downLadderAction(void);
295
296 // Set up specified animation and run through the frames
297 void genericAnimationAction(uint8 actionType);
298
299 // Offensive combat actions
300 void twoHandedSwingAction(void);
301 void oneHandedSwingAction(void);
302 void fireBowAction(void);
303 void castSpellAction(void);
304 void useWandAction(void);
305
306 // Defensive combat actions
307 void twoHandedParryAction(void);
308 void oneHandedParryAction(void);
309 void shieldParryAction(void);
310 void dodgeAction(void);
311
312 // Other combat actions
313 void acceptHitAction(void);
314 void fallDownAction(void);
315
316 // Generic offensive melee code. Called by twoHandedSwingAction()
317 // and oneHandedSwingAction
318 void offensiveMeleeAction(void);
319
320 // Generic magic weapon code. Called by useWandAction() and
321 // useStaffAction()
322 void useMagicWeaponAction(void);
323
324 // Generic defensive melee code. Called by twoHandedParryAction(),
325 // oneHandedParryAction() and shieldParryAction().
326 void defensiveMeleeAction(void);
327
328 // Retrieve the next waypoint from the path list.
329 bool nextWayPoint(void);
330 bool checkWalk(int16, int16, int16, TilePoint &);
331
332 // Determine the velocity for a ballistic motion
333 void calcVelocity(const TilePoint &vector, int16 turns);
334
335 public:
336
337 // Functions to create a new motion task. If the game object is
338 // an actor, then it will cancel any existing motion task
339 static void throwObject(GameObject &obj, const TilePoint &velocity);
340 static void throwObjectTo(GameObject &obj, const TilePoint &where);
341 static void shootObject(
342 GameObject &obj,
343 Actor &doer,
344 GameObject &target,
345 int16 speed);
346 static void walkTo(
347 Actor &obj,
348 const TilePoint &target,
349 bool run = false,
350 bool canAgitate = true);
351 static void walkTo(
352 ThreadID th,
353 Actor &obj,
354 const TilePoint &target,
355 bool run = false,
356 bool canAgitate = true);
357 static void walkToDirect(
358 Actor &obj,
359 const TilePoint &target,
360 bool run = false,
361 bool canAgitate = true);
362 static void walkToDirect(
363 ThreadID th,
364 Actor &obj,
365 const TilePoint &target,
366 bool run = false,
367 bool canAgitate = true);
368 static void wander(Actor &obj, bool run = false);
369 static void tetheredWander(Actor &obj, const TileRegion &tether, bool run = false);
370 // static void runTo( GameObject &obj, const TilePoint &target );
371 static void staggerTo(Actor &obj, const TilePoint &target);
372 static void upLadder(Actor &obj);
373 static void downLadder(Actor &obj);
374 static void talk(Actor &obj);
375 static void jump(Actor &obj);
376 static void turn(Actor &obj, Direction dir);
377 static void turn(ThreadID th, Actor &obj, Direction dir);
378 static void turnTowards(Actor &obj, const TilePoint &where);
379 static void turnTowards(ThreadID th, Actor &obj, const TilePoint &where);
380 static void give(Actor &obj, Actor &givee);
381 static void give(ThreadID th, Actor &obj, Actor &givee);
382
383 // Imobile motions
384 static void wait(Actor &a);
385 static void useObject(Actor &a, GameObject &dObj);
386 static void useObjectOnObject(
387 Actor &a,
388 GameObject &dObj,
389 GameObject &target);
390 static void useObjectOnTAI(
391 Actor &a,
392 GameObject &dObj,
393 ActiveItem &target);
394 static void useObjectOnLocation(
395 Actor &a,
396 GameObject &dObj,
397 const Location &target);
398 static void useTAI(Actor &a, ActiveItem &dTAI);
399 static void dropObject(
400 Actor &a,
401 GameObject &dObj,
402 const Location &loc,
403 int16 num = 1);
404
405 static void dropObjectOnObject(
406 Actor &a,
407 GameObject &dObj,
408 GameObject &target,
409 int16 num = 1);
410
411 static void dropObjectOnTAI(
412 Actor &a,
413 GameObject &dObj,
414 ActiveItem &target,
415 const Location &loc);
416
417 // Offensive combat actions
418 static void twoHandedSwing(Actor &obj, GameObject &target);
419 static void oneHandedSwing(Actor &obj, GameObject &target);
420 static void fireBow(Actor &obj, GameObject &target);
421 static void castSpell(Actor &obj, SkillProto &spell, GameObject &target);
422 static void castSpell(Actor &obj, SkillProto &spell, Location &target);
423 static void castSpell(Actor &obj, SkillProto &spell, ActiveItem &target);
424 static void useWand(Actor &obj, GameObject &target);
425
426 // Defensive combat actions
427 static void twoHandedParry(
428 Actor &obj,
429 GameObject &weapon,
430 Actor &opponent);
431 static void oneHandedParry(
432 Actor &obj,
433 GameObject &weapon,
434 Actor &opponent);
435 static void shieldParry(
436 Actor &obj,
437 GameObject &shield,
438 Actor &opponent);
439 static void dodge(Actor &obj, Actor &opponent);
440
441 // Other combat actions
442 static void acceptHit(Actor &obj, Actor &opponent);
443 static void fallDown(Actor &obj, Actor &opponent);
444 static void die(Actor &obj);
445
446 static void updatePositions(void);
447
448 int16 testCollision(GameObject &obstacle);
449
450 bool freeFall(TilePoint &newPos, StandingTileInfo &sti);
451
452 // Determine if the motion task is a walk motion
453 bool isWalk(void);
454
455 // Determine if the motion task is walking to a destination
isWalkToDest(void)456 bool isWalkToDest(void) {
457 return isWalk() && !(flags & wandering);
458 }
459
460 // Determine if the motion task is a wandering motion
isWander(void)461 bool isWander(void) {
462 return isWalk() && (flags & wandering);
463 }
464
465 // Determine if the motion task is tethered
isTethered(void)466 bool isTethered(void) {
467 return isWander() && (flags & tethered);
468 }
469
isRunning(void)470 bool isRunning(void) {
471 return (flags & requestRun) && runCount == 0;
472 }
473
isTurn(void)474 bool isTurn(void) {
475 return motionType == motionTypeTurn;
476 }
477
478 // Return the wandering tether region
479 TileRegion getTether(void);
480
481 // Return the final target location
getTarget(void)482 TilePoint getTarget(void) {
483 return finalTarget;
484 }
485
486 // Update to a new final target
487 void changeTarget(const TilePoint &newPos, bool run = false);
488 void changeDirectTarget(const TilePoint &newPos, bool run = false);
489 void finishWalk(void); // stop walking
finishTurn(void)490 void finishTurn(void) {
491 if (isTurn()) remove();
492 }
493 void finishTalking(void); // stop talking motion
494
495 // Determine if this MotionTask is a reflexive motion
496 bool isReflex(void);
497
498 // Determine if this MotionTask is a defensive motion
499 bool isDefense(void);
500
501 // End the defensive motion task
finishDefense(void)502 void finishDefense(void) {
503 if (isDefense()) remove();
504 }
505
506 // Determine if this MotionTask is an offensive motion
507 bool isAttack(void);
508
509 // Determine if this MotionTask is an offensive melee motion
510 bool isMeleeAttack(void);
511
512 // Compute the number of frames before the actual strike in an
513 // offensive melee motion
514 uint16 framesUntilStrike(void);
515
516 // End the offensive motion
finishAttack(void)517 void finishAttack(void) {
518 if (isAttack()) remove();
519 }
520
521 // Returns a pointer to the blocking object if it applicable to
522 // this motion task
523 GameObject *blockingObject(Actor *thisAttacker);
524
525 // Determine if this motion is a dodge motion
isDodging(Actor * thisAttacker)526 bool isDodging(Actor *thisAttacker) {
527 return motionType == motionTypeDodge && thisAttacker == d.attacker;
528 }
529
530 static void initMotionTasks(void);
531
isPrivledged(void)532 bool isPrivledged(void) {
533 return flags & privledged;
534 }
535 };
536
537 class MotionTaskList {
538 friend class MotionTask;
539
540 Common::List<MotionTask *> _list;
541 Common::List<MotionTask *>::iterator _nextMT;
542
543 public:
544 // Default constructor
545 MotionTaskList(void);
546
547 MotionTaskList(Common::SeekableReadStream *stream);
548
549 void read(Common::InSaveFile *in);
550
551 // Return the number of bytes needed to archive the motion tasks
552 // in a buffer
553 int32 archiveSize(void);
554
555 void write(Common::MemoryWriteStreamDynamic *out);
556
557 // Cleanup the motion tasks
558 void cleanup(void);
559
560 MotionTask *newTask(GameObject *obj); // get new motion task
561 };
562
563 /* ===================================================================== *
564 MotionTask inline member functions
565 * ===================================================================== */
566
walkTo(ThreadID th,Actor & actor,const TilePoint & target,bool run,bool canAgitate)567 inline void MotionTask::walkTo(
568 ThreadID th,
569 Actor &actor,
570 const TilePoint &target,
571 bool run,
572 bool canAgitate) {
573 walkTo(actor, target, run, canAgitate);
574 if (actor._moveTask != NULL)
575 actor._moveTask->thread = th;
576 }
577
walkToDirect(ThreadID th,Actor & actor,const TilePoint & target,bool run,bool canAgitate)578 inline void MotionTask::walkToDirect(
579 ThreadID th,
580 Actor &actor,
581 const TilePoint &target,
582 bool run,
583 bool canAgitate) {
584 walkToDirect(actor, target, run, canAgitate);
585 if (actor._moveTask != NULL)
586 actor._moveTask->thread = th;
587 }
588
turn(ThreadID th,Actor & actor,Direction dir)589 inline void MotionTask::turn(ThreadID th, Actor &actor, Direction dir) {
590 turn(actor, dir);
591 if (actor._moveTask != NULL)
592 actor._moveTask->thread = th;
593 }
594
turnTowards(ThreadID th,Actor & actor,const TilePoint & where)595 inline void MotionTask::turnTowards(
596 ThreadID th,
597 Actor &actor,
598 const TilePoint &where) {
599 turnTowards(actor, where);
600 if (actor._moveTask != NULL)
601 actor._moveTask->thread = th;
602 }
603
give(ThreadID th,Actor & actor,Actor & givee)604 inline void MotionTask::give(ThreadID th, Actor &actor, Actor &givee) {
605 give(actor, givee);
606 if (actor._moveTask != NULL)
607 actor._moveTask->thread = th;
608 }
609
610 /* ===================================================================== *
611 Utility functions
612 * ===================================================================== */
613
614 // Initiate ladder climbing
615 bool checkLadder(Actor *a, const TilePoint &tp);
616
617 void pauseInterruptableMotions(void);
618 void resumeInterruptableMotions(void);
619
620 /* ===================================================================== *
621 MotionTask list management functions
622 * ===================================================================== */
623
624 // Initialize the motion task list
625 void initMotionTasks(void);
626
627 void saveMotionTasks(Common::OutSaveFile *out);
628 void loadMotionTasks(Common::InSaveFile *in, int32 chunkSize);
629
630 // Cleanup the motion task list
631 void cleanupMotionTasks(void);
632
633 } // end of namespace Saga2
634
635 #endif
636