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    : OU_MARI.CPP
22 // Description : sea unit
23 
24 #include <OSYS.h>
25 #include <OTERRAIN.h>
26 #include <OU_CARA.h>
27 #include <OPOWER.h>
28 #include <OU_MARI.h>
29 #include <OREMOTE.h>
30 #include <ONATIONA.h>
31 #include <OCONFIG.h>
32 #ifdef DEBUG2
33 #include <OFONT.h>
34 #endif
35 
36 //------- Define constant ----------//
37 
38 const int WAVE_CYCLE = 8;
39 
40 //------- Begin of function UnitMarine::UnitMarine -------//
41 
UnitMarine()42 UnitMarine::UnitMarine()
43 {
44 	menu_mode  = 0;
45 	extra_move_in_beach = NO_EXTRA_MOVE;
46 	in_beach = 0;
47 	selected_unit_id = 0;
48 
49 	//------- transporting units vars ---------//
50 
51 	unit_count = 0;
52 	memset(unit_recno_array, 0, sizeof(short)*MAX_UNIT_IN_SHIP);
53 
54 	//------- transporting goods vars ---------//
55 
56 	memset( stop_array, 0, MAX_STOP_FOR_SHIP * sizeof(ShipStop) );
57 
58 	journey_status		= ON_WAY_TO_FIRM;
59 	dest_stop_id		= 0;
60 	stop_defined_num	= 0;
61 	wait_count			= 0;
62 	stop_x_loc			= 0;
63 	stop_y_loc			= 0;
64 
65 	memset(raw_qty_array, 0, sizeof(short)*MAX_RAW);
66 	memset(product_raw_qty_array, 0, sizeof(short)*MAX_PRODUCT);
67 
68 	auto_mode			= 1;	// there should be no button to toggle it if the ship is only for trading
69 	cur_firm_recno		= 0;
70 }
71 //------- End of function UnitMarine::UnitMarine -------//
72 
73 
74 //------- Begin of function UnitMarine::~UnitMarine -------//
75 
~UnitMarine()76 UnitMarine::~UnitMarine()
77 {
78 	//-------- del those units in the ship -------//
79 
80 	for(int i=0; i<unit_count; i++)
81 	{
82 		if( !unit_array.SpriteArray::is_deleted(unit_recno_array[i]) )
83 			unit_array.del(unit_recno_array[i]);
84 	}
85 }
86 //------- End of function UnitMarine::~UnitMarine -------//
87 
88 
89 //------- Begin of function UnitMarine::init -------//
90 
init(int unitId,int nationRecno,int rankId,int unitLoyalty,int startX,int startY)91 void UnitMarine::init(int unitId, int nationRecno, int rankId, int unitLoyalty, int startX, int startY)
92 {
93 	attack_mode_selected = 0;       // for fix_attack_info() to set attack_info_array
94 
95 	Unit::init(unitId, nationRecno, rankId, unitLoyalty, startX, startY);
96 
97 	short spriteId = sprite_info->get_sub_sprite_info(1)->sprite_id;
98 	splash.init( spriteId, cur_x_loc(), cur_y_loc() );
99 	splash.cur_frame = 1;
100 
101 	//------- set carry_goods_capacity -------//
102 
103 	carry_goods_capacity = unit_res[unitId]->carry_goods_capacity;
104 
105 	//------- set menu mode of the unit -------//
106 
107 	UnitInfo* unitInfo = unit_res[unitId];
108 
109 	if( unitInfo->carry_unit_capacity==0 && unitInfo->carry_goods_capacity>0 )		// if this ship only carries goods
110 		menu_mode = SHIP_MENU_GOODS;
111 	else
112 		menu_mode = SHIP_MENU_UNIT;
113 }
114 //------- End of function UnitMarine::init -------//
115 
116 
117 //------- Begin of function UnitMarine::update_abs_pos ------//
118 
update_abs_pos(SpriteFrame * spriteFrame)119 void UnitMarine::update_abs_pos(SpriteFrame *spriteFrame)
120 {
121 	Unit::update_abs_pos(spriteFrame);
122 	short h = wave_height(6);
123 	abs_y1 -= h;
124 	abs_y2 -= h;
125 }
126 //------- End of function UnitMarine::update_abs_pos -------//
127 
128 
129 //------- Begin of function UnitMarine::draw -------//
130 
draw()131 void UnitMarine::draw()
132 {
133 	// -------- update splash parameter --------//
134 	// ###### begin Gilbert 8/9 #######//
135 	char oldSplashAction = splash.cur_action;
136 
137 	switch(cur_action)
138 	{
139 	case SPRITE_MOVE:
140 		splash.cur_action = SPRITE_MOVE;
141 		if( splash.cur_action != oldSplashAction)
142 			splash.cur_frame = 1;
143 		else
144 		{
145 			++splash.cur_frame;
146 			if( splash.cur_frame < 1 || splash.cur_frame > splash.cur_sprite_move()->frame_count )
147 				splash.cur_frame = 1;
148 		}
149 		break;
150 
151 	default:
152 		splash.cur_action = SPRITE_IDLE;
153 		if( splash.cur_action != oldSplashAction)
154 			splash.cur_frame = 1;
155 		else
156 		{
157 			++splash.cur_frame;
158 			if( splash.cur_frame < 1 || splash.cur_frame > splash.cur_sprite_stop()->frame_count)
159 				splash.cur_frame = 1;
160 		}
161 		break;
162 	}
163 	// ###### end Gilbert 8/9 #######//
164 
165 	splash.cur_x = cur_x;
166 	splash.cur_y = cur_y - wave_height(7);
167 	splash.cur_dir = cur_dir;
168 	splash.final_dir = final_dir;
169 	splash.turn_delay = turn_delay;
170 
171 	// --------- draw splash and then the unit --------//
172 	// ###### begin Gilbert 24/9 #######//
173 	if( cur_action != SPRITE_DIE )
174 		splash.draw();
175 	// ###### end Gilbert 24/9 #######//
176 	Unit::draw();
177 
178 	#ifdef DEBUG2
179 		if(selected_flag && 0)
180 		{
181 			vga_util.d3_panel_up( INFO_X1, INFO_Y1+144, INFO_X2, INFO_Y1+144+87 );
182 
183 			int 	 x=INFO_X1+4, y=INFO_Y1+200, refreshFlag=INFO_REPAINT;
184 			font_san.field( x, y, " " , x+2, sprite_recno, 1, INFO_X2-2, refreshFlag);
185 			font_san.field( x+20, y, " " , x+22, next_x_loc(), 1, INFO_X2-2, refreshFlag);
186 			font_san.field( x+50, y, " " , x+52, next_y_loc(), 1, INFO_X2-2, refreshFlag);
187 			font_san.field( x+70, y, " " , x+72, nation_recno, 1, INFO_X2-2, refreshFlag);
188 
189 			font_san.field( x+100, y, " " , x+102, action_mode, 1, INFO_X2-2, refreshFlag);
190 			font_san.field( x+120, y, " " , x+122, action_para, 1, INFO_X2-2, refreshFlag);
191 			font_san.field( x+140, y, " " , x+142, action_x_loc, 1, INFO_X2-2, refreshFlag);
192 			font_san.field( x+160, y, " " , x+162, action_y_loc, 1, INFO_X2-2, refreshFlag);
193 			y-=20;
194 			font_san.field( x+100, y, " " , x+102, action_mode2, 1, INFO_X2-2, refreshFlag);
195 			font_san.field( x+120, y, " " , x+122, action_para2, 1, INFO_X2-2, refreshFlag);
196 			font_san.field( x+140, y, " " , x+142, action_x_loc2, 1, INFO_X2-2, refreshFlag);
197 			font_san.field( x+160, y, " " , x+162, action_y_loc2, 1, INFO_X2-2, refreshFlag);
198 			y-=20;
199 			font_san.field( x+160, y, " " , x+162, cur_action, 1, INFO_X2-2, refreshFlag);
200 		}
201 	#endif
202 }
203 //------- End of function UnitMarine::draw -------//
204 
205 
206 //------- Begin of function UnitMarine::draw_outlined -------//
207 
draw_outlined()208 void UnitMarine::draw_outlined()
209 {
210 	// -------- update splash parameter --------//
211 	// ###### begin Gilbert 8/9 #######//
212 	char oldSplashAction = splash.cur_action;
213 
214 	switch(cur_action)
215 	{
216 	case SPRITE_MOVE:
217 		splash.cur_action = SPRITE_MOVE;
218 		if( splash.cur_action != oldSplashAction)
219 			splash.cur_frame = 1;
220 		else
221 		{
222 			++splash.cur_frame;
223 			if( splash.cur_frame < 1 || splash.cur_frame > splash.cur_sprite_move()->frame_count )
224 				splash.cur_frame = 1;
225 		}
226 		break;
227 
228 	default:
229 		splash.cur_action = SPRITE_IDLE;
230 		if( splash.cur_action != oldSplashAction)
231 			splash.cur_frame = 1;
232 		else
233 		{
234 			++splash.cur_frame;
235 			if( splash.cur_frame < 1 || splash.cur_frame > splash.cur_sprite_stop()->frame_count)
236 				splash.cur_frame = 1;
237 		}
238 		break;
239 	}
240 	// ###### end Gilbert 8/9 #######//
241 
242 	splash.cur_x = cur_x;
243 	splash.cur_y = cur_y - wave_height(7);
244 	splash.cur_dir = cur_dir;
245 	splash.final_dir = final_dir;
246 	splash.turn_delay = turn_delay;
247 
248 	// --------- draw splash and then the unit --------//
249 	// ###### begin Gilbert 24/9 #######//
250 	if( cur_action != SPRITE_DIE )
251 		splash.draw();
252 	// ###### end Gilbert 24/9 #######//
253 	Unit::draw_outlined();
254 
255 	#ifdef DEBUG2
256 		if(selected_flag && 0)
257 		{
258 			vga_util.d3_panel_up( INFO_X1, INFO_Y1+144, INFO_X2, INFO_Y1+144+87 );
259 
260 			int 	 x=INFO_X1+4, y=INFO_Y1+200, refreshFlag=INFO_REPAINT;
261 			font_san.field( x, y, " " , x+2, sprite_recno, 1, INFO_X2-2, refreshFlag);
262 			font_san.field( x+20, y, " " , x+22, next_x_loc(), 1, INFO_X2-2, refreshFlag);
263 			font_san.field( x+50, y, " " , x+52, next_y_loc(), 1, INFO_X2-2, refreshFlag);
264 			font_san.field( x+70, y, " " , x+72, nation_recno, 1, INFO_X2-2, refreshFlag);
265 
266 			font_san.field( x+100, y, " " , x+102, action_mode, 1, INFO_X2-2, refreshFlag);
267 			font_san.field( x+120, y, " " , x+122, action_para, 1, INFO_X2-2, refreshFlag);
268 			font_san.field( x+140, y, " " , x+142, action_x_loc, 1, INFO_X2-2, refreshFlag);
269 			font_san.field( x+160, y, " " , x+162, action_y_loc, 1, INFO_X2-2, refreshFlag);
270 			y-=20;
271 			font_san.field( x+100, y, " " , x+102, action_mode2, 1, INFO_X2-2, refreshFlag);
272 			font_san.field( x+120, y, " " , x+122, action_para2, 1, INFO_X2-2, refreshFlag);
273 			font_san.field( x+140, y, " " , x+142, action_x_loc2, 1, INFO_X2-2, refreshFlag);
274 			font_san.field( x+160, y, " " , x+162, action_y_loc2, 1, INFO_X2-2, refreshFlag);
275 			y-=20;
276 			font_san.field( x+160, y, " " , x+162, cur_action, 1, INFO_X2-2, refreshFlag);
277 		}
278 	#endif
279 }
280 //------- End of function UnitMarine::draw_outlined -------//
281 
282 
283 //------- Begin of function UnitMarine::wave_height -------//
284 
wave_height(int phase)285 short UnitMarine::wave_height(int phase)
286 {
287 	err_when( phase < 0);
288 	static short height[WAVE_CYCLE] = { 4,3,2,1,0,1,2,3 };
289 	return height[((sys.frame_count /4) + phase) % WAVE_CYCLE];
290 }
291 //------- End of function UnitMarine::wave_height -------//
292 
293 
294 //--------- Begin of function UnitMarine::del_unit ---------//
295 //
296 // Delete a unit from the ship. This function is called by
297 // Unit::deinit() when the unit is killed.
298 //
299 // <int> unitRecno - recno of the unit to be loaded.
300 //
del_unit(int unitRecno)301 void UnitMarine::del_unit(int unitRecno)
302 {
303 	for( int i=0 ; i<unit_count ; i++ )
304 	{
305 		if( unit_recno_array[i] == unitRecno )
306 		{
307 			err_when( unit_count > MAX_UNIT_IN_SHIP );
308 
309 			misc.del_array_rec(unit_recno_array, unit_count, sizeof(unit_recno_array[0]), i+1);
310 			return;
311 		}
312 	}
313 
314 	err_here();
315 }
316 //----------- End of function UnitMarine::del_unit -----------//
317 
318 
319 //--------- Begin of function UnitMarine::load_unit ---------//
320 //
321 // Load an unit to the ship.
322 //
323 // <int> unitRecno - recno of the unit to be loaded.
324 //
load_unit(int unitRecno)325 void UnitMarine::load_unit(int unitRecno)
326 {
327 	if(unit_array.is_deleted(unitRecno))
328 		return;
329 
330 	Unit *unitPtr = unit_array[unitRecno];
331 
332 	if(unitPtr->hit_points<=0 || unitPtr->cur_action==SPRITE_DIE || unitPtr->action_mode2==ACTION_DIE)
333 		return;
334 
335 	if( unit_count == MAX_UNIT_IN_SHIP )
336 		return;
337 
338 	unit_recno_array[unit_count++] = unitRecno;
339 
340 	unitPtr->set_mode(UNIT_MODE_ON_SHIP, sprite_recno);	// set unit mode
341 
342 	if(unitPtr->selected_flag)
343 	{
344 		unitPtr->selected_flag = 0;
345 		unit_array.selected_count--;
346 	}
347 	unitPtr->deinit_sprite();
348 
349 	//--- if this marine unit is currently selected ---//
350 
351 	if(unit_array.selected_recno==sprite_recno)
352 	{
353 		if(!remote.is_enable() || nation_recno==nation_array.player_recno || config.show_ai_info)
354 			disp_info(INFO_UPDATE);
355 	}
356 }
357 //----------- End of function UnitMarine::load_unit -----------//
358 
359 
360 //--------- Begin of function UnitMarine::unload_unit ---------//
361 //
362 // Unload an unit from the ship.
363 //
364 // <int> unitSeqId - sequence id. of the unit in unit_recno_array[]
365 //
unload_unit(int unitSeqId,char remoteAction)366 void UnitMarine::unload_unit(int unitSeqId, char remoteAction)
367 {
368 	err_when(unitSeqId > unit_count);
369 
370 	if(!remoteAction && remote.is_enable() )
371 	{
372 		// packet structure : <unit recno> <unitSeqId>
373 		short *shortPtr = (short *)remote.new_send_queue_msg(MSG_U_SHIP_UNLOAD_UNIT, 2*sizeof(short));
374 		*shortPtr = sprite_recno;
375 		shortPtr[1] = unitSeqId;
376 		return;
377 	}
378 
379 	//-------- unload unit now -------//
380 
381 	if( unloading_unit(0, unitSeqId-1) ) 	// unit is unloaded
382 	{
383 		err_when( unit_count+1 > MAX_UNIT_IN_SHIP );
384 
385 		misc.del_array_rec(unit_recno_array, unit_count+1, sizeof(unit_recno_array[0]), unitSeqId);
386 	}
387 }
388 //----------- End of function UnitMarine::unload_unit -----------//
389 
390 
391 //--------- Begin of function UnitMarine::unload_all_units ---------//
unload_all_units(char remoteAction)392 void UnitMarine::unload_all_units(char remoteAction)
393 {
394 	if(!remoteAction && remote.is_enable() )
395 	{
396 		// packet structure : <unit recno>
397 		short *shortPtr = (short *)remote.new_send_queue_msg(MSG_U_SHIP_UNLOAD_ALL_UNITS, sizeof(short));
398 		*shortPtr = sprite_recno;
399 		return;
400 	}
401 
402 	unloading_unit(1);	// unload all units
403 }
404 //----------- End of function UnitMarine::unload_all_units -----------//
405 
406 
407 //--------- Begin of function UnitMarine::unloading_unit ---------//
408 //
409 //	<int> isAll			- 1 for unload all the units
410 //							- otherwise 0
411 // <int>	unitSeqId	- if(isAll==0) unitSeqId+1 is the recno of the
412 //							  selected unit in unit_recno_array[]
413 //
unloading_unit(int isAll,int unitSeqId)414 int UnitMarine::unloading_unit(int isAll, int unitSeqId)
415 {
416 	if( !is_on_coast() )
417 		return 0;
418 
419 	//-------------------------------------------------------------------------//
420 	// return if no territory is nearby the ship
421 	//-------------------------------------------------------------------------//
422 
423 	int curXLoc = next_x_loc();	// ship location
424 	int curYLoc = next_y_loc();
425 	int unprocess = isAll ? unit_count : 1;
426 	Unit *unitPtr = isAll ? unit_array[unit_recno_array[unprocess-1]] : unit_array[unit_recno_array[unitSeqId]];
427 	Location *locPtr;
428 	int xShift, yShift, checkXLoc, checkYLoc;
429 	int regionId = 0; // unload all the units in the same territory
430 	int found = 0, i = 2;
431 	int sqtSize = 5, sqtArea = sqtSize*sqtSize;
432 
433 	#ifdef DEBUG
434 		long debugCount = 0L;
435 	#endif
436 
437 	if(isAll &&  nation_recno == nation_array.player_recno )		// for player's camp, patrol() can only be called when the player presses the button.
438 		power.reset_selection();
439 
440 	while(unprocess) // using the calculated 'i' to reduce useless calculation
441 	{
442 		err_when(debugCount++ > 4*long(MAX_WORLD_X_LOC*MAX_WORLD_Y_LOC));
443 
444 		misc.cal_move_around_a_point(i, MAX_WORLD_X_LOC, MAX_WORLD_Y_LOC, xShift, yShift);
445 		checkXLoc = curXLoc+xShift;
446 		checkYLoc = curYLoc+yShift;
447 		if(checkXLoc<0 || checkXLoc>=MAX_WORLD_X_LOC || checkYLoc<0 || checkYLoc>=MAX_WORLD_Y_LOC)
448 		{
449 			i++;
450 			continue;
451 		}
452 
453 		locPtr = world.get_loc(checkXLoc, checkYLoc);
454 
455 		//-------------------------------------------------------------------------//
456 		// check for space to unload the unit
457 		//-------------------------------------------------------------------------//
458 		if(!regionId || locPtr->region_id == regionId)
459 		{
460 			if(locPtr->walkable())
461 				found = 1;
462 
463 			if(locPtr->can_move(UNIT_LAND))//unitPtr->mobile_type))
464 			{
465 				regionId = locPtr->region_id;
466 
467 				unitPtr->init_sprite(checkXLoc, checkYLoc);
468 				unitPtr->set_mode(0);
469 
470 				if( isAll && nation_recno == nation_array.player_recno )		// for player's camp, patrol() can only be called when the player presses the button.
471 				{
472 					unitPtr->selected_flag = 1; // mark selected if unload all
473 					unit_array.selected_count++;
474 
475 					if( !unit_array.selected_recno )
476 						unit_array.selected_recno = unitPtr->sprite_recno;
477 				}
478 
479 				unprocess--;
480 				unit_count--;
481 
482 				if(unprocess)
483 					unitPtr = unit_array[unit_recno_array[unprocess-1]]; // point to next unit
484 				else
485 					break;	// finished, all have been unloaded
486 			}
487 		}
488 
489 		//-------------------------------------------------------------------------//
490 		// stop checking if there is totally bouned by unacessible location
491 		//-------------------------------------------------------------------------//
492 		if(i==sqtArea)
493 		{
494 			if(found)
495 			{
496 				found = 0;	// reset found
497 				sqtSize += 2;
498 				sqtArea = sqtSize*sqtSize;
499 			}
500 			else // no continuous location for the unit to unload, some units can't be unloaded
501 				return 0;
502 		}
503 
504 		i++;
505 	}
506 
507 	//-------- display info --------//
508 
509 	if( nation_recno == nation_array.player_recno )		// for player's camp, patrol() can only be called when the player presses the button.
510 		info.disp();
511 
512 	return 1;
513 }
514 //----------- End of function UnitMarine::unloading_unit -----------//
515 
516 
517 //--------- Begin of function UnitMarine::is_on_coast ---------//
518 //
519 // Return whether the unit is on the coast and ready for unloading.
520 //
is_on_coast()521 int UnitMarine::is_on_coast()
522 {
523 	Location *locPtr;
524 	int 		xShift, yShift, checkXLoc, checkYLoc, found=0;
525 	int 		curXLoc = next_x_loc();	// ship location
526 	int 		curYLoc = next_y_loc();
527 
528 	for(int i=2; i<=9; i++) // checking for the surrouding location
529 	{
530 		misc.cal_move_around_a_point(i, 3, 3, xShift, yShift);
531 
532 		checkXLoc = curXLoc + xShift;
533 		checkYLoc = curYLoc + yShift;
534 
535 		if(checkXLoc<0 || checkXLoc>=MAX_WORLD_X_LOC || checkYLoc<0 || checkYLoc>=MAX_WORLD_Y_LOC)
536 			continue;
537 
538 		locPtr = world.get_loc(checkXLoc, checkYLoc);
539 
540 		if(terrain_res[locPtr->terrain_id]->average_type!=TERRAIN_OCEAN && // a territory nearby
541 			locPtr->walkable())
542 		{
543 			return 1;
544 		}
545 	}
546 
547 	return 0;
548 }
549 //----------- End of function UnitMarine::is_on_coast -----------//
550 
551 
552 //--------- Begin of function UnitMarine::extra_move ---------//
extra_move()553 void UnitMarine::extra_move()
554 {
555 	static char offset[3] = {0, 1, -1};
556 
557 	int curXLoc = next_x_loc();
558 	int curYLoc = next_y_loc();
559 
560 	int vecX = action_x_loc2 - curXLoc;
561 	int vecY = action_y_loc2 - curYLoc;
562 	int checkXLoc, checkYLoc, i, found=0;
563 
564 	if(vecX==0 || vecY==0)
565 	{
566 		if(vecX==0)
567 		{
568 			vecY /= abs(vecY);
569 			checkYLoc = curYLoc + vecY;
570 		}
571 		else // vecY==0
572 		{
573 			vecX /= abs(vecX);
574 			checkXLoc = curXLoc + vecX;
575 		}
576 
577 		for(i=0; i<3; i++)
578 		{
579 			if(vecX==0)
580 				checkXLoc = curXLoc + offset[i];
581 			else
582 				checkYLoc = curYLoc + offset[i];
583 
584 			if(checkXLoc<0 || checkXLoc>=MAX_WORLD_X_LOC || checkYLoc<0 || checkYLoc>=MAX_WORLD_Y_LOC)
585 				continue;
586 
587 			if(world.get_loc(checkXLoc, checkYLoc)->can_move(mobile_type))
588 			{
589 				found++;
590 				break;
591 			}
592 		}
593 	}
594 	else
595 	{
596 		vecX /= abs(vecX);
597 		vecY /= abs(vecY);
598 		checkXLoc = curXLoc + vecX;
599 		checkYLoc = curYLoc + vecY;
600 
601 		if(world.get_loc(checkXLoc, checkYLoc)->can_move(mobile_type))
602 			found++;
603 	}
604 
605 	if(!found)
606 		return;
607 
608 	set_dir(curXLoc, curYLoc, checkXLoc, checkYLoc);
609 	cur_action = SPRITE_SHIP_EXTRA_MOVE;
610 	go_x = checkXLoc*ZOOM_LOC_WIDTH;
611 	go_y = checkYLoc*ZOOM_LOC_HEIGHT;
612 	err_when(cur_x==go_x && cur_y==go_y);
613 	//extra_move_in_beach = EXTRA_MOVING_IN;
614 }
615 //----------- End of function UnitMarine::extra_move -----------//
616 
617 
618 //------- Begin of function UnitMarine::process_extra_move ------//
619 
process_extra_move()620 void UnitMarine::process_extra_move()
621 {
622 	static short vector_x_array[] = { 0,  1, 1, 1, 0, -1, -1, -1};	// default vectors, temporary only
623 	static short vector_y_array[] = {-1, -1, 0, 1, 1,  1,  0, -1};
624 
625 	if(!match_dir()) // process turning
626 		return;
627 
628 	if(cur_x!=go_x || cur_y!=go_y)
629 	{
630 		//------------------------------------------------------------------------//
631 		// set cargo_recno, extra_move_in_beach
632 		//------------------------------------------------------------------------//
633 		if(cur_x==next_x && cur_y==next_y)
634 		{
635 			int goXLoc = go_x>>ZOOM_X_SHIFT_COUNT;
636 			int goYLoc = go_y>>ZOOM_Y_SHIFT_COUNT;
637 			if(!world.get_loc(goXLoc, goYLoc)->can_move(mobile_type))
638 			{
639 				go_x = next_x;
640 				go_y = next_y;
641 				return;
642 			}
643 
644 			int curXLoc = next_x_loc();
645 			int curYLoc = next_y_loc();
646 			world.set_unit_recno(curXLoc, curYLoc, mobile_type, 0);
647 			world.set_unit_recno(goXLoc, goYLoc, mobile_type, sprite_recno);
648 			next_x = go_x;
649 			next_y = go_y;
650 
651 			err_when( ((curXLoc%2)|(curYLoc%2)) + ((goXLoc%2)|(goYLoc%2)) != 1); // one pair location must be even, another is not even
652 			in_beach = !(curXLoc%2 || curYLoc%2);
653 
654 			if(goXLoc%2 || goYLoc%2) // not even location
655 				extra_move_in_beach = EXTRA_MOVING_IN;
656 			else // even location
657 				extra_move_in_beach = EXTRA_MOVING_OUT;
658 		}
659 		//else
660 		//	int debug = 0;
661 
662 		//---------- process moving -----------//
663 		short stepX = sprite_info->speed;
664 		short stepY = sprite_info->speed;
665 		short vectorX = vector_x_array[final_dir] * sprite_info->speed;	// cur_dir may be changed in the above set_next() call
666 		short vectorY = vector_y_array[final_dir] * sprite_info->speed;
667 
668 		if(abs(cur_x-go_x) <= stepX)
669 			cur_x = go_x;
670 		else
671 			cur_x += vectorX;
672 
673 		if(abs(cur_y-go_y) <= stepY)
674 			cur_y = go_y;
675 		else
676 			cur_y += vectorY;
677 
678 		err_when(extra_move_in_beach!=EXTRA_MOVING_IN && extra_move_in_beach!=EXTRA_MOVING_OUT);
679 		err_when(cur_action!=SPRITE_SHIP_EXTRA_MOVE);
680 	}
681 
682 	if(cur_x==go_x && cur_y==go_y)
683 	{
684 		if(result_node_array==NULL)
685 		{
686 			cur_action = SPRITE_IDLE;
687 			cur_frame  = 1;
688 			move_to_x_loc = next_x_loc();
689 			move_to_y_loc = next_y_loc();
690 		}
691 		else
692 		{
693 			cur_action = SPRITE_MOVE;
694 			next_move();
695 		}
696 
697 		if(in_beach)
698 		{
699 			extra_move_in_beach = EXTRA_MOVE_FINISH;
700 			err_when(move_to_x_loc%2==0 && move_to_y_loc%2==0);
701 			err_when(result_node_array || result_path_dist);
702 		}
703 		else
704 		{
705 			extra_move_in_beach = NO_EXTRA_MOVE;
706 			err_when(move_to_x_loc%2 || move_to_y_loc%2);
707 			err_when(result_node_array || result_path_dist);
708 		}
709 
710 		err_when(cur_action==SPRITE_IDLE && (extra_move_in_beach==EXTRA_MOVING_IN || extra_move_in_beach==EXTRA_MOVING_OUT));
711 	}
712 }
713 //----------- End of function UnitMarine::process_extra_move -----------//
714 
715 
716 //------------ Begin of function UnitMarine::actual_damage --------------//
717 //
718 // This function returns the actual hit damage this unit can do to a target.
719 //
actual_damage()720 float UnitMarine::actual_damage()
721 {
722 	float attackDamage = Unit::actual_damage();
723 
724 	//-----------------------------------------//
725 	//
726 	// If there is units on the ship, the units
727 	// leadership will increase the attacking damage.
728 	//
729 	// actual damage = normal damage X (100+highest leadership unit on the ship) / 100
730 	//
731 	//-----------------------------------------//
732 
733 	Unit* unitPtr;
734 	int 	t, highestLeadership=0;
735 
736 	for( int i=0 ; i<unit_count ; i++ )
737 	{
738 		unitPtr = unit_array[ unit_recno_array[i] ];
739 
740 		if( unitPtr->skill.skill_id == SKILL_LEADING )
741 		{
742 			if( (t=unitPtr->skill.skill_level) > highestLeadership )
743 				highestLeadership = t;
744 		}
745 	}
746 
747 	return attackDamage * (100+highestLeadership) / 100;
748 }
749 //------------ End of function UnitMarine::actual_damage --------------//
750 
751 
752 //------- Begin of function UnitMarine::total_carried_goods -------//
753 
total_carried_goods()754 int UnitMarine::total_carried_goods()
755 {
756 	int totalQty=0;
757 
758 	for( int i=0 ; i<MAX_RAW ; i++ )
759 	{
760 		totalQty += raw_qty_array[i];
761 		totalQty += product_raw_qty_array[i];
762 	}
763 
764    return totalQty;
765 }
766 //------- End of function UnitMarine::total_carried_goods -------//
767 
768 
769 //------- Begin of function UnitMarine::can_resign -------//
can_resign()770 int UnitMarine::can_resign()
771 {
772 	err_when(unit_count < 0);
773    return unit_count == 0;
774 }
775 //------- End of function UnitMarine::can_resign -------//
776