/* Turn a number of serfs into knight for the given player. */ int player_promote_serfs_to_knights(player_t *player, int number) { int promoted = 0; for (int i = 1; i < game.max_serf_index && number > 0; i++) { if (SERF_ALLOCATED(i)) { serf_t *serf = game_get_serf(i); if (serf->state == SERF_STATE_IDLE_IN_STOCK && SERF_PLAYER(serf) == player->player_num && SERF_TYPE(serf) == SERF_GENERIC) { inventory_t *inv = game_get_inventory(serf->s.idle_in_stock.inv_index); if (inv->resources[RESOURCE_SWORD] > 0 && inv->resources[RESOURCE_SHIELD] > 0) { inv->resources[RESOURCE_SWORD] -= 1; inv->resources[RESOURCE_SHIELD] -= 1; inv->spawn_priority -= 1; inv->serfs[SERF_GENERIC] = 0; serf->type = (SERF_KNIGHT_0 << 2) | (serf->type & 3); player->serf_count[SERF_GENERIC] -= 1; player->serf_count[SERF_KNIGHT_0] += 1; player->total_military_score += 1; promoted += 1; number -= 1; } } } } return promoted; }
/* Turn a number of serfs into knight for the given player. */ int player_promote_serfs_to_knights(player_t *player, int number) { int promoted = 0; for (uint i = 1; i < game.max_serf_index && number > 0; i++) { if (SERF_ALLOCATED(i)) { serf_t *serf = game_get_serf(i); if (serf->state == SERF_STATE_IDLE_IN_STOCK && SERF_PLAYER(serf) == player->player_num && SERF_TYPE(serf) == SERF_GENERIC) { inventory_t *inv = game_get_inventory(serf->s.idle_in_stock.inv_index); if (inv->resources[RESOURCE_SWORD] > 0 && inv->resources[RESOURCE_SHIELD] > 0) { inv->resources[RESOURCE_SWORD] -= 1; inv->resources[RESOURCE_SHIELD] -= 1; inv->generic_count -= 1; inv->serfs[SERF_GENERIC] = 0; serf_set_type(serf, SERF_KNIGHT_0); promoted += 1; number -= 1; } } } } return promoted; }
void player_start_attack(player_t *player) { const int min_level_hut[] = { 1, 1, 2, 2, 3 }; const int min_level_tower[] = { 1, 2, 3, 4, 6 }; const int min_level_fortress[] = { 1, 3, 6, 9, 12 }; building_t *target = game_get_building(player->building_attacked); if (!BUILDING_IS_DONE(target) || (BUILDING_TYPE(target) != BUILDING_HUT && BUILDING_TYPE(target) != BUILDING_TOWER && BUILDING_TYPE(target) != BUILDING_FORTRESS && BUILDING_TYPE(target) != BUILDING_CASTLE) || !BUILDING_IS_ACTIVE(target) || BUILDING_STATE(target) != 3) { return; } for (int i = 0; i < player->attacking_building_count; i++) { /* TODO building index may not be valid any more(?). */ building_t *b = game_get_building(player->attacking_buildings[i]); if (BUILDING_IS_BURNING(b) || MAP_OWNER(b->pos) != player->player_num) { continue; } map_pos_t flag_pos = MAP_MOVE_DOWN_RIGHT(b->pos); if (MAP_SERF_INDEX(flag_pos) != 0) { /* Check if building is under siege. */ serf_t *s = game_get_serf(MAP_SERF_INDEX(flag_pos)); if (SERF_PLAYER(s) != player->player_num) continue; } const int *min_level = NULL; switch (BUILDING_TYPE(b)) { case BUILDING_HUT: min_level = min_level_hut; break; case BUILDING_TOWER: min_level = min_level_tower; break; case BUILDING_FORTRESS: min_level = min_level_fortress; break; default: continue; break; } int state = BUILDING_STATE(b); int knights_present = b->stock[0].available; int to_send = knights_present - min_level[player->knight_occupation[state] & 0xf]; for (int j = 0; j < to_send; j++) { /* Find most approriate knight to send according to player settings. */ int best_type = PLAYER_SEND_STRONGEST(player) ? SERF_KNIGHT_0 : SERF_KNIGHT_4; int best_index = -1; int knight_index = b->serf_index; while (knight_index != 0) { serf_t *knight = game_get_serf(knight_index); if (PLAYER_SEND_STRONGEST(player)) { if (SERF_TYPE(knight) >= best_type) { best_index = knight_index; best_type = SERF_TYPE(knight); } } else { if (SERF_TYPE(knight) <= best_type) { best_index = knight_index; best_type = SERF_TYPE(knight); } } knight_index = knight->s.defending.next_knight; } /* Unlink knight from list. */ int *def_index = &b->serf_index; serf_t *def_serf = game_get_serf(*def_index); while (*def_index != best_index) { def_index = &def_serf->s.defending.next_knight; def_serf = game_get_serf(*def_index); } *def_index = def_serf->s.defending.next_knight; b->stock[0].available -= 1; target->progress |= BIT(0); /* Calculate distance to target. */ int dist_col = (MAP_POS_COL(target->pos) - MAP_POS_COL(def_serf->pos)) & game.map.col_mask; if (dist_col >= game.map.cols/2) dist_col -= game.map.cols; int dist_row = (MAP_POS_ROW(target->pos) - MAP_POS_ROW(def_serf->pos)) & game.map.row_mask; if (dist_row >= game.map.rows/2) dist_row -= game.map.rows; /* Send this serf off to fight. */ serf_log_state_change(def_serf, SERF_STATE_KNIGHT_LEAVE_FOR_WALK_TO_FIGHT); def_serf->state = SERF_STATE_KNIGHT_LEAVE_FOR_WALK_TO_FIGHT; def_serf->s.leave_for_walk_to_fight.dist_col = dist_col; def_serf->s.leave_for_walk_to_fight.dist_row = dist_row; def_serf->s.leave_for_walk_to_fight.field_D = 0; def_serf->s.leave_for_walk_to_fight.field_E = 0; def_serf->s.leave_for_walk_to_fight.next_state = SERF_STATE_KNIGHT_FREE_WALKING; player->knights_attacking -= 1; if (player->knights_attacking == 0) return; } } }