示例#1
0
文件: main.cpp 项目: AsKorysti/anura
extern "C" int main(int argcount, char* argvec[])
#endif
{
	{
		std::vector<std::string> args;
		for(int i = 0; i != argcount; ++i) {
			args.push_back(argvec[i]);
		}

		preferences::set_argv(args);
	}

#if defined(__native_client__)
	std::cerr << "Running game_main" << std::endl;

	chdir("/frogatto");
	{
		char buf[256];
		const char* const res = getcwd(buf,sizeof(buf));
		std::cerr << "Current working directory: " << res << std::endl;
	}
#endif 

#ifdef _MSC_VER
	freopen("CON", "w", stderr);
	freopen("CON", "w", stdout);
#endif

#if defined(__APPLE__) && TARGET_OS_MAC
    chdir([[[NSBundle mainBundle] resourcePath] fileSystemRepresentation]);
#endif

	#ifdef NO_STDERR
	std::freopen("/dev/null", "w", stderr);
	std::cerr.sync_with_stdio(true);
	#endif

	std::cerr << "Frogatto engine version " << preferences::version() << "\n";
	LOG( "After print engine version" );

	#if defined(TARGET_BLACKBERRY)
		chdir("app/native");
		std::cout<< "Changed working directory to: " << getcwd(0, 0) << std::endl;
	#endif

	game_logic::init_callable_definitions();

	std::string level_cfg = "titlescreen.cfg";
	bool unit_tests_only = false, skip_tests = false;
	bool run_benchmarks = false;
	std::vector<std::string> benchmarks_list;
	std::string utility_program;
	std::vector<std::string> util_args;
	std::string server = "wesnoth.org";
#if defined(UTILITY_IN_PROC)
	bool create_utility_in_new_process = false;
	std::string utility_name;
#endif
	bool is_child_utility = false;

	const char* profile_output = NULL;
	std::string profile_output_buf;

#if defined(__ANDROID__)
	//monstartup("libapplication.so");
#endif

	std::string orig_level_cfg = level_cfg;
	std::string override_level_cfg = "";

	int modules_loaded = 0;

	std::vector<std::string> argv;
	for(int n = 1; n < argcount; ++n) {
#if defined(UTILITY_IN_PROC)
		std::string sarg(argvec[n]);
		if(sarg.compare(0, 15, "--utility-proc=") == 0) {
			create_utility_in_new_process = true;
			utility_name = "--utility-child=" + sarg.substr(15);
		} else {
			argv.push_back(argvec[n]);
		}
#else
		argv.push_back(argvec[n]);
#endif
        
        if(argv.size() >= 2 && argv[argv.size()-2] == "-NSDocumentRevisionsDebugMode" && argv.back() == "YES") {
            //XCode passes these arguments by default when debugging -- make sure they are ignored.
            argv.resize(argv.size()-2);
        }
	}

	std::cerr << "Build Options:";
	for(auto bo : preferences::get_build_options()) {
		std::cerr << " " << bo;
	}
	std::cerr << std::endl;

#if defined(UTILITY_IN_PROC)
	if(create_utility_in_new_process) {
		argv.push_back(utility_name);
#if defined(_MSC_VER)
		// app name is ignored for windows, we get windows to tell us.
		is_child_utility = create_utility_process("", argv);
#else 
		is_child_utility = create_utility_process(argvec[0], argv);
#endif
		if(!is_child_utility) {
			argv.pop_back();
		}
#if defined(_MSC_VER)
		atexit(terminate_utility_process);
#endif
	}
#endif

	if(sys::file_exists("./master-config.cfg")) {
		std::cerr << "LOADING CONFIGURATION FROM master-config.cfg" << std::endl;
		variant cfg = json::parse_from_file("./master-config.cfg");
		if(cfg.is_map()) {
			if( cfg["id"].is_null() == false) {
				std::cerr << "SETTING MODULE PATH FROM master-config.cfg: " << cfg["id"].as_string() << std::endl;
				preferences::set_preferences_path_from_module(cfg["id"].as_string());
				//XXX module::set_module_name(cfg["id"].as_string(), cfg["id"].as_string());
			}
			if(cfg["arguments"].is_null() == false) {
				std::vector<std::string> additional_args = cfg["arguments"].as_list_string();
				argv.insert(argv.begin(), additional_args.begin(), additional_args.end());
				std::cerr << "ADDING ARGUMENTS FROM master-config.cfg:";
				for(size_t n = 0; n < cfg["arguments"].num_elements(); ++n) {
					std::cerr << " " << cfg["arguments"][n].as_string();
				}
				std::cerr << std::endl;
			}
		}
	}

	stats::record_program_args(argv);

	for(size_t n = 0; n < argv.size(); ++n) {
		const int argc = argv.size();
		const std::string arg(argv[n]);
		std::string arg_name, arg_value;
		std::string::const_iterator equal = std::find(arg.begin(), arg.end(), '=');
		if(equal != arg.end()) {
			arg_name = std::string(arg.begin(), equal);
			arg_value = std::string(equal+1, arg.end());
		}
		if(arg_name == "--module") {
			if(load_module(arg_value, &argv) != 0) {
				std::cerr << "FAILED TO LOAD MODULE: " << arg_value << "\n";
				return -1;
			}
			++modules_loaded;
		} else if(arg == "--tests") {
			unit_tests_only = true;
		}
	}

	if(modules_loaded == 0 && !unit_tests_only) {
		if(load_module(DEFAULT_MODULE, &argv) != 0) {
			std::cerr << "FAILED TO LOAD MODULE: " << DEFAULT_MODULE << "\n";
			return -1;
		}
	}

	preferences::load_preferences();
	LOG( "After load_preferences()" );

	// load difficulty settings after module, before rest of args.
	difficulty::manager();

	for(size_t n = 0; n < argv.size(); ++n) {
		const size_t argc = argv.size();
		const std::string arg(argv[n]);
		std::string arg_name, arg_value;
		std::string::const_iterator equal = std::find(arg.begin(), arg.end(), '=');
		if(equal != arg.end()) {
			arg_name = std::string(arg.begin(), equal);
			arg_value = std::string(equal+1, arg.end());
		}
		std::cerr << "ARGS: " << arg << std::endl;
		if(arg.substr(0,4) == "-psn") {
			// ignore.
		} else if(arg_name == "--module") {
			// ignore already processed.
		} else if(arg_name == "--profile" || arg == "--profile") {
			profile_output_buf = arg_value;
			profile_output = profile_output_buf.c_str();
		} else if(arg_name == "--utility" || arg_name == "--utility-child") {
			if(arg_name == "--utility-child") {
				is_child_utility = true;
			}
			utility_program = arg_value;
			for(++n; n < argc; ++n) {
				const std::string arg(argv[n]);
				util_args.push_back(arg);
			}

			break;
		} else if(arg == "--benchmarks") {
			run_benchmarks = true;
		} else if(arg_name == "--benchmarks") {
			run_benchmarks = true;
			benchmarks_list = util::split(arg_value);
		} else if(arg == "--tests") {
			// ignore as already processed.
		} else if(arg == "--no-tests") {
			skip_tests = true;
		} else if(arg_name == "--width") {
			std::string w(arg_value);
			preferences::set_actual_screen_width(boost::lexical_cast<int>(w));
		} else if(arg == "--width" && n+1 < argc) {
			std::string w(argv[++n]);
			preferences::set_actual_screen_width(boost::lexical_cast<int>(w));
		} else if(arg_name == "--height") {
			std::string h(arg_value);
			preferences::set_actual_screen_height(boost::lexical_cast<int>(h));
		} else if(arg == "--height" && n+1 < argc) {
			std::string h(argv[++n]);
			preferences::set_actual_screen_height(boost::lexical_cast<int>(h));
		} else if(arg_name == "--level") {
			override_level_cfg = arg_value;
		} else if(arg == "--level" && n+1 < argc) {
			override_level_cfg = argv[++n];
		} else if(arg_name == "--host") {
			server = arg_value;
		} else if(arg == "--host" && n+1 < argc) {
			server = argv[++n];
		} else if(arg == "--compiled") {
			preferences::set_load_compiled(true);
#ifndef NO_EDITOR
		} else if(arg == "--edit") {
			preferences::set_edit_on_start(true);
#endif
		} else if(arg == "--no-compiled") {
			preferences::set_load_compiled(false);
#if defined(TARGET_PANDORA)
		} else if(arg == "--no-fbo") {
			preferences::set_fbo(false);
		} else if(arg == "--no-bequ") {
			preferences::set_bequ(false);
#endif
		} else if(arg == "--help" || arg == "-h") {
			print_help(std::string(argvec[0]));
			return 0;
		} else {
			const bool res = preferences::parse_arg(argv[n].c_str());
			if(!res) {
				std::cerr << "unrecognized arg: '" << arg << "'\n";
				return -1;
			}
		}
	}

	preferences::expand_data_paths();

	if(g_auto_update_anura != "" && anura_exe_name != "" && sys::file_exists("manifest.cfg")) {
		std::string exe_name = argvec[0];
		if(exe_name.size() >= anura_exe_name.size() && std::equal(exe_name.end()-anura_exe_name.size(), exe_name.end(), anura_exe_name.begin())) {
			variant manifest = json::parse(sys::read_file("manifest.cfg"));
			if(manifest.is_map()) {
				variant anura_entry = manifest[anura_exe_name];
				if(anura_entry.is_map()) {
					std::string expected_md5 = anura_entry["md5"].as_string();
					std::string match;
					if(expected_md5 != md5::sum(sys::read_file(exe_name))) {
						for(auto fname : alternative_anura_exe_names()) {
							if(sys::file_exists(fname) && md5::sum(sys::read_file(fname)) == expected_md5) {
								match = fname;
								break;
							}
						}


						ASSERT_LOG(match != "", "anura.exe does not match md5 in manifest and no alternative anura.exe found");

						try {
							sys::move_file(exe_name, "anura.exe.tmp");
							sys::move_file(match, exe_name);
							match = exe_name;
						} catch(...) {
						}


						std::vector<char*> args;
						for(char** a = argvec; *a; ++a) {
							args.push_back(*a);
						}
						args.push_back(NULL);
				
						exe_name.resize(exe_name.size() - anura_exe_name.size());
						exe_name += match;
						args[0] = const_cast<char*>(exe_name.c_str());
						fprintf(stderr, "ZZZ: CALLING EXEC...\n");
						execv(args[0], &args[0]);
						fprintf(stderr, "Could not exec()\n");
					}
				}
			}
		}
	}

	background_task_pool::manager bg_task_pool_manager;
	LOG( "After expand_data_paths()" );

	std::cerr << "Preferences dir: " << preferences::user_data_path() << '\n';

	//make sure that the user data path exists.
	if(!preferences::setup_preferences_dir()) {
		std::cerr << "cannot create preferences dir!\n";
	}

	std::cerr << "\n";

	variant_builder update_info;
	if(g_auto_update_module || g_auto_update_anura != "") {

		//remove any .tmp files that may have been left from previous runs.
		std::vector<std::string> tmp_files;
		sys::get_files_in_dir(".", &tmp_files, NULL);
		for(auto f : tmp_files) {
			if(f.size() > 4 && std::equal(f.end()-4,f.end(),".tmp")) {
				try {
					sys::remove_file(f);
				} catch(...) {
				}
			}
		}

		boost::intrusive_ptr<module::client> cl, anura_cl;
		
		if(g_auto_update_module) {
			cl.reset(new module::client);
			cl->install_module(module::get_module_name(), g_force_auto_update);
			update_info.add("attempt_module", true);
		}

		if(g_auto_update_anura != "") {
			anura_cl.reset(new module::client);
			anura_cl->set_install_image(true);
			anura_cl->install_module(g_auto_update_anura, g_force_auto_update);
			update_info.add("attempt_anura", true);
		}

		SDL_Window* update_window = NULL;

		int nbytes_transferred = 0, nbytes_anura_transferred = 0;
		int start_time = SDL_GetTicks();
		int original_start_time = SDL_GetTicks();
		bool timeout = false;
		bool require_restart = false;
		fprintf(stderr, "Requesting update to module from server...\n");
		while(cl || anura_cl) {
			if(update_window == NULL && SDL_GetTicks() - original_start_time > 2000) {
				update_window = SDL_CreateWindow("Updating Anura...", 0, 0, 800, 600, SDL_WINDOW_SHOWN);
			}

			int nbytes_obtained = 0;
			int nbytes_needed = 0;

			if(cl) {
				const int transferred = cl->nbytes_transferred();
				nbytes_obtained += transferred;
				nbytes_needed += cl->nbytes_total();
				if(transferred != nbytes_transferred) {
					fprintf(stderr, "Transferred %d/%dKB\n", transferred/1024, cl->nbytes_total()/1024);
					start_time = SDL_GetTicks();
					nbytes_transferred = transferred;
				}
			}

			if(anura_cl) {
				const int transferred = anura_cl->nbytes_transferred();
				nbytes_obtained += transferred;
				nbytes_needed += anura_cl->nbytes_total();
				if(transferred != nbytes_anura_transferred) {
					fprintf(stderr, "Transferred (anura) %d/%dKB\n", transferred/1024, anura_cl->nbytes_total()/1024);
					start_time = SDL_GetTicks();
					nbytes_anura_transferred = transferred;
				}
			}

			const int time_taken = SDL_GetTicks() - start_time;
			if(time_taken > g_auto_update_timeout) {
				fprintf(stderr, "Timed out updating module. Canceling. %dms vs %dms\n", time_taken, g_auto_update_timeout);
				break;
			}

			if(update_window) {
				SDL_Surface* fb= SDL_GetWindowSurface(update_window);
				SDL_Rect area = {300, 290, 200, 20};
				SDL_FillRect(fb, &area, 0xFFFFFFFF);

				SDL_Rect inner_area = {303, 292, 194, 16};
				SDL_FillRect(fb, &inner_area, 0xFF000000);

				if(nbytes_needed != 0) {
					const float ratio = float(nbytes_obtained)/float(nbytes_needed);
					SDL_Rect area = {303, 292, int(194.0*ratio), 16};
					SDL_FillRect(fb, &area, 0xFFFFFFFF);
				}

				SDL_UpdateWindowSurface(update_window);
			}

			SDL_Event event;
			while(SDL_PollEvent(&event)) {
				if(event.type == SDL_QUIT) {
					cl.reset();
					anura_cl.reset();
					break;
				}
			}

			SDL_Delay(20);

			if(cl && !cl->process()) {
				if(cl->error().empty() == false) {
					fprintf(stderr, "Error while updating module: %s\n", cl->error().c_str());
					update_info.add("module_error", variant(cl->error()));
				} else {
					update_info.add("complete_module", true);
				}
				cl.reset();
			}

			if(anura_cl && !anura_cl->process()) {
				if(anura_cl->error().empty() == false) {
					fprintf(stderr, "Error while updating anura: %s\n", anura_cl->error().c_str());
					update_info.add("anura_error", variant(anura_cl->error()));
				} else {
					update_info.add("complete_anura", true);
					require_restart = anura_cl->nfiles_written() != 0;
				}
				anura_cl.reset();
			}
		}

		if(update_window) {
			SDL_DestroyWindow(update_window);
		}

		if(require_restart) {
			std::vector<char*> args;
			for(char** a = argvec; *a; ++a) {
				std::string arg(*a);
				if(arg != "--force-auto-update" && arg != "--force_auto_update") {
					args.push_back(*a);
				}
			}
			args.push_back(NULL);
			fprintf(stderr, "ZZZ: CALLING EXEC...\n");
			execv(args[0], &args[0]);
			fprintf(stderr, "Could not exec()\n");
		}
	}

	g_auto_update_info = update_info.build();

	checksum::manager checksum_manager;
#ifndef NO_EDITOR
	sys::filesystem_manager fs_manager;
#endif // NO_EDITOR

	const tbs::internal_server_manager internal_server_manager_scope(preferences::internal_tbs_server());

	if(utility_program.empty() == false 
		&& test::utility_needs_video(utility_program) == false) {
#if defined(UTILITY_IN_PROC)
		if(is_child_utility) {
			ASSERT_LOG(ipc::semaphore::create(shared_sem_name, 1) != false, 
				"Unable to create shared semaphore: " << errno);
			std::cerr.sync_with_stdio(true);
		}
#endif
		test::run_utility(utility_program, util_args);
		return 0;
	}

#if defined(TARGET_PANDORA)
    EGL_Open();
#endif

#if defined(__ANDROID__)
	std::freopen("stdout.txt","w",stdout);
	std::freopen("stderr.txt","w",stderr);
	std::cerr.sync_with_stdio(true);
#endif

	LOG( "Start of main" );

	if(!skip_tests && !test::run_tests()) {
		return -1;
	}

	if(unit_tests_only) {
		return 0;
	}

	// Create the main window.
	// Initalise SDL and Open GL.
	main_window = graphics::window_manager_ptr(new graphics::window_manager());
	main_window->create_window(preferences::actual_screen_width(), preferences::actual_screen_height());

#ifdef TARGET_OS_HARMATTAN
	g_type_init();
#endif
	i18n::init ();
	LOG( "After i18n::init()" );

#if TARGET_OS_IPHONE || defined(TARGET_BLACKBERRY) || defined(__ANDROID__)
	//on the iPhone and PlayBook, try to restore the auto-save if it exists
	if(sys::file_exists(preferences::auto_save_file_path()) && sys::read_file(std::string(preferences::auto_save_file_path()) + ".stat") == "1") {
		level_cfg = "autosave.cfg";
		sys::write_file(std::string(preferences::auto_save_file_path()) + ".stat", "0");
	}
#endif

	if(override_level_cfg.empty() != true) {
		level_cfg = override_level_cfg;
		orig_level_cfg = level_cfg;
	}

	const stats::manager stats_manager;
#ifndef NO_EDITOR
	const external_text_editor::manager editor_manager;
#endif // NO_EDITOR

#if defined(USE_BOX2D)
	box2d::manager b2d_manager;
#endif

	const load_level_manager load_manager;

	{ //manager scope
	const font::manager font_manager;
	const sound::manager sound_manager;
#if !defined(__native_client__)
	const joystick::manager joystick_manager;
#endif 
	
	graphics::texture::manager texture_manager;

#ifndef NO_EDITOR
	editor::manager editor_manager;
#endif

	variant preloads;
	loading_screen loader;
	try {
		variant gui_node = json::parse_from_file(preferences::load_compiled() ? "data/compiled/gui.cfg" : "data/gui.cfg");
		gui_section::init(gui_node);
		loader.draw_and_increment(_("Initializing GUI"));
		framed_gui_element::init(gui_node);

		sound::init_music(json::parse_from_file("data/music.cfg"));
		graphical_font::init_for_locale(i18n::get_locale());
		preloads = json::parse_from_file("data/preload.cfg");
		int preload_items = preloads["preload"].num_elements();
		loader.set_number_of_items(preload_items+7); // 7 is the number of items that will be loaded below
		custom_object::init();
		loader.draw_and_increment(_("Initializing custom object functions"));
		loader.draw_and_increment(_("Initializing textures"));
		loader.load(preloads);
		loader.draw_and_increment(_("Initializing tiles"));
		tile_map::init(json::parse_from_file("data/tiles.cfg"));


		game_logic::formula_object::load_all_classes();

	} catch(const json::parse_error& e) {
		std::cerr << "ERROR PARSING: " << e.error_message() << "\n";
		return 0;
	}
	loader.draw(_("Loading level"));

#if defined(__native_client__)
	while(1) {
	}
#endif

#if defined(__APPLE__) && !(TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE) && !defined(USE_SHADERS)
	GLint swapInterval = 1;
	CGLSetParameter(CGLGetCurrentContext(), kCGLCPSwapInterval, &swapInterval);
#endif

	loader.finish_loading();
	//look to see if we got any quit events while loading.
	{
	SDL_Event event;
	while(input::sdl_poll_event(&event)) {
		if(event.type == SDL_QUIT) {
			return 0;
		}
	}
	}

	formula_profiler::manager profiler(profile_output);

#ifdef USE_SHADERS
	texture_frame_buffer::init(preferences::actual_screen_width(), preferences::actual_screen_height());
#else
	texture_frame_buffer::init();
#endif

	if(run_benchmarks) {
		if(benchmarks_list.empty() == false) {
			test::run_benchmarks(&benchmarks_list);
		} else {
			test::run_benchmarks();
		}
		return 0;
	} else if(utility_program.empty() == false && test::utility_needs_video(utility_program) == true) {
		test::run_utility(utility_program, util_args);
		return 0;
	}

	bool quit = false;

	while(!quit && !show_title_screen(level_cfg)) {
		boost::intrusive_ptr<level> lvl(load_level(level_cfg));
		

#if !defined(__native_client__)
		//see if we're loading a multiplayer level, in which case we
		//connect to the server.
		multiplayer::manager mp_manager(lvl->is_multiplayer());
		if(lvl->is_multiplayer()) {
			multiplayer::setup_networked_game(server);
		}

		if(lvl->is_multiplayer()) {
			last_draw_position() = screen_position();
			std::string level_cfg = "waiting-room.cfg";
			boost::intrusive_ptr<level> wait_lvl(load_level(level_cfg));
			wait_lvl->finish_loading();
			wait_lvl->set_multiplayer_slot(0);
			if(wait_lvl->player()) {
				wait_lvl->player()->set_current_level(level_cfg);
			}
			wait_lvl->set_as_current_level();

			level_runner runner(wait_lvl, level_cfg, orig_level_cfg);

			multiplayer::sync_start_time(*lvl, boost::bind(&level_runner::play_cycle, &runner));

			lvl->set_multiplayer_slot(multiplayer::slot());
		}
#endif

		last_draw_position() = screen_position();

		assert(lvl.get());
		if(!lvl->music().empty()) {
			sound::play_music(lvl->music());
		}

		if(lvl->player() && level_cfg != "autosave.cfg") {
			lvl->player()->set_current_level(level_cfg);
			lvl->player()->get_entity().save_game();
		}

		set_scene_title(lvl->title());

		try {
			quit = level_runner(lvl, level_cfg, orig_level_cfg).play_level();
			level_cfg = orig_level_cfg;
		} catch(multiplayer_exception&) {
		}
	}

	level::clear_current_level();

	} //end manager scope, make managers destruct before calling SDL_Quit
//	controls::debug_dump_controls();
#if defined(TARGET_PANDORA) || defined(TARGET_TEGRA)
    EGL_Destroy();
#endif

	preferences::save_preferences();

#if !defined(_MSC_VER) && defined(UTILITY_IN_PROC)
	if(create_utility_in_new_process) {
		terminate_utility_process();
	}
#endif

	std::set<variant*> loading;
	swap_variants_loading(loading);
	if(loading.empty() == false) {
		fprintf(stderr, "Illegal object: %p\n", (void*)(*loading.begin())->as_callable_loading());
		ASSERT_LOG(false, "Unresolved unserialized objects: " << loading.size());
	}

//#ifdef _MSC_VER
//	ExitProcess(0);
//#endif

	return 0;
}
示例#2
0
void timage::draw(surface& canvas
		, const game_logic::map_formula_callable& variables)
{
	DBG_GUI_D << "Image: draw.\n";

	/**
	 * @todo formulas are now recalculated every draw cycle which is a  bit
	 * silly unless there has been a resize. So to optimize we should use an
	 * extra flag or do the calculation in a separate routine.
	 */
	const std::string& name = image_name_(variables);

	if(name.empty()) {
		DBG_GUI_D << "Image: formula returned no value, will not be drawn.\n";
		return;
	}

	/*
	 * The locator might return a different surface for every call so we can't
	 * cache the output, also not if no formula is used.
	 */
	surface tmp(image::get_image(image::locator(name)));

	if(!tmp) {
		ERR_GUI_D << "Image: '" << name << "' not found and won't be drawn.\n";
		return;
	}

	image_.assign(make_neutral_surface(tmp));
	assert(image_);
	src_clip_ = ::create_rect(0, 0, image_->w, image_->h);

	game_logic::map_formula_callable local_variables(variables);
	local_variables.add("image_original_width", variant(image_->w));
	local_variables.add("image_original_height", variant(image_->h));

	unsigned w = w_(local_variables);
	VALIDATE_WITH_DEV_MESSAGE(
			  static_cast<int>(w) >= 0
			, _("Image doesn't fit on canvas.")
			, (formatter() << "Image '" << name
				<< "', w = " << static_cast<int>(w) << ".").str());

	unsigned h = h_(local_variables);
	VALIDATE_WITH_DEV_MESSAGE(
			  static_cast<int>(h) >= 0
			, _("Image doesn't fit on canvas.")
			, (formatter() << "Image '" << name
				<< "', h = " << static_cast<int>(h) << ".").str());

	local_variables.add("image_width", variant(w ? w : image_->w));
	local_variables.add("image_height", variant(h ? h : image_->h));

	const unsigned x = x_(local_variables);
	VALIDATE_WITH_DEV_MESSAGE(
			  static_cast<int>(x) >= 0
			, _("Image doesn't fit on canvas.")
			, (formatter() << "Image '" << name
				<< "', x = " << static_cast<int>(x) << ".").str());

	const unsigned y = y_(local_variables);
	VALIDATE_WITH_DEV_MESSAGE(
			  static_cast<int>(y) >= 0
			, _("Image doesn't fit on canvas.")
			, (formatter() << "Image '" << name
				<< "', y = " << static_cast<int>(y) << ".").str());

	// Copy the data to local variables to avoid overwriting the originals.
	SDL_Rect src_clip = src_clip_;
	SDL_Rect dst_clip = ::create_rect(x, y, 0, 0);
	surface surf;

	// Test whether we need to scale and do the scaling if needed.
	if(w || h) {
		bool done = false;
		bool stretch_image = (resize_mode_ == stretch) && (!!w ^ !!h);
		if(!w) {
			if(stretch_image) {
				DBG_GUI_D << "Image: vertical stretch from " << image_->w
						<< ',' << image_->h << " to a height of " << h << ".\n";

				surf = stretch_surface_vertical(image_, h, false);
				done = true;
			}
			w = image_->w;
		}

		if(!h) {
			if(stretch_image) {
				DBG_GUI_D << "Image: horizontal stretch from " << image_->w
						<< ',' << image_->h << " to a width of " << w << ".\n";

				surf = stretch_surface_horizontal(image_, w, false);
				done = true;
			}
			h = image_->h;
		}

		if(!done) {

			if(resize_mode_ == tile) {
				DBG_GUI_D << "Image: tiling from " << image_->w
						<< ',' << image_->h << " to " << w << ',' << h << ".\n";

				const int columns = (w + image_->w - 1) / image_->w;
				const int rows = (h + image_->h - 1) / image_->h;
				surf = create_neutral_surface(w, h);

				for(int x = 0; x < columns; ++x) {
					for(int y = 0; y < rows; ++y) {
						const SDL_Rect dest = ::create_rect(
								  x * image_->w
								, y * image_->h
								, 0
								, 0);
						blit_surface(image_, NULL, surf, &dest);
					}
				}

			} else {
				if(resize_mode_ == stretch) {
					ERR_GUI_D << "Image: failed to stretch image, "
							"fall back to scaling.\n";
				}

				DBG_GUI_D << "Image: scaling from " << image_->w
						<< ',' << image_->h << " to " << w << ',' << h << ".\n";

				surf = scale_surface(image_, w, h, false);
			}
		}
		src_clip.w = w;
		src_clip.h = h;
	} else {
		surf = image_;
	}

	if(vertical_mirror_(local_variables)) {
		surf = flip_surface(surf, false);
	}

	blit_surface(surf, &src_clip, canvas, &dst_clip);
}
示例#3
0
 void add( mutable_variant_object& vo, const char* name, const optional<M>& v )const
 { 
    if( v.valid() )
       vo(name, variant( *v, _max_depth ));
 }
