Пример #1
0
END_TEST

/*******************************************************************************
 * test for chunk_hash[_inc]()
 */

START_TEST(test_chunk_hash)
{
	chunk_t chunk;
	u_int32_t hash_a, hash_b, hash_c;

	chunk = chunk_from_str("asdf");

	/* output is randomized, so there are no test-vectors we could use */
	hash_a = chunk_hash(chunk);
	hash_b = chunk_hash(chunk);
	ck_assert(hash_a == hash_b);
	hash_b = chunk_hash_inc(chunk, hash_a);
	ck_assert(hash_a != hash_b);
	hash_c = chunk_hash_inc(chunk, hash_a);
	ck_assert(hash_b == hash_c);
}
Пример #2
0
void add_biology(chunk *c) {
  world_map_pos wmpos;
  world_region *wr, *wr_second;
  float strbest, strsecond;
  world_region *wr_neighborhood[9];
  biome *local_biome;
  list *sp_list;
  frequent_species fqsp;
  chunk_neighborhood ch_nbh;
  cell_neighborhood cl_nbh;
  cell* cl;
  block_index idx;
  block substrate;
  global_pos glpos;
  ptrdiff_t seed_hash = prng(chunk_hash(c) + 616485);
  ptrdiff_t spacing_hash = prng(THE_WORLD->seed + 44544);

  if (c->chunk_flags & CF_HAS_BIOLOGY) {
    return; // Already has biology
  }
  fill_chunk_neighborhood(&(c->glcpos), &ch_nbh);
  if (ch_nbh.members[0] == NULL) {
    return; // Return without setting the CF_HAS_BIOLOGY flag.
  }
  // Look up the local biomes:
  glcpos__wmpos(&(c->glcpos), &wmpos);
  // TODO: Avoid using THE_WORLD here?
  wr = get_world_region(THE_WORLD, &wmpos);
  if (wr == NULL) {
    // TODO: Go farther here?
    return; // outside the world map: no biology
  }
  get_world_neighborhood_small(THE_WORLD, &wmpos, wr_neighborhood);
  // Use the center of our chunk to compute region contenders:
  idx.xyz.x = CHUNK_SIZE / 2;
  idx.xyz.y = CHUNK_SIZE / 2;
  idx.xyz.z = CHUNK_SIZE / 2;
  idx.xyz.w = 0;
  cidx__glpos(c, &idx, &glpos);
  compute_region_contenders(
    THE_WORLD,
    wr_neighborhood,
    &glpos,
    1232331,
    &wr,
    &wr_second,
    &strbest,
    &strsecond
  );
  // Mix biomes for this chunk:
  local_biome = create_merged_biome(
    wr,
    wr_second,
    strbest,
    strsecond
  );
  // Add seeds:
  idx.xyz.w = 0;
  for (idx.xyz.x = 0; idx.xyz.x < CHUNK_SIZE; ++idx.xyz.x) {
    for (idx.xyz.y = 0; idx.xyz.y < CHUNK_SIZE; ++idx.xyz.y) {
      for (idx.xyz.z = 0; idx.xyz.z < CHUNK_SIZE; ++idx.xyz.z) {
        // Get global cell position for hashing:
        cidx__glpos(c, &idx, &glpos);
        // TODO: optimize this within a loop...
        fill_cell_neighborhood_exact(idx, &ch_nbh, &cl_nbh);

        cl = cl_nbh.members[NBH_CENTER];
        // Array is in xyz order so up/down is +/- 1, north/south is +/- 3, and
        // east/west is +/- 9.

        // If our secondary is empty we can put a seed here: figure out what
        // distribution to draw from.
        sp_list = NULL;
        if (b_is_void(cl->blocks[1])) {
          if (b_id(cl->blocks[0]) == B_AIR) {
            // Ephemeral species seeds settle in the air directly on top of
            // dirt/sand/mud/etc.
            substrate = cl_nbh.members[NBH_CENTER - NBH_DIR_UD]->blocks[0];
            if (b_is_natural_terrain(substrate)) {
              sp_list = local_biome->ephemeral_terrestrial_flora;
            }
          } else if (b_id(cl->blocks[0]) == B_WATER) {
            // Aquatic ephemeral species start in water above dirt/sand/mud/etc.
            substrate = cl_nbh.members[NBH_CENTER - NBH_DIR_UD]->blocks[0];
            if (b_is_natural_terrain(substrate)) {
              sp_list = local_biome->ephemeral_aquatic_flora;
            }
          } else if (b_is_natural_terrain(cl->blocks[0])) {
            substrate = cl->blocks[0];
            if (
              b_id(cl_nbh.members[NBH_CENTER + NBH_DIR_UD]->blocks[0]) == B_AIR
            ) {
              // Most terrestrial species sprout in the ground with air above.
              // TODO: Subterranean species!
              // Select between spacings:
              if (wide_spacing_hit(glpos, spacing_hash)) {
                sp_list = local_biome->wide_spaced_terrestrial_flora;
              } else if (medium_spacing_hit(glpos, spacing_hash)) {
                sp_list = local_biome->medium_spaced_terrestrial_flora;
              } else if (close_spacing_hit(glpos, spacing_hash)) {
                sp_list = local_biome->close_spaced_terrestrial_flora;
              } else {
                sp_list = local_biome->ubiquitous_terrestrial_flora;
              }
            } else if (
              b_id(cl_nbh.members[NBH_CENTER + NBH_DIR_UD]->blocks[0]) ==B_WATER
            ) {
              // Aquatic plants sprout from seeds in terrain below water.
              // Select between spacings:
              if (wide_spacing_hit(glpos, spacing_hash)) {
                sp_list = local_biome->wide_spaced_aquatic_flora;
              } else if (medium_spacing_hit(glpos, spacing_hash)) {
                sp_list = local_biome->medium_spaced_aquatic_flora;
              } else if (close_spacing_hit(glpos, spacing_hash)) {
                sp_list = local_biome->close_spaced_aquatic_flora;
              } else {
                sp_list = local_biome->ubiquitous_aquatic_flora;
              }
            } else if (
              b_id(cl_nbh.members[NBH_CENTER - NBH_DIR_UD]->blocks[0]) == B_AIR
            ) {
              // Some plants can also grow down into air from ceilings.
              sp_list = local_biome->hanging_terrestrial_flora;
            }
            // TODO: Should things grow in underwater ceilings?
          }
          // Now we generate a seed from the species list we decided on:
          if (sp_list != NULL) {
            fqsp = pick_appropriate_frequent_species(
              sp_list,
              substrate,
              seed_hash
            );
            if (frequent_species_species_type(fqsp) != SPT_NO_SPECIES) {
              cl->blocks[1] = b_make_species(
                seed_block_type(frequent_species_species_type(fqsp)),
                frequent_species_species(fqsp)
              );
              // TODO: Real sprout timers...
              gri_set_sprout_timer(&(cl->blocks[1]), 1);
              seed_hash = prng(
                idx.xyz.x + idx.xyz.y + glpos.z +
                prng(seed_hash + glpos.x + glpos.y + idx.xyz.z)
              );
            }
          }
        }
      }
    }
  }
  // Clean up the local biome info now that we're done with it:
  cleanup_biome(local_biome);
  // Grow plants a bit:
  // TODO: How many cycles to use?
#ifdef DEBUG
  if (!grow_plants(c, 2)) {
    // At this point if growth fails (it really shouldn't) the best we can do
    // is emit a warning...
    fprintf(
      stderr,
      "WARNING: Growth failed after adding seeds during biology generation.\n"
    );
  }
#else
  grow_plants(c, 2);
#endif
  // Set the CF_HAS_BIOLOGY flag for this chunk:
  c->chunk_flags |= CF_HAS_BIOLOGY;
}