~ubuntu-branches/ubuntu/raring/scummvm/raring

« back to all changes in this revision

Viewing changes to engines/hugo/route.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Moritz Muehlenhoff
  • Date: 2011-05-25 19:02:23 UTC
  • mto: (21.1.2 sid)
  • mto: This revision was merged to the branch mainline in revision 24.
  • Revision ID: james.westby@ubuntu.com-20110525190223-fiqm0oaec714xk31
Tags: upstream-1.3.0
ImportĀ upstreamĀ versionĀ 1.3.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
18
18
 * along with this program; if not, write to the Free Software
19
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20
20
 *
21
 
 * $URL: https://scummvm.svn.sourceforge.net/svnroot/scummvm/scummvm/tags/release-1-2-1/engines/hugo/route.cpp $
22
 
 * $Id: route.cpp 52406 2010-08-27 09:48:53Z strangerke $
 
21
 * $URL$
 
22
 * $Id$
23
23
 *
24
24
 */
25
25
 
32
32
 
33
33
// Find shortest route from hero to destination
34
34
 
 
35
#include "common/debug.h"
35
36
#include "common/system.h"
36
37
 
37
38
#include "hugo/hugo.h"
38
39
#include "hugo/game.h"
39
40
#include "hugo/route.h"
40
 
#include "hugo/global.h"
 
41
#include "hugo/object.h"
 
42
#include "hugo/inventory.h"
 
43
#include "hugo/mouse.h"
41
44
 