static QVariant getVariantFromDBusMessage(DBusMessageIter *iter)
{
    dbus_bool_t bool_data;
    dbus_int32_t int32_data;
    dbus_uint32_t uint32_data;
    dbus_int64_t int64_data;
    dbus_uint64_t uint64_data;
    char *str_data;
    char char_data;
    int argtype = dbus_message_iter_get_arg_type(iter);

    switch (argtype) {
    case DBUS_TYPE_BOOLEAN: {
        dbus_message_iter_get_basic(iter, &bool_data);
        QVariant variant((bool)bool_data);
        return variant;
    }
    case DBUS_TYPE_ARRAY: {
        // Handle all arrays here
        int elem_type = dbus_message_iter_get_element_type(iter);
        DBusMessageIter array_iter;

        dbus_message_iter_recurse(iter, &array_iter);

        if (elem_type == DBUS_TYPE_BYTE) {
            QByteArray byte_array;
            do {
                dbus_message_iter_get_basic(&array_iter, &char_data);
                byte_array.append(char_data);
            } while (dbus_message_iter_next(&array_iter));
            QVariant variant(byte_array);
            return variant;
        } else if (elem_type == DBUS_TYPE_STRING) {
            QStringList str_list;
            do {
                dbus_message_iter_get_basic(&array_iter, &str_data);
                str_list.append(str_data);
            } while (dbus_message_iter_next(&array_iter));
            QVariant variant(str_list);
            return variant;
        } else {
            QVariantList variantList;
            do {
                variantList << getVariantFromDBusMessage(&array_iter);
            } while (dbus_message_iter_next(&array_iter));
            QVariant variant(variantList);
            return variant;
        }
        break;
    }
    case DBUS_TYPE_BYTE: {
        dbus_message_iter_get_basic(iter, &char_data);
        QChar ch(char_data);
        QVariant variant(ch);
        return variant;
    }
    case DBUS_TYPE_INT32: {
        dbus_message_iter_get_basic(iter, &int32_data);
        QVariant variant((int)int32_data);
        return variant;
    }
    case DBUS_TYPE_UINT32: {
        dbus_message_iter_get_basic(iter, &uint32_data);
        QVariant variant((uint)uint32_data);
        return variant;
    }
    case DBUS_TYPE_OBJECT_PATH:
    case DBUS_TYPE_STRING: {
        dbus_message_iter_get_basic(iter, &str_data);
        QString str(str_data);
        QVariant variant(str);
        return variant;
    }
    case DBUS_TYPE_INT64: {
        dbus_message_iter_get_basic(iter, &int64_data);
        QVariant variant((qlonglong)int64_data);
        return variant;
    }
    case DBUS_TYPE_UINT64: {
        dbus_message_iter_get_basic(iter, &uint64_data);
        QVariant variant((qulonglong)uint64_data);
        return variant;
    }
    case DBUS_TYPE_DICT_ENTRY:
    case DBUS_TYPE_STRUCT: {
        // Handle all structs here
        DBusMessageIter struct_iter;
        dbus_message_iter_recurse(iter, &struct_iter);

        QVariantList variantList;
        do {
            variantList << getVariantFromDBusMessage(&struct_iter);
        } while (dbus_message_iter_next(&struct_iter));
        QVariant variant(variantList);
        return variant;
    }
    case DBUS_TYPE_VARIANT: {
        DBusMessageIter variant_iter;
        dbus_message_iter_recurse(iter, &variant_iter);

        return getVariantFromDBusMessage(&variant_iter);
    }
    case DBUS_TYPE_UNIX_FD: {
        dbus_message_iter_get_basic(iter, &uint32_data);
        QVariant variant((uint)uint32_data);
        return variant;
    }

    default:
        qWarning("Unsupported DBUS type: %d\n", argtype);
    }

    return QVariant();
}
示例#5
0
	std::set<std::string> already_known;
	game_logic::formula_object::visit_variants(obj, boost::bind(add_object_to_set, _1, &objects, &already_known));

	std::vector<variant> results_list;
	foreach(wml_serializable_formula_callable* item, objects) {
		char addr_buf[256];
		sprintf(addr_buf, "%p", item);
		std::string key(addr_buf);
		if(already_known.count(key)) {
			continue;
		}

		results_list.push_back(item->write_to_wml());
	}

	res[variant("character")] = variant(&results_list);

	return variant(&res);
}

