.. _program_listing_file_server_game_events_player_incantation.c: Program Listing for File player_incantation.c ============================================= |exhale_lsh| :ref:`Return to documentation for file ` (``server/game_events/player_incantation.c``) .. |exhale_lsh| unicode:: U+021B0 .. UPWARDS ARROW WITH TIP LEFTWARDS .. code-block:: cpp #include #include #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; }