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    : OW_WALL.CPP
22 // Description : class World for building wall
23 // Ownership   : Gilbert
24 
25 #include <OWORLD.h>
26 #include <OMATRIX.h>
27 #include <WALLTILE.h>
28 #include <OWALLRES.h>
29 #include <OTOWN.h>
30 #include <OREMOTE.h>
31 #include <ONATIONA.h>
32 
33 #define WALL_GROWTH_RATE 6
34 
35 //--------------- begin of function World::can_build_area ----------//
can_build_area(short x1,short y1,short x2,short y2)36 int World::can_build_area(short x1, short y1, short x2, short y2)
37 {
38 	int x,y;
39 	err_when(x1 > x2 || y1 > y2);
40 	for(y = y1; y <= y2; ++y)
41 		for( x = x1; x <= x2; ++x)
42 			if( ! get_loc(x,y)->can_build_wall())
43 				return 0;
44 	return 1;
45 }
46 //--------------- end of function World::can_build_area ----------//
47 
48 //--------------- begin of function World::build_wall ----------//
build_wall(int townRecno,short initHp)49 void World::build_wall(int townRecno, short initHp)
50 {
51 	Town* townPtr = town_array[townRecno];
52 
53 	int xLoc1 = MAX(0, townPtr->loc_x1-WALL_SPACE_LOC);
54 	int yLoc1 = MAX(0, townPtr->loc_y1-WALL_SPACE_LOC);
55 	int xLoc2 = MIN(MAX_WORLD_X_LOC-1, townPtr->loc_x2+WALL_SPACE_LOC);
56 	int yLoc2 = MIN(MAX_WORLD_Y_LOC-1, townPtr->loc_y2+WALL_SPACE_LOC);
57 
58 	//--------------- build city wall -------------//
59 	build_wall_section(xLoc1, yLoc1, xLoc2, yLoc2, townRecno, initHp);
60 }
61 //--------------- end of function World::build_wall ----------//
62 
63 //--------------- begin of function World::build_wall_section ----------//
build_wall_section(short x1,short y1,short x2,short y2,short townRecno,short initHp)64 void World::build_wall_section(short x1, short y1, short x2, short y2,
65 	short townRecno, short initHp)
66 {
67 	//--------- build west wall -----------//
68 	Location *locPtr;
69 	short westWallFirst;
70 	for( westWallFirst = y1; westWallFirst < y2; ++westWallFirst)
71 	{
72 		if( get_loc(x1,westWallFirst)->can_build_wall() )
73 		{
74 			//--------- find place for the west gate ---------//
75 			if( x1 >= GATE_WIDTH-1 && y2-y1 >= GATE_LENGTH)
76 			{
77 				//----- try from the middle, and then butterfly outward ---//
78 				short increment = 0;
79 				short trial, westGateY;
80 				for( trial=y2-y1-GATE_LENGTH, westGateY=y1+(trial+1)/2;
81 					trial > 0; --trial, westGateY += increment)
82 				{
83 					if(can_build_area(x1-GATE_WIDTH+1, westGateY,
84 						x1, westGateY+GATE_LENGTH-1) )
85 					{
86 						//-------- put west gate --------- //
87 						build_west_gate(x1-GATE_WIDTH+1, westGateY, townRecno, initHp);
88 						break;
89 					}
90 					increment = -increment;
91 					if( increment >= 0)
92 						++increment;
93 					else
94 						--increment;
95 				}
96 				//---------- put other wall ----------//
97 				build_west_wall(x1, y1, y2, townRecno, initHp);
98 
99 				//--------- open west gate ----------//
100 				open_west_gate(x1, westGateY, townRecno);
101 
102 			}
103 			else
104 			{
105 				//-------- x1 too small for gate -------//
106 				get_loc(x1,westWallFirst)->set_wall(NTOWER, townRecno, initHp);
107 				get_loc(x1,westWallFirst)->set_fire_src(-50);
108 			}
109 			break;
110 		}
111 	}
112 
113 
114 	//--------- build east wall -----------
115 	short eastWallFirst;
116 	for( eastWallFirst = y1; eastWallFirst < y2; ++eastWallFirst)
117 	{
118 		if( get_loc(x2, eastWallFirst)->can_build_wall())
119 		{
120 			//---------- find place for the gate --------- //
121 			if( x2 <= max_x_loc - GATE_WIDTH +1 && y2-y1 >= GATE_LENGTH)
122 			{
123 				//---- try from the middle, and then butterfly outward ----//
124 				short increment = 0;
125 				short trial, eastGateY;
126 				for( trial=y2-y1-GATE_LENGTH, eastGateY=y1+(trial+1)/2;
127 					trial > 0; --trial, eastGateY += increment)
128 				{
129 					if(can_build_area(x2, eastGateY,	x2+GATE_WIDTH-1, eastGateY+GATE_LENGTH-1) )
130 					{
131 						//----------- put east gate ----------//
132 						build_east_gate(x2, eastGateY, townRecno, initHp);
133 						break;
134 					}
135 					increment = -increment;
136 					if( increment >= 0)
137 						++increment;
138 					else
139 						--increment;
140 				}
141 				//-------- put other wall ---------//
142 				build_east_wall(x2, y1, y2, townRecno, initHp);
143 
144 				//--------- open east gate ----------//
145 				open_east_gate(x2, eastGateY, townRecno);
146 			}
147 			else
148 			{
149 				//------- x2 too big for gate ---------//
150 				get_loc(x2,eastWallFirst)->set_wall(NETOWER, townRecno, initHp);
151 				get_loc(x2,eastWallFirst)->set_fire_src(-50);
152 			}
153 			break;
154 		}
155 	}
156 
157 	//--------- build north wall -----------//
158 	short northWallFirst;
159 	for( northWallFirst = x1; northWallFirst < x2; ++northWallFirst)
160 	{
161 		if( (locPtr = get_loc(northWallFirst, y1))->can_build_wall() ||
162 			( locPtr->is_wall() && locPtr->wall_town_recno() == townRecno) )
163 		{
164 			//-------- find place for the north gate --------//
165 			if( y1 >= GATE_WIDTH-1 && x2-x1 >= GATE_LENGTH)
166 			{
167 				//------- try from the middle, and then butterfly outward -------//
168 				short increment = 0;
169 				short trial, northGateX;
170 				for( trial=x2-x1-GATE_LENGTH, northGateX=x1+(trial+1)/2;
171 					trial > 0; --trial, northGateX += increment)
172 				{
173 					if(can_build_area(northGateX, y1-GATE_WIDTH+1,
174 						northGateX+GATE_LENGTH-1, y1) )
175 					{
176 						//--------------- put north gate ----------------//
177 						build_north_gate(northGateX, y1-GATE_WIDTH+1, townRecno, initHp);
178 						break;
179 					}
180 					increment = -increment;
181 					if( increment >= 0)
182 						++increment;
183 					else
184 						--increment;
185 				}
186 				//----------- put other wall --------------//
187 				build_north_wall(x1, x2, y1, townRecno, initHp);
188 
189 				//--------- open north gate ----------//
190 				open_north_gate(northGateX, y1, townRecno);
191 
192 			}
193 			else
194 			{
195 				//------------ y1 too small for gate -----------//
196 				if(locPtr->can_build_wall() )
197 				{
198 					locPtr->set_wall(NTOWER, townRecno, initHp);
199 					locPtr->set_fire_src(-50);
200 				}
201 			}
202 			break;
203 		}
204 	}
205 
206 
207 	//--------- build south wall -----------
208 	short southWallFirst;
209 	for( southWallFirst = x1; southWallFirst < x2; ++southWallFirst)
210 	{
211 		if( (locPtr = get_loc(southWallFirst, y2))->can_build_wall() ||
212 			( locPtr->is_wall() && locPtr->wall_town_recno() == townRecno) )
213 		{
214 			//---------- find place for the south gate ----------//
215 			if( y2 <= max_y_loc-GATE_WIDTH+1 && x2-x1 >= GATE_LENGTH)
216 			{
217 				//----- try from the middle, and then butterfly outward ----//
218 				short increment = 0;
219 				short trial, southGateX;
220 				for( trial=x2-x1-GATE_LENGTH, southGateX=x1+(trial+1)/2;
221 					trial > 0; --trial, southGateX += increment)
222 				{
223 					if(can_build_area(southGateX, y2,
224 						southGateX+GATE_LENGTH-1, y2+GATE_WIDTH-1) )
225 					{
226 						//----------- put south gate -------------//
227 						build_south_gate(southGateX, y2, townRecno, initHp);
228 						break;
229 					}
230 					increment = -increment;
231 					if( increment >= 0)
232 						++increment;
233 					else
234 						--increment;
235 				}
236 				//----------- put other wall -------------//
237 				build_south_wall(x1, x2, y2, townRecno, initHp);
238 
239 				//--------- open north gate ----------//
240 				open_south_gate(southGateX, y2, townRecno);
241 
242 			}
243 			else
244 			{
245 				//---------- y2 too big for gate ----------//
246 				if(locPtr->can_build_wall() )
247 				{
248 					locPtr->set_wall(STOWER, townRecno, initHp);
249 					locPtr->set_fire_src(-50);
250 				}
251 			}
252 			break;
253 		}
254 	}
255 
256 }
257 //--------------- end of function World::build_wall_section ----------//
258 
259 //--------------- begin of function World::build_west_gate ----------//
build_west_gate(short x1,short y1,short townRecno,short initHp)260 void World::build_west_gate(short x1, short y1, short townRecno, short initHp)
261 {
262 	//--------- put two gate towers -----------//
263 	Location *locPtr = get_loc(x1,y1);
264 	locPtr->set_wall(WGATE_NTOWER_NW, townRecno, initHp);
265 	(locPtr+1)->set_wall(WGATE_NTOWER_NE, townRecno, initHp);
266 	locPtr->set_fire_src(-50);
267 	(locPtr+1)->set_fire_src(-50);
268 
269 	locPtr = get_loc(x1, y1+1);
270 	locPtr->set_wall(WGATE_NTOWER_SW, townRecno, initHp);
271 	(locPtr+1)->set_wall(WGATE_NTOWER_SE, townRecno, initHp);
272 	locPtr->set_fire_src(-50);
273 	(locPtr+1)->set_fire_src(-50);
274 
275 	locPtr = get_loc(x1,y1+GATE_LENGTH-2);
276 	locPtr->set_wall(WGATE_STOWER_NW, townRecno, initHp);
277 	(locPtr+1)->set_wall(WGATE_STOWER_NE, townRecno, initHp);
278 	locPtr->set_fire_src(-50);
279 	(locPtr+1)->set_fire_src(-50);
280 
281 	locPtr = get_loc(x1, y1+GATE_LENGTH-1);
282 	locPtr->set_wall(WGATE_STOWER_SW, townRecno, initHp);
283 	(locPtr+1)->set_wall(WGATE_STOWER_SE, townRecno, initHp);
284 	locPtr->set_fire_src(-50);
285 	(locPtr+1)->set_fire_src(-50);
286 
287 	//---------- put gate -----------//
288 	char gateId = WGATE_BASE;
289 	for(short y = 2; y < GATE_LENGTH-2; ++y)
290 	{
291 		locPtr = get_loc(x1, y1+y);
292 		for(short x = 0; x < GATE_WIDTH; ++x, ++locPtr)
293 		{
294 			locPtr->set_wall(gateId++, townRecno, initHp);
295 			locPtr->set_fire_src(-50);
296 		}
297 	}
298 }
299 //--------------- end of function World::build_west_gate ----------//
300 
301 //--------------- begin of function World::build_west_wall ----------//
build_west_wall(short x1,short y1,short y2,short townRecno,short initHp)302 void World::build_west_wall(short x1, short y1, short y2, short townRecno,
303 	short initHp)
304 {
305 	//---------- find segments of buildable terrain ---------//
306 	short startY = y1, endY = y1;
307 	while(startY <= y2)
308 	{
309 		for( ; startY <= y2 && !get_loc(x1,startY)->can_build_wall(); ++startY);
310 		if( startY <= y2)		// a place is found
311 		{
312 			//-------- found segment end -----------//
313 			for( endY = startY+1; endY <= y2 && get_loc(x1,endY)->can_build_wall() ;++endY);
314 			--endY;
315 
316 			if( startY == endY)
317 			{
318 				//------- equal square, draw a single tower --------//
319 				get_loc(x1, startY)->set_wall(SINGLE_TOWER, townRecno, initHp);
320 				get_loc(x1, startY)->set_fire_src(-50);
321 			}
322 			else
323 			{
324 				short startSquare = NTOWER;
325 				short endSquare = STOWER;
326 				// if startY-1 is a wall, hence a gate, start with a wall with shadow
327 				if( startY > y1 && get_loc(x1, startY-1)->is_wall() )
328 				{
329 					startSquare = NSWALL_SHADOW;
330 				}
331 				// if endY+1 is a wall, hence a gate, start with a wall
332 				if( endY < y2 && get_loc(x1, endY+1)->is_wall() )
333 				{
334 					endSquare = NSWALL;
335 				}
336 				for( short y = startY; y < endY; ++y)
337 				{
338 					get_loc(x1, y)->set_wall(startSquare, townRecno, initHp);
339 					get_loc(x1, y)->set_fire_src(-50);
340 
341 					switch(startSquare)
342 					{
343 					case NTOWER:
344 						startSquare = NSWALL_SHADOW;
345 						break;
346 					case NSWALL_SHADOW:
347 						startSquare = NSWALL;
348 						break;
349 					// otherwise unchange
350 					}
351 				}
352 				get_loc(x1, endY)->set_wall(endSquare, townRecno, initHp);
353 				get_loc(x1, endY)->set_fire_src(-50);
354 			}
355 			startY = endY +1;
356 		}
357 	}
358 }
359 //--------------- end of function World::build_west_wall ----------//
360 
361 //--------------- begin of function World::open_west_gate ----------//
open_west_gate(short x2,short y1,short townRecno)362 void World::open_west_gate(short x2, short y1, short townRecno)
363 {
364 	//------ check if any west gate tile is built ---------//
365 	Location *locPtr = get_loc(x2,y1+2);
366 	if( locPtr->is_wall() && locPtr->wall_id() == WGATE_N &&
367 		locPtr->wall_town_recno() == townRecno)
368 	{
369 		for(short y = 3; y < GATE_LENGTH-3; ++y)
370 			for(short x = 0; x < GATE_WIDTH; ++x)
371 				get_loc(x2-x, y1+y)->remove_wall();
372 
373 	}
374 }
375 //--------------- end of function World::open_west_gate ----------//
376 
377 //--------------- begin of function World::build_east_gate ----------//
build_east_gate(short x1,short y1,short townRecno,short initHp)378 void World::build_east_gate(short x1, short y1, short townRecno, short initHp)
379 {
380 	//---------- put two gate towers ----------//
381 	Location *locPtr = get_loc(x1,y1);
382 	locPtr->set_wall(EGATE_NTOWER_NW, townRecno, initHp);
383 	(locPtr+1)->set_wall(EGATE_NTOWER_NE, townRecno, initHp);
384 	locPtr->set_fire_src(-50);
385 	(locPtr+1)->set_fire_src(-50);
386 
387 	locPtr = get_loc(x1, y1+1);
388 	locPtr->set_wall(EGATE_NTOWER_SW, townRecno, initHp);
389 	(locPtr+1)->set_wall(EGATE_NTOWER_SE, townRecno, initHp);
390 	locPtr->set_fire_src(-50);
391 	(locPtr+1)->set_fire_src(-50);
392 
393 	locPtr = get_loc(x1,y1+GATE_LENGTH-2);
394 	locPtr->set_wall(EGATE_STOWER_NW, townRecno, initHp);
395 	(locPtr+1)->set_wall(EGATE_STOWER_NE, townRecno, initHp);
396 	locPtr->set_fire_src(-50);
397 	(locPtr+1)->set_fire_src(-50);
398 
399 	locPtr = get_loc(x1, y1+GATE_LENGTH-1);
400 	locPtr->set_wall(EGATE_STOWER_SW, townRecno, initHp);
401 	(locPtr+1)->set_wall(EGATE_STOWER_SE, townRecno, initHp);
402 	locPtr->set_fire_src(-50);
403 	(locPtr+1)->set_fire_src(-50);
404 
405 	//------------- put gate ----------------//
406 	char gateId = EGATE_BASE;
407 	for(short y = 2; y <  GATE_LENGTH-2; ++y)
408 	{
409 		locPtr = get_loc(x1, y+y1);
410 		for(short x = 0; x < GATE_WIDTH; ++x, ++locPtr)
411 		{
412 			locPtr->set_wall(gateId++, townRecno, initHp);
413 			locPtr->set_fire_src(-50);
414 		}
415 	}
416 }
417 //--------------- end of function World::build_east_gate ----------//
418 
419 //--------------- begin of function World::build_east_wall ----------//
build_east_wall(short x1,short y1,short y2,short townRecno,short initHp)420 void World::build_east_wall(short x1, short y1, short y2, short townRecno,
421 	short initHp)
422 {
423 	//--------- find segments of buildable terrain ---------//
424 	short startY = y1, endY = y1;
425 	while(startY <= y2)
426 	{
427 		for( ; startY <= y2 && !get_loc(x1,startY)->can_build_wall(); ++startY);
428 		if( startY <= y2)		// a place is found
429 		{
430 			//-------- found segment end -------------//
431 			for( endY = startY+1; endY <= y2 && get_loc(x1,endY)->can_build_wall() ;++endY);
432 			--endY;
433 
434 			if( startY == endY)
435 			{
436 				//----------- equal square, draw a single tower --------//
437 				get_loc(x1, startY)->set_wall(SINGLE_TOWER, townRecno, initHp);
438 				get_loc(x1, startY)->set_fire_src(-50);
439 			}
440 			else
441 			{
442 				short startSquare = NTOWER;
443 				short endSquare = STOWER;
444 				// if startY-1 is a wall, hence a gate, start with a wall with shadow
445 				if( startY > y1 && get_loc(x1, startY-1)->is_wall() )
446 				{
447 					startSquare = NSWALL_SHADOW;
448 				}
449 				// if endY+1 is a wall, hence a gate, start with a wall
450 				if( endY < y2 && get_loc(x1, endY+1)->is_wall() )
451 				{
452 					endSquare = NSWALL;
453 				}
454 				for( short y = startY; y < endY; ++y)
455 				{
456 					get_loc(x1, y)->set_wall(startSquare, townRecno, initHp);
457 					get_loc(x1, y)->set_fire_src(-50);
458 					switch(startSquare)
459 					{
460 					case NTOWER:
461 						startSquare = NSWALL_SHADOW;
462 						break;
463 					case NSWALL_SHADOW:
464 						startSquare = NSWALL;
465 						break;
466 					// otherwise unchange
467 					}
468 				}
469 				get_loc(x1, endY)->set_wall(endSquare, townRecno, initHp);
470 				get_loc(x1, endY)->set_fire_src(-50);
471 			}
472 			startY = endY +1;
473 		}
474 	}
475 }
476 //--------------- end of function World::build_east_wall ----------//
477 
478 //--------------- begin of function World::open_east_gate ----------//
open_east_gate(short x1,short y1,short townRecno)479 void World::open_east_gate(short x1, short y1, short townRecno)
480 {
481 	//------ check if any east gate tile is built ---------//
482 	Location *locPtr = get_loc(x1,y1+2);
483 	if( locPtr->is_wall() && locPtr->wall_id() == EGATE_N &&
484 		locPtr->wall_town_recno() == townRecno)
485 	{
486 		for(short y = 3; y < GATE_LENGTH-3; ++y)
487 			for(short x = 0; x < GATE_WIDTH; ++x)
488 				get_loc(x1+x, y1+y)->remove_wall();
489 
490 	}
491 }
492 //--------------- end of function World::open_east_gate ----------//
493 
494 //--------------- begin of function World::build_north_gate ----------//
build_north_gate(short x1,short y1,short townRecno,short initHp)495 void World::build_north_gate(short x1, short y1, short townRecno,
496 	short initHp)
497 {
498 	//---------- put two gate towers -----------//
499 	Location *locPtr = get_loc(x1,y1);
500 	locPtr->set_wall(NGATE_WTOWER_NW, townRecno, initHp);
501 	(locPtr+1)->set_wall(NGATE_WTOWER_NE, townRecno, initHp);
502 	locPtr->set_fire_src(-50);
503 	(locPtr+1)->set_fire_src(-50);
504 
505 	locPtr = get_loc(x1+GATE_LENGTH-2, y1);
506 	locPtr->set_wall(NGATE_ETOWER_NW, townRecno, initHp);
507 	(locPtr+1)->set_wall(NGATE_ETOWER_NE, townRecno, initHp);
508 	locPtr->set_fire_src(-50);
509 	(locPtr+1)->set_fire_src(-50);
510 
511 	locPtr = get_loc(x1,y1+1);
512 	locPtr->set_wall(NGATE_WTOWER_SW, townRecno, initHp);
513 	(locPtr+1)->set_wall(NGATE_WTOWER_SE, townRecno, initHp);
514 	locPtr->set_fire_src(-50);
515 	(locPtr+1)->set_fire_src(-50);
516 
517 	locPtr = get_loc(x1+GATE_LENGTH-2, y1+1);
518 	locPtr->set_wall(NGATE_ETOWER_SW, townRecno, initHp);
519 	(locPtr+1)->set_wall(NGATE_ETOWER_SE, townRecno, initHp);
520 	locPtr->set_fire_src(-50);
521 	(locPtr+1)->set_fire_src(-50);
522 
523 	//------------ put gate -------------//
524 	char gateId = NGATE_BASE;
525 	for(short y = 0; y < GATE_WIDTH; ++y)
526 	{
527 		locPtr = get_loc(x1+2, y1+y);
528 		for(short x = 2; x < GATE_LENGTH-2; ++x, ++locPtr)
529 		{
530 			locPtr->set_wall(gateId++, townRecno, initHp);
531 			locPtr->set_fire_src(-50);
532 		}
533 	}
534 }
535 //--------------- end of function World::build_north_gate ----------//
536 
537 //--------------- begin of function World::build_north_wall ----------//
build_north_wall(short x1,short x2,short y1,short townRecno,short initHp)538 void World::build_north_wall(short x1, short x2, short y1, short townRecno,
539 	short initHp)
540 {
541 	//---------- find segments of buildable terrain ---------//
542 	short startX = x1, endX = x1;
543 	while(startX <= x2)
544 	{
545 		for( ; startX <= x2 && !get_loc(startX, y1)->can_build_wall(); ++startX);
546 		if( startX <= x2)		// a place is found
547 		{
548 			//--------- found segment end ----------//
549 			for( endX = startX+1; endX <= x2 && get_loc(endX, y1)->can_build_wall() ;++endX);
550 			--endX;
551 
552 			if( startX == endX)
553 			{
554 				//---------- equal square, draw a single tower ---------//
555 				get_loc(startX, y1)->set_wall(SINGLE_TOWER, townRecno, initHp);
556 				get_loc(startX, y1)->set_fire_src(-50);
557 			}
558 			else
559 			{
560 				short startSquare = WTOWER;
561 				short endSquare = ETOWER;
562 				// if startX-1 is a wall, hence a gate, start with a wall with shadow
563 				if( startX > x1 && get_loc(startX-1, y1)->is_wall() )
564 				{
565 					startSquare = EWWALL_SHADOW;
566 
567 					// if startX-1 is a NTOWER (corner) , change it to NWTOWER
568 					Location *leftLoc;
569 					if( (leftLoc = get_loc(startX-1, y1))->wall_id() == NTOWER
570 						&& leftLoc->wall_town_recno() == townRecno )
571 					{
572 						leftLoc->remove_wall();
573 						leftLoc->set_wall(NWTOWER, townRecno, initHp);
574 					}
575 				}
576 				// if endX+1 is a wall, hence a gate, start with a wall
577 				if( endX < x2 && get_loc(endX+1, y1)->is_wall() )
578 				{
579 					endSquare = EWWALL;
580 
581 					// if endX+1 is a NTOWER (corner) , change it to NETOWER
582 					Location *rightLoc;
583 					if( (rightLoc = get_loc(endX+1,y1))->wall_id() == NTOWER
584 						&& rightLoc->wall_town_recno() == townRecno)
585 					{
586 						rightLoc->remove_wall();
587 						rightLoc->set_wall(NETOWER, townRecno, initHp);
588 					}
589 				}
590 				for( short x = startX; x < endX; ++x)
591 				{
592 					get_loc(x, y1)->set_wall(startSquare, townRecno, initHp);
593 					get_loc(x, y1)->set_fire_src(-50);
594 					switch(startSquare)
595 					{
596 					case WTOWER:
597 						startSquare = EWWALL_SHADOW;
598 						break;
599 					case EWWALL_SHADOW:
600 						startSquare = EWWALL;
601 						break;
602 					// otherwise unchange
603 					}
604 				}
605 				get_loc(endX, y1)->set_wall(endSquare, townRecno, initHp);
606 				get_loc(endX, y1)->set_fire_src(-50);
607 			}
608 			startX = endX +1;
609 		}
610 	}
611 }
612 //--------------- end of function World::build_north_wall ----------//
613 
614 //--------------- begin of function World::open_north_gate ----------//
open_north_gate(short x1,short y2,short townRecno)615 void World::open_north_gate(short x1, short y2, short townRecno)
616 {
617 	//------ check if any north gate tile is built ---------//
618 	Location *locPtr = get_loc(x1+2,y2);
619 	if( locPtr->is_wall() && locPtr->wall_id() == NGATE_W &&
620 		locPtr->wall_town_recno() == townRecno)
621 	{
622 		for(short x = 3; x < GATE_LENGTH-3; ++x)
623 			for(short y = 0; y < GATE_WIDTH; ++y)
624 				get_loc(x1+x, y2-y)->remove_wall();
625 
626 	}
627 }
628 //--------------- end of function World::open_north_gate ----------//
629 
630 //--------------- begin of function World::build_south_gate ----------//
build_south_gate(short x1,short y1,short townRecno,short initHp)631 void World::build_south_gate(short x1, short y1, short townRecno, short initHp)
632 {
633 	//---------- put two gate towers ----------//
634 	Location *locPtr = get_loc(x1,y1);
635 	locPtr->set_wall(SGATE_WTOWER_NW, townRecno, initHp);
636 	(locPtr+1)->set_wall(SGATE_WTOWER_NE, townRecno, initHp);
637 	locPtr->set_fire_src(-50);
638 	(locPtr+1)->set_fire_src(-50);
639 
640 	locPtr = get_loc(x1+GATE_LENGTH-2, y1);
641 	locPtr->set_wall(SGATE_ETOWER_NW, townRecno, initHp);
642 	(locPtr+1)->set_wall(SGATE_ETOWER_NE, townRecno, initHp);
643 	locPtr->set_fire_src(-50);
644 	(locPtr+1)->set_fire_src(-50);
645 
646 	locPtr = get_loc(x1,y1+1);
647 	locPtr->set_wall(SGATE_WTOWER_SW, townRecno, initHp);
648 	(locPtr+1)->set_wall(SGATE_WTOWER_SE, townRecno, initHp);
649 	locPtr->set_fire_src(-50);
650 	(locPtr+1)->set_fire_src(-50);
651 
652 	locPtr = get_loc(x1+GATE_LENGTH-2, y1+1);
653 	locPtr->set_wall(SGATE_ETOWER_SW, townRecno, initHp);
654 	(locPtr+1)->set_wall(SGATE_ETOWER_SE, townRecno, initHp);
655 	locPtr->set_fire_src(-50);
656 	(locPtr+1)->set_fire_src(-50);
657 
658 	//------------ put gate --------------//
659 	char gateId = SGATE_BASE;
660 	for(short y = 0; y < GATE_WIDTH; ++y)
661 	{
662 		locPtr = get_loc(x1+2, y1+y);
663 		for(short x = 2; x < GATE_LENGTH-2; ++x, ++locPtr)
664 		{
665 			locPtr->set_wall(gateId++, townRecno, initHp);
666 			locPtr->set_fire_src(-50);
667 		}
668 	}
669 }
670 //--------------- end of function World::build_south_gate ----------//
671 
672 //--------------- begin of function World::build_south_wall ----------//
build_south_wall(short x1,short x2,short y1,short townRecno,short initHp)673 void World::build_south_wall(short x1, short x2, short y1, short townRecno,
674 	short initHp)
675 {
676 	//----------- find segments of buildable terrain -------------//
677 	short startX = x1, endX = x1;
678 	while(startX <= x2)
679 	{
680 		for( ; startX <= x2 && !get_loc(startX, y1)->can_build_wall(); ++startX);
681 		if( startX <= x2)		// a place is found
682 		{
683 			//---------- found segment end ---------//
684 			for( endX = startX+1; endX <= x2 && get_loc(endX, y1)->can_build_wall() ;++endX);
685 			--endX;
686 
687 			if( startX == endX)
688 			{
689 				//--------- equal square, draw a single tower --------//
690 				get_loc(startX, y1)->set_wall(SINGLE_TOWER, townRecno, initHp);
691 				get_loc(startX, y1)->set_fire_src(-50);
692 			}
693 			else
694 			{
695 				short startSquare = WTOWER;
696 				short endSquare = ETOWER;
697 				// if startX-1 is a wall, hence a gate, start with a wall with shadow
698 				if( startX > x1 && get_loc(startX-1, y1)->is_wall() )
699 				{
700 					startSquare = EWWALL_SHADOW;
701 					// if startX-1 is a STOWER (corner) , change it to SWTOWER
702 					Location *leftLoc;
703 					if( (leftLoc = get_loc(startX-1, y1))->wall_id() == STOWER
704 						&& leftLoc->wall_town_recno() == townRecno )
705 					{
706 						leftLoc->remove_wall();
707 						leftLoc->set_wall(SWTOWER, townRecno, initHp);
708 					}
709 				}
710 				// if endY+1 is a wall, hence a gate, start with a wall with shadow
711 				if( endX < x2 && get_loc(endX+1, y1)->is_wall() )
712 				{
713 					endSquare = EWWALL;
714 
715 					// if endX+1 is a STOWER (corner) , change it to SETOWER
716 					Location *rightLoc;
717 					if( (rightLoc = get_loc(endX+1, y1))->wall_id() == STOWER
718 						&& rightLoc->wall_town_recno() == townRecno)
719 					{
720 						rightLoc->remove_wall();
721 						rightLoc->set_wall(SETOWER, townRecno, initHp);
722 					}
723 
724 				}
725 				for( short x = startX; x < endX; ++x)
726 				{
727 					get_loc(x, y1)->set_wall(startSquare, townRecno, initHp);
728 					get_loc(x, y1)->set_fire_src(-50);
729 					switch(startSquare)
730 					{
731 					case WTOWER:
732 						startSquare = EWWALL_SHADOW;
733 						break;
734 					case EWWALL_SHADOW:
735 						startSquare = EWWALL;
736 						break;
737 					// otherwise unchange
738 					}
739 				}
740 				get_loc(endX, y1)->set_wall(endSquare, townRecno, initHp);
741 				get_loc(endX, y1)->set_fire_src(-50);
742 			}
743 			startX = endX +1;
744 		}
745 	}
746 }
747 //--------------- end of function World::build_south_wall ----------//
748 
749 //--------------- begin of function World::open_south_gate ----------//
open_south_gate(short x1,short y1,short townRecno)750 void World::open_south_gate(short x1, short y1, short townRecno)
751 {
752 	//------ check if any south gate tile is built ---------//
753 	Location *locPtr = get_loc(x1+2,y1);
754 	if( locPtr->is_wall() && locPtr->wall_id() == SGATE_W &&
755 		locPtr->wall_town_recno() == townRecno)
756 	{
757 		for(short x = 3; x < GATE_LENGTH-3; ++x)
758 			for(short y = 0; y < GATE_WIDTH; ++y)
759 				get_loc(x1+x, y1+y)->remove_wall();
760 
761 	}
762 }
763 //--------------- end of function World::open_south_gate ----------//
764 
765 //--------------- begin of function World::form_wall -----------//
766 //
767 // adjust wall tile, return no. of tile changed
768 //
form_wall(short x,short y,short maxRecur)769 int World::form_wall(short x, short y, short maxRecur)
770 {
771 	Location *locPtr = get_loc(x,y);
772 	if( !locPtr->is_wall() || maxRecur < 0)
773 		return 0;
774 
775 	int wallTile = locPtr->wall_id();
776 	int blockChanged = 0;
777 
778 	int flag = 0;
779 	if( y == 0 || get_loc(x,y-1)->is_wall())					// north square
780 		flag |= 1;
781 	if( x == max_x_loc-1 || get_loc(x+1,y)->is_wall() )	// east square
782 		flag |= 2;
783 	if( y == max_y_loc-1 || get_loc(x,y+1)->is_wall() )	// south square
784 		flag |= 4;
785 	if( x == 0 || get_loc(x-1,y)->is_wall() )					// west square
786 		flag |= 8;
787 	int newWallTile, newWallRubble;
788 
789 	// ------- find new wall tile ---------//
790 	switch(flag)
791 	{
792 	case 0:			// no surrounding square is wall
793 		newWallTile = SINGLE_TOWER;
794 		newWallRubble = TOWER_CON1;
795 		break;
796 	case 1:			// only north square is wall
797 		newWallTile = STOWER;
798 		newWallRubble = TOWER_CON1;
799 		break;
800 	case 2:			// only east
801 		newWallTile = WTOWER;
802 		newWallRubble = TOWER_CON1;
803 		break;
804 	case 3:			// north and east
805 		newWallTile = SWTOWER;
806 		newWallRubble = TOWER_CON1;
807 		break;
808 	case 4:			// south only
809 		newWallTile = NTOWER;
810 		newWallRubble = TOWER_CON1;
811 		break;
812 	case 5:			// north and south
813 		newWallTile = NSWALL;
814 		if( y > 0 && get_loc(x,y-1)->is_wall() )
815 		{
816 			int northWallTile = get_loc(x,y-1)->wall_id();
817 			if( northWallTile != NSWALL && northWallTile != NSWALL_SHADOW &&
818 				!is_wall_rubble(northWallTile))
819 				newWallTile = NSWALL_SHADOW;
820 		}
821 		newWallRubble = NSWALL_CON1;
822 		break;
823 	case 6:			// east and south
824 		newWallTile = NWTOWER;
825 		newWallRubble = TOWER_CON1;
826 		break;
827 	case 7:			// east and north and south
828 		newWallTile = NWTOWER;
829 		newWallRubble = TOWER_CON1;
830 		break;
831 	case 8:			// west only
832 		newWallTile = ETOWER;
833 		newWallRubble = TOWER_CON1;
834 		break;
835 	case 9:			// west and north
836 		newWallTile = SETOWER;
837 		newWallRubble = TOWER_CON1;
838 		break;
839 	case 10:			// west and east
840 		newWallTile = EWWALL;
841 		if( x > 0 && get_loc(x-1,y)->is_wall() )
842 		{
843 			int westWallTile = get_loc(x-1,y)->wall_id();
844 			if( westWallTile != EWWALL && westWallTile != EWWALL_SHADOW &&
845 				!is_wall_rubble(westWallTile) )
846 				newWallTile = EWWALL_SHADOW;
847 		}
848 		newWallRubble = EWWALL_CON1;
849 		break;
850 	case 11:			// west and east and north
851 		newWallTile = ETOWER;
852 		newWallRubble = TOWER_CON1;
853 		break;
854 	case 12:			// west and south
855 		newWallTile = NETOWER;
856 		newWallRubble = TOWER_CON1;
857 		break;
858 	case 13:			// west and south and north
859 		newWallTile = NETOWER;
860 		newWallRubble = TOWER_CON1;
861 		break;
862 	case 14:			// west and south and east
863 		newWallTile = NETOWER;
864 		newWallRubble = TOWER_CON1;
865 		break;
866 	case 15:			// all four
867 		newWallTile = NETOWER;
868 		newWallRubble = TOWER_CON1;
869 		break;
870 	}
871 
872 	// --- adjust newWallTile from wall_grade() ------//
873 	switch(get_loc(x,y)->wall_grade())
874 	{
875 	case 1:
876 		newWallTile = newWallRubble;
877 		break;
878 	case -1:
879 		newWallTile = newWallRubble + TOWER_DES1 - TOWER_CON1; // e.g. TOWER_CON1 -> TOWER_DES1
880 		break;
881 	case 2:
882 		newWallTile = newWallRubble + 1;
883 		break;
884 	case -2:
885 		newWallTile = newWallRubble + TOWER_DES2 - TOWER_CON1;
886 		break;
887 	case 3:
888 		newWallTile = newWallRubble + 2;
889 		break;
890 	case -3:
891 		newWallTile = newWallRubble + TOWER_DES3 - TOWER_CON1;
892 		break;
893 	case 4:
894 	case -4:
895 		// no change
896 		break;
897 	default:
898 		err_here();
899 	}
900 
901 	// ---  change wall tile, such as change to tower, add shadow ----//
902 	if( wallTile != newWallTile)
903 	{
904 		locPtr->chg_wall_id(newWallTile);
905 		blockChanged ++;
906 	}
907 
908 	// change adjacent sqaure
909 	if( y > 0 && get_loc(x,y-1)->is_wall() )
910 		blockChanged += form_wall(x, y-1, maxRecur-1);
911 	if( y < max_y_loc-1 && get_loc(x,y+1)->is_wall() )
912 		blockChanged += form_wall(x, y+1, maxRecur-1);
913 	if( x < max_x_loc-1 && get_loc(x+1,y)->is_wall() )
914 		blockChanged += form_wall(x+1, y, maxRecur-1);
915 	if( x > 0 && get_loc(x-1,y)->is_wall() )
916 		blockChanged += form_wall(x-1, y, maxRecur-1);
917 
918 	return blockChanged;
919 }
920 //--------------- end of function World::form_wall -----------//
921 
922 
923 //--------------- begin of function World::correct_wall -----------//
924 //
925 // adjust adjacent wall tiles, return no. of tile changed
926 //
correct_wall(short x,short y,short maxRecur)927 int World::correct_wall(short x, short y, short maxRecur)
928 {
929 	if( maxRecur < 0)
930 		return 0;
931 
932 	int blockChanged = 0;
933 	// change adjacent sqaure
934 	if( y > 0 && get_loc(x,y-1)->is_wall() )
935 		blockChanged += form_wall(x, y-1, maxRecur-1);
936 	if( y < max_y_loc-1 && get_loc(x,y+1)->is_wall() )
937 		blockChanged += form_wall(x, y+1, maxRecur-1);
938 	if( x < max_x_loc-1 && get_loc(x+1,y)->is_wall() )
939 		blockChanged += form_wall(x+1, y, maxRecur-1);
940 	if( x > 0 && get_loc(x-1,y)->is_wall() )
941 		blockChanged += form_wall(x-1, y, maxRecur-1);
942 
943 	return blockChanged;
944 }
945 
946 
947 //---------- begin of function World::form_world_wall -----//
form_world_wall()948 void World::form_world_wall()
949 {
950 	static int init_build_wall_seq = 0;
951 	#define SPACING 12
952 	static char build_wall_x_seq[SPACING*SPACING];
953 	static char build_wall_y_seq[SPACING*SPACING];
954 	static int	next_build_wall_seq;
955 
956 	int x, y;
957 
958 	if(! init_build_wall_seq )
959 	{
960 		init_build_wall_seq = 1;
961 		long seed = misc.get_random_seed();
962 		// ------ initialize with linear sequence----- //
963 		for( y = 0; y < SPACING; ++y)
964 		{
965 			for( x = 0; x < SPACING; ++x)
966 			{
967 				build_wall_x_seq[y*SPACING+x] = x;
968 				build_wall_y_seq[y*SPACING+x] = y;
969 			}
970 		}
971 
972 		misc.set_random_seed(176682233); // hard code
973 
974 		//------- shuffle randomly ----------//
975 		for(int t = SPACING * SPACING -1; t >= 0; --t)
976 		{
977 			int u = misc.random(SPACING * SPACING);
978 
979 			// ----- swap build_wall_x/y_seq[t] with [u]
980 			char tmp;
981 			tmp = build_wall_x_seq[t];
982 			build_wall_x_seq[t] = build_wall_x_seq[u];
983 			build_wall_x_seq[u] = tmp;
984 			tmp = build_wall_y_seq[t];
985 			build_wall_y_seq[t] = build_wall_y_seq[u];
986 			build_wall_y_seq[u] = tmp;
987 		}
988 		next_build_wall_seq = 0;
989 		misc.set_random_seed(seed);
990 	}
991 
992 	for(int trial = 7; trial > 0 ; --trial)
993 	{
994 		for(y = build_wall_y_seq[next_build_wall_seq]; y < max_y_loc; y+= SPACING)
995 		{
996 			for(x = build_wall_x_seq[next_build_wall_seq]; x < max_x_loc; x+= SPACING)
997 			{
998 				Location *locPtr = get_loc(x,y);
999 				// ######## begin Gilbert 7/3 ##########//
1000 				if( locPtr->had_wall() )
1001 				{
1002 					locPtr->dec_wall_timeout();
1003 				}
1004 				else if( locPtr->is_wall())
1005 				// ######## end Gilbert 7/3 ##########//
1006 				{
1007 					int prevGrade = locPtr->wall_grade();
1008 					int newGrade;
1009 					if( locPtr->inc_wall_hit_point(WALL_GROWTH_RATE) == 0)
1010 					{
1011 						locPtr->remove_wall();
1012 						if( y > 0 && get_loc(x,y-1)->is_wall() )
1013 							form_wall(x,y-1, 1);
1014 						if( y < max_y_loc-1 && get_loc(x,y+1)->is_wall() )
1015 							form_wall(x,y+1, 1);
1016 						if( x > 0 && get_loc(x-1,y)->is_wall() )
1017 							form_wall(x-1,y, 1);
1018 						if( x < max_x_loc-1 && get_loc(x+1,y)->is_wall() )
1019 							form_wall(x+1,y, 1);
1020 					}
1021 					else if( prevGrade != (newGrade=locPtr->wall_grade()) )
1022 					{
1023 						form_wall(x,y,2);
1024 					}
1025 				}
1026 			}
1027 		}
1028 		next_build_wall_seq = (next_build_wall_seq+1) % (SPACING*SPACING);
1029 	}
1030 }
1031 //---------- end of function World::form_world_wall -----//
1032 
1033 
1034 //------- Begin of function World::build_wall_tile -------//
1035 //
1036 // <int> xLoc, yLoc  - the location on which the wall should be built
1037 // <int> nationRecno - recno of the builder nation
1038 //
1039 // see also ZoomMatrix->draw_build_marker
1040 //
build_wall_tile(int xLoc,int yLoc,short nationRecno,char remoteAction)1041 void World::build_wall_tile(int xLoc, int yLoc, short nationRecno, char remoteAction)
1042 {
1043 	Location *locPtr = get_loc(xLoc, yLoc);
1044 	if( can_build_wall(xLoc, yLoc, nationRecno))
1045 	{
1046 		if( !remoteAction && remote.is_enable() )
1047 		{
1048 			// packet structure : <nation recno> <xLoc> <yLoc>
1049 			short *shortPtr = (short *)remote.new_send_queue_msg(MSG_WALL_BUILD, 3*sizeof(short));
1050 			shortPtr[0] = nationRecno;
1051 			shortPtr[1] = xLoc;
1052 			shortPtr[2] = yLoc;
1053 		}
1054 		else
1055 		{
1056 			locPtr->set_wall(TOWER_CON1,nationRecno, 1);
1057 			locPtr->set_fire_src(-50);
1058 //			nation_array[nationRecno]->add_expense( (float)BUILD_WALL_COST );
1059 		}
1060 	}
1061 	else if( locPtr->is_wall_destructing() &&
1062 		can_destruct_wall(xLoc, yLoc, nationRecno))
1063 	{
1064 		if( !remoteAction && remote.is_enable() )
1065 		{
1066 			// packet structure : <nation recno> <xLoc> <yLoc>
1067 			short *shortPtr = (short *)remote.new_send_queue_msg(MSG_WALL_BUILD, 3*sizeof(short));
1068 			shortPtr[0] = nationRecno;
1069 			shortPtr[1] = xLoc;
1070 			shortPtr[2] = yLoc;
1071 		}
1072 		else
1073 		{
1074 			locPtr->set_wall_creating();
1075 //			nation_array[nationRecno]->add_expense( (float)
1076 //				BUILD_WALL_COST * (100-locPtr->wall_abs_hit_point()) / 100 );
1077 		}
1078 	}
1079 
1080 }
1081 //--------- End of function World::build_wall_tile ---------//
1082 
1083 
1084 //------- Begin of function World::destruct_wall_tile -------//
1085 //
1086 // <int> xLoc, yLoc  - the location on which the wall should be destructed
1087 // <int> nationRecno - recno of the destructer nation
1088 //
1089 // see also ZoomMatrix->draw_build_marker
1090 //
destruct_wall_tile(int xLoc,int yLoc,short nationRecno,char remoteAction)1091 void World::destruct_wall_tile(int xLoc, int yLoc, short nationRecno, char remoteAction)
1092 {
1093 	Location *locPtr = get_loc(xLoc, yLoc);
1094 
1095 	if( locPtr->is_wall_creating() && can_destruct_wall(xLoc, yLoc, nationRecno) )
1096 	{
1097 		if( !remoteAction && remote.is_enable() )
1098 		{
1099 			// packet structure : <nation recno> <xLoc> <yLoc>
1100 			short *shortPtr = (short *)remote.new_send_queue_msg(MSG_WALL_DESTRUCT, 3*sizeof(short));
1101 			shortPtr[0] = nationRecno;
1102 			shortPtr[1] = xLoc;
1103 			shortPtr[2] = yLoc;
1104 		}
1105 		else
1106 		{
1107 			locPtr->set_wall_destructing();
1108 //			nation_array[nationRecno]->add_expense( (float) DESTRUCT_WALL_COST );
1109 		}
1110 	}
1111 }
1112 //--------- End of function World::destruct_wall_tile ---------//
1113