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 }