Compare commits

...

8 Commits

7 changed files with 308 additions and 62 deletions

28
card.c
View File

@ -44,6 +44,34 @@ void shuffle_hand(Hand *h) {
} }
} }
void order_deck(Hand *h) {
Card *swap;
swap = h->cards[1];
h->cards[1] = h->cards[47-0];
h->cards[47-0] = swap;
swap = h->cards[5];
h->cards[5] = h->cards[47-1];
h->cards[47-1] = swap;
swap = h->cards[9];
h->cards[9] = h->cards[47-2];
h->cards[47-2] = swap;
swap = h->cards[0];
h->cards[0] = h->cards[47-12];
h->cards[47-12] = swap;
swap = h->cards[4];
h->cards[4] = h->cards[47-13];
h->cards[47-13] = swap;
swap = h->cards[8];
h->cards[8] = h->cards[47-14];
h->cards[47-14] = swap;
}
void remove_from_hand(Hand *h, Card *c) { void remove_from_hand(Hand *h, Card *c) {
bool card_found = false; bool card_found = false;
for (int i = 0; i < h->count - 1; i++) { for (int i = 0; i < h->count - 1; i++) {

View File

@ -1,4 +1,5 @@
#include <stddef.h> #include <stddef.h>
#include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@ -6,7 +7,7 @@
#include "dialog.h" #include "dialog.h"
Dialog dialogs[2]; Dialog dialogs[6];
void handle_click_cancel_yes(Game *g) { void handle_click_cancel_yes(Game *g) {
g->player.dekiyaku_action = DEKIYAKU_ACTION_CANCEL; g->player.dekiyaku_action = DEKIYAKU_ACTION_CANCEL;
@ -24,13 +25,23 @@ void handle_click_shoubu(Game *g) {
void handle_click_sage(Game *g) { void handle_click_sage(Game *g) {
g->player.dekiyaku_action = DEKIYAKU_ACTION_SAGE; g->player.dekiyaku_action = DEKIYAKU_ACTION_SAGE;
g->turn_number++;
g->state = GAME_STATE_CHOOSING_FROM_HAND; g->state = GAME_STATE_CHOOSING_FROM_HAND;
} }
void handle_click_ok_end_of_round(Game *g) {
g->state = GAME_STATE_END_OF_ROUND;
}
void handle_click_ok_end_of_game(Game *g) {
g->state = GAME_STATE_TITLE_SCREEN;
}
void init_dialogs(Game *g) { void init_dialogs(Game *g) {
Dialog *cancel_dialog = &dialogs[0]; Dialog *cancel_dialog = &dialogs[0];
cancel_dialog->text = malloc(200); cancel_dialog->text_count = 1;
strcpy(cancel_dialog->text, "Would you like to cancel?"); cancel_dialog->text[0] = malloc(200);
strcpy(cancel_dialog->text[0], "Would you like to cancel?");
cancel_dialog->text_color = BLACK; cancel_dialog->text_color = BLACK;
cancel_dialog->options_count = 2; cancel_dialog->options_count = 2;
cancel_dialog->game = g; cancel_dialog->game = g;
@ -45,10 +56,10 @@ void init_dialogs(Game *g) {
cancel_dialog->options[1].color = RED; cancel_dialog->options[1].color = RED;
cancel_dialog->options[1].handle = &handle_click_cancel_no; cancel_dialog->options[1].handle = &handle_click_cancel_no;
Dialog *shoubu_dialog = &dialogs[1]; Dialog *shoubu_dialog = &dialogs[1];
shoubu_dialog->text = malloc(200); shoubu_dialog->text_count = 1;
strcpy(shoubu_dialog->text, "You have dekiyaku! Sage or shoubu?"); shoubu_dialog->text[0] = malloc(200);
strcpy(shoubu_dialog->text[0], "You have dekiyaku! Sage or shoubu?");
shoubu_dialog->text_color = BLACK; shoubu_dialog->text_color = BLACK;
shoubu_dialog->options_count = 2; shoubu_dialog->options_count = 2;
shoubu_dialog->game = g; shoubu_dialog->game = g;
@ -56,16 +67,48 @@ void init_dialogs(Game *g) {
shoubu_dialog->options[0].text = malloc(50); shoubu_dialog->options[0].text = malloc(50);
strcpy(shoubu_dialog->options[0].text, "Sage"); strcpy(shoubu_dialog->options[0].text, "Sage");
shoubu_dialog->options[0].color = GREEN; shoubu_dialog->options[0].color = GREEN;
shoubu_dialog->options[0].handle = NULL; shoubu_dialog->options[0].handle = &handle_click_sage;
shoubu_dialog->options[1].text = malloc(50); shoubu_dialog->options[1].text = malloc(50);
strcpy(shoubu_dialog->options[1].text, "Shoubu"); strcpy(shoubu_dialog->options[1].text, "Shoubu");
shoubu_dialog->options[1].color = RED; shoubu_dialog->options[1].color = RED;
shoubu_dialog->options[1].handle = NULL; shoubu_dialog->options[1].handle = &handle_click_shoubu;
Dialog *no_dekiyaku_end_of_round_dialog = &dialogs[2];
no_dekiyaku_end_of_round_dialog->text_count = 3;
no_dekiyaku_end_of_round_dialog->text[0] = malloc(200);
no_dekiyaku_end_of_round_dialog->text[1] = malloc(200);
no_dekiyaku_end_of_round_dialog->text[2] = malloc(200);
strcpy(no_dekiyaku_end_of_round_dialog->text[0], "Player score");
strcpy(no_dekiyaku_end_of_round_dialog->text[1], "Right score");
strcpy(no_dekiyaku_end_of_round_dialog->text[2], "Left score");
no_dekiyaku_end_of_round_dialog->text_color = BLACK;
no_dekiyaku_end_of_round_dialog->options_count = 1;
no_dekiyaku_end_of_round_dialog->game = g;
no_dekiyaku_end_of_round_dialog->options[0].text = malloc(50);
strcpy(no_dekiyaku_end_of_round_dialog->options[0].text, "Okay");
no_dekiyaku_end_of_round_dialog->options[0].color = GREEN;
no_dekiyaku_end_of_round_dialog->options[0].handle = &handle_click_ok_end_of_round;
Dialog *end_of_game_dialog = &dialogs[3];
end_of_game_dialog->text_count = 3;
end_of_game_dialog->text[0] = malloc(200);
strcpy(end_of_game_dialog->text[0], "Game over something");
end_of_game_dialog->text_color = BLACK;
end_of_game_dialog->options_count = 1;
end_of_game_dialog->game = g;
end_of_game_dialog->options[0].text = malloc(50);
strcpy(end_of_game_dialog->options[0].text, "Okay");
end_of_game_dialog->options[0].color = GREEN;
end_of_game_dialog->options[0].handle = &handle_click_ok_end_of_game;
} }
Dialog *cancel_dialog() { return &dialogs[0]; } void cancel_dialog(Game *g) { g->dialog = &dialogs[0]; }
Dialog *shoubu_dialog() { return &dialogs[1]; } void shoubu_dialog(Game *g) { g->dialog = &dialogs[1]; }
void no_dekiyaku_end_of_round_dialog(Game *g) { g->dialog = &dialogs[2]; }
void end_of_game_dialog(Game *g) { g->dialog = &dialogs[3]; }
Rectangle dialog_option_outer_rectangle(Dialog *d, int i) { Rectangle dialog_option_outer_rectangle(Dialog *d, int i) {
return (Rectangle) { return (Rectangle) {
@ -90,8 +133,11 @@ void dialog_draw(Dialog *d) {
int text_width; int text_width;
DrawRectangleRec(DIALOG_OUTER_RECTANGLE, BLACK); DrawRectangleRec(DIALOG_OUTER_RECTANGLE, BLACK);
DrawRectangleRec(DIALOG_INNER_RECTANGLE, WHITE); DrawRectangleRec(DIALOG_INNER_RECTANGLE, WHITE);
text_width = MeasureText(d->text, DIALOG_TEXT_FONT_SIZE);
DrawText(d->text, 700 - (text_width / 2), 400, DIALOG_TEXT_FONT_SIZE, d->text_color); for (int i = 0; i < d->text_count; i++) {
text_width = MeasureText(d->text[i], DIALOG_TEXT_FONT_SIZE);
DrawText(d->text[i], 700 - (text_width / 2), 300 + (70 * (i - 1)), DIALOG_TEXT_FONT_SIZE, d->text_color);
}
for (int i = 0; i < d->options_count; i++) { for (int i = 0; i < d->options_count; i++) {
DialogOption *o = &d->options[i]; DialogOption *o = &d->options[i];

View File

@ -18,7 +18,8 @@ struct DialogOption {
}; };
struct Dialog { struct Dialog {
char *text; char *text[3];
int text_count;
Color text_color; Color text_color;
DialogOption options[3]; DialogOption options[3];
int options_count; int options_count;
@ -26,8 +27,10 @@ struct Dialog {
}; };
void init_dialogs(Game *g); void init_dialogs(Game *g);
Dialog *cancel_dialog(); void cancel_dialog(Game *g);
Dialog *shoubu_dialog(); void shoubu_dialog(Game *g);
void no_dekiyaku_end_of_round_dialog(Game *g);
void end_of_game_dialog(Game *g);
void dialog_draw(Dialog *d); void dialog_draw(Dialog *d);
void dialog_handle_input(Dialog *d); void dialog_handle_input(Dialog *d);

239
game.c
View File

@ -72,17 +72,32 @@ void initialize_game(Game *g) {
g->cards[i].selected = false; g->cards[i].selected = false;
} }
g->player.points = 10 * g->kan_value; g->player.points = 100 * g->kan_value;
g->right.points = 10 * g->kan_value; g->right.points = 100 * g->kan_value;
g->left.points = 10 * g->kan_value; g->left.points = 100 * g->kan_value;
g->player.points_string[0] = '\0'; g->player.points_string[0] = '\0';
g->right.points_string[0] = '\0'; g->right.points_string[0] = '\0';
g->left.points_string[0] = '\0'; g->left.points_string[0] = '\0';
g->player.hand.count = 0;
g->right.hand.count = 0;
g->left.hand.count = 0;
g->field.count = 0;
g->player.scored.count = 0;
g->right.scored.count = 0;
g->left.scored.count = 0;
g->player.dekiyaku_score = 0;
g->left.dekiyaku_score = 0;
g->right.dekiyaku_score = 0;
g->player.teyaku.calculated = false; g->player.teyaku.calculated = false;
g->right.teyaku.calculated = false; g->right.teyaku.calculated = false;
g->left.teyaku.calculated = false; g->left.teyaku.calculated = false;
g->player.seat = PLAYER;
g->right.seat = RIGHT;
g->left.seat = LEFT;
g->player.hand.position = (Vector2) { 300, 600 }; g->player.hand.position = (Vector2) { 300, 600 };
g->player.hand.display_type = HAND_DISPLAY_ROW; g->player.hand.display_type = HAND_DISPLAY_ROW;
g->right.hand.position = (Vector2) { 750, 125 }; g->right.hand.position = (Vector2) { 750, 125 };
@ -100,6 +115,22 @@ void initialize_game(Game *g) {
strcpy(teyaku_calculation, ""); strcpy(teyaku_calculation, "");
int dealer = rand() % 3;
switch (dealer) {
case PLAYER:
g->dealer = &g->player;
break;
case RIGHT:
g->dealer = &g->right;
break;
case LEFT:
g->dealer = &g->left;
break;
}
g->dealer = &g->player;
g->number_of_rounds = 3;
g->current_round = 0;
g->state = GAME_STATE_INITIALIZING; g->state = GAME_STATE_INITIALIZING;
} }
@ -125,8 +156,12 @@ void handle_input(Game *g) {
g->state = GAME_STATE_INITIALIZING; g->state = GAME_STATE_INITIALIZING;
return; return;
} }
if (g->dialog) {
return dialog_handle_input(g->dialog);
}
if (!is_player_turn(g)) return; if (!is_player_turn(g)) return;
if (g->dialog) return dialog_handle_input(g->dialog);
switch (g->state) { switch (g->state) {
case GAME_STATE_CHOOSING_FROM_HAND: case GAME_STATE_CHOOSING_FROM_HAND:
@ -190,6 +225,23 @@ void handle_input(Game *g) {
} }
} }
break; break;
case GAME_STATE_CHOOSING_TARGET_FROM_DECK:
if (IsMouseButtonPressed(0)) {
mouse_pos = GetMousePosition();
for (int i = 0; i < g->field.count; i++) {
if (point_within_card(g->field.cards[i], mouse_pos)) {
Card *selected_card = g->deck.cards[g->deck.count - 1];
if (valid_play(&g->field, selected_card, g->field.cards[i])) {
g->current_play_from_hand = selected_card;
g->current_play_target = g->field.cards[i];
} else {
printf("Invalid\n");
}
break;
}
}
}
break;
default: default:
break; break;
} }
@ -236,8 +288,7 @@ void run_frame_ai_playing(Game *g) {
} }
void run_frame_initializing(Game *g) { void run_frame_initializing(Game *g) {
// TODO: choose the dealer in a more effective manner g->turn_number = g->dealer->seat;
g->turn_number = -1;
g->player.hand.count = 0; g->player.hand.count = 0;
g->right.hand.count = 0; g->right.hand.count = 0;
@ -265,6 +316,7 @@ void run_frame_initializing(Game *g) {
} }
shuffle_hand(&g->deck); shuffle_hand(&g->deck);
// order_deck(&g->deck);
kan_points_string(g, g->player.points, g->player.points_string); kan_points_string(g, g->player.points, g->player.points_string);
kan_points_string(g, g->right.points, g->right.points_string); kan_points_string(g, g->right.points, g->right.points_string);
@ -286,20 +338,14 @@ bool misdeal(Game *g) {
} }
void run_frame_dealing(Game *g) { void run_frame_dealing(Game *g) {
if (g->player.hand.count < 4) { if (current_player(g)->hand.count < 4) {
deal(&g->deck, &g->player.hand, 4, true); deal(&g->deck, &current_player(g)->hand, 4, is_player_turn(g));
} else if (g->left.hand.count < 4) { g->turn_number++;
deal(&g->deck, &g->left.hand, 4, false);
} else if (g->right.hand.count < 4) {
deal(&g->deck, &g->right.hand, 4, false);
} else if (g->field.count < 3) { } else if (g->field.count < 3) {
deal(&g->deck, &g->field, 3, true); deal(&g->deck, &g->field, 3, true);
} else if (g->player.hand.count < 7) { } else if (current_player(g)->hand.count < 7) {
deal(&g->deck, &g->player.hand, 3, true); deal(&g->deck, &current_player(g)->hand, 3, is_player_turn(g));
} else if (g->left.hand.count < 7) { g->turn_number++;
deal(&g->deck, &g->left.hand, 3, false);
} else if (g->right.hand.count < 7) {
deal(&g->deck, &g->right.hand, 3, false);
} else if (g->field.count < 6) { } else if (g->field.count < 6) {
deal(&g->deck, &g->field, 3, true); deal(&g->deck, &g->field, 3, true);
} else { } else {
@ -307,6 +353,7 @@ void run_frame_dealing(Game *g) {
printf("misdeal\n"); printf("misdeal\n");
g->state = GAME_STATE_INITIALIZING; g->state = GAME_STATE_INITIALIZING;
} else { } else {
g->turn_number++;
g->state = GAME_STATE_CALCULATING_FIELD_MULTIPLIER; g->state = GAME_STATE_CALCULATING_FIELD_MULTIPLIER;
} }
} }
@ -336,7 +383,7 @@ void run_frame_start_of_turn(Game *g) {
void run_frame_checking_for_cancel(Game *g) { void run_frame_checking_for_cancel(Game *g) {
if (current_player(g)->dekiyaku_action == DEKIYAKU_ACTION_SAGE) { if (current_player(g)->dekiyaku_action == DEKIYAKU_ACTION_SAGE) {
if (is_player_turn(g)) { if (is_player_turn(g)) {
g->dialog = cancel_dialog(); cancel_dialog(g);
} else { } else {
// TODO: the AI might want to cancel at some point // TODO: the AI might want to cancel at some point
g->state = GAME_STATE_CHOOSING_FROM_HAND; g->state = GAME_STATE_CHOOSING_FROM_HAND;
@ -360,7 +407,7 @@ void run_frame_choosing_from_hand(Game *g) {
run_frame_player_choosing_from_hand(g); run_frame_player_choosing_from_hand(g);
} else { } else {
run_frame_ai_playing(g); run_frame_ai_playing(g);
g->state = GAME_STATE_PLAYING_FROM_DECK; g->state = GAME_STATE_SHOWING_CARD_FROM_DECK;
} }
} }
@ -404,29 +451,58 @@ void run_frame_choosing_target(Game *g) {
add_to_hand(&g->field, g->current_play_from_hand); add_to_hand(&g->field, g->current_play_from_hand);
g->current_play_from_hand = NULL; g->current_play_from_hand = NULL;
} }
g->state = GAME_STATE_PLAYING_FROM_DECK; g->state = GAME_STATE_SHOWING_CARD_FROM_DECK;
} }
} }
void run_frame_showing_card_from_deck(Game *g) {
Card *top_card = g->deck.cards[g->deck.count - 1];
remove_from_hand(&g->deck, top_card);
add_to_hand(&g->deck, top_card);
top_card->visible = true;
top_card->move.end_time = 0.3;
top_card->move.destination.x = top_card->move.destination.x + 100;
g->state = GAME_STATE_PLAYING_FROM_DECK;
}
void run_frame_playing_from_deck(Game *g) { void run_frame_playing_from_deck(Game *g) {
Hand *to_hand = &current_player(g)->scored; Hand *to_hand = &current_player(g)->scored;
Card *top_card = g->deck.cards[g->deck.count - 1]; Card *top_card = g->deck.cards[g->deck.count - 1];
if (top_card->visible) { Card *targets[4];
Card *target = valid_target(top_card, &g->field); int target_count = 0;
if (target) { valid_targets(top_card, &g->field, &targets[0], &target_count);
capture_card_from_field(g, top_card, target, &g->deck, to_hand);
} else { if (target_count == 1) {
capture_card_from_field(g, top_card, targets[0], &g->deck, to_hand);
g->state = GAME_STATE_CHECKING_FOR_NEW_DEKIYAKU;
} else if(target_count == 0) {
remove_from_hand(&g->deck, top_card); remove_from_hand(&g->deck, top_card);
add_to_hand(&g->field, top_card); add_to_hand(&g->field, top_card);
}
g->state = GAME_STATE_CHECKING_FOR_NEW_DEKIYAKU; g->state = GAME_STATE_CHECKING_FOR_NEW_DEKIYAKU;
} else { } else {
remove_from_hand(&g->deck, top_card); g->state = GAME_STATE_CHOOSING_TARGET_FROM_DECK;
add_to_hand(&g->deck, top_card); return;
top_card->visible = true; }
top_card->move.end_time = 0.3; }
top_card->move.destination.x = top_card->move.destination.x + 100;
void run_frame_choosing_target_from_deck(Game *g) {
Hand *to_hand = &current_player(g)->scored;
Card *top_card = g->deck.cards[g->deck.count - 1];
Card *targets[4];
int target_count = 0;
valid_targets(top_card, &g->field, &targets[0], &target_count);
if (is_player_turn(g)) {
if (g->current_play_target) {
capture_card_from_field(g, top_card, g->current_play_target, &g->deck, to_hand);
g->state = GAME_STATE_CHECKING_FOR_NEW_DEKIYAKU;
}
} else {
// TODO: better AI
capture_card_from_field(g, top_card, targets[0], &g->deck, to_hand);
g->state = GAME_STATE_CHECKING_FOR_NEW_DEKIYAKU;
} }
} }
@ -437,7 +513,7 @@ void run_frame_checking_for_new_dekiyaku(Game *g) {
if (new_score != cp->dekiyaku_score) { if (new_score != cp->dekiyaku_score) {
cp->dekiyaku_score = new_score; cp->dekiyaku_score = new_score;
if (is_player_turn(g)) { if (is_player_turn(g)) {
g->dialog = shoubu_dialog(); shoubu_dialog(g);
} else { } else {
// TODO: better AI // TODO: better AI
cp->dekiyaku_action = DEKIYAKU_ACTION_SHOUBU; cp->dekiyaku_action = DEKIYAKU_ACTION_SHOUBU;
@ -453,7 +529,7 @@ void run_frame_selecting_dekiyaku_action(Game *g) {
if (g->player.dekiyaku_action != DEKIYAKU_ACTION_NONE) { if (g->player.dekiyaku_action != DEKIYAKU_ACTION_NONE) {
g->state = GAME_STATE_CALCULATING_DEKIYAKU_SCORE; g->state = GAME_STATE_CALCULATING_DEKIYAKU_SCORE;
} else { } else {
g->dialog = shoubu_dialog(); shoubu_dialog(g);
} }
} else { } else {
// TODO: better AI // TODO: better AI
@ -463,38 +539,63 @@ void run_frame_selecting_dekiyaku_action(Game *g) {
} }
void run_frame_calculating_scores(Game *g) { void run_frame_calculating_scores(Game *g) {
printf("Hand scores: %d %d %d\n", hand_points(&g->player.scored), hand_points(&g->right.scored), hand_points(&g->left.scored)); no_dekiyaku_end_of_round_dialog(g);
int hp[3];
hp[0] = hand_points(&g->player.scored);
hp[1] = hand_points(&g->right.scored);
hp[2] = hand_points(&g->left.scored);
SpecialCase special_case = calculate_special_case(g); SpecialCase special_case = calculate_special_case(g);
switch(special_case.type) { switch(special_case.type) {
case SPECIAL_CASE_ALL_EIGHTS: case SPECIAL_CASE_ALL_EIGHTS:
printf("All eights! Dealer gets %d kan\n", special_case.score); sprintf(g->dialog->text[0], "All eights!");
sprintf(g->dialog->text[0], "Dealer gets %d kan", special_case.score);
transfer_kan(g, &g->dealer->points, &g->player.points, special_case.score);
transfer_kan(g, &g->dealer->points, &g->right.points, special_case.score);
transfer_kan(g, &g->dealer->points, &g->left.points, special_case.score);
break; break;
case SPECIAL_CASE_DOUBLE_EIGHTS: case SPECIAL_CASE_DOUBLE_EIGHTS:
case SPECIAL_CASE_SIXTEEN_CHAFF: case SPECIAL_CASE_SIXTEEN_CHAFF:
printf("Double eights or 16 chaff! Player %d gets %d kan\n", special_case.target, special_case.score); if (special_case.type == SPECIAL_CASE_DOUBLE_EIGHTS) sprintf(g->dialog->text[0], "Double eights!");
else sprintf(g->dialog->text[0], "Sixteen chaff!");
sprintf(g->dialog->text[1], "Player %d gets %d kan\n", special_case.target, special_case.score);
switch (special_case.target) { switch (special_case.target) {
case SPECIAL_CASE_TARGET_PLAYER: case SPECIAL_CASE_TARGET_PLAYER:
transfer_kan(g, &g->player.points, &g->right.points, special_case.score); transfer_kan(g, &g->player.points, &g->right.points, special_case.score);
transfer_kan(g, &g->player.points, &g->left.points, special_case.score); transfer_kan(g, &g->player.points, &g->left.points, special_case.score);
g->dealer = &g->player;
break; break;
case SPECIAL_CASE_TARGET_RIGHT: case SPECIAL_CASE_TARGET_RIGHT:
transfer_kan(g, &g->right.points, &g->player.points, special_case.score); transfer_kan(g, &g->right.points, &g->player.points, special_case.score);
transfer_kan(g, &g->right.points, &g->left.points, special_case.score); transfer_kan(g, &g->right.points, &g->left.points, special_case.score);
g->dealer = &g->right;
break; break;
case SPECIAL_CASE_TARGET_LEFT: case SPECIAL_CASE_TARGET_LEFT:
transfer_kan(g, &g->left.points, &g->right.points, special_case.score); transfer_kan(g, &g->left.points, &g->right.points, special_case.score);
transfer_kan(g, &g->left.points, &g->player.points, special_case.score); transfer_kan(g, &g->left.points, &g->player.points, special_case.score);
g->dealer = &g->left;
break; break;
} }
break; break;
default: default:
transfer_points(g, &g->player.points, &g->temp_points, hand_points(&g->player.scored)); sprintf(g->dialog->text[0], "Player score: %d", hp[0]);
transfer_points(g, &g->right.points, &g->temp_points, hand_points(&g->right.scored)); sprintf(g->dialog->text[1], "Right score: %d", hp[1]);
transfer_points(g, &g->left.points, &g->temp_points, hand_points(&g->left.scored)); sprintf(g->dialog->text[2], "Left score: %d", hp[2]);
transfer_points(g, &g->player.points, &g->temp_points, hp[0]);
transfer_points(g, &g->right.points, &g->temp_points, hp[1]);
transfer_points(g, &g->left.points, &g->temp_points, hp[2]);
if (hp[0] > hp[1]) {
if (hp[0] > hp[2]) g->dealer = &g->player;
else
if (hp[2] > hp[1]) g->dealer = &g->left;
else g->dealer = &g->right;
} else {
if (hp[1] > hp[2]) g->dealer = &g->right;
else g->dealer = &g->left;
}
break; break;
} }
g->state = GAME_STATE_INITIALIZING;
} }
void run_frame_calculating_dekiyaku_score(Game *g) { void run_frame_calculating_dekiyaku_score(Game *g) {
@ -502,6 +603,19 @@ void run_frame_calculating_dekiyaku_score(Game *g) {
g->state = GAME_STATE_INITIALIZING; g->state = GAME_STATE_INITIALIZING;
} }
void run_frame_end_of_round(Game *g) {
g->current_round++;
if (g->current_round >= g->number_of_rounds) {
g->state = GAME_STATE_END_OF_GAME;
} else {
g->state = GAME_STATE_INITIALIZING;
}
}
void run_frame_end_of_game(Game *g) {
end_of_game_dialog(g);
}
void move_cards(Game *g) { void move_cards(Game *g) {
float delta = GetFrameTime(); float delta = GetFrameTime();
for (int i = 0; i < 48; i++) { for (int i = 0; i < 48; i++) {
@ -549,9 +663,15 @@ void run_frame(Game *g) {
case GAME_STATE_CHOOSING_TARGET: case GAME_STATE_CHOOSING_TARGET:
run_frame_choosing_target(g); run_frame_choosing_target(g);
break; break;
case GAME_STATE_SHOWING_CARD_FROM_DECK:
run_frame_showing_card_from_deck(g);
break;
case GAME_STATE_PLAYING_FROM_DECK: case GAME_STATE_PLAYING_FROM_DECK:
run_frame_playing_from_deck(g); run_frame_playing_from_deck(g);
break; break;
case GAME_STATE_CHOOSING_TARGET_FROM_DECK:
run_frame_choosing_target_from_deck(g);
break;
case GAME_STATE_CHECKING_FOR_NEW_DEKIYAKU: case GAME_STATE_CHECKING_FOR_NEW_DEKIYAKU:
run_frame_checking_for_new_dekiyaku(g); run_frame_checking_for_new_dekiyaku(g);
break; break;
@ -564,17 +684,46 @@ void run_frame(Game *g) {
case GAME_STATE_CALCULATING_DEKIYAKU_SCORE: case GAME_STATE_CALCULATING_DEKIYAKU_SCORE:
run_frame_calculating_dekiyaku_score(g); run_frame_calculating_dekiyaku_score(g);
break; break;
case GAME_STATE_END_OF_ROUND:
run_frame_end_of_round(g);
break;
case GAME_STATE_END_OF_GAME:
run_frame_end_of_game(g);
break;
}
}
void draw_player_cards(Game *g, Player *p) {
for (int i = 0; i < p->hand.count; i++) {
draw_card(p->hand.cards[i], &g->cards_texture);
}
for (int i = 0; i < p->scored.count; i++) {
draw_card(p->scored.cards[i], &g->cards_texture);
}
}
void draw_cards(Game *g) {
draw_player_cards(g, &g->player);
draw_player_cards(g, &g->right);
draw_player_cards(g, &g->left);
for (int i = 0; i < g->field.count; i++) {
draw_card(g->field.cards[i], &g->cards_texture);
}
for (int i = 0; i < g->deck.count; i++) {
draw_card(g->deck.cards[i], &g->cards_texture);
} }
} }
void draw_frame(Game *g) { void draw_frame(Game *g) {
BeginDrawing(); BeginDrawing();
ClearBackground(RAYWHITE); ClearBackground(RAYWHITE);
for (int i = 0; i < 48; i++) {
draw_card(&g->cards[i], &g->cards_texture);
}
if (g->field_multiplier) DrawText(g->field_multiplier->name, 60, 385, 40, BLACK); draw_cards(g);
if (g->state == GAME_STATE_DEALING) DrawText("Dealing....", 60, 385, 40, BLACK);
else if (g->field_multiplier) DrawText(g->field_multiplier->name, 60, 385, 40, BLACK);
if (g->player.teyaku.calculated) { if (g->player.teyaku.calculated) {
char s[200]; char s[200];

8
game.h
View File

@ -22,11 +22,16 @@ typedef enum GameState {
GAME_STATE_CHECKING_FOR_CANCEL, GAME_STATE_CHECKING_FOR_CANCEL,
GAME_STATE_CHOOSING_FROM_HAND, GAME_STATE_CHOOSING_FROM_HAND,
GAME_STATE_CHOOSING_TARGET, GAME_STATE_CHOOSING_TARGET,
GAME_STATE_SHOWING_CARD_FROM_DECK,
GAME_STATE_PLAYING_FROM_DECK, GAME_STATE_PLAYING_FROM_DECK,
GAME_STATE_CHOOSING_TARGET_FROM_DECK,
GAME_STATE_CHECKING_FOR_NEW_DEKIYAKU, GAME_STATE_CHECKING_FOR_NEW_DEKIYAKU,
GAME_STATE_SELECTING_DEKIYAKU_ACTION, GAME_STATE_SELECTING_DEKIYAKU_ACTION,
GAME_STATE_CALCULATING_SCORES, GAME_STATE_CALCULATING_SCORES,
GAME_STATE_CALCULATING_DEKIYAKU_SCORE, GAME_STATE_CALCULATING_DEKIYAKU_SCORE,
GAME_STATE_END_OF_ROUND,
GAME_STATE_END_OF_GAME,
GAME_STATE_TITLE_SCREEN,
} GameState; } GameState;
struct Game { struct Game {
@ -42,6 +47,9 @@ struct Game {
int temp_points; int temp_points;
int turn_number; int turn_number;
Dialog *dialog; Dialog *dialog;
Player *dealer;
int number_of_rounds;
int current_round;
}; };
void initialize_game(Game *g); void initialize_game(Game *g);

11
play.c
View File

@ -1,4 +1,5 @@
#include <stddef.h> #include <stddef.h>
#include <stdio.h>
#include <stdbool.h> #include <stdbool.h>
#include "play.h" #include "play.h"
@ -25,6 +26,16 @@ bool valid_play(Hand *field, Card *played, Card *target) {
} }
} }
void valid_targets(Card *active, Hand *field, Card **targets, int *target_count) {
*target_count = 0;
for (int i = 0; i < field->count; i++) {
if (field->cards[i]->month == active->month) {
targets[(*target_count)++] = field->cards[i];
}
}
targets[*target_count] = NULL; // Sentinel
}
Card *valid_target(Card *active, Hand *field) { Card *valid_target(Card *active, Hand *field) {
for (int i = 0; i < field->count; i++) { for (int i = 0; i < field->count; i++) {
if (field->cards[i]->month == active->month) { if (field->cards[i]->month == active->month) {

1
play.h
View File

@ -13,6 +13,7 @@ struct Play {
}; };
bool valid_play(Hand *field, Card *played, Card *target); bool valid_play(Hand *field, Card *played, Card *target);
void valid_targets(Card *active, Hand *field, Card **targets, int *target_count);
Card *valid_target(Card *active, Hand *field); Card *valid_target(Card *active, Hand *field);
Play ai_play(Hand *hand, Hand *field); Play ai_play(Hand *hand, Hand *field);