/* * Scouter: A scouting oracle for Madden NFL 2003 (PC). * Written May 10, 2003 by George Greer * * License: public domain with no warranty. * If it breaks, you get to keep both pieces. */ #include #include #include #include #include #include /* Generic dump buffers. */ unsigned long data[1024]; char text[4096]; struct field_data { char *name; int data_bits; int offset; int unknown; }; const char *print_position[] = { "QB", "HB", "FB", "WR", "TE", "LT", "LG", "C", "RG", "RT", "LE", "RE", "DT", "LOLB", "MLB", "ROLB", "CB", "FS", "SS", "K", "P", }; int play_print_fields[] = { 1, 0, 87, 97, 4, 69, 21, 20, 68, 70, 32, 14, 29, 65, 62, 41, 36, 60, 9, 37, 38, 67, 13, 11, 35, 25, 99 }; int num_print_fields = sizeof(play_print_fields) / sizeof(int); const char *play_fields[] = { "Last Name", "First Name", "POS", "HGT", "WGT", "OVR", "Age", "SPD", "STR", "AWR", "AGI", "ACC", "CTH", "CAR", "JMP", "BTK", "TAK", "THP", "THA", "PBK", "RBK", "KPW", "KAC", "STA", "INJ", "TGH", "KR" }; int num_name_fields = sizeof(play_fields) / sizeof(char *); int field_sorter(const void *a, const void *b) { struct field_data *c = (struct field_data *)a; struct field_data *d = (struct field_data *)b; return c->offset - d->offset; } void table_print(FILE *db, FILE *output) { int field_count, record_length, record_count; int cur_field, cur_rec; struct field_data *fields; /* Header */ fread(data, sizeof(long), 6, db); record_length = data[1]; record_count = (data[3] & 0xffff0000) >> 16; field_count = data[5] & 0xff; /* Field names */ fields = calloc(field_count, sizeof(struct field_data)); for (cur_field = 0; cur_field < field_count; cur_field++) { fread(data, sizeof(long), 4, db); memcpy(text, data + 2, 4); text[4] = '\0'; fields[cur_field].unknown = data[0]; fields[cur_field].offset = data[1]; fields[cur_field].name = strdup(text); fields[cur_field].data_bits = data[3]; } qsort(fields, field_count, sizeof(struct field_data), field_sorter); /* Tab-delimited heading. */ for (cur_field = 0; cur_field < num_print_fields; cur_field++) fprintf(output, "%s,", play_fields[cur_field]); fputc('\n', output); /* Tabbed data. */ for (cur_rec = 0; cur_rec < record_count; cur_rec++) { fread(data, record_length, 1, db); if ((data[9] & 0x3ff) != 1015) /* Draft Team */ continue; for (cur_field = 0; cur_field < num_print_fields; cur_field++) { struct field_data *f = &fields[play_print_fields[cur_field]]; if (f->data_bits > 32 && f->data_bits % 8 == 0) strcpy(text, (char *)data + f->offset / 8); else { unsigned long bitdata; int bucket = f->offset / 32; int oshift = f->offset % 32; int mask = f->data_bits == 32 ? ~0 : ~(~0 << f->data_bits); bitdata = (data[bucket] & (mask << oshift)) >> oshift; if (oshift + f->data_bits > 32) { mask = ~(~0 << (f->data_bits - (32 - oshift))); bitdata |= (data[bucket + 1] & mask) << (32 - oshift); } if (cur_field == 2) /* Position */ sprintf(text, "%02lu: %s", bitdata, print_position[bitdata]); else if (cur_field == 3) /* Height */ sprintf(text, "%ld'%02ld\"", bitdata / 12, bitdata % 12); else if (cur_field == 4) /* Weight */ sprintf(text, "%lu", bitdata + 160); else sprintf(text, "%lu", bitdata); } fprintf(output, "%s,", text); } fputc('\n', output); } for (cur_field = 0; cur_field < field_count; cur_field++) free(fields[cur_field].name); free(fields); } int main(int argc, char *argv[]) { FILE *db, *output; char output_file[4096]; unsigned int cur_table, table_count; assert(num_name_fields == num_print_fields); if (argc < 2) { fprintf(stderr, "Syntax: %s yourfranchise.fra\n", argv[0]); return 1; } else if (!(db = fopen(argv[1], "rb"))) { fprintf(stderr, "%s: cannot open '%s' to read: %s\n", argv[0], argv[1], strerror(errno)); return 1; } strcpy(output_file, argv[1]); strcat(output_file, ".csv"); if (!(output = fopen(output_file, "w"))) { fprintf(stderr, "%s: cannot open '%s' to write: %s\n", argv[0], output_file, strerror(errno)); return 1; } /* Header reading. */ fread(data, sizeof(long), 5, db); table_count = data[4]; /* Table list */ for (cur_table = 0; cur_table < table_count; cur_table++) { fread(text, sizeof(char), 4, db); text[4] = '\0'; fread(data, sizeof(long), 1, db); if (strcmp(text, "PLAY") != 0) continue; fseek(db, data[0] + 20 + table_count * 8, SEEK_SET); table_print(db, output); return 0; } return 1; }