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