home *** CD-ROM | disk | FTP | other *** search
- // Quick hack to display Daggerfall character's current reputation with all factions
- // By Rick Huebner (rhuebner@probe.net): Sep. 26 1996
- // Updated to support multiple versions: Oct. 3 1996 (1.0 - 1.0.177)
- // Added rep editing, fixed int handling, general tweaks: Oct. 12 1996
- //
- // Written as 16-bit generic DOS program in Microsoft Visual C, but
- // is very vanilla and should easily recompile with any ANSI compiler.
- // Released to public domain; fold, spindle and mutilate as desired.
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <ctype.h>
- #include <conio.h>
-
- #define TRUE 1
- #define FALSE 0
-
- typedef unsigned char BYTE;
-
- // Where faction data starts in SAVEVARS.DAT in each patch level
- #define NVERSIONS 2 // 1.0 1.0.175-7
- long Starts[NVERSIONS] = { 0x17C4, 0x17D0 };
-
- typedef struct {
- char FacType; // Faction Type from FACTION.TXT
- char U1[2]; // undeciphered data
- char Name[26]; // Faction Name
- BYTE RepLow; // Character's current rep with this faction
- BYTE RepHigh;
- BYTE PowerLow; // Faction's relative power compared to other factions
- BYTE PowerHigh;
- BYTE IdLow; // Faction's ID number used in Allies & Enemies lists
- BYTE IdHigh;
- char U2[19];
- char SGroup; // Social group
- char GGroup; // Guild group
- long Allies[3]; // Allied faction ID codes
- long Enemies[3];// Enemy faction ID codes
- char U3[12];
- } FACTION;
- FACTION *Facs;
- int NFacs;
-
-
- // Faction Type as per FACTION.TXT; What kind of faction is this?
- #define NFACTYPES 16
- char *FacTypes[NFACTYPES] = {
- "Daedra", "God", "Group", "Subgroup", "Person", "Official", "Vampire Clan",
- "Region", "Witches Coven", "Temple", "FacType 10", "FacType 11", "Generic Group",
- "Thieves Den", "Court", "People"
- };
-
- // Social Group as per FACTION.TXT; What is this faction's place in society?
- #define NSGROUPS 11
- char *SGroups[NSGROUPS] = {
- "Commoners", "Merchants", "Scholars", "Nobility", "Underworld", "SGroup 5", "Supernatural Beings",
- "Guild Members", "SGroup 8", "SGroup 9", "Intelligent Artifacts?!"
- };
-
- // Guild Group deduced by examination; not sure how this is used, needs more work
- #define NGGROUPS 26
- char *GGroups[NGGROUPS] = {
- "N/A", "GGroup 0", "GGroup 1", "Oblivion", "Dark Brotherhood", "General Populace", "Bards", "The Fey",
- "Prostitutes", "GGroup 8", "Knightly Order", "Mages Guild", "Fighters Guild", "GGroup 12", "GGroup 13",
- "Necromancers", "Region", "GGroup 16", "Holy Order", "GGroup 18", "GGroup 19", "GGroup 20", "GGroup 21",
- "Witches", "Vampires", "Orsinium"
- };
-
-
-
- __inline int GetRep(FACTION *fac);
- __inline int GetPower(FACTION *fac);
- __inline int GetID(FACTION *fac);
- __inline void SetRep(FACTION *fac, int rep);
- char *FactionName(long id);
- int FriendSort(const void *elem1, const void *elem2);
- int EnemySort(const void *elem1, const void *elem2);
-
-
-
- void main(int argc, char *argv[]) {
- int i, j, changed, newrep, key;
- char selection[64], buff[64], fname[32], *p;
- long startpos, length;
- FILE *fp;
- FACTION testfac, *fac;
-
- // Parse command line arguments
- if (argc < 2 || argc > 4 || !isdigit(*argv[1])) {
- puts("Command format: REP dir# e.g. REP 4");
- puts(" or: REP dir# F e.g. REP 0 F");
- puts(" or: REP dir# E e.g. REP 5 E");
- puts(" or: REP dir# facname e.g. REP 2 arkay");
- puts(" or: REP dir# facname newrep e.g. REP 3 \"dark brotherhood\" 79\n");
-
- puts("\"dir#\" is the number of the save game directory to use.\n");
-
- puts("\"F\" requests a sorted listing of friendly factions.\n");
-
- puts("\"E\" requests a sorted listing of hostile factions.\n");
-
- puts("\"facname\" requests a listing of factions whose names contain");
- puts("the specified text. If you include spaces in the text, you");
- puts("must enclose it in quotes. Not case sensitive.\n");
-
- puts("\"newrep\" specifies a new reputation value to be optionally");
- puts("applied to each faction whose name contains \"facname\". This");
- puts("option can't be used with \"F\" or \"E\". You'll be prompted to");
- puts("confirm each possible change.\n");
-
- puts("Must be run from the main Daggerfall program directory");
- exit(1);
- }
- if (argc == 2)
- selection[0] = '\0';
- else {
- strcpy(selection, argv[2]);
- strupr(selection);
- if (argc > 3 && !isdigit(*argv[3]) && *argv[3] != '-') {
- puts("Invalid new rep value; make sure faction name is in quotes if necessary");
- exit(10);
- }
- }
-
- // Read saved game name
- sprintf(fname, "SAVE%d\\SAVENAME.TXT", atoi(argv[1]));
- fp = fopen(fname, "rb");
- if (!fp)
- strcpy(buff, "No Name");
- else {
- i = fread(buff, 1, sizeof(buff)-1, fp);
- buff[i] = '\0';
- fclose(fp);
- }
-
- // Open data file
- sprintf(fname, "SAVE%d\\SAVEVARS.DAT", atoi(argv[1]));
- fp = fopen(fname, "r+b");
- if (!fp) {
- printf("Can't open %s: %s\n", fname, _sys_errlist[errno]);
- exit(10);
- }
- printf("Processing %s: \"%s\"\n\n", fname, buff);
-
- // Find start of faction data by searching for first potential position
- // which gives a whole number of data records and in which the first
- // record appears to contain valid info
- fseek(fp, 0, SEEK_END);
- length = ftell(fp);
-
- for (i = 0; i < NVERSIONS; ++i) {
- startpos = Starts[i];
- // Remaining data length must be multiple of record length
- if ((length - startpos) % sizeof(FACTION) == 0) {
- fseek(fp, startpos, SEEK_SET);
- fread(&testfac, sizeof(testfac), 1, fp);
- // Verifiable values must be within valid ranges
- if (testfac.FacType >= 0 && testfac.FacType < NFACTYPES &&
- testfac.SGroup >= 0 && testfac.SGroup < NSGROUPS &&
- testfac.GGroup >=-1 && testfac.GGroup < NGGROUPS-1) {
- // Text field must contain only valid text characters
- for (j = 0, p = testfac.Name; j < sizeof(testfac.Name); ++j, ++p)
- if (*p && (*p < ' ' || *p > '~'))
- break;
- if (j == sizeof(testfac.Name))
- break;
- }
- }
- }
- if (i == NVERSIONS) {
- puts("Can't find start of faction data");
- exit(10);
- }
-
- // Count faction records
- NFacs = (int)((length - startpos) / sizeof(FACTION));
- fseek(fp, startpos, SEEK_SET);
-
- // Allocate memory for faction array
- Facs = (FACTION *)malloc(NFacs * sizeof(FACTION));
- if (!Facs) {
- printf("Can't allocate %d bytes\n", NFacs * sizeof(FACTION));
- exit(10);
- }
-
- // Read all faction records into array
- if (fread(Facs, sizeof(FACTION), NFacs, fp) != (size_t)NFacs) {
- puts("Error reading data file\n");
- exit(10);
- }
-
- // Sort factions as required
- if (!strcmp(selection, "F"))
- qsort(Facs, NFacs, sizeof(FACTION), FriendSort);
- if (!strcmp(selection, "E"))
- qsort(Facs, NFacs, sizeof(FACTION), EnemySort);
-
- // Display selected records
- changed = FALSE;
- for (i = 0, fac = Facs; i < NFacs; ++i, ++fac) {
- // Skip unwanted records
- if (selection[0]) {
- if (!strcmp(selection, "F")) {
- if (GetRep(fac) <= 0)
- continue;
- } else if (!strcmp(selection, "E")) {
- if (GetRep(fac) >= 0)
- continue;
- } else {
- strcpy(buff, fac->Name);
- strupr(buff);
- if (!strstr(buff, selection))
- continue;
- }
- }
-
- printf("%s, %s, %s, %s\n", fac->Name,
- fac->FacType < NFACTYPES ? FacTypes[fac->FacType] : "Unknown",
- fac->SGroup < NSGROUPS ? SGroups[fac->SGroup] : "Unknown",
- fac->GGroup+1< NGGROUPS ? GGroups[fac->GGroup+1] : "Unknown");
-
- printf(" Your reputation: %d, Their power: %d \n", GetRep(fac), GetPower(fac));
-
- printf(" Allies: ");
- if (!fac->Allies[0])
- printf("None");
- else {
- for (j = 0; j < 3; ++j) {
- if (fac->Allies[j]) {
- if (j > 0)
- printf(", ");
- printf("%s", FactionName(fac->Allies[j]));
- }
- }
- }
-
- printf("\n Enemies: ");
- if (!fac->Enemies[0])
- printf("None");
- else {
- for (j = 0; j < 3; ++j) {
- if (fac->Enemies[j]) {
- if (j > 0)
- printf(", ");
- printf("%s", FactionName(fac->Enemies[j]));
- }
- }
- }
- printf("\n\n");
-
- // Set reputation if specified
- if (argc > 3 && strcmp(selection, "F") && strcmp(selection, "E")) {
- newrep = atoi(argv[3]);
- if (newrep != GetRep(fac)) {
- printf("Change rep from %d to %d [Y/N]? ", GetRep(fac), newrep);
- do {
- key = _getch();
- key = toupper(key);
- } while (key != 'Y' && key != 'N');
- if (key == 'Y') {
- SetRep(fac, newrep);
- changed = TRUE;
- puts("Y\nChanged.\n");
- } else
- puts("N\nNot changed.\n");
- }
- }
- }
-
- if (changed) {
- puts("Saving changes.");
- fseek(fp, startpos, SEEK_SET);
- fwrite(Facs, sizeof(FACTION), NFacs, fp);
- }
-
- fclose(fp);
-
- // Release array memory
- free(Facs);
- }
-
-
-
- // These routines handle misaligned integer values in the faction
- // structure. We can't just declare them as ints, because the compiler
- // would add padding bytes to align the ints on word boundaries and
- // screw things up.
- __inline int GetRep(FACTION *fac) {
- return *((int *)&fac->RepLow);
- }
-
- __inline int GetPower(FACTION *fac) {
- return *((int *)&fac->PowerLow);
- }
-
- __inline int GetID(FACTION *fac) {
- return *((int *)&fac->IdLow);
- }
-
- _inline void SetRep(FACTION *fac, int rep) {
- *((int *)&fac->RepLow) = rep;
- }
-
-
-
- // Translate faction ID code to faction name
- char *FactionName(long id) {
- FACTION *fac;
- int i;
-
- for (i = 0, fac = Facs; i < NFacs; ++i, ++fac)
- if ((int)id == GetID(fac))
- return fac->Name;
-
- return NULL;
- }
-
-
-
- // Sort factions into decreasing order (most friendly first)
- int FriendSort(const void *elem1, const void *elem2) {
- return GetRep((FACTION *)elem2) - GetRep((FACTION *)elem1);
- }
-
-
-
- // Sort factions into increasing order (most hostile first)
- int EnemySort(const void *elem1, const void *elem2) {
- return GetRep((FACTION *)elem1) - GetRep((FACTION *)elem2);
- }
-