Lernitems

Kein Durchblick im Quellcode von Ja2? Hier werden sie geholfen.

Moderator: Flashy

Antworten
Wulfy301
Bravo-Squad
Beiträge: 640
Registriert: 18 Jun 2004, 22:58

Lernitems

Beitrag von Wulfy301 » 18 Apr 2008, 20:58

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...
Dateianhänge
Lern-Items.txt
(5.19 KiB) 1264-mal heruntergeladen
Lern-Items.doc
(32 KiB) 1275-mal heruntergeladen
Du hast Probleme mit dem "grünen Rand" (Item-Dateien)? Sinclair hat die Lösung -> Guckst Du hier!:hit:

Nitrat
Schrecken der Tyrannen
Beiträge: 19301
Registriert: 24 Jul 2000, 11:00

Beitrag von Nitrat » 18 Apr 2008, 21:04

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......

Wulfy301
Bravo-Squad
Beiträge: 640
Registriert: 18 Jun 2004, 22:58

Beitrag von Wulfy301 » 18 Apr 2008, 22:36

Würde ich mir auch wünschen, aber die Source-änderungen für 1.13 sind schwierig.

Mfg...
Du hast Probleme mit dem "grünen Rand" (Item-Dateien)? Sinclair hat die Lösung -> Guckst Du hier!:hit:

Wulfy301
Bravo-Squad
Beiträge: 640
Registriert: 18 Jun 2004, 22:58

Beitrag von Wulfy301 » 11 Mai 2008, 20:11

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...
Du hast Probleme mit dem "grünen Rand" (Item-Dateien)? Sinclair hat die Lösung -> Guckst Du hier!:hit:

shadow the deat
Alpha-Squad
Beiträge: 1593
Registriert: 01 Feb 2002, 19:22
Kontaktdaten:

Beitrag von shadow the deat » 13 Mai 2008, 10:54

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
:lhdevil: :uriel: Führer der SoS :lhdevil: (soldiers of shadow)

:lhdevil: Enominis Satanis :lhdevil:

Die Your God is Dead
Behold Satans Rise :hail:


(Action)Gamer für Gewalt und Terror :k:

Realist
Alpha-Squad
Beiträge: 1573
Registriert: 24 Apr 2003, 11:00
Wohnort: Düsseldorf

Beitrag von Realist » 13 Mai 2008, 11:05

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:

Wulfy301
Bravo-Squad
Beiträge: 640
Registriert: 18 Jun 2004, 22:58

Beitrag von Wulfy301 » 13 Mai 2008, 19:31

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...
Du hast Probleme mit dem "grünen Rand" (Item-Dateien)? Sinclair hat die Lösung -> Guckst Du hier!:hit:

Realist
Alpha-Squad
Beiträge: 1573
Registriert: 24 Apr 2003, 11:00
Wohnort: Düsseldorf

Lernitems in 1.13 - Ein Drama in fünf Akten

Beitrag von Realist » 14 Mai 2008, 10:44

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:
Dateianhänge
XML_TrainingItems.zip
(1.65 KiB) 1161-mal heruntergeladen

Realist
Alpha-Squad
Beiträge: 1573
Registriert: 24 Apr 2003, 11:00
Wohnort: Düsseldorf

Beitrag von Realist » 14 Mai 2008, 10:45

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

Wulfy301
Bravo-Squad
Beiträge: 640
Registriert: 18 Jun 2004, 22:58

Beitrag von Wulfy301 » 14 Mai 2008, 18:21

@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...
Du hast Probleme mit dem "grünen Rand" (Item-Dateien)? Sinclair hat die Lösung -> Guckst Du hier!:hit:

Mattes
Milizenausbilder
Beiträge: 104
Registriert: 27 Jul 2007, 16:04

Beitrag von Mattes » 14 Mai 2008, 19:20

Coole Sache, kann man davon ausgehen, dass das mal in v1.13 eingebaut wird? Oder wie läuft das mit Source-Änderungen normalerweise?

Antworten