Seite 1 von 1

Lernitems

Verfasst: 18 Apr 2008, 20:58
von Wulfy301
Hallo mal wieder

Ich benötige noch mal Hilfe von fähigen Source Programmierer!:help:

Im Anhang befindet sich ein Tut. für 1.12 (dank Realist:k:) das erklärt wie man Items erstellt, mit deren Hilfe es möglich ist, die Fähigkeiten der Söldner zu steigern.

Weil das ein wichtiger Bestandteil meines MOD's ist, hoffe und bitte ich das mir jemand helfen kann das ganze für 1.13 umzuschreiben.

Mfg...

Verfasst: 18 Apr 2008, 21:04
von Nitrat
Ich hoffe das dein Mod jemals released wird, denn diese
Änderungen sind einfach genial die ich mal ingame benutzen möchte.

Ich kann das nicht selbst einbauen.
MFG......

Verfasst: 18 Apr 2008, 22:36
von Wulfy301
Würde ich mir auch wünschen, aber die Source-änderungen für 1.13 sind schwierig.

Mfg...

Verfasst: 11 Mai 2008, 20:11
von Wulfy301
Das es schwierig ist die Lernitems in 1.13 einzubauen war mir klar, aber das es gar keinen gibt der das machen könnte macht mir jetzt :angst:!

Nein mal im ernst, kann mir hierbei wirklich keiner helfen?

Mfg...

Verfasst: 13 Mai 2008, 10:54
von shadow the deat
ich weiß nicht ob es auch so mit 1.13 geht aber es könnte alleine daran liegen das im tut

[PHP] INT16 sPointsToUse;
UINT16usTotalKitPoints;
[/PHP]

steht da fehlen die Leerzeichen zum Trennen bzw nur eins

[PHP] INT16 sPointsToUse;
UINT16 usTotalKitPoints;
[/PHP]


des Rest des Codes müsste richtig sein und auch so funktionieren da das Tut eigendlich einfach geschrieben ist. Es könnte nur ein Problem mit der Zuordnung mit den Items geben aber in wie weit das jetzt in 1.13 geändert war kann ich nicht mehr sagen dazu bin ich zulange wieder aus den Source raus aber wenn du Glück hast müsste es ohne weitere Probleme gehen

Verfasst: 13 Mai 2008, 11:05
von Realist
Ja ne, das "Tut" (hat diese Bezeichnung nicht ansatzweise verdient) könnt ihr löschen, das ist 1. völliger Scheiss und 2. in keinster Weise mit 113 kompatibel.
Aber halte aus, ich bin hinterher. :compiman:

Verfasst: 13 Mai 2008, 19:31
von Wulfy301
Realist weiß, das ich keine Leuchte betreffs Source modden bin, aber mit 1.13 komme ich überhaupt nicht klar!:susp:
Danke euch beiden das ihr mir helfen wollt!:erdbeerteechug:



Mfg...

Lernitems in 1.13 - Ein Drama in fünf Akten

Verfasst: 14 Mai 2008, 10:44
von Realist
Dann wollen wir mal. :enf:



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 :khelle:

Verfasst: 14 Mai 2008, 10:45
von Realist
Schritt 5: "Der eigentliche Code" oder "Wo sich Alt und Neu treffen"
Bis jetzt war alles nur Vorgeplänkel und hat kaum was damit gemein, was ich vor Jahren mal verbrochen hatte und jetzt für alle Ewigkeiten im Eingangspost unten anhängt. Aber damit ist Schluss, denn jetzt geht das Elend weiter. :khelle:

Als erstes machen wir wieder Items, die ein Lernprofil haben, auf die Söldnersilhouette anwendbar.

Code: Alles auswählen

// Tactical\Interface Items.cpp, CompatibleItemForApplyingOnMerc
// ATE: Would be nice to have flag here to check for these types....
if ( Item[usItem].camouflagekit || usItem == ADRENALINE_BOOSTER || usItem == REGEN_BOOSTER ||

    // [NEU    
    Item[usItem].iTrainingItem != -1 ||
    // neu]

    usItem == SYRINGE_3 || usItem == SYRINGE_4 || usItem == SYRINGE_5 ||
    Item[usItem].alcohol  || Item[usItem].canteen || usItem == JAR_ELIXIR )
Jetzt kommt wieder Copy/Paste Code, wo wir uns dem Wesentlichen nähern. Updaten wir den Eventhandler.

Code: Alles auswählen

// Tactical\Interface Panels.cpp, SMInvClickCamoCallback
// [NEU
else if (ApplyTrainingItem( gpSMCurrentMerc, gpItemPointer, &fGoodAPs ))
{
    // Dirty
    fInterfacePanelDirty = DIRTYLEVEL2;

    // Check if it's the same now!
    if ( gpItemPointer->exists() == false )
    {
        gbCompatibleApplyItem = FALSE;
        EndItemPointer( );
    }
    // Say OK acknowledge....
    gpSMCurrentMerc->DoMercBattleSound( BATTLE_SOUND_COOL1 );
}
// neu]

else
{
    // Send message
    ScreenMsg( FONT_MCOLOR_LTYELLOW, MSG_UI_FEEDBACK, TacticalStr[ CANNOT_DO_INV_STUFF_STR ] );
}
Auf ins große Finale. Die ApplyTrainingItem Funktion, die wir gerade aufrufen ohne das sie existiert, stellt die Krönung dar. Schreiben wir erstmal den Prototype.

Code: Alles auswählen

// z.B. items.h
BOOLEAN ApplyTrainingItem( SOLDIERTYPE * pSoldier, OBJECTTYPE * pObj, BOOLEAN *pfGoodAPs );
Nehmen wir uns Items.cpp vor und deklarieren oben einen Prototype aus campaign.cpp um jene Funktion nutzen zu können:

