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