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