1 #include <stdlib.h>
2 #include <string.h>
3
4 #include "shadowdive/internal/reader.h"
5 #include "shadowdive/internal/writer.h"
6 #include "shadowdive/animation.h"
7 #include "shadowdive/error.h"
8 #include "shadowdive/move.h"
9 #include "shadowdive/af.h"
10
sd_af_create(sd_af_file * af)11 int sd_af_create(sd_af_file *af) {
12 if(af == NULL) {
13 return SD_INVALID_INPUT;
14 }
15
16 // Clear everything
17 memset(af, 0, sizeof(sd_af_file));
18 return SD_SUCCESS;
19 }
20
sd_af_copy(sd_af_file * dst,const sd_af_file * src)21 int sd_af_copy(sd_af_file *dst, const sd_af_file *src) {
22 int ret;
23 if(dst == NULL || src == NULL) {
24 return SD_INVALID_INPUT;
25 }
26
27 // Clear destination
28 memset(dst, 0, sizeof(sd_af_file));
29
30 // Copy the basic stuff
31 dst->file_id = src->file_id;
32 dst->exec_window = src->exec_window;
33 dst->endurance = src->endurance;
34 dst->unknown_b = src->unknown_b;
35 dst->health = src->health;
36 dst->forward_speed = src->forward_speed;
37 dst->reverse_speed = src->reverse_speed;
38 dst->jump_speed = src->jump_speed;
39 dst->fall_speed = src->fall_speed;
40 dst->unknown_c = src->unknown_c;
41 dst->unknown_d = src->unknown_d;
42
43 // Copy soundtable
44 memcpy(dst->soundtable, src->soundtable, sizeof(src->soundtable));
45
46 // Copy move animations
47 for(int i = 0; i < MAX_AF_MOVES; i++) {
48 if(src->moves[i] != NULL) {
49 if((dst->moves[i] = malloc(sizeof(sd_move))) == NULL) {
50 return SD_OUT_OF_MEMORY;
51 }
52 if((ret = sd_move_copy(dst->moves[i], src->moves[i])) != SD_SUCCESS) {
53 return ret;
54 }
55 }
56 }
57
58 return SD_SUCCESS;
59 }
60
sd_af_set_move(sd_af_file * af,int index,const sd_move * move)61 int sd_af_set_move(sd_af_file *af, int index, const sd_move *move) {
62 int ret;
63 if(af == NULL || index < 0 || index >= MAX_AF_MOVES) {
64 return SD_INVALID_INPUT;
65 }
66 if(af->moves[index] != NULL) {
67 sd_move_free(af->moves[index]);
68 free(af->moves[index]);
69 }
70 if(move == NULL) {
71 return SD_SUCCESS;
72 }
73 if((af->moves[index] = malloc(sizeof(sd_move))) == NULL) {
74 return SD_OUT_OF_MEMORY;
75 }
76 if((ret = sd_move_copy(af->moves[index], move)) != SD_SUCCESS) {
77 return ret;
78 }
79 return SD_SUCCESS;
80 }
81
sd_af_get_move(sd_af_file * af,int index)82 sd_move* sd_af_get_move(sd_af_file *af, int index) {
83 if(af == NULL || index < 0 || index >= MAX_AF_MOVES) {
84 return NULL;
85 }
86 return af->moves[index];
87 }
88
sd_af_postprocess(sd_af_file * af)89 void sd_af_postprocess(sd_af_file *af) {
90 char *table[1000] = {0}; // temporary lookup table
91 sd_animation *anim;
92 // fix NULL pointers for any 'missing' sprites
93 for(int i = 0; i < 70; i++) {
94 if(af->moves[i] != NULL) {
95 anim = af->moves[i]->animation;
96 for(int j = 0; j < anim->sprite_count; j++) {
97 if(anim->sprites[j]->missing > 0) {
98 if(table[anim->sprites[j]->index]) {
99 anim->sprites[j]->data = table[anim->sprites[j]->index];
100 }
101 } else {
102 table[anim->sprites[j]->index] = anim->sprites[j]->data;
103 }
104 }
105 }
106 }
107 }
108
sd_af_load(sd_af_file * af,const char * filename)109 int sd_af_load(sd_af_file *af, const char *filename) {
110 int ret = SD_SUCCESS;
111 uint8_t moveno = 0;
112 sd_reader *r;
113
114 // Initialize reader
115 if(!(r = sd_reader_open(filename))) {
116 return SD_FILE_OPEN_ERROR;
117 }
118
119 // Header
120 af->file_id = sd_read_uword(r);
121 af->exec_window = sd_read_uword(r); // Always 10
122 af->endurance = sd_read_udword(r) / 256.0f;
123 af->unknown_b = sd_read_ubyte(r); // Always 1 or 2
124 af->health = sd_read_uword(r);
125 af->forward_speed = sd_read_dword(r) / 256.0f;
126 af->reverse_speed = sd_read_dword(r) / 256.0f;
127 af->jump_speed = sd_read_dword(r) / 256.0f;
128 af->fall_speed = sd_read_dword(r) / 256.0f;
129 af->unknown_c = sd_read_ubyte(r); // Always 0x32 ?
130 af->unknown_d = sd_read_ubyte(r); // Always 0x14 ?
131
132 // Read animations
133 while(1) {
134 moveno = sd_read_ubyte(r);
135 if(moveno >= MAX_AF_MOVES || !sd_reader_ok(r)) {
136 break;
137 }
138
139 // Read move
140 if((af->moves[moveno] = malloc(sizeof(sd_move))) == NULL) {
141 ret = SD_OUT_OF_MEMORY;
142 goto cleanup;
143 }
144 if((ret = sd_move_create(af->moves[moveno])) != SD_SUCCESS) {
145 goto cleanup;
146 }
147 if((ret = sd_move_load(r, af->moves[moveno])) != SD_SUCCESS) {
148 goto cleanup;
149 }
150 }
151
152 // Read soundtable
153 sd_read_buf(r, af->soundtable, 30);
154
155 // Fix missing sprites
156 sd_af_postprocess(af);
157
158 cleanup:
159 // Close & return
160 sd_reader_close(r);
161 return ret;
162 }
163
sd_af_save(const sd_af_file * af,const char * filename)164 int sd_af_save(const sd_af_file *af, const char* filename) {
165 int ret;
166 sd_writer *w;
167
168 if(!(w = sd_writer_open(filename))) {
169 return SD_FILE_OPEN_ERROR;
170 }
171
172 // Header
173 sd_write_uword(w, af->file_id);
174 sd_write_uword(w, af->exec_window);
175 sd_write_udword(w, (int)(af->endurance * 256));
176 sd_write_ubyte(w, af->unknown_b);
177 sd_write_uword(w, af->health);
178 sd_write_dword(w, (int)(af->forward_speed * 256));
179 sd_write_dword(w, (int)(af->reverse_speed * 256));
180 sd_write_dword(w, (int)(af->jump_speed * 256));
181 sd_write_dword(w, (int)(af->fall_speed * 256));
182 sd_write_ubyte(w, af->unknown_c);
183 sd_write_ubyte(w, af->unknown_d);
184
185 // Write animations
186 for(uint8_t i = 0; i < MAX_AF_MOVES; i++) {
187 if(af->moves[i] != NULL) {
188 sd_write_ubyte(w, i);
189 if((ret = sd_move_save(w, af->moves[i])) != SD_SUCCESS) {
190 sd_writer_close(w);
191 return ret;
192 }
193 }
194 }
195
196 // This marks the end of animations
197 sd_write_ubyte(w, 250);
198
199 // Soundtable
200 sd_write_buf(w, af->soundtable, 30);
201
202 // All done!
203 sd_writer_close(w);
204 return SD_SUCCESS;
205 }
206
sd_af_free(sd_af_file * af)207 void sd_af_free(sd_af_file *af) {
208 if(af == NULL) return;
209 for(int i = 0; i < MAX_AF_MOVES; i++) {
210 if(af->moves[i] != NULL) {
211 sd_move_free(af->moves[i]);
212 free(af->moves[i]);
213 }
214 }
215 }
216