Da ich auch auf das Inventar des Helden zugreifen möchte, dachte ich mir mal daß ich hier mit reinschreibe.
Ich möchte nämlich das Inventar-System etwas modifizieren. Sprich ein neues Äußeres Erscheinungsbild, so daß es dann möglich ist über die Maus auf ein Icon zu klicken und das Inventar damit zu öffnen und zu schließen.
Maus und Icon ist schon fertig, fehlt also nur noch der "kleine" Rest.
Ich hab nun mal folgendes probiert:
Code:
var oCNpc her; her = Hlp_GetNpc(hero);
var oCItem dat;
dat = MEM_PtrToInst(her.inventory2_inventory_data);
PrintScreen(ConcatStrings("Data: ", dat._zCObject_objectName), 1, 9, font, 1);
Laut ZSpy wird aber immer versucht eine leere Instanz zu adressieren, aber ich denke mal daß ich bei den inventory2_* schon ganz richtig unterwegs bin oder muß ich das ganz anders angehen, um daß Inventar auszulesen?!
Npc_GetInventoryItemBySlot(hero, 0, [position]) ist eventuell bequemer.
Dein Ansatz ist im Prinzip richtig, allerdings ist das erste Element einer Liste (der Listenkopf) immer leer (sonst wäre es schwierig eine leere Liste von einer Liste mit nur einem Element zu unterscheiden).
Das heißt wenn du das erste Element im Inventar des Spielers haben willst müsstest du folgendes tun:
Code:
var oCNpc her; her = Hlp_GetNpc(hero);
var zCListSort list;
list = MEM_PtrToInst(her.inventory2_inventory_next);
var oCItem dat;
dat = MEM_PtrToInst(list.data);
PrintScreen(ConcatStrings("Data: ", dat._zCObject_objectName), 1, 9, font, 1);
Das funktioniert so, falls das Inventar nicht leer ist.
Allerdings führt ein erneuter Aufruf von list = MEM_PtrToInst(her.inventory2_inventory_next); leider nicht dazu, daß nächste Element abzufangen, sondern es wird dann wieder das 1. Element ausgegeben. Evtl. wird ja bei jedem Aufruf die Liste wieder von vorne abgegrast.
Ich werde mir aber auch noch mal Npc_GetInventoryItemBySlot(hero, 0, [position]) anschauen, vielleicht bringt mich das ja auch weiter.
Im Grunde benötige ich ja nur ein Array oder was auch immer was so ähnlich aussieht wie folgt:
item[0] = "Item";
item[1] = "noch ein Item";
item[2] = EOF oder NULL oder wie auch immer
Dann könnte man das Ganze auch weiter verarbeiten, bis hin zur Darstellung in einem grafischen Inventar.
Hi, nochmal eine grundsätzliche Frage: Wie verdammt nochmal lernt man in IDA zu sehen, was worauf steht? Woher wisst Ihr immer, was z.B. eax oder esp, oder auch esp+4 usw. ist?
Wenn ich mir nachstehende FUnktion ansehe, erwarte ich eigentlich, das irgendwo ein Pointer auf das Item ist. Aber woran sehe ich, wo er sich verbirgt
Beschäftige dich dazu mal mit Calling Conventions. Diese Stellen eine Konvention (ein Protokoll) dar, wie Funktionen miteinander umgehen.
Etwa besagt die Calling Convention __thiscall, dass der "this"-Pointer, also der Zeiger auf das Objekt, auf dem die Funktion ausgeführt werden soll (nur in der objektorientierten Programmierung verwendet), im Register ecx stehen muss, zum Zeitpunkt zu dem die Funktion aufgerufen wird. Andere Parameter stehen je nach Calling Convention an anderen Stellen (typischerweise auf dem Stack).
esp ist der Stackzeiger und zeigt auf das letzte benutzte Stackwort. Deshalb sind Parameter in der Regel relativ zu diesem Stackpointer abgelegt (Achtung: Der Stack wächst von hohen Adressen in Richtung niedrigen Adressen).
Rückgabewerte werden in eax geschrieben, der Aufrufer erwartet dann, dass dort das Ergebnis steht.
Weitere Details solltest du Problemlos finden, wenn du nach x86 calling conventions suchst.
Eigentlich wollte ich den LeGo-Thread nicht mehr mit meinen Anliegen belasten, aber ich komme leider nicht weiter, obwohl es für mich keinen Sinn ergibt, warum nicht geht, was ich tun möchte.
Wie Ihr wisst, habe ich mit Zugriff auf c_npc (var int inventory2_vtbl; // 0x0550) und dieser Funktion
Code:
func void Npc_DisableTransferMoreThanOneItem(var c_npc slf, var int disable) {
const int adr = 6710736; //0x6665D0
CALL_IntParam(!!disable);
CALL__thiscall(MEM_InstToPtr(slf) + 1360, adr);
};
über Npc_DisableTransferMoreThanOneItem(hero, 1); in bestimmten Fällen Items nur einzeln aus dem Inventar in einen anderen ItemContainer zu übertragen. Neben MobContainern wollte ich nun auch die ItemContainer von anderen NPCs so manipulieren, dass ich Items nur einzeln rüberziehen kann. Wie Sektenspinner dachte auch ich, wenn das mit dem hero klappt, sollte das doch auch mit allen anderen NPCs gehen, wenn man sich vorher die Instanz holt. Komischerweise geht es nicht und ich würde gern wissen, warum es nicht geht. Kann es sein, dass die var int inventory2_vtbl nur beim hero so esxistiert?
den NPC geholt (Print des Namens funktioniert) und dann an gleicher Stelle wie Npc_DisableTransferMoreThanOneItem(hero, 1); auch noch Npc_DisableTransferMoreThanOneItem(coth, 1); aufgerufen. Der Transfer von mehr als einem Item mit Strg + Alt aus dem NPC-Inv zum Hero-Inv ist jedoch weiterhin möglich, während es vom Hero Inventar in das NPC-Inv funktioniert. Ich verstehe einfach nicht, warum das nicht geht. Bitte nochmals um Hilfe.
Edit: Ok, Ich glaube ich bin der Sache auf der Spur. Ich habe jetzt gesehen, dass Npc_DisableTransferMoreThanOneItem(hero, 1); im Trade Manager auch keine Wirkung zeigt. D.h. es muss sich im Trade Manager bei allen vier ItemContainern um vier eigenständige handeln, ich vermute mal, dass es bei den zwei äußeren "neu generierte" ItemContainer sind, die jeweils zur Laufzeit bzw. beim Aufruf nur mit den Items aus dem jeweiligen NPC-Inventar gefüllt werden. Da sollte ich nochmal in IDA nachsehen, was ich da noch finden kann. Dennoch nehme ich Ideen gerne entgegen.
Kann es sein das ein paar Dialoggestures-animationen nicht im Archiv enthalten sind?
Ich spreche von Hum_GreetGrd_M01.asc und Hum_GreetCool_M01.asc.
mfg Umfi
Das sind Gothic 2 Animationen. Du kannst sie mit dem Gothic Sourcer aus kompilierten Animationen gewinnen. Der Einfachheit halber, hab ich sie aber einfach mal angehängt.
@Der Ahnungslose: Da sich das so hartnäckig sträubt: Wofür willst du das eigentlich haben? Vielleicht krieg ich noch eine Idee, wenn ich weiß, wieso du das benötigst.
Das sind Gothic 2 Animationen. Du kannst sie mit dem Gothic Sourcer aus kompilierten Animationen gewinnen. Der Einfachheit halber, hab ich sie aber einfach mal angehängt.
Danke fürs hochladen. Hast mir gleich eine Frage erspart.
@Sektenspinner: Wie ist das eigentlich bei C_NPCs und oCNpcs? "Erbt" oCNpc von C_NPC (oder andersherum) oder wie sieht der Zusammenhang da aus?
@Der Ahnungslose: Ich habe bisher immer die Erfahrung gemacht, dass die Call Funktionen vor allem oCNpcs oder oCItems annehmen und damit funktionieren (C_NPCs haben da irgendwie immer nicht funktioniert, warum auch immer...). Vielleicht irre ich mich, aber du kannst es ja mal mit einem oCNpc probieren.
@Der Ahnungslose: Da sich das so hartnäckig sträubt: Wofür willst du das eigentlich haben? Vielleicht krieg ich noch eine Idee, wenn ich weiß, wieso du das benötigst.
Ich will einfach nur noch Item für Item plündern können. Bisher geht es aus der Truhe heraus ja schon, aber aus dem NPC-Inv hraus will es einfach nicht gehen. Der ignoriert die Einstellung von toth.inventory2_oCItemContainer_m_bCanTransferMoreThanOneItem=0; obwohl Sie 0 ist, was ich durch einen Print bestätigen lasse.
Zitat von Rantragon
@Der Ahnungslose: Ich habe bisher immer die Erfahrung gemacht, dass die Call Funktionen vor allem oCNpcs oder oCItems annehmen und damit funktionieren (C_NPCs haben da irgendwie immer nicht funktioniert, warum auch immer...). Vielleicht irre ich mich, aber du kannst es ja mal mit einem oCNpc probieren.
Glaub mir, in dieser Sache habe ich nichts unversucht gelassen, aber es will einfach nicht.
@Sektenspinner: Wie ist das eigentlich bei C_NPCs und oCNpcs? "Erbt" oCNpc von C_NPC (oder andersherum) oder wie sieht der Zusammenhang da aus?
Es ist das gleiche. Stell dir vor ein C_NPC ist genau das selbe wie in oCNpc, nur dass einige Eigenschaften als "private" deklariert sind.
Die Klassenvariable C_NPC.id hat auch nicht den Offset 0 wie man es erwarten wurde (weil ID das erste Member von C_NPC ist), sondern den Offset 0x120. Es gibt also eine Spezialbehandlung in der Engine, die alle Member von C_NPC um den passenden Wert "nach hinten verschiebt".
Jede Funktion, die einen C_NPC erwartet kann auch einen oCNpc entgegennehmen und umgekehrt, denn beides sind letztlich Pointer auf oCNpcs.
@Der Ahnungslose: Ich meinte eigentlich mehr in welcher Situation du das einsetzen willst. Grundsätzlich wäre das ja eher nervig. Wenn ich weiß, dass du es für ein tolles Feature brauchst, kann ich mich vielleichte her motivieren das nochmal genauer anzuschauen.
Hallo, ich habe mal eine Frage zu den Engine Hooks.
Wo genau soll man die aufrufen?
Ich rufe sie momentan im der Startup auf. Aber nicht in der Init_Global ().
Denn sonst stürzt G2 nach einem Levelwechsel + Item aufheben in der neuen Welt ab.
Hier mal, der Hook. Ich habe ihn hier im Thread gefunden und nur etwas verändert. (rot makiert)
Code:
///////////////////////////////////////////////////////////////////////////////
// Hook: Item aufheben
//////////////////////////////////////////////////////////////////////////////
func void Hook_oCNpc__DoTakeVob() {
const int oCNpc__DoTakeVob = 7621056; //0x7449C0
HookEngine(oCNpc__DoTakeVob, 6, "EVT_NPCTAKEVOB");
};
func void EVT_NpcTakeVob()
{
// ----- an den NPC und das item kommen -----
var c_npc slf; slf = MEM_PtrToInst(ECX); // der NPC, der das Item einsammelt
var C_ITEM itm; itm = MEM_PtrToInst(MEM_ReadInt(ESP + 4)); // Pointer auf das Item
// ----- an den NPC und das item kommen -----
// ----- stimmt das item? -----
if (!Hlp_IsValidItem (itm))
{
return;
}
else
{
if (Hlp_StrCmp (itm.name, "Unkraut"))
{
Weed_Counter = Weed_Counter+1;
};
};
};
Es funktioniert auch, aber wenn ich das Spiel starte -> 'Neues Spiel starten' und gleich nach dem laden noch mal 'Neues Spiel starten' klicke, und dann ein Item aufhebe crashed G2.