Mirai's Miscellaneous Misadventures

M54 / core / dialogues.c

1/* license: AGPLv3 or later */
2/* copyright 2024 zamfofex */
3
4#include <stdlib.h>
5#include "../mimimi.h"
6
7static void mimimi_box(struct mimimi_image *image, unsigned char stroke, unsigned char fill)
8{
9	static unsigned char colors[10][10] = {{0, 0, 0, 0, 0, 0, 0, 0, 0, 1}, {0, 0, 0, 0, 0, 0, 0, 1, 1, 1}, {0, 0, 0, 0, 0, 1, 1, 1, 1, 1}, {0, 0, 0, 0, 1, 1, 1, 1, 2, 2}, {0, 0, 0, 1, 1, 1, 2, 2, 2, 2}, {0, 0, 1, 1, 1, 2, 2, 2, 2, 2}, {0, 0, 1, 1, 2, 2, 2, 2, 2, 2}, {0, 1, 1, 1, 2, 2, 2, 2, 2, 2}, {0, 1, 1, 2, 2, 2, 2, 2, 2, 2}, {1, 1, 1, 2, 2, 2, 2, 2, 2, 2}, };
10	
11	int width, height;
12	int x0, y0, x1, y1;
13	unsigned char table[3];
14	unsigned char color;
15	
16	width = image->width;
17	height = image->height;
18	
19	table[0] = 0;
20	table[1] = stroke;
21	table[2] = fill;
22	
23	for (y1 = 0 ; y1 < height ; y1++) {
24		for (x1 = 0 ; x1 < width ; x1++) {
25			image->colors[x1 + y1 * width] = fill;
26		}
27	}
28	for (x1 = 0 ; x1 < width ; x1++) {
29		image->colors[x1 + 0 * width] = stroke;
30		image->colors[x1 + 1 * width] = stroke;
31		image->colors[x1 + (height - 1) * width] = stroke;
32		image->colors[x1 + (height - 2) * width] = stroke;
33	}
34	
35	for (y1 = 0 ; y1 < height ; y1++) {
36		image->colors[0 + y1 * width] = stroke;
37		image->colors[1 + y1 * width] = stroke;
38		image->colors[(width - 1) + y1 * width] = stroke;
39		image->colors[(width - 2) + y1 * width] = stroke;
40	}
41	
42	for (y0 = 0 ; y0 < 10 ; y0++) {
43		
44		for (x0 = 0 ; x0 < 10 ; x0++) {
45			
46			x1 = width - 1 - x0;
47			y1 = height - 1 - y0;
48			
49			color = table[colors[y0][x0]];
50			
51			image->colors[x0 + y0 * width] = color;
52			image->colors[x1 + y0 * width] = color;
53			image->colors[x0 + y1 * width] = color;
54			image->colors[x1 + y1 * width] = color;
55		}
56	}
57}
58
59static void mimimi_portrait(struct mimimi_image *image, struct mimimi_model *model, unsigned char background)
60{
61	static unsigned char mask[6][6] = {{0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 1, 1}, {0, 0, 0, 1, 1, 1}, {0, 0, 1, 1, 1, 1}, {0, 1, 1, 1, 1, 1}, {0, 1, 1, 1, 1, 1}, };
62	
63	int width, height;
64	struct mimimi_pose pose = {0};
65	int i;
66	int x0, y0, x1, y1;
67	
68	width = image->width;
69	height = image->height;
70	
71	pose.layers[0].y_angle = 42;
72	
73	pose.x = width / 2;
74	pose.y = height / 2 + 16;
75	
76	for (i = 0 ; i < width * height ; i++) image->colors[i] = background;
77	
78	mimimi_pose(image, model, &pose);
79	
80	for (y0 = 0 ; y0 < 6 ; y0++) {
81		
82		for (x0 = 0 ; x0 < 6 ; x0++) {
83			
84			if (mask[y0][x0] != 0) continue;
85			
86			x1 = width - 1 - x0;
87			y1 = height - 1 - y0;
88			
89			image->colors[x0 + y0 * width] = 0;
90			image->colors[x1 + y0 * width] = 0;
91			image->colors[x0 + y1 * width] = 0;
92			image->colors[x1 + y1 * width] = 0;
93		}
94	}
95}
96
97static void mimimi_dialogue_box(struct mimimi_image *box, struct mimimi_model *model, char *name, int width, char *paragraph)
98{
99	char *text;
100	int count;
101	int height;
102	unsigned char colors[18 * 18];
103	struct mimimi_image portrait;
104	int n, i;
105	
106	text = paragraph;
107	count = 0;
108	while (*text != 0) {
109		text = mimimi_skip_line(mimimi_font, text, width - 12);
110		count++;
111	}
112	
113	height = 30 + 14 * count;
114	
115	box->width = width;
116	box->height = height;
117	mimimi_box(box, 4, 13);
118	
119	portrait.width = 18;
120	portrait.height = 18;
121	portrait.colors = colors;
122	mimimi_portrait(&portrait, model, 8);
123	mimimi_stamp(box, 6, 6, &portrait);
124	
125	n = mimimi_draw_paragraph(mimimi_font, name, box, 28, 7, 4);
126	for (i = 28 ; i < n - 1 ; i++) box->colors[i + 18 * box->width] = 4;
127	
128	mimimi_draw_text(mimimi_font, paragraph, width - 12, 14, box, 6, 24, 4);
129}
130
131void mimimi_toast_dialogue(struct mimimi_toast_dialogue *toast_dialogue, struct mimimi_dialogue *dialogue)
132{
133	struct mimimi_image *images;
134	int i;
135	struct mimimi_dialogue_paragraph *paragraph;
136	int count;
137	
138	toast_dialogue->images = malloc(dialogue->count * sizeof *toast_dialogue->images);
139	toast_dialogue->delays = malloc(dialogue->count * sizeof *toast_dialogue->delays);
140	toast_dialogue->heights = malloc(dialogue->count * sizeof *toast_dialogue->heights);
141	
142	if (toast_dialogue->images == NULL) exit(1);
143	if (toast_dialogue->delays == NULL) exit(1);
144	if (toast_dialogue->heights == NULL) exit(1);
145	
146	images = toast_dialogue->images;
147	
148	for (i = 0 ; i < dialogue->count ; i++) {
149		
150		paragraph = dialogue->paragraphs + i;
151		
152		images[i].width = 128;
153		images[i].height = 1024;
154		
155		images[i].colors = malloc(images[i].width * images[i].height);
156		if (images[i].colors == NULL) exit(1);
157		mimimi_dialogue_box(images + i, paragraph->model, paragraph->name, images[i].width, paragraph->text);
158		toast_dialogue->heights[i] = images[i].height + 8;
159		
160		count = 0;
161		while (paragraph->text[count] != 0) count++;
162		toast_dialogue->delays[i] = count * 2;
163	}
164	
165	toast_dialogue->count = dialogue->count;
166	toast_dialogue->i = 0;
167	toast_dialogue->j = 0;
168	toast_dialogue->k = 0;
169}
170
171int mimimi_toast_dialogue_tick(struct mimimi_toast_dialogue *dialogue, struct mimimi_image *image)
172{
173	int i;
174	int height;
175	
176	i = dialogue->i;
177	if (i >= dialogue->count) return 1;
178	
179	height = dialogue->heights[i];
180	
181	if (dialogue->k == 0) {
182		mimimi_stamp(image, 8, image->height - dialogue->j * height / 8, dialogue->images + i);
183		dialogue->j++;
184		if (dialogue->j >= 8) {
185			dialogue->j = 0;
186			dialogue->k++;
187		}
188		return 0;
189	}
190	
191	if (dialogue->k == 1) {
192		mimimi_stamp(image, 8, image->height - height, dialogue->images + i);
193		dialogue->j++;
194		if (dialogue->j >= dialogue->delays[i]) {
195			dialogue->j = 0;
196			dialogue->k++;
197		}
198		return 0;
199	}
200	
201	if (dialogue->k == 2) {
202		mimimi_stamp(image, 8 - (128 + 8) * dialogue->j / 16, image->height - height, dialogue->images + i);
203		dialogue->j++;
204		if (dialogue->j >= 16) {
205			dialogue->j = 0;
206			dialogue->k = 0;
207			dialogue->i++;
208		}
209		return 0;
210	}
211	
212	/* unreachable */
213	return 0;
214}