VGA Planets 4 Ship Group Editor

From PlanetsWiki

Jump to: navigation, search

by Rick Glover aka Magik

Contents

[edit] Overview

The goal of this application is to provide a means to edit your ship groups outside of the VGA Planets 4 client. This tool will allow you to display your current groups, add new ships to a group, remove ships from a group, and sort the groups by ship ID. This utility must be executed from your VGA Planets 4 installation folder.

I haven't tested what would occur if you entered an incorrect object, such as a wing, base or enemy unit. Please be careful.

Usage: vgap4grp <slot> <player> [action]
Where action can be: display [<group>]
                     delete <group> <object id>
                     add <group> <object id>
                     sort [<group>]
If [<group>] is not provided, then it will apply to all groups.

Download VGAP4Grp from Klingon Kommand

[edit] Examples

C:\Planets> vgap4grp 2 5

This will display all members of all groups in game slot 2, player 5's ship groups.

C:\Planets> vgap4grp 2 5 display 1

This will display all members of the first group in game slot 2, player 5.

C:\Planets> vgap4grp 2 5 delete 4 1378

This will remove ship ID #1378 from group 4 in game slot 2, player 5.

C:\Planets> vgap4grp 2 5 add 7 864

This will add ship ID #864 from group 7 in game slot 2, player 5.

C:\Planets> vgap4grp 2 5 sort

This will sort all groups in ascending order in game slot 2, player 5.

C:\Planets> vgap4grp 2 5 sort 3

This will sort group 3 in ascending order in game slot 2, player 5.

[edit] Source Code

Here is the source code for those of you that are interested. Any comments or suggestions are welcome. This is written in C.