namespace {
std::map<intptr_t, wml_serializable_formula_callable_ptr> registered_objects;
}

void wml_formula_callable_read_scope::register_serialized_object(intptr_t addr, wml_serializable_formula_callable_ptr ptr)
{
	//fprintf(stderr, "REGISTER SERIALIZED: 0x%x\n", (int)addr);
	registered_objects[addr] = ptr;
}

wml_serializable_formula_callable_ptr wml_formula_callable_read_scope::get_serialized_object(intptr_t addr)
custom_object_callable::custom_object_callable(bool is_singleton)
{
	if(is_singleton) {
		instance_ptr = this;
		set_type_name("custom_obj");
	}

	//make sure 'library' is initialized as a valid type.
	game_logic::get_library_definition();

	static const Property CustomObjectProperties[] = {
	{ "value", "any" },
	{ "_data", "any" },
	{ "arg", "object" },
	{ "consts", "any" },
	{ "type", "string" },
	{ "active", "any" },
	{ "lib", "library" },

	{ "time_in_animation", "int" },
	{ "time_in_animation_delta", "int" },
	{ "frame_in_animation", "int" },
	{ "level", "any" },

	{ "animation", "string/string|map" },
	{ "available_animations", "[string]" },

	{ "hitpoints", "int" },
	{ "max_hitpoints", "int" },
	{ "mass", "int" },
	{ "label", "string" },
	{ "x", "int/int|decimal" },
	{ "y", "int/int|decimal" },
	{ "xy", "[int]" },
	{ "z", "int" },

	{ "relative_x", "int/int|decimal" },
	{ "relative_y", "int/int|decimal" },
	{ "spawned_by", "null|custom_obj" },
	{ "spawned_children", "[custom_obj]" },

	{ "parent", "null|custom_obj" },
	{ "pivot", "string" },
	{ "zorder", "int" },
	{ "zsub_order", "int" },

	{ "previous_y", "int" },
	{ "x1", "int/int|decimal" },
	{ "x2", "int/int|decimal" },
	{ "y1", "int/int|decimal" },
	{ "y2", "int/int|decimal" },
	{ "w", "int" },
	{ "h", "int" },
	{ "mid_x", "int/int|decimal" },
	{ "mid_y", "int/int|decimal" },
	{ "mid_xy", "[int]" },
	{ "midpoint_x", "int/int|decimal" },
	{ "midpoint_y", "int/int|decimal" },
	{ "midpoint_xy", "[int]" },

    { "is_solid", "bool" },
	{ "solid_rect", "rect_obj" },
	{ "solid_mid_x", "int" },
	{ "solid_mid_y", "int" },
	{ "solid_mid_xy", "[int]" }, 

	{ "img_mid_x", "int" },
	{ "img_mid_y", "int" },
	{ "img_mid_xy", "int" },
	{ "img_w", "int" },
	{ "img_h", "int" },
	{ "img_wh", "int" },
	{ "front", "int" },
	{ "back", "int" },
	{ "cycle", "int" },
	{ "facing", "int" },
	
	{ "upside_down", "int" },
	{ "up", "int" },
	{ "down", "int" },
	{ "velocity_x", "int/int|decimal" },
	{ "velocity_y", "int/int|decimal" },
	{ "velocity_xy", "[int]" }, 

	{ "velocity_magnitude", "decimal" },
	{ "velocity_angle", "decimal" },

	{ "accel_x", "int/int|decimal" },
	{ "accel_y", "int/int|decimal" },
	{ "accel_xy", "[int]" },
	{ "gravity_shift", "int" },
	{ "platform_motion_x", "int" },

	{ "registry", "object" },
	{ "globals", "object" },
	{ "vars", "object" },
	{ "tmp", "object" },
	{ "group", "int" },

	{ "rotate", "decimal" },
	{ "rotate_x", "decimal" },
	{ "rotate_y", "decimal" },
	{ "rotate_z", "decimal" },

	{ "me", "any" },
	{ "self", "any" },

	{ "red", "int" },
	{ "green", "int" },
	{ "blue", "int" },
	{ "alpha", "int" },
	{ "text_alpha", "int" },
	{ "damage", "int" },
	{ "hit_by", "null|custom_obj" },

	{ "distortion", "null|object" },
	{ "is_standing", "bool" },
	{ "standing_info", "null|object" },
	
	{ "near_cliff_edge", "bool" },
	{ "distance_to_cliff", "int" },
	
	{ "slope_standing_on", "int" },
	{ "underwater", "bool" },
	
	{ "previous_water_bounds", "[int]" },
	{ "water_bounds", "null|[int]" },
	{ "water_object", "null|custom_obj" },
	
	{ "driver", "null|custom_obj" },
	{ "is_human", "bool" },
	{ "invincible", "int" },
	
	{ "sound_volume", "int" },
	{ "destroyed", "bool" },
	{ "is_standing_on_platform", "null|bool|custom_obj" },
	{ "standing_on", "null|custom_obj" },
	
	{ "shader", "null|shader_program" },
	{ "effects", "[shader_program]" },
	{ "variations", "[string]" },
	
	{ "attached_objects", "[custom_obj]" },
	{ "call_stack", "[string]" },
	{ "lights", "[object]" },
	
	{ "solid_dimensions_in", "[string]" },
	{ "solid_dimensions_not_in", "[string]" },
	
	{ "collide_dimensions_in", "[string]" },
	{ "collide_dimensions_not_in", "[string]" },
	
	{ "brightness", "int" },
	{ "current_generator", "object" },
	{ "tags", "object" },
	{ "draw_area", "any" },
	{ "scale", "decimal" },
	
	{ "activation_area", "null|[int|decimal]" },
	{ "clip_area", "null|[int]" },

	{ "always_active", "bool" },
	{ "activation_border", "int/int|decimal" },
	{ "fall_through_platforms", "any" },
	{ "has_feet", "bool" },
	
	{ "x_schedule", "any" },
	{ "y_schedule", "any" },
	{ "rotation_schedule", "any" },
	{ "schedule_speed", "any" },
	
	{ "schedule_expires", "any" },
	
	{ "platform_area", "null|[int]" },
	{ "platform_offsets", "[int]" },
	{ "custom_draw", "list" },
	
	{ "uv_array", "[decimal]" },
	{ "xy_array", "[decimal]" },
	{ "uv_segments", "[int]" },
	
	{ "draw_primitives", "[object]/[object|map]|map" },
	{ "event_handlers", "object" },
	
	{ "use_absolute_screen_coordinates", "bool" },
	
	{ "widgets", "object/[object|map]|object|map" },
	{ "widget_list", "[widget]" },
	{ "textv", "any" },
	{ "body", "any" },
	{ "paused", "bool" },
	{ "mouseover_delay", "int" },
	{ "mouseover_area", "[int]" },
	{ "particle_systems", "{string -> object}" },

	{ "truez", "bool" },
	{ "tx", "decimal" },
	{ "ty", "decimal" },
	{ "tz", "decimal" },

	{ "animated_movements", "[string]" },

	{ "ctrl_user_output", "any" },
	
	{ "ctrl_up", "bool" },
	{ "ctrl_down", "bool" },
	{ "ctrl_left", "bool" },
	{ "ctrl_right", "bool" },
	
	{ "ctrl_attack", "bool" },
	{ "ctrl_jump", "bool" },
	{ "ctrl_tongue", "bool" },
	{ "ctrl_user", "any" },

	//player-specific
	{ "difficulty", "int" },
	{ "can_interact", "bool" },
	{ "underwater_controls", "bool" },
	{ "ctrl_mod_key", "int" },
	{ "ctrl_keys", "[string]" },
	{ "ctrl_mice", "[[int|string]]" },
	{ "ctrl_tilt", "int" },
	{ "ctrl_x", "int" },
	{ "ctrl_y", "int" },
	{ "ctrl_reverse_ab", "bool" },
	{ "control_scheme", "string" },
	{ "vertical_look", "int" },
	{ "control_lock", "null|[string]" },
};
	ASSERT_EQ(NUM_CUSTOM_OBJECT_PROPERTIES, sizeof(CustomObjectProperties)/sizeof(*CustomObjectProperties));

	if(global_entries().empty()) {
		for(int n = 0; n != sizeof(CustomObjectProperties)/sizeof(*CustomObjectProperties); ++n) {
			global_entries().push_back(entry(CustomObjectProperties[n].id));

			const std::string& type = CustomObjectProperties[n].type;
			std::string::const_iterator itor = std::find(type.begin(), type.end(), '/');
			std::string read_type(type.begin(), itor);
			global_entries().back().set_variant_type(parse_variant_type(variant(read_type)));

			if(itor != type.end()) {
				global_entries().back().write_type = parse_variant_type(variant(std::string(itor+1, type.end())));
			}
		}

		for(int n = 0; n != global_entries().size(); ++n) {
			keys_to_slots()[global_entries()[n].id] = n;
		}

		global_entries()[CUSTOM_OBJECT_ME].set_variant_type(variant_type::get_custom_object());
		global_entries()[CUSTOM_OBJECT_SELF].set_variant_type(variant_type::get_custom_object());

		const variant_type_ptr builtin = variant_type::get_builtin("level");
		global_entries()[CUSTOM_OBJECT_LEVEL].set_variant_type(builtin);
	}

	global_entries()[CUSTOM_OBJECT_PARENT].type_definition = is_singleton ? this : &instance();
	global_entries()[CUSTOM_OBJECT_LIB].type_definition = game_logic::get_library_definition().get();

	entries_ = global_entries();
}
示例#7
0
void tgame_save_oos::pre_show(CVideo& /*video*/, twindow& window)
{
	window.set_canvas_variable("border", variant("default-border"));
}
示例#8
0
 variant execute(const game_logic::formula_callable& variables) const {
     const std::string key = args()[0]->evaluate(variables).as_string();
     return variant(hex_object::get_hex_tile(key).get());
 }
