1 #include "Civ_Quotes.h"
2 #include "Directories.h"
3 #include "Font_Control.h"
4 #include "Local.h"
5 #include "MouseSystem.h"
6 #include "Soldier_Find.h"
7 #include "StrategicMap.h"
8 #include "Timer_Control.h"
9 #include "MessageBoxScreen.h"
10 #include "Queen_Command.h"
11 #include "Overhead.h"
12 #include "AI.h"
13 #include "Render_Dirty.h"
14 #include "MercTextBox.h"
15 #include "Text.h"
16 #include "ScreenIDs.h"
17 #include "Animation_Data.h"
18 #include "Video.h"
19 #include "Message.h"
20 #include "RenderWorld.h"
21 #include "Cursors.h"
22 #include "Dialogue_Control.h"
23 #include "Quests.h"
24 #include "MapScreen.h"
25 #include "Strategic_Town_Loyalty.h"
26 #include "NPC.h"
27 #include "Strategic_Mines.h"
28 #include "Random.h"
29 #include "FileMan.h"
30 #include "UILayout.h"
31 
32 #include "ContentManager.h"
33 #include "GameInstance.h"
34 
35 #include <string_theory/format>
36 #include <string_theory/string>
37 
38 
39 #define CIV_QUOTE_TEXT_SIZE		160
40 
41 
42 #define DIALOGUE_DEFAULT_WIDTH		200
43 #define EXTREAMLY_LOW_TOWN_LOYALTY	20
44 #define HIGH_TOWN_LOYALTY		80
45 #define CIV_QUOTE_HINT			99
46 
47 
48 static UINT8 const gubNumEntries[NUM_CIV_QUOTES] =
49 {
50 	15,
51 	15,
52 	15,
53 	15,
54 	15,
55 	15,
56 	15,
57 	15,
58 	15,
59 	15,
60 
61 	15,
62 	15,
63 	15,
64 	15,
65 	15,
66 	15,
67 	15,
68 	15,
69 	15,
70 	15,
71 
72 	5,
73 	5,
74 	15,
75 	15,
76 	15,
77 	15,
78 	15,
79 	15,
80 	15,
81 	15,
82 
83 	15,
84 	15,
85 	2,
86 	15,
87 	15,
88 	10,
89 	10,
90 	5,
91 	3,
92 	10,
93 
94 	3,
95 	3,
96 	3,
97 	3,
98 	3,
99 	3,
100 	3,
101 	3,
102 	3,
103 	3
104 };
105 
106 
107 struct QUOTE_SYSTEM_STRUCT
108 {
109 	BOOLEAN bActive;
110 	MOUSE_REGION MouseRegion;
111 	VIDEO_OVERLAY *video_overlay;
112 	MercPopUpBox *dialogue_box;
113 	UINT32 uiTimeOfCreation;
114 	UINT32 uiDelayTime;
115 	SOLDIERTYPE *pCiv;
116 };
117 
118 
119 static QUOTE_SYSTEM_STRUCT gCivQuoteData;
120 
121 static UINT16 gusCivQuoteBoxWidth;
122 static UINT16 gusCivQuoteBoxHeight;
123 
124 
GetCivQuoteText(UINT8 ubCivQuoteID,UINT8 ubEntryID,ST::string & zQuote)125 static BOOLEAN GetCivQuoteText(UINT8 ubCivQuoteID, UINT8 ubEntryID, ST::string& zQuote)
126 try
127 {
128 	char zFileName[164];
129 
130 	// Build filename....
131 	if ( ubCivQuoteID == CIV_QUOTE_HINT )
132 	{
133 		if ( gbWorldSectorZ > 0 )
134 		{
135 			sprintf(zFileName, NPCDATADIR "/civ%02d.edt", CIV_QUOTE_MINERS_NOT_FOR_PLAYER);
136 		}
137 		else
138 		{
139 			sprintf(zFileName, NPCDATADIR "/%c%d.edt", 'a' + (gWorldSectorY - 1) , gWorldSectorX);
140 		}
141 	}
142 	else
143 	{
144 		sprintf(zFileName, NPCDATADIR "/civ%02d.edt", ubCivQuoteID);
145 	}
146 
147 	zQuote = GCM->loadEncryptedString(zFileName, CIV_QUOTE_TEXT_SIZE * ubEntryID, CIV_QUOTE_TEXT_SIZE);
148 	return !zQuote.empty();
149 }
150 catch (...) { return FALSE; }
151 
152 
SurrenderMessageBoxCallBack(MessageBoxReturnValue const ubExitValue)153 static void SurrenderMessageBoxCallBack(MessageBoxReturnValue const ubExitValue)
154 {
155 	if ( ubExitValue == MSG_BOX_RETURN_YES )
156 	{
157 		// CJC Dec 1 2002: fix multiple captures
158 		BeginCaptureSquence();
159 
160 		// Do capture....
161 		FOR_EACH_IN_TEAM(i, OUR_TEAM)
162 		{
163 			SOLDIERTYPE& s = *i;
164 			if (!s.bInSector) continue;
165 			if (s.bLife == 0) continue;
166 			EnemyCapturesPlayerSoldier(&s);
167 			RemoveSoldierFromTacticalSector(s);
168 		}
169 
170 		EndCaptureSequence( );
171 
172 		gfSurrendered = TRUE;
173 		SetCustomizableTimerCallbackAndDelay( 3000, CaptureTimerCallback, FALSE );
174 
175 		ActionDone( gCivQuoteData.pCiv );
176 	}
177 	else
178 	{
179 		ActionDone( gCivQuoteData.pCiv );
180 	}
181 }
182 
183 
ShutDownQuoteBox(BOOLEAN fForce)184 static void ShutDownQuoteBox(BOOLEAN fForce)
185 {
186 	if ( !gCivQuoteData.bActive )
187 	{
188 		return;
189 	}
190 
191 	// Check for min time....
192 	if ( ( GetJA2Clock( ) - gCivQuoteData.uiTimeOfCreation ) > 300 || fForce )
193 	{
194 		RemoveVideoOverlay(gCivQuoteData.video_overlay);
195 
196 		// Remove mouse region...
197 		MSYS_RemoveRegion( &(gCivQuoteData.MouseRegion) );
198 
199 		RemoveMercPopupBox(gCivQuoteData.dialogue_box);
200 		gCivQuoteData.dialogue_box = 0;
201 		gCivQuoteData.bActive      = FALSE;
202 
203 		// do we need to do anything at the end of the civ quote?
204 		if ( gCivQuoteData.pCiv && gCivQuoteData.pCiv->bAction == AI_ACTION_OFFER_SURRENDER )
205 		{
206 			DoMessageBox(MSG_BOX_BASIC_STYLE, g_langRes->Message[STR_SURRENDER], GAME_SCREEN, MSG_BOX_FLAG_YESNO, SurrenderMessageBoxCallBack, NULL);
207 		}
208 	}
209 }
210 
ShutDownQuoteBoxIfActive()211 BOOLEAN ShutDownQuoteBoxIfActive( )
212 {
213 	if ( gCivQuoteData.bActive )
214 	{
215 		ShutDownQuoteBox( TRUE );
216 
217 		return( TRUE );
218 	}
219 
220 	return( FALSE );
221 }
222 
223 
GetCivType(const SOLDIERTYPE * pCiv)224 INT8 GetCivType(const SOLDIERTYPE* pCiv)
225 {
226 	if ( pCiv->ubProfile != NO_PROFILE )
227 	{
228 		return( CIV_TYPE_NA );
229 	}
230 
231 	// ATE: Check if this person is married.....
232 	// 1 ) check sector....
233 	if ( gWorldSectorX == 10 && gWorldSectorY == 6 && gbWorldSectorZ == 0 )
234 	{
235 		// 2 ) the only female....
236 		if ( pCiv->ubCivilianGroup == 0 && pCiv->bTeam != OUR_TEAM && pCiv->ubBodyType == REGFEMALE )
237 		{
238 			// She's a ho!
239 			return( CIV_TYPE_MARRIED_PC );
240 		}
241 	}
242 
243 	// OK, look for enemy type - MUST be on enemy team, merc bodytype
244 	if ( pCiv->bTeam == ENEMY_TEAM && IS_MERC_BODY_TYPE( pCiv ) )
245 	{
246 		return( CIV_TYPE_ENEMY );
247 	}
248 
249 	if ( pCiv->bTeam != CIV_TEAM && pCiv->bTeam != MILITIA_TEAM )
250 	{
251 		return( CIV_TYPE_NA );
252 	}
253 
254 	switch( pCiv->ubBodyType )
255 	{
256 		case REGMALE:
257 		case BIGMALE:
258 		case STOCKYMALE:
259 		case REGFEMALE:
260 		case FATCIV:
261 		case MANCIV:
262 		case MINICIV:
263 		case DRESSCIV:
264 		case CRIPPLECIV:
265 			return( CIV_TYPE_ADULT );
266 
267 		case ADULTFEMALEMONSTER:
268 		case AM_MONSTER:
269 		case YAF_MONSTER:
270 		case YAM_MONSTER:
271 		case LARVAE_MONSTER:
272 		case INFANT_MONSTER:
273 		case QUEENMONSTER:
274 			return( CIV_TYPE_NA );
275 
276 		case HATKIDCIV:
277 		case KIDCIV:
278 			return( CIV_TYPE_KID );
279 
280 		default:
281 			return( CIV_TYPE_NA );
282 	}
283 }
284 
285 
RenderCivQuoteBoxOverlay(VIDEO_OVERLAY * pBlitter)286 static void RenderCivQuoteBoxOverlay(VIDEO_OVERLAY* pBlitter)
287 {
288 	if (gCivQuoteData.video_overlay == NULL)
289 		return;
290 	RenderMercPopUpBox(gCivQuoteData.dialogue_box, pBlitter->sX, pBlitter->sY,  pBlitter->uiDestBuff);
291 	InvalidateRegion(pBlitter->sX, pBlitter->sY, pBlitter->sX + gusCivQuoteBoxWidth,
292 				pBlitter->sY + gusCivQuoteBoxHeight);
293 }
294 
295 
QuoteOverlayClickCallback(MOUSE_REGION * pRegion,INT32 iReason)296 static void QuoteOverlayClickCallback(MOUSE_REGION* pRegion, INT32 iReason)
297 {
298 	static BOOLEAN fLButtonDown = FALSE;
299 
300 	if (iReason & MSYS_CALLBACK_REASON_LBUTTON_DWN )
301 	{
302 		fLButtonDown = TRUE;
303 	}
304 
305 	if (iReason & MSYS_CALLBACK_REASON_LBUTTON_UP && fLButtonDown )
306 	{
307 		// Shutdown quote box....
308 		ShutDownQuoteBox( FALSE );
309 	}
310 	else if (iReason & MSYS_CALLBACK_REASON_LOST_MOUSE )
311 	{
312 		fLButtonDown = FALSE;
313 	}
314 }
315 
316 
BeginCivQuote(SOLDIERTYPE * pCiv,UINT8 ubCivQuoteID,UINT8 ubEntryID,INT16 sX,INT16 sY)317 void BeginCivQuote( SOLDIERTYPE *pCiv, UINT8 ubCivQuoteID, UINT8 ubEntryID, INT16 sX, INT16 sY )
318 {
319 	// OK, do we have another on?
320 	if ( gCivQuoteData.bActive )
321 	{
322 		// Delete?
323 		ShutDownQuoteBox( TRUE );
324 	}
325 
326 	// get text
327 	ST::string zQuote;
328 	if ( !GetCivQuoteText( ubCivQuoteID, ubEntryID, zQuote ) )
329 	{
330 		return;
331 	}
332 
333 	ST::string gzCivQuote;
334 	gzCivQuote = ST::format("\"{}\"", zQuote);
335 
336 	if ( ubCivQuoteID == CIV_QUOTE_HINT )
337 	{
338 		MapScreenMessage( FONT_MCOLOR_WHITE, MSG_DIALOG, ST::format("{}", gzCivQuote) );
339 	}
340 
341 	// Prepare text box
342 	gCivQuoteData.dialogue_box = PrepareMercPopupBox(0, BASIC_MERC_POPUP_BACKGROUND, BASIC_MERC_POPUP_BORDER, gzCivQuote, DIALOGUE_DEFAULT_WIDTH, 0, 0, 0, &gusCivQuoteBoxWidth, &gusCivQuoteBoxHeight);
343 
344 	// OK, find center for box......
345 	sX = sX - ( gusCivQuoteBoxWidth / 2 );
346 	sY = sY - ( gusCivQuoteBoxHeight / 2 );
347 
348 	// OK, limit to screen......
349 	{
350 		if ( sX < 0 )
351 		{
352 			sX = 0;
353 		}
354 
355 		// CHECK FOR LEFT/RIGHT
356 		if (sX + gusCivQuoteBoxWidth > SCREEN_WIDTH)
357 		{
358 			sX = SCREEN_WIDTH - gusCivQuoteBoxWidth;
359 		}
360 
361 		// Now check for top
362 		if ( sY < gsVIEWPORT_WINDOW_START_Y )
363 		{
364 			sY = gsVIEWPORT_WINDOW_START_Y;
365 		}
366 
367 		// Check for bottom
368 		sY = MIN(sY, gsVIEWPORT_WINDOW_END_Y - gusCivQuoteBoxHeight);
369 	}
370 
371 	UINT16 const w = gusCivQuoteBoxWidth;
372 	UINT16 const h = gusCivQuoteBoxHeight;
373 
374 	gCivQuoteData.video_overlay = RegisterVideoOverlay(RenderCivQuoteBoxOverlay, sX, sY, w, h);
375 
376 	//Define main region
377 	MSYS_DefineRegion(&gCivQuoteData.MouseRegion, sX, sY, sX + w, sY + h, MSYS_PRIORITY_HIGHEST, CURSOR_NORMAL, MSYS_NO_CALLBACK, QuoteOverlayClickCallback);
378 
379 	gCivQuoteData.bActive = TRUE;
380 
381 	gCivQuoteData.uiTimeOfCreation = GetJA2Clock( );
382 
383 	gCivQuoteData.uiDelayTime = FindDelayForString( gzCivQuote ) + 500;
384 
385 	gCivQuoteData.pCiv = pCiv;
386 
387 }
388 
389 
DetermineCivQuoteEntry(SOLDIERTYPE * pCiv,UINT8 * pubCivHintToUse,BOOLEAN fCanUseHints)390 static UINT8 DetermineCivQuoteEntry(SOLDIERTYPE* pCiv, UINT8* pubCivHintToUse, BOOLEAN fCanUseHints)
391 {
392 	UINT8   ubCivType;
393 	BOOLEAN bCivLowLoyalty = FALSE;
394 	BOOLEAN bCivHighLoyalty = FALSE;
395 	INT8    bCivHint;
396 	INT8    bMineId;
397 	BOOLEAN bMiners = FALSE;
398 
399 	(*pubCivHintToUse) = 0;
400 
401 	ubCivType = GetCivType( pCiv );
402 
403 	if ( ubCivType == CIV_TYPE_ENEMY )
404 	{
405 		// Determine what type of quote to say...
406 		// Are are we going to attack?
407 
408 		if ( pCiv->bAction == AI_ACTION_TOSS_PROJECTILE || pCiv->bAction == AI_ACTION_FIRE_GUN ||
409 			pCiv->bAction == AI_ACTION_FIRE_GUN || pCiv->bAction == AI_ACTION_KNIFE_MOVE )
410 		{
411 			return( CIV_QUOTE_ENEMY_THREAT );
412 		}
413 		else if ( pCiv->bAction == AI_ACTION_OFFER_SURRENDER )
414 		{
415 			return( CIV_QUOTE_ENEMY_OFFER_SURRENDER );
416 		}
417 		// Hurt?
418 		else if ( pCiv->bLife < 30 )
419 		{
420 			return( CIV_QUOTE_ENEMY_HURT );
421 		}
422 		// elite?
423 		else if ( pCiv->ubSoldierClass == SOLDIER_CLASS_ELITE )
424 		{
425 			return( CIV_QUOTE_ENEMY_ELITE );
426 		}
427 		else
428 		{
429 			return( CIV_QUOTE_ENEMY_ADMIN );
430 		}
431 	}
432 
433 	// Are we in a town sector?
434 	UINT8 const bTownId = GetTownIdForSector(SECTOR(gWorldSectorX, gWorldSectorY));
435 
436 	// If a married PC...
437 	if ( ubCivType == CIV_TYPE_MARRIED_PC )
438 	{
439 		return( CIV_QUOTE_PC_MARRIED );
440 	}
441 
442 	// CIV GROUPS FIRST!
443 	// Hicks.....
444 	if ( pCiv->ubCivilianGroup == HICKS_CIV_GROUP )
445 	{
446 		// Are they friendly?
447 		//if ( gTacticalStatus.fCivGroupHostile[ HICKS_CIV_GROUP ] < CIV_GROUP_WILL_BECOME_HOSTILE )
448 		if ( pCiv->bNeutral )
449 		{
450 			return( CIV_QUOTE_HICKS_FRIENDLY );
451 		}
452 		else
453 		{
454 			return( CIV_QUOTE_HICKS_ENEMIES );
455 		}
456 	}
457 
458 	// Goons.....
459 	if ( pCiv->ubCivilianGroup == KINGPIN_CIV_GROUP )
460 	{
461 		// Are they friendly?
462 		//if ( gTacticalStatus.fCivGroupHostile[ KINGPIN_CIV_GROUP ] < CIV_GROUP_WILL_BECOME_HOSTILE )
463 		if ( pCiv->bNeutral )
464 		{
465 			return( CIV_QUOTE_GOONS_FRIENDLY );
466 		}
467 		else
468 		{
469 			return( CIV_QUOTE_GOONS_ENEMIES );
470 		}
471 	}
472 
473 	// ATE: Cowering people take precedence....
474 	if ( ( pCiv->uiStatusFlags & SOLDIER_COWERING ) || ( pCiv->bTeam == CIV_TEAM && ( gTacticalStatus.uiFlags & INCOMBAT ) ) )
475 	{
476 		if ( ubCivType == CIV_TYPE_ADULT )
477 		{
478 			return( CIV_QUOTE_ADULTS_COWER );
479 		}
480 		else
481 		{
482 			return( CIV_QUOTE_KIDS_COWER );
483 		}
484 	}
485 
486 	// Kid slaves...
487 	if ( pCiv->ubCivilianGroup == FACTORY_KIDS_GROUP )
488 	{
489 		// Check fact.....
490 		if ( CheckFact( FACT_DOREEN_HAD_CHANGE_OF_HEART, 0 ) || !CheckFact( FACT_DOREEN_ALIVE, 0 ) )
491 		{
492 			return( CIV_QUOTE_KID_SLAVES_FREE );
493 		}
494 		else
495 		{
496 			return( CIV_QUOTE_KID_SLAVES );
497 		}
498 	}
499 
500 	// BEGGERS
501 	if ( pCiv->ubCivilianGroup == BEGGARS_CIV_GROUP )
502 	{
503 		// Check if we are in a town...
504 		if( bTownId != BLANK_SECTOR && gbWorldSectorZ == 0 )
505 		{
506 			if ( bTownId == SAN_MONA && ubCivType == CIV_TYPE_ADULT )
507 			{
508 				return( CIV_QUOTE_SAN_MONA_BEGGERS );
509 			}
510 		}
511 
512 		// DO normal beggers...
513 		if ( ubCivType == CIV_TYPE_ADULT )
514 		{
515 			return( CIV_QUOTE_ADULTS_BEGGING );
516 		}
517 		else
518 		{
519 			return( CIV_QUOTE_KIDS_BEGGING );
520 		}
521 	}
522 
523 	// REBELS
524 	if ( pCiv->ubCivilianGroup == REBEL_CIV_GROUP )
525 	{
526 		// DO normal beggers...
527 		if ( ubCivType == CIV_TYPE_ADULT )
528 		{
529 			return( CIV_QUOTE_ADULTS_REBELS );
530 		}
531 		else
532 		{
533 			return( CIV_QUOTE_KIDS_REBELS );
534 		}
535 	}
536 
537 	// Do miltitia...
538 	if ( pCiv->bTeam == MILITIA_TEAM )
539 	{
540 		// Different types....
541 		if ( pCiv->ubSoldierClass == SOLDIER_CLASS_GREEN_MILITIA )
542 		{
543 			return( CIV_QUOTE_GREEN_MILITIA );
544 		}
545 		if ( pCiv->ubSoldierClass == SOLDIER_CLASS_REG_MILITIA )
546 		{
547 			return( CIV_QUOTE_MEDIUM_MILITIA );
548 		}
549 		if ( pCiv->ubSoldierClass == SOLDIER_CLASS_ELITE_MILITIA )
550 		{
551 			return( CIV_QUOTE_ELITE_MILITIA );
552 		}
553 	}
554 
555 	// If we are in medunna, and queen is dead, use these...
556 	if ( bTownId == MEDUNA && CheckFact( FACT_QUEEN_DEAD, 0 ) )
557 	{
558 		return( CIV_QUOTE_DEIDRANNA_DEAD );
559 	}
560 
561 	// if in a town
562 	if( ( bTownId != BLANK_SECTOR ) && ( gbWorldSectorZ == 0 ) && gfTownUsesLoyalty[ bTownId ] )
563 	{
564 		// Check loyalty special quotes.....
565 		// EXTREMELY LOW TOWN LOYALTY...
566 		if ( gTownLoyalty[ bTownId ].ubRating < EXTREAMLY_LOW_TOWN_LOYALTY )
567 		{
568 			bCivLowLoyalty = TRUE;
569 		}
570 
571 		// HIGH TOWN LOYALTY...
572 		if ( gTownLoyalty[ bTownId ].ubRating >= HIGH_TOWN_LOYALTY )
573 		{
574 			bCivHighLoyalty = TRUE;
575 		}
576 	}
577 
578 
579 	// ATE: OK, check if we should look for a civ hint....
580 	if ( fCanUseHints )
581 	{
582 		bCivHint = ConsiderCivilianQuotes( gWorldSectorX, gWorldSectorY, gbWorldSectorZ,  FALSE );
583 	}
584 	else
585 	{
586 		bCivHint = -1;
587 	}
588 
589 	// ATE: check miners......
590 	if ( pCiv->ubSoldierClass == SOLDIER_CLASS_MINER )
591 	{
592 		bMiners = TRUE;
593 
594 		// If not a civ hint available...
595 		if ( bCivHint == -1 )
596 		{
597 			// Check if they are under our control...
598 
599 			// Should I go talk to miner?
600 			// Not done yet.
601 
602 			// Are they working for us?
603 			bMineId = GetIdOfMineForSector( gWorldSectorX, gWorldSectorY, gbWorldSectorZ );
604 
605 			if ( PlayerControlsMine( bMineId ) )
606 			{
607 				return( CIV_QUOTE_MINERS_FOR_PLAYER );
608 			}
609 			else
610 			{
611 				return( CIV_QUOTE_MINERS_NOT_FOR_PLAYER );
612 			}
613 		}
614 	}
615 
616 
617 	// Is one availible?
618 	// If we are to say low loyalty, do chance
619 	if ( bCivHint != -1 && bCivLowLoyalty && !bMiners )
620 	{
621 		if ( Random( 100 ) < 25 )
622 		{
623 			// Get rid of hint...
624 			bCivHint = -1;
625 		}
626 	}
627 
628 	// Say hint if availible...
629 	if ( bCivHint != -1 )
630 	{
631 		if ( ubCivType == CIV_TYPE_ADULT )
632 		{
633 			(*pubCivHintToUse) = bCivHint;
634 
635 			// Set quote as used...
636 			ConsiderCivilianQuotes( gWorldSectorX, gWorldSectorY, gbWorldSectorZ, TRUE );
637 
638 			// retrun value....
639 			return( CIV_QUOTE_HINT );
640 		}
641 	}
642 
643 	if ( bCivLowLoyalty )
644 	{
645 		if ( ubCivType == CIV_TYPE_ADULT )
646 		{
647 			return( CIV_QUOTE_ADULTS_EXTREMLY_LOW_LOYALTY );
648 		}
649 		else
650 		{
651 			return( CIV_QUOTE_KIDS_EXTREMLY_LOW_LOYALTY );
652 		}
653 	}
654 
655 	if ( bCivHighLoyalty )
656 	{
657 		if ( ubCivType == CIV_TYPE_ADULT )
658 		{
659 			return( CIV_QUOTE_ADULTS_HIGH_LOYALTY );
660 		}
661 		else
662 		{
663 			return( CIV_QUOTE_KIDS_HIGH_LOYALTY );
664 		}
665 	}
666 
667 
668 	// All purpose quote here....
669 	if ( ubCivType == CIV_TYPE_ADULT )
670 	{
671 		return( CIV_QUOTE_ADULTS_ALL_PURPOSE );
672 	}
673 	else
674 	{
675 		return( CIV_QUOTE_KIDS_ALL_PURPOSE );
676 	}
677 
678 }
679 
680 
HandleCivQuote()681 void HandleCivQuote( )
682 {
683 	if ( gCivQuoteData.bActive )
684 	{
685 		// Check for min time....
686 		if ( ( GetJA2Clock( ) - gCivQuoteData.uiTimeOfCreation ) > gCivQuoteData.uiDelayTime )
687 		{
688 			// Stop!
689 			ShutDownQuoteBox( TRUE );
690 		}
691 	}
692 }
693 
StartCivQuote(SOLDIERTYPE * pCiv)694 void StartCivQuote( SOLDIERTYPE *pCiv )
695 {
696 	UINT8 ubCivQuoteID;
697 	INT16 sX, sY;
698 	UINT8 ubEntryID = 0;
699 	INT16 sScreenX, sScreenY;
700 	UINT8 ubCivHintToUse;
701 
702 	// ATE: Check for old quote.....
703 	// This could have been stored on last attempt...
704 	if ( pCiv->bCurrentCivQuote == CIV_QUOTE_HINT )
705 	{
706 		// Determine which quote to say.....
707 		// CAN'T USE HINTS, since we just did one...
708 		pCiv->bCurrentCivQuote = -1;
709 		pCiv->bCurrentCivQuoteDelta = 0;
710 		ubCivQuoteID = DetermineCivQuoteEntry( pCiv, &ubCivHintToUse, FALSE );
711 	}
712 	else
713 	{
714 		// Determine which quote to say.....
715 		ubCivQuoteID = DetermineCivQuoteEntry( pCiv, &ubCivHintToUse, TRUE );
716 	}
717 
718 	// Determine entry id
719 	// ATE: Try and get entry from soldier pointer....
720 	if ( ubCivQuoteID != CIV_QUOTE_HINT )
721 	{
722 		if ( pCiv->bCurrentCivQuote == -1 )
723 		{
724 			// Pick random one
725 			pCiv->bCurrentCivQuote      = (INT8)Random(gubNumEntries[ubCivQuoteID] - 2);
726 			pCiv->bCurrentCivQuoteDelta = 0;
727 		}
728 
729 		ubEntryID = pCiv->bCurrentCivQuote + pCiv->bCurrentCivQuoteDelta;
730 	}
731 	else
732 	{
733 		ubEntryID = ubCivHintToUse;
734 
735 		// ATE: set value for quote ID.....
736 		pCiv->bCurrentCivQuote = ubCivQuoteID;
737 		pCiv->bCurrentCivQuoteDelta = ubEntryID;
738 
739 	}
740 
741 	// Determine location...
742 	// Get location of civ on screen.....
743 	GetSoldierScreenPos( pCiv, &sScreenX, &sScreenY );
744 	sX = sScreenX;
745 	sY = sScreenY;
746 
747 	// begin quote
748 	BeginCivQuote( pCiv, ubCivQuoteID, ubEntryID, sX, sY );
749 
750 	// Increment use
751 	if ( ubCivQuoteID != CIV_QUOTE_HINT )
752 	{
753 		pCiv->bCurrentCivQuoteDelta++;
754 
755 		if ( pCiv->bCurrentCivQuoteDelta == 2 )
756 		{
757 			pCiv->bCurrentCivQuoteDelta = 0;
758 		}
759 	}
760 }
761 
762 
InitCivQuoteSystem()763 void InitCivQuoteSystem( )
764 {
765 	gCivQuoteData = QUOTE_SYSTEM_STRUCT{};
766 	gCivQuoteData.bActive = FALSE;
767 	gCivQuoteData.video_overlay = NULL;
768 	gCivQuoteData.dialogue_box  = 0;
769 }
770 
771 
SaveCivQuotesToSaveGameFile(HWFILE const f)772 void SaveCivQuotesToSaveGameFile(HWFILE const f)
773 {
774 	FileSeek(f, NUM_CIV_QUOTES * 2, FILE_SEEK_FROM_CURRENT);
775 }
776 
777 
LoadCivQuotesFromLoadGameFile(HWFILE const f)778 void LoadCivQuotesFromLoadGameFile(HWFILE const f)
779 {
780 	FileSeek(f, NUM_CIV_QUOTES * 2, FILE_SEEK_FROM_CURRENT);
781 }
782