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  * aint32 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 #include "common/events.h"
28 
29 #include "saga2/saga2.h"
30 #include "saga2/tilemode.h"
31 #include "saga2/tile.h"
32 #include "saga2/setup.h"
33 #include "saga2/objects.h"
34 #include "saga2/grabinfo.h"
35 #include "saga2/mouseimg.h"
36 #include "saga2/motion.h"
37 #include "saga2/task.h"
38 #include "saga2/transit.h"
39 #include "saga2/magic.h"
40 #include "saga2/sensor.h"
41 #include "saga2/timers.h"
42 #include "saga2/intrface.h"
43 #include "saga2/dispnode.h"
44 #include "saga2/uidialog.h"
45 #include "saga2/contain.h"
46 #include "saga2/saveload.h"
47 #include "saga2/oncall.h"
48 
49 namespace Saga2 {
50 
51 #define TEST1           1           //  enable test code
52 #define TEST2           1
53 #define TEST3           1
54 
55 #define CHEATMOVE       1           // For moving with keypad in 8 directions
56 
57 /* ===================================================================== *
58    gStickyDragControl class: a gGenericControl with a sticky mouse
59  * ===================================================================== */
60 
61 class gStickyDragControl : public gGenericControl {
62 	bool    sticky;
63 
64 public:
65 	gStickyDragControl(gPanelList &, const Rect16 &, uint16, AppFunc *cmd = NULL);
66 
setSticky(bool s)67 	void setSticky(bool s) {
68 		sticky = s;
69 	}
isSticky(void)70 	bool isSticky(void) {
71 		return sticky;
72 	}
73 
74 private:
75 	void deactivate(void);
76 
77 //	void pointerMove( gPanelMessage &msg );
78 	bool pointerHit(gPanelMessage &msg);
79 	void pointerRelease(gPanelMessage &msg);
80 };
81 
82 /* ===================================================================== *
83    Globals
84  * ===================================================================== */
85 
86 //void startVideo( char *fileName,int x, int y );
87 //int16 OptionsDialog( bool disableSaveResume=false );
88 
89 extern int16        speechButtonCount;      // count of speech buttons
90 extern void         abortSpeech(void);
91 
92 extern const uint32 imageGroupID = MKTAG('I', 'M', 'A', 'G');
93 
94 extern hResContext          *tileRes;       // tile resource handle
95 extern CycleHandle          cycleList;      // list of tile cycling info
96 extern int16                    cycleCount;
97 extern int32                lastUpdateTime;         // time of last display update
98 
99 //Prototypes For Tile Mode GameMode Object Init
100 void TileModeHandleTask(void);
101 void TileModeHandleKey(int16 key, int16 qual);
102 
103 void initTileBanks(void);
104 void freeAllTileBanks(void);
105 
106 void navigateDirect(TilePoint pick, bool runFlag);
107 void navigatePath(TilePoint pick);
108 
109 void moveActors(int32 deltaTime);
110 
111 void drawMainDisplay(void);
112 void updateMainDisplay(void);
113 
114 #if DEBUG
115 void soundTest1(void);
116 void soundTest2(void);
117 void voiceTest1(void);
118 void voiceTest2(void);
119 #endif
120 
121 void toggleMusic(void);
122 
123 #if CHEATMOVE
124 void cheatMove(int16 key);
125 #endif
126 
127 void incrementActiveFaction(Actor *a);
128 
129 //  dispatch functions
130 static APPFUNC(cmdClickTileMap);                 // appFunc for map display
131 static StaticTilePoint tilePickPos = {0, 0, 0},       // mouse coord over tilemap (floor)
132                        tilePickExactPos = {0, 0, 0},  // mouse coord of click on tilemap
133                        objPickPos = {0, 0, 0},        // coord of mouse picked object
134                        walkToPos = {0, 0, 0};         // navigation target location
135 
136 ObjectID            pickedObject;           // which object picked by mouse
137 ActiveItemPtr       pickedTAI;              // which active item instance
138 
139 ObjectID            lastPickedObject = Nothing; // ID of last picked object
140 Alarm               dispObjNameAlarm;       // Alarm used for time delay
141 // in displaying mouse object's
142 // name
143 
144 Alarm               containerObjTextAlarm;  // time delay for container view object text
145 
146 ObjectID            pickedActor;
147 
148 #if CHEATMOVE
149 ObjectID            selectedObject = Nothing;
150 bool                nudge = false;
151 #endif
152 
153 extern ObjectID     viewCenterObject;
154 
155 static struct _delayedNavigation {
156 	StaticTilePoint walkToPos;
157 	bool        pathFindFlag;
158 	Alarm       delay;
159 } delayedNavigation = {{0, 0, 0}, false, {0, 0}};
160 static bool navigationDelayed = false;
161 
162 //Tile Mode GameMode Object
163 
164 GameMode            TileMode = {
165 	NULL,                                   // no previous mode
166 	false,                                  // mode is not nestable
167 	TileModeSetup,
168 	TileModeCleanup,
169 	TileModeHandleTask,
170 	TileModeHandleKey,
171 	drawMainDisplay,
172 };
173 
174 //  Duration, in timer ticks, that a character must walk before
175 //  they can begin to run.
176 
177 const int           runThreshhold = 32;
178 
179 extern Alarm        frameAlarm;             // 10 fps frame rate
180 Alarm               updateAlarm,            // max coord update rate
181                     pathFindAlarm;          // mouse click rate for path find
182 bool                tileLockFlag;           // true if tile mode is locked
183 
184 GameObject          *mouseObject = NULL;    // object being dragged
185 StaticPoint32       lastMousePos = {0, 0};           // Last mouse position over map
186 static bool         mousePressed,           // State of mouse button
187        clickActionDone = true; // Flag indication wether current
188 // mouse click action is done
189 static bool         runFlag = false;        // Reflexs wether the mouse is
190 // the run zone
191 
192 static bool         uiKeysEnabled = true;
193 
194 static char         lastUnusedKey = '\0';
195 
196 
197 //  The control that covers the scrolling tile display
198 gStickyDragControl  *tileMapControl;
199 extern gPanelList   *tileControls,          // panelList of play controls
200        *playControls;
201 
202 extern BackWindow   *mainWindow;
203 
204 extern uint32 frames;
205 //  Resource handle for UI imagery
206 
207 extern hResContext          *imageRes;              // image resource handle
208 
209 //  Combat related data
210 static bool         aggressiveActFlag = false;  //  Indicates wether or not
211 static bool         inCombat,
212        combatPaused;
213 
214 
215 // This is a correction required by MSVC's inability to provided
216 // precompiled header services if data is assigned during declaration
217 // inside a header.  GT 09/11/95
218 
219 static StaticWindow mainWindowDecorations[] = {
220 	{{0,  0, 640, 20},     nullptr, MWTopBorder},       // top border
221 	{{0, 440, 640, 40},    nullptr, MWBottomBorder},    // bottom border
222 	{{0, 20, 20, 420},     nullptr, MWLeftBorder},      // left border
223 	{{460, 20, 180, 142},  nullptr, MWRightBorder1},    // right border #1
224 	{{460, 162, 180, 151}, nullptr, MWRightBorder2},    // right border #2
225 	{{460, 313, 180, 127}, nullptr, MWRightBorder3},    // right border #3
226 };
227 
228 /* ===================================================================== *
229    TileMode utility functions
230  * ===================================================================== */
231 
InCombatPauseKludge(void)232 bool InCombatPauseKludge(void) {
233 	return (inCombat && combatPaused);
234 }
235 
236 
237 //-----------------------------------------------------------------------
238 //	Function to enable/disable user interface keys
239 
enableUIKeys(bool enabled)240 bool enableUIKeys(bool enabled) {
241 	bool        oldVal = uiKeysEnabled;
242 
243 	uiKeysEnabled = enabled;
244 	return oldVal;
245 }
246 
luckyKey(char * choices)247 char luckyKey(char *choices) {
248 	return lastUnusedKey;
249 
250 }
251 
252 //-----------------------------------------------------------------------
253 //	This function performs all combat pausing tasks
254 
pauseCombat(void)255 static void pauseCombat(void) {
256 	pauseCalender();
257 	pauseBackgroundSimulation();
258 	pauseInterruptableMotions();
259 	pauseObjectStates();
260 	pauseActorStates();
261 	pauseActorTasks();
262 
263 	setCenterActorIndicator(true);
264 }
265 
266 //-----------------------------------------------------------------------
267 //	This function performs all combat un-pausing tasks
268 
resumeCombat(void)269 static void resumeCombat(void) {
270 	setCenterActorIndicator(false);
271 
272 	resumeActorTasks();
273 	resumeActorStates();
274 	resumeObjectStates();
275 	resumeInterruptableMotions();
276 	resumeBackgroundSimulation();
277 	resumeCalender();
278 }
279 
280 //-----------------------------------------------------------------------
281 //	This function performs all combat initialization tasks
282 
startCombat(void)283 static void startCombat(void) {
284 	if (g_vm->_autoAggression)
285 		autoAdjustAggression();
286 
287 	setCombatBehavior(true);
288 	combatPaused = false;
289 }
290 
291 //-----------------------------------------------------------------------
292 //	This function performs all combat cleanup tasks
293 
endCombat(void)294 static void endCombat(void) {
295 	if (combatPaused) {
296 		combatPaused = false;
297 		resumeCombat();
298 	}
299 	setCombatBehavior(false);
300 
301 	handleEndOfCombat();
302 }
303 
304 //-----------------------------------------------------------------------
305 
toggleAutoAggression(void)306 void toggleAutoAggression(void) {
307 	g_vm->_autoAggression = !g_vm->_autoAggression;
308 	updateAutoAggressionButton(g_vm->_autoAggression);
309 }
310 
311 //-----------------------------------------------------------------------
312 
isAutoAggressionSet(void)313 bool isAutoAggressionSet(void) {
314 	return g_vm->_autoAggression;
315 }
316 
317 //-----------------------------------------------------------------------
318 
toggleAutoWeapon(void)319 void toggleAutoWeapon(void) {
320 	g_vm->_autoWeapon = !g_vm->_autoWeapon;
321 	updateAutoWeaponButton(g_vm->_autoWeapon);
322 }
323 
324 //-----------------------------------------------------------------------
325 
isAutoWeaponSet(void)326 bool isAutoWeaponSet(void) {
327 	return g_vm->_autoWeapon;
328 }
329 
330 //-----------------------------------------------------------------------
331 //	Called to notify this module of an aggressive act
332 
logAggressiveAct(ObjectID attackerID,ObjectID attackeeID)333 void logAggressiveAct(ObjectID attackerID, ObjectID attackeeID) {
334 	if (isPlayerActor(attackerID) || isPlayerActor(attackeeID)) {
335 		PlayerActorID       playerID;
336 
337 		if (actorIDToPlayerID(attackeeID, playerID))
338 			handlePlayerActorAttacked(playerID);
339 
340 		aggressiveActFlag = true;
341 		*g_vm->_tmm->_timeOfLastAggressiveAct = *g_vm->_calender;
342 	}
343 }
344 
345 //-----------------------------------------------------------------------
346 //	Determine how much time has elapsed since the last aggressive act
347 //	involving a player actor
348 
timeSinceLastAggressiveAct(void)349 uint16 timeSinceLastAggressiveAct(void) {
350 	return aggressiveActFlag ? *g_vm->_calender - *g_vm->_tmm->_timeOfLastAggressiveAct : maxuint16;
351 }
352 
353 //-----------------------------------------------------------------------
354 //	Determine if there are any enemies within the active regions.
355 
areThereActiveEnemies(void)356 bool areThereActiveEnemies(void) {
357 	ActiveRegionObjectIterator  iter;
358 	GameObject                  *obj = nullptr;
359 
360 	for (iter.first(&obj); obj != NULL; iter.next(&obj)) {
361 		if (isActor(obj)
362 		        &&  !((Actor *)obj)->isDead()
363 		        && ((Actor *)obj)->_disposition == dispositionEnemy)
364 			return true;
365 	}
366 
367 	return false;
368 }
369 
CheckCombatMood(void)370 void CheckCombatMood(void) {
371 	GameObject          *obj;
372 	TilePoint           centerLoc;
373 	ActiveRegion        *ar;
374 	GameWorld           *world;
375 	static bool         wasHostile = false;
376 
377 	ar = getActiveRegion(getCenterActorPlayerID());
378 	if (ar == NULL) return;
379 
380 	world = ar->getWorld();
381 	if (world == NULL || !isWorld(world)) return;
382 
383 	//  Search for hostile monsters.
384 
385 	//  If hostile monsters were found last time we searched, then expand the
386 	//  search radius slightly to provide a little bit of hysterisis to prevent
387 	//  indecision in music selection.
388 	CircularObjectIterator  iter8(world,
389 	                              getCenterActor()->getLocation(),
390 	                              wasHostile ? 220 : 180);
391 
392 	bool                agress = isCenterActorAggressive();
393 
394 	wasHostile = false;
395 	clearActiveFactions();
396 	for (iter8.first(&obj); obj != NULL; iter8.next(&obj)) {
397 		if (isActor(obj)
398 		        &&  !((Actor *)obj)->isDead()
399 		        && ((Actor *)obj)->_disposition == dispositionEnemy) {
400 			if (agress || !(((Actor *)obj)->_flags & Actor::afraid)) {
401 				incrementActiveFaction((Actor *) obj);
402 				wasHostile = true;
403 			}
404 		}
405 	}
406 	useActiveFactions();
407 }
408 
409 //-----------------------------------------------------------------------
410 //	This function evaluates the mouse state in the standard manner
411 
evalMouseState(void)412 static void evalMouseState(void) {
413 	GameObject      *obj = GameObject::objectAddress(pickedObject);
414 	Actor           *a = getCenterActor();
415 	bool            interruptable = a->isInterruptable();
416 
417 	g_vm->_mouseInfo->setDoable(interruptable);
418 
419 	if (g_vm->_mouseInfo->getObject() != NULL) {
420 		GameObject  *mObj = g_vm->_mouseInfo->getObject();
421 
422 		//  If the mouse pointer has an object and the intention
423 		//  is set to use, modify the doable setting depending
424 		//  on wether the mouse is pointing at another object
425 		//  and if so, wether the other object is within the
426 		//  use range of the center actor
427 		if (g_vm->_mouseInfo->getIntent() == GrabInfo::Use) {
428 			assert(obj != NULL);
429 
430 			if (mObj->containmentSet() & (ProtoObj::isSkill | ProtoObj::isSpell)) {
431 				GameObject  *tob = pickedObject != Nothing ? obj : NULL;
432 				// If it's a spell we need to do more complex testing
433 				//   to see if the current target is valid
434 				g_vm->_mouseInfo->setDoable(
435 				    interruptable
436 				    &&  validTarget(
437 				        a,
438 				        tob,
439 				        pickedTAI,
440 				        (SkillProto *)GameObject::protoAddress(
441 				            mObj->thisID())));
442 			} else {
443 				g_vm->_mouseInfo->setDoable(
444 				    interruptable
445 				    && (pickedObject == Nothing
446 				        || (a->inUseRange(
447 				                obj->getLocation(),
448 				                mObj)
449 				            && (a->inRange(obj->getLocation(), 8)
450 				                ||  lineOfSight(a, obj, terrainTransparent)))));
451 			}
452 		}
453 	} else {
454 		//  Determine if the mouse is being dragged
455 		if (mousePressed) {
456 			//  Adjust the intention and doable settings based
457 			//  factors such as center actor aggression, wether
458 			//  the mouse is pointing at an object, etc...
459 			//  Determine if the center actor is aggressive
460 			if (isCenterActorAggressive()) {
461 				//  Determine if the mouse is pointing at an
462 				//  object
463 				if (pickedObject != Nothing
464 				        &&  !isPlayerActor(pickedObject)) {
465 					//  If in attack range, set the intention
466 					//  to attack, else set the intention to walk
467 					//  to the picked object
468 					if (a->inAttackRange(obj->getLocation())
469 					        && (a->inRange(obj->getLocation(), 8)
470 					            ||  lineOfSight(a, obj, terrainTransparent)))
471 						g_vm->_mouseInfo->setIntent(GrabInfo::Attack);
472 					else {
473 						g_vm->_mouseInfo->setIntent(GrabInfo::WalkTo);
474 						walkToPos.set(obj->getLocation().u,
475 						              obj->getLocation().v,
476 						              obj->getLocation().z);
477 					}
478 				} else
479 					//  The mouse is not pointing at an object
480 				{
481 					//  Since there is no picked object,
482 					//  determine wether the center actor has
483 					//  finished can initiate a new action, if so, set
484 					//  the intention to walk to the mouse pointer
485 					if (interruptable) {
486 						g_vm->_mouseInfo->setIntent(GrabInfo::WalkTo);
487 						if (tileMapControl->isSticky())
488 							setMouseImage(kMouseAutoWalkImage, -8, -8);
489 						walkToPos = tilePickPos;
490 					}
491 				}
492 			} else
493 				//  The center actor is not aggressive
494 			{
495 				//  Set the intention to walk to the mouse
496 				//  pointer
497 				g_vm->_mouseInfo->setIntent(GrabInfo::WalkTo);
498 				if (tileMapControl->isSticky())
499 					setMouseImage(kMouseAutoWalkImage, -8, -8);
500 				walkToPos = tilePickPos;
501 			}
502 		} else
503 			//  The mouse is not being dragged
504 		{
505 			//  Determine if mouse is pointing at an object
506 			if (pickedObject != Nothing) {
507 				//  Determine if the center actor is aggressive
508 				if (isCenterActorAggressive()
509 				        &&  !isPlayerActor(pickedObject)) {
510 					//  If center actor is in attack range of
511 					//  the picked object, set the intention to
512 					//  attack, else set the intention to walk
513 					//  to the object
514 					if (a->inAttackRange(obj->getLocation())
515 					        && (a->inRange(obj->getLocation(), 8)
516 					            ||  lineOfSight(a, obj, terrainTransparent))) {
517 						g_vm->_mouseInfo->setIntent(GrabInfo::Attack);
518 						g_vm->_mouseInfo->setDoable(true);
519 					} else {
520 						g_vm->_mouseInfo->setIntent(GrabInfo::WalkTo);
521 						walkToPos.set(obj->getLocation().u,
522 						              obj->getLocation().v,
523 						              obj->getLocation().z);
524 					}
525 				} else
526 					//  Center actor is not aggressive
527 				{
528 					//  If pointing at an actor, set the
529 					//  intention to walk to the actor, else
530 					//  set the intention to pick up the object
531 					if (isActor(pickedObject)) {
532 						a = (Actor *)obj;
533 
534 						g_vm->_mouseInfo->setIntent(
535 						    !a->isDead()
536 						    ?   GrabInfo::WalkTo
537 						    :   GrabInfo::Open);
538 						walkToPos.set(obj->getLocation().u,
539 						              obj->getLocation().v,
540 						              obj->getLocation().z);
541 					} else {
542 						g_vm->_mouseInfo->setIntent(obj->isCarryable()
543 						                    ? GrabInfo::PickUp
544 						                    : GrabInfo::Open);
545 						g_vm->_mouseInfo->setDoable(
546 						    interruptable
547 						    &&  a->inReach(obj->getLocation())
548 						    && (a->inRange(obj->getLocation(), 8)
549 						        ||  lineOfSight(a, obj, terrainTransparent)));
550 					}
551 				}
552 			} else
553 				//  The mouse is not pointing at an object
554 			{
555 				//  Simply set the intention to walk to the mouse
556 				//  pointer
557 				g_vm->_mouseInfo->setIntent(GrabInfo::WalkTo);
558 				if (tileMapControl->isSticky())
559 					setMouseImage(kMouseAutoWalkImage, -8, -8);
560 				walkToPos = tilePickPos;
561 			}
562 		}
563 	}
564 
565 	if (mousePressed
566 	        &&  !clickActionDone
567 	        &&  g_vm->_mouseInfo->getObject() == NULL) {
568 		a = getCenterActor();
569 
570 		//  Since the mouse is being dragged, initiate
571 		//  the effects of the mouse drag
572 
573 		if (g_vm->_mouseInfo->getIntent() == GrabInfo::WalkTo) {
574 			if (g_vm->_mouseInfo->getDoable()
575 			        &&  !navigationDelayed) {
576 				MotionTask  *mt = a->_moveTask;
577 
578 				if (mt == NULL || !mt->isWalk()) {
579 					navigateDirect(walkToPos, runFlag);
580 				} else if (updateAlarm.check()) {
581 					mt->changeDirectTarget(
582 					    walkToPos,
583 					    runFlag);
584 					updateAlarm.set(ticksPerSecond / 2);
585 				}
586 			}
587 		} else if (g_vm->_mouseInfo->getIntent() == GrabInfo::Attack) {
588 			if (g_vm->_mouseInfo->getDoable())
589 				a->attack(GameObject::objectAddress(pickedObject));
590 		}
591 	}
592 }
593 
594 //-----------------------------------------------------------------------
595 //	Initialize the tile mode state
596 
initTileModeState(void)597 void initTileModeState(void) {
598 	assert(uiKeysEnabled);
599 
600 	aggressiveActFlag = false;
601 	inCombat = false;
602 	combatPaused = false;
603 }
604 
saveTileModeState(Common::OutSaveFile * outS)605 void saveTileModeState(Common::OutSaveFile *outS) {
606 	debugC(2, kDebugSaveload, "Saving TileModeState");
607 
608 	assert(uiKeysEnabled);
609 
610 	outS->write("TMST", 4);
611 	CHUNK_BEGIN;
612 	out->writeUint16LE(aggressiveActFlag);
613 	out->writeUint16LE(inCombat);
614 	out->writeUint16LE(combatPaused);
615 
616 	debugC(3, kDebugSaveload, "... aggressiveActFlag = %d", aggressiveActFlag);
617 	debugC(3, kDebugSaveload, "... inCombat = %d", inCombat);
618 	debugC(3, kDebugSaveload, "... combatPaused = %d", combatPaused);
619 
620 	if (aggressiveActFlag)
621 		g_vm->_tmm->_timeOfLastAggressiveAct->write(out);
622 	CHUNK_END;
623 }
624 
loadTileModeState(Common::InSaveFile * in)625 void loadTileModeState(Common::InSaveFile *in) {
626 	assert(uiKeysEnabled);
627 
628 	//  Simply read in the data
629 	aggressiveActFlag = in->readUint16LE();
630 	inCombat = in->readUint16LE();
631 	combatPaused = in->readUint16LE();
632 
633 	debugC(3, kDebugSaveload, "... aggressiveActFlag = %d", aggressiveActFlag);
634 	debugC(3, kDebugSaveload, "... inCombat = %d", inCombat);
635 	debugC(3, kDebugSaveload, "... combatPaused = %d", combatPaused);
636 
637 	if (aggressiveActFlag)
638 		g_vm->_tmm->_timeOfLastAggressiveAct->read(in);
639 
640 	tileLockFlag = false;
641 }
642 
643 /* ===================================================================== *
644    TileMode management functions
645  * ===================================================================== */
646 
647 //-----------------------------------------------------------------------
648 //	Initialize the Tile mode
649 
TileModeSetup(void)650 void TileModeSetup(void) {
651 	//  Load in decorative panels for the main window (for this mode)
652 	mainWindow->setDecorations(mainWindowDecorations, ARRAYSIZE(mainWindowDecorations), imageRes);
653 
654 	//  Test to draw borders.
655 	//  REM: We should actually have a routine to refresh the window...
656 	mainWindow->draw();
657 
658 	//  Create a control covering the map area.
659 	tileMapControl = new gStickyDragControl(*playControls, Rect16(kTileRectX, kTileRectY, kTileRectWidth, kTileRectHeight), 0, cmdClickTileMap);
660 
661 	//Enable Tile Mode Specific Controls
662 	tileControls->enable(true);
663 
664 	initTileBanks();
665 
666 	lastUpdateTime = gameTime;
667 
668 	setCurrentWorld(WorldBaseID);
669 	setCurrentMap(currentWorld->mapNum);
670 }
671 
672 //-----------------------------------------------------------------------
673 //	Cleanup function for Tile mode
674 
TileModeCleanup(void)675 void TileModeCleanup(void) {
676 	//Disable Tile Mode Specific Controls
677 	tileControls->enable(false);
678 
679 	freeAllTileBanks();
680 	delete g_vm->_tileImageBanks;
681 
682 //	freePalette();
683 
684 //	if (tileRes) resFile->disposeContext( tileRes );
685 //	tileRes = NULL;
686 
687 	delete tileMapControl;
688 
689 //	This Fixes the mousePanel That's not set up
690 	g_vm->_toolBase->mousePanel = NULL;
691 
692 	mainWindow->removeDecorations();
693 }
694 
695 //-----------------------------------------------------------------------
696 //	This code handles most of the periodic repetitive tasks in
697 //	the main game mode.
698 static int postDisplayFrame = 3;
699 
700 //  We need to test if UI is locked, so as to not pause combat
701 extern int          lockUINest;
702 
TileModeHandleTask(void)703 void TileModeHandleTask(void) {
704 	bool taskChek = false;
705 	//  Run any SAGA scripts which are waiting to run.
706 	dispatchScripts();
707 
708 
709 	// update day and night
710 	//mm("daytime transition update loop");
711 	dayNightUpdate();
712 
713 	//  If it's time to do a new frame.
714 	if (frameAlarm.check()
715 	        &&  tileLockFlag == 0) {
716 		static int flipper = 0;
717 
718 		//  Get the actor we're controlling.
719 		Actor       *a = getCenterActor();
720 
721 		audioEnvironmentSetAggression(isCenterActorAggressive());
722 
723 		//  Check combat mood once every 8 frames or so.
724 		//  Otherwise, check for combat start/stop
725 		//  (Kludge to balance CPU usage).
726 
727 		if ((++flipper & 0xF) == 0)
728 			CheckCombatMood();
729 		else if (timeSinceLastAggressiveAct() < 60
730 		         &&  areThereActiveEnemies()) {
731 			if (!inCombat) {
732 				inCombat = true;
733 				startCombat();
734 			}
735 		} else {
736 			if (inCombat) {
737 				inCombat = false;
738 				endCombat();
739 			}
740 		}
741 
742 		if (inCombat) {
743 			if (!a->isMoving() && a->isInterruptable() && lockUINest == 0) {
744 				if (!combatPaused) {
745 					combatPaused = true;
746 					pauseCombat();
747 				}
748 			} else {
749 				if (combatPaused) {
750 					combatPaused = false;
751 					resumeCombat();
752 				}
753 			}
754 		}
755 
756 		updateCalender();
757 
758 		// update the text status line
759 		StatusLine->experationCheck();
760 
761 		doBackgroundSimulation();
762 
763 		// do an alarm check for container views
764 		if (containerObjTextAlarm.check()) {
765 			ContainerView::objTextAlarm = true;
766 		}
767 
768 		if (ContainerView::objTextAlarm == true) {
769 			// if the mouse is in a container...
770 			if (ContainerView::mouseInView) {
771 				g_vm->_mouseInfo->setText(ContainerView::mouseText);
772 			}
773 		}
774 
775 
776 		if (g_vm->_toolBase->isMousePanel(tileMapControl)) {
777 			//  If mouse is near edge of screen, then run.
778 			runFlag =       lastMousePos.x < runThreshhold
779 			                ||  lastMousePos.x >= kTileRectWidth - runThreshhold
780 			                ||  lastMousePos.y < runThreshhold
781 			                ||  lastMousePos.y >= kTileRectHeight - runThreshhold;
782 
783 			//  Calculate the mouse's position on the tile map.
784 			if (runFlag) {
785 				//  Calculate the mouse's position on the tilemap,
786 				//  without regard to the actual shape of the terrain.
787 				tilePickPos = pickTilePos(lastMousePos, a->getLocation());
788 				tilePickExactPos = tilePickPos;
789 				pickedTAI = NULL;
790 			} else {
791 				//  Calculate the mouse's position on the tilemap,
792 				//  including the shape of the terrain. Actually
793 				//  this returns two seperate coords: The exact point
794 				//  clicked on, and the projection on the floor
795 				//  beneath the clicked point.
796 				tilePickExactPos = pickTile(lastMousePos,
797 				                            a->getLocation(),
798 				                            &tilePickPos,
799 				                            &pickedTAI);
800 			}
801 
802 
803 			pickedObject = pickObject(lastMousePos, objPickPos);
804 			GameObject  *item = GameObject::objectAddress(pickedObject);
805 
806 			// Find Out If Terrain Or Object Is Deeper
807 
808 			if (!item->isObscured() || (!isActor(item) && !objRoofRipped(item))) {
809 				if (tilePickExactPos.z > objPickPos.z) {
810 					pickedObject = Nothing;
811 					item = GameObject::objectAddress(pickedObject);
812 				}
813 			}
814 
815 			//  Determine if the mouse is pointing at a new object
816 			if (pickedObject != lastPickedObject) {
817 				lastPickedObject = pickedObject;
818 
819 				//  Remove current mouse cursor text and gauge
820 				g_vm->_mouseInfo->setText(NULL);
821 				g_vm->_mouseInfo->clearGauge();
822 
823 				//  If mouse in on object set alarm to determine when
824 				//  to display the object's name
825 				if (pickedObject != Nothing)
826 					dispObjNameAlarm.set(ticksPerSecond / 2);
827 			}
828 
829 			if (pickedObject != Nothing) {
830 				//  Determine if it is time to display the name of the
831 				//  object at which the mouse is pointing
832 				if (dispObjNameAlarm.check()) {
833 					const   int bufSize = 40;
834 					char    cursorText[bufSize];
835 
836 					// get the object text into the buffer
837 					item->objCursorText(cursorText, bufSize);
838 
839 					g_vm->_mouseInfo->setText(cursorText);
840 					if (isActor(pickedObject)) {
841 						a = (Actor *)GameObject::objectAddress(pickedObject);
842 						g_vm->_mouseInfo->setGauge(a->getStats()->vitality, a->getBaseStats()->vitality);
843 					} else {
844 						g_vm->_mouseInfo->clearGauge();
845 					}
846 				}
847 			}
848 
849 			evalMouseState();
850 		}
851 
852 		if (navigationDelayed && delayedNavigation.delay.check()) {
853 			if (delayedNavigation.pathFindFlag)
854 				navigatePath(delayedNavigation.walkToPos);
855 			else
856 				navigateDirect(delayedNavigation.walkToPos, false);
857 			navigationDelayed = false;
858 		}
859 
860 		updateContainerWindows();
861 
862 		updateActiveRegions();
863 
864 		checkTimers();
865 
866 		checkSensors();
867 
868 
869 		updateObjectStates();
870 		updateActorStates();
871 
872 		//  Update positions of all objects
873 		moveActors(0);               // for objects with motion task.
874 
875 		//  Update the states of all active terrain
876 		moveActiveTerrain(0);            // for terrain with activity tasks.
877 
878 		//  Set the time of the next frame
879 		frameAlarm.set(framePeriod);
880 		updateMainDisplay();
881 
882 		if (inCombat || postDisplayFrame++ > 2)
883 			taskChek = true;
884 	} else if (postDisplayFrame) {
885 		taskChek = true;
886 	}
887 	if (taskChek) {
888 		postDisplayFrame = 0;
889 		updateActorTasks();
890 	}
891 }
892 
893 //-----------------------------------------------------------------------
894 
895 extern void toggleAgression(PlayerActorID bro, bool all);
896 extern void toggleBanding(PlayerActorID bro, bool all);
897 extern void toggleIndivMode(void);
898 
TileModeHandleKey(int16 key,int16 qual)899 void TileModeHandleKey(int16 key, int16 qual) {
900 	TilePoint Pos, ActorTP;
901 	Actor   *a = getCenterActor();
902 	Location l(a->getLocation(), a->IDParent());
903 
904 	//GameObject *object = (GameObject *)getCenterActor();
905 
906 	lastUnusedKey = '\0';
907 	//This is for moving center actor in cardinal directions
908 	//by amount specified by loc const int moveDist and using keypad
909 	//without num lock on
910 
911 #if CHEATMOVE
912 	cheatMove(key);
913 #endif
914 	//  If there is currently a speech balloon up, and the
915 	//  speech balloon has embedded buttons, then disallow
916 	//  user input -- except that for now we will still allow
917 	//  the special 'quit' key.
918 	if (speechButtonCount > 0) {
919 		if (key != 0x1b && key != 'b') return;
920 	}
921 
922 	//-----------------------------------------------------------------------
923 
924 	switch (tolower(key)) {
925 
926 	case ' ':
927 		abortSpeech();
928 		if (uiKeysEnabled) {
929 			if (tileMapControl->isSticky()) {
930 				tileMapControl->setSticky(false);
931 				mousePressed = false;
932 				setMouseImage(kMouseArrowImage, 0, 0);
933 				evalMouseState();
934 			}
935 			MotionTask::wait(*a);
936 		}
937 		break;
938 
939 	case 'a':
940 		if (uiKeysEnabled)
941 			toggleAgression(getCenterActorPlayerID(), qual & qualifierShift);
942 		break;
943 	case 'b':
944 		if (uiKeysEnabled)
945 			toggleBanding(getCenterActorPlayerID(), qual & qualifierShift);
946 		break;
947 	case '\t':
948 		if (uiKeysEnabled)
949 			toggleIndivMode();
950 		break;
951 	case '1':
952 		if (uiKeysEnabled)
953 			setCenterBrother(FTA_JULIAN);
954 		break;
955 	case '2':
956 		if (uiKeysEnabled)
957 			setCenterBrother(FTA_PHILIP);
958 		break;
959 	case '3':
960 		if (uiKeysEnabled)
961 			setCenterBrother(FTA_KEVIN);
962 		break;
963 	case 'o':
964 		if (uiKeysEnabled)
965 			OptionsDialog();
966 		break;
967 
968 	//  Keyboard equivalents for mental containers
969 	case 'i':
970 		if (uiKeysEnabled)
971 			OpenMindContainer(getCenterActorPlayerID(), true, 0);
972 		break;
973 	case 's':
974 		if (uiKeysEnabled)
975 			OpenMindContainer(getCenterActorPlayerID(), true, 1);
976 		break;
977 	case 'k':
978 		if (uiKeysEnabled)
979 			OpenMindContainer(getCenterActorPlayerID(), true, 2);
980 		break;
981 
982 	case 'm':
983 		toggleMusic();
984 		break;
985 
986 
987 #if DEBUG
988 	case 'q':
989 	case 0x1b:
990 		endGame();
991 		break;
992 
993 #else
994 	case 0x1b:
995 		if (uiKeysEnabled)
996 			OptionsDialog();
997 		break;
998 #endif
999 
1000 	default:
1001 		if (uiKeysEnabled)
1002 			lastUnusedKey = key;
1003 
1004 	}
1005 }
1006 
1007 //  A debugging function to show the queue of recent mouse events.
1008 
1009 #if DEBUG
1010 static char mouseHistory[33];
1011 
showMouseEvent(char eventType)1012 void showMouseEvent(char eventType) {
1013 	memmove(mouseHistory + 1, mouseHistory, 31);
1014 	mouseHistory[0] = eventType;
1015 	mouseHistory[32] = '\0';
1016 	WriteStatusF(5, mouseHistory);
1017 }
1018 #endif
1019 
1020 //-----------------------------------------------------------------------
1021 //	Handle mouse actions on the tile map "control".
1022 
APPFUNC(cmdClickTileMap)1023 static APPFUNC(cmdClickTileMap) {
1024 
1025 	static bool dblClick = false;
1026 
1027 	//  REM: This code needs to be moved elsewhere. We put it
1028 	//  here for testing purposes only. It should actually go on
1029 	//  it's own panel, which overrides all other panels, and
1030 	//  that should be part of a special "speech button" mode.
1031 
1032 	if (!uiKeysEnabled) return;
1033 
1034 	switch (ev.eventType) {
1035 	case gEventRMouseDown:
1036 
1037 #if CHEATMOVE
1038 		selectedObject = pickedObject;
1039 #endif
1040 		if (g_vm->_teleportOnClick) {
1041 			if (g_vm->getEventManager()->getModifierState() & Common::KBD_SHIFT) {
1042 				for (ObjectID pid = ActorBaseID; pid < ActorBaseID + kPlayerActors; ++pid) {
1043 					Actor *p = (Actor *)GameObject::objectAddress(pid);
1044 					p->setLocation(walkToPos);
1045 				}
1046 			} else {
1047 				getCenterActor()->setLocation(walkToPos);
1048 			}
1049 		} else if (isActor(pickedObject)) {
1050 			PlayerActorID       playerID;
1051 
1052 			if (actorIDToPlayerID(pickedObject, playerID))
1053 				setAggression(playerID, !isAggressive(playerID));
1054 		}
1055 		break;
1056 
1057 	case gEventMouseMove:
1058 	case gEventMouseDrag:
1059 		if (ev.value & gGenericControl::leave) {
1060 			mousePressed = false;
1061 
1062 			if (g_vm->_mouseInfo->getObject() == NULL)
1063 				g_vm->_mouseInfo->setIntent(GrabInfo::WalkTo);
1064 			g_vm->_mouseInfo->setDoable(true);
1065 
1066 			//  Remove any mouse text
1067 			lastPickedObject = Nothing;
1068 			g_vm->_mouseInfo->setText(NULL);
1069 			g_vm->_mouseInfo->clearGauge();
1070 		}
1071 		lastMousePos.set(ev.mouse.x, ev.mouse.y);
1072 		break;
1073 
1074 	case gEventMouseDown:
1075 
1076 		mousePressed = true;
1077 
1078 		clickActionDone = false;
1079 
1080 		{
1081 			//  Get the center actor's ID and a pointer to the center
1082 			//  actor's structure
1083 			ObjectID    centerActorID = getCenterActorID();
1084 			Actor       *centerActorPtr =
1085 			    (Actor *)GameObject::objectAddress(centerActorID);
1086 
1087 			if ((mouseObject = g_vm->_mouseInfo->getObject()) != NULL) {
1088 				//  If we are using an intangible object (spell) then consider
1089 				//  the owner of the spell to be the center actor for the rest
1090 				//  of this action.
1091 				if (mouseObject->proto()->containmentSet() & (ProtoObj::isIntangible | ProtoObj::isSpell | ProtoObj::isSkill)) {
1092 					ObjectID    possessor = mouseObject->possessor();
1093 
1094 					if (possessor != Nothing) {
1095 						centerActorID = possessor;
1096 						centerActorPtr = (Actor *)GameObject::objectAddress(possessor);
1097 					}
1098 				}
1099 
1100 				if (pickedObject != Nothing) {
1101 					//  we dropped the object onto another object
1102 					if (g_vm->_mouseInfo->getDoable()) {
1103 						int16   intent = g_vm->_mouseInfo->getIntent();
1104 
1105 						g_vm->_mouseInfo->replaceObject();
1106 						if (intent == GrabInfo::Use) {
1107 							MotionTask::useObjectOnObject(
1108 							    *centerActorPtr,
1109 							    *mouseObject,
1110 							    *GameObject::objectAddress(pickedObject));
1111 						} else if (intent == GrabInfo::Drop) {
1112 							MotionTask::dropObjectOnObject(
1113 							    *centerActorPtr,
1114 							    *mouseObject,
1115 							    *GameObject::objectAddress(pickedObject),
1116 							    g_vm->_mouseInfo->getMoveCount());
1117 						}
1118 
1119 						((gGenericControl *)ev.panel)->disableDblClick();
1120 						clickActionDone = true;
1121 					} else if (g_vm->_mouseInfo->getIntent() == GrabInfo::Use) {
1122 						g_vm->_mouseInfo->replaceObject();
1123 						clickActionDone = true;
1124 					}
1125 				} else if (pickedTAI != NULL) {
1126 					//  we dropped the object onto active terrain
1127 
1128 					if (g_vm->_mouseInfo->getDoable()) {
1129 						if (g_vm->_mouseInfo->getIntent() == GrabInfo::Drop
1130 						        ||  g_vm->_mouseInfo->getIntent() == GrabInfo::Use) {
1131 							int16   intent = g_vm->_mouseInfo->getIntent();
1132 
1133 							g_vm->_mouseInfo->replaceObject();
1134 							if (intent == GrabInfo::Drop) {
1135 								MotionTask::dropObjectOnTAI(
1136 								    *centerActorPtr,
1137 								    *mouseObject,
1138 								    *pickedTAI,
1139 								    Location(tilePickPos, currentWorld->thisID()));
1140 							} else {
1141 								TilePoint   TAILoc;
1142 
1143 								TAILoc = getClosestPointOnTAI(pickedTAI, centerActorPtr);
1144 
1145 								if (centerActorPtr->inReach(TAILoc)
1146 								        && (centerActorPtr->inRange(TAILoc, 8)
1147 								            ||  lineOfSight(
1148 								                centerActorPtr,
1149 								                TAILoc,
1150 								                terrainTransparent)))
1151 									MotionTask::useObjectOnTAI(
1152 									    *centerActorPtr,
1153 									    *mouseObject,
1154 									    *pickedTAI);
1155 							}
1156 
1157 							((gGenericControl *)ev.panel)->disableDblClick();
1158 							clickActionDone = true;
1159 						}
1160 					} else if (g_vm->_mouseInfo->getIntent() == GrabInfo::Use) {
1161 						g_vm->_mouseInfo->replaceObject();
1162 						clickActionDone = true;
1163 					}
1164 				} else if (pickedObject == Nothing) {
1165 					//  we dropped the object on the ground
1166 
1167 					if (g_vm->_mouseInfo->getIntent() == GrabInfo::Drop
1168 					        &&  g_vm->_mouseInfo->getDoable()) {
1169 						g_vm->_mouseInfo->replaceObject();
1170 						MotionTask::dropObject(
1171 						    *centerActorPtr,
1172 						    *mouseObject,
1173 						    Location(tilePickPos, currentWorld->thisID()),
1174 						    g_vm->_mouseInfo->getMoveCount());
1175 						((gGenericControl *)ev.panel)->disableDblClick();
1176 						clickActionDone = true;
1177 					} else if (g_vm->_mouseInfo->getIntent() == GrabInfo::Use
1178 					           &&  g_vm->_mouseInfo->getDoable()) {
1179 						// New for spells - this enables objects to be used on a
1180 						//   general location (for area spells etc)
1181 						g_vm->_mouseInfo->replaceObject();
1182 						MotionTask::useObjectOnLocation(
1183 						    *centerActorPtr,
1184 						    *mouseObject,
1185 						    Location(tilePickPos, currentWorld->thisID()));
1186 						clickActionDone = true;
1187 					} else if (g_vm->_mouseInfo->getIntent() == GrabInfo::Use) {
1188 						g_vm->_mouseInfo->replaceObject();
1189 						clickActionDone = true;
1190 					}
1191 				}
1192 			} else if (pickedObject != Nothing) {
1193 				//GameObject      *obj = GameObject::objectAddress(pickedObject);
1194 
1195 				if (g_vm->_mouseInfo->getDoable()) {
1196 					PlayerActorID   pID;
1197 
1198 					if (actorIDToPlayerID(pickedObject, pID) && !isBrotherDead(pID)) {
1199 						setCenterBrother(pID);
1200 						clickActionDone = true;
1201 					} else if (g_vm->_mouseInfo->getIntent() == GrabInfo::PickUp
1202 					           ||  g_vm->_mouseInfo->getIntent() == GrabInfo::Open) {
1203 						GameObject  *pickedObjPtr =
1204 						    GameObject::objectAddress(pickedObject);
1205 						int16       quantity = 1;
1206 
1207 						MotionTask::turnTowards(
1208 						    *centerActorPtr,
1209 						    GameObject::objectAddress(pickedObject)->getLocation());
1210 
1211 						if (pickedObjPtr->proto()->flags & ResourceObjectPrototype::objPropMergeable)
1212 							quantity = pickedObjPtr->getExtra();
1213 
1214 						if (pickedObjPtr->take(centerActorID, quantity))
1215 							clickActionDone = true;
1216 					} else if (g_vm->_mouseInfo->getIntent() == GrabInfo::Attack) {
1217 						centerActorPtr->attack(
1218 						    GameObject::objectAddress(pickedObject));
1219 						((gGenericControl *)ev.panel)->disableDblClick();
1220 					}
1221 				}
1222 
1223 #if DEBUG && TEST1
1224 				if (isActor(pickedObject))
1225 					pickedActor = pickedObject;
1226 #endif
1227 
1228 			}
1229 			//  We're not pointing at an object and the mouse cursor
1230 			//  does not have an object
1231 			else {
1232 				if (g_vm->_mouseInfo->getIntent() == GrabInfo::WalkTo
1233 				        &&  g_vm->_mouseInfo->getDoable()) {
1234 					if (pickedTAI == NULL) {
1235 						navigateDirect(walkToPos, false);
1236 						//      ( ( gGenericControl * )ev.panel )->disableDblClick();
1237 					} else {
1238 						navigationDelayed = true;
1239 						delayedNavigation.walkToPos = walkToPos;
1240 						delayedNavigation.pathFindFlag = false;
1241 						delayedNavigation.delay.set(ticksPerSecond / 2);
1242 					}
1243 					pathFindAlarm.set(ticksPerSecond / 2);
1244 				}
1245 			}
1246 		}
1247 		break;
1248 
1249 	case gEventMouseUp:
1250 
1251 		mousePressed = false;
1252 
1253 		if (dblClick)
1254 			dblClick = false;
1255 		else {
1256 			if (pathFindAlarm.check()) { // mouse click was too long for path find
1257 				if (g_vm->_mouseInfo->getIntent() == GrabInfo::WalkTo) {
1258 					Actor   *a = getCenterActor();
1259 
1260 					if (a->_moveTask && a->_moveTask->isWalk())
1261 						a->_moveTask->finishWalk();
1262 				}
1263 				navigationDelayed = false;
1264 			} else {
1265 				if (navigationDelayed) {
1266 					delayedNavigation.walkToPos = walkToPos;
1267 					delayedNavigation.pathFindFlag = true;
1268 					delayedNavigation.delay.set(ticksPerSecond / 2);
1269 				} else {
1270 					Actor   *a = getCenterActor();
1271 
1272 					if ((walkToPos - a->getLocation()).quickHDistance() > 24)
1273 						navigatePath(walkToPos);
1274 					else
1275 						navigateDirect(walkToPos, false);
1276 				}
1277 			}
1278 		}
1279 		break;
1280 
1281 	case gEventDoubleClick:
1282 
1283 		dblClick = true;
1284 
1285 		navigationDelayed = false;
1286 
1287 		if ((mouseObject = g_vm->_mouseInfo->getObject()) != NULL) {
1288 			g_vm->_mouseInfo->replaceObject();
1289 			MotionTask::useObject(*getCenterActor(), *mouseObject);
1290 		} else if (pickedObject != Nothing) {
1291 			GameObject      *obj = GameObject::objectAddress(pickedObject);
1292 
1293 			if (g_vm->_mouseInfo->getDoable()) {
1294 				//  Double-click on an actor is the same as "greet".
1295 				if (isActor(pickedObject)
1296 				        &&  !((Actor *)obj)->isDead()
1297 				        &&  !isCenterActorAggressive()) {
1298 					ActorProto  *proto = (ActorProto *)obj->proto();
1299 
1300 					proto->greetActor(pickedObject, getCenterActorID());
1301 				} else if (g_vm->_mouseInfo->getIntent() == GrabInfo::PickUp
1302 				           ||  g_vm->_mouseInfo->getIntent() == GrabInfo::Open
1303 				           || (isActor(pickedObject) && ((Actor *)obj)->isDead())) {
1304 					GameObject  *pickedObjPtr =
1305 					    GameObject::objectAddress(pickedObject);
1306 
1307 					MotionTask::useObject(*getCenterActor(), *pickedObjPtr);
1308 					clickActionDone = true;
1309 				}
1310 			}
1311 		} else if (pickedTAI != NULL) {
1312 			Actor       *a = getCenterActor();
1313 			TilePoint   TAILoc;
1314 
1315 			TAILoc = getClosestPointOnTAI(pickedTAI, a);
1316 
1317 			if (a->inRange(TAILoc, 32)
1318 			        && (a->inRange(TAILoc, 8)
1319 			            ||  lineOfSight(a, TAILoc, terrainTransparent)))
1320 				MotionTask::useTAI(*a, *pickedTAI);
1321 		} else {
1322 			tileMapControl->setSticky(true);
1323 			setMouseImage(kMouseAutoWalkImage, -8, -8);
1324 			mousePressed = true;
1325 		}
1326 		break;
1327 
1328 	default:
1329 		break;
1330 	}
1331 }
1332 
1333 //-----------------------------------------------------------------------
1334 //	Sets up a motion task for the main character.
1335 
navigateDirect(TilePoint pick,bool runFlag_)1336 void navigateDirect(TilePoint pick, bool runFlag_) {
1337 	Actor   *a = getCenterActor();          // addr of actor we control
1338 
1339 	if (a) {
1340 		updateAlarm.set(ticksPerSecond / 2);
1341 
1342 		//  REM: Do running here...
1343 
1344 		MotionTask::walkToDirect(*a, pick, runFlag_, false);
1345 	}
1346 }
1347 
1348 //-----------------------------------------------------------------------
1349 //	Sets up a motion task and a path find request for the main character.
1350 
navigatePath(TilePoint pick)1351 void navigatePath(TilePoint pick) {
1352 	Actor   *a = getCenterActor();          // addr of actor we control
1353 
1354 	if (a) {
1355 		if (a->isMoving())
1356 			//  if motion task already exists, change the target
1357 			a->_moveTask->changeTarget(pick);
1358 		else
1359 			//  else create a new motion task
1360 			MotionTask::walkTo(*a, pick, false, false);
1361 	}
1362 }
1363 
1364 #if CHEATMOVE
cheatMove(int16 key)1365 void cheatMove(int16 key) {
1366 	if (selectedObject == Nothing) return;
1367 
1368 	if (tolower(key) == 'n') {
1369 		nudge = !nudge;
1370 		return;
1371 	}
1372 
1373 	union {
1374 		int16       key1;
1375 		char        key_ch[2];
1376 	} get;
1377 
1378 	GameObject  *obj = GameObject::objectAddress(selectedObject);
1379 	TilePoint   t = obj->getLocation();
1380 	int         moveDist = nudge ? 1 : 64;
1381 
1382 	get.key1 = key;
1383 
1384 	if (get.key_ch[0] == 0) {
1385 		switch (get.key_ch[1]) {
1386 		case 72:        //Up
1387 			t.u += moveDist;
1388 			t.v += moveDist;
1389 			obj->move(t);
1390 			break;
1391 
1392 		case 80:        //Down
1393 			t.u -= moveDist;
1394 			t.v -= moveDist;
1395 			obj->move(t);
1396 			break;
1397 
1398 		case 73:        //Up Right
1399 			t.u += moveDist;
1400 			obj->move(t);
1401 			break;
1402 
1403 		case 71:        //Up Left
1404 			t.v += moveDist;
1405 			obj->move(t);
1406 			break;
1407 
1408 		case 81:        //Down Right
1409 			t.v -= moveDist;
1410 			obj->move(t);
1411 			break;
1412 
1413 		case 79:        //Down Left
1414 			t.u -= moveDist;
1415 			obj->move(t);
1416 			break;
1417 
1418 		case 75:        //Left
1419 			t.u -= moveDist;
1420 			t.v += moveDist;
1421 			obj->move(t);
1422 			break;
1423 
1424 		case 77:        //Right
1425 			t.u += moveDist;
1426 			t.v -= moveDist;
1427 			obj->move(t);
1428 			break;
1429 		}
1430 		WriteStatusF(3, "U %d V %d Z %d", t.u, t.v, t.z);
1431 	}
1432 }
1433 #endif
1434 
1435 /* ===================================================================== *
1436    gStickyDragControl class: a gGenericControl with a sticky mouse
1437  * ===================================================================== */
1438 
gStickyDragControl(gPanelList & list,const Rect16 & box,uint16 ident,AppFunc * cmd)1439 gStickyDragControl::gStickyDragControl(gPanelList &list, const Rect16 &box,
1440                                        uint16 ident, AppFunc *cmd)
1441 	: gGenericControl(list, box, ident, cmd) {
1442 	sticky = false;
1443 }
1444 
deactivate(void)1445 void gStickyDragControl::deactivate(void) {
1446 	if (sticky) setMouseImage(kMouseArrowImage, 0, 0);
1447 	sticky = false;
1448 	gGenericControl::deactivate();
1449 }
1450 
1451 //void gStickyDragControl::pointerMove( gPanelMessage & )
1452 //{
1453 //	notify( gEventMouseMove, 0 );
1454 //}
1455 
pointerHit(gPanelMessage & msg)1456 bool gStickyDragControl::pointerHit(gPanelMessage &msg) {
1457 	if (sticky) setMouseImage(kMouseArrowImage, 0, 0);
1458 	sticky = false;
1459 	return gGenericControl::pointerHit(msg);
1460 }
1461 
pointerRelease(gPanelMessage & msg)1462 void gStickyDragControl::pointerRelease(gPanelMessage &msg) {
1463 	if (sticky == false)
1464 		gGenericControl::pointerRelease(msg);
1465 }
1466 
noStickyMap(void)1467 void noStickyMap(void) {
1468 	((gPanel *)tileMapControl)->deactivate();
1469 	mousePressed = false;
1470 }
1471 
TileModeManager()1472 TileModeManager::TileModeManager() {
1473 	_timeOfLastAggressiveAct = new CalenderTime;
1474 }
1475 
~TileModeManager()1476 TileModeManager::~TileModeManager() {
1477 	delete _timeOfLastAggressiveAct;
1478 }
1479 
1480 } // end of namespace Saga2
1481