1 /*
2  * Seven Kingdoms: Ancient Adversaries
3  *
4  * Copyright 1997,1998 Enlight Software Ltd.
5  * Copyright 2020 Jesse Allen
6  *
7  * This program is free software: you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation, either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
19  *
20  */
21 
22 //Filename    : OU_CARA.CPP
23 //Description : Unit Caravan
24 
25 #include <OVGA.h>
26 #include <vga_util.h>
27 #include <OSTR.h>
28 #include <OHELP.h>
29 #include <OFONT.h>
30 #include <OINFO.h>
31 #include <OCONFIG.h>
32 #include <OIMGRES.h>
33 #include <OMOUSE.h>
34 #include <OPOWER.h>
35 #include <OBUTTON.h>
36 #include <OBUTT3D.h>
37 #include <ONATION.h>
38 #include <OU_CARA.h>
39 #include <OREMOTE.h>
40 #include <OF_MINE.h>
41 #include <OF_FACT.h>
42 #include <OBUTTCUS.h>
43 #include <OSE.h>
44 #include "gettext.h"
45 
46 //------------- Define static vars ------------//
47 
48 static Button 			button_set_stop[MAX_STOP_FOR_CARAVAN];
49 static Button 			button_go_stop[MAX_STOP_FOR_CARAVAN];
50 static Button 			button_cancel_stop[MAX_STOP_FOR_CARAVAN];
51 static ButtonCustom	button_select_array[MAX_STOP_FOR_CARAVAN][MAX_GOODS_SELECT_BUTTON];
52 
53 static void				i_disp_caravan_select_button(ButtonCustom *button, int repaintBody);
54 
55 //--------- Begin of function UnitCaravan::UnitCaravan ---------//
56 //
UnitCaravan()57 UnitCaravan::UnitCaravan()
58 {
59 	memset( stop_array, 0, MAX_STOP_FOR_CARAVAN * sizeof(CaravanStop) );
60 
61 	journey_status		= ON_WAY_TO_FIRM;
62 	dest_stop_id		= 1;
63 	stop_defined_num	= 0;
64 	wait_count			= 0;
65 	stop_x_loc			= 0;
66 	stop_y_loc			= 0;
67 
68 	memset(raw_qty_array, 0, sizeof(short)*MAX_RAW);
69 	memset(product_raw_qty_array, 0, sizeof(short)*MAX_PRODUCT);
70 }
71 //---------- End of function UnitCaravan::UnitCaravan ----------//
72 
73 
74 //--------- Begin of function UnitCaravan::disp_info ---------//
75 //
disp_info(int refreshFlag)76 void UnitCaravan::disp_info(int refreshFlag)
77 {
78 	disp_basic_info(INFO_Y1, refreshFlag);
79 
80 	if( !config.show_ai_info && !is_own() )
81 		return;
82 
83 	disp_stop(INFO_Y1+54, refreshFlag);
84 
85 	disp_goods(INFO_Y1+234, refreshFlag);
86 }
87 //---------- End of function UnitCaravan::disp_info ----------//
88 
89 
90 //--------- Begin of function UnitCaravan::detect_info ---------//
91 //
detect_info()92 void UnitCaravan::detect_info()
93 {
94 	if(!is_visible())
95 		return;
96 
97 	if( detect_basic_info() )
98 		return;
99 
100 	if( detect_select_hotkey() )
101 		return;
102 
103 	if( !is_own() && !config.show_ai_info )
104 		return;
105 
106 	detect_stop();
107 }
108 //---------- End of function UnitCaravan::detect_info ----------//
109 
110 
111 //--------- Begin of function UnitCaravan::is_in_build_menu ---------//
112 // Returns true if a unit is currently in build mode.
113 // Only reliable if this unit is the selected unit.
114 // Used by Info to detect if the build mode is opened.
115 //
is_in_build_menu()116 bool UnitCaravan::is_in_build_menu()
117 {
118 	return false;
119 }
120 //----------- End of function UnitCaravan::is_in_build_menu -----------//
121 
122 
123 //--------- Begin of function UnitCaravan::disp_stop ---------//
124 //
disp_stop(int dispY1,int refreshFlag)125 void UnitCaravan::disp_stop(int dispY1, int refreshFlag)
126 {
127 //###### begin trevor 15/9 #######//
128 
129 	if(refreshFlag!=INFO_REPAINT && refreshFlag!=INFO_UPDATE)
130 		return;
131 
132 	int 	i, x=INFO_X1, y=dispY1, needRefresh;
133 	Firm	*firmPtr;
134 	static short last_firm_recno_array[MAX_STOP_FOR_CARAVAN];
135 
136 	for(i=0 ; i<MAX_STOP_FOR_CARAVAN ; i++, y+=60)
137 	{
138 		//---- compare with the previous display and see if an update is needed ----//
139 
140 		if( refreshFlag==INFO_REPAINT )
141 		{
142 			needRefresh = 1;
143 		}
144 		else if( last_firm_recno_array[i] != stop_array[i].firm_recno )
145 		{
146 			needRefresh = 1;
147 		}
148 
149 		last_firm_recno_array[i] = stop_array[i].firm_recno;
150 
151 		//----------------------------------------//
152 
153 		if( !stop_array[i].firm_recno ||
154 			 firm_array.is_deleted(stop_array[i].firm_recno) )
155 		{
156 			if( refreshFlag == INFO_REPAINT )
157 			{
158 				vga_util.d3_panel_up(x, y, INFO_X2, y+58);
159 #if(defined(FRENCH))
160 				button_set_stop[i].paint_text( x+4, y+37, x+86, y+56, "Set Stop" );
161 #else
162 				button_set_stop[i].paint_text( x+4, y+37, x+80, y+56, _("Set Stop") );
163 #endif
164 				button_set_stop[i].set_help_code( "CSETSTOP" );
165 			}
166 		}
167 		else
168 		{
169 			if( refreshFlag == INFO_REPAINT )
170 			{
171 				vga_util.d3_panel_up(x, y, INFO_X2, y+58);
172 
173 				//-------- display name of the stop --------//
174 
175 				firmPtr = firm_array[ stop_array[i].firm_recno ];
176 				nation_array[firmPtr->nation_recno]->disp_nation_color(x+4, y+4);
177 				font_san.put(x+20, y+4, firmPtr->firm_name());
178 				font_san.put(x+4, y+19, _("Pick up:"));
179 
180 #if(defined(FRENCH))
181 				button_set_stop[i].paint_text( x+4, y+37, x+86, y+56, "Set Stop" );
182 #else
183 				button_set_stop[i].paint_text( x+4, y+37, x+80, y+56, _("Set Stop") );
184 #endif
185 
186 				button_set_stop[i].set_help_code( "CSETSTOP" );
187 
188 #if(defined(FRENCH))
189 				button_go_stop[i].paint_text( x+90, y+37, x+180, y+56, "View Stop" );
190 #else
191 				button_go_stop[i].paint_text( x+84, y+37, x+180, y+56, _("View Stop") );
192 #endif
193 				button_go_stop[i].set_help_code( "CGOSTOP" );
194 
195 				button_cancel_stop[i].paint_text( x+184, y+37, INFO_X2-4, y+56, "X" );
196 				button_cancel_stop[i].set_help_code( "CDELSTOP" );
197 			}
198 
199 			disp_goods_select_button(i, y+1, refreshFlag);
200 		}
201 	}
202 //###### end trevor 15/9 #######//
203 
204 }
205 //---------- End of function UnitCaravan::disp_stop ----------//
206 
207 
208 //--------- Begin of function UnitCaravan::detect_stop ---------//
209 //
detect_stop()210 void UnitCaravan::detect_stop()
211 {
212 	int i, x=INFO_X1;
213 
214 	for( i=0 ; i<MAX_STOP_FOR_CARAVAN ; i++ )
215 	{
216 		// ###### begin Gilbert 14/8 #########//
217 		if( button_set_stop[i].detect() && is_own() )
218 			power.issue_command( COMMAND_SET_CARAVAN_STOP, sprite_recno, i+1 );		// i+1 - stop id., passed as a parameter of the command
219 		// ###### end Gilbert 14/8 #########//
220 
221 		if(i>=stop_defined_num)
222 			continue;
223 
224 		if(button_cancel_stop[i].detect())
225 		{
226 			if(is_visible())
227 			{
228 				del_stop(i+1, COMMAND_PLAYER);
229 				// ###### begin Gilbert 26/9 ######//
230 				se_ctrl.immediate_sound("TURN_OFF");
231 				// ###### end Gilbert 26/9 ######//
232 			}
233 		}
234 
235 		for(int b=0; b<MAX_GOODS_SELECT_BUTTON; ++b)
236 		{
237 			if(button_select_array[i][b].detect())
238 			{
239 				// ###### begin Gilbert 26/9 ######//
240 				se_ctrl.immediate_sound(
241 					button_select_array[i][b].elastic_flag || button_select_array[i][b].pushed_flag ?
242 					(char*)"TURN_ON" : (char*)"TURN_OFF");
243 				// ###### end Gilbert 26/9 ######//
244 
245 				set_stop_pick_up(i+1, b, COMMAND_PLAYER); // b = 1 - MAX_PICK_UP_GOODS
246 			}
247 		}
248 
249 		if( button_go_stop[i].detect() )
250 		{
251 			Firm* firmPtr = firm_array[ stop_array[i].firm_recno ];
252 			world.go_loc( firmPtr->center_x, firmPtr->center_y );
253 		}
254 	}
255 }
256 //---------- End of function UnitCaravan::detect_stop ----------//
257 
258 
259 //--------- Begin of function UnitCaravan::disp_goods_select_button ---------//
260 
disp_goods_select_button(int stopNum,int dispY1,int refreshFlag)261 void UnitCaravan::disp_goods_select_button(int stopNum, int dispY1, int refreshFlag)
262 {
263 	if(refreshFlag!=INFO_REPAINT && refreshFlag!=INFO_UPDATE)
264 		return;
265 
266 	#define SHIFT_X_OFFSET	73
267 	#define SELECT_BUTTON_WIDTH	16
268 	#define SELECT_BUTTON_HEIGHT	16
269 
270 	CaravanStop	*stopPtr = &stop_array[stopNum];
271 	Firm *firmPtr = firm_array[stopPtr->firm_recno];
272 
273 	int  x=INFO_X1+SHIFT_X_OFFSET, y=dispY1+17, x1, pick_up_goods = 0;
274 	char *pickUpArray = stopPtr->pick_up_array;
275 	char isPush;
276 
277 	//-------------- draw the buttons for the cargo -------------//
278 
279 //###### begin trevor 13/9 #######//
280 
281 	for(int i=1 ;i<=MAX_PICK_UP_GOODS; ++i, pickUpArray++)
282 	{
283 		int rawId = i;
284 		if( rawId < 1 || rawId > MAX_RAW )
285 			rawId = 0;
286 		int productId = i-MAX_RAW;
287 		if( productId < 1 || productId > MAX_PRODUCT )
288 			productId = 0;
289 
290 		int stock = -1;
291 
292 		if( FirmMarket *firmMarket = firmPtr->cast_to_FirmMarket() )
293 		{
294 			MarketGoods *marketGoods;
295 			if( rawId )
296 			{
297 				marketGoods = firmMarket->market_raw_array[rawId-1];
298 				err_when( marketGoods && marketGoods->raw_id != rawId );
299 			}
300 			else if( productId )
301 			{
302 				marketGoods = firmMarket->market_product_array[productId-1];
303 				err_when( marketGoods && marketGoods->product_raw_id != productId );
304 			}
305 			else
306 			{
307 				err_here();
308 				marketGoods = NULL;
309 			}
310 
311 			if( marketGoods )
312 			{
313 				stock = (int) marketGoods->stock_qty;
314 			}
315 		}
316 		else if( FirmMine *firmMine = firmPtr->cast_to_FirmMine() )
317 		{
318 			if( rawId && firmMine->raw_id == rawId )
319 			{
320 				stock = (int) firmMine->stock_qty;
321 			}
322 		}
323 		else if( FirmFactory *firmFactory = firmPtr->cast_to_FirmFactory() )
324 		{
325 			if( productId && firmFactory->product_raw_id == productId )
326 			{
327 				stock = (int) firmFactory->stock_qty;
328 			}
329 			//else if( rawId && firmFactory->product_raw_id == rawId )
330 			//{
331 			//	stock = (int) firmFactory->raw_stock_qty;
332 			//}
333 		}
334 
335 		x1 = x + i*SELECT_BUTTON_WIDTH;
336 
337 		if( stock >= 0 )
338 		{
339 			isPush = stopPtr->pick_up_array[i-1];
340 			err_when(isPush && (stopPtr->pick_up_type==AUTO_PICK_UP || stopPtr->pick_up_type==NO_PICK_UP));
341 
342 			button_select_array[stopNum][i].paint(x1, y, x1+SELECT_BUTTON_WIDTH,
343 				y+SELECT_BUTTON_HEIGHT, i_disp_caravan_select_button, ButtonCustomPara(this, i),
344 				0, isPush); // 0 for inelastic
345 			pick_up_goods++;
346 		}
347 		else
348 		{
349 			vga_util.blt_buf( x1, y, x1+SELECT_BUTTON_WIDTH, y+SELECT_BUTTON_HEIGHT, 0 );
350 		}
351 	}
352 
353 	//---------------- draw the buttons for auto_pick_up and no_pick_up -------------//
354 
355 	if( pick_up_goods>1 )
356 	{
357 		x1 = x;
358 		isPush = (stopPtr->pick_up_type==AUTO_PICK_UP);
359 		button_select_array[stopNum][AUTO_PICK_UP].paint(x1, y, x1+SELECT_BUTTON_WIDTH,
360 			y+SELECT_BUTTON_HEIGHT, i_disp_caravan_select_button, ButtonCustomPara(this, AUTO_PICK_UP),
361 			0, isPush); // 0 for inelastic
362 
363 		x1 = x+SELECT_BUTTON_WIDTH*NO_PICK_UP;
364 		button_select_array[stopNum][NO_PICK_UP].paint(x1, y, x1+SELECT_BUTTON_WIDTH,
365 			y+SELECT_BUTTON_HEIGHT, i_disp_caravan_select_button, ButtonCustomPara(this, NO_PICK_UP));
366 	}
367 	else
368 	{
369 		x1 = x;
370 		vga_util.blt_buf( x1, y, x1+SELECT_BUTTON_WIDTH, y+SELECT_BUTTON_HEIGHT, 0 );
371 
372 		x1 = x+SELECT_BUTTON_WIDTH*NO_PICK_UP;
373 		vga_util.blt_buf( x1, y, x1+SELECT_BUTTON_WIDTH, y+SELECT_BUTTON_HEIGHT, 0 );
374 	}
375 
376 	//###### end trevor 13/9 #######//
377 }
378 //---------- End of function UnitCaravan::disp_goods_select_button ----------//
379 
380 
381 //--------- Begin of function UnitCaravan::set_stop_pick_up ---------//
382 //
383 // Set the pickup type of a specific stop of this caravan.
384 //
385 // <int> stopId		  - id. of the stop. (1 - MAX_STOP_FOR_CARAVAN)
386 // <int> newPickUpType - set the pickup type of the specific stop. (0 - MAX_GOODS_SELECT_BUTTON-1)
387 // <int> remoteActoin  - remote action type
388 //
set_stop_pick_up(int stopId,int newPickUpType,int remoteAction)389 void UnitCaravan::set_stop_pick_up(int stopId, int newPickUpType, int remoteAction)
390 {
391 	if(remote.is_enable())
392 	{
393 		if(!remoteAction)
394 		{
395 			// packet structure : <unit recno> <stop id> <new pick_up_type>
396 			short *shortPtr = (short *)remote.new_send_queue_msg(MSG_U_CARA_CHANGE_GOODS, 3*sizeof(short));
397 			*shortPtr = sprite_recno;
398 
399 			shortPtr[1] = stopId;
400 			shortPtr[2] = newPickUpType;
401 			return;
402 		}
403 		else //-------- validate remote message ----------//
404 		{
405 			//-*******************************************************-//
406 			/*char mess[255];
407 			sprintf(mess, "Change Seed !!!! \r\n");
408 			OutputDebugString(mess);*/
409 
410 			/*Firm *firmPtr = firm_array[stop_array[stopId-1].firm_recno];
411 
412 			switch(firmPtr->firm_id)
413 			{
414 				case FIRM_MINE:
415 						//firmPtr->sell_firm(COMMAND_AUTO);
416 						//firm_array[stop_array[0].firm_recno]->sell_firm(COMMAND_AUTO);
417 						break;
418 				case FIRM_FACTORY:
419 						break;
420 				case FIRM_MARKET:
421 						break;
422 			}
423 
424 			update_stop_list();
425 			if(unit_array.selected_recno == sprite_recno)
426 			{
427 				if(!remote.is_enable() || nation_renco==nation_array.player_recno || config.show_ai_info)
428 					disp_stop(INFO_Y1+54, INFO_UPDATE);
429 			}*/
430 			//-*******************************************************-//
431 
432 			err_when(!is_visible()); // no action if the unit is invisible
433 			if(firm_array.is_deleted(stop_array[stopId-1].firm_recno))
434 				return; // firm is deleted
435 
436 			if(stop_defined_num<stopId)
437 				return; // stop_list is updated, stop exists no more
438 
439 			#ifdef DEBUG
440 			//-*******************************************************-//
441 			/*//char mess[255];
442 			sprintf(mess, "Change Seed : %d %d %d\r\n", stopId, newPickUpType, sprite_recno);
443 			OutputDebugString(mess);*/
444 			//-*******************************************************-//
445 
446 			misc.set_random_seed(stopId + newPickUpType*(misc.random(4)+1)*10 + sprite_recno*100*misc.random(100) +
447 									misc.get_random_seed());
448 
449 			//-*******************************************************-//
450 			/*//char mess[255];
451 			sprintf(mess, "Change Seed : %d\r\n", misc.random_seed);
452 			OutputDebugString(mess);*/
453 			//-*******************************************************-//
454 			#endif
455 		}
456 	}
457 
458 	switch(newPickUpType)
459 	{
460 	case AUTO_PICK_UP:
461 		stop_array[stopId-1].pick_up_set_auto();
462 		break;
463 
464 	case NO_PICK_UP:
465 		stop_array[stopId-1].pick_up_set_none();
466 		break;
467 
468 	default:
469 		err_when(newPickUpType<PICK_UP_RAW_FIRST || newPickUpType>PICK_UP_PRODUCT_LAST);
470 		stop_array[stopId-1].pick_up_toggle(newPickUpType);
471 		break;
472 	}
473 
474 	if(unit_array.selected_recno==sprite_recno)
475 	{
476 		if(nation_recno==nation_array.player_recno || config.show_ai_info)
477 			disp_stop(INFO_Y1+54, INFO_UPDATE);
478 	}
479 }
480 //---------- End of function UnitCaravan::set_stop_pick_up ----------//
481 
482 
483 //--------- Begin of function UnitCaravan::disp_goods ---------//
484 //
disp_goods(int dispY1,int refreshFlag)485 void UnitCaravan::disp_goods(int dispY1, int refreshFlag)
486 {
487 	if( refreshFlag == INFO_REPAINT )
488 		vga_util.d3_panel_up( INFO_X1, dispY1, INFO_X2, dispY1+42 );
489 
490 	int	x=INFO_X1+20, y=dispY1+5;
491 	String str;
492 
493 	int i;
494 	for(i=0; i<MAX_RAW; i++, x+=60)
495 	{
496 		vga_front.d3_panel_up( x, y, x+RAW_SMALL_ICON_WIDTH+5, y+RAW_SMALL_ICON_HEIGHT+5 );
497 
498 		raw_res.put_small_raw_icon( x+3, y+3, i+1 );
499 
500 		font_san.disp( x+25, y+2, raw_qty_array[i], 1, x+59 );
501 	}
502 
503 	x =INFO_X1+20;
504 	y+=19;
505 
506 	for( i=0; i<MAX_PRODUCT; i++, x+=60)
507 	{
508 		vga_front.d3_panel_up( x, y, x+RAW_SMALL_ICON_WIDTH+5, y+RAW_SMALL_ICON_HEIGHT+5 );
509 
510 		raw_res.put_small_product_icon( x+3, y+3, i+1 );
511 
512 		font_san.disp( x+25, y+2, product_raw_qty_array[i], 1, x+59 );
513 	}
514 }
515 //---------- End of function UnitCaravan::disp_goods ----------//
516 
517 
518 //--------- Begin of function UnitCaravan::set_stop ---------//
519 //
520 // <int> stopId 				 - the id. of the stop
521 // <int> stopXLoc, stopYLoc - the location of the stop
522 //
set_stop(int stopId,int stopXLoc,int stopYLoc,char remoteAction)523 void UnitCaravan::set_stop(int stopId, int stopXLoc, int stopYLoc, char remoteAction)
524 {
525 	//-------------------------------------------------------//
526 	// check if there is a station in the given location
527 	//-------------------------------------------------------//
528 	Location *locPtr = world.get_loc(stopXLoc, stopYLoc);
529 	if(!locPtr->is_firm())
530 		return;
531 
532 	Firm *firmPtr = firm_array[locPtr->firm_recno()];
533 
534 	if( !can_set_stop(firmPtr->firm_recno) )
535 		return;
536 
537 	//-------------------------------------------------------//
538 	// return if the market stop is in another territory
539 	//-------------------------------------------------------//
540 	if(world.get_loc(next_x_loc(), next_y_loc())->region_id!=locPtr->region_id)
541 		return;
542 
543 	//-------------------------------------------//
544 
545 	if(!remoteAction && remote.is_enable())
546 	{
547 		// packet structure : <unit recno> <stop id> <stop x> <stop y>
548 		short *shortPtr = (short *) remote.new_send_queue_msg(MSG_U_CARA_SET_STOP, 4*sizeof(short));
549 		*shortPtr = sprite_recno;
550 		shortPtr[1] = stopId;
551 		shortPtr[2] = stopXLoc;
552 		shortPtr[3] = stopYLoc;
553 		return;
554 	}
555 
556 	if(!stop_array[stopId-1].firm_recno)
557 	{
558 		stop_defined_num++;	// no plus one if the recno is defined originally
559 
560 		err_when( stop_defined_num > MAX_STOP_FOR_CARAVAN );
561 	}
562 
563 	//-------------------------------------------------------//
564 	// set the station recno of the stop
565 	//-------------------------------------------------------//
566 	CaravanStop *stopPtr = stop_array+stopId-1;
567 	if(stopPtr->firm_recno == firmPtr->firm_recno)
568 	{
569 		err_when(stopPtr->firm_loc_x1!=firmPtr->loc_x1 || stopPtr->firm_loc_y1!=firmPtr->loc_y1 ||
570 					stopPtr->firm_id!=firmPtr->firm_id);
571 		return; // same stop as before
572 	}
573 
574 	//-------------- reset ignore_power_nation -------------//
575 	ignore_power_nation = 0;
576 
577 	short oldStopFirmRecno = dest_stop_id ? stop_array[dest_stop_id-1].firm_recno : 0;
578 	short newStopFirmRecno;
579 	memset(stopPtr->pick_up_array, 0, sizeof(char)*MAX_PICK_UP_GOODS);
580 	stopPtr->firm_recno		= firmPtr->firm_recno;
581 	stopPtr->firm_id			= firmPtr->firm_id;
582 	stopPtr->firm_loc_x1		= firmPtr->loc_x1;
583 	stopPtr->firm_loc_y1		= firmPtr->loc_y1;
584 
585 	//------------------------------------------------------------------------------------//
586 	// codes for setting pick_up_type
587 	//------------------------------------------------------------------------------------//
588 	MarketGoods *goodsPtr;
589 	int i, goodsId, goodsNum;
590 	switch(firmPtr->firm_id)
591 	{
592 		case FIRM_MINE:
593 				goodsId = ((FirmMine*)firmPtr)->raw_id;
594 				if(goodsId)
595 					stopPtr->pick_up_toggle(goodsId); // enable
596 				else
597 					stopPtr->pick_up_set_none();
598 				break;
599 
600 		case FIRM_FACTORY:
601 				goodsId = ((FirmFactory*)firmPtr)->product_raw_id+MAX_RAW;
602 				if(goodsId)
603 					stopPtr->pick_up_toggle(goodsId); // enable
604 				else
605 					stopPtr->pick_up_set_none();
606 				break;
607 
608 		case FIRM_MARKET:
609 				goodsPtr = ((FirmMarket*) firmPtr)->market_goods_array;
610 				goodsNum = 0;
611 				for(i=0; i<MAX_MARKET_GOODS; ++i, goodsPtr++)
612 				{
613 					if(goodsPtr->raw_id)
614 					{
615 						if(goodsNum==0)
616 							goodsId = goodsPtr->raw_id;
617 
618 						goodsNum++;
619 					}
620 					else if(goodsPtr->product_raw_id)
621 					{
622 						if(goodsNum==0)
623 							goodsId = goodsPtr->product_raw_id+MAX_RAW;
624 
625 						goodsNum++;
626 					}
627 				}
628 
629 				if(goodsNum==1)
630 					stopPtr->pick_up_toggle(goodsId); // cancel auto_pick_up
631 				else if(goodsNum==0)
632 					stopPtr->pick_up_set_none();
633 				else
634 					stopPtr->pick_up_set_auto();
635 				break;
636 
637 		default: err_here();
638 					break;
639 	}
640 
641 	last_set_stop_date = info.game_date;
642 
643 	//-------------------------------------------------------//
644 	// remove duplicate stop or stop change nation
645 	//-------------------------------------------------------//
646 	update_stop_list();
647 
648 	if(dest_stop_id)
649 	{
650 		if((newStopFirmRecno=stop_array[dest_stop_id-1].firm_recno) != oldStopFirmRecno)
651 		{
652 			firmPtr = firm_array[newStopFirmRecno];
653 			err_when(firmPtr->firm_id!=FIRM_MARKET && firmPtr->firm_id!=FIRM_MINE && firmPtr->firm_id!=FIRM_FACTORY);
654 			move_to_firm_surround(firmPtr->loc_x1, firmPtr->loc_y1, sprite_info->loc_width, sprite_info->loc_height, stop_array[dest_stop_id-1].firm_id);
655 			journey_status = ON_WAY_TO_FIRM;
656 		}
657 	}
658 	else
659 		stop2();
660 
661 	if( unit_array.selected_recno == sprite_recno )
662 	{
663 		if(nation_recno==nation_array.player_recno || config.show_ai_info)
664 			info.disp();
665 	}
666 }
667 //---------- End of function UnitCaravan::set_stop ----------//
668 
669 
670 //--------- Begin of function UnitCaravan::del_stop ---------//
del_stop(int stopId,char remoteAction)671 void UnitCaravan::del_stop(int stopId, char remoteAction)
672 {
673 	err_when(action_para || action_para2);
674 
675 	if(!remoteAction && remote.is_enable())
676 	{
677 		// packet structure : <unit recno> <stop id>
678 		short *shortPtr = (short *) remote.new_send_queue_msg(MSG_U_CARA_DEL_STOP, 2*sizeof(short));
679 		*shortPtr = sprite_recno;
680 		shortPtr[1] = stopId;
681 		return;
682 	}
683 
684 	//------ stop is deleted before receiving this message, thus, ignore invalid message -----//
685 	if(remote.is_enable() && stop_array[stopId-1].firm_recno==0)
686 		return;
687 
688 	stop_array[stopId-1].firm_recno = 0;
689 	stop_defined_num--;
690 	err_when( stop_defined_num < 0 );
691 
692 	update_stop_list();
693 
694 	if( unit_array.selected_recno == sprite_recno )
695 	{
696 		if(!remote.is_enable() || nation_recno==nation_array.player_recno || config.show_ai_info)
697 			info.disp();
698 	}
699 }
700 //---------- End of function UnitCaravan::del_stop ----------//
701 
702 
703 //--------- Begin of function UnitCaravan::update_stop_list ---------//
update_stop_list()704 void UnitCaravan::update_stop_list()
705 {
706 	err_when(stop_defined_num<0 || stop_defined_num>MAX_STOP_FOR_CARAVAN);
707 
708 	//------------- used to debug for multiplayer game ------------------//
709 	#ifdef DEBUG
710 		misc.random(100);
711 	#endif
712 
713 	//-------------------------------------------------------//
714 	// backup original destination stop firm recno
715 	//-------------------------------------------------------//
716 	short nextStopRecno = stop_array[dest_stop_id-1].firm_recno;
717 
718 	//----------------------------------------------------------------------//
719 	// check stop existence and the relationship between firm's nation
720 	//----------------------------------------------------------------------//
721 	CaravanStop *nodePtr = stop_array;
722 	Firm			*firmPtr;
723 	int i;
724 	for(i=0; i<MAX_STOP_FOR_CARAVAN; i++, nodePtr++)
725 	{
726 		if(!nodePtr->firm_recno)
727 			continue;
728 
729 		if(firm_array.is_deleted(nodePtr->firm_recno))
730 		{
731 			nodePtr->firm_recno = 0;	// clear the recno
732 			stop_defined_num--;
733 			err_when( stop_defined_num < 0 );
734 
735 			continue;
736 		}
737 
738 		firmPtr = firm_array[nodePtr->firm_recno];
739 
740 		if( !can_set_stop(nodePtr->firm_recno) ||
741 			 firmPtr->loc_x1!=nodePtr->firm_loc_x1 ||
742 			 firmPtr->loc_y1!=nodePtr->firm_loc_y1 )
743 		{
744 			nodePtr->firm_recno = 0;
745 			stop_defined_num--;
746 			err_when( stop_defined_num < 0 );
747 
748 			continue;
749 		}
750 	}
751 
752 	//-------------------------------------------------------//
753 	// remove duplicate node
754 	//-------------------------------------------------------//
755 	CaravanStop *insertNodePtr = stop_array;
756 
757 	if(stop_defined_num<1)
758 	{
759 		memset(stop_array, 0, sizeof(CaravanStop)*MAX_STOP_FOR_CARAVAN);
760 		dest_stop_id = 0;
761 		return;	// no stop
762 	}
763 
764 	//-------------------------------------------------------//
765 	// pack the firm_recno to the beginning part of the array
766 	//-------------------------------------------------------//
767 	short compareRecno;
768 	for(i=0, nodePtr=stop_array; i<MAX_STOP_FOR_CARAVAN; i++, nodePtr++)
769 	{
770 		if(nodePtr->firm_recno)
771 		{
772 			compareRecno = nodePtr->firm_recno;
773 			break;
774 		}
775 	}
776 
777 	if(i++) // else, the first record is already in the beginning of the array
778 		memcpy(insertNodePtr, nodePtr, sizeof(CaravanStop));
779 
780 	if(stop_defined_num==1)
781 	{
782 		memset(insertNodePtr+1, 0, sizeof(CaravanStop)*(MAX_STOP_FOR_CARAVAN-1));
783 		dest_stop_id = 1;
784 		return;
785 	}
786 
787 	short unprocessed = stop_defined_num-1;
788 	err_when(i==MAX_STOP_FOR_CARAVAN); // error if only one record
789 	err_when(!unprocessed);
790 	insertNodePtr++;
791 	nodePtr++;
792 
793 	for(; i<MAX_STOP_FOR_CARAVAN && unprocessed; i++, nodePtr++)
794 	{
795 		if(!nodePtr->firm_recno)
796 			continue; // empty
797 
798 		err_when(!nodePtr->firm_recno);
799 		if(nodePtr->firm_recno==compareRecno)
800 		{
801 			nodePtr->firm_recno = 0;
802 			stop_defined_num--;
803 			err_when( stop_defined_num < 0 );
804 		}
805 		else
806 		{
807 			compareRecno = nodePtr->firm_recno;
808 
809 			if(insertNodePtr!=nodePtr)
810 				memcpy(insertNodePtr++, nodePtr, sizeof(CaravanStop));
811 			else
812 				insertNodePtr++;
813 		}
814 		unprocessed--;
815 	}
816 
817 	if(stop_defined_num>2)
818 	{
819 		//-------- compare the first and the end record -------//
820 		nodePtr = stop_array + stop_defined_num - 1; // point to the end
821 		if(nodePtr->firm_recno == stop_array[0].firm_recno)
822 		{
823 			nodePtr->firm_recno = 0;	// remove the end record
824 			stop_defined_num--;
825 			err_when( stop_defined_num < 0 );
826 		}
827 	}
828 
829 	if(stop_defined_num<MAX_STOP_FOR_CARAVAN)
830 		memset(stop_array+stop_defined_num, 0, sizeof(CaravanStop)*(MAX_STOP_FOR_CARAVAN-stop_defined_num));
831 
832 	#ifdef DEBUG
833 		int debugCount;
834 		for(debugCount=0; debugCount<stop_defined_num; debugCount++)
835 			err_when(!stop_array[debugCount].firm_recno);
836 
837 		for(; debugCount<MAX_STOP_FOR_CARAVAN; debugCount++)
838 			err_when(stop_array[debugCount].firm_recno);
839 
840 		for(debugCount=0; debugCount<stop_defined_num; debugCount++)
841 			err_when(stop_array[debugCount].firm_recno &&
842 						stop_array[debugCount].firm_recno==stop_array[(debugCount+1)%MAX_STOP_FOR_CARAVAN].firm_recno);
843 	#endif
844 
845 	//-----------------------------------------------------------------------------------------//
846 	// There should be at least one stop in the list.  Otherwise, clear all the stops
847 	//-----------------------------------------------------------------------------------------//
848 	int ourFirmExist = 0;
849 	for(i=0, nodePtr=stop_array; i<stop_defined_num; i++, nodePtr++)
850 	{
851 		err_when(firm_array.is_deleted(nodePtr->firm_recno));
852 		firmPtr = firm_array[nodePtr->firm_recno];
853 		if(firmPtr->nation_recno==nation_recno)
854 		{
855 			ourFirmExist++;
856 			break;
857 		}
858 	}
859 
860 	if(!ourFirmExist) // none of the markets belong to our nation
861 	{
862 		memset(stop_array, 0, MAX_STOP_FOR_CARAVAN * sizeof(CaravanStop));
863 		journey_status		= ON_WAY_TO_FIRM;
864 		dest_stop_id		= 0;
865 		stop_defined_num	= 0;
866 		return;
867 	}
868 
869 	//-----------------------------------------------------------------------------------------//
870 	// reset dest_stop_id since the order of the stop may be changed
871 	//-----------------------------------------------------------------------------------------//
872 	int xLoc = next_x_loc();
873 	int yLoc = next_y_loc();
874 	int dist, minDist=0x7FFF;
875 
876 	for(i=0, dest_stop_id=0, nodePtr=stop_array; i<stop_defined_num; i++, nodePtr++)
877 	{
878 		if(nodePtr->firm_recno==nextStopRecno)
879 		{
880 			dest_stop_id = i+1;
881 			break;
882 		}
883 		else
884 		{
885 			firmPtr = firm_array[nodePtr->firm_recno];
886 			dist = misc.points_distance(xLoc, yLoc, firmPtr->center_x, firmPtr->center_y);
887 
888 			if(dist<minDist)
889 			{
890 				dist = minDist;
891 				dest_stop_id = i+1;
892 			}
893 		}
894 	}
895 
896 	err_when(dest_stop_id<0 || dest_stop_id>MAX_STOP_FOR_CARAVAN);
897 }
898 //----------- End of function UnitCaravan::update_stop_list -----------//
899 
900 
901 //--------- Begin of function UnitCaravan::can_set_stop ---------//
902 //
903 // Whether can set a caravan's stop on the given firm.
904 //
can_set_stop(int firmRecno)905 int UnitCaravan::can_set_stop(int firmRecno)
906 {
907 	Firm* firmPtr = firm_array[firmRecno];
908 
909 	if( firmPtr->under_construction )
910 		return 0;
911 
912 	switch(firmPtr->firm_id)
913 	{
914 	case FIRM_MARKET:
915 		return nation_array[nation_recno]->get_relation(firmPtr->nation_recno)->trade_treaty;
916 
917 	case FIRM_MINE:
918 	case FIRM_FACTORY:
919 		return nation_recno == firmPtr->nation_recno;
920 
921 	default:
922 		return 0;
923 	}
924 }
925 //----------- End of function UnitCaravan::can_set_stop -----------//
926 
927 
928 //--------- Begin of function UnitCaravan::get_next_stop_id ---------//
929 //
930 // Get the id. of the next defined stop.
931 //
932 // [int] curStopId - the id. of the current stop.
933 //							if it is MAX_STOP_FOR_CARAVAN, this function will return
934 //							the id. of the first valid stop.
935 //
936 //      					(default: MAX_STOP_FOR_CARAVAN)
937 // return :	0 ~ MAX_STOP_FOR_CARAVAN, where 0 for no valid stop
938 //
get_next_stop_id(int curStopId)939 int UnitCaravan::get_next_stop_id(int curStopId)
940 {
941 	int nextStopId = (curStopId>=stop_defined_num) ? 1 : curStopId+1;
942 
943 	CaravanStop *stopPtr = stop_array+nextStopId-1;
944 
945 	int needUpdate = 0;
946 
947 	if(firm_array.is_deleted(stopPtr->firm_recno))
948 	{
949 		needUpdate++;
950 	}
951 	else
952 	{
953 		Firm *firmPtr = firm_array[stopPtr->firm_recno];
954 
955 		if( !can_set_stop( stopPtr->firm_recno ) ||
956 			 firmPtr->loc_x1 != stopPtr->firm_loc_x1 ||
957 			 firmPtr->loc_y1 != stopPtr->firm_loc_y1 )
958 		{
959 			needUpdate++;
960 		}
961 	}
962 
963 	//### begin alex 24/10 ###//
964 	if(needUpdate)
965 	{
966 		short preStopRecno = stop_array[curStopId-1].firm_recno;
967 
968 		update_stop_list();
969 
970 		if(!stop_defined_num)
971 			return 0;	// no stop is valid
972 
973 		int i;
974 		for(i=1, stopPtr=stop_array; i<=stop_defined_num; i++, stopPtr++)
975 		{
976 			if(stopPtr->firm_recno==preStopRecno)
977 				return (i>=stop_defined_num) ? 1 : i+1;
978 		}
979 
980 		return 1;
981 	}
982 	else
983 		return nextStopId;
984 	//#### end alex 24/10 ####//
985 }
986 //----------- End of function UnitCaravan::get_next_stop_id -----------//
987 
988 
989 //--------- Begin of function UnitCaravan::pre_process ---------//
990 //
pre_process()991 void UnitCaravan::pre_process()
992 {
993 	Unit::pre_process();
994 
995 	if(cur_x == -1) // can't use !is_visible(), keep process if cur_x < -1
996 		return;
997 
998 	#define SURROUND_FIRM_WAIT_FACTOR	10
999 
1000 	//-----------------------------------------------------------------------------//
1001 	// if all the hit points are lost, die now
1002 	//-----------------------------------------------------------------------------//
1003 	if(hit_points <= 0)
1004 	{
1005 		if(action_mode != ACTION_DIE)
1006 			set_die();
1007 
1008 		return;
1009 	}
1010 
1011 	err_when(action_mode==ACTION_DIE || cur_action==SPRITE_DIE || hit_points<=0);
1012 
1013 	//-----------------------------------------------------------------------------//
1014 	// stop action if no stop is defined
1015 	//-----------------------------------------------------------------------------//
1016 	if(!stop_defined_num)
1017 	{
1018 		err_when(dest_stop_id!=0);
1019 		if(journey_status!=NO_STOP_DEFINED)
1020 			stop();	// stop if no valid stop is defined
1021 
1022 		journey_status = NO_STOP_DEFINED;
1023 		return;
1024 	}
1025 
1026 	//-----------------------------------------------------------------------------//
1027 	// wait in the surrounding of the stop if stop_defined_num==1 (only one stop)
1028 	//-----------------------------------------------------------------------------//
1029 	if(stop_defined_num==1)
1030 	{
1031 		CaravanStop *stopPtr = &stop_array[0];
1032 		err_when(!stopPtr->firm_recno);
1033 
1034 		if(firm_array.is_deleted(stopPtr->firm_recno))
1035 		{
1036 			update_stop_list();
1037 			return;
1038 		}
1039 
1040 		Firm *firmPtr = firm_array[stopPtr->firm_recno];
1041 		int firmXLoc1 = firmPtr->loc_x1;
1042 		int firmYLoc1 = firmPtr->loc_y1;
1043 		int firmXLoc2 = firmPtr->loc_x2;
1044 		int firmYLoc2 = firmPtr->loc_y2;
1045 		int firmId = firmPtr->firm_id;
1046 		if(firmXLoc1!=stopPtr->firm_loc_x1 || firmYLoc1!=stopPtr->firm_loc_y1 ||
1047 			(firmId!=FIRM_MINE && firmId!=FIRM_FACTORY && firmId!=FIRM_MARKET))
1048 		{
1049 			update_stop_list();
1050 			return;
1051 		}
1052 
1053 		int curXLoc = next_x_loc();
1054 		int curYLoc = next_y_loc();
1055 
1056 		if(curXLoc<firmXLoc1-1 || curXLoc>firmXLoc2+1 || curYLoc<firmYLoc1-1 || curYLoc>firmYLoc2+1)
1057 		{
1058 			if(cur_action==SPRITE_IDLE)
1059 				move_to_firm_surround(firmXLoc1, firmYLoc1, sprite_info->loc_width, sprite_info->loc_height, firmId);
1060 			else
1061 				journey_status = ON_WAY_TO_FIRM;
1062 		}
1063 		else
1064 		{
1065 			journey_status = SURROUND_FIRM;
1066 			//if(firmPtr->nation_recno==nation_recno)
1067 			if(nation_array[nation_recno]->get_relation(firmPtr->nation_recno)->trade_treaty)
1068 			{
1069 				if(wait_count<=0)
1070 				{
1071 					//---------- unloading goods -------------//
1072 					switch(stopPtr->firm_id)
1073 					{
1074 						case FIRM_MINE:
1075 								break; // no goods unload to mine
1076 
1077 						case FIRM_FACTORY:
1078 								factory_unload_goods();
1079 								break;
1080 
1081 						case FIRM_MARKET:
1082 								market_unload_goods();
1083 								break;
1084 
1085 						default: err_here();
1086 									break;
1087 					}
1088 
1089 					wait_count = MAX_CARAVAN_WAIT_TERM*SURROUND_FIRM_WAIT_FACTOR;
1090 				}
1091 				else
1092 					wait_count--;
1093 			}
1094 		}
1095 		return;
1096 	}
1097 
1098 	//-----------------------------------------------------------------------------//
1099 	// at least 2 stops for the caravan to move between
1100 	//-----------------------------------------------------------------------------//
1101 	err_when(stop_defined_num<=1);
1102 
1103 	if(journey_status==INSIDE_FIRM)
1104 		caravan_in_firm();
1105 	else
1106 		caravan_on_way();
1107 }
1108 //----------- End of function UnitCaravan::pre_process -----------//
1109 
1110 
1111 //--------- Begin of function UnitCaravan::caravan_in_firm ---------//
1112 // journey_status : INSIDE_FIRM -->	ON_WAY_TO_FIRM
1113 //												NO_STOP_DEFINED if no valid stop
1114 //												SURROUND_FIRM if only one stop
1115 //
caravan_in_firm()1116 void UnitCaravan::caravan_in_firm()
1117 {
1118 	//-----------------------------------------------------------------------------//
1119 	// the market is deleted while the caravan is in market
1120 	//-----------------------------------------------------------------------------//
1121 	if(firm_array.is_deleted(action_para))
1122 	{
1123 		hit_points = (float) 0;	// caravan also die if the market is deleted
1124 		unit_array.disappear_in_firm(sprite_recno); // caravan also die if the market is deleted
1125 		return;
1126 	}
1127 
1128 	//-----------------------------------------------------------------------------//
1129 	// waiting (time to upload/download cargo)
1130 	//-----------------------------------------------------------------------------//
1131 	if(wait_count>0)
1132 	{
1133 		wait_count--;
1134 		return;
1135 	}
1136 
1137 	//-----------------------------------------------------------------------------//
1138 	// leave the market and go to another market if possible
1139 	//-----------------------------------------------------------------------------//
1140 	CaravanStop *stopPtr = stop_array + dest_stop_id - 1;
1141 	int xLoc = stop_x_loc;
1142 	int yLoc = stop_y_loc;
1143 	Location *locPtr = world.get_loc(xLoc, yLoc);
1144 	Firm		*firmPtr;
1145 
1146 	if(locPtr->can_move(mobile_type))
1147 		init_sprite(xLoc, yLoc); // appear in the location the unit disappeared before
1148 	else
1149 	{
1150 		//---- the entering location is blocked, select another location to leave ----//
1151 		err_when(action_para==0);
1152 		firmPtr = firm_array[action_para];
1153 
1154 		if(appear_in_firm_surround(xLoc, yLoc, firmPtr))
1155 		{
1156 			init_sprite(xLoc, yLoc);
1157 			stop();
1158 			err_when(action_para);
1159 		}
1160 		else
1161 		{
1162 			wait_count = MAX_CARAVAN_WAIT_TERM*10; //********* BUGHERE, continue to wait or ....
1163 			return;
1164 		}
1165 	}
1166 
1167 	//-------------- get next stop id. ----------------//
1168 	int nextStopId = get_next_stop_id(dest_stop_id);
1169 	if(!nextStopId || dest_stop_id==nextStopId)
1170 	{
1171 		dest_stop_id = nextStopId;
1172 		journey_status = (!nextStopId) ? NO_STOP_DEFINED : SURROUND_FIRM;
1173 		return;	// no stop or only one stop is valid
1174 	}
1175 
1176 	dest_stop_id = nextStopId;
1177 	firmPtr = firm_array[stop_array[dest_stop_id-1].firm_recno];
1178 
1179 	action_para = 0; // since action_para is used to store the current market recno, reset before searching
1180 	move_to_firm_surround(firmPtr->loc_x1, firmPtr->loc_y1, sprite_info->loc_width, sprite_info->loc_height, firmPtr->firm_id);
1181 
1182 	journey_status = ON_WAY_TO_FIRM;
1183 }
1184 //----------- End of function UnitCaravan::caravan_in_firm -----------//
1185 
1186 
1187 //--------- Begin of function UnitCaravan::caravan_on_way ---------//
1188 // journey_status : ON_WAY_TO_FIRM --> SURROUND_FIRM
1189 //						  SURROUND_FIRM  --> INSIDE_FIRM
1190 //
caravan_on_way()1191 void UnitCaravan::caravan_on_way()
1192 {
1193 	CaravanStop *stopPtr = stop_array + dest_stop_id - 1;
1194 
1195 	if(cur_action==SPRITE_IDLE && journey_status!=SURROUND_FIRM)
1196 	{
1197 		if(!firm_array.is_deleted(stopPtr->firm_recno))
1198 		{
1199 			Firm *firmPtr = firm_array[stopPtr->firm_recno];
1200 			move_to_firm_surround(firmPtr->loc_x1, firmPtr->loc_y1, sprite_info->loc_width, sprite_info->loc_height, firmPtr->firm_id);
1201 			int nextXLoc = next_x_loc();
1202 			int nextYLoc = next_y_loc();
1203 
1204 			if(nextXLoc>=firmPtr->loc_x1-1 && nextXLoc<=firmPtr->loc_x2+1 &&
1205 				nextYLoc>=firmPtr->loc_y1-1 && nextYLoc<=firmPtr->loc_y2+1) // hard code 1 for carvan size 1x1
1206 				journey_status = SURROUND_FIRM;
1207 
1208 			if(nextXLoc==move_to_x_loc && nextYLoc==move_to_y_loc && !ignore_power_nation)
1209 				ignore_power_nation = 1;
1210 
1211 			return;
1212 		}
1213 	}
1214 
1215 	short unitRecno = sprite_recno;
1216 
1217 	err_when(cur_action==SPRITE_ATTACK || action_mode==ACTION_ATTACK_UNIT || action_mode==ACTION_ATTACK_FIRM ||
1218 				action_mode==ACTION_ATTACK_TOWN || action_mode==ACTION_ATTACK_WALL);
1219 
1220 	if(unit_array.is_deleted(unitRecno))
1221 		return; //-***************** BUGHERE ***************//
1222 
1223 	if(firm_array.is_deleted(stopPtr->firm_recno))
1224 	{
1225 		update_stop_list();
1226 
1227 		if(stop_defined_num) // move to next stop
1228 		{
1229 			Firm *firmPtr = firm_array[stop_array[stop_defined_num-1].firm_recno];
1230 			move_to_firm_surround(firmPtr->loc_x1, firmPtr->loc_y1, sprite_info->loc_width, sprite_info->loc_height, firmPtr->firm_id);
1231 		}
1232 		return;
1233 	}
1234 
1235 	//CaravanStop *stopPtr = stop_array + dest_stop_id - 1;
1236 	Firm	*firmPtr = firm_array[stopPtr->firm_recno];
1237 
1238 	int nextXLoc = next_x_loc();
1239 	int nextYLoc = next_y_loc();
1240 
1241 	if(journey_status==SURROUND_FIRM ||
1242 		( nextXLoc==move_to_x_loc && nextYLoc==move_to_y_loc && cur_x==next_x && cur_y==next_y && // move in a tile exactly
1243 		  (nextXLoc>=firmPtr->loc_x1-1 && nextXLoc<=firmPtr->loc_x2+1 &&
1244 			nextYLoc>=firmPtr->loc_y1-1 && nextYLoc<=firmPtr->loc_y2+1) )) // in the surrounding of the firm
1245 	{
1246 		//-------------------- update pick_up_array --------------------//
1247 		stopPtr->update_pick_up();
1248 
1249 		//-------------------------------------------------------//
1250 		// load/unload goods
1251 		//-------------------------------------------------------//
1252 		if(nation_array[nation_recno]->get_relation(firmPtr->nation_recno)->trade_treaty)
1253 		{
1254 			switch(firmPtr->firm_id)
1255 			{
1256 				case FIRM_MINE:
1257 						mine_load_goods(stopPtr->pick_up_type);
1258 						break;
1259 
1260 				case FIRM_FACTORY:
1261 						factory_unload_goods();
1262 						factory_load_goods(stopPtr->pick_up_type);
1263 						break;
1264 
1265 				case FIRM_MARKET:
1266 						market_unload_goods();
1267 
1268 						if(stopPtr->pick_up_type == AUTO_PICK_UP)
1269 							market_auto_load_goods();
1270 						else if(stopPtr->pick_up_type!=NO_PICK_UP)
1271 							market_load_goods();
1272 						break;
1273 
1274 				default: err_here();
1275 							break;
1276 			}
1277 		}
1278 
1279 		//-------------------------------------------------------//
1280 		// action_para is used to store the firm_recno of the market
1281 		// where the caravan move in.
1282 		//-------------------------------------------------------//
1283 		action_para = stopPtr->firm_recno;
1284 
1285 		stop_x_loc = move_to_x_loc; // store entering location
1286 		stop_y_loc = move_to_y_loc;
1287 		wait_count = MAX_CARAVAN_WAIT_TERM;		// set waiting term
1288 
1289 		reset_path();
1290 		deinit_sprite(1);	// the caravan enters the market now. 1-keep it selected if it is currently selected
1291 
1292 		err_when(cur_x!=-1);
1293 		cur_x--;	// set cur_x to -2, such that invisible but still process pre_process()
1294 
1295 		journey_status = INSIDE_FIRM;
1296 	}
1297 	else
1298 	{
1299 		if(cur_action!=SPRITE_MOVE)
1300 		{
1301 			//----------------------------------------------------//
1302 			// blocked by something, go to the destination again
1303 			// note: if return value is 0, cannot reach the firm.		//*********BUGHERE
1304 			//----------------------------------------------------//
1305 			move_to_firm_surround(firmPtr->loc_x1, firmPtr->loc_y1, sprite_info->loc_width, sprite_info->loc_height, firmPtr->firm_id);
1306 			journey_status = ON_WAY_TO_FIRM;
1307 		}
1308 	}
1309 }
1310 //----------- End of function UnitCaravan::caravan_on_way -----------//
1311 
1312 
1313 //--------- Begin of function UnitCaravan::appear_in_firm_surround ---------//
1314 //
1315 // This function return 1 if a suitable location is found, that means the
1316 // caravan will leave the firm there. Otherwise, return 0.
1317 //
1318 // xLoc, yLoc are reference variables for returning the location found.
1319 //
appear_in_firm_surround(int & xLoc,int & yLoc,Firm * firmPtr)1320 int UnitCaravan::appear_in_firm_surround(int& xLoc, int& yLoc, Firm* firmPtr)
1321 {
1322 	int upperLeftBoundX	= firmPtr->loc_x1 - 1;	// the surrounding coordinates of the firm
1323 	int upperLeftBoundY	= firmPtr->loc_y1 - 1;
1324 	int lowerRightBoundX = firmPtr->loc_x2 + 1;
1325 	int lowerRightBoundY = firmPtr->loc_y2 + 1;
1326 
1327 	int count = 1, inside = 1, found = 0, i;
1328 	int testXLoc = xLoc;
1329 	int testYLoc = yLoc;
1330 	int limit;
1331 	Location *locPtr;
1332 
1333 	//---------------------------------------------------------//
1334 	//		9  10  11  12		the location is tested in the order
1335 	//		8   1   2  13		shown, if the location is the surrounding
1336 	//		7   x   3  14		of the firm and non-blocked, break
1337 	//		6   5   4  ...		the test
1338 	//---------------------------------------------------------//
1339 
1340 	while(inside)
1341 	{
1342 		inside = 0;
1343 		limit = count<<1;
1344 		err_when(limit!=count*2);
1345 
1346 		//------------ upper --------------//
1347 		testXLoc = xLoc - count + 1;
1348 		testYLoc = yLoc - count;
1349 		for(i=0; i<limit; i++)
1350 		{
1351 			if(testXLoc<0 || testYLoc>=MAX_WORLD_X_LOC || testYLoc<0 || testYLoc>=MAX_WORLD_Y_LOC)
1352 				continue;
1353 
1354 			if(testXLoc<upperLeftBoundX || testXLoc>lowerRightBoundX || testYLoc<upperLeftBoundY || testYLoc>lowerRightBoundY)
1355 				continue;
1356 
1357 			locPtr = world.get_loc(testXLoc, testYLoc);
1358 			if(locPtr->can_move(mobile_type))
1359 			{
1360 				found++;
1361 				break;
1362 			}
1363 			else
1364 				xLoc++;
1365 
1366 			inside++;
1367 		}
1368 
1369 		if(found)
1370 			break;
1371 
1372 		//------------ right --------------//
1373 		testXLoc = xLoc + count;
1374 		testYLoc = yLoc - count + 1;
1375 		for(i=0; i<limit; i++)
1376 		{
1377 			if(testXLoc<0 || testYLoc>=MAX_WORLD_X_LOC || testYLoc<0 || testYLoc>=MAX_WORLD_Y_LOC)
1378 				continue;
1379 
1380 			if(testXLoc<upperLeftBoundX || testXLoc>lowerRightBoundX || testYLoc<upperLeftBoundY || testYLoc>lowerRightBoundY)
1381 				continue;
1382 
1383 			locPtr = world.get_loc(testXLoc, testYLoc);
1384 			if(locPtr->can_move(mobile_type))
1385 			{
1386 				found++;
1387 				break;
1388 			}
1389 			else
1390 				yLoc++;
1391 
1392 			inside++;
1393 		}
1394 
1395 		if(found)
1396 			break;
1397 
1398 		//------------- down --------------//
1399 		testXLoc = xLoc + count - 1;
1400 		testYLoc = yLoc + count;
1401 		for(i=0; i<limit; i++)
1402 		{
1403 			if(testXLoc<0 || testYLoc>=MAX_WORLD_X_LOC || testYLoc<0 || testYLoc>=MAX_WORLD_Y_LOC)
1404 				continue;
1405 
1406 			if(testXLoc<upperLeftBoundX || testXLoc>lowerRightBoundX || testYLoc<upperLeftBoundY || testYLoc>lowerRightBoundY)
1407 				continue;
1408 
1409 			locPtr = world.get_loc(testXLoc, testYLoc);
1410 			if(locPtr->can_move(mobile_type))
1411 			{
1412 				found++;
1413 				break;
1414 			}
1415 			else
1416 				xLoc--;
1417 
1418 			inside++;
1419 		}
1420 
1421 		if(found)
1422 			break;
1423 
1424 		//------------- left --------------//
1425 		testXLoc = xLoc - count;
1426 		testYLoc = yLoc + count - 1;
1427 		for(i=0; i<limit; i++)
1428 		{
1429 			if(testXLoc<0 || testYLoc>=MAX_WORLD_X_LOC || testYLoc<0 || testYLoc>=MAX_WORLD_Y_LOC)
1430 				continue;
1431 
1432 			if(testXLoc<upperLeftBoundX || testXLoc>lowerRightBoundX || testYLoc<upperLeftBoundY || testYLoc>lowerRightBoundY)
1433 				continue;
1434 
1435 			locPtr = world.get_loc(testXLoc, testYLoc);
1436 			if(locPtr->can_move(mobile_type))
1437 			{
1438 				found++;
1439 				break;
1440 			}
1441 			else
1442 				yLoc--;
1443 
1444 			inside++;
1445 		}
1446 
1447 		if(found)
1448 			break;
1449 
1450 		//---------------------------------------------//
1451 		count++;
1452 	}
1453 
1454 	if(found)
1455 	{
1456 		xLoc = testXLoc;
1457 		yLoc = testYLoc;
1458 		return 1;
1459 	}
1460 
1461 	return 0;
1462 }
1463 //----------- End of function UnitCaravan::appear_in_firm_surround -----------//
1464 
1465 
1466 //---------- begin static function i_disp_caravan_select_button ---------------//
i_disp_caravan_select_button(ButtonCustom * button,int repaintBody)1467 static void i_disp_caravan_select_button(ButtonCustom *button, int repaintBody)
1468 {
1469 	int x1 = button->x1;
1470 	int y1 = button->y1;
1471 	int x2 = button->x2;
1472 	int y2 = button->y2;
1473 	int shift;
1474 
1475 	//------------- modify x1,y1, x2,y2 to the button body --------------//
1476 	if(button->pushed_flag)
1477 	{
1478 		int colorDown = Vga::active_buf->color_down;		// change the color of the body area to yellow to highlight the change
1479 		Vga::active_buf->color_down = (char) V_YELLOW;
1480 
1481 		Vga::active_buf->d3_panel_down(x1, y1, x2, y2);
1482 
1483 		Vga::active_buf->color_down = (char) colorDown;
1484 
1485 		x1++;
1486 		y1++;
1487 		shift = 2;
1488 	}
1489 	else
1490 	{
1491 		Vga::active_buf->d3_panel_up(x1, y1, x2, y2);
1492 		x2--;
1493 		y2--;
1494 		shift = 3;
1495 	}
1496 
1497 	//-------------- put goods icon ---------------//
1498 
1499 	int id = button->custom_para.value;
1500 	const char *iconName=NULL;
1501 
1502 	int x = x1+shift;
1503 	int y = y1+shift;
1504 
1505 	if(id==AUTO_PICK_UP)
1506 	{
1507 		iconName = "AUTOPICK";
1508 	}
1509 	else if(id==NO_PICK_UP)
1510 	{
1511 		iconName = "NOPICK";
1512 	}
1513 	else if(id>=PICK_UP_RAW_FIRST && id<=PICK_UP_RAW_LAST)
1514 	{
1515 		raw_res.put_small_raw_icon( x, y, id-PICK_UP_RAW_FIRST+1 );
1516 	}
1517 	else if(id>=PICK_UP_PRODUCT_FIRST && id<=PICK_UP_PRODUCT_LAST)
1518 	{
1519 		raw_res.put_small_product_icon( x, y, id-PICK_UP_PRODUCT_FIRST+1 );
1520 	}
1521 	else
1522 		err_here();
1523 
1524 	if( iconName )
1525 	{
1526 		help.set_help( x, y, x+9, y+9, iconName );
1527 		Vga::active_buf->put_bitmap_trans( x, y, image_icon.get_ptr(iconName) );
1528 	}
1529 }
1530 //---------- end static function i_disp_caravan_select_button ---------------//
1531 
1532 
1533 //--------- Begin of function UnitCaravan::has_pick_up_type ---------//
1534 //
1535 // Return whether the specific stop has the specific pick up types.
1536 //
has_pick_up_type(int stopId,int pickUpType)1537 int UnitCaravan::has_pick_up_type(int stopId, int pickUpType)
1538 {
1539 	return stop_array[stopId-1].pick_up_array[pickUpType-1];
1540 }
1541 //---------- End of function UnitCaravan::has_pick_up_type ----------//
1542 
1543 
1544 //--------- Begin of function UnitCaravan::carrying_qty ---------//
1545 //
1546 // Return whether the qty of the specific product/raw type that
1547 // this caravan is currently carrying.
1548 //
carrying_qty(int pickUpType)1549 int UnitCaravan::carrying_qty(int pickUpType)
1550 {
1551 	if( pickUpType >= PICK_UP_RAW_FIRST &&
1552 		 pickUpType <= PICK_UP_RAW_LAST )
1553 	{
1554 		return raw_qty_array[pickUpType-PICK_UP_RAW_FIRST];
1555 	}
1556 	else if( pickUpType >= PICK_UP_PRODUCT_FIRST &&
1557 				pickUpType <= PICK_UP_PRODUCT_LAST )
1558 	{
1559 		return product_raw_qty_array[pickUpType-PICK_UP_PRODUCT_FIRST];
1560 	}
1561 	else
1562 	{
1563 		err_here();
1564 		return 0;
1565 	}
1566 }
1567 //---------- End of function UnitCaravan::carrying_qty ----------//
1568 
1569 
1570 //--------- Begin of function UnitCaravan::copy_route ---------//
1571 //
1572 // Copies trade route from copyUnitRecno to this caravan.
1573 //
copy_route(short copyUnitRecno,int remoteAction)1574 void UnitCaravan::copy_route(short copyUnitRecno, int remoteAction)
1575 {
1576 	if( sprite_recno == copyUnitRecno )
1577 		return;
1578 
1579 	UnitCaravan* copyUnit = (UnitCaravan*)unit_array[copyUnitRecno];
1580 
1581 	if( copyUnit->nation_recno != nation_recno )
1582 		return;
1583 
1584 	if( remote.is_enable() && !remoteAction )
1585 	{
1586 		// packet structure : <unit recno> <copy recno>
1587 		short *shortPtr = (short *)remote.new_send_queue_msg(MSG_U_CARA_COPY_ROUTE, 2*sizeof(short));
1588 		*shortPtr = sprite_recno;
1589 
1590 		shortPtr[1] = copyUnitRecno;
1591 		return;
1592 	}
1593 
1594 	// clear existing stops
1595 	int num_stops = stop_defined_num;
1596 	for( int i=0; i<num_stops; i++ )
1597 		del_stop(1, COMMAND_AUTO); // stop ids shift up
1598 
1599 	CaravanStop* caravanStopA = copyUnit->stop_array;
1600 	CaravanStop* caravanStopB = stop_array;
1601 	for( int i=0; i<MAX_STOP_FOR_CARAVAN; i++, caravanStopA++, caravanStopB++ )
1602 	{
1603 		if( !caravanStopA->firm_recno )
1604 			break;
1605 
1606 		if( firm_array.is_deleted(caravanStopA->firm_recno) )
1607 			continue;
1608 
1609 		Firm* firmPtr = firm_array[caravanStopA->firm_recno];
1610 		set_stop(i+1, caravanStopA->firm_loc_x1, caravanStopA->firm_loc_y1, COMMAND_AUTO);
1611 
1612 		if( caravanStopA->pick_up_type == AUTO_PICK_UP )
1613 		{
1614 			set_stop_pick_up(i+1, AUTO_PICK_UP, COMMAND_AUTO );
1615 		}
1616 
1617 		else if( caravanStopA->pick_up_type == NO_PICK_UP )
1618 		{
1619 			set_stop_pick_up(i+1, NO_PICK_UP, COMMAND_AUTO );
1620 		}
1621 
1622 		else
1623 		{
1624 			for( int b=0; b<MAX_PICK_UP_GOODS; ++b )
1625 			{
1626 				if( caravanStopA->pick_up_array[b] != caravanStopB->pick_up_array[b] )
1627 					set_stop_pick_up(i+1, b+1, COMMAND_PLAYER);
1628 			}
1629 		}
1630 	}
1631 }
1632 //---------- End of function UnitCaravan::copy_route ----------//
1633