示例#9
0
widget_settings_dialog* widget::settings_dialog(int x, int y, int w, int h)
{
	return new widget_settings_dialog(x,y,w,h,this);
}

dialog_ptr widget::get_settings_dialog(int x, int y, int w, int h)
{

	return settings_dialog(x,y,w,h);
}

BEGIN_DEFINE_CALLABLE_NOBASE(widget)

DEFINE_FIELD(draw_area, "[int]")
	std::vector<variant> v;
	v.push_back(variant(obj.x_));
	v.push_back(variant(obj.y_));
	v.push_back(variant(obj.w_));
	v.push_back(variant(obj.h_));
	return variant(&v);
DEFINE_SET_FIELD
	std::vector<int> r = value.as_list_int();
	ASSERT_LOG(r.size() == 4, "Four values must be supplied to the draw_area attribute");
	obj.set_loc(r[0], r[1]);
	obj.set_dim(r[2], r[3]);

DEFINE_FIELD(rect, "[int]")
	std::vector<variant> v;
	v.push_back(variant(obj.x_));
	v.push_back(variant(obj.y_));
	v.push_back(variant(obj.w_));
示例#10
0
void SmoothNode::onContextFrame( qint64 pTimeStamp )
{
	if( pTimeStamp < mLastTime )
	{
		mLastTime = pTimeStamp;
	}

	const qreal		IncVal = variant( mPinIncSpeed ).toReal();
	const qreal		DecVal = variant( mPinDecSpeed ).toReal();

	for( fugio::NodeInterface::UuidPair UP : mNode->pairedPins() )
	{
		QSharedPointer<fugio::PinInterface> SrcPin = mNode->findPinByLocalId( UP.first );
		QSharedPointer<fugio::PinInterface> DstPin = mNode->findPinByLocalId( UP.second );

		if( !SrcPin || !DstPin || !DstPin->hasControl() )
		{
			continue;
		}

		fugio::VariantInterface			*DstVar = qobject_cast<fugio::VariantInterface *>( DstPin->control()->qobject() );

		qreal		CurVal = variant( SrcPin ).toReal();
		qreal		OutVal = DstVar->variant().toReal();

		if( CurVal == OutVal )
		{
			continue;
		}

		qreal		AddVal = 0;

		AddVal = qreal( pTimeStamp - mLastTime ) / 1000.0;

		if( CurVal > OutVal )
		{
			AddVal *= IncVal;

			if( OutVal + AddVal > CurVal )
			{
				AddVal = CurVal - OutVal;
			}
		}
		else
		{
			AddVal *= -DecVal;

			if( OutVal + AddVal < CurVal )
			{
				AddVal = CurVal - OutVal;
			}
		}

		qreal		NewVal = OutVal + AddVal;

		if( DstVar->variant().toReal() != NewVal )
		{
			DstVar->setVariant( OutVal + AddVal );

			pinUpdated( DstPin );
		}
	}

	mLastTime = pTimeStamp;
}
示例#11
0
Variant Object::o_set(CStrRef propName, RefResult val,
                      CStrRef context /* = null_string */) {
  return o_setRef(propName, variant(val), context);
}
	variant query_value(const std::string& key) const {
		if(has_self_ && key == "self") {
			return variant(this);
		}
		return get_value(key);
	}
