1 #include <stdlib.h>
2 #include <string.h>
3
4 #include "shadowdive/error.h"
5 #include "shadowdive/internal/reader.h"
6 #include "shadowdive/internal/memreader.h"
7 #include "shadowdive/internal/writer.h"
8 #include "shadowdive/internal/memwriter.h"
9 #include "shadowdive/chr.h"
10
11 #define UNUSED(x) (void)(x)
12
sd_chr_create(sd_chr_file * chr)13 int sd_chr_create(sd_chr_file *chr) {
14 if(chr == NULL) {
15 return SD_INVALID_INPUT;
16 }
17 memset(chr, 0, sizeof(sd_chr_file));
18 return SD_SUCCESS;
19 }
20
sd_chr_load(sd_chr_file * chr,const char * filename)21 int sd_chr_load(sd_chr_file *chr, const char *filename) {
22 if(chr == NULL ||filename == NULL) {
23 return SD_INVALID_INPUT;
24 }
25
26 sd_reader *r = sd_reader_open(filename);
27 if(!r) {
28 return SD_FILE_OPEN_ERROR;
29 }
30
31 // Read up pilot block and the unknown data
32 sd_mreader *mr = sd_mreader_open_from_reader(r, 448);
33 sd_mreader_xor(mr, 0xAC);
34 sd_pilot_create(&chr->pilot);
35 sd_pilot_load_from_mem(mr, &chr->pilot);
36 sd_mreader_close(mr);
37
38 // Read enemies block
39 mr = sd_mreader_open_from_reader(r, 68 * chr->pilot.enemies_inc_unranked);
40 sd_mreader_xor(mr, (chr->pilot.enemies_inc_unranked * 68) & 0xFF);
41
42 // Handle enemy data
43 for(int i = 0; i < chr->pilot.enemies_inc_unranked; i++) {
44 // Reserve & zero out
45 chr->enemies[i] = malloc(sizeof(sd_chr_enemy));
46 sd_pilot_create(&chr->enemies[i]->pilot);
47 sd_pilot_load_player_from_mem(mr, &chr->enemies[i]->pilot);
48 sd_mread_buf(mr, chr->enemies[i]->unknown, 25);
49 }
50
51 // Close memory reader for enemy data block
52 sd_mreader_close(mr);
53
54 // Read HAR palette
55 sd_palette_create(&chr->pal);
56 sd_palette_load_range(r, &chr->pal, 0, 48);
57
58 // No idea what this is.
59 // TODO: Find out.
60 chr->unknown_b = sd_read_udword(r);
61
62 // Load sprite
63 chr->photo = malloc(sizeof(sd_sprite));
64 sd_sprite_create(chr->photo);
65 int ret = sd_sprite_load(r, chr->photo);
66 if(ret != SD_SUCCESS) {
67 goto error_1;
68 }
69
70 // Fix photo size
71 chr->photo->width++;
72 chr->photo->height++;
73
74 // Close & return
75 sd_reader_close(r);
76 return SD_SUCCESS;
77
78
79 error_1:
80 for(int i = 0; i < chr->pilot.enemies_inc_unranked; i++) {
81 if(chr->enemies[i] != NULL) {
82 free(chr->enemies[i]);
83 }
84 }
85 sd_sprite_free(chr->photo);
86 sd_reader_close(r);
87 return SD_FILE_PARSE_ERROR;
88 }
89
sd_chr_save(sd_chr_file * chr,const char * filename)90 int sd_chr_save(sd_chr_file *chr, const char *filename) {
91 if(chr == NULL || filename == NULL) {
92 return SD_INVALID_INPUT;
93 }
94
95 sd_writer *w = sd_writer_open(filename);
96 if(!w) {
97 return SD_FILE_OPEN_ERROR;
98 }
99
100 // Save pilot and unknown
101 sd_mwriter *mw = sd_mwriter_open();
102 sd_pilot_save_to_mem(mw, &chr->pilot);
103 sd_mwriter_xor(mw, 0xAC);
104 sd_mwriter_save(mw, w);
105 sd_mwriter_close(mw);
106
107 // Write enemy data
108 mw = sd_mwriter_open();
109 for(int i = 0; i < chr->pilot.enemies_inc_unranked; i++) {
110 sd_pilot_save_player_to_mem(mw, &chr->enemies[i]->pilot);
111 sd_mwrite_buf(mw, chr->enemies[i]->unknown, 25);
112 }
113 sd_mwriter_xor(mw, (chr->pilot.enemies_inc_unranked * 68) & 0xFF);
114 sd_mwriter_save(mw, w);
115 sd_mwriter_close(mw);
116
117 // Save palette
118 sd_palette_save_range(w, &chr->pal, 0, 48);
119
120 // Save this, whatever this is.
121 sd_write_udword(w, chr->unknown_b);
122
123 // Save photo. Hacky size fix.
124 chr->photo->width--;
125 chr->photo->height--;
126 sd_sprite_save(w, chr->photo);
127 chr->photo->width++;
128 chr->photo->height++;
129
130 // Close & return
131 sd_writer_close(w);
132 return SD_SUCCESS;
133 }
134
sd_chr_free(sd_chr_file * chr)135 void sd_chr_free(sd_chr_file *chr) {
136 for(int i = 0; i < chr->pilot.enemies_inc_unranked; i++) {
137 if(chr->enemies[i] != NULL) {
138 free(chr->enemies[i]);
139 }
140 }
141 sd_sprite_free(chr->photo);
142 }
143
sd_chr_get_enemy(sd_chr_file * chr,int enemy_num)144 const sd_chr_enemy* sd_chr_get_enemy(sd_chr_file *chr, int enemy_num) {
145 if(chr == NULL || enemy_num < 0 || enemy_num >= chr->pilot.enemies_inc_unranked) {
146 return NULL;
147 }
148 return chr->enemies[enemy_num];
149 }