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  * Additional copyright for this file:
8  * Copyright (C) 1994-1998 Revolution Software Ltd.
9  *
10  * This program is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU General Public License
12  * as published by the Free Software Foundation; either version 2
13  * of the License, or (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23  */
24 
25 
26 
27 #include "sword2/sword2.h"
28 #include "sword2/defs.h"
29 #include "sword2/header.h"
30 #include "sword2/logic.h"
31 #include "sword2/screen.h"
32 
33 namespace Sword2 {
34 
35 // Max no of pixel allowed to scroll per cycle
36 #define MAX_SCROLL_DISTANCE 8
37 
38 /**
39  * Sets the scroll target position for the end of the game cycle. The driver
40  * will then automatically scroll as many times as it can to reach this
41  * position in the allotted time.
42  */
43 
setScrollTarget(int16 sx,int16 sy)44 void Screen::setScrollTarget(int16 sx, int16 sy) {
45 	_scrollXTarget = sx;
46 	_scrollYTarget = sy;
47 }
48 
49 /**
50  * If the room is larger than the physical screen, this function is called
51  * every game cycle to update the scroll offsets.
52  */
53 
setScrolling()54 void Screen::setScrolling() {
55 	// Normally we aim to get George's feet at (320,250) from top left
56 	// of screen window
57 	// feet_x = 128 + 320
58 	// feet_y = 128 + 250
59 
60 	// Set scroll offsets according to the player's coords
61 
62 	// If the scroll offsets are being forced in script, ensure that they
63 	// are neither too far to the right nor too far down.
64 	uint32 scrollX = _vm->_logic->readVar(SCROLL_X);
65 	uint32 scrollY = _vm->_logic->readVar(SCROLL_Y);
66 
67 	if (scrollX || scrollY) {
68 		_thisScreen.scroll_offset_x = MIN((uint16)scrollX, _thisScreen.max_scroll_offset_x);
69 		_thisScreen.scroll_offset_y = MIN((uint16)scrollY, _thisScreen.max_scroll_offset_y);
70 		return;
71 	}
72 
73 	// George's offset from the center - the desired position for him
74 
75 	int16 offset_x = _thisScreen.player_feet_x - _thisScreen.feet_x;
76 	int16 offset_y = _thisScreen.player_feet_y - _thisScreen.feet_y;
77 
78 	// Prevent scrolling too far left/right/up/down
79 
80 	if (offset_x < 0)
81 		offset_x = 0;
82 	else if (offset_x > _thisScreen.max_scroll_offset_x)
83 		offset_x = _thisScreen.max_scroll_offset_x;
84 
85 	if (offset_y < 0)
86 		offset_y = 0;
87 	else if (offset_y > _thisScreen.max_scroll_offset_y)
88 		offset_y = _thisScreen.max_scroll_offset_y;
89 
90 	// First time on this screen - need absolute scroll immediately!
91 
92 	if (_thisScreen.scroll_flag == 2) {
93 		debug(5, "init scroll");
94 		_thisScreen.scroll_offset_x = offset_x;
95 		_thisScreen.scroll_offset_y = offset_y;
96 		_thisScreen.scroll_flag = 1;
97 		return;
98 	}
99 
100 	// Catch up with required scroll offsets - speed depending on distance
101 	// to catch up (dx and dy) and _scrollFraction used, but limit to
102 	// certain number of pixels per cycle (MAX_SCROLL_DISTANCE)
103 
104 	int16 dx = _thisScreen.scroll_offset_x - offset_x;
105 	int16 dy = _thisScreen.scroll_offset_y - offset_y;
106 
107 	uint16 scroll_distance_x;	// how much we want to scroll
108 	uint16 scroll_distance_y;
109 
110 	if (dx < 0) {
111 		// Current scroll_offset_x is less than the required value
112 
113 		// NB. I'm adding 1 to the result of dx / SCROLL_FRACTION,
114 		// because it would otherwise not scroll at all when
115 		// dx < SCROLL_FRACTION
116 
117 		// => inc by (fraction of the differnce) NB. dx is -ve, so we
118 		// subtract dx / SCROLL_FRACTION
119 
120 		scroll_distance_x = 1 - dx / _scrollFraction;
121 
122 		if (scroll_distance_x > MAX_SCROLL_DISTANCE)
123 			scroll_distance_x = MAX_SCROLL_DISTANCE;
124 
125 		_thisScreen.scroll_offset_x += scroll_distance_x;
126 	} else if (dx > 0) {
127 		// Current scroll_offset_x is greater than
128 		// the required value
129 
130 		// => dec by (fraction of the differnce)
131 
132 		scroll_distance_x = 1 + dx / _scrollFraction;
133 
134 		if (scroll_distance_x > MAX_SCROLL_DISTANCE)
135 			scroll_distance_x = MAX_SCROLL_DISTANCE;
136 
137 		_thisScreen.scroll_offset_x -= scroll_distance_x;
138 	}
139 
140 	if (dy < 0) {
141 		scroll_distance_y = 1 - dy / _scrollFraction;
142 
143 		if (scroll_distance_y > MAX_SCROLL_DISTANCE)
144 			scroll_distance_y = MAX_SCROLL_DISTANCE;
145 
146 		_thisScreen.scroll_offset_y += scroll_distance_y;
147 	} else if (dy > 0) {
148 		scroll_distance_y = 1 + dy / _scrollFraction;
149 
150 		if (scroll_distance_y > MAX_SCROLL_DISTANCE)
151 			scroll_distance_y = MAX_SCROLL_DISTANCE;
152 
153 		_thisScreen.scroll_offset_y -= scroll_distance_y;
154 	}
155 }
156 
157 } // End of namespace Sword2
158