1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #include "bladerunner/item.h"
24 
25 #include "bladerunner/bladerunner.h"
26 
27 #include "bladerunner/savefile.h"
28 #include "bladerunner/slice_renderer.h"
29 #include "bladerunner/zbuffer.h"
30 
31 namespace BladeRunner {
32 
Item(BladeRunnerEngine * vm)33 Item::Item(BladeRunnerEngine *vm) {
34 	_vm = vm;
35 
36 	_itemId = -1;
37 	_setId = -1;
38 
39 	_animationId = -1;
40 	_position.x = 0;
41 	_position.y = 0;
42 	_position.z = 0;
43 	_facing = 0;
44 	_angle = 0.0f;
45 	_width = 0;
46 	_height = 0;
47 	_boundingBox.setXYZ(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f);
48 	_screenX = 0;
49 	_screenY = 0;
50 	_depth = 0.0f;
51 	_isTarget = false;
52 	_isSpinning = false;
53 	_facingChange = 0;
54 	_isVisible = true;
55 	_isPoliceMazeEnemy = false;
56 	_screenRectangle.bottom = -1;
57 	_screenRectangle.right = -1;
58 	_screenRectangle.top = -1;
59 	_screenRectangle.left = -1;
60 }
61 
getXYZ(float * x,float * y,float * z) const62 void Item::getXYZ(float *x, float *y, float *z) const {
63 	*x = _position.x;
64 	*y = _position.y;
65 	*z = _position.z;
66 }
67 
getWidthHeight(int * width,int * height) const68 void Item::getWidthHeight(int *width, int *height) const {
69 	*width = _width;
70 	*height = _height;
71 }
72 
getAnimationId(int * animationId) const73 void Item::getAnimationId(int *animationId) const {
74 	*animationId = _animationId;
75 }
76 
setFacing(int facing)77 void Item::setFacing(int facing) {
78 	_facing = facing;
79 	_angle = _facing * (M_PI / 512.0f);
80 }
81 
tick(Common::Rect * screenRect,bool special)82 bool Item::tick(Common::Rect *screenRect, bool special) {
83 	if (!_isVisible) {
84 		*screenRect = Common::Rect();
85 		return false;
86 	}
87 
88 	bool isVisibleFlag = false;
89 
90 	Vector3 position(_position.x, -_position.z, _position.y);
91 	int animationId = _animationId + (special ? 1 : 0);
92 	_vm->_sliceRenderer->drawInWorld(animationId, 0, position, M_PI - _angle, 1.0f, _vm->_surfaceFront, _vm->_zbuffer->getData());
93 	_vm->_sliceRenderer->getScreenRectangle(&_screenRectangle, animationId, 0, position, M_PI - _angle, 1.0f);
94 
95 	if (!_screenRectangle.isEmpty()) {
96 		*screenRect = _screenRectangle;
97 		isVisibleFlag = true;
98 	} else {
99 		*screenRect = Common::Rect();
100 	}
101 
102 	if (_isSpinning) {
103 		_facing += _facingChange;
104 
105 		if (_facing >= 1024) {
106 			_facing -= 1024;
107 		} else if (_facing < 0) {
108 			_facing += 1024;
109 		}
110 		_angle = _facing * (M_PI / 512.0f);
111 
112 		if (_facingChange > 0) {
113 			_facingChange = _facingChange - 20;
114 			if (_facingChange < 0) {
115 				_facingChange = 0;
116 				_isSpinning = false;
117 			}
118 		} else if (_facingChange < 0) {
119 			_facingChange = _facingChange + 20;
120 			if (_facingChange > 0) {
121 				_facingChange = 0;
122 				_isSpinning = false;
123 			}
124 		} else {
125 			_isSpinning = false;
126 		}
127 	}
128 
129 	return isVisibleFlag;
130 }
131 
132 // setXYZ() recalculates the item's bounding box,
133 // but in addition to the item's (Vector3) position
134 // it takes into account the item's width and height
setXYZ(Vector3 position)135 void Item::setXYZ(Vector3 position) {
136 	_position = position;
137 	int halfWidth = _width / 2;
138 	_boundingBox.setXYZ(_position.x - halfWidth, _position.y, _position.z - halfWidth,
139 	                    _position.x + halfWidth, _position.y + _height, _position.z + halfWidth);
140 	Vector3 screenPosition = _vm->_view->calculateScreenPosition(_position);
141 	_screenX = screenPosition.x;
142 	_screenY = screenPosition.y;
143 	_depth = screenPosition.z * 25.5f;
144 }
145 
setup(int itemId,int setId,int animationId,Vector3 position,int facing,int height,int width,bool isTargetFlag,bool isVisibleFlag,bool isPoliceMazeEnemyFlag)146 void Item::setup(int itemId, int setId, int animationId, Vector3 position, int facing, int height, int width, bool isTargetFlag, bool isVisibleFlag, bool isPoliceMazeEnemyFlag) {
147 	_itemId = itemId;
148 	_setId = setId;
149 	_animationId = animationId;
150 	_facing = facing;
151 	_angle = facing * (M_PI / 512.0f);
152 	_width = width;
153 	_height = height;
154 	_isTarget = isTargetFlag;
155 	_isVisible = isVisibleFlag;
156 	_isPoliceMazeEnemy = isPoliceMazeEnemyFlag;
157 	setXYZ(position);
158 	_screenRectangle.bottom = -1;
159 	_screenRectangle.right = -1;
160 	_screenRectangle.top = -1;
161 	_screenRectangle.left = -1;
162 }
163 
spinInWorld()164 void Item::spinInWorld() {
165 	_isSpinning = true;
166 	if (_vm->_rnd.getRandomNumberRng(1, 2) == 1) {
167 		_facingChange = -340;
168 	} else {
169 		_facingChange = 340;
170 	}
171 }
172 
isUnderMouse(int mouseX,int mouseY) const173 bool Item::isUnderMouse(int mouseX, int mouseY) const {
174 	return _isVisible
175 	    && mouseX >= _screenRectangle.left   - 10
176 	    && mouseX <= _screenRectangle.right  + 10
177 	    && mouseY >= _screenRectangle.top    - 10
178 	    && mouseY <= _screenRectangle.bottom + 10;
179 }
180 
save(SaveFileWriteStream & f)181 void Item::save(SaveFileWriteStream &f) {
182 	f.writeInt(_setId);
183 	f.writeInt(_itemId);
184 	f.writeBoundingBox(_boundingBox, false);
185 	f.writeRect(_screenRectangle);
186 	f.writeInt(_animationId);
187 	f.writeVector3(_position);
188 	f.writeInt(_facing);
189 	f.writeFloat(_angle);
190 	f.writeInt(_width);
191 	f.writeInt(_height);
192 	f.writeInt(_screenX);
193 	f.writeInt(_screenY);
194 	f.writeFloat(_depth);
195 	f.writeBool(_isTarget);
196 	f.writeBool(_isSpinning);
197 	f.writeInt(_facingChange);
198 	f.writeFloat(0.0f); // _viewAngle
199 	f.writeBool(_isVisible);
200 	f.writeBool(_isPoliceMazeEnemy);
201 }
202 
load(SaveFileReadStream & f)203 void Item::load(SaveFileReadStream &f) {
204 	_setId = f.readInt();
205 	_itemId = f.readInt();
206 	_boundingBox = f.readBoundingBox(false);
207 	_screenRectangle = f.readRect();
208 	_animationId = f.readInt();
209 	_position = f.readVector3();
210 	_facing  = f.readInt();
211 	_angle = f.readFloat();
212 	_width = f.readInt();
213 	_height = f.readInt();
214 	_screenX = f.readInt();
215 	_screenY = f.readInt();
216 	_depth = f.readFloat();
217 	_isTarget = f.readBool();
218 	_isSpinning = f.readBool();
219 	_facingChange = f.readInt();
220 	f.skip(4);
221 	_isVisible = f.readBool();
222 	_isPoliceMazeEnemy = f.readBool();
223 }
224 
225 } // End of namespace BladeRunner
226