示例#13
0
文件: json.hpp 项目: bitshares/fc
 static void save_to_file( const T& v, const std::string& p, bool pretty = true, output_formatting format = stringify_large_ints_and_doubles, uint32_t max_depth = DEFAULT_MAX_RECURSION_DEPTH )
 {
    save_to_file( variant(v, max_depth), fc::path(p), pretty, format, max_depth );
 } 
示例#14
0
文件: json.hpp 项目: bitshares/fc
 static string   to_pretty_string( const T& v, output_formatting format = stringify_large_ints_and_doubles, uint32_t max_depth = DEFAULT_MAX_RECURSION_DEPTH )
 {
    return to_pretty_string( variant(v, max_depth), format, max_depth );
 }
示例#15
0
   variant number_from_stream( T& in )
   {
      fc::stringstream ss;

      bool  dot = false;
      bool  neg = false;
      if( in.peek() == '-')
      {
        neg = true;
        ss.put( in.get() );
      }
      bool done = false;

      try
      {
        char c;
        while((c = in.peek()) && !done)
        {

          switch( c )
          {
              case '.':
                 if (dot)
                    FC_THROW_EXCEPTION(parse_error_exception, "Can't parse a number with two decimal places");
                 dot = true;
              case '0':
              case '1':
              case '2':
              case '3':
              case '4':
              case '5':
              case '6':
              case '7':
              case '8':
              case '9':
                 ss.put( in.get() );
                 break;
              default:
                 if( isalnum( c ) )
                 {
                    return ss.str() + stringFromToken( in );
                 }
                done = true;
                break;
          }
        }
      }
      catch (fc::eof_exception&)
      {
      }
      catch (const std::ios_base::failure&)
      {
      }
      fc::string str = ss.str();
      if (str == "-." || str == ".") // check the obviously wrong things we could have encountered
        FC_THROW_EXCEPTION(parse_error_exception, "Can't parse token \"${token}\" as a JSON numeric constant", ("token", str));
      if( dot )
        return parser_type == json::legacy_parser_with_string_doubles ? variant(str) : variant(to_double(str));
      if( neg )
        return to_int64(str);
      return to_uint64(str);
   }
示例#16
0
 variant wallet_db::get_property( property_enum property_id )const
 {
    auto property_itr = properties.find( property_id );
    if( property_itr != properties.end() ) return property_itr->second.value;
    return variant();
 }
示例#17
0
   variant token_from_stream( T& in )
   {
      std::stringstream ss;
      ss.exceptions( std::ifstream::badbit );
      bool received_eof = false;
      bool done = false;

      try
      {
        char c;
        while((c = in.peek()) && !done)
        {
           switch( c )
           {
              case 'n':
              case 'u':
              case 'l':
              case 't':
              case 'r':
              case 'e':
              case 'f':
              case 'a':
              case 's':
                 ss.put( in.get() );
                 break;
              default:
                 done = true;
                 break;
           }
        }
      }
      catch (fc::eof_exception&)
      {
        received_eof = true;
      }
      catch (const std::ios_base::failure&)
      {
        received_eof = true;
      }

      // we can get here either by processing a delimiter as in "null,"
      // an EOF like "null<EOF>", or an invalid token like "nullZ"
      fc::string str = ss.str();
      if( str == "null" )
        return variant();
      if( str == "true" )
        return true;
      if( str == "false" ) 
        return false;
      else
      {
        if (received_eof)
        {
          if (str.empty())
            FC_THROW_EXCEPTION( parse_error_exception, "Unexpected EOF" );
          else
            return str;
        }
        else
        {
          // if we've reached this point, we've either seen a partial
          // token ("tru<EOF>") or something our simple parser couldn't
          // make out ("falfe")
          // A strict JSON parser would signal this as an error, but we
          // will just treat the malformed token as an un-quoted string.
          return str + stringFromToken(in);;
        }
      }
   }
示例#18
0
	FOREACH(AUTO & tmp, canvas())
	{
		tmp.set_variable("positioner_offset", variant(positioner_offset_));
		tmp.set_variable("positioner_length", variant(positioner_length_));
	}
示例#19
0
CallLinkStatus CallLinkStatus::computeFromCallLinkInfo(
    const ConcurrentJITLocker&, CallLinkInfo& callLinkInfo)
{
    if (callLinkInfo.clearedByGC())
        return takesSlowPath();
    
    // Note that despite requiring that the locker is held, this code is racy with respect
    // to the CallLinkInfo: it may get cleared while this code runs! This is because
    // CallLinkInfo::unlink() may be called from a different CodeBlock than the one that owns
    // the CallLinkInfo and currently we save space by not having CallLinkInfos know who owns
    // them. So, there is no way for either the caller of CallLinkInfo::unlock() or unlock()
    // itself to figure out which lock to lock.
    //
    // Fortunately, that doesn't matter. The only things we ask of CallLinkInfo - the slow
    // path count, the stub, and the target - can all be asked racily. Stubs and targets can
    // only be deleted at next GC, so if we load a non-null one, then it must contain data
    // that is still marginally valid (i.e. the pointers ain't stale). This kind of raciness
    // is probably OK for now.
    
    // PolymorphicCallStubRoutine is a GCAwareJITStubRoutine, so if non-null, it will stay alive
    // until next GC even if the CallLinkInfo is concurrently cleared. Also, the variants list is
    // never mutated after the PolymorphicCallStubRoutine is instantiated. We have some conservative
    // fencing in place to make sure that we see the variants list after construction.
    if (PolymorphicCallStubRoutine* stub = callLinkInfo.stub()) {
        WTF::loadLoadFence();
        
        CallEdgeList edges = stub->edges();
        
        // Now that we've loaded the edges list, there are no further concurrency concerns. We will
        // just manipulate and prune this list to our liking - mostly removing entries that are too
        // infrequent and ensuring that it's sorted in descending order of frequency.
        
        RELEASE_ASSERT(edges.size());
        
        std::sort(
            edges.begin(), edges.end(),
            [] (CallEdge a, CallEdge b) {
                return a.count() > b.count();
            });
        RELEASE_ASSERT(edges.first().count() >= edges.last().count());
        
        double totalCallsToKnown = 0;
        double totalCallsToUnknown = callLinkInfo.slowPathCount();
        CallVariantList variants;
        for (size_t i = 0; i < edges.size(); ++i) {
            CallEdge edge = edges[i];
            // If the call is at the tail of the distribution, then we don't optimize it and we
            // treat it as if it was a call to something unknown. We define the tail as being either
            // a call that doesn't belong to the N most frequent callees (N =
            // maxPolymorphicCallVariantsForInlining) or that has a total call count that is too
            // small.
            if (i >= Options::maxPolymorphicCallVariantsForInlining()
                || edge.count() < Options::frequentCallThreshold())
                totalCallsToUnknown += edge.count();
            else {
                totalCallsToKnown += edge.count();
                variants.append(edge.callee());
            }
        }
        
        // Bail if we didn't find any calls that qualified.
        RELEASE_ASSERT(!!totalCallsToKnown == !!variants.size());
        if (variants.isEmpty())
            return takesSlowPath();
        
        // We require that the distribution of callees is skewed towards a handful of common ones.
        if (totalCallsToKnown / totalCallsToUnknown < Options::minimumCallToKnownRate())
            return takesSlowPath();
        
        RELEASE_ASSERT(totalCallsToKnown);
        RELEASE_ASSERT(variants.size());
        
        CallLinkStatus result;
        result.m_variants = variants;
        result.m_couldTakeSlowPath = !!totalCallsToUnknown;
        return result;
    }
    
    CallLinkStatus result;
    
    if (JSFunction* target = callLinkInfo.lastSeenCallee()) {
        CallVariant variant(target);
        if (callLinkInfo.hasSeenClosure())
            variant = variant.despecifiedClosure();
        result.m_variants.append(variant);
    }
    
    result.m_couldTakeSlowPath = !!callLinkInfo.slowPathCount();

    return result;
}
示例#20
0
 void  chain_interface::set_accumulated_fees( share_type fees )
 {
    set_property( accumulated_fees, variant(fees) );
 }
