Mirai's Miscellaneous Misadventures

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