1 #include <stdlib.h>
2 #include <string.h>
3 
4 #include "shadowdive/error.h"
5 #include "shadowdive/pilot.h"
6 
7 #define PILOT_BLOCK_LENGTH 428
8 
sd_pilot_create(sd_pilot * pilot)9 int sd_pilot_create(sd_pilot *pilot) {
10     if(pilot == NULL) {
11         return SD_INVALID_INPUT;
12     }
13     memset(pilot, 0, sizeof(sd_pilot));
14     return SD_SUCCESS;
15 }
16 
sd_pilot_free(sd_pilot * pilot)17 void sd_pilot_free(sd_pilot *pilot) {
18     for(int m = 0; m < 10; m++) {
19         free(pilot->quotes[m]);
20     }
21 }
22 
23 // Reads exactly 24 + 8 + 11 = 43 bytes
sd_pilot_load_player_from_mem(sd_mreader * mr,sd_pilot * pilot)24 void sd_pilot_load_player_from_mem(sd_mreader *mr, sd_pilot *pilot) {
25     sd_mread_buf(mr, pilot->name, 18);
26     pilot->wins =        sd_mread_uword(mr);
27     pilot->losses =      sd_mread_uword(mr);
28     pilot->rank =        sd_mread_ubyte(mr);
29     pilot->har_id =      sd_mread_ubyte(mr);
30 
31     uint16_t stats_a =   sd_mread_uword(mr);
32     uint16_t stats_b =   sd_mread_uword(mr);
33     uint16_t stats_c =   sd_mread_uword(mr);
34     uint8_t stats_d =    sd_mread_ubyte(mr);
35     pilot->arm_power = (stats_a >> 0) & 0x1F;
36     pilot->leg_power = (stats_a >> 5) & 0x1F;
37     pilot->arm_speed = (stats_a >> 10) & 0x1F;
38     pilot->leg_speed = (stats_b >> 0) & 0x1F;
39     pilot->armor     = (stats_b >> 5) & 0x1F;
40     pilot->stun_resistance = (stats_b >> 10) & 0x1F;
41     pilot->agility = (stats_c >> 0) & 0x7F;
42     pilot->power = (stats_c >> 7) & 0x7F;
43     pilot->endurance = (stats_d >> 0) & 0x7F;
44     sd_mskip(mr, 1);
45 
46     pilot->offense =     sd_mread_uword(mr);
47     pilot->defense =     sd_mread_uword(mr);
48     pilot->money =       sd_mread_udword(mr);
49     pilot->color_1 =     sd_mread_ubyte(mr);
50     pilot->color_2 =     sd_mread_ubyte(mr);
51     pilot->color_3 =     sd_mread_ubyte(mr);
52 }
53 
sd_pilot_load_from_mem(sd_mreader * mr,sd_pilot * pilot)54 void sd_pilot_load_from_mem(sd_mreader *mr, sd_pilot *pilot) {
55     pilot->unknown_a =   sd_mread_udword(mr);
56 
57     sd_pilot_load_player_from_mem(mr, pilot);
58 
59     sd_mread_buf(mr, pilot->trn_name, 13);
60     sd_mread_buf(mr, pilot->trn_desc, 31);
61     sd_mread_buf(mr, pilot->trn_image, 13);
62 
63     pilot->unk_f_c = sd_mread_float(mr);
64     pilot->unk_f_d = sd_mread_float(mr);
65     sd_mskip(mr, 40); // Pointless pointers
66     pilot->pilot_id =    sd_mread_ubyte(mr);
67     pilot->unknown_k =   sd_mread_ubyte(mr);
68     pilot->force_arena = sd_mread_uword(mr);
69     pilot->difficulty = (sd_mread_ubyte(mr) >> 3) & 0x3; // 155-156
70     sd_mread_buf(mr, pilot->unk_block_b, 2);
71     pilot->movement =    sd_mread_ubyte(mr);
72     sd_mread_buf(mr, (char*)pilot->unk_block_c, 6);
73     sd_mread_buf(mr, pilot->enhancements, 11);
74 
75     // Flags (3)
76     sd_mskip(mr, 1); // Nothing here
77     uint8_t req_flags = sd_mread_ubyte(mr); // Secret, only fight once flags
78     pilot->secret = (req_flags & 0x02) ? 1 : 0;
79     pilot->only_fight_once = (req_flags & 0x08) ? 1 : 0;
80     sd_mskip(mr, 1); // Nothing here either
81 
82     // Requirements (10)
83     uint16_t reqs[5];
84     sd_mread_buf(mr, (char*)reqs, 10);
85     pilot->req_rank = reqs[0] & 0xFF;
86     pilot->req_max_rank = (reqs[0] >> 8) & 0xFF;
87     pilot->req_fighter = reqs[1] & 0x1F;
88     pilot->req_difficulty = (reqs[2] >> 8) & 0x0F;
89     pilot->req_enemy = (reqs[2] & 0xFF);
90     pilot->req_vitality = reqs[3] & 0x7F;
91     pilot->req_accuracy = (reqs[3] >> 7) & 0x7F;
92     pilot->req_avg_dmg = reqs[4] & 0x7F;
93     pilot->req_scrap = (reqs[4] & 0x80) ? 1 : 0;
94     pilot->req_destroy = ((reqs[4] >> 8) & 0x01) ? 1 : 0;
95 
96     // Attitude
97     uint16_t att[3];
98     sd_mread_buf(mr, (char*)att, 6);
99     pilot->att_normal = (att[0] >> 4) & 0x7F;
100     pilot->att_hyper  = att[1] & 0x7F;
101     pilot->att_jump   = (att[1] >> 7) & 0x7F;
102     pilot->att_def    = att[2] & 0x7F;
103     pilot->att_sniper = (att[2] >> 7) & 0x7F;
104 
105     sd_mread_buf(mr, (char*)pilot->unk_block_d, 6);
106 
107     pilot->ap_throw =    sd_mread_word(mr);
108     pilot->ap_special =  sd_mread_word(mr);
109     pilot->ap_jump =     sd_mread_word(mr);
110     pilot->ap_high =     sd_mread_word(mr);
111     pilot->ap_low =      sd_mread_word(mr);
112     pilot->ap_middle =   sd_mread_word(mr);
113     pilot->pref_jump =   sd_mread_word(mr);
114     pilot->pref_fwd =    sd_mread_word(mr);
115     pilot->pref_back =   sd_mread_word(mr);
116 
117     pilot->unknown_e =   sd_mread_udword(mr);
118     pilot->learning =    sd_mread_float(mr);
119     pilot->forget =      sd_mread_float(mr);
120     sd_mread_buf(mr, pilot->unk_block_f, 14);
121     pilot->enemies_inc_unranked = sd_mread_uword(mr);
122     pilot->enemies_ex_unranked = sd_mread_uword(mr);
123     pilot->unk_d_a =     sd_mread_uword(mr);
124     pilot->unk_d_b =     sd_mread_udword(mr);
125     pilot->winnings =    sd_mread_udword(mr);
126     pilot->total_value = sd_mread_udword(mr);
127     pilot->unk_f_a = sd_mread_float(mr);
128     pilot->unk_f_b = sd_mread_float(mr);
129     sd_mskip(mr, 8);
130     sd_palette_create(&pilot->palette);
131     sd_palette_mload_range(mr, &pilot->palette, 0, 48);
132     pilot->unk_block_i = sd_mread_uword(mr);
133 
134     pilot->photo_id =    sd_mread_uword(mr) & 0x3FF;
135 }
136 
sd_pilot_load(sd_reader * reader,sd_pilot * pilot)137 int sd_pilot_load(sd_reader *reader, sd_pilot *pilot) {
138     if(reader == NULL || pilot == NULL) {
139         return SD_INVALID_INPUT;
140     }
141 
142     // Read block, XOR, Read to pilot, free memory
143     sd_mreader *mr = sd_mreader_open_from_reader(reader, PILOT_BLOCK_LENGTH);
144     sd_mreader_xor(mr, PILOT_BLOCK_LENGTH & 0xFF);
145     sd_pilot_load_from_mem(mr, pilot);
146     sd_mreader_close(mr);
147 
148     // Quote block
149     for(int m = 0; m < 10; m++) {
150         pilot->quotes[m] = sd_read_variable_str(reader);
151     }
152     return SD_SUCCESS;
153 }
154 
sd_pilot_save_player_to_mem(sd_mwriter * w,const sd_pilot * pilot)155 void sd_pilot_save_player_to_mem(sd_mwriter *w, const sd_pilot *pilot) {
156     sd_mwrite_buf(w, pilot->name, 18);
157     sd_mwrite_uword(w, pilot->wins);
158     sd_mwrite_uword(w, pilot->losses);
159     sd_mwrite_ubyte(w, pilot->rank);
160     sd_mwrite_ubyte(w, pilot->har_id);
161 
162     uint16_t stats_a = 0, stats_b = 0, stats_c = 0;
163     uint8_t stats_d = 0;
164     stats_a |= (pilot->arm_power & 0x1F) << 0;
165     stats_a |= (pilot->leg_power & 0x1F) << 5;
166     stats_a |= (pilot->arm_speed & 0x1F) << 10;
167     stats_b |= (pilot->leg_speed & 0x1F) << 0;
168     stats_b |= (pilot->armor & 0x1F) << 5;
169     stats_b |= (pilot->stun_resistance & 0x1F) << 10;
170     stats_c |= (pilot->agility & 0x7F) << 0;
171     stats_c |= (pilot->power & 0x7F) << 7;
172     stats_d |= (pilot->endurance & 0x7F) << 0;
173     sd_mwrite_uword(w, stats_a);
174     sd_mwrite_uword(w, stats_b);
175     sd_mwrite_uword(w, stats_c);
176     sd_mwrite_ubyte(w, stats_d);
177     sd_mwrite_fill(w, 0, 1);
178 
179     sd_mwrite_uword(w, pilot->offense);
180     sd_mwrite_uword(w, pilot->defense);
181     sd_mwrite_udword(w, pilot->money);
182     sd_mwrite_ubyte(w, pilot->color_1);
183     sd_mwrite_ubyte(w, pilot->color_2);
184     sd_mwrite_ubyte(w, pilot->color_3);
185 }
186 
sd_pilot_save_to_mem(sd_mwriter * w,const sd_pilot * pilot)187 void sd_pilot_save_to_mem(sd_mwriter *w, const sd_pilot *pilot) {
188     // Write the pilot block
189     sd_mwrite_udword(w, pilot->unknown_a);
190 
191     sd_pilot_save_player_to_mem(w, pilot);
192 
193     sd_mwrite_buf(w, pilot->trn_name, 13);
194     sd_mwrite_buf(w, pilot->trn_desc, 31);
195     sd_mwrite_buf(w, pilot->trn_image, 13);
196 
197     sd_mwrite_float(w, pilot->unk_f_c);
198     sd_mwrite_float(w, pilot->unk_f_d);
199     sd_mwrite_fill(w, 0, 40);
200     sd_mwrite_ubyte(w, pilot->pilot_id);
201     sd_mwrite_ubyte(w, pilot->unknown_k);
202     sd_mwrite_uword(w, pilot->force_arena);
203     sd_mwrite_ubyte(w, (pilot->difficulty & 0x3) << 3);
204     sd_mwrite_buf(w, pilot->unk_block_b, 2);
205     sd_mwrite_ubyte(w, pilot->movement);
206     sd_mwrite_buf(w, (char*)pilot->unk_block_c, 6);
207     sd_mwrite_buf(w, pilot->enhancements, 11);
208 
209     // Flags
210     sd_mwrite_ubyte(w, 0);
211     uint8_t req_flags = 0;
212     if(pilot->secret)
213         req_flags |= 0x02;
214     if(pilot->only_fight_once)
215         req_flags |= 0x08;
216     sd_mwrite_ubyte(w, req_flags);
217     sd_mwrite_ubyte(w, 0);
218 
219     // Requirements (10)
220     uint16_t reqs[5];
221     memset((char*)reqs, 0, 10);
222     reqs[0] |= (pilot->req_max_rank & 0xFF) << 8;
223     reqs[0] |= (pilot->req_rank & 0xFF);
224     reqs[1] |= (pilot->req_fighter & 0x1F);
225     reqs[2] |= (pilot->req_difficulty & 0x0F) << 8;
226     reqs[2] |= (pilot->req_enemy & 0xFF);
227     reqs[3] |= (pilot->req_accuracy & 0x7F) << 7;
228     reqs[3] |= (pilot->req_vitality & 0x7F);
229     reqs[4] |= (pilot->req_destroy & 0x01) << 8;
230     reqs[4] |= (pilot->req_scrap & 0x01) << 7;
231     reqs[4] |= (pilot->req_avg_dmg & 0x7F);
232     sd_mwrite_buf(w, (char*)reqs, 10);
233 
234     // Attitude
235     uint16_t att[3];
236     memset((char*)att, 0, 6);
237     att[0] |= (pilot->att_normal & 0x7F) << 4;
238     att[1] |= (pilot->att_jump & 0x7F) << 7;
239     att[1] |= (pilot->att_hyper & 0x7F);
240     att[2] |= (pilot->att_sniper & 0x7F) << 7;
241     att[2] |= (pilot->att_def & 0x7F);
242     sd_mwrite_buf(w, (char*)att, 6);
243 
244     sd_mwrite_buf(w, (char*)pilot->unk_block_d, 6);
245 
246     sd_mwrite_word(w, pilot->ap_throw);
247     sd_mwrite_word(w, pilot->ap_special);
248     sd_mwrite_word(w, pilot->ap_jump);
249     sd_mwrite_word(w, pilot->ap_high);
250     sd_mwrite_word(w, pilot->ap_low);
251     sd_mwrite_word(w, pilot->ap_middle);
252     sd_mwrite_word(w, pilot->pref_jump);
253     sd_mwrite_word(w, pilot->pref_fwd);
254     sd_mwrite_word(w, pilot->pref_back);
255 
256     sd_mwrite_udword(w, pilot->unknown_e);
257     sd_mwrite_float(w, pilot->learning);
258     sd_mwrite_float(w, pilot->forget);
259     sd_mwrite_buf(w, pilot->unk_block_f, 14);
260     sd_mwrite_uword(w, pilot->enemies_inc_unranked);
261     sd_mwrite_uword(w, pilot->enemies_ex_unranked);
262     sd_mwrite_uword(w, pilot->unk_d_a);
263     sd_mwrite_udword(w, pilot->unk_d_b);
264     sd_mwrite_udword(w, pilot->winnings);
265     sd_mwrite_udword(w, pilot->total_value);
266     sd_mwrite_float(w, pilot->unk_f_a);
267     sd_mwrite_float(w, pilot->unk_f_b);
268     sd_mwrite_fill(w, 0, 8);
269     sd_palette_msave_range(w, &pilot->palette, 0, 48);
270     sd_mwrite_uword(w, pilot->unk_block_i);
271 
272     sd_mwrite_uword(w, pilot->photo_id & 0x3FF);
273 }
274 
sd_pilot_save(sd_writer * fw,const sd_pilot * pilot)275 int sd_pilot_save(sd_writer *fw, const sd_pilot *pilot) {
276     if(fw == NULL || pilot == NULL) {
277         return SD_INVALID_INPUT;
278     }
279 
280     // Copy, XOR, save and close
281     sd_mwriter *w = sd_mwriter_open();
282     sd_pilot_save_to_mem(w, pilot);
283     sd_mwriter_xor(w, PILOT_BLOCK_LENGTH & 0xFF);
284     sd_mwriter_save(w, fw);
285     sd_mwriter_close(w);
286 
287     // Quote block
288     for(int m = 0; m < 10; m++) {
289         sd_write_variable_str(fw, pilot->quotes[m]);
290     }
291     return SD_SUCCESS;
292 }