Compare commits

...

7 Commits

8 changed files with 168 additions and 28 deletions

2
card.c
View File

@ -125,7 +125,7 @@ void add_to_hand(Hand *h, Card *c) {
c->move.destination.y = h->position.y; c->move.destination.y = h->position.y;
break; break;
case HAND_DISPLAY_SCORED: case HAND_DISPLAY_SCORED:
c->move.destination.x = h->position.x + (c->order * (CARD_WIDTH - 10)); c->move.destination.x = h->position.x + (c->order * (CARD_WIDTH - 30));
c->move.destination.y = h->position.y; c->move.destination.y = h->position.y;
break; break;
} }

View File

@ -37,6 +37,14 @@ void handle_click_ok_end_of_game(Game *g) {
g->state = GAME_STATE_TITLE_SCREEN; g->state = GAME_STATE_TITLE_SCREEN;
} }
void handle_click_play_again(Game *g) {
g->state = GAME_STATE_NEW_GAME;
}
void handle_click_quit(Game *g) {
g->should_close = true;
}
void init_dialogs(Game *g) { void init_dialogs(Game *g) {
Dialog *cancel_dialog = &dialogs[0]; Dialog *cancel_dialog = &dialogs[0];
cancel_dialog->text_count = 1; cancel_dialog->text_count = 1;
@ -92,23 +100,47 @@ void init_dialogs(Game *g) {
no_dekiyaku_end_of_round_dialog->options[0].handle = &handle_click_ok_end_of_round; no_dekiyaku_end_of_round_dialog->options[0].handle = &handle_click_ok_end_of_round;
Dialog *end_of_game_dialog = &dialogs[3]; Dialog *end_of_game_dialog = &dialogs[3];
end_of_game_dialog->text_count = 3; end_of_game_dialog->text_count = 4;
end_of_game_dialog->text[0] = malloc(200); end_of_game_dialog->text[0] = malloc(200);
strcpy(end_of_game_dialog->text[0], "Game over something"); end_of_game_dialog->text[1] = malloc(200);
end_of_game_dialog->text[2] = malloc(200);
end_of_game_dialog->text[3] = malloc(200);
end_of_game_dialog->text_color = BLACK; end_of_game_dialog->text_color = BLACK;
end_of_game_dialog->options_count = 1; end_of_game_dialog->options_count = 2;
end_of_game_dialog->game = g; end_of_game_dialog->game = g;
end_of_game_dialog->options[0].text = malloc(50); end_of_game_dialog->options[0].text = malloc(50);
strcpy(end_of_game_dialog->options[0].text, "Okay"); strcpy(end_of_game_dialog->options[0].text, "Play Again");
end_of_game_dialog->options[0].color = GREEN; end_of_game_dialog->options[0].color = GREEN;
end_of_game_dialog->options[0].handle = &handle_click_ok_end_of_game; end_of_game_dialog->options[0].handle = &handle_click_play_again;
end_of_game_dialog->options[1].text = malloc(50);
strcpy(end_of_game_dialog->options[1].text, "Quit");
end_of_game_dialog->options[1].color = GREEN;
end_of_game_dialog->options[1].handle = &handle_click_quit;
Dialog *dekiyaku_end_of_round_dialog = &dialogs[4];
dekiyaku_end_of_round_dialog->text_count = 3;
dekiyaku_end_of_round_dialog->text[0] = malloc(200);
dekiyaku_end_of_round_dialog->text[1] = malloc(200);
dekiyaku_end_of_round_dialog->text[2] = malloc(200);
strcpy(dekiyaku_end_of_round_dialog->text[0], "Player score");
strcpy(dekiyaku_end_of_round_dialog->text[1], "Right score");
strcpy(dekiyaku_end_of_round_dialog->text[2], "Left score");
dekiyaku_end_of_round_dialog->text_color = BLACK;
dekiyaku_end_of_round_dialog->options_count = 1;
dekiyaku_end_of_round_dialog->game = g;
dekiyaku_end_of_round_dialog->options[0].text = malloc(50);
strcpy(dekiyaku_end_of_round_dialog->options[0].text, "Okay");
dekiyaku_end_of_round_dialog->options[0].color = GREEN;
dekiyaku_end_of_round_dialog->options[0].handle = &handle_click_ok_end_of_round;
} }
void cancel_dialog(Game *g) { g->dialog = &dialogs[0]; } void cancel_dialog(Game *g) { g->dialog = &dialogs[0]; }
void shoubu_dialog(Game *g) { g->dialog = &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 no_dekiyaku_end_of_round_dialog(Game *g) { g->dialog = &dialogs[2]; }
void end_of_game_dialog(Game *g) { g->dialog = &dialogs[3]; } void end_of_game_dialog(Game *g) { g->dialog = &dialogs[3]; }
void dekiyaku_end_of_round_dialog(Game *g) { g->dialog = &dialogs[4]; }
Rectangle dialog_option_outer_rectangle(Dialog *d, int i) { Rectangle dialog_option_outer_rectangle(Dialog *d, int i) {
return (Rectangle) { return (Rectangle) {

View File

@ -18,7 +18,7 @@ struct DialogOption {
}; };
struct Dialog { struct Dialog {
char *text[3]; char *text[8];
int text_count; int text_count;
Color text_color; Color text_color;
DialogOption options[3]; DialogOption options[3];
@ -31,6 +31,7 @@ void cancel_dialog(Game *g);
void shoubu_dialog(Game *g); void shoubu_dialog(Game *g);
void no_dekiyaku_end_of_round_dialog(Game *g); void no_dekiyaku_end_of_round_dialog(Game *g);
void end_of_game_dialog(Game *g); void end_of_game_dialog(Game *g);
void dekiyaku_end_of_round_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);

View File

@ -3,9 +3,9 @@
#include "field_multiplier.h" #include "field_multiplier.h"
#include "card.h" #include "card.h"
static FieldMultiplier small_field = { "Small Field", 1 }; static FieldMultiplier small_field = { "Small Field", "", 1 };
static FieldMultiplier large_field = { "Large Field", 2 }; static FieldMultiplier large_field = { "Large Field", "Score transfers are doubled", 2 };
static FieldMultiplier grand_field = { "Grand Field", 4 }; static FieldMultiplier grand_field = { "Grand Field", "Score transfers are quadrupled" ,4 };
FieldMultiplier *calculate_field_multiplier(Hand *h) { FieldMultiplier *calculate_field_multiplier(Hand *h) {
bool large = false; bool large = false;

View File

@ -7,6 +7,7 @@ typedef struct FieldMultiplier FieldMultiplier;
struct FieldMultiplier { struct FieldMultiplier {
char *name; char *name;
char *explanation;
int value; int value;
}; };

140
game.c
View File

@ -19,7 +19,7 @@ void initialize_game(Game *g) {
UnloadImage(cards_image); UnloadImage(cards_image);
g->deck.count = 0; g->deck.count = 0;
g->deck.position = (Vector2) { 800, 400 }; g->deck.position = (Vector2) { 500, 300 };
g->deck.display_type = HAND_DISPLAY_DECK; g->deck.display_type = HAND_DISPLAY_DECK;
g->should_close = false; g->should_close = false;
g->state = GAME_STATE_INITIALIZING; g->state = GAME_STATE_INITIALIZING;
@ -64,10 +64,10 @@ void initialize_game(Game *g) {
case 41: case 41:
t = ANIMAL; break; t = ANIMAL; break;
} }
g->cards[i] = (Card) { i, t, rt, month, { 800, 100 }, false }; g->cards[i] = (Card) { i, t, rt, month, { 500, 300 }, false };
g->cards[i].move.end_time = 0.; g->cards[i].move.end_time = 0.;
g->cards[i].move.position = &g->cards[i].position; g->cards[i].move.position = &g->cards[i].position;
g->cards[i].move.destination = (Vector2) { 800, 400 }; g->cards[i].move.destination = (Vector2) { 500, 300 };
g->cards[i].order = i; g->cards[i].order = i;
g->cards[i].selected = false; g->cards[i].selected = false;
} }
@ -78,6 +78,9 @@ void initialize_game(Game *g) {
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.name = "Player";
g->right.name = "Right";
g->left.name = "Left";
g->player.hand.count = 0; g->player.hand.count = 0;
g->right.hand.count = 0; g->right.hand.count = 0;
@ -104,8 +107,6 @@ void initialize_game(Game *g) {
g->right.hand.display_type = HAND_DISPLAY_ROW; g->right.hand.display_type = HAND_DISPLAY_ROW;
g->left.hand.position = (Vector2) { 50, 125 }; g->left.hand.position = (Vector2) { 50, 125 };
g->left.hand.display_type = HAND_DISPLAY_ROW; g->left.hand.display_type = HAND_DISPLAY_ROW;
g->field.position = (Vector2) { 400, 300 };
g->field.display_type = HAND_DISPLAY_FIELD;
g->player.scored.position = (Vector2) { 300, 750 }; g->player.scored.position = (Vector2) { 300, 750 };
g->player.scored.display_type = HAND_DISPLAY_SCORED; g->player.scored.display_type = HAND_DISPLAY_SCORED;
g->right.scored.position = (Vector2) { 750, 25 }; g->right.scored.position = (Vector2) { 750, 25 };
@ -113,6 +114,9 @@ void initialize_game(Game *g) {
g->left.scored.position = (Vector2) { 50, 25 }; g->left.scored.position = (Vector2) { 50, 25 };
g->left.scored.display_type = HAND_DISPLAY_SCORED; g->left.scored.display_type = HAND_DISPLAY_SCORED;
g->field.position = (Vector2) { 600, 300 };
g->field.display_type = HAND_DISPLAY_FIELD;
strcpy(teyaku_calculation, ""); strcpy(teyaku_calculation, "");
int dealer = rand() % 3; int dealer = rand() % 3;
@ -127,9 +131,8 @@ void initialize_game(Game *g) {
g->dealer = &g->left; g->dealer = &g->left;
break; break;
} }
g->dealer = &g->player;
g->number_of_rounds = 3; g->number_of_rounds = 1;
g->current_round = 0; g->current_round = 0;
g->state = GAME_STATE_INITIALIZING; g->state = GAME_STATE_INITIALIZING;
} }
@ -461,7 +464,7 @@ void run_frame_showing_card_from_deck(Game *g) {
add_to_hand(&g->deck, top_card); add_to_hand(&g->deck, top_card);
top_card->visible = true; top_card->visible = true;
top_card->move.end_time = 0.3; top_card->move.end_time = 0.3;
top_card->move.destination.x = top_card->move.destination.x + 100; top_card->move.destination.y = top_card->move.destination.y + 150;
g->state = GAME_STATE_PLAYING_FROM_DECK; g->state = GAME_STATE_PLAYING_FROM_DECK;
} }
@ -498,6 +501,8 @@ void run_frame_choosing_target_from_deck(Game *g) {
if (g->current_play_target) { if (g->current_play_target) {
capture_card_from_field(g, top_card, g->current_play_target, &g->deck, to_hand); capture_card_from_field(g, top_card, g->current_play_target, &g->deck, to_hand);
g->state = GAME_STATE_CHECKING_FOR_NEW_DEKIYAKU; g->state = GAME_STATE_CHECKING_FOR_NEW_DEKIYAKU;
g->current_play_from_hand = NULL;
g->current_play_target = NULL;
} }
} else { } else {
// TODO: better AI // TODO: better AI
@ -598,12 +603,50 @@ void run_frame_calculating_scores(Game *g) {
} }
} }
void calculate_dekiyaku_score(Game *g, Player *p) {
Dekiyaku d;
calculate_dekiyaku(&p->scored, &d);
if (p->dekiyaku_action == DEKIYAKU_ACTION_SHOUBU) {
sprintf(g->dialog->text[0], "%s wins with dekiyaku!", p->name);
dekiyaku_to_string(&d, g->dialog->text[1]);
sprintf(g->dialog->text[2], "%s wins %d kan", p->name, dekiyaku_score(&d));
transfer_kan(g, &p->points, &g->player.points, dekiyaku_score(&d));
transfer_kan(g, &p->points, &g->right.points, dekiyaku_score(&d));
transfer_kan(g, &p->points, &g->left.points, dekiyaku_score(&d));
} else {
sprintf(g->dialog->text[0], "%s cancels with dekiyaku!", p->name);
dekiyaku_to_string(&d, g->dialog->text[1]);
if (dekiyaku_score(&d) % 2) {
sprintf(g->dialog->text[2], "%s wins %d.5 kan", p->name, dekiyaku_score(&d) / 2);
transfer_points(g, &p->points, &g->player.points, (dekiyaku_score(&d) * g->kan_value) / 2);
transfer_points(g, &p->points, &g->right.points, (dekiyaku_score(&d) * g->kan_value) / 2);
transfer_points(g, &p->points, &g->left.points, (dekiyaku_score(&d) * g->kan_value) / 2);
} else {
sprintf(g->dialog->text[2], "%s wins %d kan", p->name, dekiyaku_score(&d) / 2);
transfer_kan(g, &p->points, &g->player.points, dekiyaku_score(&d) / 2);
transfer_kan(g, &p->points, &g->right.points, dekiyaku_score(&d) / 2);
transfer_kan(g, &p->points, &g->left.points, dekiyaku_score(&d) / 2);
}
}
}
void run_frame_calculating_dekiyaku_score(Game *g) { void run_frame_calculating_dekiyaku_score(Game *g) {
printf("Somebody won with dekiyaku. Cool.\n"); fflush(stdout); dekiyaku_end_of_round_dialog(g);
g->state = GAME_STATE_INITIALIZING; if (g->player.dekiyaku_action == DEKIYAKU_ACTION_CANCEL || g->player.dekiyaku_action == DEKIYAKU_ACTION_SHOUBU) {
calculate_dekiyaku_score(g, &g->player);
} else if (g->right.dekiyaku_action == DEKIYAKU_ACTION_CANCEL || g->right.dekiyaku_action == DEKIYAKU_ACTION_SHOUBU) {
calculate_dekiyaku_score(g, &g->right);
} else if (g->left.dekiyaku_action == DEKIYAKU_ACTION_CANCEL || g->left.dekiyaku_action == DEKIYAKU_ACTION_SHOUBU) {
calculate_dekiyaku_score(g, &g->left);
} else {
// Hands are exhausted
}
} }
void run_frame_end_of_round(Game *g) { void run_frame_end_of_round(Game *g) {
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->left.points, g->left.points_string);
g->current_round++; g->current_round++;
if (g->current_round >= g->number_of_rounds) { if (g->current_round >= g->number_of_rounds) {
g->state = GAME_STATE_END_OF_GAME; g->state = GAME_STATE_END_OF_GAME;
@ -612,8 +655,60 @@ void run_frame_end_of_round(Game *g) {
} }
} }
void *winning_player_string(Game *g, char *string) {
int p = g->player.points;
int r = g->right.points;
int l = g->left.points;
if (p == r && p == l) sprintf(string, "It's a three-way tie!");
else if (p > r && p == l) sprintf(string, "%s and %s tie for the win!", g->player.name, g->left.name);
else if (p > l && p == r) sprintf(string, "%s and %s tie for the win!", g->player.name, g->right.name);
else if (p < l && l == r) sprintf(string, "%s and %s tie for the win!", g->right.name, g->left.name);
else if (p > l && p > r) sprintf(string, "%s wins!", g->player.name);
else if (l > r && l > p) sprintf(string, "%s wins!", g->left.name);
else if (r > l && r > p) sprintf(string, "%s wins!", g->right.name);
else sprintf(string, "I have no idea who wins (%d %d %d) wins!", p, r, l);
}
void run_frame_end_of_game(Game *g) { void run_frame_end_of_game(Game *g) {
end_of_game_dialog(g); end_of_game_dialog(g);
char line[200];
kan_points_string(g, g->player.points, &line[0]);
sprintf(g->dialog->text[0], "Player: %s", line);
kan_points_string(g, g->right.points, &line[0]);
sprintf(g->dialog->text[1], "Right: %s", line);
kan_points_string(g, g->left.points, &line[0]);
sprintf(g->dialog->text[2], "Left: %s", line);
winning_player_string(g, g->dialog->text[3]);
}
void run_frame_new_game(Game *g) {
g->field_multiplier = NULL;
g->dialog = NULL;
g->player.points = 100 * g->kan_value;
g->right.points = 100 * g->kan_value;
g->left.points = 100 * g->kan_value;
g->player.points_string[0] = '\0';
g->right.points_string[0] = '\0';
g->left.points_string[0] = '\0';
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->current_round = 0;
g->state = GAME_STATE_INITIALIZING;
} }
void move_cards(Game *g) { void move_cards(Game *g) {
@ -690,6 +785,9 @@ void run_frame(Game *g) {
case GAME_STATE_END_OF_GAME: case GAME_STATE_END_OF_GAME:
run_frame_end_of_game(g); run_frame_end_of_game(g);
break; break;
case GAME_STATE_NEW_GAME:
run_frame_new_game(g);
break;
} }
} }
@ -722,23 +820,29 @@ void draw_frame(Game *g) {
draw_cards(g); draw_cards(g);
if (g->state == GAME_STATE_DEALING) DrawText("Dealing....", 60, 385, 40, BLACK); if (g->state == GAME_STATE_DEALING) {
else if (g->field_multiplier) DrawText(g->field_multiplier->name, 60, 385, 40, BLACK); DrawText("Dealing....", 60, 385, 40, BLACK);
} else if (g->field_multiplier) {
if (g->player.teyaku.calculated) { DrawText(g->field_multiplier->name, 60, 385, 30, BLACK);
char s[200]; DrawText(g->field_multiplier->explanation, 60, 445, 20, BLACK);
teyaku_to_string(&g->player.teyaku, s);
DrawText(s, 5, 25, 30, BLACK);
} }
DrawText(g->player.points_string, 40, 700, 20, BLACK); DrawText(g->player.points_string, 40, 700, 20, BLACK);
DrawText(g->right.points_string, 40, 750, 20, BLACK); DrawText(g->right.points_string, 40, 750, 20, BLACK);
DrawText(g->left.points_string, 40, 800, 20, BLACK); DrawText(g->left.points_string, 40, 800, 20, BLACK);
char round_text[20];
if (g->current_round < g->number_of_rounds)
sprintf(round_text, "Round %d / %d", g->current_round+1, g->number_of_rounds);
else
sprintf(round_text, "Game Over");
DrawText(round_text, 20, 875, 20, BLACK);
if (is_player_turn(g)) { if (is_player_turn(g)) {
switch (g->state) { switch (g->state) {
case GAME_STATE_CHOOSING_FROM_HAND: case GAME_STATE_CHOOSING_FROM_HAND:
DrawText("Choose a card to play", 60, 485, 20, BLACK); DrawText("Choose a card to play from your hand", 60, 485, 20, BLACK);
break; break;
case GAME_STATE_CHOOSING_TARGET: case GAME_STATE_CHOOSING_TARGET:
DrawText("Choose a target on the field", 60, 485, 20, BLACK); DrawText("Choose a target on the field", 60, 485, 20, BLACK);

1
game.h
View File

@ -31,6 +31,7 @@ typedef enum GameState {
GAME_STATE_CALCULATING_DEKIYAKU_SCORE, GAME_STATE_CALCULATING_DEKIYAKU_SCORE,
GAME_STATE_END_OF_ROUND, GAME_STATE_END_OF_ROUND,
GAME_STATE_END_OF_GAME, GAME_STATE_END_OF_GAME,
GAME_STATE_NEW_GAME,
GAME_STATE_TITLE_SCREEN, GAME_STATE_TITLE_SCREEN,
} GameState; } GameState;

View File

@ -12,6 +12,7 @@ typedef enum PlayerSeat {
struct Player { struct Player {
PlayerSeat seat; PlayerSeat seat;
char *name;
Hand hand, scored; Hand hand, scored;
Teyaku teyaku; Teyaku teyaku;
Dekiyaku dekiyaku; Dekiyaku dekiyaku;