Code: Alles auswählen

void ChangeStat( MERCPROFILESTRUCT *pProfile, SOLDIERTYPE *pSoldier, UINT8 ubStat, INT16 sPtsChanged );
Jetzt die entscheidenden Zeilen Code, die wir irgendwo unten in items.cpp unterbringen:

Code: Alles auswählen

INT8 CalcStatDelta(INT8 currentStat, INT8 proposedDelta)
{
    if (currentStat + proposedDelta > 100)
        return 100 - currentStat;
    else if (currentStat + proposedDelta < 0)
        return -currentStat;
    else
        return proposedDelta;
}

BOOLEAN ApplyTrainingItem( SOLDIERTYPE * pSoldier, OBJECTTYPE * pObj, BOOLEAN *pfGoodAPs )
{
    INT16		sPointsToUse;
	UINT16	usTotalKitPoints;

    (*pfGoodAPs) = TRUE;

	if (Item[pObj->usItem].iTrainingItem == -1 )
	{
		return( FALSE );
	}

	usTotalKitPoints = TotalPoints( pObj );
	if (usTotalKitPoints == 0)
	{
		// HUH??? 
		return( FALSE );
	}

	if (!EnoughPoints( pSoldier, 5, 0, TRUE ) )
	{
        (*pfGoodAPs) = FALSE;
		return( TRUE );
	}

	DeductPoints( pSoldier, 5, 0 );

	sPointsToUse = usTotalKitPoints;

    
    ChangeStat( &(gMercProfiles[pSoldier->ubProfile]),  pSoldier,  HEALTHAMT, 
        CalcStatDelta( gMercProfiles[pSoldier->ubProfile].bLifeMax, TRAININGITEMS[Item[pObj->usItem].iTrainingItem].bHealth));

    ChangeStat( &(gMercProfiles[pSoldier->ubProfile]),  pSoldier,  AGILAMT,
        CalcStatDelta( gMercProfiles[pSoldier->ubProfile].bAgility, TRAININGITEMS[Item[pObj->usItem].iTrainingItem].bAgility));

    ChangeStat( &(gMercProfiles[pSoldier->ubProfile]),  pSoldier,  DEXTAMT,
        CalcStatDelta( gMercProfiles[pSoldier->ubProfile].bDexterity, TRAININGITEMS[Item[pObj->usItem].iTrainingItem].bDexterity));

    ChangeStat( &(gMercProfiles[pSoldier->ubProfile]),  pSoldier,  WISDOMAMT,
        CalcStatDelta( gMercProfiles[pSoldier->ubProfile].bWisdom, TRAININGITEMS[Item[pObj->usItem].iTrainingItem].bWisdom));

    ChangeStat( &(gMercProfiles[pSoldier->ubProfile]),  pSoldier,  MEDICALAMT,
        CalcStatDelta( gMercProfiles[pSoldier->ubProfile].bMedical, TRAININGITEMS[Item[pObj->usItem].iTrainingItem].bMedical));

    ChangeStat( &(gMercProfiles[pSoldier->ubProfile]),  pSoldier,  EXPLODEAMT,
        CalcStatDelta( gMercProfiles[pSoldier->ubProfile].bExplosive, TRAININGITEMS[Item[pObj->usItem].iTrainingItem].bExplosives));

    ChangeStat( &(gMercProfiles[pSoldier->ubProfile]),  pSoldier,  MECHANAMT,
        CalcStatDelta( gMercProfiles[pSoldier->ubProfile].bMechanical, TRAININGITEMS[Item[pObj->usItem].iTrainingItem].bMechanical));

    ChangeStat( &(gMercProfiles[pSoldier->ubProfile]),  pSoldier,  MARKAMT,
        CalcStatDelta( gMercProfiles[pSoldier->ubProfile].bMarksmanship, TRAININGITEMS[Item[pObj->usItem].iTrainingItem].bMarksmanship));

    ChangeStat( &(gMercProfiles[pSoldier->ubProfile]),  pSoldier,  STRAMT,
        CalcStatDelta( gMercProfiles[pSoldier->ubProfile].bStrength, TRAININGITEMS[Item[pObj->usItem].iTrainingItem].bStrength));

    ChangeStat( &(gMercProfiles[pSoldier->ubProfile]),  pSoldier,  LDRAMT, 
        CalcStatDelta( gMercProfiles[pSoldier->ubProfile].bLeadership, TRAININGITEMS[Item[pObj->usItem].iTrainingItem].bLeadership));


	UseKitPoints( pObj, sPointsToUse, pSoldier );

	return( TRUE );
}
Zugegebenermaßen nicht besonders schön, noch nicht einmal effektiv, aber immerhin gerade so funktionstüchtig (und damit im Einklang mit dem Originalcode).
Was passiert hier? Eigentlich nicht viel. Für jede Söldnerfähigkeit wird der Bonus aus dem Lernitemprofil hinzugerechnet; die kleine Funktion oben sorgt dafür, dass alles im Rahmen vo 0 - 100 bleibt.


Damit wärs geschafft. Ich hoffe, nichts vergessen zu haben, sonst krieg ich wieder Haue. :D

Verfasst: 14 Mai 2008, 18:21
von Wulfy301
@Realist
WOW!:eek:
Ich hab das jetzt nur mal kurz angelesen und ich komme auch erst am Wochenende dazu das auszuprobieren, aber das sieht sehr beeindruckend aus!

Schon mal ein großes DANKESCHÖÖN an Realist!:k:

Mfg...

Verfasst: 14 Mai 2008, 19:20
von Mattes
Coole Sache, kann man davon ausgehen, dass das mal in v1.13 eingebaut wird? Oder wie läuft das mit Source-Änderungen normalerweise?