Skip to content

Commit 0982c28

Browse files
authored
Merge pull request #263 from AnonymusRaccoon/develop
Develop
2 parents 2d17eff + 1a2734e commit 0982c28

File tree

8 files changed

+170
-80
lines changed

8 files changed

+170
-80
lines changed

Bot.md

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
# Bot documentation
2+
3+
A bot in this bomberman is using a lua script as way to choose what to do
4+
So you can make your own with some helper functions given from C++
5+
6+
## Update function
7+
8+
Each frame, the game will call the "Update" function in the script.
9+
This is the same lua state as the last call so this means you can set global variables to keep data between frames
10+
11+
Update function should take no arguments.
12+
13+
## Map Blocks
14+
15+
```lua
16+
nothing = 0
17+
breakable = 1
18+
hole = 2
19+
bumper = 4
20+
unbreakable = 7
21+
bomb = 10
22+
```
23+
24+
## Registered functions
25+
26+
```lua
27+
-- getMap returns a table of the blocks of the map
28+
-- From 1 to 17 {{0, 1, 2 ..}, ..}
29+
function getMap();
30+
31+
-- getDanger returns a table of the danger zone on the map
32+
-- From 1 to 17 {{0, 1, 2 ..}, ..}
33+
-- value is number of seconds before explosion
34+
function getDanger();
35+
36+
-- getPath returns a table of nodes of a path from A to B {{x = X, y = Y}, ...}
37+
-- @param x1 should be int
38+
-- @param y1 should be int
39+
-- @param x2 should be int
40+
-- @param y2 should be int
41+
-- @param throughBreakable bool path is going through breakables blocks or not
42+
function getPath(x1, y1, x2, y2, throughBreakable);
43+
44+
-- getPlayer returns player pos as {x = xPlayer, y = yPlayer}
45+
function getPlayer();
46+
47+
-- getPlayerRound returns player pos with rounded value {x = xPlayer, y = yPlayer}
48+
function getPlayerRound();
49+
50+
-- getDangerLevel returns danger level at [xpos, ypos]
51+
function getDangerLevel(xpos, ypos);
52+
53+
-- getDangerLevelPlayer get danger level on the position of the player
54+
function getDangerLevelPlayer();
55+
56+
-- getBlockType returns block type at [xpos, ypos]
57+
function getBlockType(xpos, ypos);
58+
59+
-- getClosestSafeSpace returns the block next to player where the player should go to to the closest safe space
60+
-- returns player pos if no path is found
61+
function getClosestSafeSpace();
62+
63+
-- canPutBombSafe returns true if player can put a bomb and find a path to safe space if bomb is put
64+
function canPutBombSafe();
65+
66+
-- getRadius returns the explosion radius of the current player
67+
function getRadius();
68+
69+
-- getEnemies returns a table with enemies position {{x = X, y = Y}, ...}
70+
function getEnemies();
71+
72+
-- getEnemies returns a table with enemies position rounded {{x = X, y = Y}, ...}
73+
function getEnemiesRound();
74+
```

assets/ai_scripts/john.lua

-66
Original file line numberDiff line numberDiff line change
@@ -41,71 +41,6 @@ function PrintMap(map, MaxX, maxZ)
4141
end
4242
end
4343

