#define SOL_ALL_SAFETIES_ON 1
#include <sol/sol.hpp>

#include <iostream>

struct ship {
	int bullets = 20;
	int life = 100;

	bool shoot() {
		if (bullets > 0) {
			--bullets;
			// successfully shot
			return true;
		}
		// cannot shoot
		return false;
	}

	bool hurt(int by) {
		life -= by;
		// have we died?
		return life < 1;
	}
};


int main() {

	std::cout << "=== usertype basics ===" << std::endl;

	static const bool way_1 = true;

	sol::state lua;
	lua.open_libraries(sol::lib::base);

	if (way_1) {
		lua.new_usertype<ship>(
		     "ship", // the name of the class, as you want it
		             // to be used in lua List the member
		             // functions you wish to bind:
		             // "name_of_item",
		             // &class_name::function_or_variable
		     "shoot",
		     &ship::shoot,
		     "hurt",
		     &ship::hurt,
		     // bind variable types, too
		     "life",
		     &ship::life,
		     // names in lua don't have to be the same as C++,
		     // but it probably helps if they're kept the same,
		     // here we change it just to show its possible
		     "bullet_count",
		     &ship::bullets);
	}
	else {
		// set usertype explicitly, with the given name
		sol::usertype<ship> usertype_table
		     = lua.new_usertype<ship>("ship");
		usertype_table["shoot"] = &ship::shoot;
		usertype_table["hurt"] = &ship::hurt;
		usertype_table["life"] = &ship::life;
		usertype_table["bullet_count"] = &ship::bullets;
	}

	const auto& code = R"(
		fwoosh = ship.new()
		-- note the ":" that is there: this is mandatory for member function calls
		-- ":" means "pass self" in Lua
		local success = fwoosh:shoot()
		local is_dead = fwoosh:hurt(20)
		-- check if it works
		print(is_dead) -- the ship is not dead at this point
		print(fwoosh.life .. "life left") -- 80 life left
		print(fwoosh.bullet_count) -- 19
	)";


	lua.script(code);

	std::cout << std::endl;

	return 0;
}
