29 LOG_ERROR(
"Cannot bind server game functions: world is null");
33 LOG_ERROR(
"Cannot bind server game functions: engine is null");
38 static bool seeded =
false;
40 std::srand(
static_cast<unsigned int>(std::time(
nullptr)));
45 lua.set_function(
"spawnEnemy",
54 LOG_INFO(
"[LUA] Spawned enemy '" + enemyType +
"' at (" + std::to_string(x) +
55 ", " + std::to_string(y) +
")");
58 }
catch (
const std::exception &e) {
59 LOG_ERROR(
"[LUA] Failed to spawn enemy: " + std::string(e.what()));
74 LOG_DEBUG(
"[LUA] Spawned projectile at (" + std::to_string(x) +
", " + std::to_string(y) +
78 }
catch (
const std::exception &e) {
79 LOG_ERROR(
"[LUA] Failed to spawn projectile: " + std::string(e.what()));
85 lua.set_function(
"getTime", []() ->
float {
86 return static_cast<float>(std::clock()) /
static_cast<float>(CLOCKS_PER_SEC);
90 lua.set_function(
"distance", [](
float x1,
float y1,
float x2,
float y2) ->
float {
93 return std::sqrt(dx * dx + dy * dy);
96 lua.set_function(
"normalize", [&lua](
float x,
float y) -> sol::table {
97 float length = std::sqrt(x * x + y * y);
101 sol::state_view lua_view(lua.lua_state());
102 sol::table result = lua_view.create_table();
103 result[
"x"] = x / length;
104 result[
"y"] = y / length;
111 [world](
const std::string &buffType,
float duration,
float value,
float x,
117 if (buffType ==
"speed")
119 else if (buffType ==
"damage")
121 else if (buffType ==
"firerate")
123 else if (buffType ==
"shield")
125 else if (buffType ==
"regen")
132 entity.
with(
ecs::Sprite(
"powerup.png", {0, 0, 20, 20}, 1.0f, 0.0f,
false,
false, 0));
134 LOG_INFO(
"[LUA] Spawned power-up '" + buffType +
"' at (" + std::to_string(x) +
", " +
135 std::to_string(y) +
")");
138 }
catch (
const std::exception &e) {
139 LOG_ERROR(
"[LUA] Failed to spawn power-up: " + std::string(e.what()));
152 if (buffType ==
"multishot")
154 else if (buffType ==
"doubleshot")
156 else if (buffType ==
"tripleshot")
158 else if (buffType ==
"piercing")
160 else if (buffType ==
"homing")
162 else if (buffType ==
"maxhealth")
169 entity.
with(
ecs::Sprite(
"upgrade.png", {0, 0, 20, 20}, 1.0f, 0.0f,
false,
false, 0));
171 LOG_INFO(
"[LUA] Spawned upgrade '" + buffType +
"' at (" + std::to_string(x) +
", " +
172 std::to_string(y) +
")");
175 }
catch (
const std::exception &e) {
176 LOG_ERROR(
"[LUA] Failed to spawn upgrade: " + std::string(e.what()));
189 entity.
with(
ecs::Sprite(
"health.png", {0, 0, 20, 20}, 1.0f, 0.0f,
false,
false, 0));
191 LOG_INFO(
"[LUA] Spawned health pack at (" + std::to_string(x) +
", " + std::to_string(y) +
195 }
catch (
const std::exception &e) {
196 LOG_ERROR(
"[LUA] Failed to spawn health pack: " + std::string(e.what()));
204 [world](
float x,
float y,
float width,
float height, sol::optional<bool> destructible,
207 bool isDestructible = destructible.value_or(
false);
208 int wallHealth = health.value_or(0);
215 {0, 0,
static_cast<int>(width),
static_cast<int>(height)}, 1.0f,
216 0.0f,
false,
false, 0));
218 if (isDestructible && wallHealth > 0) {
222 LOG_INFO(
"[LUA] Spawned wall at (", x,
", ", y,
") - Size: ", width,
"x", height,
223 isDestructible ?
" [Destructible]" :
" [Solid]");
226 }
catch (
const std::exception &e) {
227 LOG_ERROR(
"[LUA] Failed to spawn wall: ", e.what());
235 const std::string &enemyType,
const std::string &scriptPath,
236 float health,
int scoreValue) {
239 LOG_ERROR(
"[LUA] queueSpawn: world is null");
244 LOG_WARNING(
"[LUA] Cannot queue spawn: invalid spawner entity (address: ",
255 ecs::SpawnRequest request{x, y, enemyType, scriptPath, health, scoreValue, 0.0f};
258 LOG_DEBUG(
"[LUA] Queued spawn for ", enemyType,
" at (", x,
", ", y,
")");
259 }
catch (
const std::exception &e) {
260 LOG_ERROR(
"[LUA] queueSpawn exception: ", e.what());
264 lua.set_function(
"setSpawnerConfig", [world](
ecs::wrapper::Entity spawner, sol::table configTable) {
267 LOG_ERROR(
"[LUA] setSpawnerConfig: world is null");
272 LOG_WARNING(
"[LUA] Cannot set spawner config: invalid spawner entity (address: ",
286 sol::optional<sol::table> wavesTableOpt = configTable[
"waves"];
288 sol::table wavesTable = wavesTableOpt.value();
289 for (
auto &wavePair : wavesTable) {
290 sol::table waveTable = wavePair.second;
294 sol::optional<sol::table> enemiesTableOpt = waveTable[
"enemyConfigs"];
295 if (!enemiesTableOpt) {
296 sol::optional<sol::table> enemiesTableOpt = waveTable[
"enemies"];
298 if (enemiesTableOpt) {
299 sol::table enemiesTable = enemiesTableOpt.value();
300 for (
auto &enemyPair : enemiesTable) {
301 sol::table enemyTable = enemyPair.second;
303 request.
x = enemyTable.get_or(
"x", 0.0f);
304 request.
y = enemyTable.get_or(
"y", 0.0f);
305 request.
enemyType = enemyTable.get_or<std::string>(
"type",
"basic");
306 request.
scriptPath = enemyTable.get_or<std::string>(
"script",
"");
307 request.
health = enemyTable.get_or(
"health", 100.0f);
308 request.
scoreValue = enemyTable.get_or(
"scoreValue", 100);
309 request.
spawnDelay = enemyTable.get_or(
"delay", 0.0f);
311 waveConfig.
enemies.push_back(request);
315 waveConfig.
spawnInterval = waveTable.get_or(
"spawnInterval", 1.0f);
316 config.waves.push_back(waveConfig);
321 sol::optional<sol::table> intervalsTableOpt = configTable[
"wavesIntervals"];
322 if (intervalsTableOpt) {
323 sol::table intervalsTable = intervalsTableOpt.value();
324 for (
auto &intervalPair : intervalsTable) {
325 int interval = intervalPair.second.as<
int>();
326 config.wavesIntervals.push_back(interval);
333 config.waves.size(),
" waves");
334 }
catch (
const std::exception &e) {
335 LOG_ERROR(
"[LUA] setSpawnerConfig exception: ", e.what());
339 LOG_INFO(
"Server game bindings initialized");