44-
function getNeighborsDefend(node)
45-
local neighbors = {}
46-
for _, dir in ipairs(Dirs) do
47-
local neighborX = node.x + dir.x
48-
local neighborY = node.y + dir.y
49-
if neighborY <= MaxY and neighborX <= MaxX then
50-
if neighborY >= 0 and neighborX >= 0 then
51-
if Map[neighborX][neighborY] == 0 and Danger[neighborX][neighborY] ~= 1 then
52-
table.insert(neighbors, {x = neighborX, y = neighborY})
53-
end
54-
end
55-
end
56-
end
57-
if #neighbors == 0 and Danger[node.x][node.y] <= 1 then
58-
for _, dir in ipairs(Dirs) do
59-
local neighborX = node.x + dir.x
60-
local neighborY = node.y + dir.y
61-
if neighborY <= MaxY and neighborX <= MaxX then
62-
if neighborY >= 0 and neighborX >= 0 then
63-
if Map[neighborX][neighborY] == 0 then
64-
table.insert(neighbors, {x = neighborX, y = neighborY})
65-
end
66-
end
67-
end
68-
end
69-
end
70-
return neighbors
71-
end
72-
73-
function dist(nodeA, nodeB)
74-
return math.sqrt(math.pow(nodeB.x - nodeA.x, 2) + math.pow(nodeB.y - nodeA.y, 2))
75-
end
76-
77-
function getNeighborAttack(node)
78-
log("atta")
79-
local neighbors = {}
80-
for _, dir in ipairs(Dirs) do
81-
local neighborX = node.x + dir.x
82-
local neighborY = node.y + dir.y
83-
if neighborY <= MaxY and neighborX <= MaxX then
84-
if neighborY >= 0 and neighborX >= 0 then
85-
if Map[neighborX][neighborY] <= 1 and Danger[neighborX][neighborY] ~= 1 then
86-
table.insert(neighbors, {x = neighborX, y = neighborY})
87-
end
88-
end
89-
end
90-
end
91-
return neighbors
92-
end
93-
94-
function getPathToEnemy(player, enemies)
95-
local minDist = 100000
96-
local res = {}
97-
for _, enemy in ipairs(enemies) do
98-
local currDist = dist(player, enemy)
99-
if currDist < minDist and enemy.x ~= player.x and enemy.y ~= player.y then
100-
minDist, res = currDist, enemy
101-
end
102-
end
103-
local path = pathfind(player, res, getNeighborAttack)
104-
return path
105-
end
106-
107-
108-
10944
function getPathToSafeSpace(player)
11045
local res = getClosestSafeSpace()
11146
log("run to")
@@ -123,7 +58,6 @@ LastTarget = nil
12358
math.randomseed(os.time())
12459
function Update()
12560
log("NEW FRAME")
126-
--local path = getPath(0, 0, 16, 16);
12761

12862
local player = getPlayer()
12963
if LastTarget ~= nil then

lib/LuaGate/sources/LuaGate.cpp

+5
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,11 @@ namespace LuaG
7070
return res;
7171
}
7272

