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_CARA3.CPP
22 //Description : Unit Caravan unload/load functions
23 
24 #include <ONATION.h>
25 #include <OF_MINE.h>
26 #include <OF_FACT.h>
27 #include <OF_MARK.h>
28 #include <OU_CARA.h>
29 #include <OREMOTE.h>
30 
31 static char		 processed_raw_qty_array[MAX_RAW];					// 1 for not unload but can up load, 2 for unload but not up load
32 static char		 processed_product_raw_qty_array[MAX_PRODUCT];	// ditto
33 
34 //--------- Begin of function UnitCaravan::market_unload_goods ---------//
35 //
market_unload_goods()36 void UnitCaravan::market_unload_goods()
37 {
38 	FirmMarket *curMarket = (FirmMarket*) firm_array[stop_array[dest_stop_id-1].firm_recno];
39 	err_when(curMarket->firm_id != FIRM_MARKET);
40 
41 	memset(processed_raw_qty_array, 0, sizeof(char)*MAX_RAW);
42 	memset(processed_product_raw_qty_array, 0, sizeof(char)*MAX_PRODUCT);
43 
44 	//--------------------------------------------------------------------//
45 	// only unload goods to our market
46 	//--------------------------------------------------------------------//
47 	if(curMarket->nation_recno!=nation_recno)
48 		return;
49 
50 	//--------------------------------------------------------------------//
51 	// unload goods
52 	//-------------------------------------------------//
53 	MarketGoods *marketGoods = curMarket->market_goods_array;
54 	short	unloadQty;
55 	int	goodsId, withEmptySlot=0;
56 
57 	int i;
58 	for(i=0; i<MAX_MARKET_GOODS; i++, marketGoods++)
59 	{
60 		if(marketGoods->raw_id)
61 		{
62 			err_when(marketGoods->product_raw_id);
63 			//-------------- is raw material ----------------//
64 			goodsId = marketGoods->raw_id-1;
65 
66 			//if( (marketGoods->supply_30days()==0 && marketGoods->stock_qty<curMarket->max_stock_qty) || // no supply and stock isn't full
67 			//	 (marketGoods->stock_qty<CARAVAN_UNLOAD_TO_MARKET_QTY &&
68 			//	 //##### begin trevor 16/7 #######//
69 			//	  marketGoods->month_demand > marketGoods->supply_30days()) ) // demand > supply
70 			//	 //##### end trevor 16/7 #######//
71 			if(marketGoods->stock_qty<curMarket->max_stock_qty)
72 			{
73 				//-------- demand > supply and stock is not full ----------//
74 				if(raw_qty_array[goodsId]) // have this goods
75 				{
76 					//---------- process unload -------------//
77 					unloadQty = (short) MIN(raw_qty_array[goodsId], curMarket->max_stock_qty-marketGoods->stock_qty);
78 					raw_qty_array[goodsId]		  -= unloadQty;
79 					err_when(raw_qty_array[goodsId]<0);
80 					marketGoods->stock_qty += unloadQty;
81 					processed_raw_qty_array[goodsId] += 2;
82 				}
83 				else if(!marketGoods->stock_qty && !marketGoods->supply_30days())
84 				{
85 					//---------- no supply, no stock, without this goods ------------//
86 					withEmptySlot++;
87 					//processed_raw_qty_array[goodsId] = 0; // reset to zero for handling empty slot
88 				}
89 			}
90 			else if(raw_qty_array[goodsId]) // have this goods
91 			{
92 				processed_raw_qty_array[goodsId]++;
93 			}
94 		}
95 		else if(marketGoods->product_raw_id)
96 		{
97 			err_when(marketGoods->raw_id);
98 			//---------------- is product -------------------//
99 			goodsId = marketGoods->product_raw_id-1;
100 
101 			//if( (marketGoods->supply_30days()==0 && marketGoods->stock_qty<curMarket->max_stock_qty) || // no supply and stock isn't full
102 			//	 //##### begin trevor 16/7 #######//
103 			//	 (marketGoods->stock_qty<50 && marketGoods->month_demand > marketGoods->supply_30days()) ) // demand > supply
104 			//	 //##### end trevor 16/7 #######//
105 			if(marketGoods->stock_qty<curMarket->max_stock_qty)
106 			{
107 				if(product_raw_qty_array[goodsId]) // have this goods
108 				{
109 					unloadQty = (short) MIN(product_raw_qty_array[goodsId], curMarket->max_stock_qty-marketGoods->stock_qty);
110 					product_raw_qty_array[goodsId]	-= unloadQty;
111 					err_when(product_raw_qty_array[goodsId]<0);
112 					marketGoods->stock_qty	+= unloadQty;
113 					processed_product_raw_qty_array[goodsId] += 2;
114 				}
115 				else if(!marketGoods->stock_qty && !marketGoods->supply_30days()) // no supply, no stock, without this goods
116 				{
117 					withEmptySlot++;
118 					//processed_product_raw_qty_array[goodsId] = 0; // reset to zero for handling empty slot
119 				}
120 			}
121 			else if(product_raw_qty_array[goodsId]) // have this goods
122 			{
123 				processed_product_raw_qty_array[goodsId]++;
124 			}
125 		}
126 		else	// is empty
127 		{
128 			if(!market_unload_goods_in_empty_slot(curMarket, i))
129 				break; // no goods for further checking
130 		}
131 	}
132 
133 	//-------------------------------------------------//
134 	// unload new goods in the empty slots
135 	//-------------------------------------------------//
136 	if(withEmptySlot)
137 	{
138 		marketGoods = curMarket->market_goods_array;
139 		for(i=0; i<MAX_MARKET_GOODS && withEmptySlot; i++, marketGoods++)
140 		{
141 			if(marketGoods->stock_qty || marketGoods->supply_30days())
142 				continue;
143 
144 			market_unload_goods_in_empty_slot(curMarket, i);
145 			withEmptySlot--;
146 		}
147 	}
148 
149 	err_when(withEmptySlot);
150 }
151 //----------- End of function UnitCaravan::market_unload_goods -----------//
152 
153 
154 //--------- Begin of function UnitCaravan::market_unload_goods_in_empty_slot ---------//
155 //
156 // This function searches for possible new product or raw material to unload
157 // to a provided empty market slot. It will favor refined product first, then
158 // raw material.
159 //
160 // return 0 if no goods are unloaded and there are no other goods to unload
161 // to a different slot
162 // return 1 if goods are unloaded or there are other goods to unload to a
163 // different slot
164 //
market_unload_goods_in_empty_slot(FirmMarket * curMarket,int position)165 int UnitCaravan::market_unload_goods_in_empty_slot(FirmMarket *curMarket, int position)
166 {
167 	int more_to_unload = 0;
168 	MarketGoods* marketGoods = curMarket->market_goods_array + position;
169 
170 	//-------------------------------------------------//
171 	// unload product and then raw
172 	//-------------------------------------------------//
173 	int processed, j;
174 	for(processed=0, j=0; j<MAX_PRODUCT; j++)
175 	{
176 		MarketGoods *checkGoods;
177 		int productExistInOtherSlot;
178 
179 		if(processed_product_raw_qty_array[j] || !product_raw_qty_array[j])
180 			continue; // this product is processed or no stock in the caravan
181 
182 		// this can be unloaded, but check if it can be
183 		// unloaded into an already provided market slot
184 		// for this product type
185 
186 		checkGoods = curMarket->market_goods_array;
187 		productExistInOtherSlot = 0;
188 		for(int k=0; k<MAX_MARKET_GOODS; k++, checkGoods++)
189 		{
190 			if(checkGoods->product_raw_id==j+1)
191 			{
192 				productExistInOtherSlot++;
193 				break;
194 			}
195 		}
196 
197 		if(productExistInOtherSlot)
198 		{
199 			more_to_unload++;
200 			continue;
201 		}
202 
203 		// this does not exist in a market slot, so unload
204 		// in this empty one
205 
206 		#ifdef DEBUG
207 			MarketGoods *debugGoods = curMarket->market_goods_array;
208 			for(int debugCount=0; debugCount<MAX_MARKET_GOODS; ++debugCount, debugGoods++)
209 				err_when(debugGoods->product_raw_id==j+1);
210 		#endif
211 
212 		//-**************************************************-//
213 		//err_when(marketGoods->stock_qty);
214 		marketGoods->stock_qty = (float) 0; // BUGHERE, there is a case that marketGoods->stock_qty > 0
215 		//-**************************************************-//
216 		processed_product_raw_qty_array[j] += 2;
217 		curMarket->set_goods(0, j+1, position);
218 
219 		short unloadQty = (short) MIN(product_raw_qty_array[j], curMarket->max_stock_qty-marketGoods->stock_qty);
220 		product_raw_qty_array[j] -= unloadQty;
221 		marketGoods->stock_qty	 += unloadQty;
222 		processed++;
223 		break;
224 	}
225 
226 	if(!processed)
227 	{
228 		for(j=0; j<MAX_PRODUCT; j++)
229 		{
230 			MarketGoods *checkGoods;
231 			int rawExistInOtherSlot;
232 			if(processed_raw_qty_array[j] || !raw_qty_array[j])
233 				continue; // this product is processed or no stock in the caravan
234 
235 			// this can be unloaded, but check if it can be
236 			// unloaded into an already provided market slot
237 			// for this product type
238 
239 			checkGoods = curMarket->market_goods_array;
240 			rawExistInOtherSlot = 0;
241 			for(int k=0; k<MAX_MARKET_GOODS; k++, checkGoods++)
242 			{
243 				if(checkGoods->raw_id==j+1)
244 				{
245 					rawExistInOtherSlot++;
246 					break;
247 				}
248 			}
249 
250 			if(rawExistInOtherSlot)
251 			{
252 				more_to_unload++;
253 				continue;
254 			}
255 
256 			// this does not exist in a market slot, so unload
257 			// in this empty one
258 
259 			#ifdef DEBUG
260 				MarketGoods *debugGoods = curMarket->market_goods_array;
261 				for(int debugCount=0; debugCount<MAX_MARKET_GOODS; ++debugCount, debugGoods++)
262 					err_when(debugGoods->raw_id==j+1);
263 			#endif
264 
265 			//-**************************************************-//
266 			//err_when(marketGoods->stock_qty);
267 			marketGoods->stock_qty = (float) 0; // BUGHERE, there is a case that marketGoods->stock_qty > 0
268 			//-**************************************************-//
269 			processed_raw_qty_array[j] += 2;
270 			curMarket->set_goods(1, j+1, position);
271 
272 			short unloadQty = (short) MIN(raw_qty_array[j], curMarket->max_stock_qty-marketGoods->stock_qty);
273 			raw_qty_array[j]			-= unloadQty;
274 			marketGoods->stock_qty	+= unloadQty;
275 			processed++;
276 			break;
277 		}
278 	}
279 
280 	if( unit_array.selected_recno == sprite_recno )
281 		info.disp();
282 
283 	return (processed || more_to_unload);
284 }
285 //----------- End of function UnitCaravan::market_unload_goods_in_empty_slot -----------//
286 
287 
288 //--------- Begin of function UnitCaravan::market_load_goods ---------//
289 //
market_load_goods()290 void UnitCaravan::market_load_goods()
291 {
292 	CaravanStop *stopPtr = stop_array+dest_stop_id-1;
293 	err_when(stopPtr->pick_up_type == NO_PICK_UP);
294 
295 	FirmMarket	*curMarket = (FirmMarket*) firm_array[ stopPtr->firm_recno ];
296 	err_when(curMarket->firm_id != FIRM_MARKET);
297 	MarketGoods	*marketGoods=curMarket->market_goods_array;
298 
299 	//------------------------------------------------------------//
300 	// scan the market, see if it has the specified pickup goods
301 	//------------------------------------------------------------//
302 	for(int i=0; i<MAX_MARKET_GOODS; i++, marketGoods++)
303 	{
304 		if(marketGoods->raw_id)
305 		{
306 			if(stopPtr->pick_up_array[marketGoods->raw_id-1])
307 				market_load_goods_now(marketGoods, marketGoods->stock_qty);
308 		}
309 		else if(marketGoods->product_raw_id)
310 		{
311 			if(stopPtr->pick_up_array[marketGoods->product_raw_id-1+MAX_RAW])
312 				market_load_goods_now(marketGoods, marketGoods->stock_qty);
313 		}
314 	}
315 }
316 //----------- End of function UnitCaravan::market_load_goods -----------//
317 
318 
319 //--------- Begin of function UnitCaravan::market_auto_load_goods ---------//
320 //
market_auto_load_goods()321 void UnitCaravan::market_auto_load_goods()
322 {
323 	FirmMarket	*curMarket = (FirmMarket*) firm_array[ stop_array[dest_stop_id-1].firm_recno ];
324 	err_when(curMarket->firm_id != FIRM_MARKET);
325 
326 	MarketGoods *marketGoods = curMarket->market_goods_array;
327 	//int	isOurMarket = (curMarket->nation_recno==nation_recno); // is 1 or 0
328 	int	goodsId;
329 	short	loadQty;
330 
331 	//----------------------------------------------------------------------//
332 	// keep empty stock if the market(AI) is for sale, otherwise use the
333 	// default value
334 	//----------------------------------------------------------------------//
335 	//short minFirmStockQty = (int)curMarket->max_stock_qty/5; // keep at least 20% capacity in the firm if the market is not for sale
336 
337 	for(int i=0; i<MAX_MARKET_GOODS; i++, marketGoods++)
338 	{
339 		if(!marketGoods->stock_qty)
340 			continue;
341 
342 		if(marketGoods->raw_id)
343 		{
344 			err_when(marketGoods->product_raw_id);
345 			(goodsId = marketGoods->raw_id)--;
346 			if(processed_raw_qty_array[goodsId]==2)
347 				continue;	// continue if it is the goods unloaded
348 
349 			if(marketGoods->stock_qty > MIN_FIRM_STOCK_QTY)
350 			{
351 				loadQty = (short) (marketGoods->stock_qty - MIN_FIRM_STOCK_QTY);
352 				err_when(loadQty<0);
353 				market_load_goods_now(marketGoods, (float) loadQty);
354 			}
355 		}
356 		//else if(marketGoods->product_raw_id && isOurMarket) // only load product in our market
357 		else if(marketGoods->product_raw_id)
358 		{
359 			err_when(marketGoods->raw_id);
360 			(goodsId = marketGoods->product_raw_id)--;
361 			if(processed_product_raw_qty_array[goodsId]==2)
362 				continue;	// continue if it is the goods unloaded
363 
364 			if(marketGoods->stock_qty > MIN_FIRM_STOCK_QTY)
365 			{
366 				loadQty = (short) (marketGoods->stock_qty - MIN_FIRM_STOCK_QTY);
367 				err_when(loadQty<0);
368 				market_load_goods_now(marketGoods, (float) loadQty);
369 			}
370 		}
371 	}
372 }
373 //----------- End of function UnitCaravan::market_auto_load_goods -----------//
374 
375 
376 //--------- Begin of function UnitCaravan::market_load_goods_now ---------//
377 //
market_load_goods_now(MarketGoods * marketGoods,float loadQty)378 void UnitCaravan::market_load_goods_now(MarketGoods* marketGoods, float loadQty)
379 {
380 	Nation	*nationPtr = nation_array[nation_recno];
381 	int		marketNationRecno = firm_array[stop_array[dest_stop_id-1].firm_recno]->nation_recno;
382 	short		qty;
383 	int		goodsId;
384 
385 	if(marketGoods->product_raw_id)
386 	{
387 		//---------------- is product ------------------//
388 		err_when(marketGoods->raw_id);
389 		(goodsId = marketGoods->product_raw_id)--;
390 
391 		qty = MIN(MAX_CARAVAN_CARRY_QTY-product_raw_qty_array[goodsId], (int)loadQty);
392 		if(marketNationRecno!=nation_recno) // calculate the qty again if this is not our own market
393 		{
394 			qty = (nationPtr->cash>0) ? (short) MIN(nationPtr->cash/PRODUCT_PRICE, qty) : 0;
395 
396 			if(qty)
397 				nationPtr->import_goods(IMPORT_PRODUCT, marketNationRecno, (float)qty * PRODUCT_PRICE);
398 		}
399 
400 		product_raw_qty_array[goodsId] += qty;
401 		err_when(product_raw_qty_array[goodsId]<0 || product_raw_qty_array[goodsId]>MAX_CARAVAN_CARRY_QTY);
402 		marketGoods->stock_qty	-= qty;
403 	}
404 	else if(marketGoods->raw_id)
405 	{
406 		//---------------- is raw ---------------------//
407 		err_when(marketGoods->product_raw_id);
408 		(goodsId = marketGoods->raw_id)--;
409 
410 		qty = MIN(MAX_CARAVAN_CARRY_QTY-raw_qty_array[goodsId], (int)loadQty);
411 		if(marketNationRecno!=nation_recno) // calculate the qty again if this is not our own market
412 		{
413 			qty = (nationPtr->cash>0) ? (short) MIN(nationPtr->cash/RAW_PRICE, qty) : 0;
414 
415 			if(qty)
416 				nationPtr->import_goods(IMPORT_RAW, marketNationRecno, (float)qty * RAW_PRICE);
417 		}
418 
419 		raw_qty_array[goodsId]			+= qty;
420 		err_when(raw_qty_array[goodsId]<0 || raw_qty_array[goodsId]>MAX_CARAVAN_CARRY_QTY);
421 		marketGoods->stock_qty	-= qty;
422 	}
423 
424 	//### begin trevor 7/8 ###//
425 
426 	if( qty > 0 )
427 		last_load_goods_date = info.game_date;
428 
429 	//#### end trevor 7/8 ####//
430 }
431 //----------- End of function UnitCaravan::market_load_goods_now -----------//
432 
433 
434 //--------- Begin of function UnitCaravan::mine_load_goods ---------//
mine_load_goods(char pickUpType)435 void UnitCaravan::mine_load_goods(char pickUpType)
436 {
437 	if(pickUpType == NO_PICK_UP)
438 		return; // return if not allowed to load any goods
439 
440 	err_when(pickUpType>=PICK_UP_PRODUCT_FIRST && pickUpType<=PICK_UP_PRODUCT_LAST);
441 	CaravanStop *stopPtr = stop_array+dest_stop_id-1;
442 	FirmMine		*curMine = (FirmMine*) firm_array[stopPtr->firm_recno];
443 	err_when(curMine->firm_id != FIRM_MINE);
444 
445 	if(curMine->nation_recno!=nation_recno)
446 		return; // no action if this is not our own mine
447 
448 	//------------- load goods -----------//
449 	int searchRawId = pickUpType-PICK_UP_RAW_FIRST+1;
450 	if(pickUpType==AUTO_PICK_UP || curMine->raw_id==searchRawId) // auto_pick_up or is the raw to pick up
451 	{
452 		int		goodsId = curMine->raw_id-1;
453 		short		maxLoadQty = (pickUpType!=AUTO_PICK_UP) ? (short)curMine->stock_qty :
454 									 MAX(0, (int)(curMine->stock_qty-MIN_FIRM_STOCK_QTY)); // MAX Qty mine can supply
455 		err_when(goodsId >= MAX_RAW);
456 		short		qty = MIN(MAX_CARAVAN_CARRY_QTY-raw_qty_array[goodsId], maxLoadQty); // MAX Qty caravan can carry
457 
458 		raw_qty_array[goodsId]		+= qty;
459 		err_when(raw_qty_array[goodsId]<0 || raw_qty_array[goodsId]>MAX_CARAVAN_CARRY_QTY);
460 		curMine->stock_qty	-= qty;
461 
462 		//### begin trevor 7/8 ####//
463 
464 		if( maxLoadQty > 0 )
465 			last_load_goods_date = info.game_date;
466 
467 		//#### end trevor 7/8 ####//
468 	}
469 }
470 //----------- End of function UnitCaravan::mine_load_goods -----------//
471 
472 
473 //--------- Begin of function UnitCaravan::factory_unload_goods ---------//
474 // unload raw material to factory
475 //
factory_unload_goods()476 void UnitCaravan::factory_unload_goods()
477 {
478 	CaravanStop	*stopPtr = stop_array+dest_stop_id-1;
479 	FirmFactory	*curFactory = (FirmFactory*) firm_array[stopPtr->firm_recno];
480 	err_when(curFactory->firm_id != FIRM_FACTORY);
481 
482 	if(curFactory->nation_recno!=nation_recno)
483 		return; // don't unload goods if this isn't our own factory
484 
485 	//--- if the factory does not have any stock and there is no production, set it to type of raw materials the caravan is carring ---//
486 
487 	if( curFactory->stock_qty == 0 &&
488 		 curFactory->raw_stock_qty == 0 &&
489 		 curFactory->production_30days() == 0 )
490 	{
491 		int rawCount=0;
492 		int rawId=0;
493 
494 		for( int i=0 ; i<MAX_RAW ; i++ )
495 		{
496 			if( raw_qty_array[i] > 0 )
497 			{
498 				rawCount++;
499 				rawId=i+1;
500 			}
501 		}
502 
503 		//-- only if the caravan only carries one type of raw material --//
504 
505 		if( rawCount==1 && rawId )
506 			curFactory->product_raw_id = rawId;
507 	}
508 
509 	//---------- unload materials automatically --------//
510 	int goodsId = curFactory->product_raw_id-1;
511 
512 	if(raw_qty_array[goodsId]) // caravan has this raw materials
513 	{
514 		short qty = MIN(raw_qty_array[goodsId], (short)(curFactory->max_raw_stock_qty-curFactory->raw_stock_qty));
515 		raw_qty_array[goodsId] -= qty;
516 		err_when(raw_qty_array[goodsId]<0);
517 		curFactory->raw_stock_qty += qty;
518 		err_when(curFactory->raw_stock_qty>curFactory->max_raw_stock_qty);
519 	}
520 }
521 //----------- End of function UnitCaravan::factory_unload_goods -----------//
522 
523 
524 //--------- Begin of function UnitCaravan::factory_load_goods ---------//
factory_load_goods(char pickUpType)525 void UnitCaravan::factory_load_goods(char pickUpType)
526 {
527 	if(pickUpType==NO_PICK_UP)
528 		return; // return not allowed to load any goods
529 
530 	err_when(pickUpType>=PICK_UP_RAW_FIRST && pickUpType<=PICK_UP_RAW_LAST);
531 	CaravanStop *stopPtr = stop_array+dest_stop_id-1;
532 	FirmFactory	*curFactory = (FirmFactory*) firm_array[stopPtr->firm_recno];
533 	err_when(curFactory->firm_id != FIRM_FACTORY);
534 
535 	if(curFactory->nation_recno!=nation_recno)
536 		return; // don't load goods if this isn't our own factory
537 
538 	//------------- load goods -----------//
539 	int searchProductRawId = pickUpType-PICK_UP_PRODUCT_FIRST+1;
540 	if(pickUpType==AUTO_PICK_UP || curFactory->product_raw_id==searchProductRawId) // auto_pick_up or is the product to pick up
541 	{
542 		int		goodsId = curFactory->product_raw_id-1;
543 		short		maxLoadQty = (pickUpType!=AUTO_PICK_UP) ? (short)curFactory->stock_qty :
544 									 MAX(0, (int)(curFactory->stock_qty-MIN_FIRM_STOCK_QTY)); // MAX Qty factory can supply
545 		err_when(goodsId < 0);
546 		short		qty = MIN(MAX_CARAVAN_CARRY_QTY-product_raw_qty_array[goodsId], maxLoadQty); // MAX Qty caravan can carry
547 
548 		product_raw_qty_array[goodsId]	+= qty;
549 		err_when(product_raw_qty_array[goodsId]<0 || product_raw_qty_array[goodsId]>MAX_CARAVAN_CARRY_QTY);
550 		curFactory->stock_qty	-= qty;
551 
552 		//### begin trevor 7/8 ####//
553 
554 		if( maxLoadQty > 0 )
555 			last_load_goods_date = info.game_date;
556 
557 		//#### end trevor 7/8 ####//
558 	}
559 }
560 //----------- End of function UnitCaravan::factory_load_goods -----------//
561