42
45
namespace Hugo {
43
 
Route::Route(HugoEngine &vm) : _vm(vm) {
44
 
}
45
 
 
46
 
// Face hero in new direction, based on cursor key input by user.
47
 
void Route::setDirection(uint16 keyCode) {
48
 
        object_t *obj = _vm._hero;                      // Pointer to hero object
49
 
 
 
46
Route::Route(HugoEngine *vm) : _vm(vm) {
 
47
        _oldWalkDirection = 0;
 
48
        _routeIndex       = -1;                         // Hero not following a route
 
49
        _routeType        = kRouteSpace;                // Hero walking to space
 
50
        _routeObjId       = -1;                         // Hero not walking to anything
 
51
}
 
52
 
 
53
void Route::resetRoute() {
 
54
        _routeIndex = -1;
 
55
}
 
56
 
 
57
int16 Route::getRouteIndex() const {
 
58
        return _routeIndex;
 
59
}
 
60
 
 
61
/**
 
62
 * Face hero in new direction, based on cursor key input by user.
 
63
 */
 
64
void Route::setDirection(const uint16 keyCode) {
50
65
        debugC(1, kDebugRoute, "setDirection(%d)", keyCode);
51
66
 
 
67
        object_t *obj = _vm->_hero;                     // Pointer to hero object
 
68
 
52
69
        // Set first image in sequence
53
70
        switch (keyCode) {
54
71
        case Common::KEYCODE_UP:
 
72
        case Common::KEYCODE_KP8:
55
73
                obj->currImagePtr = obj->seqList[_UP].seqPtr;
56
74
                break;
57
75
        case Common::KEYCODE_DOWN:
 
76
        case Common::KEYCODE_KP2:
58
77
                obj->currImagePtr = obj->seqList[DOWN].seqPtr;
59
78
                break;
60
79
        case Common::KEYCODE_LEFT:
 
80
        case Common::KEYCODE_KP4:
61
81
                obj->currImagePtr = obj->seqList[LEFT].seqPtr;
62
82
                break;
63
83
        case Common::KEYCODE_RIGHT:
 
84
        case Common::KEYCODE_KP6:
64
85
                obj->currImagePtr = obj->seqList[RIGHT].seqPtr;
65
86
                break;
66
87
        case Common::KEYCODE_HOME:
 
88
        case Common::KEYCODE_KP7:
67
89
                obj->currImagePtr = obj->seqList[LEFT].seqPtr;
68
90
                break;
69
91
        case Common::KEYCODE_END:
 
92
        case Common::KEYCODE_KP1:
70
93
                obj->currImagePtr = obj->seqList[LEFT].seqPtr;
71
94
                break;
72
 
//      case Common::KEYCODE_PRIOR:
73
 
//              obj->currImagePtr = obj->seqList[RIGHT].seqPtr;
74
 
//              break;
75
 
//      case Common::KEYCODE_NEXT:
76
 
//              obj->currImagePtr = obj->seqList[RIGHT].seqPtr;
77
 
//              break;
 
95
        case Common::KEYCODE_PAGEUP:
 
96
        case Common::KEYCODE_KP9:
 
97
                obj->currImagePtr = obj->seqList[RIGHT].seqPtr;
 
98
                break;
 
99
        case Common::KEYCODE_PAGEDOWN:
 
100
        case Common::KEYCODE_KP3:
 
101
                obj->currImagePtr = obj->seqList[RIGHT].seqPtr;
 
102
                break;
78
103
        }
79
104
}
80
105
 
81
 
// Set hero walking, based on cursor key input by user.
82
 
// Hitting same key twice will stop hero.
83
 
void Route::setWalk(uint16 direction) {
84
 
        object_t *obj = _vm._hero;                      // Pointer to hero object
85
 
        static uint16 oldDirection = 0;                 // Last direction char
86
 
 
 
106
/**
 
107
 * Set hero walking, based on cursor key input by user.
 
108
 * Hitting same key twice will stop hero.
 
109
 */
 
110
void Route::setWalk(const uint16 direction) {
87
111
        debugC(1, kDebugRoute, "setWalk(%d)", direction);
88
112
 
89
 
        if (_vm.getGameStatus().storyModeFl || obj->pathType != USER)           // Make sure user has control
 
113
        object_t *obj = _vm->_hero;                     // Pointer to hero object
 
114
 
 
115
        if (_vm->getGameStatus().storyModeFl || obj->pathType != kPathUser) // Make sure user has control
90
116
                return;
91
117
 
92
118
        if (!obj->vx && !obj->vy)
93
 
                oldDirection = 0;                           // Fix for consistant restarts
 
119
                _oldWalkDirection = 0;                      // Fix for consistant restarts
94
120
 
95
 
        if (direction != oldDirection) {
 
121
        if (direction != _oldWalkDirection) {
96
122
                // Direction has changed
97
123
                setDirection(direction);                    // Face new direction
98
124
                obj->vx = obj->vy = 0;
99
125
                switch (direction) {                        // And set correct velocity
100
126
                case Common::KEYCODE_UP:
101
 
                        obj->vy = -DY;
 
127
                case Common::KEYCODE_KP8:
 
128
                        obj->vy = -kStepDy;
102
129
                        break;
103
130
                case Common::KEYCODE_DOWN:
104
 
                        obj->vy =  DY;
 
131
                case Common::KEYCODE_KP2:
 
132
                        obj->vy =  kStepDy;
105
133
                        break;
106
134
                case Common::KEYCODE_LEFT:
107
 
                        obj->vx = -DX;
 
135
                case Common::KEYCODE_KP4:
 
136
                        obj->vx = -kStepDx;
108
137
                        break;
109
138
                case Common::KEYCODE_RIGHT:
110
 
                        obj->vx =  DX;
 
139
                case Common::KEYCODE_KP6:
 
140
                        obj->vx =  kStepDx;
111
141
                        break;
112
142
                case Common::KEYCODE_HOME:
113
 
                        obj->vx = -DX;
114
 
                        obj->vy = -DY / 2;
 
143
                case Common::KEYCODE_KP7:
 
144
                        obj->vx = -kStepDx;
 
145
                        // Note: in v1 Dos and v2 Dos, obj->vy is set to DY
 
146
                        obj->vy = -kStepDy / 2;
115
147
                        break;
116
148
                case Common::KEYCODE_END:
117
 
                        obj->vx = -DX;
118
 
                        obj->vy =  DY / 2;
119
 
                        break;
120
 
//              case Common::KEYCODE_PRIOR:
121
 
//                      obj->vx =  DX;
122
 
//                      obj->vy = -DY / 2;
123
 
//                      break;
124
 
//              case Common::KEYCODE_NEXT:
125
 
//                      obj->vx =  DX;
126
 
//                      obj->vy =  DY / 2;
127
 
//                      break;
 
149
                case Common::KEYCODE_KP1:
 
150
                        obj->vx = -kStepDx;
 
151
                        // Note: in v1 Dos and v2 Dos, obj->vy is set to -DY
 
152
                        obj->vy =  kStepDy / 2;
 
153
                        break;
 
154
                case Common::KEYCODE_PAGEUP:
 
155
                case Common::KEYCODE_KP9:
 
156
                        obj->vx =  kStepDx;
 
157
                        // Note: in v1 Dos and v2 Dos, obj->vy is set to -DY
 
158
                        obj->vy = -kStepDy / 2;
 
159
                        break;
 
160
                case Common::KEYCODE_PAGEDOWN:
 
161
                case Common::KEYCODE_KP3:
 
162
                        obj->vx =  kStepDx;
 
163
                        // Note: in v1 Dos and v2 Dos, obj->vy is set to DY
 
164
                        obj->vy =  kStepDy / 2;
 
165
                        break;
128
166
                }
129
 
                oldDirection = direction;
130
 
                obj->cycling = CYCLE_FORWARD;
 
167
                _oldWalkDirection = direction;
 
168
                obj->cycling = kCycleForward;
131
169
        } else {
132
170
                // Same key twice - halt hero
133
171
                obj->vy = 0;
134
172
                obj->vx = 0;
135
 
                oldDirection = 0;
136
 
                obj->cycling = NOT_CYCLING;
 
173
                _oldWalkDirection = 0;
 
174
                obj->cycling = kCycleNotCycling;
137
175
        }
138
176
}
139
177
 
140
 
// Recursive algorithm!  Searches from hero to dest_x, dest_y
141
 
// Find horizontal line segment about supplied point and recursively
142
 
// find line segments for each point above and below that segment.
143
 
// When destination point found in segment, start surfacing and leave
144
 
// a trail in segment[] from destination back to hero.
145
 
//
146
 
// Note:  there is a bug which allows a route through a 1-pixel high
147
 
// narrow gap if between 2 segments wide enough for hero.  To work
148
 
// around this, make sure any narrow gaps are 2 or more pixels high.
149
 
// An example of this was the blocking guard in Hugo1/Dead-End.
 
178
/**
 
179
 * Recursive algorithm!  Searches from hero to dest_x, dest_y
 
180
 * Find horizontal line segment about supplied point and recursively
 
181
 * find line segments for each point above and below that segment.
 
182
 * When destination point found in segment, start surfacing and leave
 
183
 * a trail in segment[] from destination back to hero.
 
184
 *
 
185
 * Note:  there is a bug which allows a route through a 1-pixel high
 
186
 * narrow gap if between 2 segments wide enough for hero.  To work
 
187
 * around this, make sure any narrow gaps are 2 or more pixels high.
 
188
 * An example of this was the blocking guard in Hugo1/Dead-End.
 
189
 */
150
190
void Route::segment(int16 x, int16 y) {
151
 
        int16 x1, x2;                                   // Range of segment
152
 
// Note use of static - can't waste stack
 
191
        debugC(1, kDebugRoute, "segment(%d, %d)", x, y);
 
192
 
 
193
        // Note: use of static - can't waste stack
153
194
        static image_pt   p;                            // Ptr to _boundaryMap[y]
154
195
        static segment_t *seg_p;                        // Ptr to segment
155
196
 
156
 
        debugC(1, kDebugRoute, "segment(%d, %d)", x, y);
157
 
 
158
197
        // Bomb out if stack exhausted
159
198
        // Vinterstum: Is this just a safeguard, or actually used?
160
199
        //_fullStackFl = _stackavail () < 256;
162
201
 
163
202
        // Find and fill on either side of point
164
203
        p = _boundaryMap[y];
165
 
        for (x1 = x; x1 > 0; x1--)
 
204
        int16 x1, x2;                                   // Range of segment
 
205
        for (x1 = x; x1 > 0; x1--) {
166
206
                if (p[x1] == 0) {
167
207
                        p[x1] = kMapFill;
168
 
                } else
 
208
                } else {
169
209
                        break;
170
 
        for (x2 = x + 1; x2 < XPIX; x2++)
 
210
                }
 
211
        }
 
212
        for (x2 = x + 1; x2 < kXPix; x2++) {
171
213
                if (p[x2] == 0) {
172
214
                        p[x2] = kMapFill;
173
 
                } else
 
215
                } else {
174
216
                        break;
 
217
                }
 
218
        }
175
219
        x1++;
176
220
        x2--;
177
221
 
184
228
                _routeFoundFl = true;
185
229
 
186
230
        // Bounds check y in case no boundary around screen
187
 
        if (y <= 0 || y >= YPIX - 1)
 
231
        if (y <= 0 || y >= kYPix - 1)
188
232
                return;
189
233
 
190
 
        if (_vm._hero->x < x1) {
191
 
                // Hero x not in segment, search x1..x2
192
 
                // Find all segments above current
193
 
                for (x = x1; !(_routeFoundFl | _fullStackFl | _fullSegmentFl) && x <= x2; x++)
194
 
                        if (_boundaryMap[y - 1][x] == 0)
195
 
                                segment(x, y - 1);
196
 
 
197
 
                // Find all segments below current
198
 
                for (x = x1; !(_routeFoundFl | _fullStackFl | _fullSegmentFl) && x <= x2; x++)
199
 
                        if (_boundaryMap[y + 1][x] == 0)
200
 
                                segment(x, y + 1);
201
 
        } else if (_vm._hero->x + HERO_MAX_WIDTH > x2) {
202
 
                // Hero x not in segment, search x1..x2
203
 
                // Find all segments above current
204
 
                for (x = x2; !(_routeFoundFl | _fullStackFl | _fullSegmentFl) && x >= x1; x--)
205
 
                        if (_boundaryMap[y - 1][x] == 0)
206
 
                                segment(x, y - 1);
207
 
 
208
 
                // Find all segments below current
209
 
                for (x = x2; !(_routeFoundFl | _fullStackFl | _fullSegmentFl) && x >= x1; x--)
210
 
                        if (_boundaryMap[y + 1][x] == 0)
211
 
                                segment(x, y + 1);
 
234
        if (_vm->_hero->x < x1) {
 
235
                // Hero x not in segment, search x1..x2
 
236
                // Find all segments above current
 
237
                for (x = x1; !(_routeFoundFl | _fullStackFl | _fullSegmentFl) && x <= x2; x++) {
 
238
                        if (_boundaryMap[y - 1][x] == 0)
 
239
                                segment(x, y - 1);
 
240
                }
 
241
 
 
242
                // Find all segments below current
 
243
                for (x = x1; !(_routeFoundFl | _fullStackFl | _fullSegmentFl) && x <= x2; x++) {
 
244
                        if (_boundaryMap[y + 1][x] == 0)
 
245
                                segment(x, y + 1);
 
246
                }
 
247
        } else if (_vm->_hero->x + kHeroMaxWidth > x2) {
 
248
                // Hero x not in segment, search x1..x2
 
249
                // Find all segments above current
 
250
                for (x = x2; !(_routeFoundFl | _fullStackFl | _fullSegmentFl) && x >= x1; x--) {
 
251
                        if (_boundaryMap[y - 1][x] == 0)
 
252
                                segment(x, y - 1);
 
253
                }
 
254
 
 
255
                // Find all segments below current
 
256
                for (x = x2; !(_routeFoundFl | _fullStackFl | _fullSegmentFl) && x >= x1; x--) {
 
257
                        if (_boundaryMap[y + 1][x] == 0)
 
258
                                segment(x, y + 1);
 
259
                }
212
260
        } else {
213
261
                // Organize search around hero x position - this gives
214
262
                // better chance for more direct route.
215
 
                for (x = _vm._hero->x; !(_routeFoundFl | _fullStackFl | _fullSegmentFl) && x <= x2; x++)
216
 
                        if (_boundaryMap[y - 1][x] == 0)
217
 
                                segment(x, y - 1);
218
 
                for (x = x1; !(_routeFoundFl | _fullStackFl | _fullSegmentFl) && x < _vm._hero->x; x++)
219
 
                        if (_boundaryMap[y - 1][x] == 0)
220
 
                                segment(x, y - 1);
221
 
                for (x = _vm._hero->x; !(_routeFoundFl | _fullStackFl | _fullSegmentFl) && x <= x2; x++)
222
 
                        if (_boundaryMap[y + 1][x] == 0)
223
 
                                segment(x, y + 1);
224
 
                for (x = x1; !(_routeFoundFl | _fullStackFl | _fullSegmentFl) && x < _vm._hero->x; x++)
225
 
                        if (_boundaryMap[y + 1][x] == 0)
226
 
                                segment(x, y + 1);
 
263
                for (x = _vm->_hero->x; !(_routeFoundFl | _fullStackFl | _fullSegmentFl) && x <= x2; x++) {
 
264
                        if (_boundaryMap[y - 1][x] == 0)
 
265
                                segment(x, y - 1);
 
266
                }
 
267
 
 
268
                for (x = x1; !(_routeFoundFl | _fullStackFl | _fullSegmentFl) && x < _vm->_hero->x; x++) {
 
269
                        if (_boundaryMap[y - 1][x] == 0)
 
270
                                segment(x, y - 1);
 
271
                }
 
272
 
 
273
                for (x = _vm->_hero->x; !(_routeFoundFl | _fullStackFl | _fullSegmentFl) && x <= x2; x++) {
 
274
                        if (_boundaryMap[y + 1][x] == 0)
 
275
                                segment(x, y + 1);
 
276
                }
 
277
 
 
278
                for (x = x1; !(_routeFoundFl | _fullStackFl | _fullSegmentFl) && x < _vm->_hero->x; x++) {
 
279
                        if (_boundaryMap[y + 1][x] == 0)
 
280
                                segment(x, y + 1);
 
281
                }
227
282
        }
228
283
 
229
284
        // If found, surface, leaving trail back to hero
230
285
        if (_routeFoundFl) {
231
286
                // Bomb out if too many segments (leave one spare)
232
 
                if (_segmentNumb >= kMaxSeg - 1)
 
287
                if (_segmentNumb >= kMaxSeg - 1) {
233
288
                        _fullSegmentFl = true;
234
 
                else {
 
289
                } else {
235
290
                        // Create segment
236
291
                        seg_p = &_segment[_segmentNumb];
237
292
                        seg_p->y  = y;
242
297
        }
243
298
}
244
299
 
245
 
// Create and return ptr to new node.  Initialize with previous node.
246
 
// Returns NULL if MAX_NODES exceeded
 
300
/**
 
301
 * Create and return ptr to new node.  Initialize with previous node.
 
302
 * Returns 0 if MAX_NODES exceeded
 
303
 */
247
304
Point *Route::newNode() {
248
305
        debugC(1, kDebugRoute, "newNode");
249
306
 
 
307
        _routeListIndex++;
250
308
        if (_routeListIndex >= kMaxNodes)               // Too many nodes
251
 
                return(NULL);                               // Incomplete route - failure
252
 
        _routeListIndex++;
 
309
                return 0;                                   // Incomplete route - failure
 
310
 
253
311
        _route[_routeListIndex] = _route[_routeListIndex - 1];  // Initialize with previous node
254
 
        return(&_route[_routeListIndex]);
 
312
        return &_route[_routeListIndex];
255
313
}
256
314
 
257
 
// Construct route to cx, cy.  Return TRUE if successful.
258
 
// 1.  Copy boundary bitmap to local byte map (include object bases)
259
 
// 2.  Construct list of segments segment[] from hero to destination
260
 
// 3.  Compress to shortest route in route[]
261
 
bool Route::findRoute(int16 cx, int16 cy) {
262
 
        int16      i,   j,   x, y;                      // Loop on coordinates
263
 
        int16      x1,  x2,  dx;                        // Overlap between segments
264
 
        int16      herox1, herox2, heroy;               // Current hero baseline
265
 
        object_t  *obj;                                 // Ptr to object
266
 
        segment_t *seg_p;                               // Ptr to segment
267
 
        Point     *routeNode;                           // Ptr to route node
268
 
 
 
315
/**
 
316
 * Construct route to cx, cy.  Return TRUE if successful.
 
317
 * 1.  Copy boundary bitmap to local byte map (include object bases)
 
318
 * 2.  Construct list of segments segment[] from hero to destination
 
319
 * 3.  Compress to shortest route in route[]
 
320
 */
 
321
bool Route::findRoute(const int16 cx, const int16 cy) {
269
322
        debugC(1, kDebugRoute, "findRoute(%d, %d)", cx, cy);
270
323
 
271
324
        // Initialize for search
273
326
        _fullStackFl = false;                           // Stack not exhausted
274
327
        _fullSegmentFl  = false;                        // Segments not exhausted
275
328
        _segmentNumb = 0;                               // Segment index
276
 
        _heroWidth = HERO_MIN_WIDTH;                    // Minimum width of hero
 
329
        _heroWidth = kHeroMinWidth;                     // Minimum width of hero
277
330
        _destY = cy;                                    // Destination coords
278
331
        _destX = cx;                                    // Destination coords
279
 
        herox1 = _vm._hero->x + _vm._hero->currImagePtr->x1;        // Hero baseline
280
 
        herox2 = _vm._hero->x + _vm._hero->currImagePtr->x2;        // Hero baseline
281
 
        heroy  = _vm._hero->y + _vm._hero->currImagePtr->y2;        // Hero baseline
 
332
 
 
333
        int16 herox1 = _vm->_hero->x + _vm->_hero->currImagePtr->x1;        // Hero baseline
 
334
        int16 herox2 = _vm->_hero->x + _vm->_hero->currImagePtr->x2;        // Hero baseline
 
335
        int16 heroy  = _vm->_hero->y + _vm->_hero->currImagePtr->y2;        // Hero baseline
282
336
 
283
337
        // Store all object baselines into objbound (except hero's = [0])
284
 
        for (i = 1, obj = &_vm._objects[i]; i < _vm._numObj; i++, obj++)
285
 
                if ((obj->screenIndex == *_vm._screen_p) && (obj->cycling != INVISIBLE) && (obj->priority == FLOATING))
286
 
                        _vm.storeBoundary(obj->oldx + obj->currImagePtr->x1, obj->oldx + obj->currImagePtr->x2, obj->oldy + obj->currImagePtr->y2);
 
338
        object_t  *obj;                                 // Ptr to object
 
339
        int i;
 
340
        for (i = 1, obj = &_vm->_object->_objects[i]; i < _vm->_object->_numObj; i++, obj++) {
 
341
                if ((obj->screenIndex == *_vm->_screen_p) && (obj->cycling != kCycleInvisible) && (obj->priority == kPriorityFloating))
 
342
                        _vm->_object->storeBoundary(obj->oldx + obj->currImagePtr->x1, obj->oldx + obj->currImagePtr->x2, obj->oldy + obj->currImagePtr->y2);
 
343
        }
287
344
 
288
345
        // Combine objbound and boundary bitmaps to local byte map
289
 
        for (y = 0; y < YPIX; y++)
290
 
                for (x = 0; x < XBYTES; x++)
 
346
        for (uint16 y = 0; y < kYPix; y++) {
 
347
                for (uint16 x = 0; x < kCompLineSize; x++) {
 
348
                        uint16 boundIdx = y * kCompLineSize + x;
291
349
                        for (i = 0; i < 8; i++)
292
 
                                _boundaryMap[y][x * 8 + i] = ((_vm.getObjectBoundaryOverlay()[y * XBYTES + x] | _vm.getBoundaryOverlay()[y * XBYTES + x]) & (0x80 >> i)) ? kMapBound : 0;
 
350
                                _boundaryMap[y][x * 8 + i] = ((_vm->_object->getObjectBoundary(boundIdx) | _vm->_object->getBoundaryOverlay(boundIdx)) & (0x80 >> i)) ? kMapBound : 0;
 
351
                }
 
352
        }
293
353
 
294
354
        // Clear all object baselines from objbound
295
 
        for (i = 0, obj = _vm._objects; i < _vm._numObj; i++, obj++)
296
 
                if ((obj->screenIndex == *_vm._screen_p) && (obj->cycling != INVISIBLE) && (obj->priority == FLOATING))
297
 
                        _vm.clearBoundary(obj->oldx + obj->currImagePtr->x1, obj->oldx + obj->currImagePtr->x2, obj->oldy + obj->currImagePtr->y2);
 
355
        for (i = 0, obj = _vm->_object->_objects; i < _vm->_object->_numObj; i++, obj++) {
 
356
                if ((obj->screenIndex == *_vm->_screen_p) && (obj->cycling != kCycleInvisible) && (obj->priority == kPriorityFloating))
 
357
                        _vm->_object->clearBoundary(obj->oldx + obj->currImagePtr->x1, obj->oldx + obj->currImagePtr->x2, obj->oldy + obj->currImagePtr->y2);
 
358
        }
298
359
 
299
360
        // Search from hero to destination
300
361
        segment(herox1, heroy);
301
362
 
302
363
        // Not found or not enough stack or MAX_SEG exceeded
303
364
        if (!_routeFoundFl || _fullStackFl || _fullSegmentFl) {
304
 
                return(false);
 
365
                return false;
305
366
        }
306
367
 
307
368
        // Now find the route of nodes from destination back to hero
315
376
        _segment[_segmentNumb].x2 = herox2;
316
377
        _segmentNumb++;
317
378
 
 
379
        Point     *routeNode;                           // Ptr to route node
318
380
        // Look in segments[] for straight lines from destination to hero
319
381
        for (i = 0, _routeListIndex = 0; i < _segmentNumb - 1; i++) {
320
 
                if ((routeNode = newNode()) == NULL)        // New node for new segment
321
 
                        return(false);                          // Too many nodes
 
382
                if ((routeNode = newNode()) == 0)           // New node for new segment
 
383
                        return false;                           // Too many nodes
322
384
                routeNode->y = _segment[i].y;
323
385
 
324
386
                // Look ahead for furthest straight line
325
 
                for (j = i + 1; j < _segmentNumb; j++) {
326
 
                        seg_p = &_segment[j];
 
387
                for (int16 j = i + 1; j < _segmentNumb; j++) {
 
388
                        segment_t *seg_p = &_segment[j];
327
389
                        // Can we get to this segment from previous node?
328
 
                        if (seg_p->x1 <= routeNode->x && seg_p->x2 >= routeNode->x + _heroWidth - 1)
 
390
                        if (seg_p->x1 <= routeNode->x && seg_p->x2 >= routeNode->x + _heroWidth - 1) {
329
391
                                routeNode->y = seg_p->y;            // Yes, keep updating node
330
 
                        else {
 
392
                        } else {
331
393
                                // No, create another node on previous segment to reach it
332
 
                                if ((routeNode = newNode()) == NULL)    // Add new route node
333
 
                                        return (false);                 // Too many nodes
 
394
                                if ((routeNode = newNode()) == 0)   // Add new route node
 
395
                                        return false;                   // Too many nodes
334
396
 
335
397
                                // Find overlap between old and new segments
336
 
                                x1 = MAX(_segment[j - 1].x1, seg_p->x1);
337
 
                                x2 = MIN(_segment[j - 1].x2, seg_p->x2);
 
398
                                int16 x1 = MAX(_segment[j - 1].x1, seg_p->x1);
 
399
                                int16 x2 = MIN(_segment[j - 1].x2, seg_p->x2);
338
400
 
339
401
                                // If room, add a little offset to reduce staircase effect
340
 
                                dx = HERO_MAX_WIDTH >> 1;
 
402
                                int16 dx = kHeroMaxWidth >> 1;
341
403
                                if (x2 - x1 < _heroWidth + dx)
342
404
                                        dx = 0;
343
405
 
362
424
        return true;
363
425
}
364
426
 
365
 
// Process hero in route mode - called from Move_objects()
 
427
/**
 
428
 * Process hero in route mode - called from Move_objects()
 
429
 */
366
430
void Route::processRoute() {
367
 
        int16 herox, heroy;                             // Hero position
368
 
        Point *routeNode;                               // Ptr to current route node
 
431
        debugC(1, kDebugRoute, "processRoute");
 
432
 
369
433
        static bool turnedFl = false;                   // Used to get extra cylce for turning
370
434
 
371
 
        status_t &gameStatus = _vm.getGameStatus();
372
 
 
373
 
        debugC(1, kDebugRoute, "processRoute");
 
435
        if (_routeIndex < 0)
 
436
                return;
374
437
 
375
438
        // Current hero position
376
 
        herox = _vm._hero->x + _vm._hero->currImagePtr->x1;
377
 
        heroy = _vm._hero->y + _vm._hero->currImagePtr->y2;
378
 
        routeNode = &_route[gameStatus.routeIndex];
 
439
        int16 herox = _vm->_hero->x + _vm->_hero->currImagePtr->x1;
 
440
        int16 heroy = _vm->_hero->y + _vm->_hero->currImagePtr->y2;
 
441
        Point *routeNode = &_route[_routeIndex];
379
442
 
380
443
        // Arrived at node?
381
 
        if (abs(herox - routeNode->x) < DX + 1 && abs(heroy - routeNode->y) < DY) {
382
 
                // DX too low
 
444
        if (abs(herox - routeNode->x) < kStepDx + 1 && abs(heroy - routeNode->y) < kStepDy) {
 
445
                // kStepDx too low
383
446
                // Close enough - position hero exactly
384
 
                _vm._hero->x = _vm._hero->oldx = routeNode->x - _vm._hero->currImagePtr->x1;
385
 
                _vm._hero->y = _vm._hero->oldy = routeNode->y - _vm._hero->currImagePtr->y2;
386
 
                _vm._hero->vx = _vm._hero->vy = 0;
387
 
                _vm._hero->cycling = NOT_CYCLING;
 
447
                _vm->_hero->x = _vm->_hero->oldx = routeNode->x - _vm->_hero->currImagePtr->x1;
 
448
                _vm->_hero->y = _vm->_hero->oldy = routeNode->y - _vm->_hero->currImagePtr->y2;
 
449
                _vm->_hero->vx = _vm->_hero->vy = 0;
 
450
                _vm->_hero->cycling = kCycleNotCycling;
388
451
 
389
452
                // Arrived at final node?
390
 
                if (--gameStatus.routeIndex < 0) {
 
453
                if (--_routeIndex < 0) {
391
454
                        // See why we walked here
392
 
                        switch (gameStatus.go_for) {
393
 
                        case GO_EXIT:                           // Walked to an exit, proceed into it
394
 
                                setWalk(_vm._hotspots[gameStatus.go_id].direction);
395
 
                                break;
396
 
                        case GO_LOOK:                           // Look at an object
397
 
                                if (turnedFl) {
398
 
                                        _vm.lookObject(&_vm._objects[gameStatus.go_id]);
399
 
                                        turnedFl = false;
400
 
                                } else {
401
 
                                        setDirection(_vm._objects[gameStatus.go_id].direction);
402
 
                                        gameStatus.routeIndex++;        // Come round again
403
 
                                        turnedFl = true;
404
 
                                }
405
 
                                break;
406
 
                        case GO_GET:                            // Get (or use) an object
407
 
                                if (turnedFl) {
408
 
                                        _vm.useObject(gameStatus.go_id);
409
 
                                        turnedFl = false;
410
 
                                } else {
411
 
                                        setDirection(_vm._objects[gameStatus.go_id].direction);
412
 
                                        gameStatus.routeIndex++;        // Come round again
413
 
                                        turnedFl = true;
414
 
                                }
415
 
                                break;
416
 
                        case GO_SPACE:
417
 
                                warning("Unhandled gameStatus.go_for GO_STATUS");
 
455
                        switch (_routeType) {
 
456
                        case kRouteExit:                        // Walked to an exit, proceed into it
 
457
                                setWalk(_vm->_mouse->getDirection(_routeObjId));
 
458
                                break;
 
459
                        case kRouteLook:                        // Look at an object
 
460
                                if (turnedFl) {
 
461
                                        _vm->_object->lookObject(&_vm->_object->_objects[_routeObjId]);
 
462
                                        turnedFl = false;
 
463
                                } else {
 
464
                                        setDirection(_vm->_object->_objects[_routeObjId].direction);
 
465
                                        _routeIndex++;                  // Come round again
 
466
                                        turnedFl = true;
 
467
                                }
 
468
                                break;
 
469
                        case kRouteGet:                         // Get (or use) an object
 
470
                                if (turnedFl) {
 
471
                                        _vm->_object->useObject(_routeObjId);
 
472
                                        turnedFl = false;
 
473
                                } else {
 
474
                                        setDirection(_vm->_object->_objects[_routeObjId].direction);
 
475
                                        _routeIndex++;                  // Come round again
 
476
                                        turnedFl = true;
 
477
                                }
 
478
                                break;
 
479
                        default:
418
480
                                break;
419
481
                        }
420
482
                }
421
 
        } else if (_vm._hero->vx == 0 && _vm._hero->vy == 0) {
 
483
        } else if (_vm->_hero->vx == 0 && _vm->_hero->vy == 0) {
422
484
                // Set direction of travel if at a node
423
485
                // Note realignment when changing to (thinner) up/down sprite,
424
486
                // otherwise hero could bump into boundaries along route.
425
 
                if (herox < routeNode->x)
 
487
                if (herox < routeNode->x) {
426
488
                        setWalk(Common::KEYCODE_RIGHT);
427
 
                else if (herox > routeNode->x)
 
489
                } else if (herox > routeNode->x) {
428
490
                        setWalk(Common::KEYCODE_LEFT);
429
 
                else if (heroy < routeNode->y) {
 
491
                } else if (heroy < routeNode->y) {
430
492
                        setWalk(Common::KEYCODE_DOWN);
431
 
                        _vm._hero->x = _vm._hero->oldx = routeNode->x - _vm._hero->currImagePtr->x1;
 
493
                        _vm->_hero->x = _vm->_hero->oldx = routeNode->x - _vm->_hero->currImagePtr->x1;
432
494
                } else if (heroy > routeNode->y) {
433
495
                        setWalk(Common::KEYCODE_UP);
434
 
                        _vm._hero->x = _vm._hero->oldx = routeNode->x - _vm._hero->currImagePtr->x1;
 
496
                        _vm->_hero->x = _vm->_hero->oldx = routeNode->x - _vm->_hero->currImagePtr->x1;
435
497
                }
436
498
        }
437
499
}
438
500
 
439
 
// Start a new route from hero to cx, cy
440
 
// go_for is the purpose, id indexes the exit or object to walk to
441
 
// Returns FALSE if route not found
442
 
bool Route::startRoute(go_t go_for, int16 id, int16 cx, int16 cy) {
443
 
        bool foundFl = false;                           // TRUE if route found ok
444
 
 
445
 
        status_t &gameStatus = _vm.getGameStatus();
446
 
 
447
 
        debugC(1, kDebugRoute, "startRoute(%d, %d, %d, %d)", go_for, id, cx, cy);
 
501
/**
 
502
 * Start a new route from hero to cx, cy
 
503
 * go_for is the purpose, id indexes the exit or object to walk to
 
504
 * Returns FALSE if route not found
 
505
 */
 
506
bool Route::startRoute(const go_t routeType, const int16 objId, int16 cx, int16 cy) {
 
507
        debugC(1, kDebugRoute, "startRoute(%d, %d, %d, %d)", routeType, objId, cx, cy);
448
508
 
449
509
        // Don't attempt to walk if user does not have control
450
 
        if (_vm._hero->pathType != USER)
 
510
        if (_vm->_hero->pathType != kPathUser)
451
511
                return false;
452
512
 
453
513
        // if inventory showing, make it go away
454
 
        if (gameStatus.inventoryState != I_OFF)
455
 
                gameStatus.inventoryState = I_UP;
 
514
        if (_vm->_inventory->getInventoryState() != kInventoryOff)
 
515
                _vm->_inventory->setInventoryState(kInventoryUp);
456
516
 
457
 
        gameStatus.go_for = go_for;                     // Purpose of trip
458
 
        gameStatus.go_id  = id;                         // Index of exit/object
 
517
        _routeType = routeType;                         // Purpose of trip
 
518
        _routeObjId  = objId;                           // Index of exit/object
459
519
 
460
520
        // Adjust destination to center hero if walking to cursor
461
 
        if (gameStatus.go_for == GO_SPACE)
462
 
                cx -= HERO_MIN_WIDTH / 2;
 
521
        if (_routeType == kRouteSpace)
 
522
                cx -= kHeroMinWidth / 2;
463
523
 
 
524
        bool foundFl = false;                           // TRUE if route found ok
464
525
        if ((foundFl = findRoute(cx, cy))) {            // Found a route?
465
 
                gameStatus.routeIndex = _routeListIndex;    // Node index
466
 
                _vm._hero->vx = _vm._hero->vy = 0;      // Stop manual motion
 
526
                _routeIndex = _routeListIndex;              // Node index
 
527
                _vm->_hero->vx = _vm->_hero->vy = 0;        // Stop manual motion
467
528
        }
468
529
 
469
530
        return foundFl;