1 /*
2  * Seven Kingdoms: Ancient Adversaries
3  *
4  * Copyright 1997,1998 Enlight Software Ltd.
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  *
19  */
20 
21 //Filename    : OINFO.CPP
22 //Description : Info class
23 
24 #include <time.h>
25 #include <OVGA.h>
26 #include <OIMGRES.h>
27 #include <OSPY.h>
28 #include <OSTR.h>
29 #include <OBUTTON.h>
30 #include <OMOUSE.h>
31 #include <OFIRM.h>
32 #include <OSTR.h>
33 #include <ONEWS.h>
34 #include <ONATION.h>
35 #include <OFONT.h>
36 #include <ODATE.h>
37 #include <OTOWN.h>
38 #include <ODATE.h>
39 #include <OGAME.h>
40 #include <OPOWER.h>
41 #include <OSITE.h>
42 #include <OWALLRES.h>
43 #include <OSYS.h>
44 #include <OUNIT.h>
45 #include <OCOLTBL.h>
46 #include <OINFO.h>
47 #include <OOPTMENU.h>
48 #include "gettext.h"
49 
50 //------------ Define static vars ----------------//
51 
52 static const char* skill_name_array[] =
53 {
54 	"Combat Skill",
55 	"Construction Skill",
56 	"Production Skill"
57 };
58 
59 //------ define static vars --------//
60 
61 static	char *save_buf_1 = NULL;
62 static	char *save_buf_1b = NULL;
63 static	char *save_buf_2 = NULL;
64 static	char *save_buf_3 = NULL;
65 static	char *save_buf_4 = NULL;
66 
67 
68 //-------- Begin of function Info::Info --------//
69 //
Info()70 Info::Info() : report_array(sizeof(short), 50),
71 					report_array2(sizeof(short), 50),
72 					talk_msg_disp_array(sizeof(TalkMsgDisp), 50)
73 {
74 	info_background_bitmap = NULL;
75 }
76 //--------- End of function Info::Info ---------//
77 
78 
79 //-------- Begin of function Info::~Info --------//
80 //
~Info()81 Info::~Info()
82 {
83 	deinit();
84 
85 	err_when( save_buf_1 );
86 }
87 //--------- End of function Info::~Info ---------//
88 
89 
90 //-------- Begin of function Info::init --------//
91 //
init()92 void Info::init()
93 {
94 	deinit();
95 
96 	game_day   = 1;
97 	game_month = 6;
98 	game_year  = 1000;
99 
100 	game_start_date = date.julian( game_year, game_month, game_day );
101 
102 	game_date  = game_start_date;
103 
104 	year_day   = date.day_year( game_year, game_month, game_day );
105 
106 	year_passed= 0;      // no. of years has been passed since the game begins
107 
108 	goal_deadline = date.julian( date.year(info.game_start_date)+config.goal_year_limit,
109 						 date.month(info.game_start_date),
110 						 date.day(info.game_start_date) );
111 
112 	goal_difficulty  = 0;
113 	goal_score_bonus = 0;
114 
115 	//------ reset report browsers recno -----//
116 
117 	browse_nation_recno  = 0;
118 	browse_race_recno    = 0;
119 	browse_firm_recno    = 0;
120 	browse_income_recno	= 0;
121 	browse_expense_recno	= 0;
122 	browse_troop_recno   = 0;
123 	browse_unit_recno    = 0;
124 	browse_tech_recno    = 0;
125 	browse_god_recno		= 0;
126 	browse_town_recno    = 0;
127 	browse_spy_recno     = 0;
128 	browse_caravan_recno = 0;
129 	browse_ship_recno	   = 0;
130 	browse_talk_msg_recno= 0;
131 	browse_news_recno	   = 0;
132 	browse_ai_action_recno = 0;
133 	browse_ai_attack_recno = 0;
134 
135 	//------ vars of the nation report ------//
136 
137 	nation_report_mode = NATION_REPORT_INFO;
138 	player_reply_mode  = 0;
139 	chat_receiver_type = CHAT_RECEIVER_CURRENT;
140 
141 	//----------------------------------//
142 
143 	start_play_time = misc.get_time();	// the time player start playing the game
144 	total_play_time = 0;             // total time the player has played in all saved games
145 
146 	// these will be updated during loading game and saving game
147 
148 	err_when( MAX_REMOTE_CHAT_STR < DISP_NEWS_COUNT );			// it must not fewer then the maximum number of news that can be displayed on the screen at a time.
149 }
150 //--------- End of function Info::init ---------//
151 
152 
153 //-------- Begin of function Info::deinit --------//
154 //
deinit()155 void Info::deinit()
156 {
157 	if( info_background_bitmap )
158 	{
159 		mem_del( info_background_bitmap );
160 		info_background_bitmap = NULL;
161 	}
162 }
163 //--------- End of function Info::deinit ---------//
164 
165 
166 //------- Begin of function Info::init_random_seed ------//
167 //
168 // [unsigned] randomSeed - if given, it will be the random seed of the game.
169 //									random seed. otherwise a random seed will be
170 //								   picked.
171 //								   (default:0)
172 //
init_random_seed(int randomSeed)173 void Info::init_random_seed(int randomSeed)
174 {
175 	if( randomSeed )
176 		random_seed = randomSeed;
177 	else
178 	{
179 		randomSeed = time(NULL);
180 		randomSeed = randomSeed << 4 | randomSeed >> (32-4); // _rotr( randomSeed, 4 )
181 		if( randomSeed < 0 )
182 			randomSeed = ~randomSeed;
183 		if( randomSeed == 0 )
184 			randomSeed = 1;
185 		random_seed = randomSeed;
186 	}
187 
188 	misc.set_random_seed(random_seed);
189 
190 	//------ write random seed --------//
191 
192 	if( sys.testing_session )
193 	{
194 		File fileMapSeed;
195 
196 		fileMapSeed.file_create( "MAP.RS" );
197 
198 		String str(misc.format(random_seed,1));
199 
200 		fileMapSeed.file_write(str, str.len());
201 	}
202 }
203 //------- End of function Info::init_random_seed ------//
204 
205 
206 //-------- Begin of function Info::next_day ---------//
207 //
next_day()208 void Info::next_day()
209 {
210 	if( ++game_day > 30 )
211 		game_day = 30;            // game_day is limited to 1-30 for
212 										  // calculation of e.g. revenue_30days()
213 	game_date++;
214 
215 	week_day=game_date%7;
216 
217 	//-----------------------------------------//
218 
219 	if( date.month(game_date) != game_month )
220 	{
221 		game_day   = 1;
222 		game_month = date.month(game_date);
223 
224 		firm_array.next_month();
225 		nation_array.next_month();
226 	}
227 
228 	if( date.year(game_date) != game_year )
229 	{
230 		game_month = 1;
231 		game_year  = date.year(game_date);
232 		year_passed++;
233 
234 		firm_array.next_year();
235 		nation_array.next_year();
236 	}
237 
238 	//-------- set year_day ----------//
239 
240 	year_day = date.day_year( game_year, game_month, game_day );
241 
242 	//--- if a spy is viewing secret reports of other nations ---//
243 
244 	if( viewing_spy_recno )
245 		process_viewing_spy();
246 
247 	//-------- deadline approaching message -------//
248 
249 	if( !game.game_has_ended && config.goal_year_limit_flag )
250 	{
251 		int dayLeft = goal_deadline-game_date;
252 		int yearLeft = dayLeft/365;
253 
254 		if( dayLeft%365==0 && yearLeft>=1 && yearLeft<=5 )
255 			news_array.goal_deadline( yearLeft, 0 );
256 
257 		if( dayLeft==0 )		// deadline arrives, everybody loses the game
258 			game.game_end(0, 0);
259 	}
260 }
261 //---------- End of function Info::next_day --------//
262 
263 
264 //-------- Begin of function Info::disp_panel --------//
265 //
disp_panel()266 void Info::disp_panel()
267 {
268 	image_interface.put_to_buf( &vga_back, "MAINSCR" );
269 
270 	//------ keep a copy of bitmap of the panel texture -----//
271 
272 	if( !info_background_bitmap )
273 		info_background_bitmap = mem_add( 4 + (INFO_X2-INFO_X1+1)*(INFO_Y2-INFO_Y1+1) );
274 
275 	vga_back.read_bitmap( INFO_X1, INFO_Y1, INFO_X2, INFO_Y2, info_background_bitmap );
276 }
277 //--------- End of function Info::disp_panel ---------//
278 
279 
280 //-------- Begin of function Info::disp --------//
281 //
282 // Display the side info area.
283 //
disp()284 void Info::disp()
285 {
286 //	mouse.handle_flicking = 0;		// since it will be called by Firm detect functions directly which may have set mouse.handle_flicking to 1 first, so we need to cancel it here
287 
288 	if( !power.enable_flag )
289 		return;
290 
291 	if( sys.signal_exit_flag )
292 		return;
293 
294 	if( option_menu.is_active() )
295 		return;
296 
297 	vga_back.put_bitmap( INFO_X1, INFO_Y1, info_background_bitmap );
298 	vga_front.put_bitmap( INFO_X1, INFO_Y1, info_background_bitmap );
299 
300 	//------- use front buffer -------//
301 
302 	int saveUseBackBuf = vga.use_back_buf;
303 
304 	vga.use_front();
305 
306 	//------ if units/firm selected, display info --------//
307 
308 	if( firm_array.selected_recno )
309 	{
310 		firm_array[firm_array.selected_recno]->disp_info_both(INFO_REPAINT);
311 	}
312 	else if( town_array.selected_recno )
313 	{
314 		town_array[town_array.selected_recno]->disp_info(INFO_REPAINT);
315 	}
316 	else if( site_array.selected_recno )
317 	{
318 		site_array[site_array.selected_recno]->disp_info(INFO_REPAINT);
319 	}
320 	else if( unit_array.selected_recno )
321 	{
322 		unit_array[unit_array.selected_recno]->disp_info(INFO_REPAINT);
323 	}
324 	else if( wall_res.selected_x_loc >= 0 )
325 	{
326 		wall_res.disp_info(INFO_REPAINT);
327 	}
328 
329 	//----- restore use back buffer if it was ----//
330 
331 	if( saveUseBackBuf )
332 		vga.use_back();
333 }
334 //-------- End of function Info::disp --------//
335 
336 
337 //-------- Begin of function Info::update --------//
338 
update()339 void Info::update()
340 {
341 	if( !power.enable_flag )
342 		return;
343 
344 	if( option_menu.is_active() )
345 		return;
346 
347 	//-------------------------------------------//
348 
349 	disp_heading();
350 
351 	//------- use front buffer -------//
352 
353 	int saveUseBackBuf = vga.use_back_buf;
354 
355 	vga.use_front();
356 
357 	//-------------------------------------------//
358 
359 	if( firm_array.selected_recno )
360 	{
361 		firm_array[firm_array.selected_recno]->disp_info_both(INFO_UPDATE);
362 	}
363 	else if( town_array.selected_recno )
364 	{
365 		town_array[town_array.selected_recno]->disp_info(INFO_UPDATE);
366 	}
367 	else if( site_array.selected_recno )
368 	{
369 		site_array[site_array.selected_recno]->disp_info(INFO_UPDATE);
370 	}
371 	else if( unit_array.selected_recno )
372 	{
373 		unit_array[unit_array.selected_recno]->disp_info(INFO_UPDATE);
374 	}
375 	else if( wall_res.selected_x_loc >= 0 )
376 	{
377 		wall_res.disp_info(INFO_UPDATE);
378 	}
379 
380 	//----- restore use back buffer if it was ----//
381 
382 	if( saveUseBackBuf )
383 		vga.use_back();
384 }
385 //-------- End of function Info::update --------//
386 
387 
388 //-------- Begin of function Info::disp_heading --------//
389 
disp_heading()390 void Info::disp_heading()
391 {
392 	//---- display info on the top menu area ----//
393 
394 	int x=TOP_MENU_X2-250;
395 
396 	//---------- display date -----------//
397 
398 	font_mid.use_max_height();
399 	font_mid.disp( 460, 10, date.date_str(game_date,1), 575);
400 
401 	if( !nation_array.player_recno )		// the player has lost the game
402 	{
403 		font_mid.disp( 307, 10, "", 445);		// clear the display
404 		font_mid.disp( 305, 30, "", 445);
405 		// ##### begin Gilbert 4/11 #######//
406 		image_icon.put_front(447,26, "REPU_DW" );
407 		// ##### end Gilbert 4/11 #######//
408 		font_mid.disp( 476, 30, "", 575);
409 		font_mid.use_std_height();
410 		return;
411 	}
412 
413 	String  str;
414 	Nation* nationPtr = ~nation_array;
415 
416 	//------- display food and net food change --------//
417 
418 	err_when( vga.use_back_buf );
419 
420 	char* strPtr = nationPtr->food_str();
421 
422 	font_mid.disp( 307, 10, strPtr, 445);
423 
424 	//------- display cash and profit --------//
425 
426 	strPtr = nationPtr->cash_str();
427 
428 	font_mid.disp( 305, 30, strPtr, 445);
429 
430 	//------- display reputation ---------//
431 
432 	if( nationPtr->reputation >= 0 )
433 	{
434 		str = misc.format( (int)nationPtr->reputation, 4 );			// format type 4 - no thousand separators
435 	}
436 	else
437 	{
438 		str  = "-";
439 		str += misc.format( (int)-nationPtr->reputation, 4 );		// format type 4 - no thousand separators
440 	}
441 
442 	int reputationChange = (int) nationPtr->reputation_change_365days();
443 
444 	if( reputationChange )
445 	{
446 		str += " (";
447 
448 		if( reputationChange > 0 )
449 			str += "+";
450 		else
451 			str += "-";
452 
453 		str += abs(reputationChange);
454 		str += ")";
455 	}
456 
457 	image_icon.put_front(447,26, nationPtr->reputation_change_365days() >= (float)0.0 ? (char*)"REPU_UP" : (char*)"REPU_DW" );
458 	font_mid.disp( 476, 30, str, 575);
459 	font_mid.use_std_height();
460 }
461 //-------- End of function Info::disp_heading --------//
462 
463 
464 //-------- Begin of function Info::detect --------//
465 
detect()466 int Info::detect()
467 {
468 	//------------ detect objects ------------//
469 
470 	if( firm_array.selected_recno )
471 	{
472 		firm_array[firm_array.selected_recno]->detect_info_both();
473 	}
474 	else if( town_array.selected_recno )
475 	{
476 		town_array[town_array.selected_recno]->detect_info();
477 	}
478 	else if( site_array.selected_recno )
479 	{
480 		site_array[site_array.selected_recno]->detect_info();
481 	}
482 	else if( unit_array.selected_recno )
483 	{
484 		unit_array[unit_array.selected_recno]->detect_info();
485 	}
486 
487 	return 0;
488 }
489 //-------- End of function Info::detect --------//
490 
491 
492 //-------- Begin of function Info::is_unit_build_menu_opened --------//
is_unit_build_menu_opened()493 bool Info::is_unit_build_menu_opened()
494 {
495 	//--- Use exactly the same logic as Info::detect for determining if a unit is actively selected ---//
496 	if( !firm_array.selected_recno && !town_array.selected_recno && !site_array.selected_recno
497 		&& unit_array.selected_recno )
498 	{
499 		return unit_array[unit_array.selected_recno]->is_in_build_menu();
500 	}
501 	return false;
502 }
503 //-------- End of function Info::is_unit_build_menu_opened --------//
504 
505 
506 //-------- Begin of function Info::draw_selected --------//
507 
draw_selected()508 void Info::draw_selected()
509 {
510 	if( firm_array.selected_recno )
511 		firm_array[firm_array.selected_recno]->draw_selected();
512 
513 	else if( town_array.selected_recno )
514 		town_array[town_array.selected_recno]->draw_selected();
515 
516 	else if( site_array.selected_recno )
517 		site_array[site_array.selected_recno]->draw_selected();
518 
519 	else if( wall_res.selected_x_loc >= 0 )
520 		wall_res.draw_selected();
521 }
522 //-------- End of function Info::draw_selected --------//
523 
524 
525 //-------- Begin of function Info::get_report_data --------//
526 
get_report_data(int recNo)527 short Info::get_report_data(int recNo)
528 {
529 	err_when( recNo<1 || recNo>report_array.size() );
530 
531 	return *((short*)report_array.get(recNo));
532 }
533 //-------- End of function Info::get_report_data --------//
534 
535 
536 //-------- Begin of function Info::get_report_data2 --------//
537 
get_report_data2(int recNo)538 short Info::get_report_data2(int recNo)
539 {
540 	err_when( recNo<1 || recNo>report_array2.size() );
541 
542 	return *((short*)report_array2.get(recNo));
543 }
544 //-------- End of function Info::get_report_data2 --------//
545 
546 
547 //-------- Begin of function Info::process_viewing_spy --------//
548 
process_viewing_spy()549 void Info::process_viewing_spy()
550 {
551 	//---- check if the viewing spy is still valid ----//
552 
553 	int isValid=1;
554 
555 	if( spy_array.is_deleted(viewing_spy_recno) )	// the spy is dead
556 	{
557 		isValid = 0;
558 	}
559 	else
560 	{
561 		Spy* spyPtr = spy_array[viewing_spy_recno];
562 
563 		//-- check if the spy still stay in the same place --//
564 
565 		if( spyPtr->spy_place_nation_recno() != info.viewing_nation_recno )
566 		{
567 			isValid = 0;
568 		}
569 		else
570 		{
571 		/*
572 			//--- on average, a spy will get caught in 5 to 15 days when viewing the secret of its enemy ---//
573 
574 			if( misc2.random(5+spyPtr->spy_skill/5) ) // use m2 to avoid multiplayer sync problem
575 			{
576 				spyPtr->set_exposed(COMMAND_PLAYER);
577 				isValid = 0;
578 			}
579 		*/
580 		}
581 	}
582 
583 	if( !isValid )		//-- if not valid, set the mode back to normal viewing mode
584 		sys.set_view_mode(MODE_NORMAL);
585 }
586 //-------- End of function Info::process_viewing_spy --------//
587 
588 
589 //------- Begin of function Info::play_time_str --------//
590 //
play_time_str()591 char* Info::play_time_str()
592 {
593 	int totalMin = total_play_time / (60*1000);
594 	int playHour = totalMin / 60;
595 	int playMin  = totalMin - playHour*60;
596 
597 	static String str;
598 
599 	str = "";
600 
601 	if( playHour )
602 	{
603 		// TRANSLATORS: Part of "%d hour(s) and %d minute(s)"
604 		str.catf(ngettext("%d hour and", "%d hours and", playHour), playHour);
605 		str += " ";
606 	}
607 
608 	str.catf(ngettext("%d minute", "%d minutes", playMin), playMin);
609 
610 	return str;
611 }
612 //---------- End of function Info::play_time_str ---------//
613 
614 
615 //------- Begin of function Info::game_duration_str --------//
616 //
game_duration_str()617 char* Info::game_duration_str()
618 {
619 	//------- get the true game start date --------//
620 
621 	int gameStartDate;
622 
623 	//-- For scenarios (whose goal_difficulty are > 0 ), the actual game start date is no info.game_start_date, we must calculate it
624 
625 	if( info.goal_difficulty )
626 	{
627 		gameStartDate =  date.julian( date.year(info.goal_deadline)-config.goal_year_limit,
628 							  date.month(info.goal_deadline),
629 							  date.day(info.goal_deadline) );
630 	}
631 	else
632 	{
633 		gameStartDate = info.game_start_date;
634 	}
635 
636 	//---------------------------------------------//
637 
638 	int totalDay = info.game_date - gameStartDate;
639 	int playYear = totalDay / 365;
640 	int playDay  = totalDay - playYear*365;
641 
642 	static String str;
643 
644 	str = "";
645 
646 	if( playYear )
647 	{
648 		// TRANSLATORS: Part of "%d year(s) and %d day(s)"
649 		str.catf(ngettext("%d year and", "%d years and", playYear), playYear);
650 		str += " ";
651 	}
652 
653 	str.catf(ngettext("%d day", "%d days", playDay), playDay);
654 
655 	return str;
656 }
657 //---------- End of function Info::game_duration_str ---------//
658 
659 
660 //------- Begin of function Info::save_game_scr --------//
661 //
save_game_scr()662 void Info::save_game_scr()
663 {
664 	err_when( save_buf_1 );
665 
666 	// top and buttom
667 	if( 0 < ZOOM_Y1 )
668 	{
669 		save_buf_1  = vga_front.save_area(0, 0, VGA_WIDTH-1, ZOOM_Y1-1);
670 		save_buf_1b = vga_back.save_area(0, 0, VGA_WIDTH-1, ZOOM_Y1-1);		// save the back buffer also as the top area of the back buf is used for font display
671 	}
672 
673 	if( ZOOM_Y2 < VGA_HEIGHT-1 )
674 		save_buf_2 = vga_front.save_area(0, ZOOM_Y2+1, VGA_WIDTH-1, VGA_HEIGHT-1);
675 
676 	// left and right
677 	if( 0 < ZOOM_X1 )
678 		save_buf_3 = vga_front.save_area(0, ZOOM_Y1, ZOOM_X1-1, ZOOM_Y2);
679 
680 	if( ZOOM_X2 < VGA_WIDTH-1 )
681 		save_buf_4 = vga_front.save_area(ZOOM_X2+1, ZOOM_Y1, VGA_WIDTH-1, ZOOM_Y2);
682 }
683 //---------- End of function Info::save_game_scr ---------//
684 
685 
686 //------- Begin of function Info::rest_game_scr --------//
687 //
rest_game_scr()688 void Info::rest_game_scr()
689 {
690 	// restore area outside front buffer
691 	if(save_buf_4)
692 		vga_front.rest_area(save_buf_4, 1);
693 	if(save_buf_3)
694 		vga_front.rest_area(save_buf_3, 1);
695 	if(save_buf_2)
696 		vga_front.rest_area(save_buf_2, 1);
697 	if(save_buf_1)
698 		vga_front.rest_area(save_buf_1, 1);
699 	if(save_buf_1b)
700 		vga_back.rest_area(save_buf_1b, 1);
701 
702 	save_buf_1 = NULL;
703 
704 	info.disp();
705 	sys.blt_virtual_buf();		// blt the virtual front buffer to the screen
706 }
707 //---------- End of function Info::rest_game_scr ---------//
708 
709 
710 //------- Begin of function Info::free_game_scr --------//
711 //
free_game_scr()712 void Info::free_game_scr()
713 {
714 	if(save_buf_4)
715 		mem_del(save_buf_4);
716 
717 	if(save_buf_3)
718 		mem_del(save_buf_3);
719 
720 	if(save_buf_2)
721 		mem_del(save_buf_2);
722 
723 	if(save_buf_1)
724 		mem_del(save_buf_1);
725 
726 	if(save_buf_1b)
727 		mem_del(save_buf_1b);
728 
729 	save_buf_1 = NULL;
730 }
731 //---------- End of function Info::free_game_scr ---------//
732 
733 
734 //------- Begin of function Info::disp_loyalty --------//
735 //
736 // return: <int> x2 - the ending x position of the loyalty string.
737 //
disp_loyalty(int x,int y,int x2,int curLoyalty,int targetLoyalty,int nationRecno,int refreshFlag)738 int Info::disp_loyalty(int x, int y, int x2, int curLoyalty, int targetLoyalty, int nationRecno, int refreshFlag)
739 {
740 	int endX;
741 
742 	if( x != x2 )		// if x==x2, don't display the field name.
743 	{
744 		font_san.field( x, y, _("Loyalty"), x2, curLoyalty, 1, INFO_X2-2, refreshFlag);
745 		endX = x2 + 4 + font_san.text_width( misc.format(curLoyalty) );
746 	}
747 	else
748 	{
749 		endX = font_san.put( x2+4, y+2, curLoyalty, 1 );
750 	}
751 
752 	if( nation_array[nationRecno]->cash <= 0 )		// if the nation no longer has money to pay the unit
753 		targetLoyalty = 0;
754 
755 	if( curLoyalty != targetLoyalty )		// only increase, no decrease. Decrease are caused by events. Increases are made gradually
756 	{
757 		int tx = x2+6+font_san.text_width( misc.format(curLoyalty) );
758 
759 		if( targetLoyalty > curLoyalty )
760 			image_icon.put_front( tx, y+2, "ARROWUP" );
761 
762 		else if( targetLoyalty < curLoyalty )
763 			image_icon.put_front( tx, y+2, "ARROWDWN" );
764 
765 		endX = font_san.put( tx+10, y+2, targetLoyalty, 1 );
766 	}
767 
768 	return endX;
769 }
770 //---------- End of function Info::disp_loyalty ---------//
771 
772 
773