DungeonCrawl
Loading...
Searching...
No Matches
character_database.c
Go to the documentation of this file.
1
6
8#include "src/game_data.h"
9
10#include <stdio.h>
11
12#define SQL_INSERT_CHARACTER "INSERT INTO character (CH_MAXHEALTH, " \
13 "CH_MAXMANA, " \
14 "CH_MAXSTAMINA, " \
15 "CH_CURRENTHEALTH, " \
16 "CH_CURRENTMANA, " \
17 "CH_CURRENTSTAMINA, " \
18 "CH_ARMOR, " \
19 "CH_MAGICRESIST, " \
20 "CH_LEVEL, " \
21 "CH_XP, " \
22 "CH_XPREWARD, " \
23 "CH_SKILLPOINTS, " \
24 "CH_BASESTRENGTH, " \
25 "CH_BASEINTELLIGENCE, " \
26 "CH_BASEDEXTERITY, " \
27 "CH_BASECONSTITUTION, " \
28 "CH_CURRENTSTRENGTH, " \
29 "CH_CURRENTINTELLIGENCE, " \
30 "CH_CURRENTDEXTERITY, " \
31 "CH_CURRENTCONSTITUTION) " \
32 "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);"
33#define SQL_INSERT_PLAYER "INSERT INTO player (PY_CH_ID, " \
34 "PY_PS_ID, " \
35 "PY_NAME) " \
36 "VALUES (?, ?, ?);"
37#define SQL_INSERT_INVENTORY "INSERT INTO inventory (IV_TYPE) VALUES (?);"
38#define SQL_INSERT_INVENTORY_GEAR "INSERT INTO inventory_stores_gear (IG_IV_ID, IG_GR_ID, IG_EQUIPPED) VALUES (?, (SELECT GR_ID from gear WHERE GR_IDENT = ? LIMIT 1), ?);"
39#define SQL_INSERT_INVENTORY_POTION "INSERT INTO inventory_stores_potion (IP_IV_ID, IP_PO_ID) VALUES (?, (SELECT PO_ID from potion WHERE PO_TYPE = ? LIMIT 1));"
40#define SQL_INSERT_CHARACTER_INVENTORY "INSERT INTO character_has_inventory (CI_CH_ID, CI_IV_ID) VALUES (?, ?);"
41#define SQL_SELECT_CHARACTER "SELECT PY_NAME, " \
42 "CH_MAXHEALTH, " \
43 "CH_MAXMANA, " \
44 "CH_MAXSTAMINA, " \
45 "CH_CURRENTHEALTH, " \
46 "CH_CURRENTMANA, " \
47 "CH_CURRENTSTAMINA, " \
48 "CH_ARMOR, " \
49 "CH_MAGICRESIST, " \
50 "CH_LEVEL, " \
51 "CH_XP, " \
52 "CH_XPREWARD, " \
53 "CH_SKILLPOINTS, " \
54 "CH_BASESTRENGTH, " \
55 "CH_BASEINTELLIGENCE, " \
56 "CH_BASEDEXTERITY, " \
57 "CH_BASECONSTITUTION, " \
58 "CH_CURRENTSTRENGTH, " \
59 "CH_CURRENTINTELLIGENCE, " \
60 "CH_CURRENTDEXTERITY, " \
61 "CH_CURRENTCONSTITUTION, " \
62 "CH_ID " \
63 "FROM player " \
64 "join main.character on CH_ID = player.PY_CH_ID " \
65 "where PY_PS_ID = ? LIMIT 1;"
66#define SQL_SELECT_GEAR "SELECT GR_IDENT " \
67 "FROM inventory " \
68 "join main.character_has_inventory chi on inventory.IV_ID = chi.CI_IV_ID " \
69 "join main.inventory_stores_gear isg on inventory.IV_ID = isg.IG_IV_ID " \
70 "join gear g on isg.IG_GR_ID = g.GR_ID " \
71 "where CI_CH_ID = ? " \
72 "AND IV_TYPE = 0 " \
73 "AND isg.IG_EQUIPPED = ?;"
74#define SQL_SELECT_POTION "SELECT PO_TYPE " \
75 "FROM inventory " \
76 "join main.character_has_inventory chi on inventory.IV_ID = chi.CI_IV_ID " \
77 "join main.inventory_stores_potion isp on inventory.IV_ID = isp.IP_IV_ID " \
78 "join potion p on isp.IP_PO_ID = p.PO_ID " \
79 "where CI_CH_ID = ? " \
80 "AND IV_TYPE = 1;"
81
82void save_character(const db_connection_t* db_connection, const character_t character, const sqlite3_int64 game_state_id) {
83 // Check if the database connection is open
84 if (!db_is_open(db_connection)) {
85 log_msg(ERROR, "Character", "Database connection is not open");
86 return;
87 }
88 // Prepare the SQL statement
89 sqlite3_stmt* stmt;
90 int rc = sqlite3_prepare_v2(db_connection->db, SQL_INSERT_CHARACTER, -1, &stmt, NULL);
91 if (rc != SQLITE_OK) {
92 log_msg(ERROR, "Character", "Failed to prepare statement: %s", sqlite3_errmsg(db_connection->db));
93 return;
94 }
95 // Bind the character data to the statement
96 rc = sqlite3_bind_int(stmt, 1, character.max_resources.health);
97 if (rc != SQLITE_OK) {
98 log_msg(ERROR, "Character", "Failed to bind max health: %s", sqlite3_errmsg(db_connection->db));
99 sqlite3_finalize(stmt);
100 return;
101 }
102 rc = sqlite3_bind_int(stmt, 2, character.max_resources.mana);
103 if (rc != SQLITE_OK) {
104 log_msg(ERROR, "Character", "Failed to bind max mana: %s", sqlite3_errmsg(db_connection->db));
105 sqlite3_finalize(stmt);
106 return;
107 }
108 rc = sqlite3_bind_int(stmt, 3, character.max_resources.stamina);
109 if (rc != SQLITE_OK) {
110 log_msg(ERROR, "Character", "Failed to bind max stamina: %s", sqlite3_errmsg(db_connection->db));
111 sqlite3_finalize(stmt);
112 return;
113 }
114 rc = sqlite3_bind_int(stmt, 4, character.current_resources.health);
115 if (rc != SQLITE_OK) {
116 log_msg(ERROR, "Character", "Failed to bind current health: %s", sqlite3_errmsg(db_connection->db));
117 sqlite3_finalize(stmt);
118 return;
119 }
120 rc = sqlite3_bind_int(stmt, 5, character.current_resources.mana);
121 if (rc != SQLITE_OK) {
122 log_msg(ERROR, "Character", "Failed to bind current mana: %s", sqlite3_errmsg(db_connection->db));
123 sqlite3_finalize(stmt);
124 return;
125 }
126 rc = sqlite3_bind_int(stmt, 6, character.current_resources.stamina);
127 if (rc != SQLITE_OK) {
128 log_msg(ERROR, "Character", "Failed to bind current stamina: %s", sqlite3_errmsg(db_connection->db));
129 sqlite3_finalize(stmt);
130 return;
131 }
132 rc = sqlite3_bind_int(stmt, 7, character.defenses.armor);
133 if (rc != SQLITE_OK) {
134 log_msg(ERROR, "Character", "Failed to bind armor: %s", sqlite3_errmsg(db_connection->db));
135 sqlite3_finalize(stmt);
136 return;
137 }
138 rc = sqlite3_bind_int(stmt, 8, character.defenses.magic_resist);
139 if (rc != SQLITE_OK) {
140 log_msg(ERROR, "Character", "Failed to bind magic resist: %s", sqlite3_errmsg(db_connection->db));
141 sqlite3_finalize(stmt);
142 return;
143 }
144 rc = sqlite3_bind_int(stmt, 9, character.level);
145 if (rc != SQLITE_OK) {
146 log_msg(ERROR, "Character", "Failed to bind level: %s", sqlite3_errmsg(db_connection->db));
147 sqlite3_finalize(stmt);
148 return;
149 }
150 rc = sqlite3_bind_int(stmt, 10, character.xp);
151 if (rc != SQLITE_OK) {
152 log_msg(ERROR, "Character", "Failed to bind xp: %s", sqlite3_errmsg(db_connection->db));
153 sqlite3_finalize(stmt);
154 return;
155 }
156 rc = sqlite3_bind_int(stmt, 11, character.xp_reward);
157 if (rc != SQLITE_OK) {
158 log_msg(ERROR, "Character", "Failed to bind xp reward: %s", sqlite3_errmsg(db_connection->db));
159 sqlite3_finalize(stmt);
160 return;
161 }
162 rc = sqlite3_bind_int(stmt, 12, character.skill_points);
163 if (rc != SQLITE_OK) {
164 log_msg(ERROR, "Character", "Failed to bind skill points: %s", sqlite3_errmsg(db_connection->db));
165 sqlite3_finalize(stmt);
166 return;
167 }
168 rc = sqlite3_bind_int(stmt, 13, character.base_stats.strength);
169 if (rc != SQLITE_OK) {
170 log_msg(ERROR, "Character", "Failed to bind base strength: %s", sqlite3_errmsg(db_connection->db));
171 sqlite3_finalize(stmt);
172 return;
173 }
174 rc = sqlite3_bind_int(stmt, 14, character.base_stats.intelligence);
175 if (rc != SQLITE_OK) {
176 log_msg(ERROR, "Character", "Failed to bind base intelligence: %s", sqlite3_errmsg(db_connection->db));
177 sqlite3_finalize(stmt);
178 return;
179 }
180 rc = sqlite3_bind_int(stmt, 15, character.base_stats.dexterity);
181 if (rc != SQLITE_OK) {
182 log_msg(ERROR, "Character", "Failed to bind base dexterity: %s", sqlite3_errmsg(db_connection->db));
183 sqlite3_finalize(stmt);
184 return;
185 }
186 rc = sqlite3_bind_int(stmt, 16, character.base_stats.constitution);
187 if (rc != SQLITE_OK) {
188 log_msg(ERROR, "Character", "Failed to bind base constitution: %s", sqlite3_errmsg(db_connection->db));
189 sqlite3_finalize(stmt);
190 return;
191 }
192 rc = sqlite3_bind_int(stmt, 17, character.current_stats.strength);
193 if (rc != SQLITE_OK) {
194 log_msg(ERROR, "Character", "Failed to bind current strength: %s", sqlite3_errmsg(db_connection->db));
195 sqlite3_finalize(stmt);
196 return;
197 }
198 rc = sqlite3_bind_int(stmt, 18, character.current_stats.intelligence);
199 if (rc != SQLITE_OK) {
200 log_msg(ERROR, "Character", "Failed to bind current intelligence: %s", sqlite3_errmsg(db_connection->db));
201 sqlite3_finalize(stmt);
202 return;
203 }
204 rc = sqlite3_bind_int(stmt, 19, character.current_stats.dexterity);
205 if (rc != SQLITE_OK) {
206 log_msg(ERROR, "Character", "Failed to bind current dexterity: %s", sqlite3_errmsg(db_connection->db));
207 sqlite3_finalize(stmt);
208 return;
209 }
210 rc = sqlite3_bind_int(stmt, 20, character.current_stats.constitution);
211 if (rc != SQLITE_OK) {
212 log_msg(ERROR, "Character", "Failed to bind current constitution: %s", sqlite3_errmsg(db_connection->db));
213 sqlite3_finalize(stmt);
214 return;
215 }
216 // Execute the statement
217 rc = sqlite3_step(stmt);
218 // Get the character ID
219 const sqlite3_int64 character_id = sqlite3_last_insert_rowid(db_connection->db);
220 if (rc != SQLITE_DONE) {
221 log_msg(ERROR, "Character", "Failed to execute statement: %s", sqlite3_errmsg(db_connection->db));
222 sqlite3_finalize(stmt);
223 return;
224 }
225 // Finalize the statement
226 sqlite3_finalize(stmt);
227
228 // Prepare the SQL statement for player
229 sqlite3_stmt* stmt_player;
230 rc = sqlite3_prepare_v2(db_connection->db, SQL_INSERT_PLAYER, -1, &stmt_player, NULL);
231 if (rc != SQLITE_OK) {
232 log_msg(ERROR, "Character", "Failed to prepare statement: %s", sqlite3_errmsg(db_connection->db));
233 return;
234 }
235 // Bind the player data to the statement
236 rc = sqlite3_bind_int64(stmt_player, 1, character_id);
237 if (rc != SQLITE_OK) {
238 log_msg(ERROR, "Character", "Failed to bind character ID: %s", sqlite3_errmsg(db_connection->db));
239 sqlite3_finalize(stmt_player);
240 return;
241 }
242 rc = sqlite3_bind_int64(stmt_player, 2, game_state_id);
243 if (rc != SQLITE_OK) {
244 log_msg(ERROR, "Character", "Failed to bind game state ID: %s", sqlite3_errmsg(db_connection->db));
245 sqlite3_finalize(stmt_player);
246 return;
247 }
248 rc = sqlite3_bind_text(stmt_player, 3, character.name, -1, SQLITE_STATIC);
249 if (rc != SQLITE_OK) {
250 log_msg(ERROR, "Character", "Failed to bind character name: %s", sqlite3_errmsg(db_connection->db));
251 sqlite3_finalize(stmt_player);
252 return;
253 }
254 // Execute the statement
255 rc = sqlite3_step(stmt_player);
256 if (rc != SQLITE_DONE) {
257 log_msg(ERROR, "Character", "Failed to execute statement: %s", sqlite3_errmsg(db_connection->db));
258 sqlite3_finalize(stmt_player);
259 return;
260 }
261
262 save_character_inventory(db_connection, character, character_id);
263
264 // Finalize the statement
265 sqlite3_finalize(stmt_player);
266}
267
268void save_character_inventory(const db_connection_t* db_connection, const character_t character, const sqlite3_int64 character_id) {
269 // Prepare the SQL statement gear
270 sqlite3_stmt* stmt;
271 int rc = sqlite3_prepare_v2(db_connection->db, SQL_INSERT_INVENTORY, -1, &stmt, NULL);
272 if (rc != SQLITE_OK) {
273 log_msg(ERROR, "Character", "Failed to prepare statement: %s", sqlite3_errmsg(db_connection->db));
274 return;
275 }
276 // Bind the inventory type to the statement
277 rc = sqlite3_bind_int(stmt, 1, 0);
278 if (rc != SQLITE_OK) {
279 log_msg(ERROR, "Character", "Failed to bind inventory type: %s", sqlite3_errmsg(db_connection->db));
280 sqlite3_finalize(stmt);
281 return;
282 }
283 // Execute the statement
284 rc = sqlite3_step(stmt);
285
286 // Get the inventory for gear ID
287 const sqlite3_int64 inventory_gear_id = sqlite3_last_insert_rowid(db_connection->db);
288 if (rc != SQLITE_DONE) {
289 log_msg(ERROR, "Character", "Failed to execute statement: %s", sqlite3_errmsg(db_connection->db));
290 sqlite3_finalize(stmt);
291 return;
292 }
293 // Finalize the statement
294 sqlite3_finalize(stmt);
295
296 // Prepare the SQL statement for potions
297 sqlite3_stmt* stmt_potion;
298 rc = sqlite3_prepare_v2(db_connection->db, SQL_INSERT_INVENTORY, -1, &stmt_potion, NULL);
299 if (rc != SQLITE_OK) {
300 log_msg(ERROR, "Character", "Failed to prepare statement: %s", sqlite3_errmsg(db_connection->db));
301 return;
302 }
303 // Bind the inventory type to the statement
304 rc = sqlite3_bind_int(stmt_potion, 1, 1);
305 if (rc != SQLITE_OK) {
306 log_msg(ERROR, "Character", "Failed to bind inventory type: %s", sqlite3_errmsg(db_connection->db));
307 sqlite3_finalize(stmt_potion);
308 return;
309 }
310 // Execute the statement
311 rc = sqlite3_step(stmt_potion);
312 // Get the inventory for potions ID
313 const sqlite3_int64 inventory_potion_id = sqlite3_last_insert_rowid(db_connection->db);
314 if (rc != SQLITE_DONE) {
315 log_msg(ERROR, "Character", "Failed to execute statement: %s", sqlite3_errmsg(db_connection->db));
316 sqlite3_finalize(stmt_potion);
317 return;
318 }
319 // Finalize the statement
320 sqlite3_finalize(stmt_potion);
321
322 // Loop through gears in character
323 for (int i = 0; i < character.gear_count; i++) {
324 // Prepare the SQL statement for gear
325 sqlite3_stmt* stmt_gear_save;
326 rc = sqlite3_prepare_v2(db_connection->db, SQL_INSERT_INVENTORY_GEAR, -1, &stmt_gear_save, NULL);
327 if (rc != SQLITE_OK) {
328 log_msg(ERROR, "Character", "Failed to prepare statement: %s", sqlite3_errmsg(db_connection->db));
329 return;
330 }
331 // Bind the inventory ID to the statement
332 rc = sqlite3_bind_int64(stmt_gear_save, 1, inventory_gear_id);
333 if (rc != SQLITE_OK) {
334 log_msg(ERROR, "Character", "Failed to bind inventory ID: %s", sqlite3_errmsg(db_connection->db));
335 sqlite3_finalize(stmt_gear_save);
336 return;
337 }
338 // Bind the gear data to the statement
339 rc = sqlite3_bind_int(stmt_gear_save, 2, character.gear_inventory[i]->gear_identifier);
340 if (rc != SQLITE_OK) {
341 log_msg(ERROR, "Character", "Failed to bind gear type: %s", sqlite3_errmsg(db_connection->db));
342 sqlite3_finalize(stmt_gear_save);
343 return;
344 }
345 // Bind the equipped status to the statement
346 rc = sqlite3_bind_int(stmt_gear_save, 3, 0);
347
348 if (rc != SQLITE_OK) {
349 log_msg(ERROR, "Character", "Failed to bind equipped status: %s", sqlite3_errmsg(db_connection->db));
350 sqlite3_finalize(stmt_gear_save);
351 return;
352 }
353 // Execute the statement
354 rc = sqlite3_step(stmt_gear_save);
355 if (rc != SQLITE_DONE) {
356 log_msg(ERROR, "Character", "Failed to execute statement: %s", sqlite3_errmsg(db_connection->db));
357 sqlite3_finalize(stmt_gear_save);
358 return;
359 }
360 // Finalize the statement
361 sqlite3_finalize(stmt_gear_save);
362 }
363
364 // Loop through all slots in character and check if in character.equipment has gear
365 for (int i = 0; i < MAX_SLOT; i++) {
366 if (character.equipment[i] != NULL) {
367 // Prepare the SQL statement for gear
368 sqlite3_stmt* stmt_gear_save;
369 rc = sqlite3_prepare_v2(db_connection->db, SQL_INSERT_INVENTORY_GEAR, -1, &stmt_gear_save, NULL);
370 if (rc != SQLITE_OK) {
371 log_msg(ERROR, "Character", "Failed to prepare statement: %s", sqlite3_errmsg(db_connection->db));
372 return;
373 }
374 // Bind the inventory ID to the statement
375 rc = sqlite3_bind_int64(stmt_gear_save, 1, inventory_gear_id);
376 if (rc != SQLITE_OK) {
377 log_msg(ERROR, "Character", "Failed to bind inventory ID: %s", sqlite3_errmsg(db_connection->db));
378 sqlite3_finalize(stmt_gear_save);
379 return;
380 }
381 // Bind the gear data to the statement
382 rc = sqlite3_bind_int(stmt_gear_save, 2, character.equipment[i]->gear_identifier);
383 if (rc != SQLITE_OK) {
384 log_msg(ERROR, "Character", "Failed to bind gear type: %s", sqlite3_errmsg(db_connection->db));
385 sqlite3_finalize(stmt_gear_save);
386 return;
387 }
388 // Bind the equipped status to the statement
389 rc = sqlite3_bind_int(stmt_gear_save, 3, 1);
390
391 if (rc != SQLITE_OK) {
392 log_msg(ERROR, "Character", "Failed to bind equipped status: %s", sqlite3_errmsg(db_connection->db));
393 sqlite3_finalize(stmt_gear_save);
394 return;
395 }
396 // Execute the statement
397 rc = sqlite3_step(stmt_gear_save);
398 if (rc != SQLITE_DONE) {
399 log_msg(ERROR, "Character", "Failed to execute statement: %s", sqlite3_errmsg(db_connection->db));
400 sqlite3_finalize(stmt_gear_save);
401 return;
402 }
403 // Finalize the statement
404 sqlite3_finalize(stmt_gear_save);
405 }
406 }
407
408 // Loop through potions in character
409 for (int i = 0; i < character.potion_count; i++) {
410 // Prepare the SQL statement for potions
411 sqlite3_stmt* stmt_potion_save;
412 rc = sqlite3_prepare_v2(db_connection->db, SQL_INSERT_INVENTORY_POTION, -1, &stmt_potion_save, NULL);
413 if (rc != SQLITE_OK) {
414 log_msg(ERROR, "Character", "Failed to prepare statement: %s", sqlite3_errmsg(db_connection->db));
415 return;
416 }
417 // Bind the inventory ID to the statement
418 rc = sqlite3_bind_int64(stmt_potion_save, 1, inventory_potion_id);
419 if (rc != SQLITE_OK) {
420 log_msg(ERROR, "Character", "Failed to bind inventory ID: %s", sqlite3_errmsg(db_connection->db));
421 sqlite3_finalize(stmt_potion_save);
422 return;
423 }
424 // Bind the potion data to the statement
425 rc = sqlite3_bind_int(stmt_potion_save, 2, character.potion_inventory[i]->effectType);
426 if (rc != SQLITE_OK) {
427 log_msg(ERROR, "Character", "Failed to bind potion type: %s", sqlite3_errmsg(db_connection->db));
428 sqlite3_finalize(stmt_potion_save);
429 return;
430 }
431 // Execute the statement
432 rc = sqlite3_step(stmt_potion_save);
433 if (rc != SQLITE_DONE) {
434 log_msg(ERROR, "Character", "Failed to execute statement: %s", sqlite3_errmsg(db_connection->db));
435 sqlite3_finalize(stmt_potion_save);
436 return;
437 }
438 // Finalize the statement
439 sqlite3_finalize(stmt_potion_save);
440 }
441
442 // Prepare the SQL statement for character inventory
443 sqlite3_stmt* stmt_character_inventory;
444 rc = sqlite3_prepare_v2(db_connection->db, SQL_INSERT_CHARACTER_INVENTORY, -1, &stmt_character_inventory, NULL);
445 if (rc != SQLITE_OK) {
446 log_msg(ERROR, "Character", "Failed to prepare statement: %s", sqlite3_errmsg(db_connection->db));
447 return;
448 }
449 // Bind the character ID to the statement
450 rc = sqlite3_bind_int64(stmt_character_inventory, 1, character_id);
451 if (rc != SQLITE_OK) {
452 log_msg(ERROR, "Character", "Failed to bind character ID: %s", sqlite3_errmsg(db_connection->db));
453 sqlite3_finalize(stmt_character_inventory);
454 return;
455 }
456 // Bind the inventory ID to the statement
457 rc = sqlite3_bind_int64(stmt_character_inventory, 2, inventory_gear_id);
458 if (rc != SQLITE_OK) {
459 log_msg(ERROR, "Character", "Failed to bind inventory ID: %s", sqlite3_errmsg(db_connection->db));
460 sqlite3_finalize(stmt_character_inventory);
461 return;
462 }
463 // Execute the statement
464 rc = sqlite3_step(stmt_character_inventory);
465 if (rc != SQLITE_DONE) {
466 log_msg(ERROR, "Character", "Failed to execute statement: %s", sqlite3_errmsg(db_connection->db));
467 sqlite3_finalize(stmt_character_inventory);
468 return;
469 }
470 // Finalize the statement
471 sqlite3_finalize(stmt_character_inventory);
472
473 // Prepare the SQL statement for character inventory
474 sqlite3_stmt* stmt_character_inventory_potion;
475 rc = sqlite3_prepare_v2(db_connection->db, SQL_INSERT_CHARACTER_INVENTORY, -1, &stmt_character_inventory_potion, NULL);
476 if (rc != SQLITE_OK) {
477 log_msg(ERROR, "Character", "Failed to prepare statement: %s", sqlite3_errmsg(db_connection->db));
478 return;
479 }
480 // Bind the character ID to the statement
481 rc = sqlite3_bind_int64(stmt_character_inventory_potion, 1, character_id);
482 if (rc != SQLITE_OK) {
483 log_msg(ERROR, "Character", "Failed to bind character ID: %s", sqlite3_errmsg(db_connection->db));
484 sqlite3_finalize(stmt_character_inventory_potion);
485 return;
486 }
487 // Bind the inventory ID to the statement
488 rc = sqlite3_bind_int64(stmt_character_inventory_potion, 2, inventory_potion_id);
489 if (rc != SQLITE_OK) {
490 log_msg(ERROR, "Character", "Failed to bind inventory ID: %s", sqlite3_errmsg(db_connection->db));
491 sqlite3_finalize(stmt_character_inventory_potion);
492 return;
493 }
494 // Execute the statement
495 rc = sqlite3_step(stmt_character_inventory_potion);
496 if (rc != SQLITE_DONE) {
497 log_msg(ERROR, "Character", "Failed to execute statement: %s", sqlite3_errmsg(db_connection->db));
498 sqlite3_finalize(stmt_character_inventory_potion);
499 return;
500 }
501 // Finalize the statement
502 sqlite3_finalize(stmt_character_inventory_potion);
503}
504
505void get_character_from_db(const db_connection_t* db_connection, character_t* character, const int game_state_id) {
506 // add_gear(character, gear_table->gears[ARMING_SWORD]);
507 // Check if the database connection is open
508 if (!db_is_open(db_connection)) {
509 log_msg(ERROR, "Character", "Database connection is not open");
510 return;
511 }
512 // Prepare the SQL statement
513 sqlite3_stmt* stmt;
514 sqlite3_int64 character_id = 0;
515 int rc = sqlite3_prepare_v2(db_connection->db, SQL_SELECT_CHARACTER, -1, &stmt, NULL);
516 if (rc != SQLITE_OK) {
517 log_msg(ERROR, "Character", "Failed to prepare statement: %s", sqlite3_errmsg(db_connection->db));
518 return;
519 }
520 // Bind the game state ID to the statement
521 rc = sqlite3_bind_int(stmt, 1, game_state_id);
522 if (rc != SQLITE_OK) {
523 log_msg(ERROR, "Character", "Failed to bind game state ID: %s", sqlite3_errmsg(db_connection->db));
524 sqlite3_finalize(stmt);
525 return;
526 }
527 // Execute the statement
528 rc = sqlite3_step(stmt);
529 if (rc == SQLITE_ROW) {
530 // Get the character data from the result set
531 const char* name = (const char*) sqlite3_column_text(stmt, 0);
532 character->max_resources.health = sqlite3_column_int(stmt, 1);
533 character->max_resources.mana = sqlite3_column_int(stmt, 2);
534 character->max_resources.stamina = sqlite3_column_int(stmt, 3);
535 character->current_resources.health = sqlite3_column_int(stmt, 4);
536 character->current_resources.mana = sqlite3_column_int(stmt, 5);
537 character->current_resources.stamina = sqlite3_column_int(stmt, 6);
538 character->defenses.armor = sqlite3_column_int(stmt, 7);
539 character->defenses.magic_resist = sqlite3_column_int(stmt, 8);
540 character->level = sqlite3_column_int(stmt, 9);
541 character->xp = sqlite3_column_int(stmt, 10);
542 character->xp_reward = sqlite3_column_int(stmt, 11);
543 character->skill_points = sqlite3_column_int(stmt, 12);
544 character->base_stats.strength = sqlite3_column_int(stmt, 13);
545 character->base_stats.intelligence = sqlite3_column_int(stmt, 14);
546 character->base_stats.dexterity = sqlite3_column_int(stmt, 15);
547 character->base_stats.constitution = sqlite3_column_int(stmt, 16);
548 character->current_stats.strength = sqlite3_column_int(stmt, 17);
549 character->current_stats.intelligence = sqlite3_column_int(stmt, 18);
550 character->current_stats.dexterity = sqlite3_column_int(stmt, 19);
551 character->current_stats.constitution = sqlite3_column_int(stmt, 20);
552 character_id = sqlite3_column_int64(stmt, 21);
553
554 // Set the name
555 snprintf(character->name, sizeof(character->name), "%s", name);
556
557 } else {
558 log_msg(ERROR, "Character", "Failed to execute statement: %s", sqlite3_errmsg(db_connection->db));
559 }
560 // Finalize the statement
561 sqlite3_finalize(stmt);
562 // Prepare the SQL statement for gear
563 sqlite3_stmt* stmt_gear;
564 rc = sqlite3_prepare_v2(db_connection->db, SQL_SELECT_GEAR, -1, &stmt_gear, NULL);
565 if (rc != SQLITE_OK) {
566 log_msg(ERROR, "Character", "Failed to prepare statement: %s", sqlite3_errmsg(db_connection->db));
567 return;
568 }
569 // Bind the character ID to the statement
570 rc = sqlite3_bind_int64(stmt_gear, 1, character_id);
571 if (rc != SQLITE_OK) {
572 log_msg(ERROR, "Character", "Failed to bind character ID: %s", sqlite3_errmsg(db_connection->db));
573 sqlite3_finalize(stmt_gear);
574 return;
575 }
576 // Bind the equipped status to the statement
577 rc = sqlite3_bind_int(stmt_gear, 2, 1);
578 if (rc != SQLITE_OK) {
579 log_msg(ERROR, "Character", "Failed to bind equipped status: %s", sqlite3_errmsg(db_connection->db));
580 sqlite3_finalize(stmt_gear);
581 return;
582 }
583 // Execute the statement
584 rc = sqlite3_step(stmt_gear);
585 // Loop through all equipped gears in the statement with the geartable
586 while (rc == SQLITE_ROW) {
587 gear_t* loaded_gear = gear_table->gears[sqlite3_column_int(stmt_gear, 0)];
588 add_equipped_gear(character, loaded_gear);
589 rc = sqlite3_step(stmt_gear);
590 if (rc != SQLITE_DONE && rc != SQLITE_ROW) {
591 log_msg(ERROR, "Character", "Failed to execute statement: %s", sqlite3_errmsg(db_connection->db));
592 sqlite3_finalize(stmt_gear);
593 return;
594 }
595 }
596
597 // Reset the statement for unequipped gears
598 rc = sqlite3_reset(stmt_gear);
599 if (rc != SQLITE_OK) {
600 log_msg(ERROR, "Character", "Failed to reset statement: %s", sqlite3_errmsg(db_connection->db));
601 sqlite3_finalize(stmt_gear);
602 return;
603 }
604
605 // Bind the unequipped status
606 rc = sqlite3_bind_int(stmt_gear, 2, 0);
607 if (rc != SQLITE_OK) {
608 log_msg(ERROR, "Character", "Failed to bind unequipped status: %s", sqlite3_errmsg(db_connection->db));
609 sqlite3_finalize(stmt_gear);
610 return;
611 }
612 // Execute the statement
613 rc = sqlite3_step(stmt_gear);
614 // Loop through all unequipped gears in the statement with the geartable
615 while (rc == SQLITE_ROW) {
616 gear_t* loaded_gear = gear_table->gears[sqlite3_column_int(stmt_gear, 0)];
617 character->gear_inventory[character->gear_count++] = loaded_gear;
618 rc = sqlite3_step(stmt_gear);
619 if (rc != SQLITE_DONE && rc != SQLITE_ROW) {
620 log_msg(ERROR, "Character", "Failed to execute statement: %s", sqlite3_errmsg(db_connection->db));
621 sqlite3_finalize(stmt_gear);
622 return;
623 }
624 }
625 // Finalize the statement
626 sqlite3_finalize(stmt_gear);
627
628 // Prepare the SQL statement for potions
629 sqlite3_stmt* stmt_potion;
630 rc = sqlite3_prepare_v2(db_connection->db, SQL_SELECT_POTION, -1, &stmt_potion, NULL);
631 if (rc != SQLITE_OK) {
632 log_msg(ERROR, "Character", "Failed to prepare statement: %s", sqlite3_errmsg(db_connection->db));
633 return;
634 }
635 // Bind the character ID to the statement
636 rc = sqlite3_bind_int64(stmt_potion, 1, character_id);
637 if (rc != SQLITE_OK) {
638 log_msg(ERROR, "Character", "Failed to bind character ID: %s", sqlite3_errmsg(db_connection->db));
639 sqlite3_finalize(stmt_potion);
640 return;
641 }
642 // Execute the statement
643 rc = sqlite3_step(stmt_potion);
644 // Loop through all potions in the statement with the potions table
645 while (rc == SQLITE_ROW) {
646 potion_t* loaded_potion = &potion_table->potions[sqlite3_column_int(stmt_potion, 0)];
647 character->potion_inventory[character->potion_count++] = loaded_potion;
648 rc = sqlite3_step(stmt_potion);
649 if (rc != SQLITE_DONE && rc != SQLITE_ROW) {
650 log_msg(ERROR, "Character", "Failed to execute statement: %s", sqlite3_errmsg(db_connection->db));
651 sqlite3_finalize(stmt_potion);
652 return;
653 }
654 }
655 // Finalize the statement
656 sqlite3_finalize(stmt_potion);
657}
bool add_equipped_gear(character_t *character, gear_t *gear)
Adds an equipped gear in a specific slot of a character without updating stats and abilities.
Definition character.c:216
void save_character(const db_connection_t *db_connection, const character_t character, const sqlite3_int64 game_state_id)
This function saves the character to the database.
void save_character_inventory(const db_connection_t *db_connection, const character_t character, const sqlite3_int64 character_id)
This function saves the character's inventory to the database.
void get_character_from_db(const db_connection_t *db_connection, character_t *character, const int game_state_id)
This function retrieves a character from the database.
Exposes functions for working with the character and database.
int db_is_open(const db_connection_t *db_connection)
This function is to check if the database is open.
Definition database.c:27
Declares functions and globals for initializing, resetting, and freeing game data such as player,...
void log_msg(const log_level_t level, const char *module, const char *format,...)
Logs a formatted message with a specified log level and module.
Definition logger.c:246
Header file for logging functionality of the game.
This struct is used for the database connection in SQLite.
Definition database.h:22
Definition gear.h:32