E
so da bin ich schon wieder
und hoffe das ich mit meiner Angelegenheit immer noch im richtigen Forum bin.
wie schon geschrieben, konnte ich den code endlich kompillieren
und ich konnte auch die zu übersetzenden Teile übersetzen und es funktioniert immer noch.
nun habe ich allerdings immer noch ein hoffentlich kleines Problem :
der Parser liest den Chatlog aus und fügt die Werte in ein .xml Dokument ein.
Das tut er auch so wie er sollte,allerdings bei einem Wert will er nicht:
Das hier z.B. soll er lesen:
[11:20:27] <Begin Info: Obedience>
[11:20:27]
[11:20:27] usable by:
[11:20:27] - Spiritmaster
[11:20:27] - Runemaster
[11:20:27] - Bonedancer
[11:20:27]
[11:20:27] Magical Bonuses:
[11:20:27] - Summoning: 4 pts
[11:20:27] - Constitution: 18 pts
[11:20:27] - Matter: 10%
[11:20:27] - Power: 8 pts
[11:20:27]
[11:20:27] Focus Bonuses:
[11:20:27] - ALL spell lines: 50 lvls
[11:20:27]
[11:20:27]
[11:20:27] Level Requirement:
[11:20:27] - 50 Level
[11:20:27]
[11:20:27] Damage Modifiers:
[11:20:27] - 16,5 Base DPS
[11:20:27] - 4,5 Weapon Speed
[11:20:27] - 100% Quality / 100% Condition
[11:20:27] - Damage Type: Crush
[11:20:27]
[11:20:27] Effective Damage:
[11:20:27] - 16,5 DPS
[11:20:27] <End Info>
das liest er alles korrekt bis auf das:
[11:20:27] Focus Bonuses:
[11:20:27] - ALL spell lines: 50 lvls
ich habe herausgefunden, das,wenn dieser Wert unter "10" liegt, es korrekt ausgelesen wird sobald er aber auf 10 oder höher geht findet er ihn gar nicht mehr, hat vielleicht jemand eine Ahnung ?
#include <assert.h>
#include <StrUtils.hpp>
#pragma hdrstop
#include "ChatLog.h"
#include "Utils.h"
#include "MainFrame.h" // Brauch die xml_config Struktur
// Mit diesem String beginnt der Info-Bereich
const char strInfoStart[] = "<Begin Info:";
// Mit diesem String endet der Info-Bereich
const char strInfoStop[] = "<End Info>";
// Mit diesem String beginnt der Info-Bereich
const char strMagBoniStart[] = "Bonuses:";
// Ein paar Strings zur identifikation bestimmter Werte
const char strAF[] = "Armor";
const char strAbsorb[] = "Absorption"; // Daraus läßt sich Rüstungsklasse gewinnen
const char strQuality[] = "Quality";
const char strSpeed[] = "Weapon";
const char strUnique[] = "Einzigartiger Gegenstand";
const char strCrafted[] = "Hergestellt von:";
const char strBonus[] = "Bonus auf";
const char strBonus2[] = "Bonus zum";
const char strRestriction[] = "usable by:";
const char strArtifact[] = "Artefakt:";
const char strActivLevel[] = " (Benötigte Objektstufe:";
//---------------------------------------------------------------------------
CChatLog::CChatLog()
{
fChatLog = NULL;
arItemNames = new TStringList;
};
CChatLog::~CChatLog()
{
CloseChatLog();
delete arItemNames;
};
// Öffnet die ChatLog-Datei für Lesezugriff
int CChatLog::OpenChatLog(const char* Filename)
{
if (fChatLog != NULL) delete fChatLog;
// Seek funktioniert nur richtig im binary-mode. Nur ist jetzt immer /r hinter einem String
fChatLog = new fstream(Filename, ios_base::in | ios_base::binary);
iLineNo = 0;
if (fChatLog->is_open()) return true;
else return false;
};
void CChatLog::CloseChatLog()
{
if (fChatLog != NULL)
{
fChatLog->close();
delete fChatLog;
}
fChatLog = NULL;
};
// enumwerte des Parsers in Init
enum ParserStateInit
{
STATE_START, // Scanne nach Start einer Info-Section
STATE_ITEM, // Suche danach in der Sektion, das es ein Gegenstand ist
};
// Diese Funktion scannt erstmal das gesamte Log nach Gegenständen und merkt
// sich deren Position. In einem zweiten durchlauf wird versucht, die Herkunft
// der Gegenstände herauszubekommen. Doppelte Items werden herausgefiltert
void CChatLog::Init(void)
{
int posStart; // Startposition des aktuellen Info-Bereichs
AnsiString strName; // Name des aktuellen Info-Bereichs
char Line[1024]; // Hier eine maximale Länge eines Textes heruasfinden
bool bIsItem;
nItems = 0;
iLineNo = 0;
arItemNames->Clear();
arOffsets.Length = 0;
ParserStateInit State = STATE_START;
fChatLog->seekg(0, ios::beg); // Lesezeiger auf Dateianfang
fChatLog->getline(Line, 1024);
while(!fChatLog->eof())
{
assert(StrLen(Line) < 1024);
iLineNo++;
switch (State)
{
case STATE_START:
{ // Suche nach dem Start eines Info-Bereichs
char *pStart = AnsiStrPos(Line, (char*)strInfoStart);
if (pStart != NULL)
{
posStart = fChatLog->tellg() - fChatLog->gcount();
AnsiString sTemp = pStart;
strName = sTemp.SubString(sizeof(strInfoStart) + 1, StrLen(pStart) - sizeof(strInfoStart)- 2);
// Jetzt mal schauen, ob es einen Doppelpunkt gibt.
int p = strName.AnsiPos(':');
if (p > 0)
{ // Wenn ja, dann den String bis dorthin abschneiden
strName = strName.SubString(p + 2, strName.Length() - p - 1);
}
bIsItem = false;
State = STATE_ITEM;
}
}
break;
case STATE_ITEM:
{ // Suche nach Magieboni oder Info-Sektion Ende
char *pStart = AnsiStrPos(Line, (char*)strMagBoniStart);
if (pStart != NULL) bIsItem = true;
// Ist Info-Sektion zu Ende?
pStart = AnsiStrPos(Line, (char*)strInfoStop);
if (pStart != NULL)
{
State = STATE_START; // Nach der nächsten Info-Sektion suchen
if (bIsItem)
{ // Ende Info-Sektion und es ist ein Gegenstand
// Also in die Liste der zu untersuchenden Gegenstände aufnehmen
int index;
if ((index = arItemNames->IndexOf(strName)) == -1)
{ // Item mit diesem Namen gibts noch nicht (im Logfile)
arItemNames->Add(strName);
arOffsets.Length = nItems + 1;
arOffsets[nItems] = posStart;
nItems++;
}
else
{ // Name gibts schon. Offset aber auf diesen setzen,
// da immer das letzte das aktuellste sein sollte
arOffsets[index] = posStart;
}
}
}
}
break;
}
fChatLog->getline(Line, 1024);
}
}
// Diese Funktion macht die eigentliche Lesearbeit
// Input ist dabei der Index des zu beschaffenden Items und einen Zeiger
// auf eine CItem-Klasse, welche ausgefüllt werden soll
// Rückgabe ist true für keinen Fehler
int CChatLog::GetItem(int index, CItem* Item)
{
unsigned int i;
char Line[1024]; // Hier eine maximale Länge eines Textes heruasfinden
char sArg[64]; // Längere Bonusbezeichnungen gibts glaub nicht
int NextBonus = 0; // Welche Position soll der nächste Bonus eingetragen werden
int NextRestriction = 0; // Nächster Index einer Klassenbeschränkung
bool bRestriction = false;
if ((index < 0) && (index >= nItems)) return false; // Itemindex nicht im gültigen Bereich
Item->Init();
Item->Name = arItemNames->Strings[index];
Item->Realm = player->Realm; // Immer Realm des Spielers annehmen
Item->Quality = 0;
// Versuche Aufgrund des Namen auf den Itemslot zu schliessen
AnsiString strTemp = Item->Name.LowerCase();
for (i = 0; i < 18; i++)
{
for (int j = 0; j < xml_config.arItemSlots[i].arIds.Length; j++)
{
if (strTemp.AnsiPos(xml_config.arItemSlots[i].arIds[j]) > 0)
Item->Position = i;
}
}
// Lesezeiger auf Beginn der entsprechenden Info-Sektion stellen
fChatLog->clear(); // Ist nötig, da wir eventuell noch im eof-state sind
fChatLog->seekg(arOffsets[index], ios::beg);
fChatLog->getline(Line, 1024); // Erste Zeile Lesen (kann ignoriert werden)
fChatLog->getline(Line, 1024); // Erste Zeile mit Infos
while(!fChatLog->eof())
{
assert(StrLen(Line) < 1024);
int Value = 0;
// Ist Info-Sektion zu Ende?
char *pStart = AnsiStrPos(Line, (char*)strInfoStop);
if (pStart!= NULL) break;
if (Line[11] == '-')
{ // Alles danach ist ein Wert, der mich interessiert
// Suche erstmal nach einem Zahlenwert. Sollte immer nur einer sein
// Bonus-Argument ist immer der String vor einem Doppelpunkt,
// oder der String hinter einer Zahl
bool bValue = false; // Gibts eine Zahl?
bool bDoppel = false; // gibt es einen Doppelpunkt im String
bool bPercent = false; // Es ist ein Prozent-Wert
int pArg = 0; // Aktuelle Position im Argument-String
for (i = 13; i < StrLen(Line); i++)
{
if ((Line[i] >= '0') && (Line[i] <= '9'))
{
bValue = true;
Value = Value * 10 + Line[i] - '0';
}
else if (Line[i] == ':') bDoppel = true;
else if (Line[i] == ' ')
{
if (bValue && (bDoppel || (pArg > 0))) break;
pArg = 0;
}
else if (Line[i] == '%')
bPercent = true;
else if ((Line[i] == '\r') || (Line[i] == ',')) {} // Diese Zeichen ignorieren
else
{
sArg[pArg++] = Line[i];
sArg[pArg] = 0;
}
}
if (bValue)
{ // In xml_config nach einem entsprechendem Boni suchen
int bid = xml_config.GetBonusId(sArg, bPercent);
if (bid < 0)
{ // testen, ob der gesamte Text nicht vielleicht doch ein Bonus ist
bid = xml_config.GetBonusId(MidStr(AnsiString(Line), 14, i - 16), bPercent);
}
if (bid >= 0)
{ // Es ist ein regulärer Bonus
Item->Effect[NextBonus] = bid;
Item->EffectValue[NextBonus] = Value;
NextBonus++;
}
else
{ // Hier ein paar zusätzliche Werte nehmen, die keine Boni sind
if (strcmp(sArg, strAF) == 0) Item->AF = Value;
if (strcmp(sArg, strQuality) == 0) Item->Quality = Value;
if (strcmp(sArg, strSpeed) == 0) Item->Speed = Value;
if (strcmp(sArg, strAbsorb) == 0)
{ // Value in Rüstungsklasse umwandeln
switch (Value)
{
case 0: Item->Class = 0; Item->Level = Item->AF;break;
case 10: Item->Class = 1; Item->Level = Item->AF / 2; break;
case 19: Item->Class = 2; Item->Level = Item->AF / 2; break;
case 27: Item->Class = 3; Item->Level = Item->AF / 2; break;
case 34: Item->Class = 4; Item->Level = Item->AF / 2; break;
}
//if (Item->Position < 0)
// Item->Position = 0; // Alle Rüstungen als Handschuhe annehmen
// Es gibt leider keine Info darüber im Log
// Wenn wir die Position auf -1 lassen, dann kommt automatisch eine Auswahlbox
}
if (strcmp(sArg, "DPS") == 0)
{ // Nur ersten DPS-Wert speichern
if (Item->DPS == 0)
{
Item->DPS = Value;
// Berechne den Itemlevel
int level = (Value - 11) / 3;
if (level > 51) level = 51;
Item->Level = level;
}
}
}
}
}
// else
{ // noch ein paar besondere Strings auswerten
if (strncmp(&Line[11], strUnique, sizeof(strUnique) - 1) == 0)
{ // Unique Gegenstände nicht importieren
return false;
}
if (strncmp(&Line[11], strCrafted, sizeof(strCrafted) - 1) == 0)
{ // Craftet Gegenstände nicht importieren
return false;
}
if (strncmp(&Line[11], strArtifact, sizeof(strArtifact) - 1) == 0)
{
Item->MaxLevel = 10;
Item->Realm = 7;
}
if ((strncmp(&Line[11], strBonus, sizeof(strBonus) - 1) == 0) \
|| (strncmp(&Line[11], strBonus2, sizeof(strBonus2) - 1) == 0))
{ // Spezielle Werte (meist Bonuserhöhungen)
// Bonus auf BONUS: VALUE
unsigned int i;
for (i = 21; i < StrLen(Line); i++)
{ // Alles bis zum Doppelpunkt in sArg kopieren
if (Line[i] == ':') break;
sArg[i - 21] = Line[i];
}
sArg[i - 21] = 0;
for (; i < StrLen(Line); i++)
{
if ((Line[i] >= '0') && (Line[i] <= '9'))
{
Value = Value * 10 + Line[i] - '0';
}
}
// In xml_config nach einem entsprechendem Boni suchen
int bid = xml_config.GetBonusId(sArg);
if (bid >= 0)
{ // Es ist ein regulärer Bonus
Item->Effect[NextBonus] = bid;
Item->EffectValue[NextBonus] = Value;
NextBonus++;
}
else
{ // Fehlermeldung
Application->MessageBoxA(AnsiString("Ein Bonus '" + AnsiString(sArg) + "' ist unbekannt!\nDie Datei 'config.xml' bzw. die entsprechende Sprachdatei anpassen!").c_str(), "Fehler");
}
}
if (strncmp(&Line[11], strActivLevel, sizeof(strActivLevel) - 1) == 0)
{ // Danach kommt ne Zahl, welche den Level angibt
int level = Str2Int(&Line[11 + sizeof(strActivLevel)]);
Item->EffectLevel[NextBonus - 1] = level;
}
unsigned int cp = 12;
if ((strncmp(&Line[11], strRestriction, sizeof(strRestriction) - 1) == 0) \
|| (strncmp(&Line[12], strRestriction, sizeof(strRestriction) - 1) == 0))
{ // Solange nachfolgende Strings eine Klasse darstellen, solange
// diese bei den Beschränkungen eintragen
bRestriction = true;
cp = 12 + sizeof(strRestriction);
}
while (bRestriction && (cp < StrLen(Line)))
{
int pArg = 0;
for (; cp < StrLen(Line); cp++)
{
if ((Line[cp] == ' ') || (Line[cp] == ',') || (Line[cp] == '-') || (Line[cp] == '\r'))
{
sArg[pArg] = 0;
if (pArg > 0)
{ // Es gibt einen String. Schauen obs ne Klasse ist
int cid = xml_config.GetClassId(sArg);
if (cid >= 0)
{
Item->ClassRestriction[NextRestriction++] = cid;
}
else
{ // Keine Klasse mehr, Modus aufheben
bRestriction = false;
}
}
pArg = 0;
}
else
{
sArg[pArg++] = Line[cp];
}
}
}
}
fChatLog->getline(Line, 1024);
}
return true;
}
#pragma package(smart_init)