298 lines
11 KiB
C
298 lines
11 KiB
C
// Copyright 2025 Bill Rossi
|
|
//
|
|
// This file is part of Hanafuda Hachi-Hachi.
|
|
//
|
|
// Hanafuda Hachi-Hachi is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
|
//
|
|
// Hanafuda Hachi-Hachi is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License along with Hanafuda Hachi-Hachi. If not, see <https://www.gnu.org/licenses/>.
|
|
#include <stddef.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include <raylib.h>
|
|
|
|
#include "dialog.h"
|
|
|
|
Dialog dialogs[8];
|
|
|
|
void handle_click_cancel_yes(Game *g) {
|
|
g->player.dekiyaku_action = DEKIYAKU_ACTION_CANCEL;
|
|
g->state = GAME_STATE_CALCULATING_DEKIYAKU_SCORE;
|
|
}
|
|
|
|
void handle_click_cancel_no(Game *g) {
|
|
g->state = GAME_STATE_CHOOSING_FROM_HAND;
|
|
}
|
|
|
|
void handle_click_shoubu(Game *g) {
|
|
g->player.dekiyaku_action = DEKIYAKU_ACTION_SHOUBU;
|
|
g->state = GAME_STATE_CALCULATING_DEKIYAKU_SCORE;
|
|
}
|
|
|
|
void handle_click_sage(Game *g) {
|
|
if (!g->first_sage) g->first_sage = &g->player;
|
|
g->player.dekiyaku_action = DEKIYAKU_ACTION_SAGE;
|
|
g->turn_number++;
|
|
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 handle_click_play_again(Game *g) {
|
|
g->state = GAME_STATE_NEW_GAME;
|
|
}
|
|
|
|
void handle_click_quit(Game *g) {
|
|
g->should_close = true;
|
|
}
|
|
|
|
void handle_click_claim_set_teyaku(Game *g) {
|
|
g->player.teyaku.chaff = CHAFF_TEYAKU_NONE;
|
|
teyaku_to_string(&g->player.teyaku, g->player.teyaku_string);
|
|
g->state = GAME_STATE_START_OF_TURN;
|
|
}
|
|
|
|
void handle_click_claim_chaff_teyaku(Game *g) {
|
|
g->player.teyaku.set = SET_TEYAKU_NONE;
|
|
teyaku_to_string(&g->player.teyaku, g->player.teyaku_string);
|
|
g->state = GAME_STATE_START_OF_TURN;
|
|
}
|
|
|
|
void handle_click_claim_both_teyaku(Game *g) {
|
|
g->state = GAME_STATE_START_OF_TURN;
|
|
}
|
|
|
|
void handle_click_dont_claim_teyaku(Game *g) {
|
|
(&g->player.teyaku)->chaff = CHAFF_TEYAKU_NONE;
|
|
g->player.teyaku.set = SET_TEYAKU_NONE;
|
|
teyaku_to_string(&g->player.teyaku, g->player.teyaku_string);
|
|
g->state = GAME_STATE_START_OF_TURN;
|
|
}
|
|
|
|
void handle_click_no_action(Game *g) {
|
|
}
|
|
|
|
void init_dialogs(Game *g) {
|
|
Dialog *cancel_dialog = &dialogs[0];
|
|
cancel_dialog->text_count = 1;
|
|
cancel_dialog->text[0] = malloc(200);
|
|
strcpy(cancel_dialog->text[0], "Would you like to cancel?");
|
|
cancel_dialog->text_size = 60;
|
|
cancel_dialog->options_count = 2;
|
|
cancel_dialog->game = g;
|
|
|
|
cancel_dialog->options[0].text = malloc(50);
|
|
strcpy(cancel_dialog->options[0].text, "Yes");
|
|
cancel_dialog->options[0].color = GREEN;
|
|
cancel_dialog->options[0].handle = &handle_click_cancel_yes;
|
|
|
|
cancel_dialog->options[1].text = malloc(50);
|
|
strcpy(cancel_dialog->options[1].text, "No");
|
|
cancel_dialog->options[1].color = RED;
|
|
cancel_dialog->options[1].handle = &handle_click_cancel_no;
|
|
|
|
Dialog *shoubu_dialog = &dialogs[1];
|
|
shoubu_dialog->text_count = 2;
|
|
shoubu_dialog->text[0] = malloc(200);
|
|
shoubu_dialog->text[1] = malloc(200);
|
|
strcpy(shoubu_dialog->text[0], "You have dekiyaku!");
|
|
strcpy(shoubu_dialog->text[1], "Sage or shoubu?");
|
|
shoubu_dialog->text_size = 60;
|
|
shoubu_dialog->options_count = 2;
|
|
shoubu_dialog->game = g;
|
|
|
|
shoubu_dialog->options[0].text = malloc(50);
|
|
strcpy(shoubu_dialog->options[0].text, "Sage");
|
|
shoubu_dialog->options[0].color = GREEN;
|
|
shoubu_dialog->options[0].handle = &handle_click_sage;
|
|
|
|
shoubu_dialog->options[1].text = malloc(50);
|
|
strcpy(shoubu_dialog->options[1].text, "Shoubu");
|
|
shoubu_dialog->options[1].color = RED;
|
|
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_size = 40;
|
|
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 = 4;
|
|
end_of_game_dialog->text[0] = malloc(200);
|
|
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_size = 30;
|
|
end_of_game_dialog->options_count = 2;
|
|
end_of_game_dialog->game = g;
|
|
|
|
end_of_game_dialog->options[0].text = malloc(50);
|
|
strcpy(end_of_game_dialog->options[0].text, "Play Again");
|
|
end_of_game_dialog->options[0].color = GREEN;
|
|
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 = 4;
|
|
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);
|
|
dekiyaku_end_of_round_dialog->text[3] = 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");
|
|
strcpy(dekiyaku_end_of_round_dialog->text[3], "");
|
|
dekiyaku_end_of_round_dialog->text_size = 50;
|
|
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;
|
|
|
|
Dialog *teyaku_dialog = &dialogs[5];
|
|
teyaku_dialog->text_count = 4;
|
|
teyaku_dialog->text[0] = malloc(200);
|
|
teyaku_dialog->text[1] = malloc(200);
|
|
teyaku_dialog->text[2] = malloc(200);
|
|
teyaku_dialog->text[3] = malloc(200);
|
|
strcpy(teyaku_dialog->text[0], "You can claim some teyaku");
|
|
strcpy(teyaku_dialog->text[3], "(There is no reason not to claim both)");
|
|
teyaku_dialog->text_size = 40;
|
|
teyaku_dialog->options_count = 4;
|
|
teyaku_dialog->game = g;
|
|
|
|
teyaku_dialog->options[0].text = malloc(50);
|
|
strcpy(teyaku_dialog->options[0].text, "Claim Set Teyaku");
|
|
teyaku_dialog->options[0].color = SKYBLUE;
|
|
teyaku_dialog->options[0].handle = &handle_click_claim_set_teyaku;
|
|
|
|
teyaku_dialog->options[1].text = malloc(50);
|
|
strcpy(teyaku_dialog->options[1].text, "Claim Chaff Teyaku");
|
|
teyaku_dialog->options[1].color = SKYBLUE;
|
|
teyaku_dialog->options[1].handle = &handle_click_claim_chaff_teyaku;
|
|
|
|
teyaku_dialog->options[2].text = malloc(50);
|
|
strcpy(teyaku_dialog->options[2].text, "Claim Both Teyaku");
|
|
teyaku_dialog->options[2].color = GREEN;
|
|
teyaku_dialog->options[2].handle = &handle_click_claim_both_teyaku;
|
|
|
|
teyaku_dialog->options[3].text = malloc(50);
|
|
strcpy(teyaku_dialog->options[3].text, "Don't Claim");
|
|
teyaku_dialog->options[3].color = RED;
|
|
teyaku_dialog->options[3].handle = &handle_click_dont_claim_teyaku;
|
|
|
|
Dialog *end_of_round_dialog = &dialogs[6];
|
|
end_of_round_dialog->text_count = 3;
|
|
end_of_round_dialog->text[0] = malloc(200);
|
|
end_of_round_dialog->text[1] = malloc(200);
|
|
end_of_round_dialog->text[2] = malloc(200);
|
|
end_of_round_dialog->text_size = 40;
|
|
end_of_round_dialog->options_count = 1;
|
|
end_of_round_dialog->game = g;
|
|
|
|
end_of_round_dialog->options[0].text = "Okay";
|
|
end_of_round_dialog->options[0].color = GREEN;
|
|
end_of_round_dialog->options[0].handle = &handle_click_no_action;
|
|
}
|
|
|
|
void cancel_dialog(Game *g) { g->dialog = &dialogs[0]; }
|
|
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]; }
|
|
void dekiyaku_end_of_round_dialog(Game *g) { g->dialog = &dialogs[4]; }
|
|
void teyaku_dialog(Game *g) { g->dialog = &dialogs[5]; }
|
|
void end_of_round_dialog(Game *g) { g->dialog = &dialogs[6]; }
|
|
|
|
Rectangle dialog_option_outer_rectangle(Dialog *d, int i) {
|
|
if (d->options_count < 4) {
|
|
return (Rectangle) {
|
|
((960 * (i + 1)) / (d->options_count + 1)) - 10 + 200,
|
|
500,
|
|
MeasureText(d->options[i].text, DIALOG_OPTION_FONT_SIZE) + 20,
|
|
40,
|
|
};
|
|
} else {
|
|
return (Rectangle) {
|
|
((960 * (i % 2)) / ((d->options_count / 2) + 1)) - 10 + 250,
|
|
500 + ((i / 2) * 50),
|
|
MeasureText(d->options[i].text, DIALOG_OPTION_FONT_SIZE) + 20,
|
|
40,
|
|
};
|
|
}
|
|
}
|
|
|
|
Rectangle dialog_option_inner_rectangle(Dialog *d, int i) {
|
|
Rectangle outer = dialog_option_outer_rectangle(d, i);
|
|
return (Rectangle) {
|
|
outer.x + 3,
|
|
outer.y + 3,
|
|
outer.width - 6,
|
|
outer.height - 6,
|
|
};
|
|
}
|
|
|
|
void dialog_draw(Dialog *d) {
|
|
Vector2 mouse_pos = GetMousePosition();
|
|
DrawText("Hide Dialog", 1225, 870, 20, BLACK);
|
|
if (mouse_pos.x > 1225 && mouse_pos.y > 850) return;
|
|
|
|
int text_width;
|
|
DrawRectangleRec(DIALOG_OUTER_RECTANGLE, BLACK);
|
|
DrawRectangleRec(DIALOG_INNER_RECTANGLE, WHITE);
|
|
|
|
for (int i = 0; i < d->text_count; i++) {
|
|
text_width = MeasureText(d->text[i], d->text_size);
|
|
DrawText(d->text[i], 700 - (text_width / 2), 300 + (70 * (i - 1)), d->text_size, BLACK);
|
|
}
|
|
|
|
for (int i = 0; i < d->options_count; i++) {
|
|
DialogOption *o = &d->options[i];
|
|
Rectangle outer = dialog_option_outer_rectangle(d, i);
|
|
Rectangle inner = dialog_option_inner_rectangle(d, i);
|
|
DrawRectangleRec(outer, BLACK);
|
|
DrawRectangleRec(inner, o->color);
|
|
DrawText(o->text, inner.x + 3, inner.y + 3, DIALOG_OPTION_FONT_SIZE, BLACK);
|
|
}
|
|
}
|
|
|
|
void dialog_handle_input(Dialog *d) {
|
|
Vector2 mouse_pos = GetMousePosition();
|
|
if (IsMouseButtonPressed(0)) {
|
|
for (int i = 0; i < d->options_count; i++) {
|
|
DialogOption *o = &d->options[i];
|
|
Rectangle outer = dialog_option_outer_rectangle(d, i);
|
|
if (CheckCollisionPointRec(mouse_pos, outer)) {
|
|
o->handle(d->game);
|
|
d->game->dialog = NULL;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|