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 AI::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 "hdb/hdb.h"
24 #include "hdb/ai.h"
25 #include "hdb/map.h"
26 #include "hdb/sound.h"
27 #include "hdb/window.h"
28 
29 namespace HDB {
30 
isClosedDoor(int x,int y)31 bool AI::isClosedDoor(int x, int y) {
32 	int tileIndex = g_hdb->_map->getMapBGTileIndex(x, y);
33 
34 	if ((tileIndex == _targetDoorN + 3) ||		// locked SILVER door?
35 		(tileIndex == _targetDoorNv + 3) ||
36 		(tileIndex == _targetDoorP + 3) ||		// locked BLUE door?
37 		(tileIndex == _targetDoorPv + 3) ||
38 		(tileIndex == _targetDoorS + 3) ||		// locked RED door?
39 		(tileIndex == _targetDoorSv + 3) ||
40 		(tileIndex == _targetDoor2N + 3) ||		// locked SILVER door?
41 		(tileIndex == _targetDoor2Nv + 3) ||
42 		(tileIndex == _targetDoor2P + 3) ||		// locked BLUE door?
43 		(tileIndex == _targetDoor2Pv + 3) ||
44 		(tileIndex == _targetDoor2S + 3) ||		// locked RED door?
45 		(tileIndex == _targetDoor2Sv + 3) ||
46 		(tileIndex == _target2DoorN + 3) ||		// locked SILVER door?
47 		(tileIndex == _target2DoorNv + 3) ||
48 		(tileIndex == _target2DoorP + 3) ||		// locked BLUE door?
49 		(tileIndex == _target2DoorPv + 3) ||
50 		(tileIndex == _target2DoorS + 3) ||		// locked RED door?
51 		(tileIndex == _target2DoorSv + 3) ||
52 		(tileIndex == _target3DoorN + 3) ||		// locked SILVER door?
53 		(tileIndex == _target3DoorNv + 3) ||
54 		(tileIndex == _target3DoorP + 3) ||		// locked BLUE door?
55 		(tileIndex == _target3DoorPv + 3) ||
56 		(tileIndex == _target3DoorS + 3) ||		// locked RED door?
57 		(tileIndex == _target3DoorSv + 3) ||
58 		(tileIndex == _blockpole + 3))			// blockpole UP?
59 		return true;
60 	return false;
61 }
62 
isOpenDoor(int x,int y)63 bool AI::isOpenDoor(int x, int y) {
64 	int tileIndex = g_hdb->_map->getMapBGTileIndex(x, y);
65 
66 	if ((tileIndex == _targetDoorN) ||		// open SILVER door?
67 		(tileIndex == _targetDoorNv) ||
68 		(tileIndex == _targetDoorP) ||		// open BLUE door?
69 		(tileIndex == _targetDoorPv) ||
70 		(tileIndex == _targetDoorS) ||		// open RED door?
71 		(tileIndex == _targetDoorSv) ||
72 		(tileIndex == _targetDoor2N) ||		// open SILVER door?
73 		(tileIndex == _targetDoor2Nv) ||
74 		(tileIndex == _targetDoor2P) ||		// open BLUE door?
75 		(tileIndex == _targetDoor2Pv) ||
76 		(tileIndex == _targetDoor2S) ||		// open RED door?
77 		(tileIndex == _targetDoor2Sv) ||
78 		(tileIndex == _target2DoorN) ||		// open SILVER door?
79 		(tileIndex == _target2DoorNv) ||
80 		(tileIndex == _target2DoorP) ||		// open BLUE door?
81 		(tileIndex == _target2DoorPv) ||
82 		(tileIndex == _target2DoorS) ||		// open RED door?
83 		(tileIndex == _target2DoorSv) ||
84 		(tileIndex == _target3DoorN) ||		// open SILVER door?
85 		(tileIndex == _target3DoorNv) ||
86 		(tileIndex == _target3DoorP) ||		// open BLUE door?
87 		(tileIndex == _target3DoorPv) ||
88 		(tileIndex == _target3DoorS) ||		// open RED door?
89 		(tileIndex == _target3DoorSv) ||
90 		(tileIndex == _blockpole))			// blockpole DOWN?
91 		return true;
92 	return false;
93 }
94 
useTarget(int x,int y,int targetX,int targetY,int newTile,int * worked)95 bool AI::useTarget(int x, int y, int targetX, int targetY, int newTile, int *worked) {
96 	// open a locked door?
97 	if (isClosedDoor(targetX, targetY)) {
98 		int tileIndex = g_hdb->_map->getMapBGTileIndex(targetX, targetY);
99 
100 		addAnimateTarget(targetX, targetY, tileIndex, tileIndex - 3, ANIM_SLOW, false, true, nullptr);
101 		g_hdb->_map->setMapBGTileIndex(x, y, newTile);
102 		if (g_hdb->_map->onScreen(x, y))
103 			g_hdb->_sound->playSound(SND_DOOR_OPEN_CLOSE);
104 		*worked = 1;
105 		return false;						// return FALSE because we need to be able to do it some more
106 	}
107 
108 	// close an open door?
109 	if (isOpenDoor(targetX, targetY)) {
110 		int tileIndex = g_hdb->_map->getMapBGTileIndex(targetX, targetY);
111 
112 		addAnimateTarget(targetX, targetY, tileIndex, tileIndex + 3, ANIM_SLOW, false, true, nullptr);
113 		g_hdb->_map->setMapBGTileIndex(x, y, newTile);
114 		if (g_hdb->_map->onScreen(x, y))
115 			g_hdb->_sound->playSound(SND_DOOR_OPEN_CLOSE);
116 		*worked = 1;
117 		return false;						// return FALSE because we need to be able to do it some more
118 	}
119 
120 	// open up a bridge?
121 	int tileIndex = g_hdb->_map->getMapFGTileIndex(targetX, targetY);
122 	if (tileIndex == _targetBridgeU ||
123 		tileIndex == _targetBridgeD ||
124 		tileIndex == _targetBridgeL ||
125 		tileIndex == _targetBridgeR) {
126 		addBridgeExtend(targetX, targetY, tileIndex);
127 		g_hdb->_map->setMapBGTileIndex(x, y, newTile);
128 		*worked = 1;
129 		return true;						// return TRUE because we can't open it again
130 	}
131 
132 	*worked = 0;
133 	return false;
134 }
135 
136 // Black Door Switch
useSwitch(AIEntity * e,int x,int y,int targetX,int targetY,int onTile)137 bool AI::useSwitch(AIEntity *e, int x, int y, int targetX, int targetY, int onTile) {
138 	int worked;
139 	if (g_hdb->_map->onScreen(x, y))
140 		g_hdb->_sound->playSound(SND_SWITCH_USE);
141 	return useTarget(x, y, targetX, targetY, onTile, &worked);
142 }
143 
useSwitchOn(AIEntity * e,int x,int y,int targetX,int targetY,int offTile)144 bool AI::useSwitchOn(AIEntity *e, int x, int y, int targetX, int targetY, int offTile) {
145 	int worked;
146 	if (g_hdb->_map->onScreen(x, y))
147 		g_hdb->_sound->playSound(SND_SWITCH_USE);
148 	return useTarget(x, y, targetX, targetY, offTile, &worked);
149 }
150 
useSwitch2(AIEntity * e,int x,int y,int targetX,int targetY)151 bool AI::useSwitch2(AIEntity *e, int x, int y, int targetX, int targetY) {
152 	// int i = 10; // unused
153 	return true;
154 }
155 
156 // Colored Keycard Switch
useLockedSwitch(AIEntity * e,int x,int y,int targetX,int targetY,int onTile,AIType item,const char * keyerror)157 bool AI::useLockedSwitch(AIEntity *e, int x, int y, int targetX, int targetY, int onTile, AIType item, const char *keyerror) {
158 	// is the PLAYER next to this thing?  No other entities are allowed to unlock anything!
159 	if (abs(x - _player->tileX) > 1 || abs(y - _player->tileY) > 1)
160 		return false;
161 
162 	int	amount = queryInventoryType(item);
163 	if (amount) {
164 		int	worked;
165 		bool rtn = useTarget(x, y, targetX, targetY, onTile, &worked);
166 		if (worked) {
167 			removeInvItemType(item, 1);
168 			if (g_hdb->_map->onScreen(x, y))
169 				g_hdb->_sound->playSound(SND_SWITCH_USE);
170 		}
171 		return rtn;
172 	} else {
173 		if (g_hdb->_map->onScreen(x, y))
174 			g_hdb->_sound->playSound(SND_CELLHOLDER_USE_REJECT);
175 		g_hdb->_window->openMessageBar(keyerror, 3);
176 	}
177 	return false;
178 }
179 
useLockedSwitchOn(AIEntity * e,int x,int y,int targetX,int targetY,int offTile,AIType item)180 bool AI::useLockedSwitchOn(AIEntity *e, int x, int y, int targetX, int targetY, int offTile, AIType item) {
181 	// is the PLAYER next to this thing?  No other entities are allowed to unlock anything!
182 	if (abs(x - _player->tileX) > 1 || abs(y - _player->tileY) > 1)
183 		return false;
184 
185 	if (getInvAmount() == 10)
186 		return false;
187 
188 	int	worked;
189 	bool rtn = useTarget(x, y, targetX, targetY, offTile, &worked);
190 	if (worked) {
191 		addItemToInventory(item, 1, nullptr, nullptr, nullptr);
192 		if (g_hdb->_map->onScreen(x, y))
193 			g_hdb->_sound->playSound(SND_SWITCH_USE);
194 	}
195 	return rtn;
196 }
197 
198 // Purple Cell Holder Switch
useCellHolder(AIEntity * e,int x,int y,int targetX,int targetY)199 bool AI::useCellHolder(AIEntity *e, int x, int y, int targetX, int targetY) {
200 	// is the PLAYER next to this thing?  No other entities are allowed to unlock anything!
201 	if (abs(x - _player->tileX) > 1 || abs(y - _player->tileY) > 1)
202 		return false;
203 
204 	int	amount = queryInventoryType(ITEM_CELL);
205 
206 	if (amount) {
207 		int	worked;
208 		bool rtn = useTarget(x, y, targetX, targetY, _useHolderFull, &worked);
209 		if (worked) {
210 			removeInvItemType(ITEM_CELL, 1);
211 			if (g_hdb->_map->onScreen(x, y))
212 				g_hdb->_sound->playSound(SND_SWITCH_USE);
213 		}
214 		return rtn;
215 	} else {
216 		if (g_hdb->_map->onScreen(x, y))
217 			g_hdb->_sound->playSound(SND_CELLHOLDER_USE_REJECT);
218 	}
219 
220 	g_hdb->_window->openDialog("Locked!", -1, "I can't use that unless I have an Energy Cell.", 0, nullptr);
221 	g_hdb->_sound->playVoice(GUY_ENERGY_CELL, 0);
222 	return false;
223 }
224 
225 // Touchplate
useTouchplate(AIEntity * e,int x,int y,int targetX,int targetY,int type)226 bool AI::useTouchplate(AIEntity *e, int x, int y, int targetX, int targetY, int type) {
227 	int worked;
228 	g_hdb->_sound->playSound(SND_TOUCHPLATE_CLICK);
229 	return useTarget(x, y, targetX, targetY, type, &worked);
230 }
useTouchplateOn(AIEntity * e,int x,int y,int targetX,int targetY,int type)231 bool AI::useTouchplateOn(AIEntity *e, int x, int y, int targetX, int targetY, int type) {
232 	int worked;
233 	g_hdb->_sound->playSound(SND_TOUCHPLATE_CLICK);
234 	return useTarget(x, y, targetX, targetY, type, &worked);
235 }
236 
callbackDoorOpenClose(int x,int y)237 void callbackDoorOpenClose(int x, int y) {
238 	int	tileIndex = g_hdb->_map->getMapBGTileIndex(x, y);
239 
240 	// is the door gonna close on something?  if so, wait again
241 	if (!g_hdb->_ai->findEntity(x, y)) {
242 		g_hdb->_ai->addCallback(CALLBACK_DOOR_OPEN_CLOSE, x, y, kDelay5Seconds);
243 		return;
244 	}
245 
246 	g_hdb->_ai->addAnimateTarget(x, y, tileIndex, tileIndex + 3, ANIM_SLOW, false, true, nullptr);
247 	if (g_hdb->_map->onScreen(x, y))
248 		g_hdb->_sound->playSound(SND_DOOR_OPEN_CLOSE);
249 	return;
250 }
251 
252 // Normal Door
useDoorOpenClose(AIEntity * e,int x,int y)253 bool AI::useDoorOpenClose(AIEntity *e, int x, int y) {
254 	int tileIndex = g_hdb->_map->getMapBGTileIndex(x, y);
255 
256 	addAnimateTarget(x, y, tileIndex, tileIndex - 3, ANIM_SLOW, false, true, nullptr);
257 	addCallback(CALLBACK_DOOR_OPEN_CLOSE, x, y, kDelay5Seconds);
258 	if (g_hdb->_map->onScreen(x, y))
259 		g_hdb->_sound->playSound(SND_DOOR_OPEN_CLOSE);
260 	return true;
261 }
262 
callbackAutoDoorOpenClose(int x,int y)263 void callbackAutoDoorOpenClose(int x, int y) {
264 	int tileIndex = g_hdb->_map->getMapBGTileIndex(x, y);
265 
266 	// Is the door going to close on something?
267 	if (g_hdb->_ai->findEntity(x, y)) {
268 		g_hdb->_ai->addCallback(CALLBACK_AUTODOOR_OPEN_CLOSE, x, y, kDelay5Seconds);
269 		return;
270 	}
271 
272 	g_hdb->_ai->addAnimateTarget(x, y, tileIndex, tileIndex + 3, ANIM_SLOW, true, true, nullptr);
273 	if (g_hdb->_map->onScreen(x, y))
274 		g_hdb->_sound->playSound(SND_DOOR_OPEN_CLOSE);
275 	return;
276 }
277 
useAutoDoorOpenClose(AIEntity * e,int x,int y)278 bool AI::useAutoDoorOpenClose(AIEntity *e, int x, int y) {
279 	int tileIndex = g_hdb->_map->getMapBGTileIndex(x, y);
280 
281 	if (autoActive(x, y))
282 		return false;
283 
284 	addAnimateTarget(x, y, tileIndex, tileIndex - 3, ANIM_SLOW, false, true, nullptr);
285 	addCallback(CALLBACK_AUTODOOR_OPEN_CLOSE, x, y, kDelay5Seconds);
286 	if (g_hdb->_map->onScreen(x, y))
287 		g_hdb->_sound->playSound(SND_DOOR_OPEN_CLOSE);
288 	return false;
289 }
290 
291 // Any Type Door
useDoorOpenCloseBot(AIEntity * e,int x,int y)292 bool AI::useDoorOpenCloseBot(AIEntity *e, int x, int y) {
293 	int	tileIndex = g_hdb->_map->getMapBGTileIndex(x, y);
294 
295 	if (e == _player || e->type == AI_SLUG_ATTACK || e->type == AI_GEM_ATTACK) {
296 		if (isClosedDoor(x, y))
297 			g_hdb->_sound->playSound(SND_GUY_UHUH);
298 		return false;
299 	}
300 
301 	addAnimateTarget(x, y, tileIndex, tileIndex - 3, ANIM_SLOW, false, true, nullptr);
302 	//	AddCallback( CALLBACK_DOOR_OPEN_CLOSE, x, y, DELAY_5SECONDS / fs );
303 	if (g_hdb->_map->onScreen(x, y))
304 		g_hdb->_sound->playSound(SND_DOOR_OPEN_CLOSE);
305 	return true;
306 }
307 
308 } // End of Namespace
309