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/items.h"
24 
25 #include "bladerunner/game_constants.h"
26 #include "bladerunner/savefile.h"
27 #include "bladerunner/scene.h"
28 #include "bladerunner/scene_objects.h"
29 #include "bladerunner/zbuffer.h"
30 
31 namespace BladeRunner {
32 
Items(BladeRunnerEngine * vm)33 Items::Items(BladeRunnerEngine *vm) {
34 	_vm = vm;
35 }
36 
~Items()37 Items::~Items() {
38 	reset();
39 }
40 
reset()41 void Items::reset() {
42 	for (int i = _items.size() - 1; i >= 0; --i) {
43 		delete _items.remove_at(i);
44 	}
45 }
46 
getXYZ(int itemId,float * x,float * y,float * z) const47 void Items::getXYZ(int itemId, float *x, float *y, float *z) const {
48 	int itemIndex = findItem(itemId);
49 	assert(itemIndex != -1);
50 
51 	_items[itemIndex]->getXYZ(x, y, z);
52 }
53 
setXYZ(int itemId,Vector3 position)54 void Items::setXYZ(int itemId, Vector3 position) {
55 	int itemIndex = findItem(itemId);
56 	assert(itemIndex != -1);
57 
58 	_items[itemIndex]->setXYZ(position);
59 }
60 
getWidthHeight(int itemId,int * width,int * height) const61 void Items::getWidthHeight(int itemId, int *width, int *height) const {
62 	int itemIndex = findItem(itemId);
63 	assert(itemIndex != -1);
64 
65 	_items[itemIndex]->getWidthHeight(width, height);
66 }
67 
getAnimationId(int itemId,int * animationId) const68 void Items::getAnimationId(int itemId, int *animationId) const {
69 	int itemIndex = findItem(itemId);
70 	assert(itemIndex != -1);
71 
72 	_items[itemIndex]->getAnimationId(animationId);
73 }
74 
tick()75 void Items::tick() {
76 	int setId = _vm->_scene->getSetId();
77 	for (int i = 0; i < (int)_items.size(); ++i) {
78 		if (_items[i]->_setId != setId) {
79 			continue;
80 		}
81 		bool notPoliceMazeTarget = setId == kSetPS10_PS11_PS12_PS13 && !_items[i]->isTarget();
82 		Common::Rect screenRect;
83 		if (_items[i]->tick(&screenRect, notPoliceMazeTarget)) {
84 			_vm->_zbuffer->mark(screenRect);
85 		}
86 	}
87 }
88 
addToWorld(int itemId,int animationId,int setId,Vector3 position,int facing,int height,int width,bool isTargetFlag,bool isVisibleFlag,bool isPoliceMazeEnemyFlag,bool addToSetFlag)89 bool Items::addToWorld(int itemId, int animationId, int setId, Vector3 position, int facing, int height, int width, bool isTargetFlag, bool isVisibleFlag, bool isPoliceMazeEnemyFlag, bool addToSetFlag) {
90 	if (_items.size() >= 100) {
91 		return false;
92 	}
93 	int itemIndex = findItem(itemId);
94 	if (itemIndex == -1) {
95 		itemIndex = _items.size();
96 		_items.push_back(new Item(_vm));
97 	}
98 
99 	Item *item = _items[itemIndex];
100 	item->setup(itemId, setId, animationId, position, facing, height, width, isTargetFlag, isVisibleFlag, isPoliceMazeEnemyFlag);
101 
102 	if (addToSetFlag && setId == _vm->_scene->getSetId()) {
103 		return _vm->_sceneObjects->addItem(itemId + kSceneObjectOffsetItems, item->_boundingBox, item->_screenRectangle, isTargetFlag, isVisibleFlag);
104 	}
105 	return true;
106 }
107 
addToSet(int setId)108 bool Items::addToSet(int setId) {
109 	int itemCount = _items.size();
110 	if (itemCount == 0) {
111 		return true;
112 	}
113 	for (int i = 0; i < itemCount; ++i) {
114 		Item *item = _items[i];
115 		if (item->_setId == setId) {
116 			_vm->_sceneObjects->addItem(item->_itemId + kSceneObjectOffsetItems, item->_boundingBox, item->_screenRectangle, item->isTarget(), item->_isVisible);
117 		}
118 	}
119 	return true;
120 }
121 
122 #if !BLADERUNNER_ORIGINAL_BUGS
removeFromCurrentSceneOnly(int itemId)123 bool Items::removeFromCurrentSceneOnly(int itemId) {
124 	if (_items.size() == 0) {
125 		return false;
126 	}
127 	int itemIndex = findItem(itemId);
128 	if (itemIndex == -1) {
129 		return false;
130 	}
131 
132 	if (_items[itemIndex]->_setId == _vm->_scene->getSetId()) {
133 		_vm->_sceneObjects->remove(itemId + kSceneObjectOffsetItems);
134 	}
135 	return true;
136 }
137 #endif // !BLADERUNNER_ORIGINAL_BUGS
138 
remove(int itemId)139 bool Items::remove(int itemId) {
140 	if (_items.size() == 0) {
141 		return false;
142 	}
143 	int itemIndex = findItem(itemId);
144 	if (itemIndex == -1) {
145 		return false;
146 	}
147 
148 	if (_items[itemIndex]->_setId == _vm->_scene->getSetId()) {
149 		_vm->_sceneObjects->remove(itemId + kSceneObjectOffsetItems);
150 	}
151 
152 	delete _items.remove_at(itemIndex);
153 
154 	return true;
155 }
156 
setIsTarget(int itemId,bool val)157 void Items::setIsTarget(int itemId, bool val) {
158 	int itemIndex = findItem(itemId);
159 	if (itemIndex == -1) {
160 		return;
161 	}
162 	_items[itemIndex]->setIsTarget(val);
163 	_vm->_sceneObjects->setIsTarget(itemId + kSceneObjectOffsetItems, val);
164 }
165 
isTarget(int itemId) const166 bool Items::isTarget(int itemId) const {
167 	int itemIndex = findItem(itemId);
168 	if (itemIndex == -1) {
169 		return false;
170 	}
171 	return _items[itemIndex]->isTarget();
172 }
173 
isSpinning(int itemId) const174 bool Items::isSpinning(int itemId) const {
175 	int itemIndex = findItem(itemId);
176 	if (itemIndex == -1) {
177 		return false;
178 	}
179 	return _items[itemIndex]->isSpinning();
180 }
181 
isVisible(int itemId) const182 bool Items::isVisible(int itemId) const {
183 	int itemIndex = findItem(itemId);
184 	if (itemIndex == -1) {
185 		return false;
186 	}
187 	return _items[itemIndex]->isVisible();
188 }
189 
isPoliceMazeEnemy(int itemId) const190 bool Items::isPoliceMazeEnemy(int itemId) const {
191 	int itemIndex = findItem(itemId);
192 	if (itemIndex == -1) {
193 		return false;
194 	}
195 	return _items[itemIndex]->isPoliceMazeEnemy();
196 }
197 
setPoliceMazeEnemy(int itemId,bool val)198 void Items::setPoliceMazeEnemy(int itemId, bool val) {
199 	int itemIndex = findItem(itemId);
200 	if (itemIndex == -1) {
201 		return;
202 	}
203 	_items[itemIndex]->setPoliceMazeEnemy(val);
204 }
205 
setIsObstacle(int itemId,bool val)206 void Items::setIsObstacle(int itemId, bool val) {
207 	int itemIndex = findItem(itemId);
208 	if (itemIndex == -1) {
209 		return;
210 	}
211 	_items[itemIndex]->setVisible(val);
212 	_vm->_sceneObjects->setIsClickable(itemId + kSceneObjectOffsetItems, val);
213 }
214 
getBoundingBox(int itemId)215 const BoundingBox &Items::getBoundingBox(int itemId) {
216 	int itemIndex = findItem(itemId);
217 	// if (itemIndex == -1) {
218 	// 	return nullptr;
219 	// }
220 	return _items[itemIndex]->getBoundingBox();
221 }
222 
getScreenRectangle(int itemId)223 const Common::Rect &Items::getScreenRectangle(int itemId) {
224 	int itemIndex = findItem(itemId);
225 	// if (itemIndex == -1) {
226 	// 	return nullptr;
227 	// }
228 	return _items[itemIndex]->getScreenRectangle();
229 }
230 
getFacing(int itemId) const231 int Items::getFacing(int itemId) const {
232 	int itemIndex = findItem(itemId);
233 	if (itemIndex == -1) {
234 		return 0;
235 	}
236 	return _items[itemIndex]->getFacing();
237 }
238 
setFacing(int itemId,int facing)239 void Items::setFacing(int itemId, int facing) {
240 	int itemIndex = findItem(itemId);
241 	if (itemIndex == -1) {
242 		return;
243 	}
244 	_items[itemIndex]->setFacing(facing);
245 }
246 
spinInWorld(int itemId)247 void Items::spinInWorld(int itemId) {
248 	int itemIndex = findItem(itemId);
249 	if (itemIndex == -1) {
250 		return;
251 	}
252 	_items[itemIndex]->spinInWorld();
253 }
254 
findTargetUnderMouse(int mouseX,int mouseY) const255 int Items::findTargetUnderMouse(int mouseX, int mouseY) const {
256 	int setId = _vm->_scene->getSetId();
257 	for (int i = 0 ; i < (int)_items.size(); ++i) {
258 		if (_items[i]->_setId == setId && _items[i]->isTarget() && _items[i]->isUnderMouse(mouseX, mouseY)) {
259 			return _items[i]->_itemId;
260 		}
261 	}
262 	return -1;
263 }
264 
findItem(int itemId) const265 int Items::findItem(int itemId) const {
266 	for (int i = 0; i < (int)_items.size(); ++i) {
267 		if (_items[i]->_itemId == itemId) {
268 			return i;
269 		}
270 	}
271 	return -1;
272 }
273 
save(SaveFileWriteStream & f)274 void Items::save(SaveFileWriteStream &f) {
275 	int size = (int)_items.size();
276 
277 	f.writeInt(size);
278 	int i;
279 	for (i = 0; i != size; ++i) {
280 		_items[i]->save(f);
281 	}
282 
283 	// Always write out 100 items
284 	for (; i != 100; ++i) {
285 		f.padBytes(0x174); // bbox + rect + 18 float fields
286 	}
287 }
288 
load(SaveFileReadStream & f)289 void Items::load(SaveFileReadStream &f) {
290 	for (int i = _items.size() - 1; i >= 0; --i) {
291 		delete _items.remove_at(i);
292 	}
293 	_items.resize(f.readInt());
294 
295 	int size = (int)_items.size();
296 
297 	int i;
298 	for (i = 0; i != size; ++i) {
299 		_items[i] = new Item(_vm);
300 		_items[i]->load(f);
301 	}
302 
303 	// Always read out 100 items
304 	for (; i != 100; ++i) {
305 		f.skip(0x174); // bbox + rect + 18 float fields
306 	}
307 }
308 
309 } // End of namespace BladeRunner
310