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    : OUNITRES.CPP
22 //Description : Object Sprite Frame Resource
23 
24 #include <ALL.h>
25 #include <OSTR.h>
26 #include <OSYS.h>
27 #include <OGAMESET.h>
28 #include <ONATION.h>
29 #include <OSPRTRES.h>
30 #include <OUNITRES.h>
31 #include "gettext.h"
32 
33 #ifdef NO_DEBUG_UNIT
34 #undef err_when
35 #undef err_here
36 #undef err_if
37 #undef err_else
38 #undef err_now
39 #define err_when(cond)
40 #define err_here()
41 #define err_if(cond)
42 #define err_else
43 #define err_now(msg)
44 #undef DEBUG
45 #endif
46 
47 //-------- define file name -----------//
48 
49 #define UNIT_DB    		  "UNIT"
50 #define UNIT_ATTACK_DB    "UNITATTK"
51 
52 //-------- Begin of function UnitRes::init ---------//
53 
init()54 void UnitRes::init()
55 {
56 	deinit();
57 
58 	//----- open unit bitmap resource file -------//
59 
60 	String str;
61 
62 	str  = DIR_RES;
63 	str += "I_UNITLI.RES";
64 
65 	res_large_icon.init_imported(str, 1);  // 1-don't read all into buffer
66 
67 	str  = DIR_RES;
68 	str += "I_UNITGI.RES";
69 
70 	res_general_icon.init_imported(str, 1);  // 1-don't read all into buffer
71 
72 	str  = DIR_RES;
73 	str += "I_UNITKI.RES";
74 
75 	res_king_icon.init_imported(str, 1);  // 1-don't read all into buffer
76 
77 	str  = DIR_RES;
78 	str += "I_UNITSI.RES";
79 
80 	res_small_icon.init_imported(str, 1);  // 1-don't read all into buffer
81 
82 	// ######## begin Gilbert 17/10 ##########//
83 	str  = DIR_RES;
84 	str += "I_UNITTI.RES";
85 
86 	res_general_small_icon.init_imported(str, 1);  // 1-don't read all into buffer
87 
88 	str  = DIR_RES;
89 	str += "I_UNITUI.RES";
90 
91 	res_king_small_icon.init_imported(str, 1);  // 1-don't read all into buffer
92 	// ######## end Gilbert 17/10 ##########//
93 
94 	//------- load database information --------//
95 
96 	load_info();
97 	load_attack_info();
98 
99 	//---------- set vars -----------//
100 
101 	mobile_monster_count = 0;
102 
103 	init_flag=1;
104 }
105 //--------- End of function UnitRes::init ----------//
106 
107 
108 //-------- Begin of function UnitRes::deinit ---------//
109 
deinit()110 void UnitRes::deinit()
111 {
112 	if( init_flag )
113 	{
114 		mem_del(unit_info_array);
115 		mem_del(attack_info_array);
116 
117 		res_large_icon.deinit();
118 		res_general_icon.deinit();
119 		res_king_icon.deinit();
120 		res_small_icon.deinit();
121 		// ######## begin Gilbert 17/10 ##########//
122 		res_general_small_icon.deinit();
123 		res_king_small_icon.deinit();
124 		// ######## end Gilbert 17/10 ##########//
125 
126 		init_flag=0;
127 	}
128 }
129 //--------- End of function UnitRes::deinit ----------//
130 
131 
132 //------- Begin of function UnitRes::load_info ---------//
133 
load_info()134 void UnitRes::load_info()
135 {
136 	Database  *dbUnit = game_set.open_db(UNIT_DB);
137 	UnitRec 	 *unitRec;
138 	UnitInfo  *unitInfo;
139 	uint32_t	  bitmapOffset;
140 	int		 i;
141 
142 	unit_info_count = dbUnit->rec_count();
143 	unit_info_array = (UnitInfo*) mem_add(sizeof(UnitInfo) * unit_info_count);
144 
145 	memset( unit_info_array, 0, sizeof(UnitInfo)*unit_info_count );
146 
147 	//--------- read in frame information ---------//
148 
149 	for( i=0 ; i<dbUnit->rec_count() ; i++ )
150 	{
151 		unitRec  = (UnitRec*) dbUnit->read(i+1);
152 		unitInfo = unit_info_array+i;
153 
154 		misc.rtrim_fld( unitInfo->name, unitRec->name, unitRec->NAME_LEN );
155 
156 		unitInfo->unit_id 	   = i+1;
157 		unitInfo->sprite_id = misc.atoi(unitRec->sprite_id, unitRec->SPRITE_ID_LEN);
158 		unitInfo->dll_sprite_id	= misc.atoi(unitRec->dll_sprite_id, unitRec->SPRITE_ID_LEN);
159 		unitInfo->race_id = misc.atoi(unitRec->race_id, unitRec->RACE_ID_LEN);
160 
161 		unitInfo->unit_class 	= unitRec->unit_class[0];
162 		unitInfo->mobile_type   = unitRec->mobile_type;
163 
164 		unitInfo->visual_range = misc.atoi(unitRec->visual_range, unitRec->UNIT_PARA_LEN);
165 		unitInfo->visual_extend = misc.atoi(unitRec->visual_extend, unitRec->UNIT_PARA_LEN);
166 		unitInfo->shealth = misc.atoi(unitRec->shealth, unitRec->UNIT_PARA_LEN);
167 		unitInfo->hit_points = misc.atoi(unitRec->hit_points, unitRec->UNIT_PARA_LEN);
168 		unitInfo->armor = misc.atoi(unitRec->armor, unitRec->UNIT_PARA_LEN);
169 
170 		unitInfo->build_days = misc.atoi(unitRec->build_days, unitRec->BUILD_DAYS_LEN);
171 		unitInfo->year_cost = misc.atoi(unitRec->year_cost, unitRec->YEAR_COST_LEN);
172 		unitInfo->build_cost    = unitInfo->year_cost;
173 
174 		if( unitInfo->unit_class == UNIT_CLASS_WEAPON )
175 			unitInfo->weapon_power = unitRec->weapon_power-'0';
176 
177 		unitInfo->carry_unit_capacity = misc.atoi(unitRec->carry_unit_capacity, unitRec->CARRY_CAPACITY_LEN);
178 		unitInfo->carry_goods_capacity = misc.atoi(unitRec->carry_goods_capacity, unitRec->CARRY_CAPACITY_LEN);
179 		unitInfo->free_weapon_count 	 = misc.atoi(unitRec->free_weapon_count, unitRec->FREE_WEAPON_COUNT_LEN);
180 
181 		unitInfo->vehicle_id = misc.atoi(unitRec->vehicle_id, unitRec->SPRITE_ID_LEN);
182 		unitInfo->vehicle_unit_id = misc.atoi(unitRec->vehicle_unit_id, unitRec->SPRITE_ID_LEN);
183 
184 		unitInfo->transform_unit_id = misc.atoi(unitRec->transform_unit_id, unitRec->SPRITE_ID_LEN);
185 		unitInfo->transform_combat_level = misc.atoi(unitRec->transform_combat_level, unitRec->UNIT_PARA_LEN);
186 		unitInfo->guard_combat_level = misc.atoi(unitRec->guard_combat_level, unitRec->UNIT_PARA_LEN);
187 
188 		memcpy( &bitmapOffset, unitRec->large_icon_ptr, sizeof(uint32_t) );
189 		unitInfo->soldier_icon_ptr = res_large_icon.read_imported(bitmapOffset);
190 
191 		if( unitRec->general_icon_file_name[0] != '\0' && unitRec->general_icon_file_name[0] != ' ')
192 		{
193 			memcpy( &bitmapOffset, unitRec->general_icon_ptr, sizeof(uint32_t) );
194 			unitInfo->general_icon_ptr = res_general_icon.read_imported(bitmapOffset);
195 		}
196 		else
197 		{
198 			unitInfo->general_icon_ptr = unitInfo->soldier_icon_ptr;
199 		}
200 
201 		if( unitRec->king_icon_file_name[0] != '\0' && unitRec->king_icon_file_name[0] != ' ')
202 		{
203 			memcpy( &bitmapOffset, unitRec->king_icon_ptr, sizeof(uint32_t) );
204 			unitInfo->king_icon_ptr = res_king_icon.read_imported(bitmapOffset);
205 		}
206 		else
207 		{
208 			unitInfo->king_icon_ptr = unitInfo->soldier_icon_ptr;
209 		}
210 
211 		// ###### begin Gilbert 17/10 ######//
212 		memcpy( &bitmapOffset, unitRec->small_icon_ptr, sizeof(uint32_t) );
213 		unitInfo->soldier_small_icon_ptr = res_small_icon.read_imported(bitmapOffset);
214 
215 		if( unitRec->general_small_icon_file_name[0] != '\0' && unitRec->general_small_icon_file_name[0] != ' ')
216 		{
217 			memcpy( &bitmapOffset, unitRec->general_small_icon_ptr, sizeof(uint32_t) );
218 			unitInfo->general_small_icon_ptr = res_general_small_icon.read_imported(bitmapOffset);
219 		}
220 		else
221 		{
222 			unitInfo->general_small_icon_ptr = unitInfo->soldier_small_icon_ptr;
223 		}
224 
225 		if( unitRec->king_small_icon_file_name[0] != '\0' && unitRec->king_small_icon_file_name[0] != ' ')
226 		{
227 			memcpy( &bitmapOffset, unitRec->king_small_icon_ptr, sizeof(uint32_t) );
228 			unitInfo->king_small_icon_ptr = res_king_small_icon.read_imported(bitmapOffset);
229 		}
230 		else
231 		{
232 			unitInfo->king_small_icon_ptr = unitInfo->soldier_small_icon_ptr;
233 		}
234 		// ###### end Gilbert 17/10 ######//
235 
236 		unitInfo->first_attack = misc.atoi(unitRec->first_attack, unitRec->UNIT_PARA_LEN);
237 		unitInfo->attack_count = misc.atoi(unitRec->attack_count, unitRec->UNIT_PARA_LEN);
238 		unitInfo->die_effect_id = misc.atoi(unitRec->die_effect_id, unitRec->UNIT_PARA_LEN);
239 
240 		if( unitRec->all_know=='1' )
241 			memset( unitInfo->nation_tech_level_array, 1, sizeof(unitInfo->nation_tech_level_array) );
242 	}
243 
244 	//--------- set vehicle info  ---------//
245 
246 	for( i=0 ; i<unit_info_count ; i++ )
247 	{
248 		unitInfo = unit_info_array+i;
249 
250 		if( unitInfo->vehicle_unit_id )
251 		{
252 			unit_info_array[ unitInfo->vehicle_unit_id-1 ].vehicle_id = unitInfo->vehicle_id;
253 			unit_info_array[ unitInfo->vehicle_unit_id-1 ].solider_id = i+1;
254 		}
255 	}
256 }
257 //-------- End of function UnitRes::load_info ---------//
258 
259 
260 //------- Begin of function UnitRes::load_attack_info ---------//
261 
load_attack_info()262 void UnitRes::load_attack_info()
263 {
264 	Database  		 *dbUnitAttack = game_set.open_db(UNIT_ATTACK_DB);
265 	UnitAttackRec 	 *attackRec;
266 	AttackInfo  	 *attackInfo;
267 	int		 		 i;
268 
269 	attack_info_count = dbUnitAttack->rec_count();
270 	attack_info_array = (AttackInfo*) mem_add(sizeof(AttackInfo) * attack_info_count);
271 
272 	memset( attack_info_array, 0, sizeof(AttackInfo)*attack_info_count );
273 
274 	//--------- read in frame information ---------//
275 
276 	for( i=0 ; i<dbUnitAttack->rec_count() ; i++ )
277 	{
278 		attackRec  = (UnitAttackRec*) dbUnitAttack->read(i+1);
279 		attackInfo = attack_info_array+i;
280 
281 		attackInfo->combat_level = misc.atoi(attackRec->combat_level, attackRec->COMBAT_LEVEL_LEN);
282 		attackInfo->attack_delay = misc.atoi(attackRec->attack_delay, attackRec->UNIT_PARA_LEN);
283 		attackInfo->attack_range = misc.atoi(attackRec->attack_range, attackRec->UNIT_PARA_LEN);
284 		attackInfo->attack_damage = misc.atoi(attackRec->attack_damage, attackRec->UNIT_PARA_LEN);
285 		attackInfo->pierce_damage = misc.atoi(attackRec->pierce_damage, attackRec->UNIT_PARA_LEN);
286 		attackInfo->bullet_out_frame = misc.atoi(attackRec->bullet_out_frame, attackRec->UNIT_PARA_LEN);
287 		attackInfo->bullet_speed = misc.atoi(attackRec->bullet_speed, attackRec->UNIT_PARA_LEN);
288 		attackInfo->bullet_radius = misc.atoi(attackRec->bullet_radius, attackRec->UNIT_PARA_LEN);
289 		attackInfo->bullet_sprite_id = misc.atoi(attackRec->bullet_sprite_id, attackRec->UNIT_PARA_LEN);
290 		attackInfo->dll_bullet_sprite_id = misc.atoi(attackRec->dll_bullet_sprite_id, attackRec->UNIT_PARA_LEN);
291 		attackInfo->eqv_attack_next = misc.atoi(attackRec->eqv_attack_next, attackRec->UNIT_PARA_LEN);
292 		attackInfo->min_power = misc.atoi(attackRec->min_power, attackRec->UNIT_PARA_LEN);
293 		attackInfo->consume_power = misc.atoi(attackRec->consume_power, attackRec->UNIT_PARA_LEN);
294 		attackInfo->fire_radius = misc.atoi(attackRec->fire_radius, attackRec->UNIT_PARA_LEN);
295 		attackInfo->effect_id = misc.atoi(attackRec->effect_id, attackRec->UNIT_PARA_LEN);
296 	}
297 }
298 //-------- End of function UnitRes::load_attack_info ---------//
299 
300 
301 //-------- Begin of function UnitRes::mobile_type_to_mask --------//
302 
mobile_type_to_mask(int mobileType)303 char UnitRes::mobile_type_to_mask(int mobileType)
304 {
305 	switch( mobileType)
306 	{
307 		case UNIT_LAND:
308 			return 1;
309 
310 		case UNIT_SEA:
311 			return 2;
312 
313 		case UNIT_AIR:
314 			return 3;
315 
316 		default:
317 			err_here();
318 			return 0;
319 	}
320 }
321 //-------- End of function UnitRes::mobile_type_to_mask --------//
322 
323 
324 //-------- Begin of function UnitInfo::is_loaded -------//
325 
is_loaded()326 int UnitInfo::is_loaded()
327 {
328 	return sprite_res[sprite_id]->is_loaded();
329 }
330 //--------- End of function UnitInfo::is_loaded --------//
331 
332 
333 //---- Begin of function UnitInfo::inc_nation_unit_count ----//
334 
inc_nation_unit_count(int nationRecno)335 void UnitInfo::inc_nation_unit_count(int nationRecno)
336 {
337 	err_when( nationRecno<1 || nationRecno>nation_array.size() );
338 
339 	nation_unit_count_array[nationRecno-1]++;
340 
341 	//------- increase the nation's unit count ---------//
342 
343 	Nation* nationPtr = nation_array[nationRecno];
344 
345 	nationPtr->total_unit_count++;
346 
347 	if( unit_class==UNIT_CLASS_WEAPON )
348 	{
349 		nationPtr->total_weapon_count++;
350 	}
351 	else if( unit_class==UNIT_CLASS_SHIP )
352 	{
353 		nationPtr->total_ship_count++;
354 	}
355 	else if( race_id )
356 	{
357 		nationPtr->total_human_count++;
358 	}
359 }
360 //----- End of function UnitInfo::inc_nation_unit_count -----//
361 
362 
363 //---- Begin of function UnitInfo::dec_nation_unit_count ----//
364 
dec_nation_unit_count(int nationRecno)365 void UnitInfo::dec_nation_unit_count(int nationRecno)
366 {
367 	err_when( nationRecno<0 || nationRecno>MAX_NATION );
368 
369 	if( nationRecno )
370 	{
371 		nation_unit_count_array[nationRecno-1]--;
372 
373 		err_when( nation_unit_count_array[nationRecno-1] < 0 );
374 
375 		//------ decrease the nation's unit count -------//
376 
377 		Nation* nationPtr = nation_array[nationRecno];
378 
379 		nationPtr->total_unit_count--;
380 
381 		err_when( nationPtr->total_unit_count < 0 );
382 
383 		if( unit_class==UNIT_CLASS_WEAPON )
384 		{
385 			nationPtr->total_weapon_count--;
386 
387 			err_when( nationPtr->total_weapon_count < 0 );
388 		}
389 		else if( unit_class==UNIT_CLASS_SHIP )
390 		{
391 			nationPtr->total_ship_count--;
392 
393 			err_when( nationPtr->total_ship_count < 0 );
394 		}
395 		else if( race_id )
396 		{
397 			nationPtr->total_human_count--;
398 
399 			err_when( nationPtr->total_human_count < 0 );
400 
401 			if( nationPtr->total_human_count < 0 )
402 				nationPtr->total_human_count = 0;
403 		}
404 	}
405 }
406 //----- End of function UnitInfo::dec_nation_unit_count -----//
407 
408 
409 //---- Begin of function UnitInfo::inc_nation_general_count ----//
410 
inc_nation_general_count(int nationRecno)411 void UnitInfo::inc_nation_general_count(int nationRecno)
412 {
413 	err_when( nationRecno<1 || nationRecno>nation_array.size() );
414 
415 	nation_general_count_array[nationRecno-1]++;
416 
417 	nation_array[nationRecno]->total_general_count++;
418 }
419 //----- End of function UnitInfo::inc_nation_general_count -----//
420 
421 
422 //---- Begin of function UnitInfo::dec_nation_general_count ----//
423 
dec_nation_general_count(int nationRecno)424 void UnitInfo::dec_nation_general_count(int nationRecno)
425 {
426 	err_when( nationRecno<0 || nationRecno>MAX_NATION );
427 
428 	if( nationRecno )
429 	{
430 		nation_general_count_array[nationRecno-1]--;
431 
432 		nation_array[nationRecno]->total_general_count--;
433 
434 		err_when( nation_general_count_array[nationRecno-1] < 0 );
435 	}
436 }
437 //----- End of function UnitInfo::dec_nation_general_count -----//
438 
439 
440 //-------- Begin of function UnitInfo::unit_change_nation -------//
441 //
442 // Call this function when a unit changes its nation. This
443 // function updates the unit count vars in the UnitInfo.
444 //
445 // <int> newNationRecno - the new nation recno
446 // <int> oldNationRecno - the original nation recno
447 // <int> rankId			- the rank of the unit.
448 //
unit_change_nation(int newNationRecno,int oldNationRecno,int rankId)449 void UnitInfo::unit_change_nation(int newNationRecno, int oldNationRecno, int rankId)
450 {
451 	//---- update nation_unit_count_array[] ----//
452 
453 	if( oldNationRecno )
454 	{
455 		if( rankId != RANK_KING )
456 			dec_nation_unit_count(oldNationRecno);
457 
458 		if( rankId == RANK_GENERAL )
459 			dec_nation_general_count(oldNationRecno);
460 	}
461 
462 	if( newNationRecno )
463 	{
464 		if( rankId != RANK_KING )
465 			inc_nation_unit_count(newNationRecno);
466 
467 		if( rankId == RANK_GENERAL )		// if the new rank is general
468 			inc_nation_general_count(newNationRecno);
469 	}
470 }
471 //--------- End of function UnitInfo::unit_change_nation --------//
472 
473 #ifdef DYNARRAY_DEBUG_ELEMENT_ACCESS
474 
475 //-------- Begin of function UnitRes::get_attack_info -------//
476 
get_attack_info(int attackId)477 AttackInfo* UnitRes::get_attack_info(int attackId)
478 {
479 	if( attackId<1 || attackId>attack_info_count )
480 		err.run( "UnitRes::get_attack_info[]" );
481 
482 	return attack_info_array+attackId-1;
483 }
484 
485 //--------- End of function UnitRes::get_attack_info --------//
486 
487 
488 //-------- Begin of function UnitRes::operator[] -------//
489 
operator [](int unitId)490 UnitInfo* UnitRes::operator[](int unitId)
491 {
492 	if( unitId<1 || unitId>unit_info_count )
493 		err.run( "UnitRes::operator[]" );
494 
495 	return unit_info_array+unitId-1;
496 }
497 
498 //--------- End of function UnitRes::operator[] --------//
499 
500 #endif
501 
502 //-------- Begin of function UnitInfo::get_large_icon_ptr -------//
503 
get_large_icon_ptr(char rankId)504 char *UnitInfo::get_large_icon_ptr(char rankId)
505 {
506 	switch( rankId )
507 	{
508 	case RANK_KING:
509 		return king_icon_ptr;
510 	case RANK_GENERAL:
511 		return general_icon_ptr;
512 	case RANK_SOLDIER:
513 	default:
514 		return soldier_icon_ptr;
515 	}
516 }
517 //-------- End of function UnitInfo::get_large_icon_ptr -------//
518 
519 // ##### begin Gilbert 17/10 ########//
520 // -------- Begin of function UnitInfo::get_small_icon_ptr --------//
get_small_icon_ptr(char rankId)521 char *UnitInfo::get_small_icon_ptr(char rankId)
522 {
523 	switch( rankId )
524 	{
525 	case RANK_KING:
526 		return king_small_icon_ptr;
527 	case RANK_GENERAL:
528 		return general_small_icon_ptr;
529 	case RANK_SOLDIER:
530 	default:
531 		return soldier_small_icon_ptr;
532 	}
533 }
534 // -------- End of function UnitInfo::get_small_icon_ptr --------//
535 // ##### end Gilbert 17/10 ########//
536