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    : OUNITAT.CPP
22 //Description : Object Unit attack supporting functions
23 //Owner		  : Alex
24 
25 #include <ALL.h>
26 #include <ONEWS.h>
27 #include <OWORLD.h>
28 #include <ONATION.h>
29 #include <OU_MARI.h>
30 #include <OSPY.h>
31 #include <OGAME.h>
32 #include <OTOWN.h>
33 #include <OF_CAMP.h>
34 #include <OF_MONS.h>
35 #include <OEFFECT.h>
36 #include <OMONSRES.h>
37 #include <OREBEL.h>
38 #include <OSERES.h>
39 #include <OSYS.h>
40 #include <OWARPT.h>
41 
42 #ifdef NO_DEBUG_UNIT
43 #undef err_when
44 #undef err_here
45 #undef err_if
46 #undef err_else
47 #undef err_now
48 #define err_when(cond)
49 #define err_here()
50 #define err_if(cond)
51 #define err_else
52 #define err_now(msg)
53 #undef DEBUG
54 #endif
55 
56 //----------------- Begin of function Unit::update_attack_path_dist -----------------//
57 // return 1 if it is time to update result path
58 // return 0 otherwise
59 //
update_attack_path_dist()60 int Unit::update_attack_path_dist()
61 {
62 	if(result_path_dist<=6)	//1-6
63 	{
64 		return 1;
65 	}
66 	else if(result_path_dist<=10) // 8, 10
67 	{
68 		return !((result_path_dist-6)%2);
69 	}
70 	else if(result_path_dist<=20) // 15, 20
71 	{
72 		return !((result_path_dist-10)%5);
73 	}
74 	else if(result_path_dist<=60) // 28, 36, 44, 52, 60
75 	{
76 		return !((result_path_dist-20)%8);
77 	}
78 	else if(result_path_dist<=90) // 75, 90
79 	{
80 		return !((result_path_dist-60)%15);
81 	}
82 	else // 110, 130, 150, etc
83 	{
84 		return !((result_path_dist-90)%20);
85 	}
86 
87 	err_here();
88 	return 0;
89 }
90 //---------- End of function Unit::update_attack_path_dist ----------//
91 
92 //##### begin trevor 15/8 #######//
93 
94 //----------------- Begin of function Unit::hit_target -----------------//
95 //	The function can be called in by class Bullet since parent and target
96 //	are specified.
97 //
98 // <Unit*>  parentUnit is the unit attacking
99 // <Unit*>  targetUnit is the unit being attacked
100 // <int>    attackDamage is the damage done to the target Unit
101 // <short>  parentNationRecno - the nation that ordered the hit
102 //
103 // ****************************** Warning ***********************************
104 // don't use any member variables of this unit. This unit may not be involved
105 // in the attack event
106 // **************************************************************************
107 //
hit_target(Unit * parentUnit,Unit * targetUnit,float attackDamage,short parentNationRecno)108 void Unit::hit_target(Unit* parentUnit, Unit* targetUnit, float attackDamage, short parentNationRecno)
109 {
110 	short	targetNationRecno = targetUnit->nation_recno;
111 
112 	//------------------------------------------------------------//
113 	// if the attacked unit is in defense mode, order other available
114 	// unit in the same camp to help this unit
115 	// Note : checking for nation_recno since one unit can attack units
116 	//			 in same nation by bullet accidentally
117 	//------------------------------------------------------------//
118 	if(parentUnit && parentUnit->cur_action!=SPRITE_DIE && parentUnit->is_visible() &&
119 		parentNationRecno!=targetNationRecno && parentUnit->nation_can_attack(targetNationRecno) &&
120 		targetUnit->in_auto_defense_mode())
121 	{
122 		err_when(targetUnit->action_misc!=ACTION_MISC_DEFENSE_CAMP_RECNO || !targetUnit->action_misc_para);
123 		if(!firm_array.is_deleted(targetUnit->action_misc_para))
124 		{
125 			Firm *firmPtr = firm_array[targetUnit->action_misc_para];
126 			if(firmPtr->firm_id==FIRM_CAMP)
127 			{
128 				err_when(firmPtr->firm_id!=FIRM_CAMP);
129 				FirmCamp *campPtr = firmPtr->cast_to_FirmCamp();
130 				campPtr->defense(parentUnit->sprite_recno);
131 			}
132 		}
133 		else
134 			targetUnit->clear_unit_defense_mode();
135 	}
136 
137 	// ---------- add indicator on the map ----------//
138 	if( nation_array.player_recno && targetUnit->is_own() )
139 		war_point_array.add_point(targetUnit->next_x_loc(),targetUnit->next_y_loc());
140 
141 	//-----------------------------------------------------------------------//
142 	// decrease the hit points of the target Unit
143 	//-----------------------------------------------------------------------//
144 	#define DEFAULT_ARMOR		4
145 	#define DEFAULT_ARMOR_OVER_ATTACK_SLOW_DOWN	(float) DEFAULT_ARMOR / ATTACK_SLOW_DOWN
146 	#define ONE_OVER_ATTACK_SLOW_DOWN				(float) 1/ATTACK_SLOW_DOWN
147 	#define COMPARE_POINT								DEFAULT_ARMOR_OVER_ATTACK_SLOW_DOWN + ONE_OVER_ATTACK_SLOW_DOWN
148 
149 	//-*********** simulate aat ************-//
150 #ifdef DEBUG
151 		if(!debug_sim_game_type)
152 		{
153 #endif
154 			if( attackDamage >= COMPARE_POINT )
155 				targetUnit->hit_points -= attackDamage - DEFAULT_ARMOR_OVER_ATTACK_SLOW_DOWN;
156 			else
157 				targetUnit->hit_points -= MIN(attackDamage,ONE_OVER_ATTACK_SLOW_DOWN);  // in case attackDamage = 0, no hit_point is reduced
158 #ifdef DEBUG
159 		}
160 #endif
161 	//-*********** simulate aat ************-//
162 
163 	Nation *parentNationPtr = parentNationRecno ? nation_array[parentNationRecno] : NULL;
164 	Nation *targetNationPtr = targetNationRecno ? nation_array[targetNationRecno] : NULL;
165 	char targetUnitClass = unit_res[targetUnit->unit_id]->unit_class;
166 
167 	if( targetUnit->hit_points <= 0 )
168 	{
169 		targetUnit->hit_points = (float) 0;
170 
171 		//---- if the unit killed is a human unit -----//
172 
173 		if( targetUnit->race_id )
174 		{
175 			//---- if the unit killed is a town defender unit -----//
176 
177 			if( targetUnit->is_civilian() && targetUnit->in_defend_town_mode() )
178 			{
179 				if( targetNationRecno )
180 				{
181 					targetNationPtr->civilian_killed(targetUnit->race_id, 0);
182 					targetNationPtr->own_civilian_killed++;
183 				}
184 
185 				if( parentNationPtr )
186 				{
187 					parentNationPtr->civilian_killed(targetUnit->race_id, 1);
188 					parentNationPtr->enemy_civilian_killed++;
189 				}
190 			}
191 			else if( targetUnit->is_civilian() && targetUnit->skill.combat_level<20 ) //--- mobile civilian ---//
192 			{
193 				if( targetNationRecno )
194 				{
195 					targetNationPtr->civilian_killed(targetUnit->race_id, 0);
196 					targetNationPtr->own_civilian_killed++;
197 				}
198 
199 				if( parentNationPtr )
200 				{
201 					parentNationPtr->civilian_killed(targetUnit->race_id, 0);
202 					parentNationPtr->enemy_civilian_killed++;
203 				}
204 			}
205 			else	//---- if the unit killed is a soldier -----//
206 			{
207 				if( targetNationRecno )
208 					targetNationPtr->own_soldier_killed++;
209 
210 				if( parentNationPtr )
211 					parentNationPtr->enemy_soldier_killed++;
212 			}
213 		}
214 
215 		//--------- if it's a non-human unit ---------//
216 
217 		else
218 		{
219 			switch( unit_res[targetUnit->unit_id]->unit_class )
220 			{
221 				case UNIT_CLASS_WEAPON:
222 					if( parentNationPtr )
223 						parentNationPtr->enemy_weapon_destroyed++;
224 
225 					if( targetNationRecno )
226 						targetNationPtr->own_weapon_destroyed++;
227 					break;
228 
229 
230 				case UNIT_CLASS_SHIP:
231 					if( parentNationPtr )
232 						parentNationPtr->enemy_ship_destroyed++;
233 
234 					if( targetNationRecno )
235 						targetNationPtr->own_ship_destroyed++;
236 					break;
237 			}
238 
239 			//---- if the unit destroyed is a trader or caravan -----//
240 
241 			if( targetUnit->unit_id == UNIT_CARAVAN ||	// killing a caravan is resented by all races
242 				 targetUnit->unit_id == UNIT_VESSEL )
243 			{
244 				// Race-Id of 0 means a loyalty penalty applied for all races
245 				if( targetNationRecno )
246 					targetNationPtr->civilian_killed(0, -1);
247 
248 				if( parentNationPtr )
249 					parentNationPtr->civilian_killed(0, 3);
250 			}
251 		}
252 
253 		return;
254 	}
255 
256 	if(parentUnit!=NULL && parentNationRecno!=targetNationRecno)
257 		parentUnit->gain_experience(); // gain experience to increase combat level
258 
259 	//-----------------------------------------------------------------------//
260 	// action of the target to take
261 	//-----------------------------------------------------------------------//
262 	if( !parentUnit )	// do nothing if parent is dead
263 		return;
264 
265 	if( parentUnit->cur_action==SPRITE_DIE ) // skip for explosive cart
266 	{
267 		err_when(parentUnit->unit_id!=UNIT_EXPLOSIVE_CART);
268 		return;
269 	}
270 
271 	if( targetNationRecno == parentNationRecno )	// the target and the attacker's nations are different (it's possible that when a unit who has just changed nation has its bullet hitting its own nation)
272 		return;
273 
274 	//------- two nations at war ---------//
275 
276 	if( parentNationPtr && targetNationRecno )
277 	{
278 		parentNationPtr->set_at_war_today();
279 		targetNationPtr->set_at_war_today(parentUnit->sprite_recno);
280 	}
281 
282 	//-------- increase battling fryhtan score --------//
283 
284 	if( parentNationPtr && targetUnitClass==UNIT_CLASS_MONSTER )
285 	{
286 		parentNationPtr->kill_monster_score += (float) 0.1;
287 	}
288 
289 	//------ call target unit being attack functions -------//
290 
291 	if( targetNationRecno )
292 	{
293 		targetNationPtr->being_attacked(parentNationRecno);
294 
295 		if( targetUnit->ai_unit )
296 		{
297 			if( targetUnit->rank_id >= RANK_GENERAL )
298 				targetUnit->ai_leader_being_attacked(parentUnit->sprite_recno);
299 
300 			if( unit_res[targetUnit->unit_id]->unit_class == UNIT_CLASS_SHIP )
301 				((UnitMarine*)targetUnit)->ai_ship_being_attacked(parentUnit->sprite_recno);
302 		}
303 
304 		//--- if a member in a troop is under attack, ask for other troop members to help ---//
305 
306 		if( info.game_date%2 == sprite_recno%2 )
307 		{
308 			if( targetUnit->leader_unit_recno ||
309 				 (targetUnit->team_info && targetUnit->team_info->member_count > 1) )
310 			{
311 				if( !unit_array.is_deleted(parentUnit->sprite_recno) )		// it is possible that parentUnit is dying right now
312 				{
313 					targetUnit->ask_team_help_attack(parentUnit);
314 				}
315 			}
316 		}
317 	}
318 
319 	//--- increase reputation of the nation that attacks monsters ---//
320 
321 	else if( targetUnitClass == UNIT_CLASS_MONSTER )
322 	{
323 		if( parentNationPtr )
324 			parentNationPtr->change_reputation(REPUTATION_INCREASE_PER_ATTACK_MONSTER);
325 	}
326 
327 	//------------------------------------------//
328 
329 	if(!targetUnit->can_attack())	// no action if the target unit is unable to attack
330 		return;
331 
332 	err_when(!targetUnit->can_attack());
333 
334 	targetUnit->unit_auto_guarding(parentUnit);
335 }
336 //---------- End of function Unit::hit_target ----------//
337 
338 //##### end trevor 15/8 #######//
339 
340 
341 //----------- Begin of function Unit::unit_auto_guarding ---------------//
342 // the unit attacks the unit attacking it
343 //
344 // <Unit*> attackUnit	- the unit attacking this unit
345 //
unit_auto_guarding(Unit * attackUnit)346 void Unit::unit_auto_guarding(Unit *attackUnit)
347 {
348 	if( force_move_flag )
349 		return;
350 
351 	//##### begin trevor 9/10 ########//
352 
353 	//---------------------------------------//
354 	//
355 	// If the aggressive_mode is off, then don't
356 	// fight back when the unit is moving, only
357 	// fight back when the unit is already fighting
358 	// or is idle.
359 	//
360 	//---------------------------------------//
361 
362 	if( !aggressive_mode && cur_action != SPRITE_ATTACK &&
363 		 cur_action != SPRITE_IDLE )
364 	{
365 		return;
366 	}
367 
368 	//##### begin trevor 9/10 ########//
369 
370 	//--------------------------------------------------------------------//
371 	// decide attack or not
372 	//--------------------------------------------------------------------//
373 
374 	int changeToAttack=0;
375 	if(cur_action==SPRITE_ATTACK || (sprite_info->need_turning && cur_action==SPRITE_TURN &&
376 		(abs(next_x_loc()-action_x_loc)<attack_range || abs(next_y_loc()-action_y_loc)<attack_range)))
377 	{
378 		err_when(cur_x!=next_x || cur_y!=next_y);
379 		if(action_mode!=ACTION_ATTACK_UNIT)
380 			changeToAttack++;  //else continue to attack the target unit
381 		else
382 		{
383 			err_when(!action_para);
384 			if(unit_array.is_deleted(action_para))
385 				changeToAttack++; // attack new target
386 		}
387 	}
388 	else if(cur_action!=SPRITE_DIE)// && abs(cur_x-next_x)<spriteInfo->speed && abs(cur_y-next_y)<spriteInfo->speed)
389 	{
390 		changeToAttack++;
391 		/*if(!ai_unit) // player unit
392 		{
393 			if(action_mode!=ACTION_ATTACK_UNIT)
394 				changeToAttack++;  //else continue to attack the target unit
395 			else
396 			{
397 				err_when(!action_para);
398 				if(unit_array.is_deleted(action_para))
399 					changeToAttack++; // attack new target
400 			}
401 		}
402 		else
403 			changeToAttack++;*/
404 	}
405 
406 	if(!changeToAttack)
407 	{
408 		if(ai_unit) // allow ai unit to select target to attack
409 		{
410 			//------------------------------------------------------------//
411 			// conditions to let the unit escape
412 			//------------------------------------------------------------//
413 			//-************* codes here ************-//
414 
415 			//------------------------------------------------------------//
416 			// select the weaker target to attack first, if more than one
417 			// unit attack this unit
418 			//------------------------------------------------------------//
419 			int attackXLoc = attackUnit->next_x_loc();
420 			int attackYLoc = attackUnit->next_y_loc();
421 
422 			int attackDistance = cal_distance(attackXLoc, attackYLoc, attackUnit->sprite_info->loc_width,
423 														 attackUnit->sprite_info->loc_height);
424 			if(attackDistance==1) // only consider close attack
425 			{
426 				err_when(!action_para || unit_array.is_deleted(action_para));
427 				Unit *targetUnit = unit_array[action_para];
428 				if(targetUnit->hit_points > attackUnit->hit_points) // the new attacker is weaker
429 					attack_unit(attackUnit->sprite_recno);
430 			}
431 		}
432 
433 		return;
434 	}
435 
436 	//--------------------------------------------------------------------//
437 	// cancel AI actions
438 	//--------------------------------------------------------------------//
439 	if( ai_action_id )
440 		nation_array[nation_recno]->action_failure(ai_action_id, sprite_recno);
441 
442 	if(in_auto_defense_mode())
443 		set_search_tries(AUTO_DEFENSE_SEARCH_TRIES);
444 
445 	if(!attackUnit->is_visible())
446 		return;
447 
448 	//--------------------------------------------------------------------------------//
449 	// checking for ship processing trading
450 	//--------------------------------------------------------------------------------//
451 	if(sprite_info->sprite_sub_type=='M') //**** BUGHERE, is sprite_sub_type really representing UNIT_MARINE???
452 	{
453 		UnitInfo* unitInfo = unit_res[unit_id];
454 		if(unitInfo->carry_goods_capacity)
455 		{
456 			UnitMarine *shipPtr = (UnitMarine*) this;
457 			if(shipPtr->auto_mode && shipPtr->stop_defined_num>1)
458 			{
459 				int targetXLoc = attackUnit->next_x_loc();
460 				int targetYLoc = attackUnit->next_y_loc();
461 				SpriteInfo *targetSpriteInfo = attackUnit->sprite_info;
462 				int attackDistance = cal_distance(targetXLoc, targetYLoc, targetSpriteInfo->loc_width, targetSpriteInfo->loc_height);
463 				int maxAttackRange = max_attack_range();
464 				if(maxAttackRange<attackDistance)
465 					return; // can't attack the target
466 			}
467 		}
468 	}
469 
470 	switch(action_mode2)
471 	{
472 		case ACTION_AUTO_DEFENSE_DETECT_TARGET: case ACTION_AUTO_DEFENSE_BACK_CAMP:
473 				action_mode2 = ACTION_AUTO_DEFENSE_ATTACK_TARGET;
474 				break;
475 
476 		case ACTION_DEFEND_TOWN_DETECT_TARGET:	case ACTION_DEFEND_TOWN_BACK_TOWN:
477 				action_mode2 = ACTION_DEFEND_TOWN_ATTACK_TARGET;
478 				break;
479 
480 		case ACTION_MONSTER_DEFEND_DETECT_TARGET:	case ACTION_MONSTER_DEFEND_BACK_FIRM:
481 				action_mode2 = ACTION_MONSTER_DEFEND_ATTACK_TARGET;
482 				break;
483 	}
484 
485 	//##### trevor 9/10 #######//
486 
487 	save_original_action();
488 
489 	//----------------------------------------------------------//
490 	// set the original location of the attacking target when
491 	// the attack() function is called, action_x_loc2 & action_y_loc2
492 	// will change when the unit move, but these two will not.
493 	//----------------------------------------------------------//
494 
495 	original_target_x_loc = attackUnit->next_x_loc();
496 	original_target_y_loc = attackUnit->next_y_loc();
497 
498 	//##### trevor 9/10 #######//
499 
500 	if(!unit_array.is_deleted(attackUnit->sprite_recno))
501 		attack_unit(attackUnit->sprite_recno);
502 }
503 //---------- End of function Unit::unit_auto_guarding ----------//
504 
505 
506 //----------- Begin of function Unit::hit_building ---------------//
507 //
508 // note:	If parentUnit==NULL, the attacking unit is already dead.
509 //			In range attack, the unit calling this function may not be the
510 //			attacking unit.
511 //
512 // <Unit*> attackUnit   - the attacking unit
513 // <int>   target?Loc   - the target building location
514 // <int>   attackDamage - the actual damage made
515 // <short> attackNationRecno - the nation that ordered the hit
516 //
517 // ****************************** Warning ***********************************
518 // don't use any member variables of this unit. This unit may not be involved
519 // in the attack event
520 // **************************************************************************
521 //
hit_building(Unit * attackUnit,int targetXLoc,int targetYLoc,float attackDamage,short attackNationRecno)522 void Unit::hit_building(Unit* attackUnit, int targetXLoc, int targetYLoc, float attackDamage, short attackNationRecno)
523 {
524 	Location* locPtr = world.get_loc(targetXLoc, targetYLoc);
525 
526 	if(locPtr->is_firm())
527 		hit_firm(attackUnit, targetXLoc, targetYLoc, attackDamage, attackNationRecno);
528 	else if( locPtr->is_town() )
529 		hit_town(attackUnit, targetXLoc, targetYLoc, attackDamage, attackNationRecno);
530 }
531 //---------- End of function Unit::hit_building ----------//
532 
533 //##### begin trevor 15/8 #######//
534 
535 
536 //------------ Begin of function Unit::hit_firm --------------//
537 //
538 // note:	If parentUnit==NULL, the attacking unit is already dead.
539 //			In range attack, the unit calling this function may not be the
540 //			attacking unit.
541 //
542 // <Unit*> attackUnit   - the attacking unit
543 // <int>   target?Loc   - the target building location
544 // <int>   attackDamage - the actual damage made
545 // <short> attackNationRecno - the nation that ordered the hit
546 //
547 // ****************************** Warning ***********************************
548 // don't use any member variables of this unit. This unit may not be involved
549 // in the attack event
550 // **************************************************************************
551 //
hit_firm(Unit * attackUnit,int targetXLoc,int targetYLoc,float attackDamage,short attackNationRecno)552 void Unit::hit_firm(Unit* attackUnit, int targetXLoc, int targetYLoc, float attackDamage, short attackNationRecno)
553 {
554 	Location* locPtr = world.get_loc(targetXLoc, targetYLoc);
555 	if(!locPtr->is_firm())
556 		return;	// do nothing if no firm there
557 
558 	//----------- attack firm ------------//
559 	err_when(!locPtr->firm_recno());
560 	Firm *targetFirm = firm_array[locPtr->firm_recno()];
561 	err_when(!targetFirm);
562 
563 	//------------------------------------------------------------------------------//
564 	// change relation to hostile
565 	// check for NULL to skip unhandled case by bullets
566 	// check for SPRITE_DIE to skip the case by EXPLOSIVE_CART
567 	//------------------------------------------------------------------------------//
568 	if( attackUnit!=NULL && attackUnit->cur_action!=SPRITE_DIE &&
569 		 targetFirm->nation_recno != attackNationRecno )		// the target and the attacker's nations are different (it's possible that when a unit who has just changed nation has its bullet hitting its own nation)
570 	{
571 		if( attackNationRecno && targetFirm->nation_recno )
572 		{
573 			//### trevor 29/9 ###//
574 			nation_array[attackNationRecno]->set_at_war_today();
575 			nation_array[targetFirm->nation_recno]->set_at_war_today(attackUnit->sprite_recno);
576 			//### trevor 29/9 ###//
577 		}
578 
579 		if( targetFirm->nation_recno )
580 			nation_array[targetFirm->nation_recno]->being_attacked(attackNationRecno);
581 
582 		//------------ auto defense -----------------//
583 		if(attackUnit->is_visible())
584 			targetFirm->auto_defense(attackUnit->sprite_recno);
585 
586 		if( attackNationRecno != targetFirm->nation_recno )
587 			attackUnit->gain_experience(); // gain experience to increase combat level
588 
589 		targetFirm->being_attacked(attackUnit->sprite_recno);
590 
591 		//------ increase battling fryhtan score -------//
592 
593 		if( attackNationRecno && targetFirm->firm_id == FIRM_MONSTER )
594 			nation_array[attackNationRecno]->kill_monster_score += (float) 0.01;
595 	}
596 
597 	//---------- add indicator on the map ----------//
598 
599 	// ###### begin Gilbert 6/10 #######//
600 	if( nation_array.player_recno && targetFirm->own_firm() )
601 		war_point_array.add_point(targetFirm->center_x, targetFirm->center_y);
602 	// ###### end Gilbert 6/10 #######//
603 
604 	//---------- damage to the firm ------------//
605 
606 	targetFirm->hit_points -= attackDamage/3;		// /3 so that it takes longer to destroy a firm
607 
608 	//######## begin trevor 25/8 ##########//
609 
610 	if(targetFirm->hit_points <= 0)
611 	{
612 		targetFirm->hit_points = (float) 0;
613 
614 		se_res.sound(targetFirm->center_x, targetFirm->center_y, 1,
615 			'F', targetFirm->firm_id, "DIE" );
616 
617 		if( targetFirm->nation_recno == nation_array.player_recno )
618 			news_array.firm_destroyed(targetFirm->firm_recno, attackUnit, attackNationRecno);
619 
620 		if( targetFirm->nation_recno )
621 		{
622 			if( attackNationRecno )
623 				nation_array[attackNationRecno]->enemy_firm_destroyed++;
624 
625 			nation_array[targetFirm->nation_recno]->own_firm_destroyed++;
626 		}
627 
628 		else if( targetFirm->firm_id == FIRM_MONSTER )
629 		{
630 			news_array.monster_firm_destroyed( ((FirmMonster*)targetFirm)->monster_id, targetFirm->center_x, targetFirm->center_y );
631 		}
632 
633 		firm_array.del_firm(targetFirm->firm_recno);
634 	}
635 
636 	//######## end trevor 25/8 ##########//
637 }
638 //---------- End of function Unit::hit_firm ----------//
639 
640 
641 //--------- Begin of function Unit::hit_town ---------//
642 //
643 // note:	If attackUnit==NULL, the attacking unit is already dead.
644 //			In range attack, the unit calling this function may not be the
645 //			attacking unit.
646 //
647 // <Unit*> attackUnit   - the attacking unit
648 // <int>   target?Loc   - the target building location
649 // <int>   attackDamage - the actual damage made
650 // <short> attackNationRecno - the nation that ordered the hit
651 //
652 // ****************************** Warning ***********************************
653 // don't use any member variables of this unit. This unit may not be involved
654 // in the attack event
655 // **************************************************************************
656 //
hit_town(Unit * attackUnit,int targetXLoc,int targetYLoc,float attackDamage,short attackNationRecno)657 void Unit::hit_town(Unit* attackUnit, int targetXLoc, int targetYLoc, float attackDamage, short attackNationRecno)
658 {
659 	Location *locPtr = world.get_loc(targetXLoc, targetYLoc);
660 
661 	if(!locPtr->is_town())
662 		return;	// do nothing if no town there
663 
664 	//----------- attack town ----------//
665 
666 	err_when(!locPtr->town_recno());
667 
668 	Town *targetTown = town_array[locPtr->town_recno()];
669 	int   targetTownRecno = targetTown->town_recno;
670 	int 	targetTownNameId = targetTown->town_name_id;
671 	int 	targetTownXLoc = targetTown->center_x;
672 	int 	targetTownYLoc = targetTown->center_y;
673 
674 	// ---------- add indicator on the map ----------//
675 	// ###### begin Gilbert 6/10 #######//
676 	if( nation_array.player_recno && targetTown->nation_recno == nation_array.player_recno )
677 		war_point_array.add_point(targetTown->center_x, targetTown->center_y);
678 	// ###### end Gilbert 6/10 #######//
679 
680 	//------------------------------------------------------------------------------//
681 	// change relation to hostile
682 	// check for NULL to skip unhandled case by bullets
683 	// check for SPRITE_DIE to skip the case by EXPLOSIVE_CART
684 	//------------------------------------------------------------------------------//
685 	if( attackUnit!=NULL && attackUnit->cur_action!=SPRITE_DIE &&
686 		 targetTown->nation_recno != attackNationRecno )		// the target and the attacker's nations are different (it's possible that when a unit who has just changed nation has its bullet hitting its own nation)
687 	{
688 		int townNationRecno = targetTown->nation_recno;
689 
690 		//------- change to hostile relation -------//
691 
692 		if( attackNationRecno && targetTown->nation_recno )
693 		{
694 			//### trevor 29/9 ###//
695 			nation_array[attackNationRecno]->set_at_war_today();
696 			nation_array[targetTown->nation_recno]->set_at_war_today(attackUnit->sprite_recno);
697 			//### trevor 29/9 ###//
698 		}
699 
700 		if( targetTown->nation_recno)
701 		{
702 			nation_array[targetTown->nation_recno]->being_attacked(attackNationRecno);
703 		}
704 
705 		news_array.disable();		// don't add the town abandon news that might be called by Town::dec_pop() as the town is actually destroyed not abandoned
706 
707 		targetTown->being_attacked(attackUnit->sprite_recno, attackDamage);
708 
709 		news_array.enable();
710 
711 		//------ if the town is destroyed, add a news --------//
712 
713 		if( town_array.is_deleted(targetTownRecno) &&
714 			 townNationRecno == nation_array.player_recno )
715 		{
716 			news_array.town_destroyed(targetTownNameId, targetTownXLoc, targetTownYLoc, attackUnit, attackNationRecno);
717 		}
718 
719 		//---------- gain experience --------//
720 
721 		if( attackNationRecno != targetTown->nation_recno )
722 			attackUnit->gain_experience(); // gain experience to increase combat level
723 
724 		//------------ auto defense -----------------//
725 
726 		if( !firm_array.is_deleted(targetTownRecno) )
727 			targetTown->auto_defense(attackUnit->sprite_recno);
728 	}
729 }
730 //---------- End of function Unit::hit_town ----------//
731 
732 //##### end trevor 15/8 #######//
733 
734 
735 //--------- Begin of function Unit::hit_wall -----------//
736 //
737 // <Unit*> attackUnit   - the attacking unit
738 // <int>   target?Loc   - the targeted wall location
739 // <int>   attackDamage - the actual damage made
740 // <short> attackNationRecno - the nation that ordered the hit
741 //
742 // ****************************** Warning ***********************************
743 // don't use any member variables of this unit. This unit may not be involved
744 // in the attack event
745 // **************************************************************************
746 //
hit_wall(Unit * attackUnit,int targetXLoc,int targetYLoc,float attackDamage,short attackNationRecno)747 void Unit::hit_wall(Unit* attackUnit, int targetXLoc, int targetYLoc, float attackDamage, short attackNationRecno)
748 {
749 	Location *locPtr = world.get_loc(targetXLoc, targetYLoc);
750 	err_when(!locPtr->is_wall());
751 
752 	//######## begin trevor 25/6 #########//
753 /*
754 	if(attackUnit!=NULL)
755 		attackUnit->change_relation(attackNationRecno, locPtr->wall_nation_recno(), NATION_HOSTILE);
756 */
757 	//######## end trevor 25/6 #########//
758 
759 	if( !locPtr->attack_wall((int)attackDamage) )
760 		world.correct_wall(targetXLoc, targetYLoc);
761 }
762 //---------- End of function Unit::hit_wall ----------//
763 
764 
765 //--------- Begin of function Unit::cal_distance ---------//
766 // calculate the distance from this unit to the target
767 // (assume the size of this unit is a square)
768 //
769 // <int>	targetXLoc		- x location of the target
770 // <int>	targetYLoc		- y location of the target
771 // <int> targetWidth		- target width
772 // <int> targetHeight	- target height
773 //
cal_distance(int targetXLoc,int targetYLoc,int targetWidth,int targetHeight)774 int Unit::cal_distance(int targetXLoc, int targetYLoc, int targetWidth, int targetHeight)
775 {
776 	int curXLoc = next_x_loc();
777 	int curYLoc = next_y_loc();
778 	int dispX=0, dispY=0;
779 
780 	if(curXLoc<targetXLoc)
781 		dispX = (targetXLoc - curXLoc - sprite_info->loc_width) + 1;
782 	else if((dispX=curXLoc-targetXLoc-targetWidth+1)<0)
783 		dispX  = 0;
784 	err_when(dispX<0 || dispX>MAX_WORLD_X_LOC);
785 
786 	if(curYLoc<targetYLoc)
787 		dispY = (targetYLoc - curYLoc - sprite_info->loc_height) + 1;
788 	else if((dispY=curYLoc-targetYLoc-targetHeight+1)<0)
789 	{
790 		err_when(mobile_type!=UNIT_AIR && !dispX); // inside the target
791 		return dispX;
792 	}
793 	err_when(dispY<0 || dispY>MAX_WORLD_Y_LOC);
794 
795 	return (dispX>=dispY)? dispX : dispY;
796 }
797 //----------- End of function Unit::cal_distance -----------//
798 
799 
800 //------------ Begin of function Unit::actual_damage --------------//
801 //
802 // return: return the actual hit damage this unit can do to a target.
803 //
actual_damage()804 float Unit::actual_damage()
805 {
806 	AttackInfo *attackInfo = attack_info_array+cur_attack;
807 
808 	int attackDamage = attackInfo->attack_damage;
809 
810 	//-------- pierce damage --------//
811 
812 	attackDamage += misc.random(3) + attackInfo->pierce_damage
813 						 * misc.random(skill.combat_level-attackInfo->combat_level)
814 						 / (100-attackInfo->combat_level);
815 
816 	//--- if this unit is led by a general, its attacking ability is influenced by the general ---//
817 	//
818 	// The unit's attacking ability is increased by a percentage equivalent to
819 	// the leader unit's leadership.
820 	//
821 	//------------------------------------------------------------------------//
822 
823 	if( is_leader_in_range() )
824 	{
825 		Unit *leaderUnit = unit_array[leader_unit_recno];
826 		attackDamage += attackDamage * leaderUnit->skill.skill_level / 100;
827 	}
828 
829 	return (float) attackDamage / ATTACK_SLOW_DOWN;		// lessen all attacking damages, thus slowing down all battles.
830 }
831 //------------ End of function Unit::actual_damage --------------//
832 
833 
834 //--------- Begin of function Unit::gain_experience ---------//
gain_experience()835 void Unit::gain_experience()
836 {
837 	if(unit_res[unit_id]->unit_class != UNIT_CLASS_HUMAN)
838 		return; // no experience gain if unit is not human
839 
840 	//---- increase the unit's contribution to the nation ----//
841 
842 	if( nation_contribution < MAX_NATION_CONTRIBUTION )
843 	{
844 		nation_contribution++;
845 
846 		err_when( nation_contribution < 0 );		// overflow
847 	}
848 
849 	//------ increase combat skill -------//
850 
851 	err_when(skill.combat_level<0 || skill.combat_level>100);
852 
853 	inc_minor_combat_level(6);
854 
855 	//--- if this is a soldier led by a commander, increase the leadership of its commander -----//
856 
857 	if( leader_unit_recno )
858 	{
859 		Unit* leaderUnit = unit_array[leader_unit_recno];
860 		int	leaderXLoc= -1, leaderYLoc;
861 
862 		if( leaderUnit->is_visible() )
863 		{
864 			leaderXLoc = cur_x_loc();
865 			leaderYLoc = cur_y_loc();
866 		}
867 		else if( leaderUnit->unit_mode == UNIT_MODE_OVERSEE )
868 		{
869 			Firm* firmPtr = firm_array[leaderUnit->unit_mode_para];
870 
871 			leaderXLoc = firmPtr->center_x;
872 			leaderYLoc = firmPtr->center_y;
873 		}
874 		else
875 			leaderXLoc = -1;
876 
877 		if( leaderXLoc >= 0 &&
878 			 misc.points_distance( cur_x_loc(), cur_y_loc(), leaderXLoc, leaderYLoc ) <= EFFECTIVE_LEADING_DISTANCE )
879 		{
880 			leaderUnit->inc_minor_skill_level(1);
881 
882 			//-- give additional increase if the leader has skill potential on leadership --//
883 
884 			if( leaderUnit->skill.skill_potential > 0 )
885 			{
886 				if( misc.random(10-leaderUnit->skill.skill_potential/10)==0 )
887 					leaderUnit->inc_minor_skill_level(5);
888 			}
889 		}
890 
891 		//--- if this soldier has leadership potential and is led by a commander ---//
892 		//--- he learns leadership by watching how the commander commands the troop --//
893 
894 		if( skill.skill_potential > 0 )
895 		{
896 			if( misc.random(10-skill.skill_potential/10)==0 )
897 				inc_minor_skill_level(5);
898 		}
899 	}
900 }
901 //------------ End of function Unit::gain_experience --------------//
902 
903 
904 //--------- Begin of function Unit::can_attack ---------//
905 // return 1 if can attack
906 // return 0 otherwise
907 //
908 /*int Unit::can_attack()
909 {
910 	return (can_attack_flag && attack_count);
911 }*/
912 //------------ End of function Unit::can_attack --------------//
913 
914 
915 //--------- Begin of function Unit::nation_can_attack ---------//
916 // return 1 for able to attack this nation i.e. relation is not
917 //				friendly or alliance
918 // return 0 otherwise
919 //
920 // Whether this unit can attack others with the specified nation recno
921 //
922 // <short> nationRecno	-	nation recno to be checked
923 //
nation_can_attack(short nationRecno)924 int Unit::nation_can_attack(short nationRecno)
925 {
926 	if(!ai_unit)
927 	{
928 		//return 1;
929 		if( game.game_mode == GAME_TEST )	// in testing games, player units can attack their own units
930 			return 1;
931 		else
932 			return nationRecno!=nation_recno; // able to attack all nation except our own nation
933 	}
934 	else if(nation_recno == nationRecno)
935 		return 0; // ai unit don't attack its own nation, except special order
936 
937 	if(!nation_recno || !nationRecno)
938 		return 1; // true if either nation is independent
939 
940 	Nation *nationPtr = nation_array[nation_recno];
941 
942 	char relatinStatus = nationPtr->get_relation_status(nationRecno);
943 	if(relatinStatus==NATION_FRIENDLY || relatinStatus==NATION_ALLIANCE)
944 		return 0;
945 
946 	return 1;
947 }
948 //------------ End of function Unit::nation_can_attack --------------//
949 
950 
951 //--------- Begin of function Unit::independent_nation_can_attack ---------//
952 // Note: this unit should be an independent unit
953 //
954 // Should this independent unit attack other units with specified nation recno
955 //
956 // return 1 if decision is attacking
957 // return 0 otherwise
958 //
959 // <short> nationRecno	-	nation recno to be checked
960 //
independent_nation_can_attack(short nationRecno)961 int Unit::independent_nation_can_attack(short nationRecno)
962 {
963 	err_when(nation_recno);
964 
965 	Town *townPtr;
966 	FirmMonster *firmMonster;
967 	Rebel *rebelPtr;
968 
969 	switch(unit_mode)
970 	{
971 		case UNIT_MODE_DEFEND_TOWN:
972 				err_when(unit_mode_para<=0);
973 				if(town_array.is_deleted(unit_mode_para))
974 					return 0; // don't attack independent unit with no town
975 
976 				townPtr = town_array[unit_mode_para];
977 
978 				if( !townPtr->is_hostile_nation(nationRecno) )
979 					return 0; // false if the indepentent unit don't want to attack us
980 
981 				break;
982 
983 		case UNIT_MODE_REBEL:
984 				if(rebel_array.is_deleted(unit_mode_para))
985 					return 0;
986 
987 				rebelPtr = rebel_array[unit_mode_para];
988 
989 				if( !rebelPtr->is_hostile_nation(nationRecno) )
990 					return 0;
991 
992 				break;
993 
994 //######## begin trevor 22/8 ##########//
995 		case UNIT_MODE_MONSTER:
996 				if( unit_mode_para==0 )
997 					return nationRecno; // attack anything that is not independent
998 
999 				firmMonster = (FirmMonster*) firm_array[unit_mode_para];
1000 
1001 				err_when( firmMonster->firm_id != FIRM_MONSTER );
1002 
1003 				if( !firmMonster->is_hostile_nation(nationRecno) )
1004 					return 0; 			// false if the indepentent unit don't want to attack us
1005 
1006 				break;
1007 //######## end trevor 22/8 ##########//
1008 
1009 		default:
1010 				return 0;
1011 	}
1012 
1013 	return 1;
1014 }
1015 //------------ End of function Unit::independent_nation_can_attack --------------//
1016 
1017 
1018 //--------- Begin of function Unit::choose_best_attack_mode ---------//
1019 // if the unit has more than one attack mode, select the suitable mode
1020 // to attack the target
1021 //
1022 // <int>  attackDistance	- the distance from the target
1023 // [char] targetMobileType	- the target's mobile_type (default: UNIT_LAND)
1024 //
choose_best_attack_mode(int attackDistance,char targetMobileType)1025 void Unit::choose_best_attack_mode(int attackDistance, char targetMobileType)
1026 {
1027 	//------------ enable/disable range attack -----------//
1028 	//cur_attack = 0;
1029 	//return;
1030 
1031 	//-------------------- define parameters -----------------------//
1032 	uint8_t attackModeBeingUsed = cur_attack;
1033 	err_when(attackModeBeingUsed<0 || attackModeBeingUsed>MAX_UNIT_ATTACK_TYPE);
1034 	//UCHAR maxAttackRangeMode = 0;
1035 	uint8_t maxAttackRangeMode = cur_attack;
1036 	AttackInfo* attackInfoMaxRange = attack_info_array;
1037 	AttackInfo* attackInfoChecking;
1038 	AttackInfo* attackInfoSelected = attack_info_array+cur_attack;
1039 
1040 	//--------------------------------------------------------------//
1041 	// If targetMobileType==UNIT_AIR or mobile_type==UNIT_AIR,
1042 	//	force to use range_attack.
1043 	// If there is no range_attack, return 0, i.e. cur_attack=0
1044 	//--------------------------------------------------------------//
1045 	if(attack_count>1)
1046 	{
1047 		int canAttack = 0;
1048 		int checkingDamageWeight, selectedDamageWeight;
1049 
1050 		for(uint8_t i=0; i<attack_count; i++)
1051 		{
1052 			if(attackModeBeingUsed==i)
1053 				continue; // it is the mode already used
1054 
1055 			attackInfoChecking = attack_info_array+i;
1056 			if(can_attack_with(attackInfoChecking) && attackInfoChecking->attack_range>=attackDistance)
1057 			{
1058 				//-------------------- able to attack ----------------------//
1059 				canAttack = 1;
1060 
1061 				if(attackInfoSelected->attack_range<attackDistance)
1062 				{
1063 					attackModeBeingUsed = i;
1064 					attackInfoSelected = attackInfoChecking;
1065 					continue;
1066 				}
1067 
1068 				checkingDamageWeight = attackInfoChecking->attack_damage;
1069 				selectedDamageWeight = attackInfoSelected->attack_damage;
1070 
1071 				if(attackDistance==1 && (targetMobileType!=UNIT_AIR && mobile_type!=UNIT_AIR))
1072 				{
1073 					//------------ force to use close attack if possible -----------//
1074 					if(attackInfoSelected->attack_range==attackDistance)
1075 					{
1076 						if(attackInfoChecking->attack_range==attackDistance && checkingDamageWeight>selectedDamageWeight)
1077 						{
1078 							attackModeBeingUsed = i; // choose the one with strongest damage
1079 							attackInfoSelected = attackInfoChecking;
1080 						}
1081 						continue;
1082 					}
1083 					else if(attackInfoChecking->attack_range==1)
1084 					{
1085 						attackModeBeingUsed = i;
1086 						attackInfoSelected = attackInfoChecking;
1087 						continue;
1088 					}
1089 				}
1090 
1091 				//----------------------------------------------------------------------//
1092 				// further selection
1093 				//----------------------------------------------------------------------//
1094 				if(checkingDamageWeight == selectedDamageWeight)
1095 				{
1096 					if(attackInfoChecking->attack_range<attackInfoSelected->attack_range)
1097 					{
1098 						if(attackInfoChecking->attack_range>1 || (targetMobileType!=UNIT_AIR && mobile_type!=UNIT_AIR))
1099 						{
1100 							//--------------------------------------------------------------------------//
1101 							// select one with shortest attack_range
1102 							//--------------------------------------------------------------------------//
1103 							attackModeBeingUsed = i;
1104 							attackInfoSelected = attackInfoChecking;
1105 						}
1106 					}
1107 				}
1108 				else
1109 				{
1110 					//--------------------------------------------------------------------------//
1111 					// select one that can do the attacking immediately with the strongest damage point
1112 					//--------------------------------------------------------------------------//
1113 					attackModeBeingUsed = i;
1114 					attackInfoSelected = attackInfoChecking;
1115 				}
1116 			}
1117 
1118 			if(!canAttack)
1119 			{
1120 				//------------------------------------------------------------------------------//
1121 				// if unable to attack the target, choose the mode with longer attack_range and
1122 				// heavier damage
1123 				//------------------------------------------------------------------------------//
1124 				if(can_attack_with(attackInfoChecking) &&
1125 					(attackInfoChecking->attack_range>attackInfoMaxRange->attack_range ||
1126 					(attackInfoChecking->attack_range==attackInfoMaxRange->attack_range &&
1127 					 attackInfoChecking->attack_damage>attackInfoMaxRange->attack_damage)))
1128 				{
1129 					maxAttackRangeMode = i;
1130 					attackInfoMaxRange = attackInfoChecking;
1131 				}
1132 			}
1133 		}
1134 
1135 		if(canAttack)
1136 			cur_attack = attackModeBeingUsed;	// choose the strongest damage mode if able to attack
1137 		else
1138 			cur_attack = maxAttackRangeMode;		//	choose the longest attack range if unable to attack
1139 
1140 		attack_range = attack_info_array[cur_attack].attack_range;
1141 		err_when(final_dir<0 || final_dir>=MAX_SPRITE_DIR_TYPE);
1142 		err_when(cur_attack>=attack_count || cur_attack<0);
1143 	}
1144 	else
1145 	{
1146 		cur_attack = 0;	// only one mode is supported
1147 		attack_range = attack_info_array[0].attack_range;
1148 		return;
1149 	}
1150 }
1151 //---------- End of function Unit::choose_best_attack_mode ----------//
1152 
1153 
1154 //------ Begin of function Unit::set_attack_dir ---------//
1155 // set direction for attacking
1156 //
1157 //	<short>	curX		-	x location of the unit
1158 // <short>	curY		-	y location of the unit
1159 // <short>	targetX	-	x location of the target
1160 // <short>	targetY	-	y location of the target
1161 //
set_attack_dir(short curX,short curY,short targetX,short targetY)1162 void Unit::set_attack_dir(short curX, short curY, short targetX, short targetY)
1163 {
1164 	int targetDir = get_dir(curX, curY, targetX, targetY);
1165 	if(unit_res[unit_id]->unit_class==UNIT_CLASS_SHIP)
1166 	{
1167 		int attackDir1, attackDir2;
1168 
1169 		attackDir1 = (targetDir+2)%MAX_SPRITE_DIR_TYPE;
1170 		attackDir2 = (targetDir+6)%MAX_SPRITE_DIR_TYPE;
1171 
1172 		if((attackDir1+8-final_dir)%MAX_SPRITE_DIR_TYPE <= (attackDir2+8-final_dir)%MAX_SPRITE_DIR_TYPE)
1173 			final_dir = attackDir1;
1174 		else
1175 			final_dir = attackDir2;
1176 
1177 		attack_dir = targetDir;
1178 		err_when(attack_dir<0 || attack_dir>=MAX_SPRITE_DIR_TYPE);
1179 	}
1180 	else
1181 	{
1182 		attack_dir = targetDir;
1183 		set_dir(targetDir);
1184 	}
1185 }
1186 //---------- End of function Unit::set_attack_dir ----------//
1187 
1188 
1189 //--------- Begin of function Unit::set_unreachable_location ---------//
1190 // used to set the bit in the unreachable_flag (16 bits)
1191 //
1192 //	The 16 bits of the flag are used to represent the 16 location of a unit
1193 // as follows:
1194 //
1195 //	1	2	3	4			where x is the upper left corner of the unit.
1196 //	5	x	6	7			For 1x1 unit, 1,2,3,5,6,8,9,10 are meaningful
1197 //	8	9	10	11			For 2x2 unit, 1,2,3,4,5,7,8,11,12,13,14,15 are meaningful
1198 //	12	13	14	15
1199 //
set_unreachable_location(int xLoc,int yLoc)1200 void Unit::set_unreachable_location(int xLoc, int yLoc)
1201 {
1202 	static unsigned short bitFlag[16] = {0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080,
1203 	 												 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000};
1204 	/*int curXLoc = next_x_loc();
1205 	int curYLoc = next_y_loc();
1206 	int xDist = xLoc-curXLoc+1;
1207 	int yDist = yLoc-curYLoc+1;
1208 
1209 	err_when(xDist<0 || xDist>3 || yDist<0 || yDist>3);
1210 	char bitNo = yDist*4 + xDist;
1211 
1212 	err_when(bitNo==5);
1213 	if(bitNo>5)
1214 		bitNo--;
1215 
1216 	unreachable_flag |= bitFlag[bitNo];*/
1217 }
1218 //----------- End of function Unit::set_unreachable_location -----------//
1219 
1220 //--------- Begin of function Unit::check_self_surround ---------//
1221 // Note : mobile_type used is this unit's mobile_type
1222 //
check_self_surround()1223 void Unit::check_self_surround()
1224 {
1225 	/*err_when(sprite_info->loc_height!=sprite_info->loc_width);
1226 	err_when(sprite_info->loc_width<1 || sprite_info->loc_width>2);
1227 
1228 	Location *locPtr;
1229 	int width = sprite_info->loc_width;
1230 	int curXLoc = next_x_loc();
1231 	int curYLoc = next_y_loc();
1232 	int startCount = (width==1) ? 2 : 5;
1233 	int endCount = (width==1) ? 9 : 16;
1234 	int xShift, yShift;
1235 
1236 	self_surround_flag = 0;
1237 
1238 	for(int i=startCount; i<=endCount; i++)
1239 	{
1240 		misc.cal_move_around_a_point(i, width, width, xShift, yShift);
1241 		locPtr = world.get_loc(curXLoc+xShift, curYLoc+yShift);
1242 
1243 		if(!locPtr->can_move(mobile_type))
1244 			misc.set_surround_bit(self_surround_flag, i-startCount);
1245 	}*/
1246 }
1247 //----------- End of function Unit::check_self_surround -----------//
1248 
1249 
1250 //----------- Begin of function Unit::cycle_eqv_attack -----------//
cycle_eqv_attack()1251 void Unit::cycle_eqv_attack()
1252 {
1253 	int trial = MAX_UNIT_ATTACK_TYPE+2;
1254 	if( attack_info_array[cur_attack].eqv_attack_next > 0)
1255 	{
1256 		do
1257 		{
1258 			cur_attack = attack_info_array[cur_attack].eqv_attack_next-1;
1259 			err_when(--trial == 0);
1260 		} while( !can_attack_with(cur_attack) );
1261 	}
1262 	else
1263 	{
1264 		if( !can_attack_with(cur_attack) )
1265 		{
1266 			err_here();
1267 			// force to search again
1268 			char attackRange = char(attack_info_array[cur_attack].attack_range);
1269 			err_when(attackRange != attack_range);			// redundant check
1270 			AttackInfo *attackInfo = attack_info_array;
1271 			for(int i = 0; i < attack_count; ++i, ++attackInfo)
1272 			{
1273 				if( attackInfo->attack_range >= attackRange &&
1274 					can_attack_with(attackInfo))
1275 				{
1276 					cur_attack = i;
1277 					break;
1278 				}
1279 				err_when(i >= attack_count);		// not found
1280 			}
1281 		}
1282 	}
1283 	err_when(cur_attack < 0 || cur_attack >= attack_count);
1284 }
1285 //----------- End of function Unit::cycle_eqv_attack -----------//
1286 
1287 
1288 //----------- Begin of function Unit::max_attack_range -----------//
1289 // return the maximum attack range the unit can make
1290 //
1291 //
1292 //
max_attack_range()1293 int Unit::max_attack_range()
1294 {
1295 	int maxRange=0;
1296 
1297 	AttackInfo *attackInfo = attack_info_array;
1298 	for(int i=0; i<attack_count; i++, attackInfo++)
1299 	{
1300 		if(can_attack_with(attackInfo) &&
1301 			attackInfo->attack_range>maxRange)
1302 			maxRange = attackInfo->attack_range;
1303 	}
1304 
1305 	return maxRange;
1306 }
1307 //----------- End of function Unit::max_attack_range -----------//
1308 
1309 
1310 //----------- Begin of function Unit::can_attack_with -------//
can_attack_with(int i)1311 int Unit::can_attack_with(int i)
1312 {
1313 	err_when( i< 0 || i >= attack_count);
1314 	AttackInfo *attackInfo = attack_info_array+i;
1315 	return( skill.combat_level >= attackInfo->combat_level &&
1316 		cur_power >= attackInfo->min_power);
1317 
1318 }
1319 
1320 
can_attack_with(AttackInfo * attackInfo)1321 int Unit::can_attack_with(AttackInfo *attackInfo)
1322 {
1323 	return( skill.combat_level >= attackInfo->combat_level &&
1324 		cur_power >= attackInfo->min_power);
1325 }
1326 //----------- End of function Unit::can_attack_with -------//
1327 
1328 
1329 //----------- Begin of function Unit::get_hit_x_y -------//
get_hit_x_y(short * xPtr,short * yPtr)1330 void Unit::get_hit_x_y(short *xPtr, short *yPtr)
1331 {
1332 	switch(cur_dir)
1333 	{
1334 	case 0:	// north
1335 		*xPtr = cur_x;
1336 		*yPtr = cur_y - ZOOM_LOC_HEIGHT;
1337 		break;
1338 	case 1:	// north east
1339 		*xPtr = cur_x + ZOOM_LOC_WIDTH;
1340 		*yPtr = cur_y - ZOOM_LOC_HEIGHT;
1341 		break;
1342 	case 2:	// east
1343 		*xPtr = cur_x + ZOOM_LOC_WIDTH;
1344 		*yPtr = cur_y;
1345 		break;
1346 	case 3:	// south east
1347 		*xPtr = cur_x + ZOOM_LOC_WIDTH;
1348 		*yPtr = cur_y + ZOOM_LOC_HEIGHT;
1349 		break;
1350 	case 4:	// south
1351 		*xPtr = cur_x;
1352 		*yPtr = cur_y + ZOOM_LOC_HEIGHT;
1353 		break;
1354 	case 5:	// south west
1355 		*xPtr = cur_x - ZOOM_LOC_WIDTH;
1356 		*yPtr = cur_y + ZOOM_LOC_HEIGHT;
1357 		break;
1358 	case 6:	// west
1359 		*xPtr = cur_x - ZOOM_LOC_WIDTH;
1360 		*yPtr = cur_y;
1361 		break;
1362 	case 7:	// north west
1363 		*xPtr = cur_x - ZOOM_LOC_WIDTH;
1364 		*yPtr = cur_y - ZOOM_LOC_HEIGHT;
1365 		break;
1366 	default:
1367 		err_here();
1368 		*xPtr = cur_x;
1369 		*yPtr = cur_y;
1370 	}
1371 }
1372 //----------- End of function Unit::get_hit_x_y -------//
1373 
1374 
1375 //----------- Begin of function Unit::add_close_attack_effect -------//
add_close_attack_effect()1376 void Unit::add_close_attack_effect()
1377 {
1378 	short effectId = (attack_info_array+cur_attack)->effect_id;
1379 	if( effectId )
1380 	{
1381 		short x,y;
1382 		get_hit_x_y(&x, &y);
1383 		Effect::create(effectId, x, y, SPRITE_IDLE, cur_dir, mobile_type == UNIT_AIR ? 8 : 2, 0);
1384 	}
1385 }
1386 //----------- End of function Unit::add_close_attack_effect -------//
1387 
1388 
1389 //----------- Begin of function Unit::is_action_attack -------//
1390 // check whether the unit carrys on attacking action
1391 //
is_action_attack()1392 int Unit::is_action_attack()
1393 {
1394 	switch(action_mode2)
1395 	{
1396 		case ACTION_ATTACK_UNIT:
1397 		case ACTION_ATTACK_FIRM:
1398 		case ACTION_ATTACK_TOWN:
1399 		case ACTION_ATTACK_WALL:
1400 		case ACTION_AUTO_DEFENSE_ATTACK_TARGET:
1401 		case ACTION_AUTO_DEFENSE_DETECT_TARGET:
1402 		case ACTION_AUTO_DEFENSE_BACK_CAMP:
1403 		case ACTION_DEFEND_TOWN_ATTACK_TARGET:
1404 		case ACTION_DEFEND_TOWN_DETECT_TARGET:
1405 		case ACTION_DEFEND_TOWN_BACK_TOWN:
1406 		case ACTION_MONSTER_DEFEND_ATTACK_TARGET:
1407 		case ACTION_MONSTER_DEFEND_DETECT_TARGET:
1408 		case ACTION_MONSTER_DEFEND_BACK_FIRM:
1409 				return 1;
1410 
1411 		default: return 0;
1412 	}
1413 
1414 	return 0;
1415 }
1416 //----------- End of function Unit::is_action_attack -------//
1417 
1418