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