Mercurial > molko
comparison examples/example-battle.c @ 192:4ad7420ab678
rpg: add minimalist battle system, continue #2477 @60h
- Implement battle as states,
- Add basic support for spells (no calculation yet),
- Add won/lost state,
- Add animations and messages,
- Add order.
author | David Demelier <markand@malikania.fr> |
---|---|
date | Sat, 07 Nov 2020 16:00:39 +0100 |
parents | |
children | 133926e08d6e |
comparison
equal
deleted
inserted
replaced
191:633a25df450e | 192:4ad7420ab678 |
---|---|
1 /* | |
2 * example-battle.c -- show how to use battle | |
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 #include <stdio.h> | |
21 #include <string.h> | |
22 | |
23 #include <core/clock.h> | |
24 #include <core/core.h> | |
25 #include <core/event.h> | |
26 #include <core/image.h> | |
27 #include <core/painter.h> | |
28 #include <core/panic.h> | |
29 #include <core/sprite.h> | |
30 #include <core/sys.h> | |
31 #include <core/texture.h> | |
32 #include <core/util.h> | |
33 #include <core/window.h> | |
34 | |
35 #include <ui/align.h> | |
36 #include <ui/label.h> | |
37 #include <ui/theme.h> | |
38 #include <ui/ui.h> | |
39 | |
40 #include <rpg/character.h> | |
41 #include <rpg/battle.h> | |
42 #include <rpg/rpg.h> | |
43 #include <rpg/spell.h> | |
44 | |
45 #include "battle/registry.h" | |
46 #include "battle/spell-fire.h" | |
47 | |
48 #define W 1280 | |
49 #define H 720 | |
50 | |
51 static void | |
52 adventurer_reset(struct character *ch) | |
53 { | |
54 /* TODO: this function should compute the attack thanks to the level. */ | |
55 ch->hpmax = 120; | |
56 ch->mpmax = 50; | |
57 ch->atk = 50; | |
58 ch->def = 50; | |
59 ch->agt = 50; | |
60 ch->luck = 50; | |
61 } | |
62 | |
63 static void | |
64 haunted_wood_reset(struct character *ch) | |
65 { | |
66 ch->hpmax = ch->hp = 2000; | |
67 ch->mpmax = ch->mp = 250; | |
68 ch->atk = 178; | |
69 ch->def = 80; | |
70 ch->agt = 80; | |
71 ch->luck = 100; | |
72 } | |
73 | |
74 static void | |
75 black_cat_reset(struct character *ch) | |
76 { | |
77 ch->hpmax = ch->hp = 126; | |
78 ch->mpmax = ch->mp = 38; | |
79 ch->atk = 22; | |
80 ch->def = 19; | |
81 ch->agt = 21; | |
82 ch->luck = 14; | |
83 } | |
84 | |
85 static struct character team[] = { | |
86 { | |
87 .name = "Molko", | |
88 .type = "Adventurer", | |
89 .level = 1, | |
90 .hp = 120, | |
91 .mp = 50, | |
92 .reset = adventurer_reset, | |
93 .sprite = ®istry_sprites[REGISTRY_TEXTURE_JOHN], | |
94 .spells = { | |
95 &spell_fire | |
96 } | |
97 }, | |
98 { | |
99 .name = "Fake Molko", | |
100 .type = "Adventurer", | |
101 .level = 1, | |
102 .hp = 120, | |
103 .mp = 50, | |
104 .reset = adventurer_reset, | |
105 .sprite = ®istry_sprites[REGISTRY_TEXTURE_JOHN], | |
106 .spells = { | |
107 &spell_fire | |
108 } | |
109 } | |
110 }; | |
111 | |
112 static void | |
113 haunted_wood_strat(struct character *ch, struct battle *bt) | |
114 { | |
115 (void)ch; | |
116 | |
117 /* TODO: Select randomly. */ | |
118 battle_attack(bt, bt->order_cur->ch, bt->team[0].ch); | |
119 } | |
120 | |
121 static void | |
122 black_cat_strat(struct character *ch, struct battle *bt) | |
123 { | |
124 (void)ch; | |
125 | |
126 /* TODO: Select randomly. */ | |
127 battle_attack(bt, bt->order_cur->ch, bt->team[0].ch); | |
128 } | |
129 | |
130 static struct character haunted_wood = { | |
131 .name = "Haunted Wood", | |
132 .type = "Wood", | |
133 .level = 30, | |
134 .reset = haunted_wood_reset, | |
135 .sprite = ®istry_sprites[REGISTRY_TEXTURE_HAUNTED_WOOD], | |
136 .exec = haunted_wood_strat | |
137 }; | |
138 | |
139 static struct character black_cat = { | |
140 .name = "Black Cat", | |
141 .type = "Cat", | |
142 .level = 6, | |
143 .reset = black_cat_reset, | |
144 .sprite = ®istry_sprites[REGISTRY_TEXTURE_BLACK_CAT], | |
145 .exec = black_cat_strat | |
146 }; | |
147 | |
148 static void | |
149 init(void) | |
150 { | |
151 struct clock clock = {0}; | |
152 | |
153 if (!core_init() || !ui_init() || !rpg_init()) | |
154 panic(); | |
155 if (!window_open("Example - Battle", W, H)) | |
156 panic(); | |
157 | |
158 /* Wait 1 second to let all events processed. */ | |
159 while (clock_elapsed(&clock) < 1000) | |
160 for (union event ev; event_poll(&ev); ) | |
161 if (ev.type == EVENT_QUIT) | |
162 return; | |
163 | |
164 registry_init(); | |
165 | |
166 /* Set cursor in default theme. */ | |
167 theme_default()->sprites[THEME_SPRITE_CURSOR] = ®istry_sprites[REGISTRY_TEXTURE_CURSOR]; | |
168 } | |
169 | |
170 static void | |
171 prepare_to_fight(struct battle *bt) | |
172 { | |
173 assert(bt); | |
174 | |
175 // bt->enemies[0].ch = &haunted_wood; | |
176 bt->team[0].ch = &team[0]; | |
177 bt->team[1].ch = &team[1]; | |
178 | |
179 /* Positionate the single ennemy to the left. */ | |
180 align(ALIGN_LEFT, | |
181 &bt->enemies[0].x, &bt->enemies[0].y, haunted_wood.sprite->cellw, haunted_wood.sprite->cellh, | |
182 0, 0, window.w, window.h); | |
183 | |
184 /* Black cat is near the previous monster. */ | |
185 bt->enemies[1].ch = &black_cat; | |
186 bt->enemies[1].x = 500; | |
187 bt->enemies[1].y = 100; | |
188 | |
189 battle_start(bt); | |
190 } | |
191 | |
192 static void | |
193 run(void) | |
194 { | |
195 struct clock clock; | |
196 struct battle battle = {0}; | |
197 struct label info = { | |
198 .text = "Press <Space> to start a battle.", | |
199 .x = 10, | |
200 .y = 10, | |
201 .flags = LABEL_FLAGS_SHADOW | |
202 }; | |
203 | |
204 clock_start(&clock); | |
205 | |
206 for (;;) { | |
207 unsigned int elapsed = clock_elapsed(&clock); | |
208 | |
209 clock_start(&clock); | |
210 | |
211 for (union event ev; event_poll(&ev); ) { | |
212 switch (ev.type) { | |
213 case EVENT_QUIT: | |
214 return; | |
215 case EVENT_KEYDOWN: | |
216 if (ev.key.key == KEY_SPACE && !battle.state) | |
217 prepare_to_fight(&battle); | |
218 else if (battle.state) | |
219 battle_handle(&battle, &ev); | |
220 break; | |
221 default: | |
222 if (battle.state) | |
223 battle_handle(&battle, &ev); | |
224 break; | |
225 } | |
226 } | |
227 | |
228 if (battle.state) { | |
229 if (battle_update(&battle, elapsed)) | |
230 battle_finish(&battle); | |
231 else | |
232 battle_draw(&battle); | |
233 } else { | |
234 painter_set_color(0x4f8fbaff); | |
235 painter_clear(); | |
236 label_draw(&info); | |
237 } | |
238 | |
239 painter_present(); | |
240 | |
241 if ((elapsed = clock_elapsed(&clock)) < 20) | |
242 delay(1); | |
243 } | |
244 } | |
245 | |
246 static void | |
247 quit(void) | |
248 { | |
249 registry_finish(); | |
250 theme_finish(); | |
251 window_finish(); | |
252 sys_finish(); | |
253 } | |
254 | |
255 int | |
256 main(int argc, char **argv) | |
257 { | |
258 --argc; | |
259 ++argv; | |
260 | |
261 init(); | |
262 run(); | |
263 quit(); | |
264 | |
265 return 0; | |
266 } |