73+
bool State::getBool(int idx)
74+
{
75+
return lua_toboolean(_state, idx);
76+
}
77+
7378
float State::getNumber(int idx)
7479
{
7580
return lua_tonumber(_state, idx);

lib/LuaGate/sources/LuaGate.hpp

+3
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ namespace LuaG
5252
//! @brief Get return Number
5353
bool getReturnBool(void);
5454

55+
//! @brief Get bool at index in the stack
56+
bool getBool(int index);
57+
5558
//! @brief Get Number at index in the stack
5659
float getNumber(int index);
5760

sources/Component/IAControllable/IAControllableComponent.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,12 @@ namespace BBM
2020
{
2121
if (std::filesystem::exists(scriptPath)) {
2222
_state.dofile(scriptPath);
23+
_state.getGlobal("Update");
24+
if (lua_isfunction(_state.getState(), -1)) {
25+
_state.popLast();
26+
} else {
27+
throw Error("Lua script doesn't have Update function");
28+
}
2329
}
2430
else {
2531
throw Error("Couldn't load lua script: " + scriptPath);

sources/Map/LuaMap.cpp

+61-10
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ namespace BBM
5656
return path;
5757
}
5858

59-
std::vector<Vector2f> LuaMap::getNeighbors(Vector2f node) const
59+
std::vector<Vector2f> LuaMap::getNeighbors(Vector2f node, bool throughBreakable) const
6060
{
6161
std::vector<Vector2f> neighbors;
6262
for (auto &dir : _dirs) {
@@ -65,7 +65,8 @@ namespace BBM
6565
continue;
6666
if (neighbor.y >= 17 || neighbor.x >= 17)
6767
continue;
68-
if (_map[neighbor.y][neighbor.x] == 0 &&
68+
if ((_map[neighbor.y][neighbor.x] == 0 ||
69+
_map[neighbor.y][neighbor.x] == throughBreakable) &&
6970
_danger[neighbor.y][neighbor.x] != 1)
7071
neighbors.push_back(neighbor);
7172
}
@@ -83,7 +84,7 @@ namespace BBM
8384
return neighbors;
8485
}
8586

86-
std::vector<Vector2f> LuaMap::pathfind(Vector2f root, Vector2f target) const
87+
std::vector<Vector2f> LuaMap::pathfind(Vector2f root, Vector2f target, bool throughBreakable) const
8788
{
8889
std::vector<Vector2f> closed;
8990
std::vector<Vector2f> open;
@@ -117,7 +118,7 @@ namespace BBM
117118
}
118119
open.erase(std::remove(open.begin(), open.end(), current), open.end());
119120
closed.push_back(current);
120-
auto neighbors = getNeighbors(current);
121+
auto neighbors = getNeighbors(current, throughBreakable);
121122
for (auto &neighbor : neighbors) {
122123
if (std::find(closed.begin(), closed.end(), neighbor) != closed.end())
123124
continue;
@@ -224,14 +225,16 @@ namespace BBM
224225
int LuaMap::getPath(lua_State *L)
225226
{
226227
LuaG::State state(L);
227-
auto y2 = state.getNumber(-1);
228-
auto x2 = state.getNumber(-2);
229-
auto y1 = state.getNumber(-3);
230-
auto x1 = state.getNumber(-4);
231-
const LuaMap *map = reinterpret_cast<const LuaMap *>(state.getPointer(state.getFirstUpValueIdx()));
228+
auto throughBreakable = state.getBool(-1);
229+
auto y2 = state.getNumber(-2);
230+
auto x2 = state.getNumber(-3);
231+
auto y1 = state.getNumber(-4);
232+
auto x1 = state.getNumber(-5);
233+
234+
const LuaMap *map = reinterpret_cast<const LuaMap *>(state.getPointer(state.getFirstUpValueIdx()));
232235
Vector2f fst(x1, y1);
233236
Vector2f snd(x2, y2);
234-
auto path = map->pathfind(fst, snd);
237+
auto path = map->pathfind(fst, snd, throughBreakable);
235238
int index = 1;
236239
state.newTable();
237240
for (auto &r : path) {
@@ -319,6 +322,54 @@ namespace BBM
319322
return 1;
320323
}
321324

325+
int LuaMap::getRadius(lua_State *L)
326+
{
327+
LuaG::State state(L);
328+
const LuaMap *map = reinterpret_cast<const LuaMap *>(state.getPointer(state.getFirstUpValueIdx()));
329+
state.push(map->currRadius);
330+
return 1;
331+
}
332+
333+
int LuaMap::getEnemies(lua_State *L)
334+
{
335+
LuaG::State state(L);
336+
const LuaMap *map = reinterpret_cast<const LuaMap *>(state.getPointer(state.getFirstUpValueIdx()));
337+
int index = 1;
338+
state.newTable();
339+
for (auto &r : map->_enemies) {
340+
state.push(index++);
341+
state.newTable();
342+
state.push("x");
343+
state.push(r.x);
344+
state.setTable();
345+
state.push("y");
346+
state.push(r.y);
347+
state.setTable();
348+
state.setTable();
349+
}
350+
return 1;
351+
}
352+
353+
int LuaMap::getEnemiesRound(lua_State *L)
354+
{
355+
LuaG::State state(L);
356+
const LuaMap *map = reinterpret_cast<const LuaMap *>(state.getPointer(state.getFirstUpValueIdx()));
357+
int index = 1;
358+
state.newTable();
359+
for (auto &r : map->_enemies) {
360+
state.push(index++);
361+
state.newTable();
362+
state.push("x");
363+
state.push(std::round(r.x));
364+
state.setTable();
365+
state.push("y");
366+
state.push(std::round(r.y));
367+
state.setTable();
368+
state.setTable();
369+
}
370+
return 1;
371+
}
372+
322373
int LuaMap::canPutBomb(lua_State *L)
323374
{
324375
LuaG::State state(L);

sources/Map/LuaMap.hpp

+14-2
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ namespace BBM
2828
void setPlayer(Vector3f pos);
2929

3030
//! @brief A star pathfinding between two points
31-
std::vector<Vector2f> pathfind(Vector2f, Vector2f) const;
31+
std::vector<Vector2f> pathfind(Vector2f root, Vector2f target, bool throughBreakable) const;
3232

3333
//! @brief find a safe space for current player
3434
Vector2f findSafeSpace(const std::vector<std::vector<int>> &dangerMap) const;
@@ -63,6 +63,15 @@ namespace BBM
6363
//! @brief Check if current player can put a bomb with an escape
6464
static int canPutBomb(lua_State *L);
6565

66+
//! @brief Get current explosion radius of the player
67+
static int getRadius(lua_State *L);
68+
69+
//! @brief Get enemies position
70+
static int getEnemies(lua_State *L);
71+
72+
//! @brief Get enemies position rounded
73+
static int getEnemiesRound(lua_State *L);
74+
6675
//! @brief map blocks in 2D grid
6776
std::vector<std::vector<int>> _map;
6877

@@ -72,6 +81,9 @@ namespace BBM
7281
//! @brief player position
7382
Vector2f _player;
7483

84+
//! @brief other players position
85+
std::vector<Vector2f> _enemies;
86+
7587
//! @brief rounded player position
7688
Vector2f _roundedPlayer;
7789

@@ -83,7 +95,7 @@ namespace BBM
8395
std::unordered_map<Vector2f, Vector2f> &cameFrom, Vector2f node) const;
8496

8597
//! @brief get neighbors of node for a_star
86-
std::vector<Vector2f> getNeighbors(Vector2f node) const;
98+
std::vector<Vector2f> getNeighbors(Vector2f node, bool throughBreakable) const;
8799

88100
std::vector<Vector2f> _dirs = {
89101
Vector2f(1, 0), Vector2f(-1, 0), Vector2f(0, 1), Vector2f(0, -1)

sources/System/IAControllable/IAControllableSystem.cpp

+7-2
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,13 @@ namespace BBM
1919

2020
void IAControllableSystem::UpdateMapInfos(WAL::ViewEntity<PositionComponent, ControllableComponent, IAControllableComponent, BombHolderComponent> &entity)
2121
{
22-
_players.clear();
22+
_luamap._enemies.clear();
2323
if (!_wal.getScene())
2424
return;
2525
for (auto &[other, pos, _] : _wal.getScene()->view<PositionComponent, ScoreComponent>()) {
26-
_players.push_back(MapInfo(pos.position, MapGenerator::NOTHING));
26+
if (other == entity)
27+
continue;
28+
_luamap._enemies.push_back(Vector2f(pos.position.x, pos.position.z));
2729
}
2830
if (_cached)
2931
return;
@@ -86,6 +88,9 @@ namespace BBM
8688
state.registerClosure(&_luamap, "getBlockType", LuaMap::getBlockType);
8789
state.registerClosure(&_luamap, "getClosestSafeSpace", LuaMap::getClosestSafeSpace);
8890
state.registerClosure(&_luamap, "canPutBombSafe", LuaMap::canPutBomb);
91+
state.registerClosure(&_luamap, "getRadius", LuaMap::getRadius);
92+
state.registerClosure(&_luamap, "getEnemies", LuaMap::getEnemies);
93+
state.registerClosure(&_luamap, "getEnemiesRound", LuaMap::getEnemiesRound);
8994
}
9095

9196
void IAControllableSystem::onFixedUpdate(WAL::ViewEntity<PositionComponent, ControllableComponent, IAControllableComponent, BombHolderComponent> &entity)

0 commit comments

Comments
 (0)