1 #include "Cursors.h"
2 #include "Font_Control.h"
3 #include "TileDat.h"
4 #include "WorldDef.h"
5 #include "WorldMan.h"
6 #include "RenderWorld.h"
7 #include "Soldier_Find.h"
8 #include "Structure.h"
9 #include "Animation_Control.h"
10 #include "Points.h"
11 #include "Overhead.h"
12 #include "Structure_Wrap.h"
13 #include "Tile_Animation.h"
14 #include "Interactive_Tiles.h"
15 #include "Handle_Doors.h"
16 #include "Sound_Control.h"
17 #include "Interface.h"
18 #include "Keys.h"
19 #include "Message.h"
20 #include "Text.h"
21 #include "Random.h"
22 #include "SkillCheck.h"
23 #include "Dialogue_Control.h"
24 #include "Render_Fun.h"
25 #include "Quests.h"
26 #include "StrategicMap.h"
27 #include "Map_Screen_Interface_Map.h"
28 #include "Soldier_Profile.h"
29 #include "Isometric_Utils.h"
30 #include "AI.h"
31 #include "Soldier_Macros.h"
32 #include "Debug.h"
33 #include "GameRes.h"
34 
35 #include <string_theory/string>
36 
37 
38 static BOOLEAN HandleDoorsOpenClose(SOLDIERTYPE* pSoldier, INT16 sGridNo, STRUCTURE* pStructure, BOOLEAN fNoAnimations);
39 
40 
HandleDoorChangeFromGridNo(SOLDIERTYPE * const s,INT16 const grid_no,BOOLEAN const no_animation)41 void HandleDoorChangeFromGridNo(SOLDIERTYPE* const s, INT16 const grid_no, BOOLEAN const no_animation)
42 {
43 	STRUCTURE* const structure = FindStructure(grid_no, STRUCTURE_ANYDOOR);
44 	if (!structure)
45 	{
46 		SLOGE("Told to handle door that does not exist at %d.", grid_no);
47 		return;
48 	}
49 
50 	BOOLEAN const door_animated = HandleDoorsOpenClose(s, grid_no, structure, no_animation);
51 	if (SwapStructureForPartner(structure))
52 	{
53 		RecompileLocalMovementCosts(grid_no);
54 	}
55 
56 	// set door busy
57 	DOOR_STATUS* const door_status = GetDoorStatus(grid_no);
58 	if (!door_status)
59 	{
60 		SLOGE("Told to set door busy but can't get door status at %d!", grid_no);
61 		return;
62 	}
63 
64 	// ATE: Only do if animated.....
65 	if (door_animated) door_status->ubFlags |= DOOR_BUSY;
66 }
67 
68 
GetAnimStateForInteraction(SOLDIERTYPE const & s,BOOLEAN const door,UINT16 const anim_state)69 UINT16 GetAnimStateForInteraction(SOLDIERTYPE const& s, BOOLEAN const door, UINT16 const anim_state)
70 {
71 	bool const standing = gAnimControl[s.usAnimState].ubEndHeight == ANIM_STAND;
72 	switch (anim_state)
73 	{
74 		case OPEN_DOOR:
75 			if (s.ubBodyType == CRIPPLECIV)
76 			{
77 				return CRIPPLE_OPEN_DOOR;
78 			}
79 			else if (door)
80 			{
81 				return standing ? anim_state : OPEN_DOOR_CROUCHED;
82 			}
83 			else
84 			{
85 				return standing ? BEGIN_OPENSTRUCT : BEGIN_OPENSTRUCT_CROUCHED;
86 			}
87 
88 		case CLOSE_DOOR:
89 			if (s.ubBodyType == CRIPPLECIV)
90 			{
91 				return CRIPPLE_CLOSE_DOOR;
92 			}
93 			else if (door)
94 			{
95 				return standing ? anim_state : CLOSE_DOOR_CROUCHED;
96 			}
97 			else
98 			{
99 				return standing ? OPEN_STRUCT : OPEN_STRUCT_CROUCHED;
100 			}
101 
102 		case END_OPEN_DOOR:
103 			if (s.ubBodyType == CRIPPLECIV)
104 			{
105 				return CRIPPLE_END_OPEN_DOOR;
106 			}
107 			else if (door)
108 			{
109 				return standing ? anim_state : END_OPEN_DOOR_CROUCHED;
110 			}
111 			else
112 			{
113 				return standing ? END_OPENSTRUCT : END_OPENSTRUCT_CROUCHED;
114 			}
115 
116 		case END_OPEN_LOCKED_DOOR:
117 			if (s.ubBodyType == CRIPPLECIV)
118 			{
119 				return CRIPPLE_END_OPEN_LOCKED_DOOR;
120 			}
121 			else if (door)
122 			{
123 				return standing ? END_OPEN_LOCKED_DOOR : END_OPEN_LOCKED_DOOR_CROUCHED;
124 			}
125 			else
126 			{
127 				return standing ? END_OPENSTRUCT_LOCKED : END_OPENSTRUCT_LOCKED_CROUCHED;
128 			}
129 
130 		case PICK_LOCK:
131 			return standing ? PICK_LOCK : LOCKPICK_CROUCHED;
132 
133 		default:
134 			// should never happen!
135 			Assert(FALSE);
136 			return anim_state;
137 	}
138 }
139 
140 
InteractWithClosedDoor(SOLDIERTYPE * const pSoldier,HandleDoor const ubHandleCode)141 void InteractWithClosedDoor(SOLDIERTYPE* const pSoldier, HandleDoor const ubHandleCode)
142 {
143 	pSoldier->ubDoorHandleCode = ubHandleCode;
144 
145 	UINT16 state;
146 	switch( ubHandleCode )
147 	{
148 		case HANDLE_DOOR_OPEN:
149 		case HANDLE_DOOR_UNLOCK:
150 		case HANDLE_DOOR_EXAMINE:
151 		case HANDLE_DOOR_EXPLODE:
152 		case HANDLE_DOOR_LOCK:
153 		case HANDLE_DOOR_UNTRAP:
154 		case HANDLE_DOOR_CROWBAR:
155 			state = GetAnimStateForInteraction(*pSoldier, TRUE, OPEN_DOOR);
156 			break;
157 
158 		case HANDLE_DOOR_FORCE:
159 			state = KICK_DOOR;
160 			break;
161 
162 		case HANDLE_DOOR_LOCKPICK:
163 			state = GetAnimStateForInteraction(*pSoldier, TRUE, PICK_LOCK);
164 			break;
165 
166 		default: return;
167 	}
168 	ChangeSoldierState(pSoldier, state, 0 , FALSE);
169 }
170 
171 
DoTrapCheckOnStartingMenu(SOLDIERTYPE & s,DOOR & d)172 static bool DoTrapCheckOnStartingMenu(SOLDIERTYPE& s, DOOR& d)
173 {
174 	if (!d.fLocked)
175 		return false;
176 	if (d.ubTrapID == NO_TRAP)
177 		return false;
178 	if (d.bPerceivedTrapped != DOOR_PERCEIVED_UNKNOWN)
179 		return false;
180 
181 	// check for noticing the trap
182 	INT8 const detect_level = CalcTrapDetectLevel(&s, FALSE);
183 	if (detect_level < d.ubTrapLevel) return false;
184 
185 	// say quote, update status
186 	TacticalCharacterDialogue(&s, QUOTE_BOOBYTRAP_ITEM);
187 	UpdateDoorPerceivedValue(&d);
188 	return true;
189 }
190 
191 
InteractWithOpenableStruct(SOLDIERTYPE & s,STRUCTURE & structure,UINT8 const direction)192 void InteractWithOpenableStruct(SOLDIERTYPE& s, STRUCTURE& structure, UINT8 const direction)
193 {
194 	STRUCTURE& base    = *FindBaseStructure(&structure);
195 	bool const is_door = structure.fFlags & STRUCTURE_ANYDOOR;
196 
197 	if (is_door)
198 	{
199 		// get door status, if busy then just return!
200 		DOOR_STATUS const* const ds = GetDoorStatus(base.sGridNo);
201 		if (ds && ds->ubFlags & DOOR_BUSY)
202 		{
203 			// Send this guy into stationary stance
204 			EVENT_StopMerc(&s);
205 			return;
206 		}
207 	}
208 
209 	if (!s.bCollapsed)
210 	{
211 		EVENT_SetSoldierDesiredDirectionForward(&s, direction);
212 	}
213 
214 	// Is the door opened?
215 	if (structure.fFlags & STRUCTURE_OPEN)
216 	{
217 		if (IsOnOurTeam(s) && !(structure.fFlags & STRUCTURE_SWITCH))
218 		{
219 			// Bring up menu to decide what to do
220 			if (!s.bCollapsed)
221 			{
222 				SoldierGotoStationaryStance(&s);
223 			}
224 			DOOR* const d = FindDoorInfoAtGridNo(base.sGridNo);
225 			if (!d || !DoTrapCheckOnStartingMenu(s, *d))
226 				InitDoorOpenMenu(&s, TRUE);
227 		}
228 		else
229 		{ // Easily close door
230 			ChangeSoldierState(&s, GetAnimStateForInteraction(s, is_door, CLOSE_DOOR), 0, FALSE);
231 		}
232 	}
233 	else
234 	{
235 		if (IsOnOurTeam(s))
236 		{
237 			DOOR* const d = FindDoorInfoAtGridNo(base.sGridNo);
238 			if (d && d->fLocked) // Bring up the menu, only if it has a lock
239 			{
240 				// Bring up menu to decide what to do
241 				if (!s.bCollapsed)
242 				{
243 					SoldierGotoStationaryStance(&s);
244 				}
245 				if (!DoTrapCheckOnStartingMenu(s, *d))
246 				{
247 					InitDoorOpenMenu(&s, FALSE);
248 				}
249 				else
250 				{
251 					UnSetUIBusy(&s);
252 				}
253 				return;
254 			}
255 		}
256 
257 		s.ubDoorHandleCode = HANDLE_DOOR_OPEN;
258 		ChangeSoldierState(&s, GetAnimStateForInteraction(s, is_door, OPEN_DOOR), 0, FALSE);
259 	}
260 }
261 
262 
ProcessImplicationsOfPCMessingWithDoor(SOLDIERTYPE * pSoldier)263 static void ProcessImplicationsOfPCMessingWithDoor(SOLDIERTYPE* pSoldier)
264 {
265 	// if player is hacking at a door in the brothel and a kingpin guy can see him
266 	UINT8 const room = GetRoom(pSoldier->sGridNo);
267 	if (IN_BROTHEL(room) ||
268 		(gWorldSectorX == 5 &&
269 		gWorldSectorY == MAP_ROW_D &&
270 		gbWorldSectorZ == 0 &&
271 		(pSoldier->sGridNo == 11010 ||
272 		pSoldier->sGridNo == 11177 ||
273 		pSoldier->sGridNo == 11176)))
274 	{
275 		// see if a kingpin goon can see us
276 		FOR_EACH_IN_TEAM(pGoon, CIV_TEAM)
277 		{
278 			if (pGoon->ubCivilianGroup == KINGPIN_CIV_GROUP &&
279 				pGoon->bInSector &&
280 				pGoon->bLife >= OKLIFE &&
281 				pGoon->bOppList[pSoldier->ubID] == SEEN_CURRENTLY)
282 			{
283 				MakeCivHostile( pGoon, 2 );
284 				if ( ! (gTacticalStatus.uiFlags & INCOMBAT) )
285 				{
286 					EnterCombatMode( pGoon->bTeam );
287 				}
288 			}
289 		}
290 	}
291 
292 	if ( gWorldSectorX == TIXA_SECTOR_X && gWorldSectorY == TIXA_SECTOR_Y )
293 	{
294 		SOLDIERTYPE* const pGoon = FindSoldierByProfileID(WARDEN);
295 		if ( pGoon && pGoon->bAlertStatus < STATUS_RED && PythSpacesAway( pSoldier->sGridNo, pGoon->sGridNo ) <= 5 )
296 		{
297 			// alert her if she hasn't been alerted
298 			pGoon->bAlertStatus = STATUS_RED;
299 			CheckForChangingOrders( pGoon );
300 			CancelAIAction(pGoon);
301 		}
302 	}
303 }
304 
305 
306 
HandleOpenableStruct(SOLDIERTYPE * pSoldier,INT16 sGridNo,STRUCTURE * pStructure)307 BOOLEAN HandleOpenableStruct( SOLDIERTYPE *pSoldier, INT16 sGridNo, STRUCTURE *pStructure )
308 {
309 	BOOLEAN fHandleDoor = FALSE;
310 	INT16   sAPCost = 0, sBPCost = 0;
311 	DOOR    *pDoor;
312 	BOOLEAN fDoAction = TRUE;
313 	BOOLEAN fDoor     = FALSE;
314 
315 	// Are we a door?
316 	if (pStructure->fFlags & STRUCTURE_ANYDOOR)
317 	{
318 		fDoor = TRUE;
319 	}
320 
321 	// Calculate basic points...
322 
323 	// We'll add any aps for things like lockpicking, booting, etc
324 
325 	// If we are already open....no need for lockpick checks, etc
326 	if ( pStructure->fFlags & STRUCTURE_OPEN )
327 	{
328 		// Set costs for these
329 		sAPCost = AP_OPEN_DOOR;
330 		sBPCost = BP_OPEN_DOOR;
331 
332 		fHandleDoor = TRUE;
333 	}
334 	else
335 	{
336 		if (IsOnOurTeam(*pSoldier))
337 		{
338 			// Find locked door here....
339 			pDoor = FindDoorInfoAtGridNo( sGridNo );
340 
341 			// Alrighty, first check for traps ( unless we are examining.... )
342 			if (pSoldier->ubDoorHandleCode != HANDLE_DOOR_EXAMINE &&
343 				pSoldier->ubDoorHandleCode != HANDLE_DOOR_UNTRAP &&
344 				pSoldier->ubDoorHandleCode != HANDLE_DOOR_UNLOCK)
345 			{
346 				if ( pDoor != NULL )
347 				{
348 					// Do we have a trap? NB if door is unlocked disable all traps
349 					if (pDoor->fLocked && pDoor->ubTrapID != NO_TRAP)
350 					{
351 						// Set costs for these
352 						// Set AP costs to that of opening a door
353 						sAPCost = AP_OPEN_DOOR;
354 						sBPCost = BP_OPEN_DOOR;
355 
356 						ChangeSoldierState(pSoldier, GetAnimStateForInteraction(*pSoldier, fDoor, END_OPEN_DOOR), 0, FALSE);
357 
358 						// Did we inadvertently set it off?
359 						if ( HasDoorTrapGoneOff( pSoldier, pDoor ) )
360 						{
361 							// Kaboom
362 							// Code to handle trap here...
363 							HandleDoorTrap(*pSoldier, *pDoor);
364 							if (DoorTrapTable[pDoor->ubTrapID].fFlags & DOOR_TRAP_STOPS_ACTION)
365 							{
366 								// trap stops person from opening door!
367 								fDoAction = FALSE;
368 							}
369 							if (!( DoorTrapTable[pDoor->ubTrapID].fFlags & DOOR_TRAP_RECURRING ) )
370 							{
371 								// trap only happens once
372 								pDoor->ubTrapLevel = 0;
373 								pDoor->ubTrapID = NO_TRAP;
374 							}
375 							UpdateDoorPerceivedValue( pDoor );
376 						}
377 						else
378 						{
379 							// If we didn't set it off then we must have noticed it or know about it already
380 
381 							// do we know it's trapped?
382 							if ( pDoor->bPerceivedTrapped == DOOR_PERCEIVED_UNKNOWN )
383 							{
384 								ST::string trap_name = GetTrapName(*pDoor);
385 								ScreenMsg(MSG_FONT_YELLOW, MSG_INTERFACE, st_format_printf(TacticalStr[DOOR_LOCK_DESCRIPTION_STR], trap_name));
386 
387 								// Stop action this time....
388 								fDoAction = FALSE;
389 
390 								// report!
391 								TacticalCharacterDialogue( pSoldier, QUOTE_BOOBYTRAP_ITEM );
392 							}
393 							else
394 							{
395 								// Set it off!
396 								HandleDoorTrap(*pSoldier, *pDoor);
397 								if (DoorTrapTable[pDoor->ubTrapID].fFlags & DOOR_TRAP_STOPS_ACTION)
398 								{
399 									// trap stops person from opening door!
400 									fDoAction = FALSE;
401 								}
402 								if (!( DoorTrapTable[pDoor->ubTrapID].fFlags & DOOR_TRAP_RECURRING ) )
403 								{
404 									// trap only happens once
405 									pDoor->ubTrapLevel = 0;
406 									pDoor->ubTrapID = NO_TRAP;
407 								}
408 							}
409 							UpdateDoorPerceivedValue( pDoor );
410 
411 						}
412 					}
413 				}
414 			}
415 
416 			if ( fDoAction )
417 			{
418 				// OK, switch based on how we are going to open door....
419 				switch (pSoldier->ubDoorHandleCode)
420 				{
421 					case HANDLE_DOOR_OPEN:
422 
423 						// If we have no lock on door...
424 						if ( pDoor == NULL )
425 						{
426 							// Set costs for these
427 							sAPCost = AP_OPEN_DOOR;
428 							sBPCost = BP_OPEN_DOOR;
429 
430 							// Open if it's not locked....
431 							ChangeSoldierState(pSoldier, GetAnimStateForInteraction(*pSoldier, fDoor, END_OPEN_DOOR), 0, FALSE);
432 							fHandleDoor = TRUE;
433 						}
434 						else
435 						{
436 							if ( pDoor->fLocked )
437 							{
438 								// it's locked....
439 								ChangeSoldierState(pSoldier, GetAnimStateForInteraction(*pSoldier, fDoor, END_OPEN_LOCKED_DOOR), 0, FALSE);
440 
441 								// Do we have a quote for locked stuff?
442 								// Now just show on message bar
443 								if ( !AM_AN_EPC( pSoldier ) )
444 								{
445 									DoMercBattleSound( pSoldier, BATTLE_SOUND_LOCKED );
446 								}
447 								else
448 								{
449 									ScreenMsg( MSG_FONT_YELLOW, MSG_INTERFACE, TacticalStr[ DOOR_LOCK_HAS_BEEN_LOCKED_STR ] );
450 								}
451 							}
452 							else
453 							{
454 								ChangeSoldierState(pSoldier, GetAnimStateForInteraction(*pSoldier, fDoor, END_OPEN_DOOR), 0, FALSE);
455 								fHandleDoor = TRUE;
456 							}
457 							UpdateDoorPerceivedValue( pDoor );
458 						}
459 						break;
460 
461 					case HANDLE_DOOR_FORCE:
462 
463 						// Set costs for these
464 						sAPCost = AP_BOOT_DOOR;
465 						sBPCost = BP_BOOT_DOOR;
466 
467 						// OK, using force, if we have no lock, just open the door!
468 						if ( pDoor == NULL )
469 						{
470 							ChangeSoldierState(pSoldier, GetAnimStateForInteraction(*pSoldier, fDoor, END_OPEN_DOOR), 0, FALSE);
471 							fHandleDoor = TRUE;
472 
473 							ScreenMsg( MSG_FONT_YELLOW, MSG_INTERFACE, TacticalStr[ DOOR_THERE_IS_NO_LOCK_STR ] );
474 						}
475 						else
476 						{
477 							// Attempt to force door
478 							if ( AttemptToSmashDoor( pSoldier, pDoor ) )
479 							{
480 								// DoMercBattleSound( pSoldier, BATTLE_SOUND_COOL1 );
481 								fHandleDoor = TRUE;
482 							}
483 							else
484 							{
485 								UpdateDoorPerceivedValue( pDoor );
486 							}
487 							ProcessImplicationsOfPCMessingWithDoor( pSoldier );
488 						}
489 						break;
490 
491 
492 					case HANDLE_DOOR_CROWBAR:
493 
494 						// Set costs for these
495 						sAPCost = AP_USE_CROWBAR;
496 						sBPCost = BP_USE_CROWBAR;
497 
498 						// OK, using force, if we have no lock, just open the door!
499 						if ( pDoor == NULL )
500 						{
501 							ChangeSoldierState(pSoldier, GetAnimStateForInteraction(*pSoldier, fDoor, END_OPEN_DOOR), 0, FALSE);
502 							fHandleDoor = TRUE;
503 
504 							ScreenMsg( MSG_FONT_YELLOW, MSG_INTERFACE, TacticalStr[ DOOR_THERE_IS_NO_LOCK_STR ] );
505 						}
506 						else
507 						{
508 							// Attempt to force door
509 							if ( AttemptToCrowbarLock( pSoldier, pDoor ) )
510 							{
511 								//DoMercBattleSound( pSoldier, BATTLE_SOUND_COOL1 );
512 								fHandleDoor = TRUE;
513 							}
514 							else
515 							{
516 								UpdateDoorPerceivedValue( pDoor );
517 							}
518 
519 							ProcessImplicationsOfPCMessingWithDoor( pSoldier );
520 						}
521 						break;
522 
523 					case HANDLE_DOOR_EXPLODE:
524 
525 						// Set costs for these
526 						sAPCost = AP_EXPLODE_DOOR;
527 						sBPCost = BP_EXPLODE_DOOR;
528 
529 						if ( pDoor == NULL )
530 						{
531 							ScreenMsg( MSG_FONT_YELLOW, MSG_INTERFACE, TacticalStr[ DOOR_THERE_IS_NO_LOCK_STR ] );
532 						}
533 						else
534 						{
535 							// Attempt to force door
536 							if ( AttemptToBlowUpLock( pSoldier, pDoor ) )
537 							{
538 								//DoMercBattleSound( pSoldier, BATTLE_SOUND_COOL1 );
539 								fHandleDoor = TRUE;
540 							}
541 							else
542 							{
543 								UpdateDoorPerceivedValue( pDoor );
544 							}
545 							ProcessImplicationsOfPCMessingWithDoor( pSoldier );
546 						}
547 						break;
548 
549 					case HANDLE_DOOR_LOCKPICK:
550 
551 						// Set costs for these
552 						sAPCost = AP_PICKLOCK;
553 						sBPCost = BP_PICKLOCK;
554 
555 						// Attempt to pick lock
556 						if ( pDoor == NULL )
557 						{
558 							ScreenMsg( MSG_FONT_YELLOW, MSG_INTERFACE, TacticalStr[ DOOR_THERE_IS_NO_LOCK_STR ] );
559 						}
560 						else
561 						{
562 							if ( AttemptToPickLock( pSoldier, pDoor ) )
563 							{
564 								DoMercBattleSound( pSoldier, BATTLE_SOUND_COOL1 );
565 								fHandleDoor = TRUE;
566 							}
567 							ProcessImplicationsOfPCMessingWithDoor( pSoldier );
568 						}
569 						break;
570 
571 
572 					case HANDLE_DOOR_EXAMINE:
573 
574 						// Set costs for these
575 						sAPCost = AP_EXAMINE_DOOR;
576 						sBPCost = BP_EXAMINE_DOOR;
577 
578 						// Attempt to examine door
579 						// Whatever the result, end the open animation
580 						ChangeSoldierState(pSoldier, GetAnimStateForInteraction(*pSoldier, fDoor, END_OPEN_DOOR), 0, FALSE);
581 
582 						if ( pDoor == NULL )
583 						{
584 							ScreenMsg( MSG_FONT_YELLOW, MSG_INTERFACE, TacticalStr[ DOOR_THERE_IS_NO_LOCK_STR ] );
585 						}
586 						else
587 						{
588 							if ( ExamineDoorForTraps( pSoldier, pDoor ) )
589 							{
590 								// We have a trap. Use door pointer to determine what type, etc
591 								TacticalCharacterDialogue( pSoldier, QUOTE_BOOBYTRAP_ITEM );
592 								ST::string trap_name = GetTrapName(*pDoor);
593 								ScreenMsg(MSG_FONT_YELLOW, MSG_INTERFACE, st_format_printf(TacticalStr[DOOR_LOCK_DESCRIPTION_STR], trap_name));
594 
595 								UpdateDoorPerceivedValue( pDoor );
596 							}
597 							else
598 							{
599 								ScreenMsg( MSG_FONT_YELLOW, MSG_INTERFACE, TacticalStr[ DOOR_LOCK_UNTRAPPED_STR ] );
600 							}
601 						}
602 						break;
603 
604 
605 					case HANDLE_DOOR_UNLOCK:
606 
607 						// Set costs for these
608 						sAPCost = AP_UNLOCK_DOOR;
609 						sBPCost = BP_UNLOCK_DOOR;
610 
611 						// OK, if we have no lock, show that!
612 						if ( pDoor == NULL )
613 						{
614 							// Open if it's not locked....
615 							//ScreenMsg( MSG_FONT_YELLOW, MSG_INTERFACE, TacticalStr[ DOOR_THERE_IS_NO_LOCK_STR ] );
616 							ChangeSoldierState(pSoldier, GetAnimStateForInteraction(*pSoldier, fDoor, END_OPEN_DOOR), 0, FALSE);
617 							break;
618 						}
619 						else
620 						{
621 
622 							// it's locked....
623 							// Attempt to unlock....
624 							if ( AttemptToUnlockDoor( pSoldier, pDoor ) )
625 							{
626 								//DoMercBattleSound( pSoldier, BATTLE_SOUND_COOL1 );
627 
628 								ChangeSoldierState(pSoldier, GetAnimStateForInteraction(*pSoldier, fDoor, END_OPEN_DOOR), 0, FALSE);
629 								UpdateDoorPerceivedValue( pDoor );
630 
631 								fHandleDoor = TRUE;
632 							}
633 							else
634 							{
635 								ChangeSoldierState(pSoldier, GetAnimStateForInteraction(*pSoldier, fDoor, END_OPEN_LOCKED_DOOR), 0, FALSE);
636 								// Do we have a quote for locked stuff?
637 								// Now just show on message bar
638 								//ScreenMsg( MSG_FONT_YELLOW, MSG_INTERFACE, TacticalStr[ DOOR_NOT_PROPER_KEY_STR ], pSoldier->name );
639 
640 								// OK PLay damn battle sound
641 								if ( Random( 2 ) )
642 								{
643 									DoMercBattleSound(pSoldier, BATTLE_SOUND_CURSE1);
644 								}
645 							}
646 						}
647 						break;
648 
649 
650 					case HANDLE_DOOR_UNTRAP:
651 
652 						// Set costs for these
653 						sAPCost = AP_UNTRAP_DOOR;
654 						sBPCost = BP_UNTRAP_DOOR;
655 
656 						// OK, if we have no lock, show that!
657 						if ( pDoor == NULL )
658 						{
659 							// Open if it's not locked....
660 							ScreenMsg( MSG_FONT_YELLOW, MSG_INTERFACE, TacticalStr[ DOOR_THERE_IS_NO_LOCK_STR ] );
661 							ChangeSoldierState(pSoldier, GetAnimStateForInteraction(*pSoldier, fDoor, END_OPEN_DOOR), 0, FALSE);
662 							break;
663 						}
664 						else
665 						{
666 							// Do we have a trap?
667 							if (pDoor->ubTrapID != NO_TRAP)
668 							{
669 								if ( AttemptToUntrapDoor( pSoldier, pDoor ) )
670 								{
671 									DoMercBattleSound(pSoldier, BATTLE_SOUND_COOL1);
672 									ChangeSoldierState(pSoldier, GetAnimStateForInteraction(*pSoldier, fDoor, END_OPEN_DOOR), 0, FALSE);
673 									UpdateDoorPerceivedValue( pDoor );
674 									//fHandleDoor = TRUE;
675 								}
676 								else
677 								{
678 									ChangeSoldierState(pSoldier, GetAnimStateForInteraction(*pSoldier, fDoor, END_OPEN_LOCKED_DOOR), 0, FALSE);
679 									// Now just show on message bar
680 									HandleDoorTrap(*pSoldier, *pDoor);
681 
682 									if (!( DoorTrapTable[pDoor->ubTrapID].fFlags & DOOR_TRAP_RECURRING ) )
683 									{
684 										// trap only happens once
685 										pDoor->ubTrapLevel = 0;
686 										pDoor->ubTrapID = NO_TRAP;
687 									}
688 
689 									// Update perceived lock value
690 									UpdateDoorPerceivedValue( pDoor );
691 								}
692 							}
693 							else
694 							{
695 								ScreenMsg( MSG_FONT_YELLOW, MSG_INTERFACE, TacticalStr[ DOOR_LOCK_IS_NOT_TRAPPED_STR ] );
696 							}
697 						}
698 						break;
699 
700 
701 					case HANDLE_DOOR_LOCK:
702 
703 						// Set costs for these
704 						sAPCost = AP_LOCK_DOOR;
705 						sBPCost = BP_LOCK_DOOR;
706 
707 						// OK, if we have no lock, show that!
708 						if ( pDoor == NULL )
709 						{
710 							// Open if it's not locked....
711 							ScreenMsg( MSG_FONT_YELLOW, MSG_INTERFACE, TacticalStr[ DOOR_THERE_IS_NO_LOCK_STR ] );
712 							ChangeSoldierState(pSoldier, GetAnimStateForInteraction(*pSoldier, fDoor, END_OPEN_DOOR), 0, FALSE);
713 							break;
714 						}
715 						else
716 						{
717 
718 							// it's locked....
719 							// Attempt to unlock....
720 							if ( AttemptToLockDoor( pSoldier, pDoor ) )
721 							{
722 								ScreenMsg( MSG_FONT_YELLOW, MSG_INTERFACE, TacticalStr[ DOOR_LOCK_HAS_BEEN_LOCKED_STR ] );
723 								ChangeSoldierState(pSoldier, GetAnimStateForInteraction(*pSoldier, fDoor, END_OPEN_DOOR), 0, FALSE);
724 								UpdateDoorPerceivedValue( pDoor );
725 							}
726 							else
727 							{
728 								ChangeSoldierState(pSoldier, GetAnimStateForInteraction(*pSoldier, fDoor, END_OPEN_LOCKED_DOOR), 0, FALSE);
729 								// Do we have a quote for locked stuff?
730 								// Now just show on message bar
731 								ScreenMsg( MSG_FONT_YELLOW, MSG_INTERFACE, st_format_printf(TacticalStr[ DOOR_NOT_PROPER_KEY_STR ], pSoldier->name) );
732 
733 								// Update perceived lock value
734 								UpdateDoorPerceivedValue( pDoor );
735 							}
736 						}
737 						break;
738 				}
739 			}
740 		}
741 		else
742 		{
743 			// Set costs for these
744 			sAPCost = AP_OPEN_DOOR;
745 			sBPCost = BP_OPEN_DOOR;
746 
747 			// Open if it's not locked....
748 			ChangeSoldierState(pSoldier, GetAnimStateForInteraction(*pSoldier, fDoor, END_OPEN_DOOR), 0, FALSE);
749 			fHandleDoor = TRUE;
750 		}
751 	}
752 
753 	if ( fHandleDoor )
754 	{
755 		if ( fDoor )
756 		{
757 			HandleDoorChangeFromGridNo( pSoldier, sGridNo, FALSE );
758 		}
759 		else
760 		{
761 			HandleStructChangeFromGridNo( pSoldier, sGridNo );
762 		}
763 	}
764 
765 	// Deduct points!
766 	//if ( fDoor )
767 	{
768 		DeductPoints( pSoldier, sAPCost, sBPCost );
769 	}
770 
771 	return( fHandleDoor );
772 }
773 
774 
HandleDoorsOpenClose(SOLDIERTYPE * pSoldier,INT16 sGridNo,STRUCTURE * pStructure,BOOLEAN fNoAnimations)775 static BOOLEAN HandleDoorsOpenClose(SOLDIERTYPE* pSoldier, INT16 sGridNo, STRUCTURE* pStructure, BOOLEAN fNoAnimations)
776 try
777 {
778 	INT32 cnt;
779 	BOOLEAN fOpenedGraphic = FALSE;
780 	BOOLEAN fDoAnimation = TRUE;
781 	STRUCTURE *pBaseStructure;
782 
783 	pBaseStructure = FindBaseStructure( pStructure );
784 	if (!pBaseStructure)
785 	{
786 		return( FALSE );
787 	}
788 
789 	LEVELNODE* const pNode = FindLevelNodeBasedOnStructure(pBaseStructure);
790 
791 	// ATE: if we are about to swap, but have an animation playing here..... stop the animation....
792 	if ( ( pNode->uiFlags & LEVELNODE_ANIMATION ) )
793 	{
794 		if ( pNode->pAniTile != NULL )
795 		{
796 			if ( pNode->pAniTile->uiFlags & ANITILE_DOOR )
797 			{
798 				// ATE: No two doors can exist ( there can be only one )
799 				// Update value.. ie: prematurely end door animation
800 				// Update current frame...
801 
802 				if ( pNode->pAniTile->uiFlags & ANITILE_FORWARD )
803 				{
804 					pNode->sCurrentFrame = pNode->pAniTile->sStartFrame + pNode->pAniTile->usNumFrames;
805 				}
806 
807 				if ( pNode->pAniTile->uiFlags & ANITILE_BACKWARD )
808 				{
809 					pNode->sCurrentFrame = pNode->pAniTile->sStartFrame - pNode->pAniTile->usNumFrames;
810 				}
811 
812 				pNode->sCurrentFrame = pNode->pAniTile->usNumFrames - 1;
813 
814 				// Delete...
815 				DeleteAniTile( pNode->pAniTile );
816 
817 				pNode->uiFlags &= ~( LEVELNODE_LASTDYNAMIC | LEVELNODE_UPDATESAVEBUFFERONCE );
818 
819 				if ( GridNoOnScreen( pBaseStructure->sGridNo ) )
820 				{
821 					SetRenderFlags(RENDER_FLAG_FULL);
822 				}
823 			}
824 		}
825 	}
826 
827 
828 	// Check the graphic which is down!
829 	// Check for Open Door!
830 	cnt = 0;
831 	while( gOpenDoorList[ cnt ] != -1 )
832 	{
833 		// IF WE ARE A SHADOW TYPE
834 		if ( pNode->usIndex == gOpenDoorList[ cnt ] )
835 		{
836 			fOpenedGraphic = TRUE;
837 			break;
838 		}
839 		cnt++;
840 	}
841 
842 	if ( !(pStructure->fFlags & STRUCTURE_OPEN) )
843 	{
844 		//ATE, the last parameter is the perceived value, I dont know what it is so could you please add the value?
845 		//ModifyDoorStatus( INT16 sGridNo, BOOLEAN fOpen, BOOLEAN fPercievedOpen )
846 		ModifyDoorStatus(sGridNo, TRUE, DONTSETDOORSTATUS);
847 
848 		if ( gWorldSectorX == 13 && gWorldSectorY == MAP_ROW_I )
849 		{
850 			DoPOWPathChecks();
851 		}
852 
853 		if (pSoldier )
854 		{
855 			// OK, Are we a player merc or AI?
856 			if ( pSoldier->bTeam != OUR_TEAM )
857 			{
858 				// If an AI guy... do LOS check first....
859 				// If guy is visible... OR fading...
860 				if (pSoldier->bVisible == -1 && !AllMercsLookForDoor(sGridNo) && !(gTacticalStatus.uiFlags & SHOW_ALL_MERCS))
861 				{
862 					fDoAnimation = FALSE;
863 				}
864 			}
865 		}
866 		else
867 		{
868 			// door opening by action item... just do a LOS check
869 			if (!AllMercsLookForDoor(sGridNo))
870 			{
871 				fDoAnimation = FALSE;
872 			}
873 		}
874 
875 		if ( fNoAnimations )
876 		{
877 			fDoAnimation = FALSE;
878 		}
879 
880 		if ( fDoAnimation  )
881 		{
882 			// Update perceived value
883 			ModifyDoorStatus( sGridNo, DONTSETDOORSTATUS, TRUE );
884 
885 			ANITILE_PARAMS AniParams;
886 			AniParams = ANITILE_PARAMS{};
887 			AniParams.uiFlags         = ANITILE_DOOR | ANITILE_EXISTINGTILE | (fOpenedGraphic ? ANITILE_FORWARD : ANITILE_BACKWARD);
888 			AniParams.ubLevelID       = ANI_STRUCT_LEVEL;
889 			AniParams.sStartFrame     = pNode->sCurrentFrame;
890 			AniParams.sDelay          = INTTILE_DOOR_OPENSPEED;
891 			AniParams.usTileIndex     = pNode->usIndex;
892 			AniParams.sGridNo         = sGridNo;
893 			AniParams.pGivenLevelNode = pNode;
894 			CreateAnimationTile(&AniParams);
895 		}
896 
897 		if ( fDoAnimation && pSoldier && pSoldier->ubDoorOpeningNoise)
898 		{
899 			// ATE; Default to normal door...
900 			SoundID uiSoundID = SoundRange<DROPEN_1, DROPEN_3>();
901 
902 			// OK, check if this door is sliding and is multi-tiled...
903 			if ( pStructure->fFlags & STRUCTURE_SLIDINGDOOR )
904 			{
905 				// Get database value...
906 				if ( pStructure->pDBStructureRef->pDBStructure->ubNumberOfTiles > 1 )
907 				{
908 					// change sound ID
909 					uiSoundID = GARAGE_DOOR_OPEN;
910 				}
911 				else if ( pStructure->pDBStructureRef->pDBStructure->ubArmour == MATERIAL_CLOTH )
912 				{
913 					// change sound ID
914 					uiSoundID = CURTAINS_OPEN;
915 				}
916 			}
917 			else if (pStructure->pDBStructureRef->pDBStructure->ubArmour == MATERIAL_LIGHT_METAL ||
918 					pStructure->pDBStructureRef->pDBStructure->ubArmour == MATERIAL_THICKER_METAL ||
919 					pStructure->pDBStructureRef->pDBStructure->ubArmour == MATERIAL_HEAVY_METAL)
920 			{
921 				// change sound ID
922 				uiSoundID = METAL_DOOR_OPEN;
923 			}
924 
925 			// OK, We must know what sound to play, for now use same sound for all doors...
926 			PlayLocationJA2Sample(sGridNo, uiSoundID, MIDVOLUME, 1);
927 		}
928 
929 	}
930 	else
931 	{
932 		//ATE, the last parameter is the perceived value, I dont know what it is so could you please add the value?
933 		//ModifyDoorStatus( INT16 sGridNo, BOOLEAN fOpen, BOOLEAN fInitiallyPercieveOpen )
934 		ModifyDoorStatus(sGridNo, FALSE, DONTSETDOORSTATUS);
935 
936 		if (pSoldier )
937 		{
938 			// OK, Are we a player merc or AI?
939 			if ( pSoldier->bTeam != OUR_TEAM )
940 			{
941 				// If an AI guy... do LOS check first....
942 				// If guy is visible... OR fading...
943 				if (pSoldier->bVisible == -1 && !AllMercsLookForDoor(sGridNo) && !(gTacticalStatus.uiFlags & SHOW_ALL_MERCS))
944 				{
945 					fDoAnimation = FALSE;
946 				}
947 			}
948 		}
949 		else
950 		{
951 			// door opening by action item... just do a LOS check
952 			if (!AllMercsLookForDoor(sGridNo))
953 			{
954 				fDoAnimation = FALSE;
955 			}
956 		}
957 
958 		if ( fNoAnimations )
959 		{
960 			fDoAnimation = FALSE;
961 		}
962 
963 		if ( fDoAnimation )
964 		{
965 			// Update perceived value
966 			ModifyDoorStatus( sGridNo, DONTSETDOORSTATUS, FALSE );
967 
968 			// ATE; Default to normal door...
969 			SoundID uiSoundID = SoundRange<DRCLOSE_1, DRCLOSE_2>();
970 
971 			// OK, check if this door is sliding and is multi-tiled...
972 			if ( pStructure->fFlags & STRUCTURE_SLIDINGDOOR )
973 			{
974 				// Get database value...
975 				if ( pStructure->pDBStructureRef->pDBStructure->ubNumberOfTiles > 1 )
976 				{
977 					// change sound ID
978 					uiSoundID = GARAGE_DOOR_CLOSE;
979 				}
980 				else if ( pStructure->pDBStructureRef->pDBStructure->ubArmour == MATERIAL_CLOTH )
981 				{
982 					// change sound ID
983 					uiSoundID = CURTAINS_CLOSE;
984 				}
985 			}
986 			else if (pStructure->pDBStructureRef->pDBStructure->ubArmour == MATERIAL_LIGHT_METAL ||
987 				pStructure->pDBStructureRef->pDBStructure->ubArmour == MATERIAL_THICKER_METAL ||
988 				pStructure->pDBStructureRef->pDBStructure->ubArmour == MATERIAL_HEAVY_METAL)
989 			{
990 				// change sound ID
991 				uiSoundID = METAL_DOOR_CLOSE;
992 			}
993 
994 			ANITILE_PARAMS AniParams;
995 			AniParams = ANITILE_PARAMS{};
996 			AniParams.uiFlags         = ANITILE_DOOR | ANITILE_EXISTINGTILE | (fOpenedGraphic ? ANITILE_BACKWARD : ANITILE_FORWARD);
997 			AniParams.ubLevelID       = ANI_STRUCT_LEVEL;
998 			AniParams.sStartFrame     = pNode->sCurrentFrame;
999 			AniParams.sDelay          = INTTILE_DOOR_OPENSPEED;
1000 			AniParams.usTileIndex     = pNode->usIndex;
1001 			AniParams.sGridNo         = sGridNo;
1002 			AniParams.pGivenLevelNode = pNode;
1003 			AniParams.ubKeyFrame1     = pNode->sCurrentFrame + (fOpenedGraphic ? -2 : 2);
1004 			AniParams.uiKeyFrame1Code = ANI_KEYFRAME_DO_SOUND;
1005 			AniParams.v.sound         = uiSoundID;
1006 			CreateAnimationTile( &AniParams );
1007 		}
1008 
1009 	}
1010 
1011 	if ( fDoAnimation )
1012 	{
1013 		gTacticalStatus.uiFlags |= NOHIDE_REDUNDENCY;
1014 		// FOR THE NEXT RENDER LOOP, RE-EVALUATE REDUNDENT TILES
1015 		InvalidateWorldRedundency( );
1016 
1017 		if ( GridNoOnScreen( sGridNo ) )
1018 		{
1019 			SetRenderFlags(RENDER_FLAG_FULL);
1020 		}
1021 	}
1022 
1023 	return( fDoAnimation );
1024 }
1025 catch (...) { return FALSE; }
1026 
1027 
SetDoorString(INT16 const sGridNo)1028 void SetDoorString(INT16 const sGridNo)
1029 {
1030 	if (GetIntTileLocationText().empty())
1031 	{
1032 		SetIntTileLocationText(TacticalStr[DOOR_DOOR_MOUSE_DESCRIPTION]);
1033 		DOOR const* const d = FindDoorInfoAtGridNo(sGridNo);
1034 		if (d != NULL)
1035 		{
1036 			ST::string state;
1037 			if (d->bPerceivedTrapped == DOOR_PERCEIVED_TRAPPED)
1038 			{
1039 				state = TacticalStr[DOOR_TRAPPED_MOUSE_DESCRIPTION];
1040 			}
1041 			else switch (d->bPerceivedLocked)
1042 			{
1043 				case DOOR_PERCEIVED_UNKNOWN:
1044 					break;
1045 				case DOOR_PERCEIVED_LOCKED:
1046 					state = TacticalStr[DOOR_LOCKED_MOUSE_DESCRIPTION];
1047 					break;
1048 				case DOOR_PERCEIVED_UNLOCKED:
1049 					state = TacticalStr[DOOR_UNLOCKED_MOUSE_DESCRIPTION];
1050 					break;
1051 				case DOOR_PERCEIVED_BROKEN:
1052 					state = TacticalStr[DOOR_BROKEN_MOUSE_DESCRIPTION];
1053 					break;
1054 			}
1055 			if (!state.empty()) SetIntTileLocation2Text(state);
1056 		}
1057 	}
1058 
1059 	// ATE: If here, we try to say, opened or closed...
1060 	if (GetIntTileLocation2Text().empty())
1061 	{
1062 	if(isGermanVersion())
1063 	{
1064 		SetIntTileLocation2Text(TacticalStr[DOOR_DOOR_MOUSE_DESCRIPTION]);
1065 	}
1066 
1067 		// Try to get doors status here...
1068 		bool                     open;
1069 		DOOR_STATUS const* const ds = GetDoorStatus(sGridNo);
1070 		if (ds == NULL || ds->ubFlags & DOOR_PERCEIVED_NOTSET)
1071 		{
1072 			// OK, get status based on graphic.....
1073 			STRUCTURE const* const structure = FindStructure(sGridNo, STRUCTURE_ANYDOOR);
1074 			if (!structure)
1075 				return;
1076 
1077 			open = (structure->fFlags & STRUCTURE_OPEN) != 0;
1078 		}
1079 		else
1080 		{
1081 			// Use percived value
1082 			open = (ds->ubFlags & DOOR_PERCEIVED_OPEN) != 0;
1083 		}
1084 		ST::string state = open ?
1085 			pMessageStrings[MSG_OPENED] : pMessageStrings[MSG_CLOSED];
1086 	if(isGermanVersion())
1087 	{
1088 		SetIntTileLocationText(state);
1089 	}
1090 	else
1091 	{
1092 		SetIntTileLocation2Text(state);
1093 	}
1094 	}
1095 }
1096