Files
snejk/src/game/simulation/simulation_world.c

225 lines
8.3 KiB
C

#include "simulation_world.h"
#include <string.h>
#include <stdio.h>
#include <assert.h>
#define SIM_COMMANDS_PER_PLAYER 4
Simulation_World simulation_create_world(uint32_t seed, bool online, uint8_t max_players, uint16_t width, uint16_t height) {
Simulation_World w;
memset(&w, 0, sizeof(Simulation_World));
w.tick = 0;
w.online = online;
w.game_world = game_world_create(seed, width, height);
assert(w.game_world != NULL);
w.match_state = Simulation_Match_State_Waiting_To_Start;
w.players = (Simulation_Player *)calloc(max_players, sizeof(Simulation_Player));
w.max_players = max_players;
w.max_commands = w.max_players * SIM_COMMANDS_PER_PLAYER;
w.command_count = 0;
w.commands = (Simulation_Command *)calloc(w.max_commands, sizeof(Simulation_Command));
return w;
}
void simulation_destroy_world(Simulation_World *simulation_world) {
assert(simulation_world != NULL);
game_world_destroy(simulation_world->game_world);
simulation_world->game_world = NULL;
simulation_world->match_state = Simulation_Match_State_Waiting_To_Start;
free(simulation_world->players);
simulation_world->players = NULL;
free(simulation_world->commands);
simulation_world->commands = NULL;
}
void simulation_world_tick(Simulation_World *simulation_world) {
assert(simulation_world != NULL);
// printf("TICK: %lu.\n", simulation_world->tick);
for(uint16_t i = 0; i < simulation_world->command_count; i++) {
Simulation_Command *cmd = &simulation_world->commands[i];
// printf("Command type: %i, player id: %i.\n", cmd->type, cmd->player_id);
Simulation_Player *player = &simulation_world->players[cmd->player_id];
assert(player != NULL);
switch(cmd->type) {
case Simulation_Command_Type_Add_Player: {
// printf("Simulation_Command_Type_Add_Player\n");
assert(!player->active);
player->active = true;
Game_World *gw = simulation_world->game_world;
assert(gw != NULL);
uint16_t spawn_x = 0;
uint16_t spawn_y = 0;
assert(game_world_find_position_to_spawn(gw, &spawn_x, &spawn_y));
assert(game_world_create_entity(
gw,
Entity_Type_Snake_Head,
spawn_x, spawn_y,
&player->entity_id
));
Entity *player_entity = game_world_try_get_entity_by_id(gw, player->entity_id);
// Set initial move-direction for player-entities.
player_entity->move_direction = game_world_choose_initial_move_direction_based_on_coords(
gw,
spawn_x, spawn_y
);
break;
}
case Simulation_Command_Type_Remove_Player: {
// printf("Simulation_Command_Type_Remove_Player\n");
assert(player->active);
player->active = false;
game_world_destroy_entity(simulation_world->game_world, player->entity_id, true);
break;
}
case Simulation_Command_Type_Set_Player_Input: {
// printf("Simulation_Command_Type_Set_Player_Input\n");
assert(player->active);
player->input = cmd->player_input;
break;
}
}
}
simulation_world->command_count = 0;
switch(simulation_world->match_state) {
case Simulation_Match_State_Waiting_To_Start: {
if(!simulation_world->online) { // If not online, just go to Counting_Down.
simulation_world->match_state = Simulation_Match_State_Counting_Down;
}
else {
if(simulation_world_amount_of_active_players(simulation_world) > 1) {
simulation_world->match_state = Simulation_Match_State_Counting_Down;
}
}
break;
}
case Simulation_Match_State_Counting_Down: {
if(simulation_world->tick > 20) { // TEMP: SS - Hardcoded number and condition to break out of this state.
simulation_world->match_state = Simulation_Match_State_Active;
}
break;
}
case Simulation_Match_State_Active: {
if(simulation_world->tick > 500) { // TEMP: SS - Hardcoded number and condition to break out of this state.
simulation_world->match_state = Simulation_Match_State_Ended;
}
else {
Game_World *gw = simulation_world->game_world;
// Loop over all players in the simulation.
for(uint16_t i = 0; i < simulation_world->max_players; i++) {
Simulation_Player *player = &simulation_world->players[i];
if(!player->active) {
continue;
}
// printf("* Input for player %i - up: %i, down: %i, right: %i, left: %i.\n",
// i,
// player->input.up, player->input.down, player->input.right, player->input.left
// );
Entity *player_entity = game_world_try_get_entity_by_id(gw, player->entity_id);
assert(player_entity != NULL);
// Snakes can't go backwards. They have to turn.
switch(player_entity->move_direction) {
case Entity_Movement_Direction_None: {
break;
}
case Entity_Movement_Direction_Up:
case Entity_Movement_Direction_Down: // Snakes can only go right/left if it's currently moving up/down.
{
if(player->input.right) {
player_entity->move_direction = Entity_Movement_Direction_Right;
}
else if(player->input.left) {
player_entity->move_direction = Entity_Movement_Direction_Left;
}
break;
}
case Entity_Movement_Direction_Right:
case Entity_Movement_Direction_Left: // Snakes can only go up/down if it's currently moving right/left.
{
if(player->input.up) {
player_entity->move_direction = Entity_Movement_Direction_Up;
}
else if(player->input.down) {
player_entity->move_direction = Entity_Movement_Direction_Down;
}
break;
}
}
}
game_world_tick(gw);
}
break;
}
case Simulation_Match_State_Ended: {
printf("Match over!\n");
break;
}
}
simulation_world->tick += 1; // TODO: SS - Stop ticking if match has ended.
}
bool simulation_world_enqueue_command(Simulation_World *simulation_world, Simulation_Command command) {
assert(simulation_world != NULL);
if(simulation_world->command_count >= simulation_world->max_commands) {
return false;
}
simulation_world->commands[simulation_world->command_count] = command;
simulation_world->command_count += 1;
return true;
}
uint16_t simulation_world_amount_of_active_players(Simulation_World *simulation_world) {
assert(simulation_world != NULL);
uint16_t count = 0;
for(uint16_t i = 0; i < simulation_world->max_players; i++) {
Simulation_Player *player = &simulation_world->players[i];
if(player->active) {
count += 1;
}
}
return count;
}