示例#21
0
variant texture_object::get_value(const std::string& key) const
{
	return variant();
}
示例#22
0
 void  chain_interface::set_fee_rate( share_type fees )
 {
    set_property( current_fee_rate, variant(fees) );
 }
示例#23
0
GetByIdStatus GetByIdStatus::computeForStubInfo(
    const ConcurrentJITLocker& locker, CodeBlock* profiledBlock, StructureStubInfo* stubInfo, StringImpl* uid,
    CallLinkStatus::ExitSiteData callExitSiteData)
{
    if (!stubInfo || !stubInfo->seen)
        return GetByIdStatus(NoInformation);
    
    PolymorphicGetByIdList* list = 0;
    State slowPathState = TakesSlowPath;
    if (stubInfo->accessType == access_get_by_id_list) {
        list = stubInfo->u.getByIdList.list;
        for (unsigned i = 0; i < list->size(); ++i) {
            const GetByIdAccess& access = list->at(i);
            if (access.doesCalls())
                slowPathState = MakesCalls;
        }
    }
    
    // Finally figure out if we can derive an access strategy.
    GetByIdStatus result;
    result.m_state = Simple;
    result.m_wasSeenInJIT = true; // This is interesting for bytecode dumping only.
    switch (stubInfo->accessType) {
    case access_unset:
        return GetByIdStatus(NoInformation);
        
    case access_get_by_id_self: {
        Structure* structure = stubInfo->u.getByIdSelf.baseObjectStructure.get();
        if (structure->takesSlowPathInDFGForImpureProperty())
            return GetByIdStatus(slowPathState, true);
        unsigned attributesIgnored;
        GetByIdVariant variant;
        variant.m_offset = structure->getConcurrently(uid, attributesIgnored);
        if (!isValidOffset(variant.m_offset))
            return GetByIdStatus(slowPathState, true);
        
        variant.m_structureSet.add(structure);
        bool didAppend = result.appendVariant(variant);
        ASSERT_UNUSED(didAppend, didAppend);
        return result;
    }
        
    case access_get_by_id_list: {
        for (unsigned listIndex = 0; listIndex < list->size(); ++listIndex) {
            Structure* structure = list->at(listIndex).structure();
            
            ComplexGetStatus complexGetStatus = ComplexGetStatus::computeFor(
                profiledBlock, structure, list->at(listIndex).chain(),
                list->at(listIndex).chainCount(), uid);
             
            switch (complexGetStatus.kind()) {
            case ComplexGetStatus::ShouldSkip:
                continue;
                 
            case ComplexGetStatus::TakesSlowPath:
                return GetByIdStatus(slowPathState, true);
                 
            case ComplexGetStatus::Inlineable: {
                std::unique_ptr<CallLinkStatus> callLinkStatus;
                switch (list->at(listIndex).type()) {
                case GetByIdAccess::SimpleInline:
                case GetByIdAccess::SimpleStub: {
                    break;
                }
                case GetByIdAccess::Getter: {
                    AccessorCallJITStubRoutine* stub = static_cast<AccessorCallJITStubRoutine*>(
                        list->at(listIndex).stubRoutine());
                    callLinkStatus = std::make_unique<CallLinkStatus>(
                        CallLinkStatus::computeFor(
                            locker, profiledBlock, *stub->m_callLinkInfo, callExitSiteData));
                    break;
                }
                case GetByIdAccess::CustomGetter:
                case GetByIdAccess::WatchedStub:{
                    // FIXME: It would be totally sweet to support this at some point in the future.
                    // https://bugs.webkit.org/show_bug.cgi?id=133052
                    return GetByIdStatus(slowPathState, true);
                }
                default:
                    RELEASE_ASSERT_NOT_REACHED();
                }
                 
                GetByIdVariant variant(
                    StructureSet(structure), complexGetStatus.offset(), complexGetStatus.chain(),
                    WTF::move(callLinkStatus));
                 
                if (!result.appendVariant(variant))
                    return GetByIdStatus(slowPathState, true);
                break;
            } }
        }
        
        return result;
    }
        
    default:
        return GetByIdStatus(slowPathState, true);
    }
    
    RELEASE_ASSERT_NOT_REACHED();
    return GetByIdStatus();
}
示例#24
0
void tduel::reset_turn(twindow& window)
{
	std::stringstream str;

	str.str("");
	str << "misc/digit-big.png~CROP(" << 30 * (turn_ + 1) << ", 0, 30, 45)";
	find_widget<tcontrol>(&window, "turn", false, false)->set_label(str.str());

	// set up card
	for (int index = 0; index < 2; index ++) {
		setting* t = setting_ + index;
		t->cards_.clear();
		if (!t->deadfight_) {
			t->deadfight_ = (rand() % 16) < t->skill_;
		}
		if (!t->fightback_) {
			t->fightback_ = (rand() % 64) < t->skill_;
		}

		char c = index? 'r': 'l';
		for (int index2 = 4; index2 >= 0; index2 --) {
			str.str("");
			str << c << "card" << index2;
			ttoggle_button* toggle = find_widget<ttoggle_button>(&window, str.str(), false, false);
			if (t->count_ <= index2) {
				toggle->set_visible(twidget::INVISIBLE);
				continue;
			}
			if (index == 1) {
				toggle->set_active(false);
			}

			int type = rand() % nb_items;
			int point = t->min_point_ + rand() % (t->max_point_ - t->min_point_ + 1);
			t->cards_.insert(std::pair<int, int>(type, point));
		}
		int index2 = 0;
		for (std::multimap<int, int>::const_iterator c_itor = t->cards_.begin(); c_itor != t->cards_.end(); ++ c_itor, index2 ++) {
			str.str("");
			str << c << "card" << index2;
			ttoggle_button* toggle = find_widget<ttoggle_button>(&window, str.str(), false, false);
			if (index == 0) {
				connect_signal_mouse_left_click(
					 *toggle
					, boost::bind(
					  &tduel::on_card
					, this
					, boost::ref(window)
					, index2));
			}
			for (int i = 0; i < 6; i ++) {
				toggle->canvas()[i].set_variable("foreground", variant(menu_items[c_itor->first]));
			}
			str.str("");
			str << c_itor->second;
			toggle->set_label(str.str());
			// reset lcard/rcard.
			toggle->set_value(false);
			toggle->set_dirty();
		}

		// total card
		str.str("");
		str << c << "total";
		ttoggle_button* toggle = find_widget<ttoggle_button>(&window, str.str(), false, false);
		for (int i = 0; i < 6; i ++) {
			toggle->canvas()[i].set_variable("foreground", variant(""));
		}
		toggle->set_label("0");
		toggle->set_active(false);

		// skill
		str.str("");
		str << c << "skill";
		find_widget<tcontrol>(&window, str.str(), false, false)->set_label("");

		// deadfight
		str.str("");
		str << c << "skill0";
		toggle = find_widget<ttoggle_button>(&window, str.str(), false, false);
		toggle->set_value(false);
		for (int i = 0; i < 6; i ++) {
			if (t->deadfight_) {
				toggle->canvas()[i].set_variable("image", variant("misc/deadfight.png"));
			} else {
				toggle->canvas()[i].set_variable("image", variant(""));
			}
		}
		if (index == 0) {
			toggle->set_active(t->deadfight_);
		} else {
			toggle->set_active(false);
		}

		// fightback
		str.str("");
		str << c << "skill1";
		toggle = find_widget<ttoggle_button>(&window, str.str(), false, false);
		toggle->set_value(false);
		for (int i = 0; i < 6; i ++) {
			if (t->fightback_) {
				toggle->canvas()[i].set_variable("image", variant("misc/fightback.png"));
			} else {
				toggle->canvas()[i].set_variable("image", variant(""));
			}
		}
		if (index == 0) {
			toggle->set_active(t->fightback_);
		} else {
			toggle->set_active(false);
		}
	}
	endturn_->set_active(false);
}
示例#25
0
 void to_variant( const mutable_variant_object& var,  variant& vo )
 {
    vo = variant(var);
 }
