Program Listing for File player_incantation.c¶
↰ Return to documentation for file (server/game_events/player_incantation.c)
#include <stdint.h>
#include <stdio.h>
#include "client/client.h"
#include "event.h"
#include "handler.h"
#include "names.h"
struct requirement_s {
inventory_t resources;
uint8_t player_count;
};
static const struct requirement_s INCANTATION_REQUIREMENTS[] = {
{{{0, 1, 0, 0, 0, 0, 0}}, 1},
{{{0, 1, 1, 1, 0, 0, 0}}, 2},
{{{0, 2, 0, 1, 0, 2, 0}}, 2},
{{{0, 1, 1, 2, 0, 1, 0}}, 4},
{{{0, 1, 2, 1, 3, 0, 0}}, 4},
{{{0, 1, 2, 3, 0, 1, 0}}, 6},
{{{0, 2, 2, 2, 2, 2, 1}}, 6},
};
static constexpr const size_t INCANTATION = 300;
static
bool has_enough_resources(server_t *srv, uint8_t x, uint8_t y, uint8_t level)
{
const struct requirement_s *req;
size_t player_count = 0;
if (level < 1 || level > 7)
return false;
req = &INCANTATION_REQUIREMENTS[level - 1];
for (size_t i = 0; i < RES_COUNT; i++)
if (srv->map[y][x].qnts[i] < req->resources.qnts[i])
return false;
for (size_t i = srv->cm.idx_of_players; i < srv->cm.count; i++)
if (srv->cm.clients[i].x == x
&& srv->cm.clients[i].y == y
&& srv->cm.clients[i].tier == level)
player_count++;
return player_count >= req->player_count;
}
static
void send_to_participants(server_t *srv, client_state_t *cs,
const char *message, bool end)
{
client_state_t *client;
for (size_t i = srv->cm.idx_of_players; i < srv->cm.count; i++) {
client = srv->cm.clients + i;
if (!end && client->is_in_incantation)
continue;
if (client->x != cs->x
|| client->y != cs->y
|| client->tier != cs->tier
)
continue;
append_to_output(srv, client, message);
client->tier += end;
client->is_in_incantation = !end;
if (!end)
continue;
send_to_guis(srv, "plv %u %hhu\n", client->id, client->tier);
}
}
static
bool player_incantation_end_schedule(server_t *srv, const event_t *event)
{
uint64_t interval = (INCANTATION * MICROSEC_IN_SEC) / srv->frequency;
event_t new_event = {
.timestamp = get_timestamp() + interval,
.client_idx = event->client_idx,
.client_id = event->client_id,
.command = { PLAYER_END_INCANTATION }
};
if (!event_heap_push(&srv->events, &new_event)) {
perror("Failed to schedule incantation end event");
return false;
}
return true;
}
static
void player_lock_helper(
server_t *srv,
client_state_t *cs,
uint32_t idx,
const event_t *event
)
{
uint64_t interval = (INCANTATION * MICROSEC_IN_SEC) / srv->frequency;
event_t new_event = {
.timestamp = get_timestamp() + interval,
.client_idx = idx,
.client_id = cs->id,
.command = { PLAYER_LOCK }
};
if (event->client_id == (int)cs->id)
return;
if (!event_heap_push(&srv->events, &new_event)) {
perror("Failed to schedule player lock event");
return;
}
}
bool player_start_incentation_handler(server_t *srv, const event_t *event)
{
client_state_t *cs = event_get_client(srv, event);
if (cs == nullptr)
return false;
if (event->arg_count != 1
|| !has_enough_resources(srv, cs->x, cs->y, cs->tier))
return append_to_output(srv, cs, "ko\n"), true;
send_to_guis(srv, "pic %hhu %hhu %hhu", cs->x, cs->y, cs->tier);
send_to_participants(srv, cs, "Elevation underway\n", 0);
for (size_t i = srv->cm.idx_of_players; i < srv->cm.count; i++)
if (srv->cm.clients[i].x == cs->x
&& srv->cm.clients[i].y == cs->y
&& srv->cm.clients[i].tier == cs->tier
) {
send_to_guis(srv, " #%d", srv->cm.clients[i].id);
player_lock_helper(srv, &srv->cm.clients[i], i, event);
}
send_to_guis(srv, "\n");
return player_incantation_end_schedule(srv, event);
}
static
void game_check_end(server_t *srv)
{
uint8_t count_tier8 = 0;
client_state_t *player;
size_t j = 0;
for (; srv->team_names[j] != nullptr; j++) {
for (size_t i = srv->cm.idx_of_players; i < srv->cm.count; i++) {
player = &srv->cm.clients[i];
count_tier8 += player->tier == 8 && player->team_id == j;
}
if (count_tier8 == 6)
break;
count_tier8 = 0;
}
if (count_tier8 == 6) {
send_to_guis(srv, "seg %s\n", srv->team_names[j]);
for (size_t i = srv->cm.idx_of_players; i < srv->cm.count; i++) {
player = &srv->cm.clients[i];
append_to_output(srv, player, "death\n");
}
}
}
bool player_end_incentation_handler(server_t *srv, const event_t *event)
{
client_state_t *cs = event_get_client(srv, event);
char buff[64];
if (cs == nullptr)
return false;
if (!has_enough_resources(srv, cs->x, cs->y, cs->tier)) {
send_to_guis(srv, "pie %hhu %hhu %hhu\n", cs->x, cs->y, cs->tier);
append_to_output(srv, cs, "ko\n");
return true;
}
snprintf(buff, sizeof(buff), "Current level: %d\n", cs->tier + 1);
for (size_t i = 0; i < RES_COUNT; i++)
srv->map[cs->y][cs->x].qnts[i] -=
INCANTATION_REQUIREMENTS[cs->tier - 1].resources.qnts[i];
send_to_participants(srv, cs, buff, 1);
send_to_guis(srv, "pie %hhu %hhu %hhu\n", cs->x, cs->y, cs->tier);
game_check_end(srv);
return true;
}
bool player_lock_handler(server_t *, const event_t *)
{
return true;
}