void _set_temperature (const Planet& planet, const Climate_parameters&, Climate_generation_season& season) { auto temperature_at_latitude = [](float latitude) { return freezing_point() - 25 + 50*cos(latitude); }; for (auto& t : tiles(planet)) { float temperature = temperature_at_latitude(season.tropical_equator - latitude(planet, vector(t))); if (is_land(nth_tile(terrain(planet), id(t)))) { if (elevation(nth_tile(terrain(planet), id(t))) > sea_level(planet)) temperature -= temperature_lapse(elevation(nth_tile(terrain(planet), id(t))) - sea_level(planet)); } else { temperature = 0.3*temperature + 0.7*temperature_at_latitude(latitude(planet, vector(t))); } season.tiles[id(t)].temperature = temperature; } }
void testAreaShader() { Mercator::Area* a1 = new Mercator::Area(1, false); WFMath::Polygon<2> p; p.addCorner(p.numCorners(), Point2(3, 4)); p.addCorner(p.numCorners(), Point2(10, 10)); p.addCorner(p.numCorners(), Point2(14, 6)); p.addCorner(p.numCorners(), Point2(18, 4)); p.addCorner(p.numCorners(), Point2(17, 19)); p.addCorner(p.numCorners(), Point2(6, 20)); p.addCorner(p.numCorners(), Point2(-1, 18)); p.addCorner(p.numCorners(), Point2(-8, 11)); a1->setShape(p); Mercator::Area* a2 = new Mercator::Area(1, false); WFMath::Polygon<2> p2; p2.addCorner(p2.numCorners(), Point2(25, 18)); p2.addCorner(p2.numCorners(), Point2(72, 22)); p2.addCorner(p2.numCorners(), Point2(60, 30)); p2.addCorner(p2.numCorners(), Point2(27, 28)); p2.addCorner(p2.numCorners(), Point2(25, 45)); p2.addCorner(p2.numCorners(), Point2(3, 41)); p2.addCorner(p2.numCorners(), Point2(-2, 20)); a2->setShape(p2); Mercator::Terrain terrain(Mercator::Terrain::SHADED, 16); Mercator::Shader * base_shader = new Mercator::FillShader(Mercator::Shader::Parameters()); terrain.addShader(base_shader, 0); Mercator::AreaShader* ashade = new Mercator::AreaShader(1); terrain.addShader(ashade, 1); terrain.setBasePoint(0, 0, -1); terrain.setBasePoint(0, 1, 8); terrain.setBasePoint(1, 0, 2); terrain.setBasePoint(1, 1, 11); terrain.setBasePoint(2, 0, 2); terrain.setBasePoint(2, 1, 11); terrain.addArea(a1); // terrain.addArea(a2); Mercator::Segment* seg = terrain.getSegment(0,0); assert(a1->checkIntersects(*seg)); seg->populateSurfaces(); writePGMForSurface("test1.pgm", seg->getSize(), seg->getSurfaces()[1]); seg = terrain.getSegment(1,0); seg->populateSurfaces(); writePGMForSurface("test2.pgm", seg->getSize(), seg->getSurfaces()[1]); }
void _set_humidity (const Planet& planet, const Climate_parameters& par, Climate_generation_season& season) { for (auto& t : tiles(planet)) { float humidity = 0.0; if (is_water(nth_tile(terrain(planet), id(t)))) { humidity = saturation_humidity(season.tiles[id(t)].temperature); } season.tiles[id(t)].humidity = humidity; } _iterate_humidity(planet, par, season); }
void _iterate_humidity (const Planet& planet, const Climate_parameters& par, Climate_generation_season& season) { std::deque<float> humidity; std::deque<float> precipitation; humidity.resize(tile_count(planet)); precipitation.resize(tile_count(planet)); float delta = 1.0; while (delta > par.error_tolerance) { // std::cout << "delta: " << delta << "\n"; for (int i=0; i<tile_count(planet); i++) { precipitation[i] = 0.0; if (is_land(nth_tile(terrain(planet), i))) { humidity[i] = 0.0; precipitation[i] = 0.0; float incoming_wind = _incoming_wind(planet, season, i); float outgoing_wind = _outgoing_wind(planet, season, i); if (incoming_wind > 0.0) { float convection = outgoing_wind - incoming_wind; float incoming_humidity = _incoming_humidity(planet, season, i); // less humidity when incoming wind is less than outgoing float density = convection > 0 ? incoming_humidity / (incoming_wind + convection) : incoming_humidity / incoming_wind; float saturation = saturation_humidity(season.tiles[i].temperature); // limit to saturation humidity humidity[i] = std::min(saturation, density); if (saturation < density) precipitation[i] += (density - saturation) * incoming_wind; // increase humidity when outgoing wind is less than incoming if (convection < 0) { float convective = humidity[i] * (-convection / incoming_wind); if (humidity[i] + convective > saturation) precipitation[i] += (humidity[i] + convective - saturation) * (-convection); humidity[i] = std::min(saturation, humidity[i] + convective); } } // scale by constant and area precipitation[i] *= 3.0 / area(planet, nth_tile(planet, i)); } else humidity[i] = season.tiles[i].humidity; } float largest_change = 0.0; for (int i=0; i<tile_count(planet); i++) { largest_change = std::max(largest_change, _humidity_change(season.tiles[i].humidity, humidity[i])); } delta = largest_change; for (int i=0; i<tile_count(planet); i++) { season.tiles[i].humidity = humidity[i]; season.tiles[i].precipitation = precipitation[i]; } } }
void terrain(int *h, int x1, int y1, int x2, int y2) { int midx, midy, x, y; double nh, r, factor, oldheight; if (y2 < y1) swap(&y1, &y2); if (x2 < x1) swap(&x1, &x2); if (x2 - x1 < 2) return; if (y2 - y1 < 2) return; midx = x1 + (x2 - x1) / 2; midy = y1 + (y2 - y1) / 2; factor = (x2 - x1) / 2.0; oldheight = (double) h[idx(x1, y1)]; oldheight += (double) h[idx(x1, y2)]; oldheight += (double) h[idx(x2, y1)]; oldheight += (double) h[idx(x2, y2)]; oldheight /= 4.0; r = 0.0 + rand() / (0.0 + RAND_MAX) - 0.5; nh = (oldheight + factor * r); for (x = x1; x < x2; x++) { for (y = y1; y < y2; y++) { h[idx(x, y)] = nh; } } terrain(h, x1, y1, midx, midy); terrain(h, midx, y1, x2, midy); terrain(h, x1, midy, midx, y2); terrain(h, midx, midy, x2, y2); }
void create_terrain_maps(const config::const_child_itors &cfgs, t_translation::ter_list& terrain_list, std::map<t_translation::terrain_code, terrain_type>& letter_to_terrain) { for (const config &terrain_data : cfgs) { terrain_type terrain(terrain_data); DBG_G << "create_terrain_maps: " << terrain.number() << " " << terrain.id() << " " << terrain.name() << " : " << terrain.editor_group() << "\n"; std::pair<std::map<t_translation::terrain_code, terrain_type>::iterator, bool> res; res = letter_to_terrain.insert(std::make_pair(terrain.number(), terrain)); if (!res.second) { terrain_type& curr = res.first->second; if(terrain == curr) { LOG_G << "Merging terrain " << terrain.number() << ": " << terrain.id() << " (" << terrain.name() << ")\n"; std::vector<std::string> eg1 = utils::split(curr.editor_group()); std::vector<std::string> eg2 = utils::split(terrain.editor_group()); std::set<std::string> egs; bool clean_merge = true; for (std::string& t : eg1) { clean_merge &= egs.insert(t).second; } for (std::string& t : eg2) { clean_merge &= egs.insert(t).second; } std::string joined = utils::join(egs); curr.set_editor_group(joined); if(clean_merge) { LOG_G << "Editor groups merged to: " << joined << "\n"; } else { LOG_G << "Merged terrain " << terrain.number() << ": " << terrain.id() << " (" << terrain.name() << ") " << "with duplicate editor groups [" << terrain.editor_group() << "] " << "and [" << curr.editor_group() << "]\n"; } } else { ERR_G << "Duplicate terrain code definition found for " << terrain.number() << "\n" << "Failed to add terrain " << terrain.id() << " (" << terrain.name() << ") " << "[" << terrain.editor_group() << "]" << "\n" << "which conflicts with " << curr.id() << " (" << curr.name() << ") " << "[" << curr.editor_group() << "]" << "\n\n"; } } else { terrain_list.push_back(terrain.number()); } } }
int main(int argc, char** argv) { char temp[1024]=""; char ini_file[]="lightfield.ini"; ini_gets("Main", "TerrainFile", "", temp, 512, ini_file); string terrain_file=ToString(temp); ini_gets("Main", "Resources", "", temp, 512, ini_file); string resources=ToString(temp); ini_gets("Main", "Stage", "", temp, 512, ini_file); string stage=ToString(temp); ini_gets("Main", "GIA", "", temp, 512, ini_file); string gia=ToString(temp); float sample_unit_distance=ini_getf("Main", "SampleUnitDistance", 0.75f, ini_file); float saturation_multiplier=ini_getf("Main", "SaturationMultiplier", 1.0f, ini_file); float lookup_grid_size=ini_getf("Main", "LookupGridSize", 5.0f, ini_file); LibGens::initialize(); LibGens::Error::setLogging(true); LibGens::Terrain terrain(terrain_file, resources, stage, gia); printf("Done loading Terrain\n"); // Sample Unit Distance, Saturation Multiplier LibGens::VRMap *vrmap=terrain.generateVRMap(sample_unit_distance, saturation_multiplier); printf("VR Map setup...\n"); vrmap->generateLookupGrid(lookup_grid_size, sample_unit_distance); printf("Done generating VR Map of %d samples covering %f units of area.\n", vrmap->getSampleList().size(), vrmap->getAABB().size()); LibGens::LightField lightfield; float ambient_color_r=ini_getf("Main", "AmbientColorR", 1.0f, ini_file); float ambient_color_g=ini_getf("Main", "AmbientColorG", 1.0f, ini_file); float ambient_color_b=ini_getf("Main", "AmbientColorB", 1.0f, ini_file); float ambient_color_a=ini_getf("Main", "AmbientColorA", 1.0f, ini_file); int sample_min_count=ini_getl("Main", "SampleMinCount", 2, ini_file); float sample_blend_distance=ini_getf("Main", "SampleBlendDistance", 8.0f, ini_file); float min_octree_cube_size=ini_getf("Main", "MinOctreeCubeSize", 3.0f, ini_file); int cpu_threads=ini_getl("Main", "Threads", 1, ini_file); // Ambient Color, Sample Min Count, Sample Blend Distance, Min Octree Cube Size lightfield.generate(vrmap, LibGens::Color(ambient_color_r, ambient_color_g, ambient_color_b, ambient_color_a), sample_min_count, sample_blend_distance, min_octree_cube_size, cpu_threads); printf("Done generating lightfield.\n"); lightfield.save("light-field.lft"); printf("Saved lightfield. Press Enter to exit.\n"); getchar(); return 0; }
int main(int argc, char *argv[]) { int x, y; opencscad_init(); memset(height, 0, sizeof(height)); terrain(height, 0, 0, dim - 1, dim - 1); for (y = 0; y < dim; y++) { for (x = 0; x < dim; x++) { xlate(x, y, 0); cube(1.05, 1.05, (double) height[idx(x, y)], 0); endxlate(); } } finalize(); }
void getModifiedAttackAndDefenseTest() { // Test values > 0 qrw::Square square(0, 0); qrw::Terrain terrain(qrw::ET_HILL, 1, -1); square.setTerrain(&terrain); unit1->setSquare(&square); CPPUNIT_ASSERT_EQUAL(3, unit1->getModifiedAttack()); CPPUNIT_ASSERT_EQUAL(0, unit1->getModifiedDefense()); // Test values < 0 qrw::Terrain terrain2(qrw::ET_WALL, -3, -12); square.setTerrain(&terrain2); CPPUNIT_ASSERT_EQUAL(0, unit1->getModifiedAttack()); CPPUNIT_ASSERT_EQUAL(0, unit1->getModifiedDefense()); }
void EnemyAspect::followTerrain(float _dt) { TerrainContainer &terrain(*c.get<TerrainContainer>(Containers::TERRAIN)); int index = 0; float height; glm::vec2 tempPos; for(uint j = 0; j < ec->pos.size(); j++) { for(uint k = 0; k < HORDESIZE; k++) { index = j*HORDESIZE + k; tempPos = glm::vec2(ec->pos[j].x + ec->hordeunits[index].pos.x, ec->pos[j].z + ec->hordeunits[index].pos.z); height = Utility::mapToTerrain(tempPos, terrain).y; height = std::max(50.f, height); ec->hordeunits[index].pos.y = height + 10 + std::sin(ec->hordeunitwavevar1[index] * 3) * 2; } } }
void colour_topography (Planet_colours& c, const Planet& p) { static const Colour water_deep = Colour(0.0, 0.0, 0.25); static const Colour water = Colour(0.0, 0.12, 0.5); static const Colour water_shallow = Colour(0.0, 0.4, 0.6); static const Colour land[6] = { Colour(0.0, 0.4, 0.0), Colour(0.0, 0.7, 0.0), Colour(1.0, 1.0, 0.0), Colour(1.0, 0.5, 0.0), Colour(0.7, 0.0, 0.0), Colour(0.1, 0.1, 0.1)}; double land_limits[7] = {-500, 0, 500, 1000, 1500, 2000, 2500}; for (const Tile& t : tiles(p)) { const Terrain_tile& ter = nth_tile(terrain(p), id(t)); double elev = elevation(ter) - sea_level(p); if (is_water(ter)) { if (elev < -1000) { c.tiles[id(t)] = water_deep; } else if (elev < -500) { double d = (elev+500)/(-500); c.tiles[id(t)] = interpolate(water, water_deep, d); } else { double d = elev/(-500); c.tiles[id(t)] = interpolate(water_shallow, water, d); } } else { c.tiles[id(t)] = land[5]; for (int i=0; i<5; i++) { if (elev <= land_limits[i+1]) { double d = std::max(0.0, std::min(1.0, (elev - land_limits[i]) / (land_limits[i+1] - land_limits[i]))); c.tiles[id(t)] = interpolate(land[i], land[i+1], d); break; } } } } }
void testFillShader() { dymaxion::Terrain terrain(dymaxion::Terrain::SHADED, 16); dymaxion::Shader::Parameters params; dymaxion::FillShader * dshade = new dymaxion::FillShader(); delete dshade; dshade = new dymaxion::FillShader(params); terrain.addShader(dshade, 0); terrain.setBasePoint(0, 0, -20); terrain.setBasePoint(0, 1, 1); terrain.setBasePoint(1, 0, 2); terrain.setBasePoint(1, 1, 0.5); dymaxion::Segment * seg = terrain.getSegment(0, 0); seg->populate(); seg->populateSurfaces(); }
bool CTerrainMapaManager::Load( TiXmlElement* pXMLData ) { if ( !pXMLData ) return false; THROW_GAME_EXCEPTION_IF( !pXMLData->Attribute( "default" ), "Error Mapa: terreno por defecto no definido" ); std::string sTerrain( pXMLData->Attribute( "default" ) ); CTerrainType* pTerrain = TerrainManager.GetTerrainType( sTerrain ); THROW_GAME_EXCEPTION_IF( !( pTerrain ), "Error Mapa: el tipo de terreno " + sTerrain ); int basex = 0; int basey = 0; int raiz = 3; //!TODO Realizar bien esto basey = 0; for ( int y = 0; y < m_pModel->getResolution(); y++ ) { basex = 0; for ( int x = 0; x < m_pModel->getResolution(); x++ ) { CTerrainMapa_ptr terrain( new CTerrainMapa( m_pModel ) ); terrain->SetTile( pTerrain->GetTile( basex ), gcn::Point( x, y ) ); m_TerrainMapa.push_back( terrain ); basex = ( ( basex + 1 ) % raiz ) + basey * raiz; } basey = ( basey + 1 ) % raiz; } return true; }
Qt3DCore::QEntity *QgsDemTerrainTileLoader::createEntity( Qt3DCore::QEntity *parent ) { QgsTerrainTileEntity *entity = new QgsTerrainTileEntity; // create geometry renderer Qt3DRender::QGeometryRenderer *mesh = new Qt3DRender::QGeometryRenderer; mesh->setGeometry( new DemTerrainTileGeometry( mResolution, mHeightMap, mesh ) ); entity->addComponent( mesh ); // takes ownership if the component has no parent // create material createTextureComponent( entity ); // create transform Qt3DCore::QTransform *transform; transform = new Qt3DCore::QTransform(); entity->addComponent( transform ); float zMin, zMax; _heightMapMinMax( mHeightMap, zMin, zMax ); const Qgs3DMapSettings &map = terrain()->map3D(); QgsRectangle extent = map.terrainGenerator()->tilingScheme().tileToExtent( mNode->tileX(), mNode->tileY(), mNode->tileZ() ); //node->extent; double x0 = extent.xMinimum() - map.originX(); double y0 = extent.yMinimum() - map.originY(); double side = extent.width(); double half = side / 2; transform->setScale3D( QVector3D( side, map.terrainVerticalScale(), side ) ); transform->setTranslation( QVector3D( x0 + half, 0, - ( y0 + half ) ) ); mNode->setExactBbox( QgsAABB( x0, zMin * map.terrainVerticalScale(), -y0, x0 + side, zMax * map.terrainVerticalScale(), -( y0 + side ) ) ); entity->setEnabled( false ); entity->setParent( parent ); return entity; }
void colour_humidity (Planet_colours& c, const Planet& p, const Season& s) { static const Colour water = Colour(1.0, 1.0, 1.0); static const Colour land_dry = Colour(1.0, 1.0, 0.5); static const Colour land_mid = Colour(1.0, 1.0, 0.0); static const Colour land_humid = Colour(0.0, 0.7, 0.0); for (const Tile& t : tiles(p)) { double h = humidity(nth_tile(s, id(t))) / saturation_humidity(temperature(nth_tile(s, id(t)))); if (is_water(nth_tile(terrain(p), id(t)))) { c.tiles[id(t)] = water; } else { if (h <= 0.5) { double d = h / 0.5; c.tiles[id(t)] = interpolate(land_dry, land_mid, d); } else { double d = (h-0.5)/0.5; c.tiles[id(t)] = interpolate(land_mid, land_humid, d); } } } }
void colour_precipitation (Planet_colours& c, const Planet& p, const Season& s) { static const Colour water = Colour(1.0, 1.0, 1.0); static const Colour dry = Colour(1.0, 1.0, 0.5); static const Colour medium = Colour(0.0, 1.0, 0.0); static const Colour wet = Colour(0.0, 0.0, 1.0); for (const Tile& t : tiles(p)) { double high = 7e-8; double low = high/10; if (is_water(nth_tile(terrain(p), id(t)))) c.tiles[id(t)] = water; else { float prec = precipitation(nth_tile(s, id(t))); if (prec < low) { double d = prec / low; c.tiles[id(t)] = interpolate(dry, medium, d); } else { double d = std::min(1.0, (prec - low) / (high - low)); c.tiles[id(t)] = interpolate(medium, wet, d); } } } }
int main(int argc,char** args) { srand(time(NULL)); try { if (SDL_Init(SDL_INIT_VIDEO)) { fprintf(stderr,"Unable to initialize SDL: %s\n",SDL_GetError()); return EXIT_FAILURE; } atexit(SDL_Quit); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER,1); #if 0 screen = SDL_SetVideoMode(1440,900,32,SDL_OPENGL|SDL_FULLSCREEN); #else screen = SDL_SetVideoMode(1024,768,32,SDL_OPENGL/*|SDL_FULLSCREEN*/); #endif if(!screen) { fprintf(stderr,"Unable to create SDL screen: %s\n",SDL_GetError()); return EXIT_FAILURE; } SDL_WM_SetCaption("GlestNG","GlestNG"); GLenum err = glewInit(); if(GLEW_OK != err) { fprintf(stderr, "Error: %s\n", glewGetErrorString(err)); return EXIT_FAILURE; } fprintf(stdout, "Status: Using GLEW %s\n", glewGetString(GLEW_VERSION)); // we have a GL context so we can go ahead and init all the singletons std::auto_ptr<fs_t> fs_settings(fs_t::create("data/")); fs_t::settings = fs_settings.get(); // set it globally std::auto_ptr<xml_parser_t> xml_settings(new xml_parser_t("UI Settings",fs_settings->get_body("ui_settings.xml"))); xml_settings->set_as_settings(); std::auto_ptr<graphics_t::mgr_t> graphics_mgr(graphics_t::create()); std::auto_ptr<fonts_t> fonts(fonts_t::create()); std::auto_ptr<fs_t> fs; try { fs.reset(fs_t::create("data/Glest")); if(false) { fs_file_t::ptr_t logo_file(fs_settings->get("logo.g3d")); istream_t::ptr_t logostream(logo_file->reader()); logo = std::auto_ptr<model_g3d_t>(new model_g3d_t(*logostream)); } load(*fs); } catch(glest_exception_t* e) { std::cerr << "cannot load glest data: " << e << std::endl; delete e; } std::auto_ptr<ui_mgr_t> ui_(ui_mgr()); std::auto_ptr<mod_ui_t> mod_ui(mod_ui_t::create()); std::auto_ptr<terrain_t> terrain(terrain_t::gen_planet(5,500,3)); //world()->dump(std::cout); v4_t light_amb(0,0,0,1), light_dif(1.,1.,1.,1.), light_spec(1.,1.,1.,1.), light_pos(1.,1.,-1.,0.), mat_amb(.7,.7,.7,1.), mat_dif(.8,.8,.8,1.), mat_spec(1.,1.,1.,1.); glLightfv(GL_LIGHT0,GL_AMBIENT,light_amb.v); glLightfv(GL_LIGHT0,GL_DIFFUSE,light_dif.v); glLightfv(GL_LIGHT0,GL_SPECULAR,light_spec.v); glLightfv(GL_LIGHT0,GL_POSITION,light_pos.v); glLightfv(GL_LIGHT1,GL_AMBIENT,light_amb.v); glLightfv(GL_LIGHT1,GL_DIFFUSE,light_dif.v); glLightfv(GL_LIGHT1,GL_SPECULAR,light_spec.v); glMaterialfv(GL_FRONT,GL_AMBIENT,mat_amb.v); glMaterialfv(GL_FRONT,GL_DIFFUSE,mat_dif.v); glMaterialfv(GL_FRONT,GL_SPECULAR,mat_spec.v); glMaterialf(GL_FRONT,GL_SHININESS,100.0); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_LIGHT1); glDepthFunc(GL_LEQUAL); glEnable(GL_DEPTH_TEST); glAlphaFunc(GL_GREATER,0.4); glEnable(GL_COLOR_MATERIAL); glEnable(GL_RESCALE_NORMAL); glEnable(GL_BLEND); glEnable(GL_TEXTURE_2D); glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); glColorMaterial(GL_FRONT_AND_BACK,GL_AMBIENT_AND_DIFFUSE); glEnable(GL_COLOR_MATERIAL); glEnable(GL_NORMALIZE); glFrontFace(GL_CW); camera(); bool quit = false; SDL_Event event; SDL_EnableKeyRepeat(200,20); SDL_EnableUNICODE(true); const unsigned start = SDL_GetTicks(); framerate.reset(); while(!quit) { set_now(SDL_GetTicks()-start); while(!quit && SDL_PollEvent(&event)) { if(ui_mgr()->offer(event)) continue; switch (event.type) { case SDL_MOUSEMOTION: if(selection) std::cout << "drag" << std::endl; /*printf("Mouse moved by %d,%d to (%d,%d)\n", event.motion.xrel, event.motion.yrel, event.motion.x, event.motion.y);*/ break; case SDL_MOUSEBUTTONDOWN: click(event.button.x,event.button.y); if(selection) std::cout << "selection: "<<selected_point<<std::endl; break; case SDL_MOUSEBUTTONUP: if(selection) std::cout << "selection stopped" << std::endl; selection = false; break; case SDL_KEYDOWN: switch(event.key.keysym.sym) { case SDLK_PLUS: zoom += 1; camera(); break; case SDLK_MINUS: zoom -= 1; camera(); break; case SDLK_ESCAPE: quit = true; break; case SDLK_m: // MODDING MODE if(!fs.get()) { std::cerr << "(modding menu triggered but mod not loaded)" << std::endl; break; } if(mod_ui->is_shown()) mod_ui->hide(); else mod_ui->show(ref_t(*techtree,TECHTREE,techtree->name)); break; default: std::cout << "Ignoring key " << (int)event.key.keysym.scancode << "," << event.key.keysym.sym << "," << event.key.keysym.mod << "," << event.key.keysym.unicode << std::endl; } break; case SDL_QUIT: quit = true; break; } } framerate.tick(now()); tick(); } for(tests_t::iterator i=objs.begin(); i!=objs.end(); i++) delete *i; return EXIT_SUCCESS; } catch(data_error_t* de) { std::cerr << "Oh! " << de << std::endl; } catch(graphics_error_t* ge) { std::cerr << "Oh! " << ge << std::endl; } catch(panic_t* panic) { std::cerr << "Oh! " << panic << std::endl; } return EXIT_FAILURE; }
int main(int argc, char* argv[]) { LibVolume::Window::Window window; window.setTitle("Nilts"); LibVolume::Engine::Realm realm; realm.linkTo(window); realm.background_colour = glm::vec3(4.0, 3.0, 8.0) * 0.2f; //Move a kilometre out realm.camera.state.position = glm::vec3(1000.0, 1000.0, 64.0); LibVolume::Render::Structures::Light sun(LibVolume::Render::Structures::LightType::Directional, glm::vec3(0.8, 0.25, -1.0), glm::vec3(3.0, 3.0, 3.9) * 0.4f, 0.2); realm.addLight(sun); LibVolume::Engine::VoxelTerrain terrain(glm::ivec3(32, 32, 32), LibVolume::Engine::MeshingAlgorithm::MarchingCubes, false, true); realm.addObject(terrain); while (window.tick() == false) { glm::f64vec3 new_camera_position = realm.camera.state.position; if (window.event_manager.keyboard_state.key_down) new_camera_position += (glm::f64vec3(0.0, 0.0, 3.0) * 0.02) * realm.camera.state.orientation; if (window.event_manager.keyboard_state.key_right) new_camera_position += (glm::f64vec3(3.0, 0.0, 0.0) * 0.02) * realm.camera.state.orientation; if (window.event_manager.keyboard_state.key_left) new_camera_position += (glm::f64vec3(-3.0, 0.0, 0.0) * 0.02) * realm.camera.state.orientation; if (window.event_manager.keyboard_state.key_up) new_camera_position += (glm::f64vec3(0.0, 0.0, -3.0) * 0.02) * realm.camera.state.orientation; if (window.event_manager.keyboard_state.key_space) new_camera_position += (glm::f64vec3(0.0, 3.0, 0.0) * 0.02) * realm.camera.state.orientation; if (window.event_manager.keyboard_state.key_shift) new_camera_position += (glm::f64vec3(0.0, -3.0, 0.0) * 0.02) * realm.camera.state.orientation; //Stop the camera moving if it's going to go inside the terrain /*if (terrain.existsAt((glm::vec3)(new_camera_position / 32.0))) { if (terrain.getAt((glm::vec3)new_camera_position / 32.0f)->getDensityAt(glm::mod((glm::vec3)new_camera_position, 32.0f)) < 0.5) realm.camera.state.position = new_camera_position; } else*/ realm.camera.state.position = new_camera_position; if (terrain.existsAt((glm::vec3)(realm.camera.state.position / 32.0))) { while (terrain.getAt((glm::vec3)realm.camera.state.position / 32.0f)->getDensityAt(glm::mod((glm::vec3)realm.camera.state.position, 32.0f)) > 0.5) { realm.camera.state.position += terrain.getAt((glm::vec3)new_camera_position / 32.0f)->getNormalAt(glm::mod((glm::vec3)new_camera_position, 32.0f)) * 0.01f; } } if (window.event_manager.keyboard_state.key_a) realm.camera.state.orientation = glm::f64quat(glm::vec3(0.0, -0.03, 0.0)) * realm.camera.state.orientation; if (window.event_manager.keyboard_state.key_d) realm.camera.state.orientation = glm::f64quat(glm::vec3(0.0, 0.03, 0.0)) * realm.camera.state.orientation; if (window.event_manager.keyboard_state.key_w) realm.camera.state.orientation = glm::f64quat(glm::vec3(0.03, 0.0, 0.0)) * realm.camera.state.orientation; if (window.event_manager.keyboard_state.key_s) realm.camera.state.orientation = glm::f64quat(glm::vec3(-0.03, 0.0, 0.0)) * realm.camera.state.orientation; if (window.event_manager.keyboard_state.key_q) realm.camera.state.orientation = glm::f64quat(glm::vec3(0.0, 0.0, -0.03)) * realm.camera.state.orientation; if (window.event_manager.keyboard_state.key_e) realm.camera.state.orientation = glm::f64quat(glm::vec3(0.0, 0.0, 0.03)) * realm.camera.state.orientation; for (int x = -2; x < 3; x ++) { for (int y = -2; y < 3; y ++) { for (int z = 0; z < 2; z ++) { loadAt(glm::ivec3(x, y, z) + glm::ivec3(realm.camera.state.position.x, realm.camera.state.position.y, 0) / 32, terrain); //terrain.getAt(glm::ivec3(x, y, z))->extract(LibVolume::Engine::MeshingAlgorithm::MarchingCubes); } } } realm.tick(); realm.render(); } return 0; }
void ScenarioMapLoader::Impl::loadMap(std::fstream& f, Scenario& oScenario) { CityPtr oCity = oScenario.getCity(); Tilemap& oTilemap = oCity->getTilemap(); /* get number of city */ f.seekg(kLocation, std::ios::beg); unsigned int location=0; f.read((char*)&location, 1); StringHelper::debug( 0xff, "Location of city is %d", (int)(location+1) ); std::string cityName = ""; switch( location+1 ) { case 1: case 29: cityName = "Lugdunum"; break; case 2: cityName = "Corinthus"; break; case 3: case 37: cityName = "Londinium"; break; case 4: case 13: case 28: cityName = "Mediolanum"; break; case 5: case 40: cityName = "Lindum"; break; case 6: cityName = "Toletum"; break; case 7: case 33: cityName = "Valentia"; break; case 8: case 35: cityName = "Caesarea"; break; case 9: case 30: cityName = "Carthago"; break; case 10: cityName = "Cyrene"; break; case 11: case 15: case 25: cityName = "Tarraco"; break; case 12: cityName = "Hierosolyma"; break; case 14: case 26: cityName = "Syracusae"; break; case 16: case 31: cityName = "Tarsus"; break; case 17: case 32: cityName = "Tingis"; break; case 18: cityName = "Augusta Trevorum"; break; case 19: cityName = "Carthago Nova"; break; case 20: cityName = "Leptis Magna"; break; case 21: cityName = "Athenae"; break; case 22: cityName = "Brundisium"; break; case 23: cityName = "Capua"; break; case 24: cityName = "Tarentum"; break; case 27: cityName = "Miletus"; break; case 34: cityName = "Lutetia"; break; case 36: cityName = "Sarmizegetusa"; break; case 38: cityName = "Damascus"; break; case 39: cityName = "Massilia"; break; } oCity->setName( cityName ); f.seekg(kSize, std::ios::beg); int size; // 32bits int size_2; f.read((char*)&size, 4); f.read((char*)&size_2, 4); StringHelper::debug( 0xff, "Map size is %d", size ); if (size != size_2) { THROW("Horisontal and vertical map sizes are different!"); } oTilemap.init(size); // need to rewrite better short int *pGraphicGrid = (short int *)malloc(52488); unsigned char *pEdgeGrid = (unsigned char *)malloc(26244); short int *pTerrainGrid = (short int *)malloc(52488); unsigned char *pRndmTerGrid = (unsigned char *)malloc(26244); unsigned char *pRandomGrid = (unsigned char *)malloc(26244); unsigned char *pZeroGrid = (unsigned char *)malloc(26244); if( pGraphicGrid == NULL || pEdgeGrid == NULL || pTerrainGrid == NULL || pRndmTerGrid == NULL || pRandomGrid == NULL || pZeroGrid == NULL ) { THROW("NOT ENOUGH MEMORY!!!! FATAL"); } // here also make copy of original arrays in memory f.seekg(kGraphicGrid, std::ios::beg); f.read((char*)pGraphicGrid, 52488); f.seekg(kEdgeGrid, std::ios::beg); f.read((char*)pEdgeGrid, 26244); f.seekg(kTerrainGrid, std::ios::beg); f.read((char*)pTerrainGrid, 52488); f.seekg(kRndmTerGrid, std::ios::beg); f.read((char*)pRndmTerGrid, 26244); f.seekg(kRandomGrid, std::ios::beg); f.read((char*)pRandomGrid, 26244); f.seekg(kZeroGrid, std::ios::beg); f.read((char*)pZeroGrid, 26244); // loads the graphics map int border_size = (162 - size) / 2; for (int itA = 0; itA < size; ++itA) { for (int itB = 0; itB < size; ++itB) { int i = itB; int j = size - itA - 1; int index = 162 * (border_size + itA) + border_size + itB; TerrainTile terrain(pGraphicGrid[index], pEdgeGrid[index], pTerrainGrid[index], pRndmTerGrid[index], pRandomGrid[index], pZeroGrid[index] ); Tile& tile = oTilemap.at(i, j); Picture& pic = Picture::load( TerrainTileHelper::convId2PicName( pGraphicGrid[index] ) ); tile.setPicture( &pic ); tile.getTerrain() = terrain; // what happens here? } } for (int i = 0; i < size; ++i) { for (int j = 0; j < size; ++j) { Tile& tile = oTilemap.at(i, j); TerrainTile& terrain = tile.getTerrain(); if (terrain.getEdgeData()==0x00) { int size = 1; { int dj; try { // find size, 5 is maximal size for building for (dj = 0; dj < 5; ++dj) { int edge = oTilemap.at(i, j - dj).getTerrain().getEdgeData(); // find bottom left corner if (edge == 8 * dj + 0x40) { size = dj + 1; break; } } } catch(...) { size = dj + 1; } } StringHelper::debug( 0xff, "Multi-tile x %d at (%d,%d)", size, i, j ); bool bBad = false; //Str << "probing "; /* for (int di = 0; di < size && !bBad; ++di) { for (int dj = 0; dj < size && !bBad; ++dj) { //std::cout << i - di << "," << j - dj << " "; try { int edge = oTilemap.at(i - di, j - dj).getTerrain().getEdgeData(); } catch(...) { } // if (edge != 8 * dj + di && edge != 8 * dj + 0x40) // bBad = true; } }*/ //std::cout << std::endl; if (bBad) THROW ("ERROR in multi-tiles!!!"); Tile& master = oTilemap.at(i, j - size + 1); StringHelper::debug( 0xff, "Master will be at (%d,%d)", master.getI(), master.getJ() ); for (int di = 0; di < size; ++di) { for (int dj = 0; dj < size; ++dj) { oTilemap.at(master.getI() + di, master.getJ() + dj).setMasterTile(&master); } } StringHelper::debug( 0xff, " decoding " ); } TilePos pos( i, j ); Tile &ttile = oTilemap.at( pos ); LandOverlayPtr overlay = ttile.getTerrain().getOverlay(); // Check if it is building and type of building //if (ttile.getMasterTile() == NULL) decodeTerrain(ttile, oCity ); } } }
DWORD LandScape::execV( LS_OPCODE _opcode, va_list _va ) { // reset the return status - individual functions will alter this if need be mExecStatus = EXEC_SUCCESS; mExecString[0] = '\0'; switch( _opcode ) { case LS_SEED: setSeed( va_arg(_va,DWORD) ); break; case LS_LOAD: return load( va_arg(_va,char*) ); case LS_LOADM: { char * tmpCh = va_arg(_va,char*); double tmpD = va_arg(_va,double); return load(tmpCh, float(tmpD)); } case LS_SAVE: return save( va_arg(_va,char*) ); case LS_CLEAR: clear(); break; case LS_PUSH: push( va_arg(_va,int)); break; case LS_POP: pop(); break; case LS_GET: return (DWORD)get( va_arg(_va,int) ); case LS_SWAP: swap(); break; case LS_DUP: dup(); break; case LS_ADD: add( float(va_arg(_va,double)) ); break; case LS_SUB: sub( float(va_arg(_va,double)) ); break; case LS_MUL: mul( float(va_arg(_va,double)) ); break; case LS_DIV: div( float(va_arg(_va,double)) ); break; case LS_EXP: exp( float(va_arg(_va,double)) ); break; case LS_NEG: neg(); break; case LS_CLR: clr( float(va_arg(_va,double)) ); break; case LS_DIFF: diff(); break; case LS_NORMALIZE: { double i = va_arg(_va,double); double j = va_arg(_va,double); normalize( float(i), float(j) ); } break; case LS_ADDS: addStack(); break; case LS_SUBS: subStack(); break; case LS_FLOOR: { double i = va_arg(_va,double); double j = va_arg(_va,double); double k = va_arg(_va,double); floor( float(i), float(j), float(k) ); } break; case LS_CEIL: { double i = va_arg(_va,double); double j = va_arg(_va,double); double k = va_arg(_va,double); ceil( i, j, k ); } break; case LS_CLIPMIN: clipMin( float(va_arg(_va,double)) ); break; case LS_CLIPMAX: clipMax( float(va_arg(_va,double)) ); break; case LS_ROT: rot(); break; case LS_FLIPX: flipX(); break; case LS_FLIPY: flipY(); break; case LS_TERRAIN: { int i = va_arg(_va,int); double j = va_arg(_va,double); if (i > 256) { terrain( 256, float(j) ); size(i); } else terrain( i, float(j) ); } break; case LS_PLASMA: { int i = va_arg(_va,int); double j = va_arg(_va,double); if (i > 256) { plasma( 256, float(j) ); size(i); } else plasma( i, float(j) ); } break; case LS_SIZE: size( va_arg(_va,int) ); break; case LS_SLOPE: { double i = va_arg(_va,double); int j = va_arg(_va,int); slope( i, float(j) ); } break; case LS_SHAVE: { double i = va_arg(_va,double); double j = va_arg(_va,double); double k = va_arg(_va,double); shaveArea( float(i), float(j), float(k) ); } break; case LS_CURVE: { double i = va_arg(_va,double); int j = va_arg(_va,int); curve( float(i), j ); } break; case LS_FFT: if (stack.size() > 1) fft( va_arg(_va,int) ); break; case LS_FILL_N: if (stack.size() > 1) fillNormal( float(va_arg(_va,double)) ); break; case LS_OVERLAY: { int i = va_arg(_va,int); double j = va_arg(_va,double); overlay( i, float(j) ); } break; case LS_ALPHABLEND: { int x = va_arg(_va, int); int y = va_arg(_va, int); alphablend(x, y); } break; case LS_BLEND: { int i = va_arg(_va,int); int j = va_arg(_va,int); blend( i, j ); } case LS_SMOOTH: { double i = va_arg(_va,double); double j = va_arg(_va,double); smooth( float(i), float(j) ); } break; case LS_TILE: tile(); break; case LS_WRAP: wrap(); break; case LS_CLAMP: { int i = va_arg(_va,int); double j = va_arg(_va,double); clamp(i, float(j)); } break; case LS_MASK: { int i = va_arg(_va,int); double j = va_arg(_va,double); mask(i, float(j)); } break; case LS_CRATER: case LS_PEAK: case LS_RING: case LS_FILLBASIN: case LS_LPFILTER: case LS_HPFILTER: case LS_BPFILTER: case LS_BRFILTER: case LS_FFLP: case LS_FFHP: case LS_FFBP: case LS_FFBR: default: break; } return NULL; }
std::string default_generate_map(size_t width, size_t height, size_t island_size, size_t island_off_center, size_t iterations, size_t hill_size, size_t max_lakes, size_t nvillages, size_t castle_size, size_t nplayers, bool roads_between_castles, std::map<map_location,std::string>* labels, const config& cfg) { log_scope("map generation"); // Odd widths are nasty VALIDATE(is_even(width), _("Random maps with an odd width aren't supported.")); int ticks = SDL_GetTicks(); // Find out what the 'flatland' on this map is, i.e. grassland. std::string flatland = cfg["default_flatland"]; if(flatland == "") { flatland = t_translation::write_terrain_code(t_translation::GRASS_LAND); } const t_translation::t_terrain grassland = t_translation::read_terrain_code(flatland); // We want to generate a map that is 9 times bigger // than the actual size desired. // Only the middle part of the map will be used, // but the rest is so that the map we end up using // can have a context (e.g. rivers flowing from // out of the map into the map, same for roads, etc.) width *= 3; height *= 3; LOG_NG << "generating height map...\n"; // Generate the height of everything. const height_map heights = generate_height_map(width,height,iterations,hill_size,island_size,island_off_center); LOG_NG << "done generating height map...\n"; LOG_NG << (SDL_GetTicks() - ticks) << "\n"; ticks = SDL_GetTicks(); config naming = cfg.child_or_empty("naming"); // HACK: dummy names to satisfy unit_race requirements naming["id"] = "village_naming"; naming["plural_name"] = "villages"; // Make a dummy race for generating names const unit_race name_generator(naming); std::vector<terrain_height_mapper> height_conversion; BOOST_FOREACH(const config &h, cfg.child_range("height")) { height_conversion.push_back(terrain_height_mapper(h)); } terrain_map terrain(width, t_translation::t_list(height, grassland)); size_t x, y; for(x = 0; x != heights.size(); ++x) { for(y = 0; y != heights[x].size(); ++y) { for(std::vector<terrain_height_mapper>::const_iterator i = height_conversion.begin(); i != height_conversion.end(); ++i) { if(i->convert_terrain(heights[x][y])) { terrain[x][y] = i->convert_to(); break; } } } } std::map<int, t_translation::coordinate> starting_positions; LOG_NG << output_map(terrain, starting_positions); LOG_NG << "placed land forms\n"; LOG_NG << (SDL_GetTicks() - ticks) << "\n"; ticks = SDL_GetTicks(); // Now that we have our basic set of flatland/hills/mountains/water, // we can place lakes and rivers on the map. // All rivers are sourced at a lake. // Lakes must be in high land - at least 'min_lake_height'. // (Note that terrain below a certain altitude may be made // into bodies of water in the code above - i.e. 'sea', // but these are not considered 'lakes', because // they are not sources of rivers). // // We attempt to place 'max_lakes' lakes. // Each lake will be placed at a random location, // if that random location meets the minimum terrain requirements for a lake. // We will also attempt to source a river from each lake. std::set<location> lake_locs; std::map<location, std::string> river_names, lake_names, road_names, bridge_names, mountain_names, forest_names, swamp_names; const size_t nlakes = max_lakes > 0 ? (rand()%max_lakes) : 0; for(size_t lake = 0; lake != nlakes; ++lake) { for(int tries = 0; tries != 100; ++tries) { const int x = rand()%width; const int y = rand()%height; if (heights[x][y] > cfg["min_lake_height"].to_int()) { std::vector<location> river = generate_river(heights, terrain, x, y, cfg["river_frequency"]); if(river.empty() == false && labels != NULL) { std::string base_name; LOG_NG << "generating name for river...\n"; const std::string& name = generate_name(name_generator,"river_name",&base_name); LOG_NG << "named river '" << name << "'\n"; size_t name_frequency = 20; for(std::vector<location>::const_iterator r = river.begin(); r != river.end(); ++r) { const map_location loc(r->x-width/3,r->y-height/3); if(((r - river.begin())%name_frequency) == name_frequency/2) { labels->insert(std::pair<map_location,std::string>(loc,name)); } river_names.insert(std::pair<location,std::string>(loc,base_name)); } LOG_NG << "put down river name...\n"; } LOG_NG << "generating lake...\n"; std::set<location> locs; bool res = generate_lake(terrain, x, y, cfg["lake_size"], locs); if(res && labels != NULL) { bool touches_other_lake = false; std::string base_name; const std::string& name = generate_name(name_generator,"lake_name",&base_name); std::set<location>::const_iterator i; // Only generate a name if the lake hasn't touched any other lakes, // so that we don't end up with one big lake with multiple names. for(i = locs.begin(); i != locs.end(); ++i) { if(lake_locs.count(*i) != 0) { touches_other_lake = true; // Reassign the name of this lake to be the same as the other lake const location loc(i->x-width/3,i->y-height/3); const std::map<location,std::string>::const_iterator other_name = lake_names.find(loc); if(other_name != lake_names.end()) { base_name = other_name->second; } } lake_locs.insert(*i); } if(!touches_other_lake) { const map_location loc(x-width/3,y-height/3); labels->erase(loc); labels->insert(std::pair<map_location,std::string>(loc,name)); } for(i = locs.begin(); i != locs.end(); ++i) { const location loc(i->x-width/3,i->y-height/3); lake_names.insert(std::pair<location, std::string>(loc, base_name)); } } break; } } } LOG_NG << "done generating rivers...\n"; LOG_NG << (SDL_GetTicks() - ticks) << "\n"; ticks = SDL_GetTicks(); const size_t default_dimensions = 40*40*9; /* * Convert grassland terrain to other types of flat terrain. * * We generate a 'temperature map' which uses the height generation * algorithm to generate the temperature levels all over the map. Then we * can use a combination of height and terrain to divide terrain up into * more interesting types than the default. */ const height_map temperature_map = generate_height_map(width,height, cfg["temperature_iterations"].to_int() * width * height / default_dimensions, cfg["temperature_size"], 0, 0); LOG_NG << "generated temperature map...\n"; LOG_NG << (SDL_GetTicks() - ticks) << "\n"; ticks = SDL_GetTicks(); std::vector<terrain_converter> converters; BOOST_FOREACH(const config &cv, cfg.child_range("convert")) { converters.push_back(terrain_converter(cv)); } LOG_NG << "created terrain converters\n"; LOG_NG << (SDL_GetTicks() - ticks) << "\n"; ticks = SDL_GetTicks(); // Iterate over every flatland tile, and determine // what type of flatland it is, based on our [convert] tags. for(x = 0; x != width; ++x) { for(y = 0; y != height; ++y) { for(std::vector<terrain_converter>::const_iterator i = converters.begin(); i != converters.end(); ++i) { if(i->convert_terrain(terrain[x][y],heights[x][y],temperature_map[x][y])) { terrain[x][y] = i->convert_to(); break; } } } } LOG_NG << "placing villages...\n"; LOG_NG << (SDL_GetTicks() - ticks) << "\n"; ticks = SDL_GetTicks(); /* * Place villages in a 'grid', to make placing fair, but with villages * displaced from their position according to terrain and randomness, to * add some variety. */ std::set<location> villages; LOG_NG << "placing castles...\n"; /** Try to find configuration for castles. */ const config &castle_config = cfg.child("castle"); if (!castle_config) { LOG_NG << "Could not find castle configuration\n"; return std::string(); } /* * Castle configuration tag contains a 'valid_terrain' attribute which is a * list of terrains that the castle may appear on. */ const t_translation::t_list list = t_translation::read_list(castle_config["valid_terrain"]); const is_valid_terrain terrain_tester(terrain, list); /* * Attempt to place castles at random. * * Once we have placed castles, we run a sanity check to make sure that the * castles are well-placed. If the castles are not well-placed, we try * again. Definition of 'well-placed' is if no two castles are closer than * 'min_distance' hexes from each other, and the castles appear on a * terrain listed in 'valid_terrain'. */ std::vector<location> castles; std::set<location> failed_locs; for(size_t player = 0; player != nplayers; ++player) { LOG_NG << "placing castle for " << player << "\n"; log_scope("placing castle"); const int min_x = width/3 + 3; const int min_y = height/3 + 3; const int max_x = (width/3)*2 - 4; const int max_y = (height/3)*2 - 4; int min_distance = castle_config["min_distance"]; location best_loc; int best_ranking = 0; for(int x = min_x; x != max_x; ++x) { for(int y = min_y; y != max_y; ++y) { const location loc(x,y); if(failed_locs.count(loc)) { continue; } const int ranking = rank_castle_location(x,y,terrain_tester,min_x,max_x,min_y,max_y,min_distance,castles,best_ranking); if(ranking <= 0) { failed_locs.insert(loc); } if(ranking > best_ranking) { best_ranking = ranking; best_loc = loc; } } } if(best_ranking == 0) { ERR_NG << "No castle location found, aborting.\n"; std::string error = _("No valid castle location found. Too many or too few mountain hexes? (please check the 'max hill size' parameter)"); throw mapgen_exception(error); } assert(std::find(castles.begin(), castles.end(), best_loc) == castles.end()); castles.push_back(best_loc); // Make sure the location can't get a second castle. failed_locs.insert(best_loc); } LOG_NG << "placing roads...\n"; LOG_NG << (SDL_GetTicks() - ticks) << "\n"; ticks = SDL_GetTicks(); // Place roads. // We select two tiles at random locations on the borders // of the map, and try to build roads between them. int nroads = cfg["roads"]; if(roads_between_castles) { nroads += castles.size()*castles.size(); } std::set<location> bridges; road_path_calculator calc(terrain,cfg); for (int road = 0; road != nroads; ++road) { log_scope("creating road"); /* * We want the locations to be on the portion of the map we're actually * going to use, since roads on other parts of the map won't have any * influence, and doing it like this will be quicker. */ location src = random_point_at_side(width/3 + 2,height/3 + 2); location dst = random_point_at_side(width/3 + 2,height/3 + 2); src.x += width/3 - 1; src.y += height/3 - 1; dst.x += width/3 - 1; dst.y += height/3 - 1; if (roads_between_castles && road < int(castles.size() * castles.size())) { const size_t src_castle = road/castles.size(); const size_t dst_castle = road%castles.size(); if(src_castle >= dst_castle) { continue; } src = castles[src_castle]; dst = castles[dst_castle]; } // If the road isn't very interesting (on the same border), don't draw it. else if(src.x == dst.x || src.y == dst.y) { continue; } if (calc.cost(src, 0.0) >= 1000.0 || calc.cost(dst, 0.0) >= 1000.0) { continue; } // Search a path out for the road pathfind::plain_route rt = pathfind::a_star_search(src, dst, 10000.0, &calc, width, height); std::string road_base_name; const std::string& name = generate_name(name_generator, "road_name", &road_base_name); const int name_frequency = 20; int name_count = 0; bool on_bridge = false; // Draw the road. // If the search failed, rt.steps will simply be empty. for(std::vector<location>::const_iterator step = rt.steps.begin(); step != rt.steps.end(); ++step) { const int x = step->x; const int y = step->y; if(x < 0 || y < 0 || x >= static_cast<long>(width) || y >= static_cast<long>(height)) { continue; } // Find the configuration which tells us // what to convert this tile to, to make it into a road. if (const config &child = cfg.find_child("road_cost", "terrain", t_translation::write_terrain_code(terrain[x][y]))) { // Convert to bridge means that we want to convert // depending upon the direction the road is going. // Typically it will be in a format like, // convert_to_bridge=\,|,/ // '|' will be used if the road is going north-south // '/' will be used if the road is going south west-north east // '\' will be used if the road is going south east-north west // The terrain will be left unchanged otherwise // (if there is no clear direction). const std::string &convert_to_bridge = child["convert_to_bridge"]; if(convert_to_bridge.empty() == false) { if(step == rt.steps.begin() || step+1 == rt.steps.end()) continue; const location& last = *(step-1); const location& next = *(step+1); location adj[6]; get_adjacent_tiles(*step,adj); int direction = -1; // If we are going north-south if((last == adj[0] && next == adj[3]) || (last == adj[3] && next == adj[0])) { direction = 0; } // If we are going south west-north east else if((last == adj[1] && next == adj[4]) || (last == adj[4] && next == adj[1])) { direction = 1; } // If we are going south east-north west else if((last == adj[2] && next == adj[5]) || (last == adj[5] && next == adj[2])) { direction = 2; } if(labels != NULL && on_bridge == false) { on_bridge = true; std::string bridge_base_name; const std::string& name = generate_name(name_generator, "bridge_name", &bridge_base_name); const location loc(x - width / 3, y-height/3); labels->insert(std::pair<map_location,std::string>(loc,name)); bridge_names.insert(std::pair<location,std::string>(loc, bridge_base_name)); //add to use for village naming bridges.insert(loc); } if(direction != -1) { const std::vector<std::string> items = utils::split(convert_to_bridge); if(size_t(direction) < items.size() && items[direction].empty() == false) { terrain[x][y] = t_translation::read_terrain_code(items[direction]); } continue; } } else { on_bridge = false; } // Just a plain terrain substitution for a road const std::string &convert_to = child["convert_to"]; if(convert_to.empty() == false) { const t_translation::t_terrain letter = t_translation::read_terrain_code(convert_to); if(labels != NULL && terrain[x][y] != letter && name_count++ == name_frequency && on_bridge == false) { labels->insert(std::pair<map_location,std::string>(map_location(x-width/3,y-height/3),name)); name_count = 0; } terrain[x][y] = letter; const location loc(x - width / 3, y - height / 3); //add to use for village naming road_names.insert(std::pair<location,std::string>(loc, road_base_name)); } } } LOG_NG << "looked at " << calc.calls << " locations\n"; } // Now that road drawing is done, we can plonk down the castles. for(std::vector<location>::const_iterator c = castles.begin(); c != castles.end(); ++c) { if(c->valid() == false) { continue; } const int x = c->x; const int y = c->y; const int player = c - castles.begin() + 1; const struct t_translation::coordinate coord(x, y); starting_positions.insert(std::pair<int, t_translation::coordinate>(player, coord)); terrain[x][y] = t_translation::HUMAN_KEEP; const int castles[13][2] = { {-1, 0}, {-1, -1}, {0, -1}, {1, -1}, {1, 0}, {0, 1}, {-1, 1}, {-2, 1}, {-2, 0}, {-2, -1}, {-1, -2}, {0, -2}, {1, -2} }; for (size_t i = 0; i < castle_size - 1; i++) { terrain[x+castles[i][0]][y+castles[i][1]] = t_translation::HUMAN_CASTLE; } // Remove all labels under the castle tiles if(labels != NULL) { labels->erase(location(x-width/3,y-height/3)); for (size_t i = 0; i < castle_size - 1; i++) { labels->erase(location(x+castles[i][0]-width/3, y+castles[i][1]-height/3)); } } } LOG_NG << "placed castles\n"; LOG_NG << (SDL_GetTicks() - ticks) << "\n"; ticks = SDL_GetTicks(); /*Random naming for landforms: mountains, forests, swamps, hills *we name these now that everything else is placed (as e.g., placing * roads could split a forest) */ for (x = width / 3; x < (width / 3)*2; x++) { for (y = height / 3; y < (height / 3) * 2;y++) { //check the terrain of the tile const location loc(x - width / 3, y - height / 3); const t_translation::t_terrain terr = terrain[x][y]; std::string name, base_name; std::set<std::string> used_names; if (t_translation::terrain_matches(terr, t_translation::ALL_MOUNTAINS)) { //name every 15th mountain if ((rand()%15) == 0) { for(size_t ntry = 0; ntry != 30 && (ntry == 0 || used_names.count(name) > 0); ++ntry) { name = generate_name(name_generator, "mountain_name", &base_name); } labels->insert(std::pair<map_location, std::string>(loc, name)); mountain_names.insert(std::pair<location, std::string>(loc, base_name)); } } else if (t_translation::terrain_matches(terr, t_translation::ALL_FORESTS)) { //if the forest tile is not named yet, name it const std::map<location, std::string>::const_iterator forest_name = forest_names.find(loc); if(forest_name == forest_names.end()) { for(size_t ntry = 0; ntry != 30 && (ntry == 0 || used_names.count(name) > 0); ++ntry) { name = generate_name(name_generator, "forest_name", &base_name); } forest_names.insert(std::pair<location, std::string>(loc, base_name)); // name all connected forest tiles accordingly flood_name(loc, base_name, forest_names, t_translation::ALL_FORESTS, terrain, width, height, 0, labels, name); } } else if (t_translation::terrain_matches(terr, t_translation::ALL_SWAMPS)) { //if the swamp tile is not named yet, name it const std::map<location, std::string>::const_iterator swamp_name = swamp_names.find(loc); if(swamp_name == swamp_names.end()) { for(size_t ntry = 0; ntry != 30 && (ntry == 0 || used_names.count(name) > 0); ++ntry) { name = generate_name(name_generator, "swamp_name", &base_name); } swamp_names.insert(std::pair<location, std::string>(loc, base_name)); // name all connected swamp tiles accordingly flood_name(loc, base_name, swamp_names, t_translation::ALL_SWAMPS, terrain, width, height, 0, labels, name); } } } } if (nvillages > 0) { config naming_cfg = cfg.child_or_empty("village_naming"); // HACK: dummy names to satisfy unit_race requirements naming_cfg["id"] = "village_naming"; naming_cfg["plural_name"] = "villages"; const unit_race village_names_generator(naming_cfg); // First we work out the size of the x and y distance between villages const size_t tiles_per_village = ((width*height)/9)/nvillages; size_t village_x = 1, village_y = 1; // Alternate between incrementing the x and y value. // When they are high enough to equal or exceed the tiles_per_village, // then we have them to the value we want them at. while(village_x*village_y < tiles_per_village) { if(village_x < village_y) { ++village_x; } else { ++village_y; } } std::set<std::string> used_names; tcode_list_cache adj_liked_cache; for(size_t vx = 0; vx < width; vx += village_x) { LOG_NG << "village at " << vx << "\n"; for(size_t vy = rand()%village_y; vy < height; vy += village_y) { const size_t add_x = rand()%3; const size_t add_y = rand()%3; const size_t x = (vx + add_x) - 1; const size_t y = (vy + add_y) - 1; const map_location res = place_village(terrain,x,y,2,cfg,adj_liked_cache); if(res.x >= static_cast<long>(width) / 3 && res.x < static_cast<long>(width * 2) / 3 && res.y >= static_cast<long>(height) / 3 && res.y < static_cast<long>(height * 2) / 3) { const std::string str = t_translation::write_terrain_code(terrain[res.x][res.y]); if (const config &child = cfg.find_child("village", "terrain", str)) { const std::string &convert_to = child["convert_to"]; if(convert_to != "") { terrain[res.x][res.y] = t_translation::read_terrain_code(convert_to); villages.insert(res); if(labels != NULL && naming_cfg.empty() == false) { const map_location loc(res.x-width/3,res.y-height/3); map_location adj[6]; get_adjacent_tiles(loc,adj); std::string name_type = "village_name"; const t_translation::t_list field = t_translation::t_list(1, t_translation::GRASS_LAND), forest = t_translation::t_list(1, t_translation::FOREST), mountain = t_translation::t_list(1, t_translation::MOUNTAIN), hill = t_translation::t_list(1, t_translation::HILL); size_t field_count = 0, forest_count = 0, mountain_count = 0, hill_count = 0; utils::string_map symbols; size_t n; for(n = 0; n != 6; ++n) { const std::map<location,std::string>::const_iterator road_name = road_names.find(adj[n]); if(road_name != road_names.end()) { symbols["road"] = road_name->second; name_type = "village_name_road"; break; } const std::map<location,std::string>::const_iterator river_name = river_names.find(adj[n]); if(river_name != river_names.end()) { symbols["river"] = river_name->second; name_type = "village_name_river"; const std::map<location,std::string>::const_iterator bridge_name = bridge_names.find(adj[n]); if(bridge_name != bridge_names.end()) { //we should always end up here, since if there is an adjacent bridge, there has to be an adjacent river too symbols["bridge"] = bridge_name->second; name_type = "village_name_river_bridge"; } break; } const std::map<location,std::string>::const_iterator forest_name = forest_names.find(adj[n]); if(forest_name != forest_names.end()) { symbols["forest"] = forest_name->second; name_type = "village_name_forest"; break; } const std::map<location,std::string>::const_iterator lake_name = lake_names.find(adj[n]); if(lake_name != lake_names.end()) { symbols["lake"] = lake_name->second; name_type = "village_name_lake"; break; } const std::map<location,std::string>::const_iterator mountain_name = mountain_names.find(adj[n]); if(mountain_name != mountain_names.end()) { symbols["mountain"] = mountain_name->second; name_type = "village_name_mountain"; break; } const std::map<location,std::string>::const_iterator swamp_name = swamp_names.find(adj[n]); if(swamp_name != swamp_names.end()) { symbols["swamp"] = swamp_name->second; name_type = "village_name_swamp"; break; } const t_translation::t_terrain terr = terrain[adj[n].x+width/3][adj[n].y+height/3]; if(std::count(field.begin(),field.end(),terr) > 0) { ++field_count; } else if(std::count(forest.begin(),forest.end(),terr) > 0) { ++forest_count; } else if(std::count(hill.begin(),hill.end(),terr) > 0) { ++hill_count; } else if(std::count(mountain.begin(),mountain.end(),terr) > 0) { ++mountain_count; } } if(n == 6) { if(field_count == 6) { name_type = "village_name_grassland"; } else if(forest_count >= 2) { name_type = "village_name_forest"; } else if(mountain_count >= 1) { name_type = "village_name_mountain_anonymous"; } else if(hill_count >= 2) { name_type = "village_name_hill"; } } std::string name; for(size_t ntry = 0; ntry != 30 && (ntry == 0 || used_names.count(name) > 0); ++ntry) { name = generate_name(village_names_generator,name_type,NULL,&symbols); } used_names.insert(name); labels->insert(std::pair<map_location,std::string>(loc,name)); } } } } } } } LOG_NG << "placed villages\n"; LOG_NG << (SDL_GetTicks() - ticks) << "\n"; ticks = SDL_GetTicks(); return output_map(terrain, starting_positions); }
int delegate_server( void *query, size_t query_length, void **response, size_t *response_length, int source, void *arg) { if(query_length <= 0) { error("Empty message - something went wrong."); return -1; } delegate_t *data = (delegate_t*)arg; char cmd = ((char*)query)[0]; if(cmd == ACT_DELEGATE_GIVE_WORK) { int wrkno; if(match(query, query_length, "@c %i", ACT_DELEGATE_GIVE_WORK, &wrkno) == 0) { if(Wydobyte[wrkno + data->l] == Rezerwacje[wrkno + data->l]) { combine(response, response_length, "%c", ACT_REJECT); Uswiadomione[wrkno+data->l] = 1; return 0; } else { combine(response, response_length, "%c %i", ACT_OK, terrain(wrkno+data->l, Wydobyte[wrkno+data->l])); return 0; } } else { combine(response, response_length, "%c", ACT_ERROR); return 0; } } else if(cmd == ACT_DELEGATE_CHECK_WORK) { int wrkno; int sym; int results[32]; if(match(query, query_length, "@c %i %i %b", ACT_DELEGATE_CHECK_WORK, &wrkno, &sym, results, 32 * sizeof(int)) == 0) { long long int mul = results[0], ter = terrain(wrkno+data->l, Wydobyte[wrkno+data->l]); for(int i = 1; i < 32; i++) mul *= results[i]; if(mul > ter || sym != ter || ter % mul != 0) { combine(response, response_length, "%c", ACT_ERROR); return 0; } else { pthread_mutex_lock(&ochrona); Wydobyte[wrkno+data->l]++; if(Wydobyte[wrkno+data->l] == data->g) { int flag = 1; for(int i = 0; i < data->k; i++) { if(Wydobyte[data->l + i] < data->g || Uswiadomione[data->l + i] == 0) { flag = 0; break; } } if(flag) { data->do_exit = 1; for(int i = 0; i < data->k; i++) { Rezerwacje[data->l + i] = 0; } } } pthread_mutex_unlock(&ochrona); combine(response, response_length, "%c", ACT_OK); return 0; } } else { combine(response, response_length, "%c", ACT_ERROR); return 0; } } else if(cmd == ACT_DELEGATE_FIRE) { pthread_mutex_lock(&ochrona); data->do_exit = 1; for(int i = 0; i < data->k; i++) { Rezerwacje[data->l + i] = 0; } pthread_mutex_unlock(&ochrona); } else { warning("Unsupported command 0x%x.", cmd); combine(response, response_length, "%c", ACT_ERROR); return 0; } return -1; }
Wind _default_wind (const Planet& p, int i, double tropical_equator) { Vector2 pressure_force = _default_pressure_gradient_force(tropical_equator, latitude(p, vector(nth_tile(p,i)))); double coriolis_coeff = coriolis_coefficient(p, latitude(p, vector(nth_tile(p,i)))); double friction = is_land(nth_tile(terrain(p), i)) ? 0.000045 : 0.000045; return _prevailing_wind(pressure_force, coriolis_coeff, friction); }
int main(int argc, char* argv[]) { Mercator::Area* a1 = new Mercator::Area(1, false); WFMath::Polygon<2> p; p.addCorner(p.numCorners(), Point2(3, 4)); p.addCorner(p.numCorners(), Point2(10, 10)); p.addCorner(p.numCorners(), Point2(-1, 18)); p.addCorner(p.numCorners(), Point2(-8, 11)); a1->setShape(p); Mercator::Terrain terrain(Mercator::Terrain::SHADED, seg_size); Mercator::AreaShader* ashade = new Mercator::AreaShader(1); terrain.addShader(ashade, 0); terrain.setBasePoint(-2, -1, 5); terrain.setBasePoint(-2, 0, 2); terrain.setBasePoint(-2, 1, 19); terrain.setBasePoint(-1, -1, 4); terrain.setBasePoint(-1, 0, 6); terrain.setBasePoint(-1, 1, 10); terrain.setBasePoint(0, -1, 2); terrain.setBasePoint(0, 0, -1); terrain.setBasePoint(0, 1, 8); terrain.setBasePoint(0, 2, 11); terrain.setBasePoint(1, -1, 7); terrain.setBasePoint(1, 0, 2); terrain.setBasePoint(1, 1, 11); terrain.setBasePoint(1, 2, 9); terrain.setBasePoint(2, -1, 3); terrain.setBasePoint(2, 0, 8); terrain.setBasePoint(2, 1, 2); terrain.setBasePoint(3, -1, 6); terrain.setBasePoint(3, 0, 7); terrain.setBasePoint(3, 1, 9); terrain.addArea(a1); Mercator::Segment* seg = terrain.getSegment(0,0); assert(seg->getAreas().size() == 1); assert(seg->getAreas().count(1) == 1); assert(a1->checkIntersects(*seg)); seg = terrain.getSegment(1,0); assert(seg->getAreas().size() == 0); assert(seg->getAreas().count(1) == 0); assert(a1->checkIntersects(*seg) == false); WFMath::Polygon<2> clipped = a1->clipToSegment(*seg); assert(clipped.isValid()); seg = terrain.getSegment(-1,0); assert(seg->getAreas().size() == 1); assert(seg->getAreas().count(1) == 1); assert(a1->checkIntersects(*seg)); clipped = a1->clipToSegment(*seg); assert(clipped.isValid()); seg = terrain.getSegment(0,1); assert(seg->getAreas().size() == 1); assert(seg->getAreas().count(1) == 1); assert(a1->checkIntersects(*seg)); clipped = a1->clipToSegment(*seg); assert(clipped.isValid()); seg = terrain.getSegment(2,0); assert(seg->getAreas().size() == 0); assert(seg->getAreas().count(1) == 0); assert(a1->checkIntersects(*seg) == false); p.clear(); p.addCorner(p.numCorners(), Point2(3 + seg_size, 4)); p.addCorner(p.numCorners(), Point2(10 + seg_size, 10)); p.addCorner(p.numCorners(), Point2(-1 + seg_size, 18)); p.addCorner(p.numCorners(), Point2(-8 + seg_size, 11)); a1->setShape(p); terrain.updateArea(a1); seg = terrain.getSegment(0,0); assert(seg->getAreas().size() == 1); assert(seg->getAreas().count(1) == 1); assert(a1->checkIntersects(*seg)); seg = terrain.getSegment(1,0); assert(seg->getAreas().size() == 1); assert(seg->getAreas().count(1) == 1); assert(a1->checkIntersects(*seg)); clipped = a1->clipToSegment(*seg); assert(clipped.isValid()); seg = terrain.getSegment(-1,0); assert(seg->getAreas().size() == 0); assert(seg->getAreas().count(1) == 0); assert(a1->checkIntersects(*seg) == false); seg = terrain.getSegment(0,1); assert(seg->getAreas().size() == 1); assert(seg->getAreas().count(1) == 1); assert(a1->checkIntersects(*seg)); clipped = a1->clipToSegment(*seg); assert(clipped.isValid()); seg = terrain.getSegment(2,0); assert(seg->getAreas().size() == 0); assert(seg->getAreas().count(1) == 0); assert(a1->checkIntersects(*seg) == false); clipped = a1->clipToSegment(*seg); assert(clipped.isValid()); terrain.removeArea(a1); seg = terrain.getSegment(0,0); assert(seg->getAreas().size() == 0); assert(seg->getAreas().count(1) == 0); seg = terrain.getSegment(1,0); assert(seg->getAreas().size() == 0); assert(seg->getAreas().count(1) == 0); seg = terrain.getSegment(-1,0); assert(seg->getAreas().size() == 0); assert(seg->getAreas().count(1) == 0); seg = terrain.getSegment(0,1); assert(seg->getAreas().size() == 0); assert(seg->getAreas().count(1) == 0); testAreaShader(); testAddToSegment(); return EXIT_SUCCESS; }
void DownGroup::updateVisuals() { ParticleGroup::updateVisuals(); PxParticleReadData * readData = m_particleSystem->lockParticleReadData(); assert(readData); m_particleDrawable->updateParticles(readData); // Get drained Particles std::vector<uint32_t> particlesToDelete; PxStrideIterator<const PxParticleFlags> flagsIt(readData->flagsBuffer); PxStrideIterator<const PxVec3> positionIt = readData->positionBuffer; TerrainInteraction terrain("water"); std::vector<unsigned int> lavaToSteam; glowutils::AxisAlignedBoundingBox steamBbox; std::vector<glm::vec3> steamPositions; const TerrainSettings & terrainSettings = terrain.terrain().settings; for (unsigned i = 0; i < readData->validParticleRange; ++i, ++flagsIt, ++positionIt) { // check range if (!(*flagsIt & PxParticleFlag::eVALID)) { continue; } if (positionIt->y > terrainSettings.maxHeight * 0.75f) { particlesToDelete.push_back(i); continue; } if (*flagsIt & PxParticleFlag::eCOLLISION_WITH_STATIC) { if (positionIt->y < m_particleSize + 0.1) // collision with water plane { if (m_elementName == "lava") { lavaToSteam.push_back(i); steamBbox.extend(reinterpret_cast<const glm::vec3&>(*positionIt)); steamPositions.push_back(reinterpret_cast<const glm::vec3&>(*positionIt)); continue; } else { particlesToDelete.push_back(i); continue; } } if (terrain.topmostElementAt(positionIt->x, positionIt->z) == m_elementName) { particlesToDelete.push_back(i); } } } assert(m_numParticles == readData->nbValidParticles); readData->unlock(); if (!particlesToDelete.empty()) releaseParticles(particlesToDelete); if (!lavaToSteam.empty()) { DownGroup * steamGroup = ParticleGroupTycoon::instance().getNearestGroup("steam", steamBbox.center()); steamGroup->createParticles(steamPositions); releaseParticles(lavaToSteam); } }
Terrain *TerrainGenerator::generateRandomLandform() { std::unique_ptr<Terrain> terrain(new Terrain(size_)); // Make sure size is power of two Q_ASSERT((size_.width() & (size_.width() - 1)) == 0); Q_ASSERT((size_.height() & (size_.height() - 1)) == 0); // Make sure size is square Q_ASSERT(size_.width() == size_.height()); const int sz = size_.width(); std::mt19937 rnd(static_cast<std::uint_fast32_t>(std::random_device()())); std::normal_distribution<float> dist; auto landform = [&](int x, int y) -> float& { return terrain->landform(x & sz - 1, y & sz - 1); }; landform(0, 0) = 50.f; float noiseScale = 30.f; for(int detail = sz >> 1; detail >= 1; detail >>= 1) { int step = detail << 1; for (int y = 0; y < sz; y += step) { for (int x = 0; x < sz; x += step) { auto p1 = landform(x, y); auto p2 = landform(x + step, y); auto p3 = landform(x, y + step); auto p4 = landform(x + step, y + step); landform(x + detail, y) = (p1 + p2) * 0.5f + dist(rnd) * noiseScale; landform(x, y + detail) = (p1 + p3) * 0.5f + dist(rnd) * noiseScale; landform(x + detail, y + detail) = (p1 + p4 + p2 + p3) * 0.25f + dist(rnd) * noiseScale; } } noiseScale *= 0.5f; } for (int y = 0; y < sz; ++y) { for (int x = 0; x < sz; ++x) { float altitude = 62.5f - terrain->landform(x, y); float red, green, blue; float landAltitude = std::max(altitude, 0.f); red = landAltitude * 1.5f + 140.f; green = 160.f + std::max(landAltitude - 40.f, 0.f); blue = 80.f + std::max(landAltitude - 40.f, 0.f) * 2.f; if (altitude < 0.f) { float mix = 1.f - std::exp2(altitude * .3f); mix = .2f + mix * 0.8f; red += (10.f - red) * mix; green += (100.f - green) * mix; blue += (160.f - blue) * mix; } red = std::min(red, 255.f); green = std::min(green, 255.f); blue = std::min(blue, 255.f); red = std::max(red, 0.f); green = std::max(green, 0.f); blue = std::max(blue, 0.f); //red = green = blue = latitude * 4.f + 128.f; terrain->color(x, y) = static_cast<int>(blue) | (static_cast<int>(green) << 8) | (static_cast<int>(red) << 16); } } return terrain.release(); }
void display(void) { #if 1 glViewport(0, 0, gw, gh / 5 * 4); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(80, 1, 1, 400); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); x = current_origin_x + _distance * cos(angle * vl_pi / 180); z = current_origin_z + _distance * sin(angle * vl_pi / 180); float y = bilinear(x, z); Vec3 tmove, ttri[3]; tmove = proj(HTrans4(Vec3(x, y, z)) * HRot4(Vec3(0, -1, 0), angle / 180 * vl_pi) * Vec4(move, 1)); for(int i = 0; i < 3; i++){ ttri[i] = proj(HTrans4(Vec3(x, 0, z)) * HRot4(Vec3(0, -1, 0), angle / 180 * vl_pi) * Vec4(tri[i], 1)); ttri[i][1] = bilinear(ttri[i][0], ttri[i][2]); } // car configuration Vec3 xx, yy, zz, tmp; tmp = ttri[1] - (ttri[0] + ttri[2]) / 2; tmp[1] = 0; yy = norm(cross((ttri[0] - ttri[2]), (ttri[1] - ttri[2]))); xx = norm(tmp - dot(yy, tmp) * yy); zz = cross(xx, yy); float mat[16] = {xx[0], xx[1], xx[2], 0.0, yy[0], yy[1], yy[2], 0.0, zz[0], zz[1], zz[2], 0.0, x, y + 4.5, z, 1.0}; // testing /* cout << "ttri[0] = " << ttri[0] << endl << "ttri[1] = " << ttri[1] << endl << "ttri[2] = " << ttri[2] << endl; cout << "ttri[0] - ttri[2] = " << ttri[0] - ttri[2] << endl << "ttri[1] - ttri[2] = " << ttri[1] - ttri[2] << endl; cout << "cross((ttri[0] - ttri[2]), (ttri[1] - ttri[2])) = " << cross((ttri[0] - ttri[2]), (ttri[1] - ttri[2])) << endl; cout << "yy = norm(cross((ttri[0] - ttri[2]), (ttri[1] - ttri[2])))\n = " << norm(cross((ttri[0] - ttri[2]), (ttri[1] - ttri[2]))) << endl << endl; printf("(%f, %f, %f)\nxx = (%f, %f, %f)\nyy = (%f, %f, %f)\nzz = (%f, %f, %f)\n", x, y, z, xx[0], xx[1], xx[2], yy[0], yy[1], yy[2], zz[0], zz[1], zz[2]); printf("ttri = (%f, %f, %f)\n", ttri[0][0], ttri[0][1], ttri[0][2]); printf("tmp = (%f, %f, %f)\n", tmp[0], tmp[1], tmp[2]); system("CLS"); */ gluLookAt(0, 100, 150, 0, 0, 0, 0, 1, 0); glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glDisable(GL_LIGHTING); glColor3f (1,1,1); terrain(); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glPushMatrix(); glMultMatrixf(mat); glRotatef(-90, 0, -1, 0); glmDraw(car, GLM_MATERIAL | GLM_SMOOTH); glPopMatrix(); glDisable(GL_LIGHTING); #endif #if 1 // map glViewport(gw / 5 * 4 + 1, gh / 5 * 4 + 1, gw / 5, gh / 5); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(80, 1, 1, 400); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(0, 150, 1, 0, 0, 0, 0, 1, 0); glColor3f (1,1,1); terrain(); glPushAttrib(GL_ENABLE_BIT); glColor3f(1, 0, 0); glPointSize(7); glDisable(GL_TEXTURE_2D); glEnable(GL_POINT_SMOOTH); glBegin(GL_POINTS); glVertex3dv(tmove.Ref()); glEnd(); glPopAttrib(); #endif glutSwapBuffers(); }
int main() { GameManager newManager; newManager.Initialize(); //Load and create objects ResourceManager* resourceManager = newManager.GetResourceManager(); //Loads the meshes from the model file into a //simple gameobject hierarchy and returns the root game object //Returns null if the model wasn't found /* GameObject* dwarfObject = newManager.CreateGameObjectsFromModel("data/dwarf2.b3d"); if(dwarfObject != NULL) { dwarfObject->GetTransform().SetScale(0.05f,0.05f,0.05f); dwarfObject->GetTransform().SetPosition(-3.0f,0.0f,0.0f); newManager.AddComponentToGameObject(dwarfObject, new RotateObject(dwarfObject)); } */ /* resourceManager->StoreAndInitMaterial("terrainMaterial", new Diffuse(resourceManager->GetShaderProgram("Diffuse", "../data/Diffuse.vert", "../data/Diffuse.frag"), resourceManager->GetTexture2D("data/heightmap4.bmp"))); TerrainHeightMap newTerrain; newTerrain.CreateHeightMap(resourceManager->GetTexture2D("data/heightmap4.bmp"), 128); //Test int numberOfTerrainPatches = newTerrain.GetNumberOfPatches(); for(int i = 0; i < numberOfTerrainPatches; i++) { GameObject* terrainObject = new GameObject(); terrainObject->AddComponent(new MeshRenderer(terrainObject,newTerrain.GetTerrainMeshes()[i], resourceManager->GetMaterial("terrainMaterial"))); newManager.AddGameObject(terrainObject); } */ //TEST 2D OBJECT & Material /* resourceManager->StoreAndInitMaterial("2DMaterial", new Diffuse2D(resourceManager->GetShaderProgram("Diffuse2D", "../data/Diffuse2D.vert", "../data/Diffuse2D.frag"), resourceManager->GetTexture2D("../data/test.bmp"))); GameObject* cubeObject = new GameObject(); cubeObject->GetTransform().SetScale(128,128,1); cubeObject->GetTransform().SetPosition(Vector3(500,300,0)); cubeObject->AddComponent(new MeshRenderer(cubeObject,resourceManager->GetPrimitive(PLANE_PRIMITIVE), resourceManager->GetMaterial("2DMaterial"), ComponentUpdateStep::Render2DUpdate())); newManager.AddGameObject(cubeObject); */ //CDLOD TERRAIN resourceManager->StoreAndInitMaterial("TerrainMaterial", new TerrainMaterial(resourceManager->GetShaderProgram("TerrainShader", "../data/Terrain.vert", "../data/Terrain.frag"),resourceManager->GetTexture2D("data/heightmap4.bmp"))); TerrainCDLOD terrain((Camera*)newManager.GetMainCameraObject()->GetComponent(typeid(Camera)),resourceManager->GetTexture2D("data/heightmap4.bmp")); GameObject* terrainObject = new GameObject(); terrainObject->AddComponent(new TerrainRenderer(terrainObject, &terrain, (TerrainMaterial*)resourceManager->GetMaterial("TerrainMaterial"),newManager.GetGraphicsDevice())); newManager.AddGameObject(terrainObject); //Add a movement script to the camera GameObject* cameraObject = newManager.GetMainCameraObject(); newManager.AddComponentToGameObject(cameraObject, new FreeLookCamera(cameraObject)); newManager.Update(); newManager.Shutdown(); }
std::string default_map_generator_job::default_generate_map(generator_data data, std::map<map_location,std::string>* labels, const config& cfg) { log_scope("map generation"); // Odd widths are nasty VALIDATE(is_even(data.width), _("Random maps with an odd width aren't supported.")); // Try to find configuration for castles const config& castle_config = cfg.child("castle"); int ticks = SDL_GetTicks(); // We want to generate a map that is 9 times bigger than the actual size desired. // Only the middle part of the map will be used, but the rest is so that the map we // end up using can have a context (e.g. rivers flowing from out of the map into the map, // same for roads, etc.) data.width *= 3; data.height *= 3; config naming; if(cfg.has_child("naming")) { naming = game_config_.child("naming"); naming.append_attributes(cfg.child("naming")); } // If the [naming] child is empty, we cannot provide good names. std::map<map_location,std::string>* misc_labels = naming.empty() ? nullptr : labels; std::shared_ptr<name_generator> base_name_generator, river_name_generator, lake_name_generator, road_name_generator, bridge_name_generator, mountain_name_generator, forest_name_generator, swamp_name_generator; if(misc_labels != nullptr) { name_generator_factory base_generator_factory{ naming, {"male", "base", "bridge", "road", "river", "forest", "lake", "mountain", "swamp"} }; naming.get_old_attribute("base_names", "male_names", "[naming]male_names= is deprecated, use base_names= instead"); //Due to the attribute detection feature of the factory we also support male_name_generator= but keep it undocumented. base_name_generator = base_generator_factory.get_name_generator( (naming.has_attribute("base_names") || naming.has_attribute("base_name_generator")) ? "base" : "male" ); river_name_generator = base_generator_factory.get_name_generator("river"); lake_name_generator = base_generator_factory.get_name_generator("lake"); road_name_generator = base_generator_factory.get_name_generator("road"); bridge_name_generator = base_generator_factory.get_name_generator("bridge"); mountain_name_generator = base_generator_factory.get_name_generator("mountain"); forest_name_generator = base_generator_factory.get_name_generator("forest"); swamp_name_generator = base_generator_factory.get_name_generator("swamp"); } // Generate the height of everything. const height_map heights = generate_height_map(data.width, data.height, data.iterations, data.hill_size, data.island_size, data.island_off_center); LOG_NG << "Done generating height map. " << (SDL_GetTicks() - ticks) << " ticks elapsed" << "\n"; ticks = SDL_GetTicks(); // Find out what the 'flatland' on this map is, i.e. grassland. std::string flatland = cfg["default_flatland"]; if(flatland.empty()) { flatland = t_translation::write_terrain_code(t_translation::GRASS_LAND); } const t_translation::terrain_code grassland = t_translation::read_terrain_code(flatland); std::vector<terrain_height_mapper> height_conversion; for(const config& h : cfg.child_range("height")) { height_conversion.emplace_back(h); } terrain_map terrain(data.width, data.height, grassland); for(size_t x = 0; x != heights.size(); ++x) { for(size_t y = 0; y != heights[x].size(); ++y) { for(auto i : height_conversion) { if(i.convert_terrain(heights[x][y])) { terrain[x][y] = i.convert_to(); break; } } } } t_translation::starting_positions starting_positions; LOG_NG << output_map(terrain, starting_positions); LOG_NG << "Placed landforms. " << (SDL_GetTicks() - ticks) << " ticks elapsed" << "\n"; ticks = SDL_GetTicks(); /* Now that we have our basic set of flatland/hills/mountains/water, * we can place lakes and rivers on the map. * All rivers are sourced at a lake. * Lakes must be in high land - at least 'min_lake_height'. * (Note that terrain below a certain altitude may be made into bodies of water * in the code above - i.e. 'sea', but these are not considered 'lakes', * because they are not sources of rivers). * * We attempt to place 'max_lakes' lakes. * Each lake will be placed at a random location, if that random location meets theminimum * terrain requirements for a lake. We will also attempt to source a river from each lake. */ std::set<map_location> lake_locs; std::map<map_location, std::string> river_names, lake_names, road_names, bridge_names, mountain_names, forest_names, swamp_names; const size_t nlakes = data.max_lakes > 0 ? (rng_()%data.max_lakes) : 0; for(size_t lake = 0; lake != nlakes; ++lake) { for(int tries = 0; tries != 100; ++tries) { const int x = rng_()%data.width; const int y = rng_()%data.height; if(heights[x][y] <= cfg["min_lake_height"].to_int()) { continue; } std::vector<map_location> river = generate_river(heights, terrain, x, y, cfg["river_frequency"]); if(!river.empty() && misc_labels != nullptr) { const std::string base_name = base_name_generator->generate(); const std::string& name = river_name_generator->generate({{"base", base_name}}); LOG_NG << "Named river '" << name << "'\n"; size_t name_frequency = 20; for(std::vector<map_location>::const_iterator r = river.begin(); r != river.end(); ++r) { const map_location loc(r->x-data.width/3,r->y-data.height/3); if(((r - river.begin())%name_frequency) == name_frequency/2) { misc_labels->emplace(loc, name); } river_names.emplace(loc, base_name); } } LOG_NG << "Generating lake...\n"; std::set<map_location> locs; if(generate_lake(terrain, x, y, cfg["lake_size"], locs) && misc_labels != nullptr) { bool touches_other_lake = false; std::string base_name = base_name_generator->generate(); const std::string& name = lake_name_generator->generate({{"base", base_name}}); // Only generate a name if the lake hasn't touched any other lakes, // so that we don't end up with one big lake with multiple names. for(auto i : locs) { if(lake_locs.count(i) != 0) { touches_other_lake = true; // Reassign the name of this lake to be the same as the other lake const map_location loc(i.x-data.width/3,i.y-data.height/3); const std::map<map_location,std::string>::const_iterator other_name = lake_names.find(loc); if(other_name != lake_names.end()) { base_name = other_name->second; } } lake_locs.insert(i); } if(!touches_other_lake) { const map_location loc(x-data.width/3,y-data.height/3); misc_labels->erase(loc); misc_labels->emplace(loc, name); } for(auto i : locs) { const map_location loc(i.x-data.width/3,i.y-data.height/3); lake_names.emplace(loc, base_name); } } break; } } LOG_NG << "Generated rivers. " << (SDL_GetTicks() - ticks) << " ticks elapsed" << "\n"; ticks = SDL_GetTicks(); const size_t default_dimensions = 40*40*9; /* * Convert grassland terrain to other types of flat terrain. * * We generate a 'temperature map' which uses the height generation * algorithm to generate the temperature levels all over the map. Then we * can use a combination of height and terrain to divide terrain up into * more interesting types than the default. */ const height_map temperature_map = generate_height_map(data.width,data.height, cfg["temperature_iterations"].to_int() * data.width * data.height / default_dimensions, cfg["temperature_size"], 0, 0); LOG_NG << "Generated temperature map. " << (SDL_GetTicks() - ticks) << " ticks elapsed" << "\n"; ticks = SDL_GetTicks(); std::vector<terrain_converter> converters; for(const config& cv : cfg.child_range("convert")) { converters.emplace_back(cv); } LOG_NG << "Created terrain converters. " << (SDL_GetTicks() - ticks) << " ticks elapsed" << "\n"; ticks = SDL_GetTicks(); // Iterate over every flatland tile, and determine what type of flatland it is, based on our [convert] tags. for(int x = 0; x != data.width; ++x) { for(int y = 0; y != data.height; ++y) { for(auto i : converters) { if(i.convert_terrain(terrain[x][y],heights[x][y],temperature_map[x][y])) { terrain[x][y] = i.convert_to(); break; } } } } LOG_NG << "Placing castles...\n"; /* * Attempt to place castles at random. * * After they are placed, we run a sanity check to make sure no two castles * are closer than 'min_distance' hexes apart, and that they appear on a * terrain listed in 'valid_terrain'. * * If not, we attempt to place them again. */ std::vector<map_location> castles; std::set<map_location> failed_locs; if(castle_config) { /* * Castle configuration tag contains a 'valid_terrain' attribute which is a * list of terrains that the castle may appear on. */ const t_translation::ter_list list = t_translation::read_list(castle_config["valid_terrain"]); const is_valid_terrain terrain_tester(terrain, list); for(int player = 0; player != data.nplayers; ++player) { LOG_NG << "placing castle for " << player << "\n"; lg::scope_logger inner_scope_logging_object__(lg::general(), "placing castle"); const int min_x = data.width/3 + 3; const int min_y = data.height/3 + 3; const int max_x = (data.width/3)*2 - 4; const int max_y = (data.height/3)*2 - 4; int min_distance = castle_config["min_distance"]; map_location best_loc; int best_ranking = 0; for(int x = min_x; x != max_x; ++x) { for(int y = min_y; y != max_y; ++y) { const map_location loc(x,y); if(failed_locs.count(loc)) { continue; } const int ranking = rank_castle_location(x, y, terrain_tester, min_x, max_x, min_y, max_y, min_distance, castles, best_ranking); if(ranking <= 0) { failed_locs.insert(loc); } if(ranking > best_ranking) { best_ranking = ranking; best_loc = loc; } } } if(best_ranking == 0) { ERR_NG << "No castle location found, aborting." << std::endl; const std::string error = _("No valid castle location found. Too many or too few mountain hexes? (please check the 'max hill size' parameter)"); throw mapgen_exception(error); } assert(std::find(castles.begin(), castles.end(), best_loc) == castles.end()); castles.push_back(best_loc); // Make sure the location can't get a second castle. failed_locs.insert(best_loc); } LOG_NG << "Placed castles. " << (SDL_GetTicks() - ticks) << " ticks elapsed" << "\n"; } LOG_NG << "Placing roads...\n"; ticks = SDL_GetTicks(); // Place roads. // We select two tiles at random locations on the borders of the map // and try to build roads between them. int nroads = cfg["roads"]; if(data.link_castles) { nroads += castles.size()*castles.size(); } std::set<map_location> bridges; road_path_calculator calc(terrain, cfg, rng_()); for(int road = 0; road != nroads; ++road) { lg::scope_logger another_inner_scope_logging_object__(lg::general(), "creating road"); /* * We want the locations to be on the portion of the map we're actually * going to use, since roads on other parts of the map won't have any * influence, and doing it like this will be quicker. */ map_location src = random_point_at_side(data.width/3 + 2,data.height/3 + 2); map_location dst = random_point_at_side(data.width/3 + 2,data.height/3 + 2); src.x += data.width/3 - 1; src.y += data.height/3 - 1; dst.x += data.width/3 - 1; dst.y += data.height/3 - 1; if(data.link_castles && road < int(castles.size() * castles.size())) { const size_t src_castle = road/castles.size(); const size_t dst_castle = road%castles.size(); if(src_castle >= dst_castle) { continue; } src = castles[src_castle]; dst = castles[dst_castle]; } else if(src.x == dst.x || src.y == dst.y) { // If the road isn't very interesting (on the same border), don't draw it. continue; } if(calc.cost(src, 0.0) >= 1000.0 || calc.cost(dst, 0.0) >= 1000.0) { continue; } // Search a path out for the road pathfind::plain_route rt = pathfind::a_star_search(src, dst, 10000.0, calc, data.width, data.height); const std::string& road_base_name = misc_labels != nullptr ? base_name_generator->generate() : ""; const std::string& road_name = misc_labels != nullptr ? road_name_generator->generate({{"base", road_base_name}}) : ""; const int name_frequency = 20; int name_count = 0; bool on_bridge = false; // Draw the road. // If the search failed, rt.steps will simply be empty. for(std::vector<map_location>::const_iterator step = rt.steps.begin(); step != rt.steps.end(); ++step) { const int x = step->x; const int y = step->y; if(x < 0 || y < 0 || x >= static_cast<long>(data.width) || y >= static_cast<long>(data.height)) { continue; } // Find the configuration which tells us what to convert this tile to, to make it into a road. const config& child = cfg.find_child("road_cost", "terrain", t_translation::write_terrain_code(terrain[x][y])); if(child.empty()){ continue; } /* Convert to bridge means that we want to convert depending on the direction of the road. * Typically it will be in a format like convert_to_bridge = \,|,/ * '|' will be used if the road is going north-south * '/' will be used if the road is going south west-north east * '\' will be used if the road is going south east-north west * The terrain will be left unchanged otherwise (if there is no clear direction). */ const std::string& convert_to_bridge = child["convert_to_bridge"]; if(!convert_to_bridge.empty()) { if(step == rt.steps.begin() || step+1 == rt.steps.end()) { continue; } const map_location& last = *(step-1); const map_location& next = *(step+1); map_location adj[6]; get_adjacent_tiles(*step,adj); int direction = -1; // If we are going north-south if((last == adj[0] && next == adj[3]) || (last == adj[3] && next == adj[0])) { direction = 0; } // If we are going south west-north east else if((last == adj[1] && next == adj[4]) || (last == adj[4] && next == adj[1])) { direction = 1; } // If we are going south east-north west else if((last == adj[2] && next == adj[5]) || (last == adj[5] && next == adj[2])) { direction = 2; } if(misc_labels != nullptr && !on_bridge) { on_bridge = true; std::string bridge_base_name = base_name_generator->generate(); const std::string& name = bridge_name_generator->generate({{"base", bridge_base_name}}); const map_location loc(x - data.width / 3, y-data.height/3); misc_labels->emplace(loc, name); bridge_names.emplace(loc, bridge_base_name); //add to use for village naming bridges.insert(loc); } if(direction != -1) { const std::vector<std::string> items = utils::split(convert_to_bridge); if(size_t(direction) < items.size() && !items[direction].empty()) { terrain[x][y] = t_translation::read_terrain_code(items[direction]); } continue; } } else { on_bridge = false; } // Just a plain terrain substitution for a road const std::string& convert_to = child["convert_to"]; if(!convert_to.empty()) { const t_translation::terrain_code letter = t_translation::read_terrain_code(convert_to); if(misc_labels != nullptr && terrain[x][y] != letter && name_count++ == name_frequency && !on_bridge) { misc_labels->emplace(map_location(x - data.width / 3, y - data.height / 3), road_name); name_count = 0; } terrain[x][y] = letter; if(misc_labels != nullptr) { const map_location loc(x - data.width / 3, y - data.height / 3); //add to use for village naming if(!road_base_name.empty()) road_names.emplace(loc, road_base_name); } } } } // Now that road drawing is done, we can plonk down the castles. for(std::vector<map_location>::const_iterator c = castles.begin(); c != castles.end(); ++c) { if(!c->valid()) { continue; } const int x = c->x; const int y = c->y; const int player = c - castles.begin() + 1; const t_translation::coordinate coord(x, y); starting_positions.insert(t_translation::starting_positions::value_type(std::to_string(player), coord)); terrain[x][y] = t_translation::HUMAN_KEEP; const int castle_array[13][2] { {-1, 0}, {-1, -1}, {0, -1}, {1, -1}, {1, 0}, {0, 1}, {-1, 1}, {-2, 1}, {-2, 0}, {-2, -1}, {-1, -2}, {0, -2}, {1, -2} }; for(int i = 0; i < data.castle_size - 1; i++) { terrain[x+ castle_array[i][0]][y+ castle_array[i][1]] = t_translation::HUMAN_CASTLE; } // Remove all labels under the castle tiles if(labels != nullptr) { labels->erase(map_location(x-data.width/3,y-data.height/3)); for(int i = 0; i < data.castle_size - 1; i++) { labels->erase(map_location(x+ castle_array[i][0]-data.width/3, y+ castle_array[i][1]-data.height/3)); } } } LOG_NG << "Placed roads. " << (SDL_GetTicks() - ticks) << " ticks elapsed" << "\n"; ticks = SDL_GetTicks(); /* Random naming for landforms: mountains, forests, swamps, hills * we name these now that everything else is placed (as e.g., placing * roads could split a forest) */ if(misc_labels != nullptr) { for(int x = data.width / 3; x < (data.width / 3)*2; x++) { for(int y = data.height / 3; y < (data.height / 3) * 2;y++) { //check the terrain of the tile const map_location loc(x - data.width / 3, y - data.height / 3); const t_translation::terrain_code terr = terrain[x][y]; std::string name, base_name; std::set<std::string> used_names; if(t_translation::terrain_matches(terr, t_translation::ALL_MOUNTAINS)) { //name every 15th mountain if((rng_() % 15) == 0) { for(size_t ntry = 0; ntry != 30 && (ntry == 0 || used_names.count(name) > 0); ++ntry) { base_name = base_name_generator->generate(); name = mountain_name_generator->generate({{"base", base_name}}); } misc_labels->emplace(loc, name); mountain_names.emplace(loc, base_name); } } else if(t_translation::terrain_matches(terr, t_translation::ALL_FORESTS)) { // If the forest tile is not named yet, name it const std::map<map_location, std::string>::const_iterator forest_name = forest_names.find(loc); if(forest_name == forest_names.end()) { for(size_t ntry = 0; ntry != 30 && (ntry == 0 || used_names.count(name) > 0); ++ntry) { base_name = base_name_generator->generate(); name = forest_name_generator->generate({{"base", base_name}}); } forest_names.emplace(loc, base_name); // name all connected forest tiles accordingly flood_name(loc, base_name, forest_names, t_translation::ALL_FORESTS, terrain, data.width, data.height, 0, misc_labels, name); } } else if(t_translation::terrain_matches(terr, t_translation::ALL_SWAMPS)) { // If the swamp tile is not named yet, name it const std::map<map_location, std::string>::const_iterator swamp_name = swamp_names.find(loc); if(swamp_name == swamp_names.end()) { for(size_t ntry = 0; ntry != 30 && (ntry == 0 || used_names.count(name) > 0); ++ntry) { base_name = base_name_generator->generate(); name = swamp_name_generator->generate({{"base", base_name}}); } swamp_names.emplace(loc, base_name); // name all connected swamp tiles accordingly flood_name(loc, base_name, swamp_names, t_translation::ALL_SWAMPS, terrain, data.width, data.height, 0, misc_labels, name); } } } } } LOG_NG << "Named landforms. " << (SDL_GetTicks() - ticks) << " ticks elapsed" << "\n"; LOG_NG << "Placing villages...\n"; ticks = SDL_GetTicks(); /* * Place villages in a 'grid', to make placing fair, but with villages * displaced from their position according to terrain and randomness, to * add some variety. */ std::set<map_location> villages; if(data.nvillages > 0) { // First we work out the size of the x and y distance between villages const size_t tiles_per_village = ((data.width*data.height)/9)/data.nvillages; size_t village_x = 1, village_y = 1; // Alternate between incrementing the x and y value. // When they are high enough to equal or exceed the tiles_per_village, // then we have them to the value we want them at. while(village_x*village_y < tiles_per_village) { if(village_x < village_y) { ++village_x; } else { ++village_y; } } std::set<std::string> used_names; tcode_list_cache adj_liked_cache; config village_naming = game_config_.child("village_naming"); if(cfg.has_child("village_naming")) { village_naming.append_attributes(cfg.child("village_naming")); } // If the [village_naming] child is empty, we cannot provide good names. std::map<map_location,std::string>* village_labels = village_naming.empty() ? nullptr : labels; for(int vx = 0; vx < data.width; vx += village_x) { LOG_NG << "village at " << vx << "\n"; for(int vy = rng_()%village_y; vy < data.height; vy += village_y) { const size_t add = rng_()%3; const size_t x = (vx + add) - 1; const size_t y = (vy + add) - 1; const map_location res = place_village(terrain, x, y, 2, cfg, adj_liked_cache); if(res.x < static_cast<long>(data.width ) / 3 || res.x >= static_cast<long>(data.width * 2) / 3 || res.y < static_cast<long>(data.height ) / 3 || res.y >= static_cast<long>(data.height * 2) / 3) { continue; } const std::string str = t_translation::write_terrain_code(terrain[res.x][res.y]); const std::string& convert_to = cfg.find_child("village", "terrain", str)["convert_to"].str(); if(convert_to.empty()) { continue; } terrain[res.x][res.y] = t_translation::read_terrain_code(convert_to); villages.insert(res); if(village_labels == nullptr) { continue; } name_generator_factory village_name_generator_factory{ village_naming, {"base", "male", "village", "lake", "river", "bridge", "grassland", "forest", "hill", "mountain", "mountain_anon", "road", "swamp"} }; village_naming.get_old_attribute("base_names", "male_names", "[village_naming]male_names= is deprecated, use base_names= instead"); //Due to the attribute detection feature of the factory we also support male_name_generator= but keep it undocumented. base_name_generator = village_name_generator_factory.get_name_generator( (village_naming.has_attribute("base_names") || village_naming.has_attribute("base_name_generator")) ? "base" : "male" ); const map_location loc(res.x-data.width/3,res.y-data.height/3); map_location adj[6]; get_adjacent_tiles(loc,adj); std::string name_type = "village"; const t_translation::ter_list field = t_translation::ter_list(1, t_translation::GRASS_LAND), forest = t_translation::ter_list(1, t_translation::FOREST), mountain = t_translation::ter_list(1, t_translation::MOUNTAIN), hill = t_translation::ter_list(1, t_translation::HILL); size_t field_count = 0, forest_count = 0, mountain_count = 0, hill_count = 0; std::map<std::string,std::string> symbols; size_t n; for(n = 0; n != 6; ++n) { const std::map<map_location,std::string>::const_iterator road_name = road_names.find(adj[n]); if(road_name != road_names.end()) { symbols["road"] = road_name->second; name_type = "road"; break; } const std::map<map_location,std::string>::const_iterator river_name = river_names.find(adj[n]); if(river_name != river_names.end()) { symbols["river"] = river_name->second; name_type = "river"; const std::map<map_location,std::string>::const_iterator bridge_name = bridge_names.find(adj[n]); if(bridge_name != bridge_names.end()) { //we should always end up here, since if there is an adjacent bridge, there has to be an adjacent river too symbols["bridge"] = bridge_name->second; name_type = "river_bridge"; } break; } const std::map<map_location,std::string>::const_iterator forest_name = forest_names.find(adj[n]); if(forest_name != forest_names.end()) { symbols["forest"] = forest_name->second; name_type = "forest"; break; } const std::map<map_location,std::string>::const_iterator lake_name = lake_names.find(adj[n]); if(lake_name != lake_names.end()) { symbols["lake"] = lake_name->second; name_type = "lake"; break; } const std::map<map_location,std::string>::const_iterator mountain_name = mountain_names.find(adj[n]); if(mountain_name != mountain_names.end()) { symbols["mountain"] = mountain_name->second; name_type = "mountain"; break; } const std::map<map_location,std::string>::const_iterator swamp_name = swamp_names.find(adj[n]); if(swamp_name != swamp_names.end()) { symbols["swamp"] = swamp_name->second; name_type = "swamp"; break; } const t_translation::terrain_code terr = terrain[adj[n].x+data.width/3][adj[n].y+data.height/3]; if(std::count(field.begin(),field.end(),terr) > 0) { ++field_count; } else if(std::count(forest.begin(),forest.end(),terr) > 0) { ++forest_count; } else if(std::count(hill.begin(),hill.end(),terr) > 0) { ++hill_count; } else if(std::count(mountain.begin(),mountain.end(),terr) > 0) { ++mountain_count; } } if(n == 6) { if(field_count == 6) { name_type = "grassland"; } else if(forest_count >= 2) { name_type = "forest"; } else if(mountain_count >= 1) { name_type = "mountain_anon"; } else if(hill_count >= 2) { name_type = "hill"; } } std::string name; symbols["base"] = base_name_generator->generate(); std::shared_ptr<name_generator> village_name_generator = village_name_generator_factory.get_name_generator(name_type); for(size_t ntry = 0; ntry != 30 && (ntry == 0 || used_names.count(name) > 0); ++ntry) { name = village_name_generator->generate(symbols); } used_names.insert(name); village_labels->emplace(loc, name); } } } LOG_NG << "Placed villages. " << (SDL_GetTicks() - ticks) << " ticks elapsed" << "\n"; return output_map(terrain, starting_positions); }