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    : OBATTLE.CPP
22 //Description : Battle Object
23 
24 #include <OSYS.h>
25 #include <OWORLD.h>
26 #include <OPOWER.h>
27 #include <OCONFIG.h>
28 #include <OSPY.h>
29 #include <OMOUSE.h>
30 #include <OMUSIC.h>
31 #include <OSITE.h>
32 #include <ORACERES.h>
33 #include <OGODRES.h>
34 #include <OTECHRES.h>
35 #include <OCONFIG.h>
36 #include <OREMOTE.h>
37 #include <OTOWN.h>
38 #include <OFIRM.h>
39 #include <ONEWS.h>
40 #include <ONATION.h>
41 #include <OMONSRES.h>
42 #include <OWALLRES.h>
43 #include <OINFO.h>
44 #include <OUNITALL.h>
45 #include <OGAME.h>
46 #include <OBATTLE.h>
47 #include <OMOUSECR.h>
48 #include <vga_util.h>
49 #include <CmdLine.h>
50 #include <FilePath.h>
51 #include <ConfigAdv.h>
52 
53 //---------- define static functions -------------//
54 
55 static int is_space(int xLoc1, int yLoc1, int xLoc2, int yLoc2, char mobileType);
56 static char random_race();
57 static char random_race_time();
58 
59 //-------- Begin of function Battle::init --------//
60 //
init()61 void Battle::init()
62 {
63 }
64 //-------- End of function Battle::init --------//
65 
66 
67 //-------- Begin of function Battle::deinit --------//
68 //
deinit()69 void Battle::deinit()
70 {
71 }
72 //-------- End of function Battle::deinit --------//
73 
74 
75 //-------- Begin of function Battle::run --------//
76 //
77 // <int> mpGame - whether this is a multiplayer game or not.
78 //
run(NewNationPara * mpGame,int mpPlayerCount)79 void Battle::run(NewNationPara *mpGame, int mpPlayerCount)
80 {
81 	int oldCursor = mouse_cursor.get_icon();
82 	mouse_cursor.set_icon(CURSOR_WAITING);
83 
84 #ifdef DEBUG
85 	debug_sim_game_type = (misc.is_file_exist("sim.sys")) ? 2 : 0;
86 	if(debug_sim_game_type)
87 	{
88 		run_sim();
89 		return;
90 	}
91 #endif
92 
93 	// ####### begin Gilbert 24/10 #######//
94 	//-- random seed is initalized at connecting multiplayer --//
95 	//if( !mpGame )
96 	//	info.init_random_seed(0);
97 	// ####### end Gilbert 24/10 #######//
98 
99 	//----------- save the current seed for generating map -----------//
100 	#ifdef DEBUG2
101 		File seedFile;
102 		char *chPtr = misc.format(misc.get_random_seed());
103 		seedFile.file_create("mapseed.rs");
104 		seedFile.file_write(chPtr, strlen(chPtr));
105 		seedFile.file_close();
106 	#endif
107 
108 	world.generate_map();
109 
110 	//------- create player nation --------//
111 
112 	if( mpGame )
113 	{
114 		for( int i = 0; i < mpPlayerCount; ++i )
115 		{
116 			int nationRecno = nation_array.new_nation(mpGame[i]);
117 			if( nationRecno != mpGame[i].nation_recno )
118 				err.run( "Unexpected nation recno created" );
119 			nation_array.set_human_name( nationRecno, mpGame[i].player_name );
120 		}
121 	}
122 	else if( game.game_mode != GAME_DEMO )
123 	{
124 		// if config.race_id == 0, select a random race, but don't call misc.random
125 		int nationRecno = nation_array.new_nation( NATION_OWN,
126 								config.race_id ? config.race_id : random_race_time(),
127 								config.player_nation_color );
128 
129 		nation_array.set_human_name( nationRecno, config.player_name );
130 	}
131 
132 	//--------- create ai nations --------//
133 
134 	if( mpGame )
135 	{
136 		int aiToCreate = config.ai_nation_count;
137 		if( aiToCreate + mpPlayerCount > MAX_NATION )
138 			aiToCreate = MAX_NATION - mpPlayerCount;
139 		err_when( aiToCreate < 0 );
140 		create_ai_nation(aiToCreate);
141 	}
142 	else if( game.game_mode == GAME_DEMO )
143 	{
144 		create_ai_nation(config.ai_nation_count+1); // no human player
145 	} else {
146 		create_ai_nation(config.ai_nation_count);
147 	}
148 
149 	//------ create pregame objects ------//
150 
151 	create_pregame_object();
152 
153 	//------- update nation statistic -------//
154 
155 	nation_array.update_statistic();
156 
157 	//--- highlight the player's town in the beginning of the game ---//
158 
159 	Town* townPtr;
160 
161 	for( int i=1 ; i<=town_array.size() ; i++ )
162 	{
163 		townPtr = town_array[i];
164 
165 		if( townPtr->nation_recno == nation_array.player_recno )
166 		{
167 			world.go_loc( townPtr->loc_x1, townPtr->loc_y1 );
168 			break;
169 		}
170 	}
171 
172 	//---- reset config parameter ----//
173 
174 	if( !remote.is_enable() && cmd_line.game_speed >= 0 )
175 		sys.set_speed(cmd_line.game_speed, COMMAND_AUTO);
176 	else
177 		sys.set_speed(12, COMMAND_AUTO);
178 
179 	//---- reset cheats ----//
180 
181 	config.fast_build = 0;
182 	config.king_undie_flag = sys.testing_session && !mpGame;
183 	config.blacken_map = 1;
184 	config.disable_ai_flag = 0;
185 
186 	if( sys.testing_session )
187 		config.show_unit_path = 3;
188 
189 	if( game.game_mode == GAME_DEMO )
190 	{
191 		// observation mode
192 		world.unveil(0, 0, MAX_WORLD_X_LOC-1, MAX_WORLD_Y_LOC-1);
193 		world.visit(0, 0, MAX_WORLD_X_LOC-1, MAX_WORLD_Y_LOC-1, 0, 0);
194 
195 		config.blacken_map = 0;
196 	}
197 
198 	// ######## begin Gilbert 11/11 #######//
199 	// enable tech and god, useful for multi-player
200 #if(0)
201 	for( i = 1; i < nation_array.size(); ++i )
202 	{
203 		if( !nation_array.is_deleted(i) && !nation_array[i]->is_ai() )
204 		{
205 			tech_res.inc_all_tech_level(i);
206 			god_res.enable_know_all(i);
207 		}
208 	}
209 #endif
210 	// ######## end Gilbert 11/11 #######//
211 
212 	//------- enable/disable sound effects -------//
213 
214 	int songId;
215 	if( nation_array.player_recno && (~nation_array)->race_id <= 7 )
216 		songId = (~nation_array)->race_id+1;
217 	else
218 		songId = music.random_bgm_track();
219 	music.play(songId, sys.cdrom_drive ? MUSIC_CD_THEN_WAV : 0 );
220 
221 	mouse_cursor.restore_icon(oldCursor);
222 
223 	//--- give the control to the system main loop, start the game now ---//
224 
225 	sys.run();
226 }
227 //--------- End of function Battle::run ---------//
228 
229 
230 //-------- Begin of function Battle::run_sim --------//
231 // run simulation
232 //
233 #ifdef DEBUG
run_sim()234 void Battle::run_sim()
235 {
236 	err_when(!debug_sim_game_type);
237 
238 	info.disp_panel();
239 	//info.init_random_seed(0);
240 	//info.init_random_seed(869451513); // for testing marine
241 	info.init_random_seed(869639665); // for testing marine
242 
243 	//info.init_random_seed(866608391);
244 	//info.init_random_seed(866621716);
245 	//info.init_random_seed(867299236);
246 
247 	world.generate_map();
248 
249 	//--------- refresh world ---------//
250 	world.refresh();
251 	vga_util.blt_buf(0, 0, VGA_WIDTH-1, VGA_HEIGHT-1);
252 	world.paint();
253 
254 	//------- create player nation --------//
255 
256 	// if config.race_id == 0, select a random race, but don't call misc.random
257 	nation_array.new_nation( NATION_OWN,
258 		config.race_id ? config.race_id : random_race_time(),
259 		config.player_nation_color );
260 
261 	//--------- create ai nations --------//
262 	create_ai_nation(config.ai_nation_count);
263 
264 	//------ create pregame objects ------//
265 	create_pregame_object();
266 
267 	//--- highlight the player's town in the beginning of the game ---//
268 	Town* townPtr;
269 	for( int i=1 ; i<=town_array.size() ; i++ )
270 	{
271 		townPtr = town_array[i];
272 
273 		if( townPtr->nation_recno == nation_array.player_recno )
274 		{
275 			world.go_loc( townPtr->loc_x1, townPtr->loc_y1 );
276 			break;
277 		}
278 	}
279 
280 	//-*************** create units, objects *****************-//
281 	int maxNationCount = 2;
282 	int unitId = UNIT_DRAGON;
283 	int nationCount;
284 	SpriteInfo *spriteInfo;
285 	char teraMask;
286 	int unitRecno, x, y, xLoc, yLoc;
287 
288 	//--------- create dragon ---------//
289 	spriteInfo = sprite_res[unit_res[unitId]->sprite_id];
290 	teraMask = UnitRes::mobile_type_to_mask(unit_res[unitId]->mobile_type);
291 	for(nationCount=1; nationCount<=maxNationCount; nationCount++)
292 	{
293 		xLoc = 0;
294 		yLoc = MIN(20*nationCount, 180);
295 
296 		for(int createCount=0; createCount<10; createCount++, xLoc+=4) // createCount<50
297 		{
298 			for(y=0; y<4; y+=2)
299 			{
300 				for(x=0; x<4; x+=2)
301 				{
302 					unitRecno = unit_array.add_unit(unitId, nationCount, RANK_SOLDIER, 100, xLoc+x, yLoc+y);
303 					unit_array[unitRecno]->set_combat_level(100);
304 					((UnitGod*)unit_array[unitRecno])->god_id = 1;
305 				}
306 			}
307 		}
308 	}
309 
310 	//--------- create marine units ---------//
311 	unitId = UNIT_CARAVEL;
312 	spriteInfo = sprite_res[unit_res[unitId]->sprite_id];
313 	teraMask = UnitRes::mobile_type_to_mask(unit_res[unitId]->mobile_type);
314 	for(nationCount=1; nationCount<=maxNationCount; nationCount++)
315 	{
316 		for(int t=0; t<30; t++)
317 		{
318 			xLoc=0;
319 			yLoc=0;
320 			if(world.locate_space_random(xLoc, yLoc, MAX_WORLD_X_LOC-1,
321 				MAX_WORLD_Y_LOC-1, spriteInfo->loc_width*4, spriteInfo->loc_height*4,
322 				MAX_WORLD_X_LOC*MAX_WORLD_Y_LOC, 0, 0, teraMask))
323 			{
324 				if(xLoc%2)
325 					xLoc++;
326 				if(yLoc%2)
327 					yLoc++;
328 
329 				for(y=0; y<2; y++)
330 				{
331 					for(x=0; x<2; x++)
332 					{
333 						//world.get_loc(startXLoc, startYLoc)->can_move(unit_res[unit_id]->mobile_type)
334 						unitRecno = unit_array.add_unit(unitId, nationCount, RANK_SOLDIER, 100, xLoc+x*2, yLoc+y*2);
335 						unit_array[unitRecno]->set_combat_level(100);
336 					}
337 				}
338 			}
339 		}
340 	}
341 
342 	//--------- create land units ---------//
343 	for(nationCount=1; nationCount<=maxNationCount; nationCount++)
344 	{
345 		for(unitId=UNIT_NORMAN; unitId<=UNIT_JAPANESE; unitId++)
346 		{
347 			spriteInfo = sprite_res[unit_res[unitId]->sprite_id];
348 			teraMask = UnitRes::mobile_type_to_mask(unit_res[unitId]->mobile_type);
349 			for(int t=0; t<5; t++)
350 			{
351 				xLoc=0;
352 				yLoc=0;
353 				if(world.locate_space_random(xLoc, yLoc, MAX_WORLD_X_LOC-1,
354 					MAX_WORLD_Y_LOC-1, spriteInfo->loc_width*2, spriteInfo->loc_height*2,
355 					MAX_WORLD_X_LOC*MAX_WORLD_Y_LOC, 0, 0, teraMask))
356 				{
357 					for(y=0; y<2; y++)
358 					{
359 						for(x=0; x<2; x++)
360 						{
361 							//world.get_loc(startXLoc, startYLoc)->can_move(unit_res[unit_id]->mobile_type)
362 							unitRecno = unit_array.add_unit(unitId, nationCount, RANK_SOLDIER, 100, xLoc+x, yLoc+y);
363 							unit_array[unitRecno]->set_combat_level(100);
364 						}
365 					}
366 				}
367 			}
368 		}
369 	}
370 
371 	//-- enable power after the game objets has been initialized --//
372 	power.enable();      // enable power, which handle mouse inputs
373 
374 	//--- give the control to the system main loop, start the game now ---//
375 	sys.run();
376 }
377 #endif
378 //--------- End of function Battle::run_sim ---------//
379 
380 
381 //-------- Begin of function Battle::create_ai_nation --------//
382 //
383 // Create AI nations.
384 //
create_ai_nation(int aiNationCount)385 void Battle::create_ai_nation(int aiNationCount)
386 {
387 	int raceId;
388 
389 	for( int i=0 ; i<aiNationCount ; i++ )
390 	{
391 		err_when( nation_array.size() == MAX_NATION );
392 
393 		if( config.random_start_up )
394 			raceId = random_race();
395 		else
396 			raceId = nation_array.random_unused_race();
397 
398 		err_when( raceId < 1 || raceId > MAX_RACE );
399 
400 		int nationRecno;
401 		nationRecno = nation_array.new_nation( NATION_AI, raceId, nation_array.random_unused_color() );     // 2nd parameter = the race id., 3rd parameters = color scheme id.
402 	}
403 }
404 //--------- End of function Battle::create_ai_nation ---------//
405 
406 
407 //-------- Begin of function Battle::create_pregame_object --------//
408 //
409 // Initialize pre-game objects - towns, sites, independent towns.
410 //
create_pregame_object()411 void Battle::create_pregame_object()
412 {
413 	#define CREATE_UNIT_AREA_WIDTH     16
414 	#define CREATE_UNIT_AREA_HEIGHT    16
415 
416 	// ###### begin Gilbert 24/10 ######//
417 	const int dispProgress = 1;
418 	const int maxGenMapSteps = 100;
419 	const int newWorldSection = 1;
420 	vga_front.unlock_buf();
421 
422 	int curGenMapSteps = 0;
423 	if( dispProgress )
424 	{
425 		vga_front.lock_buf();
426 		game.disp_gen_map_status( curGenMapSteps, maxGenMapSteps, newWorldSection);
427 		vga_front.unlock_buf();
428 	}
429 	// ###### end Gilbert 24/10 ######//
430 
431 	//------- create nation and units --------//
432 
433 	int 		nationRecno, unitId, rankId, xLoc, yLoc, townRecno;
434 	int		kingUnitRecno;
435 	int		noSpaceFlag=0;
436 	Nation*  nationPtr;
437 
438 	for( nationRecno=1 ; nationRecno<=nation_array.size() ; nationRecno++ )
439 	{
440 		if( nation_array.is_deleted(nationRecno) )
441 			continue;
442 
443 		nationPtr = nation_array[nationRecno];
444 
445 		//--------- create town -----------//
446 
447 		townRecno = create_town( nationRecno, nationPtr->race_id, xLoc, yLoc );
448 
449 		if( !townRecno )
450 		{
451 			noSpaceFlag = 1;
452 			break;
453 		}
454 
455 		//------- create military camp -------//
456 
457 		Town* townPtr = town_array[townRecno];
458 
459 		int firmRecno = firm_array.build_firm(townPtr->loc_x1+6, townPtr->loc_y1,
460 							 nationRecno, FIRM_CAMP, race_res[nationPtr->race_id]->code);
461 
462 		if( !firmRecno )
463 		{
464 			noSpaceFlag = 1;
465 			break;
466 		}
467 
468 		firm_array[firmRecno]->complete_construction();
469 
470 		//--------- create units ----------//
471 
472 		unitId = race_res[nationPtr->race_id]->basic_unit_id;
473 
474 		kingUnitRecno = create_unit(townRecno, unitId, RANK_KING);
475 
476 		if( kingUnitRecno )
477 		{
478 			nation_array[nationRecno]->set_king(kingUnitRecno, 1);		// 1-this is the first king of the nation
479 			firm_array[firmRecno]->assign_overseer(kingUnitRecno);	// assign the king as the overseer of the command base
480 		}
481 		else
482 		{
483 			noSpaceFlag = 1;
484 			break;
485 		}
486 
487 		//----- create skilled units if config.random_start_up is 1 -----//
488 
489 		if( config.random_start_up )
490 		{
491 			int createCount = (50-townPtr->population)/3;		// the less population the villager has the more mobile units will be created
492 
493 			for( int i=0 ; i<createCount ; i++ )
494 			{
495 				if( misc.random(2)==0 )
496 					unitId = race_res[nationPtr->race_id]->basic_unit_id;
497 				else
498 					unitId = race_res[ random_race() ]->basic_unit_id;
499 
500 				if( misc.random(3)==0 )
501 					rankId = RANK_GENERAL;
502 				else
503 					rankId = RANK_SOLDIER;
504 
505 				if( !create_unit(townRecno, unitId, rankId) )
506 					break;
507 			}
508 		}
509 
510 		//------ create mines near towns in the beginning -----//
511 
512 		if( config.start_up_has_mine_nearby && !nationPtr->is_ai() )
513 			site_array.create_raw_site(0, townRecno);
514 	}
515 
516 	//--- if there is no space for creating new town/firm or unit, delete the unprocessed nations ---//
517 
518 	if( noSpaceFlag )
519 	{
520 		for( ; nationRecno<=nation_array.size() ; nationRecno++ )
521 			nation_array.del_nation(nationRecno);		// no space for creating a town for the nation, so we have to delete the nation
522 	}
523 
524 	// ###### begin Gilbert 24/10 ########//
525 	curGenMapSteps += 10;			// 10
526 	if( dispProgress )
527 	{
528 		vga_front.lock_buf();
529 		game.disp_gen_map_status( curGenMapSteps, maxGenMapSteps, newWorldSection);
530 		vga_front.unlock_buf();
531 	}
532 	// ###### end Gilbert 24/10 ######//
533 
534 	//---- init the type of active monsters in this game ----//
535 
536 	monster_res.init_active_monster();
537 	// ###### begin Gilbert 24/10 ########//
538 	curGenMapSteps += 5;			// 15
539 	if( dispProgress )
540 	{
541 		vga_front.lock_buf();
542 		game.disp_gen_map_status( curGenMapSteps, maxGenMapSteps, newWorldSection);
543 		vga_front.unlock_buf();
544 	}
545 	// ###### end Gilbert 24/10 ######//
546 
547 	//------ create independent towns -------//
548 
549 	//### begin alex 27/8 ###//
550 	int startUpIndependentTown = config.start_up_independent_town;
551 	//int startUpRawSite = config.start_up_raw_site;
552 	int startUpMonsterFirm = 10;
553 	int i, j, raceId;
554 
555 	site_array.generate_raw_site(config.start_up_raw_site);
556 	// ###### begin Gilbert 24/10 ########//
557 	curGenMapSteps += 10;			// 25
558 	if( dispProgress )
559 	{
560 		vga_front.lock_buf();
561 		game.disp_gen_map_status( curGenMapSteps, maxGenMapSteps, newWorldSection);
562 		vga_front.unlock_buf();
563 	}
564 
565 	int targetStep = maxGenMapSteps;
566 	// ###### end Gilbert 24/10 ######//
567 
568 	int maxLoopCount = startUpIndependentTown + startUpMonsterFirm;
569 
570 	for(j=0, i=1; j<maxLoopCount; j++, i++)
571 	{
572 		if(startUpIndependentTown)
573 		{
574 			//------ create independent towns -------//
575 			raceId = config_adv.race_random_list[i%config_adv.race_random_list_max];
576 			if(!create_town( 0, raceId, xLoc, yLoc ) )
577 			{
578 				startUpIndependentTown = 0;
579 				break;
580 			}
581 			// ##### begin Gilbert 24/10 #######//
582 			else
583 				startUpIndependentTown--;
584 			// ###### end Gilbert 24/10 ########//
585 		}
586 
587 		if(startUpMonsterFirm)
588 		{
589 			//------- create mosnters --------//
590 			if(config.monster_type != OPTION_MONSTER_NONE)
591 			{
592 				monster_res.generate(1);
593 				startUpMonsterFirm--;
594 			}
595 			else
596 				startUpMonsterFirm = 0;
597 		}
598 
599 		if(!(startUpIndependentTown+startUpMonsterFirm))
600 			break;
601 
602 		// ###### begin Gilbert 24/10 ########//
603 		if( dispProgress )
604 		{
605 			vga_front.lock_buf();
606 			game.disp_gen_map_status( curGenMapSteps + j*(targetStep-curGenMapSteps)/maxLoopCount, maxGenMapSteps, newWorldSection);
607 			vga_front.unlock_buf();
608 		}
609 		// ###### end Gilbert 24/10 ######//
610 	}
611 	//#### end alex 27/8 ####//
612 
613 	// ###### begin Gilbert 24/10 ########//
614 	// finish
615 	curGenMapSteps = targetStep;		// 100
616 	if( dispProgress )
617 	{
618 		vga_front.lock_buf();
619 		game.disp_gen_map_status( curGenMapSteps, maxGenMapSteps, newWorldSection);
620 		vga_front.unlock_buf();
621 	}
622 	// ###### end Gilbert 24/10 ######//
623 
624 	vga_front.lock_buf();
625 }
626 //--------- End of function Battle::create_pregame_object ---------//
627 
628 
629 //-------- Begin of function Battle::run_loaded --------//
630 //
run_loaded()631 void Battle::run_loaded()
632 {
633 	//-------- play music ---------//
634 
635 	char kingRace = 0;
636 
637 	if( !nation_array.is_deleted(nation_array.player_recno) )
638 	{
639 		if( !unit_array.is_deleted((~nation_array)->king_unit_recno) )
640 			// if there is king in the nation take his race
641 			kingRace = unit_array[(~nation_array)->king_unit_recno]->race_id;
642 		else
643 			// if king is killed, get the original nation
644 			kingRace = (~nation_array)->race_id;
645 	}
646 
647 	int songId = kingRace <= 7 ? kingRace+1 : music.random_bgm_track();
648 	music.play(songId, sys.cdrom_drive ? MUSIC_CD_THEN_WAV : 0 );
649 
650 	//--- give the control to the system main loop, start the game now ---//
651 
652 	sys.run(1);
653 }
654 //--------- End of function Battle::run_loaded ---------//
655 
656 
657 //-------- Begin of function Battle::run_replay --------//
658 //
run_replay()659 void Battle::run_replay()
660 {
661 	NewNationPara *mpGame = (NewNationPara *)mem_add(sizeof(NewNationPara)*MAX_NATION);
662 	int mpPlayerCount = 0;
663 	FilePath full_path(sys.dir_config);
664 
665 	full_path += "NONAME.RPL";
666 	if( full_path.error_flag )
667 		return;
668 
669 	if( !remote.init_replay_load(full_path, mpGame, &mpPlayerCount) )
670 		return;
671 
672 	game.init();
673 	game.game_mode = GAME_DEMO;
674 	game.game_has_ended = 1;
675 	battle.run(mpGame, mpPlayerCount);
676 	mem_del(mpGame);
677 	remote.deinit();
678 	game.deinit();
679 }
680 //--------- End of function Battle::run_replay ---------//
681 
682 
683 //-------- Begin of function Battle::run_test --------//
684 //
run_test()685 void Battle::run_test()
686 {
687 	info.disp_panel();
688 
689 	info.init_random_seed(153542);
690 
691 	world.generate_map();
692 
693 	//--------- refresh world ---------//
694 
695 	world.refresh();
696 
697 	vga_util.blt_buf(0, 0, VGA_WIDTH-1, VGA_HEIGHT-1);
698 
699 	world.paint();
700 
701 	//-------- create nation and units --------//
702 
703 	nation_array.new_nation( NATION_OWN, 1, 1 );		// 2nd parameter = the race id.	3rd parameters = color scheme id.
704 	nation_array.new_nation( NATION_AI , 2, 2 );		// 2nd parameter = the race id.	3rd parameters = color scheme id.
705 
706 	tech_res.inc_all_tech_level(1);		// set all tech of nation 1 to level 1
707 	tech_res.inc_all_tech_level(2);		// set all tech of nation 2 to level 1
708 
709 	create_test_unit(1);
710 	create_test_unit(2);
711 
712 	//-- enable power after the game objets has been initialized --//
713 
714 	power.enable();		// enable power, which handle mouse inputs
715 
716 	//--- give the control to the system main loop, start the game now ---//
717 
718 	sys.run();
719 }
720 //--------- End of function Battle::run_test ---------//
721 
722 
723 //-------- Begin of function Battle::create_test_unit --------//
724 //
create_test_unit(int nationRecno)725 void Battle::create_test_unit(int nationRecno)
726 {
727 	int 			x, y, unitId, xLoc, yLoc;
728 	SpriteInfo* spriteInfo;
729 
730 	for( unitId=1 ; unitId<=MAX_UNIT_TYPE ; unitId++ )
731 	{
732 		if( unitId == UNIT_CARAVAN )		// caravan cannot be created independently without market places
733 			continue;
734 
735 		xLoc=0;
736 		yLoc=0;
737 
738 		spriteInfo = sprite_res[ unit_res[unitId]->sprite_id ];
739 		char teraMask = UnitRes::mobile_type_to_mask(unit_res[unitId]->mobile_type);
740 
741 		if( world.locate_space_random(xLoc, yLoc, MAX_WORLD_X_LOC-1,
742 			 MAX_WORLD_Y_LOC-1, spriteInfo->loc_width*4, spriteInfo->loc_height*4,
743 			 MAX_WORLD_X_LOC*MAX_WORLD_Y_LOC, 0, 0, teraMask) )
744 		{
745 			for( y=spriteInfo->loc_height ; y<spriteInfo->loc_height*4 ; y+=spriteInfo->loc_height*2 )
746 			{
747 				for( x=spriteInfo->loc_width ; x<spriteInfo->loc_width*4 ; x+=spriteInfo->loc_width*2 )
748 				{
749 					// force the location to be even number
750 					int unitRecno = unit_array.add_unit( unitId, nationRecno, RANK_SOLDIER, 100, (xLoc+x)& ~1, (yLoc+y) & ~1 );
751 
752 					unit_array[unitRecno]->set_combat_level(100);
753 				}
754 			}
755 		}
756 	}
757 }
758 //--------- End of function Battle::create_test_unit ---------//
759 
760 
761 //-------- Begin of function Battle::create_town --------//
762 //
763 // <int> nationRecno = the nation recno of the town
764 // <int> raceId      = the race id. of the town
765 //
766 // <int&> xLoc = for the starting location of the town
767 // <int&> yLoc = for the starting location of the town
768 //
769 // return: <int> townRecno - >0  the recno of the town created
770 //                           ==0 no town created
771 //
create_town(int nationRecno,int raceId,int & xLoc,int & yLoc)772 int Battle::create_town(int nationRecno, int raceId, int& xLoc, int& yLoc)
773 {
774 	//------- locate for a space to build the town ------//
775 
776 	if( !town_array.think_town_loc(MAX_WORLD_X_LOC*MAX_WORLD_Y_LOC, xLoc, yLoc) )
777 		return 0;
778 
779 	//--------------- create town ---------------//
780 
781 	int townRecno = town_array.add_town(nationRecno, raceId, xLoc, yLoc);
782 
783 	Town* townPtr = town_array[townRecno];
784 
785 	//--------- no. of mixed races ---------//
786 
787 	if( nationRecno )
788 	{
789 		int initPop;
790 
791 		if( config.random_start_up )
792 			initPop = 25 + misc.random(26);		// 25 to 50
793 		else
794 			initPop = 40;
795 
796 		Town* townPtr = town_array[townRecno];
797 
798 		townPtr->init_pop( raceId, initPop, 100, 0, 1 );		// 100-startup loyalty, last 1-first initialization at the beginning of the game
799 	}
800 	else
801 	{
802 		int mixedRaceCount;
803 
804 		if( nationRecno )
805 			mixedRaceCount = 1;
806 		else
807 			mixedRaceCount= misc.random(3)+1;		// 1 to 3 mixed races
808 
809 		int curPop, totalPop=0, townResistance;
810 
811 		for( int i=0 ; i<mixedRaceCount ; i++ )
812 		{
813 			if(totalPop>=MAX_TOWN_POPULATION)
814 				break;
815 
816 			townResistance = town_array.independent_town_resistance();
817 
818 			if( i==0 )
819 			{
820 				curPop = 15/mixedRaceCount + misc.random(15/mixedRaceCount);
821 				if(curPop>=MAX_TOWN_POPULATION)
822 					curPop = MAX_TOWN_POPULATION;
823 
824 				err_when(curPop==0);
825 				townPtr->init_pop( raceId, curPop, townResistance, 0, 1 ); 	// last 1-first initialization at the beginning of the game
826 				totalPop += curPop;
827 			}
828 			else
829 			{
830 				curPop = 10/mixedRaceCount + misc.random(10/mixedRaceCount);
831 				if(curPop>=MAX_TOWN_POPULATION-totalPop)
832 					curPop = MAX_TOWN_POPULATION-totalPop;
833 
834 				err_when(curPop==0);
835 				townPtr->init_pop( random_race(), curPop, townResistance, 0, 1 );
836 				totalPop += curPop;
837 			}
838 		}
839 	}
840 
841 	//---------- set town layout -----------//
842 
843 	townPtr->auto_set_layout();
844 
845 	return townRecno;
846 }
847 //--------- End of function Battle::create_town ---------//
848 
849 
850 //-------- Begin of function Battle::create_unit --------//
851 //
852 // Add a specific no. of units within a given area
853 //
854 // <int> townRecno   - create units around this town.
855 // <int> unitId      - id. of the units to be added
856 // <int> rankId      - rank id. of the unit
857 //
858 // return: <int> recno of the unit created.
859 //
create_unit(int townRecno,int unitId,int rankId)860 int Battle::create_unit(int townRecno, int unitId, int rankId)
861 {
862 	SpriteInfo* spriteInfo = sprite_res[ unit_res[unitId]->sprite_id ];
863 	Town* 		townPtr = town_array[townRecno];
864 
865 	//------ locate space for the unit ------//
866 
867 	int xLoc = townPtr->loc_x1;
868 	int yLoc = townPtr->loc_y1;
869 
870 	if( !world.locate_space( &xLoc, &yLoc, xLoc+STD_TOWN_LOC_WIDTH-1, yLoc+STD_TOWN_LOC_HEIGHT-1,
871 									 spriteInfo->loc_width, spriteInfo->loc_height ) )
872 	{
873 		return 0;
874 	}
875 
876 	//---------- create the unit --------//
877 
878 	int unitLoyalty = 80 + misc.random(20);
879 
880 	int unitRecno = unit_array.add_unit( unitId, townPtr->nation_recno, rankId, unitLoyalty, xLoc, yLoc );
881 
882 	if( !unitRecno )
883 		return 0;
884 
885 	Unit* unitPtr = unit_array[unitRecno];
886 
887 	//----------- set skill -------------//
888 
889 	switch( rankId )
890 	{
891 		case RANK_KING:
892 			unitPtr->skill.set_skill(SKILL_LEADING);
893 			unitPtr->skill.skill_level = 100;
894 			unitPtr->set_combat_level(100);
895 			break;
896 
897 		case RANK_GENERAL:
898 			unitPtr->skill.set_skill(SKILL_LEADING);
899 			unitPtr->skill.skill_level = 40 + misc.random(50);		// 40 to 90
900 			unitPtr->set_combat_level(30 + misc.random(70));		// 30 to 100
901 			break;
902 
903 		case RANK_SOLDIER:
904 		{
905 			int skillId = misc.random(MAX_TRAINABLE_SKILL)+1;
906 			int spyFlag = 0;
907 
908 			if( skillId == SKILL_SPYING )
909 			{
910 				spyFlag = 1;
911 
912 				unitPtr->set_combat_level(10+misc.random(10));
913 			}
914 			else
915 			{
916 				unitPtr->skill.skill_id 	= skillId;
917 				unitPtr->skill.skill_level = 30+misc.random(70);
918 
919 				if( skillId == SKILL_LEADING )
920 					unitPtr->set_combat_level(30+misc.random(70));
921 				else
922 					unitPtr->set_combat_level(10+misc.random(10));
923 
924 				if( misc.random(5)==0 )
925 					spyFlag = 1;
926 			}
927 
928 			if( spyFlag )
929 			{
930 				int spySkill = 20 + misc.random(80);		// 20 to 100
931 				unitPtr->spy_recno = spy_array.add_spy(unitRecno, spySkill);
932 			}
933 
934 			break;
935 		}
936 
937 		default:
938 			err_here();
939 	}
940 
941 	return unitRecno;
942 }
943 //--------- End of function Battle::create_unit ---------//
944 
945 
946 //-------- Begin of static function is_space --------//
947 //
948 // Check whether all locations in the given area are space
949 //
950 // return : <int> 1 - all are space
951 //                0 - not all are space
952 //
is_space(int xLoc1,int yLoc1,int xLoc2,int yLoc2,char mobileType)953 static int is_space(int xLoc1, int yLoc1, int xLoc2, int yLoc2, char mobileType)
954 {
955    int       xLoc, yLoc;
956    Location* locPtr;
957 
958    for( yLoc=yLoc1 ; yLoc<=yLoc2 ; yLoc++ )
959    {
960       locPtr = world.get_loc(xLoc1, yLoc);
961 
962       for( xLoc=xLoc1 ; xLoc<=xLoc2 ; xLoc++, locPtr++ )
963       {
964 			if( !locPtr->can_move(mobileType) )
965 				return 0;
966       }
967    }
968 
969    return 1;
970 }
971 //--------- End of static function is_space ---------//
972 
973 
974 //-------- Begin of static function random_race --------//
975 //
976 // Uses misc.random() for random race
977 //
random_race()978 static char random_race()
979 {
980 	int num = misc.random(config_adv.race_random_list_max);
981 	return config_adv.race_random_list[num];
982 }
983 //--------- End of static function random_race ---------//
984 
985 
986 //-------- Begin of static function random_race_time --------//
987 //
988 // Uses current time for random race
989 //
random_race_time()990 static char random_race_time()
991 {
992 	int num = misc.get_time();
993 	return config_adv.race_random_list[num%config_adv.race_random_list_max];
994 }
995 //--------- End of static function random_race_time ---------//
996