comparison examples/example-action/main.c @ 209:23a844fdc911

examples: move all into subdirectories, closes #2513
author David Demelier <markand@malikania.fr>
date Wed, 11 Nov 2020 17:10:40 +0100
parents examples/example-action.c@133926e08d6e
children 76afe639fd72
comparison
equal deleted inserted replaced
208:c0e0d4accae8 209:23a844fdc911
1 /*
2 * example-action.c -- example on how to use automatic actions
3 *
4 * Copyright (c) 2020 David Demelier <markand@malikania.fr>
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 #include <assert.h>
20
21 #include <core/action.h>
22 #include <core/core.h>
23 #include <core/event.h>
24 #include <core/game.h>
25 #include <core/image.h>
26 #include <core/maths.h>
27 #include <core/painter.h>
28 #include <core/panic.h>
29 #include <core/script.h>
30 #include <core/sprite.h>
31 #include <core/state.h>
32 #include <core/sys.h>
33 #include <core/texture.h>
34 #include <core/util.h>
35 #include <core/window.h>
36
37 #include <ui/theme.h>
38 #include <ui/ui.h>
39
40 #include <rpg/message.h>
41 #include <rpg/rpg.h>
42
43 #include <assets/sprites/chest.h>
44 #include <assets/sprites/people.h>
45
46 #define W (1280)
47 #define H (720)
48
49 #define MW (W * 0.75)
50 #define MX ((W / 2) - (MW / 2))
51 #define MY (100)
52
53 /* This is a stack of "parallel" events. */
54 static struct action_stack events;
55
56 /* This is a stack of modal events. */
57 static struct action_stack modal;
58
59 /*
60 * Event object for the chest to click on.
61 */
62 static struct {
63 struct message msg;
64 struct action msg_act;
65 int x;
66 int y;
67 bool opened;
68 struct texture image;
69 struct sprite sprite;
70 struct action event;
71 } chest = {
72 .msg = {
73 .x = MX,
74 .y = MY,
75 .w = MW,
76 .text = {
77 "100000 pièces.",
78 "Te voilà riche sale file de crevette."
79 }
80 }
81 };
82
83 /*
84 * Event object for the guide who ask dialog with you.
85 *
86 * It is a script spawned upon click like this.
87 *
88 * [guide.event]
89 * | spawn
90 * (on click)------------------->[message 1]
91 * v
92 * [message 2]
93 * v
94 * [question 3]
95 * spawn v
96 * [response]<---------------------[check result]
97 * v
98 * [message 4/5]
99 */
100 static struct {
101 struct {
102 struct message msg;
103 struct action act;
104 } msgs[5];
105
106 /* This is the sprite and action to click on. */
107 int x;
108 int y;
109 struct texture image;
110 struct sprite sprite;
111 struct action event;
112
113 /* This is the event for the response. */
114 struct action response;
115
116 struct script script;
117 struct action script_act;
118 } guide = {
119 .msgs = {
120 {
121 .msg = {
122 .x = MX,
123 .y = MY,
124 .w = MW,
125 .delay = MESSAGE_DELAY_DEFAULT,
126 .flags = MESSAGE_FLAGS_FADEIN,
127 .text = {
128 "Bienvenue dans ce monde Molko."
129 }
130 },
131 },
132 {
133 .msg = {
134 .x = MX,
135 .y = MY,
136 .w = MW,
137 .text = {
138 "Penses tu vraiment pouvoir me battre ?"
139 }
140 }
141 },
142 {
143 .msg = {
144 .x = MX,
145 .y = MY,
146 .w = MW,
147 .flags = MESSAGE_FLAGS_QUESTION,
148 .text = {
149 "Non j'ai la trouille.",
150 "Bien sûr, je suis la légende."
151 }
152 }
153 },
154
155 /* In case of NO. */
156 {
157 .msg = {
158 .x = MX,
159 .y = MY,
160 .w = MW,
161 .text = {
162 "Poule mouillée."
163 }
164 }
165 },
166
167 /* In case of YES. */
168 {
169 .msg = {
170 .x = MX,
171 .y = MY,
172 .w = MW,
173 .text = {
174 "Prépare toi à souffrir."
175 }
176 }
177 }
178 }
179 };
180
181 static bool
182 guide_response_update(struct action *act, unsigned int ticks)
183 {
184 /* Immediately return to get access to end. */
185 (void)act;
186 (void)ticks;
187
188 return true;
189 }
190
191 static void
192 guide_response_end(struct action *act)
193 {
194 (void)act;
195
196 /* We add a final response depending on the result. */
197 const int index = guide.msgs[2].msg.index + 3;
198
199 message_action(&guide.msgs[index].msg, &guide.msgs[index].act);
200 message_query(&guide.msgs[index].msg, NULL, &guide.msgs[index].msg.h);
201 action_stack_add(&modal, &guide.msgs[index].act);
202 }
203
204 static void
205 guide_popup(void)
206 {
207 /* Prepare the script with first 3 messages. */
208 for (size_t i = 0; i < 3; ++i) {
209 message_action(&guide.msgs[i].msg, &guide.msgs[i].act);
210 message_query(&guide.msgs[i].msg, NULL, &guide.msgs[i].msg.h);
211 script_append(&guide.script, &guide.msgs[i].act);
212 }
213
214 /* Reset the message index. */
215 guide.msgs[2].msg.index = 0;
216
217 /* This is final action that analyze user input. */
218 guide.response.update = guide_response_update;
219 guide.response.end = guide_response_end;
220 script_append(&guide.script, &guide.response);
221
222 script_action(&guide.script, &guide.script_act);
223 action_stack_add(&modal, &guide.script_act);
224 }
225
226 static void
227 guide_handle(struct action *act, const union event *ev)
228 {
229 (void)act;
230
231 if (!action_stack_completed(&modal))
232 return;
233
234 switch (ev->type) {
235 case EVENT_CLICKDOWN:
236 if (maths_is_boxed(guide.x, guide.y,
237 guide.sprite.cellw, guide.sprite.cellh,
238 ev->click.x, ev->click.y))
239 guide_popup();
240 break;
241 default:
242 break;
243 }
244 }
245
246 static void
247 guide_draw(struct action *act)
248 {
249 (void)act;
250
251 sprite_draw(&guide.sprite, 0, 0, guide.x, guide.y);
252 }
253
254 static void
255 guide_init(void)
256 {
257 if (!image_openmem(&guide.image, sprites_people, sizeof (sprites_people)))
258 panic();
259
260 sprite_init(&guide.sprite, &guide.image, 48, 48);
261
262 /* This is the global guide action. */
263 guide.event.handle = guide_handle;
264 guide.event.draw = guide_draw;
265 guide.x = 200;
266 guide.y = 200;
267 }
268
269 static void
270 chest_handle(struct action *act, const union event *ev)
271 {
272 (void)act;
273
274 if (chest.opened || !action_stack_completed(&modal))
275 return;
276
277 switch (ev->type) {
278 case EVENT_CLICKDOWN:
279 if (maths_is_boxed(chest.x, chest.y, chest.sprite.cellw, chest.sprite.cellh,
280 ev->click.x, ev->click.y)) {
281 chest.opened = true;
282 message_action(&chest.msg, &chest.msg_act);
283 message_query(&chest.msg, NULL, &chest.msg.h);
284 action_stack_add(&modal, &chest.msg_act);
285 }
286 default:
287 break;
288 }
289 }
290
291 static void
292 chest_draw(struct action *act)
293 {
294 (void)act;
295
296 const int row = chest.opened ? 3 : 0;
297
298 sprite_draw(&chest.sprite, row, 0, chest.x, chest.y);
299 }
300
301 static void
302 chest_init(void)
303 {
304 if (!image_openmem(&chest.image, sprites_chest, sizeof (sprites_chest)))
305 panic();
306
307 sprite_init(&chest.sprite, &chest.image, 32, 32);
308
309 chest.x = 100;
310 chest.y = 100;
311 chest.event.handle = chest_handle;
312 chest.event.draw = chest_draw;
313 }
314
315 static void
316 init(void)
317 {
318 if (!core_init() || !ui_init() || !rpg_init())
319 panic();
320 if (!window_open("Example - Action", W, H))
321 panic();
322
323 guide_init();
324 chest_init();
325 }
326
327 static void
328 handle(struct state *st, const union event *ev)
329 {
330 (void)st;
331
332 switch (ev->type) {
333 case EVENT_QUIT:
334 game_quit();
335 break;
336 default:
337 action_stack_handle(&events, ev);
338 action_stack_handle(&modal, ev);
339 break;
340 }
341 }
342
343 static void
344 update(struct state *st, unsigned int ticks)
345 {
346 (void)st;
347
348 action_stack_update(&events, ticks);
349 action_stack_update(&modal, ticks);
350 }
351
352 static void
353 draw(struct state *st)
354 {
355 (void)st;
356
357 painter_set_color(0xffffffff);
358 painter_clear();
359 action_stack_draw(&events);
360 action_stack_draw(&modal);
361 painter_present();
362 }
363
364 static void
365 run(void)
366 {
367 struct state state = {
368 .handle = handle,
369 .update = update,
370 .draw = draw
371 };
372
373 action_stack_add(&events, &chest.event);
374 action_stack_add(&events, &guide.event);
375
376 game_switch(&state, true);
377 game_loop();
378 }
379
380 static void
381 quit(void)
382 {
383 window_finish();
384 rpg_finish();
385 ui_finish();
386 core_finish();
387 }
388
389 int
390 main(int argc, char **argv)
391 {
392 (void)argc;
393 (void)argv;
394
395 init();
396 run();
397 quit();
398
399 return 0;
400 }