NOTE: This topic does not have a working visual interface. The visuals provided are only mockups and animations of how the topic could look like. Additionally, the technical part of the documentation (Topic manual) is outdated and incorrect regarding server connection protocols and message formats. Please refer to the Technical Documentation section at the bottom of this README for accurate and up-to-date implementation details.
Elementals is a competitive, turn-based strategy game for two players, where each player assembles a team of elemental creatures to battle for dominance. Each match consists of up to five rounds, with players selecting a pool of 12 unique elementals at the start. Before each round, players choose which creatures to send into battle, manage their positions, and spend currency on upgrades or powerful domain effects.
Combat is resolved simultaneously, with creatures attacking based on their speed and attack type (melee, ranged, or area-of-effect). Elemental affinities (Fire, Water, Nature) introduce a rock-paper-scissors dynamic, and special abilities or status effects can turn the tide of battle. Victory goes to the first player to win three rounds or eliminate all of the opponent’s creatures.
Created by:
- Krešimir Bačić (Topic responsible)
- Ante Balaić-Marmun
- Domagoj Marić
- Filip Pavletić
- Petar Hajduk
- Jakov Jakovac
This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.
This topic was used in the following events:
Before you begin, make sure your environment is set up to run the game. The following prerequisites will help you configure your system to run the server, agents, and visuals correctly.
-
Install Java 17 or higher (for server)
-
Install Gradle (for building and running server)
-
Install Node.js and npm (for JavaScript agents)
-
Install required dependencies:
-
For server:
cd game ./gradlew build -
For JavaScript agents:
cd agents npm install
-
- Start the server (it will run on port 8080 by default)
- Start the first agent (waiting player) - it will register/login and wait
- Start the second agent with both usernames - it will register/login and initiate the game
- The game will proceed automatically through all phases until completion
- Both agents will disconnect when the game ends
-
Navigate to the game directory:
cd game -
Start the server using Gradle:
./gradlew bootRun
- The server runs on port 8080 by default
- The server provides REST API endpoints and WebSocket connections
- Server logs will show when it's ready to accept connections
-
Start the first agent (waiting player):
node simpleAgent.js username1 password123
- This agent will register/login and wait for another player to start the game
-
Start the second agent (game starter):
node simpleAgent.js username2 password456 username1
- This agent will register/login and start a game between
username2andusername1
- This agent will register/login and start a game between
node simpleAgent.js <playerName> <password> [otherPlayerName]playerName: Your agent's username (will auto-register if doesn't exist)password: Your agent's passwordotherPlayerName: Optional - if provided, this agent will start a game with that player
# Terminal 1 - First player waits
node simpleAgent.js Alice mypass123
# Terminal 2 - Second player starts the game
node simpleAgent.js Bob otherpass456 Alice- Both players must be registered users (agents auto-register if needed)
- If you provide an
otherPlayerName, this agent will automatically start the game - If you don't provide an
otherPlayerName, this agent will wait for another player to start - The server validates that both players exist before starting the game
- Agents will play automatically through all game phases until completion
This section provides detailed information about the server architecture, communication protocols, and game command structure for developers creating custom agents.
The Elementals server is built with Spring Boot and uses the following technologies:
- REST API: For user authentication and game management
- WebSocket + STOMP: For real-time game communication
- JWT Authentication: Token-based authentication system
- Spring Security: Handles user registration and login
POST /public/register
Content-Type: application/x-www-form-urlencoded
username=playerName&password=playerPasswordResponse: JWT token string
POST /public/login
Content-Type: application/x-www-form-urlencoded
username=playerName&password=playerPasswordResponse: JWT token string
POST /game/start
Content-Type: application/x-www-form-urlencoded
Authorization: Bearer <jwt-token>
player1=username1&player2=username2Response: Game ID (integer)
// Connect with JWT token as URL parameter
const socketUrl = `http://localhost:8080/player?t=${jwtToken}`;
const socket = new SockJS(socketUrl);
const stompClient = Stomp.over(socket);stompClient.subscribe("/user/queue/player", (message) => {
const serverMessage = JSON.parse(message.body);
// Handle server response
});const gameMessage = {
gameId: gameId,
messageType: "COMMAND_TYPE",
messageText: "command_parameters",
};
stompClient.send("/websocket/game", {}, JSON.stringify(gameMessage));| Command | Description | Response |
|---|---|---|
GET_GAME_PHASE |
Get current game phase | "POOL_SELECTION", "ROUND_SELECTION", "ROUND_IN_PROGRESS", "GAME_OVER" |
| Command | Description | Parameters | Response |
|---|---|---|---|
GET_POSSIBLE_CREATURES |
Get list of all available creatures | None | Array of creature templates |
SELECT_PLAYER_CREATURE_POOL |
Select 12 creatures for your pool | {"items": ["creature1", "creature2", ...]} |
Confirmation message |
| Command | Description | Parameters | Response |
|---|---|---|---|
GET_PLAYER_CREATURE_POOL |
Get your creature pool | None | Array of creatures with IDs and health |
SELECT_PLAYER_CREATURES_IN_PLAY |
Select up to 4 creatures for the round | [id1, id2, id3, id4] |
Confirmation message |
| Command | Description | Parameters | Response |
|---|---|---|---|
GET_PLAYER_CREATURES_IN_PLAY |
Get your creatures in current round | None | Array of creatures with stats |
GET_OPPONENT_CREATURES_IN_PLAY |
Get opponent's creatures | None | Array of creatures with stats |
GET_CURRENCY |
Get current currency amount | None | Currency value |
SELECT_MOVE |
Make a combat move | Move string (see below) | Confirmation message |
Attack Commands:
"attack"- Attack with melee/AOE creatures (no target needed)"attack 0"- Attack specific slot with ranged creatures (slot 0-3)
Other Commands:
"wait"- Skip turn- Domain effects and upgrades (refer to game manual)
All server responses follow this structure:
{
"gameId": 0,
"messageType": "RESPONSE",
"contentJson": "response_data_or_json_string",
"message": "alternative_response_field"
}Response Types:
- Game Phase: Simple string (
"POOL_SELECTION", etc.) - Creature Arrays: JSON array of creature objects
- Confirmations: Plain text messages
- Errors: JSON object with
errorfield
- POOL_SELECTION: Each player selects 12 creatures from available pool
- ROUND_SELECTION: Each player selects up to 4 creatures for the current round
- ROUND_IN_PROGRESS: Players take turns making combat moves
- GAME_OVER: Game completed, winner determined
Common server errors and their meanings:
| Error | Meaning | Solution |
|---|---|---|
BAD_REQUEST (400) |
Invalid parameters or missing player | Check usernames exist |
FORBIDDEN (403) |
Authentication failed | Re-authenticate with valid credentials |
Server error: ... |
Game state error | Check game phase and valid commands |
// 1. Get game phase
send: {"gameId": 0, "messageType": "GET_GAME_PHASE", "messageText": ""}
receive: {"messageType": "RESPONSE", "contentJson": "POOL_SELECTION"}
// 2. Get available creatures
send: {"gameId": 0, "messageType": "GET_POSSIBLE_CREATURES", "messageText": ""}
receive: {"messageType": "RESPONSE", "contentJson": "[{\"name\":\"Fire Dragon\", ...}, ...]"}
// 3. Select creature pool
send: {"gameId": 0, "messageType": "SELECT_PLAYER_CREATURE_POOL",
"messageText": "{\"items\":[\"Fire Dragon\",\"Water Elemental\",...]}"}
receive: {"messageType": "RESPONSE", "contentJson": "Creature pool set successfully"}
// 4. Make attack move
send: {"gameId": 0, "messageType": "SELECT_MOVE", "messageText": "attack 0"}
receive: {"messageType": "RESPONSE", "contentJson": "Move selected"}

