Dann wollen wir mal.
Schritt 1: Neue XML-Datei
Gehen wir mal ganz 1.13 konform und erstellen erstmal eine neue XML-Datei mit dem Namen "trainingitems.xml" im Verzeichnis "TableData". Da kopieren wir dann folgenden Inhalt hinein:
Code: Alles auswählen
<?xml version="1.0" encoding="utf-8"?>
<TRAININGITEMLIST>
<TRAININGITEM>
<usIndex>0</usIndex>
<bHealth>10</bHealth>
<bAgility>-2</bAgility>
<bDexterity>3</bDexterity>
<bStrength>-4</bStrength>
<bWisdom>5</bWisdom>
<bLeadership>-6</bLeadership>
<bMarksmanship>7</bMarksmanship>
<bExplosives>-8</bExplosives>
<bMechanical>9</bMechanical>
<bMedical>-10</bMedical>
</TRAININGITEM>
</TRAININGITEMLIST>
Hier können verschiedene Auswirkungsprofile angelegt werden, die über die usIndex Eigenschaft referenziert werden.
Schritt 2: Repräsentation im Code
Unsere hübsche XML Struktur müssen wir natürlich in Code abbilden. Hierzu habe ich völlig uneleganterweise eine Struktur gewählt, die jedes Attribut einzeln aufführt.
Code: Alles auswählen
// z.B. "item types.h"
struct TrainingItem
{
UINT16 usIndex;
INT8 bHealth;
INT8 bAgility;
INT8 bDexterity;
INT8 bStrength;
INT8 bWisdom;
INT8 bLeadership;
INT8 bMarksmanship;
INT8 bExplosives;
INT8 bMechanical;
INT8 bMedical;
};
Nicht schön, aber verständlich. Legen wir jetzt unsere Datenbank an, in der wir die XML-Vorgaben aufnehmen können.
Code: Alles auswählen
// z.B. "items.cpp"
struct TrainingItem TRAININGITEMS[MAX_TRAININGITEMS];
MAX_TRAININGITEMS ist unser Limit, wieviele Einträge wir in der XML-Datei aufnehmen können. Einfach nach Belieben wir folgt setzen:
Code: Alles auswählen
// z.B. "items types.h"
#define MAX_TRAININGITEMS 100
extern struct TrainingItem TRAININGITEMS[MAX_TRAININGITEMS];
Schritt 3: Einlesen der XML-Datei
Das ganze Gefriemel die XML-Datei zu parsen, spare ich an dieser Stelle mal aus und hänge die entsprechende "XML_TrainingITems.cpp" an. Diese kann einfach dem Tactical-Projekt hinzugefügt werden, unter der Vorraussetzung, dass obiger Code in den empfohlenen Quellcodedateien eingefügt wurde.
Anschließend verpassen wir der Tactical\XML.h noch ein Update:
Code: Alles auswählen
// XML.h
#define TRAININGITEMSFILENAME "trainingitems.xml"
extern BOOLEAN ReadInTrainingItemStats(STR filename);
Anschließend lesen wir die Datei tatsächlich ein, indem wir "LoadExternalGameplayData" aus Init.cpp updaten. Dazu fügen wir in geeigneter Weise folgenden Code ein:
Code: Alles auswählen
strcpy(fileName, directoryName);
strcat(fileName, TRAININGITEMSFILENAME);
if(!ReadInTrainingItemStats(fileName))
return FALSE;
Schritt 4: Verknüpfung mit Items.xml herstellen
Was uns bei den XMLs jetzt noch fehlt, ist die Möglichkeit ein Item in items.xml mit einem Lernprofil zu verbinden. Das Ziel soll es sein ein TrainingItem Tag einzubauen, welches die Referenz stellt, sodass dies Möglich wird:
Code: Alles auswählen
<ITEM>
<uiIndex>266</uiIndex>
<szItemName>Walkman</szItemName>
<TrainingItem>0</TrainingItem>
</ITEM>
Wie bereits angedeutet, stellt die "0" die Verknüpfung zum Lernitemprofil mit usIndex = 0 her. Damit das geht, müssen wir natürlich ein paar Sachen hinzufügen.
Fangen wir mit der INVTYPE struct in "item types.h" an, wo wir zum Schluss unsere Verweisvariable einbauen:
Code: Alles auswählen
BOOLEAN scifi; // item only available in scifi mode
BOOLEAN newinv; // item only available in new inventory mode
UINT16 defaultattachment;
// neu:
INT32 iTrainingItem;
} INVTYPE;
Haben wir diese Voraussetzung im Code geschaffen, können wir uns daran machen, dort einen entsprechenden Wert aus items.xml einzulesen. Dazu muss XML_Items.cpp dran glauben. Als erstes nehmen wir uns
static void XMLCALL
itemStartElementHandle(void *userData, const XML_Char *name, const XML_Char **atts)
vor. Weit oben gibt es folgenden Zweig, hier in aktualisierter Form:
Code: Alles auswählen
else if(strcmp(name, "ITEM") == 0 && pData->curElement == ELEMENT_LIST)
{
pData->curElement = ELEMENT;
if ( !localizedTextOnly )
memset(&pData->curItem,0,sizeof(INVTYPE));
// NEU
pData->curItem.iTrainingItem = -1;
pData->maxReadDepth++; //we are not skipping this element
}
Diese -1, die wir bei jedem Item setzen, belegt unsere Verknüpfung mit -1 statt mit 0 vor. Dies hat die Bewandnis, dass standardmäßig eine 0 gesetzt wird, falls kein entsprechendes Tag in items.cpp gefunden wird. 0 stellt aber ein gülitges Verweiselement dar, daher weichen wir auf -1 aus als Indikator, dass kein TrainingItem Tag gesetzt worden ist.
Was nun im Code folgt, sind zahlreiche Vergleiche mit bekannten Tagnamen. An dieser Stelle jubeln wir unser TrainingItem Tag unter.
Code: Alles auswählen
strcmp(name, "SciFi") == 0 ||
strcmp(name, "NewInv") == 0 ||
strcmp(name, "TrainingItem") == 0 || // NEU
strcmp(name, "fFlags") == 0 ))
Als nächstes ist
static void XMLCALL
itemEndElementHandle(void *userData, const XML_Char *name)
an der Reihe. Dort schmuggeln wir die eigentliche Einleseprozedur unseres Tags ein.
Code: Alles auswählen
if(strcmp(name, "BestLaserRange") == 0)
{
pData->curElement = ELEMENT;
pData->curItem.bestlaserrange = (INT16) atol(pData->szCharData);
}
// [NEU
if(strcmp(name, "TrainingItem") == 0)
{
pData->curElement = ELEMENT;
pData->curItem.iTrainingItem = (INT32) atol(pData->szCharData);
}
// NEU]
pData->maxReadDepth--;
Das wars mit allem XML. Jetzt gehts ans Eingemachte.
[EDIT]
Selbstverständlich vergessen, den versprochenen Anhang hochzuladen