VGA Planets 4 Ship Group Editor
From PlanetsWiki
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.