示例#26
0
void tduel::pre_show(CVideo& /*video*/, twindow& window)
{
	// Override the user value, to make sure it's set properly.
	window.set_click_dismiss(false);

	// ***** ***** ***** ***** Set up the widgets ***** ***** ***** *****
	window.canvas(1).set_variable("left_image", variant(left_.image(true)));
	window.canvas(1).set_variable("right_image", variant(right_.image(true)));
	window.canvas(1).set_variable("center_image", variant(""));
	
	window.canvas(1).set_variable("hp_left", variant("misc/hp-blue.png"));
	window.canvas(1).set_variable("hp_right", variant("misc/hp-red.png"));
	window.canvas(1).set_variable("percentage", variant((hp_ * 100) / TOTAL_HP));

	std::stringstream str;

	tbutton* b = find_widget<tbutton>(&window, "endturn", false, false);
	for (int i = 0; i < 4; i ++) {
		b->canvas()[i].set_variable("image", variant("misc/ok.png"));
	}

	find_widget<tcontrol>(&window, "lname", false, false)->set_label(left_.name());
	find_widget<tcontrol>(&window, "rname", false, false)->set_label(right_.name());

	tcontrol* control = find_widget<tcontrol>(&window, "lforce", false, false);
	str.str("");
	str << setting_[0].force_ << "(" << hero::adaptability_str2(left_.skill_[hero_skill_hero]).c_str() << ")";
	control->set_label(str.str());

	control = find_widget<tcontrol>(&window, "rforce", false, false);
	str.str("");
	str << setting_[1].force_ << "(" << hero::adaptability_str2(right_.skill_[hero_skill_hero]).c_str() << ")";;
	control->set_label(str.str());

	endturn_ = find_widget<tbutton>(&window, "endturn", false, false);
	connect_signal_mouse_left_click(
		*endturn_
		, boost::bind(
			&tduel::end_turn
			, this
			, boost::ref(window)));
	endturn_->set_sound_button_click("hatchet.wav");
	
	lskill0_ = find_widget<ttoggle_button>(&window, "lskill0", false, false);
	connect_signal_mouse_left_click(
		 *lskill0_
		, boost::bind(
		  &tduel::on_deadfight
		, this
		, boost::ref(window)));

	lskill1_ = find_widget<ttoggle_button>(&window, "lskill1", false, false);
	connect_signal_mouse_left_click(
		 *lskill1_
		, boost::bind(
		  &tduel::on_fightback
		, this
		, boost::ref(window)));
	
	find_widget<ttoggle_button>(&window, "lturn0", false, false)->set_visible(twidget::INVISIBLE);
	find_widget<ttoggle_button>(&window, "lturn0_skill", false, false)->set_visible(twidget::INVISIBLE);
	find_widget<tlabel>(&window, "turn0", false, false)->set_visible(twidget::INVISIBLE);
	find_widget<ttoggle_button>(&window, "rturn0", false, false)->set_visible(twidget::INVISIBLE);
	find_widget<ttoggle_button>(&window, "rturn0_skill", false, false)->set_visible(twidget::INVISIBLE);
	find_widget<ttoggle_button>(&window, "lturn1", false, false)->set_visible(twidget::INVISIBLE);
	find_widget<ttoggle_button>(&window, "lturn1_skill", false, false)->set_visible(twidget::INVISIBLE);
	find_widget<tlabel>(&window, "turn1", false, false)->set_visible(twidget::INVISIBLE);
	find_widget<ttoggle_button>(&window, "rturn1", false, false)->set_visible(twidget::INVISIBLE);
	find_widget<ttoggle_button>(&window, "rturn1_skill", false, false)->set_visible(twidget::INVISIBLE);
	find_widget<ttoggle_button>(&window, "lturn2", false, false)->set_visible(twidget::INVISIBLE);
	find_widget<ttoggle_button>(&window, "lturn2_skill", false, false)->set_visible(twidget::INVISIBLE);
	find_widget<tlabel>(&window, "turn2", false, false)->set_visible(twidget::INVISIBLE);
	find_widget<ttoggle_button>(&window, "rturn2", false, false)->set_visible(twidget::INVISIBLE);
	find_widget<ttoggle_button>(&window, "rturn2_skill", false, false)->set_visible(twidget::INVISIBLE);
	find_widget<ttoggle_button>(&window, "lturn3", false, false)->set_visible(twidget::INVISIBLE);
	find_widget<ttoggle_button>(&window, "lturn3_skill", false, false)->set_visible(twidget::INVISIBLE);
	find_widget<tlabel>(&window, "turn3", false, false)->set_visible(twidget::INVISIBLE);
	find_widget<ttoggle_button>(&window, "rturn3", false, false)->set_visible(twidget::INVISIBLE);
	find_widget<ttoggle_button>(&window, "rturn3_skill", false, false)->set_visible(twidget::INVISIBLE);
	find_widget<ttoggle_button>(&window, "lturn4", false, false)->set_visible(twidget::INVISIBLE);
	find_widget<ttoggle_button>(&window, "lturn4_skill", false, false)->set_visible(twidget::INVISIBLE);
	find_widget<tlabel>(&window, "turn4", false, false)->set_visible(twidget::INVISIBLE);
	find_widget<ttoggle_button>(&window, "rturn4", false, false)->set_visible(twidget::INVISIBLE);
	find_widget<ttoggle_button>(&window, "rturn4_skill", false, false)->set_visible(twidget::INVISIBLE);

	reset_turn(window);
}
示例#27
0
void ttext::draw(surface& canvas
		, const game_logic::map_formula_callable& variables)
{
	assert(variables.has_key("text"));

	// We first need to determine the size of the text which need the rendered
	// text. So resolve and render the text first and then start to resolve
	// the other formulas.
	const t_string text = text_(variables); // Björn: Add text to canvas labels here

	if(text.empty()) {
		DBG_GUI_D << "Text: no text to render, leave.\n";
		return;
	}

	static font::ttext text_renderer;
	text_renderer.set_text(text, text_markup_(variables));

	text_renderer.set_font_size(font_size_)
			.set_font_style(font_style_)
			.set_alignment(text_alignment_(variables))
			.set_foreground_color(color_)
			.set_maximum_width(maximum_width_(variables))
			.set_maximum_height(maximum_height_(variables))
			.set_ellipse_mode(variables.has_key("text_wrap_mode")
				? static_cast<PangoEllipsizeMode>
					(variables.query_value("text_wrap_mode").as_int())
				: PANGO_ELLIPSIZE_END);

	surface surf = text_renderer.render();
	if(surf->w == 0) {
		DBG_GUI_D  << "Text: Rendering '"
				<< text << "' resulted in an empty canvas, leave.\n";
		return;
	}

	game_logic::map_formula_callable local_variables(variables);
	local_variables.add("text_width", variant(surf->w));
	local_variables.add("text_height", variant(surf->h));
/*
	std::cerr << "Text: drawing text '" << text
		<< " maximum width " << maximum_width_(variables)
		<< " maximum height " << maximum_height_(variables)
		<< " text width " << surf->w
		<< " text height " << surf->h;
*/
	///@todo formulas are now recalculated every draw cycle which is a
	// bit silly unless there has been a resize. So to optimize we should
	// use an extra flag or do the calculation in a separate routine.

	const unsigned x = x_(local_variables);
	const unsigned y = y_(local_variables);
	const unsigned w = w_(local_variables);
	const unsigned h = h_(local_variables);

	DBG_GUI_D << "Text: drawing text '" << text
			<< "' drawn from " << x << ',' << y
			<< " width " << w << " height " << h
			<< " canvas size " << canvas->w << ',' << canvas->h << ".\n";

	VALIDATE(static_cast<int>(x) < canvas->w && static_cast<int>(y) < canvas->h
			, _("Text doesn't start on canvas."));

	// A text might be to long and will be clipped.
	if(surf->w > static_cast<int>(w)) {
		WRN_GUI_D << "Text: text is too wide for the "
				"canvas and will be clipped.\n";
	}

	if(surf->h > static_cast<int>(h)) {
		WRN_GUI_D << "Text: text is too high for the "
				"canvas and will be clipped.\n";
	}

	SDL_Rect dst = ::create_rect(x, y, canvas->w, canvas->h);
	blit_surface(surf, 0, canvas, &dst);
}
示例#28
0
void OculusRiftNode::render( qint64 pTimeStamp, QUuid pSourcePinId )
{
	Q_UNUSED( pSourcePinId )

#if !defined( OCULUS_PLUGIN_SUPPORTED )
	Q_UNUSED( pTimeStamp )
#else
	fugio::Performance	Perf( mNode, "drawGeometry", pTimeStamp );

	if( !mNode->isInitialised() )
	{
		return;
	}

	if( !mOculusRift->hmd() )
	{
		return;
	}

	// We need to keep a reference to ourselves here as ovr_SubmitFrame can
	// call the main app event loop, which can close the context and delete us!

	QSharedPointer<fugio::NodeControlInterface>	C = mNode->control();

	mOculusRift->drawStart();

	const float		NearPlane = variant( mPinNearPlane ).toFloat();
	const float		FarPlane  = variant( mPinFarPlane ).toFloat();

	//	float Yaw(3.141592f);
	//	Vector3f Pos2(0.0f,1.6f,-5.0f);
	//	Pos2.y = ovrHmd_GetFloat(mHMD, OVR_KEY_EYE_HEIGHT, Pos2.y);

	QMatrix4x4		MatEye = variant( mPinViewMatrix ).value<QMatrix4x4>();
	QVector3D		TrnEye = MatEye.column( 3 ).toVector3D();

	MatEye.setColumn( 3, QVector4D( 0, 0, 0, 1 ) );

	const Vector3f Pos2( TrnEye.x(), TrnEye.y(), TrnEye.z() );

	Matrix4f tempRollPitchYaw;

	memcpy( tempRollPitchYaw.M, MatEye.constData(), sizeof( float ) * 16 );

	const Matrix4f rollPitchYaw = tempRollPitchYaw;

	// Render Scene to Eye Buffers
	for (int eye = 0; eye < 2; eye++)
	{
		mOculusRift->drawEyeStart( eye );

		// Get view and projection matrices
		//Matrix4f rollPitchYaw = Matrix4f( MatEye.transposed().data() );
		Matrix4f finalRollPitchYaw = rollPitchYaw * Matrix4f( mOculusRift->eyeRenderPos( eye ).Orientation);
		Vector3f finalUp = finalRollPitchYaw.Transform(Vector3f(0, 1, 0));
		Vector3f finalForward = finalRollPitchYaw.Transform(Vector3f(0, 0, -1));
		Vector3f shiftedEyePos = Pos2 + rollPitchYaw.Transform( mOculusRift->eyeRenderPos( eye ).Position );

		Matrix4f view = Matrix4f::LookAtRH(shiftedEyePos, shiftedEyePos + finalForward, finalUp);
		Matrix4f proj = ovrMatrix4f_Projection( mOculusRift->defaultEyeFOV( eye ), NearPlane, FarPlane, ovrProjection_None );

		mProjection->setVariant( QMatrix4x4( &proj.M[ 0 ][ 0 ], 4, 4 ).transposed() );

		mView->setVariant( QMatrix4x4( &view.M[ 0 ][ 0 ], 4, 4 ).transposed() );

		fugio::OpenGLStateInterface		*CurrentState = 0;

		for( QSharedPointer<fugio::PinInterface> P : mNode->enumInputPins() )
		{
			if( !P->isConnected() )
			{
				continue;
			}

			if( P->connectedPin().isNull() )
			{
				continue;
			}

			if( P->connectedPin()->control().isNull() )
			{
				continue;
			}

			QObject					*O = P->connectedPin()->control()->qobject();

			if( !O )
			{
				continue;
			}

			if( true )
			{
				fugio::RenderInterface		*Geometry = qobject_cast<fugio::RenderInterface *>( O );

				if( Geometry )
				{
					Geometry->render( pTimeStamp );

					continue;
				}
			}

			if( true )
			{
				fugio::OpenGLStateInterface		*NextState = qobject_cast<fugio::OpenGLStateInterface *>( O );

				if( NextState != 0 )
				{
					if( CurrentState != 0 )
					{
						CurrentState->stateEnd();
					}

					CurrentState = NextState;

					CurrentState->stateBegin();

					continue;
				}
			}
		}

		if( CurrentState != 0 )
		{
			CurrentState->stateEnd();
		}

		mOculusRift->drawEyeEnd( eye );
	}

	mOculusRift->drawEnd();

	pinUpdated( mPinProjection );
	pinUpdated( mPinView );
#endif
}
示例#29
0
 void add( mutable_variant_object& vo, const char* name, const M& v )const
 { vo(name, variant( v, _max_depth )); }
