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