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