/*
 * VGA Planets v4 Ship Group Editor v1.0
 *
 * This program is used to add/remove or display VGA Planets v4 ship groups.  It must be
 * executed from the Planets 4 installation folder.
 *
 * From Tim Wisseman 12/14/2005:
 * Private Type GroupType
 *    nm As String * 40
 *    Log As String * 40
 *    count As Long
 *    flag1 As Long 'Unused
 *    flag2(1 To 200) As Long 'Unused 
 *    Item(1 To 500) As Long 'Object ID
 *    itemSerNum(1 To 500) As Long 'Object Serial number
 * End Type
 * 
 * Private m_group(1 To 12) As GroupType
 * 
 * Public Sub SaveGroupData()
 * Dim sDir As String
 * Dim i As Long
 * Dim sA As String
 * Dim f1 As Long
 *    sDir = exepath & "groups\s" & Trim$(Str$(fileList.GameSlot)) & "x" & Trim$(Str$(WAR.pNum)) & "\"
 *    For i = 1 To 12
 *       sA = sDir & "group" & Trim$(Str$(i)) & ".grp"
 *       If m_booActive(i) Then
 *          f1 = FreeFile
 *          Open sA For Binary As #f1
 *             Put #f1, 1, m_group(i)
 *          Close #f1
 *       End If
 *    Next i
 * End Sub
 *
 * When you remove a ship from a group in the Planets 4 client, it will replace
 * the existing entry with a 0.
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define MAX_SHIPS       500

// Global variables
FILE *input, *output;
struct gdata {
  char sName[40];
  char sLog[40];
  long int iCount;
  long int iFlag1;
  long int iFlag2[200];
  long int iItem[MAX_SHIPS];
  long int iSerial[MAX_SHIPS];
} group[12];
int iSlot, iPlayer, iGroup, iObject;

// Prototypes
void usage(int);
int read_file(char *, int);
int write_file(int);
void get_group(char *);
void get_object(char *);
void bsort(int);
//extern void exit();

int main(int argc, char **argv) {
  int i, j;
  char buf[512];

  if (argc < 3) {
    printf("Missing parameter(s).\n");
    usage(1);
  }
  iSlot = atoi(argv[1]);
  if (iSlot < 1 || iSlot > 12) {
    printf("Slot number is out of range.  Valid range is 1 to 12.\n");
    usage(1);
  }
  iPlayer = atoi(argv[2]);
  if (iSlot < 1 || iSlot > 12) {
    printf("Player number is out of range.  Valid range is 1 to 30.\n");
    usage(1);
  }

  // Read the group files into RAM
  for (i = 0; i < 12; i++) {
    sprintf(buf, "groups\\s%dx%d\\group%d.grp", iSlot, iPlayer, i + 1);
    read_file(buf, i);
  }
  if (argc == 3 || !strcmp(argv[3], "display")) {
    // Just display the groups as they are
    if (argc == 3 || argc < 5) {
      for (i = 0; i < 12; i++) {
        if (group[i].iCount) {
          strcpy(buf, group[i].sName);
          buf[39] = '\0';
          printf("Name: %s\n", buf);
	        for (j = 0; j < group[i].iCount; j++) {
            if (group[i].iItem[j]) {
              printf("%d\n", group[i].iItem[j]);
            }
          }
          printf("\n");
        }
      }
    } else {
      get_group(argv[4]);
      if (group[iGroup].iCount) {
        strcpy(buf, group[iGroup].sName);
        buf[39] = '\0';
        printf("Name: %s\n", buf);
        for (j = 0; j < group[iGroup].iCount; j++) {
          if (group[iGroup].iItem[j]) {
            printf("%d\n", group[iGroup].iItem[j]);
          }
        }
      } else {
        printf("Group %d has no members.\n", iGroup + 1);
      }
    }
    return(0);
  } else if (!strcmp(argv[3], "delete")) {
    // remove object ID from the given group
    int bFound = 0;

    if (argc < 6) {
      printf("Missing parameter(s).\n");
      usage(1);
    }
    get_group(argv[4]);
    get_object(argv[5]);
    for (i = 0; i < group[iGroup].iCount; i++) {
      if (group[iGroup].iItem[i] == iObject) {
        group[iGroup].iItem[i] = 0;
        group[iGroup].iSerial[i] = 0;
        printf("Object ID %d has been removed from group %d.\n", iObject, iGroup + 1);
        if (i == group[iGroup].iCount) {
          // Last entry
          group[iGroup].iCount--;
        }
        bFound = 1;
        break;
      }
    }
    if (!bFound) {
      printf("Object ID %d was not found in group %d.\n", iObject, iGroup + 1);
    } else {
      write_file(iGroup);
    }
    return(0);
  } else if (!strcmp(argv[3], "add")) {
    // add object ID from the given group
    if (argc < 6) {
      printf("Missing parameter(s).\n");
      usage(1);
    }
    get_group(argv[4]);
    get_object(argv[5]);
    j = 0;
    for (i = 0; i < group[iGroup].iCount; i++) {
      if (group[iGroup].iItem[i] == iObject) {
        printf("Object ID %d already exists in group %d.\n", iObject, iGroup + 1);
        return(1);
      } else if (group[iGroup].iItem[i] == 0) {
        j = i;
      }
    }
    if (j) {
      group[iGroup].iItem[j] = iObject;
      group[iGroup].iSerial[i] = iObject;
    } else {
      group[iGroup].iItem[group[iGroup].iCount] = iObject;
      group[iGroup].iSerial[group[iGroup].iCount] = iObject;
      group[iGroup].iCount++;
    }
    printf("Object ID %d added to group %d.\n", iObject, iGroup + 1);
    write_file(iGroup);
    return(0);
  } else if (!strcmp(argv[3], "sort")) {
    // sort the object IDs in the given group
    if (argc < 5) {
      for (i = 0; i < 12; i++) {
        bsort(i);
        write_file(i);
      }
      printf("All groups have been sorted.\n");
    } else {
      get_group(argv[4]);
      bsort(iGroup);
      write_file(iGroup);
      printf("Group %d has been sorted.\n", iGroup + 1);
    }
    return(0);
  }
  // Unhandled action chosen
  printf("Unknown action.\n");
  usage(1);
}

void usage(int iCode) {
  printf("Usage: vgap4grp <slot> <player> [action]\n"
      "  Where action can be: display [<group>]\n"
      "                       delete <group> <object id>\n"
      "                       add <group> <object id>\n"
      "                       sort [<group>]\n"
      "  If [<group>] is not provided, then it will apply to all groups.\n");
  exit(iCode);
}

int read_file(char *sFilename, int iNum) {
  struct gdata *ptr;

  if ((input = fopen(sFilename, "rb")) == NULL) {
    printf("Error opening file %s for reading.\n", sFilename);
    return(0);
  }
  ptr = &group[iNum];
  fread(ptr, sizeof(group[iNum]), 1, input);
  fclose(input);

  return(1);
}

int write_file(int iNum) {
  char sFilename[512];

  sprintf(sFilename, "groups\\s%dx%d\\group%d.grp", iSlot, iPlayer, iNum + 1);
  if ((output = fopen(sFilename, "wb")) == NULL) {
    printf("Error opening file %s for writing.\n", sFilename);
    return(0);
  }
  fwrite(&group[iNum], sizeof(group[iNum]), 1, output);
  fclose(output);

  return(1);
}

void get_group(char *sArg) {
  iGroup = atoi(sArg);
  if (iGroup < 1 || iGroup > 12) {
    printf("Group number is out of range.  Valid range is 1 to 12.\n");
    usage(1);
  }
  iGroup--;
}

void get_object(char *sArg) {
  iObject = atoi(sArg);
  if (iObject < 1 || iObject > 20000) {
    printf("Object number is out of range.  Valid range is 1 to 20000.\n");
    usage(1);
  }
}

// Use Bubble Sort to sort the given group
void bsort(int iGroup) {
  int iSwapI, iSwapS, iPass, iStep;

  for (iPass = 0; iPass < group[iGroup].iCount - 1; iPass++) {
    for (iStep = 0; iStep < group[iGroup].iCount - 1 - iPass; iStep++) {
      if (group[iGroup].iItem[iStep] > group[iGroup].iItem[iStep + 1]) {
        iSwapI = group[iGroup].iItem[iStep];
        iSwapS = group[iGroup].iSerial[iStep];
        group[iGroup].iItem[iStep] = group[iGroup].iItem[iStep + 1];
        group[iGroup].iSerial[iStep] = group[iGroup].iSerial[iStep + 1];
        group[iGroup].iItem[iStep + 1] = iSwapI;
        group[iGroup].iSerial[iStep + 1] = iSwapS;
      }
    }
  }
}

[edit] Future Development

  • Change it into a GUI application.
  • Give it the option of checking for exported CSV data to pull ship object information from.
  • Allow the ADD option to create new GROUPx.GRP files.
  • Handle missing GROUPx.GRP files better.
  • Check to see if the application is being run from the proper folder.
  • Review any odd findings from how the Planets 4 client handles ship group files.
Personal tools