示例#30
0
bool basic_unit_filter_impl::internal_matches_filter(const unit & u, const map_location& loc, const unit* u2) const
{
	if (!vcfg["name"].blank() && vcfg["name"].t_str() != u.name()) {
		return false;
	}

	if (!vcfg["id"].empty()) {
		std::vector<std::string> id_list = utils::split(vcfg["id"]);
		if (std::find(id_list.begin(), id_list.end(), u.id()) == id_list.end()) {
			return false;
		}
	}

	// Allow 'speaker' as an alternative to id, since people use it so often
	if (!vcfg["speaker"].blank() && vcfg["speaker"].str() != u.id()) {
		return false;
	}

	if (vcfg.has_child("filter_location")) {
		if (vcfg.count_children("filter_location") > 1) {
			FAIL("Encountered multiple [filter_location] children of a standard unit filter. "
				 "This is not currently supported and in all versions of wesnoth would have "
				 "resulted in the later children being ignored. You must use [and] or similar "
				 "to achieve the desired result.");
		}
		terrain_filter filt(vcfg.child("filter_location"), &fc_, use_flat_tod_);
		if (!filt.match(loc)) {
			return false;
		}
	}

	if(vcfg.has_child("filter_side")) {
		if (vcfg.count_children("filter_side") > 1) {
			FAIL("Encountered multiple [filter_side] children of a standard unit filter. "
				 "This is not currently supported and in all versions of wesnoth would have "
				 "resulted in the later children being ignored. You must use [and] or similar "
				 "to achieve the desired result.");
		}
		side_filter filt(vcfg.child("filter_side"), &fc_);
		if(!filt.match(u.side()))
			return false;
	}

	// Also allow filtering on location ranges outside of the location filter
	if (!vcfg["x"].blank() || !vcfg["y"].blank()){
		if(vcfg["x"] == "recall" && vcfg["y"] == "recall") {
			//locations on the map are considered to not be on a recall list
			if (fc_.get_disp_context().map().on_board(loc))
			{
				return false;
			}
		} else if(vcfg["x"].empty() && vcfg["y"].empty()) {
			return false;
		} else if(!loc.matches_range(vcfg["x"], vcfg["y"])) {
			return false;
		}
	}

	// The type could be a comma separated list of types
	if (!vcfg["type"].empty()) {
		std::vector<std::string> types = utils::split(vcfg["type"]);
		if (std::find(types.begin(), types.end(), u.type_id()) == types.end()) {
			return false;
		}
	}

	// Shorthand for all advancements of a given type
	if (!vcfg["type_tree"].empty()) {
		std::set<std::string> types;
		for(const std::string type : utils::split(vcfg["type_tree"])) {
			if(types.count(type)) {
				continue;
			}
			if(const unit_type* ut = unit_types.find(type)) {
				const auto& tree = ut->advancement_tree();
				types.insert(tree.begin(), tree.end());
				types.insert(type);
			}
		}
		if(types.find(u.type_id()) == types.end()) {
			return false;
		}
	}

	// The variation_type could be a comma separated list of types
	if (!vcfg["variation"].empty())
	{
		std::vector<std::string> types = utils::split(vcfg["variation"]);
		if (std::find(types.begin(), types.end(), u.variation()) == types.end()) {
			return false;
		}
	}

	// The has_variation_type could be a comma separated list of types
	if (!vcfg["has_variation"].empty())
	{
		bool match = false;
		// If this unit is a variation itself then search in the base unit's variations.
		const unit_type* const type = u.variation().empty() ? &u.type() : unit_types.find(u.type().base_id());
		assert(type);

		for (const std::string& variation_id : utils::split(vcfg["has_variation"])) {
			if (type->has_variation(variation_id)) {
				match = true;
				break;
			}
		}
		if (!match) return false;
	}

	if (!vcfg["ability"].empty())
	{
		bool match = false;

		for (const std::string& ability_id : utils::split(vcfg["ability"])) {
			if (u.has_ability_by_id(ability_id)) {
				match = true;
				break;
			}
		}
		if (!match) return false;
	}

	if (!vcfg["race"].empty()) {
		std::vector<std::string> races = utils::split(vcfg["race"]);
		if (std::find(races.begin(), races.end(), u.race()->id()) == races.end()) {
			return false;
		}
	}

	if (!vcfg["gender"].blank() && string_gender(vcfg["gender"]) != u.gender()) {
		return false;
	}

	if (!vcfg["side"].empty() && vcfg["side"].to_int(-999) != u.side()) {
		std::vector<std::string> sides = utils::split(vcfg["side"]);
		const std::string u_side = std::to_string(u.side());
		if (std::find(sides.begin(), sides.end(), u_side) == sides.end()) {
			return false;
		}
	}

	// handle statuses list
	if (!vcfg["status"].empty()) {
		bool status_found = false;

		for (const std::string status : utils::split(vcfg["status"])) {
			if(u.get_state(status)) {
				status_found = true;
				break;
			}
		}

		if(!status_found) {
			return false;
		}
	}

	if (vcfg.has_child("has_attack")) {
		const vconfig& weap_filter = vcfg.child("has_attack");
		bool has_weapon = false;
		for(const attack_type& a : u.attacks()) {
			if(a.matches_filter(weap_filter.get_parsed_config())) {
				has_weapon = true;
				break;
			}
		}
		if(!has_weapon) {
			return false;
		}
	} else if (!vcfg["has_weapon"].blank()) {
		std::string weapon = vcfg["has_weapon"];
		bool has_weapon = false;
		for(const attack_type& a : u.attacks()) {
			if(a.id() == weapon) {
				has_weapon = true;
				break;
			}
		}
		if(!has_weapon) {
			return false;
		}
	}

	if (!vcfg["role"].blank() && vcfg["role"].str() != u.get_role()) {
		return false;
	}

	if (!vcfg["ai_special"].blank() && ((vcfg["ai_special"].str() == "guardian") != u.get_state(unit::STATE_GUARDIAN))) {
		return false;
	}

	if (!vcfg["canrecruit"].blank() && vcfg["canrecruit"].to_bool() != u.can_recruit()) {
		return false;
	}

	if (!vcfg["recall_cost"].blank() && vcfg["recall_cost"].to_int(-1) != u.recall_cost()) {
		return false;
	}

	if (!vcfg["level"].blank() && vcfg["level"].to_int(-1) != u.level()) {
		return false;
	}

	if (!vcfg["defense"].blank() && vcfg["defense"].to_int(-1) != u.defense_modifier(fc_.get_disp_context().map().get_terrain(loc))) {
		return false;
	}

	if (!vcfg["movement_cost"].blank() && vcfg["movement_cost"].to_int(-1) != u.movement_cost(fc_.get_disp_context().map().get_terrain(loc))) {
		return false;
	}

	// Now start with the new WML based comparison.
	// If a key is in the unit and in the filter, they should match
	// filter only => not for us
	// unit only => not filtered
	config unit_cfg; // No point in serializing the unit once for each [filter_wml]!
	for (const vconfig& wmlcfg : vcfg.get_children("filter_wml")) {
			config fwml = wmlcfg.get_parsed_config();
			/* Check if the filter only cares about variables.
			   If so, no need to serialize the whole unit. */
			config::all_children_itors ci = fwml.all_children_range();
			if (fwml.all_children_count() == 1 && 
				fwml.attribute_count() == 1 &&
			    ci.front().key == "variables") {
				if (!u.variables().matches(ci.front().cfg))
					return false;
			} else {
				if (unit_cfg.empty())
					u.write(unit_cfg);
				if (!unit_cfg.matches(fwml))
					return false;
			}
	}

	for (const vconfig& vision : vcfg.get_children("filter_vision")) {
		std::set<int> viewers;

		// Use standard side filter
		side_filter ssf(vision, &fc_);
		std::vector<int> sides = ssf.get_teams();
		viewers.insert(sides.begin(), sides.end());

		bool found = false;
		for (const int viewer : viewers) {
			bool fogged = fc_.get_disp_context().teams()[viewer - 1].fogged(loc);
			bool hiding = u.invisible(loc, fc_.get_disp_context())
				&& fc_.get_disp_context().teams()[viewer - 1].is_enemy(u.side());
			bool unit_hidden = fogged || hiding;
			if (vision["visible"].to_bool(true) != unit_hidden) {
				found = true;
				break;
			}
		}
		if (!found) {return false;}
	}

	if (vcfg.has_child("filter_adjacent")) {
		const unit_map& units = fc_.get_disp_context().units();
		map_location adjacent[6];
		get_adjacent_tiles(loc, adjacent);

		for (const vconfig& adj_cfg : vcfg.get_children("filter_adjacent")) {
			int match_count=0;
			unit_filter filt(adj_cfg, &fc_, use_flat_tod_);

			config::attribute_value i_adjacent = adj_cfg["adjacent"];
			std::vector<map_location::DIRECTION> dirs;
			if (i_adjacent.blank()) {
				dirs = map_location::default_dirs();
			} else {
				dirs = map_location::parse_directions(i_adjacent);
			}

			std::vector<map_location::DIRECTION>::const_iterator j, j_end = dirs.end();
			for (j = dirs.begin(); j != j_end; ++j) {
				unit_map::const_iterator unit_itor = units.find(adjacent[*j]);
				if (unit_itor == units.end() || !filt(*unit_itor, u)) {
					continue;
				}
				boost::optional<bool> is_enemy;
				if (!adj_cfg["is_enemy"].blank()) {
					is_enemy = adj_cfg["is_enemy"].to_bool();
				}
				if (!is_enemy || *is_enemy ==
				    fc_.get_disp_context().teams()[u.side() - 1].is_enemy(unit_itor->side())) {
					++match_count;
				}
			}

			static std::vector<std::pair<int,int> > default_counts = utils::parse_ranges("1-6");
			config::attribute_value i_count = adj_cfg["count"];
			if(!in_ranges(match_count, !i_count.blank() ? utils::parse_ranges(i_count) : default_counts)) {
				return false;
			}
		}
	}

	if (!vcfg["find_in"].blank()) {
		// Allow filtering by searching a stored variable of units
		if (const game_data * gd = fc_.get_game_data()) {
			try
			{
				variable_access_const vi = gd->get_variable_access_read(vcfg["find_in"]);
				bool found_id = false;
				for (const config& c : vi.as_array())
				{
					if(c["id"] == u.id())
						found_id = true;
				}
				if(!found_id)
				{
					return false;
				}
			}
			catch(const invalid_variablename_exception&)
			{
				return false;
			}
		}
	}
	if (!vcfg["formula"].blank()) {
		try {
			const unit_callable main(loc,u);
			game_logic::map_formula_callable callable(&main);
			if (u2) {
				std::shared_ptr<unit_callable> secondary(new unit_callable(*u2));
				callable.add("other", variant(secondary.get()));
				// It's not destroyed upon scope exit because the variant holds a reference
			}
			const game_logic::formula form(vcfg["formula"]);
			if(!form.evaluate(callable).as_bool()) {
				return false;
			}
			return true;
		} catch(game_logic::formula_error& e) {
			lg::wml_error() << "Formula error in unit filter: " << e.type << " at " << e.filename << ':' << e.line << ")\n";
			// Formulae with syntax errors match nothing
			return false;
		}
	}

	if (!vcfg["lua_function"].blank()) {
		if (game_lua_kernel * lk = fc_.get_lua_kernel()) {
			bool b = lk->run_filter(vcfg["lua_function"].str().c_str(), u);
			if (!b) return false;
		}
	}

	return true;
}