home *** CD-ROM | disk | FTP | other *** search
/ The Games Machine 27 / CITE.iso / patch / dagger / dag212.arj / REP177.ZIP / REP.C < prev    next >
Encoding:
C/C++ Source or Header  |  1996-10-12  |  11.2 KB  |  332 lines

  1. // Quick hack to display Daggerfall character's current reputation with all factions
  2. // By Rick Huebner (rhuebner@probe.net): Sep. 26 1996
  3. // Updated to support multiple versions: Oct. 3 1996 (1.0 - 1.0.177)
  4. // Added rep editing, fixed int handling, general tweaks: Oct. 12 1996
  5. //
  6. // Written as 16-bit generic DOS program in Microsoft Visual C, but
  7. // is very vanilla and should easily recompile with any ANSI compiler.
  8. // Released to public domain; fold, spindle and mutilate as desired.
  9.  
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <string.h>
  13. #include <ctype.h>
  14. #include <conio.h>
  15.  
  16. #define TRUE  1
  17. #define FALSE 0
  18.  
  19. typedef unsigned char BYTE;
  20.  
  21. // Where faction data starts in SAVEVARS.DAT in each patch level
  22. #define NVERSIONS 2 //     1.0   1.0.175-7
  23. long Starts[NVERSIONS] = { 0x17C4, 0x17D0 };
  24.                     
  25. typedef struct {
  26.     char FacType;   // Faction Type from FACTION.TXT
  27.     char U1[2];     // undeciphered data
  28.     char Name[26];  // Faction Name
  29.     BYTE RepLow;    // Character's current rep with this faction
  30.     BYTE RepHigh;
  31.     BYTE PowerLow;  // Faction's relative power compared to other factions
  32.     BYTE PowerHigh;
  33.     BYTE IdLow;     // Faction's ID number used in Allies & Enemies lists
  34.     BYTE IdHigh;
  35.     char U2[19];
  36.     char SGroup;    // Social group
  37.     char GGroup;    // Guild group
  38.     long Allies[3]; // Allied faction ID codes
  39.     long Enemies[3];// Enemy faction ID codes
  40.     char U3[12];
  41. } FACTION;
  42. FACTION *Facs;
  43. int NFacs;
  44.  
  45.  
  46. // Faction Type as per FACTION.TXT; What kind of faction is this?
  47. #define NFACTYPES 16
  48. char *FacTypes[NFACTYPES] = {
  49.     "Daedra", "God", "Group", "Subgroup", "Person", "Official", "Vampire Clan",
  50.     "Region", "Witches Coven", "Temple", "FacType 10", "FacType 11", "Generic Group",
  51.     "Thieves Den", "Court",  "People"
  52. };
  53.  
  54. // Social Group as per FACTION.TXT; What is this faction's place in society?
  55. #define NSGROUPS 11
  56. char *SGroups[NSGROUPS] = {
  57.     "Commoners", "Merchants", "Scholars", "Nobility", "Underworld", "SGroup 5", "Supernatural Beings",
  58.     "Guild Members", "SGroup 8", "SGroup 9", "Intelligent Artifacts?!"
  59. };
  60.  
  61. // Guild Group deduced by examination; not sure how this is used, needs more work
  62. #define NGGROUPS 26
  63. char *GGroups[NGGROUPS] = {
  64.     "N/A", "GGroup 0", "GGroup 1", "Oblivion", "Dark Brotherhood", "General Populace", "Bards", "The Fey", 
  65.     "Prostitutes", "GGroup 8", "Knightly Order", "Mages Guild", "Fighters Guild", "GGroup 12", "GGroup 13",
  66.     "Necromancers", "Region", "GGroup 16", "Holy Order", "GGroup 18", "GGroup 19", "GGroup 20", "GGroup 21",
  67.     "Witches", "Vampires", "Orsinium"
  68. };
  69.  
  70.  
  71.  
  72. __inline int  GetRep(FACTION *fac);
  73. __inline int  GetPower(FACTION *fac);
  74. __inline int  GetID(FACTION *fac);
  75. __inline void SetRep(FACTION *fac, int rep);
  76. char *FactionName(long id);
  77. int   FriendSort(const void *elem1, const void *elem2);
  78. int   EnemySort(const void *elem1, const void *elem2);
  79.  
  80.  
  81.  
  82. void main(int argc, char *argv[]) {
  83.     int i, j, changed, newrep, key;
  84.     char selection[64], buff[64], fname[32], *p;
  85.     long startpos, length;
  86.     FILE *fp;
  87.     FACTION testfac, *fac;
  88.  
  89.     // Parse command line arguments    
  90.     if (argc < 2 || argc > 4 || !isdigit(*argv[1])) {
  91.         puts("Command format: REP dir#                  e.g. REP 4");
  92.         puts("            or: REP dir# F                e.g. REP 0 F");
  93.         puts("            or: REP dir# E                e.g. REP 5 E");
  94.         puts("            or: REP dir# facname          e.g. REP 2 arkay");
  95.         puts("            or: REP dir# facname newrep   e.g. REP 3 \"dark brotherhood\" 79\n");
  96.         
  97.         puts("\"dir#\" is the number of the save game directory to use.\n");
  98.         
  99.         puts("\"F\" requests a sorted listing of friendly factions.\n");
  100.         
  101.         puts("\"E\" requests a sorted listing of hostile factions.\n");
  102.         
  103.         puts("\"facname\" requests a listing of factions whose names contain");
  104.         puts("the specified text.  If you include spaces in the text, you");
  105.         puts("must enclose it in quotes.  Not case sensitive.\n");
  106.         
  107.         puts("\"newrep\" specifies a new reputation value to be optionally");
  108.         puts("applied to each faction whose name contains \"facname\".  This");
  109.         puts("option can't be used with \"F\" or \"E\".  You'll be prompted to");
  110.         puts("confirm each possible change.\n");
  111.         
  112.         puts("Must be run from the main Daggerfall program directory");
  113.         exit(1);
  114.     }
  115.     if (argc == 2)
  116.         selection[0] = '\0';
  117.     else {
  118.         strcpy(selection, argv[2]);
  119.         strupr(selection);
  120.         if (argc > 3 && !isdigit(*argv[3]) && *argv[3] != '-') {
  121.             puts("Invalid new rep value; make sure faction name is in quotes if necessary");
  122.             exit(10);
  123.         }
  124.     }
  125.  
  126.     // Read saved game name
  127.     sprintf(fname, "SAVE%d\\SAVENAME.TXT", atoi(argv[1]));
  128.     fp = fopen(fname, "rb");
  129.     if (!fp)
  130.         strcpy(buff, "No Name");
  131.     else {
  132.         i = fread(buff, 1, sizeof(buff)-1, fp);
  133.         buff[i] = '\0';
  134.         fclose(fp);
  135.     }
  136.     
  137.     // Open data file
  138.     sprintf(fname, "SAVE%d\\SAVEVARS.DAT", atoi(argv[1]));
  139.     fp = fopen(fname, "r+b");
  140.     if (!fp) {
  141.         printf("Can't open %s: %s\n", fname, _sys_errlist[errno]);
  142.         exit(10);
  143.     }
  144.     printf("Processing %s: \"%s\"\n\n", fname, buff);
  145.     
  146.     // Find start of faction data by searching for first potential position
  147.     // which gives a whole number of data records and in which the first
  148.     // record appears to contain valid info
  149.     fseek(fp, 0, SEEK_END);
  150.     length = ftell(fp);
  151.     
  152.     for (i = 0; i < NVERSIONS; ++i) {
  153.         startpos = Starts[i];
  154.         // Remaining data length must be multiple of record length
  155.         if ((length - startpos) % sizeof(FACTION) == 0) {
  156.             fseek(fp, startpos, SEEK_SET);
  157.             fread(&testfac, sizeof(testfac), 1, fp);
  158.             // Verifiable values must be within valid ranges
  159.             if (testfac.FacType >= 0 && testfac.FacType < NFACTYPES &&
  160.                 testfac.SGroup  >= 0 && testfac.SGroup  < NSGROUPS  &&
  161.                 testfac.GGroup  >=-1 && testfac.GGroup  < NGGROUPS-1) {
  162.                 // Text field must contain only valid text characters
  163.                 for (j = 0, p = testfac.Name; j < sizeof(testfac.Name); ++j, ++p)
  164.                     if (*p && (*p < ' ' || *p > '~'))
  165.                         break;
  166.                 if (j == sizeof(testfac.Name))
  167.                     break;
  168.             }
  169.         }
  170.     }
  171.     if (i == NVERSIONS) {
  172.         puts("Can't find start of faction data");
  173.         exit(10);
  174.     }
  175.  
  176.     // Count faction records                     
  177.     NFacs = (int)((length - startpos) / sizeof(FACTION));
  178.     fseek(fp, startpos, SEEK_SET);
  179.  
  180.     // Allocate memory for faction array    
  181.     Facs = (FACTION *)malloc(NFacs * sizeof(FACTION));
  182.     if (!Facs) {
  183.         printf("Can't allocate %d bytes\n", NFacs * sizeof(FACTION));
  184.         exit(10);
  185.     }
  186.  
  187.     // Read all faction records into array    
  188.     if (fread(Facs, sizeof(FACTION), NFacs, fp) != (size_t)NFacs) {
  189.         puts("Error reading data file\n");
  190.         exit(10);
  191.     }
  192.  
  193.     // Sort factions as required
  194.     if (!strcmp(selection, "F"))
  195.         qsort(Facs, NFacs, sizeof(FACTION), FriendSort);
  196.     if (!strcmp(selection, "E"))
  197.         qsort(Facs, NFacs, sizeof(FACTION), EnemySort);
  198.  
  199.     // Display selected records
  200.     changed = FALSE;
  201.     for (i = 0, fac = Facs; i < NFacs; ++i, ++fac) {
  202.         // Skip unwanted records
  203.         if (selection[0]) {
  204.             if (!strcmp(selection, "F")) {
  205.                 if (GetRep(fac) <= 0)
  206.                     continue;
  207.             } else if (!strcmp(selection, "E")) {
  208.                 if (GetRep(fac) >= 0)
  209.                     continue;
  210.             } else {
  211.                 strcpy(buff, fac->Name);
  212.                 strupr(buff);
  213.                 if (!strstr(buff, selection))
  214.                     continue;
  215.             }
  216.         }
  217.             
  218.         printf("%s, %s, %s, %s\n", fac->Name,
  219.             fac->FacType < NFACTYPES ? FacTypes[fac->FacType] : "Unknown", 
  220.             fac->SGroup  < NSGROUPS  ? SGroups[fac->SGroup]   : "Unknown",
  221.             fac->GGroup+1< NGGROUPS  ? GGroups[fac->GGroup+1] : "Unknown");
  222.             
  223.         printf("   Your reputation: %d, Their power: %d \n", GetRep(fac), GetPower(fac));
  224.         
  225.         printf("   Allies: ");
  226.         if (!fac->Allies[0])
  227.             printf("None");
  228.         else {
  229.             for (j = 0; j < 3; ++j) {
  230.                 if (fac->Allies[j]) {
  231.                     if (j > 0)
  232.                         printf(", ");
  233.                     printf("%s", FactionName(fac->Allies[j]));
  234.                 }
  235.             }
  236.         }
  237.         
  238.         printf("\n   Enemies: ");
  239.         if (!fac->Enemies[0])
  240.             printf("None");
  241.         else {
  242.             for (j = 0; j < 3; ++j) {
  243.                 if (fac->Enemies[j]) {
  244.                     if (j > 0)
  245.                         printf(", ");
  246.                     printf("%s", FactionName(fac->Enemies[j]));
  247.                 }
  248.             }
  249.         }
  250.         printf("\n\n");
  251.  
  252.         // Set reputation if specified        
  253.         if (argc > 3 && strcmp(selection, "F") && strcmp(selection, "E")) {
  254.             newrep = atoi(argv[3]);
  255.             if (newrep != GetRep(fac)) {
  256.                 printf("Change rep from %d to %d [Y/N]? ", GetRep(fac), newrep);
  257.                 do {
  258.                     key = _getch();
  259.                     key = toupper(key);
  260.                 } while (key != 'Y' && key != 'N');
  261.                 if (key == 'Y') {
  262.                     SetRep(fac, newrep);
  263.                     changed = TRUE;
  264.                     puts("Y\nChanged.\n");
  265.                 } else
  266.                     puts("N\nNot changed.\n");
  267.             }
  268.         }
  269.     }
  270.     
  271.     if (changed) {
  272.         puts("Saving changes.");
  273.         fseek(fp, startpos, SEEK_SET);
  274.         fwrite(Facs, sizeof(FACTION), NFacs, fp);
  275.     }
  276.     
  277.     fclose(fp);
  278.  
  279.     // Release array memory    
  280.     free(Facs);
  281. }
  282.  
  283.  
  284.  
  285. // These routines handle misaligned integer values in the faction
  286. // structure.  We can't just declare them as ints, because the compiler
  287. // would add padding bytes to align the ints on word boundaries and 
  288. // screw things up.
  289. __inline int GetRep(FACTION *fac) {
  290.     return *((int *)&fac->RepLow);
  291. }
  292.  
  293. __inline int GetPower(FACTION *fac) {
  294.     return *((int *)&fac->PowerLow);
  295. }
  296.  
  297. __inline int GetID(FACTION *fac) {
  298.     return *((int *)&fac->IdLow);
  299. }
  300.  
  301. _inline void SetRep(FACTION *fac, int rep) {
  302.     *((int *)&fac->RepLow) = rep;
  303. }
  304.  
  305.  
  306.  
  307. // Translate faction ID code to faction name
  308. char *FactionName(long id) {
  309.     FACTION *fac;
  310.     int i;
  311.     
  312.     for (i = 0, fac = Facs; i < NFacs; ++i, ++fac)
  313.         if ((int)id == GetID(fac))
  314.             return fac->Name;
  315.             
  316.     return NULL;
  317. }
  318.  
  319.  
  320.  
  321. // Sort factions into decreasing order (most friendly first)
  322. int FriendSort(const void *elem1, const void *elem2) {
  323.     return GetRep((FACTION *)elem2) - GetRep((FACTION *)elem1);
  324. }
  325.  
  326.  
  327.  
  328. // Sort factions into increasing order (most hostile first)
  329. int EnemySort(const void *elem1, const void *elem2) {
  330.     return GetRep((FACTION *)elem1) - GetRep((FACTION *)elem2);
  331. }
  332.