Noble Ape
The Central Directories of the Noble Ape Simulation.
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros
land.c
Go to the documentation of this file.
1 /****************************************************************
2 
3  land.c
4 
5  =============================================================
6 
7  Copyright 1996-2014 Tom Barbalet. All rights reserved.
8 
9  Permission is hereby granted, free of charge, to any person
10  obtaining a copy of this software and associated documentation
11  files (the "Software"), to deal in the Software without
12  restriction, including without limitation the rights to use,
13  copy, modify, merge, publish, distribute, sublicense, and/or
14  sell copies of the Software, and to permit persons to whom the
15  Software is furnished to do so, subject to the following
16  conditions:
17 
18  The above copyright notice and this permission notice shall be
19  included in all copies or substantial portions of the Software.
20 
21  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
23  OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
25  HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
26  WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
28  OTHER DEALINGS IN THE SOFTWARE.
29 
30  This software and Noble Ape are a continuing work of Tom Barbalet,
31  begun on 13 June 1996. No apes or cats were harmed in the writing
32  of this software.
33 
34  ****************************************************************/
35 
36 #ifndef _WIN32
37 
38 #include "../noble/noble.h"
39 
40 #else
41 
42 #include "..\noble\noble.h"
43 
44 #endif
45 
46 /*
47 
48  Resources
49 
50  Wood
51  Meat - Fish
52  Meat - Animals
53  Gold
54  Silver
55  Tin
56  Lead
57  Copper
58  Stone
59  Limestone
60 
61  Landscape Changes
62 
63  Path
64  Road
65  Hut
66  Smelter/Blacksmith
67  Boat Building
68  Boat
69 
70  Posessions
71 
72  ?
73  */
74 
75 static n_int weather_delta(n_land * local_land)
76 {
77  n_int lx = 0;
78  n_int average = 0;
79  n_int map_dimensions2;
80  n_int map_bits2;
81 
82  NA_ASSERT(local_land, "local_weather NULL");
83 
84  map_dimensions2 = land_map_dimension(local_land) / 2;
85 
86  map_bits2 = land_map_bits(local_land) - 1;
87  if (map_bits2 < 0) return 0;
88 
89  while (lx < map_dimensions2)
90  {
91  n_int ly = 0;
92  while (ly < map_dimensions2)
93  {
94  average += weather_pressure(local_land, WEATHER_TO_MAPSPACE(lx), WEATHER_TO_MAPSPACE(ly));
95  ly++;
96  }
97  lx++;
98  }
99  average = average >> map_bits2;
100  return average;
101 }
102 
103 /*
104  * The weather is maintained in a 18-bit band from bits_neg
105  */
106 static void weather_wrap(n_c_int * section)
107 {
108  const n_int bits_neg = (-131072 * 254) / 256;
109  const n_int bits_pos = ( 131071 * 254) / 256;
110  n_int max = bits_neg;
111  n_int min = bits_pos;
112  {
113  n_int placement = 0;
114  while (placement < (MAP_AREA / 4))
115  {
116  n_c_int value = section[placement++];
117  if (value > max)
118  {
119  max = value;
120  }
121  if (value < min)
122  {
123  min = value;
124  }
125  }
126  }
127  if ((min < bits_neg) || (max > bits_pos))
128  {
129  n_int placement = 0;
130  while (placement < (MAP_AREA / 4))
131  {
132  n_c_int value = section[placement];
133  section[placement++] = (value * 253) / 256;
134  }
135  }
136 }
137 
138 void weather_cycle(n_land * local_land)
139 {
140  n_int local_delta;
141  n_c_int * atmosphere;
142  n_byte2 * delta_pressure;
143  n_int ly = 0;
144  n_int map_dimensions2;
145  n_int map_bits2;
146 
147  NA_ASSERT(local_land, "local_land NULL");
148 
149  map_dimensions2 = land_map_dimension(local_land)/ 2;
150  map_bits2 = land_map_bits(local_land) - 1;
151  if (map_bits2 < 0) return;
152 
153  local_delta = weather_delta(local_land);
154  atmosphere = local_land->atmosphere;
155  delta_pressure = local_land->delta_pressure;
156 
157  NA_ASSERT(atmosphere, "atmosphere NULL");
158  NA_ASSERT(delta_pressure, "delta_pressure NULL");
159 
160  if (atmosphere == 0L) return;
161  if (delta_pressure == 0L) return;
162 
163  while ( ly < map_dimensions2 )
164  {
165  n_int ly_min = ((ly + (map_dimensions2-1) ) & ((map_dimensions2)-1)) * map_dimensions2;
166  n_int ly_plu = ((ly + 1 ) & (map_dimensions2-1)) * map_dimensions2;
167  n_int ly_neu = ly * map_dimensions2;
168  n_int lx = 0;
169  while ( lx < map_dimensions2 )
170  {
171  n_int local_atm =
172  ((n_int)delta_pressure[ lx | ly_neu ] << map_bits2)
173  - (512 << map_bits2)
174  - atmosphere[ ((lx + 1 ) & (map_dimensions2-1)) | ly_neu ]
175  + atmosphere[ ((lx + (map_dimensions2-1) ) & ((map_dimensions2)-1)) | ly_neu ]
176  - atmosphere[ lx | ly_plu ]
177  + atmosphere[ lx | ly_min ];
178 
179  atmosphere[ lx | ly_neu ] += (local_atm - local_delta) >> map_bits2;
180  lx++;
181  }
182  ly++;
183  }
184 
185  weather_wrap(atmosphere);
186 }
187 
188 void weather_init(n_land * local_land)
189 {
190  n_c_int *atmosphere;
191  n_byte2 *delta_pressure;
192  n_int ly = 0;
193  n_int ly2 = 0;
194  n_int map_dimension2;
195  n_int map_bits2;
196 
197  NA_ASSERT(local_land, "local_land NULL");
198 
199  if (local_land == 0L) return;
200 
201  atmosphere = local_land->atmosphere;
202  delta_pressure = local_land->delta_pressure;
203  map_dimension2 = land_map_dimension(local_land)/2;
204  map_bits2 = land_map_bits(local_land) - 1;
205  if (map_bits2 < 0) return;
206 
207  NA_ASSERT(atmosphere, "atmosphere NULL");
208  NA_ASSERT(delta_pressure, "delta_pressure NULL");
209  io_erase((n_byte *)local_land->atmosphere, sizeof(n_c_int) * MAP_AREA / 4);
210  io_erase((n_byte *)local_land->delta_pressure, sizeof(n_byte2) * MAP_AREA / 4);
211 
212  while ( ly < map_dimension2 )
213  {
214  n_int lx = 0;
215  ly2 = ly << 1;
216  while ( lx < map_dimension2 )
217  {
218  n_int lx2 = lx << 1;
219  n_int total_land = land_location(local_land, lx2, ly2)
220  + land_location(local_land, lx2 + 1, ly2)
221  + land_location(local_land, lx2, ly2 + 1)
222  + land_location(local_land, lx2 + 1, ly2 + 1);
223 
224 
225  atmosphere[ (map_dimension2 * ly) + lx ] = (n_c_int)total_land;
226  lx++;
227  }
228  ly++;
229  }
230  ly=0;
231  while ( ly < (map_dimension2) )
232  {
233  n_int lx = 0;
234  n_uint ly_plu = ((ly + 1 ) & ((map_dimension2)-1)) * map_dimension2;
235  n_uint ly_min = ((ly + (map_dimension2-1)) & (map_dimension2-1)) * map_dimension2;
236  n_uint ly_neu = (ly * map_dimension2);
237  while ( lx < (map_dimension2) )
238  {
239  delta_pressure[ ly_neu + lx ]
240  = (n_byte2)(atmosphere[ (( lx + 1 ) & ((map_dimension2)-1)) + ly_neu]
241  - atmosphere[(( lx + ((map_dimension2)-1) ) & ((map_dimension2)-1)) + ly_neu]
242  + atmosphere[ lx + ly_plu ]
243  - atmosphere[ lx + ly_min ]
244  + 512);
245  lx++;
246  }
247  ly++;
248  }
249 
250  ly = 0;
251  while( ly < (map_dimension2 * map_dimension2))
252  {
253  atmosphere[ ly ] = 0;
254  ly++;
255  }
256  ly = 0;
257  while( ly < (map_dimension2 * 2))
258  {
259  weather_cycle(local_land);
260  ly++;
261  }
262 }
263 
265 {
266  n_int dimension2 = land_map_dimension(land)/2;
267 
268  n_int tpx = ((px/2) + dimension2) % dimension2;
269  n_int tpy = ((py/2) + dimension2) % dimension2;
270 
271  return land->atmosphere[(dimension2 * tpy) + tpx];
272 }
273 
274 void weather_wind_vector(n_land * local_land, n_vect2 * pos, n_vect2 * wind)
275 {
276  n_int local_pressure;
277  NA_ASSERT(local_land, "local_land NULL");
278  NA_ASSERT(pos, "pos NULL");
279  NA_ASSERT(wind, "wind NULL");
280 
281  if (pos == 0L) return;
282  if (wind == 0L) return;
283 
284  local_pressure = weather_pressure(local_land, pos->x, pos->y);
285  wind->x = local_pressure - weather_pressure(local_land, pos->x - WEATHER_TO_MAPSPACE(1), (pos->y>>1));
286  wind->y = local_pressure - weather_pressure(local_land, pos->x, pos->y - WEATHER_TO_MAPSPACE(1));
287 }
288 
290 {
291  n_byte ret_val;
292  n_int val;
293  n_int local_time;
296 
297  NA_ASSERT(local_land, "local_land NULL");
298 
299  local_time = local_land->time;
300 
301  if(IS_DAWNDUSK(local_time))
302  {
304  }
305  if(IS_NIGHT(local_time))
306  {
307  ret_val = WEATHER_SEVEN_CLEAR_NIGHT;
308  }
309  else
310  {
311  ret_val = WEATHER_SEVEN_SUNNY_DAY;
312  }
313 
314  val = weather_pressure(local_land, map_x, map_y);
315 
316  if ( val == -1)
317  {
318  return WEATHER_SEVEN_ERROR; /* Error has already been shown */
319  }
320 
321  if(val > WEATHER_RAIN)
322  {
323  return ret_val+2;
324  }
325  if(val > WEATHER_CLOUD)
326  {
327  return ret_val+1;
328  }
329 
330  return ret_val;
331 }
332 
334 {
335  (void)land; /* land is not used here */
336  return MAP_DIMENSION;
337 }
338 
340 {
341  (void)land;
342  return MAP_BITS;
343 }
344 
346 {
347  return land->topology[math_memory_location(px, py)];
348 }
349 
350 void land_tide(n_land * local_land)
351 {
352  n_int time_of_day;
353  n_int current_time;
354  NA_ASSERT(local_land, "local_land NULL");
355 
356  time_of_day = local_land->time;
357  current_time = time_of_day + (local_land->date * TIME_DAY_MINUTES);
358 
359  {
360  n_int lunar_mins = current_time % LUNAR_ORBIT_MINS;
361  n_int lunar_angle_256 = (((time_of_day * 255) / 720)+((lunar_mins * 255) / LUNAR_ORBIT_MINS));
362  n_int solar_mins = current_time % (TIME_DAY_MINUTES * TIME_YEAR_DAYS);
363  n_int solar_angle_256 = (solar_mins * 255) / (TIME_DAY_MINUTES * TIME_YEAR_DAYS);
364 
365  n_int lunar = math_sine(lunar_angle_256, NEW_SD_MULTIPLE / TIDE_AMPLITUDE_LUNAR);
366  n_int solar = math_sine(solar_angle_256, NEW_SD_MULTIPLE / TIDE_AMPLITUDE_SOLAR);
367 
368  NA_ASSERT((((WATER_MAP + lunar + solar) > -1) && ((WATER_MAP + lunar + solar) < 256)), "(WATER_MAP + lunar + solar) outside byte boundaries");
369 
370  local_land->tide_level = (n_byte)(WATER_MAP + lunar + solar);
371  }
372 }
373 
374 void land_cycle(n_land * local_land)
375 {
376  NA_ASSERT(local_land, "local_land NULL");
377 
378  if (local_land == 0L) return;
379 
380  local_land->time++;
381  if (local_land->time == TIME_DAY_MINUTES)
382  {
383  local_land->time = 0;
384  local_land->date++;
385 
386  }
387 
388  land_tide(local_land);
389 }
390 
391 #define OPERATOR_AREA(fg, dfg, fdg) ((((dfg) * (dfg)) + ((fdg) * (fdg))) >> 6)
392 #define OPERATOR_HEIGHT(fg, dfg, fdg) (((WATER_MAP + fg) * (WATER_MAP + fg)) >> 8 )
393 #define OPERATOR_WATER(fg, dfg, fdg) (((WATER_MAP - fg) * (WATER_MAP - fg)) >> 8 )
394 #define OPERATOR_SUN(fg, dfg, fdg, ct, st) (((((ct) * (fg)) + ((st) * (dfg))) >> 4) + WATER_MAP)
395 #define OPERATOR_SALT(fg, dfg, fdg, fs) (((fs*fs)+(dfg*fdg))>>4)
396 
397 #define WATER_MAP2 (WATER_MAP * 2)
398 
399 static n_int land_operator(n_land * local_land, n_int locx, n_int locy, n_byte *specific_kind)
400 {
401  n_int temp = 0, temp_add;
402  n_int number_sum = 0;
403 
404  n_int fg;
405  n_int dfg;
406  n_int fdg;
407 
408  NA_ASSERT(local_land, "local_land NULL");
409  NA_ASSERT(specific_kind, "specific_kind NULL");
410 
411  fg = land_location(local_land, locx, locy);
412  dfg = land_location(local_land, locx + 1, locy);
413  fdg = land_location(local_land, locx, locy + 1);
414 
415  dfg = (dfg - fg) * 8;
416  fdg = (fdg - fg) * 8;
417 
418  fg = fg - WATER_MAP;
419 
420  if(specific_kind[0] != '.')
421  {
422  number_sum ++;
423  temp_add = OPERATOR_AREA(fg, dfg, fdg); /* A */
424  if(specific_kind[0] == '+')
425  temp += temp_add;
426  else
427  temp += WATER_MAP2 - temp_add;
428  }
429  if(specific_kind[1] != '.')
430  {
431  number_sum ++;
432  temp_add = OPERATOR_HEIGHT(fg, dfg, fdg); /* H */
433  if(specific_kind[1] == '+')
434  temp += temp_add;
435  else
436  temp += WATER_MAP2 - temp_add;
437  }
438  if(specific_kind[2] != '.')
439  {
440  number_sum ++;
441  temp_add = OPERATOR_WATER(fg, dfg, fdg); /* W */
442  if(specific_kind[2] == '+')
443  temp += temp_add;
444  else
445  temp += WATER_MAP2 - temp_add;
446  }
447  if(specific_kind[3] != '.')
448  {
449  if(IS_NIGHT(local_land->time) == 0)
450  {
451  /* 180 is minutes in the day / 8 */
452  n_int hr = ((((local_land->time << 6) / 180) + 32) & 255);
453 
454  n_int weather = weather_seven_values(local_land, MAPSPACE_TO_APESPACE(locx), MAPSPACE_TO_APESPACE(locy));
455 
456  n_int weather_divide = (105 + ((weather % 3) * 30));
457  n_vect2 time_weather;
458 
459  vect2_direction(&time_weather, hr, weather_divide * 32);
460  vect2_offset(&time_weather, 840/ weather_divide, 840/ weather_divide);
461 
462  number_sum ++;
463  temp_add = OPERATOR_SUN(fg, dfg, fdg, time_weather.x, time_weather.y); /* O */
464  if(specific_kind[3] == '+')
465  temp += temp_add;
466  else
467  temp += WATER_MAP2 - temp_add;
468  }
469  }
470  if(specific_kind[4] != '.')
471  {
472  number_sum ++;
473  temp_add = OPERATOR_SUN(fg, dfg, fdg, 11, 11); /* U */
474  if(specific_kind[4] == '+')
475  temp += temp_add;
476  else
477  temp += WATER_MAP2 - temp_add;
478  }
479  if(specific_kind[5] != '.')
480  {
482  if ((fs < 0) || (fs > (TIDE_AMPLITUDE_LUNAR + TIDE_AMPLITUDE_SOLAR)*2))
483  {
484  if(specific_kind[5] == '+') temp=0;
485  }
486  else
487  {
488  number_sum ++;
489  if(specific_kind[5] == '+')
490  temp += OPERATOR_SALT(fg, dfg, fdg, fs); /* S */
491  }
492  }
493  NA_ASSERT(number_sum, "number_sum is ZERO");
494  if(number_sum != 0)
495  {
496  temp = temp / number_sum;
497  }
498  return (temp);
499 }
500 
501 n_int land_operator_interpolated(n_land * local_land, n_int locx, n_int locy, n_byte * kind)
502 {
503  NA_ASSERT(local_land, "local_land NULL");
504  NA_ASSERT(kind, "kind NULL");
505 
506  {
507  n_int map_dimension = land_map_dimension(local_land);
508  n_int map_x = APESPACE_TO_MAPSPACE(locx);
509  n_int map_y = APESPACE_TO_MAPSPACE(locy);
510 
511  /* Not bilinear interpolation but linear interpolation. Probably should replace with bilinear (ie each value has x and y dependency) */
512  n_int interpolated;
513  interpolated = APESPACE_TO_MAPSPACE(
514  land_operator(local_land, (map_x+1)&(map_dimension-1), map_y, kind)*(locx-MAPSPACE_TO_APESPACE(map_x)));
515  interpolated += APESPACE_TO_MAPSPACE(
516  land_operator(local_land, (map_x-1)&(map_dimension-1), map_y, kind)*(MAPSPACE_TO_APESPACE(map_x+1)-locx));
517  interpolated += APESPACE_TO_MAPSPACE(
518  land_operator(local_land, map_x, (map_y+1)&(map_dimension-1), kind)*(locy-MAPSPACE_TO_APESPACE(map_y)));
519  interpolated += APESPACE_TO_MAPSPACE(
520  land_operator(local_land, map_x, (map_y-1)&(map_dimension-1), kind)*(MAPSPACE_TO_APESPACE(map_y+1)-locy));
521  return interpolated >> 1;
522  }
523 }
524 
525 void land_clear(n_land * local, KIND_OF_USE kind, n_byte4 start)
526 {
527  NA_ASSERT(local, "local NULL");
528  if (local == 0L) return;
529  {
530  n_byte *local_map = local->topology;
531  n_uint loop = 0;
532  NA_ASSERT(local_map, "local_map NULL");
533 
534  if (local_map == 0L) return;
535 
536  while (loop < (MAP_AREA))
537  {
538  local_map[loop] = 128;
539  loop++;
540  }
541  if (kind != KIND_LOAD_FILE)
542  {
543  local->time = 0;
544  local->date = start;
545  }
546  }
547 }
548 
549 void land_init(n_land * local_land, n_byte * scratch, n_byte double_spread)
550 {
551  n_byte2 local_random[2];
552  n_int refine = 0;
553 
554  local_random[0] = local_land->genetics[0];
555  local_random[1] = local_land->genetics[1];
556 
557  math_pack(MAP_AREA, 128, local_land->topology, scratch);
558 
559  while (refine < 7)
560  {
561  math_patch(local_land->topology, &math_memory_location, &math_random, local_random, refine);
562  math_round_smarter(local_land->topology, scratch, &math_memory_location);
563  refine++;
564  }
565 
566  if (local_land->topology_highdef)
567  {
568  n_uint lp = 0;
569  n_byte4 value_setting = 0;
570  n_byte4 * local_hires_tides= local_land->highres_tide;
571  n_byte * local_hires = local_land->topology_highdef;
572  math_bilinear_8_times(local_land->topology, local_land->topology_highdef, double_spread);
573 
574  io_erase((n_byte *)local_land->highres_tide, sizeof(n_byte4) * HI_RES_MAP_AREA/32);
575 
576  while (lp < HI_RES_MAP_AREA)
577  {
578  n_byte val = local_hires[lp<<1];
579  if ((val > 105) && (val < 151))
580  {
581  value_setting |= 1 << (lp & 31);
582  }
583 
584  if ((lp & 31) == 31)
585  {
586  local_hires_tides[lp>>5] = value_setting;
587  value_setting = 0;
588  }
589  lp++;
590 
591  }
592  }
593 }
594 
595 void land_vect2(n_vect2 * output, n_int * actual_z, n_land * local, n_vect2 * location)
596 {
597  n_int loc_x;
598  n_int loc_y;
599  n_int z;
600 
601  NA_ASSERT(output, "output NULL");
602  NA_ASSERT(actual_z, "actual_z NULL");
603  NA_ASSERT(local, "local NULL");
604  NA_ASSERT(location, "location NULL");
605 
606  if (output == 0L) return;
607  if (local == 0L) return;
608  if (location == 0L) return;
609 
610  loc_x = location->x;
611  loc_y = location->y;
612  z = land_location(local, APESPACE_TO_MAPSPACE(loc_x), APESPACE_TO_MAPSPACE(loc_y));
613 
614  if (actual_z != 0L)
615  {
616  *actual_z = z;
617  }
618  output->x = (z - land_location(local, (APESPACE_TO_MAPSPACE(loc_x) + 1), APESPACE_TO_MAPSPACE(loc_y)));
619  output->y = (z - land_location(local, APESPACE_TO_MAPSPACE(loc_x), (APESPACE_TO_MAPSPACE(loc_y) + 1)));
620 }
621 
623 {
624  if (initial->date < second->date)
625  {
626  return 0;
627  }
628  if (initial->date > second->date)
629  {
630  return 1;
631  }
632  if (initial->time > second->time)
633  {
634  return 1;
635  }
636  return 0;
637 }
638 
640 {
641  if (initial->date > now->date)
642  {
643  return 0;
644  }
645  if (initial->date < now->date)
646  {
647  return 1;
648  }
649  if (initial->time < now->time)
650  {
651  return 1;
652  }
653  return 0;
654 }
655 
657 {
658  to->location[0] = from->location[0];
659  to->location[1] = from->location[1];
660 
661  to->date = from->date;
662  to->time = from->time;
663 }
664 
665 void spacetime_set(n_spacetime * set, n_land * local, n_byte2 * location)
666 {
667  set->location[0] = location[0];
668  set->location[1] = location[1];
669  set->time = local->time;
670  set->date = local->date;
671 
672 }